142 lines
4.2 KiB
Python
142 lines
4.2 KiB
Python
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...")
|