mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-06 12:33:51 +08:00
Reuse exact GM configuration checks in driving hot paths
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"protected_inventory_sha256": "dabfff0be2893804d33116e4de36581871df656eba9f080a56dacc251284802d", "schema_version": 1}
|
||||
{"protected_inventory_sha256": "59cca55bbc8f9f8d42bee954161022f1014f9087f480d4b0b77ff6b27116542a", "schema_version": 1}
|
||||
|
||||
Reference in New Issue
Block a user