From ddd67e58bc8d9331bfcd394ca3594170a6910d0d Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Sat, 31 Oct 2026 17:00:37 -0500 Subject: [PATCH] Reuse exact GM configuration checks in driving hot paths --- opendbc_repo/opendbc/car/gm/carstate.py | 28 ++++---- .../opendbc/car/gm/feature_capabilities.py | 12 +++- .../gm/tests/test_hotpath_configuration.py | 65 +++++++++++++++++++ prebuilt.json | 2 +- 4 files changed, 90 insertions(+), 17 deletions(-) create mode 100644 opendbc_repo/opendbc/car/gm/tests/test_hotpath_configuration.py diff --git a/opendbc_repo/opendbc/car/gm/carstate.py b/opendbc_repo/opendbc/car/gm/carstate.py index 4b5d50495f..32cca34414 100644 --- a/opendbc_repo/opendbc/car/gm/carstate.py +++ b/opendbc_repo/opendbc/car/gm/carstate.py @@ -136,6 +136,8 @@ class CarState(CarStateBase): return self.car_gps_tracker.get() def update(self, can_parsers) -> structs.CarState: + bolt_pedal_profile = is_bolt_pedal_profile(self.CP) + volt_camera_removed = is_volt_camera_removed(self.CP) pt_cp = can_parsers[Bus.pt] cam_cp = can_parsers[Bus.cam] loopback_cp = can_parsers[Bus.loopback] @@ -157,7 +159,7 @@ class CarState(CarStateBase): self.bolt_pedal_removed_stock_active = bool(pt_cp.vl["ECMCruiseControl"]["CruiseActive"]) present_no_acc_pedal = (is_bolt_present_no_acc_pedal_profile(self.CP) or is_bolt_present_no_acc_pedal_profile(self.CP, stock_only=True)) - if is_bolt_pedal_profile(self.CP) or present_no_acc_pedal: + if bolt_pedal_profile or present_no_acc_pedal: self.bolt_pedal_gear_ts_nanos = (self.conventional_cancel_credit.gear_ns if present_no_acc_pedal else pt_cp.ts_nanos["ECMPRDNL2"]["PRNDL2"]) self.bolt_pedal_main_ts_nanos = pt_cp.ts_nanos["ECMEngineStatus"]["CruiseMainOn"] @@ -233,7 +235,7 @@ class CarState(CarStateBase): ("ASCMSteeringButton", "RollingCounter"), ("ECMPRDNL2", "PRNDL2")) self.ordinary_removed_sources = tuple(pt_cp.ts_nanos[name][field] for name, field in names) - if (is_volt_camera_removed(self.CP) or self.camera_pedal_profile is not None and + if (volt_camera_removed or self.camera_pedal_profile is not None and self.camera_pedal_profile.topology in ("gateway", "ascm", "sdgm") and not self.camera_pedal_profile.longitudinal): names = (("PSCMStatus", "LKATorqueDelivered"), ("EBCMWheelSpdRear", "RLWheelSpd"), ("AcceleratorPedal2", "CruiseState"), ("ECMEngineStatus", "CruiseMainOn"), @@ -308,7 +310,7 @@ class CarState(CarStateBase): if is_volt_longitudinal(self.CP): # Observe only actual resume/driver sources, using the finalized brake owner. alternate = is_volt_gateway_alternate_brake(self.CP) or ( - is_volt_camera_removed(self.CP) and bool(self.CP.flags & GMFlags.NO_ACCELERATOR_POS_MSG)) + volt_camera_removed and bool(self.CP.flags & GMFlags.NO_ACCELERATOR_POS_MSG)) c9 = self.CP.networkLocation == NetworkLocation.fwdCamera and not ( gm_control_word(self.CP) & (GMSafetyFlags.ASCM_INTERCEPT | GMSafetyFlags.SDGM) and not gm_control_word(self.CP) & GMSafetyFlags.BRAKE_C9) @@ -328,7 +330,7 @@ class CarState(CarStateBase): gm_auto_hold = is_gm_auto_hold(self.CP) if gm_auto_hold: alternate = is_volt_gateway_alternate_brake(self.CP) - alternate_force = alternate or (is_volt_camera_removed(self.CP) and bool(self.CP.flags & GMFlags.NO_ACCELERATOR_POS_MSG)) or ( + alternate_force = alternate or (volt_camera_removed and bool(self.CP.flags & GMFlags.NO_ACCELERATOR_POS_MSG)) or ( self.camera_pedal_profile is not None and self.camera_pedal_profile.volt and self.camera_pedal_profile.brake_source == BrakeSource.F1) c9 = self.CP.networkLocation == NetworkLocation.fwdCamera and ( @@ -387,7 +389,7 @@ class CarState(CarStateBase): not (self.hybrid_profile is not None and self.hybrid_profile.removed) and not removed_pedal): if not is_conventional_cc_pedal_profile(self.CP): self.pt_lka_steering_cmd_counter = pt_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] - if not self.bolt_cc_removed and not is_volt_camera_removed(self.CP) and not is_ordinary_camera_removed(self.CP): + if not self.bolt_cc_removed and not volt_camera_removed and not is_ordinary_camera_removed(self.CP): self.cam_lka_steering_cmd_counter = cam_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] # This is to avoid a fault where you engage while still moving backwards after shifting to D. @@ -428,7 +430,7 @@ class CarState(CarStateBase): ret.brakePressed = (pt_cp.vl["EBCMBrakePedalPosition"]["BrakePedalPosition"] / 0xD0 >= .10 if self.CP.flags & GMFlags.NO_ACCELERATOR_POS_MSG else pt_cp.vl["ECMAcceleratorPos"]["BrakePedalPos"] >= 8) - elif is_volt_camera_removed(self.CP): + elif volt_camera_removed: ret.brakePressed = pt_cp.vl["ECMEngineStatus"]["BrakePressed"] != 0 elif is_volt_gateway_alternate_brake(self.CP): pedal_position = pt_cp.vl["EBCMBrakePedalPosition"]["BrakePedalPosition"] @@ -489,7 +491,7 @@ class CarState(CarStateBase): self.pedal_sensor_ts_nanos = 0 self.pedal_sensor_counter = None if self.pedal_sensor_healthy: - if is_bolt_pedal_profile(self.CP): + if bolt_pedal_profile: ret.gasPressed = first + second > 1190 elif self.camera_pedal_profile is not None and self.camera_pedal_profile.longitudinal: ret.gasPressed = ret.gasPressed or first + second > 1190 @@ -517,7 +519,7 @@ class CarState(CarStateBase): # 1 - latched ret.seatbeltUnlatched = pt_cp.vl["BCMDoorBeltStatus"]["LeftSeatBelt"] == 0 - if int(self.CP.safetyConfigs[0].safetyParam) == 0x1CD and is_bolt_pedal_profile(self.CP): + if int(self.CP.safetyConfigs[0].safetyParam) == 0x1CD and bolt_pedal_profile: self.bolt_acc_brake_clock_ns = cam_cp.ts_nanos["EBCMFrictionBrakeCmd"]["RollingCounter"] self.bolt_acc_brake_clock_counter = int(cam_cp.vl["EBCMFrictionBrakeCmd"]["RollingCounter"]) @@ -536,7 +538,7 @@ class CarState(CarStateBase): ret.accFaulted = acc_state == AccState.FAULTED or (friction_unavailable and not secondary_only) ret.cruiseState.enabled = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] != AccState.OFF - if is_volt_camera_removed(self.CP): + if volt_camera_removed: # A missing camera can leave the ECU faulted; that is not engaged cruise. ret.cruiseState.enabled &= pt_cp.vl["AcceleratorPedal2"]["CruiseState"] != AccState.FAULTED ret.cruiseState.standstill = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] == AccState.STANDSTILL @@ -571,7 +573,7 @@ class CarState(CarStateBase): if self.CP.carFingerprint in NO_ACC_BOLT_CAR and not self.bolt_cc_profile: ret.accFaulted = False ret.cruiseState.enabled = pt_cp.vl["ECMCruiseControl"]["CruiseActive"] != 0 if pedal_stock_no_acc else False - if is_bolt_pedal_profile(self.CP): + if bolt_pedal_profile: self.bolt_pedal_standstill_ts_nanos = pt_cp.ts_nanos["AcceleratorPedal2"]["CruiseState"] stamp = self.bolt_pedal_standstill_ts_nanos ret.cruiseState.standstill = (0 < stamp <= pt_cp._last_update_nanos and @@ -580,7 +582,7 @@ class CarState(CarStateBase): else: ret.cruiseState.standstill = False if (self.hybrid_profile is None and not removed_pedal and self.volt_cc_pedal_profile is None and self.CP.networkLocation == NetworkLocation.fwdCamera - and not is_volt_camera_removed(self.CP) + and not volt_camera_removed and not is_conventional_cc_pedal_profile(self.CP) and not is_ordinary_camera_removed(self.CP) and not (self.camera_pedal_profile is not None and self.camera_pedal_profile.removed)): if (self.CP.carFingerprint not in ALT_ACCS or self.camera_pedal_profile is not None or is_ordinary_camera_profile(self.CP) or @@ -611,13 +613,13 @@ class CarState(CarStateBase): if (self.CP.carFingerprint in (ORDINARY_ASCM_CAR | ORDINARY_SDGM_CAR) or is_ordinary_camera_profile(self.CP) or is_ordinary_camera_profile(self.CP, longitudinal=True) or - self.CP.carFingerprint in (CAR.CHEVROLET_VOLT_ASCM, CAR.CHEVROLET_VOLT_CAMERA, CAR.CHEVROLET_VOLT_2019)) and not is_volt_camera_removed(self.CP) and \ + self.CP.carFingerprint in (CAR.CHEVROLET_VOLT_ASCM, CAR.CHEVROLET_VOLT_CAMERA, CAR.CHEVROLET_VOLT_2019)) and not volt_camera_removed and \ not is_ordinary_camera_removed(self.CP): self.stock_fcw_alert = int(cam_cp.vl["ASCMActiveCruiseControlStatus"]["FCWAlert"]) & 0x3 ret.stockFcw = self.stock_fcw_alert != 0 if (self.CP.carFingerprint == CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL and - is_bolt_pedal_profile(self.CP) and not removed_pedal): + bolt_pedal_profile and not removed_pedal): self.stock_fcw_alert = int(cam_cp.vl["ASCMActiveCruiseControlStatus"]["FCWAlert"]) & 0x3 ret.stockFcw = self.stock_fcw_alert != 0 diff --git a/opendbc_repo/opendbc/car/gm/feature_capabilities.py b/opendbc_repo/opendbc/car/gm/feature_capabilities.py index 179a1c4373..14a6d0ba3a 100644 --- a/opendbc_repo/opendbc/car/gm/feature_capabilities.py +++ b/opendbc_repo/opendbc/car/gm/feature_capabilities.py @@ -1,5 +1,6 @@ """Optional planner owners follow the finalized GM driving ownership.""" +from opendbc.car.config_cache import cached_config from opendbc.car.gm.lateral import lane_centering_supported from opendbc.car.gm.suburban import stopping_decel_rate from opendbc.car.gm.values import (malibu_hybrid_profile, camera_acc_pedal_profile, control_flags, CAR, GMFlags, GMSafetyFlags, @@ -20,15 +21,20 @@ def longitudinal_supported(cp) -> bool: try: if not _healthy(cp) or not cp.openpilotLongitudinalControl or cp.pcmCruise: return False - return (volt_cc_pedal_profile(cp) is not None or camera_acc_pedal_profile(cp) is not None or is_ordinary_camera_profile(cp, longitudinal=True) or + return _longitudinal_owner(cp) + except (AttributeError, IndexError, TypeError, ValueError): + return False + + +@cached_config +def _longitudinal_owner(cp) -> bool: + return (volt_cc_pedal_profile(cp) is not None or camera_acc_pedal_profile(cp) is not None or is_ordinary_camera_profile(cp, longitudinal=True) or is_ordinary_cc_profile(cp) or is_conventional_cc_pedal_profile(cp) or malibu_hybrid_profile(cp) is not None or is_ordinary_ascm_profile(cp, longitudinal=True) or is_ordinary_sdgm_profile(cp, longitudinal=True) or is_volt_longitudinal(cp) or is_volt_cc_longitudinal(cp) or is_bolt_euv_longitudinal(cp) or is_bolt_pedal_profile(cp) or (control_flags(cp) == int(GMFlags.CC_LONG) and is_bolt_cc_profile(cp)) or (control_flags(cp) == 0 and stopping_decel_rate(cp) is not None)) - except (AttributeError, IndexError, TypeError, ValueError): - return False def display_supported(cp) -> bool: diff --git a/opendbc_repo/opendbc/car/gm/tests/test_hotpath_configuration.py b/opendbc_repo/opendbc/car/gm/tests/test_hotpath_configuration.py new file mode 100644 index 0000000000..6e0f48189c --- /dev/null +++ b/opendbc_repo/opendbc/car/gm/tests/test_hotpath_configuration.py @@ -0,0 +1,65 @@ +"""Static admission remains exact; live authority is never cached.""" +from types import SimpleNamespace +from unittest.mock import patch +import pytest +from opendbc.car.gm import feature_capabilities as capabilities +from opendbc.car.gm.tests.test_bolt_pedal import params +from opendbc.car.gm.values import CAR, is_bolt_pedal_profile +from opendbc.car.gm.interface import CarInterface +from openpilot.starpilot.aol.tests.test_gm import _configurations +from openpilot.starpilot.aol.tests.test_gm_held_native import parse, NOW + + +def uncached(cp): + return bool(capabilities._healthy(cp) and cp.openpilotLongitudinalControl and not cp.pcmCruise and + capabilities._longitudinal_owner.__wrapped__(cp)) + + +def test_all_finalized_gm_profiles_keep_their_original_capability(): + for cp in _configurations(): + assert capabilities.longitudinal_supported(cp) == uncached(cp) + assert capabilities.longitudinal_supported(cp.as_reader()) == uncached(cp) + assert capabilities._longitudinal_owner.cache_info().currsize <= 8 + + +@pytest.mark.parametrize('field,value', [('brand', 'hyundai'), ('carFingerprint', 'unknown'), ('flags', 0), + ('passive', True), ('dashcamOnly', True), ('notCar', True), ('pcmCruise', True), + ('openpilotLongitudinalControl', False), ('alphaLongitudinalAvailable', True), ('networkLocation', 'gateway'), + ('safetyParam', 0), ('safetyModel', 'noOutput'), ('safetyConfigs', []), ('alternativeExperience', 1)]) +def test_configuration_mutations_never_reuse_an_old_capability(field, value): + cp = params(CAR.CHEVROLET_BOLT_CC_2018_2021, pedal=True, camera=True) + alias = cp.as_reader() + assert capabilities.longitudinal_supported(cp) + if field in ('safetyParam', 'safetyModel'): + setattr(cp.safetyConfigs[0], field, value) + else: + setattr(cp, field, value) + assert capabilities.longitudinal_supported(cp) == uncached(cp) + assert capabilities.longitudinal_supported(alias) == uncached(cp) + + +def test_other_brands_and_stock_longitudinal_skip_snapshot_work(): + cp = params(CAR.CHEVROLET_BOLT_CC_2018_2021, pedal=True, camera=True) + for brand, stock in [('hyundai', False), ('honda', False), ('gm', True)]: + cp.brand = brand + cp.openpilotLongitudinalControl = not stock + with patch.object(capabilities, '_longitudinal_owner', side_effect=AssertionError('unnecessary ownership snapshot')): + assert not capabilities.longitudinal_supported(cp) + + +def test_carstate_qualifies_once_per_sample_and_rechecks_next_sample(): + cp = params(CAR.CHEVROLET_BOLT_CC_2018_2021, pedal=True, camera=True) + ci = CarInterface(cp) + shell = SimpleNamespace(CP=cp) + for tick in range(40): + stamp = NOW + tick * 10_000_000 + ci.update([(stamp, parse(shell, stamp, counter=tick % 4, packets_only=True))]) + with patch('opendbc.car.gm.carstate.is_bolt_pedal_profile', wraps=is_bolt_pedal_profile) as qualify: + for tick, blocked in enumerate((False, True, False), 40): + ci.CS.CP.notCar = blocked + stamp = NOW + tick * 10_000_000 + before = len(qualify.call_args_list) + ci.update([(stamp, parse(shell, stamp, counter=tick % 4, packets_only=True))]) + current = [call for call in qualify.call_args_list[before:] if not call.kwargs.get('stock_only', False)] + assert len(current) == 1 + assert is_bolt_pedal_profile(ci.CS.CP) is not blocked diff --git a/prebuilt.json b/prebuilt.json index 79b277b469..2838af9608 100644 --- a/prebuilt.json +++ b/prebuilt.json @@ -1 +1 @@ -{"protected_inventory_sha256": "dabfff0be2893804d33116e4de36581871df656eba9f080a56dacc251284802d", "schema_version": 1} +{"protected_inventory_sha256": "59cca55bbc8f9f8d42bee954161022f1014f9087f480d4b0b77ff6b27116542a", "schema_version": 1}