This commit is contained in:
firestar5683
2026-04-11 22:16:50 -05:00
parent d43b7d0d3f
commit f5aa89b3ff
2 changed files with 79 additions and 7 deletions
+12 -6
View File
@@ -137,7 +137,8 @@ class CarInterfaceBase(ABC):
self.params_memory = Params(memory=True)
self.distance_button = 0
self.onroad_distance_button = False
self.physical_distance_button = False
def apply(self, c: structs.CarControl, now_nanos: int | None = None, starpilot_toggles: SimpleNamespace = None) -> tuple[structs.CarControl.Actuators, list[CanData]]:
if now_nanos is None:
@@ -343,14 +344,19 @@ class CarInterfaceBase(ABC):
# save for next iteration
self.CS.out = ret
prev_distance_button = self.distance_button
self.distance_button = self.params_memory.get_bool("OnroadDistanceButtonPressed")
if self.distance_button != prev_distance_button:
ret.buttonEvents = create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise})
for be in ret.buttonEvents:
if be.type == ButtonType.gapAdjustCruise:
self.physical_distance_button = be.pressed
prev_distance_button = self.onroad_distance_button
self.onroad_distance_button = self.params_memory.get_bool("OnroadDistanceButtonPressed")
if self.onroad_distance_button != prev_distance_button:
onroad_distance_events = create_button_events(self.onroad_distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise})
ret.buttonEvents = [*(be.to_dict() for be in ret.buttonEvents), *(be.to_dict() for be in onroad_distance_events)]
# Preserve brand-specific injections (e.g. GM cancel->distance remap hold) while
# still honoring the onroad virtual distance button and native distance button.
fp_ret.distancePressed = bool(fp_ret.distancePressed) or self.distance_button or bool(self.CS.distance_button)
fp_ret.distancePressed = bool(fp_ret.distancePressed) or self.onroad_distance_button or self.physical_distance_button or bool(self.CS.distance_button)
fp_ret.ecoGear |= ret.gearShifter == GearShifter.eco
fp_ret.sportGear |= ret.gearShifter == GearShifter.sport
@@ -7,13 +7,14 @@ from hypothesis import Phase, given, settings
from collections.abc import Callable
from typing import Any
from cereal import custom
from opendbc.car import DT_CTRL, CanData, structs
from opendbc.car.car_helpers import interfaces
from opendbc.car.chrysler.carstate import CarState as ChryslerCarState
from opendbc.car.fingerprints import FW_VERSIONS
from opendbc.car.fw_versions import FW_QUERY_CONFIGS
from opendbc.car.gm.values import CAR as GM_CAR, CanBus as GMCanBus, GMSafetyFlags
from opendbc.car.interfaces import CarInterfaceBase, get_interface_attr
from opendbc.car.interfaces import CarInterfaceBase, CarStateBase, get_interface_attr
from opendbc.car.mock.values import CAR as MOCK
from opendbc.car.values import PLATFORMS
@@ -30,6 +31,34 @@ DLC_TO_LEN = [0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64]
MAX_EXAMPLES = int(os.environ.get('MAX_EXAMPLES', '15'))
class DummyCarState(CarStateBase):
def __init__(self, CP: structs.CarParams, FPCP: custom.StarPilotCarParams):
super().__init__(CP, FPCP)
self.next_button_events: list[structs.CarState.ButtonEvent] = []
def update(self, can_parsers, starpilot_toggles):
ret = structs.CarState()
ret.buttonEvents = list(self.next_button_events)
return ret, custom.StarPilotCarState.new_message()
class DummyCarController:
def __init__(self, dbc_names, CP):
self.CP = CP
def update(self, CC, CS, now_nanos, starpilot_toggles=None):
return structs.CarControl.Actuators(), []
class DummyCarInterface(CarInterfaceBase):
CarState = DummyCarState
CarController = DummyCarController
@staticmethod
def _get_params(ret, candidate, fingerprint, car_fw, alpha_long, is_release, docs):
return ret
def get_test_starpilot_toggles() -> SimpleNamespace:
return SimpleNamespace(
car_model="",
@@ -82,6 +111,43 @@ def get_fuzzy_car_interface(car_name: str, draw: DrawType) -> CarInterfaceBase:
class TestCarInterfaces:
def test_distance_button_state_tracks_gap_adjust_edges(self):
CP = structs.CarParams()
CP.carFingerprint = MOCK.MOCK
FPCP = custom.StarPilotCarParams.new_message()
car_interface = DummyCarInterface(CP, FPCP)
pressed_event = structs.CarState.ButtonEvent(pressed=True, type=structs.CarState.ButtonEvent.Type.gapAdjustCruise)
released_event = structs.CarState.ButtonEvent(pressed=False, type=structs.CarState.ButtonEvent.Type.gapAdjustCruise)
car_interface.CS.next_button_events = [pressed_event]
_, fp_ret = car_interface.update([], get_test_starpilot_toggles())
assert fp_ret.distancePressed
car_interface.CS.next_button_events = []
_, fp_ret = car_interface.update([], get_test_starpilot_toggles())
assert fp_ret.distancePressed
car_interface.CS.next_button_events = [released_event]
_, fp_ret = car_interface.update([], get_test_starpilot_toggles())
assert not fp_ret.distancePressed
def test_onroad_distance_button_does_not_replace_native_button_events(self):
CP = structs.CarParams()
CP.carFingerprint = MOCK.MOCK
FPCP = custom.StarPilotCarParams.new_message()
car_interface = DummyCarInterface(CP, FPCP)
car_interface.params_memory = SimpleNamespace(get_bool=lambda key: True)
native_event = structs.CarState.ButtonEvent(pressed=True, type=structs.CarState.ButtonEvent.Type.decelCruise)
car_interface.CS.next_button_events = [native_event]
ret, fp_ret = car_interface.update([], get_test_starpilot_toggles())
assert any(be.type == structs.CarState.ButtonEvent.Type.decelCruise and be.pressed for be in ret.buttonEvents)
assert any(be.type == structs.CarState.ButtonEvent.Type.gapAdjustCruise and be.pressed for be in ret.buttonEvents)
assert fp_ret.distancePressed
def test_chrysler_missing_lkas_signal_defaults_unpressed(self):
assert not ChryslerCarState.get_lkas_button({"TRACTION_BUTTON": {"TRACTION_OFF": 1}}, is_ram=False)
assert ChryslerCarState.get_lkas_button({"TRACTION_BUTTON": {"TOGGLE_LKAS": 1}}, is_ram=False)