From 59272ea85cbb648d835e310e3f3a301940ee8707 Mon Sep 17 00:00:00 2001 From: James <91348155+FrogAi@users.noreply.github.com> Date: Mon, 1 Dec 2025 12:00:00 -0700 Subject: [PATCH] Force Drive State --- frogpilot/common/frogpilot_variables.py | 6 ++++-- frogpilot/ui/qt/offroad/utilities.cc | 28 +++++++++++++++++++++++++ selfdrive/selfdrived/selfdrived.py | 2 +- selfdrive/ui/qt/onroad/alerts.cc | 2 +- selfdrive/ui/ui.cc | 2 ++ system/hardware/hardwared.py | 2 ++ system/manager/manager.py | 2 +- 7 files changed, 39 insertions(+), 5 deletions(-) mode change 100755 => 100644 system/hardware/hardwared.py mode change 100644 => 100755 system/manager/manager.py diff --git a/frogpilot/common/frogpilot_variables.py b/frogpilot/common/frogpilot_variables.py index 1570fae3..621e781f 100644 --- a/frogpilot/common/frogpilot_variables.py +++ b/frogpilot/common/frogpilot_variables.py @@ -306,6 +306,8 @@ class FrogPilotVariables: toggle.liveValid = False toggle.debug_mode = self.params.get_bool("DebugMode") + toggle.force_offroad = self.params.get_bool("ForceOffroad") + toggle.force_onroad = self.params.get_bool("ForceOnroad") toggle.is_metric = self.params.get_bool("IsMetric") distance_conversion = 1 if toggle.is_metric else CV.FOOT_TO_METER @@ -475,7 +477,7 @@ class FrogPilotVariables: toggle.device_shutdown_time = DEVICE_SHUTDOWN_TIMES.get(self.get_value("DeviceShutdown", cast=int, condition=device_management)) toggle.increase_thermal_limits = self.get_value("IncreaseThermalLimits", condition=device_management) toggle.low_voltage_shutdown = self.get_value("LowVoltageShutdown", cast=float, condition=device_management, min=VBATT_PAUSE_CHARGING, max=12.5) - toggle.no_logging = self.get_value("NoLogging", condition=device_management and not self.vetting_branch) + toggle.no_logging = self.get_value("NoLogging", condition=device_management and not self.vetting_branch) or toggle.force_onroad toggle.no_uploads = self.get_value("NoUploads", condition=device_management and not self.vetting_branch) toggle.no_onroad_uploads = self.get_value("DisableOnroadUploads", condition=toggle.no_uploads) @@ -592,7 +594,7 @@ class FrogPilotVariables: screen_management = self.get_value("ScreenManagement") toggle.screen_brightness = max(self.get_value("ScreenBrightness", cast=float, condition=screen_management), 1) - toggle.screen_brightness_onroad = self.get_value("ScreenBrightnessOnroad", cast=float, condition=(screen_management)) + toggle.screen_brightness_onroad = self.get_value("ScreenBrightnessOnroad", cast=float, condition=(screen_management and not toggle.force_onroad)) toggle.screen_recorder = self.get_value("ScreenRecorder", condition=screen_management) or toggle.debug_mode toggle.screen_timeout = self.get_value("ScreenTimeout", cast=float, condition=screen_management) toggle.screen_timeout_onroad = self.get_value("ScreenTimeoutOnroad", cast=float, condition=screen_management) diff --git a/frogpilot/ui/qt/offroad/utilities.cc b/frogpilot/ui/qt/offroad/utilities.cc index 9c86abba..1d74b61a 100644 --- a/frogpilot/ui/qt/offroad/utilities.cc +++ b/frogpilot/ui/qt/offroad/utilities.cc @@ -40,6 +40,34 @@ FrogPilotUtilitiesPanel::FrogPilotUtilitiesPanel(FrogPilotSettingsWindow *parent } addItem(flashPandaButton); + FrogPilotButtonsControl *forceStartedButton = new FrogPilotButtonsControl(tr("Force Drive State"), tr("Force openpilot to be offroad or onroad."), "", {tr("OFFROAD"), tr("ONROAD"), tr("OFF")}, true); + QObject::connect(forceStartedButton, &FrogPilotButtonsControl::buttonClicked, [this](int id) { + if (id == 0) { + params.putBool("ForceOffroad", true); + params.putBool("ForceOnroad", false); + + updateFrogPilotToggles(); + } else if (id == 1) { + params.put("CarParams", params.get("CarParamsPersistent")); + params.put("FrogPilotCarParams", params.get("FrogPilotCarParamsPersistent")); + + params.putBool("ForceOffroad", false); + params.putBool("ForceOnroad", true); + + updateFrogPilotToggles(); + } else if (id == 2) { + params.putBool("ForceOffroad", false); + params.putBool("ForceOnroad", false); + + updateFrogPilotToggles(); + } + }); + forceStartedButton->setCheckedButton(2); + if (forceOpenDescriptions) { + forceStartedButton->showDescription(); + } + addItem(forceStartedButton); + ButtonControl *resetTogglesButton = new ButtonControl(tr("Reset Toggles to Default"), tr("RESET"), tr("Reset all toggles to their default values.")); QObject::connect(resetTogglesButton, &ButtonControl::clicked, [parent, resetTogglesButton, this]() { if (ConfirmationDialog::confirm(tr("Are you sure you want to reset all toggles to their default values?"), tr("Reset"), this)) { diff --git a/selfdrive/selfdrived/selfdrived.py b/selfdrive/selfdrived/selfdrived.py index fb31b152..dc3db508 100644 --- a/selfdrive/selfdrived/selfdrived.py +++ b/selfdrive/selfdrived/selfdrived.py @@ -344,7 +344,7 @@ class SelfdriveD: self.events.add(EventName.usbError) if CS.canTimeout: self.events.add(EventName.canBusMissing) - elif not CS.canValid: + elif not CS.canValid and not self.frogpilot_toggles.force_onroad: self.events.add(EventName.canError) # generic catch-all. ideally, a more specific event should be added above instead diff --git a/selfdrive/ui/qt/onroad/alerts.cc b/selfdrive/ui/qt/onroad/alerts.cc index 17c3f83a..456927b6 100644 --- a/selfdrive/ui/qt/onroad/alerts.cc +++ b/selfdrive/ui/qt/onroad/alerts.cc @@ -51,7 +51,7 @@ OnroadAlerts::Alert OnroadAlerts::getAlert(const SubMaster &sm, const SubMaster } } - if (!sm.updated("selfdriveState") && (sm.frame - started_frame) > 5 * UI_FREQ) { + if (!sm.updated("selfdriveState") && (sm.frame - started_frame) > 5 * UI_FREQ && !frogpilot_toggles.value("force_onroad").toBool()) { const int SELFDRIVE_STATE_TIMEOUT = 5; const int ss_missing = (nanos_since_boot() - sm.rcv_time("selfdriveState")) / 1e9; diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index ab8fae0f..2d3b9b4b 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -77,6 +77,8 @@ static void update_state(UIState *s, FrogPilotUIState *fs) { if (scene.started) { frogpilot_scene.started_timer += 1; } + scene.started |= frogpilot_scene.frogpilot_toggles.value("force_onroad").toBool(); + scene.started &= !frogpilot_scene.frogpilot_toggles.value("force_offroad").toBool(); } void ui_update_params(UIState *s) { diff --git a/system/hardware/hardwared.py b/system/hardware/hardwared.py old mode 100755 new mode 100644 index 8cc0f6f8..564f90d8 --- a/system/hardware/hardwared.py +++ b/system/hardware/hardwared.py @@ -352,6 +352,8 @@ def hardware_thread(end_event, hw_queue) -> None: should_start = should_start and all(startup_conditions.values()) # FrogPilot variables + should_start |= frogpilot_toggles.force_onroad + should_start &= not frogpilot_toggles.force_offroad if should_start != should_start_prev or (count == 0): params.put_bool("IsEngaged", False) diff --git a/system/manager/manager.py b/system/manager/manager.py old mode 100644 new mode 100755 index 01875256..ab33734a --- a/system/manager/manager.py +++ b/system/manager/manager.py @@ -155,7 +155,7 @@ def manager_thread() -> None: started = sm['deviceState'].started - if started and not started_prev: + if started and not started_prev and not frogpilot_toggles.force_onroad: params.clear_all(ParamKeyFlag.CLEAR_ON_ONROAD_TRANSITION) # FrogPilot variables