2023-05-22 12:19:19 +08:00
|
|
|
import os
|
2017-08-24 03:49:56 +08:00
|
|
|
import usb1
|
|
|
|
import struct
|
2019-10-04 10:46:28 +08:00
|
|
|
import binascii
|
2017-08-24 03:49:56 +08:00
|
|
|
|
2023-03-07 01:24:00 +08:00
|
|
|
from .base import BaseSTBootloaderHandle
|
2023-03-07 13:52:08 +08:00
|
|
|
from .spi import STBootloaderSPIHandle, PandaSpiException
|
2023-03-07 01:24:00 +08:00
|
|
|
from .usb import STBootloaderUSBHandle
|
2023-05-22 12:19:19 +08:00
|
|
|
from .constants import FW_PATH, McuType
|
2017-08-24 03:49:56 +08:00
|
|
|
|
2021-08-03 11:26:15 +08:00
|
|
|
|
2023-01-27 12:54:11 +08:00
|
|
|
class PandaDFU:
|
2024-02-25 05:56:28 +08:00
|
|
|
def __init__(self, dfu_serial: str | None):
|
2023-03-07 01:24:00 +08:00
|
|
|
# try USB, then SPI
|
2024-02-25 05:56:28 +08:00
|
|
|
handle: BaseSTBootloaderHandle | None
|
2023-08-25 10:15:37 +08:00
|
|
|
self._context, handle = PandaDFU.usb_connect(dfu_serial)
|
2023-03-07 13:52:08 +08:00
|
|
|
if handle is None:
|
2023-08-25 10:15:37 +08:00
|
|
|
self._context, handle = PandaDFU.spi_connect(dfu_serial)
|
2023-03-07 01:24:00 +08:00
|
|
|
|
2023-03-07 13:52:08 +08:00
|
|
|
if handle is None:
|
2023-03-07 01:24:00 +08:00
|
|
|
raise Exception(f"failed to open DFU device {dfu_serial}")
|
|
|
|
|
|
|
|
self._handle: BaseSTBootloaderHandle = handle
|
2023-03-07 13:52:08 +08:00
|
|
|
self._mcu_type: McuType = self._handle.get_mcu_type()
|
2023-03-07 01:24:00 +08:00
|
|
|
|
2023-08-25 10:15:37 +08:00
|
|
|
def __enter__(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def __exit__(self, *args):
|
|
|
|
self.close()
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
if self._handle is not None:
|
|
|
|
self._handle.close()
|
|
|
|
self._handle = None
|
|
|
|
if self._context is not None:
|
|
|
|
self._context.close()
|
|
|
|
|
2023-03-07 01:24:00 +08:00
|
|
|
@staticmethod
|
2024-02-25 05:56:28 +08:00
|
|
|
def usb_connect(dfu_serial: str | None):
|
2023-03-07 13:52:08 +08:00
|
|
|
handle = None
|
2017-08-24 03:49:56 +08:00
|
|
|
context = usb1.USBContext()
|
2023-04-02 14:09:12 +08:00
|
|
|
context.open()
|
2017-08-24 03:49:56 +08:00
|
|
|
for device in context.getDeviceList(skip_on_error=True):
|
|
|
|
if device.getVendorID() == 0x0483 and device.getProductID() == 0xdf11:
|
|
|
|
try:
|
2019-06-27 04:56:02 +08:00
|
|
|
this_dfu_serial = device.open().getASCIIStringDescriptor(3)
|
2017-08-24 03:49:56 +08:00
|
|
|
except Exception:
|
2017-08-30 03:08:53 +08:00
|
|
|
continue
|
2023-03-07 13:52:08 +08:00
|
|
|
|
2017-10-01 14:17:50 +08:00
|
|
|
if this_dfu_serial == dfu_serial or dfu_serial is None:
|
2023-03-07 13:52:08 +08:00
|
|
|
handle = STBootloaderUSBHandle(device, device.open())
|
2023-01-27 12:54:11 +08:00
|
|
|
break
|
|
|
|
|
2023-08-25 10:15:37 +08:00
|
|
|
return context, handle
|
2023-03-07 01:24:00 +08:00
|
|
|
|
|
|
|
@staticmethod
|
2024-02-25 05:56:28 +08:00
|
|
|
def spi_connect(dfu_serial: str | None):
|
2023-03-07 13:52:08 +08:00
|
|
|
handle = None
|
|
|
|
this_dfu_serial = None
|
|
|
|
|
|
|
|
try:
|
|
|
|
handle = STBootloaderSPIHandle()
|
|
|
|
this_dfu_serial = PandaDFU.st_serial_to_dfu_serial(handle.get_uid(), handle.get_mcu_type())
|
|
|
|
except PandaSpiException:
|
|
|
|
handle = None
|
|
|
|
|
|
|
|
if dfu_serial is not None and dfu_serial != this_dfu_serial:
|
|
|
|
handle = None
|
|
|
|
|
2023-08-25 10:15:37 +08:00
|
|
|
return None, handle
|
2023-03-07 01:24:00 +08:00
|
|
|
|
|
|
|
@staticmethod
|
2024-02-25 05:56:28 +08:00
|
|
|
def usb_list() -> list[str]:
|
2017-08-24 03:49:56 +08:00
|
|
|
dfu_serials = []
|
2017-09-13 11:53:40 +08:00
|
|
|
try:
|
2023-04-02 14:09:12 +08:00
|
|
|
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
|
2017-09-13 11:53:40 +08:00
|
|
|
except Exception:
|
|
|
|
pass
|
2017-08-24 03:49:56 +08:00
|
|
|
return dfu_serials
|
|
|
|
|
2023-03-07 01:24:00 +08:00
|
|
|
@staticmethod
|
2024-02-25 05:56:28 +08:00
|
|
|
def spi_list() -> list[str]:
|
2023-03-07 13:52:08 +08:00
|
|
|
try:
|
2023-08-25 10:15:37 +08:00
|
|
|
_, h = PandaDFU.spi_connect(None)
|
2023-03-07 13:52:08 +08:00
|
|
|
if h is not None:
|
|
|
|
dfu_serial = PandaDFU.st_serial_to_dfu_serial(h.get_uid(), h.get_mcu_type())
|
|
|
|
return [dfu_serial, ]
|
|
|
|
except PandaSpiException:
|
|
|
|
pass
|
2023-03-07 01:24:00 +08:00
|
|
|
return []
|
|
|
|
|
2017-08-24 03:49:56 +08:00
|
|
|
@staticmethod
|
2023-03-06 12:19:27 +08:00
|
|
|
def st_serial_to_dfu_serial(st: str, mcu_type: McuType = McuType.F4):
|
2020-06-01 16:49:26 +08:00
|
|
|
if st is None or st == "none":
|
2017-10-01 14:17:50 +08:00
|
|
|
return None
|
2020-06-01 16:49:26 +08:00
|
|
|
uid_base = struct.unpack("H" * 6, bytes.fromhex(st))
|
2023-01-27 12:54:11 +08:00
|
|
|
if mcu_type == McuType.H7:
|
2021-08-03 11:26:15 +08:00
|
|
|
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")
|
|
|
|
|
2023-03-07 01:24:00 +08:00
|
|
|
def get_mcu_type(self) -> McuType:
|
|
|
|
return self._mcu_type
|
|
|
|
|
|
|
|
def reset(self):
|
|
|
|
self._handle.jump(self._mcu_type.config.bootstub_address)
|
2017-08-24 03:49:56 +08:00
|
|
|
|
2017-08-29 01:42:23 +08:00
|
|
|
def program_bootstub(self, code_bootstub):
|
2023-03-07 01:24:00 +08:00
|
|
|
self._handle.clear_status()
|
2023-09-15 03:49:59 +08:00
|
|
|
|
|
|
|
# erase all sectors
|
|
|
|
for i in range(len(self._mcu_type.config.sector_sizes)):
|
|
|
|
self._handle.erase_sector(i)
|
|
|
|
|
2023-03-07 13:52:08 +08:00
|
|
|
self._handle.program(self._mcu_type.config.bootstub_address, code_bootstub)
|
2017-08-29 01:42:23 +08:00
|
|
|
|
|
|
|
def recover(self):
|
2023-05-22 12:19:19 +08:00
|
|
|
fn = os.path.join(FW_PATH, self._mcu_type.config.bootstub_fn)
|
|
|
|
with open(fn, "rb") as f:
|
2017-08-29 01:42:23 +08:00
|
|
|
code = f.read()
|
|
|
|
self.program_bootstub(code)
|
2023-05-22 11:05:21 +08:00
|
|
|
self.reset()
|
2024-02-25 05:56:28 +08:00
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def list() -> list[str]:
|
|
|
|
ret = PandaDFU.usb_list()
|
|
|
|
ret += PandaDFU.spi_list()
|
|
|
|
return list(set(ret))
|