diff --git a/.importlinter b/.importlinter index 0a4ce2245a6ba5..79f541ccb38578 100644 --- a/.importlinter +++ b/.importlinter @@ -1,6 +1,8 @@ [importlinter] root_packages = openpilot + cereal + capnp [importlinter:contract:1] name = Forbid imports from openpilot.selfdrive.car to openpilot.system @@ -8,6 +10,8 @@ type = forbidden source_modules = openpilot.selfdrive.car forbidden_modules = + cereal + capnp openpilot.common openpilot.selfdrive.controls openpilot.selfdrive.debug @@ -44,5 +48,16 @@ ignore_imports = openpilot.selfdrive.car.tests.test_car_interfaces -> openpilot.selfdrive.pandad openpilot.selfdrive.car.tests.test_models -> openpilot.selfdrive.pandad openpilot.selfdrive.car.tests.test_car_interfaces -> openpilot.selfdrive.test.fuzzy_generation + openpilot.selfdrive.car.tests.test_models -> capnp + openpilot.selfdrive.car.tests.test_car_interfaces -> cereal + openpilot.selfdrive.car.tests.test_car_interfaces -> cereal.messaging + openpilot.selfdrive.car.tests.test_car_interfaces -> openpilot.selfdrive.test.fuzzy_generation + openpilot.selfdrive.car.tests.test_models -> cereal + openpilot.selfdrive.car.tests.test_models -> cereal.messaging + openpilot.selfdrive.car.card -> cereal + openpilot.selfdrive.car.card -> cereal.messaging openpilot.selfdrive.car.car_specific -> openpilot.selfdrive.controls.lib.events + openpilot.selfdrive.car.car_specific -> cereal + openpilot.selfdrive.car.car_specific -> cereal.messaging + openpilot.selfdrive.car.card -> capnp unmatched_ignore_imports_alerting = warn diff --git a/selfdrive/car/__init__.py b/selfdrive/car/__init__.py index 567ac7199c53d7..e6a195d7c9daa2 100644 --- a/selfdrive/car/__init__.py +++ b/selfdrive/car/__init__.py @@ -5,10 +5,8 @@ from enum import IntFlag, ReprEnum, EnumType from dataclasses import replace -import capnp - -from cereal import car from panda.python.uds import SERVICE_TYPE +from openpilot.selfdrive.car import structs from openpilot.selfdrive.car.can_definitions import CanData from openpilot.selfdrive.car.docs_definitions import CarDocs from openpilot.selfdrive.car.common.numpy_fast import clip, interp @@ -23,7 +21,7 @@ # kg of standard extra cargo to count for drive, gas, etc... STD_CARGO_KG = 136. -ButtonType = car.CarState.ButtonEvent.Type +ButtonType = structs.CarState.ButtonEvent.Type AngleRateLimit = namedtuple('AngleRateLimit', ['speed_bp', 'angle_v']) @@ -35,9 +33,9 @@ def apply_hysteresis(val: float, val_steady: float, hyst_gap: float) -> float: return val_steady -def create_button_events(cur_btn: int, prev_btn: int, buttons_dict: dict[int, capnp.lib.capnp._EnumModule], - unpressed_btn: int = 0) -> list[capnp.lib.capnp._DynamicStructBuilder]: - events: list[capnp.lib.capnp._DynamicStructBuilder] = [] +def create_button_events(cur_btn: int, prev_btn: int, buttons_dict: dict[int, structs.CarState.ButtonEvent.Type], + unpressed_btn: int = 0) -> list[structs.CarState.ButtonEvent]: + events: list[structs.CarState.ButtonEvent] = [] if cur_btn == prev_btn: return events @@ -45,8 +43,8 @@ def create_button_events(cur_btn: int, prev_btn: int, buttons_dict: dict[int, ca # Add events for button presses, multiple when a button switches without going to unpressed for pressed, btn in ((False, prev_btn), (True, cur_btn)): if btn != unpressed_btn: - events.append(car.CarState.ButtonEvent(pressed=pressed, - type=buttons_dict.get(btn, ButtonType.unknown))) + events.append(structs.CarState.ButtonEvent(pressed=pressed, + type=buttons_dict.get(btn, ButtonType.unknown))) return events @@ -183,7 +181,7 @@ def rate_limit(new_value, last_value, dw_step, up_step): def get_friction(lateral_accel_error: float, lateral_accel_deadzone: float, friction_threshold: float, - torque_params: car.CarParams.LateralTorqueTuning, friction_compensation: bool) -> float: + torque_params: structs.CarParams.LateralTorqueTuning, friction_compensation: bool) -> float: friction_interp = interp( apply_center_deadzone(lateral_accel_error, lateral_accel_deadzone), [-friction_threshold, friction_threshold], @@ -203,8 +201,8 @@ def make_tester_present_msg(addr, bus, subaddr=None, suppress_response=False): return CanData(addr, bytes(dat), bus) -def get_safety_config(safety_model, safety_param = None): - ret = car.CarParams.SafetyConfig.new_message() +def get_safety_config(safety_model: structs.CarParams.SafetyModel, safety_param: int = None) -> structs.CarParams.SafetyConfig: + ret = structs.CarParams.SafetyConfig() ret.safetyModel = safety_model if safety_param is not None: ret.safetyParam = safety_param diff --git a/selfdrive/car/body/carcontroller.py b/selfdrive/car/body/carcontroller.py index 0d6450a44d0215..941147396887e1 100644 --- a/selfdrive/car/body/carcontroller.py +++ b/selfdrive/car/body/carcontroller.py @@ -1,3 +1,4 @@ +import copy import numpy as np from numbers import Number @@ -132,7 +133,7 @@ def update(self, CC, CS, now_nanos): can_sends = [] can_sends.append(bodycan.create_control(self.packer, torque_l, torque_r)) - new_actuators = CC.actuators.as_builder() + new_actuators = copy.copy(CC.actuators) new_actuators.accel = torque_l new_actuators.steer = torque_r new_actuators.steerOutputCan = torque_r diff --git a/selfdrive/car/body/carstate.py b/selfdrive/car/body/carstate.py index 1c981a6c6e38a7..7ce0ef192093d6 100644 --- a/selfdrive/car/body/carstate.py +++ b/selfdrive/car/body/carstate.py @@ -1,12 +1,12 @@ -from cereal import car from opendbc.can.parser import CANParser +from openpilot.selfdrive.car import structs from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.body.values import DBC class CarState(CarStateBase): - def update(self, cp, *_): - ret = car.CarState.new_message() + def update(self, cp, *_) -> structs.CarState: + ret = structs.CarState() ret.wheelSpeeds.fl = cp.vl['MOTORS_DATA']['SPEED_L'] ret.wheelSpeeds.fr = cp.vl['MOTORS_DATA']['SPEED_R'] @@ -23,7 +23,7 @@ def update(self, cp, *_): ret.fuelGauge = cp.vl["BODY_DATA"]["BATT_PERCENTAGE"] / 100 # irrelevant for non-car - ret.gearShifter = car.CarState.GearShifter.drive + ret.gearShifter = structs.CarState.GearShifter.drive ret.cruiseState.enabled = True ret.cruiseState.available = True diff --git a/selfdrive/car/body/fingerprints.py b/selfdrive/car/body/fingerprints.py index ab7a5f8d7b3408..9c4b29d8279516 100644 --- a/selfdrive/car/body/fingerprints.py +++ b/selfdrive/car/body/fingerprints.py @@ -1,8 +1,8 @@ # ruff: noqa: E501 -from cereal import car +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.body.values import CAR -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu # debug ecu fw version is the git hash of the firmware diff --git a/selfdrive/car/body/interface.py b/selfdrive/car/body/interface.py index 68509aa2463f4f..9d3e1ccab60679 100644 --- a/selfdrive/car/body/interface.py +++ b/selfdrive/car/body/interface.py @@ -1,16 +1,15 @@ import math -from cereal import car -from openpilot.selfdrive.car import get_safety_config +from openpilot.selfdrive.car import get_safety_config, structs from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.body.values import SPEED_FROM_RPM class CarInterface(CarInterfaceBase): @staticmethod - def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams: ret.notCar = True ret.carName = "body" - ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.body)] + ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.body)] ret.minSteerSpeed = -math.inf ret.maxLateralAccel = math.inf # TODO: set to a reasonable value @@ -21,6 +20,6 @@ def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): ret.radarUnavailable = True ret.openpilotLongitudinalControl = True - ret.steerControlType = car.CarParams.SteerControlType.angle + ret.steerControlType = structs.CarParams.SteerControlType.angle return ret diff --git a/selfdrive/car/body/values.py b/selfdrive/car/body/values.py index a1195f7cb539c3..73d65a9f67754d 100644 --- a/selfdrive/car/body/values.py +++ b/selfdrive/car/body/values.py @@ -1,9 +1,9 @@ -from cereal import car from openpilot.selfdrive.car import CarSpecs, PlatformConfig, Platforms, dbc_dict +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.docs_definitions import CarDocs from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu SPEED_FROM_RPM = 0.008587 diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py index 823f038a9c22cd..0981689b317146 100644 --- a/selfdrive/car/car_helpers.py +++ b/selfdrive/car/car_helpers.py @@ -1,9 +1,9 @@ import os import time -from cereal import car from openpilot.selfdrive.car import carlog, gen_empty_fingerprint from openpilot.selfdrive.car.can_definitions import CanRecvCallable, CanSendCallable +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.fingerprints import eliminate_incompatible_cars, all_legacy_fingerprint_cars from openpilot.selfdrive.car.fw_versions import ObdCallback, get_fw_versions_ordered, get_present_ecus, match_fw_to_car from openpilot.selfdrive.car.interfaces import get_interface_attr @@ -82,7 +82,7 @@ def can_fingerprint(can_recv: CanRecvCallable) -> tuple[str | None, dict[int, di # **** for use live only **** def fingerprint(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback, num_pandas: int, - cached_params: type[car.CarParams] | None) -> tuple[str | None, dict, str, list, int, bool]: + cached_params: CarParams | None) -> tuple[str | None, dict, str, list[CarParams.CarFw], CarParams.FingerprintSource, bool]: fixed_fingerprint = os.environ.get('FINGERPRINT', "") skip_fw_query = os.environ.get('SKIP_FW_QUERY', False) disable_fw_cache = os.environ.get('DISABLE_FW_CACHE', False) @@ -129,17 +129,17 @@ def fingerprint(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_mu car_fingerprint, finger = can_fingerprint(can_recv) exact_match = True - source = car.CarParams.FingerprintSource.can + source = CarParams.FingerprintSource.can # If FW query returns exactly 1 candidate, use it if len(fw_candidates) == 1: car_fingerprint = list(fw_candidates)[0] - source = car.CarParams.FingerprintSource.fw + source = CarParams.FingerprintSource.fw exact_match = exact_fw_match if fixed_fingerprint: car_fingerprint = fixed_fingerprint - source = car.CarParams.FingerprintSource.fixed + source = CarParams.FingerprintSource.fixed carlog.error({"event": "fingerprinted", "car_fingerprint": str(car_fingerprint), "source": source, "fuzzy": not exact_match, "cached": cached, "fw_count": len(car_fw), "ecu_responses": list(ecu_rx_addrs), "vin_rx_addr": vin_rx_addr, @@ -148,13 +148,13 @@ def fingerprint(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_mu return car_fingerprint, finger, vin, car_fw, source, exact_match -def get_car_interface(CP): +def get_car_interface(CP: CarParams): CarInterface, CarController, CarState = interfaces[CP.carFingerprint] return CarInterface(CP, CarController, CarState) def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback, experimental_long_allowed: bool, - num_pandas: int = 1, cached_params: type[car.CarParams] | None = None): + num_pandas: int = 1, cached_params: CarParams | None = None): candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(can_recv, can_send, set_obd_multiplexing, num_pandas, cached_params) if candidate is None: @@ -162,7 +162,7 @@ def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multip candidate = "MOCK" CarInterface, _, _ = interfaces[candidate] - CP = CarInterface.get_params(candidate, fingerprints, car_fw, experimental_long_allowed, docs=False) + CP: CarParams = CarInterface.get_params(candidate, fingerprints, car_fw, experimental_long_allowed, docs=False) CP.carVin = vin CP.carFw = car_fw CP.fingerprintSource = source diff --git a/selfdrive/car/car_specific.py b/selfdrive/car/car_specific.py index e8e03320fff6f8..6f620e5e977899 100644 --- a/selfdrive/car/car_specific.py +++ b/selfdrive/car/car_specific.py @@ -1,16 +1,16 @@ from cereal import car import cereal.messaging as messaging -from openpilot.selfdrive.car import DT_CTRL -from openpilot.selfdrive.car.interfaces import MAX_CTRL_SPEED +from openpilot.selfdrive.car import DT_CTRL, structs +from openpilot.selfdrive.car.interfaces import MAX_CTRL_SPEED, CarStateBase, CarControllerBase from openpilot.selfdrive.car.volkswagen.values import CarControllerParams as VWCarControllerParams from openpilot.selfdrive.car.hyundai.interface import ENABLE_BUTTONS as HYUNDAI_ENABLE_BUTTONS from openpilot.selfdrive.controls.lib.events import Events -ButtonType = car.CarState.ButtonEvent.Type -GearShifter = car.CarState.GearShifter +ButtonType = structs.CarState.ButtonEvent.Type +GearShifter = structs.CarState.GearShifter EventName = car.CarEvent.EventName -NetworkLocation = car.CarParams.NetworkLocation +NetworkLocation = structs.CarParams.NetworkLocation # TODO: the goal is to abstract this file into the CarState struct and make events generic @@ -29,7 +29,7 @@ def update(self, CS: car.CarState): class CarSpecificEvents: - def __init__(self, CP: car.CarParams): + def __init__(self, CP: structs.CarParams): self.CP = CP self.steering_unpressed = 0 @@ -37,7 +37,7 @@ def __init__(self, CP: car.CarParams): self.no_steer_warning = False self.silent_steer_warning = True - def update(self, CS, CS_prev, CC, CC_prev): + def update(self, CS: CarStateBase, CS_prev: car.CarState, CC: CarControllerBase, CC_prev: car.CarControl): if self.CP.carName in ('body', 'mock'): events = Events() @@ -50,15 +50,15 @@ def update(self, CS, CS_prev, CC, CC_prev): elif self.CP.carName == 'nissan': events = self.create_common_events(CS.out, CS_prev, extra_gears=[GearShifter.brake]) - if CS.lkas_enabled: + if CS.lkas_enabled: # type: ignore[attr-defined] events.add(EventName.invalidLkasSetting) elif self.CP.carName == 'mazda': events = self.create_common_events(CS.out, CS_prev) - if CS.lkas_disabled: + if CS.lkas_disabled: # type: ignore[attr-defined] events.add(EventName.lkasDisabled) - elif CS.low_speed_alert: + elif CS.low_speed_alert: # type: ignore[attr-defined] events.add(EventName.belowSteerSpeed) elif self.CP.carName == 'chrysler': @@ -99,7 +99,7 @@ def update(self, CS, CS_prev, CC, CC_prev): if self.CP.openpilotLongitudinalControl: if CS.out.cruiseState.standstill and not CS.out.brakePressed: events.add(EventName.resumeRequired) - if CS.low_speed_lockout: + if CS.low_speed_lockout: # type: ignore[attr-defined] events.add(EventName.lowSpeedLockout) if CS.out.vEgo < self.CP.minEnableSpeed: events.add(EventName.belowEngageSpeed) @@ -121,7 +121,7 @@ def update(self, CS, CS_prev, CC, CC_prev): # Enabling at a standstill with brake is allowed # TODO: verify 17 Volt can enable for the first time at a stop and allow for all GMs - below_min_enable_speed = CS.out.vEgo < self.CP.minEnableSpeed or CS.moving_backward + below_min_enable_speed = CS.out.vEgo < self.CP.minEnableSpeed or CS.moving_backward # type: ignore[attr-defined] if below_min_enable_speed and not (CS.out.standstill and CS.out.brake >= 20 and self.CP.networkLocation == NetworkLocation.fwdCamera): events.add(EventName.belowEngageSpeed) @@ -149,14 +149,14 @@ def update(self, CS, CS_prev, CC, CC_prev): if CC_prev.enabled and CS.out.vEgo < self.CP.minEnableSpeed: events.add(EventName.speedTooLow) - if CC.eps_timer_soft_disable_alert: + if CC.eps_timer_soft_disable_alert: # type: ignore[attr-defined] events.add(EventName.steerTimeLimit) elif self.CP.carName == 'hyundai': # On some newer model years, the CANCEL button acts as a pause/resume button based on the PCM state # To avoid re-engaging when openpilot cancels, check user engagement intention via buttons # Main button also can trigger an engagement on these cars - allow_enable = any(btn in HYUNDAI_ENABLE_BUTTONS for btn in CS.cruise_buttons) or any(CS.main_buttons) + allow_enable = any(btn in HYUNDAI_ENABLE_BUTTONS for btn in CS.cruise_buttons) or any(CS.main_buttons) # type: ignore[attr-defined] events = self.create_common_events(CS.out, CS_prev, pcm_enable=self.CP.pcmCruise, allow_enable=allow_enable) # low speed steer alert hysteresis logic (only for cars with steer cut off above 10 m/s) @@ -172,8 +172,8 @@ def update(self, CS, CS_prev, CC, CC_prev): return events - def create_common_events(self, CS, CS_prev, extra_gears=None, pcm_enable=True, allow_enable=True, - enable_buttons=(ButtonType.accelCruise, ButtonType.decelCruise)): + def create_common_events(self, CS: structs.CarState, CS_prev: car.CarState, extra_gears=None, pcm_enable=True, + allow_enable=True, enable_buttons=(ButtonType.accelCruise, ButtonType.decelCruise)): events = Events() if CS.doorOpen: diff --git a/selfdrive/car/card.py b/selfdrive/car/card.py index aab50701110f48..7aaef6e94ac0ab 100755 --- a/selfdrive/car/card.py +++ b/selfdrive/car/card.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 +import capnp import os import time +from typing import Any import cereal.messaging as messaging @@ -13,7 +15,7 @@ from openpilot.common.swaglog import cloudlog, ForwardingHandler from openpilot.selfdrive.pandad import can_capnp_to_list, can_list_to_can_capnp -from openpilot.selfdrive.car import DT_CTRL, carlog +from openpilot.selfdrive.car import DT_CTRL, carlog, structs from openpilot.selfdrive.car.can_definitions import CanData, CanRecvCallable, CanSendCallable from openpilot.selfdrive.car.car_specific import CarSpecificEvents, MockCarState from openpilot.selfdrive.car.fw_versions import ObdCallback @@ -22,6 +24,7 @@ from openpilot.selfdrive.controls.lib.events import Events REPLAY = "REPLAY" in os.environ +_FIELDS = '__dataclass_fields__' # copy of dataclasses._FIELDS EventName = car.CarEvent.EventName @@ -58,8 +61,74 @@ def can_send(msgs: list[CanData]) -> None: return can_recv, can_send +def is_dataclass(obj): + """Similar to dataclasses.is_dataclass without instance type check checking""" + return hasattr(obj, _FIELDS) + + +def asdictref(obj) -> dict[str, Any]: + """ + Similar to dataclasses.asdict without recursive type checking and copy.deepcopy + Note that the resulting dict will contain references to the original struct as a result + """ + if not is_dataclass(obj): + raise TypeError("asdictref() should be called on dataclass instances") + + def _asdictref_inner(obj) -> dict[str, Any] | Any: + if is_dataclass(obj): + ret = {} + for field in getattr(obj, _FIELDS): # similar to dataclasses.fields() + ret[field] = _asdictref_inner(getattr(obj, field)) + return ret + elif isinstance(obj, (tuple, list)): + return type(obj)(_asdictref_inner(v) for v in obj) + else: + return obj + + return _asdictref_inner(obj) + + +def convert_to_capnp(struct: structs.CarParams | structs.CarState | structs.CarControl.Actuators) -> capnp.lib.capnp._DynamicStructBuilder: + struct_dict = asdictref(struct) + + if isinstance(struct, structs.CarParams): + del struct_dict['lateralTuning'] + struct_capnp = car.CarParams.new_message(**struct_dict) + + # this is the only union, special handling + which = struct.lateralTuning.which() + struct_capnp.lateralTuning.init(which) + lateralTuning_dict = asdictref(getattr(struct.lateralTuning, which)) + setattr(struct_capnp.lateralTuning, which, lateralTuning_dict) + elif isinstance(struct, structs.CarState): + struct_capnp = car.CarState.new_message(**struct_dict) + elif isinstance(struct, structs.CarControl.Actuators): + struct_capnp = car.CarControl.Actuators.new_message(**struct_dict) + else: + raise ValueError(f"Unsupported struct type: {type(struct)}") + + return struct_capnp + + +def convert_carControl(struct: capnp.lib.capnp._DynamicStructReader) -> structs.CarControl: + # TODO: recursively handle any car struct as needed + def remove_deprecated(s: dict) -> dict: + return {k: v for k, v in s.items() if not k.endswith('DEPRECATED')} + + struct_dict = struct.to_dict() + struct_dataclass = structs.CarControl(**remove_deprecated({k: v for k, v in struct_dict.items() if not isinstance(k, dict)})) + + struct_dataclass.actuators = structs.CarControl.Actuators(**remove_deprecated(struct_dict.get('actuators', {}))) + struct_dataclass.cruiseControl = structs.CarControl.CruiseControl(**remove_deprecated(struct_dict.get('cruiseControl', {}))) + struct_dataclass.hudControl = structs.CarControl.HUDControl(**remove_deprecated(struct_dict.get('hudControl', {}))) + + return struct_dataclass + + class Car: CI: CarInterfaceBase + CP: structs.CarParams + CP_capnp: car.CarParams def __init__(self, CI=None) -> None: self.can_sock = messaging.sub_sock('can', timeout=20) @@ -72,7 +141,7 @@ def __init__(self, CI=None) -> None: self.CS_prev = car.CarState.new_message() self.initialized_prev = False - self.last_actuators_output = car.CarControl.Actuators.new_message() + self.last_actuators_output = structs.CarControl.Actuators() self.params = Params() @@ -93,7 +162,7 @@ def __init__(self, CI=None) -> None: cached_params_raw = self.params.get("CarParamsCache") if cached_params_raw is not None: with car.CarParams.from_bytes(cached_params_raw) as _cached_params: - cached_params = _cached_params + cached_params = structs.CarParams(carName=_cached_params.carName, carFw=_cached_params.carFw, carVin=_cached_params.carVin) self.CI = get_car(*self.can_callbacks, obd_callback(self.params), experimental_long_allowed, num_pandas, cached_params) self.CP = self.CI.CP @@ -115,8 +184,8 @@ def __init__(self, CI=None) -> None: self.CP.passive = not controller_available or self.CP.dashcamOnly if self.CP.passive: - safety_config = car.CarParams.SafetyConfig.new_message() - safety_config.safetyModel = car.CarParams.SafetyModel.noOutput + safety_config = structs.CarParams.SafetyConfig() + safety_config.safetyModel = structs.CarParams.SafetyModel.noOutput self.CP.safetyConfigs = [safety_config] # Write previous route's CarParams @@ -125,7 +194,9 @@ def __init__(self, CI=None) -> None: self.params.put("CarParamsPrevRoute", prev_cp) # Write CarParams for controls and radard - cp_bytes = self.CP.to_bytes() + # convert to pycapnp representation for caching and logging + self.CP_capnp = convert_to_capnp(self.CP) + cp_bytes = self.CP_capnp.to_bytes() self.params.put("CarParams", cp_bytes) self.params.put_nonblocking("CarParamsCache", cp_bytes) self.params.put_nonblocking("CarParamsPersistent", cp_bytes) @@ -143,7 +214,7 @@ def state_update(self) -> car.CarState: # Update carState from CAN can_strs = messaging.drain_sock_raw(self.can_sock, wait_for_one=True) - CS = self.CI.update(can_capnp_to_list(can_strs)) + CS = convert_to_capnp(self.CI.update(can_capnp_to_list(can_strs))) if self.CP.carName == 'mock': CS = self.mock_carstate.update(CS) @@ -189,13 +260,13 @@ def state_publish(self, CS: car.CarState): if self.sm.frame % int(50. / DT_CTRL) == 0: cp_send = messaging.new_message('carParams') cp_send.valid = True - cp_send.carParams = self.CP + cp_send.carParams = self.CP_capnp self.pm.send('carParams', cp_send) # publish new carOutput co_send = messaging.new_message('carOutput') co_send.valid = self.sm.all_checks(['carControl']) - co_send.carOutput.actuatorsOutput = self.last_actuators_output + co_send.carOutput.actuatorsOutput = convert_to_capnp(self.last_actuators_output) self.pm.send('carOutput', co_send) # kick off controlsd step while we actuate the latest carControl packet @@ -219,7 +290,7 @@ def controls_update(self, CS: car.CarState, CC: car.CarControl): if self.sm.all_alive(['carControl']): # send car controls over can now_nanos = self.can_log_mono_time if REPLAY else int(time.monotonic() * 1e9) - self.last_actuators_output, can_sends = self.CI.apply(CC, now_nanos) + self.last_actuators_output, can_sends = self.CI.apply(convert_carControl(CC), now_nanos) self.pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=CS.canValid)) self.CC_prev = CC diff --git a/selfdrive/car/chrysler/carcontroller.py b/selfdrive/car/chrysler/carcontroller.py index c194488de967c3..b9b1a9f4cb2acd 100644 --- a/selfdrive/car/chrysler/carcontroller.py +++ b/selfdrive/car/chrysler/carcontroller.py @@ -1,3 +1,4 @@ +import copy from opendbc.can.packer import CANPacker from openpilot.selfdrive.car import DT_CTRL, apply_meas_steer_torque_limits from openpilot.selfdrive.car.chrysler import chryslercan @@ -76,7 +77,7 @@ def update(self, CC, CS, now_nanos): self.frame += 1 - new_actuators = CC.actuators.as_builder() + new_actuators = copy.copy(CC.actuators) new_actuators.steer = self.apply_steer_last / self.params.STEER_MAX new_actuators.steerOutputCan = self.apply_steer_last diff --git a/selfdrive/car/chrysler/carstate.py b/selfdrive/car/chrysler/carstate.py index 216e6f789141fd..f7ebf82f1aa8e6 100644 --- a/selfdrive/car/chrysler/carstate.py +++ b/selfdrive/car/chrysler/carstate.py @@ -1,12 +1,11 @@ -from cereal import car from opendbc.can.parser import CANParser from opendbc.can.can_define import CANDefine -from openpilot.selfdrive.car import create_button_events +from openpilot.selfdrive.car import create_button_events, structs from openpilot.selfdrive.car.chrysler.values import DBC, STEER_THRESHOLD, RAM_CARS from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.interfaces import CarStateBase -ButtonType = car.CarState.ButtonEvent.Type +ButtonType = structs.CarState.ButtonEvent.Type class CarState(CarStateBase): @@ -26,9 +25,9 @@ def __init__(self, CP): self.distance_button = 0 - def update(self, cp, cp_cam, *_): + def update(self, cp, cp_cam, *_) -> structs.CarState: - ret = car.CarState.new_message() + ret = structs.CarState() prev_distance_button = self.distance_button self.distance_button = cp.vl["CRUISE_BUTTONS"]["ACC_Distance_Dec"] diff --git a/selfdrive/car/chrysler/chryslercan.py b/selfdrive/car/chrysler/chryslercan.py index 96439f35d8cf2a..9fefeef8fb7ce0 100644 --- a/selfdrive/car/chrysler/chryslercan.py +++ b/selfdrive/car/chrysler/chryslercan.py @@ -1,8 +1,8 @@ -from cereal import car +from openpilot.selfdrive.car import structs from openpilot.selfdrive.car.chrysler.values import RAM_CARS -GearShifter = car.CarState.GearShifter -VisualAlert = car.CarControl.HUDControl.VisualAlert +GearShifter = structs.CarState.GearShifter +VisualAlert = structs.CarControl.HUDControl.VisualAlert def create_lkas_hud(packer, CP, lkas_active, hud_alert, hud_count, car_model, auto_high_beam): # LKAS_HUD - Controls what lane-keeping icon is displayed diff --git a/selfdrive/car/chrysler/fingerprints.py b/selfdrive/car/chrysler/fingerprints.py index 1f453d8f50d4ea..aac12c114941ff 100644 --- a/selfdrive/car/chrysler/fingerprints.py +++ b/selfdrive/car/chrysler/fingerprints.py @@ -1,7 +1,7 @@ -from cereal import car +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.chrysler.values import CAR -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu FW_VERSIONS = { CAR.CHRYSLER_PACIFICA_2018: { diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index 21e752889e4bd5..9092e92313d4d9 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -1,14 +1,13 @@ #!/usr/bin/env python3 -from cereal import car from panda import Panda -from openpilot.selfdrive.car import get_safety_config +from openpilot.selfdrive.car import get_safety_config, structs from openpilot.selfdrive.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags from openpilot.selfdrive.car.interfaces import CarInterfaceBase class CarInterface(CarInterfaceBase): @staticmethod - def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams: ret.carName = "chrysler" ret.dashcamOnly = candidate in RAM_HD @@ -18,7 +17,7 @@ def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): ret.steerLimitTimer = 0.4 # safety config - ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.chrysler)] + ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.chrysler)] if candidate in RAM_HD: ret.safetyConfigs[0].safetyParam |= Panda.FLAG_CHRYSLER_RAM_HD elif candidate in RAM_DT: diff --git a/selfdrive/car/chrysler/radar_interface.py b/selfdrive/car/chrysler/radar_interface.py index f1d863d1e15db2..c386274c5c89b3 100755 --- a/selfdrive/car/chrysler/radar_interface.py +++ b/selfdrive/car/chrysler/radar_interface.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 from opendbc.can.parser import CANParser -from cereal import car +from openpilot.selfdrive.car import structs from openpilot.selfdrive.car.interfaces import RadarInterfaceBase from openpilot.selfdrive.car.chrysler.values import DBC @@ -53,7 +53,7 @@ def update(self, can_strings): if self.trigger_msg not in self.updated_messages: return None - ret = car.RadarData.new_message() + ret = structs.RadarData() errors = [] if not self.rcp.can_valid: errors.append("canError") @@ -64,7 +64,7 @@ def update(self, can_strings): trackId = _address_to_track(ii) if trackId not in self.pts: - self.pts[trackId] = car.RadarData.RadarPoint.new_message() + self.pts[trackId] = structs.RadarData.RadarPoint() self.pts[trackId].trackId = trackId self.pts[trackId].aRel = float('nan') self.pts[trackId].yvRel = float('nan') diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index c44c647fd4f667..e568c8af1d54e0 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -1,13 +1,13 @@ from enum import IntFlag from dataclasses import dataclass, field -from cereal import car from panda.python import uds from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.docs_definitions import CarHarness, CarDocs, CarParts from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16 -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu class ChryslerFlags(IntFlag): diff --git a/selfdrive/car/docs.py b/selfdrive/car/docs.py index 17f8947522a4e5..a9e9c7ee83eeda 100644 --- a/selfdrive/car/docs.py +++ b/selfdrive/car/docs.py @@ -3,8 +3,8 @@ from enum import Enum from natsort import natsorted -from cereal import car from openpilot.selfdrive.car import gen_empty_fingerprint +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.docs_definitions import CarDocs, Column, CommonFootnote, PartType from openpilot.selfdrive.car.car_helpers import interfaces, get_interface_attr from openpilot.selfdrive.car.values import PLATFORMS @@ -24,7 +24,7 @@ def get_all_car_docs() -> list[CarDocs]: car_docs = platform.config.car_docs # If available, uses experimental longitudinal limits for the docs CP = interfaces[model][0].get_params(platform, fingerprint=gen_empty_fingerprint(), - car_fw=[car.CarParams.CarFw(ecu="unknown")], experimental_long=True, docs=True) + car_fw=[CarParams.CarFw(ecu=CarParams.Ecu.unknown)], experimental_long=True, docs=True) if CP.dashcamOnly or not len(car_docs): continue diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index f039fea9ac3ccc..6df109facfdd11 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -4,8 +4,8 @@ from dataclasses import dataclass, field from enum import Enum -from cereal import car from openpilot.selfdrive.car.conversions import Conversions as CV +from openpilot.selfdrive.car.structs import CarParams GOOD_TORQUE_THRESHOLD = 1.0 # m/s^2 MODEL_YEARS_RE = r"(?<= )((\d{4}-\d{2})|(\d{4}))(,|$)" @@ -248,7 +248,7 @@ def __post_init__(self): self.make, self.model, self.years = split_name(self.name) self.year_list = get_year_list(self.years) - def init(self, CP: car.CarParams, all_footnotes: dict[Enum, int]): + def init(self, CP: CarParams, all_footnotes: dict[Enum, int]): self.car_name = CP.carName self.car_fingerprint = CP.carFingerprint @@ -316,7 +316,7 @@ def display_func(parts): return self - def init_make(self, CP: car.CarParams): + def init_make(self, CP: CarParams): """CarDocs subclasses can add make-specific logic for harness selection, footnotes, etc.""" def get_detail_sentence(self, CP): diff --git a/selfdrive/car/ford/carcontroller.py b/selfdrive/car/ford/carcontroller.py index 1eaccf7a3e6a2e..e4e7bc50407b59 100644 --- a/selfdrive/car/ford/carcontroller.py +++ b/selfdrive/car/ford/carcontroller.py @@ -1,13 +1,13 @@ -from cereal import car +import copy from opendbc.can.packer import CANPacker -from openpilot.selfdrive.car import apply_std_steer_angle_limits +from openpilot.selfdrive.car import apply_std_steer_angle_limits, structs from openpilot.selfdrive.car.ford import fordcan from openpilot.selfdrive.car.ford.values import CarControllerParams, FordFlags from openpilot.selfdrive.car.common.numpy_fast import clip from openpilot.selfdrive.car.interfaces import CarControllerBase, V_CRUISE_MAX -LongCtrlState = car.CarControl.Actuators.LongControlState -VisualAlert = car.CarControl.HUDControl.VisualAlert +LongCtrlState = structs.CarControl.Actuators.LongControlState +VisualAlert = structs.CarControl.HUDControl.VisualAlert def apply_ford_curvature_limits(apply_curvature, apply_curvature_last, current_curvature, v_ego_raw): @@ -111,7 +111,7 @@ def update(self, CC, CS, now_nanos): self.steer_alert_last = steer_alert self.lead_distance_bars_last = hud_control.leadDistanceBars - new_actuators = actuators.as_builder() + new_actuators = copy.copy(actuators) new_actuators.curvature = self.apply_curvature_last self.frame += 1 diff --git a/selfdrive/car/ford/carstate.py b/selfdrive/car/ford/carstate.py index 6d1e4ae5dcd561..813af76949b1ab 100644 --- a/selfdrive/car/ford/carstate.py +++ b/selfdrive/car/ford/carstate.py @@ -1,15 +1,14 @@ -from cereal import car from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser -from openpilot.selfdrive.car import create_button_events +from openpilot.selfdrive.car import create_button_events, structs from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.ford.fordcan import CanBus from openpilot.selfdrive.car.ford.values import DBC, CarControllerParams, FordFlags from openpilot.selfdrive.car.interfaces import CarStateBase -ButtonType = car.CarState.ButtonEvent.Type -GearShifter = car.CarState.GearShifter -TransmissionType = car.CarParams.TransmissionType +ButtonType = structs.CarState.ButtonEvent.Type +GearShifter = structs.CarState.GearShifter +TransmissionType = structs.CarParams.TransmissionType class CarState(CarStateBase): @@ -21,8 +20,8 @@ def __init__(self, CP): self.distance_button = 0 - def update(self, cp, cp_cam, *_): - ret = car.CarState.new_message() + def update(self, cp, cp_cam, *_) -> structs.CarState: + ret = structs.CarState() # Occasionally on startup, the ABS module recalibrates the steering pinion offset, so we need to block engagement # The vehicle usually recovers out of this state within a minute of normal driving diff --git a/selfdrive/car/ford/fingerprints.py b/selfdrive/car/ford/fingerprints.py index 2201072fa3a29d..a9e4ed9a5e2f2a 100644 --- a/selfdrive/car/ford/fingerprints.py +++ b/selfdrive/car/ford/fingerprints.py @@ -1,7 +1,7 @@ -from cereal import car +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.ford.values import CAR -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu FW_VERSIONS = { CAR.FORD_BRONCO_SPORT_MK1: { diff --git a/selfdrive/car/ford/fordcan.py b/selfdrive/car/ford/fordcan.py index 5bb3d0570ff5de..b2cbe945c3172a 100644 --- a/selfdrive/car/ford/fordcan.py +++ b/selfdrive/car/ford/fordcan.py @@ -1,7 +1,6 @@ -from cereal import car -from openpilot.selfdrive.car import CanBusBase +from openpilot.selfdrive.car import CanBusBase, structs -HUDControl = car.CarControl.HUDControl +HUDControl = structs.CarControl.HUDControl class CanBus(CanBusBase): diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 4021f583c17bf0..17f136b1be5c38 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -1,29 +1,28 @@ -from cereal import car from panda import Panda -from openpilot.selfdrive.car import get_safety_config +from openpilot.selfdrive.car import get_safety_config, structs from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.ford.fordcan import CanBus from openpilot.selfdrive.car.ford.values import Ecu, FordFlags from openpilot.selfdrive.car.interfaces import CarInterfaceBase -TransmissionType = car.CarParams.TransmissionType +TransmissionType = structs.CarParams.TransmissionType class CarInterface(CarInterfaceBase): @staticmethod - def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams: ret.carName = "ford" ret.dashcamOnly = bool(ret.flags & FordFlags.CANFD) ret.radarUnavailable = True - ret.steerControlType = car.CarParams.SteerControlType.angle + ret.steerControlType = structs.CarParams.SteerControlType.angle ret.steerActuatorDelay = 0.2 ret.steerLimitTimer = 1.0 CAN = CanBus(fingerprint=fingerprint) - cfgs = [get_safety_config(car.CarParams.SafetyModel.ford)] + cfgs = [get_safety_config(structs.CarParams.SafetyModel.ford)] if CAN.main >= 4: - cfgs.insert(0, get_safety_config(car.CarParams.SafetyModel.noOutput)) + cfgs.insert(0, get_safety_config(structs.CarParams.SafetyModel.noOutput)) ret.safetyConfigs = cfgs ret.experimentalLongitudinalAvailable = True diff --git a/selfdrive/car/ford/radar_interface.py b/selfdrive/car/ford/radar_interface.py index f405373661925f..a4e80380e734f8 100644 --- a/selfdrive/car/ford/radar_interface.py +++ b/selfdrive/car/ford/radar_interface.py @@ -1,6 +1,6 @@ from math import cos, sin -from cereal import car from opendbc.can.parser import CANParser +from openpilot.selfdrive.car import structs from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.ford.fordcan import CanBus from openpilot.selfdrive.car.ford.values import DBC, RADAR @@ -58,7 +58,7 @@ def update(self, can_strings): if self.trigger_msg not in self.updated_messages: return None - ret = car.RadarData.new_message() + ret = structs.RadarData() errors = [] if not self.rcp.can_valid: errors.append("canError") @@ -89,7 +89,7 @@ def _update_delphi_esr(self): # radar point only valid if there have been enough valid measurements if self.valid_cnt[ii] > 0: if ii not in self.pts: - self.pts[ii] = car.RadarData.RadarPoint.new_message() + self.pts[ii] = structs.RadarData.RadarPoint() self.pts[ii].trackId = self.track_id self.track_id += 1 self.pts[ii].dRel = cpt['X_Rel'] # from front of car @@ -112,7 +112,7 @@ def _update_delphi_mrr(self): i = (ii - 1) * 4 + scanIndex if i not in self.pts: - self.pts[i] = car.RadarData.RadarPoint.new_message() + self.pts[i] = structs.RadarData.RadarPoint() self.pts[i].trackId = self.track_id self.pts[i].aRel = float('nan') self.pts[i].yvRel = float('nan') diff --git a/selfdrive/car/ford/tests/print_platform_codes.py b/selfdrive/car/ford/tests/print_platform_codes.py index 670199980a6838..1384985779bc13 100755 --- a/selfdrive/car/ford/tests/print_platform_codes.py +++ b/selfdrive/car/ford/tests/print_platform_codes.py @@ -1,30 +1,28 @@ #!/usr/bin/env python3 from collections import defaultdict -from cereal import car +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.ford.values import get_platform_codes from openpilot.selfdrive.car.ford.fingerprints import FW_VERSIONS -Ecu = car.CarParams.Ecu -ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()} - +Ecu = CarParams.Ecu if __name__ == "__main__": cars_for_code: defaultdict = defaultdict(lambda: defaultdict(set)) for car_model, ecus in FW_VERSIONS.items(): print(car_model) - for ecu in sorted(ecus, key=lambda x: int(x[0])): + for ecu in sorted(ecus): platform_codes = get_platform_codes(ecus[ecu]) for code in platform_codes: cars_for_code[ecu][code].add(car_model) - print(f' (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])}, {ecu[2]}):') + print(f' (Ecu.{ecu[0]}, {hex(ecu[1])}, {ecu[2]}):') print(f' Codes: {sorted(platform_codes)}') print() print('\nCar models vs. platform codes:') for ecu, codes in cars_for_code.items(): - print(f' (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])}, {ecu[2]}):') + print(f' (Ecu.{ecu[0]}, {hex(ecu[1])}, {ecu[2]}):') for code, cars in codes.items(): print(f' {code!r}: {sorted(map(str, cars))}') diff --git a/selfdrive/car/ford/tests/test_ford.py b/selfdrive/car/ford/tests/test_ford.py index b1a19017d401b0..4d3a9a53bc520c 100644 --- a/selfdrive/car/ford/tests/test_ford.py +++ b/selfdrive/car/ford/tests/test_ford.py @@ -1,16 +1,15 @@ import random from collections.abc import Iterable -import capnp from hypothesis import settings, given, strategies as st from parameterized import parameterized -from cereal import car +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.fw_versions import build_fw_dict from openpilot.selfdrive.car.ford.values import CAR, FW_QUERY_CONFIG, FW_PATTERN, get_platform_codes from openpilot.selfdrive.car.ford.fingerprints import FW_VERSIONS -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu ECU_ADDRESSES = { @@ -49,7 +48,7 @@ def test_fw_query_config(self): assert subaddr is None, "Unexpected ECU subaddress" @parameterized.expand(FW_VERSIONS.items()) - def test_fw_versions(self, car_model: str, fw_versions: dict[tuple[capnp.lib.capnp._EnumModule, int, int | None], Iterable[bytes]]): + def test_fw_versions(self, car_model: str, fw_versions: dict[tuple[Ecu, int, int | None], Iterable[bytes]]): for (ecu, addr, subaddr), fws in fw_versions.items(): assert ecu in ECU_PART_NUMBER, "Unexpected ECU" assert addr == ECU_ADDRESSES[ecu], "ECU address mismatch" @@ -93,10 +92,10 @@ def test_fuzzy_match(self): for ecu, fw_versions in fw_by_addr.items(): ecu_name, addr, sub_addr = ecu fw = random.choice(fw_versions) - car_fw.append({"ecu": ecu_name, "fwVersion": fw, "address": addr, - "subAddress": 0 if sub_addr is None else sub_addr}) + car_fw.append(CarParams.CarFw(ecu=ecu_name, fwVersion=fw, address=addr, + subAddress=0 if sub_addr is None else sub_addr)) - CP = car.CarParams.new_message(carFw=car_fw) + CP = CarParams(carFw=car_fw) matches = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(build_fw_dict(CP.carFw), CP.carVin, FW_VERSIONS) assert matches == {platform} diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index b1868bfa9bb97d..5b415a44ec68ce 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -4,13 +4,13 @@ from enum import Enum, IntFlag import panda.python.uds as uds -from cereal import car from openpilot.selfdrive.car import AngleRateLimit, CarSpecs, dbc_dict, DbcDict, PlatformConfig, Platforms +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column, \ Device from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, LiveFwVersions, OfflineFwVersions, Request, StdQueries, p16 -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu class CarControllerParams: @@ -65,7 +65,7 @@ class FordCarDocs(CarDocs): hybrid: bool = False plug_in_hybrid: bool = False - def init_make(self, CP: car.CarParams): + def init_make(self, CP: CarParams): harness = CarHarness.ford_q4 if CP.flags & FordFlags.CANFD else CarHarness.ford_q3 if CP.carFingerprint in (CAR.FORD_BRONCO_SPORT_MK1, CAR.FORD_MAVERICK_MK1, CAR.FORD_F_150_MK14, CAR.FORD_F_150_LIGHTNING_MK1): self.car_parts = CarParts([Device.threex_angled_mount, harness]) diff --git a/selfdrive/car/fw_query_definitions.py b/selfdrive/car/fw_query_definitions.py index e5020414625240..a39cd889ab7d78 100644 --- a/selfdrive/car/fw_query_definitions.py +++ b/selfdrive/car/fw_query_definitions.py @@ -1,4 +1,3 @@ -import capnp import copy from dataclasses import dataclass, field import struct @@ -6,9 +5,11 @@ import panda.python.uds as uds +from openpilot.selfdrive.car.structs import CarParams + AddrType = tuple[int, int | None] EcuAddrBusType = tuple[int, int | None, int] -EcuAddrSubAddr = tuple[int, int, int | None] +EcuAddrSubAddr = tuple[CarParams.Ecu, int, int | None] LiveFwVersions = dict[AddrType, set[bytes]] OfflineFwVersions = dict[str, dict[EcuAddrSubAddr, list[bytes]]] @@ -77,7 +78,7 @@ class StdQueries: class Request: request: list[bytes] response: list[bytes] - whitelist_ecus: list[int] = field(default_factory=list) + whitelist_ecus: list[CarParams.Ecu] = field(default_factory=list) rx_offset: int = 0x8 bus: int = 1 # Whether this query should be run on the first auxiliary panda (CAN FD cars for example) @@ -93,9 +94,9 @@ class FwQueryConfig: requests: list[Request] # TODO: make this automatic and remove hardcoded lists, or do fingerprinting with ecus # Overrides and removes from essential ecus for specific models and ecus (exact matching) - non_essential_ecus: dict[capnp.lib.capnp._EnumModule, list[str]] = field(default_factory=dict) + non_essential_ecus: dict[CarParams.Ecu, list[str]] = field(default_factory=dict) # Ecus added for data collection, not to be fingerprinted on - extra_ecus: list[tuple[capnp.lib.capnp._EnumModule, int, int | None]] = field(default_factory=list) + extra_ecus: list[tuple[CarParams.Ecu, int, int | None]] = field(default_factory=list) # Function a brand can implement to provide better fuzzy matching. Takes in FW versions and VIN, # returns set of candidates. Only will match if one candidate is returned match_fw_to_car_fuzzy: Callable[[LiveFwVersions, str, OfflineFwVersions], set[str]] | None = None diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 47c74d999818a6..71278505c619f5 100644 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -3,19 +3,18 @@ from typing import Protocol, TypeVar from tqdm import tqdm -import capnp import panda.python.uds as uds -from cereal import car from openpilot.selfdrive.car import carlog +from openpilot.selfdrive.car.can_definitions import CanRecvCallable, CanSendCallable +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.ecu_addrs import get_ecu_addrs from openpilot.selfdrive.car.fingerprints import FW_VERSIONS -from openpilot.selfdrive.car.can_definitions import CanRecvCallable, CanSendCallable from openpilot.selfdrive.car.fw_query_definitions import AddrType, EcuAddrBusType, FwQueryConfig, LiveFwVersions, OfflineFwVersions from openpilot.selfdrive.car.interfaces import get_interface_attr from openpilot.selfdrive.car.isotp_parallel_query import IsoTpParallelQuery -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu ESSENTIAL_ECUS = [Ecu.engine, Ecu.eps, Ecu.abs, Ecu.fwdRadar, Ecu.fwdCamera, Ecu.vsa] FUZZY_EXCLUDE_ECUS = [Ecu.fwdCamera, Ecu.fwdRadar, Ecu.eps, Ecu.debug] @@ -39,7 +38,7 @@ def is_brand(brand: str, filter_brand: str | None) -> bool: return filter_brand is None or brand == filter_brand -def build_fw_dict(fw_versions: list[capnp.lib.capnp._DynamicStructBuilder], filter_brand: str = None) -> dict[AddrType, set[bytes]]: +def build_fw_dict(fw_versions: list[CarParams.CarFw], filter_brand: str = None) -> dict[AddrType, set[bytes]]: fw_versions_dict: defaultdict[AddrType, set[bytes]] = defaultdict(set) for fw in fw_versions: if is_brand(fw.brand, filter_brand) and not fw.logging: @@ -144,8 +143,8 @@ def match_fw_to_car_exact(live_fw_versions: LiveFwVersions, match_brand: str = N return set(candidates.keys()) - invalid -def match_fw_to_car(fw_versions: list[capnp.lib.capnp._DynamicStructBuilder], vin: str, - allow_exact: bool = True, allow_fuzzy: bool = True, log: bool = True) -> tuple[bool, set[str]]: +def match_fw_to_car(fw_versions: list[CarParams.CarFw], vin: str, allow_exact: bool = True, + allow_fuzzy: bool = True, log: bool = True) -> tuple[bool, set[str]]: # Try exact matching first exact_matches: list[tuple[bool, MatchFwToCar]] = [] if allow_exact: @@ -229,7 +228,7 @@ def get_brand_ecu_matches(ecu_rx_addrs: set[EcuAddrBusType]) -> dict[str, set[Ad def get_fw_versions_ordered(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback, vin: str, ecu_rx_addrs: set[EcuAddrBusType], timeout: float = 0.1, num_pandas: int = 1, debug: bool = False, - progress: bool = False) -> list[capnp.lib.capnp._DynamicStructBuilder]: + progress: bool = False) -> list[CarParams.CarFw]: """Queries for FW versions ordering brands by likelihood, breaks when exact match is found""" all_car_fw = [] @@ -254,7 +253,7 @@ def get_fw_versions_ordered(can_recv: CanRecvCallable, can_send: CanSendCallable def get_fw_versions(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback, query_brand: str = None, extra: OfflineFwVersions = None, timeout: float = 0.1, num_pandas: int = 1, debug: bool = False, - progress: bool = False) -> list[capnp.lib.capnp._DynamicStructBuilder]: + progress: bool = False) -> list[CarParams.CarFw]: versions = VERSIONS.copy() if query_brand is not None: @@ -306,7 +305,7 @@ def get_fw_versions(can_recv: CanRecvCallable, can_send: CanSendCallable, set_ob if query_addrs: query = IsoTpParallelQuery(can_send, can_recv, r.bus, query_addrs, r.request, r.response, r.rx_offset, debug=debug) for (tx_addr, sub_addr), version in query.get_data(timeout).items(): - f = car.CarParams.CarFw.new_message() + f = CarParams.CarFw() f.ecu = ecu_types.get((brand, tx_addr, sub_addr), Ecu.unknown) f.fwVersion = version diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index 60d472620f130f..e562ef6e83f795 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -1,15 +1,15 @@ -from cereal import car +import copy from opendbc.can.packer import CANPacker -from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits -from openpilot.selfdrive.car.conversions import Conversions as CV +from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits, structs from openpilot.selfdrive.car.gm import gmcan +from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.gm.values import DBC, CanBus, CarControllerParams, CruiseButtons from openpilot.selfdrive.car.common.numpy_fast import interp from openpilot.selfdrive.car.interfaces import CarControllerBase -VisualAlert = car.CarControl.HUDControl.VisualAlert -NetworkLocation = car.CarParams.NetworkLocation -LongCtrlState = car.CarControl.Actuators.LongControlState +VisualAlert = structs.CarControl.HUDControl.VisualAlert +NetworkLocation = structs.CarParams.NetworkLocation +LongCtrlState = structs.CarControl.Actuators.LongControlState # Camera cancels up to 0.1s after brake is pressed, ECM allows 0.5s CAMERA_CANCEL_DELAY_FRAMES = 10 @@ -153,7 +153,7 @@ def update(self, CC, CS, now_nanos): if self.frame % 10 == 0: can_sends.append(gmcan.create_pscm_status(self.packer_pt, CanBus.CAMERA, CS.pscm_status)) - new_actuators = actuators.as_builder() + new_actuators = copy.copy(actuators) new_actuators.steer = self.apply_steer_last / self.params.STEER_MAX new_actuators.steerOutputCan = self.apply_steer_last new_actuators.gas = self.apply_gas diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index d6e729ef4af460..99823c9e7e3e65 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -1,16 +1,15 @@ import copy -from cereal import car from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser -from openpilot.selfdrive.car import create_button_events +from openpilot.selfdrive.car import create_button_events, structs from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.common.numpy_fast import mean from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.gm.values import DBC, AccState, CanBus, CruiseButtons, STEER_THRESHOLD -ButtonType = car.CarState.ButtonEvent.Type -TransmissionType = car.CarParams.TransmissionType -NetworkLocation = car.CarParams.NetworkLocation +ButtonType = structs.CarState.ButtonEvent.Type +TransmissionType = structs.CarParams.TransmissionType +NetworkLocation = structs.CarParams.NetworkLocation STANDSTILL_THRESHOLD = 10 * 0.0311 * CV.KPH_TO_MS @@ -34,8 +33,8 @@ def __init__(self, CP): self.distance_button = 0 - def update(self, pt_cp, cam_cp, _, __, loopback_cp): - ret = car.CarState.new_message() + def update(self, pt_cp, cam_cp, _, __, loopback_cp) -> structs.CarState: + ret = structs.CarState() prev_cruise_buttons = self.cruise_buttons prev_distance_button = self.distance_button diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index e6985b6144f521..4f47dbde2c3226 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -1,18 +1,17 @@ #!/usr/bin/env python3 import os -from cereal import car from math import fabs, exp from panda import Panda -from openpilot.selfdrive.car import get_safety_config, get_friction +from openpilot.selfdrive.car import get_safety_config, get_friction, structs from openpilot.selfdrive.car.common.basedir import BASEDIR from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.gm.radar_interface import RADAR_HEADER_MSG from openpilot.selfdrive.car.gm.values import CAR, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, CanBus from openpilot.selfdrive.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, FRICTION_THRESHOLD, LatControlInputs, NanoFFModel -TransmissionType = car.CarParams.TransmissionType -NetworkLocation = car.CarParams.NetworkLocation +TransmissionType = structs.CarParams.TransmissionType +NetworkLocation = structs.CarParams.NetworkLocation NON_LINEAR_TORQUE_PARAMS = { CAR.CHEVROLET_BOLT_EUV: [2.6531724862969748, 1.0, 0.1919764879840985, 0.009054123646805178], @@ -41,8 +40,8 @@ def get_steer_feedforward_function(self): else: return CarInterfaceBase.get_steer_feedforward_default - def torque_from_lateral_accel_siglin(self, latcontrol_inputs: LatControlInputs, torque_params: car.CarParams.LateralTorqueTuning, lateral_accel_error: float, - lateral_accel_deadzone: float, friction_compensation: bool, gravity_adjusted: bool) -> float: + def torque_from_lateral_accel_siglin(self, latcontrol_inputs: LatControlInputs, torque_params: structs.CarParams.LateralTorqueTuning, + lateral_accel_error: float, lateral_accel_deadzone: float, friction_compensation: bool, gravity_adjusted: bool) -> float: friction = get_friction(lateral_accel_error, lateral_accel_deadzone, FRICTION_THRESHOLD, torque_params, friction_compensation) def sig(val): @@ -57,14 +56,14 @@ def sig(val): # An important thing to consider is that the slope at 0 should be > 0 (ideally >1) # This has big effect on the stability about 0 (noise when going straight) # ToDo: To generalize to other GMs, explore tanh function as the nonlinear - non_linear_torque_params = NON_LINEAR_TORQUE_PARAMS.get(self.CP.carFingerprint) + non_linear_torque_params = NON_LINEAR_TORQUE_PARAMS.get(self.CP.carFingerprint) # type: ignore[call-overload] assert non_linear_torque_params, "The params are not defined" a, b, c, _ = non_linear_torque_params steer_torque = (sig(latcontrol_inputs.lateral_acceleration * a) * b) + (latcontrol_inputs.lateral_acceleration * c) return float(steer_torque) + friction - def torque_from_lateral_accel_neural(self, latcontrol_inputs: LatControlInputs, torque_params: car.CarParams.LateralTorqueTuning, lateral_accel_error: float, - lateral_accel_deadzone: float, friction_compensation: bool, gravity_adjusted: bool) -> float: + def torque_from_lateral_accel_neural(self, latcontrol_inputs: LatControlInputs, torque_params: structs.CarParams.LateralTorqueTuning, + lateral_accel_error: float, lateral_accel_deadzone: float, friction_compensation: bool, gravity_adjusted: bool) -> float: friction = get_friction(lateral_accel_error, lateral_accel_deadzone, FRICTION_THRESHOLD, torque_params, friction_compensation) inputs = list(latcontrol_inputs) if gravity_adjusted: @@ -81,9 +80,9 @@ def torque_from_lateral_accel(self) -> TorqueFromLateralAccelCallbackType: return self.torque_from_lateral_accel_linear @staticmethod - def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams: ret.carName = "gm" - ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.gm)] + ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.gm)] ret.autoResumeSng = False ret.enableBsm = 0x142 in fingerprint[CanBus.POWERTRAIN] diff --git a/selfdrive/car/gm/radar_interface.py b/selfdrive/car/gm/radar_interface.py index b305d418b8a649..919e2940f869e9 100755 --- a/selfdrive/car/gm/radar_interface.py +++ b/selfdrive/car/gm/radar_interface.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 import math -from cereal import car from opendbc.can.parser import CANParser +from openpilot.selfdrive.car import structs from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.gm.values import DBC, CanBus from openpilot.selfdrive.car.interfaces import RadarInterfaceBase @@ -52,7 +52,7 @@ def update(self, can_strings): if self.trigger_msg not in self.updated_messages: return None - ret = car.RadarData.new_message() + ret = structs.RadarData() header = self.rcp.vl[RADAR_HEADER_MSG] fault = header['FLRRSnsrBlckd'] or header['FLRRSnstvFltPrsntInt'] or \ header['FLRRYawRtPlsblityFlt'] or header['FLRRHWFltPrsntInt'] or \ @@ -82,7 +82,7 @@ def update(self, can_strings): targetId = cpt['TrkObjectID'] currentTargets.add(targetId) if targetId not in self.pts: - self.pts[targetId] = car.RadarData.RadarPoint.new_message() + self.pts[targetId] = structs.RadarData.RadarPoint() self.pts[targetId].trackId = targetId distance = cpt['TrkRange'] self.pts[targetId].dRel = distance # from front of car diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index 53a4621d27fe89..ff669b39404c85 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -1,11 +1,11 @@ from dataclasses import dataclass, field -from cereal import car from openpilot.selfdrive.car import dbc_dict, PlatformConfig, DbcDict, Platforms, CarSpecs +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.docs_definitions import CarHarness, CarDocs, CarParts from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu class CarControllerParams: @@ -63,8 +63,8 @@ def __init__(self, CP): class GMCarDocs(CarDocs): package: str = "Adaptive Cruise Control (ACC)" - def init_make(self, CP: car.CarParams): - if CP.networkLocation == car.CarParams.NetworkLocation.fwdCamera: + def init_make(self, CP: CarParams): + if CP.networkLocation == CarParams.NetworkLocation.fwdCamera: self.car_parts = CarParts.common([CarHarness.gm]) else: self.car_parts = CarParts.common([CarHarness.obd_ii]) diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index 87b867d2b359c8..b088f775eab4c6 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -1,15 +1,15 @@ +import copy from collections import namedtuple -from cereal import car from opendbc.can.packer import CANPacker -from openpilot.selfdrive.car import DT_CTRL, rate_limit, make_tester_present_msg +from openpilot.selfdrive.car import DT_CTRL, rate_limit, make_tester_present_msg, structs from openpilot.selfdrive.car.common.numpy_fast import clip, interp from openpilot.selfdrive.car.honda import hondacan from openpilot.selfdrive.car.honda.values import CruiseButtons, VISUAL_HUD, HONDA_BOSCH, HONDA_BOSCH_RADARLESS, HONDA_NIDEC_ALT_PCM_ACCEL, CarControllerParams from openpilot.selfdrive.car.interfaces import CarControllerBase -VisualAlert = car.CarControl.HUDControl.VisualAlert -LongCtrlState = car.CarControl.Actuators.LongControlState +VisualAlert = structs.CarControl.HUDControl.VisualAlert +LongCtrlState = structs.CarControl.Actuators.LongControlState def compute_gb_honda_bosch(accel, speed): @@ -83,11 +83,11 @@ def process_hud_alert(hud_alert): # priority is: FCW, steer required, all others if hud_alert == VisualAlert.fcw: - fcw_display = VISUAL_HUD[hud_alert.raw] + fcw_display = VISUAL_HUD[hud_alert] elif hud_alert in (VisualAlert.steerRequired, VisualAlert.ldw): - steer_required = VISUAL_HUD[hud_alert.raw] + steer_required = VISUAL_HUD[hud_alert] else: - acc_alert = VISUAL_HUD[hud_alert.raw] + acc_alert = VISUAL_HUD[hud_alert] return fcw_display, steer_required, acc_alert @@ -242,7 +242,7 @@ def update(self, CC, CS, now_nanos): self.speed = pcm_speed self.gas = pcm_accel / self.params.NIDEC_GAS_MAX - new_actuators = actuators.as_builder() + new_actuators = copy.copy(actuators) new_actuators.speed = self.speed new_actuators.accel = self.accel new_actuators.gas = self.gas diff --git a/selfdrive/car/honda/carstate.py b/selfdrive/car/honda/carstate.py index 1f4cec775890e7..7558562d00f7fd 100644 --- a/selfdrive/car/honda/carstate.py +++ b/selfdrive/car/honda/carstate.py @@ -1,9 +1,8 @@ from collections import defaultdict -from cereal import car from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser -from openpilot.selfdrive.car import create_button_events +from openpilot.selfdrive.car import create_button_events, structs from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.common.numpy_fast import interp from openpilot.selfdrive.car.honda.hondacan import CanBus, get_cruise_speed_conversion @@ -12,8 +11,8 @@ HondaFlags, CruiseButtons, CruiseSettings from openpilot.selfdrive.car.interfaces import CarStateBase -TransmissionType = car.CarParams.TransmissionType -ButtonType = car.CarState.ButtonEvent.Type +TransmissionType = structs.CarParams.TransmissionType +ButtonType = structs.CarState.ButtonEvent.Type BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.DECEL_SET: ButtonType.decelCruise, CruiseButtons.MAIN: ButtonType.altButton3, CruiseButtons.CANCEL: ButtonType.cancel} @@ -110,8 +109,8 @@ def __init__(self, CP): # However, on cars without a digital speedometer this is not always present (HRV, FIT, CRV 2016, ILX and RDX) self.dash_speed_seen = False - def update(self, cp, cp_cam, _, cp_body, __): - ret = car.CarState.new_message() + def update(self, cp, cp_cam, _, cp_body, __) -> structs.CarState: + ret = structs.CarState() # car params v_weight_v = [0., 1.] # don't trust smooth speed at low values to avoid premature zero snapping @@ -198,7 +197,7 @@ def update(self, cp, cp_cam, _, cp_body, __): ret.steeringTorque = cp.vl["STEER_STATUS"]["STEER_TORQUE_SENSOR"] ret.steeringTorqueEps = cp.vl["STEER_MOTOR_TORQUE"]["MOTOR_TORQUE"] - ret.steeringPressed = abs(ret.steeringTorque) > STEER_THRESHOLD.get(self.CP.carFingerprint, 1200) + ret.steeringPressed = abs(ret.steeringTorque) > STEER_THRESHOLD.get(self.CP.carFingerprint, 1200) # type: ignore[call-overload] if self.CP.carFingerprint in HONDA_BOSCH: # The PCM always manages its own cruise control state, but doesn't publish it diff --git a/selfdrive/car/honda/fingerprints.py b/selfdrive/car/honda/fingerprints.py index 191fd8e44a159b..9160031ab49212 100644 --- a/selfdrive/car/honda/fingerprints.py +++ b/selfdrive/car/honda/fingerprints.py @@ -1,7 +1,7 @@ -from cereal import car +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.honda.values import CAR -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu # Modified FW can be identified by the second dash being replaced by a comma # For example: `b'39990-TVA,A150\x00\x00'` diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 28b6849769c5f2..54df6c2579bad5 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -1,16 +1,15 @@ #!/usr/bin/env python3 -from cereal import car from panda import Panda +from openpilot.selfdrive.car import get_safety_config, structs from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.common.numpy_fast import interp from openpilot.selfdrive.car.honda.hondacan import CanBus from openpilot.selfdrive.car.honda.values import CarControllerParams, HondaFlags, CAR, HONDA_BOSCH, \ HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_RADARLESS -from openpilot.selfdrive.car import get_safety_config from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.disable_ecu import disable_ecu -TransmissionType = car.CarParams.TransmissionType +TransmissionType = structs.CarParams.TransmissionType class CarInterface(CarInterfaceBase): @@ -26,13 +25,13 @@ def get_pid_accel_limits(CP, current_speed, cruise_speed): return CarControllerParams.NIDEC_ACCEL_MIN, interp(current_speed, ACCEL_MAX_BP, ACCEL_MAX_VALS) @staticmethod - def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams: ret.carName = "honda" CAN = CanBus(ret, fingerprint) if candidate in HONDA_BOSCH: - ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hondaBosch)] + ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.hondaBosch)] ret.radarUnavailable = True # Disable the radar and let openpilot control longitudinal # WARNING: THIS DISABLES AEB! @@ -41,7 +40,7 @@ def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): ret.openpilotLongitudinalControl = experimental_long ret.pcmCruise = not ret.openpilotLongitudinalControl else: - ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hondaNidec)] + ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.hondaNidec)] ret.openpilotLongitudinalControl = True ret.pcmCruise = True diff --git a/selfdrive/car/honda/radar_interface.py b/selfdrive/car/honda/radar_interface.py index 8090f8e03e7735..8dd1ddd529f72a 100755 --- a/selfdrive/car/honda/radar_interface.py +++ b/selfdrive/car/honda/radar_interface.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -from cereal import car from opendbc.can.parser import CANParser +from openpilot.selfdrive.car import structs from openpilot.selfdrive.car.interfaces import RadarInterfaceBase from openpilot.selfdrive.car.honda.values import DBC @@ -47,7 +47,7 @@ def update(self, can_strings): return rr def _update(self, updated_messages): - ret = car.RadarData.new_message() + ret = structs.RadarData() for ii in sorted(updated_messages): cpt = self.rcp.vl[ii] @@ -57,7 +57,7 @@ def _update(self, updated_messages): self.radar_wrong_config = cpt['RADAR_STATE'] == 0x69 elif cpt['LONG_DIST'] < 255: if ii not in self.pts or cpt['NEW_TRACK']: - self.pts[ii] = car.RadarData.RadarPoint.new_message() + self.pts[ii] = structs.RadarData.RadarPoint() self.pts[ii].trackId = self.track_id self.track_id += 1 self.pts[ii].dRel = cpt['LONG_DIST'] # from front of car diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 53e5435f294c45..499cbbc0e083b5 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -1,15 +1,14 @@ from dataclasses import dataclass from enum import Enum, IntFlag -from cereal import car from panda.python import uds -from openpilot.selfdrive.car import CarSpecs, PlatformConfig, Platforms, dbc_dict +from openpilot.selfdrive.car import CarSpecs, PlatformConfig, Platforms, dbc_dict, structs from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16 -Ecu = car.CarParams.Ecu -VisualAlert = car.CarControl.HUDControl.VisualAlert +Ecu = structs.CarParams.Ecu +VisualAlert = structs.CarControl.HUDControl.VisualAlert class CarControllerParams: @@ -90,7 +89,7 @@ class CruiseSettings: class HondaCarDocs(CarDocs): package: str = "Honda Sensing" - def init_make(self, CP: car.CarParams): + def init_make(self, CP: structs.CarParams): if CP.flags & HondaFlags.BOSCH: self.car_parts = CarParts.common([CarHarness.bosch_b]) if CP.flags & HondaFlags.BOSCH_RADARLESS else CarParts.common([CarHarness.bosch_a]) else: diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index cfca7ab1d93000..f9f2603058ad21 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -1,6 +1,6 @@ -from cereal import car +import copy from opendbc.can.packer import CANPacker -from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits, common_fault_avoidance, make_tester_present_msg +from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits, common_fault_avoidance, make_tester_present_msg, structs from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.common.numpy_fast import clip from openpilot.selfdrive.car.hyundai import hyundaicanfd, hyundaican @@ -9,8 +9,8 @@ from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CANFD_CAR, CAR from openpilot.selfdrive.car.interfaces import CarControllerBase -VisualAlert = car.CarControl.HUDControl.VisualAlert -LongCtrlState = car.CarControl.Actuators.LongControlState +VisualAlert = structs.CarControl.HUDControl.VisualAlert +LongCtrlState = structs.CarControl.Actuators.LongControlState # EPS faults if you apply torque while the steering angle is above 90 degrees for more than 1 second # All slightly below EPS thresholds to avoid fault @@ -162,7 +162,7 @@ def update(self, CC, CS, now_nanos): if self.frame % 50 == 0 and self.CP.openpilotLongitudinalControl: can_sends.append(hyundaican.create_frt_radar_opt(self.packer)) - new_actuators = actuators.as_builder() + new_actuators = copy.copy(actuators) new_actuators.steer = apply_steer / self.params.STEER_MAX new_actuators.steerOutputCan = apply_steer new_actuators.accel = accel @@ -170,7 +170,7 @@ def update(self, CC, CS, now_nanos): self.frame += 1 return new_actuators, can_sends - def create_button_messages(self, CC: car.CarControl, CS: CarState, use_clu11: bool): + def create_button_messages(self, CC: structs.CarControl, CS: CarState, use_clu11: bool): can_sends = [] if use_clu11: if CC.cruiseControl.cancel: diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index 2173565d06b65e..2aa8e453c4ea46 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -2,17 +2,16 @@ import copy import math -from cereal import car from opendbc.can.parser import CANParser from opendbc.can.can_define import CANDefine -from openpilot.selfdrive.car import create_button_events +from openpilot.selfdrive.car import create_button_events, structs from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CAN_GEARS, CAMERA_SCC_CAR, \ CANFD_CAR, Buttons, CarControllerParams from openpilot.selfdrive.car.interfaces import CarStateBase -ButtonType = car.CarState.ButtonEvent.Type +ButtonType = structs.CarState.ButtonEvent.Type PREV_BUTTON_SAMPLES = 8 CLUSTER_SAMPLE_RATE = 20 # frames @@ -58,11 +57,11 @@ def __init__(self, CP): self.params = CarControllerParams(CP) - def update(self, cp, cp_cam, *_): + def update(self, cp, cp_cam, *_) -> structs.CarState: if self.CP.carFingerprint in CANFD_CAR: return self.update_canfd(cp, cp_cam) - ret = car.CarState.new_message() + ret = structs.CarState() cp_cruise = cp_cam if self.CP.carFingerprint in CAMERA_SCC_CAR else cp self.is_metric = cp.vl["CLU11"]["CF_Clu_SPEED_UNIT"] == 0 speed_conv = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS @@ -177,8 +176,8 @@ def update(self, cp, cp_cam, *_): return ret - def update_canfd(self, cp, cp_cam): - ret = car.CarState.new_message() + def update_canfd(self, cp, cp_cam) -> structs.CarState: + ret = structs.CarState() self.is_metric = cp.vl["CRUISE_BUTTONS_ALT"]["DISTANCE_UNIT"] != 1 speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS diff --git a/selfdrive/car/hyundai/fingerprints.py b/selfdrive/car/hyundai/fingerprints.py index a109d3a0b21f38..22172a2a1f7008 100644 --- a/selfdrive/car/hyundai/fingerprints.py +++ b/selfdrive/car/hyundai/fingerprints.py @@ -1,7 +1,7 @@ -from cereal import car +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.hyundai.values import CAR -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu # The existence of SCC or RDR in the fwdRadar FW usually determines the radar's function, # i.e. if it sends the SCC messages or if another ECU like the camera or ADAS Driving ECU does diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 923c84d4b27535..4530704ed297d2 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -1,6 +1,5 @@ -from cereal import car from panda import Panda -from openpilot.selfdrive.car import get_safety_config +from openpilot.selfdrive.car import get_safety_config, structs from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CANFD_CAR, CAMERA_SCC_CAR, CANFD_RADAR_SCC_CAR, \ CANFD_UNSUPPORTED_LONGITUDINAL_CAR, EV_CAR, HYBRID_CAR, LEGACY_SAFETY_MODE_CAR, \ @@ -9,14 +8,14 @@ from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.disable_ecu import disable_ecu -Ecu = car.CarParams.Ecu +Ecu = structs.CarParams.Ecu ENABLE_BUTTONS = (Buttons.RES_ACCEL, Buttons.SET_DECEL, Buttons.CANCEL) class CarInterface(CarInterfaceBase): @staticmethod - def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams: ret.carName = "hyundai" ret.radarUnavailable = RADAR_START_ADDR not in fingerprint[1] or DBC[ret.carFingerprint]["radar"] is None @@ -97,9 +96,9 @@ def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): # *** panda safety config *** if candidate in CANFD_CAR: - cfgs = [get_safety_config(car.CarParams.SafetyModel.hyundaiCanfd), ] + cfgs = [get_safety_config(structs.CarParams.SafetyModel.hyundaiCanfd), ] if CAN.ECAN >= 4: - cfgs.insert(0, get_safety_config(car.CarParams.SafetyModel.noOutput)) + cfgs.insert(0, get_safety_config(structs.CarParams.SafetyModel.noOutput)) ret.safetyConfigs = cfgs if ret.flags & HyundaiFlags.CANFD_HDA2: @@ -113,9 +112,9 @@ def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): else: if candidate in LEGACY_SAFETY_MODE_CAR: # these cars require a special panda safety mode due to missing counters and checksums in the messages - ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hyundaiLegacy)] + ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.hyundaiLegacy)] else: - ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hyundai, 0)] + ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.hyundai, 0)] if candidate in CAMERA_SCC_CAR: ret.safetyConfigs[0].safetyParam |= Panda.FLAG_HYUNDAI_CAMERA_SCC diff --git a/selfdrive/car/hyundai/radar_interface.py b/selfdrive/car/hyundai/radar_interface.py index 52600509860f5a..1a5915f298fdc2 100644 --- a/selfdrive/car/hyundai/radar_interface.py +++ b/selfdrive/car/hyundai/radar_interface.py @@ -1,7 +1,7 @@ import math -from cereal import car from opendbc.can.parser import CANParser +from openpilot.selfdrive.car import structs from openpilot.selfdrive.car.interfaces import RadarInterfaceBase from openpilot.selfdrive.car.hyundai.values import DBC @@ -44,7 +44,7 @@ def update(self, can_strings): return rr def _update(self, updated_messages): - ret = car.RadarData.new_message() + ret = structs.RadarData() if self.rcp is None: return ret @@ -58,7 +58,7 @@ def _update(self, updated_messages): msg = self.rcp.vl[f"RADAR_TRACK_{addr:x}"] if addr not in self.pts: - self.pts[addr] = car.RadarData.RadarPoint.new_message() + self.pts[addr] = structs.RadarData.RadarPoint() self.pts[addr].trackId = self.track_id self.track_id += 1 diff --git a/selfdrive/car/hyundai/tests/print_platform_codes.py b/selfdrive/car/hyundai/tests/print_platform_codes.py index f641535678c22f..d719f73e379fad 100755 --- a/selfdrive/car/hyundai/tests/print_platform_codes.py +++ b/selfdrive/car/hyundai/tests/print_platform_codes.py @@ -1,22 +1,21 @@ #!/usr/bin/env python3 -from cereal import car +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.hyundai.values import PLATFORM_CODE_ECUS, get_platform_codes from openpilot.selfdrive.car.hyundai.fingerprints import FW_VERSIONS -Ecu = car.CarParams.Ecu -ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()} +Ecu = CarParams.Ecu if __name__ == "__main__": for car_model, ecus in FW_VERSIONS.items(): print() print(car_model) - for ecu in sorted(ecus, key=lambda x: int(x[0])): + for ecu in sorted(ecus): if ecu[0] not in PLATFORM_CODE_ECUS: continue platform_codes = get_platform_codes(ecus[ecu]) codes = {code for code, _ in platform_codes} dates = {date for _, date in platform_codes if date is not None} - print(f' (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])}, {ecu[2]}):') + print(f' (Ecu.{ecu[0]}, {hex(ecu[1])}, {ecu[2]}):') print(f' Codes: {codes}') print(f' Dates: {dates}') diff --git a/selfdrive/car/hyundai/tests/test_hyundai.py b/selfdrive/car/hyundai/tests/test_hyundai.py index 66b65ea95b474a..3c008e3ebb50bb 100644 --- a/selfdrive/car/hyundai/tests/test_hyundai.py +++ b/selfdrive/car/hyundai/tests/test_hyundai.py @@ -2,8 +2,8 @@ import pytest -from cereal import car from openpilot.selfdrive.car import gen_empty_fingerprint +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.fw_versions import build_fw_dict from openpilot.selfdrive.car.hyundai.interface import CarInterface from openpilot.selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR @@ -13,8 +13,7 @@ HyundaiFlags, get_platform_codes from openpilot.selfdrive.car.hyundai.fingerprints import FW_VERSIONS -Ecu = car.CarParams.Ecu -ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()} +Ecu = CarParams.Ecu # Some platforms have date codes in a different format we don't yet parse (or are missing). # For now, assert list of expected missing date cars @@ -46,7 +45,7 @@ class TestHyundaiFingerprint: def test_feature_detection(self): # HDA2 for has_adas in (True, False): - car_fw = [car.CarParams.CarFw(ecu=Ecu.adas if has_adas else Ecu.fwdCamera)] + car_fw = [CarParams.CarFw(ecu=Ecu.adas if has_adas else Ecu.fwdCamera)] CP = CarInterface.get_params(CAR.KIA_EV6, gen_empty_fingerprint(), car_fw, False, False) assert bool(CP.flags & HyundaiFlags.CANFD_HDA2) == has_adas @@ -76,7 +75,7 @@ def test_canfd_ecu_whitelist(self): for car_model in CANFD_CAR: ecus = {fw[0] for fw in FW_VERSIONS[car_model].keys()} ecus_not_in_whitelist = ecus - CANFD_EXPECTED_ECUS - ecu_strings = ", ".join([f"Ecu.{ECU_NAME[ecu]}" for ecu in ecus_not_in_whitelist]) + ecu_strings = ", ".join([f"Ecu.{ecu}" for ecu in ecus_not_in_whitelist]) assert len(ecus_not_in_whitelist) == 0, \ f"{car_model}: Car model has unexpected ECUs: {ecu_strings}" @@ -223,10 +222,10 @@ def test_fuzzy_excluded_platforms(self): for ecu, fw_versions in fw_by_addr.items(): ecu_name, addr, sub_addr = ecu for fw in fw_versions: - car_fw.append({"ecu": ecu_name, "fwVersion": fw, "address": addr, - "subAddress": 0 if sub_addr is None else sub_addr}) + car_fw.append(CarParams.CarFw(ecu=ecu_name, fwVersion=fw, address=addr, + subAddress=0 if sub_addr is None else sub_addr)) - CP = car.CarParams.new_message(carFw=car_fw) + CP = CarParams(carFw=car_fw) matches = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(build_fw_dict(CP.carFw), CP.carVin, FW_VERSIONS) if len(matches) == 1: assert list(matches)[0] == platform diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 0db82a7577f69c..6937b719c8d501 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -2,14 +2,14 @@ from dataclasses import dataclass, field from enum import Enum, IntFlag -from cereal import car from panda.python import uds from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict from openpilot.selfdrive.car.conversions import Conversions as CV +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16 -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu class CarControllerParams: @@ -107,7 +107,7 @@ class Footnote(Enum): class HyundaiCarDocs(CarDocs): package: str = "Smart Cruise Control (SCC)" - def init_make(self, CP: car.CarParams): + def init_make(self, CP: CarParams): if CP.flags & HyundaiFlags.CANFD: self.footnotes.insert(0, Footnote.CANFD) diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index e56c2d77ca4eca..e89b63eb1ee72e 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -8,8 +8,8 @@ from collections.abc import Callable from functools import cache -from cereal import car from openpilot.selfdrive.car import DT_CTRL, apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness, get_friction, STD_CARGO_KG +from openpilot.selfdrive.car import structs from openpilot.selfdrive.car.can_definitions import CanData, CanRecvCallable, CanSendCallable from openpilot.selfdrive.car.common.basedir import BASEDIR from openpilot.selfdrive.car.conversions import Conversions as CV @@ -17,7 +17,7 @@ from openpilot.selfdrive.car.common.numpy_fast import clip from openpilot.selfdrive.car.values import PLATFORMS -GearShifter = car.CarState.GearShifter +GearShifter = structs.CarState.GearShifter V_CRUISE_MAX = 145 MAX_CTRL_SPEED = (V_CRUISE_MAX + 4) * CV.KPH_TO_MS @@ -29,7 +29,7 @@ TORQUE_OVERRIDE_PATH = os.path.join(BASEDIR, 'torque_data/override.toml') TORQUE_SUBSTITUTE_PATH = os.path.join(BASEDIR, 'torque_data/substitute.toml') -GEAR_SHIFTER_MAP: dict[str, car.CarState.GearShifter] = { +GEAR_SHIFTER_MAP: dict[str, GearShifter] = { 'P': GearShifter.park, 'PARK': GearShifter.park, 'R': GearShifter.reverse, 'REVERSE': GearShifter.reverse, 'N': GearShifter.neutral, 'NEUTRAL': GearShifter.neutral, @@ -49,7 +49,7 @@ class LatControlInputs(NamedTuple): aego: float -TorqueFromLateralAccelCallbackType = Callable[[LatControlInputs, car.CarParams.LateralTorqueTuning, float, float, bool, bool], float] +TorqueFromLateralAccelCallbackType = Callable[[LatControlInputs, structs.CarParams.LateralTorqueTuning, float, float, bool, bool], float] @cache @@ -84,7 +84,7 @@ def get_torque_params(): # generic car and radar interfaces class CarInterfaceBase(ABC): - def __init__(self, CP: car.CarParams, CarController, CarState): + def __init__(self, CP: structs.CarParams, CarController, CarState): self.CP = CP self.frame = 0 @@ -101,7 +101,7 @@ def __init__(self, CP: car.CarParams, CarController, CarState): dbc_name = "" if self.cp is None else self.cp.dbc_name self.CC: CarControllerBase = CarController(dbc_name, CP) - def apply(self, c: car.CarControl, now_nanos: int) -> tuple[car.CarControl.Actuators, list[CanData]]: + def apply(self, c: structs.CarControl, now_nanos: int) -> tuple[structs.CarControl.Actuators, list[CanData]]: return self.CC.update(c, self.CS, now_nanos) @staticmethod @@ -109,14 +109,15 @@ def get_pid_accel_limits(CP, current_speed, cruise_speed): return ACCEL_MIN, ACCEL_MAX @classmethod - def get_non_essential_params(cls, candidate: str) -> car.CarParams: + def get_non_essential_params(cls, candidate: str) -> structs.CarParams: """ Parameters essential to controlling the car may be incomplete or wrong without FW versions or fingerprints. """ return cls.get_params(candidate, gen_empty_fingerprint(), list(), False, False) @classmethod - def get_params(cls, candidate: str, fingerprint: dict[int, dict[int, int]], car_fw: list[car.CarParams.CarFw], experimental_long: bool, docs: bool): + def get_params(cls, candidate: str, fingerprint: dict[int, dict[int, int]], car_fw: list[structs.CarParams.CarFw], + experimental_long: bool, docs: bool) -> structs.CarParams: ret = CarInterfaceBase.get_std_params(candidate) platform = PLATFORMS[candidate] @@ -143,12 +144,12 @@ def get_params(cls, candidate: str, fingerprint: dict[int, dict[int, int]], car_ @staticmethod @abstractmethod - def _get_params(ret: car.CarParams, candidate, fingerprint: dict[int, dict[int, int]], - car_fw: list[car.CarParams.CarFw], experimental_long: bool, docs: bool) -> car.CarParams: + def _get_params(ret: structs.CarParams, candidate, fingerprint: dict[int, dict[int, int]], + car_fw: list[structs.CarParams.CarFw], experimental_long: bool, docs: bool) -> structs.CarParams: raise NotImplementedError @staticmethod - def init(CP: car.CarParams, can_recv: CanRecvCallable, can_send: CanSendCallable): + def init(CP: structs.CarParams, can_recv: CanRecvCallable, can_send: CanSendCallable): pass @staticmethod @@ -159,7 +160,7 @@ def get_steer_feedforward_default(desired_angle, v_ego): def get_steer_feedforward_function(self): return self.get_steer_feedforward_default - def torque_from_lateral_accel_linear(self, latcontrol_inputs: LatControlInputs, torque_params: car.CarParams.LateralTorqueTuning, + def torque_from_lateral_accel_linear(self, latcontrol_inputs: LatControlInputs, torque_params: structs.CarParams.LateralTorqueTuning, lateral_accel_error: float, lateral_accel_deadzone: float, friction_compensation: bool, gravity_adjusted: bool) -> float: # The default is a linear relationship between torque and lateral acceleration (accounting for road roll and steering friction) friction = get_friction(lateral_accel_error, lateral_accel_deadzone, FRICTION_THRESHOLD, torque_params, friction_compensation) @@ -170,8 +171,8 @@ def torque_from_lateral_accel(self) -> TorqueFromLateralAccelCallbackType: # returns a set of default params to avoid repetition in car specific params @staticmethod - def get_std_params(candidate): - ret = car.CarParams.new_message() + def get_std_params(candidate: str) -> structs.CarParams: + ret = structs.CarParams() ret.carFingerprint = candidate # Car docs fields @@ -180,7 +181,7 @@ def get_std_params(candidate): # standard ALC params ret.tireStiffnessFactor = 1.0 - ret.steerControlType = car.CarParams.SteerControlType.torque + ret.steerControlType = structs.CarParams.SteerControlType.torque ret.minSteerSpeed = 0. ret.wheelSpeedFactor = 1.0 @@ -204,7 +205,7 @@ def get_std_params(candidate): return ret @staticmethod - def configure_torque_tune(candidate: str, tune: car.CarParams.LateralTuning, steering_angle_deadzone_deg: float = 0.0, use_steering_angle: bool = True): + def configure_torque_tune(candidate: str, tune: structs.CarParams.LateralTuning, steering_angle_deadzone_deg: float = 0.0, use_steering_angle: bool = True): params = get_torque_params()[candidate] tune.init('torque') @@ -217,10 +218,10 @@ def configure_torque_tune(candidate: str, tune: car.CarParams.LateralTuning, ste tune.torque.latAccelOffset = 0.0 tune.torque.steeringAngleDeadzoneDeg = steering_angle_deadzone_deg - def _update(self) -> car.CarState: + def _update(self) -> structs.CarState: return self.CS.update(*self.can_parsers) - def update(self, can_packets: list[tuple[int, list[CanData]]]) -> car.CarState: + def update(self, can_packets: list[tuple[int, list[CanData]]]) -> structs.CarState: # parse can for cp in self.can_parsers: if cp is not None: @@ -245,33 +246,33 @@ def update(self, can_packets: list[tuple[int, list[CanData]]]) -> car.CarState: if ret.cruiseState.speedCluster == 0: ret.cruiseState.speedCluster = ret.cruiseState.speed - # copy back for next iteration - self.CS.out = ret.as_reader() + # save for next iteration + self.CS.out = ret return ret class RadarInterfaceBase(ABC): - def __init__(self, CP: car.CarParams): + def __init__(self, CP: structs.CarParams): self.CP = CP self.rcp = None - self.pts: dict[int, car.RadarData.RadarPoint] = {} + self.pts: dict[int, structs.RadarData.RadarPoint] = {} self.delay = 0 self.radar_ts = CP.radarTimeStep self.frame = 0 - def update(self, can_strings): + def update(self, can_strings) -> structs.RadarData | None: self.frame += 1 if (self.frame % int(100 * self.radar_ts)) == 0: - return car.RadarData.new_message() + return structs.RadarData() return None class CarStateBase(ABC): - def __init__(self, CP: car.CarParams): + def __init__(self, CP: structs.CarParams): self.CP = CP self.car_fingerprint = CP.carFingerprint - self.out = car.CarState.new_message() + self.out = structs.CarState() self.cruise_buttons = 0 self.left_blinker_cnt = 0 @@ -291,7 +292,7 @@ def __init__(self, CP: car.CarParams): self.v_ego_kf = KF1D(x0=x0, A=A, C=C[0], K=K) @abstractmethod - def update(self, cp, cp_cam, cp_adas, cp_body, cp_loopback) -> car.CarState: + def update(self, cp, cp_cam, cp_adas, cp_body, cp_loopback) -> structs.CarState: pass def update_speed_kf(self, v_ego_raw): @@ -304,7 +305,7 @@ def update_speed_kf(self, v_ego_raw): def get_wheel_speeds(self, fl, fr, rl, rr, unit=CV.KPH_TO_MS): factor = unit * self.CP.wheelSpeedFactor - wheelSpeeds = car.CarState.WheelSpeeds.new_message() + wheelSpeeds = structs.CarState.WheelSpeeds() wheelSpeeds.fl = fl * factor wheelSpeeds.fr = fr * factor wheelSpeeds.rl = rl * factor @@ -349,7 +350,7 @@ def update_blinker_from_stalk(self, blinker_time: int, left_blinker_stalk: bool, return bool(left_blinker_stalk or self.left_blinker_cnt > 0), bool(right_blinker_stalk or self.right_blinker_cnt > 0) @staticmethod - def parse_gear_shifter(gear: str | None) -> car.CarState.GearShifter: + def parse_gear_shifter(gear: str | None) -> GearShifter: if gear is None: return GearShifter.unknown return GEAR_SHIFTER_MAP.get(gear.upper(), GearShifter.unknown) @@ -376,12 +377,12 @@ def get_loopback_can_parser(CP): class CarControllerBase(ABC): - def __init__(self, dbc_name: str, CP: car.CarParams): + def __init__(self, dbc_name: str, CP: structs.CarParams): self.CP = CP self.frame = 0 @abstractmethod - def update(self, CC: car.CarControl, CS: CarStateBase, now_nanos: int) -> tuple[car.CarControl.Actuators, list[CanData]]: + def update(self, CC: structs.CarControl, CS: CarStateBase, now_nanos: int) -> tuple[structs.CarControl.Actuators, list[CanData]]: pass diff --git a/selfdrive/car/mazda/carcontroller.py b/selfdrive/car/mazda/carcontroller.py index 910e2303d805ba..db52c07dea2e42 100644 --- a/selfdrive/car/mazda/carcontroller.py +++ b/selfdrive/car/mazda/carcontroller.py @@ -1,11 +1,11 @@ -from cereal import car +import copy from opendbc.can.packer import CANPacker -from openpilot.selfdrive.car import apply_driver_steer_torque_limits +from openpilot.selfdrive.car import apply_driver_steer_torque_limits, structs from openpilot.selfdrive.car.interfaces import CarControllerBase from openpilot.selfdrive.car.mazda import mazdacan from openpilot.selfdrive.car.mazda.values import CarControllerParams, Buttons -VisualAlert = car.CarControl.HUDControl.VisualAlert +VisualAlert = structs.CarControl.HUDControl.VisualAlert class CarController(CarControllerBase): @@ -57,7 +57,7 @@ def update(self, CC, CS, now_nanos): can_sends.append(mazdacan.create_steering_control(self.packer, self.CP, self.frame, apply_steer, CS.cam_lkas)) - new_actuators = CC.actuators.as_builder() + new_actuators = copy.copy(CC.actuators) new_actuators.steer = apply_steer / CarControllerParams.STEER_MAX new_actuators.steerOutputCan = apply_steer diff --git a/selfdrive/car/mazda/carstate.py b/selfdrive/car/mazda/carstate.py index 1693d167be148c..d48d078243feac 100644 --- a/selfdrive/car/mazda/carstate.py +++ b/selfdrive/car/mazda/carstate.py @@ -1,12 +1,11 @@ -from cereal import car from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser -from openpilot.selfdrive.car import create_button_events +from openpilot.selfdrive.car import create_button_events, structs from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.mazda.values import DBC, LKAS_LIMITS, MazdaFlags -ButtonType = car.CarState.ButtonEvent.Type +ButtonType = structs.CarState.ButtonEvent.Type class CarState(CarStateBase): @@ -24,9 +23,9 @@ def __init__(self, CP): self.distance_button = 0 - def update(self, cp, cp_cam, *_): + def update(self, cp, cp_cam, *_) -> structs.CarState: - ret = car.CarState.new_message() + ret = structs.CarState() prev_distance_button = self.distance_button self.distance_button = cp.vl["CRZ_BTNS"]["DISTANCE_LESS"] diff --git a/selfdrive/car/mazda/fingerprints.py b/selfdrive/car/mazda/fingerprints.py index c7b331b1cbdbee..41c1e7fb628962 100644 --- a/selfdrive/car/mazda/fingerprints.py +++ b/selfdrive/car/mazda/fingerprints.py @@ -1,7 +1,7 @@ -from cereal import car +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.mazda.values import CAR -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu FW_VERSIONS = { CAR.MAZDA_CX5_2022: { diff --git a/selfdrive/car/mazda/interface.py b/selfdrive/car/mazda/interface.py index e37fca384a9784..3c868745fca86d 100755 --- a/selfdrive/car/mazda/interface.py +++ b/selfdrive/car/mazda/interface.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -from cereal import car -from openpilot.selfdrive.car import get_safety_config +from openpilot.selfdrive.car import get_safety_config, structs from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.mazda.values import CAR, LKAS_LIMITS from openpilot.selfdrive.car.interfaces import CarInterfaceBase @@ -10,9 +9,9 @@ class CarInterface(CarInterfaceBase): @staticmethod - def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams: ret.carName = "mazda" - ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.mazda)] + ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.mazda)] ret.radarUnavailable = True ret.dashcamOnly = candidate not in (CAR.MAZDA_CX5_2022, CAR.MAZDA_CX9_2021) diff --git a/selfdrive/car/mazda/values.py b/selfdrive/car/mazda/values.py index cfd7067db60841..ea49eeaecf4c4d 100644 --- a/selfdrive/car/mazda/values.py +++ b/selfdrive/car/mazda/values.py @@ -1,13 +1,13 @@ from dataclasses import dataclass, field from enum import IntFlag -from cereal import car from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict from openpilot.selfdrive.car.conversions import Conversions as CV +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.docs_definitions import CarHarness, CarDocs, CarParts from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu # Steer torque limits diff --git a/selfdrive/car/mock/carcontroller.py b/selfdrive/car/mock/carcontroller.py index 0cd37c03695d53..cd1d67747ed829 100644 --- a/selfdrive/car/mock/carcontroller.py +++ b/selfdrive/car/mock/carcontroller.py @@ -1,5 +1,6 @@ from openpilot.selfdrive.car.interfaces import CarControllerBase + class CarController(CarControllerBase): def update(self, CC, CS, now_nanos): - return CC.actuators.as_builder(), [] + return CC.actuators, [] diff --git a/selfdrive/car/mock/carstate.py b/selfdrive/car/mock/carstate.py index 3937e8d75e2ef6..4fbebf5a4f9154 100644 --- a/selfdrive/car/mock/carstate.py +++ b/selfdrive/car/mock/carstate.py @@ -1,7 +1,7 @@ -from cereal import car +from openpilot.selfdrive.car import structs from openpilot.selfdrive.car.interfaces import CarStateBase class CarState(CarStateBase): - def update(self, *_) -> car.CarState: - return car.CarState.new_message() + def update(self, *_) -> structs.CarState: + return structs.CarState() diff --git a/selfdrive/car/mock/interface.py b/selfdrive/car/mock/interface.py index 95887b444231c6..d33cc7d164cf1d 100755 --- a/selfdrive/car/mock/interface.py +++ b/selfdrive/car/mock/interface.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +from openpilot.selfdrive.car import structs from openpilot.selfdrive.car.interfaces import CarInterfaceBase @@ -6,7 +7,7 @@ class CarInterface(CarInterfaceBase): @staticmethod - def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams: ret.carName = "mock" ret.mass = 1700. ret.wheelbase = 2.70 diff --git a/selfdrive/car/nissan/carcontroller.py b/selfdrive/car/nissan/carcontroller.py index 35a70ff106b3b5..e0e0389866e66c 100644 --- a/selfdrive/car/nissan/carcontroller.py +++ b/selfdrive/car/nissan/carcontroller.py @@ -1,11 +1,11 @@ -from cereal import car +import copy from opendbc.can.packer import CANPacker -from openpilot.selfdrive.car import apply_std_steer_angle_limits +from openpilot.selfdrive.car import apply_std_steer_angle_limits, structs from openpilot.selfdrive.car.interfaces import CarControllerBase from openpilot.selfdrive.car.nissan import nissancan from openpilot.selfdrive.car.nissan.values import CAR, CarControllerParams -VisualAlert = car.CarControl.HUDControl.VisualAlert +VisualAlert = structs.CarControl.HUDControl.VisualAlert class CarController(CarControllerBase): @@ -74,7 +74,7 @@ def update(self, CC, CS, now_nanos): self.packer, CS.lkas_hud_info_msg, steer_hud_alert )) - new_actuators = actuators.as_builder() + new_actuators = copy.copy(actuators) new_actuators.steeringAngleDeg = apply_angle self.frame += 1 diff --git a/selfdrive/car/nissan/carstate.py b/selfdrive/car/nissan/carstate.py index 9da8e8d4bada26..78d57b7e2e4d79 100644 --- a/selfdrive/car/nissan/carstate.py +++ b/selfdrive/car/nissan/carstate.py @@ -1,14 +1,13 @@ import copy from collections import deque -from cereal import car from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser -from openpilot.selfdrive.car import create_button_events +from openpilot.selfdrive.car import create_button_events, structs from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.nissan.values import CAR, DBC, CarControllerParams -ButtonType = car.CarState.ButtonEvent.Type +ButtonType = structs.CarState.ButtonEvent.Type TORQUE_SAMPLES = 12 @@ -26,8 +25,8 @@ def __init__(self, CP): self.distance_button = 0 - def update(self, cp, cp_cam, cp_adas, *_): - ret = car.CarState.new_message() + def update(self, cp, cp_cam, cp_adas, *_) -> structs.CarState: + ret = structs.CarState() prev_distance_button = self.distance_button self.distance_button = cp.vl["CRUISE_THROTTLE"]["FOLLOW_DISTANCE_BUTTON"] diff --git a/selfdrive/car/nissan/fingerprints.py b/selfdrive/car/nissan/fingerprints.py index 743feeace9c6f3..0ba4140fb7f035 100644 --- a/selfdrive/car/nissan/fingerprints.py +++ b/selfdrive/car/nissan/fingerprints.py @@ -1,8 +1,8 @@ # ruff: noqa: E501 -from cereal import car +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.nissan.values import CAR -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu FINGERPRINTS = { CAR.NISSAN_XTRAIL: [{ diff --git a/selfdrive/car/nissan/interface.py b/selfdrive/car/nissan/interface.py index c3418cabe61013..4a9b31dacf3ebf 100644 --- a/selfdrive/car/nissan/interface.py +++ b/selfdrive/car/nissan/interface.py @@ -1,6 +1,5 @@ -from cereal import car from panda import Panda -from openpilot.selfdrive.car import get_safety_config +from openpilot.selfdrive.car import get_safety_config, structs from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.nissan.values import CAR @@ -8,16 +7,16 @@ class CarInterface(CarInterfaceBase): @staticmethod - def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams: ret.carName = "nissan" - ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.nissan)] + ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.nissan)] ret.autoResumeSng = False ret.steerLimitTimer = 1.0 ret.steerActuatorDelay = 0.1 - ret.steerControlType = car.CarParams.SteerControlType.angle + ret.steerControlType = structs.CarParams.SteerControlType.angle ret.radarUnavailable = True if candidate == CAR.NISSAN_ALTIMA: diff --git a/selfdrive/car/nissan/values.py b/selfdrive/car/nissan/values.py index eecffb21bcc0d1..e50ffbd94b3739 100644 --- a/selfdrive/car/nissan/values.py +++ b/selfdrive/car/nissan/values.py @@ -1,12 +1,12 @@ from dataclasses import dataclass, field -from cereal import car from panda.python import uds from openpilot.selfdrive.car import AngleRateLimit, CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.docs_definitions import CarDocs, CarHarness, CarParts from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu class CarControllerParams: diff --git a/selfdrive/car/structs.py b/selfdrive/car/structs.py new file mode 100644 index 00000000000000..c375468353218a --- /dev/null +++ b/selfdrive/car/structs.py @@ -0,0 +1,499 @@ +from dataclasses import dataclass as _dataclass, field, is_dataclass +from enum import Enum, StrEnum as _StrEnum, auto +from typing import dataclass_transform, get_origin + +AUTO_OBJ = object() + + +def auto_field(): + return AUTO_OBJ + + +@dataclass_transform() +def auto_dataclass(cls=None, /, **kwargs): + cls_annotations = cls.__dict__.get('__annotations__', {}) + for name, typ in cls_annotations.items(): + current_value = getattr(cls, name) + if current_value is AUTO_OBJ: + origin_typ = get_origin(typ) or typ + if isinstance(origin_typ, str): + raise TypeError(f"Forward references are not supported for auto_field: '{origin_typ}'. Use a default_factory with lambda instead.") + elif origin_typ in (int, float, str, bytes, list, tuple, bool) or is_dataclass(origin_typ): + setattr(cls, name, field(default_factory=origin_typ)) + elif issubclass(origin_typ, Enum): # first enum is the default + setattr(cls, name, field(default=next(iter(origin_typ)))) + else: + raise TypeError(f"Unsupported type for auto_field: {origin_typ}") + + # TODO: use slots, this prevents accidentally setting attributes that don't exist + return _dataclass(cls, **kwargs) + + +class StrEnum(_StrEnum): + @staticmethod + def _generate_next_value_(name, *args): + # auto() defaults to name.lower() + return name + + +@auto_dataclass +class CarState: + # CAN health + canValid: bool = auto_field() # invalid counter/checksums + canTimeout: bool = auto_field() # CAN bus dropped out + canErrorCounter: int = auto_field() + + # car speed + vEgo: float = auto_field() # best estimate of speed + aEgo: float = auto_field() # best estimate of acceleration + vEgoRaw: float = auto_field() # unfiltered speed from CAN sensors + vEgoCluster: float = auto_field() # best estimate of speed shown on car's instrument cluster, used for UI + + yawRate: float = auto_field() # best estimate of yaw rate + standstill: bool = auto_field() + wheelSpeeds: 'CarState.WheelSpeeds' = field(default_factory=lambda: CarState.WheelSpeeds()) + + # gas pedal, 0.0-1.0 + gas: float = auto_field() # this is user pedal only + gasPressed: bool = auto_field() # this is user pedal only + + engineRpm: float = auto_field() + + # brake pedal, 0.0-1.0 + brake: float = auto_field() # this is user pedal only + brakePressed: bool = auto_field() # this is user pedal only + regenBraking: bool = auto_field() # this is user pedal only + parkingBrake: bool = auto_field() + brakeHoldActive: bool = auto_field() + + # steering wheel + steeringAngleDeg: float = auto_field() + steeringAngleOffsetDeg: float = auto_field() # Offset betweens sensors in case there multiple + steeringRateDeg: float = auto_field() + steeringTorque: float = auto_field() # TODO: standardize units + steeringTorqueEps: float = auto_field() # TODO: standardize units + steeringPressed: bool = auto_field() # if the user is using the steering wheel + steerFaultTemporary: bool = auto_field() # temporary EPS fault + steerFaultPermanent: bool = auto_field() # permanent EPS fault + stockAeb: bool = auto_field() + stockFcw: bool = auto_field() + espDisabled: bool = auto_field() + accFaulted: bool = auto_field() + carFaultedNonCritical: bool = auto_field() # some ECU is faulted, but car remains controllable + espActive: bool = auto_field() + vehicleSensorsInvalid: bool = auto_field() # invalid steering angle readings, etc. + + # cruise state + cruiseState: 'CarState.CruiseState' = field(default_factory=lambda: CarState.CruiseState()) + + # gear + gearShifter: 'CarState.GearShifter' = field(default_factory=lambda: CarState.GearShifter.unknown) + + # button presses + buttonEvents: list['CarState.ButtonEvent'] = auto_field() + leftBlinker: bool = auto_field() + rightBlinker: bool = auto_field() + genericToggle: bool = auto_field() + + # lock info + doorOpen: bool = auto_field() + seatbeltUnlatched: bool = auto_field() + + # clutch (manual transmission only) + clutchPressed: bool = auto_field() + + # blindspot sensors + leftBlindspot: bool = auto_field() # Is there something blocking the left lane change + rightBlindspot: bool = auto_field() # Is there something blocking the right lane change + + fuelGauge: float = auto_field() # battery or fuel tank level from 0.0 to 1.0 + charging: bool = auto_field() + + # process meta + cumLagMs: float = auto_field() + + @auto_dataclass + class WheelSpeeds: + # optional wheel speeds + fl: float = auto_field() + fr: float = auto_field() + rl: float = auto_field() + rr: float = auto_field() + + @auto_dataclass + class CruiseState: + enabled: bool = auto_field() + speed: float = auto_field() + speedCluster: float = auto_field() # Set speed as shown on instrument cluster + available: bool = auto_field() + speedOffset: float = auto_field() + standstill: bool = auto_field() + nonAdaptive: bool = auto_field() + + class GearShifter(StrEnum): + unknown = auto() + park = auto() + drive = auto() + neutral = auto() + reverse = auto() + sport = auto() + low = auto() + brake = auto() + eco = auto() + manumatic = auto() + + # send on change + @auto_dataclass + class ButtonEvent: + pressed: bool = auto_field() + type: 'CarState.ButtonEvent.Type' = field(default_factory=lambda: CarState.ButtonEvent.Type.unknown) + + class Type(StrEnum): + unknown = auto() + leftBlinker = auto() + rightBlinker = auto() + accelCruise = auto() + decelCruise = auto() + cancel = auto() + altButton1 = auto() + altButton2 = auto() + altButton3 = auto() + setCruise = auto() + resumeCruise = auto() + gapAdjustCruise = auto() + + +@auto_dataclass +class RadarData: + errors: list['Error'] = auto_field() + points: list['RadarPoint'] = auto_field() + + class Error(StrEnum): + canError = auto() + fault = auto() + wrongConfig = auto() + + @auto_dataclass + class RadarPoint: + trackId: int = auto_field() # no trackId reuse + + # these 3 are the minimum required + dRel: float = auto_field() # m from the front bumper of the car + yRel: float = auto_field() # m + vRel: float = auto_field() # m/s + + # these are optional and valid if they are not NaN + aRel: float = auto_field() # m/s^2 + yvRel: float = auto_field() # m/s + + # some radars flag measurements VS estimates + measured: bool = auto_field() + + +@auto_dataclass +class CarControl: + # must be true for any actuator commands to work + enabled: bool = auto_field() + latActive: bool = auto_field() + longActive: bool = auto_field() + + # Actuator commands as computed by controlsd + actuators: 'CarControl.Actuators' = field(default_factory=lambda: CarControl.Actuators()) + + leftBlinker: bool = auto_field() + rightBlinker: bool = auto_field() + + orientationNED: list[float] = auto_field() + angularVelocity: list[float] = auto_field() + + cruiseControl: 'CarControl.CruiseControl' = field(default_factory=lambda: CarControl.CruiseControl()) + hudControl: 'CarControl.HUDControl' = field(default_factory=lambda: CarControl.HUDControl()) + + @auto_dataclass + class Actuators: + # range from 0.0 - 1.0 + gas: float = auto_field() + brake: float = auto_field() + # range from -1.0 - 1.0 + steer: float = auto_field() + # value sent over can to the car + steerOutputCan: float = auto_field() + steeringAngleDeg: float = auto_field() + + curvature: float = auto_field() + + speed: float = auto_field() # m/s + accel: float = auto_field() # m/s^2 + longControlState: 'CarControl.Actuators.LongControlState' = field(default_factory=lambda: CarControl.Actuators.LongControlState.off) + + class LongControlState(StrEnum): + off = auto() + pid = auto() + stopping = auto() + starting = auto() + + @auto_dataclass + class CruiseControl: + cancel: bool = auto_field() + resume: bool = auto_field() + override: bool = auto_field() + + @auto_dataclass + class HUDControl: + speedVisible: bool = auto_field() + setSpeed: float = auto_field() + lanesVisible: bool = auto_field() + leadVisible: bool = auto_field() + visualAlert: 'CarControl.HUDControl.VisualAlert' = field(default_factory=lambda: CarControl.HUDControl.VisualAlert.none) + audibleAlert: 'CarControl.HUDControl.AudibleAlert' = field(default_factory=lambda: CarControl.HUDControl.AudibleAlert.none) + rightLaneVisible: bool = auto_field() + leftLaneVisible: bool = auto_field() + rightLaneDepart: bool = auto_field() + leftLaneDepart: bool = auto_field() + leadDistanceBars: int = auto_field() # 1-3: 1 is closest, 3 is farthest. some ports may utilize 2-4 bars instead + + class VisualAlert(StrEnum): + # these are the choices from the Honda + # map as good as you can for your car + none = auto() + fcw = auto() + steerRequired = auto() + brakePressed = auto() + wrongGear = auto() + seatbeltUnbuckled = auto() + speedTooHigh = auto() + ldw = auto() + + class AudibleAlert(StrEnum): + none = auto() + + engage = auto() + disengage = auto() + refuse = auto() + + warningSoft = auto() + warningImmediate = auto() + + prompt = auto() + promptRepeat = auto() + promptDistracted = auto() + + +@auto_dataclass +class CarParams: + carName: str = auto_field() + carFingerprint: str = auto_field() + fuzzyFingerprint: bool = auto_field() + + notCar: bool = auto_field() # flag for non-car robotics platforms + + pcmCruise: bool = auto_field() # is openpilot's state tied to the PCM's cruise state? + enableDsu: bool = auto_field() # driving support unit + enableBsm: bool = auto_field() # blind spot monitoring + flags: int = auto_field() # flags for car specific quirks + experimentalLongitudinalAvailable: bool = auto_field() + + minEnableSpeed: float = auto_field() + minSteerSpeed: float = auto_field() + safetyConfigs: list['CarParams.SafetyConfig'] = auto_field() + alternativeExperience: int = auto_field() # panda flag for features like no disengage on gas + + maxLateralAccel: float = auto_field() + autoResumeSng: bool = auto_field() # describes whether car can resume from a stop automatically + + mass: float = auto_field() # [kg] curb weight: all fluids no cargo + wheelbase: float = auto_field() # [m] distance from rear axle to front axle + centerToFront: float = auto_field() # [m] distance from center of mass to front axle + steerRatio: float = auto_field() # [] ratio of steering wheel angle to front wheel angle + steerRatioRear: float = auto_field() # [] ratio of steering wheel angle to rear wheel angle (usually 0) + + rotationalInertia: float = auto_field() # [kg*m2] body rotational inertia + tireStiffnessFactor: float = auto_field() # scaling factor used in calculating tireStiffness[Front,Rear] + tireStiffnessFront: float = auto_field() # [N/rad] front tire coeff of stiff + tireStiffnessRear: float = auto_field() # [N/rad] rear tire coeff of stiff + + longitudinalTuning: 'CarParams.LongitudinalPIDTuning' = field(default_factory=lambda: CarParams.LongitudinalPIDTuning()) + lateralParams: 'CarParams.LateralParams' = field(default_factory=lambda: CarParams.LateralParams()) + lateralTuning: 'CarParams.LateralTuning' = field(default_factory=lambda: CarParams.LateralTuning()) + + @auto_dataclass + class LateralTuning: + def init(self, which: str): + self.which = CarParams.LateralTuning.Which(which) + + class Which(StrEnum): + pid = auto() + torque = auto() + + def __call__(self): + return self.value + + which: 'CarParams.LateralTuning.Which' = field(default_factory=lambda: CarParams.LateralTuning.Which.pid) + + pid: 'CarParams.LateralPIDTuning' = field(default_factory=lambda: CarParams.LateralPIDTuning()) + torque: 'CarParams.LateralTorqueTuning' = field(default_factory=lambda: CarParams.LateralTorqueTuning()) + + @auto_dataclass + class SafetyConfig: + safetyModel: 'CarParams.SafetyModel' = field(default_factory=lambda: CarParams.SafetyModel.silent) + safetyParam: int = auto_field() + + @auto_dataclass + class LateralParams: + torqueBP: list[int] = auto_field() + torqueV: list[int] = auto_field() + + @auto_dataclass + class LateralPIDTuning: + kpBP: list[float] = auto_field() + kpV: list[float] = auto_field() + kiBP: list[float] = auto_field() + kiV: list[float] = auto_field() + kf: float = auto_field() + + @auto_dataclass + class LateralTorqueTuning: + useSteeringAngle: bool = auto_field() + kp: float = auto_field() + ki: float = auto_field() + friction: float = auto_field() + kf: float = auto_field() + steeringAngleDeadzoneDeg: float = auto_field() + latAccelFactor: float = auto_field() + latAccelOffset: float = auto_field() + + steerLimitAlert: bool = auto_field() + steerLimitTimer: float = auto_field() # time before steerLimitAlert is issued + + vEgoStopping: float = auto_field() # Speed at which the car goes into stopping state + vEgoStarting: float = auto_field() # Speed at which the car goes into starting state + stoppingControl: bool = auto_field() # Does the car allow full control even at lows speeds when stopping + steerControlType: 'CarParams.SteerControlType' = field(default_factory=lambda: CarParams.SteerControlType.torque) + radarUnavailable: bool = auto_field() # True when radar objects aren't visible on CAN or aren't parsed out + stopAccel: float = auto_field() # Required acceleration to keep vehicle stationary + stoppingDecelRate: float = auto_field() # m/s^2/s while trying to stop + startAccel: float = auto_field() # Required acceleration to get car moving + startingState: bool = auto_field() # Does this car make use of special starting state + + steerActuatorDelay: float = auto_field() # Steering wheel actuator delay in seconds + longitudinalActuatorDelay: float = auto_field() # Gas/Brake actuator delay in seconds + openpilotLongitudinalControl: bool = auto_field() # is openpilot doing the longitudinal control? + carVin: str = auto_field() # VIN number queried during fingerprinting + dashcamOnly: bool = auto_field() + passive: bool = auto_field() # is openpilot in control? + transmissionType: 'CarParams.TransmissionType' = field(default_factory=lambda: CarParams.TransmissionType.unknown) + carFw: list['CarParams.CarFw'] = auto_field() + + radarTimeStep: float = 0.05 # time delta between radar updates, 20Hz is very standard + fingerprintSource: 'CarParams.FingerprintSource' = field(default_factory=lambda: CarParams.FingerprintSource.can) + # Where Panda/C2 is integrated into the car's CAN network + networkLocation: 'CarParams.NetworkLocation' = field(default_factory=lambda: CarParams.NetworkLocation.fwdCamera) + + wheelSpeedFactor: float = auto_field() # Multiplier on wheels speeds to computer actual speeds + + @auto_dataclass + class LongitudinalPIDTuning: + kpBP: list[float] = auto_field() + kpV: list[float] = auto_field() + kiBP: list[float] = auto_field() + kiV: list[float] = auto_field() + kf: float = auto_field() + + class SafetyModel(StrEnum): + silent = auto() + hondaNidec = auto() + toyota = auto() + elm327 = auto() + gm = auto() + hondaBoschGiraffe = auto() + ford = auto() + cadillac = auto() + hyundai = auto() + chrysler = auto() + tesla = auto() + subaru = auto() + gmPassive = auto() + mazda = auto() + nissan = auto() + volkswagen = auto() + toyotaIpas = auto() + allOutput = auto() + gmAscm = auto() + noOutput = auto() # like silent but without silent CAN TXs + hondaBosch = auto() + volkswagenPq = auto() + subaruPreglobal = auto() # pre-Global platform + hyundaiLegacy = auto() + hyundaiCommunity = auto() + volkswagenMlb = auto() + hongqi = auto() + body = auto() + hyundaiCanfd = auto() + volkswagenMqbEvo = auto() + chryslerCusw = auto() + psa = auto() + + class SteerControlType(StrEnum): + torque = auto() + angle = auto() + + class TransmissionType(StrEnum): + unknown = auto() + automatic = auto() # Traditional auto, including DSG + manual = auto() # True "stick shift" only + direct = auto() # Electric vehicle or other direct drive + cvt = auto() + + @auto_dataclass + class CarFw: + ecu: 'CarParams.Ecu' = field(default_factory=lambda: CarParams.Ecu.unknown) + fwVersion: bytes = auto_field() + address: int = auto_field() + subAddress: int = auto_field() + responseAddress: int = auto_field() + request: list[bytes] = auto_field() + brand: str = auto_field() + bus: int = auto_field() + logging: bool = auto_field() + obdMultiplexing: bool = auto_field() + + 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() + + class FingerprintSource(StrEnum): + can = auto() + fw = auto() + fixed = auto() + + class NetworkLocation(StrEnum): + fwdCamera = auto() # Standard/default integration at LKAS camera + gateway = auto() # Integration at vehicle's CAN gateway diff --git a/selfdrive/car/subaru/carcontroller.py b/selfdrive/car/subaru/carcontroller.py index ba8a87b2d57252..2b8de77cb12700 100644 --- a/selfdrive/car/subaru/carcontroller.py +++ b/selfdrive/car/subaru/carcontroller.py @@ -1,3 +1,4 @@ +import copy from opendbc.can.packer import CANPacker from openpilot.selfdrive.car import apply_driver_steer_torque_limits, common_fault_avoidance, make_tester_present_msg from openpilot.selfdrive.car.common.numpy_fast import clip, interp @@ -135,7 +136,7 @@ def update(self, CC, CS, now_nanos): if self.frame % 2 == 0: can_sends.append(subarucan.create_es_static_2(self.packer)) - new_actuators = actuators.as_builder() + new_actuators = copy.copy(actuators) new_actuators.steer = self.apply_steer_last / self.p.STEER_MAX new_actuators.steerOutputCan = self.apply_steer_last diff --git a/selfdrive/car/subaru/carstate.py b/selfdrive/car/subaru/carstate.py index 125d58992865e2..5ae7416c9e4762 100644 --- a/selfdrive/car/subaru/carstate.py +++ b/selfdrive/car/subaru/carstate.py @@ -1,7 +1,7 @@ import copy -from cereal import car from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser +from openpilot.selfdrive.car import structs from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.subaru.values import DBC, CanBus, SubaruFlags @@ -16,8 +16,8 @@ def __init__(self, CP): self.angle_rate_calulator = CanSignalRateCalculator(50) - def update(self, cp, cp_cam, _, cp_body, __): - ret = car.CarState.new_message() + def update(self, cp, cp_cam, _, cp_body, __) -> structs.CarState: + ret = structs.CarState() throttle_msg = cp.vl["Throttle"] if not (self.CP.flags & SubaruFlags.HYBRID) else cp_body.vl["Throttle_Hybrid"] ret.gas = throttle_msg["Throttle_Pedal"] / 255. diff --git a/selfdrive/car/subaru/fingerprints.py b/selfdrive/car/subaru/fingerprints.py index 7f3ae73163e418..340844e56122fb 100644 --- a/selfdrive/car/subaru/fingerprints.py +++ b/selfdrive/car/subaru/fingerprints.py @@ -1,7 +1,7 @@ -from cereal import car +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.subaru.values import CAR -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu FW_VERSIONS = { CAR.SUBARU_ASCENT: { diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py index c733ef291bd808..d392edc60b6c13 100644 --- a/selfdrive/car/subaru/interface.py +++ b/selfdrive/car/subaru/interface.py @@ -1,6 +1,5 @@ -from cereal import car from panda import Panda -from openpilot.selfdrive.car import get_safety_config +from openpilot.selfdrive.car import get_safety_config, structs from openpilot.selfdrive.car.disable_ecu import disable_ecu from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.subaru.values import CAR, GLOBAL_ES_ADDR, SubaruFlags @@ -9,7 +8,7 @@ class CarInterface(CarInterfaceBase): @staticmethod - def _get_params(ret, candidate: CAR, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret: structs.CarParams, candidate: CAR, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams: ret.carName = "subaru" ret.radarUnavailable = True # for HYBRID CARS to be upstreamed, we need: @@ -25,10 +24,10 @@ def _get_params(ret, candidate: CAR, fingerprint, car_fw, experimental_long, doc if ret.flags & SubaruFlags.PREGLOBAL: ret.enableBsm = 0x25c in fingerprint[0] - ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.subaruPreglobal)] + ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.subaruPreglobal)] else: ret.enableBsm = 0x228 in fingerprint[0] - ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.subaru)] + ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.subaru)] if ret.flags & SubaruFlags.GLOBAL_GEN2: ret.safetyConfigs[0].safetyParam |= Panda.FLAG_SUBARU_GEN2 @@ -36,7 +35,7 @@ def _get_params(ret, candidate: CAR, fingerprint, car_fw, experimental_long, doc ret.steerActuatorDelay = 0.1 if ret.flags & SubaruFlags.LKAS_ANGLE: - ret.steerControlType = car.CarParams.SteerControlType.angle + ret.steerControlType = structs.CarParams.SteerControlType.angle else: CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) diff --git a/selfdrive/car/subaru/subarucan.py b/selfdrive/car/subaru/subarucan.py index 41bd177ff2de76..fd6644c22c8ca8 100644 --- a/selfdrive/car/subaru/subarucan.py +++ b/selfdrive/car/subaru/subarucan.py @@ -1,7 +1,7 @@ -from cereal import car +from openpilot.selfdrive.car import structs from openpilot.selfdrive.car.subaru.values import CanBus -VisualAlert = car.CarControl.HUDControl.VisualAlert +VisualAlert = structs.CarControl.HUDControl.VisualAlert def create_steering_control(packer, apply_steer, steer_req): diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index dcbea1979fd227..655627159d2a05 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -1,13 +1,13 @@ from dataclasses import dataclass, field from enum import Enum, IntFlag -from cereal import car from panda.python import uds from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Tool, Column from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16 -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu class CarControllerParams: @@ -93,7 +93,7 @@ class SubaruCarDocs(CarDocs): car_parts: CarParts = field(default_factory=CarParts.common([CarHarness.subaru_a])) footnotes: list[Enum] = field(default_factory=lambda: [Footnote.GLOBAL]) - def init_make(self, CP: car.CarParams): + def init_make(self, CP: CarParams): self.car_parts.parts.extend([Tool.socket_8mm_deep, Tool.pry_tool]) if CP.experimentalLongitudinalAvailable: diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index e863c1d08cdfd5..249fb24a7a8cab 100644 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -7,7 +7,9 @@ from cereal import car, messaging from openpilot.selfdrive.car import DT_CTRL, gen_empty_fingerprint +from openpilot.selfdrive.car.card import convert_carControl, convert_to_capnp from openpilot.selfdrive.car.car_helpers import interfaces +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.fingerprints import all_known_cars from openpilot.selfdrive.car.fw_versions import FW_VERSIONS, FW_QUERY_CONFIGS from openpilot.selfdrive.car.interfaces import get_interface_attr @@ -43,8 +45,8 @@ def get_fuzzy_car_interface_args(draw: DrawType) -> dict: }) params: dict = draw(params_strategy) - params['car_fw'] = [car.CarParams.CarFw(ecu=fw[0], address=fw[1], subAddress=fw[2] or 0, - request=draw(st.sampled_from(sorted(ALL_REQUESTS)))) + params['car_fw'] = [CarParams.CarFw(ecu=fw[0], address=fw[1], subAddress=fw[2] or 0, + request=draw(st.sampled_from(sorted(ALL_REQUESTS)))) for fw in params['car_fw']] return params @@ -63,7 +65,6 @@ def test_car_interfaces(self, car_name, data): car_params = CarInterface.get_params(car_name, args['fingerprints'], args['car_fw'], experimental_long=args['experimental_long'], docs=False) - car_params = car_params.as_reader() car_interface = CarInterface(car_params, CarController, CarState) assert car_params assert car_interface @@ -79,7 +80,7 @@ def test_car_interfaces(self, car_name, data): assert len(car_params.longitudinalTuning.kiV) == len(car_params.longitudinalTuning.kiBP) # Lateral sanity checks - if car_params.steerControlType != car.CarParams.SteerControlType.angle: + if car_params.steerControlType != CarParams.SteerControlType.angle: tune = car_params.lateralTuning if tune.which() == 'pid': if car_name != MOCK.MOCK: @@ -95,28 +96,31 @@ def test_car_interfaces(self, car_name, data): # Run car interface now_nanos = 0 CC = car.CarControl.new_message(**cc_msg) + CC = convert_carControl(CC.as_reader()) for _ in range(10): car_interface.update([]) - car_interface.apply(CC.as_reader(), now_nanos) + car_interface.apply(CC, now_nanos) now_nanos += DT_CTRL * 1e9 # 10 ms CC = car.CarControl.new_message(**cc_msg) CC.enabled = True + CC = convert_carControl(CC.as_reader()) for _ in range(10): car_interface.update([]) - car_interface.apply(CC.as_reader(), now_nanos) + car_interface.apply(CC, now_nanos) now_nanos += DT_CTRL * 1e9 # 10ms # Test controller initialization # TODO: wait until card refactor is merged to run controller a few times, # hypothesis also slows down significantly with just one more message draw - LongControl(car_params) - if car_params.steerControlType == car.CarParams.SteerControlType.angle: - LatControlAngle(car_params, car_interface) + car_params_capnp = convert_to_capnp(car_params).as_reader() + LongControl(car_params_capnp) + if car_params.steerControlType == CarParams.SteerControlType.angle: + LatControlAngle(car_params_capnp, car_interface) elif car_params.lateralTuning.which() == 'pid': - LatControlPID(car_params, car_interface) + LatControlPID(car_params_capnp, car_interface) elif car_params.lateralTuning.which() == 'torque': - LatControlTorque(car_params, car_interface) + LatControlTorque(car_params_capnp, car_interface) # Test radar interface RadarInterface = importlib.import_module(f'selfdrive.car.{car_params.carName}.radar_interface').RadarInterface diff --git a/selfdrive/car/tests/test_fw_fingerprint.py b/selfdrive/car/tests/test_fw_fingerprint.py index bd24054450a30b..c859287cbdf903 100644 --- a/selfdrive/car/tests/test_fw_fingerprint.py +++ b/selfdrive/car/tests/test_fw_fingerprint.py @@ -4,18 +4,16 @@ from collections import defaultdict from parameterized import parameterized -from cereal import car from openpilot.selfdrive.car.can_definitions import CanData from openpilot.selfdrive.car.car_helpers import interfaces +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.fingerprints import FW_VERSIONS from openpilot.selfdrive.car.fw_versions import ESSENTIAL_ECUS, FW_QUERY_CONFIGS, FUZZY_EXCLUDE_ECUS, VERSIONS, build_fw_dict, \ match_fw_to_car, get_brand_ecu_matches, get_fw_versions, get_fw_versions_ordered, get_present_ecus from openpilot.selfdrive.car.vin import get_vin -CarFw = car.CarParams.CarFw -Ecu = car.CarParams.Ecu - -ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()} +CarFw = CarParams.CarFw +Ecu = CarParams.Ecu class TestFwFingerprint: @@ -27,7 +25,7 @@ def assertFingerprints(self, candidates, expected): @parameterized.expand([(b, c, e[c], n) for b, e in VERSIONS.items() for c in e for n in (True, False)]) def test_exact_match(self, brand, car_model, ecus, test_non_essential): config = FW_QUERY_CONFIGS[brand] - CP = car.CarParams.new_message() + CP = CarParams() for _ in range(100): fw = [] for ecu, fw_versions in ecus.items(): @@ -37,8 +35,8 @@ def test_exact_match(self, brand, car_model, ecus, test_non_essential): continue ecu_name, addr, sub_addr = ecu - fw.append({"ecu": ecu_name, "fwVersion": random.choice(fw_versions), 'brand': brand, - "address": addr, "subAddress": 0 if sub_addr is None else sub_addr}) + fw.append(CarFw(ecu=ecu_name, fwVersion=random.choice(fw_versions), brand=brand, + address=addr, subAddress=0 if sub_addr is None else sub_addr)) CP.carFw = fw _, matches = match_fw_to_car(CP.carFw, CP.carVin, allow_fuzzy=False) if not test_non_essential: @@ -55,13 +53,13 @@ def test_custom_fuzzy_match(self, brand, car_model, ecus): if config.match_fw_to_car_fuzzy is None: pytest.skip("Brand does not implement custom fuzzy fingerprinting function") - CP = car.CarParams.new_message() + CP = CarParams() for _ in range(5): fw = [] for ecu, fw_versions in ecus.items(): ecu_name, addr, sub_addr = ecu - fw.append({"ecu": ecu_name, "fwVersion": random.choice(fw_versions), 'brand': brand, - "address": addr, "subAddress": 0 if sub_addr is None else sub_addr}) + fw.append(CarFw(ecu=ecu_name, fwVersion=random.choice(fw_versions), brand=brand, + address=addr, subAddress=0 if sub_addr is None else sub_addr)) CP.carFw = fw _, matches = match_fw_to_car(CP.carFw, CP.carVin, allow_exact=False, log=False) brand_matches = config.match_fw_to_car_fuzzy(build_fw_dict(CP.carFw), CP.carVin, VERSIONS[brand]) @@ -82,13 +80,13 @@ def test_fuzzy_match_ecu_count(self, brand, car_model, ecus): ecu_name, addr, sub_addr = ecu for _ in range(5): # Add multiple FW versions to simulate ECU returning to multiple queries in a brand - fw.append({"ecu": ecu_name, "fwVersion": random.choice(ecus[ecu]), 'brand': brand, - "address": addr, "subAddress": 0 if sub_addr is None else sub_addr}) - CP = car.CarParams.new_message(carFw=fw) + fw.append(CarFw(ecu=ecu_name, fwVersion=random.choice(ecus[ecu]), brand=brand, + address=addr, subAddress=0 if sub_addr is None else sub_addr)) + CP = CarParams(carFw=fw) _, matches = match_fw_to_car(CP.carFw, CP.carVin, allow_exact=False, log=False) # Assert no match if there are not enough unique ECUs - unique_ecus = {(f['address'], f['subAddress']) for f in fw} + unique_ecus = {(f.address, f.subAddress) for f in fw} if len(unique_ecus) < 2: assert len(matches) == 0, car_model # There won't always be a match due to shared FW, but if there is it should be correct @@ -99,10 +97,10 @@ def test_fw_version_lists(self, subtests): for car_model, ecus in FW_VERSIONS.items(): with subtests.test(car_model=car_model.value): for ecu, ecu_fw in ecus.items(): - with subtests.test(ecu): + with subtests.test((ecu[0].value, ecu[1], ecu[2])): duplicates = {fw for fw in ecu_fw if ecu_fw.count(fw) > 1} - assert not len(duplicates), f'{car_model}: Duplicate FW versions: Ecu.{ECU_NAME[ecu[0]]}, {duplicates}' - assert len(ecu_fw) > 0, f'{car_model}: No FW versions: Ecu.{ECU_NAME[ecu[0]]}' + assert not len(duplicates), f'{car_model}: Duplicate FW versions: Ecu.{ecu[0]}, {duplicates}' + assert len(ecu_fw) > 0, f'{car_model}: No FW versions: Ecu.{ecu[0]}' def test_all_addrs_map_to_one_ecu(self): for brand, cars in VERSIONS.items(): @@ -111,7 +109,7 @@ def test_all_addrs_map_to_one_ecu(self): for ecu_type, addr, sub_addr in ecus.keys(): addr_to_ecu[(addr, sub_addr)].add(ecu_type) ecus_for_addr = addr_to_ecu[(addr, sub_addr)] - ecu_strings = ", ".join([f'Ecu.{ECU_NAME[ecu]}' for ecu in ecus_for_addr]) + ecu_strings = ", ".join([f'Ecu.{ecu}' for ecu in ecus_for_addr]) assert len(ecus_for_addr) <= 1, f"{brand} has multiple ECUs that map to one address: {ecu_strings} -> ({hex(addr)}, {sub_addr})" def test_data_collection_ecus(self, subtests): @@ -129,13 +127,13 @@ def test_blacklisted_ecus(self, subtests): CP = interfaces[car_model][0].get_non_essential_params(car_model) if CP.carName == 'subaru': for ecu in ecus.keys(): - assert ecu[1] not in blacklisted_addrs, f'{car_model}: Blacklisted ecu: (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])})' + assert ecu[1] not in blacklisted_addrs, f'{car_model}: Blacklisted ecu: (Ecu.{ecu[0]}, {hex(ecu[1])})' elif CP.carName == "chrysler": # Some HD trucks have a combined TCM and ECM if CP.carFingerprint.startswith("RAM_HD"): for ecu in ecus.keys(): - assert ecu[0] != Ecu.transmission, f"{car_model}: Blacklisted ecu: (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])})" + assert ecu[0] != Ecu.transmission, f"{car_model}: Blacklisted ecu: (Ecu.{ecu[0]}, {hex(ecu[1])})" def test_non_essential_ecus(self, subtests): for brand, config in FW_QUERY_CONFIGS.items(): @@ -143,7 +141,7 @@ def test_non_essential_ecus(self, subtests): # These ECUs are already not in ESSENTIAL_ECUS which the fingerprint functions give a pass if missing unnecessary_non_essential_ecus = set(config.non_essential_ecus) - set(ESSENTIAL_ECUS) assert unnecessary_non_essential_ecus == set(), "Declaring non-essential ECUs non-essential is not required: " + \ - f"{', '.join([f'Ecu.{ECU_NAME[ecu]}' for ecu in unnecessary_non_essential_ecus])}" + f"{', '.join([f'Ecu.{ecu}' for ecu in unnecessary_non_essential_ecus])}" def test_missing_versions_and_configs(self, subtests): brand_versions = set(VERSIONS.keys()) @@ -172,7 +170,7 @@ def test_fw_request_ecu_whitelist(self, subtests): # each ecu in brand's fw versions + extra ecus needs to be whitelisted at least once ecus_not_whitelisted = brand_ecus - whitelisted_ecus - ecu_strings = ", ".join([f'Ecu.{ECU_NAME[ecu]}' for ecu in ecus_not_whitelisted]) + ecu_strings = ", ".join([f'Ecu.{ecu}' for ecu in ecus_not_whitelisted]) assert not (len(whitelisted_ecus) and len(ecus_not_whitelisted)), \ f'{brand.title()}: ECUs not in any FW query whitelists: {ecu_strings}' diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index c8b0b0fc1f413a..eecb6c1ba947b2 100644 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -1,4 +1,6 @@ import capnp +import copy +import dataclasses import os import importlib import pytest @@ -13,12 +15,13 @@ from openpilot.common.basedir import BASEDIR from openpilot.common.params import Params from openpilot.selfdrive.car import DT_CTRL, gen_empty_fingerprint +from openpilot.selfdrive.car import structs from openpilot.selfdrive.car.fingerprints import all_known_cars, MIGRATION from openpilot.selfdrive.car.car_helpers import FRAME_FINGERPRINT, interfaces from openpilot.selfdrive.car.honda.values import CAR as HONDA, HondaFlags from openpilot.selfdrive.car.tests.routes import non_tested_cars, routes, CarTestRoute from openpilot.selfdrive.car.values import Platform -from openpilot.selfdrive.car.card import Car +from openpilot.selfdrive.car.card import Car, convert_to_capnp from openpilot.selfdrive.pandad import can_capnp_to_list from openpilot.selfdrive.test.helpers import read_segment_list from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT @@ -181,7 +184,7 @@ def tearDownClass(cls): del cls.can_msgs def setUp(self): - self.CI = self.CarInterface(self.CP.copy(), self.CarController, self.CarState) + self.CI = self.CarInterface(copy.deepcopy(self.CP), self.CarController, self.CarState) assert self.CI Params().put_bool("OpenpilotEnabledToggle", self.openpilot_enabled) @@ -189,7 +192,7 @@ def setUp(self): # TODO: check safetyModel is in release panda build self.safety = libpanda_py.libpanda - cfg = self.CP.safetyConfigs[-1] + cfg = car.CarParams.SafetyConfig(**dataclasses.asdict(self.CP.safetyConfigs[-1])) set_status = self.safety.set_safety_hooks(cfg.safetyModel.raw, cfg.safetyParam) self.assertEqual(0, set_status, f"failed to set safetyModel {cfg}") self.safety.init_tests() @@ -201,7 +204,7 @@ def test_car_params(self): # make sure car params are within a valid range self.assertGreater(self.CP.mass, 1) - if self.CP.steerControlType != car.CarParams.SteerControlType.angle: + if self.CP.steerControlType != structs.CarParams.SteerControlType.angle: tuning = self.CP.lateralTuning.which() if tuning == 'pid': self.assertTrue(len(self.CP.lateralTuning.pid.kpV)) @@ -214,7 +217,7 @@ def test_car_interface(self): # TODO: also check for checksum violations from can parser can_invalid_cnt = 0 can_valid = False - CC = car.CarControl.new_message().as_reader() + CC = structs.CarControl() for i, msg in enumerate(self.can_msgs): CS = self.CI.update(can_capnp_to_list((msg.as_builder().to_bytes(),))) @@ -238,9 +241,9 @@ def test_radar_interface(self): # start parsing CAN messages after we've left ELM mode and can expect CAN traffic error_cnt = 0 for i, msg in enumerate(self.can_msgs[self.elm_frame:]): - rr = RI.update(can_capnp_to_list((msg.as_builder().to_bytes(),))) + rr: structs.RadarData | None = RI.update(can_capnp_to_list((msg.as_builder().to_bytes(),))) if rr is not None and i > 50: - error_cnt += car.RadarData.Error.canError in rr.errors + error_cnt += structs.RadarData.Error.canError in rr.errors self.assertEqual(error_cnt, 0) def test_panda_safety_rx_checks(self): @@ -306,18 +309,18 @@ def test_car_controller(car_control): self.assertGreater(msgs_sent, 50) # Make sure we can send all messages while inactive - CC = car.CarControl.new_message() - test_car_controller(CC.as_reader()) + CC = structs.CarControl() + test_car_controller(CC) # Test cancel + general messages (controls_allowed=False & cruise_engaged=True) self.safety.set_cruise_engaged_prev(True) - CC = car.CarControl.new_message(cruiseControl={'cancel': True}) - test_car_controller(CC.as_reader()) + CC = structs.CarControl(cruiseControl=structs.CarControl.CruiseControl(cancel=True)) + test_car_controller(CC) # Test resume + general messages (controls_allowed=True & cruise_engaged=True) self.safety.set_controls_allowed(True) - CC = car.CarControl.new_message(cruiseControl={'resume': True}) - test_car_controller(CC.as_reader()) + CC = structs.CarControl(cruiseControl=structs.CarControl.CruiseControl(resume=True)) + test_car_controller(CC) # Skip stdout/stderr capture with pytest, causes elevated memory usage @pytest.mark.nocapture @@ -403,7 +406,7 @@ def test_panda_safety_carstate(self): checks = defaultdict(int) card = Car(CI=self.CI) for idx, can in enumerate(self.can_msgs): - CS = self.CI.update(can_capnp_to_list((can.as_builder().to_bytes(), ))) + CS = convert_to_capnp(self.CI.update(can_capnp_to_list((can.as_builder().to_bytes(), )))) for msg in filter(lambda m: m.src in range(64), can.can): to_send = libpanda_py.make_CANPacket(msg.address, msg.src % 4, msg.dat) ret = self.safety.safety_rx_hook(to_send) diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index 427796cae99061..aaaf072de727e3 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -1,5 +1,5 @@ -from cereal import car -from openpilot.selfdrive.car import apply_meas_steer_torque_limits, apply_std_steer_angle_limits, common_fault_avoidance, make_tester_present_msg +import copy +from openpilot.selfdrive.car import apply_meas_steer_torque_limits, apply_std_steer_angle_limits, common_fault_avoidance, make_tester_present_msg, structs from openpilot.selfdrive.car.can_definitions import CanData from openpilot.selfdrive.car.common.numpy_fast import clip from openpilot.selfdrive.car.interfaces import CarControllerBase @@ -9,8 +9,8 @@ UNSUPPORTED_DSU_CAR from opendbc.can.packer import CANPacker -SteerControlType = car.CarParams.SteerControlType -VisualAlert = car.CarControl.HUDControl.VisualAlert +SteerControlType = structs.CarParams.SteerControlType +VisualAlert = structs.CarControl.HUDControl.VisualAlert # LKA limits # EPS faults if you apply torque while the steering rate is above 100 deg/s for too long @@ -168,7 +168,7 @@ def update(self, CC, CS, now_nanos): if self.frame % 20 == 0 and self.CP.flags & ToyotaFlags.DISABLE_RADAR.value: can_sends.append(make_tester_present_msg(0x750, 0, 0xF)) - new_actuators = actuators.as_builder() + new_actuators = copy.copy(actuators) new_actuators.steer = apply_steer / self.params.STEER_MAX new_actuators.steerOutputCan = apply_steer new_actuators.steeringAngleDeg = self.last_angle diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py index bea4e408961673..2970d8c34dbbb1 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -1,9 +1,8 @@ import copy -from cereal import car from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser -from openpilot.selfdrive.car import DT_CTRL, create_button_events +from openpilot.selfdrive.car import DT_CTRL, create_button_events, structs from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.common.filter_simple import FirstOrderFilter from openpilot.selfdrive.car.common.numpy_fast import mean @@ -11,8 +10,8 @@ from openpilot.selfdrive.car.toyota.values import ToyotaFlags, CAR, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, \ TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR -ButtonType = car.CarState.ButtonEvent.Type -SteerControlType = car.CarParams.SteerControlType +ButtonType = structs.CarState.ButtonEvent.Type +SteerControlType = structs.CarParams.SteerControlType # These steering fault definitions seem to be common across LKA (torque) and LTA (angle): # - high steer rate fault: goes to 21 or 25 for 1 frame, then 9 for 2 seconds @@ -49,8 +48,8 @@ def __init__(self, CP): self.acc_type = 1 self.lkas_hud = {} - def update(self, cp, cp_cam, *_): - ret = car.CarState.new_message() + def update(self, cp, cp_cam, *_) -> structs.CarState: + ret = structs.CarState() ret.doorOpen = any([cp.vl["BODY_CONTROL_STATE"]["DOOR_OPEN_FL"], cp.vl["BODY_CONTROL_STATE"]["DOOR_OPEN_FR"], cp.vl["BODY_CONTROL_STATE"]["DOOR_OPEN_RL"], cp.vl["BODY_CONTROL_STATE"]["DOOR_OPEN_RR"]]) diff --git a/selfdrive/car/toyota/fingerprints.py b/selfdrive/car/toyota/fingerprints.py index 292be96fc85e73..6a0bbbdf9442ac 100644 --- a/selfdrive/car/toyota/fingerprints.py +++ b/selfdrive/car/toyota/fingerprints.py @@ -1,7 +1,7 @@ -from cereal import car +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.toyota.values import CAR -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu FW_VERSIONS = { CAR.TOYOTA_AVALON: { diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index fb63ab557b2084..39586a8de8aff7 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -1,13 +1,12 @@ -from cereal import car from panda import Panda from panda.python import uds +from openpilot.selfdrive.car import structs, get_safety_config from openpilot.selfdrive.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, \ MIN_ACC_SPEED, EPS_SCALE, UNSUPPORTED_DSU_CAR, NO_STOP_TIMER_CAR, ANGLE_CONTROL_CAR -from openpilot.selfdrive.car import get_safety_config from openpilot.selfdrive.car.disable_ecu import disable_ecu from openpilot.selfdrive.car.interfaces import CarInterfaceBase -SteerControlType = car.CarParams.SteerControlType +SteerControlType = structs.CarParams.SteerControlType class CarInterface(CarInterfaceBase): @@ -16,9 +15,9 @@ def get_pid_accel_limits(CP, current_speed, cruise_speed): return CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX @staticmethod - def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams: ret.carName = "toyota" - ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.toyota)] + ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.toyota)] ret.safetyConfigs[0].safetyParam = EPS_SCALE[candidate] # BRAKE_MODULE is on a different address for these cars diff --git a/selfdrive/car/toyota/radar_interface.py b/selfdrive/car/toyota/radar_interface.py index fae6eecaf634e2..162b8a891db4e4 100755 --- a/selfdrive/car/toyota/radar_interface.py +++ b/selfdrive/car/toyota/radar_interface.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 from opendbc.can.parser import CANParser -from cereal import car +from openpilot.selfdrive.car.structs import RadarData from openpilot.selfdrive.car.toyota.values import DBC, TSS2_CAR from openpilot.selfdrive.car.interfaces import RadarInterfaceBase @@ -54,7 +54,7 @@ def update(self, can_strings): return rr def _update(self, updated_messages): - ret = car.RadarData.new_message() + ret = RadarData() errors = [] if not self.rcp.can_valid: errors.append("canError") @@ -77,7 +77,7 @@ def _update(self, updated_messages): # radar point only valid if it's a valid measurement and score is above 50 if cpt['VALID'] or (score > 50 and cpt['LONG_DIST'] < 255 and self.valid_cnt[ii] > 0): if ii not in self.pts or cpt['NEW_TRACK']: - self.pts[ii] = car.RadarData.RadarPoint.new_message() + self.pts[ii] = RadarData.RadarPoint() self.pts[ii].trackId = self.track_id self.track_id += 1 self.pts[ii].dRel = cpt['LONG_DIST'] # from front of car diff --git a/selfdrive/car/toyota/tests/print_platform_codes.py b/selfdrive/car/toyota/tests/print_platform_codes.py index 9ec7a14cd3eed0..495a9f72429b3d 100755 --- a/selfdrive/car/toyota/tests/print_platform_codes.py +++ b/selfdrive/car/toyota/tests/print_platform_codes.py @@ -1,19 +1,15 @@ #!/usr/bin/env python3 from collections import defaultdict -from cereal import car from openpilot.selfdrive.car.toyota.values import PLATFORM_CODE_ECUS, get_platform_codes from openpilot.selfdrive.car.toyota.fingerprints import FW_VERSIONS -Ecu = car.CarParams.Ecu -ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()} - if __name__ == "__main__": parts_for_ecu: dict = defaultdict(set) cars_for_code: dict = defaultdict(lambda: defaultdict(set)) for car_model, ecus in FW_VERSIONS.items(): print() print(car_model) - for ecu in sorted(ecus, key=lambda x: int(x[0])): + for ecu in sorted(ecus): if ecu[0] not in PLATFORM_CODE_ECUS: continue @@ -21,15 +17,15 @@ parts_for_ecu[ecu] |= {code.split(b'-')[0] for code in platform_codes if code.count(b'-') > 1} for code in platform_codes: cars_for_code[ecu][b'-'.join(code.split(b'-')[:2])] |= {car_model} - print(f' (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])}, {ecu[2]}):') + print(f' (Ecu.{ecu[0]}, {hex(ecu[1])}, {ecu[2]}):') print(f' Codes: {platform_codes}') print('\nECU parts:') for ecu, parts in parts_for_ecu.items(): - print(f' (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])}, {ecu[2]}): {parts}') + print(f' (Ecu.{ecu[0]}, {hex(ecu[1])}, {ecu[2]}): {parts}') print('\nCar models vs. platform codes (no major versions):') for ecu, codes in cars_for_code.items(): - print(f' (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])}, {ecu[2]}):') + print(f' (Ecu.{ecu[0]}, {hex(ecu[1])}, {ecu[2]}):') for code, cars in codes.items(): print(f' {code!r}: {sorted(cars)}') diff --git a/selfdrive/car/toyota/tests/test_toyota.py b/selfdrive/car/toyota/tests/test_toyota.py index 75e3ea70378d87..6648e56cef16ba 100644 --- a/selfdrive/car/toyota/tests/test_toyota.py +++ b/selfdrive/car/toyota/tests/test_toyota.py @@ -1,14 +1,13 @@ from hypothesis import given, settings, strategies as st -from cereal import car +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.fw_versions import build_fw_dict from openpilot.selfdrive.car.toyota.fingerprints import FW_VERSIONS from openpilot.selfdrive.car.toyota.values import CAR, DBC, TSS2_CAR, ANGLE_CONTROL_CAR, RADAR_ACC_CAR, \ FW_QUERY_CONFIG, PLATFORM_CODE_ECUS, FUZZY_EXCLUDED_PLATFORMS, \ get_platform_codes -Ecu = car.CarParams.Ecu -ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()} +Ecu = CarParams.Ecu def check_fw_version(fw_version: bytes) -> bool: @@ -153,10 +152,10 @@ def test_fuzzy_excluded_platforms(self): for ecu, fw_versions in fw_by_addr.items(): ecu_name, addr, sub_addr = ecu for fw in fw_versions: - car_fw.append({"ecu": ecu_name, "fwVersion": fw, "address": addr, - "subAddress": 0 if sub_addr is None else sub_addr}) + car_fw.append(CarParams.CarFw(ecu=ecu_name, fwVersion=fw, address=addr, + subAddress=0 if sub_addr is None else sub_addr)) - CP = car.CarParams.new_message(carFw=car_fw) + CP = CarParams(carFw=car_fw) matches = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(build_fw_dict(CP.carFw), CP.carVin, FW_VERSIONS) if len(matches) == 1: assert list(matches)[0] == platform diff --git a/selfdrive/car/toyota/toyotacan.py b/selfdrive/car/toyota/toyotacan.py index 1cc99b41b57873..8068b8e1438410 100644 --- a/selfdrive/car/toyota/toyotacan.py +++ b/selfdrive/car/toyota/toyotacan.py @@ -1,6 +1,6 @@ -from cereal import car +from openpilot.selfdrive.car.structs import CarParams -SteerControlType = car.CarParams.SteerControlType +SteerControlType = CarParams.SteerControlType def create_steer_command(packer, steer, steer_req): diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 345fe3c1f5bc46..e10eba13b47b8e 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -3,13 +3,13 @@ from dataclasses import dataclass, field from enum import Enum, IntFlag -from cereal import car from openpilot.selfdrive.car import CarSpecs, PlatformConfig, Platforms, AngleRateLimit, dbc_dict from openpilot.selfdrive.car.conversions import Conversions as CV +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarDocs, Column, CarParts, CarHarness from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu MIN_ACC_SPEED = 19. * CV.MPH_TO_MS PEDAL_TRANSITION = 10. * CV.MPH_TO_MS diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py index cc76aaf493d23a..72168f6e45d18a 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -1,14 +1,14 @@ -from cereal import car +import copy from opendbc.can.packer import CANPacker -from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits +from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits, structs from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.common.numpy_fast import clip from openpilot.selfdrive.car.interfaces import CarControllerBase from openpilot.selfdrive.car.volkswagen import mqbcan, pqcan from openpilot.selfdrive.car.volkswagen.values import CANBUS, CarControllerParams, VolkswagenFlags -VisualAlert = car.CarControl.HUDControl.VisualAlert -LongCtrlState = car.CarControl.Actuators.LongControlState +VisualAlert = structs.CarControl.HUDControl.VisualAlert +LongCtrlState = structs.CarControl.Actuators.LongControlState class CarController(CarControllerBase): @@ -17,7 +17,7 @@ def __init__(self, dbc_name, CP): self.CCP = CarControllerParams(CP) self.CCS = pqcan if CP.flags & VolkswagenFlags.PQ else mqbcan self.packer_pt = CANPacker(dbc_name) - self.ext_bus = CANBUS.pt if CP.networkLocation == car.CarParams.NetworkLocation.fwdCamera else CANBUS.cam + self.ext_bus = CANBUS.pt if CP.networkLocation == structs.CarParams.NetworkLocation.fwdCamera else CANBUS.cam self.apply_steer_last = 0 self.gra_acc_counter_last = None @@ -110,7 +110,7 @@ def update(self, CC, CS, now_nanos): can_sends.append(self.CCS.create_acc_buttons_control(self.packer_pt, self.ext_bus, CS.gra_stock_values, cancel=CC.cruiseControl.cancel, resume=CC.cruiseControl.resume)) - new_actuators = actuators.as_builder() + new_actuators = copy.copy(actuators) new_actuators.steer = self.apply_steer_last / self.CCP.STEER_MAX new_actuators.steerOutputCan = self.apply_steer_last diff --git a/selfdrive/car/volkswagen/carstate.py b/selfdrive/car/volkswagen/carstate.py index 31343887a41d9f..8feb0642b580d3 100644 --- a/selfdrive/car/volkswagen/carstate.py +++ b/selfdrive/car/volkswagen/carstate.py @@ -1,6 +1,6 @@ import numpy as np -from cereal import car from opendbc.can.parser import CANParser +from openpilot.selfdrive.car import structs from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.volkswagen.values import DBC, CANBUS, NetworkLocation, TransmissionType, GearShifter, \ @@ -24,7 +24,7 @@ def create_button_events(self, pt_cp, buttons): for button in buttons: state = pt_cp.vl[button.can_addr][button.can_msg] in button.values if self.button_states[button.event_type] != state: - event = car.CarState.ButtonEvent.new_message() + event = structs.CarState.ButtonEvent() event.type = button.event_type event.pressed = state button_events.append(event) @@ -32,14 +32,14 @@ def create_button_events(self, pt_cp, buttons): return button_events - def update(self, pt_cp, cam_cp, *_): + def update(self, pt_cp, cam_cp, *_) -> structs.CarState: ext_cp = pt_cp if self.CP.networkLocation == NetworkLocation.fwdCamera else cam_cp if self.CP.flags & VolkswagenFlags.PQ: return self.update_pq(pt_cp, cam_cp, ext_cp) - ret = car.CarState.new_message() + ret = structs.CarState() # Update vehicle speed and acceleration from ABS wheel speeds. ret.wheelSpeeds = self.get_wheel_speeds( pt_cp.vl["ESP_19"]["ESP_VL_Radgeschw_02"], @@ -158,8 +158,8 @@ def update(self, pt_cp, cam_cp, *_): self.frame += 1 return ret - def update_pq(self, pt_cp, cam_cp, ext_cp): - ret = car.CarState.new_message() + def update_pq(self, pt_cp, cam_cp, ext_cp) -> structs.CarState: + ret = structs.CarState() # Update vehicle speed and acceleration from ABS wheel speeds. ret.wheelSpeeds = self.get_wheel_speeds( pt_cp.vl["Bremse_3"]["Radgeschw__VL_4_1"], diff --git a/selfdrive/car/volkswagen/fingerprints.py b/selfdrive/car/volkswagen/fingerprints.py index f78fbb6591485c..4c17b9113fa19d 100644 --- a/selfdrive/car/volkswagen/fingerprints.py +++ b/selfdrive/car/volkswagen/fingerprints.py @@ -1,7 +1,7 @@ -from cereal import car +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.volkswagen.values import CAR -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu # TODO: Sharan Mk2 EPS and DQ250 auto trans both require KWP2000 support for fingerprinting diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index 48656d5e82cad5..96f3493fe8e930 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -1,19 +1,18 @@ -from cereal import car from panda import Panda -from openpilot.selfdrive.car import get_safety_config +from openpilot.selfdrive.car import get_safety_config, structs from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.volkswagen.values import CAR, NetworkLocation, TransmissionType, VolkswagenFlags class CarInterface(CarInterfaceBase): @staticmethod - def _get_params(ret, candidate: CAR, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret: structs.CarParams, candidate: CAR, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams: ret.carName = "volkswagen" ret.radarUnavailable = True if ret.flags & VolkswagenFlags.PQ: # Set global PQ35/PQ46/NMS parameters - ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.volkswagenPq)] + ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.volkswagenPq)] ret.enableBsm = 0x3BA in fingerprint[0] # SWA_1 if 0x440 in fingerprint[0] or docs: # Getriebe_1 @@ -36,7 +35,7 @@ def _get_params(ret, candidate: CAR, fingerprint, car_fw, experimental_long, doc else: # Set global MQB parameters - ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.volkswagen)] + ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.volkswagen)] ret.enableBsm = 0x30F in fingerprint[0] # SWA_01 if 0xAD in fingerprint[0] or docs: # Getriebe_11 diff --git a/selfdrive/car/volkswagen/tests/test_volkswagen.py b/selfdrive/car/volkswagen/tests/test_volkswagen.py index 00025781057324..ba27806ddab0a8 100644 --- a/selfdrive/car/volkswagen/tests/test_volkswagen.py +++ b/selfdrive/car/volkswagen/tests/test_volkswagen.py @@ -1,11 +1,11 @@ import random import re -from cereal import car +from openpilot.selfdrive.car.structs import CarParams from openpilot.selfdrive.car.volkswagen.values import CAR, FW_QUERY_CONFIG, WMI from openpilot.selfdrive.car.volkswagen.fingerprints import FW_VERSIONS -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu CHASSIS_CODE_PATTERN = re.compile('[A-Z0-9]{2}') # TODO: determine the unknown groups diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 27816712f6da26..f4562f3c0931ac 100644 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -2,19 +2,19 @@ from dataclasses import dataclass, field from enum import Enum, IntFlag, StrEnum -from cereal import car from panda.python import uds from opendbc.can.can_define import CANDefine from openpilot.selfdrive.car import dbc_dict, CarSpecs, DbcDict, PlatformConfig, Platforms from openpilot.selfdrive.car.conversions import Conversions as CV +from openpilot.selfdrive.car import structs from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column, \ Device from openpilot.selfdrive.car.fw_query_definitions import EcuAddrSubAddr, FwQueryConfig, Request, p16 -Ecu = car.CarParams.Ecu -NetworkLocation = car.CarParams.NetworkLocation -TransmissionType = car.CarParams.TransmissionType -GearShifter = car.CarState.GearShifter +Ecu = structs.CarParams.Ecu +NetworkLocation = structs.CarParams.NetworkLocation +TransmissionType = structs.CarParams.TransmissionType +GearShifter = structs.CarState.GearShifter Button = namedtuple('Button', ['event_type', 'can_addr', 'can_msg', 'values']) @@ -54,12 +54,12 @@ def __init__(self, CP): self.hca_status_values = can_define.dv["Lenkhilfe_2"]["LH2_Sta_HCA"] self.BUTTONS = [ - Button(car.CarState.ButtonEvent.Type.setCruise, "GRA_Neu", "GRA_Neu_Setzen", [1]), - Button(car.CarState.ButtonEvent.Type.resumeCruise, "GRA_Neu", "GRA_Recall", [1]), - Button(car.CarState.ButtonEvent.Type.accelCruise, "GRA_Neu", "GRA_Up_kurz", [1]), - Button(car.CarState.ButtonEvent.Type.decelCruise, "GRA_Neu", "GRA_Down_kurz", [1]), - Button(car.CarState.ButtonEvent.Type.cancel, "GRA_Neu", "GRA_Abbrechen", [1]), - Button(car.CarState.ButtonEvent.Type.gapAdjustCruise, "GRA_Neu", "GRA_Zeitluecke", [1]), + Button(structs.CarState.ButtonEvent.Type.setCruise, "GRA_Neu", "GRA_Neu_Setzen", [1]), + Button(structs.CarState.ButtonEvent.Type.resumeCruise, "GRA_Neu", "GRA_Recall", [1]), + Button(structs.CarState.ButtonEvent.Type.accelCruise, "GRA_Neu", "GRA_Up_kurz", [1]), + Button(structs.CarState.ButtonEvent.Type.decelCruise, "GRA_Neu", "GRA_Down_kurz", [1]), + Button(structs.CarState.ButtonEvent.Type.cancel, "GRA_Neu", "GRA_Abbrechen", [1]), + Button(structs.CarState.ButtonEvent.Type.gapAdjustCruise, "GRA_Neu", "GRA_Zeitluecke", [1]), ] self.LDW_MESSAGES = { @@ -85,12 +85,12 @@ def __init__(self, CP): self.hca_status_values = can_define.dv["LH_EPS_03"]["EPS_HCA_Status"] self.BUTTONS = [ - Button(car.CarState.ButtonEvent.Type.setCruise, "GRA_ACC_01", "GRA_Tip_Setzen", [1]), - Button(car.CarState.ButtonEvent.Type.resumeCruise, "GRA_ACC_01", "GRA_Tip_Wiederaufnahme", [1]), - Button(car.CarState.ButtonEvent.Type.accelCruise, "GRA_ACC_01", "GRA_Tip_Hoch", [1]), - Button(car.CarState.ButtonEvent.Type.decelCruise, "GRA_ACC_01", "GRA_Tip_Runter", [1]), - Button(car.CarState.ButtonEvent.Type.cancel, "GRA_ACC_01", "GRA_Abbrechen", [1]), - Button(car.CarState.ButtonEvent.Type.gapAdjustCruise, "GRA_ACC_01", "GRA_Verstellung_Zeitluecke", [1]), + Button(structs.CarState.ButtonEvent.Type.setCruise, "GRA_ACC_01", "GRA_Tip_Setzen", [1]), + Button(structs.CarState.ButtonEvent.Type.resumeCruise, "GRA_ACC_01", "GRA_Tip_Wiederaufnahme", [1]), + Button(structs.CarState.ButtonEvent.Type.accelCruise, "GRA_ACC_01", "GRA_Tip_Hoch", [1]), + Button(structs.CarState.ButtonEvent.Type.decelCruise, "GRA_ACC_01", "GRA_Tip_Runter", [1]), + Button(structs.CarState.ButtonEvent.Type.cancel, "GRA_ACC_01", "GRA_Abbrechen", [1]), + Button(structs.CarState.ButtonEvent.Type.gapAdjustCruise, "GRA_ACC_01", "GRA_Verstellung_Zeitluecke", [1]), ] self.LDW_MESSAGES = { @@ -190,7 +190,7 @@ class VWCarDocs(CarDocs): package: str = "Adaptive Cruise Control (ACC) & Lane Assist" car_parts: CarParts = field(default_factory=CarParts.common([CarHarness.vw_j533])) - def init_make(self, CP: car.CarParams): + def init_make(self, CP: structs.CarParams): self.footnotes.append(Footnote.VW_EXP_LONG) if "SKODA" in CP.carFingerprint: self.footnotes.append(Footnote.SKODA_HEATED_WINDSHIELD) diff --git a/selfdrive/controls/lib/tests/test_latcontrol.py b/selfdrive/controls/lib/tests/test_latcontrol.py index 4835aa234964bd..2f4a2aef812564 100644 --- a/selfdrive/controls/lib/tests/test_latcontrol.py +++ b/selfdrive/controls/lib/tests/test_latcontrol.py @@ -1,6 +1,7 @@ from parameterized import parameterized from cereal import car, log +from openpilot.selfdrive.car.card import convert_to_capnp from openpilot.selfdrive.car.car_helpers import interfaces from openpilot.selfdrive.car.honda.values import CAR as HONDA from openpilot.selfdrive.car.toyota.values import CAR as TOYOTA @@ -20,6 +21,7 @@ def test_saturation(self, car_name, controller): CarInterface, CarController, CarState = interfaces[car_name] CP = CarInterface.get_non_essential_params(car_name) CI = CarInterface(CP, CarController, CarState) + CP = convert_to_capnp(CP) VM = VehicleModel(CP) controller = controller(CP.as_reader(), CI) diff --git a/selfdrive/controls/lib/tests/test_vehicle_model.py b/selfdrive/controls/lib/tests/test_vehicle_model.py index f666f875a69d95..dae465a50d0556 100644 --- a/selfdrive/controls/lib/tests/test_vehicle_model.py +++ b/selfdrive/controls/lib/tests/test_vehicle_model.py @@ -3,6 +3,7 @@ import numpy as np +from openpilot.selfdrive.car.card import convert_to_capnp from openpilot.selfdrive.car.honda.interface import CarInterface from openpilot.selfdrive.car.honda.values import CAR from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel, dyn_ss_sol, create_dyn_state_matrices @@ -11,7 +12,7 @@ class TestVehicleModel: def setup_method(self): CP = CarInterface.get_non_essential_params(CAR.HONDA_CIVIC) - self.VM = VehicleModel(CP) + self.VM = VehicleModel(convert_to_capnp(CP)) def test_round_trip_yaw_rate(self): # TODO: fix VM to work at zero speed diff --git a/selfdrive/controls/radard.py b/selfdrive/controls/radard.py index bf19801a87b460..eb1cdb2d2c5c6d 100755 --- a/selfdrive/controls/radard.py +++ b/selfdrive/controls/radard.py @@ -11,6 +11,7 @@ from openpilot.common.realtime import DT_CTRL, Ratekeeper, Priority, config_realtime_process from openpilot.common.swaglog import cloudlog from openpilot.common.simple_kalman import KF1D +from openpilot.selfdrive.car import structs from openpilot.selfdrive.pandad import can_capnp_to_list @@ -208,7 +209,7 @@ def __init__(self, radar_ts: float, delay: int = 0): self.ready = False - def update(self, sm: messaging.SubMaster, rr: car.RadarData): + def update(self, sm: messaging.SubMaster, rr: structs.RadarData): self.ready = sm.seen['modelV2'] self.current_time = 1e-9*max(sm.logMonoTime.values()) @@ -301,7 +302,7 @@ def main() -> None: while 1: can_strings = messaging.drain_sock_raw(can_sock, wait_for_one=True) - rr: car.RadarData | None = RI.update(can_capnp_to_list(can_strings)) + rr: structs.RadarData | None = RI.update(can_capnp_to_list(can_strings)) sm.update(0) if rr is None: continue diff --git a/selfdrive/debug/format_fingerprints.py b/selfdrive/debug/format_fingerprints.py index 2a5e4e60802e5a..ac4cef0ccca694 100755 --- a/selfdrive/debug/format_fingerprints.py +++ b/selfdrive/debug/format_fingerprints.py @@ -2,28 +2,24 @@ import jinja2 import os -from cereal import car from openpilot.common.basedir import BASEDIR from openpilot.selfdrive.car.interfaces import get_interface_attr -Ecu = car.CarParams.Ecu - CARS = get_interface_attr('CAR') FW_VERSIONS = get_interface_attr('FW_VERSIONS') FINGERPRINTS = get_interface_attr('FINGERPRINTS') -ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()} FINGERPRINTS_PY_TEMPLATE = jinja2.Template(""" {%- if FINGERPRINTS[brand] %} # ruff: noqa: E501 {% endif %} {% if FW_VERSIONS[brand] %} -from cereal import car +from openpilot.selfdrive.car.structs import CarParams {% endif %} from openpilot.selfdrive.car.{{brand}}.values import CAR {% if FW_VERSIONS[brand] %} -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu {% endif %} {% if comments +%} {{ comments | join() }} @@ -49,7 +45,7 @@ {% for car, _ in FW_VERSIONS[brand].items() %} CAR.{{car.name}}: { {% for key, fw_versions in FW_VERSIONS[brand][car].items() %} - (Ecu.{{ECU_NAME[key[0]]}}, 0x{{"%0x" | format(key[1] | int)}}, \ + (Ecu.{{key[0]}}, 0x{{"%0x" | format(key[1] | int)}}, \ {% if key[2] %}0x{{"%0x" | format(key[2] | int)}}{% else %}{{key[2]}}{% endif %}): [ {% for fw_version in (fw_versions + extra_fw_versions.get(car, {}).get(key, [])) | unique | sort %} {{fw_version}}, @@ -71,9 +67,8 @@ def format_brand_fw_versions(brand, extra_fw_versions: None | dict[str, dict[tup comments = [line for line in f.readlines() if line.startswith("#") and "noqa" not in line] with open(fingerprints_file, "w") as f: - f.write(FINGERPRINTS_PY_TEMPLATE.render(brand=brand, comments=comments, ECU_NAME=ECU_NAME, - FINGERPRINTS=FINGERPRINTS, FW_VERSIONS=FW_VERSIONS, - extra_fw_versions=extra_fw_versions)) + f.write(FINGERPRINTS_PY_TEMPLATE.render(brand=brand, comments=comments, FINGERPRINTS=FINGERPRINTS, + FW_VERSIONS=FW_VERSIONS, extra_fw_versions=extra_fw_versions)) if __name__ == "__main__": diff --git a/selfdrive/modeld/modeld.py b/selfdrive/modeld/modeld.py index f439578afd26ea..a4d873b174a10c 100755 --- a/selfdrive/modeld/modeld.py +++ b/selfdrive/modeld/modeld.py @@ -16,6 +16,7 @@ from openpilot.common.transformations.camera import DEVICE_CAMERAS from openpilot.common.transformations.model import get_warp_matrix from openpilot.system import sentry +from openpilot.selfdrive.car.card import convert_to_capnp from openpilot.selfdrive.car.car_helpers import get_demo_car_params from openpilot.selfdrive.controls.lib.desire_helper import DesireHelper from openpilot.selfdrive.modeld.runners import ModelRunner, Runtime @@ -170,7 +171,7 @@ def main(demo=False): if demo: - CP = get_demo_car_params() + CP = convert_to_capnp(get_demo_car_params()) else: CP = messaging.log_from_bytes(params.get("CarParams", block=True), car.CarParams) diff --git a/selfdrive/modeld/tests/test_modeld.py b/selfdrive/modeld/tests/test_modeld.py index 03c08fd0349e43..e407b12d6a0c90 100644 --- a/selfdrive/modeld/tests/test_modeld.py +++ b/selfdrive/modeld/tests/test_modeld.py @@ -6,6 +6,7 @@ from openpilot.common.params import Params from openpilot.common.transformations.camera import DEVICE_CAMERAS from openpilot.common.realtime import DT_MDL +from openpilot.selfdrive.car.card import convert_to_capnp from openpilot.selfdrive.car.car_helpers import get_demo_car_params from openpilot.system.manager.process_config import managed_processes from openpilot.selfdrive.test.process_replay.vision_meta import meta_from_camera_state @@ -23,7 +24,7 @@ def setup_method(self): self.vipc_server.create_buffers(VisionStreamType.VISION_STREAM_DRIVER, 40, False, CAM.width, CAM.height) self.vipc_server.create_buffers(VisionStreamType.VISION_STREAM_WIDE_ROAD, 40, False, CAM.width, CAM.height) self.vipc_server.start_listener() - Params().put("CarParams", get_demo_car_params().to_bytes()) + Params().put("CarParams", convert_to_capnp(get_demo_car_params()).to_bytes()) self.sm = messaging.SubMaster(['modelV2', 'cameraOdometry']) self.pm = messaging.PubMaster(['roadCameraState', 'wideRoadCameraState', 'liveCalibration']) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 170dbd0c824f2f..c2041efd3f94b4 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -22,8 +22,9 @@ from openpilot.common.timeout import Timeout from openpilot.common.realtime import DT_CTRL from panda.python import ALTERNATIVE_EXPERIENCE -from openpilot.selfdrive.car.card import can_comm_callbacks +from openpilot.selfdrive.car.card import can_comm_callbacks, convert_to_capnp from openpilot.selfdrive.car.car_helpers import get_car, interfaces +from openpilot.selfdrive.car import structs from openpilot.system.manager.process_config import managed_processes from openpilot.selfdrive.test.process_replay.vision_meta import meta_from_camera_state, available_streams from openpilot.selfdrive.test.process_replay.migration import migrate_all @@ -362,14 +363,14 @@ def get_car_params_callback(rc, pm, msgs, fingerprint): cached_params = None if has_cached_cp: with car.CarParams.from_bytes(cached_params_raw) as _cached_params: - cached_params = _cached_params + cached_params = structs.CarParams(carName=_cached_params.carName, carFw=_cached_params.carFw, carVin=_cached_params.carVin) CP = get_car(*can_callbacks, lambda obd: None, Params().get_bool("ExperimentalLongitudinalEnabled"), cached_params=cached_params).CP if not params.get_bool("DisengageOnAccelerator"): CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS - params.put("CarParams", CP.to_bytes()) + params.put("CarParams", convert_to_capnp(CP).to_bytes()) def controlsd_rcv_callback(msg, cfg, frame): diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 0d83bf96d1cf1d..e580430a3693c4 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -d768496a1a85bfe5b74c99a79203affdf9a0a065 \ No newline at end of file +fa4965a27dee4449ad8b255f9f7674d69327b6f7 \ No newline at end of file diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 5f9e72585203c7..61b0e28483d984 100644 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -36,7 +36,7 @@ PROCS = { # Baseline CPU usage by process "selfdrive.controls.controlsd": 32.0, - "selfdrive.car.card": 22.0, + "selfdrive.car.card": 26.0, "./loggerd": 14.0, "./encoderd": 17.0, "./camerad": 14.5, diff --git a/system/hardware/tici/tests/test_power_draw.py b/system/hardware/tici/tests/test_power_draw.py index 4919b6e6b398c1..22246f44d1b197 100644 --- a/system/hardware/tici/tests/test_power_draw.py +++ b/system/hardware/tici/tests/test_power_draw.py @@ -9,6 +9,7 @@ from cereal.services import SERVICE_LIST from openpilot.common.mock import mock_messages from openpilot.common.params import Params +from openpilot.selfdrive.car.card import convert_to_capnp from openpilot.selfdrive.car.car_helpers import get_demo_car_params from openpilot.system.hardware.tici.power_monitor import get_power from openpilot.system.manager.process_config import managed_processes @@ -42,7 +43,7 @@ def name(self): class TestPowerDraw: def setup_method(self): - Params().put("CarParams", get_demo_car_params().to_bytes()) + Params().put("CarParams", convert_to_capnp(get_demo_car_params()).to_bytes()) # wait a bit for power save to disable time.sleep(5)