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:
Igor Biletskyy
2021-11-12 16:36:34 -08:00
committed by GitHub
parent 73bbf58567
commit ae26b75d7b
46 changed files with 531 additions and 341 deletions

View File

@@ -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