python: assume F4 MCU for bootstubs without bcdDevice set (#1229)

* python: assume F4 MCU for bootstubs without bcdDevice set

* cleanup
This commit is contained in:
Adeeb Shihadeh
2023-01-28 14:41:52 -08:00
committed by GitHub
parent 6ae5212d6a
commit e7f36a2992
6 changed files with 62 additions and 22 deletions

View File

@@ -227,8 +227,6 @@ class Panda:
self._disable_checks = disable_checks
self._handle = None
self._bcd_device = None
self.can_rx_overflow_buffer = b''
# connect and set mcu type
@@ -253,13 +251,30 @@ class Panda:
self._handle = None
# try USB first, then SPI
self._handle, serial, self.bootstub, self._bcd_device = self.usb_connect(self._serial, claim=claim, wait=wait)
self._handle, serial, self.bootstub, bcd = self.usb_connect(self._serial, claim=claim, wait=wait)
if self._handle is None:
self._handle, serial, self.bootstub, _ = self.spi_connect(self._serial)
self._handle, serial, self.bootstub, bcd = self.spi_connect(self._serial)
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._mcu_type = self.get_mcu_type()
self.health_version, self.can_version, self.can_health_version = self.get_packets_versions()
@@ -584,10 +599,9 @@ class Panda:
def get_type(self):
ret = self._handle.controlRead(Panda.REQUEST_IN, 0xc1, 0, 0, 0x40)
# bootstub doesn't implement this call, so fallback to bcdDevice
invalid_type = self.bootstub and (ret is None or len(ret) != 1)
if invalid_type and self._bcd_device is not None:
ret = self._bcd_device
# 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
@@ -608,6 +622,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 has_obd(self):

View File

@@ -5,6 +5,8 @@ from panda import Panda, PandaDFU, McuType, BASEDIR
from .helpers import test_all_pandas, panda_connect_and_init, check_signature
# TODO: make more comprehensive bootstub tests and run on a few production ones + current
# TODO: also test release-signed app
@test_all_pandas
@panda_connect_and_init
def test_a_known_bootstub(p):
@@ -12,25 +14,44 @@ def test_a_known_bootstub(p):
Test that compiled app can work with known production bootstub
"""
known_bootstubs = {
McuType.F4: "bootstub.panda.bin",
McuType.H7: "bootstub.panda_h7.bin",
# covers the two cases listed in Panda.connect
McuType.F4: [
# case A - no bcdDevice or panda type, has to assume F4
"bootstub_f4_first_dos_production.panda.bin",
# case B - just bcdDevice
"bootstub_f4_only_bcd.panda.bin",
],
McuType.H7: ["bootstub.panda_h7.bin"],
}
p.reset(enter_bootstub=True)
p.reset(enter_bootloader=True)
for kb in known_bootstubs[p.get_mcu_type()]:
app_ids = (p.get_mcu_type(), p.get_usb_serial())
assert None not in app_ids
dfu_serial = PandaDFU.st_serial_to_dfu_serial(p._serial, p._mcu_type)
assert Panda.wait_for_dfu(dfu_serial, timeout=30)
p.reset(enter_bootstub=True)
p.reset(enter_bootloader=True)
dfu = PandaDFU(dfu_serial)
fn = known_bootstubs[p._mcu_type]
with open(os.path.join(BASEDIR, "tests/hitl/known_bootstub", fn), "rb") as f:
code = f.read()
dfu_serial = PandaDFU.st_serial_to_dfu_serial(p._serial, p._mcu_type)
assert Panda.wait_for_dfu(dfu_serial, timeout=30)
dfu.program_bootstub(code)
p.connect(True, True)
p.flash()
check_signature(p)
dfu = PandaDFU(dfu_serial)
with open(os.path.join(BASEDIR, "tests/hitl/known_bootstub", kb), "rb") as f:
code = f.read()
dfu.program_bootstub(code)
p.connect(claim=False, wait=True)
# check for MCU or serial mismatch
with Panda(p._serial, claim=False) as np:
bootstub_ids = (np.get_mcu_type(), np.get_usb_serial())
assert app_ids == bootstub_ids
# ensure we can flash app and it jumps to app
p.flash()
check_signature(p)
assert not p.bootstub
@test_all_pandas
@panda_connect_and_init

0
tests/hitl/known_bootstub/bootstub.panda_h7.bin Executable file → Normal file
View File

Binary file not shown.