diff --git a/common/params_keys.h b/common/params_keys.h index 30b094fd8..6728b59a3 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -372,7 +372,7 @@ inline static std::unordered_map keys = { {"LateralTune", {PERSISTENT, BOOL, "1", "0", 1}}, {"LeadDepartingAlert", {PERSISTENT, BOOL, "0", "0", 0}}, {"LeadDetectionThreshold", {PERSISTENT, INT, "35", "50", 3}}, - {"LeadIndicator", {PERSISTENT, BOOL, "1", "1", 2}}, + {"LeadIndicator", {PERSISTENT, BOOL, "0", "0", 2}}, {"LeadInfo", {PERSISTENT, BOOL, "1", "0", 3}}, {"LKASButtonControl", {PERSISTENT, INT, "5", "0", 2}}, {"LockDoors", {PERSISTENT, BOOL, "1", "0", 0}}, @@ -545,8 +545,8 @@ inline static std::unordered_map keys = { {"SLCMapboxFiller", {PERSISTENT, BOOL, "1", "0", 1}}, {"SLCOverride", {PERSISTENT, INT, "1", "0", 1}}, {"SLCPriority", {PERSISTENT, STRING, "", "", 2}}, - {"SLCPriority1", {PERSISTENT, STRING, "Map Data", "Map Data", 2}}, - {"SLCPriority2", {PERSISTENT, STRING, "Dashboard", "Dashboard", 2}}, + {"SLCPriority1", {PERSISTENT, STRING, "Vision", "Map Data", 2}}, + {"SLCPriority2", {PERSISTENT, STRING, "Map Data", "Dashboard", 2}}, {"SNGHack", {PERSISTENT, BOOL, "1", "0", 2}}, {"SoundPack", {PERSISTENT, STRING, "stock", "stock", 0}}, {"SoundToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}}, @@ -561,7 +561,7 @@ inline static std::unordered_map keys = { {"SpeedLimitSources", {PERSISTENT, BOOL, "0", "0", 3}}, {"VisionSpeedLimitAutoBookmark", {PERSISTENT, BOOL, "0", "0", 0}}, {"VisionSpeedLimitAutoPreserveSegment", {PERSISTENT, BOOL, "0", "0", 0}}, - {"VisionSpeedLimitDetection", {PERSISTENT, BOOL, "0", "0", 0}}, + {"VisionSpeedLimitDetection", {PERSISTENT, BOOL, "1", "0", 0}}, {"VisionSpeedLimitTrainingCollector", {PERSISTENT, BOOL, "1", "1", 0}}, {"StandardFollow", {PERSISTENT, FLOAT, "1.45", "1.45", 2}}, {"StandardFollowHigh", {PERSISTENT, FLOAT, "1.2", "1.2", 2}}, diff --git a/selfdrive/ui/lib/starpilot_visuals.py b/selfdrive/ui/lib/starpilot_visuals.py index 5e186a22e..c21b0b201 100644 --- a/selfdrive/ui/lib/starpilot_visuals.py +++ b/selfdrive/ui/lib/starpilot_visuals.py @@ -19,8 +19,7 @@ def get_border_width(base_width: int, params: Params | None = None) -> int: def lead_indicator_enabled(params: Params | None = None) -> bool: active_params = params if params is not None else Params() - enabled = not active_params.get_bool("HideLeadMarker", default=False) - if active_params.get("LeadIndicator") is not None: - enabled = enabled and active_params.get_bool("LeadIndicator", default=True) - - return enabled + return ( + active_params.get_bool("LeadIndicator", default=False) + and not active_params.get_bool("HideLeadMarker", default=False) + ) diff --git a/selfdrive/ui/onroad/model_renderer.py b/selfdrive/ui/onroad/model_renderer.py index c9be8d076..8a000fe4a 100644 --- a/selfdrive/ui/onroad/model_renderer.py +++ b/selfdrive/ui/onroad/model_renderer.py @@ -123,14 +123,16 @@ class ModelRenderer(Widget): radar_state = sm['radarState'] if sm.valid['radarState'] else None lead_one = radar_state.leadOne if radar_state else None - # StarPilot lead indicator visibility conditions - hide_lead_marker = self._params.get_bool("HideLeadMarker") self._lead_info_enabled = self._params.get_bool("LeadInfo") self._use_rainbow = self._params.get_bool('RainbowPath', default=False) self._use_accel_path = self._params.get_bool('AccelerationPath', default=True) self._is_metric = self._params.get_bool('IsMetric') lead_info_enabled = self._lead_info_enabled - render_lead_indicator = (self._longitudinal_control or lead_info_enabled) and radar_state is not None and not hide_lead_marker + render_lead_indicator = ( + (self._longitudinal_control or lead_info_enabled) + and radar_state is not None + and lead_indicator_enabled(self._params) + ) # Update model data when needed model_updated = sm.updated['modelV2'] diff --git a/selfdrive/ui/tests/test_starpilot_visuals.py b/selfdrive/ui/tests/test_starpilot_visuals.py new file mode 100644 index 000000000..5f57970bf --- /dev/null +++ b/selfdrive/ui/tests/test_starpilot_visuals.py @@ -0,0 +1,37 @@ +import importlib.util +import unittest +from pathlib import Path + + +MODULE_PATH = Path(__file__).resolve().parents[1] / "lib" / "starpilot_visuals.py" +SPEC = importlib.util.spec_from_file_location("starpilot_visuals_under_test", MODULE_PATH) +MODULE = importlib.util.module_from_spec(SPEC) +assert SPEC is not None and SPEC.loader is not None +SPEC.loader.exec_module(MODULE) +lead_indicator_enabled = MODULE.lead_indicator_enabled + + +class FakeParams: + def __init__(self, values=None): + self.values = values or {} + + def get_bool(self, key, block=False, default=False): + value = self.values.get(key, default) + if isinstance(value, bool): + return value + return str(value or "").strip() in ("1", "true", "True") + + +class TestStarPilotVisuals(unittest.TestCase): + def test_lead_indicator_disabled_by_default(self): + self.assertFalse(lead_indicator_enabled(FakeParams())) + + def test_lead_indicator_can_be_enabled(self): + self.assertTrue(lead_indicator_enabled(FakeParams({"LeadIndicator": True}))) + + def test_hide_lead_marker_suppresses_lead_indicator(self): + self.assertFalse(lead_indicator_enabled(FakeParams({"LeadIndicator": True, "HideLeadMarker": True}))) + + +if __name__ == "__main__": + unittest.main() diff --git a/starpilot/system/the_galaxy/assets/components/tools/device_settings_layout.json b/starpilot/system/the_galaxy/assets/components/tools/device_settings_layout.json index 1fda6448c..19a1951e1 100644 --- a/starpilot/system/the_galaxy/assets/components/tools/device_settings_layout.json +++ b/starpilot/system/the_galaxy/assets/components/tools/device_settings_layout.json @@ -1779,12 +1779,11 @@ "parent_key": "AdvancedCustomUI" }, { - "key": "HideLeadMarker", - "label": "Hide Lead Marker", - "description": "Hide the lead-vehicle marker from the driving screen.", + "key": "LeadIndicator", + "label": "Lead Indicator", + "description": "Show the lead-vehicle marker on the driving screen.", "data_type": "bool", - "ui_type": "toggle", - "parent_key": "AdvancedCustomUI" + "ui_type": "toggle" }, { "key": "HideMaxSpeed", diff --git a/starpilot/system/the_galaxy/tests/test_navigation_params.py b/starpilot/system/the_galaxy/tests/test_navigation_params.py index de489dbee..849b0edd1 100644 --- a/starpilot/system/the_galaxy/tests/test_navigation_params.py +++ b/starpilot/system/the_galaxy/tests/test_navigation_params.py @@ -35,6 +35,10 @@ class FakeParamsBackend: self.writes.append((key, value)) self.values[key] = value + def put_bool(self, key, value): + self.writes.append((key, bool(value))) + self.values[key] = bool(value) + def get(self, key, block=False): return self.values.get(key) @@ -51,6 +55,24 @@ def test_params_compat_accepts_json_strings_for_json_keys(): assert backend.writes == [("FavoriteDestinations", [{"name": "Home"}])] +def test_params_compat_syncs_lead_indicator_inverse_key(): + backend = FakeParamsBackend() + compat = the_galaxy.ParamsCompat(backend) + + compat.put_bool("LeadIndicator", True) + + assert backend.writes == [("LeadIndicator", True), ("HideLeadMarker", False)] + + +def test_params_compat_syncs_hide_lead_marker_inverse_key(): + backend = FakeParamsBackend() + compat = the_galaxy.ParamsCompat(backend) + + compat.put_bool("HideLeadMarker", True) + + assert backend.writes == [("HideLeadMarker", True), ("LeadIndicator", False)] + + def test_navigation_last_position_uses_recent_persisted_fix(monkeypatch): recent_payload = json.dumps({ "latitude": 41.0, diff --git a/starpilot/system/the_galaxy/the_galaxy.py b/starpilot/system/the_galaxy/the_galaxy.py index af2e1a10c..b2f512997 100644 --- a/starpilot/system/the_galaxy/the_galaxy.py +++ b/starpilot/system/the_galaxy/the_galaxy.py @@ -398,6 +398,18 @@ class ParamsCompat: self._put_single(self._key(key), value) def put_bool(self, key, value): + if key == "LeadIndicator": + enabled = bool(value) + self._params.put_bool("LeadIndicator", enabled) + self._params.put_bool("HideLeadMarker", not enabled) + return + + if key == "HideLeadMarker": + hidden = bool(value) + self._params.put_bool("HideLeadMarker", hidden) + self._params.put_bool("LeadIndicator", not hidden) + return + self._params.put_bool(self._key(key), bool(value)) def remove(self, key): @@ -2332,6 +2344,9 @@ def _get_current_param_value(key, value_type, defaults_lookup=None): if key == CUSTOM_ACCEL_PROFILE_INITIALIZED_KEY: return _get_custom_accel_profile_initialized() + if key == "LeadIndicator": + return _get_lead_indicator_enabled(defaults_lookup) + if key == "IsRHD" and not _safe_params_get_bool("IsRHDOverride"): return _safe_params_get_bool("IsRhdDetected") @@ -2351,6 +2366,21 @@ def _get_current_param_value(key, value_type, defaults_lookup=None): return value +def _get_lead_indicator_enabled(defaults_lookup=None): + if defaults_lookup is None: + defaults_lookup = _get_default_param_values() + + lead_raw = _safe_params_get_live_raw("LeadIndicator") + if _is_blank_param_raw(lead_raw): + lead_raw = defaults_lookup.get("LeadIndicator", "0") + + hide_raw = _safe_params_get_live_raw("HideLeadMarker") + if _is_blank_param_raw(hide_raw): + hide_raw = defaults_lookup.get("HideLeadMarker", "0") + + return _coerce_param_value(lead_raw, bool) and not _coerce_param_value(hide_raw, bool) + + def _get_custom_accel_profile_initialized(): raw_values = { key: _safe_params_get_live_raw(key) @@ -3976,6 +4006,21 @@ def setup(app): if key in PANDA_FIRMWARE_TOGGLE_KEYS and data.get(PANDA_FIRMWARE_CONFIRMATION_FIELD) is not True: return jsonify({"error": "Panda firmware changes require confirmation before flashing."}), 409 + if key in {"LeadIndicator", "HideLeadMarker"}: + enabled = str_val.strip() in ("1", "true", "True") + if key == "LeadIndicator": + params.put_bool("LeadIndicator", enabled) + updated = {"LeadIndicator": enabled, "HideLeadMarker": not enabled} + else: + params.put_bool("HideLeadMarker", enabled) + updated = {"HideLeadMarker": enabled, "LeadIndicator": not enabled} + + update_starpilot_toggles() + return jsonify({ + "message": f"Parameter '{key}' updated successfully.", + "updated": updated, + }), 200 + if key == "AllowImpossibleAcceleration": enabled = str_val.strip() in ("1", "true", "True") params.put_bool(key, enabled) @@ -4251,6 +4296,8 @@ def setup(app): return _serialize_param_write_value(defaults_lookup.get(request_key)), 200 if request_key == CUSTOM_ACCEL_PROFILE_INITIALIZED_KEY: return _serialize_param_write_value(_get_custom_accel_profile_initialized()), 200 + if request_key == "LeadIndicator": + return _serialize_param_write_value(_get_lead_indicator_enabled()), 200 if request_key == "IsRHD" and not params.get_bool("IsRHDOverride"): return ("1" if params.get_bool("IsRhdDetected") else "0"), 200 value = params.get(request_key) or ""