This commit is contained in:
1okko
2025-11-19 13:55:09 +08:00
parent ec60d7beea
commit ded8a94d77
5 changed files with 57 additions and 36 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -116,23 +116,25 @@ class Panda:
HW_TYPE_UNKNOWN = b'\x00'
HW_TYPE_WHITE = b'\x01'
HW_TYPE_BLACK = b'\x03'
HW_TYPE_DOS = b'\x06'
HW_TYPE_RED_PANDA = b'\x07'
HW_TYPE_TRES = b'\x09'
HW_TYPE_CUATRO = b'\x0a'
CAN_PACKET_VERSION = 4
HEALTH_PACKET_VERSION = 17
HEALTH_PACKET_VERSION = 16
CAN_HEALTH_PACKET_VERSION = 5
HEALTH_STRUCT = struct.Struct("<IIIIIIIIBBBBBHBBBHfBBHHHB")
HEALTH_STRUCT = struct.Struct("<IIIIIIIIBBBBBHBBBHfBBHBHHB")
CAN_HEALTH_STRUCT = struct.Struct("<BIBBBBBBBBIIIIIIIHHBBBIIII")
F4_DEVICES = [HW_TYPE_WHITE, HW_TYPE_BLACK]
F4_DEVICES = [HW_TYPE_WHITE, HW_TYPE_BLACK, HW_TYPE_DOS, ]
H7_DEVICES = [HW_TYPE_RED_PANDA, HW_TYPE_TRES, HW_TYPE_CUATRO]
SUPPORTED_DEVICES = H7_DEVICES
INTERNAL_DEVICES = (HW_TYPE_TRES, HW_TYPE_CUATRO)
INTERNAL_DEVICES = (HW_TYPE_DOS, HW_TYPE_TRES, HW_TYPE_CUATRO)
DEPRECATED_DEVICES = (HW_TYPE_WHITE, HW_TYPE_BLACK)
MAX_FAN_RPMs = {
HW_TYPE_DOS: 6500,
HW_TYPE_TRES: 6600,
HW_TYPE_CUATRO: 12500,
}
@@ -208,6 +210,23 @@ class Panda:
if self._handle is None:
raise Exception("failed to connect to panda")
# Some fallback logic to determine panda and MCU type for old bootstubs,
# since we now support multiple MCUs and need to know which fw to flash.
# Three cases to consider:
# A) oldest bootstubs don't have any way to distinguish
# MCU or panda type
# B) slightly newer (~2 weeks after first C3's built) bootstubs
# have the panda type set in the USB bcdDevice
# C) latest bootstubs also implement the endpoint for panda type
self._bcd_hw_type = None
ret = self._handle.controlRead(Panda.REQUEST_IN, 0xc1, 0, 0, 0x40)
missing_hw_type_endpoint = self.bootstub and ret.startswith(b'\xff\x00\xc1\x3e\xde\xad\xd0\x0d')
if missing_hw_type_endpoint and bcd is not None:
self._bcd_hw_type = bcd
# For case A, we assume F4 MCU type, since all H7 pandas should be case B at worst
self._assume_f4_mcu = (self._bcd_hw_type is None) and missing_hw_type_endpoint
self._serial = serial
self._connect_serial = serial
self._handle_open = True
@@ -216,7 +235,7 @@ class Panda:
logger.debug("connected")
hw_type = self.get_type()
if hw_type not in self.SUPPORTED_DEVICES:
if hw_type in Panda.DEPRECATED_DEVICES:
print("WARNING: Using deprecated HW")
# disable openpilot's heartbeat checks
@@ -432,7 +451,7 @@ class Panda:
handle.controlWrite(Panda.REQUEST_IN, 0xb2, i, 0, b'')
# flash over EP2
STEP = 0x200
STEP = 0x10
logger.info("flash: flashing")
for i in range(0, len(code), STEP):
handle.bulkWrite(2, code[i:i + STEP])
@@ -450,7 +469,7 @@ class Panda:
return
hw_type = self.get_type()
if hw_type not in self.SUPPORTED_DEVICES:
if hw_type in Panda.DEPRECATED_DEVICES:
raise RuntimeError(f"HW type {hw_type.hex()} is deprecated and can no longer be flashed.")
if not fn:
@@ -556,9 +575,10 @@ class Panda:
"fan_power": a[19],
"safety_rx_checks_invalid": a[20],
"spi_error_count": a[21],
"sbu1_voltage_mV": a[22],
"sbu2_voltage_mV": a[23],
"som_reset_triggered": a[24],
"fan_stall_count": a[22],
"sbu1_voltage_mV": a[23],
"sbu2_voltage_mV": a[24],
"som_reset_triggered": a[25],
}
@ensure_can_health_packet_version
@@ -621,7 +641,16 @@ class Panda:
return bytes(part_1 + part_2)
def get_type(self):
return self._handle.controlRead(Panda.REQUEST_IN, 0xc1, 0, 0, 0x40)
ret = self._handle.controlRead(Panda.REQUEST_IN, 0xc1, 0, 0, 0x40)
# rick - UNO to DOS for lite
if ret == bytearray(b'\x05'):
ret = bytearray(b'\x06')
# old bootstubs don't implement this endpoint, see comment in Panda.device
if self._bcd_hw_type is not None and (ret is None or len(ret) != 1):
ret = self._bcd_hw_type
return ret
# Returns tuple with health packet version and CAN packet/USB packet version
def get_packets_versions(self):
@@ -638,6 +667,11 @@ class Panda:
return McuType.F4
elif hw_type in Panda.H7_DEVICES:
return McuType.H7
else:
# have to assume F4, see comment in Panda.connect
if self._assume_f4_mcu:
return McuType.F4
raise ValueError(f"unknown HW type: {hw_type}")
def is_internal(self):
@@ -678,8 +712,8 @@ class Panda:
# ******************* configuration *******************
def set_alternative_experience(self, alternative_experience, safety_param_sp=0):
self._handle.controlWrite(Panda.REQUEST_OUT, 0xdf, int(alternative_experience), int(safety_param_sp), b'')
def set_alternative_experience(self, alternative_experience):
self._handle.controlWrite(Panda.REQUEST_OUT, 0xdf, int(alternative_experience), 0, b'')
def set_power_save(self, power_save_enabled=0):
self._handle.controlWrite(Panda.REQUEST_OUT, 0xe7, int(power_save_enabled), 0, b'')
@@ -784,8 +818,8 @@ class Panda:
ret += self._handle.bulkWrite(2, struct.pack("B", port_number) + ln[i:i + 0x20])
return ret
def send_heartbeat(self, engaged=True, engaged_mads=True):
self._handle.controlWrite(Panda.REQUEST_OUT, 0xf3, engaged, engaged_mads, b'')
def send_heartbeat(self, engaged=True):
self._handle.controlWrite(Panda.REQUEST_OUT, 0xf3, engaged, 0, b'')
# disable heartbeat checks for use outside of openpilot
# sending a heartbeat will reenable the checks
@@ -815,6 +849,8 @@ class Panda:
self._handle.controlWrite(Panda.REQUEST_OUT, 0xf6, int(enabled), 0, b'')
# ****************** Debug *****************
def set_green_led(self, enabled):
self._handle.controlWrite(Panda.REQUEST_OUT, 0xf7, int(enabled), 0, b'')
# arr: timer period
# ccrN: channel N pulse length

Binary file not shown.

View File

@@ -29,12 +29,6 @@ def flash_panda(panda_serial: str) -> Panda:
HARDWARE.recover_internal_panda()
raise
# skip flashing if the detected panda is not supported
supported_panda = check_panda_support(panda)
if not supported_panda:
cloudlog.warning(f"Panda {panda_serial} is not supported (hw_type: {panda.get_type()}), skipping flash...")
return panda
fw_signature = get_expected_signature(panda)
internal_panda = panda.is_internal()
@@ -67,14 +61,6 @@ def flash_panda(panda_serial: str) -> Panda:
return panda
def check_panda_support(panda) -> bool:
hw_type = panda.get_type()
if hw_type in Panda.SUPPORTED_DEVICES:
return True
return False
def main() -> None:
# signal pandad to close the relay and exit
def signal_handler(signum, frame):
@@ -99,6 +85,11 @@ def main() -> None:
cloudlog.event("pandad.flash_and_connect", count=count)
params.remove("PandaSignatures")
# TODO: remove this in the next AGNOS
# wait until USB is up before counting
if time.monotonic() < 60.:
no_internal_panda_count = 0
# Handle missing internal panda
if no_internal_panda_count > 0:
if no_internal_panda_count == 3:
@@ -148,12 +139,6 @@ def main() -> None:
params.put("PandaSignatures", b','.join(p.get_signature() for p in pandas))
for panda in pandas:
# skip health check if the detected panda is not supported
supported_panda = check_panda_support(panda)
if not supported_panda:
cloudlog.warning(f"Panda {panda.get_usb_serial()} is not supported (hw_type: {panda.get_type()}), skipping health check...")
continue
# check health for lost heartbeat
health = panda.health()
if health["heartbeat_lost"]: