mirror of
https://github.com/infiniteCable2/panda.git
synced 2026-02-18 17:23:52 +08:00
CAN_FIFOMailBox to CANPacket struct + USB dynamic packet size (#739)
* Squashed commits, no cleanup * Few fixes * No init = garbage * Only receive with new canpacket * Add send with canpacket * Revert "Add send with canpacket" This reverts commit 7d06686ddd6d447c714b5289d31af24403d36931. * Packet must be aligned to word, or bad performance * Cleaner * Fix tests * Tests... * MISRA 10.4 * More MISRA * libpandasafety_py * cffi * even more tests... * typo * ... * ... * ... * Slight cleanup * MISRA 6.1 * MISRA 17.7 * Bug in bxcan + even style * MISRA 10.1 * Revert "MISRA 10.1" This reverts commit 404ae7fcc39556f80f528de9015702e69f4ea0a5. * ... * MISRA 10.1 and 10.4 suppress until next PR * MISRA 20.1 * ... * test_honda * ... * ... * test_toyota * test_volkswagen_mqb * test_volkswagen_pq * Sketchy thing... * Revert "Sketchy thing..." This reverts commit 3b2e5715bdc1954f7b7b3b7469ba3d0eaa06bdf9. * remove comment * bxcan extended address bug * Concept, experimental dynamic usb packet size * increase each buffer to 10240 bytes * raise python bulk read/write limits * ... * Move packet size to start * Experimental send, stream-like * New receive test, stream-like * cleanup * cleanup + rebase fixes * MISRA * Extra receive method, stream-like, commented out * type change * Revert back to buffer for send, stream commented * forgot ZLP * lower buffer, add rx failsafe * ... remove ZLP * return ZLP back * Add tx checks to panda fw * TX stream with counter * fix counter overflow * 13 free slots should be enough * limit tx usb packet * ... * Revert max_bulk_msg doubling * python lib improve speed * Stream with counter for RX, dirty, needs cleanup * Increase chunk length to 4096 bytes * cleanup fdcan.h * cleanup __init__.py * MISRA 12.1 * MISRA 10.8 * remove non-streaming usb functions * more main.c cleanup * MISRA 15.6 * MISRA 15.5 * MISRA 18.4 and suppress objectIndex * handling usb pakcets > 63bytes, naming and cleanup * Cleanup old from tests and update CANPacket_t struct * Switch to 4 bit DLC instead of 6 bit length * ops) * ... * pylint * receive python buffer increase * USB increase receive packet len * tweak buffers * No need for so high limits * MISRA 20.1 workaround * performance tweaks * cleanup, dlc to data_len_code naming * main.c naming * comments and cleanup for main.c usb * clean py lib * pylint * do not discard good rx messages on stream fail * cleanups * naming * remove bitstruct lib and lower tx limit * bitstruct lefovers * fix bug in VW test * remove adjusting data size and assert on wrong len * ... * test new memcpy before merging * Revert "test new memcpy before merging" This reverts commit 399465a264835061adabdd785718c4b6fc18c267. * macros for to/fromuint8_t array * MISRA hates me! * tests.c include macros instead * move CANPacket to can_definitions.h * vw_pq python test fix * new memcpy test, REMOVE * check without alignment * revert macros for uint8 arrays * Revert "revert macros for uint8 arrays" This reverts commit 581a9db735a42d0d68200bd270d87a8fd34e43fe. * check assert * Revert "check assert" This reverts commit 9e970d029a50597a1718b2bb0260196c050fd77f. * one more variation * Revert "one more variation" This reverts commit f6c0528b7ac7e125750dc0d9445c7ce97f6954b5. * what about read performance * Revert "what about read performance" This reverts commit d2610f90958a816fe7f1822157a84f85e97d9249. * check struct alignment to word * check for aligned memcpy again * cleanup * add CANPacket structure diagram * update CANPacket and add USB packet struct * bugfix + refactoring of EP1 * move dlc_to_len to header * missed include * typo... * MISRA * fk * lower MAX_CAN_MSGS_PER_BULK_TRANSFER * bump CAN_PACKET_VERSION to 2 * bump python lib CAN_PACKET_VERSION to 2 * rename parse_can_buffer to unpack_can_buffer * CANPacket_t const fields * Revert "CANPacket_t const fields" This reverts commit cf91c035b7706a14e317550c5f0501ae3fce7c70. * test.c relative path * cleanup * move macros to safety_declarations * Refactor pack/unpack funcs and add unittest * usb_protocol.h * oops * Update .github/workflows/test.yaml Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com> * remove print from unittest Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
This commit is contained in:
@@ -16,26 +16,83 @@ from .serial import PandaSerial # noqa pylint: disable=import-error
|
||||
from .isotp import isotp_send, isotp_recv # pylint: disable=import-error
|
||||
from .config import DEFAULT_FW_FN, DEFAULT_H7_FW_FN # noqa pylint: disable=import-error
|
||||
|
||||
__version__ = '0.0.9'
|
||||
__version__ = '0.0.10'
|
||||
|
||||
BASEDIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../")
|
||||
|
||||
DEBUG = os.getenv("PANDADEBUG") is not None
|
||||
|
||||
def parse_can_buffer(dat):
|
||||
ret = []
|
||||
for j in range(0, len(dat), 0x10):
|
||||
ddat = dat[j:j + 0x10]
|
||||
f1, f2 = struct.unpack("II", ddat[0:8])
|
||||
extended = 4
|
||||
if f1 & extended:
|
||||
address = f1 >> 3
|
||||
else:
|
||||
address = f1 >> 21
|
||||
dddat = ddat[8:8 + (f2 & 0xF)]
|
||||
CANPACKET_HEAD_SIZE = 0x5
|
||||
DLC_TO_LEN = [0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64]
|
||||
LEN_TO_DLC = {length: dlc for (dlc, length) in enumerate(DLC_TO_LEN)}
|
||||
|
||||
def pack_can_buffer(arr):
|
||||
snds = [b'']
|
||||
idx = 0
|
||||
for address, _, dat, bus in arr:
|
||||
assert len(dat) in LEN_TO_DLC
|
||||
if DEBUG:
|
||||
print(f" R 0x{address:x}: 0x{dddat.hex()}")
|
||||
ret.append((address, f2 >> 16, dddat, (f2 >> 4) & 0xFF))
|
||||
print(f" W 0x{address:x}: 0x{dat.hex()}")
|
||||
extended = 1 if address >= 0x800 else 0
|
||||
data_len_code = LEN_TO_DLC[len(dat)]
|
||||
header = bytearray(5)
|
||||
word_4b = address << 3 | extended << 2
|
||||
header[0] = (data_len_code << 4) | (bus << 1)
|
||||
header[1] = word_4b & 0xFF
|
||||
header[2] = (word_4b >> 8) & 0xFF
|
||||
header[3] = (word_4b >> 16) & 0xFF
|
||||
header[4] = (word_4b >> 24) & 0xFF
|
||||
snds[idx] += header + dat
|
||||
if len(snds[idx]) > 256: # Limit chunks to 256 bytes
|
||||
snds.append(b'')
|
||||
idx += 1
|
||||
|
||||
#Apply counter to each 64 byte packet
|
||||
for idx in range(len(snds)):
|
||||
tx = b''
|
||||
counter = 0
|
||||
for i in range (0, len(snds[idx]), 63):
|
||||
tx += bytes([counter]) + snds[idx][i:i+63]
|
||||
counter += 1
|
||||
snds[idx] = tx
|
||||
return snds
|
||||
|
||||
def unpack_can_buffer(dat):
|
||||
ret = []
|
||||
counter = 0
|
||||
tail = bytearray()
|
||||
for i in range(0, len(dat), 64):
|
||||
if counter != dat[i]:
|
||||
print("CAN: LOST RECV PACKET COUNTER")
|
||||
break
|
||||
counter+=1
|
||||
chunk = tail + dat[i+1:i+64]
|
||||
tail = bytearray()
|
||||
pos = 0
|
||||
while pos<len(chunk):
|
||||
data_len = DLC_TO_LEN[(chunk[pos]>>4)]
|
||||
pckt_len = CANPACKET_HEAD_SIZE + data_len
|
||||
if pckt_len <= len(chunk[pos:]):
|
||||
header = chunk[pos:pos+CANPACKET_HEAD_SIZE]
|
||||
if len(header) < 5:
|
||||
print("CAN: MALFORMED USB RECV PACKET")
|
||||
break
|
||||
bus = (header[0] >> 1) & 0x7
|
||||
address = (header[4] << 24 | header[3] << 16 | header[2] << 8 | header[1]) >> 3
|
||||
returned = (header[1] >> 1) & 0x1
|
||||
rejected = header[1] & 0x1
|
||||
data = chunk[pos + CANPACKET_HEAD_SIZE:pos + CANPACKET_HEAD_SIZE + data_len]
|
||||
if returned:
|
||||
bus += 128
|
||||
if rejected:
|
||||
bus += 192
|
||||
if DEBUG:
|
||||
print(f" R 0x{address:x}: 0x{data.hex()}")
|
||||
ret.append((address, 0, data, bus))
|
||||
pos += pckt_len
|
||||
else:
|
||||
tail = chunk[pos:]
|
||||
break
|
||||
return ret
|
||||
|
||||
def ensure_health_packet_version(fn):
|
||||
@@ -76,7 +133,7 @@ class PandaWifiStreaming(object):
|
||||
try:
|
||||
dat, addr = self.sock.recvfrom(0x200 * 0x10)
|
||||
if addr == (self.ip, self.port):
|
||||
ret += parse_can_buffer(dat)
|
||||
ret += unpack_can_buffer(dat)
|
||||
except socket.error as e:
|
||||
if e.errno != 35 and e.errno != 11:
|
||||
traceback.print_exc()
|
||||
@@ -161,7 +218,7 @@ class Panda(object):
|
||||
HW_TYPE_DOS = b'\x06'
|
||||
HW_TYPE_RED_PANDA = b'\x07'
|
||||
|
||||
CAN_PACKET_VERSION = 1
|
||||
CAN_PACKET_VERSION = 2
|
||||
HEALTH_PACKET_VERSION = 1
|
||||
|
||||
F2_DEVICES = [HW_TYPE_PEDAL]
|
||||
@@ -546,34 +603,20 @@ class Panda(object):
|
||||
|
||||
@ensure_can_packet_version
|
||||
def can_send_many(self, arr, timeout=CAN_SEND_TIMEOUT_MS):
|
||||
snds = []
|
||||
transmit = 1
|
||||
extended = 4
|
||||
for addr, _, dat, bus in arr:
|
||||
assert len(dat) <= 8
|
||||
if DEBUG:
|
||||
print(f" W 0x{addr:x}: 0x{dat.hex()}")
|
||||
if addr >= 0x800:
|
||||
rir = (addr << 3) | transmit | extended
|
||||
else:
|
||||
rir = (addr << 21) | transmit
|
||||
snd = struct.pack("II", rir, len(dat) | (bus << 4)) + dat
|
||||
snd = snd.ljust(0x10, b'\x00')
|
||||
snds.append(snd)
|
||||
|
||||
snds = pack_can_buffer(arr)
|
||||
while True:
|
||||
try:
|
||||
if self.wifi:
|
||||
for s in snds:
|
||||
self._handle.bulkWrite(3, s)
|
||||
else:
|
||||
dat = b''.join(snds)
|
||||
while True:
|
||||
bs = self._handle.bulkWrite(3, dat, timeout=timeout)
|
||||
dat = dat[bs:]
|
||||
if len(dat) == 0:
|
||||
break
|
||||
print("CAN: PARTIAL SEND MANY, RETRYING")
|
||||
for tx in snds:
|
||||
while True:
|
||||
bs = self._handle.bulkWrite(3, tx, timeout=timeout)
|
||||
tx = tx[bs:]
|
||||
if len(tx) == 0:
|
||||
break
|
||||
print("CAN: PARTIAL SEND MANY, RETRYING")
|
||||
break
|
||||
except (usb1.USBErrorIO, usb1.USBErrorOverflow):
|
||||
print("CAN: BAD SEND MANY, RETRYING")
|
||||
@@ -586,12 +629,12 @@ class Panda(object):
|
||||
dat = bytearray()
|
||||
while True:
|
||||
try:
|
||||
dat = self._handle.bulkRead(1, 0x10 * 256)
|
||||
dat = self._handle.bulkRead(1, 16384) # Max receive batch size + 2 extra reserve frames
|
||||
break
|
||||
except (usb1.USBErrorIO, usb1.USBErrorOverflow):
|
||||
print("CAN: BAD RECV, RETRYING")
|
||||
time.sleep(0.1)
|
||||
return parse_can_buffer(dat)
|
||||
return unpack_can_buffer(dat)
|
||||
|
||||
def can_clear(self, bus):
|
||||
"""Clears all messages from the specified internal CAN ringbuffer as
|
||||
|
||||
Reference in New Issue
Block a user