mirror of
https://github.com/dragonpilot/dragonpilot.git
synced 2026-07-14 09:22:05 +08:00
lp-dp 2023-05-09T02:32:30 for EON/C2
version: lp-dp v0.9.2 for EON/C2 date: 2023-05-09T02:32:30 commit: cb8adff9d368de2e442e1e7f4309b70a4a2013ad
This commit is contained in:
+43
-25
@@ -183,21 +183,31 @@ class Panda:
|
||||
HW_TYPE_TRES = b'\x09'
|
||||
|
||||
CAN_PACKET_VERSION = 4
|
||||
HEALTH_PACKET_VERSION = 11
|
||||
HEALTH_PACKET_VERSION = 14
|
||||
CAN_HEALTH_PACKET_VERSION = 4
|
||||
# dp - 2 extra "B" at the end:
|
||||
# "usb_power_mode": a[23],
|
||||
# "torque_interceptor_detected": a[24],
|
||||
HEALTH_STRUCT = struct.Struct("<IIIIIIIIIBBBBBBHBBBHfBBBB")
|
||||
HEALTH_STRUCT = struct.Struct("<IIIIIIIIIBBBBBBHBBBHfBBHBHHBB")
|
||||
CAN_HEALTH_STRUCT = struct.Struct("<BIBBBBBBBBIIIIIIIHHBBB")
|
||||
|
||||
F2_DEVICES = (HW_TYPE_PEDAL, )
|
||||
F4_DEVICES = (HW_TYPE_WHITE_PANDA, HW_TYPE_GREY_PANDA, HW_TYPE_BLACK_PANDA, HW_TYPE_UNO, HW_TYPE_DOS)
|
||||
H7_DEVICES = (HW_TYPE_RED_PANDA, HW_TYPE_RED_PANDA_V2, HW_TYPE_TRES)
|
||||
|
||||
INTERNAL_DEVICES = (HW_TYPE_UNO, HW_TYPE_DOS)
|
||||
INTERNAL_DEVICES = (HW_TYPE_UNO, HW_TYPE_DOS, HW_TYPE_TRES)
|
||||
HAS_OBD = (HW_TYPE_BLACK_PANDA, HW_TYPE_UNO, HW_TYPE_DOS, HW_TYPE_RED_PANDA, HW_TYPE_RED_PANDA_V2, HW_TYPE_TRES)
|
||||
|
||||
MAX_FAN_RPMs = {
|
||||
HW_TYPE_UNO: 5100,
|
||||
HW_TYPE_DOS: 6500,
|
||||
HW_TYPE_TRES: 6600,
|
||||
}
|
||||
|
||||
HARNESS_STATUS_NC = 0
|
||||
HARNESS_STATUS_NORMAL = 1
|
||||
HARNESS_STATUS_FLIPPED = 2
|
||||
|
||||
# first byte is for EPS scaling factor
|
||||
FLAG_TOYOTA_ALT_BRAKE = (1 << 8)
|
||||
FLAG_TOYOTA_STOCK_LONGITUDINAL = (2 << 8)
|
||||
@@ -319,8 +329,9 @@ class Panda:
|
||||
@staticmethod
|
||||
def usb_connect(serial, claim=True, wait=False):
|
||||
handle, usb_serial, bootstub, bcd = None, None, None, None
|
||||
context = usb1.USBContext()
|
||||
while 1:
|
||||
context = usb1.USBContext()
|
||||
context.open()
|
||||
try:
|
||||
for device in context.getDeviceList(skip_on_error=True):
|
||||
if device.getVendorID() == 0xbbaa and device.getProductID() in (0xddcc, 0xddee):
|
||||
@@ -351,7 +362,7 @@ class Panda:
|
||||
logging.exception("USB connect error")
|
||||
if not wait or handle is not None:
|
||||
break
|
||||
context = usb1.USBContext() # New context needed so new devices show up
|
||||
context.close()
|
||||
|
||||
usb_handle = None
|
||||
if handle is not None:
|
||||
@@ -367,21 +378,21 @@ class Panda:
|
||||
|
||||
@staticmethod
|
||||
def usb_list():
|
||||
context = usb1.USBContext()
|
||||
ret = []
|
||||
try:
|
||||
for device in context.getDeviceList(skip_on_error=True):
|
||||
if device.getVendorID() == 0xbbaa and device.getProductID() in (0xddcc, 0xddee):
|
||||
try:
|
||||
serial = device.getSerialNumber()
|
||||
if len(serial) == 24:
|
||||
ret.append(serial)
|
||||
else:
|
||||
warnings.warn(f"found device with panda descriptors but invalid serial: {serial}", RuntimeWarning)
|
||||
except Exception:
|
||||
continue
|
||||
with usb1.USBContext() as context:
|
||||
for device in context.getDeviceList(skip_on_error=True):
|
||||
if device.getVendorID() == 0xbbaa and device.getProductID() in (0xddcc, 0xddee):
|
||||
try:
|
||||
serial = device.getSerialNumber()
|
||||
if len(serial) == 24:
|
||||
ret.append(serial)
|
||||
else:
|
||||
warnings.warn(f"found device with panda descriptors but invalid serial: {serial}", RuntimeWarning)
|
||||
except Exception:
|
||||
continue
|
||||
except Exception:
|
||||
pass
|
||||
logging.exception("exception while listing pandas")
|
||||
return ret
|
||||
|
||||
@staticmethod
|
||||
@@ -424,7 +435,7 @@ class Panda:
|
||||
except Exception:
|
||||
logging.debug("reconnecting is taking %d seconds...", i + 1)
|
||||
try:
|
||||
dfu = PandaDFU(PandaDFU.st_serial_to_dfu_serial(self._serial, self._mcu_type))
|
||||
dfu = PandaDFU(self.get_dfu_serial())
|
||||
dfu.recover()
|
||||
except Exception:
|
||||
pass
|
||||
@@ -495,8 +506,8 @@ class Panda:
|
||||
if reconnect:
|
||||
self.reconnect()
|
||||
|
||||
def recover(self, timeout: Optional[int] = None, reset: bool = True) -> bool:
|
||||
dfu_serial = PandaDFU.st_serial_to_dfu_serial(self._serial, self._mcu_type)
|
||||
def recover(self, timeout: Optional[int] = 60, reset: bool = True) -> bool:
|
||||
dfu_serial = self.get_dfu_serial()
|
||||
|
||||
if reset:
|
||||
self.reset(enter_bootstub=True)
|
||||
@@ -561,8 +572,12 @@ class Panda:
|
||||
"interrupt_load": a[20],
|
||||
"fan_power": a[21],
|
||||
"safety_rx_checks_invalid": a[22],
|
||||
"usb_power_mode": a[23],
|
||||
"torque_interceptor_detected": a[24],
|
||||
"spi_checksum_error_count": a[23],
|
||||
"fan_stall_count": a[24],
|
||||
"sbu1_voltage_mV": a[25],
|
||||
"sbu2_voltage_mV": a[26],
|
||||
"usb_power_mode": a[27],
|
||||
"torque_interceptor_detected": a[28],
|
||||
}
|
||||
|
||||
@ensure_can_health_packet_version
|
||||
@@ -617,9 +632,9 @@ class Panda:
|
||||
|
||||
@staticmethod
|
||||
def get_signature_from_firmware(fn) -> bytes:
|
||||
f = open(fn, 'rb')
|
||||
f.seek(-128, 2) # Seek from end of file
|
||||
return f.read(128)
|
||||
with open(fn, 'rb') as f:
|
||||
f.seek(-128, 2) # Seek from end of file
|
||||
return f.read(128)
|
||||
|
||||
def get_signature(self) -> bytes:
|
||||
part_1 = self._handle.controlRead(Panda.REQUEST_IN, 0xd3, 0, 0, 0x40)
|
||||
@@ -681,6 +696,9 @@ class Panda:
|
||||
"""
|
||||
return self._serial
|
||||
|
||||
def get_dfu_serial(self):
|
||||
return PandaDFU.st_serial_to_dfu_serial(self._serial, self._mcu_type)
|
||||
|
||||
def get_uid(self):
|
||||
"""
|
||||
Returns the UID from the MCU
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import os
|
||||
|
||||
BASEDIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../")
|
||||
|
||||
BOOTSTUB_ADDRESS = 0x8000000
|
||||
|
||||
BLOCK_SIZE_FX = 0x800
|
||||
APP_ADDRESS_FX = 0x8004000
|
||||
SECTOR_SIZES_FX = [0x4000 for _ in range(4)] + [0x10000] + [0x20000 for _ in range(11)]
|
||||
DEVICE_SERIAL_NUMBER_ADDR_FX = 0x1FFF79C0
|
||||
DEFAULT_FW_FN = os.path.join(BASEDIR, "board", "obj", "panda.bin.signed")
|
||||
DEFAULT_BOOTSTUB_FN = os.path.join(BASEDIR, "board", "obj", "bootstub.panda.bin")
|
||||
|
||||
BLOCK_SIZE_H7 = 0x400
|
||||
APP_ADDRESS_H7 = 0x8020000
|
||||
SECTOR_SIZES_H7 = [0x20000 for _ in range(7)] # there is an 8th sector, but we use that for the provisioning chunk, so don't program over that!
|
||||
DEVICE_SERIAL_NUMBER_ADDR_H7 = 0x080FFFC0
|
||||
DEFAULT_H7_FW_FN = os.path.join(BASEDIR, "board", "obj", "panda_h7.bin.signed")
|
||||
DEFAULT_H7_BOOTSTUB_FN = os.path.join(BASEDIR, "board", "obj", "bootstub.panda_h7.bin")
|
||||
+8
-7
@@ -27,6 +27,7 @@ class PandaDFU:
|
||||
def usb_connect(dfu_serial: Optional[str]) -> Optional[STBootloaderUSBHandle]:
|
||||
handle = None
|
||||
context = usb1.USBContext()
|
||||
context.open()
|
||||
for device in context.getDeviceList(skip_on_error=True):
|
||||
if device.getVendorID() == 0x0483 and device.getProductID() == 0xdf11:
|
||||
try:
|
||||
@@ -64,15 +65,15 @@ class PandaDFU:
|
||||
|
||||
@staticmethod
|
||||
def usb_list() -> List[str]:
|
||||
context = usb1.USBContext()
|
||||
dfu_serials = []
|
||||
try:
|
||||
for device in context.getDeviceList(skip_on_error=True):
|
||||
if device.getVendorID() == 0x0483 and device.getProductID() == 0xdf11:
|
||||
try:
|
||||
dfu_serials.append(device.open().getASCIIStringDescriptor(3))
|
||||
except Exception:
|
||||
pass
|
||||
with usb1.USBContext() as context:
|
||||
for device in context.getDeviceList(skip_on_error=True):
|
||||
if device.getVendorID() == 0x0483 and device.getProductID() == 0xdf11:
|
||||
try:
|
||||
dfu_serials.append(device.open().getASCIIStringDescriptor(3))
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
return dfu_serials
|
||||
|
||||
+28
-16
@@ -28,7 +28,7 @@ CHECKSUM_START = 0xAB
|
||||
MIN_ACK_TIMEOUT_MS = 100
|
||||
MAX_XFER_RETRY_COUNT = 5
|
||||
|
||||
USB_MAX_SIZE = 0x40
|
||||
XFER_SIZE = 1000
|
||||
|
||||
DEV_PATH = "/dev/spidev0.0"
|
||||
|
||||
@@ -58,7 +58,7 @@ class SpiDevice:
|
||||
"""
|
||||
Provides locked, thread-safe access to a panda's SPI interface.
|
||||
"""
|
||||
def __init__(self, speed=30000000):
|
||||
def __init__(self, speed):
|
||||
if not os.path.exists(DEV_PATH):
|
||||
raise PandaSpiUnavailable(f"SPI device not found: {DEV_PATH}")
|
||||
if spidev is None:
|
||||
@@ -87,7 +87,9 @@ class PandaSpiHandle(BaseHandle):
|
||||
A class that mimics a libusb1 handle for panda SPI communications.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.dev = SpiDevice()
|
||||
# 50MHz is the max of the 845. older rev comma three
|
||||
# may not support the full 50MHz
|
||||
self.dev = SpiDevice(50000000)
|
||||
|
||||
# helpers
|
||||
def _calc_checksum(self, data: List[int]) -> int:
|
||||
@@ -96,12 +98,12 @@ class PandaSpiHandle(BaseHandle):
|
||||
cksum ^= b
|
||||
return cksum
|
||||
|
||||
def _wait_for_ack(self, spi, ack_val: int, timeout: int) -> None:
|
||||
def _wait_for_ack(self, spi, ack_val: int, timeout: int, tx: int) -> None:
|
||||
timeout_s = max(MIN_ACK_TIMEOUT_MS, timeout) * 1e-3
|
||||
|
||||
start = time.monotonic()
|
||||
while (timeout == 0) or ((time.monotonic() - start) < timeout_s):
|
||||
dat = spi.xfer2(b"\x12")[0]
|
||||
dat = spi.xfer2([tx, ])[0]
|
||||
if dat == NACK:
|
||||
raise PandaSpiNackResponse
|
||||
elif dat == ack_val:
|
||||
@@ -123,7 +125,7 @@ class PandaSpiHandle(BaseHandle):
|
||||
spi.xfer2(packet)
|
||||
|
||||
logging.debug("- waiting for header ACK")
|
||||
self._wait_for_ack(spi, HACK, timeout)
|
||||
self._wait_for_ack(spi, HACK, timeout, 0x11)
|
||||
|
||||
# send data
|
||||
logging.debug("- sending data")
|
||||
@@ -131,7 +133,7 @@ class PandaSpiHandle(BaseHandle):
|
||||
spi.xfer2(packet)
|
||||
|
||||
logging.debug("- waiting for data ACK")
|
||||
self._wait_for_ack(spi, DACK, timeout)
|
||||
self._wait_for_ack(spi, DACK, timeout, 0x13)
|
||||
|
||||
# get response length, then response
|
||||
response_len_bytes = bytes(spi.xfer2(b"\x00" * 2))
|
||||
@@ -147,7 +149,7 @@ class PandaSpiHandle(BaseHandle):
|
||||
return dat[:-1]
|
||||
except PandaSpiException as e:
|
||||
exc = e
|
||||
logging.debug("SPI transfer failed, %d retries left", n, exc_info=True)
|
||||
logging.debug("SPI transfer failed, %d retries left", MAX_XFER_RETRY_COUNT - n - 1, exc_info=True)
|
||||
raise exc
|
||||
|
||||
# libusb1 functions
|
||||
@@ -165,17 +167,17 @@ class PandaSpiHandle(BaseHandle):
|
||||
# TODO: implement these properly
|
||||
def bulkWrite(self, endpoint: int, data: List[int], timeout: int = TIMEOUT) -> int:
|
||||
with self.dev.acquire() as spi:
|
||||
for x in range(math.ceil(len(data) / USB_MAX_SIZE)):
|
||||
self._transfer(spi, endpoint, data[USB_MAX_SIZE*x:USB_MAX_SIZE*(x+1)], timeout)
|
||||
for x in range(math.ceil(len(data) / XFER_SIZE)):
|
||||
self._transfer(spi, endpoint, data[XFER_SIZE*x:XFER_SIZE*(x+1)], timeout)
|
||||
return len(data)
|
||||
|
||||
def bulkRead(self, endpoint: int, length: int, timeout: int = TIMEOUT) -> bytes:
|
||||
ret: List[int] = []
|
||||
with self.dev.acquire() as spi:
|
||||
for _ in range(math.ceil(length / USB_MAX_SIZE)):
|
||||
d = self._transfer(spi, endpoint, [], timeout, max_rx_len=USB_MAX_SIZE)
|
||||
for _ in range(math.ceil(length / XFER_SIZE)):
|
||||
d = self._transfer(spi, endpoint, [], timeout, max_rx_len=XFER_SIZE)
|
||||
ret += d
|
||||
if len(d) < USB_MAX_SIZE:
|
||||
if len(d) < XFER_SIZE:
|
||||
break
|
||||
return bytes(ret)
|
||||
|
||||
@@ -199,7 +201,7 @@ class STBootloaderSPIHandle(BaseSTBootloaderHandle):
|
||||
spi.xfer([self.SYNC, ])
|
||||
try:
|
||||
self._get_ack(spi)
|
||||
except PandaSpiNackResponse:
|
||||
except (PandaSpiNackResponse, PandaSpiMissingAck):
|
||||
# NACK ok here, will only ACK the first time
|
||||
pass
|
||||
|
||||
@@ -220,13 +222,13 @@ class STBootloaderSPIHandle(BaseSTBootloaderHandle):
|
||||
elif data != self.ACK:
|
||||
raise PandaSpiMissingAck
|
||||
|
||||
def _cmd(self, cmd: int, data: Optional[List[bytes]] = None, read_bytes: int = 0, predata=None) -> bytes:
|
||||
def _cmd_no_retry(self, cmd: int, data: Optional[List[bytes]] = None, read_bytes: int = 0, predata=None) -> bytes:
|
||||
ret = b""
|
||||
with self.dev.acquire() as spi:
|
||||
# sync + command
|
||||
spi.xfer([self.SYNC, ])
|
||||
spi.xfer([cmd, cmd ^ 0xFF])
|
||||
self._get_ack(spi)
|
||||
self._get_ack(spi, timeout=0.1)
|
||||
|
||||
# "predata" - for commands that send the first data without a checksum
|
||||
if predata is not None:
|
||||
@@ -250,6 +252,16 @@ class STBootloaderSPIHandle(BaseSTBootloaderHandle):
|
||||
|
||||
return bytes(ret)
|
||||
|
||||
def _cmd(self, cmd: int, data: Optional[List[bytes]] = None, read_bytes: int = 0, predata=None) -> bytes:
|
||||
exc = PandaSpiException()
|
||||
for n in range(MAX_XFER_RETRY_COUNT):
|
||||
try:
|
||||
return self._cmd_no_retry(cmd, data, read_bytes, predata)
|
||||
except PandaSpiException as e:
|
||||
exc = e
|
||||
logging.debug("SPI transfer failed, %d retries left", MAX_XFER_RETRY_COUNT - n - 1, exc_info=True)
|
||||
raise exc
|
||||
|
||||
def _checksum(self, data: bytes) -> bytes:
|
||||
if len(data) == 1:
|
||||
ret = data[0] ^ 0xFF
|
||||
|
||||
+38
-22
@@ -141,6 +141,12 @@ class DYNAMIC_DEFINITION_TYPE(IntEnum):
|
||||
DEFINE_BY_MEMORY_ADDRESS = 2
|
||||
CLEAR_DYNAMICALLY_DEFINED_DATA_IDENTIFIER = 3
|
||||
|
||||
class ISOTP_FRAME_TYPE(IntEnum):
|
||||
SINGLE = 0
|
||||
FIRST = 1
|
||||
CONSECUTIVE = 2
|
||||
FLOW = 3
|
||||
|
||||
class DynamicSourceDefinition(NamedTuple):
|
||||
data_identifier: int
|
||||
position: int
|
||||
@@ -438,38 +444,41 @@ class IsoTpMessage():
|
||||
timeout = self.timeout
|
||||
|
||||
start_time = time.monotonic()
|
||||
updated = False
|
||||
rx_in_progress = False
|
||||
try:
|
||||
while True:
|
||||
for msg in self._can_client.recv():
|
||||
self._isotp_rx_next(msg)
|
||||
frame_type = self._isotp_rx_next(msg)
|
||||
start_time = time.monotonic()
|
||||
updated = True
|
||||
rx_in_progress = frame_type == ISOTP_FRAME_TYPE.CONSECUTIVE
|
||||
if self.tx_done and self.rx_done:
|
||||
return self.rx_dat, updated
|
||||
return self.rx_dat, False
|
||||
# no timeout indicates non-blocking
|
||||
if timeout == 0:
|
||||
return None, updated
|
||||
return None, rx_in_progress
|
||||
if time.monotonic() - start_time > timeout:
|
||||
raise MessageTimeoutError("timeout waiting for response")
|
||||
finally:
|
||||
if self.debug and self.rx_dat:
|
||||
print(f"ISO-TP: RESPONSE - {hex(self._can_client.rx_addr)} 0x{bytes.hex(self.rx_dat)}")
|
||||
|
||||
def _isotp_rx_next(self, rx_data: bytes) -> None:
|
||||
# single rx_frame
|
||||
if rx_data[0] >> 4 == 0x0:
|
||||
def _isotp_rx_next(self, rx_data: bytes) -> ISOTP_FRAME_TYPE:
|
||||
# ISO 15765-2 specifies an eight byte CAN frame for ISO-TP communication
|
||||
assert len(rx_data) == self.max_len, f"isotp - rx: invalid CAN frame length: {len(rx_data)}"
|
||||
|
||||
if rx_data[0] >> 4 == ISOTP_FRAME_TYPE.SINGLE:
|
||||
self.rx_len = rx_data[0] & 0xFF
|
||||
assert self.rx_len < self.max_len, f"isotp - rx: invalid single frame length: {self.rx_len}"
|
||||
self.rx_dat = rx_data[1:1 + self.rx_len]
|
||||
self.rx_idx = 0
|
||||
self.rx_done = True
|
||||
if self.debug:
|
||||
print(f"ISO-TP: RX - single frame - {hex(self._can_client.rx_addr)} idx={self.rx_idx} done={self.rx_done}")
|
||||
return
|
||||
return ISOTP_FRAME_TYPE.SINGLE
|
||||
|
||||
# first rx_frame
|
||||
if rx_data[0] >> 4 == 0x1:
|
||||
elif rx_data[0] >> 4 == ISOTP_FRAME_TYPE.FIRST:
|
||||
self.rx_len = ((rx_data[0] & 0x0F) << 8) + rx_data[1]
|
||||
assert self.max_len <= self.rx_len, f"isotp - rx: invalid first frame length: {self.rx_len}"
|
||||
self.rx_dat = rx_data[2:]
|
||||
self.rx_idx = 0
|
||||
self.rx_done = False
|
||||
@@ -479,10 +488,9 @@ class IsoTpMessage():
|
||||
print(f"ISO-TP: TX - flow control continue - {hex(self._can_client.tx_addr)}")
|
||||
# send flow control message
|
||||
self._can_client.send([self.flow_control_msg])
|
||||
return
|
||||
return ISOTP_FRAME_TYPE.FIRST
|
||||
|
||||
# consecutive rx frame
|
||||
if rx_data[0] >> 4 == 0x2:
|
||||
elif rx_data[0] >> 4 == ISOTP_FRAME_TYPE.CONSECUTIVE:
|
||||
assert not self.rx_done, "isotp - rx: consecutive frame with no active frame"
|
||||
self.rx_idx += 1
|
||||
assert self.rx_idx & 0xF == rx_data[0] & 0xF, "isotp - rx: invalid consecutive frame index"
|
||||
@@ -495,10 +503,9 @@ class IsoTpMessage():
|
||||
self._can_client.send([self.flow_control_msg])
|
||||
if self.debug:
|
||||
print(f"ISO-TP: RX - consecutive frame - {hex(self._can_client.rx_addr)} idx={self.rx_idx} done={self.rx_done}")
|
||||
return
|
||||
return ISOTP_FRAME_TYPE.CONSECUTIVE
|
||||
|
||||
# flow control
|
||||
if rx_data[0] >> 4 == 0x3:
|
||||
elif rx_data[0] >> 4 == ISOTP_FRAME_TYPE.FLOW:
|
||||
assert not self.tx_done, "isotp - rx: flow control with no active frame"
|
||||
assert rx_data[0] != 0x32, "isotp - rx: flow-control overflow/abort"
|
||||
assert rx_data[0] == 0x30 or rx_data[0] == 0x31, "isotp - rx: flow-control transfer state indicator invalid"
|
||||
@@ -512,7 +519,7 @@ class IsoTpMessage():
|
||||
|
||||
# first frame = 6 bytes, each consecutive frame = 7 bytes
|
||||
num_bytes = self.max_len - 1
|
||||
start = 6 + self.tx_idx * num_bytes
|
||||
start = self.max_len - 2 + self.tx_idx * num_bytes
|
||||
count = rx_data[1]
|
||||
end = start + count * num_bytes if count > 0 else self.tx_len
|
||||
tx_msgs = []
|
||||
@@ -531,9 +538,16 @@ class IsoTpMessage():
|
||||
# wait (do nothing until next flow control message)
|
||||
if self.debug:
|
||||
print(f"ISO-TP: TX - flow control wait - {hex(self._can_client.tx_addr)}")
|
||||
return ISOTP_FRAME_TYPE.FLOW
|
||||
|
||||
# 4-15 - reserved
|
||||
else:
|
||||
raise Exception(f"isotp - rx: invalid frame type: {rx_data[0] >> 4}")
|
||||
|
||||
|
||||
FUNCTIONAL_ADDRS = [0x7DF, 0x18DB33F1]
|
||||
|
||||
|
||||
def get_rx_addr_for_tx_addr(tx_addr, rx_offset=0x8):
|
||||
if tx_addr in FUNCTIONAL_ADDRS:
|
||||
return None
|
||||
@@ -551,15 +565,16 @@ def get_rx_addr_for_tx_addr(tx_addr, rx_offset=0x8):
|
||||
|
||||
|
||||
class UdsClient():
|
||||
def __init__(self, panda, tx_addr: int, rx_addr: int = None, bus: int = 0, timeout: float = 1, debug: bool = False,
|
||||
tx_timeout: float = 1, response_pending_timeout: float = 10):
|
||||
def __init__(self, panda, tx_addr: int, rx_addr: int = None, bus: int = 0, sub_addr: int = None, timeout: float = 1,
|
||||
debug: bool = False, tx_timeout: float = 1, response_pending_timeout: float = 10):
|
||||
self.bus = bus
|
||||
self.tx_addr = tx_addr
|
||||
self.rx_addr = rx_addr if rx_addr is not None else get_rx_addr_for_tx_addr(tx_addr)
|
||||
self.sub_addr = sub_addr
|
||||
self.timeout = timeout
|
||||
self.debug = debug
|
||||
can_send_with_timeout = partial(panda.can_send, timeout=int(tx_timeout*1000))
|
||||
self._can_client = CanClient(can_send_with_timeout, panda.can_recv, self.tx_addr, self.rx_addr, self.bus, debug=self.debug)
|
||||
self._can_client = CanClient(can_send_with_timeout, panda.can_recv, self.tx_addr, self.rx_addr, self.bus, self.sub_addr, debug=self.debug)
|
||||
self.response_pending_timeout = response_pending_timeout
|
||||
|
||||
# generic uds request
|
||||
@@ -571,7 +586,8 @@ class UdsClient():
|
||||
req += data
|
||||
|
||||
# send request, wait for response
|
||||
isotp_msg = IsoTpMessage(self._can_client, timeout=self.timeout, debug=self.debug)
|
||||
max_len = 8 if self.sub_addr is None else 7
|
||||
isotp_msg = IsoTpMessage(self._can_client, timeout=self.timeout, debug=self.debug, max_len=max_len)
|
||||
isotp_msg.send(req)
|
||||
response_pending = False
|
||||
while True:
|
||||
|
||||
Reference in New Issue
Block a user