cleanup MCU definitions (#1226)

* cleanup MCU definitions

* rename

* enum

* enum

* fix that
This commit is contained in:
Adeeb Shihadeh 2023-01-26 20:54:11 -08:00 committed by GitHub
parent 33e576214d
commit 76d0459182
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 96 additions and 77 deletions

View File

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

View File

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

View File

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

50
python/constants.py Normal file
View File

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

View File

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

View File

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

View File

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

View File

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