diff --git a/common/params_keys.h b/common/params_keys.h index dcdc95e7d..62c24430d 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -339,6 +339,7 @@ inline static std::unordered_map keys = { {"ForceStops", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}}, {"ForceStopDistanceOffset", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}}, {"ForceStandstill", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}}, + {"FordLKASButtonControlMigrated", {PERSISTENT, BOOL, "0", "0"}}, {"ForceTorqueController", {PERSISTENT, BOOL, "0", "0", 3}}, {"FordAngleBlend", {PERSISTENT, FLOAT, "0.5", "0.5", 2}}, {"FordAngleHighSpeedDamping", {PERSISTENT, FLOAT, "1.0", "1.0", 2}}, diff --git a/opendbc_repo/opendbc/car/torque_data/override.toml b/opendbc_repo/opendbc/car/torque_data/override.toml index b6d1bc697..4e8066838 100644 --- a/opendbc_repo/opendbc/car/torque_data/override.toml +++ b/opendbc_repo/opendbc/car/torque_data/override.toml @@ -131,7 +131,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] # Note that some Rivians achieve significantly less lateral acceleration than this "RIVIAN_R1_GEN1" = [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_ACCORD_11G" = [3.0, 1.35, 0.16] "HONDA_PILOT_4G" = [1.25, 1.25, 0.21] "HONDA_PASSPORT_4G" = [1.2, 1.2, 0.16] "ACURA_MDX_4G_MMR" = [1.25, 1.25, 0.15] diff --git a/opendbc_repo/opendbc/car/toyota/carcontroller.py b/opendbc_repo/opendbc/car/toyota/carcontroller.py index 32135bac5..e5b39222e 100644 --- a/opendbc_repo/opendbc/car/toyota/carcontroller.py +++ b/opendbc_repo/opendbc/car/toyota/carcontroller.py @@ -518,7 +518,8 @@ class CarController(CarControllerBase): main_accel_cmd = 0. if self.CP.flags & ToyotaFlags.SECOC.value else pcm_accel_cmd can_sends.append(toyotacan.create_accel_command(self.packer, main_accel_cmd, pcm_cancel_cmd, self.permit_braking, self.standstill_req, lead, - CS.acc_type, fcw_alert, self.distance_button, starpilot_toggles.reverse_cruise_increase)) + CS.acc_type, fcw_alert, self.distance_button, + getattr(starpilot_toggles, "reverse_cruise_increase", False))) if self.CP.flags & ToyotaFlags.SECOC.value: acc_cmd_2 = toyotacan.create_accel_command_2(self.packer, pcm_accel_cmd) acc_cmd_2 = add_mac(self.secoc_key, @@ -538,7 +539,8 @@ class CarController(CarControllerBase): can_sends.append(toyotacan.create_acc_cancel_command(self.packer)) else: can_sends.append(toyotacan.create_accel_command(self.packer, 0, pcm_cancel_cmd, True, False, lead, CS.acc_type, False, - self.distance_button, starpilot_toggles.reverse_cruise_increase)) + self.distance_button, + getattr(starpilot_toggles, "reverse_cruise_increase", False))) # *** hud ui *** if self.CP.carFingerprint != CAR.TOYOTA_PRIUS_V: diff --git a/opendbc_repo/opendbc/car/toyota/fingerprints.py b/opendbc_repo/opendbc/car/toyota/fingerprints.py index ff51888de..12863d43b 100644 --- a/opendbc_repo/opendbc/car/toyota/fingerprints.py +++ b/opendbc_repo/opendbc/car/toyota/fingerprints.py @@ -1360,6 +1360,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', @@ -1377,6 +1378,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', @@ -1411,6 +1413,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: { @@ -1448,21 +1451,26 @@ FW_VERSIONS = { CAR.LEXUS_GS_F: { (Ecu.engine, 0x7e0, None): [ b'\x0233075200\x00\x00\x00\x00\x00\x00\x00\x00530B9000\x00\x00\x00\x00\x00\x00\x00\x00', + b'\x02330Y8000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.abs, 0x7b0, None): [ b'F152630700\x00\x00\x00\x00\x00\x00', + b'F152630400\x00\x00\x00\x00\x00\x00', ], (Ecu.dsu, 0x791, None): [ b'881513016200\x00\x00\x00\x00', + b'881513011300\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ b'8965B30551\x00\x00\x00\x00\x00\x00', + b'8965B30431\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ b'8821F4702000\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ b'8646F3002100\x00\x00\x00\x00', + b'8646F3001200\x00\x00\x00\x00', ], }, CAR.LEXUS_NX: { diff --git a/opendbc_repo/opendbc/car/toyota/tests/test_toyota.py b/opendbc_repo/opendbc/car/toyota/tests/test_toyota.py index 9920d01fa..bea85747a 100644 --- a/opendbc_repo/opendbc/car/toyota/tests/test_toyota.py +++ b/opendbc_repo/opendbc/car/toyota/tests/test_toyota.py @@ -19,7 +19,7 @@ from opendbc.car.toyota.interface import CarInterface from opendbc.car.toyota.radar_interface import RadarInterface, TSSP_RADAR_EGO_SPEED_SCALE from opendbc.car.toyota.values import CAR, DBC, TSS2_CAR, ANGLE_CONTROL_CAR, RADAR_ACC_CAR, SECOC_CAR, \ FW_QUERY_CONFIG, PLATFORM_CODE_ECUS, FUZZY_EXCLUDED_PLATFORMS, \ - ToyotaFlags, ToyotaSafetyFlags, get_platform_codes + ToyotaFlags, ToyotaSafetyFlags, ToyotaStarPilotFlags, get_platform_codes from opendbc.safety import ALTERNATIVE_EXPERIENCE from openpilot.common.params import Params @@ -40,6 +40,32 @@ class TestToyotaInterfaces: # At this time, only RAV4 2023 is expected to use LTA/angle control assert ANGLE_CONTROL_CAR == {CAR.TOYOTA_RAV4_TSS2_2023} + @pytest.mark.parametrize("candidate", [CAR.TOYOTA_RAV4_TSS2, CAR.TOYOTA_RAV4_TSS2_2023]) + def test_rav4_can_filter_is_optional(self, candidate): + def get_params(has_can_filter): + fingerprint = {bus: {} for bus in range(8)} + if has_can_filter: + fingerprint[0][0x2AA] = 8 + + car_params = CarInterface.get_params( + candidate, + fingerprint, + [], + alpha_long=False, + is_release=False, + docs=False, + starpilot_toggles=SimpleNamespace(force_torque_controller=False, nnff=False, nnff_lite=False), + ) + return CarInterface.get_starpilot_params(candidate, fingerprint, [], car_params, SimpleNamespace()) + + without_filter = get_params(False) + with_filter = get_params(True) + + assert not without_filter.flags & ToyotaStarPilotFlags.RADAR_CAN_FILTER.value + assert not without_filter.flags & ToyotaStarPilotFlags.SMART_DSU.value + assert with_filter.flags & ToyotaStarPilotFlags.RADAR_CAN_FILTER.value + assert with_filter.flags & ToyotaStarPilotFlags.SMART_DSU.value + def test_rav4_prime_force_torque_controller(self): fingerprint = {bus: {} for bus in range(8)} @@ -845,6 +871,22 @@ class TestToyotaCarController: parser.update([(1, [reverse_msg])]) assert parser.vl["ACC_CONTROL"]["ALLOW_LONG_PRESS"] == 2 + def test_acc_control_accepts_toggle_namespace_without_reverse_cruise_option(self): + # Older or partially refreshed toggle broadcasts do not include this optional field. + toggles = SimpleNamespace() + assert getattr(toggles, "reverse_cruise_increase", False) is False + + packer = CANPacker(DBC[CAR.TOYOTA_HIGHLANDER_TSS2][Bus.pt]) + msg = toyotacan.create_accel_command( + packer, 0.0, False, True, False, False, 1, False, 0, + getattr(toggles, "reverse_cruise_increase", False), + ) + parser = CANParser(DBC[CAR.TOYOTA_HIGHLANDER_TSS2][Bus.pt], [("ACC_CONTROL", 0)], 0) + parser.update([(1, [msg])]) + + assert parser.can_valid + assert parser.vl["ACC_CONTROL"]["ALLOW_LONG_PRESS"] == 1 + def test_auto_brake_hold_sends_modified_pre_collision_after_timer(self): controller = self._make_controller() controller.packer = CANPacker(DBC[CAR.TOYOTA_CAMRY_TSS2][Bus.pt]) diff --git a/selfdrive/controls/tests/test_drive_helpers.py b/selfdrive/controls/tests/test_drive_helpers.py index 51ae2b554..d2ff69e48 100644 --- a/selfdrive/controls/tests/test_drive_helpers.py +++ b/selfdrive/controls/tests/test_drive_helpers.py @@ -28,3 +28,7 @@ def test_kona_non_scc_aol_gate_does_not_change_fault_or_normal_lateral_gates(): assert get_kona_non_scc_lateral_active( True, True, False, False, False, False, False, True, True, False, ) + + +def test_get_lateral_active_honors_manual_pause_while_cruise_is_engaged(): + assert not get_lateral_active(True, True, False, False, False, False, False, False) diff --git a/selfdrive/controls/tests/test_starpilot_planner.py b/selfdrive/controls/tests/test_starpilot_planner.py index deea9de2c..8625ba6b6 100644 --- a/selfdrive/controls/tests/test_starpilot_planner.py +++ b/selfdrive/controls/tests/test_starpilot_planner.py @@ -120,6 +120,20 @@ def test_standstill_without_turn_signal_keeps_lateral_allowed(monkeypatch): planner.shutdown() +def test_manual_lateral_pause_blocks_lateral_while_cruise_is_enabled(monkeypatch): + planner = make_planner(monkeypatch) + + try: + sm = make_sm(planner, frame=1, v_ego=20.0, left_blinker=False) + sm["starpilotCarState"].pauseLateral = True + + planner.update(0.0, False, sm, make_toggles()) + + assert planner.lateral_check is False + finally: + planner.shutdown() + + def test_pulse_glide_target_is_published_after_vcruise_update(monkeypatch): planner = make_planner(monkeypatch) diff --git a/selfdrive/ui/lib/starpilot_state.py b/selfdrive/ui/lib/starpilot_state.py index ba15bd506..896da931e 100644 --- a/selfdrive/ui/lib/starpilot_state.py +++ b/selfdrive/ui/lib/starpilot_state.py @@ -42,7 +42,6 @@ class StarPilotCarState: canUseSDSU: bool = False # ========== Device/Car State ========== - isFrogsGoMoo: bool = False hasPCMCruise: bool = False hasModeStarButtons: bool = False lkasAllowedForAOL: bool = False diff --git a/selfdrive/ui/mici/layouts/settings/software.py b/selfdrive/ui/mici/layouts/settings/software.py index 909623609..a329fb6d7 100644 --- a/selfdrive/ui/mici/layouts/settings/software.py +++ b/selfdrive/ui/mici/layouts/settings/software.py @@ -2,8 +2,6 @@ import os import threading from collections.abc import Callable from enum import IntEnum -from functools import cache -from pathlib import Path import pyray as rl @@ -13,7 +11,6 @@ from openpilot.selfdrive.ui.mici.layouts.settings.device import EngagedConfirmat from openpilot.selfdrive.ui.mici.widgets.button import BigButton, BigParamControl from openpilot.selfdrive.ui.mici.widgets.dialog import BigConfirmationDialog, BigDialog from openpilot.selfdrive.ui.ui_state import ui_state -from openpilot.system.hardware.hw import Paths from openpilot.system.ui.lib.application import FontWeight, MousePos, gui_app from openpilot.system.ui.lib.multilang import tr from openpilot.system.ui.widgets import Widget @@ -23,11 +20,6 @@ from openpilot.system.ui.widgets.scroller import NavScroller UPDATER_TIMEOUT = 10.0 -@cache -def _is_frogs_go_moo() -> bool: - return (Path(Paths.persist_root()) / "frogsgomoo.py").is_file() - - def _split_description(desc: str) -> tuple[str, str, str, str] | None: parts = [p.strip() for p in desc.split(" / ")] if len(parts) != 4: @@ -233,10 +225,9 @@ class BranchSelectPage(NavScroller): branches_str = params.get("UpdaterAvailableBranches") or "" branches = [b for b in branches_str.split(",") if b] - if not _is_frogs_go_moo(): - for hidden_branch in ("StarPilot-Vetting", "MAKE-PRS-HERE"): - if hidden_branch in branches: - branches.remove(hidden_branch) + for hidden_branch in ("StarPilot-Vetting", "MAKE-PRS-HERE"): + if hidden_branch in branches: + branches.remove(hidden_branch) for branch in [current_git_branch, "devel-staging", "devel", "nightly", "nightly-dev", "master"]: if branch in branches: diff --git a/selfdrive/ui/tests/test_starpilot_navigation_structure.py b/selfdrive/ui/tests/test_starpilot_navigation_structure.py index d58436c79..d0077b927 100644 --- a/selfdrive/ui/tests/test_starpilot_navigation_structure.py +++ b/selfdrive/ui/tests/test_starpilot_navigation_structure.py @@ -24,7 +24,6 @@ if "openpilot.starpilot.common.starpilot_variables" not in sys.modules: sv_mod.MODELS_PATH = "/tmp" sv_mod.EARTH_RADIUS = 6371000 sv_mod.STARPILOT_API = "" - sv_mod.FROGS_GO_MOO_PATH = "/tmp" sv_mod.KONIK_PATH = "/tmp" sys.modules["openpilot.starpilot.common.starpilot_variables"] = sv_mod @@ -362,4 +361,3 @@ def test_breadcrumb_panel_stack_unwinds_nav_stack(monkeypatch): assert len(layout._panel_stack) == 1 assert layout._panel_stack[0] == (StarPilotPanelType.MAPS, "sub1") - diff --git a/starpilot/common/starpilot_functions.py b/starpilot/common/starpilot_functions.py index 603d398c3..ce7f67799 100644 --- a/starpilot/common/starpilot_functions.py +++ b/starpilot/common/starpilot_functions.py @@ -29,9 +29,9 @@ from openpilot.starpilot.common.maps_download_progress import ( storage_bytes, ) from openpilot.starpilot.common.theme_asset_names import find_matching_theme_asset_file -from openpilot.starpilot.common.starpilot_utilities import get_starpilot_api_info, is_FrogsGoMoo, is_url_pingable, run_cmd +from openpilot.starpilot.common.starpilot_utilities import get_starpilot_api_info, is_url_pingable, run_cmd from openpilot.starpilot.common.starpilot_variables import ( - ERROR_LOGS_PATH, STARPILOT_API, FROGS_GO_MOO_PATH, HD_LOGS_PATH, KONIK_LOGS_PATH, MAPS_PATH, THEME_SAVE_PATH, + ERROR_LOGS_PATH, STARPILOT_API, HD_LOGS_PATH, KONIK_LOGS_PATH, MAPS_PATH, THEME_SAVE_PATH, StarPilotVariables, get_starpilot_toggles ) @@ -113,13 +113,6 @@ def install_starpilot(build_metadata, params): update_boot_logo(starpilot=True, selected_logo=params.get("BootLogo")) - if is_FrogsGoMoo(): - mount_options = run_cmd(["findmnt", "-n", "-o", "OPTIONS", "/persist"], "Successfully retrieved mount options", "Failed to retrieve mount options") - run_cmd(["sudo", "mount", "-o", "remount,rw", "/persist"], "Successfully remounted /persist as read-write", "Failed to remount /persist") - run_cmd(["sudo", "python3", FROGS_GO_MOO_PATH], "Successfully ran frogsgomoo.py", "Failed to run frogsgomoo.py") - run_cmd(["sudo", "mount", "-o", f"remount,{mount_options}", "/persist"], "Successfully restored /persist mount options", "Failed to restore /persist mount options") - - def register_device(build_metadata, params): def register_thread(): dongle_id = params.get("DongleId") diff --git a/starpilot/common/starpilot_utilities.py b/starpilot/common/starpilot_utilities.py index b207a347f..efd3f3ce3 100644 --- a/starpilot/common/starpilot_utilities.py +++ b/starpilot/common/starpilot_utilities.py @@ -23,7 +23,7 @@ from openpilot.system.hardware import HARDWARE from openpilot.system.version import get_build_metadata from panda import Panda, FW_PATH -from openpilot.starpilot.common.starpilot_variables import EARTH_RADIUS, STARPILOT_API, FROGS_GO_MOO_PATH, KONIK_PATH +from openpilot.starpilot.common.starpilot_variables import EARTH_RADIUS, STARPILOT_API, KONIK_PATH def capture_exception(exception): @@ -272,11 +272,6 @@ def get_sentry_dsn(): return "" -@cache -def is_FrogsGoMoo(): - return FROGS_GO_MOO_PATH.is_file() - - def is_url_pingable(url): if not url: return False diff --git a/starpilot/common/starpilot_variables.py b/starpilot/common/starpilot_variables.py index 69281f1be..201dc518b 100644 --- a/starpilot/common/starpilot_variables.py +++ b/starpilot/common/starpilot_variables.py @@ -74,7 +74,7 @@ def _lkas_allowed_for_aol(car_make, cp_flags, fpcp_safety_configs) -> bool: hyundai_can_use_lkas_for_aol = car_make == "hyundai" and ( bool(cp_flags & HyundaiFlags.CANFD) or hyundai_has_lda_button ) - return hyundai_can_use_lkas_for_aol or car_make == "honda" + return hyundai_can_use_lkas_for_aol or car_make in ("ford", "honda") def _main_cruise_aol_allowed(button_control: float) -> bool: @@ -145,8 +145,6 @@ BACKUP_PATH = _FP_CACHE_ROOT / "on_backup" STARPILOT_BACKUPS = _FP_DATA_ROOT / "backups" TOGGLE_BACKUPS = _FP_DATA_ROOT / "toggle_backups" -FROGS_GO_MOO_PATH = _FP_PERSIST_ROOT / "frogsgomoo.py" - HD_LOGS_PATH = _FP_DATA_ROOT / "media/0/realdata_HD" HD_PATH = _FP_CACHE_ROOT / "use_HD" @@ -183,6 +181,7 @@ CANCEL_BUTTON_MAPPINGS = ( ) AOL_LKAS_MIGRATION_KEY = "AOLLKASMigratedToButtonControl" +FORD_LKAS_MIGRATION_KEY = "FordLKASButtonControlMigrated" def sync_reboot_marker(marker_path: Path, enabled: bool, params: Params) -> bool: @@ -401,6 +400,18 @@ def migrate_aol_lkas_to_button_control(params: Params | None = None) -> bool: return True +def migrate_ford_lkas_button_default(car_make: str, params: Params | None = None) -> bool: + params = params or Params(return_defaults=True) + if car_make != "ford" or params.get_bool(FORD_LKAS_MIGRATION_KEY): + return False + + if params.get_int("LKASButtonControl") == BUTTON_FUNCTIONS["EXPERIMENTAL_MODE"]: + params.put_int("LKASButtonControl", BUTTON_FUNCTIONS["AOL_TOGGLE"]) + + params.put_bool(FORD_LKAS_MIGRATION_KEY, True) + return True + + class StarPilotVariables: def __init__(self): self.params = Params(return_defaults=True) @@ -419,7 +430,6 @@ class StarPilotVariables: self.testing_branch = branch == "StarPilot-Testing" self.vetting_branch = branch == "StarPilot-Vetting" - self.frogs_go_moo = FROGS_GO_MOO_PATH.is_file() # Development/vetting branches are no longer gated into dashcam mode. toggle.block_user = False @@ -611,6 +621,7 @@ class StarPilotVariables: alpha_longitudinal = CP.alphaLongitudinalAvailable toggle.car_make = CP.brand + migrate_ford_lkas_button_default(toggle.car_make, self.params) toggle.car_model = CP.carFingerprint toggle.disable_openpilot_long = self.get_value("DisableOpenpilotLongitudinal", condition=not alpha_longitudinal) friction = CP.lateralTuning.torque.friction @@ -789,7 +800,10 @@ class StarPilotVariables: toggle.always_on_lateral = self.get_value("AlwaysOnLateral") lkas_button_assigned_to_aol = self.get_button_function("LKASButtonControl") == BUTTON_FUNCTIONS["AOL_TOGGLE"] - toggle.always_on_lateral_lkas = toggle.always_on_lateral and toggle.lkas_allowed_for_aol and lkas_button_assigned_to_aol + toggle.ford_lkas_aol_toggle = toggle.car_make == "ford" and lkas_button_assigned_to_aol + toggle.always_on_lateral_lkas = ( + toggle.always_on_lateral and toggle.lkas_allowed_for_aol and lkas_button_assigned_to_aol and not toggle.ford_lkas_aol_toggle + ) toggle.always_on_lateral_main = toggle.always_on_lateral and not prohibited_main_aol toggle.always_on_lateral_pause_speed = self.get_value("PauseAOLOnBrake", cast=float, condition=toggle.always_on_lateral) diff --git a/starpilot/common/tests/test_starpilot_variables.py b/starpilot/common/tests/test_starpilot_variables.py index a52852911..09db9240d 100644 --- a/starpilot/common/tests/test_starpilot_variables.py +++ b/starpilot/common/tests/test_starpilot_variables.py @@ -21,6 +21,10 @@ def test_hyundai_and_honda_keep_lkas_aol_button_path(): assert spv._lkas_allowed_for_aol("hyundai", spv.HyundaiFlags.CANFD, []) is True +def test_ford_can_map_lkas_button_to_aol(): + assert spv._lkas_allowed_for_aol("ford", 0, []) is True + + def test_explicit_main_cruise_aol_mapping_is_not_disabled_by_longitudinal_gate(): aol_button = spv.BUTTON_FUNCTIONS["AOL_TOGGLE"] @@ -130,6 +134,33 @@ class _FakeParams: self.bools.pop(key, None) +def test_ford_lkas_default_migrates_from_experimental_to_aol_toggle(): + params = _FakeParams(ints={"LKASButtonControl": spv.BUTTON_FUNCTIONS["EXPERIMENTAL_MODE"]}) + + assert spv.migrate_ford_lkas_button_default("ford", params) is True + assert params.get_int("LKASButtonControl") == spv.BUTTON_FUNCTIONS["AOL_TOGGLE"] + assert params.get_bool(spv.FORD_LKAS_MIGRATION_KEY) is True + + params.put_int("LKASButtonControl", spv.BUTTON_FUNCTIONS["EXPERIMENTAL_MODE"]) + assert spv.migrate_ford_lkas_button_default("ford", params) is False + assert params.get_int("LKASButtonControl") == spv.BUTTON_FUNCTIONS["EXPERIMENTAL_MODE"] + + +def test_ford_lkas_default_migration_preserves_custom_mapping(): + params = _FakeParams(ints={"LKASButtonControl": spv.BUTTON_FUNCTIONS["BOOKMARK"]}) + + assert spv.migrate_ford_lkas_button_default("ford", params) is True + assert params.get_int("LKASButtonControl") == spv.BUTTON_FUNCTIONS["BOOKMARK"] + + +def test_ford_lkas_default_migration_ignores_other_brands(): + params = _FakeParams(ints={"LKASButtonControl": spv.BUTTON_FUNCTIONS["EXPERIMENTAL_MODE"]}) + + assert spv.migrate_ford_lkas_button_default("honda", params) is False + assert params.get_int("LKASButtonControl") == spv.BUTTON_FUNCTIONS["EXPERIMENTAL_MODE"] + assert params.get_bool(spv.FORD_LKAS_MIGRATION_KEY) is False + + def test_sync_reboot_marker_uses_manager_guard(tmp_path): params = _FakeParams() marker = tmp_path / "cache" / "use_HD" diff --git a/starpilot/controls/lib/starpilot_vcruise.py b/starpilot/controls/lib/starpilot_vcruise.py index fcd60bce8..50ac41853 100644 --- a/starpilot/controls/lib/starpilot_vcruise.py +++ b/starpilot/controls/lib/starpilot_vcruise.py @@ -545,7 +545,7 @@ class StarPilotVCruise: v_ego_cluster = max(sm["carState"].vEgoCluster, v_ego) v_ego_diff = v_ego_cluster - v_ego - # FrogsGoMoo's Curve Speed Controller + # Curve Speed Controller following_lead = bool(getattr(self.starpilot_planner.starpilot_following, "following_lead", False)) manual_speed_control = is_manual_speed_control(sm) csc_available = ( diff --git a/starpilot/controls/starpilot_card.py b/starpilot/controls/starpilot_card.py index 0d24a6401..04b857f4e 100644 --- a/starpilot/controls/starpilot_card.py +++ b/starpilot/controls/starpilot_card.py @@ -16,7 +16,6 @@ from openpilot.starpilot.common.experimental_state import ( sync_manual_ce_state, ) from openpilot.starpilot.common.favorite_slots import FAVORITE_ACTION_TRAFFIC_MODE_COUNTER, toggle_favorite_slot -from openpilot.starpilot.common.starpilot_utilities import is_FrogsGoMoo from openpilot.starpilot.common.starpilot_variables import ERROR_LOGS_PATH, GearShifter, NON_DRIVING_GEARS HYUNDAI_MAIN_CRUISE_AOL_CONFIRM_TIMEOUT_FRAMES = 100 @@ -74,8 +73,6 @@ class StarPilotCard: self._onroad_distance_pressed = False self.always_on_lateral_set = bool(FPCP.alternativeExperience & ALTERNATIVE_EXPERIENCE.ALWAYS_ON_LATERAL) - self.frogs_go_moo = is_FrogsGoMoo() - self.long_press_threshold = CRUISE_LONG_PRESS self.very_long_press_threshold = CRUISE_LONG_PRESS * 5 @@ -215,6 +212,13 @@ class StarPilotCard: self.params_memory.put_bool("SLCAdoptSpeedLimit", True) cruise_available_changed = self.prev_cruise_available is not None and carState.cruiseState.available != self.prev_cruise_available + ford_lateral_session_started = self.CP.brand == "ford" and ( + (cruise_available_changed and carState.cruiseState.available) or + (carState.cruiseState.enabled and not self.prev_cruise_enabled) + ) + if ford_lateral_session_started: + self.pause_lateral = False + if self.g70_main_cruise_aol_pending: if cruise_available_changed: self.always_on_lateral_allowed = carState.cruiseState.available @@ -256,9 +260,9 @@ class StarPilotCard: self.always_on_lateral_enabled &= sm["starpilotPlan"].lateralCheck self.always_on_lateral_enabled &= sm["liveCalibration"].calPerc >= 1 alert_types = sm["selfdriveState"].alertType + sm["starpilotSelfdriveState"].alertType - self.always_on_lateral_enabled &= ET.IMMEDIATE_DISABLE not in alert_types or self.frogs_go_moo + self.always_on_lateral_enabled &= ET.IMMEDIATE_DISABLE not in alert_types self.always_on_lateral_enabled &= not (carState.brakePressed and carState.vEgo < starpilot_toggles.always_on_lateral_pause_speed) or carState.standstill - self.always_on_lateral_enabled &= not self.error_log.is_file() or self.frogs_go_moo + self.always_on_lateral_enabled &= not self.error_log.is_file() if sm.updated["starpilotPlan"] or any(be_type in (ButtonType.accelCruise, ButtonType.resumeCruise) for be_type in button_event_types): self.accel_pressed = any(be_type in (ButtonType.accelCruise, ButtonType.resumeCruise) for be_type in button_event_types) @@ -327,7 +331,11 @@ class StarPilotCard: self.cancel_pulse_glide_suppressed = False if lkas_pressed: - self.handle_button_event("lkas", sm, starpilot_toggles) + if self.CP.brand != "ford" or carState.cruiseState.available: + if self.CP.brand == "ford" and getattr(starpilot_toggles, "ford_lkas_aol_toggle", False): + self.pause_lateral = not self.pause_lateral + else: + self.handle_button_event("lkas", sm, starpilot_toggles) if getattr(starpilot_toggles, "has_canfd_media_buttons", False): if starpilotCarState.modePressed: diff --git a/starpilot/controls/tests/test_starpilot_card.py b/starpilot/controls/tests/test_starpilot_card.py index c390c2273..b8ed4714f 100644 --- a/starpilot/controls/tests/test_starpilot_card.py +++ b/starpilot/controls/tests/test_starpilot_card.py @@ -83,6 +83,7 @@ def make_toggles(**overrides): "conditional_experimental_mode": False, "experimental_mode_via_lkas": False, "force_coast_via_lkas": False, + "ford_lkas_aol_toggle": False, "pulse_and_glide_available": False, "pulse_and_glide_via_cancel": False, "pulse_and_glide_via_cancel_long": False, @@ -103,7 +104,6 @@ def make_toggles(**overrides): def test_pulse_and_glide_requires_developer_access_and_active_longitudinal(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="gm"), SimpleNamespace(alternativeExperience=0)) @@ -128,7 +128,6 @@ def test_pulse_and_glide_requires_developer_access_and_active_longitudinal(monke def test_pulse_and_glide_consumes_native_cancel_when_mapped(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="gm"), SimpleNamespace(alternativeExperience=0)) @@ -155,7 +154,6 @@ def test_pulse_and_glide_consumes_native_cancel_when_mapped(monkeypatch, tmp_pat def test_pulse_and_glide_consumes_lkas_when_mapped(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="gm"), SimpleNamespace(alternativeExperience=0)) @@ -177,7 +175,6 @@ def test_pulse_and_glide_consumes_lkas_when_mapped(monkeypatch, tmp_path): def test_pulse_and_glide_long_cancel_consumes_release_after_threshold(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="gm"), SimpleNamespace(alternativeExperience=0)) @@ -230,7 +227,6 @@ def test_distance_release_normalization_is_limited_to_reported_elantra_hybrid( monkeypatch, tmp_path, car_fingerprint, expect_normalized_release, ): monkeypatch.setattr(spc, "Params", FakeParams) - monkeypatch.setattr(spc, "is_FrogsGoMoo", lambda: False) monkeypatch.setattr(spc, "ERROR_LOGS_PATH", tmp_path) card = spc.StarPilotCard( @@ -263,7 +259,6 @@ def test_distance_release_normalization_is_limited_to_reported_elantra_hybrid( def test_honda_lkas_button_can_toggle_always_on_lateral(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="honda"), SimpleNamespace(alternativeExperience=0)) @@ -281,7 +276,6 @@ def test_honda_lkas_button_can_toggle_always_on_lateral(monkeypatch, tmp_path): def test_hyundai_lkas_button_can_start_aol_before_normal_engagement(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( @@ -311,7 +305,6 @@ def test_hyundai_lkas_button_can_start_aol_before_normal_engagement(monkeypatch, def test_sonata_hybrid_lkas_button_can_start_aol_before_normal_engagement(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( @@ -332,7 +325,6 @@ def test_sonata_hybrid_lkas_button_can_start_aol_before_normal_engagement(monkey def test_sonata_hybrid_preserves_aol_latch_across_reverse(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( @@ -363,7 +355,6 @@ def test_sonata_hybrid_preserves_aol_latch_across_reverse(monkeypatch, tmp_path) def test_hyundai_aol_does_not_auto_start_from_cruise_availability(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( @@ -380,7 +371,6 @@ def test_hyundai_aol_does_not_auto_start_from_cruise_availability(monkeypatch, t def test_genesis_g90_main_aol_can_start_before_set(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( @@ -398,7 +388,6 @@ def test_genesis_g90_main_aol_can_start_before_set(monkeypatch, tmp_path): def test_other_legacy_hyundai_main_aol_still_waits_for_set(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( @@ -415,7 +404,6 @@ def test_other_legacy_hyundai_main_aol_still_waits_for_set(monkeypatch, tmp_path def test_legacy_hyundai_main_aol_waits_for_main_button_permission(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( @@ -447,7 +435,6 @@ def test_legacy_hyundai_main_aol_waits_for_main_button_permission(monkeypatch, t def test_nissan_main_aol_can_start_before_normal_engagement(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( @@ -464,7 +451,6 @@ def test_nissan_main_aol_can_start_before_normal_engagement(monkeypatch, tmp_pat def test_hyundai_canfd_lkas_button_can_toggle_aol_before_engagement(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( @@ -485,7 +471,6 @@ def test_hyundai_canfd_lkas_button_can_toggle_aol_before_engagement(monkeypatch, def test_hyundai_canfd_lkas_button_wrapped_enum_can_toggle_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( @@ -510,7 +495,6 @@ def test_hyundai_canfd_lkas_button_wrapped_enum_can_toggle_aol(monkeypatch, tmp_ def test_kia_forte_non_scc_main_cruise_button_toggles_aol_immediately(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( @@ -540,7 +524,6 @@ def test_kia_forte_non_scc_main_cruise_button_toggles_aol_immediately(monkeypatc def test_genesis_g90_main_cruise_button_toggles_aol_immediately(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( @@ -566,7 +549,6 @@ def test_genesis_g90_main_cruise_button_toggles_aol_immediately(monkeypatch, tmp def test_genesis_g70_main_cruise_button_waits_for_cruise_availability(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( @@ -604,7 +586,6 @@ def test_genesis_g70_main_cruise_button_waits_for_cruise_availability(monkeypatc def test_legacy_hyundai_main_cruise_button_toggles_aol_immediately(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( @@ -630,7 +611,6 @@ def test_legacy_hyundai_main_cruise_button_toggles_aol_immediately(monkeypatch, def test_hyundai_main_cruise_button_toggles_aol_immediately(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( @@ -655,7 +635,6 @@ def test_hyundai_main_cruise_button_toggles_aol_immediately(monkeypatch, tmp_pat def test_hyundai_main_cruise_button_wrapped_enum_can_toggle_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( @@ -688,7 +667,6 @@ def test_hyundai_main_cruise_button_wrapped_enum_can_toggle_aol(monkeypatch, tmp def test_hyundai_lda_platform_main_aol_waits_for_engagement_without_lkas_mapping(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( @@ -711,7 +689,6 @@ def test_hyundai_lda_platform_main_aol_waits_for_engagement_without_lkas_mapping def test_honda_mapped_main_cruise_button_keeps_immediate_toggle(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( @@ -729,7 +706,6 @@ def test_honda_mapped_main_cruise_button_keeps_immediate_toggle(monkeypatch, tmp def test_hyundai_main_cruise_button_adopts_slc_when_assigned_to_slc(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)) @@ -749,7 +725,6 @@ def test_hyundai_main_cruise_button_adopts_slc_when_assigned_to_slc(monkeypatch, def test_honda_lkas_button_pauses_lateral_when_cruise_is_active(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( @@ -776,9 +751,204 @@ def test_honda_lkas_button_pauses_lateral_when_cruise_is_active(monkeypatch, tmp assert ret.pauseLateral is False +def test_ford_lkas_button_pauses_lateral_when_cruise_is_active(monkeypatch, tmp_path): + monkeypatch.setattr(spc, "Params", FakeParams) + monkeypatch.setattr(spc, "ERROR_LOGS_PATH", tmp_path) + + card = spc.StarPilotCard( + SimpleNamespace(brand="ford"), + SimpleNamespace(alternativeExperience=spc.ALTERNATIVE_EXPERIENCE.ALWAYS_ON_LATERAL), + ) + card.always_on_lateral_allowed = True + + car_state = make_car_state(available=True, enabled=True, button_events=[SimpleNamespace(type=spc.ButtonType.lkas, pressed=True)]) + starpilot_car_state = SimpleNamespace(distancePressed=False) + sm = make_sm() + sm["selfdriveState"].active = True + sm["carControl"].longActive = True + toggles = make_toggles(always_on_lateral=True, always_on_lateral_main=True, pause_lateral_via_lkas=True) + card.prev_active = True + + ret = card.update(car_state, starpilot_car_state, sm, toggles) + + assert ret.alwaysOnLateralAllowed is True + assert ret.pauseLateral is True + assert ret.pauseLongitudinal is False + + car_state.buttonEvents = [SimpleNamespace(type=spc.ButtonType.lkas, pressed=False)] + card.update(car_state, starpilot_car_state, sm, toggles) + car_state.buttonEvents = [SimpleNamespace(type=spc.ButtonType.lkas, pressed=True)] + ret = card.update(car_state, starpilot_car_state, sm, toggles) + + assert ret.alwaysOnLateralAllowed is True + assert ret.pauseLateral is False + assert ret.pauseLongitudinal is False + + +def test_ford_lkas_button_pauses_aol_with_only_cruise_master_on(monkeypatch, tmp_path): + monkeypatch.setattr(spc, "Params", FakeParams) + monkeypatch.setattr(spc, "ERROR_LOGS_PATH", tmp_path) + + card = spc.StarPilotCard( + SimpleNamespace(brand="ford"), + SimpleNamespace(alternativeExperience=spc.ALTERNATIVE_EXPERIENCE.ALWAYS_ON_LATERAL), + ) + starpilot_car_state = SimpleNamespace(distancePressed=False) + sm = make_sm() + toggles = make_toggles(always_on_lateral=True, always_on_lateral_main=True, pause_lateral_via_lkas=True) + + master_on = make_car_state(available=True, enabled=False) + ret = card.update(master_on, starpilot_car_state, sm, toggles) + + assert ret.alwaysOnLateralAllowed is True + assert ret.alwaysOnLateralEnabled is True + + master_on.buttonEvents = [SimpleNamespace(type=spc.ButtonType.lkas, pressed=True)] + ret = card.update(master_on, starpilot_car_state, sm, toggles) + + assert ret.alwaysOnLateralAllowed is True + assert ret.pauseLateral is True + assert ret.pauseLongitudinal is False + + sm["starpilotPlan"].lateralCheck = False + master_on.buttonEvents = [] + ret = card.update(master_on, starpilot_car_state, sm, toggles) + + assert ret.alwaysOnLateralAllowed is True + assert ret.alwaysOnLateralEnabled is False + + master_on.cruiseState.available = False + master_on.buttonEvents = [SimpleNamespace(type=spc.ButtonType.lkas, pressed=True)] + ret = card.update(master_on, starpilot_car_state, sm, toggles) + + assert ret.alwaysOnLateralAllowed is False + assert ret.pauseLateral is True + + sm["starpilotPlan"].lateralCheck = True + master_on.cruiseState.available = True + master_on.buttonEvents = [] + ret = card.update(master_on, starpilot_car_state, sm, toggles) + + assert ret.alwaysOnLateralAllowed is True + assert ret.alwaysOnLateralEnabled is True + assert ret.pauseLateral is False + + +def test_ford_lkas_button_pauses_lateral_when_aol_is_disabled(monkeypatch, tmp_path): + monkeypatch.setattr(spc, "Params", FakeParams) + monkeypatch.setattr(spc, "ERROR_LOGS_PATH", tmp_path) + + card = spc.StarPilotCard(SimpleNamespace(brand="ford"), SimpleNamespace(alternativeExperience=0)) + car_state = make_car_state(available=True, enabled=True, button_events=[SimpleNamespace(type=spc.ButtonType.lkas, pressed=True)]) + starpilot_car_state = SimpleNamespace(distancePressed=False) + sm = make_sm() + sm["selfdriveState"].active = True + sm["carControl"].longActive = True + toggles = make_toggles(pause_lateral_via_lkas=True) + card.prev_active = True + + ret = card.update(car_state, starpilot_car_state, sm, toggles) + + assert ret.alwaysOnLateralAllowed is False + assert ret.pauseLateral is True + assert ret.pauseLongitudinal is False + + car_state.buttonEvents = [SimpleNamespace(type=spc.ButtonType.lkas, pressed=False)] + card.update(car_state, starpilot_car_state, sm, toggles) + 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 + assert ret.pauseLongitudinal is False + + +def test_ford_lkas_button_can_use_aol_mapping(monkeypatch, tmp_path): + monkeypatch.setattr(spc, "Params", FakeParams) + monkeypatch.setattr(spc, "ERROR_LOGS_PATH", tmp_path) + + card = spc.StarPilotCard( + SimpleNamespace(brand="ford"), + SimpleNamespace(alternativeExperience=spc.ALTERNATIVE_EXPERIENCE.ALWAYS_ON_LATERAL), + ) + car_state = make_car_state(available=True) + toggles = make_toggles(always_on_lateral=True, always_on_lateral_main=True, ford_lkas_aol_toggle=True, lkas_allowed_for_aol=True) + + ret = card.update(car_state, SimpleNamespace(distancePressed=False), make_sm(), toggles) + + assert ret.alwaysOnLateralAllowed is True + assert ret.pauseLateral is False + + car_state.buttonEvents = [SimpleNamespace(type=spc.ButtonType.lkas, pressed=True)] + ret = card.update(car_state, SimpleNamespace(distancePressed=False), make_sm(), toggles) + + assert ret.alwaysOnLateralAllowed is True + assert ret.pauseLateral is True + + car_state.buttonEvents = [SimpleNamespace(type=spc.ButtonType.lkas, pressed=False)] + card.update(car_state, SimpleNamespace(distancePressed=False), make_sm(), toggles) + car_state.buttonEvents = [SimpleNamespace(type=spc.ButtonType.lkas, pressed=True)] + ret = card.update(car_state, SimpleNamespace(distancePressed=False), make_sm(), toggles) + + assert ret.alwaysOnLateralAllowed is True + assert ret.pauseLateral is False + + +def test_ford_aol_mapping_pauses_lateral_when_aol_is_disabled(monkeypatch, tmp_path): + monkeypatch.setattr(spc, "Params", FakeParams) + monkeypatch.setattr(spc, "ERROR_LOGS_PATH", tmp_path) + + card = spc.StarPilotCard(SimpleNamespace(brand="ford"), SimpleNamespace(alternativeExperience=0)) + card.prev_cruise_enabled = True + car_state = make_car_state(available=True, enabled=True, button_events=[SimpleNamespace(type=spc.ButtonType.lkas, pressed=True)]) + sm = make_sm() + sm["selfdriveState"].active = True + sm["carControl"].longActive = True + + ret = card.update(car_state, SimpleNamespace(distancePressed=False), sm, make_toggles(ford_lkas_aol_toggle=True)) + + assert ret.alwaysOnLateralAllowed is False + assert ret.pauseLateral is True + assert ret.pauseLongitudinal is False + + +def test_ford_lkas_button_can_keep_experimental_mapping(monkeypatch, tmp_path): + monkeypatch.setattr(spc, "Params", FakeParams) + monkeypatch.setattr(spc, "ERROR_LOGS_PATH", tmp_path) + + card = spc.StarPilotCard(SimpleNamespace(brand="ford"), SimpleNamespace(alternativeExperience=0)) + card.prev_cruise_enabled = True + car_state = make_car_state(available=True, enabled=True, button_events=[SimpleNamespace(type=spc.ButtonType.lkas, pressed=True)]) + sm = make_sm() + sm["carControl"].longActive = True + + ret = card.update(car_state, SimpleNamespace(distancePressed=False), sm, make_toggles(experimental_mode_via_lkas=True)) + + assert card.params.get_bool("ExperimentalMode") is True + assert ret.pauseLateral is False + + +def test_ford_new_longitudinal_engagement_resumes_lateral(monkeypatch, tmp_path): + monkeypatch.setattr(spc, "Params", FakeParams) + monkeypatch.setattr(spc, "ERROR_LOGS_PATH", tmp_path) + + card = spc.StarPilotCard(SimpleNamespace(brand="ford"), SimpleNamespace(alternativeExperience=0)) + card.pause_lateral = True + + car_state = make_car_state(available=True, enabled=True) + starpilot_car_state = SimpleNamespace(distancePressed=False) + sm = make_sm() + sm["selfdriveState"].active = True + sm["carControl"].longActive = True + + ret = card.update(car_state, starpilot_car_state, sm, make_toggles()) + + assert ret.pauseLateral is False + assert ret.pauseLongitudinal is False + + def test_honda_main_aol_follows_cruise_main_without_manual_aol_button_mapping(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( @@ -795,7 +965,6 @@ def test_honda_main_aol_follows_cruise_main_without_manual_aol_button_mapping(mo def test_hyundai_main_aol_persists_after_brake_disengage_without_manual_aol_button_mapping(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( @@ -823,7 +992,6 @@ def test_hyundai_main_aol_persists_after_brake_disengage_without_manual_aol_butt def test_non_button_aol_platform_keeps_main_aol_when_main_cruise_is_mapped(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( @@ -840,7 +1008,6 @@ def test_non_button_aol_platform_keeps_main_aol_when_main_cruise_is_mapped(monke def test_main_aol_still_follows_cruise_main_for_other_platforms(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="toyota", carFingerprint="TOYOTA_TEST", pcmCruise=True), @@ -855,7 +1022,6 @@ def test_main_aol_still_follows_cruise_main_for_other_platforms(monkeypatch, tmp def test_pacifica_hybrid_main_aol_waits_for_set_press(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( @@ -890,7 +1056,6 @@ def test_pacifica_hybrid_main_aol_waits_for_set_press(monkeypatch, tmp_path): def test_conditional_chill_wheel_override_cycles_manual_state(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="gm"), SimpleNamespace(alternativeExperience=0)) @@ -907,7 +1072,6 @@ def test_conditional_chill_wheel_override_cycles_manual_state(monkeypatch, tmp_p def test_cancel_button_short_press_can_run_independent_mapping(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="gm"), SimpleNamespace(alternativeExperience=0)) @@ -933,7 +1097,6 @@ def test_cancel_button_short_press_can_run_independent_mapping(monkeypatch, tmp_ def test_lkas_button_press_creates_bookmark(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="toyota"), SimpleNamespace(alternativeExperience=0)) @@ -946,7 +1109,6 @@ def test_lkas_button_press_creates_bookmark(monkeypatch, tmp_path): def test_favorite_wheel_action_toggles_hidden_onroad_slot(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="gm"), SimpleNamespace(alternativeExperience=0)) @@ -963,7 +1125,6 @@ def test_favorite_wheel_action_toggles_hidden_onroad_slot(monkeypatch, tmp_path) def test_favorite_wheel_action_can_press_virtual_resume(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="gm"), SimpleNamespace(alternativeExperience=0)) @@ -978,7 +1139,6 @@ def test_favorite_wheel_action_can_press_virtual_resume(monkeypatch, tmp_path): def test_favorite_action_toggles_traffic_mode_when_longitudinal_control_is_active(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="gm"), SimpleNamespace(alternativeExperience=0)) @@ -998,7 +1158,6 @@ def test_favorite_action_toggles_traffic_mode_when_longitudinal_control_is_activ def test_favorite_traffic_mode_action_is_consumed_when_not_active(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="gm"), SimpleNamespace(alternativeExperience=0)) diff --git a/starpilot/system/starpilot_stats.py b/starpilot/system/starpilot_stats.py index 3f3dc7dc6..f8c0214d3 100644 --- a/starpilot/system/starpilot_stats.py +++ b/starpilot/system/starpilot_stats.py @@ -200,10 +200,6 @@ def send_stats(): build_metadata = get_build_metadata() starpilot_toggles = get_starpilot_toggles() - frogs_go_moo = getattr(starpilot_toggles, "frogs_go_moo", False) - if frogs_go_moo: - return - if starpilot_toggles.car_make == "mock": return