diff --git a/opendbc/car/body/interface.py b/opendbc/car/body/interface.py index 24e571ee952..a27c89aa669 100644 --- a/opendbc/car/body/interface.py +++ b/opendbc/car/body/interface.py @@ -2,18 +2,23 @@ from opendbc.car import get_safety_config, structs from opendbc.car.body.carcontroller import CarController from opendbc.car.body.carstate import CarState -from opendbc.car.body.values import SPEED_FROM_RPM +from opendbc.car.body.fingerprints import FW_VERSIONS, FINGERPRINTS +from opendbc.car.body.values import FW_QUERY_CONFIG, CAR, SPEED_FROM_RPM from opendbc.car.interfaces import CarInterfaceBase -class CarInterface(CarInterfaceBase): +class BodyInterface(CarInterfaceBase): CarState = CarState CarController = CarController + CAR = CAR + BRAND = "body" + FW_QUERY_CONFIG = FW_QUERY_CONFIG + FW_VERSIONS = FW_VERSIONS + FINGERPRINTS = FINGERPRINTS @staticmethod def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: ret.notCar = True - ret.brand = "body" ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.body)] ret.minSteerSpeed = -math.inf diff --git a/opendbc/car/car_helpers.py b/opendbc/car/car_helpers.py index 319e124f1fb..7269e9b7265 100644 --- a/opendbc/car/car_helpers.py +++ b/opendbc/car/car_helpers.py @@ -7,36 +7,17 @@ from opendbc.car.structs import CarParams, CarParamsT from opendbc.car.fingerprints import eliminate_incompatible_cars, all_legacy_fingerprint_cars from opendbc.car.fw_versions import ObdCallback, get_fw_versions_ordered, get_present_ecus, match_fw_to_car -from opendbc.car.mock.values import CAR as MOCK -from opendbc.car.values import BRANDS +from opendbc.car.mock.interface import MockInterface +from opendbc.car.values import ALL_INTERFACES from opendbc.car.vin import get_vin, is_valid_vin, VIN_UNKNOWN FRAME_FINGERPRINT = 100 # 1s - -def load_interfaces(brand_names): - ret = {} - for brand_name in brand_names: - path = f'opendbc.car.{brand_name}' - CarInterface = __import__(path + '.interface', fromlist=['CarInterface']).CarInterface - for model_name in brand_names[brand_name]: - ret[model_name] = CarInterface - return ret - - -def _get_interface_names() -> dict[str, list[str]]: - # returns a dict of brand name and its respective models - brand_names = {} - for brand in BRANDS: - brand_name = brand.__module__.split('.')[-2] - brand_names[brand_name] = [model.value for model in brand] - - return brand_names - - -# imports from directory opendbc/car// -interface_names = _get_interface_names() -interfaces = load_interfaces(interface_names) +# Map every platform string to its brand's Interface. Interface carries +# its platform enum as a class attribute (CAR), so no dynamic import is needed. +interfaces: dict[str, type] = { + platform.value: ci for ci in ALL_INTERFACES for platform in ci.CAR +} def can_fingerprint(can_recv: CanRecvCallable) -> tuple[str | None, dict[int, dict]]: @@ -156,8 +137,8 @@ def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multip carlog.error({"event": "car doesn't match any fingerprints", "fingerprints": repr(fingerprints)}) candidate = "MOCK" - CarInterface = interfaces[candidate] - CP: CarParams = CarInterface.get_params(candidate, fingerprints, car_fw, alpha_long_allowed, is_release, docs=False) + Interface = interfaces[candidate] + CP: CarParams = Interface.get_params(candidate, fingerprints, car_fw, alpha_long_allowed, is_release, docs=False) CP.carVin = vin CP.carFw = car_fw CP.fingerprintSource = source @@ -167,7 +148,7 @@ def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multip def get_demo_car_params(): - platform = MOCK.MOCK - CarInterface = interfaces[platform] - CP = CarInterface.get_non_essential_params(platform) + platform = MockInterface.CAR.MOCK + Interface = interfaces[platform] + CP = Interface.get_non_essential_params(platform) return CP diff --git a/opendbc/car/chrysler/interface.py b/opendbc/car/chrysler/interface.py index 0cb2b781645..fb69b03c897 100755 --- a/opendbc/car/chrysler/interface.py +++ b/opendbc/car/chrysler/interface.py @@ -3,20 +3,24 @@ from opendbc.car.chrysler.carcontroller import CarController from opendbc.car.chrysler.carstate import CarState from opendbc.car.chrysler.radar_interface import RadarInterface -from opendbc.car.chrysler.values import CAR, CUSW_CARS, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags, ChryslerSafetyFlags +from opendbc.car.chrysler.fingerprints import FW_VERSIONS +from opendbc.car.chrysler.values import FW_QUERY_CONFIG, CAR, CUSW_CARS, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags, ChryslerSafetyFlags from opendbc.car.interfaces import CarInterfaceBase -class CarInterface(CarInterfaceBase): +class ChryslerInterface(CarInterfaceBase): CarState = CarState CarController = CarController RadarInterface = RadarInterface + CAR = CAR + BRAND = "chrysler" + FW_QUERY_CONFIG = FW_QUERY_CONFIG + FW_VERSIONS = FW_VERSIONS DRIVABLE_GEARS = (structs.CarState.GearShifter.low,) @staticmethod def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: - ret.brand = "chrysler" # TODO: Chrysler CUSW in dashcam pending comma safety validation and a fix for LKAS fault on disengage ret.dashcamOnly = candidate in (RAM_HD | CUSW_CARS) diff --git a/opendbc/car/docs.py b/opendbc/car/docs.py index b4a21150170..e8185179c05 100755 --- a/opendbc/car/docs.py +++ b/opendbc/car/docs.py @@ -14,9 +14,9 @@ from opendbc.car.structs import CarParams from opendbc.car.docs_definitions import CarDocs, ExtraCarDocs, ExtraCarsColumn, CommonFootnote from opendbc.car.car_helpers import interfaces -from opendbc.car.interfaces import get_interface_attr +from opendbc.car.values import FOOTNOTES from opendbc.car.values import Platform -from opendbc.car.mock.values import CAR as MOCK +from opendbc.car.mock.interface import MockInterface from opendbc.car.extra_cars import CAR as EXTRA @@ -30,7 +30,7 @@ def get_params_for_docs(platform) -> CarParams: - cp_platform = platform if platform in interfaces else MOCK.MOCK + cp_platform = platform if platform in interfaces else MockInterface.CAR.MOCK CP: CarParams = interfaces[cp_platform].get_params(cp_platform, fingerprint=gen_empty_fingerprint(), car_fw=[CarParams.CarFw(ecu=CarParams.Ecu.unknown)], alpha_long=True, is_release=True, docs=True) @@ -39,7 +39,7 @@ def get_params_for_docs(platform) -> CarParams: def get_all_footnotes() -> dict[Enum, int]: all_footnotes = list(CommonFootnote) - for footnotes in get_interface_attr("Footnote", ignore_none=True).values(): + for footnotes in FOOTNOTES: all_footnotes.extend(footnotes) return {fn: idx + 1 for idx, fn in enumerate(all_footnotes)} diff --git a/opendbc/car/fingerprints.py b/opendbc/car/fingerprints.py index 81800aaa3a9..4636a8108d7 100644 --- a/opendbc/car/fingerprints.py +++ b/opendbc/car/fingerprints.py @@ -1,4 +1,4 @@ -from opendbc.car.interfaces import get_interface_attr +from opendbc.car.values import FINGERPRINTS as _FINGERPRINTS from opendbc.car.body.values import CAR as BODY from opendbc.car.chrysler.values import CAR as CHRYSLER from opendbc.car.ford.values import CAR as FORD @@ -13,9 +13,6 @@ from opendbc.car.toyota.values import CAR as TOYOTA from opendbc.car.volkswagen.values import CAR as VW -FW_VERSIONS = get_interface_attr('FW_VERSIONS', combine_brands=True, ignore_none=True) -_FINGERPRINTS = get_interface_attr('FINGERPRINTS', combine_brands=True, ignore_none=True) - _DEBUG_ADDRESS = {1880: 8} # reserved for debug purposes diff --git a/opendbc/car/ford/interface.py b/opendbc/car/ford/interface.py index 3c387542221..122e90c9086 100644 --- a/opendbc/car/ford/interface.py +++ b/opendbc/car/ford/interface.py @@ -6,16 +6,22 @@ from opendbc.car.ford.carstate import CarState from opendbc.car.ford.fordcan import CanBus from opendbc.car.ford.radar_interface import RadarInterface -from opendbc.car.ford.values import CarControllerParams, DBC, Ecu, FordFlags, RADAR, FordSafetyFlags +from opendbc.car.ford.fingerprints import FW_VERSIONS +from opendbc.car.ford.values import Footnote, FW_QUERY_CONFIG, CAR, CarControllerParams, DBC, Ecu, FordFlags, RADAR, FordSafetyFlags from opendbc.car.interfaces import CarInterfaceBase TransmissionType = structs.CarParams.TransmissionType -class CarInterface(CarInterfaceBase): +class FordInterface(CarInterfaceBase): CarState = CarState CarController = CarController RadarInterface = RadarInterface + CAR = CAR + BRAND = "ford" + FW_QUERY_CONFIG = FW_QUERY_CONFIG + FW_VERSIONS = FW_VERSIONS + Footnote = Footnote DRIVABLE_GEARS = (structs.CarState.GearShifter.low, structs.CarState.GearShifter.manumatic) @@ -29,7 +35,6 @@ def get_pid_accel_limits(CP, current_speed, cruise_speed): @staticmethod def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: - ret.brand = "ford" ret.radarUnavailable = Bus.radar not in DBC[candidate] ret.steerControlType = structs.CarParams.SteerControlType.angle diff --git a/opendbc/car/fw_versions.py b/opendbc/car/fw_versions.py index d672b039984..d09ecf0f09b 100644 --- a/opendbc/car/fw_versions.py +++ b/opendbc/car/fw_versions.py @@ -9,17 +9,13 @@ from opendbc.car.carlog import carlog from opendbc.car.structs import CarParams from opendbc.car.ecu_addrs import get_ecu_addrs -from opendbc.car.fingerprints import FW_VERSIONS -from opendbc.car.fw_query_definitions import ESSENTIAL_ECUS, AddrType, EcuAddrBusType, FwQueryConfig, LiveFwVersions, OfflineFwVersions -from opendbc.car.interfaces import get_interface_attr +from opendbc.car.values import FW_VERSIONS, FW_QUERY_CONFIGS, VERSIONS +from opendbc.car.fw_query_definitions import ESSENTIAL_ECUS, AddrType, EcuAddrBusType, LiveFwVersions, OfflineFwVersions from opendbc.car.isotp_parallel_query import IsoTpParallelQuery Ecu = CarParams.Ecu FUZZY_EXCLUDE_ECUS = [Ecu.fwdCamera, Ecu.fwdRadar, Ecu.eps, Ecu.debug] -FW_QUERY_CONFIGS: dict[str, FwQueryConfig] = get_interface_attr('FW_QUERY_CONFIG', ignore_none=True) -VERSIONS = get_interface_attr('FW_VERSIONS', ignore_none=True) - MODEL_TO_BRAND = {c: b for b, e in VERSIONS.items() for c in e} REQUESTS = [(brand, config, r) for brand, config in FW_QUERY_CONFIGS.items() for r in config.requests] diff --git a/opendbc/car/gm/interface.py b/opendbc/car/gm/interface.py index 0c7b2e7937c..0f8c2a65cd3 100755 --- a/opendbc/car/gm/interface.py +++ b/opendbc/car/gm/interface.py @@ -7,7 +7,8 @@ from opendbc.car.gm.carcontroller import CarController from opendbc.car.gm.carstate import CarState from opendbc.car.gm.radar_interface import RadarInterface, RADAR_HEADER_MSG, CAMERA_DATA_HEADER_MSG -from opendbc.car.gm.values import CAR, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, SDGM_CAR, ALT_ACCS, CanBus, GMSafetyFlags +from opendbc.car.gm.fingerprints import FW_VERSIONS, FINGERPRINTS +from opendbc.car.gm.values import Footnote, FW_QUERY_CONFIG, CAR, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, SDGM_CAR, ALT_ACCS, CanBus, GMSafetyFlags from opendbc.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, LateralAccelFromTorqueCallbackType TransmissionType = structs.CarParams.TransmissionType @@ -20,10 +21,16 @@ } -class CarInterface(CarInterfaceBase): +class GMInterface(CarInterfaceBase): CarState = CarState CarController = CarController RadarInterface = RadarInterface + CAR = CAR + BRAND = "gm" + FW_QUERY_CONFIG = FW_QUERY_CONFIG + FW_VERSIONS = FW_VERSIONS + FINGERPRINTS = FINGERPRINTS + Footnote = Footnote DRIVABLE_GEARS = (structs.CarState.GearShifter.sport, structs.CarState.GearShifter.low, structs.CarState.GearShifter.eco, structs.CarState.GearShifter.manumatic) @@ -86,7 +93,6 @@ def lateral_accel_from_torque_siglin(torque: float, torque_params: structs.CarPa @staticmethod def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: - ret.brand = "gm" ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.gm)] ret.autoResumeSng = False ret.enableBsm = 0x142 in fingerprint[CanBus.POWERTRAIN] diff --git a/opendbc/car/honda/interface.py b/opendbc/car/honda/interface.py index d367a5f2ef5..eb18a646324 100755 --- a/opendbc/car/honda/interface.py +++ b/opendbc/car/honda/interface.py @@ -4,7 +4,8 @@ from opendbc.car.common.conversions import Conversions as CV from opendbc.car.disable_ecu import disable_ecu from opendbc.car.honda.hondacan import CanBus -from opendbc.car.honda.values import CarControllerParams, HondaFlags, CAR, HondaSafetyFlags +from opendbc.car.honda.fingerprints import FW_VERSIONS +from opendbc.car.honda.values import Footnote, FW_QUERY_CONFIG, CarControllerParams, HondaFlags, CAR, HondaSafetyFlags from opendbc.car.honda.carcontroller import CarController from opendbc.car.honda.carstate import CarState from opendbc.car.honda.radar_interface import RadarInterface @@ -13,10 +14,15 @@ TransmissionType = structs.CarParams.TransmissionType -class CarInterface(CarInterfaceBase): +class HondaInterface(CarInterfaceBase): CarState = CarState CarController = CarController RadarInterface = RadarInterface + CAR = CAR + BRAND = "honda" + FW_QUERY_CONFIG = FW_QUERY_CONFIG + FW_VERSIONS = FW_VERSIONS + Footnote = Footnote DRIVABLE_GEARS = (structs.CarState.GearShifter.sport,) @@ -33,7 +39,6 @@ def get_pid_accel_limits(CP, current_speed, cruise_speed): @staticmethod def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: - ret.brand = "honda" CAN = CanBus(ret, fingerprint) @@ -252,4 +257,4 @@ def init(CP, can_recv, can_send, communication_control=None): def deinit(CP, can_recv, can_send): communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL, 0x80 | uds.CONTROL_TYPE.ENABLE_RX_ENABLE_TX, uds.MESSAGE_TYPE.NORMAL_AND_NETWORK_MANAGEMENT]) - CarInterface.init(CP, can_recv, can_send, communication_control) + HondaInterface.init(CP, can_recv, can_send, communication_control) diff --git a/opendbc/car/hyundai/interface.py b/opendbc/car/hyundai/interface.py index 08a426f07c1..799e6db7e8e 100644 --- a/opendbc/car/hyundai/interface.py +++ b/opendbc/car/hyundai/interface.py @@ -1,6 +1,7 @@ from opendbc.car import Bus, get_safety_config, structs, uds from opendbc.car.hyundai.hyundaicanfd import CanBus -from opendbc.car.hyundai.values import HyundaiFlags, CAR, DBC, HyundaiSafetyFlags +from opendbc.car.hyundai.fingerprints import FW_VERSIONS +from opendbc.car.hyundai.values import FW_QUERY_CONFIG, HyundaiFlags, CAR, DBC, HyundaiSafetyFlags from opendbc.car.hyundai.radar_interface import RADAR_START_ADDR from opendbc.car.interfaces import CarInterfaceBase from opendbc.car.disable_ecu import disable_ecu @@ -15,16 +16,19 @@ ENABLE_BUTTONS = (ButtonType.accelCruise, ButtonType.decelCruise, ButtonType.cancel, ButtonType.mainCruise) -class CarInterface(CarInterfaceBase): +class HyundaiInterface(CarInterfaceBase): CarState = CarState CarController = CarController RadarInterface = RadarInterface + CAR = CAR + BRAND = "hyundai" + FW_QUERY_CONFIG = FW_QUERY_CONFIG + FW_VERSIONS = FW_VERSIONS DRIVABLE_GEARS = (structs.CarState.GearShifter.sport, structs.CarState.GearShifter.manumatic) @staticmethod def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: - ret.brand = "hyundai" if ret.flags & HyundaiFlags.CANFD: # Shared configuration for CAN-FD cars @@ -171,4 +175,4 @@ def init(CP, can_recv, can_send, communication_control=None): @staticmethod def deinit(CP, can_recv, can_send): communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL, 0x80 | uds.CONTROL_TYPE.ENABLE_RX_ENABLE_TX, uds.MESSAGE_TYPE.NORMAL]) - CarInterface.init(CP, can_recv, can_send, communication_control) + HyundaiInterface.init(CP, can_recv, can_send, communication_control) diff --git a/opendbc/car/hyundai/tests/test_hyundai.py b/opendbc/car/hyundai/tests/test_hyundai.py index 7b1241fc767..2aea5479932 100644 --- a/opendbc/car/hyundai/tests/test_hyundai.py +++ b/opendbc/car/hyundai/tests/test_hyundai.py @@ -3,7 +3,7 @@ from opendbc.car import gen_empty_fingerprint from opendbc.car.structs import CarParams from opendbc.car.fw_versions import build_fw_dict -from opendbc.car.hyundai.interface import CarInterface +from opendbc.car.hyundai.interface import HyundaiInterface from opendbc.car.hyundai.hyundaicanfd import CanBus from opendbc.car.hyundai.radar_interface import RADAR_START_ADDR from opendbc.car.hyundai.values import CAR, DATE_FW_ECUS, FW_QUERY_CONFIG, CANFD_FUZZY_WHITELIST, \ @@ -58,7 +58,7 @@ def test_feature_detection(self): if lka_steering: cam_can = CanBus(None, fingerprint).CAM fingerprint[cam_can] = [0x50, 0x110] # LKA steering messages - CP = CarInterface.get_params(CAR.KIA_EV6, fingerprint, [], False, False, False) + CP = HyundaiInterface.get_params(CAR.KIA_EV6, fingerprint, [], False, False, False) assert bool(CP.flags & HyundaiFlags.CANFD_LKA_STEER_MSG) == lka_steering # radar available @@ -66,14 +66,14 @@ def test_feature_detection(self): fingerprint = gen_empty_fingerprint() if radar: fingerprint[1][RADAR_START_ADDR] = 8 - CP = CarInterface.get_params(CAR.HYUNDAI_SONATA, fingerprint, [], False, False, False) + CP = HyundaiInterface.get_params(CAR.HYUNDAI_SONATA, fingerprint, [], False, False, False) assert CP.radarUnavailable != radar def test_alternate_limits(self): # Alternate lateral control limits, for high torque cars, verify Panda safety mode flag is set fingerprint = gen_empty_fingerprint() for car_model in CAR: - CP = CarInterface.get_params(car_model, fingerprint, [], False, False, False) + CP = HyundaiInterface.get_params(car_model, fingerprint, [], False, False, False) assert bool(CP.flags & HyundaiFlags.ALT_LIMITS) == bool(CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.ALT_LIMITS) def test_can_features(self): diff --git a/opendbc/car/interfaces.py b/opendbc/car/interfaces.py index 5da6e9ecc32..423d11c88dc 100644 --- a/opendbc/car/interfaces.py +++ b/opendbc/car/interfaces.py @@ -4,17 +4,15 @@ import tomllib from abc import abstractmethod, ABC from enum import StrEnum -from typing import Any from collections.abc import Callable from functools import cache from opendbc.car import DT_CTRL, apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness, STD_CARGO_KG -from opendbc.car import structs +from opendbc.car import structs, Platforms from opendbc.car.can_definitions import CanData, CanRecvCallable, CanSendCallable from opendbc.car.common.basedir import BASEDIR from opendbc.car.common.conversions import Conversions as CV from opendbc.car.common.simple_kalman import KF1D, get_kalman_gain -from opendbc.car.values import PLATFORMS from opendbc.can import CANParser GearShifter = structs.CarState.GearShifter @@ -97,6 +95,11 @@ class CarInterfaceBase(ABC): CarController: type['CarControllerBase'] RadarInterface: type['RadarInterfaceBase'] = RadarInterfaceBase + # Brand identity and static config. Every concrete Interface sets CAR and BRAND; + # the firmware/fingerprint attributes are set by brands that publish them. + CAR: type[Platforms] + BRAND: str + DRIVABLE_GEARS: tuple[structs.CarState.GearShifter, ...] = () def __init__(self, CP: structs.CarParams): @@ -130,9 +133,34 @@ def get_non_essential_params(cls, candidate: str) -> structs.CarParams: @classmethod def get_params(cls, candidate: str, fingerprint: dict[int, dict[int, int]], car_fw: list[structs.CarParams.CarFw], alpha_long: bool, is_release: bool, docs: bool) -> structs.CarParams: - ret = CarInterfaceBase.get_std_params(candidate) + ret = structs.CarParams() + ret.carFingerprint = candidate + ret.brand = cls.BRAND + + # Car docs fields + ret.maxLateralAccel = get_torque_params()[candidate]['MAX_LAT_ACCEL_MEASURED'] + ret.autoResumeSng = True # describes whether car can resume from a stop automatically + + # standard ALC params + ret.tireStiffnessFactor = 1.0 + ret.steerControlType = structs.CarParams.SteerControlType.torque + ret.minSteerSpeed = 0. + ret.wheelSpeedFactor = 1.0 + + ret.pcmCruise = True # openpilot's state is tied to the PCM's cruise state on most cars + ret.minEnableSpeed = -1. # enable is done by stock ACC, so ignore this + ret.steerRatioRear = 0. # no rear steering, at least on the listed cars above + ret.openpilotLongitudinalControl = False + ret.stopAccel = -2.0 + ret.longitudinalTuning.kpBP = [0.] + ret.longitudinalTuning.kpV = [0.] + ret.longitudinalTuning.kiBP = [0.] + ret.longitudinalTuning.kiV = [0.] + # TODO estimate car specific lag, use .15s for now + ret.longitudinalActuatorDelay = 0.15 + ret.steerLimitTimer = 1.0 - platform = PLATFORMS[candidate] + platform = cls.CAR(candidate) ret.mass = platform.config.specs.mass ret.wheelbase = platform.config.specs.wheelbase ret.steerRatio = platform.config.specs.steerRatio @@ -189,36 +217,6 @@ def lateral_accel_from_torque_linear(self, torque: float, torque_params: structs def lateral_accel_from_torque(self) -> LateralAccelFromTorqueCallbackType: return self.lateral_accel_from_torque_linear - # returns a set of default params to avoid repetition in car specific params - @staticmethod - def get_std_params(candidate: str) -> structs.CarParams: - ret = structs.CarParams() - ret.carFingerprint = candidate - - # Car docs fields - ret.maxLateralAccel = get_torque_params()[candidate]['MAX_LAT_ACCEL_MEASURED'] - ret.autoResumeSng = True # describes whether car can resume from a stop automatically - - # standard ALC params - ret.tireStiffnessFactor = 1.0 - ret.steerControlType = structs.CarParams.SteerControlType.torque - ret.minSteerSpeed = 0. - ret.wheelSpeedFactor = 1.0 - - ret.pcmCruise = True # openpilot's state is tied to the PCM's cruise state on most cars - ret.minEnableSpeed = -1. # enable is done by stock ACC, so ignore this - ret.steerRatioRear = 0. # no rear steering, at least on the listed cars aboveA - ret.openpilotLongitudinalControl = False - ret.stopAccel = -2.0 - ret.longitudinalTuning.kpBP = [0.] - ret.longitudinalTuning.kpV = [0.] - ret.longitudinalTuning.kiBP = [0.] - ret.longitudinalTuning.kiV = [0.] - # TODO estimate car specific lag, use .15s for now - ret.longitudinalActuatorDelay = 0.15 - ret.steerLimitTimer = 1.0 - return ret - @staticmethod def configure_torque_tune(candidate: str, tune: structs.CarParams.LateralTuning, steering_angle_deadzone_deg: float = 0.0): params = get_torque_params()[candidate] @@ -367,37 +365,3 @@ def __init__(self, dbc_names: dict[StrEnum, str], CP: structs.CarParams): @abstractmethod def update(self, CC: structs.CarControl, CS: CarStateBase, now_nanos: int) -> tuple[structs.CarControl.Actuators, list[CanData]]: pass - - -INTERFACE_ATTR_FILE = { - "FINGERPRINTS": "fingerprints", - "FW_VERSIONS": "fingerprints", -} - -# interface-specific helpers - - -def get_interface_attr(attr: str, combine_brands: bool = False, ignore_none: bool = False) -> dict[str | StrEnum, Any]: - # read all the folders in opendbc/car and return a dict where: - # - keys are all the car models or brand names - # - values are attr values from all car folders - result = {} - for car_folder in sorted([x[0] for x in os.walk(BASEDIR)]): - try: - brand_name = car_folder.split('/')[-1] - brand_values = __import__(f'opendbc.car.{brand_name}.{INTERFACE_ATTR_FILE.get(attr, "values")}', fromlist=[attr]) - if hasattr(brand_values, attr) or not ignore_none: - attr_data = getattr(brand_values, attr, None) - else: - continue - - if combine_brands: - if isinstance(attr_data, dict): - for f, v in attr_data.items(): - result[f] = v - else: - result[brand_name] = attr_data - except (ImportError, OSError): - pass - - return result diff --git a/opendbc/car/mazda/interface.py b/opendbc/car/mazda/interface.py index 814846e8528..8f7f0649529 100755 --- a/opendbc/car/mazda/interface.py +++ b/opendbc/car/mazda/interface.py @@ -4,16 +4,20 @@ from opendbc.car.interfaces import CarInterfaceBase from opendbc.car.mazda.carcontroller import CarController from opendbc.car.mazda.carstate import CarState -from opendbc.car.mazda.values import CAR, LKAS_LIMITS +from opendbc.car.mazda.fingerprints import FW_VERSIONS +from opendbc.car.mazda.values import FW_QUERY_CONFIG, CAR, LKAS_LIMITS -class CarInterface(CarInterfaceBase): +class MazdaInterface(CarInterfaceBase): CarState = CarState CarController = CarController + CAR = CAR + BRAND = "mazda" + FW_QUERY_CONFIG = FW_QUERY_CONFIG + FW_VERSIONS = FW_VERSIONS @staticmethod def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: - ret.brand = "mazda" ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.mazda)] ret.radarUnavailable = True diff --git a/opendbc/car/mock/interface.py b/opendbc/car/mock/interface.py index 0c5f459d143..e2d33fe18e8 100755 --- a/opendbc/car/mock/interface.py +++ b/opendbc/car/mock/interface.py @@ -3,16 +3,18 @@ from opendbc.car.interfaces import CarInterfaceBase from opendbc.car.mock.carcontroller import CarController from opendbc.car.mock.carstate import CarState +from opendbc.car.mock.values import CAR # mocked car interface for dashcam mode -class CarInterface(CarInterfaceBase): +class MockInterface(CarInterfaceBase): CarState = CarState CarController = CarController + CAR = CAR + BRAND = "mock" @staticmethod def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: - ret.brand = "mock" ret.lateralTuning.pid.kpBP = [0.] ret.lateralTuning.pid.kpV = [0.] ret.lateralTuning.pid.kiBP = [0.] diff --git a/opendbc/car/nissan/interface.py b/opendbc/car/nissan/interface.py index 8253d4844fd..74f506059ef 100644 --- a/opendbc/car/nissan/interface.py +++ b/opendbc/car/nissan/interface.py @@ -2,17 +2,22 @@ from opendbc.car.interfaces import CarInterfaceBase from opendbc.car.nissan.carcontroller import CarController from opendbc.car.nissan.carstate import CarState -from opendbc.car.nissan.values import CAR, NissanSafetyFlags +from opendbc.car.nissan.fingerprints import FW_VERSIONS +from opendbc.car.nissan.values import Footnote, FW_QUERY_CONFIG, CAR, NissanSafetyFlags -class CarInterface(CarInterfaceBase): +class NissanInterface(CarInterfaceBase): CarState = CarState CarController = CarController + CAR = CAR + BRAND = "nissan" + FW_QUERY_CONFIG = FW_QUERY_CONFIG + FW_VERSIONS = FW_VERSIONS + Footnote = Footnote DRIVABLE_GEARS = (structs.CarState.GearShifter.brake, structs.CarState.GearShifter.low) @staticmethod def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: - ret.brand = "nissan" ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.nissan)] ret.autoResumeSng = False ret.steerAtStandstill = True diff --git a/opendbc/car/psa/interface.py b/opendbc/car/psa/interface.py index f719a3d6aaa..10312e00371 100644 --- a/opendbc/car/psa/interface.py +++ b/opendbc/car/psa/interface.py @@ -2,17 +2,22 @@ from opendbc.car.interfaces import CarInterfaceBase from opendbc.car.psa.carcontroller import CarController from opendbc.car.psa.carstate import CarState +from opendbc.car.psa.fingerprints import FW_VERSIONS +from opendbc.car.psa.values import FW_QUERY_CONFIG, CAR TransmissionType = structs.CarParams.TransmissionType -class CarInterface(CarInterfaceBase): +class PSAInterface(CarInterfaceBase): CarState = CarState CarController = CarController + CAR = CAR + BRAND = "psa" + FW_QUERY_CONFIG = FW_QUERY_CONFIG + FW_VERSIONS = FW_VERSIONS @staticmethod def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: - ret.brand = 'psa' ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.psa)] diff --git a/opendbc/car/rivian/interface.py b/opendbc/car/rivian/interface.py index 66253489e43..30916ffa5fd 100644 --- a/opendbc/car/rivian/interface.py +++ b/opendbc/car/rivian/interface.py @@ -3,17 +3,21 @@ from opendbc.car.rivian.carcontroller import CarController from opendbc.car.rivian.carstate import CarState from opendbc.car.rivian.radar_interface import RadarInterface -from opendbc.car.rivian.values import RivianFlags, RivianSafetyFlags +from opendbc.car.rivian.fingerprints import FW_VERSIONS +from opendbc.car.rivian.values import FW_QUERY_CONFIG, CAR, RivianFlags, RivianSafetyFlags -class CarInterface(CarInterfaceBase): +class RivianInterface(CarInterfaceBase): CarState = CarState CarController = CarController RadarInterface = RadarInterface + CAR = CAR + BRAND = "rivian" + FW_QUERY_CONFIG = FW_QUERY_CONFIG + FW_VERSIONS = FW_VERSIONS @staticmethod def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: - ret.brand = "rivian" ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.rivian)] diff --git a/opendbc/car/subaru/interface.py b/opendbc/car/subaru/interface.py index 5b16f17d253..f01abba2fe0 100644 --- a/opendbc/car/subaru/interface.py +++ b/opendbc/car/subaru/interface.py @@ -3,16 +3,21 @@ from opendbc.car.interfaces import CarInterfaceBase from opendbc.car.subaru.carcontroller import CarController from opendbc.car.subaru.carstate import CarState -from opendbc.car.subaru.values import CAR, GLOBAL_ES_ADDR, SubaruFlags, SubaruSafetyFlags +from opendbc.car.subaru.fingerprints import FW_VERSIONS +from opendbc.car.subaru.values import Footnote, FW_QUERY_CONFIG, CAR, GLOBAL_ES_ADDR, SubaruFlags, SubaruSafetyFlags -class CarInterface(CarInterfaceBase): +class SubaruInterface(CarInterfaceBase): CarState = CarState CarController = CarController + CAR = CAR + BRAND = "subaru" + FW_QUERY_CONFIG = FW_QUERY_CONFIG + FW_VERSIONS = FW_VERSIONS + Footnote = Footnote @staticmethod def _get_params(ret: structs.CarParams, candidate: CAR, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: - ret.brand = "subaru" ret.radarUnavailable = True # for HYBRID CARS to be upstreamed, we need: # - replacement for ES_Distance so we can cancel the cruise control @@ -109,4 +114,4 @@ def init(CP, can_recv, can_send, communication_control=None): @staticmethod def deinit(CP, can_recv, can_send): communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL, uds.CONTROL_TYPE.ENABLE_RX_ENABLE_TX, uds.MESSAGE_TYPE.NORMAL]) - CarInterface.init(CP, can_recv, can_send, communication_control) + SubaruInterface.init(CP, can_recv, can_send, communication_control) diff --git a/opendbc/car/tesla/carcontroller.py b/opendbc/car/tesla/carcontroller.py index 8b7d9989c44..7ffac6ed446 100644 --- a/opendbc/car/tesla/carcontroller.py +++ b/opendbc/car/tesla/carcontroller.py @@ -11,8 +11,8 @@ def get_safety_CP(): # We use the TESLA_MODEL_Y platform for lateral limiting to match safety # A Model 3 at 40 m/s using the Model Y limits sees a <0.3% difference in max angle (from curvature factor) - from opendbc.car.tesla.interface import CarInterface - return CarInterface.get_non_essential_params("TESLA_MODEL_Y") + from opendbc.car.tesla.interface import TeslaInterface + return TeslaInterface.get_non_essential_params("TESLA_MODEL_Y") class CarController(CarControllerBase): diff --git a/opendbc/car/tesla/interface.py b/opendbc/car/tesla/interface.py index b55e35e3802..05438863c51 100644 --- a/opendbc/car/tesla/interface.py +++ b/opendbc/car/tesla/interface.py @@ -2,18 +2,23 @@ from opendbc.car.interfaces import CarInterfaceBase from opendbc.car.tesla.carcontroller import CarController from opendbc.car.tesla.carstate import CarState -from opendbc.car.tesla.values import TeslaSafetyFlags, TeslaFlags, CANBUS, CAR, DBC, FSD_14_FW, Ecu +from opendbc.car.tesla.fingerprints import FW_VERSIONS +from opendbc.car.tesla.values import Footnote, FW_QUERY_CONFIG, TeslaSafetyFlags, TeslaFlags, CANBUS, CAR, DBC, FSD_14_FW, Ecu from opendbc.car.tesla.radar_interface import RadarInterface, RADAR_START_ADDR -class CarInterface(CarInterfaceBase): +class TeslaInterface(CarInterfaceBase): CarState = CarState CarController = CarController RadarInterface = RadarInterface + CAR = CAR + BRAND = "tesla" + FW_QUERY_CONFIG = FW_QUERY_CONFIG + FW_VERSIONS = FW_VERSIONS + Footnote = Footnote @staticmethod def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: - ret.brand = "tesla" ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.tesla)] diff --git a/opendbc/car/tesla/tests/test_tesla.py b/opendbc/car/tesla/tests/test_tesla.py index 7981f03b8ed..9fa40817c42 100644 --- a/opendbc/car/tesla/tests/test_tesla.py +++ b/opendbc/car/tesla/tests/test_tesla.py @@ -3,7 +3,7 @@ from opendbc.car import gen_empty_fingerprint from opendbc.car.structs import CarParams -from opendbc.car.tesla.interface import CarInterface +from opendbc.car.tesla.interface import TeslaInterface from opendbc.car.tesla.fingerprints import FW_VERSIONS from opendbc.car.tesla.radar_interface import RADAR_START_ADDR from opendbc.car.tesla.values import CAR, FSD_14_FW @@ -91,7 +91,7 @@ def test_radar_detection(self): fingerprint = gen_empty_fingerprint() if radar: fingerprint[1][RADAR_START_ADDR] = 8 - CP = CarInterface.get_params(CAR.TESLA_MODEL_3, fingerprint, [], False, False, False) + CP = TeslaInterface.get_params(CAR.TESLA_MODEL_3, fingerprint, [], False, False, False) assert CP.radarUnavailable != radar def test_no_radar_car(self): @@ -100,5 +100,5 @@ def test_no_radar_car(self): fingerprint = gen_empty_fingerprint() if radar: fingerprint[1][RADAR_START_ADDR] = 8 - CP = CarInterface.get_params(CAR.TESLA_MODEL_X, fingerprint, [], False, False, False) + CP = TeslaInterface.get_params(CAR.TESLA_MODEL_X, fingerprint, [], False, False, False) assert CP.radarUnavailable # Always unavailable since no radar DBC diff --git a/opendbc/car/tests/car_diff.py b/opendbc/car/tests/car_diff.py index 37d82314056..a1adfc6d948 100755 --- a/opendbc/car/tests/car_diff.py +++ b/opendbc/car/tests/car_diff.py @@ -66,9 +66,9 @@ def can_recv(wait_for_one: bool = False) -> list[list[CanData]]: _, fingerprint = can_fingerprint(can_recv) - CarInterface = interfaces[platform] - CP = CarInterface.get_params(platform, fingerprint, [], False, False, False) - CI = CarInterface(CP) + Interface = interfaces[platform] + CP = Interface.get_params(platform, fingerprint, [], False, False, False) + CI = Interface(CP) CC = structs.CarControl().as_reader() states, timestamps = [], [] diff --git a/opendbc/car/tests/test_can_fingerprint.py b/opendbc/car/tests/test_can_fingerprint.py index 3e71317d2ce..fd25c9d349f 100644 --- a/opendbc/car/tests/test_can_fingerprint.py +++ b/opendbc/car/tests/test_can_fingerprint.py @@ -1,7 +1,7 @@ import unittest from opendbc.car.can_definitions import CanData from opendbc.car.car_helpers import FRAME_FINGERPRINT, can_fingerprint -from opendbc.car.fingerprints import _FINGERPRINTS as FINGERPRINTS +from opendbc.car.values import FINGERPRINTS from opendbc.testing import parameterized diff --git a/opendbc/car/tests/test_car_interfaces.py b/opendbc/car/tests/test_car_interfaces.py index 1c2c778f9de..c3573a53dc0 100644 --- a/opendbc/car/tests/test_car_interfaces.py +++ b/opendbc/car/tests/test_car_interfaces.py @@ -3,10 +3,9 @@ from opendbc.car import DT_CTRL, CanData, structs from opendbc.car.car_helpers import interfaces -from opendbc.car.fingerprints import FW_VERSIONS +from opendbc.car.values import FW_VERSIONS, PLATFORMS +from opendbc.car.interfaces import CarInterfaceBase from opendbc.car.fw_versions import FW_QUERY_CONFIGS -from opendbc.car.interfaces import CarInterfaceBase, get_interface_attr -from opendbc.car.values import PLATFORMS from opendbc.testing import Fuzzy, fuzzy_test ALL_ECUS = tuple(sorted({ecu for ecus in FW_VERSIONS.values() for ecu in ecus} | @@ -29,10 +28,10 @@ def generate_car_fw(): request=fuzzy.choice(ALL_REQUESTS)) # initialize car interface - CarInterface = interfaces[car_name] - car_params = CarInterface.get_params(car_name, fingerprints, fuzzy.list(generate_car_fw), - alpha_long=fuzzy.boolean(), is_release=False, docs=False) - return CarInterface(car_params) + Interface = interfaces[car_name] + car_params = Interface.get_params(car_name, fingerprints, fuzzy.list(generate_car_fw), + alpha_long=fuzzy.boolean(), is_release=False, docs=False) + return Interface(car_params) def _make_car_test(car_name): @@ -102,30 +101,7 @@ def test(self, fuzzy): class TestCarInterfaces(unittest.TestCase): - def test_interface_attrs(self): - """Asserts basic behavior of interface attribute getter""" - num_brands = len(get_interface_attr('CAR')) - assert num_brands >= 12 - - # Should return value for all brands when not combining, even if attribute doesn't exist - ret = get_interface_attr('FAKE_ATTR') - assert len(ret) == num_brands - - # Make sure we can combine dicts - ret = get_interface_attr('DBC', combine_brands=True) - assert len(ret) >= 160 - - # We don't support combining non-dicts - ret = get_interface_attr('CAR', combine_brands=True) - assert len(ret) == 0 - - # If brand has None value, it shouldn't return when ignore_none=True is specified - none_brands = {b for b, v in get_interface_attr('FINGERPRINTS').items() if v is None} - assert len(none_brands) >= 1 - - ret = get_interface_attr('FINGERPRINTS', ignore_none=True) - none_brands_in_ret = none_brands.intersection(ret) - assert len(none_brands_in_ret) == 0, f'Brands with None values in ignore_none=True result: {none_brands_in_ret}' + pass for car_name in sorted(PLATFORMS): diff --git a/opendbc/car/tests/test_fw_fingerprint.py b/opendbc/car/tests/test_fw_fingerprint.py index 4aafde8e150..e269f82bc43 100644 --- a/opendbc/car/tests/test_fw_fingerprint.py +++ b/opendbc/car/tests/test_fw_fingerprint.py @@ -8,7 +8,7 @@ from opendbc.car.can_definitions import CanData from opendbc.car.car_helpers import interfaces from opendbc.car.structs import CarParams -from opendbc.car.fingerprints import FW_VERSIONS +from opendbc.car.values import FW_VERSIONS from opendbc.car.fw_versions import FW_QUERY_CONFIGS, FUZZY_EXCLUDE_ECUS, VERSIONS, build_fw_dict, \ match_fw_to_car, get_brand_ecu_matches, get_fw_versions, get_present_ecus from opendbc.car.vin import get_vin diff --git a/opendbc/car/tests/test_lateral_limits.py b/opendbc/car/tests/test_lateral_limits.py index 45116e69117..9f738135529 100755 --- a/opendbc/car/tests/test_lateral_limits.py +++ b/opendbc/car/tests/test_lateral_limits.py @@ -27,8 +27,8 @@ def setUpClass(cls): if 'car_model' not in cls.__dict__: raise unittest.SkipTest('Base class') - CarInterface = interfaces[cls.car_model] - CP = CarInterface.get_non_essential_params(cls.car_model) + Interface = interfaces[cls.car_model] + CP = Interface.get_non_essential_params(cls.car_model) if cls.car_model == 'MOCK': raise unittest.SkipTest('Mock car') diff --git a/opendbc/car/tests/test_models.py b/opendbc/car/tests/test_models.py index 5a911e96746..ec16bccd26a 100755 --- a/opendbc/car/tests/test_models.py +++ b/opendbc/car/tests/test_models.py @@ -170,8 +170,8 @@ def setUpClass(cls): car_fw, cls.can_msgs, alpha_long = cls.get_testing_data() cls.raw_can_keys = {(msg.address, msg.src) for _, messages in cls.can_msgs for msg in messages if msg.src < 128} - cls.CarInterface = interfaces[cls.platform] - cls.CP = cls.CarInterface.get_params(cls.platform, cls.fingerprint, car_fw, alpha_long, False, docs=False) + cls.Interface = interfaces[cls.platform] + cls.CP = cls.Interface.get_params(cls.platform, cls.fingerprint, car_fw, alpha_long, False, docs=False) assert cls.CP assert cls.CP.carFingerprint == cls.platform @@ -180,7 +180,7 @@ def tearDownClass(cls): del cls.can_msgs def setUp(self): - self.CI = self.CarInterface(self.CP.copy()) + self.CI = self.Interface(self.CP.copy()) assert self.CI self.safety = libsafety_py.libsafety @@ -214,7 +214,7 @@ def test_car_interface(self): self.assertEqual(can_invalid_cnt, 0) def test_radar_interface(self): - RI = self.CarInterface.RadarInterface(self.CP) + RI = self.Interface.RadarInterface(self.CP) assert RI error_cnt = 0 @@ -293,12 +293,12 @@ def test_panda_safety_tx_cases(self): controller_params = self.CP if self.CP.brand == "volkswagen" and self.CP.flags & VolkswagenFlags.MLB and self.CP.openpilotLongitudinalControl: # Some archived MLB routes record alpha longitudinal, which current MLB safety does not support. - controller_params = self.CarInterface.get_params(self.platform, self.fingerprint, self.CP.carFw, False, False, docs=False) + controller_params = self.Interface.get_params(self.platform, self.fingerprint, self.CP.carFw, False, False, docs=False) def test_car_controller(car_control): now_nanos = 0 msgs_sent = 0 - CI = self.CarInterface(controller_params) + CI = self.Interface(controller_params) for _ in range(round(10.0 / DT_CTRL)): CI.update([]) _, sendcan = CI.apply(car_control, now_nanos) diff --git a/opendbc/car/tests/test_vehicle_model.py b/opendbc/car/tests/test_vehicle_model.py index a3e4afd9fae..08174ec1230 100644 --- a/opendbc/car/tests/test_vehicle_model.py +++ b/opendbc/car/tests/test_vehicle_model.py @@ -3,14 +3,14 @@ import numpy as np -from opendbc.car.honda.interface import CarInterface +from opendbc.car.honda.interface import HondaInterface from opendbc.car.honda.values import CAR from opendbc.car.vehicle_model import VehicleModel, dyn_ss_sol, create_dyn_state_matrices class TestVehicleModel(unittest.TestCase): def setUp(self): - CP = CarInterface.get_non_essential_params(CAR.HONDA_CIVIC) + CP = HondaInterface.get_non_essential_params(CAR.HONDA_CIVIC) self.VM = VehicleModel(CP) def test_round_trip_yaw_rate(self): diff --git a/opendbc/car/toyota/interface.py b/opendbc/car/toyota/interface.py index e143f55adf4..377778af20d 100644 --- a/opendbc/car/toyota/interface.py +++ b/opendbc/car/toyota/interface.py @@ -2,7 +2,8 @@ from opendbc.car.toyota.carstate import CarState from opendbc.car.toyota.carcontroller import CarController from opendbc.car.toyota.radar_interface import RadarInterface -from opendbc.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, CarControllerParams, MIN_ACC_SPEED, \ +from opendbc.car.toyota.fingerprints import FW_VERSIONS +from opendbc.car.toyota.values import Footnote, FW_QUERY_CONFIG, Ecu, CAR, DBC, ToyotaFlags, CarControllerParams, MIN_ACC_SPEED, \ EPS_SCALE, ToyotaSafetyFlags from opendbc.car.disable_ecu import disable_ecu from opendbc.car.interfaces import CarInterfaceBase @@ -10,10 +11,15 @@ SteerControlType = structs.CarParams.SteerControlType -class CarInterface(CarInterfaceBase): +class ToyotaInterface(CarInterfaceBase): CarState = CarState CarController = CarController RadarInterface = RadarInterface + CAR = CAR + BRAND = "toyota" + FW_QUERY_CONFIG = FW_QUERY_CONFIG + FW_VERSIONS = FW_VERSIONS + Footnote = Footnote DRIVABLE_GEARS = (structs.CarState.GearShifter.sport,) @@ -23,7 +29,6 @@ def get_pid_accel_limits(CP, current_speed, cruise_speed): @staticmethod def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: - ret.brand = "toyota" ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.toyota)] ret.safetyConfigs[0].safetyParam = EPS_SCALE[candidate] @@ -134,4 +139,4 @@ def init(CP, can_recv, can_send, communication_control=None): def deinit(CP, can_recv, can_send): # re-enable radar if alpha longitudinal toggled on radar-ACC car communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL, uds.CONTROL_TYPE.ENABLE_RX_ENABLE_TX, uds.MESSAGE_TYPE.NORMAL]) - CarInterface.init(CP, can_recv, can_send, communication_control) + ToyotaInterface.init(CP, can_recv, can_send, communication_control) diff --git a/opendbc/car/values.py b/opendbc/car/values.py index f606249a4e0..4cbc1501644 100644 --- a/opendbc/car/values.py +++ b/opendbc/car/values.py @@ -1,21 +1,43 @@ from typing import get_args -from opendbc.car.body.values import CAR as BODY -from opendbc.car.chrysler.values import CAR as CHRYSLER -from opendbc.car.ford.values import CAR as FORD -from opendbc.car.gm.values import CAR as GM -from opendbc.car.honda.values import CAR as HONDA -from opendbc.car.hyundai.values import CAR as HYUNDAI -from opendbc.car.mazda.values import CAR as MAZDA -from opendbc.car.mock.values import CAR as MOCK -from opendbc.car.nissan.values import CAR as NISSAN -from opendbc.car.psa.values import CAR as PSA -from opendbc.car.rivian.values import CAR as RIVIAN -from opendbc.car.subaru.values import CAR as SUBARU -from opendbc.car.tesla.values import CAR as TESLA -from opendbc.car.toyota.values import CAR as TOYOTA -from opendbc.car.volkswagen.values import CAR as VOLKSWAGEN -Platform = BODY | CHRYSLER | FORD | GM | HONDA | HYUNDAI | MAZDA | MOCK | NISSAN | PSA | RIVIAN | SUBARU | TESLA | TOYOTA | VOLKSWAGEN +from opendbc.car.body.interface import BodyInterface +from opendbc.car.chrysler.interface import ChryslerInterface +from opendbc.car.ford.interface import FordInterface +from opendbc.car.gm.interface import GMInterface +from opendbc.car.honda.interface import HondaInterface +from opendbc.car.hyundai.interface import HyundaiInterface +from opendbc.car.mazda.interface import MazdaInterface +from opendbc.car.mock.interface import MockInterface +from opendbc.car.nissan.interface import NissanInterface +from opendbc.car.psa.interface import PSAInterface +from opendbc.car.rivian.interface import RivianInterface +from opendbc.car.subaru.interface import SubaruInterface +from opendbc.car.tesla.interface import TeslaInterface +from opendbc.car.toyota.interface import ToyotaInterface +from opendbc.car.volkswagen.interface import VolkswagenInterface + +# Every brand's Interface, carrying its platform enum, firmware versions, and +# query config as class attributes (see CarInterfaceBase). This is the single +# import point: given an Interface you have typed access to everything about +# that brand without magic module-level names. +ALL_INTERFACES: tuple = (BodyInterface, ChryslerInterface, FordInterface, GMInterface, HondaInterface, + HyundaiInterface, MazdaInterface, MockInterface, NissanInterface, PSAInterface, + RivianInterface, SubaruInterface, TeslaInterface, ToyotaInterface, VolkswagenInterface) + +# Platform enums (lightweight type union for annotations) +Platform = (BodyInterface.CAR | ChryslerInterface.CAR | FordInterface.CAR | GMInterface.CAR | + HondaInterface.CAR | HyundaiInterface.CAR | MazdaInterface.CAR | MockInterface.CAR | + NissanInterface.CAR | PSAInterface.CAR | RivianInterface.CAR | SubaruInterface.CAR | + TeslaInterface.CAR | ToyotaInterface.CAR | VolkswagenInterface.CAR) BRANDS = get_args(Platform) PLATFORMS: dict[str, Platform] = {str(platform): platform for brand in BRANDS for platform in brand} + +# Aggregated firmware/fingerprint data, built from the Interface classes. +FW_VERSIONS: dict = {p: v for _ci in ALL_INTERFACES for p, v in getattr(_ci, 'FW_VERSIONS', {}).items()} +FINGERPRINTS: dict = {p: v for _ci in ALL_INTERFACES for p, v in getattr(_ci, 'FINGERPRINTS', {}).items()} + +# Per-brand data, keyed by brand name string. +VERSIONS: dict = {_ci.BRAND: _ci.FW_VERSIONS for _ci in ALL_INTERFACES if hasattr(_ci, 'FW_VERSIONS')} +FW_QUERY_CONFIGS: dict = {_ci.BRAND: _ci.FW_QUERY_CONFIG for _ci in ALL_INTERFACES if hasattr(_ci, 'FW_QUERY_CONFIG')} +FOOTNOTES: list = [_ci.Footnote for _ci in ALL_INTERFACES if hasattr(_ci, 'Footnote')] diff --git a/opendbc/car/volkswagen/carstate.py b/opendbc/car/volkswagen/carstate.py index 3844a39a8d6..7bb8ab61631 100644 --- a/opendbc/car/volkswagen/carstate.py +++ b/opendbc/car/volkswagen/carstate.py @@ -227,7 +227,7 @@ def update_pq(self, pt_cp, cam_cp, ext_cp) -> structs.CarState: ret.buttonEvents = self.create_button_events(pt_cp, self.CCP.BUTTONS) self.gra_stock_values = pt_cp.vl["GRA_Neu"] - # Additional safety checks performed in CarInterface. + # Additional safety checks performed in Interface. ret.espDisabled = bool(pt_cp.vl["Bremse_1"]["BR1_ESPASR_passive"]) ret.lowSpeedAlert = self.update_low_speed_alert(ret.vEgo) diff --git a/opendbc/car/volkswagen/interface.py b/opendbc/car/volkswagen/interface.py index cc2aa4a8044..7e6e3c594f3 100644 --- a/opendbc/car/volkswagen/interface.py +++ b/opendbc/car/volkswagen/interface.py @@ -3,19 +3,24 @@ from opendbc.car.volkswagen.carcontroller import CarController from opendbc.car.volkswagen.carstate import CarState from opendbc.car.volkswagen.radar_interface import RadarInterface -from opendbc.car.volkswagen.values import CanBus, CAR, DBC, NetworkLocation, TransmissionType, VolkswagenFlags, VolkswagenSafetyFlags +from opendbc.car.volkswagen.fingerprints import FW_VERSIONS +from opendbc.car.volkswagen.values import Footnote, FW_QUERY_CONFIG, CanBus, CAR, DBC, NetworkLocation, TransmissionType, VolkswagenFlags, VolkswagenSafetyFlags -class CarInterface(CarInterfaceBase): +class VolkswagenInterface(CarInterfaceBase): CarState = CarState CarController = CarController RadarInterface = RadarInterface + CAR = CAR + BRAND = "volkswagen" + FW_QUERY_CONFIG = FW_QUERY_CONFIG + FW_VERSIONS = FW_VERSIONS + Footnote = Footnote DRIVABLE_GEARS = (structs.CarState.GearShifter.eco, structs.CarState.GearShifter.sport, structs.CarState.GearShifter.manumatic) @staticmethod def _get_params(ret: structs.CarParams, candidate: CAR, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: - ret.brand = "volkswagen" ret.radarUnavailable = Bus.radar not in DBC[candidate] if ret.flags & VolkswagenFlags.PQ: