You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
4.0 KiB
153 lines
4.0 KiB
from dataclasses import dataclass, fields, is_dataclass
|
|
from enum import Enum, StrEnum as _StrEnum, auto
|
|
# from typing import Type, TypeVar
|
|
from typing import Type, TypeVar, TYPE_CHECKING, Any, get_type_hints, get_origin
|
|
|
|
if TYPE_CHECKING:
|
|
from _typeshed import DataclassInstance
|
|
#
|
|
# DataclassT = TypeVar("DataclassT", bound="DataclassInstance")
|
|
#
|
|
# T = TypeVar('T', bound='Struct')
|
|
|
|
|
|
class StrEnum(_StrEnum):
|
|
@staticmethod
|
|
def _generate_next_value_(name, *args):
|
|
# auto() defaults to name.lower()
|
|
return name
|
|
|
|
|
|
# class Struct:
|
|
# @classmethod
|
|
# def new_message(cls, **kwargs):
|
|
# init_values = {}
|
|
# for f in fields(cls):
|
|
# init_values[f.name] = kwargs.get(f.name, f.type())
|
|
#
|
|
# return cls(**init_values)
|
|
|
|
T = TypeVar('T', bound='DataclassInstance')
|
|
|
|
|
|
class Struct:
|
|
@classmethod
|
|
def new_message(cls: Type[T], **kwargs: Any) -> T:
|
|
if not is_dataclass(cls):
|
|
raise TypeError(f"{cls.__name__} is not a dataclass")
|
|
|
|
init_values = {}
|
|
type_hints = get_type_hints(cls)
|
|
print(type_hints)
|
|
for f in fields(cls):
|
|
field_type = type_hints[f.name]
|
|
print(f.name, f.type, field_type)
|
|
print(issubclass(field_type, Enum))
|
|
if issubclass(field_type, Enum):
|
|
init_values[f.name] = kwargs.get(f.name, list(field_type)[0])
|
|
# TODO: fix this
|
|
# assert issubclass(init_values[f.name], type(field_type)), f"Expected {field_type} for {f.name}, got {type(init_values[f.name])}"
|
|
else:
|
|
# FIXME: typing check hack since mypy doesn't catch anything
|
|
init_values[f.name] = kwargs.get(f.name, field_type())
|
|
print('field_type', field_type, f.type)
|
|
# TODO: this is so bad
|
|
assert isinstance(init_values[f.name], get_origin(f.type) or f.type), f"Expected {field_type} for {f.name}, got {type(init_values[f.name])}"
|
|
|
|
return cls(**init_values)
|
|
|
|
|
|
@dataclass
|
|
class RadarData(Struct):
|
|
errors: list['Error']
|
|
points: list['RadarPoint']
|
|
|
|
class Error(StrEnum):
|
|
canError = auto()
|
|
fault = auto()
|
|
wrongConfig = auto()
|
|
|
|
@dataclass
|
|
class RadarPoint(Struct):
|
|
trackId: int # no trackId reuse
|
|
|
|
# these 3 are the minimum required
|
|
dRel: float # m from the front bumper of the car
|
|
yRel: float # m
|
|
vRel: float # m/s
|
|
|
|
# these are optional and valid if they are not NaN
|
|
aRel: float # m/s^2
|
|
yvRel: float # m/s
|
|
|
|
# some radars flag measurements VS estimates
|
|
measured: bool
|
|
|
|
|
|
@dataclass
|
|
class CarParams(Struct):
|
|
carName: str
|
|
carFingerprint: str
|
|
fuzzyFingerprint: bool
|
|
|
|
notCar: bool # flag for non-car robotics platforms
|
|
|
|
carFw: list['CarFw']
|
|
|
|
class SteerControlType(StrEnum):
|
|
torque = auto()
|
|
angle = auto()
|
|
|
|
@dataclass
|
|
class CarFw(Struct):
|
|
ecu: 'CarParams.Ecu'
|
|
fwVersion: bytes
|
|
address: int
|
|
subAddress: int
|
|
responseAddress: int
|
|
request: list[bytes]
|
|
brand: str
|
|
bus: int
|
|
logging: bool
|
|
obdMultiplexing: bool
|
|
|
|
class Ecu(StrEnum):
|
|
eps = auto()
|
|
abs = auto()
|
|
fwdRadar = auto()
|
|
fwdCamera = auto()
|
|
engine = auto()
|
|
unknown = auto()
|
|
transmission = auto() # Transmission Control Module
|
|
hybrid = auto() # hybrid control unit, e.g. Chrysler's HCP, Honda's IMA Control Unit, Toyota's hybrid control computer
|
|
srs = auto() # airbag
|
|
gateway = auto() # can gateway
|
|
hud = auto() # heads up display
|
|
combinationMeter = auto() # instrument cluster
|
|
electricBrakeBooster = auto()
|
|
shiftByWire = auto()
|
|
adas = auto()
|
|
cornerRadar = auto()
|
|
hvac = auto()
|
|
parkingAdas = auto() # parking assist system ECU, e.g. Toyota's IPAS, Hyundai's RSPA, etc.
|
|
epb = auto() # electronic parking brake
|
|
telematics = auto()
|
|
body = auto() # body control module
|
|
|
|
# Toyota only
|
|
dsu = auto()
|
|
|
|
# Honda only
|
|
vsa = auto() # Vehicle Stability Assist
|
|
programmedFuelInjection = auto()
|
|
|
|
debug = auto()
|
|
|
|
|
|
# CP: CarParams = CarParams.new_message(carName='toyota', fuzzyFingerprint=123)
|
|
# CP: CarParams = CarParams(carName='toyota', fuzzyFingerprint=123)
|
|
|
|
import ast
|
|
|
|
|
|
# test = ast.literal_eval('CarParams.CarFw')
|
|
|