team-3/src/c3nav/mesh/dataformats.py

243 lines
7.6 KiB
Python

import re
from dataclasses import dataclass, field
from enum import IntEnum, unique
from c3nav.api.utils import EnumSchemaByNameMixin
from c3nav.mesh.baseformats import (BoolFormat, EnumFormat, FixedHexFormat, FixedStrFormat, SimpleFormat, StructType,
VarArrayFormat, TwoNibblesEnumFormat, ChipRevFormat, SimpleConstFormat)
class MacAddressFormat(FixedHexFormat):
def __init__(self):
super().__init__(num=6, sep=':')
class MacAddressesListFormat(VarArrayFormat):
def __init__(self):
super().__init__(child_type=MacAddressFormat())
@unique
class LedType(IntEnum):
NONE = 0
SERIAL = 1
MULTIPIN = 2
@property
def pretty_name(self):
return self.name.lower()
@unique
class SerialLedType(IntEnum):
WS2812 = 1
SK6812 = 2
@dataclass
class LedConfig(StructType, union_type_field="led_type"):
"""
configuration for an optional connected status LED
"""
led_type: LedType = field(metadata={"format": EnumFormat(), "c_name": "type"})
@dataclass
class NoLedConfig(LedConfig, led_type=LedType.NONE):
pass
@dataclass
class SerialLedConfig(LedConfig, led_type=LedType.SERIAL):
serial_led_type: SerialLedType = field(metadata={"format": EnumFormat(), "c_name": "type"})
gpio: int = field(metadata={"format": SimpleFormat('B')})
@dataclass
class MultipinLedConfig(LedConfig, led_type=LedType.MULTIPIN):
gpio_red: int = field(metadata={"format": SimpleFormat('B')})
gpio_green: int = field(metadata={"format": SimpleFormat('B')})
gpio_blue: int = field(metadata={"format": SimpleFormat('B')})
@dataclass
class UWBConfig(StructType):
"""
configuration for the connection to the UWB module
"""
enable: bool = field(metadata={"format": BoolFormat()})
gpio_miso: int = field(metadata={"format": SimpleFormat('B')})
gpio_mosi: int = field(metadata={"format": SimpleFormat('B')})
gpio_clk: int = field(metadata={"format": SimpleFormat('B')})
gpio_cs: int = field(metadata={"format": SimpleFormat('B')})
gpio_irq: int = field(metadata={"format": SimpleFormat('B')})
gpio_rst: int = field(metadata={"format": SimpleFormat('B')})
gpio_wakeup: int = field(metadata={"format": SimpleFormat('B')})
gpio_exton: int = field(metadata={"format": SimpleFormat('B')})
@unique
class BoardType(EnumSchemaByNameMixin, IntEnum):
CUSTOM = 0x00
# devboards
ESP32_C3_DEVKIT_M_1 = 0x01
ESP32_C3_32S = 2
# custom boards
C3NAV_UWB_BOARD = 0x10
C3NAV_LOCATION_PCB_REV_0_1 = 0x11
C3NAV_LOCATION_PCB_REV_0_2 = 0x12
@property
def pretty_name(self):
if self.name.startswith('ESP32'):
return self.name.replace('_', '-').replace('DEVKIT-', 'DevKit')
if self.name.startswith('C3NAV'):
name = self.name.replace('_', ' ').lower()
name = name.replace('uwb', 'UWB').replace('pcb', 'PCB')
name = re.sub(r'[0-9]+( [0-9+])+', lambda s: s[0].replace(' ', '.'), name)
name = re.sub(r'rev.*', lambda s: s[0].replace(' ', ''), name)
return name
return self.name
@dataclass
class BoardConfig(StructType, union_type_field="board"):
board: BoardType = field(metadata={"format": EnumFormat(as_hex=True)})
@dataclass
class CustomBoardConfig(BoardConfig, board=BoardType.CUSTOM):
uwb: UWBConfig = field(metadata={"as_definition": True})
led: LedConfig = field(metadata={"as_definition": True})
@dataclass
class DevkitMBoardConfig(BoardConfig, board=BoardType.ESP32_C3_DEVKIT_M_1):
uwb: UWBConfig = field(metadata={"as_definition": True})
@dataclass
class Esp32SBoardConfig(BoardConfig, board=BoardType.ESP32_C3_32S):
uwb: UWBConfig = field(metadata={"as_definition": True})
@dataclass
class UwbBoardConfig(BoardConfig, board=BoardType.C3NAV_UWB_BOARD):
pass
@dataclass
class LocationPCBRev0Dot1BoardConfig(BoardConfig, board=BoardType.C3NAV_LOCATION_PCB_REV_0_1):
pass
@dataclass
class LocationPCBRev0Dot2BoardConfig(BoardConfig, board=BoardType.C3NAV_LOCATION_PCB_REV_0_2):
pass
@dataclass
class RangeResultItem(StructType):
peer: str = field(metadata={"format": MacAddressFormat()})
rssi: int = field(metadata={"format": SimpleFormat('b')})
distance: int = field(metadata={"format": SimpleFormat('H')})
@dataclass
class RawFTMEntry(StructType):
dlog_token: int = field(metadata={"format": SimpleFormat('B')})
rssi: int = field(metadata={"format": SimpleFormat('b')})
rtt: int = field(metadata={"format": SimpleFormat('I')})
t1: int = field(metadata={"format": SimpleFormat('Q')})
t2: int = field(metadata={"format": SimpleFormat('Q')})
t3: int = field(metadata={"format": SimpleFormat('Q')})
t4: int = field(metadata={"format": SimpleFormat('Q')})
@dataclass
class FirmwareAppDescription(StructType, existing_c_struct="esp_app_desc_t"):
magic_word: int = field(metadata={"format": SimpleConstFormat('I', 0xAB_CD_54_32)}, repr=False)
secure_version: int = field(metadata={"format": SimpleFormat('I')})
reserv1: list[int] = field(metadata={"format": SimpleFormat('2I')}, repr=False)
version: str = field(metadata={"format": FixedStrFormat(32)})
project_name: str = field(metadata={"format": FixedStrFormat(32)})
compile_time: str = field(metadata={"format": FixedStrFormat(16)})
compile_date: str = field(metadata={"format": FixedStrFormat(16)})
idf_version: str = field(metadata={"format": FixedStrFormat(32)})
app_elf_sha256: str = field(metadata={"format": FixedHexFormat(32)})
reserv2: list[int] = field(metadata={"format": SimpleFormat('20I')}, repr=False)
@unique
class SPIFlashMode(EnumSchemaByNameMixin, IntEnum):
QIO = 0
QOUT = 1
DIO = 2
DOUT = 3
@unique
class FlashSize(EnumSchemaByNameMixin, IntEnum):
SIZE_1MB = 0
SIZE_2MB = 1
SIZE_4MB = 2
SIZE_8MB = 3
SIZE_16MB = 4
SIZE_32MB = 5
SIZE_64MB = 6
SIZE_128MB = 7
@unique
class FlashFrequency(EnumSchemaByNameMixin, IntEnum):
FREQ_40MHZ = 0
FREQ_26MHZ = 1
FREQ_20MHZ = 2
FREQ_80MHZ = 0xf
@dataclass
class FlashSettings:
size: FlashSize
frequency: FlashFrequency
@unique
class ChipType(EnumSchemaByNameMixin, IntEnum):
ESP32_S2 = 2
ESP32_C3 = 5
@property
def pretty_name(self):
return self.name.replace('_', '-')
@dataclass
class FirmwareImageFileHeader(StructType):
magic_word: int = field(metadata={"format": SimpleConstFormat('B', 0xE9)}, repr=False)
num_segments: int = field(metadata={"format": SimpleFormat('B')})
spi_flash_mode: SPIFlashMode = field(metadata={"format": EnumFormat()})
flash_stuff: FlashSettings = field(metadata={"format": TwoNibblesEnumFormat()})
entry_point: int = field(metadata={"format": SimpleFormat('I')})
@dataclass
class FirmwareImageExtendedFileHeader(StructType):
wp_pin: int = field(metadata={"format": SimpleFormat('B')})
drive_settings: int = field(metadata={"format": SimpleFormat('3B')})
chip_id: ChipType = field(metadata={"format": EnumFormat('H')})
min_chip_rev_old: int = field(metadata={"format": SimpleFormat('B')})
min_chip_rev: tuple[int, int] = field(metadata={"format": ChipRevFormat()})
max_chip_rev: tuple[int, int] = field(metadata={"format": ChipRevFormat()})
reserv: int = field(metadata={"format": SimpleFormat('I')}, repr=False)
hash_appended: bool = field(metadata={"format": BoolFormat()})
@dataclass
class FirmwareImage(StructType):
header: FirmwareImageFileHeader
ext_header: FirmwareImageExtendedFileHeader
first_segment_headers: tuple[int, int] = field(metadata={"format": SimpleFormat('2I')}, repr=False)
app_desc: FirmwareAppDescription