From 26de11932ac7d4a585a8b862e9e3006fa1134d5f Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Tue, 15 Sep 2026 20:23:01 -0500 Subject: [PATCH] In&Out --- opendbc_repo/opendbc/car/hyundai/carstate.py | 6 ++ .../car/hyundai/tests/test_ray_pedal.py | 37 +++++++++++ opendbc_repo/opendbc/safety/modes/hyundai.h | 6 +- .../safety/tests/test_hyundai_ray_pedal.py | 35 +++++++++++ selfdrive/ui/mici/onroad/hud_renderer.py | 12 +++- selfdrive/ui/onroad/exp_button.py | 35 +++++++++-- selfdrive/ui/onroad/starpilot/pedal_icons.py | 6 +- .../ui/tests/test_rivian_lateral_mode.py | 18 +++++- selfdrive/ui/ui_state.py | 5 +- .../common/assets/device_settings_layout.json | 16 +---- starpilot/common/car_params_capability.py | 39 ++++++++++++ .../tests/test_car_params_capability.py | 63 +++++++++++++++++++ .../tests/test_device_settings_layout.py | 9 +-- starpilot/system/the_galaxy/the_galaxy.py | 3 +- 14 files changed, 260 insertions(+), 30 deletions(-) create mode 100644 starpilot/common/car_params_capability.py create mode 100644 starpilot/common/tests/test_car_params_capability.py diff --git a/opendbc_repo/opendbc/car/hyundai/carstate.py b/opendbc_repo/opendbc/car/hyundai/carstate.py index c2d58219b4..60fdad9c19 100644 --- a/opendbc_repo/opendbc/car/hyundai/carstate.py +++ b/opendbc_repo/opendbc/car/hyundai/carstate.py @@ -413,6 +413,12 @@ class CarState(CarStateBase): else: ret.gasPressed = bool(cp.vl["EMS16"]["CF_Ems_AclAct"]) + if self.CP.carFingerprint == CAR.KIA_RAY_EV and self.CP.enableGasInterceptorDEPRECATED and self.ray_pedal_valid: + driver_pedal = cp_pedal.vl_raw["GAS_SENSOR"] + track1 = int.from_bytes(driver_pedal[:2], "big") + track2 = int.from_bytes(driver_pedal[2:4], "big") + ret.gasPressed = track1 > 272 or track2 > 513 + # Gear Selection via Cluster - For those Kia/Hyundai which are not fully discovered, we can use the Cluster Indicator for Gear Selection, # as this seems to be standard over all cars, but is not the preferred method. if self.CP.flags & (HyundaiFlags.HYBRID | HyundaiFlags.EV): diff --git a/opendbc_repo/opendbc/car/hyundai/tests/test_ray_pedal.py b/opendbc_repo/opendbc/car/hyundai/tests/test_ray_pedal.py index fe8a339619..64be3e83eb 100644 --- a/opendbc_repo/opendbc/car/hyundai/tests/test_ray_pedal.py +++ b/opendbc_repo/opendbc/car/hyundai/tests/test_ray_pedal.py @@ -91,6 +91,43 @@ def test_ray_pedal_fault_clears_only_with_healthy_sensor_state(): assert not ret.accFaulted +def test_ray_driver_override_uses_physical_interceptor_tracks(): + CP = CarInterface.get_params(CAR.KIA_RAY_EV, ray_fingerprint(), [], False, False, False, None) + state = CarState(CP, None) + parsers = state.get_can_parsers(CP) + native_gas = (0x371, bytes.fromhex("004e008000ae0700"), 0) + physical_rest = (0x201, bytes.fromhex("010801f30cef"), 0) + for parser in parsers.values(): + parser.update([(1_000_000_000, [native_gas, physical_rest])]) + ret, _ = state.update(parsers, SimpleNamespace()) + assert state.ray_pedal_valid + assert not ret.gasPressed + + packer = CANPacker("hyundai_kia_ray_pedal") + physical_press = packer.make_can_msg("GAS_SENSOR", 0, { + "INTERCEPTOR_GAS": (310 - 264) * 0.672, + "INTERCEPTOR_GAS2": (593 - 497) * 0.332, + "STATE": 0, "COUNTER_PEDAL": 13, + }) + for parser in parsers.values(): + parser.update([(1_020_000_000, [physical_press])]) + ret, _ = state.update(parsers, SimpleNamespace()) + assert ret.gasPressed + + +def test_ray_without_pedal_keeps_native_gas_detection(): + CP = CarInterface.get_params(CAR.KIA_RAY_EV, ray_fingerprint(sensor_length=8), [], False, False, False, None) + assert not CP.enableGasInterceptorDEPRECATED + state = CarState(CP, None) + parsers = state.get_can_parsers(CP) + assert Bus.party not in parsers + native_gas = (0x371, bytes.fromhex("004e008000ae0700"), 0) + for parser in parsers.values(): + parser.update([(1_000_000_000, [native_gas])]) + ret, _ = state.update(parsers, SimpleNamespace()) + assert ret.gasPressed + + def test_ray_controller_heartbeats_and_only_actuates_when_ready(): CP = CarInterface.get_params(CAR.KIA_RAY_EV, ray_fingerprint(), [], False, False, False, None) controller = CarController(DBC[CP.carFingerprint], CP) diff --git a/opendbc_repo/opendbc/safety/modes/hyundai.h b/opendbc_repo/opendbc/safety/modes/hyundai.h index 67ace4925b..09c324e67d 100644 --- a/opendbc_repo/opendbc/safety/modes/hyundai.h +++ b/opendbc_repo/opendbc/safety/modes/hyundai.h @@ -259,7 +259,11 @@ static void hyundai_rx_hook(const CANPacket_t *msg) { } // gas press, different for EV, hybrid, and ICE models - if ((msg->addr == 0x371U) && hyundai_ev_gas_signal) { + if ((msg->addr == 0x201U) && hyundai_ray_pedal) { + const uint16_t track1 = ((uint16_t)msg->data[0] << 8U) | msg->data[1]; + const uint16_t track2 = ((uint16_t)msg->data[2] << 8U) | msg->data[3]; + gas_pressed = (track1 > 272U) || (track2 > 513U); + } else if ((msg->addr == 0x371U) && hyundai_ev_gas_signal && !hyundai_ray_pedal) { gas_pressed = (((msg->data[4] & 0x7FU) << 1) | (msg->data[3] >> 7)) != 0U; } else if ((msg->addr == 0x371U) && hyundai_hybrid_gas_signal) { gas_pressed = msg->data[7] != 0U; diff --git a/opendbc_repo/opendbc/safety/tests/test_hyundai_ray_pedal.py b/opendbc_repo/opendbc/safety/tests/test_hyundai_ray_pedal.py index 7dd0280e9a..2845f4db93 100644 --- a/opendbc_repo/opendbc/safety/tests/test_hyundai_ray_pedal.py +++ b/opendbc_repo/opendbc/safety/tests/test_hyundai_ray_pedal.py @@ -47,3 +47,38 @@ def test_ray_pedal_rx_crc_is_checked_only_for_ray_signature(): bad_crc = bytearray(dat) bad_crc[-1] ^= 1 assert not safety.safety_rx_hook(libsafety_py.make_CANPacket(0x201, 0, bytes(bad_crc))) + + +def test_ray_native_commanded_gas_does_not_cancel_driver_override_safety(): + safety = libsafety_py.libsafety + safety.set_safety_hooks(CarParams.SafetyModel.hyundai, 0x9405) + safety.init_tests() + safety.set_controls_allowed(True) + packer = CANPacker("hyundai_kia_ray_pedal") + + physical_rest = bytes.fromhex("010801f30cef") + native_gas = bytes.fromhex("004e008000ae0700") + assert safety.safety_rx_hook(libsafety_py.make_CANPacket(0x201, 0, physical_rest)) + assert safety.safety_rx_hook(libsafety_py.make_CANPacket(0x371, 0, native_gas)) + assert not safety.get_gas_pressed_prev() + addr, dat, bus = create_gas_interceptor_command(packer, 0.1, 3) + assert safety.safety_tx_hook(libsafety_py.make_CANPacket(addr, bus, dat)) + + physical_press = packer.make_can_msg("GAS_SENSOR", 0, { + "INTERCEPTOR_GAS": (310 - 264) * 0.672, + "INTERCEPTOR_GAS2": (593 - 497) * 0.332, + "STATE": 0, "COUNTER_PEDAL": 13, + }) + press_addr, press_dat, press_bus = physical_press + assert safety.safety_rx_hook(libsafety_py.make_CANPacket(press_addr, press_bus, press_dat)) + assert safety.get_gas_pressed_prev() + assert not safety.safety_tx_hook(libsafety_py.make_CANPacket(addr, bus, dat)) + + +def test_non_ray_hyundai_ev_keeps_native_driver_gas_detection(): + safety = libsafety_py.libsafety + safety.set_safety_hooks(CarParams.SafetyModel.hyundai, 0x1001) + safety.init_tests() + native_gas = bytes.fromhex("004e008000ae0700") + assert safety.safety_rx_hook(libsafety_py.make_CANPacket(0x371, 0, native_gas)) + assert safety.get_gas_pressed_prev() diff --git a/selfdrive/ui/mici/onroad/hud_renderer.py b/selfdrive/ui/mici/onroad/hud_renderer.py index f5861b8dfa..b48020759d 100644 --- a/selfdrive/ui/mici/onroad/hud_renderer.py +++ b/selfdrive/ui/mici/onroad/hud_renderer.py @@ -195,12 +195,20 @@ class HudRenderer(Widget): controls_state = sm['controlsState'] car_state = sm['carState'] rivian_lateral_mode.update() + car_control = sm['carControl'] if sm.valid.get('carControl', False) else None + actuators = getattr(car_control, "actuators", None) + long_active = bool(getattr(car_control, "longActive", False)) starpilot_car_state = sm['starpilotCarState'] if sm.valid.get('starpilotCarState', False) else None + pedal_feedback_enabled = ui_state.ui_params.get_bool("PedalsOnUI") or ui_state.ui_params.get_bool("ShowBrakeStatus") self._wheel_tint = get_wheel_tint( - getattr(car_state, "brakePressed", False), + getattr(car_state, "brakePressed", False) or getattr(car_state, "regenBraking", False), rivian_lateral_mode.wheel_tint, - ui_state.ui_params.get_bool("ShowBrakeStatus"), + pedal_feedback_enabled, getattr(starpilot_car_state, "brakeLights", False), + getattr(car_state, "aEgo", 0.0), + getattr(car_state, "gasPressed", False), + getattr(actuators, "accel", 0.0) if long_active else 0.0, + getattr(actuators, "gas", 0.0) if long_active else 0.0, ) v_cruise_cluster = car_state.vCruiseCluster diff --git a/selfdrive/ui/onroad/exp_button.py b/selfdrive/ui/onroad/exp_button.py index 927e78d142..84f94fee35 100644 --- a/selfdrive/ui/onroad/exp_button.py +++ b/selfdrive/ui/onroad/exp_button.py @@ -14,11 +14,27 @@ from openpilot.starpilot.common.experimental_state import ( BRAKE_WHEEL_COLOR = rl.Color(255, 0, 0, 255) +ACCEL_WHEEL_COLOR = rl.Color(22, 127, 64, 255) +BRAKE_ACCEL_THRESHOLD = 0.25 +COMMAND_ACCEL_THRESHOLD = 0.05 -def get_wheel_tint(brake_pressed: bool, mode_tint: rl.Color | None, brake_status_enabled: bool, - brake_lights: bool = False) -> rl.Color | None: - return BRAKE_WHEEL_COLOR if brake_status_enabled and (brake_pressed or brake_lights) else mode_tint +def get_wheel_tint(brake_pressed: bool, mode_tint: rl.Color | None, pedal_feedback_enabled: bool, + brake_lights: bool = False, acceleration: float = 0.0, + gas_pressed: bool = False, commanded_accel: float = 0.0, + commanded_gas: float = 0.0) -> rl.Color | None: + if not pedal_feedback_enabled: + return mode_tint + + braking = brake_pressed or brake_lights or acceleration < -BRAKE_ACCEL_THRESHOLD or \ + commanded_accel < -COMMAND_ACCEL_THRESHOLD + accelerating = gas_pressed or acceleration > BRAKE_ACCEL_THRESHOLD or \ + commanded_accel > COMMAND_ACCEL_THRESHOLD or commanded_gas > COMMAND_ACCEL_THRESHOLD + if braking: + return BRAKE_WHEEL_COLOR + if accelerating: + return ACCEL_WHEEL_COLOR + return mode_tint class ExpButton(Widget): @@ -112,12 +128,21 @@ class ExpButton(Widget): texture = self._txt_exp if exp_mode else self._txt_wheel color = self._white_color tint = None + car_state = ui_state.sm["carState"] + car_control = ui_state.sm["carControl"] if getattr(ui_state.sm, "valid", {}).get("carControl", False) else None + actuators = getattr(car_control, "actuators", None) + long_active = bool(getattr(car_control, "longActive", False)) starpilot_car_state = ui_state.sm["starpilotCarState"] if getattr(ui_state.sm, "valid", {}).get("starpilotCarState", False) else None + pedal_feedback_enabled = self._params.get_bool("PedalsOnUI") or self._params.get_bool("ShowBrakeStatus") wheel_tint = get_wheel_tint( - getattr(ui_state.sm["carState"], "brakePressed", False), + getattr(car_state, "brakePressed", False) or getattr(car_state, "regenBraking", False), self.wheel_tint, - self._params.get_bool("ShowBrakeStatus"), + pedal_feedback_enabled, getattr(starpilot_car_state, "brakeLights", False), + getattr(car_state, "aEgo", 0.0), + getattr(car_state, "gasPressed", False), + getattr(actuators, "accel", 0.0) if long_active else 0.0, + getattr(actuators, "gas", 0.0) if long_active else 0.0, ) if wheel_tint is not None: tint = rl.Color(wheel_tint.r, wheel_tint.g, wheel_tint.b, self._white_color.a) diff --git a/selfdrive/ui/onroad/starpilot/pedal_icons.py b/selfdrive/ui/onroad/starpilot/pedal_icons.py index 0a4417a74f..96939f97c0 100644 --- a/selfdrive/ui/onroad/starpilot/pedal_icons.py +++ b/selfdrive/ui/onroad/starpilot/pedal_icons.py @@ -15,7 +15,11 @@ def render_pedal_icons(start_x: float, start_y: float, font): return standstill = getattr(car_state, "standstill", False) - brake_lights = getattr(car_state, "brakeLights", False) + starpilot_car_state = ui_state.sm["starpilotCarState"] if ui_state.sm.valid.get("starpilotCarState", False) else None + brake_lights = (getattr(car_state, "brakeLights", False) or + getattr(car_state, "brakeLightsDEPRECATED", False) or + getattr(car_state, "regenBraking", False) or + getattr(starpilot_car_state, "brakeLights", False)) acceleration_ego = getattr(car_state, "aEgo", 0.0) dynamic_pedals = params.get_bool("DynamicPedalsOnUI") diff --git a/selfdrive/ui/tests/test_rivian_lateral_mode.py b/selfdrive/ui/tests/test_rivian_lateral_mode.py index eaff996d75..ca80c701df 100644 --- a/selfdrive/ui/tests/test_rivian_lateral_mode.py +++ b/selfdrive/ui/tests/test_rivian_lateral_mode.py @@ -300,7 +300,7 @@ def test_non_mici_wheel_icon_turns_red_when_brakes_are_pressed(monkeypatch): module, draws = load_exp_button(monkeypatch) button = module.ExpButton(192, 144) button.wheel_tint = FakeColor(0x4D, 0x9D, 0xFF, 255) - module.ui_state.ui_params.get_bool = lambda key, *args, **kwargs: key == "ShowBrakeStatus" + module.ui_state.ui_params.get_bool = lambda key, *args, **kwargs: key == "PedalsOnUI" module.ui_state.sm["carState"].brakePressed = True button._update_state() @@ -311,6 +311,20 @@ def test_non_mici_wheel_icon_turns_red_when_brakes_are_pressed(monkeypatch): assert (texture_color.r, texture_color.g, texture_color.b, texture_color.a) == (255, 0, 0, 255) +def test_non_mici_wheel_icon_turns_green_when_accelerating(monkeypatch): + module, draws = load_exp_button(monkeypatch) + button = module.ExpButton(192, 144) + button.wheel_tint = FakeColor(0x4D, 0x9D, 0xFF, 255) + module.ui_state.ui_params.get_bool = lambda key, *args, **kwargs: key == "PedalsOnUI" + module.ui_state.sm["carState"].aEgo = 0.4 + button._update_state() + + button._render(FakeRectangle(0, 0, 192, 192)) + + texture_color = draws["textures"][0][-1] + assert (texture_color.r, texture_color.g, texture_color.b, texture_color.a) == (22, 127, 64, 255) + + def test_non_mici_wheel_icon_uses_reported_brake_lights(monkeypatch): module, draws = load_exp_button(monkeypatch) button = module.ExpButton(192, 144) @@ -321,7 +335,7 @@ def test_non_mici_wheel_icon_uses_reported_brake_lights(monkeypatch): module.ui_state.sm = FakeUiSubMaster(module.ui_state.sm) module.ui_state.sm.valid = {"starpilotCarState": True} module.ui_state.sm["starpilotCarState"] = SimpleNamespace(brakeLights=True) - module.ui_state.ui_params.get_bool = lambda key, *args, **kwargs: key == "ShowBrakeStatus" + module.ui_state.ui_params.get_bool = lambda key, *args, **kwargs: key == "PedalsOnUI" button._update_state() button._render(FakeRectangle(0, 0, 192, 192)) diff --git a/selfdrive/ui/ui_state.py b/selfdrive/ui/ui_state.py index 3bcfb1007a..10c22d6384 100644 --- a/selfdrive/ui/ui_state.py +++ b/selfdrive/ui/ui_state.py @@ -13,6 +13,7 @@ from openpilot.selfdrive.ui.lib.prime_state import PrimeState from openpilot.selfdrive.ui.lib.ui_param_cache import shared_ui_params from openpilot.system.ui.lib.application import gui_app from openpilot.starpilot.common.lateral_only_experimental import lateral_only_experimental_available +from openpilot.starpilot.common.car_params_capability import capability_car_params_bytes from openpilot.system.hardware import HARDWARE, PC from openpilot.starpilot.common.screen_settings import ( alert_wake_key, brightness_preferences, calculate_screen_brightness, enabled_wake_keys, standby_button_press_time, @@ -284,7 +285,7 @@ class UIState: def update_params(self) -> None: # For slower operations # Update longitudinal control state - CP_bytes = self.params.get("CarParamsPersistent") + CP_bytes = capability_car_params_bytes(self.params) if CP_bytes is not None: self.CP = messaging.log_from_bytes(CP_bytes, car.CarParams) if self.CP.alphaLongitudinalAvailable: @@ -296,6 +297,8 @@ class UIState: lateral_only_experimental_available(self.CP) ) else: + self.CP = None + self.has_longitudinal_control = False self.experimental_mode_available = False self._param_update_time = time.monotonic() diff --git a/starpilot/common/assets/device_settings_layout.json b/starpilot/common/assets/device_settings_layout.json index c9983a6ee1..e61ab71aab 100644 --- a/starpilot/common/assets/device_settings_layout.json +++ b/starpilot/common/assets/device_settings_layout.json @@ -2768,9 +2768,9 @@ }, { "key": "PedalsOnUI", - "label": "Gas / Brake Pedal Indicators", - "description": "On-screen gas and brake indicators.\n\nDynamic: Opacity changes according to how much openpilot is accelerating or braking\nStatic: Full when active, dim when not", - "picker_description": "Shows gas and brake indicators on the driving screen.", + "label": "Pedal-Responsive Wheel", + "description": "Tint the on-screen steering-wheel icon green while accelerating and red while braking. Also show gas and brake indicators.\n\nDynamic: Opacity changes according to how much openpilot is accelerating or braking\nStatic: Full when active, dim when not", + "picker_description": "Colors the driving-screen wheel by acceleration and braking, with optional pedal indicators.", "data_type": "bool", "ui_type": "toggle", "is_parent_toggle": true, @@ -2807,16 +2807,6 @@ "parent_key": "CustomUI", "settings_tier": "simple" }, - { - "key": "ShowBrakeStatus", - "label": "Show Brake Status", - "description": "Tint the on-screen steering-wheel icon red while the car reports that its brake lights are on.", - "picker_description": "Tints the on-screen steering-wheel icon red while the brake lights are on.", - "data_type": "bool", - "ui_type": "toggle", - "galaxy_only": true, - "settings_tier": "simple" - }, { "key": "ModelUI", "label": "Model UI", diff --git a/starpilot/common/car_params_capability.py b/starpilot/common/car_params_capability.py new file mode 100644 index 0000000000..08a9af2a6d --- /dev/null +++ b/starpilot/common/car_params_capability.py @@ -0,0 +1,39 @@ +"""Choose a recognized CarParams snapshot for capability-gated settings. + +The current persistent snapshot may temporarily be MOCK while the car process +starts. A matching previous route is safe for displaying an *available* toggle; +it never enables control or changes the panda safety configuration by itself. +""" + +from cereal import car + + +def _fingerprint(raw: bytes | None) -> str: + if not raw: + return "" + try: + with car.CarParams.from_bytes(raw) as cp: + return str(cp.carFingerprint) + except Exception: + return "" + + +def capability_car_params_bytes(params) -> bytes | None: + """Prefer live/recognized params; fallback only to the exact forced model.""" + model = params.get("CarModel", encoding="utf-8") or "" + forced = params.get_bool("ForceFingerprint") + current_keys = ("CarParams", "CarParamsPersistent") if params.get_bool("IsOnroad") else ("CarParamsPersistent",) + + for key in current_keys: + raw = params.get(key) + fingerprint = _fingerprint(raw) + if fingerprint and fingerprint != "MOCK": + if forced and model and fingerprint != model: + return None + return raw + + if forced and model: + previous = params.get("CarParamsPrevRoute") + if _fingerprint(previous) == model: + return previous + return None diff --git a/starpilot/common/tests/test_car_params_capability.py b/starpilot/common/tests/test_car_params_capability.py new file mode 100644 index 0000000000..364fb4158e --- /dev/null +++ b/starpilot/common/tests/test_car_params_capability.py @@ -0,0 +1,63 @@ +from cereal import car + +from openpilot.starpilot.common.car_params_capability import capability_car_params_bytes + + +class FakeParams: + def __init__(self, values): + self.values = values + + def get(self, key, encoding=None): + value = self.values.get(key) + return value.decode() if encoding and isinstance(value, bytes) else value + + def get_bool(self, key): + return self.values.get(key) in (True, b"1", "1") + + +def cp_bytes(fingerprint, alpha_available=False): + cp = car.CarParams.new_message() + cp.carFingerprint = fingerprint + cp.alphaLongitudinalAvailable = alpha_available + return cp.to_bytes() + + +def test_matching_previous_route_unblocks_capability_after_transient_mock(): + hw1 = cp_bytes("TESLA_MODEL_S_HW1", alpha_available=True) + params = FakeParams({ + "CarModel": "TESLA_MODEL_S_HW1", "ForceFingerprint": True, + "CarParamsPersistent": cp_bytes("MOCK"), "CarParamsPrevRoute": hw1, + }) + assert capability_car_params_bytes(params) == hw1 + + +def test_live_recognized_params_take_precedence_over_previous_route(): + hw1 = cp_bytes("TESLA_MODEL_S_HW1", alpha_available=True) + live = cp_bytes("TESLA_MODEL_S_HW1", alpha_available=False) + params = FakeParams({ + "CarModel": "TESLA_MODEL_S_HW1", "ForceFingerprint": True, "IsOnroad": True, + "CarParams": live, "CarParamsPersistent": cp_bytes("MOCK"), "CarParamsPrevRoute": hw1, + }) + assert capability_car_params_bytes(params) == live + + +def test_previous_route_must_match_explicit_forced_model(): + previous = cp_bytes("TESLA_MODEL_S_HW1", alpha_available=True) + params = FakeParams({ + "CarModel": "TESLA_MODEL_S_PREAP", "ForceFingerprint": True, + "CarParamsPersistent": cp_bytes("MOCK"), "CarParamsPrevRoute": previous, + }) + assert capability_car_params_bytes(params) is None + + params.values["CarModel"] = "TESLA_MODEL_S_HW1" + params.values["ForceFingerprint"] = False + assert capability_car_params_bytes(params) is None + + +def test_current_recognized_mismatch_blocks_stale_fallback(): + params = FakeParams({ + "CarModel": "TESLA_MODEL_S_HW1", "ForceFingerprint": True, + "CarParamsPersistent": cp_bytes("TESLA_MODEL_S_PREAP"), + "CarParamsPrevRoute": cp_bytes("TESLA_MODEL_S_HW1", alpha_available=True), + }) + assert capability_car_params_bytes(params) is None diff --git a/starpilot/system/the_galaxy/tests/test_device_settings_layout.py b/starpilot/system/the_galaxy/tests/test_device_settings_layout.py index 0351bda2ef..a6de4f1285 100644 --- a/starpilot/system/the_galaxy/tests/test_device_settings_layout.py +++ b/starpilot/system/the_galaxy/tests/test_device_settings_layout.py @@ -111,13 +111,14 @@ def test_driving_personality_controls_are_not_parked_only(): assert all(params[key].get("requires_offroad") is not True for key in personality_keys) -def test_brake_status_toggle_is_galaxy_only(): - setting = _params_by_section(_layout())["Visual (Display & UI)"]["ShowBrakeStatus"] +def test_pedal_feedback_wheel_uses_existing_pedal_toggle(): + setting = _params_by_section(_layout())["Visual (Display & UI)"]["PedalsOnUI"] - assert _declared_default("ShowBrakeStatus") == "0" - assert setting["galaxy_only"] is True + assert _declared_default("PedalsOnUI") == "0" + assert setting["label"] == "Pedal-Responsive Wheel" assert setting["settings_tier"] == "simple" assert setting["ui_type"] == "toggle" + assert "ShowBrakeStatus" not in _params_by_section(_layout())["Visual (Display & UI)"] def test_ford_lateral_controls_are_ford_only_and_galaxy_only(): diff --git a/starpilot/system/the_galaxy/the_galaxy.py b/starpilot/system/the_galaxy/the_galaxy.py index 2d2cd10fc4..daef37db2c 100644 --- a/starpilot/system/the_galaxy/the_galaxy.py +++ b/starpilot/system/the_galaxy/the_galaxy.py @@ -78,6 +78,7 @@ from openpilot.starpilot.common.model_lab import ( ) from openpilot.starpilot.assets.theme_manager import HOLIDAY_THEME_PATH, THEME_COMPONENT_PARAMS from openpilot.starpilot.common import param_profiles +from openpilot.starpilot.common.car_params_capability import capability_car_params_bytes from openpilot.starpilot.system.the_galaxy import version_history, version_install from openpilot.starpilot.common.accel_profile import ( A_CRUISE_MAX_BP_CUSTOM, @@ -4463,7 +4464,7 @@ def _get_is_tici_or_tizi(): return HARDWARE.get_device_type() in ("tici", "tizi") def _get_alpha_longitudinal_available(): - cp_bytes = _safe_params_get_live_raw("CarParamsPersistent") + cp_bytes = capability_car_params_bytes(params) if not cp_bytes: return False