From 76d0459182d544d17c86d8b352e9cc1c26035f4d Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 26 Jan 2023 20:54:11 -0800 Subject: [PATCH] cleanup MCU definitions (#1226) * cleanup MCU definitions * rename * enum * enum * fix that --- __init__.py | 13 +++------ python/__init__.py | 20 ++++++-------- python/config.py | 19 ------------- python/constants.py | 50 ++++++++++++++++++++++++++++++++++ python/dfu.py | 45 +++++++++++++----------------- tests/hitl/1_program.py | 16 +++++++---- tests/hitl/helpers.py | 5 ++-- tests/pedal/enter_canloader.py | 5 ++-- 8 files changed, 96 insertions(+), 77 deletions(-) delete mode 100644 python/config.py create mode 100644 python/constants.py diff --git a/__init__.py b/__init__.py index 8558783a8..8b43e9938 100644 --- a/__init__.py +++ b/__init__.py @@ -1,10 +1,5 @@ -from .python import (Panda, PandaDFU, # noqa: F401 - BASEDIR, pack_can_buffer, unpack_can_buffer, calculate_checksum, - DEFAULT_FW_FN, DEFAULT_H7_FW_FN, MCU_TYPE_H7, MCU_TYPE_F4, DLC_TO_LEN, LEN_TO_DLC, - ALTERNATIVE_EXPERIENCE, USBPACKET_MAX_SIZE, CANPACKET_HEAD_SIZE) - +from .python.constants import McuType, BASEDIR # noqa: F401 from .python.serial import PandaSerial # noqa: F401 - -from .python.config import (BOOTSTUB_ADDRESS, BLOCK_SIZE_FX, APP_ADDRESS_FX, # noqa: F401 - BLOCK_SIZE_H7, APP_ADDRESS_H7, DEVICE_SERIAL_NUMBER_ADDR_H7, # noqa: F401 - DEVICE_SERIAL_NUMBER_ADDR_FX) +from .python import (Panda, PandaDFU, # noqa: F401 + pack_can_buffer, unpack_can_buffer, calculate_checksum, + DLC_TO_LEN, LEN_TO_DLC, ALTERNATIVE_EXPERIENCE, USBPACKET_MAX_SIZE, CANPACKET_HEAD_SIZE) diff --git a/python/__init__.py b/python/__init__.py index e22c08bec..71d416bd6 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -13,8 +13,8 @@ from functools import wraps from typing import Optional from itertools import accumulate -from .config import DEFAULT_FW_FN, DEFAULT_H7_FW_FN, SECTOR_SIZES_FX, SECTOR_SIZES_H7 -from .dfu import PandaDFU, MCU_TYPE_F2, MCU_TYPE_F4, MCU_TYPE_H7 +from .constants import McuType +from .dfu import PandaDFU from .isotp import isotp_send, isotp_recv from .spi import SpiHandle, PandaSpiException @@ -25,8 +25,6 @@ LOGLEVEL = os.environ.get('LOGLEVEL', 'INFO').upper() logging.basicConfig(level=LOGLEVEL, format='%(message)s') -BASEDIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../") - USBPACKET_MAX_SIZE = 0x40 CANPACKET_HEAD_SIZE = 0x6 DLC_TO_LEN = [0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64] @@ -409,7 +407,7 @@ class Panda: assert fr[4:8] == b"\xde\xad\xd0\x0d" # determine sectors to erase - apps_sectors_cumsum = accumulate(SECTOR_SIZES_H7[1:] if mcu_type == MCU_TYPE_H7 else SECTOR_SIZES_FX[1:]) + apps_sectors_cumsum = accumulate(mcu_type.config.sector_sizes[1:]) last_sector = next((i + 1 for i, v in enumerate(apps_sectors_cumsum) if v > len(code)), -1) assert last_sector >= 1, "Binary too small? No sector to erase." assert last_sector < 7, "Binary too large! Risk of overwriting provisioning chunk." @@ -438,7 +436,7 @@ class Panda: def flash(self, fn=None, code=None, reconnect=True): if not fn: - fn = DEFAULT_H7_FW_FN if self._mcu_type == MCU_TYPE_H7 else DEFAULT_FW_FN + fn = self._mcu_type.config.app_path assert os.path.isfile(fn) logging.debug("flash: main version is %s", self.get_version()) if not self.bootstub: @@ -602,15 +600,15 @@ class Panda: else: return (0, 0, 0) - def get_mcu_type(self): + def get_mcu_type(self) -> McuType: hw_type = self.get_type() if hw_type in Panda.F2_DEVICES: - return MCU_TYPE_F2 + return McuType.F2 elif hw_type in Panda.F4_DEVICES: - return MCU_TYPE_F4 + return McuType.F4 elif hw_type in Panda.H7_DEVICES: - return MCU_TYPE_H7 - return None + return McuType.H7 + raise ValueError(f"unknown HW type: {hw_type}") def has_obd(self): return self.get_type() in Panda.HAS_OBD diff --git a/python/config.py b/python/config.py deleted file mode 100644 index 56940ed72..000000000 --- a/python/config.py +++ /dev/null @@ -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") diff --git a/python/constants.py b/python/constants.py new file mode 100644 index 000000000..0b8c1a331 --- /dev/null +++ b/python/constants.py @@ -0,0 +1,50 @@ +import os +import enum +from typing import List, NamedTuple + +BASEDIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../") + + +class McuConfig(NamedTuple): + mcu: str + block_size: int + sector_sizes: List[int] + serial_number_address: int + app_address: int + app_path: str + bootstub_address: int + bootstub_path: str + +Fx = ( + 0x800, + [0x4000 for _ in range(4)] + [0x10000] + [0x20000 for _ in range(11)], + 0x1FFF79C0, + 0x8004000, + os.path.join(BASEDIR, "board", "obj", "panda.bin.signed"), + 0x8000000, + os.path.join(BASEDIR, "board", "obj", "bootstub.panda.bin"), +) +F2Config = McuConfig("STM32F2", *Fx) +F4Config = McuConfig("STM32F4", *Fx) + +H7Config = McuConfig( + "STM32H7", + 0x400, + # there is an 8th sector, but we use that for the provisioning chunk, so don't program over that! + [0x20000 for _ in range(7)], + 0x080FFFC0, + 0x8020000, + os.path.join(BASEDIR, "board", "obj", "panda_h7.bin.signed"), + 0x8000000, + os.path.join(BASEDIR, "board", "obj", "bootstub.panda_h7.bin"), +) + +@enum.unique +class McuType(enum.Enum): + F2 = F2Config + F4 = F4Config + H7 = H7Config + + @property + def config(self): + return self.value diff --git a/python/dfu.py b/python/dfu.py index 317780ca8..dfdec1fd3 100644 --- a/python/dfu.py +++ b/python/dfu.py @@ -1,12 +1,9 @@ import usb1 import struct import binascii -from .config import BOOTSTUB_ADDRESS, APP_ADDRESS_H7, APP_ADDRESS_FX, BLOCK_SIZE_H7, BLOCK_SIZE_FX, DEFAULT_H7_BOOTSTUB_FN, DEFAULT_BOOTSTUB_FN +from .constants import McuType -MCU_TYPE_F2 = 0 -MCU_TYPE_F4 = 1 -MCU_TYPE_H7 = 2 # *** DFU mode *** DFU_DNLOAD = 1 @@ -15,8 +12,9 @@ DFU_GETSTATUS = 3 DFU_CLRSTATUS = 4 DFU_ABORT = 6 -class PandaDFU(object): +class PandaDFU: def __init__(self, dfu_serial): + self._handle = None context = usb1.USBContext() for device in context.getDeviceList(skip_on_error=True): if device.getVendorID() == 0x0483 and device.getProductID() == 0xdf11: @@ -25,10 +23,12 @@ class PandaDFU(object): except Exception: continue if this_dfu_serial == dfu_serial or dfu_serial is None: - self._mcu_type = self.get_mcu_type(device) self._handle = device.open() - return - raise Exception("failed to open " + dfu_serial if dfu_serial is not None else "DFU device") + self._mcu_type = self.get_mcu_type(device) + break + + if self._handle is None: + raise Exception(f"failed to open DFU device {dfu_serial}") @staticmethod def list(): @@ -46,18 +46,19 @@ class PandaDFU(object): return dfu_serials @staticmethod - def st_serial_to_dfu_serial(st, mcu_type=MCU_TYPE_F4): + def st_serial_to_dfu_serial(st, mcu_type=McuType.F4): if st is None or st == "none": return None uid_base = struct.unpack("H" * 6, bytes.fromhex(st)) - if mcu_type == MCU_TYPE_H7: + if mcu_type == McuType.H7: return binascii.hexlify(struct.pack("!HHH", uid_base[1] + uid_base[5], uid_base[0] + uid_base[4], uid_base[3])).upper().decode("utf-8") else: return binascii.hexlify(struct.pack("!HHH", uid_base[1] + uid_base[5], uid_base[0] + uid_base[4] + 0xA, uid_base[3])).upper().decode("utf-8") - # TODO: Find a way to detect F4 vs F2 - def get_mcu_type(self, dev): - return MCU_TYPE_H7 if dev.getbcdDevice() == 512 else MCU_TYPE_F4 + def get_mcu_type(self, dev) -> McuType: + # TODO: Find a way to detect F4 vs F2 + # TODO: also check F4 BCD, don't assume in else + return McuType.H7 if dev.getbcdDevice() == 512 else McuType.F4 def status(self): while 1: @@ -97,26 +98,18 @@ class PandaDFU(object): def program_bootstub(self, code_bootstub): self.clear_status() - self.erase(BOOTSTUB_ADDRESS) - if self._mcu_type == MCU_TYPE_H7: - self.erase(APP_ADDRESS_H7) - self.program(BOOTSTUB_ADDRESS, code_bootstub, BLOCK_SIZE_H7) - else: - self.erase(APP_ADDRESS_FX) - self.program(BOOTSTUB_ADDRESS, code_bootstub, BLOCK_SIZE_FX) + self.erase(self._mcu_type.config.bootstub_address) + self.erase(self._mcu_type.config.app_address) + self.program(self._mcu_type.config.bootstub_address, code_bootstub, self._mcu_type.config.block_size) self.reset() def recover(self): - fn = DEFAULT_H7_BOOTSTUB_FN if self._mcu_type == MCU_TYPE_H7 else DEFAULT_BOOTSTUB_FN - - with open(fn, "rb") as f: + with open(self._mcu_type.config.bootstub_path, "rb") as f: code = f.read() - self.program_bootstub(code) def reset(self): - # **** Reset **** - self._handle.controlWrite(0x21, DFU_DNLOAD, 0, 0, b"\x21" + struct.pack("I", BOOTSTUB_ADDRESS)) + self._handle.controlWrite(0x21, DFU_DNLOAD, 0, 0, b"\x21" + struct.pack("I", self._mcu_type.config.bootstub_address)) self.status() try: self._handle.controlWrite(0x21, DFU_DNLOAD, 2, 0, b"") diff --git a/tests/hitl/1_program.py b/tests/hitl/1_program.py index cec7fa2e9..20c1be21f 100644 --- a/tests/hitl/1_program.py +++ b/tests/hitl/1_program.py @@ -1,16 +1,20 @@ import os import time -from panda import Panda, PandaDFU, MCU_TYPE_H7, BASEDIR +from panda import Panda, PandaDFU, McuType, BASEDIR from .helpers import test_all_pandas, panda_connect_and_init, check_signature @test_all_pandas @panda_connect_and_init def test_a_known_bootstub(p): - # Test that compiled app can work with known production bootstub - KNOWN_H7_BOOTSTUB_FN = os.path.join(BASEDIR, "tests", "hitl", "known_bootstub", "bootstub.panda_h7.bin") - KNOWN_BOOTSTUB_FN = os.path.join(BASEDIR, "tests", "hitl", "known_bootstub", "bootstub.panda.bin") + """ + Test that compiled app can work with known production bootstub + """ + known_bootstubs = { + McuType.F4: "bootstub.panda.bin", + McuType.H7: "bootstub.panda_h7.bin", + } p.reset(enter_bootstub=True) p.reset(enter_bootloader=True) @@ -19,8 +23,8 @@ def test_a_known_bootstub(p): assert Panda.wait_for_dfu(dfu_serial, timeout=30) dfu = PandaDFU(dfu_serial) - fn = KNOWN_H7_BOOTSTUB_FN if p._mcu_type == MCU_TYPE_H7 else KNOWN_BOOTSTUB_FN - with open(fn, "rb") as f: + fn = known_bootstubs[p._mcu_type] + with open(os.path.join(BASEDIR, "tests/hitl/known_bootstub", fn), "rb") as f: code = f.read() dfu.program_bootstub(code) diff --git a/tests/hitl/helpers.py b/tests/hitl/helpers.py index 1e66251a4..99070f0f9 100644 --- a/tests/hitl/helpers.py +++ b/tests/hitl/helpers.py @@ -7,7 +7,7 @@ from functools import wraps, partial from nose.tools import assert_equal from parameterized import parameterized -from panda import Panda, DEFAULT_H7_FW_FN, DEFAULT_FW_FN, MCU_TYPE_H7 +from panda import Panda from panda_jungle import PandaJungle # pylint: disable=import-error SPEED_NORMAL = 500 @@ -210,7 +210,6 @@ def clear_can_buffers(panda): def check_signature(p): assert not p.bootstub, "Flashed firmware not booting. Stuck in bootstub." - fn = DEFAULT_H7_FW_FN if p.get_mcu_type() == MCU_TYPE_H7 else DEFAULT_FW_FN - firmware_sig = Panda.get_signature_from_firmware(fn) + firmware_sig = Panda.get_signature_from_firmware(p.get_mcu_type().config.app_path) panda_sig = p.get_signature() assert_equal(panda_sig, firmware_sig) diff --git a/tests/pedal/enter_canloader.py b/tests/pedal/enter_canloader.py index c7ae195b5..bdd0d6286 100755 --- a/tests/pedal/enter_canloader.py +++ b/tests/pedal/enter_canloader.py @@ -1,8 +1,7 @@ #!/usr/bin/env python3 import time import argparse -from panda import Panda -from panda.python.dfu import MCU_TYPE_F2 +from panda import Panda, McuType from panda.tests.pedal.canhandle import CanHandle @@ -29,6 +28,6 @@ if __name__ == "__main__": time.sleep(0.1) print("flashing", args.fn) code = open(args.fn, "rb").read() - Panda.flash_static(CanHandle(p, 0), code, mcu_type=MCU_TYPE_F2) + Panda.flash_static(CanHandle(p, 0), code, mcu_type=McuType.F2) print("can flash done")