Merge branch 'upstream/opendbc/master' into sync-20260401

# Conflicts:
#	docs/CARS.md
#	opendbc/car/car_helpers.py
#	opendbc/car/chrysler/carcontroller.py
#	opendbc/car/chrysler/values.py
#	opendbc/car/honda/carcontroller.py
#	opendbc/car/honda/hondacan.py
#	opendbc/car/hyundai/hyundaicanfd.py
#	opendbc/car/rivian/interface.py
This commit is contained in:
Jason Wen
2026-04-01 22:42:15 -04:00
84 changed files with 1307 additions and 581 deletions

View File

@@ -110,11 +110,11 @@ jobs:
repository: 'sunnypilot/sunnypilot'
ref: 'master'
submodules: true
- run: ./tools/op.sh setup
- run: rm -rf opendbc_repo/
- uses: actions/checkout@v4
with:
path: opendbc_repo
- run: ./tools/op.sh setup
- name: Cache test routes
id: routes-cache
uses: actions/cache@v4

1
.gitignore vendored
View File

@@ -22,6 +22,7 @@ __pycache__/
*.profraw
opendbc/can/build/
opendbc/can/obj/
opendbc/dbc/*_generated.dbc
cppcheck-addon-ctu-file-list
opendbc/safety/tests/coverage-out

View File

@@ -19,6 +19,19 @@
[![X Follow](https://img.shields.io/twitter/follow/comma_ai)](https://x.com/comma_ai)
[![Discord](https://img.shields.io/discord/469524606043160576)](https://discord.comma.ai)
<br>
<h3><i>How to Port a Car — Jason Young, COMMA_CON 2023</i></h3>
<a href="https://www.youtube.com/watch?v=XxPS5TpTUnI&t=142s">
<img src="https://github.com/user-attachments/assets/ae89198e-561b-4210-a0d4-ccecd917577d" alt="▶ How to Port a Car - Jason Young, COMMA_CON 2023" width="800">
</a>
<br>
<h3><i>How Do We Control The Car? — Robbe Derks, COMMA_CON 2021</i></h3>
<a href="https://www.youtube.com/watch?v=nNU6ipme878">
<img src="https://github.com/user-attachments/assets/28c40bc0-7884-47e9-b392-f47f03190497" alt="▶ How Do We Control The Car? - Robbe Derks, COMMA_CON 2021" width="800">
</a>
<br>
</div>
---

View File

@@ -27,4 +27,4 @@ test:
# *** tests ***
unittest:
run: unittest-parallel -j8 -s opendbc -p 'test_*.py' -t .
run: unittest-parallel -j4

View File

@@ -206,7 +206,7 @@ def get_checksum_state(dbc_name: str) -> ChecksumState | None:
elif dbc_name.startswith("subaru_global_"):
return ChecksumState(8, -1, 0, -1, True, SignalType.SUBARU_CHECKSUM, subaru_checksum)
elif dbc_name.startswith("chrysler_"):
return ChecksumState(8, -1, 7, -1, False, SignalType.CHRYSLER_CHECKSUM, chrysler_checksum)
return ChecksumState(8, 4, 7, -1, False, SignalType.CHRYSLER_CHECKSUM, chrysler_checksum)
elif dbc_name.startswith("fca_giorgio"):
return ChecksumState(8, -1, 7, -1, False, SignalType.FCA_GIORGIO_CHECKSUM, fca_giorgio_checksum)
elif dbc_name.startswith("comma_body"):

View File

@@ -83,7 +83,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,
def fingerprint(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback,
cached_params: CarParamsT | None,
fixed_fingerprint: str | None) -> tuple[str | None, dict, str, list[CarParams.CarFw], CarParams.FingerprintSource, bool]:
fixed_fingerprint = fixed_fingerprint or os.environ.get('FINGERPRINT', "")
@@ -106,8 +106,8 @@ def fingerprint(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_mu
set_obd_multiplexing(True)
# VIN query only reliably works through OBDII
vin_rx_addr, vin_rx_bus, vin = get_vin(can_recv, can_send, (0, 1))
ecu_rx_addrs = get_present_ecus(can_recv, can_send, set_obd_multiplexing, num_pandas=num_pandas)
car_fw = get_fw_versions_ordered(can_recv, can_send, set_obd_multiplexing, vin, ecu_rx_addrs, num_pandas=num_pandas)
ecu_rx_addrs = get_present_ecus(can_recv, can_send, set_obd_multiplexing)
car_fw = get_fw_versions_ordered(can_recv, can_send, set_obd_multiplexing, vin, ecu_rx_addrs)
cached = False
exact_fw_match, fw_candidates = match_fw_to_car(car_fw, vin)
@@ -152,9 +152,9 @@ def fingerprint(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_mu
def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback, alpha_long_allowed: bool,
is_release: bool, num_pandas: int = 1, cached_params: CarParamsT | None = None,
is_release: bool, cached_params: CarParamsT | None = None,
fixed_fingerprint: str | None = None, init_params_list_sp: list[dict[str, str]] | None = None, is_release_sp: bool = False):
candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(can_recv, can_send, set_obd_multiplexing, num_pandas, cached_params,
candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(can_recv, can_send, set_obd_multiplexing, cached_params,
fixed_fingerprint)
if candidate is None:

View File

@@ -2,7 +2,7 @@ from opendbc.can import CANPacker
from opendbc.car import Bus, DT_CTRL
from opendbc.car.lateral import apply_meas_steer_torque_limits
from opendbc.car.chrysler import chryslercan
from opendbc.car.chrysler.values import RAM_CARS, CarControllerParams, ChryslerFlags, RAM_DT
from opendbc.car.chrysler.values import CUSW_CARS, RAM_CARS, CarControllerParams, ChryslerFlags, RAM_DT
from opendbc.car.interfaces import CarControllerBase
from opendbc.sunnypilot.car.chrysler.carcontroller_ext import CarControllerExt
@@ -69,6 +69,9 @@ class CarController(CarControllerBase, MadsCarController, CarControllerExt, Inte
elif self.CP.carFingerprint in RAM_CARS:
if CS.out.vEgo < (self.CP.minSteerSpeed - 0.5):
lkas_control_bit = False
elif self.CP.carFingerprint in CUSW_CARS:
if CS.out.vEgo < (self.CP.minSteerSpeed - 2.0):
lkas_control_bit = False
# EPS faults if LKAS re-enables too quickly
lkas_control_bit = lkas_control_bit and (self.frame - self.last_lkas_falling_edge > 200)
@@ -86,7 +89,7 @@ class CarController(CarControllerBase, MadsCarController, CarControllerExt, Inte
can_sends.append(chryslercan.create_lkas_command(self.packer, self.CP, int(apply_torque), lkas_control_bit))
if self.frame % 10 == 0 and self.CP.carFingerprint not in RAM_CARS:
if self.frame % 10 == 0 and self.CP.carFingerprint not in (RAM_CARS | CUSW_CARS):
can_sends.append(MadsCarController.create_lkas_heartbit(self.packer, CS.lkas_heartbit, self.mads))
# Intelligent Cruise Button Management

View File

@@ -1,6 +1,6 @@
from opendbc.can import CANDefine, CANParser
from opendbc.car import Bus, create_button_events, structs
from opendbc.car.chrysler.values import DBC, STEER_THRESHOLD, RAM_CARS
from opendbc.car.chrysler.values import CUSW_CARS, DBC, STEER_THRESHOLD, RAM_CARS
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.interfaces import CarStateBase
@@ -33,6 +33,9 @@ class CarState(CarStateBase, MadsCarState, CarStateExt):
cp = can_parsers[Bus.pt]
cp_cam = can_parsers[Bus.cam]
if self.CP.carFingerprint in CUSW_CARS:
return self.update_cusw(cp, cp_cam)
ret = structs.CarState()
ret_sp = structs.CarStateSP()
@@ -112,6 +115,55 @@ class CarState(CarStateBase, MadsCarState, CarStateExt):
return ret, ret_sp
def update_cusw(self, cp, cp_cam):
ret = structs.CarState()
ret_sp = structs.CarStateSP()
ret.doorOpen = any([cp.vl["DOORS"]["DOOR_OPEN_FL"],
cp.vl["DOORS"]["DOOR_OPEN_FR"],
cp.vl["DOORS"]["DOOR_OPEN_RL"],
cp.vl["DOORS"]["DOOR_OPEN_RR"]])
ret.seatbeltUnlatched = bool(cp.vl["SEATBELT_STATUS"]["SEATBELT_DRIVER_UNLATCHED"])
ret.brakePressed = bool(cp.vl["BRAKE_3"]["DRIVER_BRAKE_SWITCH"])
ret.brake = cp.vl["BRAKE_1"]["DRIVER_BRAKE_PRESSURE"]
ret.gasPressed = cp.vl["ACCEL_GAS"]["GAS_HUMAN"] > 0
ret.espDisabled = bool(cp.vl["TRACTION_BUTTON"]["TRACTION_OFF"])
ret.vEgoRaw = cp.vl["BRAKE_1"]["VEHICLE_SPEED"]
ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
ret.standstill = not ret.vEgoRaw > 0.001
self.parse_wheel_speeds(ret,
cp.vl["WHEEL_SPEEDS_FRONT"]["WHEEL_SPEED_FL"],
cp.vl["WHEEL_SPEEDS_REAR"]["WHEEL_SPEED_RR"],
cp.vl["WHEEL_SPEEDS_REAR"]["WHEEL_SPEED_RL"],
cp.vl["WHEEL_SPEEDS_FRONT"]["WHEEL_SPEED_FR"],
unit=1,
)
ret.leftBlinker = cp.vl["STEERING_LEVERS"]["TURN_SIGNALS"] == 1
ret.rightBlinker = cp.vl["STEERING_LEVERS"]["TURN_SIGNALS"] == 2
ret.steeringAngleDeg = cp.vl["STEERING"]["STEER_ANGLE"]
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(cp.vl["GEAR"]["PRNDL"], None))
ret.cruiseState.speed = cp.vl["ACC_HUD"]["ACC_SET_SPEED_KMH"] * CV.KPH_TO_MS
ret.cruiseState.available = bool(cp.vl["ACC_CONTROL"]["ACC_MAIN_ON"])
ret.cruiseState.enabled = bool(cp.vl["ACC_CONTROL"]["ACC_ACTIVE"])
ret.steeringTorque = cp.vl["EPS_STATUS"]["TORQUE_DRIVER"]
ret.steeringTorqueEps = cp.vl["EPS_STATUS"]["TORQUE_MOTOR"]
ret.steeringPressed = abs(ret.steeringTorque) > STEER_THRESHOLD
ret.steerFaultPermanent = bool(cp.vl["EPS_STATUS"]["LKAS_FAULT"])
if self.CP.enableBsm:
ret.leftBlindspot = bool(cp.vl["BSM_LEFT"]["LEFT_DETECTED"])
ret.rightBlindspot = bool(cp.vl["BSM_RIGHT"]["RIGHT_DETECTED"])
self.lkas_car_model = cp_cam.vl["DAS_6"]["CAR_MODEL"]
return ret, ret_sp
@staticmethod
def get_can_parsers(CP, CP_SP):
return {

View File

@@ -1,6 +1,6 @@
from opendbc.car import structs
from opendbc.car.crc import CRC8J1850
from opendbc.car.chrysler.values import RAM_CARS
from opendbc.car.chrysler.values import CUSW_CARS, RAM_CARS
GearShifter = structs.CarState.GearShifter
VisualAlert = structs.CarControl.HUDControl.VisualAlert
@@ -48,7 +48,7 @@ def create_lkas_hud(packer, CP, lkas_active, hud_alert, hud_count, car_model, au
"LKAS_ICON_COLOR": color,
"CAR_MODEL": car_model,
"LKAS_LANE_LINES": lines,
"LKAS_ALERTS": alerts,
"LKAS_ALERTS": alerts if CP.carFingerprint not in CUSW_CARS else 0, # TODO: HUD behavior not yet understood for CUSW
}
if CP.carFingerprint in RAM_CARS:

View File

@@ -281,6 +281,26 @@ FW_VERSIONS = {
b'68676877AB',
],
},
CAR.JEEP_CHEROKEE_5TH_GEN: {
(Ecu.combinationMeter, 0x18da60f1, None): [
b'68492643AC',
],
(Ecu.srs, 0x18dac0f1, None): [
b'68469498AA',
],
(Ecu.abs, 0x18da28f1, None): [
b'68477674AB',
],
(Ecu.eps, 0x18da30f1, None): [
b'68319152AJ',
],
(Ecu.engine, 0x18da10f1, None): [
b'68493558AD ',
],
(Ecu.transmission, 0x18da18f1, None): [
b'68492011AD',
],
},
CAR.JEEP_GRAND_CHEROKEE: {
(Ecu.combinationMeter, 0x742, None): [
b'68243549AG',

View File

@@ -3,7 +3,7 @@ from opendbc.car import get_safety_config, structs
from opendbc.car.chrysler.carcontroller import CarController
from opendbc.car.chrysler.carstate import CarState
from opendbc.car.chrysler.radar_interface import RadarInterface
from opendbc.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags, ChryslerSafetyFlags
from opendbc.car.chrysler.values import CAR, CUSW_CARS, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags, ChryslerSafetyFlags
from opendbc.car.interfaces import CarInterfaceBase
from opendbc.sunnypilot.car.chrysler.values_ext import ChryslerFlagsSP
@@ -18,7 +18,9 @@ class CarInterface(CarInterfaceBase):
@staticmethod
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
ret.brand = "chrysler"
ret.dashcamOnly = candidate in RAM_HD
# TODO: Chrysler CUSW in dashcam pending comma safety validation and a fix for LKAS fault on disengage
ret.dashcamOnly = candidate in (RAM_HD | CUSW_CARS)
# radar parsing needs some work, see https://github.com/commaai/openpilot/issues/26842
ret.radarUnavailable = True # Bus.radar not in DBC[candidate][Bus.radar]
@@ -31,6 +33,8 @@ class CarInterface(CarInterfaceBase):
ret.safetyConfigs[0].safetyParam |= ChryslerSafetyFlags.RAM_HD.value
elif candidate in RAM_DT:
ret.safetyConfigs[0].safetyParam |= ChryslerSafetyFlags.RAM_DT.value
elif candidate in CUSW_CARS:
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.chryslerCusw)]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
if candidate not in RAM_CARS:
@@ -49,6 +53,9 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kf = 0.00006
# Jeep
elif candidate == CAR.JEEP_CHEROKEE_5TH_GEN:
ret.steerActuatorDelay = 0.15
elif candidate in (CAR.JEEP_GRAND_CHEROKEE, CAR.JEEP_GRAND_CHEROKEE_2019):
ret.steerActuatorDelay = 0.2
@@ -77,7 +84,7 @@ class CarInterface(CarInterfaceBase):
ret.minSteerSpeed = 17.5 # m/s 17 on the way up, 13 on the way down once engaged.
ret.centerToFront = ret.wheelbase * 0.44
ret.enableBsm = 720 in fingerprint[0]
ret.enableBsm = (0x62cc033 if candidate in CUSW_CARS else 0x2d0) in fingerprint[0]
return ret

View File

@@ -67,6 +67,11 @@ class CAR(Platforms):
)
# Jeep
JEEP_CHEROKEE_5TH_GEN = ChryslerPlatformConfig(
[ChryslerCarDocs("Jeep Cherokee 2019-23")],
ChryslerCarSpecs(mass=1747., wheelbase=2.70, steerRatio=17.0, minSteerSpeed=18.5),
{Bus.pt: 'chrysler_cusw'},
)
JEEP_GRAND_CHEROKEE = ChryslerPlatformConfig( # includes 2017 Trailhawk
[ChryslerCarDocs("Jeep Grand Cherokee 2016-18", video="https://www.youtube.com/watch?v=eLR9o2JkuRk")],
ChryslerCarSpecs(mass=1778., wheelbase=2.71, steerRatio=16.7),
@@ -105,6 +110,11 @@ class CarControllerParams:
self.STEER_DELTA_UP = 6
self.STEER_DELTA_DOWN = 6
self.STEER_MAX = 350 # EPS allows more, up to 350?
elif CP.carFingerprint in CUSW_CARS:
self.STEER_STEP = 1 # 100 Hz
self.STEER_DELTA_UP = 4
self.STEER_DELTA_DOWN = 4
self.STEER_MAX = 250 # TODO: Some CUSW will go to 261, some not quite, exact boundaries not yet determined
else:
self.STEER_DELTA_UP = 3
self.STEER_DELTA_DOWN = 3
@@ -116,6 +126,7 @@ STEER_THRESHOLD = 120
RAM_DT = {CAR.RAM_1500_5TH_GEN, }
RAM_HD = {CAR.RAM_HD_5TH_GEN, }
RAM_CARS = RAM_DT | RAM_HD
CUSW_CARS = {CAR.JEEP_CHEROKEE_5TH_GEN, }
CHRYSLER_VERSION_REQUEST = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \

View File

@@ -42,12 +42,11 @@ class CAR(Platforms):
CommunityCarDocs("Acura MDX 2015-16", "Advance Package"),
CommunityCarDocs("Acura MDX 2017-20"),
CommunityCarDocs("Acura MDX Hybrid 2017-20"),
CommunityCarDocs("Acura MDX 2022-24"),
CommunityCarDocs("Acura RDX 2022-25"),
CommunityCarDocs("Acura RDX 2025"),
CommunityCarDocs("Acura RLX 2017", "Advance Package or Technology Package"),
CommunityCarDocs("Acura TLX 2015-17", "Advance Package"),
CommunityCarDocs("Acura TLX 2018-20"),
CommunityCarDocs("Acura TLX 2022-23"),
CommunityCarDocs("Acura TLX 2023"),
GMSecurityCarDocs("Acura ZDX 2024"),
CommunityCarDocs("Honda Accord 2016-17", "Honda Sensing"),
CommunityCarDocs("Honda Accord Hybrid 2017"),

View File

@@ -8,6 +8,7 @@ from opendbc.car.hyundai.values import CAR as HYUNDAI
from opendbc.car.mazda.values import CAR as MAZDA
from opendbc.car.mock.values import CAR as MOCK
from opendbc.car.nissan.values import CAR as NISSAN
from opendbc.car.rivian.values import CAR as RIVIAN
from opendbc.car.subaru.values import CAR as SUBARU
from opendbc.car.toyota.values import CAR as TOYOTA
from opendbc.car.volkswagen.values import CAR as VW
@@ -333,6 +334,8 @@ MIGRATION = {
"SKODA SCALA 1ST GEN": VW.SKODA_KAMIQ_MK1,
"SKODA_SCALA_MK1": VW.SKODA_KAMIQ_MK1,
"SKODA SUPERB 3RD GEN": VW.SKODA_SUPERB_MK3,
"RIVIAN_R1_GEN1": RIVIAN.RIVIAN_R1,
"RIVIAN_R1_GEN2": RIVIAN.RIVIAN_R1,
"mock": MOCK.MOCK,
}

View File

@@ -106,10 +106,12 @@ FW_VERSIONS = {
},
CAR.FORD_F_150_MK14: {
(Ecu.eps, 0x730, None): [
b'ML3V-14D003-BA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3V-14D003-BC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3V-14D003-BD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.abs, 0x760, None): [
b'ML34-2D053-AJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'NL34-2D053-CA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PL34-2D053-CA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PL34-2D053-CC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@@ -117,6 +119,7 @@ FW_VERSIONS = {
b'PL3V-2D053-BB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.fwdRadar, 0x764, None): [
b'ML3T-14D049-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3T-14D049-AK\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
@@ -124,6 +127,7 @@ FW_VERSIONS = {
b'ML3T-14H102-ABR\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3T-14H102-ABS\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3T-14H102-ABT\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3T-14H102-ACA\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PJ6T-14H102-ABJ\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PJ6T-14H102-ABS\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'RJ6T-14H102-ACJ\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@@ -211,6 +215,7 @@ FW_VERSIONS = {
b'PB3C-2D053-ZD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PB3C-2D053-ZG\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PB3C-2D053-ZJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'RB3C-2D053-AK\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.fwdRadar, 0x764, None): [
b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',

View File

@@ -292,7 +292,6 @@ FW_QUERY_CONFIG = FwQueryConfig(
[StdQueries.TESTER_PRESENT_RESPONSE, StdQueries.MANUFACTURER_SOFTWARE_VERSION_RESPONSE],
whitelist_ecus=[Ecu.abs, Ecu.debug, Ecu.engine, Ecu.eps, Ecu.fwdCamera, Ecu.fwdRadar, Ecu.shiftByWire],
bus=0,
auxiliary=True,
),
*[Request(
[StdQueries.TESTER_PRESENT_REQUEST, ford_asbuilt_block_request(block_id)],

View File

@@ -1,4 +1,3 @@
import copy
from dataclasses import dataclass, field
import struct
from collections.abc import Callable
@@ -90,8 +89,6 @@ class Request:
whitelist_ecus: list[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)
auxiliary: bool = False
# FW responses from these queries will not be used for fingerprinting
logging: bool = False
# pandad toggles OBD multiplexing on/off as needed
@@ -130,17 +127,6 @@ class FwQueryConfig:
assert len(request_obj.request) == len(request_obj.response), ("Request and response lengths do not match: " +
f"{request_obj.request} vs. {request_obj.response}")
# No request on the OBD port (bus 1, multiplexed) should be run on an aux panda
assert not (request_obj.auxiliary and request_obj.bus == 1 and request_obj.obd_multiplexing), ("OBD multiplexed request should not " +
f"be marked auxiliary: {request_obj}")
# Add aux requests (second panda) for all requests that are marked as auxiliary
for i in range(len(self.requests)):
if self.requests[i].auxiliary:
new_request = copy.deepcopy(self.requests[i])
new_request.bus += 4
self.requests.append(new_request)
def get_all_ecus(self, offline_fw_versions: OfflineFwVersions,
include_extra_ecus: bool = True) -> set[EcuAddrSubAddr]:
# Add ecus in database + extra ecus

View File

@@ -170,17 +170,13 @@ def match_fw_to_car(fw_versions: list[CarParams.CarFw], vin: str, allow_exact: b
return True, set()
def get_present_ecus(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback, num_pandas: int = 1) -> set[EcuAddrBusType]:
def get_present_ecus(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback) -> set[EcuAddrBusType]:
# queries are split by OBD multiplexing mode
queries: dict[bool, list[list[EcuAddrBusType]]] = {True: [], False: []}
parallel_queries: dict[bool, list[EcuAddrBusType]] = {True: [], False: []}
responses: set[EcuAddrBusType] = set()
for brand, config, r in REQUESTS:
# Skip query if no panda available
if r.bus > num_pandas * 4 - 1:
continue
for ecu_type, addr, sub_addr in config.get_all_ecus(VERSIONS[brand]):
# Only query ecus in whitelist if whitelist is not empty
if len(r.whitelist_ecus) == 0 or ecu_type in r.whitelist_ecus:
@@ -229,7 +225,7 @@ def get_brand_ecu_matches(ecu_rx_addrs: set[EcuAddrBusType]) -> dict[str, list[b
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, progress: bool = False) -> list[CarParams.CarFw]:
ecu_rx_addrs: set[EcuAddrBusType], timeout: float = 0.1, progress: bool = False) -> list[CarParams.CarFw]:
"""Queries for FW versions ordering brands by likelihood, breaks when exact match is found"""
all_car_fw = []
@@ -242,7 +238,7 @@ def get_fw_versions_ordered(can_recv: CanRecvCallable, can_send: CanSendCallable
if True not in brand_matches[brand]:
continue
car_fw = get_fw_versions(can_recv, can_send, set_obd_multiplexing, query_brand=brand, timeout=timeout, num_pandas=num_pandas, progress=progress)
car_fw = get_fw_versions(can_recv, can_send, set_obd_multiplexing, query_brand=brand, timeout=timeout, progress=progress)
all_car_fw.extend(car_fw)
# If there is a match using this brand's FW alone, finish querying early
@@ -254,7 +250,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 = None,
extra: OfflineFwVersions | None = None, timeout: float = 0.1, num_pandas: int = 1, progress: bool = False) -> list[CarParams.CarFw]:
extra: OfflineFwVersions | None = None, timeout: float = 0.1, progress: bool = False) -> list[CarParams.CarFw]:
versions = VERSIONS.copy()
if query_brand is not None:
@@ -291,10 +287,6 @@ def get_fw_versions(can_recv: CanRecvCallable, can_send: CanSendCallable, set_ob
for addr_group in tqdm(addrs, disable=not progress): # split by subaddr, if any
for addr_chunk in chunks(addr_group):
for brand, config, r in requests:
# Skip query if no panda available
if r.bus > num_pandas * 4 - 1:
continue
# Toggle OBD multiplexing for each request
if r.bus % 4 == 1:
set_obd_multiplexing(r.obd_multiplexing)

View File

@@ -234,10 +234,9 @@ class CarController(CarControllerBase, MadsCarController, GasInterceptorCarContr
can_sends.append(hondacan.create_acc_hud(self.packer, self.CAN.pt, self.CP, CC.enabled, pcm_speed, pcm_accel,
hud_control, hud_v_cruise, CS.is_metric, CS.acc_hud))
steering_available = CS.out.cruiseState.available and CS.out.vEgo > self.CP.minSteerSpeed
reduced_steering = CS.out.steeringPressed
steering_available = CS.out.cruiseState.available and CS.out.vEgo > max(self.params.STEER_GLOBAL_MIN_SPEED, self.CP.minSteerSpeed)
can_sends.extend(hondacan.create_lkas_hud(self.packer, self.CAN.lkas, self.CP, hud_control, CC.latActive,
steering_available, reduced_steering, alert_steer_required, CS.lkas_hud, self.dashed_lanes))
steering_available, alert_steer_required, CS.lkas_hud, self.dashed_lanes))
if self.CP.openpilotLongitudinalControl:
# TODO: combining with create_acc_hud block above will change message order and will need replay logs regenerated

View File

@@ -113,6 +113,10 @@ class CarState(CarStateBase, CarStateExt):
# FIXME: the stock camera stops steering on NO_TORQUE_ALERT_1
ret.steerFaultTemporary = steer_status not in ("NORMAL", "LOW_SPEED_LOCKOUT", "NO_TORQUE_ALERT_2")
if (self.CP.carFingerprint == CAR.ACURA_MDX_4G) and (steer_status == "TJA_LOW_SPEED_LOCKOUT"):
ret.steerFaultPermanent = False
ret.steerFaultTemporary = False
# All Honda EPS cut off slightly above standstill, some much higher
# Don't alert in the near-standstill range, but alert for per-vehicle configured minimums above that
if CarControllerParams.STEER_GLOBAL_MIN_SPEED < ret.vEgo < (self.CP.minSteerSpeed + 0.5):
@@ -126,7 +130,10 @@ class CarState(CarStateBase, CarStateExt):
ret.accFaulted = bool(cp.vl["CRUISE_FAULT_STATUS"]["CRUISE_FAULT"])
else:
if self.CP.openpilotLongitudinalControl:
ret.accFaulted = bool(cp.vl[self.brake_error_msg]["BRAKE_ERROR_1"] or cp.vl[self.brake_error_msg]["BRAKE_ERROR_2"])
if (self.CP.carFingerprint == CAR.ACURA_MDX_4G) and (self.CP.flags & HondaFlags.BOSCH_ALT_BRAKE):
ret.accFaulted = bool(cp.vl["BRAKE_MODULE"]["CRUISE_FAULT"])
else:
ret.accFaulted = bool(cp.vl[self.brake_error_msg]["BRAKE_ERROR_1"] or cp.vl[self.brake_error_msg]["BRAKE_ERROR_2"])
# Log non-critical stock ACC/LKAS faults if Nidec (camera)
if self.CP.carFingerprint not in HONDA_BOSCH:
@@ -149,7 +156,7 @@ class CarState(CarStateBase, CarStateExt):
ret.parkingBrake = bool(cp.vl[self.car_state_scm_msg]["PARKING_BRAKE_ON"])
if self.CP.transmissionType == TransmissionType.manual:
ret.gearShifter = GearShifter.reverse if bool(cp.vl["SCM_FEEDBACK"]["REVERSE_LIGHT"]) else GearShifter.drive
ret.gearShifter = GearShifter.reverse if bool(cp.vl[self.car_state_scm_msg]["REVERSE_LIGHT"]) else GearShifter.drive
else:
gear_position = self.shifter_values.get(cp.vl[self.gearbox_msg]["GEAR_SHIFTER"], None)
ret.gearShifter = self.parse_gear_shifter(gear_position)

View File

@@ -493,6 +493,7 @@ FW_VERSIONS = {
(Ecu.vsa, 0x18da28f1, None): [
b'57114-T5R-L020\x00\x00',
b'57114-T5R-L220\x00\x00',
b'57114-T5R-L320\x00\x00',
],
(Ecu.eps, 0x18da30f1, None): [
b'39990-T5R-C020\x00\x00',
@@ -504,6 +505,7 @@ FW_VERSIONS = {
(Ecu.fwdRadar, 0x18dab0f1, None): [
b'36161-T5R-A040\x00\x00',
b'36161-T5R-A240\x00\x00',
b'36161-T5R-A340\x00\x00',
b'36161-T5R-A520\x00\x00',
],
(Ecu.srs, 0x18da53f1, None): [
@@ -528,6 +530,49 @@ FW_VERSIONS = {
b'36161-TDK-J530\x00\x00',
],
},
CAR.ACURA_MDX_4G: {
(Ecu.gateway, 0x18daeff1, None): [
b'38897-TYA-A010\x00\x00',
b'38897-TYB-A010\x00\x00',
b'38897-TYC-A010\x00\x00',
],
(Ecu.eps, 0x18da30f1, None): [
b'39990-TYA-A070\x00\x00',
b'39990-TYA-A080\x00\x00',
b'39990-TYB-A020\x00\x00',
],
(Ecu.srs, 0x18da53f1, None): [
b'77959-TYA-A050\x00\x00',
b'77959-TYB-A020\x00\x00',
b'77959-TYC-A050\x00\x00',
],
(Ecu.fwdCamera, 0x18dab5f1, None): [
b'36161-TYA-A040\x00\x00',
b'36161-TYA-A050\x00\x00',
b'36161-TYB-A030\x00\x00',
],
(Ecu.fwdRadar, 0x18dab0f1, None): [
b'36802-TYA-A040\x00\x00',
b'36802-TYB-A040\x00\x00',
],
(Ecu.transmission, 0x18da1ef1, None): [
b'28102-61D-A000\x00\x00',
b'28102-61E-A010\x00\x00',
b'28102-61F-A010\x00\x00',
],
(Ecu.vsa, 0x18da28f1, None): [
b'57114-TYA-A060\x00\x00',
b'57114-TYA-A070\x00\x00',
b'57114-TYB-A150\x00\x00',
],
(Ecu.shiftByWire, 0x18da0bf1, None): [
b'54008-TGV-A810\x00\x00',
],
(Ecu.electricBrakeBooster, 0x18da2bf1, None): [
b'46114-TYA-A040\x00\x00',
b'46114-TYA-A060\x00\x00',
],
},
CAR.ACURA_MDX_4G_MMR: {
(Ecu.fwdCamera, 0x18dab5f1, None): [
b'8S102-TYA-A020\x00\x00',
@@ -593,12 +638,21 @@ FW_VERSIONS = {
CAR.HONDA_ODYSSEY_TWN: {
(Ecu.eps, 0x18da30f1, None): [
b'39990-T6A-J210\x00\x00',
b'39990-T6A-J420\x00\x00',
],
(Ecu.srs, 0x18da53f1, None): [
b'77959-T6A-J130\x00\x00',
b'77959-T6A-P110\x00\x00',
],
(Ecu.fwdRadar, 0x18dab0f1, None): [
b'36161-T6A-P040\x00\x00',
b'36161-T6A-U230\x00\x00',
],
(Ecu.gateway, 0x18daeff1, None): [
b'38897-T6A-J110\x00\x00',
],
(Ecu.transmission, 0x18da1ef1, None): [
b'28101-5X9-U010\x00\x00',
],
},
CAR.HONDA_ODYSSEY_5G_MMR: {
@@ -786,6 +840,36 @@ FW_VERSIONS = {
b'39990-TJB-A130\x00\x00',
],
},
# mid-model refresh
CAR.ACURA_RDX_3G_MMR: {
(Ecu.vsa, 0x18da28f1, None): [
b'57114-TJB-A120\x00\x00',
],
(Ecu.fwdRadar, 0x18dab0f1, None): [
b'36802-TJB-A540\x00\x00',
],
(Ecu.fwdCamera, 0x18dab5f1, None): [
b'36161-TJB-A530\x00\x00',
],
(Ecu.shiftByWire, 0x18da0bf1, None): [
b'54008-TJB-A530\x00\x00',
],
(Ecu.transmission, 0x18da1ef1, None): [
b'28102-5YK-A800\x00\x00',
],
(Ecu.srs, 0x18da53f1, None): [
b'77959-TJB-A120\x00\x00',
],
(Ecu.electricBrakeBooster, 0x18da2bf1, None): [
b'46114-TJB-A120\x00\x00',
],
(Ecu.gateway, 0x18daeff1, None): [
b'38897-TJB-A220\x00\x00',
],
(Ecu.eps, 0x18da30f1, None): [
b'39990-TJB-A070\x00\x00',
],
},
CAR.HONDA_RIDGELINE: {
(Ecu.eps, 0x18da30f1, None): [
b'39990-T6Z-A020\x00\x00',
@@ -946,6 +1030,14 @@ FW_VERSIONS = {
b'57114-TYF-E030\x00\x00',
],
},
CAR.HONDA_E_ADVANCE: {
(Ecu.fwdCamera, 0x18dab5f1, None): [
b'36161-TYF-E020\x00\x00',
],
(Ecu.fwdRadar, 0x18dab0f1, None): [
b'36802-TYF-E050\x00\x00',
],
},
CAR.HONDA_CIVIC_2022: {
(Ecu.eps, 0x18da30f1, None): [
b'39990-T24-T120\x00\x00',
@@ -995,6 +1087,7 @@ FW_VERSIONS = {
b'36161-T47-A060\x00\x00',
b'36161-T47-A070\x00\x00',
b'8S102-T20-AA10\x00\x00',
b'8S102-T20-AA20\x00\x00',
b'8S102-T43-J540\x00\x00',
b'8S102-T47-AA10\x00\x00',
b'8S102-T47-AA20\x00\x00',
@@ -1003,6 +1096,7 @@ FW_VERSIONS = {
b'8S102-T56-A070\x00\x00',
b'8S102-T60-AA10\x00\x00',
b'8S102-T64-A040\x00\x00',
b'8S102-T64-A050\x00\x00',
],
(Ecu.vsa, 0x18da28f1, None): [
b'57114-T20-AB40\x00\x00',
@@ -1095,6 +1189,7 @@ FW_VERSIONS = {
],
(Ecu.fwdCamera, 0x18dab5f1, None): [
b'36161-TGV-A030\x00\x00',
b'36161-TGV-A040\x00\x00',
],
},
CAR.ACURA_TLX_2G_MMR: {

View File

@@ -172,7 +172,7 @@ def create_acc_hud(packer, bus, CP, enabled, pcm_speed, pcm_accel, hud_control,
return packer.make_can_msg("ACC_HUD", bus, acc_hud_values)
def create_lkas_hud(packer, bus, CP, hud_control, lat_active, steering_available, reduced_steering, alert_steer_required, lkas_hud, dashed_lanes):
def create_lkas_hud(packer, bus, CP, hud_control, lat_active, steering_available, alert_steer_required, lkas_hud, dashed_lanes):
commands = []
lkas_hud_values = {
@@ -202,7 +202,6 @@ def create_lkas_hud(packer, bus, CP, hud_control, lat_active, steering_available
if CP.carFingerprint in HONDA_BOSCH_ALT_RADAR:
lkas_hud_values['DASHED_LANES'] = steering_available and lat_active
lkas_hud_values['SOLID_LANES'] = lat_active
lkas_hud_values['LKAS_PROBLEM'] = lat_active and reduced_steering
if CP.flags & HondaFlags.BOSCH_EXT_HUD and not CP.openpilotLongitudinalControl:
commands.append(packer.make_can_msg('LKAS_HUD_A', bus, lkas_hud_values))

View File

@@ -72,8 +72,7 @@ class CarInterface(CarInterfaceBase):
if 0x184 in fingerprint[CAN.pt]:
ret.flags |= HondaFlags.HYBRID.value
if ret.flags & HondaFlags.ALLOW_MANUAL_TRANS and all(msg not in fingerprint[CAN.pt] for msg in (0x191, 0x1A3)):
# Manual transmission support for allowlisted cars only, to prevent silent fall-through on auto-detection failures
if all(msg not in fingerprint[CAN.pt] for msg in (0x191, 0x1A3)):
ret.transmissionType = TransmissionType.manual
elif 0x191 in fingerprint[CAN.pt] and candidate != CAR.ACURA_RDX:
# Traditional CVTs, gearshift position in GEARBOX_CVT
@@ -183,7 +182,7 @@ class CarInterface(CarInterfaceBase):
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]]
elif candidate == CAR.HONDA_E:
elif candidate in (CAR.HONDA_E, CAR.HONDA_E_ADVANCE):
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
@@ -199,7 +198,7 @@ class CarInterface(CarInterfaceBase):
# When using stock ACC, the radar intercepts and filters steering commands the EPS would otherwise accept
ret.minSteerSpeed = 70. * CV.KPH_TO_MS
elif candidate == CAR.ACURA_TLX_2G_MMR:
elif candidate in (CAR.ACURA_TLX_2G_MMR, CAR.ACURA_MDX_4G):
ret.steerActuatorDelay = 0.15
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
@@ -213,8 +212,13 @@ class CarInterface(CarInterfaceBase):
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560], [0, 2560]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
if candidate == CAR.ACURA_RDX_3G_MMR:
CarControllerParams.BOSCH_GAS_LOOKUP_V = [0, 2000] # alpha longitudinal pedal tuning
ret.dashcamOnly = is_release # TODO: release from dashcam when there's enough driving data for torqued/paramsd to converge
# These cars use alternate user brake msg (0x1BE)
if 0x1BE in fingerprint[CAN.pt] and candidate in (CAR.HONDA_ACCORD, CAR.HONDA_HRV_3G, CAR.ACURA_RDX_3G, *HONDA_BOSCH_CANFD):
if 0x1BE in fingerprint[CAN.pt] and candidate in (CAR.HONDA_ACCORD, CAR.HONDA_HRV_3G, CAR.ACURA_RDX_3G, CAR.ACURA_MDX_4G,
*HONDA_BOSCH_CANFD):
ret.flags |= HondaFlags.BOSCH_ALT_BRAKE.value
if ret.flags & HondaFlags.BOSCH_ALT_BRAKE:

View File

@@ -76,7 +76,7 @@ class HondaFlags(IntFlag):
HAS_ALL_DOOR_STATES = 256 # Some Hondas have all door states, others only driver door
BOSCH_ALT_RADAR = 512
ALLOW_MANUAL_TRANS = 1024
# 1024 is available
HYBRID = 2048
BOSCH_TJA_CONTROL = 4096
@@ -173,7 +173,6 @@ class CAR(Platforms):
# steerRatio: 11.82 is spec end-to-end
CarSpecs(mass=3279 * CV.LB_TO_KG, wheelbase=2.83, steerRatio=16.33, centerToFrontRatio=0.39, tireStiffnessFactor=0.8467),
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'},
flags=HondaFlags.ALLOW_MANUAL_TRANS,
)
HONDA_ACCORD_11G = HondaBoschCANFDPlatformConfig(
[
@@ -191,7 +190,6 @@ class CAR(Platforms):
],
CarSpecs(mass=1326, wheelbase=2.7, steerRatio=15.38, centerToFrontRatio=0.4), # steerRatio: 10.93 is end-to-end spec
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'},
flags=HondaFlags.ALLOW_MANUAL_TRANS,
)
HONDA_CIVIC_BOSCH_DIESEL = HondaBoschPlatformConfig(
[], # don't show in docs
@@ -209,7 +207,7 @@ class CAR(Platforms):
],
HONDA_CIVIC_BOSCH.specs,
{Bus.pt: 'honda_bosch_radarless_generated'},
flags=HondaFlags.BOSCH_RADARLESS | HondaFlags.ALLOW_MANUAL_TRANS
flags=HondaFlags.BOSCH_RADARLESS
)
HONDA_CRV_5G = HondaBoschPlatformConfig(
[HondaCarDocs("Honda CR-V 2017-22", min_steer_speed=15. * CV.MPH_TO_MS)],
@@ -249,6 +247,12 @@ class CAR(Platforms):
{Bus.pt: 'acura_rdx_2020_can_generated'},
flags=HondaFlags.BOSCH_ALT_BRAKE,
)
ACURA_RDX_3G_MMR = HondaBoschPlatformConfig(
[HondaCarDocs("Acura RDX 2022-24", "All", min_steer_speed=70. * CV.KPH_TO_MS)],
CarSpecs(mass=4079 * CV.LB_TO_KG, wheelbase=2.75, centerToFrontRatio=0.41, steerRatio=16.2),
{Bus.pt: 'acura_rdx_2020_can_generated'},
flags=HondaFlags.BOSCH_ALT_BRAKE | HondaFlags.BOSCH_ALT_RADAR,
)
HONDA_INSIGHT = HondaBoschPlatformConfig(
[HondaCarDocs("Honda Insight 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS)],
CarSpecs(mass=2987 * CV.LB_TO_KG, wheelbase=2.7, steerRatio=15.0, centerToFrontRatio=0.39, tireStiffnessFactor=0.82), # as spec
@@ -259,6 +263,11 @@ class CAR(Platforms):
CarSpecs(mass=3338.8 * CV.LB_TO_KG, wheelbase=2.5, centerToFrontRatio=0.5, steerRatio=16.71, tireStiffnessFactor=0.82),
{Bus.pt: 'acura_rdx_2020_can_generated'},
)
HONDA_E_ADVANCE = HondaBoschPlatformConfig(
[], # don't show in docs, base trim already in docs
CarSpecs(mass=1527, wheelbase=2.5, centerToFrontRatio=0.5, steerRatio=16.71, tireStiffnessFactor=0.82),
{Bus.pt: 'honda_e_advance_2020_can_generated'}, # 8 bit LKAS_HUD in Advance trim
)
HONDA_PILOT_4G = HondaBoschCANFDPlatformConfig(
[HondaCarDocs("Honda Pilot 2023-25", "All")],
CarSpecs(mass=4660 * CV.LB_TO_KG, wheelbase=2.89, centerToFrontRatio=0.442, steerRatio=17.5),
@@ -267,6 +276,12 @@ class CAR(Platforms):
[HondaCarDocs("Honda Passport 2026", "All")],
CarSpecs(mass=4620 * CV.LB_TO_KG, wheelbase=2.89, centerToFrontRatio=0.442, steerRatio=18.5),
)
ACURA_MDX_4G = HondaBoschPlatformConfig(
[HondaCarDocs("Acura MDX 2022-24", "All", min_steer_speed=70. * CV.KPH_TO_MS)],
CarSpecs(mass=4788 * CV.LB_TO_KG, wheelbase=2.89, steerRatio=15.8, centerToFrontRatio=0.428), # as spec
{Bus.pt: 'honda_common_canfd_generated'}, # not CANFD car but shares same dbc
flags=HondaFlags.BOSCH_ALT_RADAR,
)
# mid-model refresh
ACURA_MDX_4G_MMR = HondaBoschCANFDPlatformConfig(
[HondaCarDocs("Acura MDX 2025-26", "All except Type S")],
@@ -279,7 +294,7 @@ class CAR(Platforms):
flags=HondaFlags.BOSCH_ALT_BRAKE | HondaFlags.BOSCH_ALT_RADAR,
)
ACURA_TLX_2G = HondaBoschPlatformConfig(
[HondaCarDocs("Acura TLX 2021", "All")],
[HondaCarDocs("Acura TLX 2021-22", "All")],
CarSpecs(mass=3982 * CV.LB_TO_KG, wheelbase=2.87, steerRatio=14.0, centerToFrontRatio=0.43),
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'},
flags=HondaFlags.BOSCH_ALT_RADAR,
@@ -337,7 +352,10 @@ class CAR(Platforms):
flags=HondaFlags.NIDEC_ALT_PCM_ACCEL | HondaFlags.HAS_ALL_DOOR_STATES,
)
HONDA_ODYSSEY_TWN = HondaNidecPlatformConfig(
[HondaCarDocs("Honda Odyssey (Taiwan) 2018-19")],
[
HondaCarDocs("Honda Odyssey (Taiwan) 2018-19"),
HondaCarDocs("Honda Odyssey (Singapore) 2021")
],
CarSpecs(mass=1865, wheelbase=2.9, steerRatio=14.35, centerToFrontRatio=0.44, tireStiffnessFactor=0.82),
radar_dbc_dict('honda_odyssey_twn_2018_generated'),
flags=HondaFlags.NIDEC_ALT_SCM_MESSAGES,
@@ -446,9 +464,11 @@ FW_QUERY_CONFIG = FwQueryConfig(
# Note that we still attempt to match with them when they are present
# This is or'd with (ALL_ECUS - ESSENTIAL_ECUS) from fw_versions.py
non_essential_ecus={
Ecu.eps: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_E, *HONDA_BOSCH_ALT_RADAR, *HONDA_BOSCH_RADARLESS, *HONDA_BOSCH_CANFD],
Ecu.vsa: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_CIVIC, CAR.HONDA_CIVIC_BOSCH, CAR.HONDA_CRV_5G, CAR.HONDA_CRV_HYBRID,
CAR.HONDA_E, CAR.HONDA_INSIGHT, CAR.HONDA_NBOX_2G, *HONDA_BOSCH_ALT_RADAR, *HONDA_BOSCH_RADARLESS, *HONDA_BOSCH_CANFD],
Ecu.eps: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_E, CAR.HONDA_E_ADVANCE, CAR.ACURA_MDX_4G, *HONDA_BOSCH_ALT_RADAR,
*HONDA_BOSCH_RADARLESS, *HONDA_BOSCH_CANFD],
Ecu.vsa: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_CIVIC, CAR.HONDA_CIVIC_BOSCH, CAR.HONDA_CRV_5G, CAR.HONDA_CRV_HYBRID, CAR.HONDA_E,
CAR.HONDA_E_ADVANCE, CAR.HONDA_INSIGHT, CAR.HONDA_NBOX_2G, CAR.ACURA_MDX_4G, *HONDA_BOSCH_ALT_RADAR, *HONDA_BOSCH_RADARLESS,
*HONDA_BOSCH_CANFD],
},
extra_ecus=[
(Ecu.combinationMeter, 0x18da60f1, None),

View File

@@ -253,10 +253,10 @@ class CarState(CarStateBase, EsccCarStateBase, MadsCarState, CarStateExt):
ret.steeringRateDeg = cp.vl["STEERING_SENSORS"]["STEERING_RATE"]
ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEERING_ANGLE"]
ret.steeringTorque = cp.vl["MDPS"]["STEERING_COL_TORQUE"]
ret.steeringTorqueEps = cp.vl["MDPS"]["STEERING_OUT_TORQUE"]
ret.steeringTorque = cp.vl["MDPS"]["MDPS_StrTqSnsrVal"]
ret.steeringTorqueEps = cp.vl["MDPS"]["MDPS_OutTqVal"]
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
ret.steerFaultTemporary = cp.vl["MDPS"]["LKA_FAULT"] != 0
ret.steerFaultTemporary = cp.vl["MDPS"]["MDPS_LkaFailSta"] != 0
# TODO: alt signal usage may be described by cp.vl['BLINKERS']['USE_ALT_LAMP']
left_blinker_sig, right_blinker_sig = "LEFT_LAMP", "RIGHT_LAMP"
@@ -265,8 +265,8 @@ class CarState(CarStateBase, EsccCarStateBase, MadsCarState, CarStateExt):
ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(50, cp.vl["BLINKERS"][left_blinker_sig],
cp.vl["BLINKERS"][right_blinker_sig])
if self.CP.enableBsm:
ret.leftBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FL_INDICATOR"] != 0
ret.rightBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FR_INDICATOR"] != 0
ret.leftBlindspot = bool(cp.vl["ADAS_CMD_50_50ms"]["BCW_LtIndSta"])
ret.rightBlindspot = bool(cp.vl["ADAS_CMD_50_50ms"]["BCW_RtIndSta"])
# cruise state
# CAN FD cars enable on main button press, set available if no TCS faults preventing engagement

View File

@@ -345,8 +345,10 @@ FW_VERSIONS = {
b'\xf1\x00TM MDPS C 1.00 1.02 56310-CLAC0 4TSHC102',
b'\xf1\x00TM MDPS C 1.00 1.02 56310-CLEC0 4TSHC102',
b'\xf1\x00TM MDPS C 1.00 1.02 56310CLEC0\x00 4TSHC102',
b'\xf1\x00TM MDPS R 1.00 1.06 57700-CL090 4TSHP106',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00TMP MFC AT EUR RHD 1.00 1.06 99211-S1500 220727',
b'\xf1\x00TMP MFC AT USA LHD 1.00 1.03 99211-S1500 210224',
b'\xf1\x00TMP MFC AT USA LHD 1.00 1.05 99211-S1500 220126',
b'\xf1\x00TMP MFC AT USA LHD 1.00 1.06 99211-S1500 220727',
@@ -687,6 +689,7 @@ FW_VERSIONS = {
},
CAR.HYUNDAI_KONA_EV_2022: {
(Ecu.abs, 0x7d1, None): [
b'\xf1\x00OS IEB \x02 101 \x11\x13 58520-K4010',
b'\xf1\x00OS IEB \x02 102"\x05\x16 58520-K4010',
b'\xf1\x00OS IEB \x03 101 \x11\x13 58520-K4010',
b'\xf1\x00OS IEB \x03 102"\x05\x16 58520-K4010',
@@ -702,6 +705,7 @@ FW_VERSIONS = {
],
(Ecu.eps, 0x7d4, None): [
b'\xf1\x00OSP MDPS C 1.00 1.02 56310-K4271 4OEPC102',
b'\xf1\x00OSP MDPS C 1.00 1.02 56310/K4261 4OEPC102',
b'\xf1\x00OSP MDPS C 1.00 1.02 56310/K4271 4OEPC102',
b'\xf1\x00OSP MDPS C 1.00 1.02 56310/K4970 4OEPC102',
b'\xf1\x00OSP MDPS C 1.00 1.02 56310/K4971 4OEPC102',
@@ -1202,6 +1206,7 @@ FW_VERSIONS = {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00SG2HMFC AT USA LHD 1.01 1.08 99211-AT000 220531',
b'\xf1\x00SG2HMFC AT USA LHD 1.01 1.09 99211-AT000 220801',
b'\xf1\x00SG2HMFC AT USA LHD 1.00 1.00 99211-AT100 230216',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00SG2_ RDR ----- 1.00 1.01 99110-AT000 ',

View File

@@ -79,7 +79,7 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
values["CF_Lkas_LdwsActivemode"] = 0
values["CF_Lkas_FcwOpt_USM"] = 0
elif CP.carFingerprint == CAR.HYUNDAI_GENESIS:
elif CP.carFingerprint in (CAR.HYUNDAI_GENESIS, CAR.KIA_OPTIMA_H):
# This field is actually LdwsActivemode
# Genesis and Optima fault when forwarding while engaged
values["CF_Lkas_LdwsActivemode"] = 2

View File

@@ -1,4 +1,3 @@
import copy
import numpy as np
from opendbc.car import CanBusBase
from opendbc.car.crc import CRC16_XMODEM
@@ -38,32 +37,25 @@ class CanBus(CanBusBase):
def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_torque, lkas_icon):
common_values = {
"LKA_MODE": 2,
"LKA_ICON": lkas_icon,
"TORQUE_REQUEST": apply_torque,
"LKA_ASSIST": 0,
"STEER_REQ": 1 if lat_active else 0,
"STEER_MODE": 0,
"HAS_LANE_SAFETY": 0, # hide LKAS settings
"NEW_SIGNAL_2": 0,
"DAMP_FACTOR": 100, # can potentially tuned for better perf [3, 200]
values = {
"LKA_OptUsmSta": 2,
"LKA_SysIndReq": lkas_icon,
"StrTqReqVal": apply_torque,
"LKA_SysWrn": 0,
"ActToiSta": 1 if lat_active else 0,
"LKA_UsmMod": 0, # hide LKAS settings
"LKA_RcgSta": 0,
"Damping_Gain": 100, # can potentially tuned for better perf [3, 200]
}
lkas_values = copy.copy(common_values)
lkas_values["LKA_AVAILABLE"] = 0
lfa_values = copy.copy(common_values)
lfa_values["NEW_SIGNAL_1"] = 0
ret = []
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
lkas_msg = "LKAS_ALT" if CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT else "LKAS"
if CP.openpilotLongitudinalControl:
ret.append(packer.make_can_msg("LFA", CAN.ECAN, lfa_values))
ret.append(packer.make_can_msg(lkas_msg, CAN.ACAN, lkas_values))
ret.append(packer.make_can_msg("LFA", CAN.ECAN, values))
ret.append(packer.make_can_msg(lkas_msg, CAN.ACAN, values))
else:
ret.append(packer.make_can_msg("LFA", CAN.ECAN, lfa_values))
ret.append(packer.make_can_msg("LFA", CAN.ECAN, values))
return ret

View File

@@ -1,8 +1,6 @@
from opendbc.car import Bus, get_safety_config, structs, uds
from opendbc.car.hyundai.hyundaicanfd import CanBus
from opendbc.car.hyundai.values import HyundaiFlags, CAR, DBC, \
CANFD_UNSUPPORTED_LONGITUDINAL_CAR, \
UNSUPPORTED_LONGITUDINAL_CAR, HyundaiSafetyFlags
from opendbc.car.hyundai.values import HyundaiFlags, CAR, DBC, HyundaiSafetyFlags
from opendbc.car.hyundai.radar_interface import RADAR_START_ADDR
from opendbc.car.interfaces import CarInterfaceBase
from opendbc.car.disable_ecu import disable_ecu
@@ -42,12 +40,12 @@ class CarInterface(CarInterfaceBase):
if ret.flags & HyundaiFlags.CANFD:
# Shared configuration for CAN-FD cars
ret.alphaLongitudinalAvailable = candidate not in CANFD_UNSUPPORTED_LONGITUDINAL_CAR
ret.alphaLongitudinalAvailable = not (ret.flags & HyundaiFlags.CANFD_NO_RADAR_DISABLE)
if lka_steering and Ecu.adas not in [fw.ecu for fw in car_fw]:
# this needs to be figured out for cars without an ADAS ECU
ret.alphaLongitudinalAvailable = False
ret.enableBsm = 0x1e5 in fingerprint[CAN.ECAN]
ret.enableBsm = 0x1ba in fingerprint[CAN.ECAN]
# Check if the car is hybrid. Only HEV/PHEV cars have 0xFA on E-CAN.
if 0xFA in fingerprint[CAN.ECAN]:
@@ -89,7 +87,7 @@ class CarInterface(CarInterfaceBase):
else:
# Shared configuration for non CAN-FD cars
ret.alphaLongitudinalAvailable = candidate not in UNSUPPORTED_LONGITUDINAL_CAR
ret.alphaLongitudinalAvailable = not (ret.flags & (HyundaiFlags.LEGACY | HyundaiFlags.UNSUPPORTED_LONGITUDINAL))
ret.enableBsm = 0x58b in fingerprint[0]
# Send LFA message on cars with HDA

View File

@@ -75,7 +75,8 @@ class TestHyundaiFingerprint(unittest.TestCase):
assert set.union(*CAN_GEARS.values()) & (HYBRID_CAR | EV_CAR) == set()
# Test CAN FD car not in CAN feature lists
can_specific_feature_list = set.union(*CAN_GEARS.values(), *CHECKSUM.values(), LEGACY_SAFETY_MODE_CAR, UNSUPPORTED_LONGITUDINAL_CAR, CAMERA_SCC_CAR)
can_specific_feature_list = set.union(*CAN_GEARS.values(), *CHECKSUM.values(), LEGACY_SAFETY_MODE_CAR,
*UNSUPPORTED_LONGITUDINAL_CAR.values(), CAMERA_SCC_CAR)
for car_model in CANFD_CAR:
assert car_model not in can_specific_feature_list, "CAN FD car unexpectedly found in a CAN feature list"

View File

@@ -427,7 +427,7 @@ class CAR(Platforms):
KIA_NIRO_EV_2ND_GEN = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Kia Niro EV (without HDA II) 2023-25", "All", car_parts=CarParts.common([CarHarness.hyundai_a])),
HyundaiCarDocs("Kia Niro EV (with HDA II) 2025", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_r])),
HyundaiCarDocs("Kia Niro EV (with HDA II) 2024-25", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_r])),
],
KIA_NIRO_EV.specs,
flags=HyundaiFlags.EV,
@@ -458,7 +458,7 @@ class CAR(Platforms):
flags=HyundaiFlags.HYBRID,
)
KIA_NIRO_HEV_2ND_GEN = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Kia Niro Hybrid 2023", car_parts=CarParts.common([CarHarness.hyundai_a]))],
[HyundaiCarDocs("Kia Niro Hybrid 2023-24", car_parts=CarParts.common([CarHarness.hyundai_a]))],
KIA_NIRO_EV.specs,
)
KIA_OPTIMA_G4 = HyundaiPlatformConfig(
@@ -780,13 +780,11 @@ FW_QUERY_CONFIG = FwQueryConfig(
[HYUNDAI_VERSION_REQUEST_LONG],
[HYUNDAI_VERSION_RESPONSE],
bus=0,
auxiliary=True,
),
Request(
[HYUNDAI_VERSION_REQUEST_LONG],
[HYUNDAI_VERSION_RESPONSE],
bus=1,
auxiliary=True,
obd_multiplexing=False,
),
@@ -796,7 +794,6 @@ FW_QUERY_CONFIG = FwQueryConfig(
[HYUNDAI_ECU_MANUFACTURING_DATE],
[HYUNDAI_VERSION_RESPONSE],
bus=0,
auxiliary=True,
logging=True,
),
@@ -805,14 +802,12 @@ FW_QUERY_CONFIG = FwQueryConfig(
[HYUNDAI_VERSION_REQUEST_ALT],
[HYUNDAI_VERSION_RESPONSE],
bus=0,
auxiliary=True,
logging=True,
),
Request(
[HYUNDAI_VERSION_REQUEST_ALT],
[HYUNDAI_VERSION_RESPONSE],
bus=1,
auxiliary=True,
logging=True,
obd_multiplexing=False,
),
@@ -847,9 +842,6 @@ CAN_GEARS = {
}
CANFD_CAR = CAR.with_flags(HyundaiFlags.CANFD)
CANFD_RADAR_SCC_CAR = CAR.with_flags(HyundaiFlags.RADAR_SCC) # TODO: merge with UNSUPPORTED_LONGITUDINAL_CAR
CANFD_UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.CANFD_NO_RADAR_DISABLE) # TODO: merge with UNSUPPORTED_LONGITUDINAL_CAR
CAMERA_SCC_CAR = CAR.with_flags(HyundaiFlags.CAMERA_SCC)
@@ -859,9 +851,10 @@ EV_CAR = CAR.with_flags(HyundaiFlags.EV)
LEGACY_SAFETY_MODE_CAR = CAR.with_flags(HyundaiFlags.LEGACY)
# TODO: another PR with (HyundaiFlags.LEGACY | HyundaiFlags.UNSUPPORTED_LONGITUDINAL | HyundaiFlags.CAMERA_SCC |
# HyundaiFlags.CANFD_RADAR_SCC | HyundaiFlags.CANFD_NO_RADAR_DISABLE | )
UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.LEGACY) | CAR.with_flags(HyundaiFlags.UNSUPPORTED_LONGITUDINAL)
UNSUPPORTED_LONGITUDINAL_CAR = {
"legacy": CAR.with_flags(HyundaiFlags.LEGACY),
"can": CAR.with_flags(HyundaiFlags.UNSUPPORTED_LONGITUDINAL),
}
# port extensions
NON_SCC_CAR = CAR.with_sp_flags(HyundaiFlagsSP.NON_SCC)

View File

@@ -4,7 +4,7 @@ from opendbc.car import Bus
from opendbc.car.lateral import apply_driver_steer_torque_limits
from opendbc.car.interfaces import CarControllerBase
from opendbc.car.rivian.riviancan import create_lka_steering, create_longitudinal, create_wheel_touch, create_adas_status
from opendbc.car.rivian.values import CarControllerParams
from opendbc.car.rivian.values import CarControllerParams, RivianFlags
from opendbc.sunnypilot.car.rivian.mads import MadsCarController
@@ -35,7 +35,7 @@ class CarController(CarControllerBase, MadsCarController):
self.apply_torque_last = apply_torque
can_sends.append(create_lka_steering(self.packer, self.frame, CS.acm_lka_hba_cmd, apply_torque, CC.enabled, CC.latActive, self.mads))
if self.frame % 5 == 0:
if self.frame % 5 == 0 and not (self.CP.flags & RivianFlags.GEN2):
can_sends.append(create_wheel_touch(self.packer, CS.sccm_wheel_touch, CC.enabled))
# Longitudinal control
@@ -52,7 +52,8 @@ class CarController(CarControllerBase, MadsCarController):
else:
self.cancel_frames = 0
can_sends.append(create_adas_status(self.packer, CS.vdm_adas_status, interface_status))
for msg in CS.vdm_adas_status:
can_sends.append(create_adas_status(self.packer, msg, interface_status))
new_actuators = actuators.as_builder()
new_actuators.torque = apply_torque / steer_max

View File

@@ -2,7 +2,7 @@ import copy
from opendbc.can import CANParser
from opendbc.car import Bus, structs
from opendbc.car.interfaces import CarStateBase
from opendbc.car.rivian.values import DBC, GEAR_MAP
from opendbc.car.rivian.values import DBC, GEAR_MAP, RivianFlags
from opendbc.car.common.conversions import Conversions as CV
from opendbc.sunnypilot.car.rivian.carstate_ext import CarStateExt
@@ -15,9 +15,9 @@ class CarState(CarStateBase, CarStateExt):
CarStateExt.__init__(self, CP, CP_SP)
self.last_speed = 30
self.acm_lka_hba_cmd = None
self.sccm_wheel_touch = None
self.vdm_adas_status = None
self.acm_lka_hba_cmd: dict | None = None
self.sccm_wheel_touch: dict | None = None
self.vdm_adas_status: list[dict] | None = None
def update(self, can_parsers) -> tuple[structs.CarState, structs.CarStateSP]:
cp = can_parsers[Bus.pt]
@@ -73,16 +73,18 @@ class CarState(CarStateBase, CarStateExt):
# Gear
ret.gearShifter = GEAR_MAP.get(int(cp.vl["VDM_PropStatus"]["VDM_Prndl_Status"]), GearShifter.unknown)
# Doors
ret.doorOpen = any(cp_adas.vl["IndicatorLights"][door] != 2 for door in ("RearDriverDoor", "FrontPassengerDoor", "DriverDoor", "RearPassengerDoor"))
# Doors and seatbelt
# GEN2 has no CAN signal for these, but stock ACC already handles disengaging
# door locks prevent opening while driving
# on standstill, stock ACC disengages when a door is opened or seatbelt is unbuckled
if not (self.CP.flags & RivianFlags.GEN2):
ret.doorOpen = any(cp_adas.vl["IndicatorLights"][door] != 2 for door in ("RearDriverDoor", "FrontPassengerDoor", "DriverDoor", "RearPassengerDoor"))
ret.seatbeltUnlatched = cp.vl["RCM_Status"]["RCM_Status_IND_WARN_BELT_DRIVER"] != 0
# Blinkers
ret.leftBlinker = cp_adas.vl["IndicatorLights"]["TurnLightLeft"] in (1, 2)
ret.rightBlinker = cp_adas.vl["IndicatorLights"]["TurnLightRight"] in (1, 2)
# Seatbelt
ret.seatbeltUnlatched = cp.vl["RCM_Status"]["RCM_Status_IND_WARN_BELT_DRIVER"] != 0
# Blindspot
# ret.leftBlindspot = False
# ret.rightBlindspot = False
@@ -92,8 +94,11 @@ class CarState(CarStateBase, CarStateExt):
# Messages needed by carcontroller
self.acm_lka_hba_cmd = copy.copy(cp_cam.vl["ACM_lkaHbaCmd"])
self.sccm_wheel_touch = copy.copy(cp.vl["SCCM_WheelTouch"])
self.vdm_adas_status = copy.copy(cp.vl["VDM_AdasSts"])
if not (self.CP.flags & RivianFlags.GEN2):
self.sccm_wheel_touch = copy.copy(cp.vl["SCCM_WheelTouch"])
# This message can lag and send two messages at once, make sure we forward all of them
adas_status_msgs = cp.vl_all["VDM_AdasSts"]
self.vdm_adas_status = [dict(zip(adas_status_msgs, vals, strict=True)) for vals in zip(*adas_status_msgs.values(), strict=True)]
CarStateExt.update(self, ret, can_parsers)

View File

@@ -5,10 +5,10 @@ from opendbc.car.rivian.values import CAR
Ecu = CarParams.Ecu
FW_VERSIONS = {
CAR.RIVIAN_R1_GEN1: {
CAR.RIVIAN_R1: {
(Ecu.eps, 0x733, None): [
b'R1TS_v3.4.1(51),3.4.1\x00',
b'R1TS_v4.4.1(63),4.4.1\x00',
],
},
}
}

View File

@@ -3,7 +3,7 @@ from opendbc.car.interfaces import CarInterfaceBase
from opendbc.car.rivian.carcontroller import CarController
from opendbc.car.rivian.carstate import CarState
from opendbc.car.rivian.radar_interface import RadarInterface
from opendbc.car.rivian.values import RivianSafetyFlags
from opendbc.car.rivian.values import RivianFlags, RivianSafetyFlags
from opendbc.sunnypilot.car.rivian.values import RivianFlagsSP
@@ -18,6 +18,10 @@ class CarInterface(CarInterfaceBase):
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.rivian)]
# GEN2 (2025+) doesn't have SCCM_WheelTouch on the bus
if 0x321 not in fingerprint[0]:
ret.flags |= RivianFlags.GEN2.value
ret.steerActuatorDelay = 0.15
ret.steerLimitTimer = 0.4
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)

View File

@@ -19,5 +19,5 @@ class TestRivian:
vin = "".join(vin)
matches = FW_QUERY_CONFIG.match_fw_to_car_fuzzy({}, vin, FW_VERSIONS)
should_match = year != ModelYear.S_2025 and not bad
should_match = year in platform.config.years and not bad
assert (matches == {platform}) == should_match, "Bad match"

View File

@@ -22,6 +22,7 @@ class ModelYear(StrEnum):
P_2023 = "P"
R_2024 = "R"
S_2025 = "S"
T_2026 = "T"
@dataclass
@@ -40,17 +41,24 @@ class RivianPlatformConfig(PlatformConfig):
years: set[ModelYear] = field(default_factory=set)
class RivianFlags(IntFlag):
GEN2 = 1
class RivianSafetyFlags(IntFlag):
LONG_CONTROL = 1
class CAR(Platforms):
RIVIAN_R1_GEN1 = RivianPlatformConfig(
# TODO: verify this
RIVIAN_R1 = RivianPlatformConfig(
[
RivianCarDocs("Rivian R1S 2022-24"),
RivianCarDocs("Rivian R1T 2022-24"),
RivianCarDocs("Rivian R1S 2022-25"),
RivianCarDocs("Rivian R1T 2022-25"),
],
CarSpecs(mass=3206., wheelbase=3.08, steerRatio=15.2),
wmis={WMI.RIVIAN_TRUCK, WMI.RIVIAN_MPV},
lines={ModelLine.R1T, ModelLine.R1S},
years={ModelYear.N_2022, ModelYear.P_2023, ModelYear.R_2024},
years={ModelYear.N_2022, ModelYear.P_2023, ModelYear.R_2024, ModelYear.S_2025},
)
@@ -132,8 +140,4 @@ class CarControllerParams:
pass
class RivianSafetyFlags(IntFlag):
LONG_CONTROL = 1
DBC = CAR.create_dbc_map()

View File

@@ -21,6 +21,8 @@ FW_VERSIONS = {
b'TeMYG4_Main_0.0.0 (65),E4H015.01.0',
b'TeMYG4_Main_0.0.0 (67),E4H015.02.1',
b'TeMYG4_Main_0.0.0 (77),E4H015.04.5',
b'TeMYG4_Main_0.0.0 (77),E4HP015.04.5',
b'TeMYG4_Main_0.0.0 (78),E4HP015.05.0',
b'TeMYG4_SingleECU_0.0.0 (33),E4S014.27',
],
},
@@ -37,10 +39,11 @@ FW_VERSIONS = {
b'TeMYG4_Legacy3Y_0.0.0 (2),Y4P003.02.0',
b'TeMYG4_Legacy3Y_0.0.0 (5),Y4003.03.2',
b'TeMYG4_Legacy3Y_0.0.0 (5),Y4P003.03.2',
b'TeMYG4_SingleECU_0.0.0 (28),Y4S002.23.0',
b'TeMYG4_SingleECU_0.0.0 (33),Y4S002.26',
b'TeMYG4_Legacy3Y_0.0.0 (6),Y4003.04.0',
b'TeMYG4_Main_0.0.0 (77),Y4003.05.4',
b'TeMYG4_Main_0.0.0 (78),Y4003.06.0',
b'TeMYG4_SingleECU_0.0.0 (28),Y4S002.23.0',
b'TeMYG4_SingleECU_0.0.0 (33),Y4S002.26',
],
},
CAR.TESLA_MODEL_X: {

View File

@@ -81,9 +81,14 @@ FW_QUERY_CONFIG = FwQueryConfig(
# Cars with this EPS FW have FSD 14 and use TeslaFlags.FSD_14
FSD_14_FW = {
CAR.TESLA_MODEL_3: [
b'TeMYG4_Main_0.0.0 (77),E4HP015.04.5',
b'TeMYG4_Main_0.0.0 (78),E4HP015.05.0',
],
CAR.TESLA_MODEL_Y: [
b'TeMYG4_Legacy3Y_0.0.0 (6),Y4003.04.0',
b'TeMYG4_Main_0.0.0 (77),Y4003.05.4',
b'TeMYG4_Main_0.0.0 (78),Y4003.06.0',
]
}

View File

@@ -66,6 +66,7 @@ class CarTestRoute(NamedTuple):
routes = [
CarTestRoute("efdf9af95e71cd84/2022-05-13--19-03-31", COMMA.COMMA_BODY),
CarTestRoute("c5e3aa51055c8f47|2023-12-06--20-01-44", CHRYSLER.JEEP_CHEROKEE_5TH_GEN),
CarTestRoute("0c94aa1e1296d7c6/2021-05-05--19-48-37", CHRYSLER.JEEP_GRAND_CHEROKEE),
CarTestRoute("91dfedae61d7bd75/2021-05-22--20-07-52", CHRYSLER.JEEP_GRAND_CHEROKEE_2019),
CarTestRoute("420a8e183f1aed48/2020-03-05--07-15-29", CHRYSLER.CHRYSLER_PACIFICA_2018_HYBRID), # 2017
@@ -113,6 +114,7 @@ routes = [
CarTestRoute("68aac44ad69f838e/2021-05-18--20-40-52", HONDA.HONDA_CRV),
CarTestRoute("14fed2e5fa0aa1a5/2021-05-25--14-59-42", HONDA.HONDA_CRV_HYBRID),
CarTestRoute("52f3e9ae60c0d886/2021-05-23--15-59-43", HONDA.HONDA_FIT),
CarTestRoute("7a27edd824e984f1/0000000a--4fb8a92b44", HONDA.HONDA_FIT), # manual transmission
CarTestRoute("2c4292a5cd10536c/2021-08-19--21-32-15", HONDA.HONDA_FREED),
CarTestRoute("03be5f2fd5c508d1/2020-04-19--18-44-15", HONDA.HONDA_HRV),
CarTestRoute("320098ff6c5e4730/2023-04-13--17-47-46", HONDA.HONDA_HRV_3G),
@@ -126,7 +128,8 @@ routes = [
CarTestRoute("f29e2b57a55e7ad5/2021-03-24--20-52-38", HONDA.HONDA_ACCORD), # hybrid, 2021 with new style HUD msgs
CarTestRoute("1ad763dd22ef1a0e/2020-02-29--18-37-03", HONDA.HONDA_CRV_5G),
CarTestRoute("0a96f86fcfe35964/2020-02-05--07-25-51", HONDA.HONDA_ODYSSEY),
CarTestRoute("7817fe954aff07b8/00000001--fdaaf36c4f", HONDA.HONDA_ODYSSEY_TWN),
CarTestRoute("7817fe954aff07b8/00000001--fdaaf36c4f", HONDA.HONDA_ODYSSEY_TWN), # Taiwan
CarTestRoute("5bd1fcb9a66f60e1/000001d6--f1bff3e876", HONDA.HONDA_ODYSSEY_TWN), # Singapore
CarTestRoute("d7233a428eb7d0b5/00000001--9b99b04d43", HONDA.HONDA_ODYSSEY_5G_MMR),
CarTestRoute("d83f36766f8012a5/2020-02-05--18-42-21", HONDA.HONDA_CIVIC_BOSCH_DIESEL),
CarTestRoute("f0890d16a07a236b/2021-05-25--17-27-22", HONDA.HONDA_INSIGHT),
@@ -134,8 +137,10 @@ routes = [
CarTestRoute("684e8f96bd491a0e/2021-11-03--11-08-42", HONDA.HONDA_PILOT), # Passport
CarTestRoute("0a78dfbacc8504ef/2020-03-04--13-29-55", HONDA.HONDA_CIVIC_BOSCH),
CarTestRoute("f34a60d68d83b1e5/2020-10-06--14-35-55", HONDA.ACURA_RDX),
CarTestRoute("23412c73dbeccd3a/00000000--be4606224f", HONDA.ACURA_RDX_3G_MMR),
CarTestRoute("54fd8451b3974762/2021-04-01--14-50-10", HONDA.HONDA_RIDGELINE),
CarTestRoute("2d5808fae0b38ac6/2021-09-01--17-14-11", HONDA.HONDA_E),
CarTestRoute("16a94dfbfdf5a51f/00000007--5ac9e58f1b", HONDA.HONDA_E_ADVANCE),
CarTestRoute("f44aa96ace22f34a/2021-12-22--06-22-31", HONDA.HONDA_CIVIC_2022),
CarTestRoute("1f032f5173c8ad99/00000006--573b3fcaf5", HONDA.HONDA_CIVIC_2022), # Civic Type R with manual transmission
CarTestRoute("b1c832ad56b6bc9d/00000010--debfcf5867", HONDA.HONDA_CIVIC_2022), # 2025 Civic Hatch Hybrid with new eCVT transmission
@@ -147,6 +152,7 @@ routes = [
CarTestRoute("414af83891dbf72c/00000006--51fa6d99cd", HONDA.HONDA_NBOX_2G),
CarTestRoute("ad9840558640c31d/0000001a--d6cd4871c2", HONDA.ACURA_MDX_4G_MMR), # 2025 MDX
CarTestRoute("ad9840558640c31d/000001f2--026c4f6275", HONDA.ACURA_TLX_2G_MMR),
CarTestRoute("619b464263ab23f2/00000025--ece505fdfc", HONDA.ACURA_MDX_4G),
CarTestRoute("87d7f06ade479c2e/2023-09-11--23-30-11", HYUNDAI.HYUNDAI_AZERA_6TH_GEN),
CarTestRoute("66189dd8ec7b50e6/2023-09-20--07-02-12", HYUNDAI.HYUNDAI_AZERA_HEV_6TH_GEN),
@@ -312,6 +318,7 @@ routes = [
CarTestRoute("07667b885add75fd/2021-01-23--19-48-42", VOLKSWAGEN.AUDI_A3_MK3),
CarTestRoute("6c6b466346192818/2021-06-06--14-17-47", VOLKSWAGEN.AUDI_Q2_MK1),
CarTestRoute("0cd0b7f7e31a3853/2021-12-03--03-12-05", VOLKSWAGEN.AUDI_Q3_MK2),
CarTestRoute("5432d2499e17e646/00000001--a99353214f", VOLKSWAGEN.AUDI_Q5_MK1),
CarTestRoute("8f205bdd11bcbb65/2021-03-26--01-00-17", VOLKSWAGEN.SEAT_ATECA_MK1),
CarTestRoute("fc6b6c9a3471c846/2021-05-27--13-39-56", VOLKSWAGEN.SEAT_ATECA_MK1), # Leon
CarTestRoute("0bbe367c98fa1538/2023-03-04--17-46-11", VOLKSWAGEN.SKODA_FABIA_MK4),
@@ -355,7 +362,8 @@ routes = [
CarTestRoute("6a7075a4fdd765ee/0000004e--1f612006dd", PSA.PSA_PEUGEOT_208),
CarTestRoute("bc095dc92e101734/000000db--ee9fe46e57", RIVIAN.RIVIAN_R1_GEN1),
CarTestRoute("bc095dc92e101734/000000db--ee9fe46e57", RIVIAN.RIVIAN_R1),
CarTestRoute("c70d59e4150956fc/0000006e--48bfbfda01", RIVIAN.RIVIAN_R1), # GEN2
CarTestRoute("7dc058789994da80/00000112--adb970f6a8", TESLA.TESLA_MODEL_3),
CarTestRoute("c8a98e58647765ad/00000002--84e4746136", TESLA.TESLA_MODEL_Y),

View File

@@ -218,7 +218,7 @@ class TestFwFingerprintTiming(unittest.TestCase):
self.total_time += timeout
return {}
def _benchmark_brand(self, brand, num_pandas):
def _benchmark_brand(self, brand):
self.total_time = 0
with patch("opendbc.car.isotp_parallel_query.IsoTpParallelQuery.get_data", self.fake_get_data):
for _ in range(self.N):
@@ -226,7 +226,7 @@ class TestFwFingerprintTiming(unittest.TestCase):
self.current_obd_multiplexing = True
t = time.perf_counter()
get_fw_versions(self.fake_can_recv, self.fake_can_send, self.fake_set_obd_multiplexing, brand, num_pandas=num_pandas)
get_fw_versions(self.fake_can_recv, self.fake_can_send, self.fake_set_obd_multiplexing, brand)
self.total_time += time.perf_counter() - t
return self.total_time / self.N
@@ -248,7 +248,7 @@ class TestFwFingerprintTiming(unittest.TestCase):
with patch("opendbc.car.fw_versions.get_ecu_addrs", fake_get_ecu_addrs):
for _ in range(self.N):
self.current_obd_multiplexing = True
get_present_ecus(self.fake_can_recv, self.fake_can_send, self.fake_set_obd_multiplexing, num_pandas=2)
get_present_ecus(self.fake_can_recv, self.fake_can_send, self.fake_set_obd_multiplexing)
self._assert_timing(self.total_time / self.N, present_ecu_ref_time)
print(f'get_present_ecus, query time={self.total_time / self.N} seconds')
@@ -262,51 +262,39 @@ class TestFwFingerprintTiming(unittest.TestCase):
print(f'get_vin {name} case, query time={self.total_time / self.N} seconds')
def test_fw_query_timing(self):
total_ref_time = {1: 7.4, 2: 8.0}
total_ref_time = 7.4
brand_ref_times = {
1: {
'gm': 1.0,
'body': 0.1,
'chrysler': 0.3,
'ford': 1.5,
'honda': 0.45,
'hyundai': 0.65,
'mazda': 0.1,
'nissan': 0.8,
'subaru': 0.65,
'tesla': 0.1,
'toyota': 0.7,
'volkswagen': 0.65,
'rivian': 0.3,
'psa': 0.1,
},
2: {
'ford': 1.6,
'hyundai': 1.15,
}
'gm': 1.0,
'body': 0.1,
'chrysler': 0.3,
'ford': 1.5,
'honda': 0.45,
'hyundai': 0.65,
'mazda': 0.1,
'nissan': 0.8,
'subaru': 0.65,
'tesla': 0.1,
'toyota': 0.7,
'volkswagen': 0.65,
'rivian': 0.3,
'psa': 0.1,
}
total_times = {1: 0.0, 2: 0.0}
for num_pandas in (1, 2):
for brand, config in FW_QUERY_CONFIGS.items():
with self.subTest(brand=brand, num_pandas=num_pandas):
avg_time = self._benchmark_brand(brand, num_pandas)
total_times[num_pandas] += avg_time
avg_time = round(avg_time, 2)
total_times = 0.0
for brand, config in FW_QUERY_CONFIGS.items():
with self.subTest(brand=brand):
avg_time = self._benchmark_brand(brand)
total_times += avg_time
avg_time = round(avg_time, 2)
ref_time = brand_ref_times[num_pandas].get(brand)
if ref_time is None:
# ref time should be same as 1 panda if no aux queries
ref_time = brand_ref_times[num_pandas - 1][brand]
ref_time = brand_ref_times[brand]
self._assert_timing(avg_time, ref_time)
print(f'{brand=}, {len(config.requests)=}, avg FW query time={avg_time} seconds')
self._assert_timing(avg_time, ref_time)
print(f'{brand=}, {num_pandas=}, {len(config.requests)=}, avg FW query time={avg_time} seconds')
for num_pandas in (1, 2):
with self.subTest(brand='all_brands', num_pandas=num_pandas):
total_time = round(total_times[num_pandas], 2)
self._assert_timing(total_time, total_ref_time[num_pandas])
print(f'all brands, total FW query time={total_time} seconds')
with self.subTest(brand='all_brands'):
total_time = round(total_times, 2)
self._assert_timing(total_time, total_ref_time)
print(f'all brands, total FW query time={total_time} seconds')
def test_get_fw_versions(self):
# some coverage on IsoTpParallelQuery and panda UDS library

View File

@@ -80,7 +80,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"GENESIS_GV70_ELECTRIFIED_1ST_GEN" = [1.9, 1.9, 0.09]
"GENESIS_G80_2ND_GEN_FL" = [2.5819356441497803, 2.5, 0.11244568973779678]
# Note that some Rivians achieve significantly less lateral acceleration than this
"RIVIAN_R1_GEN1" = [2.8, 2.5, 0.07]
"RIVIAN_R1" = [2.8, 2.5, 0.07]
"HYUNDAI_NEXO_1ST_GEN" = [2.5, 2.5, 0.1]
"HONDA_ACCORD_11G" = [1.35, 1.35, 0.17]
"HONDA_PILOT_4G" = [1.25, 1.25, 0.21]
@@ -93,10 +93,14 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"ACURA_TLX_2G" = [1.2, 1.2, 0.15]
"ACURA_TLX_2G_MMR" = [1.7, 1.7, 0.16]
"PORSCHE_MACAN_MK1" = [2.0, 2.0, 0.2]
"AUDI_Q5_MK1" = [1.8, 1.8, 0.18]
"LEXUS_LS" = [1.35, 1.7, 0.17]
"TOYOTA_RAV4_PRIME" = [1.7, 2.0, 0.14]
"TOYOTA_RAV4_TSS2_2022" = [1.9, 1.9304407208090029, 0.112174]
"KIA_K7_2017" = [2.2, 2.2, 0.1]
"JEEP_CHEROKEE_5TH_GEN" = [1.5, 1.5, 0.15]
"ACURA_MDX_4G" = [1.4, 1.4, 0.17]
"ACURA_RDX_3G_MMR" = [1.5, 1.5, 0.16]
# Dashcam or fallback configured as ideal car
"MOCK" = [10.0, 10, 0.0]

View File

@@ -50,6 +50,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"HONDA_CRV_EU" = "HONDA_CRV"
"HONDA_CIVIC_BOSCH_DIESEL" = "HONDA_CIVIC_BOSCH"
"HONDA_E" = "HONDA_CIVIC_BOSCH"
"HONDA_E_ADVANCE" = "HONDA_CIVIC_BOSCH"
"HONDA_ODYSSEY_TWN" = "HONDA_ODYSSEY"
"BUICK_LACROSSE" = "CHEVROLET_VOLT"

View File

@@ -1354,6 +1354,7 @@ FW_VERSIONS = {
b'\x018966333T5100\x00\x00\x00\x00',
b'\x018966333X6000\x00\x00\x00\x00',
b'\x01896633T07000\x00\x00\x00\x00',
b'\x01896633T24000\x00\x00\x00\x00',
b'\x01896633T38000\x00\x00\x00\x00',
b'\x01896633T58000\x00\x00\x00\x00',
b'\x01896633T63000\x00\x00\x00\x00',
@@ -1371,6 +1372,7 @@ FW_VERSIONS = {
b'\x01F152606461\x00\x00\x00\x00\x00\x00',
b'\x01F15260646200\x00\x00\x00\x00',
b'\x01F152633A71\x00\x00\x00\x00\x00\x00',
b'\x01F152633E2100\x00\x00\x00\x00',
b'F152633423\x00\x00\x00\x00\x00\x00',
b'F152633680\x00\x00\x00\x00\x00\x00',
b'F152633681\x00\x00\x00\x00\x00\x00',
@@ -1405,6 +1407,7 @@ FW_VERSIONS = {
b'\x028646F3309100\x00\x00\x00\x008646G3304000\x00\x00\x00\x00',
b'\x028646F3309100\x00\x00\x00\x008646G5301200\x00\x00\x00\x00',
b'\x028646F3309400\x00\x00\x00\x008646G3304000\x00\x00\x00\x00',
b'\x028646F3313000\x00\x00\x00\x008646G3304000\x00\x00\x00\x00',
],
},
CAR.LEXUS_ES: {

View File

@@ -111,7 +111,7 @@ class VehicleModel:
u: Speed [m/s]
Returns:
Roll compensation curvature [rad]
Roll compensation curvature [1/m]
"""
sf = calc_slip_factor(self)

View File

@@ -46,11 +46,12 @@ class CarState(CarStateBase):
pt_cp = can_parsers[Bus.pt]
cam_cp = can_parsers[Bus.cam]
ext_cp = pt_cp if self.CP.networkLocation == NetworkLocation.fwdCamera else cam_cp
alt_cp = can_parsers[Bus.alt]
if self.CP.flags & VolkswagenFlags.PQ:
return self.update_pq(pt_cp, cam_cp, ext_cp)
elif self.CP.flags & VolkswagenFlags.MLB:
return self.update_mlb(pt_cp, cam_cp, ext_cp)
return self.update_mlb(pt_cp, cam_cp, ext_cp, alt_cp)
ret = structs.CarState()
ret_sp = structs.CarStateSP()
@@ -232,7 +233,7 @@ class CarState(CarStateBase):
self.frame += 1
return ret, ret_sp
def update_mlb(self, pt_cp, cam_cp, ext_cp) -> structs.CarState:
def update_mlb(self, pt_cp, cam_cp, ext_cp, alt_cp) -> structs.CarState:
ret = structs.CarState()
ret_sp = structs.CarStateSP()
@@ -244,14 +245,14 @@ class CarState(CarStateBase):
)
ret.gasPressed = pt_cp.vl["Motor_03"]["MO_Fahrpedalrohwert_01"] > 0
ret.gearShifter = self.parse_gear_shifter(self.CCP.shifter_values.get(pt_cp.vl["Getriebe_03"]["GE_Waehlhebel"], None))
ret.gearShifter = self.parse_gear_shifter(self.CCP.shifter_values.get(alt_cp.vl["Getriebe_03"]["GE_Waehlhebel"], None))
# ACC okay but disabled (1), ACC ready (2), a radar visibility or other fault/disruption (6 or 7)
# currently regulating speed (3), driver accel override (4), brake only (5)
# TODO: get this from the drivetrain side instead, for openpilot long support later
ret.cruiseState.available = ext_cp.vl["ACC_05"]["ACC_Status_ACC"] in (2, 3, 4, 5)
ret.cruiseState.enabled = ext_cp.vl["ACC_05"]["ACC_Status_ACC"] in (3, 4, 5)
ret.accFaulted = ext_cp.vl["ACC_05"]["ACC_Status_ACC"] in (6, 7)
# TODO: We don't have a true mainswitch state yet, might need stateful tracking on LS_01 if momentary-press is a thing
# TSK_04.TSK_Status_GRA_ACC_02 0 = not engaged, 1 = engaged, 2 = engaged with driver accel override, 3 = fault
ret.cruiseState.available = alt_cp.vl["TSK_04"]["TSK_Status_GRA_ACC_02"] in (0, 1, 2)
ret.cruiseState.available = alt_cp.vl["TSK_04"]["TSK_Status_GRA_ACC_02"] in (1, 2)
ret.accFaulted = alt_cp.vl["TSK_04"]["TSK_Status_GRA_ACC_02"] == 3
ret.cruiseState.speed = ext_cp.vl["ACC_02"]["ACC_Wunschgeschw_02"] * CV.KPH_TO_MS
self.parse_mlb_mqb_steering_state(ret, pt_cp)
@@ -262,14 +263,14 @@ class CarState(CarStateBase):
ret.parkingBrake = bool(pt_cp.vl["Kombi_01"]["KBI_Handbremse"])
ret.espDisabled = pt_cp.vl["ESP_01"]["ESP_Tastung_passiv"] != 0
ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_stalk(300, pt_cp.vl["Gateway_11"]["BH_Blinker_li"],
pt_cp.vl["Gateway_11"]["BH_Blinker_re"])
ret.leftBlinker = bool(pt_cp.vl["BCM"]["BLINKER_LEFT"])
ret.rightBlinker = bool(pt_cp.vl["BCM"]["BLINKER_RIGHT"])
ret.seatbeltUnlatched = pt_cp.vl["Gateway_06"]["AB_Gurtschloss_FA"] != 3
ret.doorOpen = any([pt_cp.vl["Gateway_05"]["FT_Tuer_geoeffnet"],
pt_cp.vl["Gateway_05"]["BT_Tuer_geoeffnet"],
pt_cp.vl["Gateway_05"]["HL_Tuer_geoeffnet"],
pt_cp.vl["Gateway_05"]["HR_Tuer_geoeffnet"]])
ret.seatbeltUnlatched = bool(pt_cp.vl["Airbag_01"]["AB_Gurtwarn_VF"])
ret.doorOpen = any([alt_cp.vl["Gateway_05"]["FT_Tuer_geoeffnet"],
alt_cp.vl["Gateway_05"]["BT_Tuer_geoeffnet"],
alt_cp.vl["Gateway_05"]["HL_Tuer_geoeffnet"],
alt_cp.vl["Gateway_05"]["HR_Tuer_geoeffnet"]])
# Consume blind-spot monitoring info/warning LED states, if available.
# Infostufe: BSM LED on, Warnung: BSM LED flashing
@@ -320,7 +321,7 @@ class CarState(CarStateBase):
return CarState.get_can_parsers_pq(CP)
# manually configure some optional and variable-rate/edge-triggered messages
pt_messages, cam_messages = [], []
pt_messages, cam_messages, alt_messages = [], [], []
if not CP.flags & VolkswagenFlags.MLB:
pt_messages += [
@@ -334,6 +335,7 @@ class CarState(CarStateBase):
return {
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], pt_messages, CanBus(CP).pt),
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], cam_messages, CanBus(CP).cam),
Bus.alt: CANParser(DBC[CP.carFingerprint][Bus.pt], alt_messages, CanBus(CP).alt),
}
@staticmethod
@@ -341,4 +343,5 @@ class CarState(CarStateBase):
return {
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).pt),
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).cam),
Bus.alt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).alt),
}

View File

@@ -972,6 +972,26 @@ FW_VERSIONS = {
b'\xf1\x872Q0907572T \xf1\x890383',
],
},
CAR.AUDI_Q5_MK1: {
(Ecu.engine, 0x7e0, None): [
b'\xf1\x878R0907115N \xf1\x890006',
b'\xf1\x878R0907551F \xf1\x890007',
],
(Ecu.transmission, 0x7e1, None): [
b'\xf1\x878R0927158D \xf1\x891010',
b'\xf1\x878R0927158AM\xf1\x891003',
],
(Ecu.srs, 0x715, None): [
b'\xf1\x878R0959655F \xf1\x890610\xf1\x82\x050304010402',
],
(Ecu.eps, 0x712, None): [
b'\xf1\x878R0909144R \xf1\x890511\xf1\x82\x01\n\x1a',
b'\xf1\x878R0909144F \xf1\x890507\xf1\x82\x01\t\xe6',
],
(Ecu.fwdRadar, 0x757, None): [
b'\xf1\x878R0907561A\x00\xf1\x890410\xf1\x80100',
],
},
CAR.PORSCHE_MACAN_MK1: {
(Ecu.engine, 0x7e0, None): [
b'\xf1\x8795B906259BJ\xf1\x890001',

View File

@@ -225,6 +225,10 @@ class VolkswagenCarSpecs(CarSpecs):
class Footnote(Enum):
SETUP = CarFootnote(
"The J533 harness plugs in at the CAN gateway under the dashboard, just above the steering column. " +
"More information can be found at <a href=\"https://docs.howtocomma.com/docs/j533-harness-install\" target=\"_blank\">this guide</a>.",
Column.MAKE, setup_note=True)
KAMIQ = CarFootnote(
"Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform.",
Column.MODEL)
@@ -249,6 +253,7 @@ class Footnote(Enum):
class VWCarDocs(CarDocs):
package: str = "Adaptive Cruise Control (ACC) & Lane Assist"
car_parts: CarParts = field(default_factory=CarParts.common([CarHarness.vw_j533]))
footnotes: list[Enum] = field(default_factory=lambda: [Footnote.SETUP])
def init_make(self, CP: structs.CarParams):
self.footnotes.append(Footnote.VW_EXP_LONG)
@@ -440,6 +445,12 @@ class CAR(Platforms):
chassis_codes={"8U", "F3", "FS"},
wmis={WMI.AUDI_EUROPE_MPV, WMI.AUDI_GERMANY_CAR, WMI.VOLKSWAGEN_CHINA_FAW},
)
AUDI_Q5_MK1 = VolkswagenMLBPlatformConfig(
[VWCarDocs("Audi Q5 2013-17")],
VolkswagenCarSpecs(mass=1895, wheelbase=2.81),
chassis_codes={"8R"},
wmis={WMI.AUDI_EUROPE_MPV, WMI.AUDI_GERMANY_CAR},
)
PORSCHE_MACAN_MK1 = VolkswagenMLBPlatformConfig(
[VWCarDocs("Porsche Macan 2017-24")],
VolkswagenCarSpecs(mass=1895, wheelbase=2.81, steerRatio=16.2),

View File

@@ -86,16 +86,16 @@ ERROR_CODES = {
class CONNECT_MODE(IntEnum):
NORMAL = 0x00,
USER_DEFINED = 0x01,
NORMAL = 0x00
USER_DEFINED = 0x01
class GET_ID_REQUEST_TYPE(IntEnum):
ASCII = 0x00,
ASAM_MC2_FILE = 0x01,
ASAM_MC2_PATH = 0x02,
ASAM_MC2_URL = 0x03,
ASAM_MC2_UPLOAD = 0x04,
ASCII = 0x00
ASAM_MC2_FILE = 0x01
ASAM_MC2_PATH = 0x02
ASAM_MC2_URL = 0x03
ASAM_MC2_UPLOAD = 0x04
# 128-255 user defined

View File

@@ -108,8 +108,9 @@ BO_ 1498 LKAS_1: 2 XXX
BO_ 1500 DAS_6: 4 XXX
SG_ LKAS_ICON_COLOR : 1|2@0+ (1,0) [0|1] "" XXX
SG_ SET_ME_0XAC : 15|8@0+ (1,0) [0|255] "" XXX
SG_ CAR_MODEL : 15|8@0+ (1,0) [0|255] "" XXX
SG_ LKAS_LANE_LINES : 19|4@0+ (1,0) [0|15] "" XXX
SG_ LKAS_ALERTS : 27|4@0+ (1,0) [0|1] "" XXX
BO_ 1508 LKAS_HEARTBIT: 8 XXX
SG_ LKAS_STATUS_OK : 28|1@0+ (1,0) [0|1] "" XXX
@@ -127,11 +128,17 @@ BO_ 762 CRUISE_BUTTONS: 3 XXX
SG_ CHECKSUM : 23|8@0+ (1,0) [0|1] "" XXX
BO_ 484 BRAKE_1: 8 XXX
SG_ BRAKE_PSI : 7|12@0+ (1,0) [0|1] "" XXX
SG_ DRIVER_BRAKE_PRESSURE : 7|12@0+ (1,0) [0|1] "" XXX
SG_ VEHICLE_SPEED : 35|12@0+ (0.0174,0) [0|4095] "m/s" XXX
SG_ COUNTER : 51|4@0+ (1,0) [0|1] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|1] "" XXX
BO_ 488 BRAKE_3: 5 XXX
SG_ DRIVER_BRAKE_UNKNOWN : 17|1@0+ (1,0) [0|1] "" XXX
SG_ DRIVER_BRAKE_SWITCH : 18|1@0+ (1,0) [0|1] "" XXX
SG_ COUNTER : 27|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 39|8@0+ (1,0) [0|255] "" XXX
BO_ 500 GEARBOX_1: 7 XXX
SG_ DESIRED_GEAR : 35|4@0+ (1,0) [0|1] "" XXX
SG_ ACTUAL_GEAR : 39|4@0+ (1,0) [0|1] "" XXX
@@ -172,6 +179,12 @@ BO_ 496 CLUSTER_1: 8 XXX
SG_ COUNTER : 51|4@0+ (1,0) [0|1] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|1] "" XXX
BO_ 103596083 BSM_LEFT: 8 XXX
SG_ LEFT_DETECTED : 21|1@0+ (1,0) [0|1] "" XXX
BO_ 103596084 BSM_RIGHT: 7 XXX
SG_ RIGHT_DETECTED : 21|1@0+ (1,0) [0|1] "" XXX
CM_ SG_ 1250 TRUNK "1 = open, 0 = closed";
CM_ SG_ 1250 DOOR_OPEN_FL "1 = open, 0 = closed";

View File

@@ -212,7 +212,7 @@ CM_ SG_ 577 LINE_DASHED "1 = line is dashed";
CM_ SG_ 577 LINE_SOLID "1 = line is solid";
VAL_ 228 CONTROL_STATE 0 "init" 1 "standby" 2 "lka_active" 3 "driver_override" 5 "rdm_active";
VAL_ 399 STEER_STATUS 6 "tmp_fault" 5 "fault_1" 4 "no_torque_alert_2" 3 "low_speed_lockout" 2 "no_torque_alert_1" 0 "normal";
VAL_ 399 STEER_STATUS 6 "tmp_fault" 5 "fault_1" 4 "no_torque_alert_2" 3 "low_speed_lockout" 2 "no_torque_alert_1" 1 "tja_low_speed_lockout" 0 "normal";
VAL_ 662 CRUISE_BUTTONS 7 "tbd" 6 "tbd" 5 "tbd" 4 "accel_res" 3 "decel_set" 2 "cancel" 1 "main" 0 "none" ;
VAL_ 662 CRUISE_SETTING 3 "distance_adj" 2 "tbd" 1 "lkas_button" 0 "none" ;
VAL_ 806 CMBS_STATES 3 "pressed" 0 "released" ;

View File

@@ -1,17 +1,20 @@
BO_ 479 ACC_CONTROL: 8 EON
SG_ SET_TO_0 : 20|5@0+ (1,0) [0|1] "" XXX
SG_ CONTROL_ON : 23|3@0+ (1,0) [0|5] "" XXX
SG_ GAS_COMMAND : 7|16@0- (1,0) [0|0] "" XXX
SG_ ACC_ENABLED : 16|1@0+ (1,0) [0|1] "" XXX
SG_ ACC_FAULTED : 20|1@0+ (1,0) [0|1] "" XXX
SG_ CONTROL_ON : 23|3@0+ (1,0) [0|5] "" XXX
SG_ ACCEL_COMMAND : 31|11@0- (0.01,0) [0|0] "m/s2" XXX
SG_ BRAKE_LIGHTS : 62|1@0+ (1,0) [0|1] "" XXX
SG_ AEB_STATUS : 33|1@0+ (1,0) [0|1] "" XXX
SG_ BRAKE_REQUEST : 34|1@0+ (1,0) [0|1] "" XXX
SG_ STANDSTILL : 35|1@0+ (1,0) [0|1] "" XXX
SG_ STANDSTILL_RELEASE : 36|1@0+ (1,0) [0|1] "" XXX
SG_ AEB_STATUS : 33|1@0+ (1,0) [0|1] "" XXX
SG_ AEB_BRAKING : 47|1@0+ (1,0) [0|1] "" XXX
SG_ MAYBE_DISENGAGE_COMMAND : 41|2@0+ (1,0) [0|3] "" XXX
SG_ AEB_PREPARE : 43|1@0+ (1,0) [0|1] "" XXX
SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" XXX
SG_ AEB_BRAKING : 47|1@0+ (1,0) [0|1] "" XXX
SG_ MAYBE_DISENGAGE_ALERT : 54|1@0+ (1,0) [0|1] "" XXX
SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" XXX
SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" XXX
SG_ BRAKE_LIGHTS : 62|1@0+ (1,0) [0|1] "" XXX
BO_ 495 ACC_CONTROL_ON: 8 XXX
SG_ SET_TO_75 : 31|8@0+ (1,0) [0|255] "" XXX
@@ -28,3 +31,5 @@ CM_ SG_ 479 CONTROL_ON "Set to 5 when car is being controlled";
CM_ SG_ 479 AEB_STATUS "set for the duration of AEB event";
CM_ SG_ 479 AEB_BRAKING "set when braking is commanded during AEB event";
CM_ SG_ 479 AEB_PREPARE "set 1s before AEB";
CM_ SG_ 479 MAYBE_DISENGAGE_COMMAND "Might signal the powertrain to disengage or prevent engagement on radar-side ACC faults";
CM_ SG_ 479 MAYBE_DISENGAGE_ALERT "Signals the instrument cluster to display an ACC fault";

View File

@@ -59,6 +59,7 @@ BO_ 420 VSA_STATUS: 8 VSA
SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON
BO_ 427 STEER_MOTOR_TORQUE: 3 EPS
SG_ UNKNOWN_TORQUE_STATE_BIT : 3|1@0+ (1,0) [0|1] "" XXX
SG_ CONFIG_VALID : 7|1@0+ (1,0) [0|1] "" EON
SG_ MOTOR_TORQUE : 1|10@0+ (1,0) [0|256] "" EON
SG_ OUTPUT_DISABLED : 22|1@0+ (1,0) [0|1] "" EON
@@ -206,6 +207,7 @@ BO_ 1302 ODOMETER: 8 XXX
CM_ SG_ 304 "Seems to be platform-agnostic";
CM_ SG_ 316 "Should exist on Nidec";
CM_ SG_ 420 BRAKE_HOLD_RELATED "On when Brake Hold engaged";
CM_ SG_ 427 UNKNOWN_TORQUE_STATE_BIT "Might signal driver input above threshold, for driver inactivity detection";
CM_ SG_ 490 LONG_ACCEL "wheel speed derivative, noisy and zero snapping";
CM_ SG_ 773 PASS_AIRBAG_ON "Might just be indicator light";
CM_ SG_ 773 PASS_AIRBAG_OFF "Might just be indicator light";

View File

@@ -9,6 +9,7 @@ BO_ 422 SCM_BUTTONS: 8 SCM
SG_ CRUISE_BUTTONS : 7|3@0+ (1,0) [0|7] "" EON
SG_ LIGHTS_SETTING : 1|2@0+ (1,0) [0|3] "" EON
SG_ PARKING_BRAKE_ON : 2|1@0+ (1,0) [0|1] "" EON
SG_ REVERSE_LIGHT : 18|1@0+ (1,0) [0|1] "" XXX
SG_ MAIN_ON : 47|1@0+ (1,0) [0|1] "" EON
SG_ CRUISE_SETTING : 43|2@0+ (1,0) [0|3] "" EON
SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON

View File

@@ -40,7 +40,7 @@ BO_ 254913108 LKAS_HUD_2: 8 ADAS
SG_ LKAS_BOH_1 : 15|6@0+ (1,0) [0|63] "" XXX
SG_ LEFT_LANE : 23|2@0+ (1,0) [0|3] "" XXX
SG_ RIGHT_LANE : 21|2@0+ (1,0) [0|3] "" XXX
SG_ LKAS_BOH_2 : 30|5@0+ (1,0) [0|31] "" XXX
SG_ LKAS_BOH_2 : 31|6@0+ (1,0) [0|63] "" XXX
SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" XXX
SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" XXX

View File

@@ -0,0 +1,7 @@
CM_ "IMPORT _honda_common.dbc";
CM_ "IMPORT _bosch_2018.dbc";
CM_ "IMPORT _bosch_radar_acc.dbc";
CM_ "IMPORT _lkas_hud_8byte.dbc";
CM_ "IMPORT _bosch_standstill.dbc";
CM_ "IMPORT _steering_sensors_b.dbc";
CM_ "IMPORT _gearbox_common.dbc";

View File

@@ -39,19 +39,21 @@ BU_: XXX CAMERA FRONT_RADAR ADRV APRK
BO_ 80 LKAS: 16 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ LKA_MODE : 24|3@1+ (1,0) [0|7] "" XXX
SG_ LKA_AVAILABLE : 27|2@1+ (1,0) [0|255] "" XXX
SG_ LKA_WARNING : 32|1@1+ (1,0) [0|1] "" XXX
SG_ LKA_ICON : 38|2@1+ (1,0) [0|255] "" XXX
SG_ FCA_SYSWARN : 40|1@0+ (1,0) [0|1] "" XXX
SG_ TORQUE_REQUEST : 41|11@1+ (1,-1024) [0|4095] "" XXX
SG_ STEER_REQ : 52|1@1+ (1,0) [0|1] "" XXX
SG_ LKA_OptUsmSta : 24|3@1+ (1,0) [0|7] "" ADAS_DRV
SG_ LKA_RcgSta : 27|3@1+ (1,0) [0|7] "" ADAS_DRV
SG_ LKA_LHLnWrnSta : 30|2@1+ (1,0) [0|3] "" ADAS_DRV
SG_ LKA_RHLnWrnSta : 32|2@1+ (1,0) [0|3] "" ADAS_DRV
SG_ LKA_HndsoffSnd : 34|2@1+ (1,0) [0|3] "" ADAS_DRV
SG_ LKA_StrSnd : 36|2@1+ (1,0) [0|3] "" ADAS_DRV
SG_ LKA_SysIndReq : 38|3@1+ (1,0) [0|7] "" ADAS_DRV
SG_ StrTqReqVal : 41|11@1+ (1,-1024) [0|4095] "" XXX
SG_ ActToiSta : 52|2@1+ (1,0) [0|3] "" ADAS_DRV
SG_ ToiFltSta : 54|2@1+ (1,0) [0|3] "" ADAS_DRV
SG_ LFA_BUTTON : 56|1@1+ (1,0) [0|255] "" XXX
SG_ LKA_ASSIST : 62|1@1+ (1,0) [0|1] "" XXX
SG_ STEER_MODE : 65|3@1+ (1,0) [0|1] "" XXX
SG_ NEW_SIGNAL_2 : 70|2@0+ (1,0) [0|3] "" XXX
SG_ HAS_LANE_SAFETY : 80|1@0+ (1,0) [0|1] "" XXX
SG_ DAMP_FACTOR : 64|8@1+ (1,0) [0|255] "" XXX
SG_ LKA_SysWrn : 60|4@1+ (1,0) [0|15] "" ADAS_DRV
SG_ Damping_Gain : 64|8@1+ (1,0) [0|255] "" CGW
SG_ LKA_UsmMod : 80|2@1+ (1,0) [0|3] "" ADAS_DRV
SG_ Info_PedtrnDst : 84|3@1+ (1,0) [0|7] "" ADAS_DRV
BO_ 81 ADRV_0x51: 32 ADRV
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
@@ -221,12 +223,26 @@ BO_ 702 CAM_0x2be: 32 CAMERA
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
CM_ BO_ 80 "Known in official DBC as L_ADAS_CMD_30_10ms";
CM_ SG_ 80 StrTqReqVal "This is the driver torque overlay demand value. A negative value represents a torque that would accelerate the steering wheel in a clockwise direction. This signal is always zero whilst the TOI is inactive. (the official DBC defines this as SG_ StrTqReqVal : xx|11@1+ (0.0078125,-8) [-8|7.9921875] \"Nm\" XXX but I am not changing it since it has a broader impact on the OP code)";
CM_ SG_ 80 ActToiSta "This is a flag that is set to 1 when requesting the steering to activate the torque overlay interface (TOI). This must be done before an attempt is made to request non-zero steering torque overlay.";
CM_ SG_ 80 ToiFltSta "This fault flag is set when a fault in the LKA system has been detected by the LKA ECU such that LKA can no longer function. CAN failures, internal video ECU failures, hard-wired component (e.g. master switch) failures and other system logic failures are";
CM_ SG_ 80 LKA_SysWrn "A signal that provides additional information on the operation of the LKA system for the HMI to display to the driver. This includes additional fault information, reasons for unavailability of the system and additional warnings like the hands-off warning";
CM_ SG_ 80 LKA_UsmMod "This signal indicates LKA USM Mode";
CM_ SG_ 80 Info_PedtrnDst "Distance of the nearest pedestrian";
CM_ BO_ 676 "Contains signals with detailed lane line information. Used by ADAS ECU on HDA 2 vehicles to operate LFA.";
CM_ SG_ 80 HAS_LANE_SAFETY "If 0, hides LKAS 'Lane Safety' menu from vehicle settings";
CM_ SG_ 676 LEFT_LANE_LINE "Left lane line confidence";
CM_ SG_ 676 RIGHT_LANE_LINE "Right lane line confidence";
VAL_ 80 LKA_ICON 0 "hidden" 1 "grey" 2 "green" 3 "flashing green" ;
VAL_ 80 LKA_MODE 1 "warning only" 2 "assist" 6 "off" ;
VAL_ 80 LKA_OptUsmSta 0 "None LKA/LDW Option (Default)" 1 "LDW" 2 "LKA" 3 "Reserved" 4 "LDW Only (None LKA)" 5 "LDW only OFF (None LKA)" 6 "LDW/LKA OFF" 7 "Invalid";
VAL_ 80 LKA_RcgSta 0 "Not Recognized" 1 "Full Lane Recognized" 2 "Left Line Recognized" 3 "Right Line Recognized" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Reserved";
VAL_ 80 LKA_LHLnWrnSta 0 "No Warning" 1 "Lane Departure Warning" 2 "Reserved" 3 "Reserved";
VAL_ 80 LKA_RHLnWrnSta 0 "No Warning" 1 "Lane Departure Warning" 2 "Reserved" 3 "Reserved";
VAL_ 80 LKA_HndsoffSnd 0 "Off" 1 "Hands-off Sound Warning" 2 "Reserved" 3 "Reserved";
VAL_ 80 LKA_StrSnd 0 "Off" 1 "Warning" 2 "Reserved" 3 "Reserved";
VAL_ 80 LKA_SysIndReq 0 "Off" 1 "Unavailable_(Grey On)" 2 "Lane Recognized_(Green On)" 3 "Lane Departure_(Green Blink)" 4 "System Fail_(Orange On)" 5 "Not Calibrated_(Orange Blink)" 6 "Regulation_(Orange On)" 7 "Reserved";
VAL_ 80 ActToiSta 0 "De-activate TOI" 1 "Activate TOI" 2 "Reserved" 3 "Error indicator";
VAL_ 80 ToiFltSta 0 "No Fault" 1 "Fault" 2 "Reserved" 3 "Error indicatorr";
VAL_ 80 LKA_SysWrn 0 "No Info" 1 "Reserved" 2 "Reserved" 3 "Reserved" 4 "Hands-Off Warning 1" 5 "Hands-Off Warning 2" 6 "Reserved" 7 "Reserved" 8 "Reserved" 9 "System Automatic off" 10 "Reserved" 11 "Reserved" 12 "Reserved" 13 "Reserved" 14 "Reserved" 15 "System Fail";
VAL_ 80 LKA_UsmMod 0 "NONE" 1 "LKA 1 mode" 2 "LKA 2 mode" 3 "LDW";
VAL_ 676 LEFT_LANE_LINE 0 "Not Detected" 1 "Low Confidence" 2 "Medium Confidence" 3 "High Confidence";
VAL_ 676 RIGHT_LANE_LINE 0 "Not Detected" 1 "Low Confidence" 2 "Medium Confidence" 3 "High Confidence";

View File

@@ -16,6 +16,25 @@ BO_ 69 GEAR: 24 XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ GEAR : 44|3@1+ (1,0) [0|7] "" XXX
BO_ 74 IMU_01_10ms: 32 CGW_CCU
SG_ IMU_Crc1Val : 0|16@1+ (1,0) [0|0] "" ECS,ESC,FCU_C,GW_RGW,ICSC,MDPS,RCU,RWS,SFA,VPC_C
SG_ IMU_AlvCnt1Val : 16|8@1+ (1,0) [0|0] "" ECS,ESC,FCU_C,GW_RGW,ICSC,MDPS,RCU,RWS,SFA,VPC_C
SG_ IMU_YawSigSta : 24|4@1+ (1,0) [0|15] "" CLU,ADAS_PRK,FR_CMR,RR_C_RDR
SG_ IMU_LatAccelSigSta : 28|4@1+ (1,0) [0|15] "" CLU,ADAS_PRK,FR_CMR,RR_C_RDR
SG_ IMU_LongAccelSigSta : 32|4@1+ (1,0) [0|15] "" CLU,ADAS_PRK,FR_CMR,RR_C_RDR
SG_ IMU_VerAccelSigSta : 36|4@1+ (1,0) [0|15] "" XXX
SG_ IMU_McuVoltSta : 40|4@1+ (1,0) [0|15] "" XXX
SG_ IMU_AcuRstSta : 44|4@1+ (1,0) [0|15] "" XXX
SG_ IMU_SnsrTyp : 48|8@1+ (1,0) [0|255] "" XXX
SG_ IMU_RollSigSta : 56|8@1+ (1,0) [0|255] "" XXX
SG_ IMU_YawRtVal : 64|16@1+ (0.005,-163.84) [-163.84|163.835] "Deg/s" CLU,ADAS_PRK,FR_CMR,RR_C_RDR
SG_ IMU_LatAccelVal : 80|16@1+ (0.000127465,-4.17677312) [-4.17677312|4.176645655] "g" CLU,ADAS_PRK,FR_CMR,RR_C_RDR
SG_ IMU_LongAccelVal : 96|16@1+ (0.000127465,-4.17677312) [-4.17677312|4.176645655] "g" CLU,ADAS_PRK,FR_CMR,RR_C_RDR
SG_ IMU_SnsrTempVal : 112|16@1+ (1,0) [0|65535] "" XXX
SG_ IMU_SeralNumVal : 128|64@1+ (1,0) [0|1.84467440737096e+19] "" XXX
SG_ IMU_RollRtVal : 192|16@1+ (0.005,-163.84) [0|0] "º/s" XXX
SG_ IMU_VerAccelVal : 208|8@1+ (1,0) [0|255] "" XXX
BO_ 96 ESP_STATUS: 32 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
@@ -46,7 +65,7 @@ BO_ 160 WHEEL_SPEEDS: 24 XXX
SG_ WHL_SpdRLVal : 96|14@1+ (0.03125,0) [0|0] "km^h" XXX
SG_ WHL_SpdRRVal : 112|14@1+ (0.03125,0) [0|0] "km^h" XXX
BO_ 203 ADAS_CMD_35_10ms: 24 CGW_CCU
BO_ 203 LFA_ALT: 24 CGW_CCU
SG_ CHECKSUM : 0|16@1+ (1,0) [0|0] "0" FCU_C,GW_RGW,MDPS,SFA
SG_ COUNTER : 16|8@1+ (1,0) [0|0] "0" FCU_C,GW_RGW,MDPS,SFA
SG_ ADAS_ActvACISta : 24|4@1+ (1,0) [0|0] "" GW_RGW,MDPS,SFA
@@ -56,17 +75,50 @@ BO_ 203 ADAS_CMD_35_10ms: 24 CGW_CCU
SG_ FCA_ESA_ActvSta : 56|2@1+ (1,0) [0|0] "" GW_RGW,MDPS,SFA
SG_ FCA_ESA_TqBstGainVal : 64|8@1+ (0.004,0) [0|0] "" GW_RGW,MDPS,SFA
BO_ 234 MDPS: 24 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ LKA_ACTIVE : 48|1@0+ (1,0) [0|16777215] "" XXX
SG_ LKA_FAULT : 54|1@0+ (1,0) [0|1] "" XXX
SG_ STEERING_OUT_TORQUE : 64|12@1+ (0.1,-204.8) [0|65535] "" XXX
SG_ STEERING_COL_TORQUE : 80|13@1+ (1,-4095) [0|4095] "" XXX
SG_ STEERING_ANGLE : 96|16@1- (0.1,0) [0|255] "deg" XXX
SG_ STEERING_ANGLE_2 : 128|16@1- (0.1,0) [0|65535] "deg" XXX
SG_ LKA_ANGLE_ACTIVE : 145|2@0+ (1,0) [0|3] "" XXX
SG_ LKA_ANGLE_FAULT : 149|1@0+ (1,0) [0|1] "" XXX
BO_ 229 ESC_02_10ms: 32 CGW
SG_ ESC_YawSigSta : 24|4@1+ (1,0) [0|15] "" CLU,ADAS_PRK,FR_CMR,RR_C_RDR
SG_ ESC_LatAccelSigSta : 28|4@1+ (1,0) [0|15] "" CLU,ADAS_PRK,FR_CMR,RR_C_RDR
SG_ ESC_LongAccelSigSta : 32|4@1+ (1,0) [0|15] "" CLU,ADAS_PRK,FR_CMR,RR_C_RDR
SG_ ESC_YawRtVal : 64|16@1+ (0.005,-163.84) [-163.84|163.835] "Deg/s" CLU,ADAS_PRK,FR_CMR,RR_C_RDR
SG_ ESC_LatAccelVal : 80|16@1+ (0.000127465,-4.17677312) [-4.17677312|4.176645655] "g" CLU,ADAS_PRK,FR_CMR,RR_C_RDR
SG_ ESC_LongAccelVal : 96|16@1+ (0.000127465,-4.17677312) [-4.17677312|4.176645655] "g" CLU,ADAS_PRK,FR_CMR,RR_C_RDR
BO_ 234 MDPS: 24 SFA
SG_ CHECKSUM : 0|16@1+ (1,0) [0|0] "" CGW_CCU,ESC,ICSC,RCU,RWA,RWS,VPC_C
SG_ COUNTER : 16|8@1+ (1,0) [0|0] "" CGW_CCU,ESC,ICSC,RCU,RWA,RWS,VPC_C
SG_ MDPS_WrngLmpSta : 24|3@1+ (1,0) [0|0] "" CGW_CCU,ESC,ICSC,RCU,RWA,RWS
SG_ MDPS_Typ : 27|3@1+ (1,0) [0|0] "" CGW_CCU,ICSC,RWA
SG_ MDPS_EngIdleRpmReq : 30|2@1+ (1,0) [0|0] "" CGW_CCU,RWA
SG_ MDPS_VsmPlgInSta : 32|2@1+ (1,0) [0|0] "flag" ESC,ICSC,RCU,RWA
SG_ MDPS_VsmDfctvSta : 34|2@1+ (1,0) [0|0] "" ESC,ICSC,RCU,RWA
SG_ MDPS_VsmSigErrSta : 36|2@1+ (1,0) [0|0] "" ESC,RCU,RWA
SG_ MDPS_PaPlugInSta : 38|2@1+ (1,0) [0|0] "" CGW_CCU,ESC,RCU,RWA
SG_ MDPS_PaModeSta : 40|4@1+ (1,0) [0|0] "" CGW_CCU,RWA
SG_ MDPS_PaCanfltSta : 44|2@1+ (1,0) [0|0] "" CGW_CCU,RWA
SG_ MDPS_LkaPlgInSta : 46|2@1+ (1,0) [0|0] "" CGW_CCU,ICSC,RWA
SG_ MDPS_LkaToiActvSta : 48|2@1+ (1,0) [0|0] "" CGW_CCU,RWA
SG_ MDPS_LkaToiUnblSta : 50|2@1+ (1,0) [0|0] "" CGW_CCU,RWA
SG_ MDPS_LkaToiFltSta : 52|2@1+ (1,0) [0|0] "" CGW_CCU,RWA
SG_ MDPS_LkaFailSta : 54|2@1+ (1,0) [0|0] "" CGW_CCU,RWA
SG_ MDPS_ResetOpSta : 59|2@1+ (1,0) [0|0] "" Vector__XXX
SG_ MDPS_CurrModVal : 61|3@1+ (1,0) [0|0] "" CGW_CCU,RWA
SG_ MDPS_OutTqVal : 64|12@1+ (0.1,-204.8) [0|0] "Nm" CGW_CCU,ESC,ICSC,RCU,RWA
SG_ MDPS_VsmActResp : 76|2@1+ (1,0) [0|0] "" ESC,RCU,RWA
SG_ Reprogram_State_MDPS : 78|2@1+ (1,0) [0|0] "" CGW_CCU
SG_ MDPS_StrTqSnsrVal : 80|13@1+ (1,-4095) [0|4095] "" CGW_CCU,ESC,ICSC,RCU,RWA,VPC_C
SG_ MDPS_PaStrAnglVal : 96|16@1- (0.1,0) [0|0] "Deg" CGW_CCU,RWA
SG_ MDPS_LoamModSta : 112|2@1+ (1,0) [0|0] "" CGW_CCU,RWA
SG_ MDPS_HDPSpprtSWVer : 114|5@1+ (1,0) [0|0] "" CGW_CCU,RWA
SG_ MDPS_ADASAciActvSta : 120|4@1+ (1,0) [0|0] "" CGW_CCU,ESC,RWA,RWS
SG_ MDPS_ADASAciPluginSta : 124|2@1+ (1,0) [0|0] "" RWA
SG_ MDPS_ADAS_AciFltSig : 126|2@1+ (1,0) [0|0] "" CGW_CCU,ESC,RWA
SG_ MDPS_EstStrAnglVal : 128|16@1- (0.1,0) [0|0] "Deg" CGW_CCU,RWA,RWS
SG_ MDPS_ADASAciActvSta_Lv2 : 144|4@1+ (1,0) [0|0] "" CGW_CCU,RWA
SG_ MDPS_ADAS_AciFltSig_Lv2 : 148|3@1+ (1,0) [0|0] "" CGW_CCU,RWA
SG_ MDPS_TpaPlugInSta : 152|2@1+ (1,0) [0|0] "" RWA,VPC_C
SG_ MDPS_TpaCanfltSta : 154|2@1+ (1,0) [0|0] "" RWA,VPC_C
SG_ MDPS_TpaModeSta : 156|4@1+ (1,0) [0|0] "" RWA,VPC_C
SG_ MDPS_TpaStrAnglVal : 160|16@1- (0.1,0) [0|0] "Deg" RWA,VPC_C
BO_ 256 ACCELERATOR_BRAKE_ALT: 32 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
@@ -82,22 +134,24 @@ BO_ 261 ACCELERATOR_ALT: 32 XXX
BO_ 272 LKAS_ALT: 32 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ LKA_MODE : 24|3@1+ (1,0) [0|7] "" XXX
SG_ LKA_AVAILABLE : 27|2@1+ (1,0) [0|255] "" XXX
SG_ LKA_WARNING : 32|1@1+ (1,0) [0|1] "" XXX
SG_ LKA_ICON : 38|2@1+ (1,0) [0|255] "" XXX
SG_ FCA_SYSWARN : 40|1@0+ (1,0) [0|1] "" XXX
SG_ TORQUE_REQUEST : 41|11@1+ (1,-1024) [0|4095] "" XXX
SG_ STEER_REQ : 52|1@1+ (1,0) [0|1] "" XXX
SG_ LKA_OptUsmSta : 24|3@1+ (1,0) [0|7] "" ADAS_DRV
SG_ LKA_RcgSta : 27|3@1+ (1,0) [0|7] "" ADAS_DRV
SG_ LKA_LHLnWrnSta : 30|2@1+ (1,0) [0|3] "" ADAS_DRV
SG_ LKA_RHLnWrnSta : 32|2@1+ (1,0) [0|3] "" ADAS_DRV
SG_ LKA_HndsoffSnd : 34|2@1+ (1,0) [0|3] "" ADAS_DRV
SG_ LKA_StrSnd : 36|2@1+ (1,0) [0|3] "" ADAS_DRV
SG_ LKA_SysIndReq : 38|3@1+ (1,0) [0|7] "" ADAS_DRV
SG_ StrTqReqVal : 41|11@1+ (1,-1024) [0|4095] "" XXX
SG_ ActToiSta : 52|2@1+ (1,0) [0|3] "" ADAS_DRV
SG_ ToiFltSta : 54|2@1+ (1,0) [0|3] "" ADAS_DRV
SG_ LFA_BUTTON : 56|1@1+ (1,0) [0|255] "" XXX
SG_ LKA_ASSIST : 62|1@1+ (1,0) [0|1] "" XXX
SG_ STEER_MODE : 65|3@1+ (1,0) [0|1] "" XXX
SG_ NEW_SIGNAL_2 : 70|2@0+ (1,0) [0|3] "" XXX
SG_ LKA_SysWrn : 60|4@1+ (1,0) [0|15] "" ADAS_DRV
SG_ Damping_Gain : 64|8@1+ (1,0) [0|255] "" CGW
SG_ LKAS_ANGLE_ACTIVE : 77|2@0+ (1,0) [0|3] "" XXX
SG_ HAS_LANE_SAFETY : 80|1@0+ (1,0) [0|1] "" XXX
SG_ LKA_UsmMod : 80|2@1+ (1,0) [0|3] "" ADAS_DRV
SG_ ADAS_StrAnglReqVal : 82|14@1- (0.1,0) [0|176.7] "Deg" GW_RGW,MDPS,SFA
SG_ ADAS_ACIAnglTqRedcGainVal : 96|8@1+ (0.004,0) [0|1] "" GW_RGW,MDPS,SFA
SG_ DAMP_FACTOR : 64|8@1+ (1,0) [0|255] "" XXX
SG_ FCA_ESA_CtrlSta : 107|1@0+ (1,0) [0|1] "" XXX
BO_ 282 FR_CMR_01_10ms: 16 FR_CMR
SG_ FR_CMR_Crc1Val : 0|16@1+ (1,0) [0|0] "" Dummy,IBU_HS,vBDM
@@ -131,21 +185,31 @@ BO_ 293 STEERING_SENSORS: 16 XXX
SG_ STEERING_RATE : 40|8@1+ (4,0) [0|1016] "deg/s" XXX
BO_ 298 LFA: 16 ADRV
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ LKA_MODE : 24|3@1+ (1,0) [0|7] "" XXX
SG_ NEW_SIGNAL_1 : 27|2@1+ (1,0) [0|255] "" XXX
SG_ LKA_WARNING : 32|1@1+ (1,0) [0|1] "" XXX
SG_ LKA_ICON : 38|2@1+ (1,0) [0|255] "" XXX
SG_ TORQUE_REQUEST : 41|11@1+ (1,-1024) [0|4095] "" XXX
SG_ STEER_REQ : 52|1@1+ (1,0) [0|1] "" XXX
SG_ LFA_BUTTON : 56|1@1+ (1,0) [0|255] "" XXX
SG_ LKA_ASSIST : 62|1@1+ (1,0) [0|1] "" XXX
SG_ STEER_MODE : 65|3@1+ (1,0) [0|1] "" XXX
SG_ NEW_SIGNAL_2 : 70|2@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_4 : 72|4@1+ (1,0) [0|15] "" XXX
SG_ HAS_LANE_SAFETY : 80|1@0+ (1,0) [0|1] "" XXX
SG_ DAMP_FACTOR : 104|8@1+ (1,0) [0|255] "" XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" CLU,CGW
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" CLU,CGW
SG_ LKA_OptUsmSta : 24|3@1+ (1,0) [0|7] "" CLU,CGW
SG_ LKA_RcgSta : 27|3@1+ (1,0) [0|7] "" CLU,CGW
SG_ LKA_LHLnWrnSta : 30|2@1+ (1,0) [0|3] "" CLU,CGW
SG_ LKA_RHLnWrnSta : 32|2@1+ (1,0) [0|3] "" CLU,CGW
SG_ LKA_HndsoffSnd : 34|2@1+ (1,0) [0|3] "" CLU,CGW
SG_ LKA_StrSnd : 36|2@1+ (1,0) [0|3] "" CLU,CGW
SG_ LKA_SysIndReq : 38|3@1+ (1,0) [0|7] "" CLU,RR_C_RDR,CGW
SG_ StrTqReqVal : 41|11@1+ (1,-1024) [0|4095] "" XXX
SG_ ActToiSta : 52|2@1+ (1,0) [0|3] "" CLU,CGW
SG_ ToiFltSta : 54|2@1+ (1,0) [0|3] "" CGW
SG_ LFA_BUTTON : 56|1@0+ (1,0) [0|255] "" XXX
SG_ BCA_Rear_WrnSta : 57|3@1+ (1,0) [0|255] "" ADRV
SG_ LKA_SysWrn : 60|4@1+ (1,0) [0|15] "" CLU,CGW
SG_ FCA_LO_WrnSta : 64|1@1+ (1,0) [0|1] "" ADRV
SG_ FCA_LS_WrnSta : 68|1@1+ (1,0) [0|1] "" ADRV
SG_ LKA_OnOffEquip2Sta : 72|2@1+ (1,0) [0|255] "" ADRV
SG_ LKA_UsmMod : 80|2@1+ (1,0) [0|3] "" CLU,CGW
SG_ Info_PedtrnDst : 84|3@0+ (1,0) [0|7] "" ADAS_DRV
SG_ ELK_SysFlrSta : 85|5@1+ (1,0) [0|31] "" ADRV
SG_ ELK_SymbDisp : 90|3@1+ (1,0) [0|7] "" ADRV
SG_ FCA_ESA_WrnSta : 93|1@1+ (1,0) [0|7] "" ADRV
SG_ FCA_ESA_CtrlSta : 101|1@1+ (1,0) [0|7] "" ADRV
SG_ Damping_Gain : 104|8@1+ (1,0) [0|255] "" CGW
BO_ 304 GEAR_SHIFTER: 16 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
@@ -390,19 +454,33 @@ BO_ 437 FR_CMR_03_50ms: 32 FR_CMR
SG_ Relative_Velocity : 200|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
SG_ Longitudinal_Distance : 212|12@1+ (0.05,0) [0|204.75] "m" XXX
BO_ 442 BLINDSPOTS_REAR_CORNERS: 24 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ LEFT_BLOCKED : 24|1@0+ (1,0) [0|1] "" XXX
SG_ LEFT_MB : 30|1@0+ (1,0) [0|3] "" XXX
SG_ MORE_LEFT_PROB : 32|1@1+ (1,0) [0|3] "" XXX
BO_ 442 ADAS_CMD_50_50ms: 24 XXX
SG_ ADAS_CMD_Crc50Val : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ ADAS_CMD_AlvCnt50Val : 16|8@1+ (1,0) [0|255] "" XXX
SG_ BCW_Sta : 24|1@0+ (1,0) [0|1] "" XXX
SG_ BCW_OnOffEquipSta : 28|2@1+ (1,0) [0|3] "" XXX
SG_ BCW_LtIndSta : 30|1@0+ (1,0) [0|3] "" XXX
SG_ BCW_RtIndSta : 32|1@1+ (1,0) [0|3] "" XXX
SG_ BCW_LtSndWrngSta : 34|2@1+ (1,0) [0|3] "" XXX
SG_ BCW_RtSndWrngSta : 36|10@1+ (1,0) [0|1023] "" XXX
SG_ FL_INDICATOR : 46|6@0+ (1,0) [0|1] "" XXX
SG_ FR_INDICATOR : 54|6@0+ (1,0) [0|63] "" XXX
SG_ RIGHT_BLOCKED : 64|1@0+ (1,0) [0|1] "" XXX
SG_ COLLISION_AVOIDANCE_ACTIVE : 68|1@0+ (1,0) [0|1] "" XXX
SG_ NEW_SIGNAL_2 : 96|1@0+ (1,0) [0|1] "" XXX
SG_ FL_INDICATOR_ALT : 138|1@0+ (1,0) [0|1] "" XXX
SG_ FR_INDICATOR_ALT : 141|1@0+ (1,0) [0|1] "" XXX
SG_ FR_INDICATOR : 54|2@0+ (1,0) [0|3] "" XXX
SG_ BCW_SnstvtyModRetVal : 56|3@1+ (1,0) [0|7] "" XXX
SG_ BCW_IndSta : 59|3@1+ (1,0) [0|7] "" XXX
SG_ BCA_OnOffEquip2Sta : 62|2@1+ (1,0) [0|3] "" XXX
SG_ BCA_Sta : 64|1@0+ (1,0) [0|1] "" XXX
SG_ BCA_OnOffEquipSta : 68|1@0+ (1,0) [0|1] "" XXX
SG_ BCA_DRV_WarnSta : 76|4@1+ (1,0) [0|15] "" XXX
SG_ BCA_Plus_Deccel_Req : 80|4@1+ (1,0) [0|15] "" XXX
SG_ BCA_Plus_BrkCmdSta : 84|2@1+ (1,0) [0|3] "" XXX
SG_ BCA_Plus_LtWrngSta : 86|2@1+ (1,0) [0|3] "" XXX
SG_ BCA_Plus_RtWrngSta : 88|5@1+ (1,0) [0|31] "" XXX
SG_ BCA_Plus_FuncStat : 93|3@1+ (1,0) [0|7] "" XXX
SG_ BCA_Plus_Sta : 96|1@0+ (1,0) [0|1] "" XXX
SG_ Brake_Control_RL : 110|2@1+ (1,0) [0|3] "" XXX
SG_ Brake_Control_RR : 118|2@1+ (1,0) [0|3] "" XXX
SG_ OSMrrLamp_LtIndSta : 128|2@1+ (1,0) [0|3] "" XXX
SG_ OSMrrLamp_RtIndSta : 130|6@1+ (1,0) [0|63] "" XXX
BO_ 463 CRUISE_BUTTONS: 8 XXX
SG_ _CHECKSUM : 0|8@1+ (1,0) [0|65535] "" XXX
@@ -674,16 +752,69 @@ BO_ 1264 LOCAL_TIME: 8 XXX
SG_ MINUTES : 21|6@0+ (1,0) [0|63] "" XXX
SG_ SECONDS : 31|8@0+ (1,0) [0|59] "" XXX
CM_ BO_ 74 "[P] Periodic";
CM_ SG_ 74 IMU_Crc1Val "The data area for CRC calculation is based on the data length (DLC) of the message DB.The CRC shall be calculated over the entire data block (excluding the CRC bytes) including the user data, alive counter and Data ID- CRC Polynomial (0x1021) , Ini";
CM_ SG_ 74 IMU_AlvCnt1Val "For the first transmission request for a data element the counter shall be initialized with 0 and shall be incremented by 1 for every subsequent send request. When the counter reaches the maximum value(0xFF), then it shall restart with 0 for the next s";
CM_ SG_ 74 IMU_YawSigSta "This signal indicates failure status of yaw rate signal and yaw rate sensing element.0000B : No failure xxx1B : IMU_Yawrate_failurexx1xB : Initialization is runningx1xxB : Reserved1xxxB : ReservedThis signal represents the physica";
CM_ SG_ 74 IMU_LatAccelSigSta "This signal indicates failure status of lateral acceleration signal and sensing element.0000B : No failurexxx1B : IMU_Lateral acceleration failurexx1xB : Initialization is runningx1xxB : Reserved1xxxB : ReservedThis signal represe";
CM_ SG_ 74 IMU_AcuRstSta "This signal indicates the status of IMU.0000B : Normal mode xxx1B : IMU Reset modexx1xB : Reservedx1xxB : Reserved1xxxB : ReservedIf ACU reset is required, ACU will send IMU RESET bit(XXX1B) up to 30 times and perform a reset. If ";
CM_ SG_ 74 IMU_YawRtVal "This signal indicates Information regarding yaw rate.physical range : -163.84..163.83 ˚/s = 0000H..FFFEhConversion : (PH) = ((HEX)-8000H)*0.005[˚/s/digit] = (HEX)*0.005[˚/s/digit] - 163.84[˚/s] ";
CM_ SG_ 74 IMU_LatAccelVal "This signal indicates Information regarding lateral acceleration.physical range : -4.1768g..4.1765g = 0000H..FFFEhConversion : (PH) = ((HEX)-8000H)*0.000127465[g/digit] = (HEX)*0.000127465[g/digit] - 4.17677312[g]";
CM_ SG_ 96 BRAKE_PRESSURE "User applied brake pedal pressure. Ramps from computer applied pressure on falling edge of cruise. Cruise cancels if !=0";
CM_ SG_ 101 BRAKE_POSITION "User applied brake pedal position, max is ~700. Signed on some vehicles";
CM_ BO_ 203 "Known in official DBC as ADAS_CMD_35_10ms";
CM_ SG_ 203 ADAS_ActvACISta "ADAS Active AngleControlInterface State";
CM_ SG_ 203 ADAS_ActvACILvl2Sta "ADAS Active AngleControlInterface Level 2 State";
CM_ SG_ 203 ADAS_StrAnglReqVal "(LFA) ADAS Steering Angle Request Value; Capped at 119.9;";
CM_ SG_ 203 ADAS_ACIAnglTqRedcGainVal "(LFA) ADAS AngleControlInterface Angle Torque Reduction Gain Value";
CM_ SG_ 203 FCA_ESA_ActvSta "FCA_ESA Active State";
CM_ SG_ 203 FCA_ESA_TqBstGainVal "FCA_ESA Torque Boost Gain Value";
CM_ BO_ 234 "Named MDPS_01_10ms on the official DBC.";
CM_ SG_ 234 CHECKSUM "The data area for CRC calculation is based on the data length (DLC) of the message DB. The CRC shall be calculated over the entire data block (excluding the CRC bytes) including the user data, alive counter and Data ID. CRC Polynomial (0x1021).";
CM_ BO_ 229 "[P] Periodic";
CM_ SG_ 229 ESC_YawSigSta "ESC_YawSigSta";
CM_ SG_ 229 ESC_LatAccelSigSta "ESC_LatAccelSigSta";
CM_ SG_ 229 ESC_LongAccelSigSta "ESC_LongAccelSigSta";
CM_ SG_ 229 ESC_YawRtVal "ESC_YawRtVal";
CM_ SG_ 229 ESC_LatAccelVal "ESC_LatAccelVal";
CM_ SG_ 229 ESC_LongAccelVal "ESC_LongAccelVal";
CM_ SG_ 234 COUNTER "For the first transmission request for a data element the counter shall be initialized with 0 and shall be incremented by 1 for every subsequent send request. When the counter reaches the maximum value(0xFF), then it shall restart with 0 for the next send request.";
CM_ SG_ 234 MDPS_WrngLmpSta "The signal indicates the ststus of the MDPS Warning lamp";
CM_ SG_ 234 MDPS_Typ "Information regarding the type of MDPS. (C-MDPS / R-MDPS / SbW)";
CM_ SG_ 234 MDPS_EngIdleRpmReq "This signal indicates the request status for engine idle rpm up according to MDPS fast rotation.";
CM_ SG_ 234 MDPS_VsmPlgInSta "This signal indicates whether the VSM function of MDPS is plugged in or not.";
CM_ SG_ 234 MDPS_VsmDfctvSta "Information regarding the MDPS defective Indication For VSM";
CM_ SG_ 234 MDPS_VsmSigErrSta "Information indicating VSM signal status";
CM_ SG_ 234 MDPS_PaPlugInSta "This signal indicates whether the PA function of MDPS is plugged in or not.";
CM_ SG_ 234 MDPS_PaModeSta "This signal indicates the status of the PA steering function.";
CM_ SG_ 234 MDPS_PaCanfltSta "This Signal should be used by only PA. This signal indicates whether the MDPS is defective in PA cooperation control. This signal is set as '1' only when MDPS Detects CAN Failure(TIMEOUT, Signal Error) of PA CAN Message";
CM_ SG_ 234 MDPS_LkaPlgInSta "This signal indicates whether the LKA function of MDPS is plugged in or not.";
CM_ SG_ 234 MDPS_LkaToiActvSta "This flag is set to 1 in response to the LKA Controller requesting the activation of the torque interface and set back to 0 in response to the LKA Controller requesting the de-activation of the torque interface.";
CM_ SG_ 234 MDPS_LkaToiUnblSta "This is a flag that is set when the MDPS is not faulty, but is temporarily unable to activate the TOI due to steering torque limiting e.g. when the supply voltage is too low.";
CM_ SG_ 234 MDPS_LkaToiFltSta "This fault flag is set when a fault within the MDPS system has been detected such that the LKA TOI can no longer function. CAN failures, internal MDPS failures, and LKA controller logic failures are all reported by this flag. Failures reported by the LKA";
CM_ SG_ 234 MDPS_LkaFailSta "This fault flag is set whilst the MDPS TOI is in a fail state and has not yet recovered from it. This could either be due to an MDPS detected fault (as communicated by the MDPS_LkaToiFltSta' flag) or an LKA detected fault (as communicated by the LKA_";
CM_ SG_ 234 MDPS_ResetOpSta "Information regarding the state of reset";
CM_ SG_ 234 MDPS_CurrModVal "This signal indicates flex steer parameter value in MDPS. For information about flex steer mode set by user, refer to MDPS_FlxStrSta signal.";
CM_ SG_ 234 MDPS_OutTqVal "MDPS column torque. This signal has direction information. '+' Value means Counter clock wise rotation. '-' value means Clock wise rotation.";
CM_ SG_ 234 MDPS_VsmActResp "Information of VSM Tqrque Intervention Act Response";
CM_ SG_ 234 Reprogram_State_MDPS "Information regarding the reprogram state";
CM_ SG_ 234 MDPS_StrTqSnsrVal "Steering torque sensor value. Physical Value > 0: Left Direction (CCW). Physical Value < 0: Right Direction (CW). '+' Value means Counter clock wise rotation. '-' value means Clock wise rotation. (Original definition was (0.005,-20.48) [0|0] but it's different from all OP expects)";
CM_ SG_ 234 MDPS_PaStrAnglVal "This value is used to inform PA of a compensated steering wheel angle by MDPS. The signal is signed 16bits. (PH) = (HEX) * 0.1 (for 0 < HEX <= 32767) or = (HEX - 65536) * 0.1 (for HEX > 32767) [Deg]. This signal has direction information.";
CM_ SG_ 234 MDPS_LoamModSta "The signal represent status of the LOAM(Loss Of Assist Mitigation) Mode";
CM_ SG_ 234 MDPS_HDPSpprtSWVer "This signal indicates HDP-MDPS Control Requirement Spec Version";
CM_ SG_ 234 MDPS_ADASAciActvSta "State for angle control";
CM_ SG_ 234 MDPS_ADASAciPluginSta "This signal indicates whether the ADASAci function of MDPS is plugged in or not.";
CM_ SG_ 234 MDPS_ADAS_AciFltSig "MDPS Fault Status for HDP Function";
CM_ SG_ 234 MDPS_EstStrAnglVal "This value is used to inform of a compensated steering wheel angle by MDPS. The signal is signed 16bits, and made by motor position sensor. (PH) = (HEX) * 0.1 (for 0 < HEX <= 32767) or = (HEX - 65536) * 0.1 (for HEX > 32767) [Deg].";
CM_ SG_ 234 MDPS_ADASAciActvSta_Lv2 "States for angle control (LV2)";
CM_ SG_ 234 MDPS_ADAS_AciFltSig_Lv2 "MDPS Fault Status for LV2 Angle Control Function";
CM_ SG_ 234 MDPS_TpaPlugInSta "This signal indicates whether the TPA function of MDPS is plugged in or not.";
CM_ SG_ 234 MDPS_TpaCanfltSta "This Signal should be used by only TPA. This signal indicates whether the MDPS is defective in TPA cooperation control. This signal is set as '1' only when MDPS Detects CAN Failure(TIMEOUT, Signal Error) of TPA CAN Message";
CM_ SG_ 234 MDPS_TpaModeSta "This signal indicates the status of the TPA steering function.";
CM_ SG_ 234 MDPS_TpaStrAnglVal "This value is used to inform TPA of a compensated steering wheel angle by MDPS. The signal is signed 16bits. (PH) = (HEX) * 0.1 (for 0 < HEX <= 32767) or = (HEX - 65536) * 0.1 (for HEX > 32767) [Deg]";
CM_ BO_ 272 "Alternative LKAS message, used on cars such as 2023 Ioniq 6, 2nd gen Kona. Matches LKAS except size is 32 bytes";
CM_ SG_ 272 LKA_AVAILABLE "Angle control cars: 3 when LKA is generally available, goes to 0 during changes with LFA";
CM_ SG_ 272 ToiFltSta "This fault flag is set when a fault in the LKA system has been detected by the LKA ECU such that LKA can no longer function. CAN failures, internal video ECU failures, hard-wired component (e.g. master switch) failures and other system logic failures are";
CM_ SG_ 272 ADAS_StrAnglReqVal "(LKAS) ADAS Steering Angle Request Value; Capped at 176.7; tracks MDPS->STEERING_ANGLE when not engaged, not STEERING_SENSORS->STEERING_ANGLE";
CM_ SG_ 272 ADAS_ACIAnglTqRedcGainVal "(LKAS) ADAS AngleControlInterface Angle Torque Reduction Gain Value";
CM_ BO_ 282 "Sent by the camera containing DAW (Driver Attention Warning) information and information about HBA (High Beam Assist).";
@@ -705,7 +836,22 @@ CM_ SG_ 282 FR_CMR_SCCEquipSta "This signal indicates equipment for SCC";
CM_ SG_ 282 FR_CMR_ReqADASMapMsgVal "This signal indicates an ADAS map message request from FR_CMR to H_U. Each bit indicates the request messages as follows. - Bit 0 : H_U_NAVI_V2_STUB_E - Bit 1 : HU_NAVI_V2_PROSHORT_E_00 (곡률) - Bit 2 : HU_NAVI_V2_PROSHORT_E_00 (곡률 외 정보)";
CM_ SG_ 282 FR_CMR_SwVer1Val "This signal indicates a major version of FR_CMR software. If FR_CMR software version is A.00, 'A' and '00' mean major and minor version respectively.";
CM_ SG_ 282 FR_CMR_SwVer2Val "This signal indicates a minor version of FR_CMR software. If FR_CMR software version is A.00, 'A' and '00' mean major and minor version respectively.";
CM_ SG_ 298 NEW_SIGNAL_4 "todo: figure out why always set to 9";
CM_ BO_ 298 "This message controls steering and alerts regarding lateral control. Formerly known as LFA. Node is flagged as ADRV, but in reality this signal can be seen from either the FR_CMR (front camera) or the ADRV (adas ecu) for some trims.";
CM_ SG_ 298 LKA_OptUsmSta "LKA_OptionUsmStatus ##2G##LDW_LKA - LKA11 - CF_LKA_Opt_USM";
CM_ SG_ 298 LKA_RcgSta "LKA_RecognitionStatus ##2G##LDW_LKA - LKA11 - CF_LKA_LaneRecogState";
CM_ SG_ 298 LKA_LHLnWrnSta "LKA_LHLaneWarningStatus ##2G##LDW_LKA - LKA11 - CF_LKA_LHWarning";
CM_ SG_ 298 LKA_RHLnWrnSta "LKA_RHLaneWarningStatus ##2G##LDW_LKA - LKA11 - CF_LKA_RHWarning";
CM_ SG_ 298 LKA_HndsoffSnd "LKA_HandsoffSound ##2G##LDW_LKA - LKA11 - CF_LKA_HandsOff_Snd";
CM_ SG_ 298 LKA_StrSnd "LKA_SteeringSound ##2G##LDW_LKA - LKA11 - CF_LKA_Steer_Snd";
CM_ SG_ 298 LKA_SysIndReq "LKA_SystemIndicatorRequest ##2G##LDW_LKA - LKA11 - CF_LKA_SymbolState";
CM_ SG_ 298 StrTqReqVal "This is the driver torque overlay demand value. A negative value represents a torque that would accelerate the steering wheel in a clockwise direction. This signal is always zero whilst the TOI is inactive. (the official DBC defines this as SG_ StrTqReqVal : xx|11@1+ (0.0078125,-8) [-8|7.9921875] \"Nm\" XXX but I am not changing it since it has a broader impact on the OP code)";
CM_ SG_ 298 ActToiSta "This is a flag that is set to 1 when requesting the steering to activate the torque overlay interface (TOI). This must be done before an attempt is made to request non-zero steering torque overlay.";
CM_ SG_ 298 ToiFltSta "This fault flag is set when a fault in the LKA system has been detected by the LKA ECU such that LKA can no longer function. CAN failures, internal video ECU failures, hard-wired component (e.g. master switch) failures and other system logic failures are";
CM_ SG_ 298 LKA_SysWrn "A signal that provides additional information on the operation of the LKA system for the HMI to display to the driver. This includes additional fault information, reasons for unavailability of the system and additional warnings like the hands-off warning";
CM_ SG_ 298 FCA_LS_WrnSta "(Reverse Engineered) This signal was observed while ELK was taking over to prevent a blind spot collision.";
CM_ SG_ 298 LKA_UsmMod "This signal indicates LKA USM Mode";
CM_ SG_ 298 ELK_SymbDisp "Emergency Lane-Keeping";
CM_ SG_ 298 Damping_Gain "ADAS Damping Gain for MDPS";
CM_ SG_ 352 SET_ME_9 "has something to do with AEB settings";
CM_ SG_ 373 ACCEnable "Likely a copy of CAN's TCS13->ACCEnable";
CM_ SG_ 373 DriverBraking "Likely derived from BRAKE->BRAKE_POSITION";
@@ -812,14 +958,56 @@ VAL_ 96 TRACTION_AND_STABILITY_CONTROL 0 "On" 5 "Limited" 1 "Off";
VAL_ 112 GEAR 0 "P" 5 "D" 6 "N" 7 "R";
VAL_ 203 ADAS_ActvACISta 0 "INIT" 1 "INACTIVE" 2 "ACTIVE35(ACTIVE)" 3 "ACTIVE33(Redundancy)" 4 "RESERVED" 5 "RESERVED" 6 "RESERVED" 7 "RESERVED" 8 "RESERVED" 9 "RESERVED" 10 "RESERVED" 11 "RESERVED" 12 "RESERVED" 13 "RESERVED" 14 "RESERVED" 15 "RESERVED";
VAL_ 203 ADAS_ActvACILvl2Sta 0 "INIT" 1 "INACTIVE" 2 "ACTIVE35(ACTIVE)" 3 "RESERVED" 4 "RESERVED" 5 "RESERVED" 6 "RESERVED" 7 "RESERVED" 8 "RESERVED" 9 "RESERVED" 10 "RESERVED" 11 "RESERVED" 12 "RESERVED" 13 "RESERVED" 14 "RESERVED" 15 "RESERVED";
VAL_ 203 ADAS_StrAnglReqVal 0 "0x0x000~0x3FFF:Real Values" 16383 "0x0x000~0x3FFF:Real Values";
VAL_ 203 ADAS_StrAnglReqVal 0 "0 (0x000~0x3FFF valid range)" 16383 "16383 (0x000~0x3FFF valid range)";
VAL_ 203 ADAS_ACIAnglTqRedcGainVal 0 "0x0x00~0xFA:Real Values" 250 "0x0x00~0xFA:Real Values" 251 "RESERVED" 252 "RESERVED" 253 "RESERVED" 254 "RESERVED" 255 "RESERVED";
VAL_ 203 FCA_ESA_ActvSta 0 "Inactive" 1 "Active" 2 "RESERVED" 3 "RESERVED";
VAL_ 203 FCA_ESA_TqBstGainVal 0 "0x0x00~0xFA:Real Values" 250 "0x0x00~0xFA:Real Values" 251 "RESERVED" 252 "RESERVED" 253 "RESERVED" 254 "RESERVED" 255 "RESERVED";
VAL_ 234 LKA_FAULT 0 "ok" 1 "lka fault";
VAL_ 272 LKA_MODE 1 "warning only" 2 "assist" 6 "off";
VAL_ 272 LKA_ICON 0 "hidden" 1 "grey" 2 "green" 3 "flashing green";
VAL_ 272 LKAS_ANGLE_ACTIVE 0 "off" 1 "not active" 2 "active";
VAL_ 234 MDPS_WrngLmpSta 0 "MDPS Malfunction Warning lamp OFF" 1 "MDPS Malfunciton Warning lamp BLANKING(2Hz)" 2 "MDPS Malfunction Warning lamp ON" 3 "MDPS Malfunction Warning lamp BLANKING(1Hz)" 4 "RESERVED" 5 "RESERVED" 6 "RESERVED" 7 "Error Indicator";
VAL_ 234 MDPS_Typ 0 "C-MDPS" 1 "R-MDPS(Dual Pinion)" 2 "R-MDPS(Belt)" 3 "SbW" 4 "RESERVED" 5 "RESERVED" 6 "RESERVED" 7 "Error Indicator";
VAL_ 234 MDPS_EngIdleRpmReq 0 "Current Consumption is Low" 1 "Current Consumption is High" 2 ":RESERVED" 3 "Error Indicator";
VAL_ 234 MDPS_VsmPlgInSta 0 "The VSM function of MDPS is not plugged in (unplugged)." 1 "The VSM function of MDPS is plugged in." 2 "RESERVED" 3 "Error Indicator";
VAL_ 234 MDPS_VsmDfctvSta 0 "MDPS is not defective" 1 "MDPS is defective" 2 "RESERVED" 3 "Error Indicator";
VAL_ 234 MDPS_VsmSigErrSta 0 "VSM1 signal is not error" 1 "VSM signal is error" 2 "RESERVED" 3 "Error Indicator";
VAL_ 234 MDPS_PaPlugInSta 0 "The PA function of MDPS is not plugged in (unplugged)." 1 "The PA function of MDPS is plugged in." 2 "RESERVED" 3 "Error Indicator";
VAL_ 234 MDPS_PaModeSta 0 "RESERVED" 1 "Steering still in initialization phase" 2 "Steering ready, waits for PA command" 3 "Steering set in standby by PA" 4 "Steering requested to go to first activation step" 5 "Steering requested to go to final activation step" 6 "Steering went to error internally" 7 "Steering aborted the automatic function" 8 "RESERVED" 9 "RESERVED" 10 "RESERVED" 11 "RESERVED" 12 "RESERVED" 13 "RESERVED" 14 "RESERVED" 15 "Error Indicator";
VAL_ 234 MDPS_PaCanfltSta 0 "No Failure" 1 "Failure about Pa can message" 2 "RESERVED" 3 "Error Indicator";
VAL_ 234 MDPS_LkaPlgInSta 0 "The LKA function of MDPS is not plugged in (unplugged)." 1 "The LKA function of MDPS is plugged in." 2 "RESERVED" 3 "Error Indicator";
VAL_ 234 MDPS_LkaToiActvSta 0 "Deactivated" 1 "Activated" 2 "RESERVED" 3 "Error Indicator";
VAL_ 234 MDPS_LkaToiUnblSta 0 "Available" 1 "Unavailable" 2 "RESERVED" 3 "Error Indicator";
VAL_ 234 MDPS_LkaToiFltSta 0 "No fault" 1 "Faulty" 2 "RESERVED" 3 "Error Indicator";
VAL_ 234 MDPS_LkaFailSta 0 "Not in fail state" 1 "In fail state" 2 "RESERVED" 3 "Error Indicator";
VAL_ 234 MDPS_ResetOpSta 0 "Normal" 1 "Reset Complete" 2 "Reset Fail" 3 "RESERVED";
VAL_ 234 MDPS_CurrModVal 0 "Comfort Mode" 1 "Sport Mode" 2 "Sport+ Mode" 3 "Chauffeur Mode" 4 "Mild Mode" 5 "Drift Mode" 6 "RESERVED" 7 "Error Indicator";
VAL_ 234 MDPS_OutTqVal 0 "0x0x000~0xFFD:real values" 4093 "0x0x000~0xFFD:real values" 4094 "RESERVED" 4095 "Error Indicator";
VAL_ 234 MDPS_VsmActResp 0 "VSM Control inactivated" 1 "VSM Control Activated" 2 "RESERVED" 3 "Invalid";
VAL_ 234 Reprogram_State_MDPS 0 "normal operation" 1 "reprogramming" 2 "RESERVED" 3 "Error Indicator";
VAL_ 234 MDPS_StrTqSnsrVal 0 "0 (0x000~0x7FFD valid range)" 8189 "32765 (0x000~0x1FFD valid range)" 8190 "RESERVED" 8191 "Error Indicator";
VAL_ 234 MDPS_PaStrAnglVal 0 "0 (0x000~0x7FFD valid range)" 32765 "32765 (0x000~0x7FFD valid range)" 32766 "Not Initialized" 32767 "Error Indicator" 32768 "32768 (0x8000~0xFFFF valid range)" 65535 "65535 (0x8000~0xFFFF valid range)";
VAL_ 234 MDPS_LoamModSta 0 "Normal" 1 "Loam Flag Warning Display" 2 "RESERVED" 3 "Error Indicator";
VAL_ 234 MDPS_HDPSpprtSWVer 0 "HDP-MDPS Control Requirement Version" 1 "HDP-MDPS Control Requirement Version" 2 "HDP-MDPS Control Requirement Version" 3 "HDP-MDPS Control Requirement Version" 4 "HDP-MDPS Control Requirement Version" 5 "HDP-MDPS Control Requirement Version" 6 "HDP-MDPS Control Requirement Version" 7 "HDP-MDPS Control Requirement Version" 8 "HDP-MDPS Control Requirement Version" 9 "HDP-MDPS Control Requirement Version" 10 "HDP-MDPS Control Requirement Version" 11 "HDP-MDPS Control Requirement Version" 12 "HDP-MDPS Control Requirement Version" 13 "HDP-MDPS Control Requirement Version" 14 "HDP-MDPS Control Requirement Version" 15 "HDP-MDPS Control Requirement Version" 16 "HDP-MDPS Control Requirement Version" 17 "HDP-MDPS Control Requirement Version" 18 "HDP-MDPS Control Requirement Version" 19 "HDP-MDPS Control Requirement Version" 20 "HDP-MDPS Control Requirement Version" 21 "HDP-MDPS Control Requirement Version" 22 "HDP-MDPS Control Requirement Version" 23 "HDP-MDPS Control Requirement Version" 24 "HDP-MDPS Control Requirement Version" 25 "HDP-MDPS Control Requirement Version" 26 "HDP-MDPS Control Requirement Version" 27 "HDP-MDPS Control Requirement Version" 28 "HDP-MDPS Control Requirement Version" 29 "HDP-MDPS Control Requirement Version" 30 "HDP-MDPS Control Requirement Version" 31 "HDP-MDPS Control Requirement Version";
VAL_ 234 MDPS_ADASAciActvSta 0 "INIT" 1 "INACTIVE" 2 "ACTIVE35(ACTIVE)" 3 "ACTIVE33(Redundancy)" 4 "RESERVED" 5 "RESERVED" 6 "RESERVED" 7 "RESERVED" 8 "RESERVED" 9 "RESERVED" 10 "RESERVED" 11 "RESERVED" 12 "RESERVED" 13 "RESERVED" 14 "RESERVED" 15 "RESERVED";
VAL_ 234 MDPS_ADASAciPluginSta 0 "ADASAciNotPlugged-in" 1 "ADASAciPlugged-in" 2 "RESERVED" 3 "ErrorIndicator";
VAL_ 234 MDPS_ADAS_AciFltSig 0 "No Fault" 1 "MDPS Fault" 2 "Fault Except MDPS" 3 "Both Fault";
VAL_ 234 MDPS_EstStrAnglVal 0 "0 (0x000~0x7FFD valid range)" 32765 "32765 (0x000~0x7FFD valid range)" 32766 "Not Initialized" 32767 "Error Indicator" 32768 "32768 (0x8000~0xFFFF valid range)" 65535 "65535 (0x8000~0xFFFF valid range)";
VAL_ 234 MDPS_ADASAciActvSta_Lv2 0 "Not USED" 1 "INACTIVE" 2 "ACTIVE35(Active)" 3 "Reserved" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Reserved" 8 "Reserved" 9 "Reserved" 10 "Reserved" 11 "Reserved" 12 "Reserved" 13 "Reserved" 14 "Reserved" 15 "Reserved";
VAL_ 234 MDPS_ADAS_AciFltSig_Lv2 0 "No Fault" 1 "MDPS Fault" 2 "Fault Except MDPS" 3 "Both Fault" 4 "Temporarily Unavailable" 5 "Temporarily Unavailable and MDPS Fault" 6 "Temporarily Unavailable and Fault Except MDPS" 7 "Temporarily Unavailable and Both Fault";
VAL_ 234 MDPS_TpaPlugInSta 0 "The TPA function of MDPS is not plugged in (unplugged)" 1 "The TPA function of MDPS is plugged in" 2 "RESERVED" 3 "Error Indicator";
VAL_ 234 MDPS_TpaCanfltSta 0 "No Failure" 1 "Failure about Tpa can message" 2 "RESERVED" 3 "Error Indicator";
VAL_ 234 MDPS_TpaModeSta 0 "RESERVED" 1 "Steering still in initialization phase" 2 "Steering ready, waits for TPA command" 3 "Steering set in standby by TPA" 4 "Steering requested to go to first activation step activation step" 5 "Steering requested to go to final activation step" 6 "Steering went to error internally" 7 "Steering aborted the automatic function" 14 "RESERVED" 15 "Error Indicator";
VAL_ 234 MDPS_TpaStrAnglVal 0 "0 (0x000~0x7FFD valid range)" 32765 "32765 (0x000~0x7FFD valid range)" 32766 "Not Initialized" 32767 "Error Indicator" 32768 "32768 (0x8000~0xFFFF valid range)" 65535 "65535 (0x8000~0xFFFF valid range)";
VAL_ 272 LKA_OptUsmSta 0 "None LKA/LDW Option (Default)" 1 "LDW" 2 "LKA" 3 "Reserved" 4 "LDW Only (None LKA)" 5 "LDW only OFF (None LKA)" 6 "LDW/LKA OFF" 7 "Invalid";
VAL_ 272 LKA_RcgSta 0 "Not Recognized" 1 "Left Lane Recognition" 2 "Right Lane Recognition" 3 "Full Lane Recognition" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Reserved";
VAL_ 272 LKA_LHLnWrnSta 0 "No Warning" 1 "Lane Departure Warning" 2 "Reserved" 3 "Reserved";
VAL_ 272 LKA_RHLnWrnSta 0 "No Warning" 1 "Lane Departure Warning" 2 "Reserved" 3 "Reserved";
VAL_ 272 LKA_HndsoffSnd 0 "Off" 1 "Hands-off Sound Warning" 2 "Reserved" 3 "Reserved";
VAL_ 272 LKA_StrSnd 0 "Off" 1 "Warning" 2 "Reserved" 3 "Reserved";
VAL_ 272 LKA_SysIndReq 0 "Off" 1 "Unavailable_(Grey On)" 2 "Lane Recognized_(Green On)" 3 "Lane Departure_(Green Blink)" 4 "System Fail_(Orange On)" 5 "Not Calibrated_(Orange Blink)" 6 "Regulation_(Orange On)" 7 "Reserved";
VAL_ 272 StrTqReqVal 2046 "Reserved" 2047 "Invalid";
VAL_ 272 ActToiSta 0 "De-activate TOI" 1 "Activate TOI" 2 "Reserved" 3 "Error indicator";
VAL_ 272 ToiFltSta 0 "No Fault" 1 "Fault" 2 "Reserved" 3 "Error indicatorr";
VAL_ 272 LKA_SysWrn 0 "No Info" 1 "Reserved" 2 "Reserved" 3 "Reserved" 4 "Hands-Off Warning 1" 5 "Hands-Off Warning 2" 6 "Hands-Off Warning 3" 7 "Reserved" 8 "Reserved" 9 "System Automatic off" 10 "Reserved" 11 "Reserved" 12 "Reserved" 13 "Reserved" 14 "Reserved" 15 "System Fail";
VAL_ 272 LKA_UsmMod 0 "NONE" 1 "LKA 1 mode" 2 "Reserved" 3 "LDW";
VAL_ 272 ADAS_ACIAnglTqRedcGainVal 0 "0x0x00~0xFA:Real Values" 250 "0x0x00~0xFA:Real Values" 251 "RESERVED" 252 "RESERVED" 253 "RESERVED" 254 "RESERVED" 255 "RESERVED";
VAL_ 282 HBA_SysOptSta 0 "None HBA Option (Default)" 1 "HBA Option" 2 "Reserved" 3 "Error indicator";
VAL_ 282 HBA_SysSta 0 "HBA Disable" 1 "HBA Enable & High Beam Off" 2 "HBA Enable & High Beam On" 3 "Reserved" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "System Fail";
VAL_ 282 HBA_IndLmpReq 0 "HBA Indicator Lamp Off" 1 "HBA Indicator Lamp On" 2 "Reserved" 3 "Error indicator";
@@ -833,8 +1021,20 @@ VAL_ 282 DAW_WrnMsgSta 0 "No Warning" 1 "Rest Recommend Warning" 2 "Hands-Off TM
VAL_ 282 DAW_TimeRstReq 0 "No signal" 1 "Time reset" 2 "Reserved" 3 "Error indicator";
VAL_ 282 DAW_SnstvtyModRetVal 0 "Default" 1 "Late" 2 "Normal" 3 "Reserved" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Invalid";
VAL_ 282 FR_CMR_SCCEquipSta 0 "Not Applied" 1 "Applied" 2 "Not used" 3 "Error Indicator";
VAL_ 298 LKA_MODE 1 "warning only" 2 "assist" 6 "off";
VAL_ 298 LKA_ICON 0 "hidden" 1 "grey" 2 "green" 3 "flashing green";
VAL_ 298 LKA_OptUsmSta 0 "None LKA/LDW Option (Default)" 1 "LDW" 2 "LKA" 3 "Reserved" 4 "LDW Only (None LKA)" 5 "LDW only OFF (None LKA)" 6 "LDW/LKA OFF" 7 "Invalid";
VAL_ 298 LKA_RcgSta 0 "Not Recognized" 1 "Left Lane Recognition" 2 "Right Lane Recognition" 3 "Full Lane Recognition" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Reserved";
VAL_ 298 LKA_LHLnWrnSta 0 "No Warning" 1 "Lane Departure Warning" 2 "Reserved" 3 "Reserved";
VAL_ 298 LKA_RHLnWrnSta 0 "No Warning" 1 "Lane Departure Warning" 2 "Reserved" 3 "Reserved";
VAL_ 298 LKA_HndsoffSnd 0 "Off" 1 "Hands-off Sound Warning" 2 "Reserved" 3 "Reserved";
VAL_ 298 LKA_StrSnd 0 "Off" 1 "Warning" 2 "Reserved" 3 "Reserved";
VAL_ 298 LKA_SysIndReq 0 "Off" 1 "Unavailable_(Grey On)" 2 "Lane Recognized_(Green On)" 3 "Lane Departure_(Green Blink)" 4 "System Fail_(Orange On)" 5 "Not Calibrated_(Orange Blink)" 6 "Regulation_(Orange On)" 7 "Reserved";
VAL_ 298 StrTqReqVal 2046 "Reserved" 2047 "Invalid";
VAL_ 298 ActToiSta 0 "De-activate TOI" 1 "Activate TOI" 2 "Reserved" 3 "Error indicator";
VAL_ 298 ToiFltSta 0 "No Fault" 1 "Fault" 2 "Reserved" 3 "Error indicatorr";
VAL_ 298 LKA_SysWrn 0 "No Info" 1 "Reserved" 2 "Reserved" 3 "Reserved" 4 "Hands-Off Warning 1" 5 "Hands-Off Warning 2" 6 "Hands-Off Warning 3" 7 "Reserved" 8 "Reserved" 9 "System Automatic off" 10 "Reserved" 11 "Reserved" 12 "Reserved" 13 "Reserved" 14 "Reserved" 15 "System Fail";
VAL_ 298 FCA_LS_WrnSta 3 "ELK Steering to the right";
VAL_ 298 LKA_UsmMod 0 "NONE" 1 "LKA 1 mode" 2 "Reserved" 3 "LDW";
VAL_ 298 ELK_SymbDisp 3 "Evasive Action Taking Place";
VAL_ 304 PARK_BUTTON 1 "Pressed" 2 "Not Pressed";
VAL_ 304 KNOB_POSITION 1 "R" 2 "N (on R side)" 3 "Centered" 4 "N (on D side)" 5 "D";
VAL_ 304 GEAR 1 "P" 2 "R" 3 "N" 4 "D";

View File

@@ -1708,7 +1708,7 @@ BO_ 786 TSK_03: 8 Motor_EDC17_D4
BO_ 270 TSK_04: 8 Motor_EDC17_D4
SG_ TSK_04_CHK : 0|8@1+ (1,0) [0|255] "" Getriebe_AL551_951_D4_C7,Getriebe_DL501_C7,Getriebe_VL381_C7
SG_ TSK_04_BZ : 8|4@1+ (1,0) [0|15] "" Getriebe_AL551_951_D4_C7,Getriebe_DL501_C7,Getriebe_VL381_C7
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" Getriebe_AL551_951_D4_C7,Getriebe_DL501_C7,Getriebe_VL381_C7
SG_ TSK_zul_Regelabw : 12|6@1+ (0.024,0) [0.000|1.512] "Unit_MeterPerSeconSquar" Getriebe_AL551_951_D4_C7,Getriebe_DL501_C7,Getriebe_VL381_C7
SG_ TSK_ax_Getriebe : 18|9@1+ (0.024,-2.016) [-2.016|10.224] "Unit_MeterPerSeconSquar" Getriebe_AL551_951_D4_C7,Getriebe_DL501_C7,Getriebe_VL381_C7
SG_ TSK_Wunsch_Uebersetz : 27|10@1+ (0.0245,0) [0.0245|25.0635] "" Getriebe_AL551_951_D4_C7,Getriebe_DL501_C7,Getriebe_VL381_C7
@@ -1758,6 +1758,13 @@ BO_ 1716 VIN_01: 8 Gateway_D4C7
BO_ 1414 Waehlhebel_02: 8 Getriebe_AL551_951_D4_C7
SG_ WH_KD_Fehler : 63|1@1+ (1.0,0.0) [0.0|1] "" Gateway_D4C7
BO_ 1318 BCM: 8 XXX
SG_ INVERTED_BLINKER_ACTIVE : 4|1@0+ (1,0) [0|1] "" XXX
SG_ TURNSTALK_LEFT : 26|1@0+ (1,0) [0|1] "" XXX
SG_ TURNSTALK_RIGHT : 27|1@0+ (1,0) [0|1] "" XXX
SG_ BLINKER_LEFT : 34|1@0+ (1,0) [0|1] "" XXX
SG_ BLINKER_RIGHT : 35|1@0+ (1,0) [0|1] "" XXX
SG_ UNKNOWN_DRIVER_DOOR_RELATED : 43|1@0+ (1,0) [0|1] "" XXX
VAL_ 159 EPS_HCA_Status 0 "disabled" 1 "initializing" 2 "fault" 3 "ready" 4 "rejected" 5 "active" ;
VAL_ 269 ACC_Freigabe_Momentenanf 0 "Momanf_nicht_freigegeben" 1 "Momanf_freigegeben" ;

View File

@@ -5,8 +5,6 @@ static const unsigned char dlc_to_len[] = {0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 1
#define CANPACKET_HEAD_SIZE 6U // non-data portion of CANPacket_t
#define CANPACKET_DATA_SIZE_MAX 64U
// bump this when changing the CAN packet
#define CAN_PACKET_VERSION 4
typedef struct {
unsigned char fd : 1;
unsigned char bus : 3;

View File

@@ -30,6 +30,7 @@
#define SAFETY_FAW 26U
#define SAFETY_BODY 27U
#define SAFETY_HYUNDAI_CANFD 28U
#define SAFETY_CHRYSLER_CUSW 30U
#define SAFETY_PSA 31U
#define SAFETY_RIVIAN 33U
#define SAFETY_VOLKSWAGEN_MEB 34U
@@ -324,6 +325,7 @@ int set_safety_hooks(uint16_t mode, uint16_t param);
extern const safety_hooks body_hooks;
extern const safety_hooks chrysler_hooks;
extern const safety_hooks chrysler_cusw_hooks;
extern const safety_hooks elm327_hooks;
extern const safety_hooks nooutput_hooks;
extern const safety_hooks alloutput_hooks;

View File

@@ -1,6 +1,7 @@
#pragma once
#include "opendbc/safety/declarations.h"
#include "opendbc/safety/modes/chrysler_common.h"
// Chrysler Pacifica/Jeep addresses
#define CHRYSLER_EPS_2 0x220 // EPS driver input torque
@@ -51,43 +52,6 @@ static ChryslerPlatform chrysler_platform;
#define CHRYSLER_ADDR(name) ((uint32_t)((chrysler_platform == CHRYSLER_RAM_DT) ? CHRYSLER_RAM_DT_##name : \
((chrysler_platform == CHRYSLER_RAM_HD) ? CHRYSLER_RAM_HD_##name : CHRYSLER_##name)))
static uint32_t chrysler_get_checksum(const CANPacket_t *msg) {
int checksum_byte = GET_LEN(msg) - 1U;
return (uint8_t)(msg->data[checksum_byte]);
}
static uint32_t chrysler_compute_checksum(const CANPacket_t *msg) {
// TODO: clean this up
// http://illmatics.com/Remote%20Car%20Hacking.pdf
uint8_t checksum = 0xFFU;
int len = GET_LEN(msg);
for (int j = 0; j < (len - 1); j++) {
uint8_t shift = 0x80U;
uint8_t curr = (uint8_t)msg->data[j];
for (int i=0; i<8; i++) {
uint8_t bit_sum = curr & shift;
uint8_t temp_chk = checksum & 0x80U;
if (bit_sum != 0U) {
bit_sum = 0x1C;
if (temp_chk != 0U) {
bit_sum = 1;
}
checksum = checksum << 1;
temp_chk = checksum | 1U;
bit_sum ^= temp_chk;
} else {
if (temp_chk != 0U) {
bit_sum = 0x1D;
}
checksum = checksum << 1;
bit_sum ^= checksum;
}
checksum = bit_sum;
shift = shift >> 1;
}
}
return (uint8_t)(~checksum);
}
static uint8_t chrysler_get_counter(const CANPacket_t *msg) {
return (uint8_t)(msg->data[6] >> 4);

View File

@@ -0,0 +1,39 @@
#pragma once
static uint32_t chrysler_get_checksum(const CANPacket_t *msg) {
int checksum_byte = GET_LEN(msg) - 1U;
return (uint8_t)(msg->data[checksum_byte]);
}
static uint32_t chrysler_compute_checksum(const CANPacket_t *msg) {
// TODO: clean this up
// http://illmatics.com/Remote%20Car%20Hacking.pdf
uint8_t checksum = 0xFFU;
int len = GET_LEN(msg);
for (int j = 0; j < (len - 1); j++) {
uint8_t shift = 0x80U;
uint8_t curr = (uint8_t)msg->data[j];
for (int i=0; i<8; i++) {
uint8_t bit_sum = curr & shift;
uint8_t temp_chk = checksum & 0x80U;
if (bit_sum != 0U) {
bit_sum = 0x1C;
if (temp_chk != 0U) {
bit_sum = 1;
}
checksum = checksum << 1;
temp_chk = checksum | 1U;
bit_sum ^= temp_chk;
} else {
if (temp_chk != 0U) {
bit_sum = 0x1D;
}
checksum = checksum << 1;
bit_sum ^= checksum;
}
checksum = bit_sum;
shift = shift >> 1;
}
}
return (uint8_t)(~checksum);
}

View File

@@ -0,0 +1,107 @@
#include "opendbc/safety/modes/chrysler_common.h"
static safety_config chrysler_cusw_init(uint16_t param) {
SAFETY_UNUSED(param);
static const CanMsg CHRYSLER_CUSW_TX_MSGS[] = {
{0x1F6U, 0, 4, .check_relay = true},
{0x5DCU, 0, 4, .check_relay = true},
{0x2FAU, 0, 3, .check_relay = false},
};
static RxCheck chrysler_cusw_rx_checks[] = {
{.msg = {{0x1E4U, 0, 8, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
{.msg = {{0x1E8U, 0, 5, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
{.msg = {{0x1ECU, 0, 8, 100U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
{.msg = {{0x1FEU, 0, 5, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
{.msg = {{0x2ECU, 0, 8, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
};
return BUILD_SAFETY_CFG(chrysler_cusw_rx_checks, CHRYSLER_CUSW_TX_MSGS);
}
static void chrysler_cusw_rx_hook(const CANPacket_t *msg) {
if (msg->bus == 0U) {
if (msg->addr == 0x1ECU) {
// Signal: EPS_STATUS.TORQUE_MOTOR
int torque_meas_new = ((msg->data[3] & 0xFU) << 8) + msg->data[4] - 2048U;
update_sample(&torque_meas, torque_meas_new);
}
if (msg->addr == 0x2ECU) {
// Signal: ACC_CONTROL.ACC_ACTIVE
bool cruise_engaged = GET_BIT(msg, 7U);
pcm_cruise_check(cruise_engaged);
}
if (msg->addr == 0x1E4U) {
// Signal: BRAKE_1.VEHICLE_SPEED
vehicle_moving = (((msg->data[4] & 0x7U) << 8) + msg->data[5]) != 0U;
}
if (msg->addr == 0x1FEU) {
// Signal: ACCEL_GAS.GAS_HUMAN
gas_pressed = msg->data[1] != 0U;
}
if (msg->addr == 0x1E8U) {
// Signal: BRAKE_3.DRIVER_BRAKE_SWITCH
brake_pressed = GET_BIT(msg, 18U);
}
}
}
static bool chrysler_cusw_tx_hook(const CANPacket_t *msg) {
const TorqueSteeringLimits CHRYSLER_CUSW_STEERING_LIMITS = {
.max_torque = 250, // TODO: Find the actual cap, think we're faulting before 261
.max_rt_delta = 150,
.max_rate_up = 4,
.max_rate_down = 4,
.max_torque_error = 80,
.type = TorqueMotorLimited,
};
bool tx = true;
if (msg->addr == 0x1F6U) {
// Signal: LKAS_COMMAND.STEERING_TORQUE
int desired_torque = ((msg->data[0]) << 3) | ((msg->data[1] & 0xE0U) >> 5);
desired_torque -= 1024;
// Signal: LKAS_COMMAND.LKAS_CONTROL_BIT
const bool steer_req = GET_BIT(msg, 12U);
if (steer_torque_cmd_checks(desired_torque, steer_req, CHRYSLER_CUSW_STEERING_LIMITS)) {
tx = false;
// FIXME: too many problems here right now, hotwire things while investigating
// tx = true;
}
}
if (msg->addr == 0x2FAU) {
// Signal: CRUISE_BUTTONS.ACC_Cancel
// Signal: CRUISE_BUTTONS.ACC_Resume
const bool is_cancel = GET_BIT(msg, 0U);
const bool is_resume = GET_BIT(msg, 4U);
const bool allowed = is_cancel || (is_resume && controls_allowed);
if (!allowed) {
tx = false;
}
}
return tx;
}
static uint8_t chrysler_cusw_get_counter(const CANPacket_t *msg) {
int counter_byte = GET_LEN(msg) - 2U;
return (uint8_t)(msg->data[counter_byte] & 0xFU);
}
const safety_hooks chrysler_cusw_hooks = {
.init = chrysler_cusw_init,
.rx = chrysler_cusw_rx_hook,
.tx = chrysler_cusw_tx_hook,
.get_counter = chrysler_cusw_get_counter,
.get_checksum = chrysler_get_checksum,
.compute_checksum = chrysler_compute_checksum,
};

View File

@@ -419,7 +419,7 @@ static safety_config honda_bosch_init(uint16_t param) {
{0x33D, 0, 5, .check_relay = true}, {0x33D, 0, 8, .check_relay = true}, {0x33DA, 0, 5, .check_relay = true}, {0x33DB, 0, 8, .check_relay = true}}; // Bosch
static CanMsg HONDA_BOSCH_LONG_TX_MSGS[] = {{0xE4, 1, 5, .check_relay = true}, {0x1DF, 1, 8, .check_relay = true}, {0x1EF, 1, 8, .check_relay = false},
{0x1FA, 1, 8, .check_relay = false}, {0x30C, 1, 8, .check_relay = false}, {0x33D, 1, 5, .check_relay = true},
{0x1FA, 1, 8, .check_relay = false}, {0x30C, 1, 8, .check_relay = false}, {0x33D, 1, 5, .check_relay = true}, {0x33D, 1, 8, .check_relay = true},
{0x33DA, 1, 5, .check_relay = true}, {0x33DB, 1, 8, .check_relay = true}, {0x39F, 1, 8, .check_relay = false},
{0x18DAB0F1, 1, 8, .check_relay = false}}; // Bosch w/ gas and brakes

View File

@@ -36,8 +36,7 @@ bool volkswagen_brake_pressure_detected = false;
#define MSG_ESP_03 0x103U // RX from ABS, for wheel speeds
#define MSG_LS_01 0x10BU // TX by OP, ACC control buttons for cancel/resume
#define MSG_MOTOR_03 0x105U // RX from ECU, for driver throttle input and brake switch status
#define MSG_TSK_02 0x10CU // RX from ECU, for ACC status from drivetrain coordinator
#define MSG_ACC_05 0x10DU // RX from radar, for ACC status
#define MSG_TSK_04 0x10EU // RX from ECU, for ACC status from drivetrain coordinator
static void volkswagen_common_init(void) {
volkswagen_set_button_prev = false;

View File

@@ -14,7 +14,7 @@ static safety_config volkswagen_mlb_init(uint16_t param) {
{.msg = {{MSG_ESP_03, 0, 8, 50U, .ignore_checksum = true, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
{.msg = {{MSG_LH_EPS_03, 0, 8, 100U, .ignore_checksum = true, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
{.msg = {{MSG_ESP_05, 0, 8, 50U, .ignore_checksum = true, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
{.msg = {{MSG_ACC_05, 2, 8, 50U, .ignore_checksum = true, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
{.msg = {{MSG_TSK_04, 1, 8, 50U, .ignore_checksum = true, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
{.msg = {{MSG_MOTOR_03, 0, 8, 100U, .ignore_checksum = true, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
{.msg = {{MSG_LS_01, 0, 4, 10U, .ignore_checksum = true, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
};
@@ -66,21 +66,14 @@ static void volkswagen_mlb_rx_hook(const CANPacket_t *msg) {
}
if (msg->bus == 2U) {
// TODO: See if there's a bus-agnostic TSK message we can use instead
if (msg->addr == MSG_ACC_05) {
if (msg->bus == 1U) {
if (msg->addr == MSG_TSK_04) {
// When using stock ACC, enter controls on rising edge of stock ACC engage, exit on disengage
// Always exit controls on main switch off
// Signal: ACC_05.ACC_Status_ACC
int acc_status = (msg->data[7] & 0xEU) >> 1;
bool cruise_engaged = (acc_status == 3) || (acc_status == 4) || (acc_status == 5);
acc_main_on = cruise_engaged || (acc_status == 2);
// Signal: TSK_04.TSK_Status_GRA_ACC_02
int acc_status = (msg->data[7] & 0xC0U) >> 6;
bool cruise_engaged = (acc_status == 1) || (acc_status == 2);
pcm_cruise_check(cruise_engaged);
if (!acc_main_on) {
controls_allowed = false;
}
}
}
}

View File

@@ -15,6 +15,7 @@
#include "opendbc/safety/modes/ford.h"
#include "opendbc/safety/modes/hyundai.h"
#include "opendbc/safety/modes/chrysler.h"
#include "opendbc/safety/modes/chrysler_cusw.h"
#include "opendbc/safety/modes/rivian.h"
#include "opendbc/safety/modes/subaru.h"
#include "opendbc/safety/modes/subaru_preglobal.h"
@@ -409,6 +410,7 @@ int set_safety_hooks(uint16_t mode, uint16_t param) {
{SAFETY_TESLA, &tesla_hooks},
{SAFETY_HYUNDAI_CANFD, &hyundai_canfd_hooks},
#ifdef ALLOW_DEBUG
{SAFETY_CHRYSLER_CUSW, &chrysler_cusw_hooks},
{SAFETY_PSA, &psa_hooks},
{SAFETY_SUBARU_PREGLOBAL, &subaru_preglobal_hooks},
{SAFETY_VOLKSWAGEN_MLB, &volkswagen_mlb_hooks},

View File

@@ -92,12 +92,25 @@ class SafetyTestBase(unittest.TestCase):
def _tx(self, msg):
return self.safety.safety_tx_hook(msg)
@staticmethod
def _boundary_values(boundaries, min_val, max_val, step=1, width=5, sparse_count=100):
"""Generate test values dense around boundaries and sparse across the full range."""
values = set()
for b in boundaries:
for offset in range(-width, width + 1):
v = round(b + offset * step, 2)
if min_val <= v < max_val:
values.add(v)
sparse_step = max(step, (max_val - min_val) / sparse_count)
for v in np.arange(min_val, max_val, sparse_step):
values.add(round(v, 2))
return sorted(values)
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):
"""
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.
Message is also only allowed to be sent when controls_allowed is true, unless the value is equal to inactive_value.
Message is never allowed if msg_allowed is false, for example when stock longitudinal is enabled and you are sending acceleration requests.
additional_setup is used for extra setup before each _tx, ex: for setting the previous torque for rate limits
@@ -107,10 +120,11 @@ class SafetyTestBase(unittest.TestCase):
self.assertGreater(max_possible_value, max_allowed_value)
self.assertLessEqual(min_possible_value, min_allowed_value)
test_values = self._boundary_values([min_allowed_value, max_allowed_value, 0, inactive_value],
min_possible_value, max_possible_value, test_delta)
for controls_allowed in [False, True]:
# enforce we don't skip over 0 or inactive
for v in np.concatenate((np.arange(min_possible_value, max_possible_value, test_delta), np.array([0, inactive_value]))):
v = round(v, 2) # floats might not hit exact boundary conditions without rounding
for v in test_values:
self.safety.set_controls_allowed(controls_allowed)
if additional_setup is not None:
additional_setup(v)
@@ -450,7 +464,7 @@ class DriverTorqueSteeringSafetyTest(TorqueSteeringSafetyTestBase, abc.ABC):
# Cannot stay at MAX_TORQUE if above DRIVER_TORQUE_ALLOWANCE
for sign in [-1, 1]:
for driver_torque in np.arange(0, self.DRIVER_TORQUE_ALLOWANCE * 2, 1):
for driver_torque in self._boundary_values([self.DRIVER_TORQUE_ALLOWANCE], 0, self.DRIVER_TORQUE_ALLOWANCE * 2):
self._reset_torque_driver_measurement(-driver_torque * sign)
self._set_prev_torque(max_torque * sign)
should_tx = abs(driver_torque) <= self.DRIVER_TORQUE_ALLOWANCE

View File

@@ -1,5 +0,0 @@
*.pdf
*.txt
.output.log
new_table
cppcheck/

View File

@@ -625,6 +625,7 @@ def main():
("opendbc/safety/sunnypilot/mads.h", 149, "boundary"),
("opendbc/safety/sunnypilot/mads.h", 150, "boundary"),
("opendbc/safety/sunnypilot/mads.h", 151, "boundary"),
("opendbc/safety/longitudinal.h", 38, "remove_negation"),
}
survivors = [r for r in survivors if (str(r.site.origin_file.relative_to(ROOT)), r.site.origin_line, r.site.mutator) not in known_survivors]

View File

@@ -10,7 +10,7 @@ source ../../../setup.sh
rm -f ./libsafety/*.gcda
# run safety tests and generate coverage data
python -m unittest discover -s . -p 'test_*.py' -t ../../../
python -m unittest discover -s .
# NOTE: we accept that these tools will have slight differences,
# and in return, we get to use the stock toolchain instead of

View File

@@ -0,0 +1,75 @@
#!/usr/bin/env python3
import unittest
from opendbc.car.structs import CarParams
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.common import CANPackerSafety
class TestChryslerCuswSafety(common.CarSafetyTest, common.MotorTorqueSteeringSafetyTest):
TX_MSGS = [[0x1F6, 0], [0x2FA, 0], [0x5DC, 0]]
STANDSTILL_THRESHOLD = 0
RELAY_MALFUNCTION_ADDRS = {0: (0x1F6, 0x5DC)}
FWD_BLACKLISTED_ADDRS = {2: [0x1F6, 0x5DC]}
MAX_RATE_UP = 4
MAX_RATE_DOWN = 4
MAX_TORQUE_LOOKUP = [0], [250]
MAX_RT_DELTA = 150
MAX_TORQUE_ERROR = 80
def setUp(self):
self.packer = CANPackerSafety("chrysler_cusw")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.chryslerCusw, 0)
self.safety.init_tests()
def _button_msg(self, cancel=False, resume=False):
values = {"ACC_Cancel": cancel, "ACC_Resume": resume}
return self.packer.make_can_msg_safety("CRUISE_BUTTONS", 0, values)
def _pcm_status_msg(self, enable):
values = {"ACC_ACTIVE": 1 if enable else 0}
return self.packer.make_can_msg_safety("ACC_CONTROL", 0, values)
def _speed_msg(self, speed):
values = {"VEHICLE_SPEED": speed}
return self.packer.make_can_msg_safety("BRAKE_1", 0, values)
def _user_gas_msg(self, gas):
values = {"GAS_HUMAN": gas}
return self.packer.make_can_msg_safety("ACCEL_GAS", 0, values)
def _user_brake_msg(self, brake):
values = {"DRIVER_BRAKE_SWITCH": 1 if brake else 0}
return self.packer.make_can_msg_safety("BRAKE_3", 0, values)
def _torque_meas_msg(self, torque):
values = {"TORQUE_MOTOR": torque}
return self.packer.make_can_msg_safety("EPS_STATUS", 0, values)
def _torque_cmd_msg(self, torque, steer_req=1):
values = {"STEERING_TORQUE": torque, "LKAS_CONTROL_BIT": steer_req}
return self.packer.make_can_msg_safety("LKAS_COMMAND", 0, values)
def test_buttons(self):
for controls_allowed in (True, False):
self.safety.set_controls_allowed(controls_allowed)
# resume only while controls allowed
self.assertEqual(controls_allowed, self._tx(self._button_msg(resume=True)))
# can always cancel
self.assertTrue(self._tx(self._button_msg(cancel=True)))
def test_rx_hook(self):
for count in range(20):
self.assertTrue(self._rx(self._speed_msg(0)), f"{count=}")
self.assertTrue(self._rx(self._user_brake_msg(False)), f"{count=}")
self.assertTrue(self._rx(self._torque_meas_msg(0)), f"{count=}")
self.assertTrue(self._rx(self._user_gas_msg(0)), f"{count=}")
self.assertTrue(self._rx(self._pcm_status_msg(False)), f"{count=}")
if __name__ == "__main__":
unittest.main()

View File

@@ -241,16 +241,22 @@ class TestFordSafetyBase(common.CarSafetyTest):
def test_max_lateral_acceleration(self):
# Ford CAN FD can achieve a higher max lateral acceleration than CAN so we limit curvature based on speed
step = 1 / self.DEG_TO_CAN
for speed in np.arange(0, 40, 0.5):
# Clip so we test curvature limiting at low speed due to low max curvature
_, curvature_accel_limit_upper = self.get_canfd_curvature_limits(speed)
curvature_accel_limit_upper = np.clip(curvature_accel_limit_upper, -self.MAX_CURVATURE, self.MAX_CURVATURE)
# Test boundary curvature values around the limit, rounded to CAN precision
lower = curvature_accel_limit_upper * 0.8
upper = min(curvature_accel_limit_upper * 1.2, self.MAX_CURVATURE)
test_curvatures = {round(c * self.DEG_TO_CAN) / self.DEG_TO_CAN
for c in self._boundary_values([curvature_accel_limit_upper], lower, upper, step)
if 0 <= c <= self.MAX_CURVATURE}
for sign in (-1, 1):
# Test above and below the lateral by 20%, max is clipped since
# max curvature at low speed is higher than the signal max
for curvature in np.arange(curvature_accel_limit_upper * 0.8, min(curvature_accel_limit_upper * 1.2, self.MAX_CURVATURE), 1 / self.DEG_TO_CAN):
curvature = sign * round(curvature * self.DEG_TO_CAN) / self.DEG_TO_CAN # fix np rounding errors
for curvature in sorted(test_curvatures):
curvature = sign * curvature
self.safety.set_controls_allowed(True)
self._set_prev_desired_angle(curvature)
self._reset_curvature_measurement(curvature, speed)
@@ -448,11 +454,12 @@ class TestFordLongitudinalSafetyBase(TestFordSafetyBase):
self.assertEqual(should_tx, self._tx(self._acc_command_msg(gas, self.INACTIVE_ACCEL, controls_allowed)))
def test_brake_safety_check(self):
brake_values = self._boundary_values([self.MIN_ACCEL, self.MAX_ACCEL, self.INACTIVE_ACCEL],
self.MIN_ACCEL - 2, self.MAX_ACCEL + 2, 0.05)
for controls_allowed in (True, False):
self.safety.set_controls_allowed(controls_allowed)
for brake_actuation in (True, False):
for brake in np.arange(self.MIN_ACCEL - 2, self.MAX_ACCEL + 2, 0.05):
brake = round(brake, 2) # floats might not hit exact boundary conditions without rounding
for brake in brake_values:
should_tx = (controls_allowed and self.MIN_ACCEL <= brake <= self.MAX_ACCEL) or brake == self.INACTIVE_ACCEL
should_tx = should_tx and (controls_allowed or not brake_actuation)
self.assertEqual(should_tx, self._tx(self._acc_command_msg(self.INACTIVE_GAS, brake, brake_actuation)))

View File

@@ -49,11 +49,11 @@ class TestHyundaiCanfdBase(HyundaiButtonBase, common.CarSafetyTest, common.Drive
BUTTONS_TX_BUS = 1
def _torque_driver_msg(self, torque):
values = {"STEERING_COL_TORQUE": torque}
values = {"MDPS_StrTqSnsrVal": torque}
return self.packer.make_can_msg_safety("MDPS", self.PT_BUS, values)
def _torque_cmd_msg(self, torque, steer_req=1):
values = {"TORQUE_REQUEST": torque, "STEER_REQ": steer_req}
values = {"StrTqReqVal": torque, "ActToiSta": steer_req}
return self.packer.make_can_msg_safety(self.STEER_MSG, self.STEER_BUS, values)
def _speed_msg(self, speed):

View File

@@ -264,28 +264,33 @@ class TestToyotaSafetyAngle(TestToyotaSafetyBase, common.AngleSteeringSafetyTest
should_tx = req == req2 and (torque_wind_down in (0, 100)) and not mismatch
self.assertEqual(should_tx, self._tx(self._lta_msg(req, req2, angle, torque_wind_down)))
# Test max EPS torque and driver override thresholds
cases = itertools.product(
(0, self.MAX_MEAS_TORQUE - 1, self.MAX_MEAS_TORQUE, self.MAX_MEAS_TORQUE + 1, self.MAX_MEAS_TORQUE * 2),
(0, self.MAX_LTA_DRIVER_TORQUE - 1, self.MAX_LTA_DRIVER_TORQUE, self.MAX_LTA_DRIVER_TORQUE + 1, self.MAX_LTA_DRIVER_TORQUE * 2)
)
for eps_torque, driver_torque in cases:
for sign in (-1, 1):
for _ in range(6):
self._rx(self._torque_meas_msg(sign * eps_torque, sign * driver_torque))
# Toyota adds 1 to EPS torque since it is rounded after EPS factor
should_tx = (eps_torque - 1) <= self.MAX_MEAS_TORQUE and driver_torque <= self.MAX_LTA_DRIVER_TORQUE
self.assertEqual(should_tx, self._tx(self._lta_msg(1, 1, angle, 100)))
self.assertTrue(self._tx(self._lta_msg(1, 1, angle, 0))) # should tx if we wind down torque
else:
# Controls not allowed
for req, req2, torque_wind_down in itertools.product([0, 1], [0, 1], [0, 50, 100]):
should_tx = not (req or req2) and torque_wind_down == 0
self.assertEqual(should_tx, self._tx(self._lta_msg(req, req2, angle, torque_wind_down)))
# Test max EPS torque and driver override thresholds (independent of angle, test a few representative angles)
for angle in (-89, 0, 89):
self.safety.set_controls_allowed(True)
self._reset_angle_measurement(angle)
self._set_prev_desired_angle(angle)
cases = itertools.product(
(0, self.MAX_MEAS_TORQUE - 1, self.MAX_MEAS_TORQUE, self.MAX_MEAS_TORQUE + 1, self.MAX_MEAS_TORQUE * 2),
(0, self.MAX_LTA_DRIVER_TORQUE - 1, self.MAX_LTA_DRIVER_TORQUE, self.MAX_LTA_DRIVER_TORQUE + 1, self.MAX_LTA_DRIVER_TORQUE * 2)
)
for eps_torque, driver_torque in cases:
for sign in (-1, 1):
for _ in range(6):
self._rx(self._torque_meas_msg(sign * eps_torque, sign * driver_torque))
# Toyota adds 1 to EPS torque since it is rounded after EPS factor
should_tx = (eps_torque - 1) <= self.MAX_MEAS_TORQUE and driver_torque <= self.MAX_LTA_DRIVER_TORQUE
self.assertEqual(should_tx, self._tx(self._lta_msg(1, 1, angle, 100)))
self.assertTrue(self._tx(self._lta_msg(1, 1, angle, 0))) # should tx if we wind down torque
def test_angle_measurements(self):
"""
* Tests angle meas quality flag dictates whether angle measurement is parsed, and if rx is valid

View File

@@ -10,7 +10,7 @@ MSG_ESP_03 = 0x103 # RX from ABS, for wheel speeds
MSG_MOTOR_03 = 0x105 # RX from ECU, for driver throttle input and driver brake input
MSG_ESP_05 = 0x106 # RX from ABS, for brake light state
MSG_LS_01 = 0x10B # TX by OP, ACC control buttons for cancel/resume
MSG_TSK_02 = 0x10C # RX from ECU, for ACC status from drivetrain coordinator
MSG_TSK_04 = 0x10E # RX from ECU, for ACC status from drivetrain coordinator
MSG_HCA_01 = 0x126 # TX by OP, Heading Control Assist steering torque
MSG_LDW_02 = 0x397 # TX by OP, Lane line recognition and text alerts
@@ -51,9 +51,9 @@ class TestVolkswagenMlbSafetyBase(common.CarSafetyTest, common.DriverTorqueSteer
return self._motor_03_msg(gas_signal=gas)
# ACC engagement status
def _tsk_status_msg(self, enable, main_switch=True):
values = {"ACC_Status_ACC": 1 if not main_switch else 3 if enable else 2}
return self.packer.make_can_msg_safety("ACC_05", 2, values)
def _tsk_status_msg(self, enable):
values = {"TSK_Status_GRA_ACC_02": 1 if enable else 0}
return self.packer.make_can_msg_safety("TSK_04", 1, values)
def _pcm_status_msg(self, enable):
return self._tsk_status_msg(enable)
@@ -131,7 +131,7 @@ class TestVolkswagenMlbStockSafety(TestVolkswagenMlbSafetyBase):
def test_cancel_button(self):
# Disable on rising edge of cancel button
self._rx(self._tsk_status_msg(False, main_switch=True))
self._rx(self._tsk_status_msg(False))
self.safety.set_controls_allowed(1)
self._rx(self._ls_01_msg(cancel=True, bus=0))
self.assertFalse(self.safety.get_controls_allowed(), "controls allowed after cancel")

View File

@@ -4259,4 +4259,4 @@
],
"package": "Adaptive Cruise Control (ACC) & Lane Assist"
}
}
}

View File

@@ -4,6 +4,8 @@ Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
This file is part of sunnypilot and is licensed under the MIT License.
See the LICENSE.md file in the root directory for more details.
"""
import unittest
from opendbc.testing import parameterized
from opendbc.car import gen_empty_fingerprint
@@ -14,7 +16,7 @@ from opendbc.car.honda.values import CAR
CarFw = CarParams.CarFw
class TestHondaEpsMod:
class TestHondaEpsMod(unittest.TestCase):
@parameterized("car_name, fw", [(CAR.HONDA_CIVIC, b'39990-TBA,A030\x00\x00'), (CAR.HONDA_CIVIC, b'39990-TBA-A030\x00\x00'),
(CAR.HONDA_CLARITY, b'39990-TRW-A020\x00\x00'), (CAR.HONDA_CLARITY, b'39990,TRW,A020\x00\x00')])
@@ -26,4 +28,4 @@ class TestHondaEpsMod:
CP = CarInterface.get_params(car_name, fingerprint, car_fw, False, False, False)
_ = CarInterface.get_params_sp(CP, car_name, fingerprint, car_fw, False, False, False)
assert not CP.dashcamOnly
self.assertFalse(CP.dashcamOnly)

View File

@@ -1,3 +1,4 @@
import unittest
from enum import IntFlag
from opendbc.sunnypilot.car.hyundai.lead_data_ext import LeadDataCarController, CanLeadData, CanFdLeadData
@@ -20,41 +21,41 @@ def make_carcontrolsp(leadDistance=10.0, leadRelSpeed=0.0, leadVisible=True):
return c
class TestLeadDataCarController:
class TestLeadDataCarController(unittest.TestCase):
def test_update_object_gap(self):
ctrl = LeadDataCarController(make_carparams())
# Initial value should be 0
assert ctrl.object_gap == 0
self.assertEqual(ctrl.object_gap, 0)
# Set to 15 (should become 2 after hysteresis)
for _ in range(ctrl.LEAD_HYSTERESIS_FRAMES):
ctrl._update_object_gap(15)
assert ctrl.object_gap == 2
self.assertEqual(ctrl.object_gap, 2)
# Set to 22 (should become 3 after hysteresis)
for _ in range(ctrl.LEAD_HYSTERESIS_FRAMES):
ctrl._update_object_gap(22)
assert ctrl.object_gap == 3
self.assertEqual(ctrl.object_gap, 3)
# Set to 0 (should become 0 after hysteresis)
for _ in range(ctrl.LEAD_HYSTERESIS_FRAMES):
ctrl._update_object_gap(0)
assert ctrl.object_gap == 0
self.assertEqual(ctrl.object_gap, 0)
def test_update_lead_visible_hysteresis(self):
ctrl = LeadDataCarController(make_carparams())
ctrl._update_lead_visible_hysteresis(True)
assert isinstance(ctrl.lead_visible, bool)
self.assertIsInstance(ctrl.lead_visible, bool)
ctrl._update_lead_visible_hysteresis(False)
assert isinstance(ctrl.lead_visible, bool)
self.assertIsInstance(ctrl.lead_visible, bool)
def test_update(self):
ctrl = LeadDataCarController(make_carparams())
sp = make_carcontrolsp(leadDistance=25, leadRelSpeed=-0.5, leadVisible=True)
ctrl.update(sp)
assert ctrl.lead_distance == 25
assert ctrl.lead_rel_speed == -0.5
assert isinstance(ctrl.lead_visible, bool)
self.assertEqual(ctrl.lead_distance, 25)
self.assertEqual(ctrl.lead_rel_speed, -0.5)
self.assertIsInstance(ctrl.lead_visible, bool)
def test_lead_data_can(self):
ctrl = LeadDataCarController(make_carparams())
@@ -63,8 +64,8 @@ class TestLeadDataCarController:
ctrl.lead_rel_speed = -0.3
ctrl.lead_visible = True
ld = ctrl.lead_data
assert isinstance(ld, CanLeadData)
assert ld.object_rel_gap == 2
self.assertIsInstance(ld, CanLeadData)
self.assertEqual(ld.object_rel_gap, 2)
def test_lead_data_canfd(self):
ctrl = LeadDataCarController(make_carparams(HyundaiFlags.CANFD))
@@ -73,5 +74,5 @@ class TestLeadDataCarController:
ctrl.lead_rel_speed = 1.0
ctrl.lead_visible = True
ld = ctrl.lead_data
assert isinstance(ld, CanFdLeadData)
assert ld.object_rel_gap == 1
self.assertIsInstance(ld, CanFdLeadData)
self.assertEqual(ld.object_rel_gap, 1)

View File

@@ -1,3 +1,5 @@
import unittest
from opendbc.testing import parameterized
from opendbc.car import CanData
@@ -20,7 +22,7 @@ STANDARD_RADAR_CARS = [
]
class TestRadarInterfaceExt:
class TestRadarInterfaceExt(unittest.TestCase):
@staticmethod
def _setup_platform(car_name, additional_flags=0, escc_msg=None):
@@ -51,9 +53,9 @@ class TestRadarInterfaceExt:
# Assert that ESCC features are present
if hasattr(RD, 'use_escc'):
assert RD.use_escc, "ESCC car should have use_escc=True"
self.assertTrue(RD.use_escc, "ESCC car should have use_escc=True")
if hasattr(RD, 'use_radar_interface_ext'):
assert RD.use_radar_interface_ext, "ESCC car should use radar interface ext"
self.assertTrue(RD.use_radar_interface_ext, "ESCC car should use radar interface ext")
# Run radar interface once
RD.update([])
@@ -62,7 +64,7 @@ class TestRadarInterfaceExt:
if not CP.radarUnavailable and RD.rcp is not None:
cans = [(0, [CanData(0, b'', 0) for _ in range(5)])]
rr = RD.update(cans)
assert rr is None or len(rr.errors) > 0
self.assertTrue(rr is None or len(rr.errors) > 0)
@parameterized("car_name, flags, expected_trigger, msg_src", CAMERA_SCC_CARS)
def test_camera_scc_radar_interface(self, car_name, flags, expected_trigger, msg_src):
@@ -71,17 +73,17 @@ class TestRadarInterfaceExt:
# Assert Camera SCC flag is set appropriately
if flags & HyundaiFlags.CAMERA_SCC:
assert CP.flags & HyundaiFlags.CAMERA_SCC, "Car should have CAMERA_SCC flag"
self.assertTrue(CP.flags & HyundaiFlags.CAMERA_SCC, "Car should have CAMERA_SCC flag")
if flags & HyundaiFlags.CANFD_CAMERA_SCC:
assert CP.flags & HyundaiFlags.CANFD_CAMERA_SCC, "Car should have CANFD_CAMERA_SCC flag"
self.assertTrue(CP.flags & HyundaiFlags.CANFD_CAMERA_SCC, "Car should have CANFD_CAMERA_SCC flag")
# Check if using radar interface ext
if hasattr(RD, 'use_radar_interface_ext'):
assert RD.use_radar_interface_ext, "Camera SCC car should use radar interface ext"
self.assertTrue(RD.use_radar_interface_ext, "Camera SCC car should use radar interface ext")
# Verify trigger message
if hasattr(RD, 'trigger_msg'):
assert RD.trigger_msg == expected_trigger, f"Expected trigger_msg {expected_trigger}, got {RD.trigger_msg}"
self.assertEqual(RD.trigger_msg, expected_trigger, f"Expected trigger_msg {expected_trigger}, got {RD.trigger_msg}")
# Run radar interface once
RD.update([])
@@ -90,7 +92,7 @@ class TestRadarInterfaceExt:
if not CP.radarUnavailable and RD.rcp is not None:
cans = [(0, [CanData(0, b'', 0) for _ in range(5)])]
rr = RD.update(cans)
assert rr is None or len(rr.errors) > 0
self.assertTrue(rr is None or len(rr.errors) > 0)
@parameterized("car_name, flags", STANDARD_RADAR_CARS)
def test_standard_radar_interface(self, car_name, flags):
@@ -99,7 +101,7 @@ class TestRadarInterfaceExt:
# Standard cars should not use radar interface ext
if hasattr(RD, 'use_radar_interface_ext'):
assert not RD.use_radar_interface_ext, "Standard car should not use radar interface ext"
self.assertFalse(RD.use_radar_interface_ext, "Standard car should not use radar interface ext")
# Run radar interface once
RD.update([])
@@ -116,4 +118,4 @@ class TestRadarInterfaceExt:
if not CP.radarUnavailable and RD.rcp is not None:
cans = [(0, [CanData(0, b'', 0) for _ in range(5)])]
rr = RD.update(cans)
assert rr is None or len(rr.errors) > 0
self.assertTrue(rr is None or len(rr.errors) > 0)

View File

@@ -1,9 +1,10 @@
import json
import unittest
from opendbc.sunnypilot.car.platform_list import get_car_list, CAR_LIST_JSON_OUT
class TestCarList:
class TestCarList(unittest.TestCase):
def test_generator(self):
generated_car_list = json.dumps(get_car_list(), indent=2, ensure_ascii=False)
with open(CAR_LIST_JSON_OUT) as f:

View File

@@ -33,7 +33,7 @@ testing = [
"lefthook",
"cpplint",
"codespell",
"cppcheck @ git+https://github.com/commaai/dependencies.git@releases#subdirectory=cppcheck",
"cppcheck @ git+https://github.com/commaai/dependencies.git@release-cppcheck#subdirectory=cppcheck",
]
docs = [
"Jinja2",

316
uv.lock generated
View File

@@ -4,20 +4,20 @@ requires-python = ">=3.11, <3.13"
[[package]]
name = "attrs"
version = "25.4.0"
version = "26.1.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" }
sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" },
{ url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" },
]
[[package]]
name = "certifi"
version = "2026.1.4"
version = "2026.2.25"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" }
sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" },
{ url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" },
]
[[package]]
@@ -58,52 +58,52 @@ wheels = [
[[package]]
name = "charset-normalizer"
version = "3.4.4"
version = "3.4.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" }
sdist = { url = "https://files.pythonhosted.org/packages/7b/60/e3bec1881450851b087e301bedc3daa9377a4d45f1c26aa90b0b235e38aa/charset_normalizer-3.4.6.tar.gz", hash = "sha256:1ae6b62897110aa7c79ea2f5dd38d1abca6db663687c0b1ad9aed6f6bae3d9d6", size = 143363, upload-time = "2026-03-15T18:53:25.478Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988, upload-time = "2025-10-14T04:40:33.79Z" },
{ url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324, upload-time = "2025-10-14T04:40:34.961Z" },
{ url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742, upload-time = "2025-10-14T04:40:36.105Z" },
{ url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863, upload-time = "2025-10-14T04:40:37.188Z" },
{ url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837, upload-time = "2025-10-14T04:40:38.435Z" },
{ url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550, upload-time = "2025-10-14T04:40:40.053Z" },
{ url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162, upload-time = "2025-10-14T04:40:41.163Z" },
{ url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019, upload-time = "2025-10-14T04:40:42.276Z" },
{ url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310, upload-time = "2025-10-14T04:40:43.439Z" },
{ url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022, upload-time = "2025-10-14T04:40:44.547Z" },
{ url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383, upload-time = "2025-10-14T04:40:46.018Z" },
{ url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098, upload-time = "2025-10-14T04:40:47.081Z" },
{ url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991, upload-time = "2025-10-14T04:40:48.246Z" },
{ url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456, upload-time = "2025-10-14T04:40:49.376Z" },
{ url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978, upload-time = "2025-10-14T04:40:50.844Z" },
{ url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969, upload-time = "2025-10-14T04:40:52.272Z" },
{ url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" },
{ url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" },
{ url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" },
{ url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" },
{ url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" },
{ url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" },
{ url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" },
{ url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" },
{ url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" },
{ url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" },
{ url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" },
{ url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" },
{ url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" },
{ url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" },
{ url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" },
{ url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" },
{ url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" },
{ url = "https://files.pythonhosted.org/packages/62/28/ff6f234e628a2de61c458be2779cb182bc03f6eec12200d4a525bbfc9741/charset_normalizer-3.4.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:82060f995ab5003a2d6e0f4ad29065b7672b6593c8c63559beefe5b443242c3e", size = 293582, upload-time = "2026-03-15T18:50:25.454Z" },
{ url = "https://files.pythonhosted.org/packages/1c/b7/b1a117e5385cbdb3205f6055403c2a2a220c5ea80b8716c324eaf75c5c95/charset_normalizer-3.4.6-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60c74963d8350241a79cb8feea80e54d518f72c26db618862a8f53e5023deaf9", size = 197240, upload-time = "2026-03-15T18:50:27.196Z" },
{ url = "https://files.pythonhosted.org/packages/a1/5f/2574f0f09f3c3bc1b2f992e20bce6546cb1f17e111c5be07308dc5427956/charset_normalizer-3.4.6-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6e4333fb15c83f7d1482a76d45a0818897b3d33f00efd215528ff7c51b8e35d", size = 217363, upload-time = "2026-03-15T18:50:28.601Z" },
{ url = "https://files.pythonhosted.org/packages/4a/d1/0ae20ad77bc949ddd39b51bf383b6ca932f2916074c95cad34ae465ab71f/charset_normalizer-3.4.6-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bc72863f4d9aba2e8fd9085e63548a324ba706d2ea2c83b260da08a59b9482de", size = 212994, upload-time = "2026-03-15T18:50:30.102Z" },
{ url = "https://files.pythonhosted.org/packages/60/ac/3233d262a310c1b12633536a07cde5ddd16985e6e7e238e9f3f9423d8eb9/charset_normalizer-3.4.6-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9cc4fc6c196d6a8b76629a70ddfcd4635a6898756e2d9cac5565cf0654605d73", size = 204697, upload-time = "2026-03-15T18:50:31.654Z" },
{ url = "https://files.pythonhosted.org/packages/25/3c/8a18fc411f085b82303cfb7154eed5bd49c77035eb7608d049468b53f87c/charset_normalizer-3.4.6-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:0c173ce3a681f309f31b87125fecec7a5d1347261ea11ebbb856fa6006b23c8c", size = 191673, upload-time = "2026-03-15T18:50:33.433Z" },
{ url = "https://files.pythonhosted.org/packages/ff/a7/11cfe61d6c5c5c7438d6ba40919d0306ed83c9ab957f3d4da2277ff67836/charset_normalizer-3.4.6-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c907cdc8109f6c619e6254212e794d6548373cc40e1ec75e6e3823d9135d29cc", size = 201120, upload-time = "2026-03-15T18:50:35.105Z" },
{ url = "https://files.pythonhosted.org/packages/b5/10/cf491fa1abd47c02f69687046b896c950b92b6cd7337a27e6548adbec8e4/charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:404a1e552cf5b675a87f0651f8b79f5f1e6fd100ee88dc612f89aa16abd4486f", size = 200911, upload-time = "2026-03-15T18:50:36.819Z" },
{ url = "https://files.pythonhosted.org/packages/28/70/039796160b48b18ed466fde0af84c1b090c4e288fae26cd674ad04a2d703/charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e3c701e954abf6fc03a49f7c579cc80c2c6cc52525340ca3186c41d3f33482ef", size = 192516, upload-time = "2026-03-15T18:50:38.228Z" },
{ url = "https://files.pythonhosted.org/packages/ff/34/c56f3223393d6ff3124b9e78f7de738047c2d6bc40a4f16ac0c9d7a1cb3c/charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7a6967aaf043bceabab5412ed6bd6bd26603dae84d5cb75bf8d9a74a4959d398", size = 218795, upload-time = "2026-03-15T18:50:39.664Z" },
{ url = "https://files.pythonhosted.org/packages/e8/3b/ce2d4f86c5282191a041fdc5a4ce18f1c6bd40a5bd1f74cf8625f08d51c1/charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5feb91325bbceade6afab43eb3b508c63ee53579fe896c77137ded51c6b6958e", size = 201833, upload-time = "2026-03-15T18:50:41.552Z" },
{ url = "https://files.pythonhosted.org/packages/3b/9b/b6a9f76b0fd7c5b5ec58b228ff7e85095370282150f0bd50b3126f5506d6/charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f820f24b09e3e779fe84c3c456cb4108a7aa639b0d1f02c28046e11bfcd088ed", size = 213920, upload-time = "2026-03-15T18:50:43.33Z" },
{ url = "https://files.pythonhosted.org/packages/ae/98/7bc23513a33d8172365ed30ee3a3b3fe1ece14a395e5fc94129541fc6003/charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b35b200d6a71b9839a46b9b7fff66b6638bb52fc9658aa58796b0326595d3021", size = 206951, upload-time = "2026-03-15T18:50:44.789Z" },
{ url = "https://files.pythonhosted.org/packages/32/73/c0b86f3d1458468e11aec870e6b3feac931facbe105a894b552b0e518e79/charset_normalizer-3.4.6-cp311-cp311-win32.whl", hash = "sha256:9ca4c0b502ab399ef89248a2c84c54954f77a070f28e546a85e91da627d1301e", size = 143703, upload-time = "2026-03-15T18:50:46.103Z" },
{ url = "https://files.pythonhosted.org/packages/c6/e3/76f2facfe8eddee0bbd38d2594e709033338eae44ebf1738bcefe0a06185/charset_normalizer-3.4.6-cp311-cp311-win_amd64.whl", hash = "sha256:a9e68c9d88823b274cf1e72f28cb5dc89c990edf430b0bfd3e2fb0785bfeabf4", size = 153857, upload-time = "2026-03-15T18:50:47.563Z" },
{ url = "https://files.pythonhosted.org/packages/e2/dc/9abe19c9b27e6cd3636036b9d1b387b78c40dedbf0b47f9366737684b4b0/charset_normalizer-3.4.6-cp311-cp311-win_arm64.whl", hash = "sha256:97d0235baafca5f2b09cf332cc275f021e694e8362c6bb9c96fc9a0eb74fc316", size = 142751, upload-time = "2026-03-15T18:50:49.234Z" },
{ url = "https://files.pythonhosted.org/packages/e5/62/c0815c992c9545347aeea7859b50dc9044d147e2e7278329c6e02ac9a616/charset_normalizer-3.4.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ef7fedc7a6ecbe99969cd09632516738a97eeb8bd7258bf8a0f23114c057dab", size = 295154, upload-time = "2026-03-15T18:50:50.88Z" },
{ url = "https://files.pythonhosted.org/packages/a8/37/bdca6613c2e3c58c7421891d80cc3efa1d32e882f7c4a7ee6039c3fc951a/charset_normalizer-3.4.6-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a4ea868bc28109052790eb2b52a9ab33f3aa7adc02f96673526ff47419490e21", size = 199191, upload-time = "2026-03-15T18:50:52.658Z" },
{ url = "https://files.pythonhosted.org/packages/6c/92/9934d1bbd69f7f398b38c5dae1cbf9cc672e7c34a4adf7b17c0a9c17d15d/charset_normalizer-3.4.6-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:836ab36280f21fc1a03c99cd05c6b7af70d2697e374c7af0b61ed271401a72a2", size = 218674, upload-time = "2026-03-15T18:50:54.102Z" },
{ url = "https://files.pythonhosted.org/packages/af/90/25f6ab406659286be929fd89ab0e78e38aa183fc374e03aa3c12d730af8a/charset_normalizer-3.4.6-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f1ce721c8a7dfec21fcbdfe04e8f68174183cf4e8188e0645e92aa23985c57ff", size = 215259, upload-time = "2026-03-15T18:50:55.616Z" },
{ url = "https://files.pythonhosted.org/packages/4e/ef/79a463eb0fff7f96afa04c1d4c51f8fc85426f918db467854bfb6a569ce3/charset_normalizer-3.4.6-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e28d62a8fc7a1fa411c43bd65e346f3bce9716dc51b897fbe930c5987b402d5", size = 207276, upload-time = "2026-03-15T18:50:57.054Z" },
{ url = "https://files.pythonhosted.org/packages/f7/72/d0426afec4b71dc159fa6b4e68f868cd5a3ecd918fec5813a15d292a7d10/charset_normalizer-3.4.6-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:530d548084c4a9f7a16ed4a294d459b4f229db50df689bfe92027452452943a0", size = 195161, upload-time = "2026-03-15T18:50:58.686Z" },
{ url = "https://files.pythonhosted.org/packages/bf/18/c82b06a68bfcb6ce55e508225d210c7e6a4ea122bfc0748892f3dc4e8e11/charset_normalizer-3.4.6-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:30f445ae60aad5e1f8bdbb3108e39f6fbc09f4ea16c815c66578878325f8f15a", size = 203452, upload-time = "2026-03-15T18:51:00.196Z" },
{ url = "https://files.pythonhosted.org/packages/44/d6/0c25979b92f8adafdbb946160348d8d44aa60ce99afdc27df524379875cb/charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ac2393c73378fea4e52aa56285a3d64be50f1a12395afef9cce47772f60334c2", size = 202272, upload-time = "2026-03-15T18:51:01.703Z" },
{ url = "https://files.pythonhosted.org/packages/2e/3d/7fea3e8fe84136bebbac715dd1221cc25c173c57a699c030ab9b8900cbb7/charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:90ca27cd8da8118b18a52d5f547859cc1f8354a00cd1e8e5120df3e30d6279e5", size = 195622, upload-time = "2026-03-15T18:51:03.526Z" },
{ url = "https://files.pythonhosted.org/packages/57/8a/d6f7fd5cb96c58ef2f681424fbca01264461336d2a7fc875e4446b1f1346/charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8e5a94886bedca0f9b78fecd6afb6629142fd2605aa70a125d49f4edc6037ee6", size = 220056, upload-time = "2026-03-15T18:51:05.269Z" },
{ url = "https://files.pythonhosted.org/packages/16/50/478cdda782c8c9c3fb5da3cc72dd7f331f031e7f1363a893cdd6ca0f8de0/charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:695f5c2823691a25f17bc5d5ffe79fa90972cc34b002ac6c843bb8a1720e950d", size = 203751, upload-time = "2026-03-15T18:51:06.858Z" },
{ url = "https://files.pythonhosted.org/packages/75/fc/cc2fcac943939c8e4d8791abfa139f685e5150cae9f94b60f12520feaa9b/charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:231d4da14bcd9301310faf492051bee27df11f2bc7549bc0bb41fef11b82daa2", size = 216563, upload-time = "2026-03-15T18:51:08.564Z" },
{ url = "https://files.pythonhosted.org/packages/a8/b7/a4add1d9a5f68f3d037261aecca83abdb0ab15960a3591d340e829b37298/charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a056d1ad2633548ca18ffa2f85c202cfb48b68615129143915b8dc72a806a923", size = 209265, upload-time = "2026-03-15T18:51:10.312Z" },
{ url = "https://files.pythonhosted.org/packages/6c/18/c094561b5d64a24277707698e54b7f67bd17a4f857bbfbb1072bba07c8bf/charset_normalizer-3.4.6-cp312-cp312-win32.whl", hash = "sha256:c2274ca724536f173122f36c98ce188fd24ce3dad886ec2b7af859518ce008a4", size = 144229, upload-time = "2026-03-15T18:51:11.694Z" },
{ url = "https://files.pythonhosted.org/packages/ab/20/0567efb3a8fd481b8f34f739ebddc098ed062a59fed41a8d193a61939e8f/charset_normalizer-3.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:c8ae56368f8cc97c7e40a7ee18e1cedaf8e780cd8bc5ed5ac8b81f238614facb", size = 154277, upload-time = "2026-03-15T18:51:13.004Z" },
{ url = "https://files.pythonhosted.org/packages/15/57/28d79b44b51933119e21f65479d0864a8d5893e494cf5daab15df0247c17/charset_normalizer-3.4.6-cp312-cp312-win_arm64.whl", hash = "sha256:899d28f422116b08be5118ef350c292b36fc15ec2daeb9ea987c89281c7bb5c4", size = 142817, upload-time = "2026-03-15T18:51:14.408Z" },
{ url = "https://files.pythonhosted.org/packages/2a/68/687187c7e26cb24ccbd88e5069f5ef00eba804d36dde11d99aad0838ab45/charset_normalizer-3.4.6-py3-none-any.whl", hash = "sha256:947cf925bc916d90adba35a64c82aace04fa39b46b52d4630ece166655905a69", size = 61455, upload-time = "2026-03-15T18:53:23.833Z" },
]
[[package]]
name = "codespell"
version = "2.4.1"
version = "2.4.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/15/e0/709453393c0ea77d007d907dd436b3ee262e28b30995ea1aa36c6ffbccaf/codespell-2.4.1.tar.gz", hash = "sha256:299fcdcb09d23e81e35a671bbe746d5ad7e8385972e65dbb833a2eaac33c01e5", size = 344740, upload-time = "2025-01-28T18:52:39.411Z" }
sdist = { url = "https://files.pythonhosted.org/packages/2d/9d/1d0903dff693160f893ca6abcabad545088e7a2ee0a6deae7c24e958be69/codespell-2.4.2.tar.gz", hash = "sha256:3c33be9ae34543807f088aeb4832dfad8cb2dae38da61cac0a7045dd376cfdf3", size = 352058, upload-time = "2026-03-05T18:10:42.936Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/20/01/b394922252051e97aab231d416c86da3d8a6d781eeadcdca1082867de64e/codespell-2.4.1-py3-none-any.whl", hash = "sha256:3dadafa67df7e4a3dbf51e0d7315061b80d265f9552ebd699b3dd6834b47e425", size = 344501, upload-time = "2025-01-28T18:52:37.057Z" },
{ url = "https://files.pythonhosted.org/packages/42/a1/52fa05533e95fe45bcc09bcf8a503874b1c08f221a4e35608017e0938f55/codespell-2.4.2-py3-none-any.whl", hash = "sha256:97e0c1060cf46bd1d5db89a936c98db8c2b804e1fdd4b5c645e82a1ec6b1f886", size = 353715, upload-time = "2026-03-05T18:10:41.398Z" },
]
[[package]]
@@ -143,47 +143,47 @@ requires-dist = [{ name = "requests" }]
[[package]]
name = "coverage"
version = "7.13.4"
version = "7.13.5"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/24/56/95b7e30fa389756cb56630faa728da46a27b8c6eb46f9d557c68fff12b65/coverage-7.13.4.tar.gz", hash = "sha256:e5c8f6ed1e61a8b2dcdf31eb0b9bbf0130750ca79c1c49eb898e2ad86f5ccc91", size = 827239, upload-time = "2026-02-09T12:59:03.86Z" }
sdist = { url = "https://files.pythonhosted.org/packages/9d/e0/70553e3000e345daff267cec284ce4cbf3fc141b6da229ac52775b5428f1/coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179", size = 915967, upload-time = "2026-03-17T10:33:18.341Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b4/ad/b59e5b451cf7172b8d1043dc0fa718f23aab379bc1521ee13d4bd9bfa960/coverage-7.13.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d490ba50c3f35dd7c17953c68f3270e7ccd1c6642e2d2afe2d8e720b98f5a053", size = 219278, upload-time = "2026-02-09T12:56:31.673Z" },
{ url = "https://files.pythonhosted.org/packages/f1/17/0cb7ca3de72e5f4ef2ec2fa0089beafbcaaaead1844e8b8a63d35173d77d/coverage-7.13.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:19bc3c88078789f8ef36acb014d7241961dbf883fd2533d18cb1e7a5b4e28b11", size = 219783, upload-time = "2026-02-09T12:56:33.104Z" },
{ url = "https://files.pythonhosted.org/packages/ab/63/325d8e5b11e0eaf6d0f6a44fad444ae58820929a9b0de943fa377fe73e85/coverage-7.13.4-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3998e5a32e62fdf410c0dbd3115df86297995d6e3429af80b8798aad894ca7aa", size = 250200, upload-time = "2026-02-09T12:56:34.474Z" },
{ url = "https://files.pythonhosted.org/packages/76/53/c16972708cbb79f2942922571a687c52bd109a7bd51175aeb7558dff2236/coverage-7.13.4-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8e264226ec98e01a8e1054314af91ee6cde0eacac4f465cc93b03dbe0bce2fd7", size = 252114, upload-time = "2026-02-09T12:56:35.749Z" },
{ url = "https://files.pythonhosted.org/packages/eb/c2/7ab36d8b8cc412bec9ea2d07c83c48930eb4ba649634ba00cb7e4e0f9017/coverage-7.13.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a3aa4e7b9e416774b21797365b358a6e827ffadaaca81b69ee02946852449f00", size = 254220, upload-time = "2026-02-09T12:56:37.796Z" },
{ url = "https://files.pythonhosted.org/packages/d6/4d/cf52c9a3322c89a0e6febdfbc83bb45c0ed3c64ad14081b9503adee702e7/coverage-7.13.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:71ca20079dd8f27fcf808817e281e90220475cd75115162218d0e27549f95fef", size = 256164, upload-time = "2026-02-09T12:56:39.016Z" },
{ url = "https://files.pythonhosted.org/packages/78/e9/eb1dd17bd6de8289df3580e967e78294f352a5df8a57ff4671ee5fc3dcd0/coverage-7.13.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e2f25215f1a359ab17320b47bcdaca3e6e6356652e8256f2441e4ef972052903", size = 250325, upload-time = "2026-02-09T12:56:40.668Z" },
{ url = "https://files.pythonhosted.org/packages/71/07/8c1542aa873728f72267c07278c5cc0ec91356daf974df21335ccdb46368/coverage-7.13.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d65b2d373032411e86960604dc4edac91fdfb5dca539461cf2cbe78327d1e64f", size = 251913, upload-time = "2026-02-09T12:56:41.97Z" },
{ url = "https://files.pythonhosted.org/packages/74/d7/c62e2c5e4483a748e27868e4c32ad3daa9bdddbba58e1bc7a15e252baa74/coverage-7.13.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94eb63f9b363180aff17de3e7c8760c3ba94664ea2695c52f10111244d16a299", size = 249974, upload-time = "2026-02-09T12:56:43.323Z" },
{ url = "https://files.pythonhosted.org/packages/98/9f/4c5c015a6e98ced54efd0f5cf8d31b88e5504ecb6857585fc0161bb1e600/coverage-7.13.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e856bf6616714c3a9fbc270ab54103f4e685ba236fa98c054e8f87f266c93505", size = 253741, upload-time = "2026-02-09T12:56:45.155Z" },
{ url = "https://files.pythonhosted.org/packages/bd/59/0f4eef89b9f0fcd9633b5d350016f54126ab49426a70ff4c4e87446cabdc/coverage-7.13.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:65dfcbe305c3dfe658492df2d85259e0d79ead4177f9ae724b6fb245198f55d6", size = 249695, upload-time = "2026-02-09T12:56:46.636Z" },
{ url = "https://files.pythonhosted.org/packages/b5/2c/b7476f938deb07166f3eb281a385c262675d688ff4659ad56c6c6b8e2e70/coverage-7.13.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b507778ae8a4c915436ed5c2e05b4a6cecfa70f734e19c22a005152a11c7b6a9", size = 250599, upload-time = "2026-02-09T12:56:48.13Z" },
{ url = "https://files.pythonhosted.org/packages/b8/34/c3420709d9846ee3785b9f2831b4d94f276f38884032dca1457fa83f7476/coverage-7.13.4-cp311-cp311-win32.whl", hash = "sha256:784fc3cf8be001197b652d51d3fd259b1e2262888693a4636e18879f613a62a9", size = 221780, upload-time = "2026-02-09T12:56:50.479Z" },
{ url = "https://files.pythonhosted.org/packages/61/08/3d9c8613079d2b11c185b865de9a4c1a68850cfda2b357fae365cf609f29/coverage-7.13.4-cp311-cp311-win_amd64.whl", hash = "sha256:2421d591f8ca05b308cf0092807308b2facbefe54af7c02ac22548b88b95c98f", size = 222715, upload-time = "2026-02-09T12:56:51.815Z" },
{ url = "https://files.pythonhosted.org/packages/18/1a/54c3c80b2f056164cc0a6cdcb040733760c7c4be9d780fe655f356f433e4/coverage-7.13.4-cp311-cp311-win_arm64.whl", hash = "sha256:79e73a76b854d9c6088fe5d8b2ebe745f8681c55f7397c3c0a016192d681045f", size = 221385, upload-time = "2026-02-09T12:56:53.194Z" },
{ url = "https://files.pythonhosted.org/packages/d1/81/4ce2fdd909c5a0ed1f6dedb88aa57ab79b6d1fbd9b588c1ac7ef45659566/coverage-7.13.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:02231499b08dabbe2b96612993e5fc34217cdae907a51b906ac7fca8027a4459", size = 219449, upload-time = "2026-02-09T12:56:54.889Z" },
{ url = "https://files.pythonhosted.org/packages/5d/96/5238b1efc5922ddbdc9b0db9243152c09777804fb7c02ad1741eb18a11c0/coverage-7.13.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40aa8808140e55dc022b15d8aa7f651b6b3d68b365ea0398f1441e0b04d859c3", size = 219810, upload-time = "2026-02-09T12:56:56.33Z" },
{ url = "https://files.pythonhosted.org/packages/78/72/2f372b726d433c9c35e56377cf1d513b4c16fe51841060d826b95caacec1/coverage-7.13.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5b856a8ccf749480024ff3bd7310adaef57bf31fd17e1bfc404b7940b6986634", size = 251308, upload-time = "2026-02-09T12:56:57.858Z" },
{ url = "https://files.pythonhosted.org/packages/5d/a0/2ea570925524ef4e00bb6c82649f5682a77fac5ab910a65c9284de422600/coverage-7.13.4-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c048ea43875fbf8b45d476ad79f179809c590ec7b79e2035c662e7afa3192e3", size = 254052, upload-time = "2026-02-09T12:56:59.754Z" },
{ url = "https://files.pythonhosted.org/packages/e8/ac/45dc2e19a1939098d783c846e130b8f862fbb50d09e0af663988f2f21973/coverage-7.13.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b7b38448866e83176e28086674fe7368ab8590e4610fb662b44e345b86d63ffa", size = 255165, upload-time = "2026-02-09T12:57:01.287Z" },
{ url = "https://files.pythonhosted.org/packages/2d/4d/26d236ff35abc3b5e63540d3386e4c3b192168c1d96da5cb2f43c640970f/coverage-7.13.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:de6defc1c9badbf8b9e67ae90fd00519186d6ab64e5cc5f3d21359c2a9b2c1d3", size = 257432, upload-time = "2026-02-09T12:57:02.637Z" },
{ url = "https://files.pythonhosted.org/packages/ec/55/14a966c757d1348b2e19caf699415a2a4c4f7feaa4bbc6326a51f5c7dd1b/coverage-7.13.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7eda778067ad7ffccd23ecffce537dface96212576a07924cbf0d8799d2ded5a", size = 251716, upload-time = "2026-02-09T12:57:04.056Z" },
{ url = "https://files.pythonhosted.org/packages/77/33/50116647905837c66d28b2af1321b845d5f5d19be9655cb84d4a0ea806b4/coverage-7.13.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e87f6c587c3f34356c3759f0420693e35e7eb0e2e41e4c011cb6ec6ecbbf1db7", size = 253089, upload-time = "2026-02-09T12:57:05.503Z" },
{ url = "https://files.pythonhosted.org/packages/c2/b4/8efb11a46e3665d92635a56e4f2d4529de6d33f2cb38afd47d779d15fc99/coverage-7.13.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8248977c2e33aecb2ced42fef99f2d319e9904a36e55a8a68b69207fb7e43edc", size = 251232, upload-time = "2026-02-09T12:57:06.879Z" },
{ url = "https://files.pythonhosted.org/packages/51/24/8cd73dd399b812cc76bb0ac260e671c4163093441847ffe058ac9fda1e32/coverage-7.13.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:25381386e80ae727608e662474db537d4df1ecd42379b5ba33c84633a2b36d47", size = 255299, upload-time = "2026-02-09T12:57:08.245Z" },
{ url = "https://files.pythonhosted.org/packages/03/94/0a4b12f1d0e029ce1ccc1c800944a9984cbe7d678e470bb6d3c6bc38a0da/coverage-7.13.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:ee756f00726693e5ba94d6df2bdfd64d4852d23b09bb0bc700e3b30e6f333985", size = 250796, upload-time = "2026-02-09T12:57:10.142Z" },
{ url = "https://files.pythonhosted.org/packages/73/44/6002fbf88f6698ca034360ce474c406be6d5a985b3fdb3401128031eef6b/coverage-7.13.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fdfc1e28e7c7cdce44985b3043bc13bbd9c747520f94a4d7164af8260b3d91f0", size = 252673, upload-time = "2026-02-09T12:57:12.197Z" },
{ url = "https://files.pythonhosted.org/packages/de/c6/a0279f7c00e786be75a749a5674e6fa267bcbd8209cd10c9a450c655dfa7/coverage-7.13.4-cp312-cp312-win32.whl", hash = "sha256:01d4cbc3c283a17fc1e42d614a119f7f438eabb593391283adca8dc86eff1246", size = 221990, upload-time = "2026-02-09T12:57:14.085Z" },
{ url = "https://files.pythonhosted.org/packages/77/4e/c0a25a425fcf5557d9abd18419c95b63922e897bc86c1f327f155ef234a9/coverage-7.13.4-cp312-cp312-win_amd64.whl", hash = "sha256:9401ebc7ef522f01d01d45532c68c5ac40fb27113019b6b7d8b208f6e9baa126", size = 222800, upload-time = "2026-02-09T12:57:15.944Z" },
{ url = "https://files.pythonhosted.org/packages/47/ac/92da44ad9a6f4e3a7debd178949d6f3769bedca33830ce9b1dcdab589a37/coverage-7.13.4-cp312-cp312-win_arm64.whl", hash = "sha256:b1ec7b6b6e93255f952e27ab58fbc68dcc468844b16ecbee881aeb29b6ab4d8d", size = 221415, upload-time = "2026-02-09T12:57:17.497Z" },
{ url = "https://files.pythonhosted.org/packages/0d/4a/331fe2caf6799d591109bb9c08083080f6de90a823695d412a935622abb2/coverage-7.13.4-py3-none-any.whl", hash = "sha256:1af1641e57cf7ba1bd67d677c9abdbcd6cc2ab7da3bca7fa1e2b7e50e65f2ad0", size = 211242, upload-time = "2026-02-09T12:59:02.032Z" },
{ url = "https://files.pythonhosted.org/packages/4b/37/d24c8f8220ff07b839b2c043ea4903a33b0f455abe673ae3c03bbdb7f212/coverage-7.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66a80c616f80181f4d643b0f9e709d97bcea413ecd9631e1dedc7401c8e6695d", size = 219381, upload-time = "2026-03-17T10:30:14.68Z" },
{ url = "https://files.pythonhosted.org/packages/35/8b/cd129b0ca4afe886a6ce9d183c44d8301acbd4ef248622e7c49a23145605/coverage-7.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:145ede53ccbafb297c1c9287f788d1bc3efd6c900da23bf6931b09eafc931587", size = 219880, upload-time = "2026-03-17T10:30:16.231Z" },
{ url = "https://files.pythonhosted.org/packages/55/2f/e0e5b237bffdb5d6c530ce87cc1d413a5b7d7dfd60fb067ad6d254c35c76/coverage-7.13.5-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0672854dc733c342fa3e957e0605256d2bf5934feeac328da9e0b5449634a642", size = 250303, upload-time = "2026-03-17T10:30:17.748Z" },
{ url = "https://files.pythonhosted.org/packages/92/be/b1afb692be85b947f3401375851484496134c5554e67e822c35f28bf2fbc/coverage-7.13.5-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ec10e2a42b41c923c2209b846126c6582db5e43a33157e9870ba9fb70dc7854b", size = 252218, upload-time = "2026-03-17T10:30:19.804Z" },
{ url = "https://files.pythonhosted.org/packages/da/69/2f47bb6fa1b8d1e3e5d0c4be8ccb4313c63d742476a619418f85740d597b/coverage-7.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be3d4bbad9d4b037791794ddeedd7d64a56f5933a2c1373e18e9e568b9141686", size = 254326, upload-time = "2026-03-17T10:30:21.321Z" },
{ url = "https://files.pythonhosted.org/packages/d5/d0/79db81da58965bd29dabc8f4ad2a2af70611a57cba9d1ec006f072f30a54/coverage-7.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d2afbc5cc54d286bfb54541aa50b64cdb07a718227168c87b9e2fb8f25e1743", size = 256267, upload-time = "2026-03-17T10:30:23.094Z" },
{ url = "https://files.pythonhosted.org/packages/e5/32/d0d7cc8168f91ddab44c0ce4806b969df5f5fdfdbb568eaca2dbc2a04936/coverage-7.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3ad050321264c49c2fa67bb599100456fc51d004b82534f379d16445da40fb75", size = 250430, upload-time = "2026-03-17T10:30:25.311Z" },
{ url = "https://files.pythonhosted.org/packages/4d/06/a055311d891ddbe231cd69fdd20ea4be6e3603ffebddf8704b8ca8e10a3c/coverage-7.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7300c8a6d13335b29bb76d7651c66af6bd8658517c43499f110ddc6717bfc209", size = 252017, upload-time = "2026-03-17T10:30:27.284Z" },
{ url = "https://files.pythonhosted.org/packages/d6/f6/d0fd2d21e29a657b5f77a2fe7082e1568158340dceb941954f776dce1b7b/coverage-7.13.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:eb07647a5738b89baab047f14edd18ded523de60f3b30e75c2acc826f79c839a", size = 250080, upload-time = "2026-03-17T10:30:29.481Z" },
{ url = "https://files.pythonhosted.org/packages/4e/ab/0d7fb2efc2e9a5eb7ddcc6e722f834a69b454b7e6e5888c3a8567ecffb31/coverage-7.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9adb6688e3b53adffefd4a52d72cbd8b02602bfb8f74dcd862337182fd4d1a4e", size = 253843, upload-time = "2026-03-17T10:30:31.301Z" },
{ url = "https://files.pythonhosted.org/packages/ba/6f/7467b917bbf5408610178f62a49c0ed4377bb16c1657f689cc61470da8ce/coverage-7.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7c8d4bc913dd70b93488d6c496c77f3aff5ea99a07e36a18f865bca55adef8bd", size = 249802, upload-time = "2026-03-17T10:30:33.358Z" },
{ url = "https://files.pythonhosted.org/packages/75/2c/1172fb689df92135f5bfbbd69fc83017a76d24ea2e2f3a1154007e2fb9f8/coverage-7.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0e3c426ffc4cd952f54ee9ffbdd10345709ecc78a3ecfd796a57236bfad0b9b8", size = 250707, upload-time = "2026-03-17T10:30:35.2Z" },
{ url = "https://files.pythonhosted.org/packages/67/21/9ac389377380a07884e3b48ba7a620fcd9dbfaf1d40565facdc6b36ec9ef/coverage-7.13.5-cp311-cp311-win32.whl", hash = "sha256:259b69bb83ad9894c4b25be2528139eecba9a82646ebdda2d9db1ba28424a6bf", size = 221880, upload-time = "2026-03-17T10:30:36.775Z" },
{ url = "https://files.pythonhosted.org/packages/af/7f/4cd8a92531253f9d7c1bbecd9fa1b472907fb54446ca768c59b531248dc5/coverage-7.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:258354455f4e86e3e9d0d17571d522e13b4e1e19bf0f8596bcf9476d61e7d8a9", size = 222816, upload-time = "2026-03-17T10:30:38.891Z" },
{ url = "https://files.pythonhosted.org/packages/12/a6/1d3f6155fb0010ca68eba7fe48ca6c9da7385058b77a95848710ecf189b1/coverage-7.13.5-cp311-cp311-win_arm64.whl", hash = "sha256:bff95879c33ec8da99fc9b6fe345ddb5be6414b41d6d1ad1c8f188d26f36e028", size = 221483, upload-time = "2026-03-17T10:30:40.463Z" },
{ url = "https://files.pythonhosted.org/packages/a0/c3/a396306ba7db865bf96fc1fb3b7fd29bcbf3d829df642e77b13555163cd6/coverage-7.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01", size = 219554, upload-time = "2026-03-17T10:30:42.208Z" },
{ url = "https://files.pythonhosted.org/packages/a6/16/a68a19e5384e93f811dccc51034b1fd0b865841c390e3c931dcc4699e035/coverage-7.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422", size = 219908, upload-time = "2026-03-17T10:30:43.906Z" },
{ url = "https://files.pythonhosted.org/packages/29/72/20b917c6793af3a5ceb7fb9c50033f3ec7865f2911a1416b34a7cfa0813b/coverage-7.13.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f", size = 251419, upload-time = "2026-03-17T10:30:45.545Z" },
{ url = "https://files.pythonhosted.org/packages/8c/49/cd14b789536ac6a4778c453c6a2338bc0a2fb60c5a5a41b4008328b9acc1/coverage-7.13.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:03ccc709a17a1de074fb1d11f217342fb0d2b1582ed544f554fc9fc3f07e95f5", size = 254159, upload-time = "2026-03-17T10:30:47.204Z" },
{ url = "https://files.pythonhosted.org/packages/9d/00/7b0edcfe64e2ed4c0340dac14a52ad0f4c9bd0b8b5e531af7d55b703db7c/coverage-7.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f4818d065964db3c1c66dc0fbdac5ac692ecbc875555e13374fdbe7eedb4376", size = 255270, upload-time = "2026-03-17T10:30:48.812Z" },
{ url = "https://files.pythonhosted.org/packages/93/89/7ffc4ba0f5d0a55c1e84ea7cee39c9fc06af7b170513d83fbf3bbefce280/coverage-7.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:012d5319e66e9d5a218834642d6c35d265515a62f01157a45bcc036ecf947256", size = 257538, upload-time = "2026-03-17T10:30:50.77Z" },
{ url = "https://files.pythonhosted.org/packages/81/bd/73ddf85f93f7e6fa83e77ccecb6162d9415c79007b4bc124008a4995e4a7/coverage-7.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8dd02af98971bdb956363e4827d34425cb3df19ee550ef92855b0acb9c7ce51c", size = 251821, upload-time = "2026-03-17T10:30:52.5Z" },
{ url = "https://files.pythonhosted.org/packages/a0/81/278aff4e8dec4926a0bcb9486320752811f543a3ce5b602cc7a29978d073/coverage-7.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f08fd75c50a760c7eb068ae823777268daaf16a80b918fa58eea888f8e3919f5", size = 253191, upload-time = "2026-03-17T10:30:54.543Z" },
{ url = "https://files.pythonhosted.org/packages/70/ee/fe1621488e2e0a58d7e94c4800f0d96f79671553488d401a612bebae324b/coverage-7.13.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:843ea8643cf967d1ac7e8ecd4bb00c99135adf4816c0c0593fdcc47b597fcf09", size = 251337, upload-time = "2026-03-17T10:30:56.663Z" },
{ url = "https://files.pythonhosted.org/packages/37/a6/f79fb37aa104b562207cc23cb5711ab6793608e246cae1e93f26b2236ed9/coverage-7.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9d44d7aa963820b1b971dbecd90bfe5fe8f81cff79787eb6cca15750bd2f79b9", size = 255404, upload-time = "2026-03-17T10:30:58.427Z" },
{ url = "https://files.pythonhosted.org/packages/75/f0/ed15262a58ec81ce457ceb717b7f78752a1713556b19081b76e90896e8d4/coverage-7.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7132bed4bd7b836200c591410ae7d97bf7ae8be6fc87d160b2bd881df929e7bf", size = 250903, upload-time = "2026-03-17T10:31:00.093Z" },
{ url = "https://files.pythonhosted.org/packages/0f/e9/9129958f20e7e9d4d56d51d42ccf708d15cac355ff4ac6e736e97a9393d2/coverage-7.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a698e363641b98843c517817db75373c83254781426e94ada3197cabbc2c919c", size = 252780, upload-time = "2026-03-17T10:31:01.916Z" },
{ url = "https://files.pythonhosted.org/packages/a4/d7/0ad9b15812d81272db94379fe4c6df8fd17781cc7671fdfa30c76ba5ff7b/coverage-7.13.5-cp312-cp312-win32.whl", hash = "sha256:bdba0a6b8812e8c7df002d908a9a2ea3c36e92611b5708633c50869e6d922fdf", size = 222093, upload-time = "2026-03-17T10:31:03.642Z" },
{ url = "https://files.pythonhosted.org/packages/29/3d/821a9a5799fac2556bcf0bd37a70d1d11fa9e49784b6d22e92e8b2f85f18/coverage-7.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:d2c87e0c473a10bffe991502eac389220533024c8082ec1ce849f4218dded810", size = 222900, upload-time = "2026-03-17T10:31:05.651Z" },
{ url = "https://files.pythonhosted.org/packages/d4/fa/2238c2ad08e35cf4f020ea721f717e09ec3152aea75d191a7faf3ef009a8/coverage-7.13.5-cp312-cp312-win_arm64.whl", hash = "sha256:bf69236a9a81bdca3bff53796237aab096cdbf8d78a66ad61e992d9dac7eb2de", size = 221515, upload-time = "2026-03-17T10:31:07.293Z" },
{ url = "https://files.pythonhosted.org/packages/9e/ee/a4cf96b8ce1e566ed238f0659ac2d3f007ed1d14b181bcb684e19561a69a/coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61", size = 211346, upload-time = "2026-03-17T10:33:15.691Z" },
]
[[package]]
name = "cppcheck"
version = "2.16.0"
source = { git = "https://github.com/commaai/dependencies.git?subdirectory=cppcheck&rev=releases#2f738421b9b6af97bf242319a1bea68e161d9b82" }
source = { git = "https://github.com/commaai/dependencies.git?subdirectory=cppcheck&rev=release-cppcheck#b631125c6c762b2ff19df670401b462dd75fb19f" }
[[package]]
name = "cpplint"
@@ -254,11 +254,15 @@ wheels = [
[[package]]
name = "lefthook"
version = "2.0.15"
version = "2.1.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/7c/8f/e90724128f481c637b7e9343b6535622cfa136541959a49f8a3de0d0e7a5/lefthook-2.0.15.tar.gz", hash = "sha256:8a32c9f2d44f0ff0f3e3ab48f9802ca10f1222b491f3f14e03f577ec175b6649", size = 50175274, upload-time = "2026-01-13T10:02:58.76Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/7c/d5/243d967f541d422a7252f92dbcc201cfd588bd404a66935baacc83be49c5/lefthook-2.0.15-py3-none-any.whl", hash = "sha256:54b174520f18a4fa2545ff1e5eae4c4d2515539fb25b8c4fe04b9224a2ff07ee", size = 50416709, upload-time = "2026-01-13T10:02:55.761Z" },
{ url = "https://files.pythonhosted.org/packages/3c/c1/0e76e13ff1cc52e6dcf295d6b1d9ea18eb7b48bda54075cbdcc0aa6df20c/lefthook-2.1.4-py3-none-macosx_10_15_x86_64.whl", hash = "sha256:f1dc03042222ee7f1ee7dbbae7ee3046beb9a12ebdfae09bca1107c19c1be988", size = 5432992, upload-time = "2026-03-12T07:25:17.326Z" },
{ url = "https://files.pythonhosted.org/packages/53/73/93f1a67afac0fa97c38004c43eb14df97414b6d3b4b0069b6d2b96b9de10/lefthook-2.1.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a8db48e35307394cf0277d199b3b5a541324308642a16c3b3a9de688d64e165d", size = 4957289, upload-time = "2026-03-12T07:25:26.561Z" },
{ url = "https://files.pythonhosted.org/packages/03/70/2b5641a32f4ae7f31f38d67e987c4943d1f0ec401395e779c03dbca2484b/lefthook-2.1.4-py3-none-manylinux_2_17_aarch64.whl", hash = "sha256:31300ac6bde3512a62252da4c6e0685b5c5d0adefb5dfa1f7f5e1f0aea63ba8b", size = 4785792, upload-time = "2026-03-12T07:25:21.731Z" },
{ url = "https://files.pythonhosted.org/packages/8d/58/b6253c7ba669ecb21300c03ba0342e30392d2a22d3d54a7dfa398beb5bcd/lefthook-2.1.4-py3-none-manylinux_2_17_x86_64.whl", hash = "sha256:9b4e34d5771bb4484e10df644ad0bb3e348ac026d8c2305b9a151e932fc3e2b8", size = 5359026, upload-time = "2026-03-12T07:25:23.372Z" },
{ url = "https://files.pythonhosted.org/packages/a0/d2/a9ae9afe0b728b4eae171c5f95b1f57d213154533fbfb0cbb9281c3c60e9/lefthook-2.1.4-py3-none-win_amd64.whl", hash = "sha256:d8ae5640d4393e460d00f9b53cc60c9f8112b6194c1d85efd9cad9682e1e91ac", size = 5509363, upload-time = "2026-03-12T07:25:24.961Z" },
{ url = "https://files.pythonhosted.org/packages/2a/44/ab9d096f758f8de7e45a80eb5b49a60dbb5b12de20df308489cc4738ed50/lefthook-2.1.4-py3-none-win_arm64.whl", hash = "sha256:8c7ae0094d8d946cab0fd7977a9cd935a4c2d302401a561ab64bb175c6b5eb9d", size = 4862370, upload-time = "2026-03-12T07:25:19.554Z" },
]
[[package]]
@@ -341,39 +345,39 @@ wheels = [
[[package]]
name = "numpy"
version = "2.4.2"
version = "2.4.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/57/fd/0005efbd0af48e55eb3c7208af93f2862d4b1a56cd78e84309a2d959208d/numpy-2.4.2.tar.gz", hash = "sha256:659a6107e31a83c4e33f763942275fd278b21d095094044eb35569e86a21ddae", size = 20723651, upload-time = "2026-01-31T23:13:10.135Z" }
sdist = { url = "https://files.pythonhosted.org/packages/d7/9f/b8cef5bffa569759033adda9481211426f12f53299629b410340795c2514/numpy-2.4.4.tar.gz", hash = "sha256:2d390634c5182175533585cc89f3608a4682ccb173cc9bb940b2881c8d6f8fa0", size = 20731587, upload-time = "2026-03-29T13:22:01.298Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d3/44/71852273146957899753e69986246d6a176061ea183407e95418c2aa4d9a/numpy-2.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e7e88598032542bd49af7c4747541422884219056c268823ef6e5e89851c8825", size = 16955478, upload-time = "2026-01-31T23:10:25.623Z" },
{ url = "https://files.pythonhosted.org/packages/74/41/5d17d4058bd0cd96bcbd4d9ff0fb2e21f52702aab9a72e4a594efa18692f/numpy-2.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7edc794af8b36ca37ef5fcb5e0d128c7e0595c7b96a2318d1badb6fcd8ee86b1", size = 14965467, upload-time = "2026-01-31T23:10:28.186Z" },
{ url = "https://files.pythonhosted.org/packages/49/48/fb1ce8136c19452ed15f033f8aee91d5defe515094e330ce368a0647846f/numpy-2.4.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:6e9f61981ace1360e42737e2bae58b27bf28a1b27e781721047d84bd754d32e7", size = 5475172, upload-time = "2026-01-31T23:10:30.848Z" },
{ url = "https://files.pythonhosted.org/packages/40/a9/3feb49f17bbd1300dd2570432961f5c8a4ffeff1db6f02c7273bd020a4c9/numpy-2.4.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:cb7bbb88aa74908950d979eeaa24dbdf1a865e3c7e45ff0121d8f70387b55f73", size = 6805145, upload-time = "2026-01-31T23:10:32.352Z" },
{ url = "https://files.pythonhosted.org/packages/3f/39/fdf35cbd6d6e2fcad42fcf85ac04a85a0d0fbfbf34b30721c98d602fd70a/numpy-2.4.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f069069931240b3fc703f1e23df63443dbd6390614c8c44a87d96cd0ec81eb1", size = 15966084, upload-time = "2026-01-31T23:10:34.502Z" },
{ url = "https://files.pythonhosted.org/packages/1b/46/6fa4ea94f1ddf969b2ee941290cca6f1bfac92b53c76ae5f44afe17ceb69/numpy-2.4.2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c02ef4401a506fb60b411467ad501e1429a3487abca4664871d9ae0b46c8ba32", size = 16899477, upload-time = "2026-01-31T23:10:37.075Z" },
{ url = "https://files.pythonhosted.org/packages/09/a1/2a424e162b1a14a5bd860a464ab4e07513916a64ab1683fae262f735ccd2/numpy-2.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2653de5c24910e49c2b106499803124dde62a5a1fe0eedeaecf4309a5f639390", size = 17323429, upload-time = "2026-01-31T23:10:39.704Z" },
{ url = "https://files.pythonhosted.org/packages/ce/a2/73014149ff250628df72c58204822ac01d768697913881aacf839ff78680/numpy-2.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1ae241bbfc6ae276f94a170b14785e561cb5e7f626b6688cf076af4110887413", size = 18635109, upload-time = "2026-01-31T23:10:41.924Z" },
{ url = "https://files.pythonhosted.org/packages/6c/0c/73e8be2f1accd56df74abc1c5e18527822067dced5ec0861b5bb882c2ce0/numpy-2.4.2-cp311-cp311-win32.whl", hash = "sha256:df1b10187212b198dd45fa943d8985a3c8cf854aed4923796e0e019e113a1bda", size = 6237915, upload-time = "2026-01-31T23:10:45.26Z" },
{ url = "https://files.pythonhosted.org/packages/76/ae/e0265e0163cf127c24c3969d29f1c4c64551a1e375d95a13d32eab25d364/numpy-2.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:b9c618d56a29c9cb1c4da979e9899be7578d2e0b3c24d52079c166324c9e8695", size = 12607972, upload-time = "2026-01-31T23:10:47.021Z" },
{ url = "https://files.pythonhosted.org/packages/29/a5/c43029af9b8014d6ea157f192652c50042e8911f4300f8f6ed3336bf437f/numpy-2.4.2-cp311-cp311-win_arm64.whl", hash = "sha256:47c5a6ed21d9452b10227e5e8a0e1c22979811cad7dcc19d8e3e2fb8fa03f1a3", size = 10485763, upload-time = "2026-01-31T23:10:50.087Z" },
{ url = "https://files.pythonhosted.org/packages/51/6e/6f394c9c77668153e14d4da83bcc247beb5952f6ead7699a1a2992613bea/numpy-2.4.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:21982668592194c609de53ba4933a7471880ccbaadcc52352694a59ecc860b3a", size = 16667963, upload-time = "2026-01-31T23:10:52.147Z" },
{ url = "https://files.pythonhosted.org/packages/1f/f8/55483431f2b2fd015ae6ed4fe62288823ce908437ed49db5a03d15151678/numpy-2.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40397bda92382fcec844066efb11f13e1c9a3e2a8e8f318fb72ed8b6db9f60f1", size = 14693571, upload-time = "2026-01-31T23:10:54.789Z" },
{ url = "https://files.pythonhosted.org/packages/2f/20/18026832b1845cdc82248208dd929ca14c9d8f2bac391f67440707fff27c/numpy-2.4.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:b3a24467af63c67829bfaa61eecf18d5432d4f11992688537be59ecd6ad32f5e", size = 5203469, upload-time = "2026-01-31T23:10:57.343Z" },
{ url = "https://files.pythonhosted.org/packages/7d/33/2eb97c8a77daaba34eaa3fa7241a14ac5f51c46a6bd5911361b644c4a1e2/numpy-2.4.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:805cc8de9fd6e7a22da5aed858e0ab16be5a4db6c873dde1d7451c541553aa27", size = 6550820, upload-time = "2026-01-31T23:10:59.429Z" },
{ url = "https://files.pythonhosted.org/packages/b1/91/b97fdfd12dc75b02c44e26c6638241cc004d4079a0321a69c62f51470c4c/numpy-2.4.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d82351358ffbcdcd7b686b90742a9b86632d6c1c051016484fa0b326a0a1548", size = 15663067, upload-time = "2026-01-31T23:11:01.291Z" },
{ url = "https://files.pythonhosted.org/packages/f5/c6/a18e59f3f0b8071cc85cbc8d80cd02d68aa9710170b2553a117203d46936/numpy-2.4.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e35d3e0144137d9fdae62912e869136164534d64a169f86438bc9561b6ad49f", size = 16619782, upload-time = "2026-01-31T23:11:03.669Z" },
{ url = "https://files.pythonhosted.org/packages/b7/83/9751502164601a79e18847309f5ceec0b1446d7b6aa12305759b72cf98b2/numpy-2.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adb6ed2ad29b9e15321d167d152ee909ec73395901b70936f029c3bc6d7f4460", size = 17013128, upload-time = "2026-01-31T23:11:05.913Z" },
{ url = "https://files.pythonhosted.org/packages/61/c4/c4066322256ec740acc1c8923a10047818691d2f8aec254798f3dd90f5f2/numpy-2.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8906e71fd8afcb76580404e2a950caef2685df3d2a57fe82a86ac8d33cc007ba", size = 18345324, upload-time = "2026-01-31T23:11:08.248Z" },
{ url = "https://files.pythonhosted.org/packages/ab/af/6157aa6da728fa4525a755bfad486ae7e3f76d4c1864138003eb84328497/numpy-2.4.2-cp312-cp312-win32.whl", hash = "sha256:ec055f6dae239a6299cace477b479cca2fc125c5675482daf1dd886933a1076f", size = 5960282, upload-time = "2026-01-31T23:11:10.497Z" },
{ url = "https://files.pythonhosted.org/packages/92/0f/7ceaaeaacb40567071e94dbf2c9480c0ae453d5bb4f52bea3892c39dc83c/numpy-2.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:209fae046e62d0ce6435fcfe3b1a10537e858249b3d9b05829e2a05218296a85", size = 12314210, upload-time = "2026-01-31T23:11:12.176Z" },
{ url = "https://files.pythonhosted.org/packages/2f/a3/56c5c604fae6dd40fa2ed3040d005fca97e91bd320d232ac9931d77ba13c/numpy-2.4.2-cp312-cp312-win_arm64.whl", hash = "sha256:fbde1b0c6e81d56f5dccd95dd4a711d9b95df1ae4009a60887e56b27e8d903fa", size = 10220171, upload-time = "2026-01-31T23:11:14.684Z" },
{ url = "https://files.pythonhosted.org/packages/f4/f8/50e14d36d915ef64d8f8bc4a087fc8264d82c785eda6711f80ab7e620335/numpy-2.4.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:89f7268c009bc492f506abd6f5265defa7cb3f7487dc21d357c3d290add45082", size = 16833179, upload-time = "2026-01-31T23:12:53.5Z" },
{ url = "https://files.pythonhosted.org/packages/17/17/809b5cad63812058a8189e91a1e2d55a5a18fd04611dbad244e8aeae465c/numpy-2.4.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6dee3bb76aa4009d5a912180bf5b2de012532998d094acee25d9cb8dee3e44a", size = 14889755, upload-time = "2026-01-31T23:12:55.933Z" },
{ url = "https://files.pythonhosted.org/packages/3e/ea/181b9bcf7627fc8371720316c24db888dcb9829b1c0270abf3d288b2e29b/numpy-2.4.2-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:cd2bd2bbed13e213d6b55dc1d035a4f91748a7d3edc9480c13898b0353708920", size = 5399500, upload-time = "2026-01-31T23:12:58.671Z" },
{ url = "https://files.pythonhosted.org/packages/33/9f/413adf3fc955541ff5536b78fcf0754680b3c6d95103230252a2c9408d23/numpy-2.4.2-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:cf28c0c1d4c4bf00f509fa7eb02c58d7caf221b50b467bcb0d9bbf1584d5c821", size = 6714252, upload-time = "2026-01-31T23:13:00.518Z" },
{ url = "https://files.pythonhosted.org/packages/91/da/643aad274e29ccbdf42ecd94dafe524b81c87bcb56b83872d54827f10543/numpy-2.4.2-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e04ae107ac591763a47398bb45b568fc38f02dbc4aa44c063f67a131f99346cb", size = 15797142, upload-time = "2026-01-31T23:13:02.219Z" },
{ url = "https://files.pythonhosted.org/packages/66/27/965b8525e9cb5dc16481b30a1b3c21e50c7ebf6e9dbd48d0c4d0d5089c7e/numpy-2.4.2-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:602f65afdef699cda27ec0b9224ae5dc43e328f4c24c689deaf77133dbee74d0", size = 16727979, upload-time = "2026-01-31T23:13:04.62Z" },
{ url = "https://files.pythonhosted.org/packages/de/e5/b7d20451657664b07986c2f6e3be564433f5dcaf3482d68eaecd79afaf03/numpy-2.4.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:be71bf1edb48ebbbf7f6337b5bfd2f895d1902f6335a5830b20141fc126ffba0", size = 12502577, upload-time = "2026-01-31T23:13:07.08Z" },
{ url = "https://files.pythonhosted.org/packages/ef/c6/4218570d8c8ecc9704b5157a3348e486e84ef4be0ed3e38218ab473c83d2/numpy-2.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f983334aea213c99992053ede6168500e5f086ce74fbc4acc3f2b00f5762e9db", size = 16976799, upload-time = "2026-03-29T13:18:15.438Z" },
{ url = "https://files.pythonhosted.org/packages/dd/92/b4d922c4a5f5dab9ed44e6153908a5c665b71acf183a83b93b690996e39b/numpy-2.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:72944b19f2324114e9dc86a159787333b77874143efcf89a5167ef83cfee8af0", size = 14971552, upload-time = "2026-03-29T13:18:18.606Z" },
{ url = "https://files.pythonhosted.org/packages/8a/dc/df98c095978fa6ee7b9a9387d1d58cbb3d232d0e69ad169a4ce784bde4fd/numpy-2.4.4-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:86b6f55f5a352b48d7fbfd2dbc3d5b780b2d79f4d3c121f33eb6efb22e9a2015", size = 5476566, upload-time = "2026-03-29T13:18:21.532Z" },
{ url = "https://files.pythonhosted.org/packages/28/34/b3fdcec6e725409223dd27356bdf5a3c2cc2282e428218ecc9cb7acc9763/numpy-2.4.4-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:ba1f4fc670ed79f876f70082eff4f9583c15fb9a4b89d6188412de4d18ae2f40", size = 6806482, upload-time = "2026-03-29T13:18:23.634Z" },
{ url = "https://files.pythonhosted.org/packages/68/62/63417c13aa35d57bee1337c67446761dc25ea6543130cf868eace6e8157b/numpy-2.4.4-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a87ec22c87be071b6bdbd27920b129b94f2fc964358ce38f3822635a3e2e03d", size = 15973376, upload-time = "2026-03-29T13:18:26.677Z" },
{ url = "https://files.pythonhosted.org/packages/cf/c5/9fcb7e0e69cef59cf10c746b84f7d58b08bc66a6b7d459783c5a4f6101a6/numpy-2.4.4-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:df3775294accfdd75f32c74ae39fcba920c9a378a2fc18a12b6820aa8c1fb502", size = 16925137, upload-time = "2026-03-29T13:18:30.14Z" },
{ url = "https://files.pythonhosted.org/packages/7e/43/80020edacb3f84b9efdd1591120a4296462c23fd8db0dde1666f6ef66f13/numpy-2.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0d4e437e295f18ec29bc79daf55e8a47a9113df44d66f702f02a293d93a2d6dd", size = 17329414, upload-time = "2026-03-29T13:18:33.733Z" },
{ url = "https://files.pythonhosted.org/packages/fd/06/af0658593b18a5f73532d377188b964f239eb0894e664a6c12f484472f97/numpy-2.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6aa3236c78803afbcb255045fbef97a9e25a1f6c9888357d205ddc42f4d6eba5", size = 18658397, upload-time = "2026-03-29T13:18:37.511Z" },
{ url = "https://files.pythonhosted.org/packages/e6/ce/13a09ed65f5d0ce5c7dd0669250374c6e379910f97af2c08c57b0608eee4/numpy-2.4.4-cp311-cp311-win32.whl", hash = "sha256:30caa73029a225b2d40d9fae193e008e24b2026b7ee1a867b7ee8d96ca1a448e", size = 6239499, upload-time = "2026-03-29T13:18:40.372Z" },
{ url = "https://files.pythonhosted.org/packages/bd/63/05d193dbb4b5eec1eca73822d80da98b511f8328ad4ae3ca4caf0f4db91d/numpy-2.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:6bbe4eb67390b0a0265a2c25458f6b90a409d5d069f1041e6aff1e27e3d9a79e", size = 12614257, upload-time = "2026-03-29T13:18:42.95Z" },
{ url = "https://files.pythonhosted.org/packages/87/c5/8168052f080c26fa984c413305012be54741c9d0d74abd7fbeeccae3889f/numpy-2.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:fcfe2045fd2e8f3cb0ce9d4ba6dba6333b8fa05bb8a4939c908cd43322d14c7e", size = 10486775, upload-time = "2026-03-29T13:18:45.835Z" },
{ url = "https://files.pythonhosted.org/packages/28/05/32396bec30fb2263770ee910142f49c1476d08e8ad41abf8403806b520ce/numpy-2.4.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:15716cfef24d3a9762e3acdf87e27f58dc823d1348f765bbea6bef8c639bfa1b", size = 16689272, upload-time = "2026-03-29T13:18:49.223Z" },
{ url = "https://files.pythonhosted.org/packages/c5/f3/a983d28637bfcd763a9c7aafdb6d5c0ebf3d487d1e1459ffdb57e2f01117/numpy-2.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:23cbfd4c17357c81021f21540da84ee282b9c8fba38a03b7b9d09ba6b951421e", size = 14699573, upload-time = "2026-03-29T13:18:52.629Z" },
{ url = "https://files.pythonhosted.org/packages/9b/fd/e5ecca1e78c05106d98028114f5c00d3eddb41207686b2b7de3e477b0e22/numpy-2.4.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:8b3b60bb7cba2c8c81837661c488637eee696f59a877788a396d33150c35d842", size = 5204782, upload-time = "2026-03-29T13:18:55.579Z" },
{ url = "https://files.pythonhosted.org/packages/de/2f/702a4594413c1a8632092beae8aba00f1d67947389369b3777aed783fdca/numpy-2.4.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:e4a010c27ff6f210ff4c6ef34394cd61470d01014439b192ec22552ee867f2a8", size = 6552038, upload-time = "2026-03-29T13:18:57.769Z" },
{ url = "https://files.pythonhosted.org/packages/7f/37/eed308a8f56cba4d1fdf467a4fc67ef4ff4bf1c888f5fc980481890104b1/numpy-2.4.4-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f9e75681b59ddaa5e659898085ae0eaea229d054f2ac0c7e563a62205a700121", size = 15670666, upload-time = "2026-03-29T13:19:00.341Z" },
{ url = "https://files.pythonhosted.org/packages/0a/0d/0e3ecece05b7a7e87ab9fb587855548da437a061326fff64a223b6dcb78a/numpy-2.4.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:81f4a14bee47aec54f883e0cad2d73986640c1590eb9bfaaba7ad17394481e6e", size = 16645480, upload-time = "2026-03-29T13:19:03.63Z" },
{ url = "https://files.pythonhosted.org/packages/34/49/f2312c154b82a286758ee2f1743336d50651f8b5195db18cdb63675ff649/numpy-2.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:62d6b0f03b694173f9fcb1fb317f7222fd0b0b103e784c6549f5e53a27718c44", size = 17020036, upload-time = "2026-03-29T13:19:07.428Z" },
{ url = "https://files.pythonhosted.org/packages/7b/e9/736d17bd77f1b0ec4f9901aaec129c00d59f5d84d5e79bba540ef12c2330/numpy-2.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fbc356aae7adf9e6336d336b9c8111d390a05df88f1805573ebb0807bd06fd1d", size = 18368643, upload-time = "2026-03-29T13:19:10.775Z" },
{ url = "https://files.pythonhosted.org/packages/63/f6/d417977c5f519b17c8a5c3bc9e8304b0908b0e21136fe43bf628a1343914/numpy-2.4.4-cp312-cp312-win32.whl", hash = "sha256:0d35aea54ad1d420c812bfa0385c71cd7cc5bcf7c65fed95fc2cd02fe8c79827", size = 5961117, upload-time = "2026-03-29T13:19:13.464Z" },
{ url = "https://files.pythonhosted.org/packages/2d/5b/e1deebf88ff431b01b7406ca3583ab2bbb90972bbe1c568732e49c844f7e/numpy-2.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:b5f0362dc928a6ecd9db58868fca5e48485205e3855957bdedea308f8672ea4a", size = 12320584, upload-time = "2026-03-29T13:19:16.155Z" },
{ url = "https://files.pythonhosted.org/packages/58/89/e4e856ac82a68c3ed64486a544977d0e7bdd18b8da75b78a577ca31c4395/numpy-2.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:846300f379b5b12cc769334464656bc882e0735d27d9726568bc932fdc49d5ec", size = 10221450, upload-time = "2026-03-29T13:19:18.994Z" },
{ url = "https://files.pythonhosted.org/packages/6b/33/8fae8f964a4f63ed528264ddf25d2b683d0b663e3cba26961eb838a7c1bd/numpy-2.4.4-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:58c8b5929fcb8287cbd6f0a3fae19c6e03a5c48402ae792962ac465224a629a4", size = 16854491, upload-time = "2026-03-29T13:21:38.03Z" },
{ url = "https://files.pythonhosted.org/packages/bc/d0/1aabee441380b981cf8cdda3ae7a46aa827d1b5a8cce84d14598bc94d6d9/numpy-2.4.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:eea7ac5d2dce4189771cedb559c738a71512768210dc4e4753b107a2048b3d0e", size = 14895830, upload-time = "2026-03-29T13:21:41.509Z" },
{ url = "https://files.pythonhosted.org/packages/a5/b8/aafb0d1065416894fccf4df6b49ef22b8db045187949545bced89c034b8e/numpy-2.4.4-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:51fc224f7ca4d92656d5a5eb315f12eb5fe2c97a66249aa7b5f562528a3be38c", size = 5400927, upload-time = "2026-03-29T13:21:44.747Z" },
{ url = "https://files.pythonhosted.org/packages/d6/77/063baa20b08b431038c7f9ff5435540c7b7265c78cf56012a483019ca72d/numpy-2.4.4-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:28a650663f7314afc3e6ec620f44f333c386aad9f6fc472030865dc0ebb26ee3", size = 6715557, upload-time = "2026-03-29T13:21:47.406Z" },
{ url = "https://files.pythonhosted.org/packages/c7/a8/379542d45a14f149444c5c4c4e7714707239ce9cc1de8c2803958889da14/numpy-2.4.4-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:19710a9ca9992d7174e9c52f643d4272dcd1558c5f7af7f6f8190f633bd651a7", size = 15804253, upload-time = "2026-03-29T13:21:50.753Z" },
{ url = "https://files.pythonhosted.org/packages/a2/c8/f0a45426d6d21e7ea3310a15cf90c43a14d9232c31a837702dba437f3373/numpy-2.4.4-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b2aec6af35c113b05695ebb5749a787acd63cafc83086a05771d1e1cd1e555f", size = 16753552, upload-time = "2026-03-29T13:21:54.344Z" },
{ url = "https://files.pythonhosted.org/packages/04/74/f4c001f4714c3ad9ce037e18cf2b9c64871a84951eaa0baf683a9ca9301c/numpy-2.4.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f2cf083b324a467e1ab358c105f6cad5ea950f50524668a80c486ff1db24e119", size = 12509075, upload-time = "2026-03-29T13:21:57.644Z" },
]
[[package]]
@@ -416,7 +420,7 @@ requires-dist = [
{ name = "cffi", marker = "extra == 'testing'" },
{ name = "codespell", marker = "extra == 'testing'" },
{ name = "comma-car-segments", marker = "extra == 'testing'", url = "https://huggingface.co/datasets/commaai/commaCarSegments/resolve/main/dist/comma_car_segments-0.1.0-py3-none-any.whl" },
{ name = "cppcheck", marker = "extra == 'testing'", git = "https://github.com/commaai/dependencies.git?subdirectory=cppcheck&rev=releases" },
{ name = "cppcheck", marker = "extra == 'testing'", git = "https://github.com/commaai/dependencies.git?subdirectory=cppcheck&rev=release-cppcheck" },
{ name = "cpplint", marker = "extra == 'testing'" },
{ name = "gcovr", marker = "extra == 'testing'" },
{ name = "hypothesis", marker = "extra == 'testing'", specifier = "==6.47.*" },
@@ -498,16 +502,16 @@ wheels = [
[[package]]
name = "pygments"
version = "2.19.2"
version = "2.20.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
]
[[package]]
name = "requests"
version = "2.32.5"
version = "2.33.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "certifi" },
@@ -515,34 +519,34 @@ dependencies = [
{ name = "idna" },
{ name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" }
sdist = { url = "https://files.pythonhosted.org/packages/34/64/8860370b167a9721e8956ae116825caff829224fbca0ca6e7bf8ddef8430/requests-2.33.0.tar.gz", hash = "sha256:c7ebc5e8b0f21837386ad0e1c8fe8b829fa5f544d8df3b2253bff14ef29d7652", size = 134232, upload-time = "2026-03-25T15:10:41.586Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
{ url = "https://files.pythonhosted.org/packages/56/5d/c814546c2333ceea4ba42262d8c4d55763003e767fa169adc693bd524478/requests-2.33.0-py3-none-any.whl", hash = "sha256:3324635456fa185245e24865e810cecec7b4caf933d7eb133dcde67d48cee69b", size = 65017, upload-time = "2026-03-25T15:10:40.382Z" },
]
[[package]]
name = "ruff"
version = "0.15.2"
version = "0.15.8"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/06/04/eab13a954e763b0606f460443fcbf6bb5a0faf06890ea3754ff16523dce5/ruff-0.15.2.tar.gz", hash = "sha256:14b965afee0969e68bb871eba625343b8673375f457af4abe98553e8bbb98342", size = 4558148, upload-time = "2026-02-19T22:32:20.271Z" }
sdist = { url = "https://files.pythonhosted.org/packages/14/b0/73cf7550861e2b4824950b8b52eebdcc5adc792a00c514406556c5b80817/ruff-0.15.8.tar.gz", hash = "sha256:995f11f63597ee362130d1d5a327a87cb6f3f5eae3094c620bcc632329a4d26e", size = 4610921, upload-time = "2026-03-26T18:39:38.675Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2f/70/3a4dc6d09b13cb3e695f28307e5d889b2e1a66b7af9c5e257e796695b0e6/ruff-0.15.2-py3-none-linux_armv6l.whl", hash = "sha256:120691a6fdae2f16d65435648160f5b81a9625288f75544dc40637436b5d3c0d", size = 10430565, upload-time = "2026-02-19T22:32:41.824Z" },
{ url = "https://files.pythonhosted.org/packages/71/0b/bb8457b56185ece1305c666dc895832946d24055be90692381c31d57466d/ruff-0.15.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a89056d831256099658b6bba4037ac6dd06f49d194199215befe2bb10457ea5e", size = 10820354, upload-time = "2026-02-19T22:32:07.366Z" },
{ url = "https://files.pythonhosted.org/packages/2d/c1/e0532d7f9c9e0b14c46f61b14afd563298b8b83f337b6789ddd987e46121/ruff-0.15.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e36dee3a64be0ebd23c86ffa3aa3fd3ac9a712ff295e192243f814a830b6bd87", size = 10170767, upload-time = "2026-02-19T22:32:13.188Z" },
{ url = "https://files.pythonhosted.org/packages/47/e8/da1aa341d3af017a21c7a62fb5ec31d4e7ad0a93ab80e3a508316efbcb23/ruff-0.15.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9fb47b6d9764677f8c0a193c0943ce9a05d6763523f132325af8a858eadc2b9", size = 10529591, upload-time = "2026-02-19T22:32:02.547Z" },
{ url = "https://files.pythonhosted.org/packages/93/74/184fbf38e9f3510231fbc5e437e808f0b48c42d1df9434b208821efcd8d6/ruff-0.15.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f376990f9d0d6442ea9014b19621d8f2aaf2b8e39fdbfc79220b7f0c596c9b80", size = 10260771, upload-time = "2026-02-19T22:32:36.938Z" },
{ url = "https://files.pythonhosted.org/packages/05/ac/605c20b8e059a0bc4b42360414baa4892ff278cec1c91fff4be0dceedefd/ruff-0.15.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dcc987551952d73cbf5c88d9fdee815618d497e4df86cd4c4824cc59d5dd75f", size = 11045791, upload-time = "2026-02-19T22:32:31.642Z" },
{ url = "https://files.pythonhosted.org/packages/fd/52/db6e419908f45a894924d410ac77d64bdd98ff86901d833364251bd08e22/ruff-0.15.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42a47fd785cbe8c01b9ff45031af875d101b040ad8f4de7bbb716487c74c9a77", size = 11879271, upload-time = "2026-02-19T22:32:29.305Z" },
{ url = "https://files.pythonhosted.org/packages/3e/d8/7992b18f2008bdc9231d0f10b16df7dda964dbf639e2b8b4c1b4e91b83af/ruff-0.15.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cbe9f49354866e575b4c6943856989f966421870e85cd2ac94dccb0a9dcb2fea", size = 11303707, upload-time = "2026-02-19T22:32:22.492Z" },
{ url = "https://files.pythonhosted.org/packages/d7/02/849b46184bcfdd4b64cde61752cc9a146c54759ed036edd11857e9b8443b/ruff-0.15.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7a672c82b5f9887576087d97be5ce439f04bbaf548ee987b92d3a7dede41d3a", size = 11149151, upload-time = "2026-02-19T22:32:44.234Z" },
{ url = "https://files.pythonhosted.org/packages/70/04/f5284e388bab60d1d3b99614a5a9aeb03e0f333847e2429bebd2aaa1feec/ruff-0.15.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ecc64f46f7019e2bcc3cdc05d4a7da958b629a5ab7033195e11a438403d956", size = 11091132, upload-time = "2026-02-19T22:32:24.691Z" },
{ url = "https://files.pythonhosted.org/packages/fa/ae/88d844a21110e14d92cf73d57363fab59b727ebeabe78009b9ccb23500af/ruff-0.15.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:8dcf243b15b561c655c1ef2f2b0050e5d50db37fe90115507f6ff37d865dc8b4", size = 10504717, upload-time = "2026-02-19T22:32:26.75Z" },
{ url = "https://files.pythonhosted.org/packages/64/27/867076a6ada7f2b9c8292884ab44d08fd2ba71bd2b5364d4136f3cd537e1/ruff-0.15.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dab6941c862c05739774677c6273166d2510d254dac0695c0e3f5efa1b5585de", size = 10263122, upload-time = "2026-02-19T22:32:10.036Z" },
{ url = "https://files.pythonhosted.org/packages/e7/ef/faf9321d550f8ebf0c6373696e70d1758e20ccdc3951ad7af00c0956be7c/ruff-0.15.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1b9164f57fc36058e9a6806eb92af185b0697c9fe4c7c52caa431c6554521e5c", size = 10735295, upload-time = "2026-02-19T22:32:39.227Z" },
{ url = "https://files.pythonhosted.org/packages/2f/55/e8089fec62e050ba84d71b70e7834b97709ca9b7aba10c1a0b196e493f97/ruff-0.15.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:80d24fcae24d42659db7e335b9e1531697a7102c19185b8dc4a028b952865fd8", size = 11241641, upload-time = "2026-02-19T22:32:34.617Z" },
{ url = "https://files.pythonhosted.org/packages/23/01/1c30526460f4d23222d0fabd5888868262fd0e2b71a00570ca26483cd993/ruff-0.15.2-py3-none-win32.whl", hash = "sha256:fd5ff9e5f519a7e1bd99cbe8daa324010a74f5e2ebc97c6242c08f26f3714f6f", size = 10507885, upload-time = "2026-02-19T22:32:15.635Z" },
{ url = "https://files.pythonhosted.org/packages/5c/10/3d18e3bbdf8fc50bbb4ac3cc45970aa5a9753c5cb51bf9ed9a3cd8b79fa3/ruff-0.15.2-py3-none-win_amd64.whl", hash = "sha256:d20014e3dfa400f3ff84830dfb5755ece2de45ab62ecea4af6b7262d0fb4f7c5", size = 11623725, upload-time = "2026-02-19T22:32:04.947Z" },
{ url = "https://files.pythonhosted.org/packages/6d/78/097c0798b1dab9f8affe73da9642bb4500e098cb27fd8dc9724816ac747b/ruff-0.15.2-py3-none-win_arm64.whl", hash = "sha256:cabddc5822acdc8f7b5527b36ceac55cc51eec7b1946e60181de8fe83ca8876e", size = 10941649, upload-time = "2026-02-19T22:32:18.108Z" },
{ url = "https://files.pythonhosted.org/packages/4a/92/c445b0cd6da6e7ae51e954939cb69f97e008dbe750cfca89b8cedc081be7/ruff-0.15.8-py3-none-linux_armv6l.whl", hash = "sha256:cbe05adeba76d58162762d6b239c9056f1a15a55bd4b346cfd21e26cd6ad7bc7", size = 10527394, upload-time = "2026-03-26T18:39:41.566Z" },
{ url = "https://files.pythonhosted.org/packages/eb/92/f1c662784d149ad1414cae450b082cf736430c12ca78367f20f5ed569d65/ruff-0.15.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d3e3d0b6ba8dca1b7ef9ab80a28e840a20070c4b62e56d675c24f366ef330570", size = 10905693, upload-time = "2026-03-26T18:39:30.364Z" },
{ url = "https://files.pythonhosted.org/packages/ca/f2/7a631a8af6d88bcef997eb1bf87cc3da158294c57044aafd3e17030613de/ruff-0.15.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6ee3ae5c65a42f273f126686353f2e08ff29927b7b7e203b711514370d500de3", size = 10323044, upload-time = "2026-03-26T18:39:33.37Z" },
{ url = "https://files.pythonhosted.org/packages/67/18/1bf38e20914a05e72ef3b9569b1d5c70a7ef26cd188d69e9ca8ef588d5bf/ruff-0.15.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdce027ada77baa448077ccc6ebb2fa9c3c62fd110d8659d601cf2f475858d94", size = 10629135, upload-time = "2026-03-26T18:39:44.142Z" },
{ url = "https://files.pythonhosted.org/packages/d2/e9/138c150ff9af60556121623d41aba18b7b57d95ac032e177b6a53789d279/ruff-0.15.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12e617fc01a95e5821648a6df341d80456bd627bfab8a829f7cfc26a14a4b4a3", size = 10348041, upload-time = "2026-03-26T18:39:52.178Z" },
{ url = "https://files.pythonhosted.org/packages/02/f1/5bfb9298d9c323f842c5ddeb85f1f10ef51516ac7a34ba446c9347d898df/ruff-0.15.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:432701303b26416d22ba696c39f2c6f12499b89093b61360abc34bcc9bf07762", size = 11121987, upload-time = "2026-03-26T18:39:55.195Z" },
{ url = "https://files.pythonhosted.org/packages/10/11/6da2e538704e753c04e8d86b1fc55712fdbdcc266af1a1ece7a51fff0d10/ruff-0.15.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d910ae974b7a06a33a057cb87d2a10792a3b2b3b35e33d2699fdf63ec8f6b17a", size = 11951057, upload-time = "2026-03-26T18:39:19.18Z" },
{ url = "https://files.pythonhosted.org/packages/83/f0/c9208c5fd5101bf87002fed774ff25a96eea313d305f1e5d5744698dc314/ruff-0.15.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2033f963c43949d51e6fdccd3946633c6b37c484f5f98c3035f49c27395a8ab8", size = 11464613, upload-time = "2026-03-26T18:40:06.301Z" },
{ url = "https://files.pythonhosted.org/packages/f8/22/d7f2fabdba4fae9f3b570e5605d5eb4500dcb7b770d3217dca4428484b17/ruff-0.15.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f29b989a55572fb885b77464cf24af05500806ab4edf9a0fd8977f9759d85b1", size = 11257557, upload-time = "2026-03-26T18:39:57.972Z" },
{ url = "https://files.pythonhosted.org/packages/71/8c/382a9620038cf6906446b23ce8632ab8c0811b8f9d3e764f58bedd0c9a6f/ruff-0.15.8-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:ac51d486bf457cdc985a412fb1801b2dfd1bd8838372fc55de64b1510eff4bec", size = 11169440, upload-time = "2026-03-26T18:39:22.205Z" },
{ url = "https://files.pythonhosted.org/packages/4d/0d/0994c802a7eaaf99380085e4e40c845f8e32a562e20a38ec06174b52ef24/ruff-0.15.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c9861eb959edab053c10ad62c278835ee69ca527b6dcd72b47d5c1e5648964f6", size = 10605963, upload-time = "2026-03-26T18:39:46.682Z" },
{ url = "https://files.pythonhosted.org/packages/19/aa/d624b86f5b0aad7cef6bbf9cd47a6a02dfdc4f72c92a337d724e39c9d14b/ruff-0.15.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8d9a5b8ea13f26ae90838afc33f91b547e61b794865374f114f349e9036835fb", size = 10357484, upload-time = "2026-03-26T18:39:49.176Z" },
{ url = "https://files.pythonhosted.org/packages/35/c3/e0b7835d23001f7d999f3895c6b569927c4d39912286897f625736e1fd04/ruff-0.15.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c2a33a529fb3cbc23a7124b5c6ff121e4d6228029cba374777bd7649cc8598b8", size = 10830426, upload-time = "2026-03-26T18:40:03.702Z" },
{ url = "https://files.pythonhosted.org/packages/f0/51/ab20b322f637b369383adc341d761eaaa0f0203d6b9a7421cd6e783d81b9/ruff-0.15.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:75e5cd06b1cf3f47a3996cfc999226b19aa92e7cce682dcd62f80d7035f98f49", size = 11345125, upload-time = "2026-03-26T18:39:27.799Z" },
{ url = "https://files.pythonhosted.org/packages/37/e6/90b2b33419f59d0f2c4c8a48a4b74b460709a557e8e0064cf33ad894f983/ruff-0.15.8-py3-none-win32.whl", hash = "sha256:bc1f0a51254ba21767bfa9a8b5013ca8149dcf38092e6a9eb704d876de94dc34", size = 10571959, upload-time = "2026-03-26T18:39:36.117Z" },
{ url = "https://files.pythonhosted.org/packages/1f/a2/ef467cb77099062317154c63f234b8a7baf7cb690b99af760c5b68b9ee7f/ruff-0.15.8-py3-none-win_amd64.whl", hash = "sha256:04f79eff02a72db209d47d665ba7ebcad609d8918a134f86cb13dd132159fc89", size = 11743893, upload-time = "2026-03-26T18:39:25.01Z" },
{ url = "https://files.pythonhosted.org/packages/15/e2/77be4fff062fa78d9b2a4dea85d14785dac5f1d0c1fb58ed52331f0ebe28/ruff-0.15.8-py3-none-win_arm64.whl", hash = "sha256:cf891fa8e3bb430c0e7fac93851a5978fc99c8fa2c053b57b118972866f8e5f2", size = 11048175, upload-time = "2026-03-26T18:40:01.06Z" },
]
[[package]]
@@ -605,26 +609,26 @@ wheels = [
[[package]]
name = "ty"
version = "0.0.18"
version = "0.0.26"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/74/15/9682700d8d60fdca7afa4febc83a2354b29cdcd56e66e19c92b521db3b39/ty-0.0.18.tar.gz", hash = "sha256:04ab7c3db5dcbcdac6ce62e48940d3a0124f377c05499d3f3e004e264ae94b83", size = 5214774, upload-time = "2026-02-20T21:51:31.173Z" }
sdist = { url = "https://files.pythonhosted.org/packages/18/94/4879b81f8681117ccaf31544579304f6dc2ddcc0c67f872afb35869643a2/ty-0.0.26.tar.gz", hash = "sha256:0496b62405d62de7b954d6d677dc1cc5d3046197215d7a0a7fef37745d7b6d29", size = 5393643, upload-time = "2026-03-26T16:27:11.067Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ae/d8/920460d4c22ea68fcdeb0b2fb53ea2aeb9c6d7875bde9278d84f2ac767b6/ty-0.0.18-py3-none-linux_armv6l.whl", hash = "sha256:4e5e91b0a79857316ef893c5068afc4b9872f9d257627d9bc8ac4d2715750d88", size = 10280825, upload-time = "2026-02-20T21:51:25.03Z" },
{ url = "https://files.pythonhosted.org/packages/83/56/62587de582d3d20d78fcdddd0594a73822ac5a399a12ef512085eb7a4de6/ty-0.0.18-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ee0e578b3f8416e2d5416da9553b78fd33857868aa1384cb7fefeceee5ff102d", size = 10118324, upload-time = "2026-02-20T21:51:22.27Z" },
{ url = "https://files.pythonhosted.org/packages/2f/2d/dbdace8d432a0755a7417f659bfd5b8a4261938ecbdfd7b42f4c454f5aa9/ty-0.0.18-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3f7a0487d36b939546a91d141f7fc3dbea32fab4982f618d5b04dc9d5b6da21e", size = 9605861, upload-time = "2026-02-20T21:51:16.066Z" },
{ url = "https://files.pythonhosted.org/packages/6b/d9/de11c0280f778d5fc571393aada7fe9b8bc1dd6a738f2e2c45702b8b3150/ty-0.0.18-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5e2fa8d45f57ca487a470e4bf66319c09b561150e98ae2a6b1a97ef04c1a4eb", size = 10092701, upload-time = "2026-02-20T21:51:26.862Z" },
{ url = "https://files.pythonhosted.org/packages/0f/94/068d4d591d791041732171e7b63c37a54494b2e7d28e88d2167eaa9ad875/ty-0.0.18-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d75652e9e937f7044b1aca16091193e7ef11dac1c7ec952b7fb8292b7ba1f5f2", size = 10109203, upload-time = "2026-02-20T21:51:11.59Z" },
{ url = "https://files.pythonhosted.org/packages/34/e4/526a4aa56dc0ca2569aaa16880a1ab105c3b416dd70e87e25a05688999f3/ty-0.0.18-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:563c868edceb8f6ddd5e91113c17d3676b028f0ed380bdb3829b06d9beb90e58", size = 10614200, upload-time = "2026-02-20T21:51:20.298Z" },
{ url = "https://files.pythonhosted.org/packages/fd/3d/b68ab20a34122a395880922587fbfc3adf090d22e0fb546d4d20fe8c2621/ty-0.0.18-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:502e2a1f948bec563a0454fc25b074bf5cf041744adba8794d024277e151d3b0", size = 11153232, upload-time = "2026-02-20T21:51:14.121Z" },
{ url = "https://files.pythonhosted.org/packages/68/ea/678243c042343fcda7e6af36036c18676c355878dcdcd517639586d2cf9e/ty-0.0.18-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc881dea97021a3aa29134a476937fd8054775c4177d01b94db27fcfb7aab65b", size = 10832934, upload-time = "2026-02-20T21:51:32.92Z" },
{ url = "https://files.pythonhosted.org/packages/d8/bd/7f8d647cef8b7b346c0163230a37e903c7461c7248574840b977045c77df/ty-0.0.18-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:421fcc3bc64cab56f48edb863c7c1c43649ec4d78ff71a1acb5366ad723b6021", size = 10700888, upload-time = "2026-02-20T21:51:09.673Z" },
{ url = "https://files.pythonhosted.org/packages/6e/06/cb3620dc48c5d335ba7876edfef636b2f4498eff4a262ff90033b9e88408/ty-0.0.18-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0fe5038a7136a0e638a2fb1ad06e3d3c4045314c6ba165c9c303b9aeb4623d6c", size = 10078965, upload-time = "2026-02-20T21:51:07.678Z" },
{ url = "https://files.pythonhosted.org/packages/60/27/c77a5a84533fa3b685d592de7b4b108eb1f38851c40fac4e79cc56ec7350/ty-0.0.18-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d123600a52372677613a719bbb780adeb9b68f47fb5f25acb09171de390e0035", size = 10134659, upload-time = "2026-02-20T21:51:18.311Z" },
{ url = "https://files.pythonhosted.org/packages/43/6e/60af6b88c73469e628ba5253a296da6984e0aa746206f3034c31f1a04ed1/ty-0.0.18-py3-none-musllinux_1_2_i686.whl", hash = "sha256:bb4bc11d32a1bf96a829bf6b9696545a30a196ac77bbc07cc8d3dfee35e03723", size = 10297494, upload-time = "2026-02-20T21:51:39.631Z" },
{ url = "https://files.pythonhosted.org/packages/33/90/612dc0b68224c723faed6adac2bd3f930a750685db76dfe17e6b9e534a83/ty-0.0.18-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:dda2efbf374ba4cd704053d04e32f2f784e85c2ddc2400006b0f96f5f7e4b667", size = 10791944, upload-time = "2026-02-20T21:51:37.13Z" },
{ url = "https://files.pythonhosted.org/packages/0d/da/f4ada0fd08a9e4138fe3fd2bcd3797753593f423f19b1634a814b9b2a401/ty-0.0.18-py3-none-win32.whl", hash = "sha256:c5768607c94977dacddc2f459ace6a11a408a0f57888dd59abb62d28d4fee4f7", size = 9677964, upload-time = "2026-02-20T21:51:42.039Z" },
{ url = "https://files.pythonhosted.org/packages/5e/fa/090ed9746e5c59fc26d8f5f96dc8441825171f1f47752f1778dad690b08b/ty-0.0.18-py3-none-win_amd64.whl", hash = "sha256:b78d0fa1103d36fc2fce92f2092adace52a74654ab7884d54cdaec8eb5016a4d", size = 10636576, upload-time = "2026-02-20T21:51:29.159Z" },
{ url = "https://files.pythonhosted.org/packages/92/4f/5dd60904c8105cda4d0be34d3a446c180933c76b84ae0742e58f02133713/ty-0.0.18-py3-none-win_arm64.whl", hash = "sha256:01770c3c82137c6b216aa3251478f0b197e181054ee92243772de553d3586398", size = 10095449, upload-time = "2026-02-20T21:51:34.914Z" },
{ url = "https://files.pythonhosted.org/packages/83/24/99fe33ecd7e16d23c53b0d4244778c6d1b6eb1663b091236dcba22882d67/ty-0.0.26-py3-none-linux_armv6l.whl", hash = "sha256:35beaa56cf59725fd59ab35d8445bbd40b97fe76db39b052b1fcb31f9bf8adf7", size = 10521856, upload-time = "2026-03-26T16:27:06.335Z" },
{ url = "https://files.pythonhosted.org/packages/55/97/1b5e939e2ff69b9bb279ab680bfa8f677d886309a1ac8d9588fd6ce58146/ty-0.0.26-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:487a0be58ab0eb02e31ba71eb6953812a0f88e50633469b0c0ce3fb795fe0fa1", size = 10320958, upload-time = "2026-03-26T16:27:13.849Z" },
{ url = "https://files.pythonhosted.org/packages/71/25/37081461e13d38a190e5646948d7bc42084f7bd1c6b44f12550be3923e7e/ty-0.0.26-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a01b7de5693379646d423b68f119719a1338a20017ba48a93eefaff1ee56f97b", size = 9799905, upload-time = "2026-03-26T16:26:55.805Z" },
{ url = "https://files.pythonhosted.org/packages/a1/1c/295d8f55a7b0e037dfc3a5ec4bdda3ab3cbca6f492f725bf269f96a4d841/ty-0.0.26-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:628c3ee869d113dd2bd249925662fd39d9d0305a6cb38f640ddaa7436b74a1ef", size = 10317507, upload-time = "2026-03-26T16:27:31.887Z" },
{ url = "https://files.pythonhosted.org/packages/1d/62/48b3875c5d2f48fe017468d4bbdde1164c76a8184374f1d5e6162cf7d9b8/ty-0.0.26-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:63d04f35f5370cbc91c0b9675dc83e0c53678125a7b629c9c95769e86f123e65", size = 10319821, upload-time = "2026-03-26T16:27:29.647Z" },
{ url = "https://files.pythonhosted.org/packages/ff/28/cfb2d495046d5bf42d532325cea7412fa1189912d549dbfae417a24fd794/ty-0.0.26-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a53c4e6f6a91927f8b90e584a4b12bcde05b0c1870ddff8d17462168ad7947a", size = 10831757, upload-time = "2026-03-26T16:27:37.441Z" },
{ url = "https://files.pythonhosted.org/packages/26/bf/dbc3e42f448a2d862651de070b4108028c543ca18cab096b38d7de449915/ty-0.0.26-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:caf2ced0e58d898d5e3ba5cb843e0ebd377c8a461464748586049afbd9321f51", size = 11369556, upload-time = "2026-03-26T16:26:58.655Z" },
{ url = "https://files.pythonhosted.org/packages/92/4c/6d2f8f34bc6d502ab778c9345a4a936a72ae113de11329c1764bb1f204f6/ty-0.0.26-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:384807bbcb7d7ce9b97ee5aaa6417a8ae03ccfb426c52b08018ca62cf60f5430", size = 11085679, upload-time = "2026-03-26T16:27:21.746Z" },
{ url = "https://files.pythonhosted.org/packages/cc/f4/f3f61c203bc980dd9bba0ba7ed3c6e81ddfd36b286330f9487c2c7d041aa/ty-0.0.26-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a2c766a94d79b4f82995d41229702caf2d76e5c440ec7e543d05c70e98bf8ab", size = 10900581, upload-time = "2026-03-26T16:27:24.39Z" },
{ url = "https://files.pythonhosted.org/packages/3d/fd/3ca1b4e4bdd129829e9ce78677e0f8e0f1038a7702dccecfa52f037c6046/ty-0.0.26-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f41ac45a0f8e3e8e181508d863a0a62156341db0f624ffd004b97ee550a9de80", size = 10294401, upload-time = "2026-03-26T16:27:03.999Z" },
{ url = "https://files.pythonhosted.org/packages/de/20/4ee3d8c3f90e008843795c765cb8bb245f188c23e5e5cc612c7697406fba/ty-0.0.26-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:73eb8327a34d529438dfe4db46796946c4e825167cbee434dc148569892e435f", size = 10351469, upload-time = "2026-03-26T16:27:19.003Z" },
{ url = "https://files.pythonhosted.org/packages/3d/b1/9fb154ade65906d4148f0b999c4a8257c2a34253cb72e15d84c1f04a064e/ty-0.0.26-py3-none-musllinux_1_2_i686.whl", hash = "sha256:4bb53a79259516535a1b55f613ba1619e9c666854946474ca8418c35a5c4fd60", size = 10529488, upload-time = "2026-03-26T16:27:01.378Z" },
{ url = "https://files.pythonhosted.org/packages/a5/70/9b02b03b1862e27b64143db65946d68b138160a5b6bfea193bee0b8bbc34/ty-0.0.26-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:2f0e75edc1aeb1b4b84af516c7891f631254a4ca3dcd15e848fa1e061e1fe9da", size = 10999015, upload-time = "2026-03-26T16:27:34.636Z" },
{ url = "https://files.pythonhosted.org/packages/21/16/0a56b8667296e2989b9d48095472d98ebf57a0006c71f2a101bbc62a142d/ty-0.0.26-py3-none-win32.whl", hash = "sha256:943c998c5523ed6b519c899c0c39b26b4c751a9759e460fb964765a44cde226f", size = 9912378, upload-time = "2026-03-26T16:27:08.999Z" },
{ url = "https://files.pythonhosted.org/packages/60/c2/fef0d4bba9cd89a82d725b3b1a66efb1b36629ecf0fb1d8e916cb75b8829/ty-0.0.26-py3-none-win_amd64.whl", hash = "sha256:19c856d343efeb1ecad8ee220848f5d2c424daf7b2feda357763ad3036e2172f", size = 10863737, upload-time = "2026-03-26T16:27:27.06Z" },
{ url = "https://files.pythonhosted.org/packages/4d/05/888ebcb3c4d3b6b72d5d3241fddd299142caa3c516e6d26a9cd887dfed3b/ty-0.0.26-py3-none-win_arm64.whl", hash = "sha256:2cde58ccffa046db1223dc28f3e7d4f2c7da8267e97cc5cd186af6fe85f1758a", size = 10285408, upload-time = "2026-03-26T16:27:16.432Z" },
]
[[package]]