import ctypes import time import os # Carrega a DLL dll = ctypes.cdll.LoadLibrary(os.path.abspath("ControlCANFD.dll")) DEVICE_TYPE = 41 DEVICE_INDEX = 0 CHANNEL_INDEX = 0 # troca pra 1 se estiver usando CAN2 class VCI_INIT_CONFIG(ctypes.Structure): _fields_ = [ ("AccCode", ctypes.c_uint), ("AccMask", ctypes.c_uint), ("Reserved", ctypes.c_uint), ("Filter", ctypes.c_ubyte), ("Timing0", ctypes.c_ubyte), ("Timing1", ctypes.c_ubyte), ("Mode", ctypes.c_ubyte), ] class VCI_CAN_OBJ(ctypes.Structure): _fields_ = [ ("ID", ctypes.c_uint), ("TimeStamp", ctypes.c_uint), ("TimeFlag", ctypes.c_ubyte), ("SendType", ctypes.c_ubyte), ("RemoteFlag", ctypes.c_ubyte), ("ExternFlag", ctypes.c_ubyte), ("DataLen", ctypes.c_ubyte), ("Data", ctypes.c_ubyte * 8), ("Reserved", ctypes.c_ubyte * 3), ] def u16_be(hi, lo): return ((hi & 0xFF) << 8) | (lo & 0xFF) def parse_0x90(data_bytes): total_v_raw = u16_be(data_bytes[0], data_bytes[1]) meas_v_raw = u16_be(data_bytes[2], data_bytes[3]) current_raw = u16_be(data_bytes[4], data_bytes[5]) soc_raw = u16_be(data_bytes[6], data_bytes[7]) total_v = total_v_raw / 10.0 meas_v = meas_v_raw / 10.0 current = (current_raw - 30000) / 10.0 soc = soc_raw / 10.0 print(f"🔋 Tensão total : {total_v:.1f} V (raw={total_v_raw})") print(f" Tensão medida: {meas_v:.1f} V (raw={meas_v_raw})") print(f" Corrente : {current:.1f} A (raw={current_raw})") print(f" SOC : {soc:.1f} % (raw={soc_raw})") # -------- init device -------- ret = dll.VCI_OpenDevice(DEVICE_TYPE, DEVICE_INDEX, 0) if ret != 1: print("❌ Falha ao abrir dispositivo.") raise SystemExit print("✅ Dispositivo aberto.") # baud 250 kbps baud_250k = ctypes.c_uint(0x1C0008) ret = dll.VCI_SetReference(DEVICE_TYPE, DEVICE_INDEX, CHANNEL_INDEX, 0, ctypes.byref(baud_250k)) if ret != 1: print("❌ Falha ao configurar baudrate.") raise SystemExit print("🔧 Baudrate configurado para 250 kbps.") config = VCI_INIT_CONFIG() config.AccCode = 0 config.AccMask = 0xFFFFFFFF config.Reserved = 0 config.Filter = 0 config.Timing0 = 0 config.Timing1 = 0 config.Mode = 0 ret = dll.VCI_InitCAN(DEVICE_TYPE, DEVICE_INDEX, CHANNEL_INDEX, ctypes.byref(config)) if ret != 1: print("❌ Falha ao inicializar CAN.") raise SystemExit ret = dll.VCI_StartCAN(DEVICE_TYPE, DEVICE_INDEX, CHANNEL_INDEX) if ret != 1: print("❌ Falha ao iniciar CAN.") raise SystemExit dll.VCI_ClearBuffer(DEVICE_TYPE, DEVICE_INDEX, CHANNEL_INDEX) print("🚀 Canal iniciado.\n") recv_buffer = (VCI_CAN_OBJ * 100)() try: while True: # monta request 0x90 send_obj = VCI_CAN_OBJ() send_obj.ID = 0x18900140 # PC -> BMS, DataID 0x90 send_obj.SendType = 0 send_obj.RemoteFlag = 0 send_obj.ExternFlag = 1 # extended send_obj.DataLen = 8 for i in range(8): send_obj.Data[i] = 0x00 dll.VCI_Transmit(DEVICE_TYPE, DEVICE_INDEX, CHANNEL_INDEX, ctypes.byref(send_obj), 1) # espera resposta rápida start = time.time() resp_ok = False while time.time() - start < 0.5: count = dll.VCI_Receive( DEVICE_TYPE, DEVICE_INDEX, CHANNEL_INDEX, ctypes.byref(recv_buffer), 100, 50 ) if count > 0: for i in range(count): obj = recv_buffer[i] if obj.ID == 0x18904001 and obj.DataLen == 8: data = [obj.Data[j] for j in range(8)] print(f"\n📥 RX ID=0x{obj.ID:08X} Data=" + " ".join(f"{b:02X}" for b in data)) parse_0x90(data) resp_ok = True break if resp_ok: break time.sleep(0.05) if not resp_ok: print("\n⚠️ Sem resposta do BMS para 0x90 nesse ciclo.") time.sleep(1.0) except KeyboardInterrupt: print("\n🧹 Encerrando monitor...")