mirror of
https://github.com/dragonpilot/dragonpilot.git
synced 2026-10-13 17:53:43 +08:00
dragonpilot beta3
date: 2023-10-09T10:55:55 commit: 91b6e3aecd7170f24bccacb10c515ec281c30295
This commit is contained in:
+2
-2
@@ -1,9 +1,9 @@
|
||||
from .python.constants import McuType, BASEDIR, FW_PATH, USBPACKET_MAX_SIZE # noqa: F401
|
||||
from .python.spi import PandaSpiException, PandaProtocolMismatch # noqa: F401
|
||||
from .python.spi import PandaSpiException, PandaProtocolMismatch, STBootloaderSPIHandle # noqa: F401
|
||||
from .python.serial import PandaSerial # noqa: F401
|
||||
from .python.canhandle import CanHandle # noqa: F401
|
||||
from .python import (Panda, PandaDFU, # noqa: F401
|
||||
pack_can_buffer, unpack_can_buffer, calculate_checksum, unpack_log,
|
||||
pack_can_buffer, unpack_can_buffer, calculate_checksum,
|
||||
DLC_TO_LEN, LEN_TO_DLC, ALTERNATIVE_EXPERIENCE, CANPACKET_HEAD_SIZE)
|
||||
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ class PandaJungle(Panda):
|
||||
|
||||
@classmethod
|
||||
def spi_connect(cls, serial, ignore_version=False):
|
||||
return None, None, None, None
|
||||
return None, None, None, None, None
|
||||
|
||||
def flash(self, fn=None, code=None, reconnect=True):
|
||||
if not fn:
|
||||
@@ -132,6 +132,9 @@ class PandaJungle(Panda):
|
||||
def set_panda_power(self, enabled):
|
||||
self._handle.controlWrite(PandaJungle.REQUEST_OUT, 0xa0, int(enabled), 0, b'')
|
||||
|
||||
def set_panda_individual_power(self, port, enabled):
|
||||
self._handle.controlWrite(PandaJungle.REQUEST_OUT, 0xa3, int(port), int(enabled), b'')
|
||||
|
||||
def set_harness_orientation(self, mode):
|
||||
self._handle.controlWrite(PandaJungle.REQUEST_OUT, 0xa1, int(mode), 0, b'')
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ typedef void (*board_set_led)(uint8_t color, bool enabled);
|
||||
typedef void (*board_board_tick)(void);
|
||||
typedef bool (*board_get_button)(void);
|
||||
typedef void (*board_set_panda_power)(bool enabled);
|
||||
typedef void (*board_set_panda_individual_power)(uint8_t port_num, bool enabled);
|
||||
typedef void (*board_set_ignition)(bool enabled);
|
||||
typedef void (*board_set_individual_ignition)(uint8_t bitmask);
|
||||
typedef void (*board_set_harness_orientation)(uint8_t orientation);
|
||||
@@ -23,6 +24,7 @@ struct board {
|
||||
board_board_tick board_tick;
|
||||
board_get_button get_button;
|
||||
board_set_panda_power set_panda_power;
|
||||
board_set_panda_individual_power set_panda_individual_power;
|
||||
board_set_ignition set_ignition;
|
||||
board_set_individual_ignition set_individual_ignition;
|
||||
board_set_harness_orientation set_harness_orientation;
|
||||
@@ -75,3 +77,8 @@ void unused_board_enable_header_pin(uint8_t pin_num, bool enabled) {
|
||||
UNUSED(pin_num);
|
||||
UNUSED(enabled);
|
||||
}
|
||||
|
||||
void unused_set_panda_individual_power(uint8_t port_num, bool enabled) {
|
||||
UNUSED(port_num);
|
||||
UNUSED(enabled);
|
||||
}
|
||||
|
||||
@@ -164,6 +164,7 @@ const board board_v1 = {
|
||||
.board_tick = &board_v1_tick,
|
||||
.get_button = &board_v1_get_button,
|
||||
.set_panda_power = &board_v1_set_panda_power,
|
||||
.set_panda_individual_power = &unused_set_panda_individual_power,
|
||||
.set_ignition = &board_v1_set_ignition,
|
||||
.set_individual_ignition = &unused_set_individual_ignition,
|
||||
.set_harness_orientation = &board_v1_set_harness_orientation,
|
||||
|
||||
@@ -178,9 +178,26 @@ void board_v2_set_can_mode(uint8_t mode) {
|
||||
}
|
||||
|
||||
bool panda_power = false;
|
||||
uint8_t panda_power_bitmask = 0U;
|
||||
void board_v2_set_panda_power(bool enable) {
|
||||
panda_power = enable;
|
||||
gpio_set_all_output(power_pins, sizeof(power_pins) / sizeof(gpio_t), enable);
|
||||
if (enable) {
|
||||
panda_power_bitmask = 0xFFU;
|
||||
} else {
|
||||
panda_power_bitmask = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
void board_v2_set_panda_individual_power(uint8_t port_num, bool enable) {
|
||||
port_num -= 1U;
|
||||
if (port_num < 6U) {
|
||||
panda_power_bitmask &= ~(1U << port_num);
|
||||
panda_power_bitmask |= (enable ? 1U : 0U) << port_num;
|
||||
} else {
|
||||
print("Invalid port number ("); puth(port_num); print("): enabling failed\n");
|
||||
}
|
||||
gpio_set_bitmask(power_pins, sizeof(power_pins) / sizeof(gpio_t), (uint32_t)panda_power_bitmask);
|
||||
}
|
||||
|
||||
bool board_v2_get_button(void) {
|
||||
@@ -297,6 +314,7 @@ const board board_v2 = {
|
||||
.board_tick = &board_v2_tick,
|
||||
.get_button = &board_v2_get_button,
|
||||
.set_panda_power = &board_v2_set_panda_power,
|
||||
.set_panda_individual_power = &board_v2_set_panda_individual_power,
|
||||
.set_ignition = &board_v2_set_ignition,
|
||||
.set_individual_ignition = &board_v2_set_individual_ignition,
|
||||
.set_harness_orientation = &board_v2_set_harness_orientation,
|
||||
|
||||
@@ -141,6 +141,9 @@ int main(void) {
|
||||
clock_init();
|
||||
peripherals_init();
|
||||
detect_board_type();
|
||||
// red+green leds enabled until succesful USB init, as a debug indicator
|
||||
current_board->set_led(LED_RED, true);
|
||||
current_board->set_led(LED_GREEN, true);
|
||||
|
||||
// print hello
|
||||
print("\n\n\n************************ MAIN START ************************\n");
|
||||
@@ -172,6 +175,9 @@ int main(void) {
|
||||
// enable USB (right before interrupts or enum can fail!)
|
||||
usb_init();
|
||||
|
||||
current_board->set_led(LED_RED, false);
|
||||
current_board->set_led(LED_GREEN, false);
|
||||
|
||||
print("**** INTERRUPTS ON ****\n");
|
||||
enable_interrupts();
|
||||
|
||||
|
||||
@@ -58,6 +58,10 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
|
||||
case 0xa2:
|
||||
current_board->set_ignition((req->param1 == 1U));
|
||||
break;
|
||||
// **** 0xa0: Set panda power per channel by bitmask.
|
||||
case 0xa3:
|
||||
current_board->set_panda_individual_power(req->param1, (req->param2 > 0U));
|
||||
break;
|
||||
// **** 0xa8: get microsecond timer
|
||||
case 0xa8:
|
||||
time = microsecond_timer_get();
|
||||
@@ -80,6 +84,7 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
|
||||
case 0xc2:
|
||||
COMPILE_TIME_ASSERT(sizeof(can_health_t) <= USBPACKET_MAX_SIZE);
|
||||
if (req->param1 < 3U) {
|
||||
update_can_health_pkt(req->param1, 0U);
|
||||
can_health[req->param1].can_speed = (bus_config[req->param1].can_speed / 10U);
|
||||
can_health[req->param1].can_data_speed = (bus_config[req->param1].can_data_speed / 10U);
|
||||
can_health[req->param1].canfd_enabled = bus_config[req->param1].canfd_enabled;
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
const uint8_t gitversion[] = "DEV-bbab69eb-DEBUG";
|
||||
const uint8_t gitversion[] = "DEV-b6dc9e48-DEBUG";
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
DEV-bbab69eb-DEBUG
|
||||
DEV-b6dc9e48-DEBUG
|
||||
@@ -266,7 +266,7 @@ int main(void) {
|
||||
REGISTER_INTERRUPT(CAN1_TX_IRQn, CAN1_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
|
||||
REGISTER_INTERRUPT(CAN1_RX0_IRQn, CAN1_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
|
||||
REGISTER_INTERRUPT(CAN1_SCE_IRQn, CAN1_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
|
||||
|
||||
|
||||
// Should run at around 732Hz (see init below)
|
||||
REGISTER_INTERRUPT(TIM3_IRQn, TIM3_IRQ_Handler, 1000U, FAULT_INTERRUPT_RATE_TIM3)
|
||||
|
||||
@@ -290,12 +290,12 @@ int main(void) {
|
||||
adc_init();
|
||||
|
||||
// init can
|
||||
bool llcan_speed_set = llcan_set_speed(CAN1, 5000, false, false);
|
||||
bool llcan_speed_set = llcan_set_speed(CAN, 5000, false, false);
|
||||
if (!llcan_speed_set) {
|
||||
print("Failed to set llcan speed");
|
||||
}
|
||||
|
||||
bool ret = llcan_init(CAN1);
|
||||
bool ret = llcan_init(CAN);
|
||||
UNUSED(ret);
|
||||
|
||||
// 48mhz / 65536 ~= 732
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+23
-61
@@ -8,7 +8,7 @@ import hashlib
|
||||
import binascii
|
||||
import datetime
|
||||
import logging
|
||||
from functools import wraps
|
||||
from functools import wraps, partial
|
||||
from typing import Optional
|
||||
from itertools import accumulate
|
||||
|
||||
@@ -90,53 +90,21 @@ def unpack_can_buffer(dat):
|
||||
|
||||
return (ret, dat)
|
||||
|
||||
def ensure_health_packet_version(fn):
|
||||
|
||||
def ensure_version(desc, lib_field, panda_field, fn):
|
||||
@wraps(fn)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
if self.health_version < self.HEALTH_PACKET_VERSION:
|
||||
raise RuntimeError("Panda firmware has outdated health packet definition. Reflash panda firmware.")
|
||||
elif self.health_version > self.HEALTH_PACKET_VERSION:
|
||||
raise RuntimeError("Panda python library has outdated health packet definition. Update panda python library.")
|
||||
lib_version = getattr(self, lib_field)
|
||||
panda_version = getattr(self, panda_field)
|
||||
if lib_version != panda_version:
|
||||
raise RuntimeError(f"{desc} packet version mismatch: panda's firmware v{panda_version}, library v{lib_version}. Reflash panda.")
|
||||
return fn(self, *args, **kwargs)
|
||||
return wrapper
|
||||
ensure_can_packet_version = partial(ensure_version, "CAN", "CAN_PACKET_VERSION", "can_version")
|
||||
ensure_can_health_packet_version = partial(ensure_version, "CAN health", "CAN_HEALTH_PACKET_VERSION", "can_health_version")
|
||||
ensure_health_packet_version = partial(ensure_version, "health", "HEALTH_PACKET_VERSION", "health_version")
|
||||
|
||||
def ensure_can_packet_version(fn):
|
||||
@wraps(fn)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
if self.can_version < self.CAN_PACKET_VERSION:
|
||||
raise RuntimeError("Panda firmware has outdated CAN packet definition. Reflash panda firmware.")
|
||||
elif self.can_version > self.CAN_PACKET_VERSION:
|
||||
raise RuntimeError("Panda python library has outdated CAN packet definition. Update panda python library.")
|
||||
return fn(self, *args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
def ensure_can_health_packet_version(fn):
|
||||
@wraps(fn)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
if self.can_health_version < self.CAN_HEALTH_PACKET_VERSION:
|
||||
raise RuntimeError("Panda firmware has outdated CAN health packet definition. Reflash panda firmware.")
|
||||
elif self.can_health_version > self.CAN_HEALTH_PACKET_VERSION:
|
||||
raise RuntimeError("Panda python library has outdated CAN health packet definition. Update panda python library.")
|
||||
return fn(self, *args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
def parse_timestamp(dat):
|
||||
a = struct.unpack("HBBBBBB", dat)
|
||||
if a[0] == 0:
|
||||
return None
|
||||
|
||||
try:
|
||||
return datetime.datetime(a[0], a[1], a[2], a[4], a[5], a[6])
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
def unpack_log(dat):
|
||||
return {
|
||||
'id': struct.unpack("H", dat[:2])[0],
|
||||
'timestamp': parse_timestamp(dat[2:10]),
|
||||
'uptime': struct.unpack("I", dat[10:14])[0],
|
||||
'msg': bytes(dat[14:]).decode('utf-8', 'ignore').strip('\x00'),
|
||||
}
|
||||
|
||||
class ALTERNATIVE_EXPERIENCE:
|
||||
DEFAULT = 0
|
||||
@@ -239,6 +207,7 @@ class Panda:
|
||||
FLAG_HYUNDAI_CANFD_HDA2 = 16
|
||||
FLAG_HYUNDAI_CANFD_ALT_BUTTONS = 32
|
||||
FLAG_HYUNDAI_ALT_LIMITS = 64
|
||||
FLAG_HYUNDAI_CANFD_HDA2_ALT_STEERING = 128
|
||||
|
||||
FLAG_TESLA_POWERTRAIN = 1
|
||||
FLAG_TESLA_LONG_CONTROL = 2
|
||||
@@ -251,6 +220,8 @@ class Panda:
|
||||
FLAG_SUBARU_GEN2 = 1
|
||||
FLAG_SUBARU_LONG = 2
|
||||
|
||||
FLAG_NISSAN_ALT_EPS_BUS = 1
|
||||
|
||||
FLAG_GM_HW_CAM = 1
|
||||
FLAG_GM_HW_CAM_LONG = 2
|
||||
|
||||
@@ -281,6 +252,8 @@ class Panda:
|
||||
if self._handle_open:
|
||||
self._handle.close()
|
||||
self._handle_open = False
|
||||
if self._context is not None:
|
||||
self._context.close()
|
||||
|
||||
def connect(self, claim=True, wait=False):
|
||||
self.close()
|
||||
@@ -288,9 +261,9 @@ class Panda:
|
||||
self._handle = None
|
||||
while self._handle is None:
|
||||
# try USB first, then SPI
|
||||
self._handle, serial, self.bootstub, bcd = self.usb_connect(self._connect_serial, claim=claim)
|
||||
self._context, self._handle, serial, self.bootstub, bcd = self.usb_connect(self._connect_serial, claim=claim)
|
||||
if self._handle is None:
|
||||
self._handle, serial, self.bootstub, bcd = self.spi_connect(self._connect_serial)
|
||||
self._context, self._handle, serial, self.bootstub, bcd = self.spi_connect(self._connect_serial)
|
||||
if not wait:
|
||||
break
|
||||
|
||||
@@ -366,7 +339,7 @@ class Panda:
|
||||
err = f"panda protocol mismatch: expected {handle.PROTOCOL_VERSION}, got {spi_version}. reflash panda"
|
||||
raise PandaProtocolMismatch(err)
|
||||
|
||||
return handle, spi_serial, bootstub, None
|
||||
return None, handle, spi_serial, bootstub, None
|
||||
|
||||
@classmethod
|
||||
def usb_connect(cls, serial, claim=True):
|
||||
@@ -408,7 +381,7 @@ class Panda:
|
||||
else:
|
||||
context.close()
|
||||
|
||||
return usb_handle, usb_serial, bootstub, bcd
|
||||
return context, usb_handle, usb_serial, bootstub, bcd
|
||||
|
||||
@classmethod
|
||||
def list(cls): # noqa: A003
|
||||
@@ -437,7 +410,7 @@ class Panda:
|
||||
|
||||
@classmethod
|
||||
def spi_list(cls):
|
||||
_, serial, _, _ = cls.spi_connect(None, ignore_version=True)
|
||||
_, _, serial, _, _ = cls.spi_connect(None, ignore_version=True)
|
||||
if serial is not None:
|
||||
return [serial, ]
|
||||
return []
|
||||
@@ -468,7 +441,7 @@ class Panda:
|
||||
|
||||
success = False
|
||||
# wait up to 15 seconds
|
||||
for _ in range(0, 15*10):
|
||||
for _ in range(15*10):
|
||||
try:
|
||||
self.connect()
|
||||
success = True
|
||||
@@ -976,7 +949,8 @@ class Panda:
|
||||
|
||||
def get_datetime(self):
|
||||
dat = self._handle.controlRead(Panda.REQUEST_IN, 0xa0, 0, 0, 8)
|
||||
return parse_timestamp(dat)
|
||||
a = struct.unpack("HBBBBBB", dat)
|
||||
return datetime.datetime(a[0], a[1], a[2], a[4], a[5], a[6])
|
||||
|
||||
# ****************** Timer *****************
|
||||
def get_microsecond_timer(self):
|
||||
@@ -1013,15 +987,3 @@ class Panda:
|
||||
|
||||
def force_relay_drive(self, intercept_relay_drive, ignition_relay_drive):
|
||||
self._handle.controlWrite(Panda.REQUEST_OUT, 0xc5, (int(intercept_relay_drive) | int(ignition_relay_drive) << 1), 0, b'')
|
||||
|
||||
# ****************** Logging *****************
|
||||
def get_logs(self, last_id=None, get_all=False):
|
||||
assert (last_id is None) or (0 <= last_id < 0xFFFF)
|
||||
|
||||
logs = []
|
||||
dat = self._handle.controlRead(Panda.REQUEST_IN, 0xfd, 1 if get_all else 0, last_id if last_id is not None else 0xFFFF, 0x40)
|
||||
while len(dat) > 0:
|
||||
if len(dat) == 0x40:
|
||||
logs.append(unpack_log(dat))
|
||||
dat = self._handle.controlRead(Panda.REQUEST_IN, 0xfd, 0, 0xFFFF, 0x40)
|
||||
return logs
|
||||
|
||||
@@ -53,14 +53,9 @@ class BaseSTBootloaderHandle(ABC):
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def erase_app(self) -> None:
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def erase_bootstub(self) -> None:
|
||||
def erase_sector(self, sector: int) -> None:
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def jump(self, address: int) -> None:
|
||||
...
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import time
|
||||
import struct
|
||||
|
||||
@@ -10,35 +10,40 @@ USBPACKET_MAX_SIZE = 0x40
|
||||
class McuConfig(NamedTuple):
|
||||
mcu: str
|
||||
mcu_idcode: int
|
||||
sector_sizes: List[int]
|
||||
sector_count: int # total sector count, used for MCU identification in DFU mode
|
||||
uid_address: int
|
||||
block_size: int
|
||||
sector_sizes: List[int]
|
||||
serial_number_address: int
|
||||
app_address: int
|
||||
app_fn: str
|
||||
bootstub_address: int
|
||||
bootstub_fn: str
|
||||
|
||||
def sector_address(self, i):
|
||||
# assume bootstub is in sector 0
|
||||
return self.bootstub_address + sum(self.sector_sizes[:i])
|
||||
|
||||
Fx = (
|
||||
0x1FFF7A10,
|
||||
0x800,
|
||||
[0x4000 for _ in range(4)] + [0x10000] + [0x20000 for _ in range(11)],
|
||||
0x1FFF79C0,
|
||||
0x8004000,
|
||||
"panda.bin.signed",
|
||||
0x8000000,
|
||||
"bootstub.panda.bin",
|
||||
)
|
||||
F2Config = McuConfig("STM32F2", 0x411, *Fx)
|
||||
F4Config = McuConfig("STM32F4", 0x463, *Fx)
|
||||
F2Config = McuConfig("STM32F2", 0x411, [0x4000 for _ in range(4)] + [0x10000] + [0x20000 for _ in range(7)], 12, *Fx)
|
||||
F4Config = McuConfig("STM32F4", 0x463, [0x4000 for _ in range(4)] + [0x10000] + [0x20000 for _ in range(11)], 16, *Fx)
|
||||
|
||||
H7Config = McuConfig(
|
||||
"STM32H7",
|
||||
0x483,
|
||||
[0x20000 for _ in range(7)],
|
||||
8,
|
||||
0x1FF1E800,
|
||||
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,
|
||||
"panda_h7.bin.signed",
|
||||
|
||||
+25
-9
@@ -14,9 +14,9 @@ class PandaDFU:
|
||||
def __init__(self, dfu_serial: Optional[str]):
|
||||
# try USB, then SPI
|
||||
handle: Optional[BaseSTBootloaderHandle]
|
||||
handle = PandaDFU.usb_connect(dfu_serial)
|
||||
self._context, handle = PandaDFU.usb_connect(dfu_serial)
|
||||
if handle is None:
|
||||
handle = PandaDFU.spi_connect(dfu_serial)
|
||||
self._context, handle = PandaDFU.spi_connect(dfu_serial)
|
||||
|
||||
if handle is None:
|
||||
raise Exception(f"failed to open DFU device {dfu_serial}")
|
||||
@@ -24,8 +24,21 @@ class PandaDFU:
|
||||
self._handle: BaseSTBootloaderHandle = handle
|
||||
self._mcu_type: McuType = self._handle.get_mcu_type()
|
||||
|
||||
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()
|
||||
|
||||
@staticmethod
|
||||
def usb_connect(dfu_serial: Optional[str]) -> Optional[STBootloaderUSBHandle]:
|
||||
def usb_connect(dfu_serial: Optional[str]):
|
||||
handle = None
|
||||
context = usb1.USBContext()
|
||||
context.open()
|
||||
@@ -40,10 +53,10 @@ class PandaDFU:
|
||||
handle = STBootloaderUSBHandle(device, device.open())
|
||||
break
|
||||
|
||||
return handle
|
||||
return context, handle
|
||||
|
||||
@staticmethod
|
||||
def spi_connect(dfu_serial: Optional[str]) -> Optional[STBootloaderSPIHandle]:
|
||||
def spi_connect(dfu_serial: Optional[str]):
|
||||
handle = None
|
||||
this_dfu_serial = None
|
||||
|
||||
@@ -56,7 +69,7 @@ class PandaDFU:
|
||||
if dfu_serial is not None and dfu_serial != this_dfu_serial:
|
||||
handle = None
|
||||
|
||||
return handle
|
||||
return None, handle
|
||||
|
||||
@staticmethod
|
||||
def list() -> List[str]: # noqa: A003
|
||||
@@ -82,7 +95,7 @@ class PandaDFU:
|
||||
@staticmethod
|
||||
def spi_list() -> List[str]:
|
||||
try:
|
||||
h = PandaDFU.spi_connect(None)
|
||||
_, 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, ]
|
||||
@@ -108,8 +121,11 @@ class PandaDFU:
|
||||
|
||||
def program_bootstub(self, code_bootstub):
|
||||
self._handle.clear_status()
|
||||
self._handle.erase_bootstub()
|
||||
self._handle.erase_app()
|
||||
|
||||
# erase all sectors
|
||||
for i in range(len(self._mcu_type.config.sector_sizes)):
|
||||
self._handle.erase_sector(i)
|
||||
|
||||
self._handle.program(self._mcu_type.config.bootstub_address, code_bootstub)
|
||||
|
||||
def recover(self):
|
||||
|
||||
+2
-9
@@ -17,10 +17,8 @@ from .utils import crc8_pedal
|
||||
|
||||
try:
|
||||
import spidev
|
||||
import spidev2
|
||||
except ImportError:
|
||||
spidev = None
|
||||
spidev2 = None
|
||||
|
||||
# Constants
|
||||
SYNC = 0x5A
|
||||
@@ -194,6 +192,7 @@ class PandaSpiHandle(BaseHandle):
|
||||
return dat[3:-1]
|
||||
|
||||
def _transfer_kernel_driver(self, spi, endpoint: int, data, timeout: int, max_rx_len: int = 1000, expect_disconnect: bool = False) -> bytes:
|
||||
import spidev2
|
||||
self.tx_buf[:len(data)] = data
|
||||
self.ioctl_data.endpoint = endpoint
|
||||
self.ioctl_data.tx_length = len(data)
|
||||
@@ -403,12 +402,6 @@ class STBootloaderSPIHandle(BaseSTBootloaderHandle):
|
||||
|
||||
# *** PandaDFU API ***
|
||||
|
||||
def erase_app(self):
|
||||
self.erase_sector(1)
|
||||
|
||||
def erase_bootstub(self):
|
||||
self.erase_sector(0)
|
||||
|
||||
def get_mcu_type(self):
|
||||
return self._mcu_type
|
||||
|
||||
@@ -421,7 +414,7 @@ class STBootloaderSPIHandle(BaseSTBootloaderHandle):
|
||||
def program(self, address, dat):
|
||||
bs = 256 # max block size for writing to flash over SPI
|
||||
dat += b"\xFF" * ((bs - len(dat)) % bs)
|
||||
for i in range(0, len(dat) // bs):
|
||||
for i in range(len(dat) // bs):
|
||||
block = dat[i * bs:(i + 1) * bs]
|
||||
self._cmd(0x31, data=[
|
||||
struct.pack('>I', address + i*bs),
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python3
|
||||
import time
|
||||
import struct
|
||||
from collections import deque
|
||||
|
||||
+13
-9
@@ -34,9 +34,16 @@ class STBootloaderUSBHandle(BaseSTBootloaderHandle):
|
||||
def __init__(self, libusb_device, libusb_handle):
|
||||
self._libusb_handle = libusb_handle
|
||||
|
||||
# TODO: Find a way to detect F4 vs F2
|
||||
# TODO: also check F4 BCD, don't assume in else
|
||||
self._mcu_type = McuType.H7 if libusb_device.getbcdDevice() == 512 else McuType.F4
|
||||
# example from F4: lsusb -v | grep Flash
|
||||
# iInterface 4 @Internal Flash /0x08000000/04*016Kg,01*064Kg,011*128Kg
|
||||
for i in range(20):
|
||||
desc = libusb_handle.getStringDescriptor(i, 0)
|
||||
if desc is not None and desc.startswith("@Internal Flash"):
|
||||
sector_count = sum([int(s.split('*')[0]) for s in desc.split('/')[-1].split(',')])
|
||||
break
|
||||
mcu_by_sector_count = {m.config.sector_count: m for m in McuType}
|
||||
assert sector_count in mcu_by_sector_count, f"Unkown MCU: {sector_count=}"
|
||||
self._mcu_type = mcu_by_sector_count[sector_count]
|
||||
|
||||
def _status(self) -> None:
|
||||
while 1:
|
||||
@@ -51,11 +58,8 @@ class STBootloaderUSBHandle(BaseSTBootloaderHandle):
|
||||
def get_mcu_type(self):
|
||||
return self._mcu_type
|
||||
|
||||
def erase_app(self):
|
||||
self._erase_page_address(self._mcu_type.config.app_address)
|
||||
|
||||
def erase_bootstub(self):
|
||||
self._erase_page_address(self._mcu_type.config.bootstub_address)
|
||||
def erase_sector(self, sector: int):
|
||||
self._erase_page_address(self._mcu_type.config.sector_address(sector))
|
||||
|
||||
def clear_status(self):
|
||||
# Clear status
|
||||
@@ -78,7 +82,7 @@ class STBootloaderUSBHandle(BaseSTBootloaderHandle):
|
||||
# Program
|
||||
bs = min(len(dat), self._mcu_type.config.block_size)
|
||||
dat += b"\xFF" * ((bs - len(dat)) % bs)
|
||||
for i in range(0, len(dat) // bs):
|
||||
for i in range(len(dat) // bs):
|
||||
ldat = dat[i * bs:(i + 1) * bs]
|
||||
print("programming %d with length %d" % (i, len(ldat)))
|
||||
self._libusb_handle.controlWrite(0x21, self.DFU_DNLOAD, 2 + i, 0, ldat)
|
||||
|
||||
Reference in New Issue
Block a user