dragonpilot 2023-03-27T06:11:06 for EON/C2

version: dragonpilot v0.9.2 beta for EON/C2
date: 2023-03-27T06:11:06
dp-dev(priv2) master commit: 0a08aa2b73a505e11e4c98ac6c5989464b7d339f
This commit is contained in:
Dragonpilot Team
2023-03-25 08:58:31 +00:00
committed by Comma Device
parent f770882b7f
commit ea800c8f74
452 changed files with 22242 additions and 10694 deletions

View File

@@ -1,22 +1,31 @@
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 typing import List, Optional
from .base import BaseSTBootloaderHandle
from .spi import STBootloaderSPIHandle, PandaSpiException
from .usb import STBootloaderUSBHandle
from .constants import McuType
MCU_TYPE_F2 = 0
MCU_TYPE_F4 = 1
MCU_TYPE_H7 = 2
class PandaDFU:
def __init__(self, dfu_serial: Optional[str]):
# try USB, then SPI
handle: Optional[BaseSTBootloaderHandle]
handle = PandaDFU.usb_connect(dfu_serial)
if handle is None:
handle = PandaDFU.spi_connect(dfu_serial)
# *** DFU mode ***
DFU_DNLOAD = 1
DFU_UPLOAD = 2
DFU_GETSTATUS = 3
DFU_CLRSTATUS = 4
DFU_ABORT = 6
if handle is None:
raise Exception(f"failed to open DFU device {dfu_serial}")
class PandaDFU(object):
def __init__(self, dfu_serial):
self._handle: BaseSTBootloaderHandle = handle
self._mcu_type: McuType = self._handle.get_mcu_type()
@staticmethod
def usb_connect(dfu_serial: Optional[str]) -> Optional[STBootloaderUSBHandle]:
handle = None
context = usb1.USBContext()
for device in context.getDeviceList(skip_on_error=True):
if device.getVendorID() == 0x0483 and device.getProductID() == 0xdf11:
@@ -24,14 +33,37 @@ class PandaDFU(object):
this_dfu_serial = device.open().getASCIIStringDescriptor(3)
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")
handle = STBootloaderUSBHandle(device, device.open())
break
return handle
@staticmethod
def list():
def spi_connect(dfu_serial: Optional[str]) -> Optional[STBootloaderSPIHandle]:
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
return handle
@staticmethod
def list() -> List[str]:
ret = PandaDFU.usb_list()
ret += PandaDFU.spi_list()
return list(set(ret))
@staticmethod
def usb_list() -> List[str]:
context = usb1.USBContext()
dfu_serials = []
try:
@@ -46,80 +78,41 @@ class PandaDFU(object):
return dfu_serials
@staticmethod
def st_serial_to_dfu_serial(st, mcu_type=MCU_TYPE_F4):
def spi_list() -> List[str]:
try:
h = PandaDFU.spi_connect(None)
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
return []
@staticmethod
def st_serial_to_dfu_serial(st: str, mcu_type: McuType = 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) -> McuType:
return self._mcu_type
def status(self):
while 1:
dat = self._handle.controlRead(0x21, DFU_GETSTATUS, 0, 0, 6)
if dat[1] == 0:
break
def clear_status(self):
# Clear status
stat = self._handle.controlRead(0x21, DFU_GETSTATUS, 0, 0, 6)
if stat[4] == 0xa:
self._handle.controlRead(0x21, DFU_CLRSTATUS, 0, 0, 0)
elif stat[4] == 0x9:
self._handle.controlWrite(0x21, DFU_ABORT, 0, 0, b"")
self.status()
stat = str(self._handle.controlRead(0x21, DFU_GETSTATUS, 0, 0, 6))
def erase(self, address):
self._handle.controlWrite(0x21, DFU_DNLOAD, 0, 0, b"\x41" + struct.pack("I", address))
self.status()
def program(self, address, dat, block_size=None):
if block_size is None:
block_size = len(dat)
# Set Address Pointer
self._handle.controlWrite(0x21, DFU_DNLOAD, 0, 0, b"\x21" + struct.pack("I", address))
self.status()
# Program
dat += b"\xFF" * ((block_size - len(dat)) % block_size)
for i in range(0, len(dat) // block_size):
ldat = dat[i * block_size:(i + 1) * block_size]
print("programming %d with length %d" % (i, len(ldat)))
self._handle.controlWrite(0x21, DFU_DNLOAD, 2 + i, 0, ldat)
self.status()
def reset(self):
self._handle.jump(self._mcu_type.config.bootstub_address)
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._handle.clear_status()
self._handle.erase_bootstub()
self._handle.erase_app()
self._handle.program(self._mcu_type.config.bootstub_address, code_bootstub)
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.status()
try:
self._handle.controlWrite(0x21, DFU_DNLOAD, 2, 0, b"")
_ = str(self._handle.controlRead(0x21, DFU_GETSTATUS, 0, 0, 6))
except Exception:
pass