diff --git a/examples/joystick.py b/examples/joystick.py index c34878f36..2b80b342b 100755 --- a/examples/joystick.py +++ b/examples/joystick.py @@ -11,6 +11,7 @@ from kbhit import KBHit from opendbc.car.structs import CarControl from opendbc.car.panda_runner import PandaRunner + class Keyboard: def __init__(self): self.kb = KBHit() @@ -37,6 +38,7 @@ class Keyboard: return False return True + class Joystick: def __init__(self, gamepad=False): # TODO: find a way to get this from API, perhaps "inputs" doesn't support it @@ -72,10 +74,12 @@ class Joystick: return False return True + def joystick_thread(joystick): while True: joystick.update() + def main(joystick): threading.Thread(target=joystick_thread, args=(joystick,), daemon=True).start() with PandaRunner() as p: diff --git a/examples/kbhit.py b/examples/kbhit.py index 35f67b477..58fde349f 100755 --- a/examples/kbhit.py +++ b/examples/kbhit.py @@ -6,6 +6,7 @@ from select import select STDIN_FD = sys.stdin.fileno() + class KBHit: def __init__(self) -> None: self.set_kbhit_terminal() diff --git a/opendbc/can/dbc.py b/opendbc/can/dbc.py index f8a819801..73b2c1154 100644 --- a/opendbc/can/dbc.py +++ b/opendbc/can/dbc.py @@ -16,7 +16,6 @@ from opendbc.car.tesla.teslacan import tesla_checksum from opendbc.car.body.bodycan import body_checksum - class SignalType: DEFAULT = 0 COUNTER = 1 @@ -47,7 +46,6 @@ class Signal: calc_checksum: 'Callable[[int, Signal, bytearray], int] | None' = None - @dataclass class Msg: name: str @@ -70,6 +68,7 @@ SGM_RE = re.compile(r"^SG_ (\w+) (\w+) *: (\d+)\|(\d+)@(\d)([+-]) \(([0-9.+\-eE] VAL_RE = re.compile(r"^VAL_ (\w+) (\w+) (.*);") VAL_SPLIT_RE = re.compile(r'["]+') + @dataclass class DBC: name: str diff --git a/opendbc/can/parser.py b/opendbc/can/parser.py index 5eb7d341a..5e634351c 100644 --- a/opendbc/can/parser.py +++ b/opendbc/can/parser.py @@ -11,7 +11,6 @@ MAX_BAD_COUNTER = 5 CAN_INVALID_CNT = 5 - def get_raw_value(dat: bytes | bytearray, sig: Signal) -> int: ret = 0 i = sig.msb // 8 @@ -118,6 +117,7 @@ class VLDict(dict): self.parser._add_message(key) return super().__getitem__(key) + class CANParser: def __init__(self, dbc_name: str, messages: list[tuple[str | int, int]], bus: int): self.dbc_name: str = dbc_name diff --git a/opendbc/can/tests/benchmark.py b/opendbc/can/tests/benchmark.py index 54f203786..6652f44da 100755 --- a/opendbc/can/tests/benchmark.py +++ b/opendbc/can/tests/benchmark.py @@ -38,6 +38,7 @@ def _benchmark(checks, n): avg_nanos = et / len(can_msgs) print('[%d] %.1fms to pack, %.1fms to parse %s messages, avg: %dns' % (n, pack_dt/1e6, et/1e6, len(can_msgs), avg_nanos)) + if __name__ == "__main__": # python -m cProfile -s cumulative benchmark.py _benchmark([('ACC_CONTROL', 10)], 1) diff --git a/opendbc/can/tests/test_checksums.py b/opendbc/can/tests/test_checksums.py index b06ab3262..27668e68b 100644 --- a/opendbc/can/tests/test_checksums.py +++ b/opendbc/can/tests/test_checksums.py @@ -5,7 +5,7 @@ from opendbc.can import CANPacker, CANParser class TestCanChecksums: def verify_checksum(self, subtests, dbc_file: str, msg_name: str, msg_addr: int, test_messages: list[bytes], - checksum_field: str = 'CHECKSUM', counter_field = 'COUNTER'): + checksum_field: str = 'CHECKSUM', counter_field='COUNTER'): """ Verify that opendbc calculates payload CRCs/checksums matching those received in known-good sample messages Depends on all non-zero bits in the sample message having a corresponding DBC signal, add UNKNOWN signals if needed diff --git a/opendbc/can/tests/test_packer_parser.py b/opendbc/can/tests/test_packer_parser.py index d7a782196..51aa527f5 100644 --- a/opendbc/can/tests/test_packer_parser.py +++ b/opendbc/can/tests/test_packer_parser.py @@ -228,6 +228,7 @@ class TestCanParserPacker: packer = CANPacker(dbc_file) i = 0 + def send_msg(blank=False): nonlocal i i += 1 diff --git a/opendbc/car/__init__.py b/opendbc/car/__init__.py index 966e6e457..79fb45537 100644 --- a/opendbc/car/__init__.py +++ b/opendbc/car/__init__.py @@ -77,6 +77,7 @@ def scale_tire_stiffness(mass, wheelbase, center_to_front, tire_stiffness_factor DbcDict = dict[StrEnum, str] + class Bus(StrEnum): pt = auto() cam = auto() diff --git a/opendbc/car/ccp.py b/opendbc/car/ccp.py index 52ba48463..4d415fb1b 100644 --- a/opendbc/car/ccp.py +++ b/opendbc/car/ccp.py @@ -4,6 +4,7 @@ import struct from enum import IntEnum, Enum from dataclasses import dataclass + @dataclass class ExchangeStationIdsReturn: id_length: int @@ -11,26 +12,31 @@ class ExchangeStationIdsReturn: available: int protected: int + @dataclass class GetDaqListSizeReturn: list_size: int first_pid: int + @dataclass class GetSessionStatusReturn: status: int info: int | None + @dataclass class DiagnosticServiceReturn: length: int type: int + @dataclass class ActionServiceReturn: length: int type: int + class COMMAND_CODE(IntEnum): CONNECT = 0x01 SET_MTA = 0x02 @@ -61,6 +67,7 @@ class COMMAND_CODE(IntEnum): PROGRAM_6 = 0x22 DNLOAD_6 = 0x23 + COMMAND_RETURN_CODES = { 0x00: "acknowledge / no error", 0x01: "DAQ processor overload", @@ -82,16 +89,20 @@ COMMAND_RETURN_CODES = { 0x36: "resource/function not available", } + class BYTE_ORDER(Enum): LITTLE_ENDIAN = '<' BIG_ENDIAN = '>' + class CommandTimeoutError(Exception): pass + class CommandCounterError(Exception): pass + class CommandResponseError(Exception): def __init__(self, message, return_code): super().__init__() @@ -101,8 +112,9 @@ class CommandResponseError(Exception): def __str__(self): return self.message + class CcpClient: - def __init__(self, panda, tx_addr: int, rx_addr: int, bus: int=0, byte_order: BYTE_ORDER=BYTE_ORDER.BIG_ENDIAN, debug=False): + def __init__(self, panda, tx_addr: int, rx_addr: int, bus: int = 0, byte_order: BYTE_ORDER = BYTE_ORDER.BIG_ENDIAN, debug=False): self.tx_addr = tx_addr self.rx_addr = rx_addr self.can_bus = bus diff --git a/opendbc/car/chrysler/chryslercan.py b/opendbc/car/chrysler/chryslercan.py index 76d05d624..677582ef4 100644 --- a/opendbc/car/chrysler/chryslercan.py +++ b/opendbc/car/chrysler/chryslercan.py @@ -5,6 +5,7 @@ from opendbc.car.chrysler.values import RAM_CARS 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/opendbc/car/chrysler/interface.py b/opendbc/car/chrysler/interface.py index 0be2ccacb..e767bc6a7 100755 --- a/opendbc/car/chrysler/interface.py +++ b/opendbc/car/chrysler/interface.py @@ -18,7 +18,7 @@ class CarInterface(CarInterfaceBase): ret.dashcamOnly = candidate in RAM_HD # radar parsing needs some work, see https://github.com/commaai/openpilot/issues/26842 - ret.radarUnavailable = True # Bus.radar not in DBC[candidate][Bus.radar] + ret.radarUnavailable = True # Bus.radar not in DBC[candidate][Bus.radar] ret.steerActuatorDelay = 0.1 ret.steerLimitTimer = 0.4 diff --git a/opendbc/car/chrysler/radar_interface.py b/opendbc/car/chrysler/radar_interface.py index d044a3c31..4ad4afa1d 100755 --- a/opendbc/car/chrysler/radar_interface.py +++ b/opendbc/car/chrysler/radar_interface.py @@ -9,6 +9,7 @@ RADAR_MSGS_D = list(range(0x2a2, 0x2b4+2, 2)) # d_ messages LAST_MSG = max(RADAR_MSGS_C + RADAR_MSGS_D) NUMBER_MSGS = len(RADAR_MSGS_C) + len(RADAR_MSGS_D) + def _create_radar_can_parser(car_fingerprint): if Bus.radar not in DBC[car_fingerprint]: return None @@ -28,6 +29,7 @@ def _create_radar_can_parser(car_fingerprint): return CANParser(DBC[car_fingerprint][Bus.radar], messages, 1) + def _address_to_track(address): if address in RADAR_MSGS_C: return (address - RADAR_MSGS_C[0]) // 2 @@ -35,6 +37,7 @@ def _address_to_track(address): return (address - RADAR_MSGS_D[0]) // 2 raise ValueError("radar received unexpected address %d" % address) + class RadarInterface(RadarInterfaceBase): def __init__(self, CP): super().__init__(CP) diff --git a/opendbc/car/chrysler/values.py b/opendbc/car/chrysler/values.py index a729d68eb..232e5712e 100644 --- a/opendbc/car/chrysler/values.py +++ b/opendbc/car/chrysler/values.py @@ -18,6 +18,7 @@ class ChryslerFlags(IntFlag): # Detected flags HIGHER_MIN_STEERING_SPEED = 1 + @dataclass class ChryslerCarDocs(CarDocs): package: str = "Adaptive Cruise Control (ACC)" diff --git a/opendbc/car/common/conversions.py b/opendbc/car/common/conversions.py index b02b33c62..111c92884 100644 --- a/opendbc/car/common/conversions.py +++ b/opendbc/car/common/conversions.py @@ -1,5 +1,6 @@ import numpy as np + class Conversions: # Speed MPH_TO_KPH = 1.609344 diff --git a/opendbc/car/common/pid.py b/opendbc/car/common/pid.py index f2ab935f4..e9b5bb981 100644 --- a/opendbc/car/common/pid.py +++ b/opendbc/car/common/pid.py @@ -1,6 +1,7 @@ import numpy as np from numbers import Number + class PIDController: def __init__(self, k_p, k_i, k_f=0., k_d=0., pos_limit=1e308, neg_limit=-1e308, rate=100): self._k_p = k_p diff --git a/opendbc/car/common/simple_kalman.py b/opendbc/car/common/simple_kalman.py index 194b27204..c4e04e6a6 100644 --- a/opendbc/car/common/simple_kalman.py +++ b/opendbc/car/common/simple_kalman.py @@ -38,7 +38,7 @@ class KF1D: # self.K = np.transpose(K) def update(self, meas): - #self.x = np.dot(self.A_K, self.x) + np.dot(self.K, meas) + # self.x = np.dot(self.A_K, self.x) + np.dot(self.K, meas) x0_0 = self.A_K_0 * self.x0_0 + self.A_K_1 * self.x1_0 + self.K0_0 * meas x1_0 = self.A_K_2 * self.x0_0 + self.A_K_3 * self.x1_0 + self.K1_0 * meas self.x0_0 = x0_0 diff --git a/opendbc/car/ford/carcontroller.py b/opendbc/car/ford/carcontroller.py index eb63852d9..120a571a9 100644 --- a/opendbc/car/ford/carcontroller.py +++ b/opendbc/car/ford/carcontroller.py @@ -85,7 +85,7 @@ class CarController(CarControllerBase): steer_alert = hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw) fcw_alert = hud_control.visualAlert == VisualAlert.fcw - ### acc buttons ### + # acc buttons ### if CC.cruiseControl.cancel: can_sends.append(fordcan.create_button_msg(self.packer, self.CAN.camera, CS.buttons_stock_values, cancel=True)) can_sends.append(fordcan.create_button_msg(self.packer, self.CAN.main, CS.buttons_stock_values, cancel=True)) @@ -97,7 +97,7 @@ class CarController(CarControllerBase): elif CS.acc_tja_status_stock_values["Tja_D_Stat"] != 0 and (self.frame % CarControllerParams.ACC_UI_STEP) == 0: can_sends.append(fordcan.create_button_msg(self.packer, self.CAN.camera, CS.buttons_stock_values, tja_toggle=True)) - ### lateral control ### + # lateral control ### # send steer msg at 20Hz if (self.frame % CarControllerParams.STEER_STEP) == 0: # Bronco and some other cars consistently overshoot curv requests @@ -131,7 +131,7 @@ class CarController(CarControllerBase): if (self.frame % CarControllerParams.LKA_STEP) == 0: can_sends.append(fordcan.create_lka_msg(self.packer, self.CAN)) - ### longitudinal control ### + # longitudinal control ### # send acc msg at 50Hz if self.CP.openpilotLongitudinalControl and (self.frame % CarControllerParams.ACC_CONTROL_STEP) == 0: accel = actuators.accel @@ -172,7 +172,7 @@ class CarController(CarControllerBase): self.accel = accel self.gas = gas - ### ui ### + # ui ### send_ui = (self.main_on_last != main_on) or (self.lkas_enabled_last != CC.latActive) or (self.steer_alert_last != steer_alert) # send lkas ui msg at 1Hz or if ui state changes if (self.frame % CarControllerParams.LKAS_UI_STEP) == 0 or send_ui: diff --git a/opendbc/car/ford/radar_interface.py b/opendbc/car/ford/radar_interface.py index 87a8f2344..2dc8236fe 100644 --- a/opendbc/car/ford/radar_interface.py +++ b/opendbc/car/ford/radar_interface.py @@ -150,7 +150,7 @@ class RadarInterface(RadarInterfaceBase): self.valid_cnt[ii] += 1 else: self.valid_cnt[ii] = max(self.valid_cnt[ii] - 1, 0) - #print ii, self.valid_cnt[ii], cpt['VALID'], cpt['X_Rel'], cpt['Angle'] + # print ii, self.valid_cnt[ii], cpt['VALID'], cpt['X_Rel'], cpt['Angle'] # radar point only valid if there have been enough valid measurements if self.valid_cnt[ii] > 0: diff --git a/opendbc/car/ford/tests/test_ford.py b/opendbc/car/ford/tests/test_ford.py index 5e3cc420b..9dc35c856 100644 --- a/opendbc/car/ford/tests/test_ford.py +++ b/opendbc/car/ford/tests/test_ford.py @@ -133,7 +133,7 @@ class TestFordFW: # model year hint in between the range should match live_fw[(0x706, None)] = {b"MB5T-14F397-XX\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"} - candidates = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(live_fw, '', {expected_fingerprint: offline_fw,}) + candidates = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(live_fw, '', {expected_fingerprint: offline_fw, }) assert candidates == {expected_fingerprint} # unseen model year hint should not match diff --git a/opendbc/car/ford/values.py b/opendbc/car/ford/values.py index e4af32f25..2bda03b8d 100644 --- a/opendbc/car/ford/values.py +++ b/opendbc/car/ford/values.py @@ -86,6 +86,7 @@ class FordCarDocs(CarDocs): if CP.carFingerprint in (CAR.FORD_F_150_MK14, CAR.FORD_F_150_LIGHTNING_MK1, CAR.FORD_EXPEDITION_MK4): self.setup_video = "https://www.youtube.com/watch?v=MewJc9LYp9M" + @dataclass class FordPlatformConfig(PlatformConfig): dbc_dict: DbcDict = field(default_factory=lambda: { @@ -113,6 +114,7 @@ class FordCANFDPlatformConfig(FordPlatformConfig): super().init() self.flags |= FordFlags.CANFD + @dataclass class FordF150LightningPlatform(FordCANFDPlatformConfig): def init(self): diff --git a/opendbc/car/gm/carstate.py b/opendbc/car/gm/carstate.py index 7f56bb30d..f4a62a301 100644 --- a/opendbc/car/gm/carstate.py +++ b/opendbc/car/gm/carstate.py @@ -177,4 +177,3 @@ class CarState(CarStateBase): Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 2), Bus.loopback: CANParser(DBC[CP.carFingerprint][Bus.pt], loopback_messages, 128), } - diff --git a/opendbc/car/gm/gmcan.py b/opendbc/car/gm/gmcan.py index cb74b609e..11bad5436 100644 --- a/opendbc/car/gm/gmcan.py +++ b/opendbc/car/gm/gmcan.py @@ -84,7 +84,7 @@ def create_friction_brake_command(packer, bus, apply_brake, idx, enabled, near_s # TODO: this is to have GM bringing the car to complete stop, # but currently it conflicts with OP controls, so turned off. Not set by all cars - #elif near_stop: + # elif near_stop: # mode = 0xb brake = (0x1000 - apply_brake) & 0xfff @@ -137,7 +137,7 @@ def create_adas_accelerometer_speed_status(bus, speed_ms, idx): spd = int(speed_ms * 16) & 0xfff accel = 0 & 0xfff # 0 if in park/neutral, 0x10 if in reverse, 0x08 for D/L - #stick = 0x08 + # stick = 0x08 near_range_cutoff = 0x27 near_range_mode = 1 if spd <= near_range_cutoff else 0 far_range_mode = 1 - near_range_mode diff --git a/opendbc/car/gm/values.py b/opendbc/car/gm/values.py index 8cb6179da..13793537b 100644 --- a/opendbc/car/gm/values.py +++ b/opendbc/car/gm/values.py @@ -106,6 +106,7 @@ class GMASCMPlatformConfig(GMPlatformConfig): # ASCM is supported, but due to a janky install and hardware configuration, we are not showing in the car docs self.car_docs = [] + @dataclass class GMSDGMPlatformConfig(GMPlatformConfig): def init(self): @@ -202,12 +203,14 @@ class CruiseButtons: MAIN = 5 CANCEL = 6 + class AccState: OFF = 0 ACTIVE = 1 FAULTED = 3 STANDSTILL = 4 + class CanBus: POWERTRAIN = 0 OBSTACLE = 1 diff --git a/opendbc/car/honda/interface.py b/opendbc/car/honda/interface.py index b0e4e9058..2ef1339ea 100755 --- a/opendbc/car/honda/interface.py +++ b/opendbc/car/honda/interface.py @@ -88,7 +88,7 @@ class CarInterface(CarInterfaceBase): ret.lateralTuning.pid.kf = 0.00006 # conservative feed-forward if candidate in HONDA_BOSCH: - ret.longitudinalActuatorDelay = 0.5 # s + ret.longitudinalActuatorDelay = 0.5 # s if candidate in HONDA_BOSCH_RADARLESS: ret.stopAccel = CarControllerParams.BOSCH_ACCEL_MIN # stock uses -4.0 m/s^2 once stopped but limited by safety model else: @@ -200,7 +200,7 @@ class CarInterface(CarInterfaceBase): elif candidate == CAR.HONDA_E: ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]] # TODO: can probably use some tuning + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]] # TODO: can probably use some tuning else: raise ValueError(f"unsupported car {candidate}") diff --git a/opendbc/car/honda/values.py b/opendbc/car/honda/values.py index ddb1015c2..e3c1982a0 100644 --- a/opendbc/car/honda/values.py +++ b/opendbc/car/honda/values.py @@ -10,6 +10,7 @@ Ecu = structs.CarParams.Ecu VisualAlert = structs.CarControl.HUDControl.VisualAlert GearShifter = structs.CarState.GearShifter + class CarControllerParams: # Allow small margin below -3.5 m/s^2 from ISO 15622:2018 since we # perform the closed loop control, and might need some @@ -75,6 +76,7 @@ class HondaFlags(IntFlag): HAS_EPB = 512 ALLOW_MANUAL_TRANS = 1024 + # Car button codes class CruiseButtons: RES_ACCEL = 4 diff --git a/opendbc/car/hyundai/hyundaican.py b/opendbc/car/hyundai/hyundaican.py index 82fcb9b70..7f60d33f0 100644 --- a/opendbc/car/hyundai/hyundaican.py +++ b/opendbc/car/hyundai/hyundaican.py @@ -3,6 +3,7 @@ from opendbc.car.hyundai.values import CAR, HyundaiFlags hyundai_checksum = crcmod.mkCrcFun(0x11D, initCrc=0xFD, rev=False, xorOut=0xdf) + def create_lkas11(packer, frame, CP, apply_torque, steer_req, torque_fault, lkas11, sys_warning, sys_state, enabled, left_lane, right_lane, @@ -123,6 +124,7 @@ def create_lfahda_mfc(packer, enabled): } return packer.make_can_msg("LFAHDA_MFC", 0, values) + def create_acc_commands(packer, enabled, accel, upper_jerk, idx, hud_control, set_speed, stopping, long_override, use_fca, CP): commands = [] @@ -131,11 +133,11 @@ def create_acc_commands(packer, enabled, accel, upper_jerk, idx, hud_control, se "TauGapSet": hud_control.leadDistanceBars, "VSetDis": set_speed if enabled else 0, "AliveCounterACC": idx % 0x10, - "ObjValid": 1, # close lead makes controls tighter - "ACC_ObjStatus": 1, # close lead makes controls tighter + "ObjValid": 1, # close lead makes controls tighter + "ACC_ObjStatus": 1, # close lead makes controls tighter "ACC_ObjLatPos": 0, "ACC_ObjRelSpd": 0, - "ACC_ObjDist": 1, # close lead makes controls tighter + "ACC_ObjDist": 1, # close lead makes controls tighter } commands.append(packer.make_can_msg("SCC11", 0, scc11_values)) @@ -159,12 +161,12 @@ def create_acc_commands(packer, enabled, accel, upper_jerk, idx, hud_control, se commands.append(packer.make_can_msg("SCC12", 0, scc12_values)) scc14_values = { - "ComfortBandUpper": 0.0, # stock usually is 0 but sometimes uses higher values - "ComfortBandLower": 0.0, # stock usually is 0 but sometimes uses higher values - "JerkUpperLimit": upper_jerk, # stock usually is 1.0 but sometimes uses higher values - "JerkLowerLimit": 5.0, # stock usually is 0.5 but sometimes uses higher values - "ACCMode": 2 if enabled and long_override else 1 if enabled else 4, # stock will always be 4 instead of 0 after first disengage - "ObjGap": 2 if hud_control.leadVisible else 0, # 5: >30, m, 4: 25-30 m, 3: 20-25 m, 2: < 20 m, 0: no lead + "ComfortBandUpper": 0.0, # stock usually is 0 but sometimes uses higher values + "ComfortBandLower": 0.0, # stock usually is 0 but sometimes uses higher values + "JerkUpperLimit": upper_jerk, # stock usually is 1.0 but sometimes uses higher values + "JerkLowerLimit": 5.0, # stock usually is 0.5 but sometimes uses higher values + "ACCMode": 2 if enabled and long_override else 1 if enabled else 4, # stock will always be 4 instead of 0 after first disengage + "ObjGap": 2 if hud_control.leadVisible else 0, # 5: >30, m, 4: 25-30 m, 3: 20-25 m, 2: < 20 m, 0: no lead } commands.append(packer.make_can_msg("SCC14", 0, scc14_values)) @@ -185,6 +187,7 @@ def create_acc_commands(packer, enabled, accel, upper_jerk, idx, hud_control, se return commands + def create_acc_opt(packer, CP): commands = [] @@ -200,12 +203,13 @@ def create_acc_opt(packer, CP): if not (CP.flags & HyundaiFlags.CAMERA_SCC): fca12_values = { "FCA_DrvSetState": 2, - "FCA_USM": 1, # AEB disabled + "FCA_USM": 1, # AEB disabled } commands.append(packer.make_can_msg("FCA12", 0, fca12_values)) return commands + def create_frt_radar_opt(packer): frt_radar11_values = { "CF_FCA_Equip_Front_Radar": 1, diff --git a/opendbc/car/hyundai/hyundaicanfd.py b/opendbc/car/hyundai/hyundaicanfd.py index d1958b18e..1537bb4fd 100644 --- a/opendbc/car/hyundai/hyundaicanfd.py +++ b/opendbc/car/hyundai/hyundaicanfd.py @@ -66,6 +66,7 @@ def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_torque) return ret + def create_suppress_lfa(packer, CAN, lfa_block_msg, lka_steering_alt): suppress_msg = "CAM_0x362" if lka_steering_alt else "CAM_0x2a4" msg_bytes = 32 if lka_steering_alt else 24 @@ -78,6 +79,7 @@ def create_suppress_lfa(packer, CAN, lfa_block_msg, lka_steering_alt): values["RIGHT_LANE_LINE"] = 0 return packer.make_can_msg(suppress_msg, CAN.ACAN, values) + def create_buttons(packer, CP, CAN, cnt, btn): values = { "COUNTER": cnt, @@ -88,6 +90,7 @@ def create_buttons(packer, CP, CAN, cnt, btn): bus = CAN.ECAN if CP.flags & HyundaiFlags.CANFD_LKA_STEERING else CAN.CAM return packer.make_can_msg("CRUISE_BUTTONS", bus, values) + def create_acc_cancel(packer, CP, CAN, cruise_info_copy): # TODO: why do we copy different values here? if CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value: @@ -118,6 +121,7 @@ def create_acc_cancel(packer, CP, CAN, cruise_info_copy): }) return packer.make_can_msg("SCC_CONTROL", CAN.ECAN, values) + def create_lfahda_cluster(packer, CAN, enabled): values = { "HDA_ICON": 1 if enabled else 0, diff --git a/opendbc/car/hyundai/radar_interface.py b/opendbc/car/hyundai/radar_interface.py index 7e8c30708..3cabb9517 100644 --- a/opendbc/car/hyundai/radar_interface.py +++ b/opendbc/car/hyundai/radar_interface.py @@ -10,6 +10,7 @@ RADAR_MSG_COUNT = 32 # POC for parsing corner radars: https://github.com/commaai/openpilot/pull/24221/ + def get_radar_can_parser(CP): if Bus.radar not in DBC[CP.carFingerprint]: return None diff --git a/opendbc/car/hyundai/values.py b/opendbc/car/hyundai/values.py index 42b06043d..0b803246c 100644 --- a/opendbc/car/hyundai/values.py +++ b/opendbc/car/hyundai/values.py @@ -12,8 +12,8 @@ Ecu = CarParams.Ecu class CarControllerParams: - ACCEL_MIN = -3.5 # m/s - ACCEL_MAX = 2.0 # m/s + ACCEL_MIN = -3.5 # m/s + ACCEL_MAX = 2.0 # m/s def __init__(self, CP): self.STEER_DELTA_UP = 3 diff --git a/opendbc/car/interfaces.py b/opendbc/car/interfaces.py index 29a1d7d97..e02d05c3c 100644 --- a/opendbc/car/interfaces.py +++ b/opendbc/car/interfaces.py @@ -210,11 +210,11 @@ class CarInterfaceBase(ABC): ret.wheelSpeedFactor = 1.0 ret.pcmCruise = True # openpilot's state is tied to the PCM's cruise state on most cars - ret.minEnableSpeed = -1. # enable is done by stock ACC, so ignore this + ret.minEnableSpeed = -1. # enable is done by stock ACC, so ignore this ret.steerRatioRear = 0. # no rear steering, at least on the listed cars aboveA ret.openpilotLongitudinalControl = False ret.stopAccel = -2.0 - ret.stoppingDecelRate = 0.8 # brake_travel/s while trying to stop + ret.stoppingDecelRate = 0.8 # brake_travel/s while trying to stop ret.vEgoStopping = 0.5 ret.vEgoStarting = 0.5 ret.longitudinalTuning.kf = 1. @@ -294,7 +294,7 @@ class CarStateBase(ABC): R = 0.3 A = [[1.0, DT_CTRL], [0.0, 1.0]] C = [[1.0, 0.0]] - x0=[[0.0], [0.0]] + x0 = [[0.0], [0.0]] K = get_kalman_gain(DT_CTRL, np.array(A), np.array(C), np.array(Q), R) self.v_ego_kf = KF1D(x0=x0, A=A, C=C[0], K=K) @@ -387,6 +387,7 @@ INTERFACE_ATTR_FILE = { # interface-specific helpers + def get_interface_attr(attr: str, combine_brands: bool = False, ignore_none: bool = False) -> dict[str | StrEnum, Any]: # read all the folders in opendbc/car and return a dict where: # - keys are all the car models or brand names diff --git a/opendbc/car/isotp.py b/opendbc/car/isotp.py index ac64c413b..8ead67e6f 100644 --- a/opendbc/car/isotp.py +++ b/opendbc/car/isotp.py @@ -3,6 +3,7 @@ import time DEBUG = False + def msg(x): if DEBUG: print("S:", binascii.hexlify(x)) @@ -10,7 +11,10 @@ def msg(x): ret = bytes([len(x)]) + x return ret.ljust(8, b"\x00") + kmsgs = [] + + def recv(panda, cnt, addr, nbus): global kmsgs ret = [] @@ -27,6 +31,7 @@ def recv(panda, cnt, addr, nbus): kmsgs = nmsgs[-256:] return ret + def isotp_recv_subaddr(panda, addr, bus, sendaddr, subaddr): msg = recv(panda, 1, addr, bus)[0] @@ -60,6 +65,7 @@ def isotp_recv_subaddr(panda, addr, bus, sendaddr, subaddr): # **** import below this line **** + def isotp_send(panda, x, addr, bus=0, recvaddr=None, subaddr=None, rate=None): if recvaddr is None: recvaddr = addr + 8 @@ -102,6 +108,7 @@ def isotp_send(panda, x, addr, bus=0, recvaddr=None, subaddr=None, rate=None): panda.can_send(addr, dat, bus) time.sleep(rate) + def isotp_recv(panda, addr, bus=0, sendaddr=None, subaddr=None): if sendaddr is None: sendaddr = addr - 8 diff --git a/opendbc/car/mazda/mazdacan.py b/opendbc/car/mazda/mazdacan.py index 441f76a4f..adccdd642 100644 --- a/opendbc/car/mazda/mazdacan.py +++ b/opendbc/car/mazda/mazdacan.py @@ -23,12 +23,12 @@ def create_steering_control(packer, CP, frame, apply_torque, lkas): tmp = steering_angle + 2048 ahi = tmp >> 10 amd = (tmp & 0x3FF) >> 2 - amd = (amd >> 4) | (( amd & 0xF) << 4) + amd = (amd >> 4) | ((amd & 0xF) << 4) alo = (tmp & 0x3) << 2 ctr = frame % 16 # bytes: [ 1 ] [ 2 ] [ 3 ] [ 4 ] - csum = 249 - ctr - hi - lo - (lnv << 3) - er1 - (ldw << 7) - ( er2 << 4) - (b1 << 5) + csum = 249 - ctr - hi - lo - (lnv << 3) - er1 - (ldw << 7) - (er2 << 4) - (b1 << 5) # bytes [ 5 ] [ 6 ] [ 7 ] csum = csum - ahi - amd - alo - b2 @@ -50,7 +50,7 @@ def create_steering_control(packer, CP, frame, apply_torque, lkas): "LKAS_REQUEST": apply_torque, "CTR": ctr, "ERR_BIT_1": er1, - "LINE_NOT_VISIBLE" : lnv, + "LINE_NOT_VISIBLE": lnv, "LDW": ldw, "BIT_1": b1, "ERR_BIT_2": er2, diff --git a/opendbc/car/nissan/carcontroller.py b/opendbc/car/nissan/carcontroller.py index 16f990a82..e859a96cc 100644 --- a/opendbc/car/nissan/carcontroller.py +++ b/opendbc/car/nissan/carcontroller.py @@ -24,7 +24,7 @@ class CarController(CarControllerBase): can_sends = [] - ### STEER ### + # STEER ### steer_hud_alert = 1 if hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw) else 0 # windup slower diff --git a/opendbc/car/panda_runner.py b/opendbc/car/panda_runner.py index c1d0dcd01..3c811750e 100644 --- a/opendbc/car/panda_runner.py +++ b/opendbc/car/panda_runner.py @@ -6,6 +6,7 @@ from opendbc.car.car_helpers import get_car from opendbc.car.can_definitions import CanData from opendbc.car.structs import CarParams, CarControl + class PandaRunner(AbstractContextManager): def __enter__(self): self.p = Panda() @@ -52,6 +53,7 @@ class PandaRunner(AbstractContextManager): self.p.can_send_many(can_sends, timeout=25) self.p.send_heartbeat() + if __name__ == "__main__": with PandaRunner() as p: print(p.read()) diff --git a/opendbc/car/rivian/radar_interface.py b/opendbc/car/rivian/radar_interface.py index 6e1cad363..f74acafe9 100644 --- a/opendbc/car/rivian/radar_interface.py +++ b/opendbc/car/rivian/radar_interface.py @@ -8,6 +8,7 @@ from opendbc.car.rivian.values import DBC RADAR_START_ADDR = 0x500 RADAR_MSG_COUNT = 32 + def get_radar_can_parser(CP): messages = [(f"RADAR_TRACK_{addr:x}", 20) for addr in range(RADAR_START_ADDR, RADAR_START_ADDR + RADAR_MSG_COUNT)] return CANParser(DBC[CP.carFingerprint][Bus.radar], messages, 1) diff --git a/opendbc/car/rivian/riviancan.py b/opendbc/car/rivian/riviancan.py index bbe679c20..a2e88d82d 100644 --- a/opendbc/car/rivian/riviancan.py +++ b/opendbc/car/rivian/riviancan.py @@ -35,7 +35,7 @@ def create_lka_steering(packer, frame, acm_lka_hba_cmd, apply_torque, enabled, a # TODO: what are these used for? "ACM_ldwWarnTypeState": 2, # always 2 "ACM_ldwWarnTimingState": 1, # always 1 - #"ACM_lkaHandsoffDisplayWarning": 1, # TODO: we can send this when openpilot wants you to pay attention + # "ACM_lkaHandsoffDisplayWarning": 1, # TODO: we can send this when openpilot wants you to pay attention } data = packer.make_can_msg("ACM_lkaHbaCmd", 0, values)[1] diff --git a/opendbc/car/secoc.py b/opendbc/car/secoc.py index 971ea36a1..89f58e4a8 100644 --- a/opendbc/car/secoc.py +++ b/opendbc/car/secoc.py @@ -3,6 +3,7 @@ import struct from Crypto.Hash import CMAC from Crypto.Cipher import AES + def add_mac(key, trip_cnt, reset_cnt, msg_cnt, msg): # TODO: clean up conversion to and from hex @@ -22,7 +23,7 @@ def add_mac(key, trip_cnt, reset_cnt, msg_cnt, msg): # Step 3: Calculate CMAC (28 bit) cmac = CMAC.new(key, ciphermod=AES) cmac.update(to_auth) - mac = cmac.digest().hex()[:7] # truncated MAC + mac = cmac.digest().hex()[:7] # truncated MAC # Step 4: Build message # [Payload (32 bit)][Message Counter Flag (2 bit)][Reset Flag (2 bit)][Authenticator (28 bit)] @@ -32,12 +33,13 @@ def add_mac(key, trip_cnt, reset_cnt, msg_cnt, msg): return (addr, payload, bus) -def build_sync_mac(key, trip_cnt, reset_cnt, id_=0xf): - id_ = struct.pack('>H', id_) # 16 - trip_cnt = struct.pack('>H', trip_cnt) # 16 - reset_cnt = struct.pack('>I', reset_cnt << 12)[:-1] # 20 + 4 padding - to_auth = id_ + trip_cnt + reset_cnt # SecOC 11.4.1.1 page 138 +def build_sync_mac(key, trip_cnt, reset_cnt, id_=0xf): + id_ = struct.pack('>H', id_) # 16 + trip_cnt = struct.pack('>H', trip_cnt) # 16 + reset_cnt = struct.pack('>I', reset_cnt << 12)[:-1] # 20 + 4 padding + + to_auth = id_ + trip_cnt + reset_cnt # SecOC 11.4.1.1 page 138 cmac = CMAC.new(key, ciphermod=AES) cmac.update(to_auth) diff --git a/opendbc/car/subaru/subarucan.py b/opendbc/car/subaru/subarucan.py index 61477a920..4ed462b27 100644 --- a/opendbc/car/subaru/subarucan.py +++ b/opendbc/car/subaru/subarucan.py @@ -25,7 +25,8 @@ def create_steering_control_angle(packer, apply_torque, steer_req): def create_steering_status(packer): return packer.make_can_msg("ES_LKAS_State", 0, {}) -def create_es_distance(packer, frame, es_distance_msg, bus, pcm_cancel_cmd, long_enabled = False, brake_cmd = False, cruise_throttle = 0): + +def create_es_distance(packer, frame, es_distance_msg, bus, pcm_cancel_cmd, long_enabled=False, brake_cmd=False, cruise_throttle=0): values = {s: es_distance_msg[s] for s in [ "CHECKSUM", "Signal1", @@ -61,7 +62,7 @@ def create_es_distance(packer, frame, es_distance_msg, bus, pcm_cancel_cmd, long if pcm_cancel_cmd: values["Cruise_Cancel"] = 1 - values["Cruise_Throttle"] = 1818 # inactive throttle + values["Cruise_Throttle"] = 1818 # inactive throttle return packer.make_can_msg("ES_Distance", bus, values) @@ -129,6 +130,7 @@ def create_es_lkas_state(packer, frame, es_lkas_state_msg, enabled, visual_alert return packer.make_can_msg("ES_LKAS_State", CanBus.main, values) + def create_es_dashstatus(packer, frame, dashstatus_msg, enabled, long_enabled, long_active, lead_visible): values = {s: dashstatus_msg[s] for s in [ "CHECKSUM", @@ -167,7 +169,7 @@ def create_es_dashstatus(packer, frame, dashstatus_msg, enabled, long_enabled, l values["Cruise_Disengaged"] = 0 values["Car_Follow"] = int(lead_visible) - values["PCB_Off"] = 1 # AEB is not presevered, so show the PCB_Off on dash + values["PCB_Off"] = 1 # AEB is not presevered, so show the PCB_Off on dash values["LDW_Off"] = 0 values["Cruise_Fault"] = 0 @@ -177,6 +179,7 @@ def create_es_dashstatus(packer, frame, dashstatus_msg, enabled, long_enabled, l return packer.make_can_msg("ES_DashStatus", CanBus.main, values) + def create_es_brake(packer, frame, es_brake_msg, long_enabled, long_active, brake_value): values = {s: es_brake_msg[s] for s in [ "CHECKSUM", @@ -203,6 +206,7 @@ def create_es_brake(packer, frame, es_brake_msg, long_enabled, long_active, brak return packer.make_can_msg("ES_Brake", CanBus.main, values) + def create_es_status(packer, frame, es_status_msg, long_enabled, long_active, cruise_rpm): values = {s: es_status_msg[s] for s in [ "CHECKSUM", diff --git a/opendbc/car/tesla/interface.py b/opendbc/car/tesla/interface.py index baf159323..792910655 100644 --- a/opendbc/car/tesla/interface.py +++ b/opendbc/car/tesla/interface.py @@ -31,6 +31,6 @@ class CarInterface(CarInterfaceBase): ret.vEgoStarting = 0.1 ret.stoppingDecelRate = 0.3 - ret.dashcamOnly = candidate in (CAR.TESLA_MODEL_X) # dashcam only, pending find invalidLkasSetting signal + ret.dashcamOnly = candidate in (CAR.TESLA_MODEL_X) # dashcam only, pending find invalidLkasSetting signal return ret diff --git a/opendbc/car/tests/routes.py b/opendbc/car/tests/routes.py index a85218381..893df6480 100644 --- a/opendbc/car/tests/routes.py +++ b/opendbc/car/tests/routes.py @@ -59,7 +59,7 @@ routes = [ CarTestRoute("83a4e056c7072678/2023-11-13--16-51-33", FORD.FORD_MUSTANG_MACH_E_MK1), CarTestRoute("37998aa0fade36ab/00000000--48f927c4f5", FORD.FORD_RANGER_MK2), CarTestRoute("61a1b9e7a4eae0f6/00000000--79d85d1315", FORD.FORD_EXPEDITION_MK4), - #TestRoute("f1b4c567731f4a1b/2018-04-30--10-15-35", FORD.FUSION), + # TestRoute("f1b4c567731f4a1b/2018-04-30--10-15-35", FORD.FUSION), CarTestRoute("7cc2a8365b4dd8a9/2018-12-02--12-10-44", GM.GMC_ACADIA), CarTestRoute("aa20e335f61ba898/2019-02-05--16-59-04", GM.BUICK_REGAL), @@ -316,7 +316,7 @@ routes = [ CarTestRoute("7dc058789994da80/00000112--adb970f6a8", TESLA.TESLA_MODEL_3), CarTestRoute("46cdc864ec865f4b/00000007--42f94db730", TESLA.TESLA_MODEL_Y), CarTestRoute("2c912ca5de3b1ee9/0000025d--6eb6bcbca4", TESLA.TESLA_MODEL_Y, segment=4), - CarTestRoute("bdda168c0c35fad7/00000001--5c5a36ec06", TESLA.TESLA_MODEL_X), # openpilot longitudinal + CarTestRoute("bdda168c0c35fad7/00000001--5c5a36ec06", TESLA.TESLA_MODEL_X), # openpilot longitudinal # Segments that test specific issues # Controls mismatch due to standstill threshold diff --git a/opendbc/car/toyota/radar_interface.py b/opendbc/car/toyota/radar_interface.py index fc54b513a..2c166ff5b 100755 --- a/opendbc/car/toyota/radar_interface.py +++ b/opendbc/car/toyota/radar_interface.py @@ -20,6 +20,7 @@ def _create_radar_can_parser(car_fingerprint): return CANParser(DBC[car_fingerprint][Bus.radar], messages, 1) + class RadarInterface(RadarInterfaceBase): def __init__(self, CP): super().__init__(CP) diff --git a/opendbc/car/toyota/toyotacan.py b/opendbc/car/toyota/toyotacan.py index 1ca3ca5ef..cf1341244 100644 --- a/opendbc/car/toyota/toyotacan.py +++ b/opendbc/car/toyota/toyotacan.py @@ -70,8 +70,8 @@ def create_pcs_commands(packer, accel, active, mass): "DSS1GDRV": min(accel, 0), # accel "PCSALM": 1 if active else 0, # goes high same time as PRECOLLISION_ACTIVE "IBTRGR": 1 if active else 0, # unknown - "PBATRGR": 1 if active else 0, # noisy actuation bit? - "PREFILL": 1 if active else 0, # goes on and off before DSS1GDRV + "PBATRGR": 1 if active else 0, # noisy actuation bit? + "PREFILL": 1 if active else 0, # goes on and off before DSS1GDRV "AVSTRGR": 1 if active else 0, } msg2 = packer.make_can_msg("PRE_COLLISION_2", 0, values2) diff --git a/opendbc/car/toyota/values.py b/opendbc/car/toyota/values.py index 93597c7b1..72b2a21f4 100644 --- a/opendbc/car/toyota/values.py +++ b/opendbc/car/toyota/values.py @@ -147,7 +147,7 @@ class CAR(Platforms): TOYOTA_AVALON.specs, dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'), ) - TOYOTA_AVALON_TSS2 = ToyotaTSS2PlatformConfig( # TSS 2.5 + TOYOTA_AVALON_TSS2 = ToyotaTSS2PlatformConfig( # TSS 2.5 [ ToyotaCarDocs("Toyota Avalon 2022"), ToyotaCarDocs("Toyota Avalon Hybrid 2022"), @@ -163,7 +163,7 @@ class CAR(Platforms): dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'), flags=ToyotaFlags.NO_DSU, ) - TOYOTA_CAMRY_TSS2 = ToyotaTSS2PlatformConfig( # TSS 2.5 + TOYOTA_CAMRY_TSS2 = ToyotaTSS2PlatformConfig( # TSS 2.5 [ ToyotaCarDocs("Toyota Camry 2021-24", footnotes=[Footnote.CAMRY]), ToyotaCarDocs("Toyota Camry Hybrid 2021-24"), @@ -294,7 +294,7 @@ class CAR(Platforms): CarSpecs(mass=1170, wheelbase=2.55, steerRatio=14.80, tireStiffnessFactor=0.5533), flags=ToyotaFlags.RADAR_ACC, ) - TOYOTA_MIRAI = ToyotaTSS2PlatformConfig( # TSS 2.5 + TOYOTA_MIRAI = ToyotaTSS2PlatformConfig( # TSS 2.5 [ToyotaCarDocs("Toyota Mirai 2021")], CarSpecs(mass=4300. * CV.LB_TO_KG, wheelbase=2.91, steerRatio=14.8, tireStiffnessFactor=0.8), ) @@ -399,7 +399,7 @@ class CAR(Platforms): # (addr, cars, bus, 1/freq*100, vl) STATIC_DSU_MSGS = [ - (0x128, (CAR.TOYOTA_PRIUS, CAR.TOYOTA_RAV4H, CAR.LEXUS_RX, CAR.LEXUS_NX, CAR.TOYOTA_RAV4, CAR.TOYOTA_COROLLA, CAR.TOYOTA_AVALON), \ + (0x128, (CAR.TOYOTA_PRIUS, CAR.TOYOTA_RAV4H, CAR.LEXUS_RX, CAR.LEXUS_NX, CAR.TOYOTA_RAV4, CAR.TOYOTA_COROLLA, CAR.TOYOTA_AVALON), 1, 3, b'\xf4\x01\x90\x83\x00\x37'), (0x128, (CAR.TOYOTA_HIGHLANDER, CAR.TOYOTA_SIENNA, CAR.LEXUS_CTH, CAR.LEXUS_ES), 1, 3, b'\x03\x00\x20\x00\x00\x52'), (0x141, (CAR.TOYOTA_PRIUS, CAR.TOYOTA_RAV4H, CAR.LEXUS_RX, CAR.LEXUS_NX, CAR.TOYOTA_RAV4, CAR.TOYOTA_COROLLA, CAR.TOYOTA_HIGHLANDER, CAR.TOYOTA_AVALON, diff --git a/opendbc/car/uds.py b/opendbc/car/uds.py index 49f677f69..0ae06be70 100644 --- a/opendbc/car/uds.py +++ b/opendbc/car/uds.py @@ -36,12 +36,14 @@ class SERVICE_TYPE(IntEnum): TRANSFER_DATA = 0x36 REQUEST_TRANSFER_EXIT = 0x37 + class SESSION_TYPE(IntEnum): DEFAULT = 1 PROGRAMMING = 2 EXTENDED_DIAGNOSTIC = 3 SAFETY_SYSTEM_DIAGNOSTIC = 4 + class RESET_TYPE(IntEnum): HARD = 1 KEY_OFF_ON = 2 @@ -49,31 +51,37 @@ class RESET_TYPE(IntEnum): ENABLE_RAPID_POWER_SHUTDOWN = 4 DISABLE_RAPID_POWER_SHUTDOWN = 5 + class ACCESS_TYPE(IntEnum): REQUEST_SEED = 1 SEND_KEY = 2 + class CONTROL_TYPE(IntEnum): ENABLE_RX_ENABLE_TX = 0 ENABLE_RX_DISABLE_TX = 1 DISABLE_RX_ENABLE_TX = 2 DISABLE_RX_DISABLE_TX = 3 + class MESSAGE_TYPE(IntEnum): NORMAL = 1 NETWORK_MANAGEMENT = 2 NORMAL_AND_NETWORK_MANAGEMENT = 3 + class TIMING_PARAMETER_TYPE(IntEnum): READ_EXTENDED_SET = 1 SET_TO_DEFAULT_VALUES = 2 READ_CURRENTLY_ACTIVE = 3 SET_TO_GIVEN_VALUES = 4 + class DTC_SETTING_TYPE(IntEnum): ON = 1 OFF = 2 + class RESPONSE_EVENT_TYPE(IntEnum): STOP_RESPONSE_ON_EVENT = 0 ON_DTC_STATUS_CHANGE = 1 @@ -84,11 +92,13 @@ class RESPONSE_EVENT_TYPE(IntEnum): CLEAR_RESPONSE_ON_EVENT = 6 ON_COMPARISON_OF_VALUES = 7 + class LINK_CONTROL_TYPE(IntEnum): VERIFY_BAUDRATE_TRANSITION_WITH_FIXED_BAUDRATE = 1 VERIFY_BAUDRATE_TRANSITION_WITH_SPECIFIC_BAUDRATE = 2 TRANSITION_BAUDRATE = 3 + class BAUD_RATE_TYPE(IntEnum): PC9600 = 1 PC19200 = 2 @@ -100,6 +110,7 @@ class BAUD_RATE_TYPE(IntEnum): CAN500000 = 18 CAN1000000 = 19 + class DATA_IDENTIFIER_TYPE(IntEnum): BOOT_SOFTWARE_IDENTIFICATION = 0xF180 APPLICATION_SOFTWARE_IDENTIFICATION = 0xF181 @@ -133,33 +144,39 @@ class DATA_IDENTIFIER_TYPE(IntEnum): ODX_FILE = 0xF19E ENTITY = 0xF19F + class TRANSMISSION_MODE_TYPE(IntEnum): SEND_AT_SLOW_RATE = 1 SEND_AT_MEDIUM_RATE = 2 SEND_AT_FAST_RATE = 3 STOP_SENDING = 4 + class DYNAMIC_DEFINITION_TYPE(IntEnum): DEFINE_BY_IDENTIFIER = 1 DEFINE_BY_MEMORY_ADDRESS = 2 CLEAR_DYNAMICALLY_DEFINED_DATA_IDENTIFIER = 3 + class ISOTP_FRAME_TYPE(IntEnum): SINGLE = 0 FIRST = 1 CONSECUTIVE = 2 FLOW = 3 + class DynamicSourceDefinition(NamedTuple): data_identifier: int position: int memory_size: int memory_address: int + class DTC_GROUP_TYPE(IntEnum): EMISSIONS = 0x000000 ALL = 0xFFFFFF + class DTC_REPORT_TYPE(IntEnum): NUMBER_OF_DTC_BY_STATUS_MASK = 0x01 DTC_BY_STATUS_MASK = 0x02 @@ -183,6 +200,7 @@ class DTC_REPORT_TYPE(IntEnum): DTC_FAULT_DETECTION_COUNTER = 0x14 DTC_WITH_PERMANENT_STATUS = 0x15 + class DTC_STATUS_MASK_TYPE(IntEnum): TEST_FAILED = 0x01 TEST_FAILED_THIS_OPERATION_CYCLE = 0x02 @@ -194,31 +212,37 @@ class DTC_STATUS_MASK_TYPE(IntEnum): WARNING_INDICATOR_REQUESTED = 0x80 ALL = 0xFF + class DTC_SEVERITY_MASK_TYPE(IntEnum): MAINTENANCE_ONLY = 0x20 CHECK_AT_NEXT_HALT = 0x40 CHECK_IMMEDIATELY = 0x80 ALL = 0xE0 + class CONTROL_PARAMETER_TYPE(IntEnum): RETURN_CONTROL_TO_ECU = 0 RESET_TO_DEFAULT = 1 FREEZE_CURRENT_STATE = 2 SHORT_TERM_ADJUSTMENT = 3 + class ROUTINE_CONTROL_TYPE(IntEnum): START = 1 STOP = 2 REQUEST_RESULTS = 3 + class ROUTINE_IDENTIFIER_TYPE(IntEnum): ERASE_MEMORY = 0xFF00 CHECK_PROGRAMMING_DEPENDENCIES = 0xFF01 ERASE_MIRROR_MEMORY_DTCS = 0xFF02 + class MessageTimeoutError(Exception): pass + class NegativeResponseError(Exception): def __init__(self, message, service_id, error_code): super().__init__() @@ -229,15 +253,19 @@ class NegativeResponseError(Exception): def __str__(self): return self.message + class InvalidServiceIdError(Exception): pass + class InvalidSubFunctionError(Exception): pass + class InvalidSubAddressError(Exception): pass + _negative_response_codes = { 0x00: 'positive response', 0x10: 'general reject', @@ -282,6 +310,7 @@ _negative_response_codes = { 0x93: 'voltage too low', } + def get_dtc_num_as_str(dtc_num_bytes): # ISO 15031-6 designator = { @@ -294,6 +323,7 @@ def get_dtc_num_as_str(dtc_num_bytes): n = bytes([dtc_num_bytes[0] & 0x3F]) + dtc_num_bytes[1:] return d + n.hex() + def get_dtc_status_names(status): result = list() for m in DTC_STATUS_MASK_TYPE: @@ -303,6 +333,7 @@ def get_dtc_status_names(status): result.append(m.name) return result + class CanClient: def __init__(self, can_send: Callable[[int, bytes, int], None], can_recv: Callable[[], list[tuple[int, bytes, int]]], tx_addr: int, rx_addr: int, bus: int, sub_addr: int | None = None, rx_sub_addr: int | None = None): @@ -383,6 +414,7 @@ class CanClient: if i % 10 == 9: self._recv_buffer() + class IsoTpMessage: def __init__(self, can_client: CanClient, timeout: float = 1, single_frame_mode: bool = False, separation_time: float = 0): self._can_client = can_client diff --git a/opendbc/car/volkswagen/carcontroller.py b/opendbc/car/volkswagen/carcontroller.py index a42ddf2cb..7b356b2df 100644 --- a/opendbc/car/volkswagen/carcontroller.py +++ b/opendbc/car/volkswagen/carcontroller.py @@ -86,7 +86,7 @@ class CarController(CarControllerBase): can_sends.extend(self.CCS.create_acc_accel_control(self.packer_pt, self.CAN.pt, CS.acc_type, CC.longActive, accel, acc_control, stopping, starting, CS.esp_hold_confirmation)) - #if self.aeb_available: + # if self.aeb_available: # if self.frame % self.CCP.AEB_CONTROL_STEP == 0: # can_sends.append(self.CCS.create_aeb_control(self.packer_pt, False, False, 0.0)) # if self.frame % self.CCP.AEB_HUD_STEP == 0: diff --git a/opendbc/car/volkswagen/carstate.py b/opendbc/car/volkswagen/carstate.py index 86ac2bdaa..80eda638b 100644 --- a/opendbc/car/volkswagen/carstate.py +++ b/opendbc/car/volkswagen/carstate.py @@ -275,4 +275,3 @@ class CarState(CarStateBase): Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).pt), Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).cam), } - diff --git a/opendbc/car/volkswagen/mqbcan.py b/opendbc/car/volkswagen/mqbcan.py index 02580e999..32c72b123 100644 --- a/opendbc/car/volkswagen/mqbcan.py +++ b/opendbc/car/volkswagen/mqbcan.py @@ -152,7 +152,7 @@ def create_aeb_control(packer, fcw_active, aeb_active, accel): "AWV2_Freigabe": 0, # Stage 2 braking release "AWV2_Ruckprofil": 0, # Brake jerk level "AWV2_Priowarnung": 0, # Suppress lane departure warning in favor of FCW - "ANB_Notfallblinken": 0, # Hazard flashers request + "ANB_Notfallblinken": 0, # Hazard flashers request "ANB_Teilbremsung_Freigabe": 0, # Target braking release "ANB_Zielbremsung_Freigabe": 0, # Partial braking release "ANB_Zielbrems_Teilbrems_Verz_Anf": 0.0, # Acceleration requirement for target/partial braking, m/s/s @@ -166,7 +166,7 @@ def create_aeb_control(packer, fcw_active, aeb_active, accel): def create_aeb_hud(packer, aeb_supported, fcw_active): values = { "AWV_Texte": 5 if aeb_supported else 7, # FCW/AEB system status, display text (from menu in VAL) - "AWV_Status_Anzeige": 1 if aeb_supported else 2, # FCW/AEB system status, available or disabled + "AWV_Status_Anzeige": 1 if aeb_supported else 2, # FCW/AEB system status, available or disabled } return packer.make_can_msg("ACC_15", 0, values) diff --git a/opendbc/car/volkswagen/tests/test_volkswagen.py b/opendbc/car/volkswagen/tests/test_volkswagen.py index cc046e572..1f74bf48e 100644 --- a/opendbc/car/volkswagen/tests/test_volkswagen.py +++ b/opendbc/car/volkswagen/tests/test_volkswagen.py @@ -26,7 +26,7 @@ class TestVolkswagenPlatformConfigs: with subtests.test(platform=platform.value): assert len(platform.config.wmis) > 0, "WMIs not set" assert len(platform.config.chassis_codes) > 0, "Chassis codes not set" - assert all(CHASSIS_CODE_PATTERN.match(cc) for cc in \ + assert all(CHASSIS_CODE_PATTERN.match(cc) for cc in platform.config.chassis_codes), "Bad chassis codes" # No two platforms should share chassis codes diff --git a/opendbc/car/xcp.py b/opendbc/car/xcp.py index c5cf99c77..60c34f14e 100644 --- a/opendbc/car/xcp.py +++ b/opendbc/car/xcp.py @@ -3,6 +3,7 @@ import time import struct from enum import IntEnum + class COMMAND_CODE(IntEnum): CONNECT = 0xFF DISCONNECT = 0xFE @@ -61,6 +62,7 @@ class COMMAND_CODE(IntEnum): PROGRAM_MAX = 0xC9 PROGRAM_VERIFY = 0xC8 + ERROR_CODES = { 0x00: "Command processor synchronization", 0x10: "Command was not executed", @@ -82,10 +84,12 @@ ERROR_CODES = { 0x32: "The slave internal program verify routine detects an error", } + class CONNECT_MODE(IntEnum): NORMAL = 0x00, USER_DEFINED = 0x01, + class GET_ID_REQUEST_TYPE(IntEnum): ASCII = 0x00, ASAM_MC2_FILE = 0x01, @@ -94,12 +98,15 @@ class GET_ID_REQUEST_TYPE(IntEnum): ASAM_MC2_UPLOAD = 0x04, # 128-255 user defined + class CommandTimeoutError(Exception): pass + class CommandCounterError(Exception): pass + class CommandResponseError(Exception): def __init__(self, message, return_code): super().__init__() @@ -109,8 +116,9 @@ class CommandResponseError(Exception): def __str__(self): return self.message + class XcpClient: - def __init__(self, panda, tx_addr: int, rx_addr: int, bus: int=0, timeout: float=0.1, debug=False, pad=True): + def __init__(self, panda, tx_addr: int, rx_addr: int, bus: int = 0, timeout: float = 0.1, debug=False, pad=True): self.tx_addr = tx_addr self.rx_addr = rx_addr self.can_bus = bus @@ -164,7 +172,7 @@ class XcpClient: raise CommandTimeoutError("timeout waiting for response") # commands - def connect(self, connect_mode: CONNECT_MODE=CONNECT_MODE.NORMAL) -> dict: + def connect(self, connect_mode: CONNECT_MODE = CONNECT_MODE.NORMAL) -> dict: self._send_cto(COMMAND_CODE.CONNECT, bytes([connect_mode])) resp = self._recv_dto(self.timeout) assert len(resp) == 7, f"incorrect data length: {len(resp)}" @@ -237,7 +245,7 @@ class XcpClient: resp = b"" while len(resp) < size: resp += self._recv_dto(self.timeout)[:size - len(resp) + 1] - return resp[:size] # trim off bytes with undefined values + return resp[:size] # trim off bytes with undefined values def short_upload(self, size: int, addr_ext: int, addr: int) -> bytes: if size > 6: @@ -245,7 +253,7 @@ class XcpClient: if addr_ext > 255: raise ValueError("address extension must be less than 256") self._send_cto(COMMAND_CODE.SHORT_UPLOAD, bytes([size, 0x00, addr_ext]) + struct.pack(f"{self._byte_order}I", addr)) - return self._recv_dto(self.timeout)[:size] # trim off bytes with undefined values + return self._recv_dto(self.timeout)[:size] # trim off bytes with undefined values def download(self, data: bytes) -> bytes: size = len(data) diff --git a/opendbc/dbc/generator/generator.py b/opendbc/dbc/generator/generator.py index d0f41fc80..2c0a4934b 100755 --- a/opendbc/dbc/generator/generator.py +++ b/opendbc/dbc/generator/generator.py @@ -52,13 +52,14 @@ def create_all(output_path: str): if src_dir == generator_path: continue - #print(src_dir) + # print(src_dir) for filename in filenames: if filename.startswith('_') or not filename.endswith('.dbc'): continue - #print(filename) + # print(filename) create_dbc(src_dir, filename, output_path) + if __name__ == "__main__": create_all(opendbc_root) diff --git a/opendbc/dbc/generator/tesla/_radar_common.py b/opendbc/dbc/generator/tesla/_radar_common.py index 737c203b0..c25f57d3e 100755 --- a/opendbc/dbc/generator/tesla/_radar_common.py +++ b/opendbc/dbc/generator/tesla/_radar_common.py @@ -31,6 +31,7 @@ BO_ {base_id+1} {base_name}_B: 8 Radar SG_ Index2 : 63|1@1+ (1,0) [0|1] "" Autopilot """ + def get_val_definition(base_id): return f""" VAL_ {base_id+1} MovingState 3 "RADAR_MOVESTATE_STANDING" 2 "RADAR_MOVESTATE_STOPPED" 1 "RADAR_MOVESTATE_MOVING" 0 "RADAR_MOVESTATE_INDETERMINATE" ; diff --git a/opendbc/safety/tests/common.py b/opendbc/safety/tests/common.py index 75b8b4e9c..1932d3775 100644 --- a/opendbc/safety/tests/common.py +++ b/opendbc/safety/tests/common.py @@ -92,7 +92,7 @@ class PandaSafetyTestBase(unittest.TestCase): def _generic_limit_safety_check(self, msg_function: MessageFunction, min_allowed_value: float, max_allowed_value: float, min_possible_value: float, max_possible_value: float, test_delta: float = 1, inactive_value: float = 0, - msg_allowed = True, additional_setup: Callable[[float], None] | None = None): + msg_allowed=True, additional_setup: Callable[[float], None] | None = None): """ Enforces that a signal within a message is only allowed to be sent within a specific range, min_allowed_value -> max_allowed_value. Tests the range of min_possible_value -> max_possible_value with a delta of test_delta. diff --git a/opendbc/safety/tests/libsafety/libsafety_py.py b/opendbc/safety/tests/libsafety/libsafety_py.py index 4624adbb7..bae99fc0a 100644 --- a/opendbc/safety/tests/libsafety/libsafety_py.py +++ b/opendbc/safety/tests/libsafety/libsafety_py.py @@ -37,6 +37,7 @@ void can_set_checksum(CANPacket_t *packet); setup_safety_helpers(ffi) + class CANPacket: reserved: int bus: int @@ -47,6 +48,7 @@ class CANPacket: addr: int data: list[int] + class Panda(PandaSafety, Protocol): # CAN def can_set_checksum(self, p: CANPacket) -> None: ... diff --git a/opendbc/safety/tests/libsafety/safety_helpers.py b/opendbc/safety/tests/libsafety/safety_helpers.py index 984693e7a..49c7a9579 100644 --- a/opendbc/safety/tests/libsafety/safety_helpers.py +++ b/opendbc/safety/tests/libsafety/safety_helpers.py @@ -1,6 +1,7 @@ # panda safety helpers, from safety_helpers.c from typing import Protocol + def setup_safety_helpers(ffi): ffi.cdef(""" void set_controls_allowed(bool c); @@ -52,6 +53,7 @@ def setup_safety_helpers(ffi): int get_honda_hw(void); """) + class PandaSafety(Protocol): def set_controls_allowed(self, c: bool) -> None: ... def get_controls_allowed(self) -> bool: ... @@ -100,5 +102,3 @@ class PandaSafety(Protocol): def set_honda_alt_brake_msg(self, c: bool) -> None: ... def set_honda_bosch_long(self, c: bool) -> None: ... def get_honda_hw(self) -> int: ... - - diff --git a/opendbc/safety/tests/misra/test_mutation.py b/opendbc/safety/tests/misra/test_mutation.py index 723b4a7ce..1d55f71c3 100644 --- a/opendbc/safety/tests/misra/test_mutation.py +++ b/opendbc/safety/tests/misra/test_mutation.py @@ -43,6 +43,7 @@ for p in patterns: mutations = random.sample(mutations, 2) # can remove this once cppcheck is faster + @pytest.mark.parametrize("fn, rule, transform, should_fail", mutations) def test_misra_mutation(fn, rule, transform, should_fail): with tempfile.TemporaryDirectory() as tmp: @@ -59,7 +60,7 @@ def test_misra_mutation(fn, rule, transform, should_fail): # run test r = subprocess.run(f"OPENDBC_ROOT={tmp} opendbc/safety/tests/misra/test_misra.sh", stdout=subprocess.PIPE, cwd=ROOT, shell=True, encoding='utf8') - print(r.stdout) # helpful for debugging failures + print(r.stdout) # helpful for debugging failures failed = r.returncode != 0 assert failed == should_fail if should_fail: diff --git a/opendbc/safety/tests/safety_replay/helpers.py b/opendbc/safety/tests/safety_replay/helpers.py index f869836e6..e30cd5a69 100644 --- a/opendbc/safety/tests/safety_replay/helpers.py +++ b/opendbc/safety/tests/safety_replay/helpers.py @@ -4,12 +4,14 @@ from opendbc.car.toyota.values import ToyotaSafetyFlags from opendbc.car.structs import CarParams from opendbc.safety.tests.libsafety import libsafety_py + def to_signed(d, bits): ret = d if d >= (1 << (bits - 1)): ret = d - (1 << bits) return ret + def is_steering_msg(mode, param, addr): ret = False if mode in (CarParams.SafetyModel.hondaNidec, CarParams.SafetyModel.hondaBosch): @@ -38,6 +40,7 @@ def is_steering_msg(mode, param, addr): ret = addr == 0x488 return ret + def get_steer_value(mode, param, msg): # TODO: use CANParser torque, angle = 0, 0 @@ -77,9 +80,11 @@ def get_steer_value(mode, param, msg): angle = (((msg.data[0] & 0x7F) << 8) | (msg.data[1])) - 16384 # ceil(1638.35/0.1) return torque, angle + def package_can_msg(msg): return libsafety_py.make_CANPacket(msg.address, msg.src % 4, msg.dat) + def init_segment(safety, msgs, mode, param): sendcan = (msg for msg in msgs if msg.which() == 'sendcan') steering_msgs = (can for msg in sendcan for can in msg.sendcan if is_steering_msg(mode, param, can.address)) diff --git a/opendbc/safety/tests/safety_replay/replay_drive.py b/opendbc/safety/tests/safety_replay/replay_drive.py index a4098a41f..f34fc18a8 100755 --- a/opendbc/safety/tests/safety_replay/replay_drive.py +++ b/opendbc/safety/tests/safety_replay/replay_drive.py @@ -7,6 +7,7 @@ from opendbc.car.carlog import carlog from opendbc.safety.tests.libsafety import libsafety_py from opendbc.safety.tests.safety_replay.helpers import package_can_msg, init_segment + # replay a drive to check for safety violations def replay_drive(msgs, safety_mode, param, alternative_experience): safety = libsafety_py.libsafety @@ -71,6 +72,7 @@ def replay_drive(msgs, safety_mode, param, alternative_experience): return tx_controls_blocked == 0 and rx_invalid == 0 and not safety_tick_rx_invalid + if __name__ == "__main__": from openpilot.tools.lib.logreader import LogReader diff --git a/opendbc/safety/tests/test_chrysler.py b/opendbc/safety/tests/test_chrysler.py index d8c982566..f3af1fb3c 100755 --- a/opendbc/safety/tests/test_chrysler.py +++ b/opendbc/safety/tests/test_chrysler.py @@ -95,6 +95,7 @@ class TestChryslerRamDTSafety(TestChryslerSafety): values = {"Vehicle_Speed": speed} return self.packer.make_can_msg_panda("ESP_8", 0, values) + class TestChryslerRamHDSafety(TestChryslerSafety): TX_MSGS = [[0x275, 0], [0x276, 0], [0x23A, 2]] RELAY_MALFUNCTION_ADDRS = {0: (0x276, 0x275)} diff --git a/opendbc/safety/tests/test_honda.py b/opendbc/safety/tests/test_honda.py index 643c595a7..bbf1fe9c8 100755 --- a/opendbc/safety/tests/test_honda.py +++ b/opendbc/safety/tests/test_honda.py @@ -10,6 +10,7 @@ from opendbc.safety.tests.common import CANPackerPanda, MAX_WRONG_COUNTERS HONDA_N_COMMON_TX_MSGS = [[0xE4, 0], [0x194, 0], [0x1FA, 0], [0x30C, 0], [0x33D, 0]] + class Btn: NONE = 0 MAIN = 1 diff --git a/opendbc/safety/tests/test_hyundai.py b/opendbc/safety/tests/test_hyundai.py index c0c972cae..df0ba302e 100755 --- a/opendbc/safety/tests/test_hyundai.py +++ b/opendbc/safety/tests/test_hyundai.py @@ -190,6 +190,7 @@ class TestHyundaiLegacySafetyHEV(TestHyundaiSafety): values = {"CR_Vcu_AccPedDep_Pos": gas} return self.packer.make_can_msg_panda("E_EMS11", 0, values, fix_checksum=checksum) + class TestHyundaiLongitudinalSafety(HyundaiLongitudinalBase, TestHyundaiSafety): TX_MSGS = [[0x340, 0], [0x4F1, 0], [0x485, 0], [0x420, 0], [0x421, 0], [0x50A, 0], [0x389, 0], [0x4A2, 0], [0x38D, 0], [0x483, 0], [0x7D0, 0]] diff --git a/opendbc/safety/tests/test_subaru.py b/opendbc/safety/tests/test_subaru.py index f31a8df5c..7b628c53e 100755 --- a/opendbc/safety/tests/test_subaru.py +++ b/opendbc/safety/tests/test_subaru.py @@ -9,6 +9,7 @@ import opendbc.safety.tests.common as common from opendbc.safety.tests.common import CANPackerPanda from functools import partial + class SubaruMsg(enum.IntEnum): Brake_Status = 0x13c CruiseControl = 0x240 @@ -41,19 +42,23 @@ def lkas_tx_msgs(alt_bus, lkas_msg=SubaruMsg.ES_LKAS): [SubaruMsg.ES_LKAS_State, SUBARU_MAIN_BUS], [SubaruMsg.ES_Infotainment, SUBARU_MAIN_BUS]] + def long_tx_msgs(alt_bus): return [[SubaruMsg.ES_Brake, alt_bus], [SubaruMsg.ES_Status, alt_bus]] + def gen2_long_additional_tx_msgs(): return [[SubaruMsg.ES_UDS_Request, SUBARU_CAM_BUS], [SubaruMsg.ES_HighBeamAssist, SUBARU_MAIN_BUS], [SubaruMsg.ES_STATIC_1, SUBARU_MAIN_BUS], [SubaruMsg.ES_STATIC_2, SUBARU_MAIN_BUS]] + def fwd_blacklisted_addr(lkas_msg=SubaruMsg.ES_LKAS): return {SUBARU_CAM_BUS: [lkas_msg, SubaruMsg.ES_DashStatus, SubaruMsg.ES_LKAS_State, SubaruMsg.ES_Infotainment]} + class TestSubaruSafetyBase(common.PandaCarSafetyTest): FLAGS = 0 RELAY_MALFUNCTION_ADDRS = {SUBARU_MAIN_BUS: (SubaruMsg.ES_LKAS, SubaruMsg.ES_DashStatus, SubaruMsg.ES_LKAS_State, diff --git a/opendbc/safety/tests/test_volkswagen_pq.py b/opendbc/safety/tests/test_volkswagen_pq.py index 22b897d9a..b00e62f41 100755 --- a/opendbc/safety/tests/test_volkswagen_pq.py +++ b/opendbc/safety/tests/test_volkswagen_pq.py @@ -187,5 +187,6 @@ class TestVolkswagenPqLongSafety(TestVolkswagenPqSafetyBase, common.Longitudinal self.assertTrue(self._tx(self._torque_cmd_msg(self.MAX_RATE_UP, steer_req=1, hca_status=enabled_status)), f"torque cmd rejected with {enabled_status=}") + if __name__ == "__main__": unittest.main()