From 95b6ecec8604294ffbc2af12a9d306ec44512fba Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Wed, 10 Jun 2026 10:48:32 -0500 Subject: [PATCH] Hello Poppet --- common/params_keys.h | 2 +- .../opendbc/car/subaru/carcontroller.py | 32 +++++------ .../opendbc/car/subaru/tests/test_subaru.py | 53 +++++++++++++++++++ starpilot/common/starpilot_variables.py | 8 ++- .../common/tests/test_starpilot_variables.py | 16 ++++++ starpilot/controls/starpilot_card.py | 17 +++++- .../controls/tests/test_starpilot_card.py | 41 +++++++++++--- 7 files changed, 143 insertions(+), 26 deletions(-) diff --git a/common/params_keys.h b/common/params_keys.h index d050499fb..b4f0eeadb 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -381,7 +381,7 @@ inline static std::unordered_map keys = { {"LoudBlindspotAlert", {PERSISTENT, BOOL, "0", "0", 0}}, {"LoudBlindspotAlertWhenDisengaged", {PERSISTENT, BOOL, "0", "0", 0}}, {"LowVoltageShutdown", {PERSISTENT, FLOAT, "11.8", "11.8", 3}}, - {"MainCruiseButtonControl", {PERSISTENT, INT, "9", "9", 2}}, + {"MainCruiseButtonControl", {PERSISTENT, INT, "0", "0", 2}}, {"ManualUpdateInitiated", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}}, {"AMapKey1", {PERSISTENT | DONT_LOG, STRING, "", "", 0}}, {"AMapKey2", {PERSISTENT | DONT_LOG, STRING, "", "", 0}}, diff --git a/opendbc_repo/opendbc/car/subaru/carcontroller.py b/opendbc_repo/opendbc/car/subaru/carcontroller.py index 94b83f4e3..41378ee74 100644 --- a/opendbc_repo/opendbc/car/subaru/carcontroller.py +++ b/opendbc_repo/opendbc/car/subaru/carcontroller.py @@ -107,10 +107,10 @@ class CarController(CarControllerBase): if starpilot_toggles.subaru_sng: can_sends.append(subarucan.create_preglobal_throttle(self.packer, CS.throttle_msg["COUNTER"] + 1, CS.throttle_msg, - throttle_cmd and not subaru_sng_manual_parking_brake)) + throttle_cmd)) if self.frame % 2 == 0: can_sends.append(subarucan.create_preglobal_brake_pedal(self.packer, CS.brake_pedal_msg, - speed_cmd and subaru_sng_manual_parking_brake)) + speed_cmd)) else: if self.frame % 10 == 0: can_sends.append(subarucan.create_es_dashstatus(self.packer, self.frame // 10, CS.es_dashstatus_msg, CC.enabled, @@ -125,10 +125,10 @@ class CarController(CarControllerBase): if starpilot_toggles.subaru_sng: can_sends.append(subarucan.create_throttle(self.packer, CS.throttle_msg["COUNTER"] + 1, CS.throttle_msg, - throttle_cmd and not subaru_sng_manual_parking_brake)) + throttle_cmd)) if self.frame % 2 == 0: can_sends.append(subarucan.create_brake_pedal(self.packer, self.frame // 2, CS.brake_pedal_msg, - speed_cmd and subaru_sng_manual_parking_brake, pcm_cancel_cmd)) + speed_cmd, pcm_cancel_cmd)) if self.CP.openpilotLongitudinalControl: if self.frame % 5 == 0: @@ -185,20 +185,20 @@ class CarController(CarControllerBase): if standstill_duration >= standstill_timers[1]: self.last_standstill_frame = self.frame - if manual_parking_brake: + if manual_parking_brake or not (self.CP.flags & SubaruFlags.PREGLOBAL): speed_cmd = in_standstill_hold - else: - should_resume = ( - CS.out.standstill and - _SNG_ACC_MIN_DIST < close_distance < _SNG_ACC_MAX_DIST and - close_distance > self.prev_close_distance - ) - if should_resume: - self.epb_resume_frames_remaining = 15 - throttle_cmd = self.epb_resume_frames_remaining > 0 - if self.epb_resume_frames_remaining > 0: - self.epb_resume_frames_remaining -= 1 + should_resume = ( + CS.out.standstill and + _SNG_ACC_MIN_DIST < close_distance < _SNG_ACC_MAX_DIST and + close_distance > self.prev_close_distance + ) + if should_resume: + self.epb_resume_frames_remaining = 15 + + throttle_cmd = self.epb_resume_frames_remaining > 0 + if self.epb_resume_frames_remaining > 0: + self.epb_resume_frames_remaining -= 1 self.prev_close_distance = close_distance return throttle_cmd, speed_cmd diff --git a/opendbc_repo/opendbc/car/subaru/tests/test_subaru.py b/opendbc_repo/opendbc/car/subaru/tests/test_subaru.py index 7f3d9bb3c..45e87f111 100644 --- a/opendbc_repo/opendbc/car/subaru/tests/test_subaru.py +++ b/opendbc_repo/opendbc/car/subaru/tests/test_subaru.py @@ -1,4 +1,57 @@ +from types import SimpleNamespace + +from opendbc.car.subaru.carcontroller import CarController from opendbc.car.subaru.fingerprints import FW_VERSIONS +from opendbc.car.subaru.values import SubaruFlags + + +def make_sng_controller(flags=0, prev_close_distance=4.0): + controller = object.__new__(CarController) + controller.CP = SimpleNamespace(flags=flags) + controller.frame = 60 + controller.last_standstill_frame = 0 + controller.prev_close_distance = prev_close_distance + controller.epb_resume_frames_remaining = -1 + return controller + + +def make_sng_state(close_distance=4.0, standstill=True): + cc = SimpleNamespace(enabled=True, hudControl=SimpleNamespace(leadVisible=True)) + cs = SimpleNamespace( + close_distance=close_distance, + out=SimpleNamespace(standstill=standstill), + ) + return cc, cs + + +def test_global_sng_keeps_standstill_alive_without_manual_parking_brake_toggle(): + controller = make_sng_controller() + cc, cs = make_sng_state() + + throttle_cmd, speed_cmd = controller.stop_and_go(cc, cs, manual_parking_brake=False) + + assert throttle_cmd is False + assert speed_cmd is True + + +def test_manual_parking_brake_sng_still_sends_resume_throttle(): + controller = make_sng_controller(prev_close_distance=3.9) + cc, cs = make_sng_state(close_distance=4.0) + + throttle_cmd, speed_cmd = controller.stop_and_go(cc, cs, manual_parking_brake=True) + + assert throttle_cmd is True + assert speed_cmd is True + + +def test_preglobal_sng_does_not_send_standstill_keepalive_without_manual_toggle(): + controller = make_sng_controller(flags=SubaruFlags.PREGLOBAL) + cc, cs = make_sng_state() + + throttle_cmd, speed_cmd = controller.stop_and_go(cc, cs, manual_parking_brake=False) + + assert throttle_cmd is False + assert speed_cmd is False class TestSubaruFingerprint: diff --git a/starpilot/common/starpilot_variables.py b/starpilot/common/starpilot_variables.py index c6c1890c3..8baf7e9b6 100644 --- a/starpilot/common/starpilot_variables.py +++ b/starpilot/common/starpilot_variables.py @@ -335,6 +335,11 @@ def update_starpilot_toggles(): update_starpilot_toggles._params_memory.put_bool("StarPilotTogglesUpdated", True) + +def set_speed_limit_available(openpilot_longitudinal: bool, has_cc_long: bool, pcm_cruise_speed: bool) -> bool: + return openpilot_longitudinal or has_cc_long or not pcm_cruise_speed + + def migrate_cancel_button_controls(params: Params | None = None) -> bool: params = params or Params(return_defaults=True) if params.get_bool(CANCEL_BUTTON_MIGRATION_KEY) or not params.get_bool("RemapCancelToDistance"): @@ -1193,10 +1198,11 @@ class StarPilotVariables: toggle.toyota_auto_hold = self.get_value("ToyotaAutoHold", condition=toggle.car_make == "toyota") toggle.speed_limit_controller = toggle.openpilot_longitudinal and self.get_value("SpeedLimitController") + set_speed_limit_on_engage = set_speed_limit_available(toggle.openpilot_longitudinal, toggle.has_cc_long, FPCP.pcmCruiseSpeed) speed_limit_display = toggle.show_speed_limits or toggle.speed_limit_controller toggle.map_speed_lookahead_higher = self.get_value("SLCLookaheadHigher", cast=float, condition=speed_limit_display) toggle.map_speed_lookahead_lower = self.get_value("SLCLookaheadLower", cast=float, condition=speed_limit_display) - toggle.set_speed_limit = self.get_value("SetSpeedLimit", condition=toggle.speed_limit_controller) + toggle.set_speed_limit = self.get_value("SetSpeedLimit", condition=set_speed_limit_on_engage) toggle.show_speed_limit_offset = self.get_value("ShowSLCOffset", condition=toggle.speed_limit_controller) or toggle.debug_mode slc_fallback_method = self.get_value("SLCFallback", cast=float, condition=toggle.speed_limit_controller) toggle.slc_fallback_experimental_mode = slc_fallback_method == 1 diff --git a/starpilot/common/tests/test_starpilot_variables.py b/starpilot/common/tests/test_starpilot_variables.py index b23b11e86..cc4b656fe 100644 --- a/starpilot/common/tests/test_starpilot_variables.py +++ b/starpilot/common/tests/test_starpilot_variables.py @@ -91,3 +91,19 @@ def test_cancel_button_migration_copies_distance_actions_once(): assert spv.migrate_cancel_button_controls(params) is False assert params.get_int("CancelButtonControl") == 3 + + +def test_set_speed_limit_available_on_openpilot_longitudinal(): + assert spv.set_speed_limit_available(openpilot_longitudinal=True, has_cc_long=False, pcm_cruise_speed=True) is True + + +def test_set_speed_limit_available_on_gm_helper_path(): + assert spv.set_speed_limit_available(openpilot_longitudinal=False, has_cc_long=True, pcm_cruise_speed=True) is True + + +def test_set_speed_limit_available_on_redneck_helper_path(): + assert spv.set_speed_limit_available(openpilot_longitudinal=False, has_cc_long=False, pcm_cruise_speed=False) is True + + +def test_set_speed_limit_unavailable_on_stock_pcm_without_helper(): + assert spv.set_speed_limit_available(openpilot_longitudinal=False, has_cc_long=False, pcm_cruise_speed=True) is False diff --git a/starpilot/controls/starpilot_card.py b/starpilot/controls/starpilot_card.py index d0db301a1..be3900591 100644 --- a/starpilot/controls/starpilot_card.py +++ b/starpilot/controls/starpilot_card.py @@ -25,6 +25,7 @@ class StarPilotCard: self.accel_pressed = False self.always_on_lateral_allowed = False + self.hyundai_aol_ready = False self.prev_active = False self.prev_cruise_enabled = False self.decel_pressed = False @@ -94,14 +95,23 @@ class StarPilotCard: def update(self, carState, starpilotCarState, sm, starpilot_toggles): self.switchback_mode_enabled = self.params_memory.get_bool("SwitchbackModeEnabled") + if self.CP.brand == "hyundai": + if carState.gearShifter in NON_DRIVING_GEARS or not carState.cruiseState.available: + self.hyundai_aol_ready = False + self.always_on_lateral_allowed = False + elif sm["selfdriveState"].active or carState.cruiseState.enabled: + self.hyundai_aol_ready = True + + can_toggle_aol = self.CP.brand != "hyundai" or self.hyundai_aol_ready + if self.CP.brand == "hyundai" or starpilot_toggles.lkas_allowed_for_aol: for be in carState.buttonEvents: - if be.type == ButtonType.lkas and be.pressed and starpilot_toggles.always_on_lateral_lkas: + if be.type == ButtonType.lkas and be.pressed and starpilot_toggles.always_on_lateral_lkas and can_toggle_aol: self.always_on_lateral_allowed = not self.always_on_lateral_allowed if carState.cruiseState.enabled or self.pause_lateral: self.pause_lateral = not self.always_on_lateral_allowed elif be.type == ButtonType.mainCruise and be.pressed: - if starpilot_toggles.main_cruise_aol_toggle: + if starpilot_toggles.main_cruise_aol_toggle and can_toggle_aol: self.always_on_lateral_allowed = not self.always_on_lateral_allowed elif starpilot_toggles.main_cruise_slc_adopt and starpilot_toggles.speed_limit_controller: self.params_memory.put_bool("SLCAdoptSpeedLimit", True) @@ -119,6 +129,8 @@ class StarPilotCard: # On rising edge of engagement (SET press enabling lat+long), auto-enable AOL # so that lateral persists when braking disengages longitudinal if sm["selfdriveState"].active and not self.prev_active and self.always_on_lateral_set and starpilot_toggles.always_on_lateral_lkas: + if self.CP.brand == "hyundai": + self.hyundai_aol_ready = True self.always_on_lateral_allowed = True self.prev_active = sm["selfdriveState"].active @@ -126,6 +138,7 @@ class StarPilotCard: self.always_on_lateral_enabled = self.always_on_lateral_allowed and self.always_on_lateral_set self.always_on_lateral_enabled &= carState.gearShifter not in NON_DRIVING_GEARS + self.always_on_lateral_enabled &= self.CP.brand != "hyundai" or self.hyundai_aol_ready self.always_on_lateral_enabled &= sm["starpilotPlan"].lateralCheck self.always_on_lateral_enabled &= sm["liveCalibration"].calPerc >= 1 self.always_on_lateral_enabled &= (ET.IMMEDIATE_DISABLE not in sm["selfdriveState"].alertType + sm["starpilotSelfdriveState"].alertType) or self.frogs_go_moo diff --git a/starpilot/controls/tests/test_starpilot_card.py b/starpilot/controls/tests/test_starpilot_card.py index d823a409c..6a5227e67 100644 --- a/starpilot/controls/tests/test_starpilot_card.py +++ b/starpilot/controls/tests/test_starpilot_card.py @@ -97,14 +97,17 @@ def test_honda_lkas_button_can_toggle_always_on_lateral(monkeypatch, tmp_path): assert ret.pauseLateral is False -def test_hyundai_lkas_button_still_toggles_aol_with_cruise_button_events(monkeypatch, tmp_path): +def test_hyundai_lkas_button_waits_for_normal_engagement_before_aol(monkeypatch, tmp_path): monkeypatch.setattr(spc, "Params", FakeParams) monkeypatch.setattr(spc, "is_FrogsGoMoo", lambda: False) monkeypatch.setattr(spc, "ERROR_LOGS_PATH", tmp_path) - card = spc.StarPilotCard(SimpleNamespace(brand="hyundai"), SimpleNamespace(alternativeExperience=0)) + card = spc.StarPilotCard( + SimpleNamespace(brand="hyundai"), + SimpleNamespace(alternativeExperience=spc.ALTERNATIVE_EXPERIENCE.ALWAYS_ON_LATERAL), + ) - car_state = make_car_state(button_events=[ + car_state = make_car_state(available=True, button_events=[ SimpleNamespace(type=spc.ButtonType.decelCruise, pressed=True), SimpleNamespace(type=spc.ButtonType.lkas, pressed=True), ]) @@ -114,7 +117,21 @@ def test_hyundai_lkas_button_still_toggles_aol_with_cruise_button_events(monkeyp ret = card.update(car_state, starpilot_car_state, sm, toggles) + assert ret.alwaysOnLateralAllowed is False + assert ret.alwaysOnLateralEnabled is False + + sm["selfdriveState"].active = True + car_state.buttonEvents = [] + ret = card.update(car_state, starpilot_car_state, sm, toggles) + assert ret.alwaysOnLateralAllowed is True + assert ret.alwaysOnLateralEnabled is True + + sm["selfdriveState"].active = False + car_state.buttonEvents = [SimpleNamespace(type=spc.ButtonType.lkas, pressed=True)] + ret = card.update(car_state, starpilot_car_state, sm, toggles) + + assert ret.alwaysOnLateralAllowed is False assert ret.pauseLateral is False @@ -123,13 +140,25 @@ def test_hyundai_main_cruise_button_toggles_aol_when_assigned_to_aol(monkeypatch monkeypatch.setattr(spc, "is_FrogsGoMoo", lambda: False) monkeypatch.setattr(spc, "ERROR_LOGS_PATH", tmp_path) - card = spc.StarPilotCard(SimpleNamespace(brand="hyundai"), SimpleNamespace(alternativeExperience=0)) + card = spc.StarPilotCard( + SimpleNamespace(brand="hyundai"), + SimpleNamespace(alternativeExperience=spc.ALTERNATIVE_EXPERIENCE.ALWAYS_ON_LATERAL), + ) - car_state = make_car_state(button_events=[SimpleNamespace(type=spc.ButtonType.mainCruise, pressed=True)]) + car_state = make_car_state(available=True, button_events=[SimpleNamespace(type=spc.ButtonType.mainCruise, pressed=True)]) starpilot_car_state = SimpleNamespace(distancePressed=False) sm = make_sm() - toggles = make_toggles(always_on_lateral=True, always_on_lateral_lkas=True, main_cruise_aol_toggle=True) + toggles = make_toggles(always_on_lateral=True, main_cruise_aol_toggle=True) + ret = card.update(car_state, starpilot_car_state, sm, toggles) + assert ret.alwaysOnLateralAllowed is False + + sm["selfdriveState"].active = True + car_state.buttonEvents = [] + ret = card.update(car_state, starpilot_car_state, sm, toggles) + assert ret.alwaysOnLateralAllowed is False + + car_state.buttonEvents = [SimpleNamespace(type=spc.ButtonType.mainCruise, pressed=True)] ret = card.update(car_state, starpilot_car_state, sm, toggles) assert ret.alwaysOnLateralAllowed is True