From e2cd1568e68d4a8cea679dd38473508102b77219 Mon Sep 17 00:00:00 2001 From: James <91348155+FrogAi@users.noreply.github.com> Date: Sun, 7 Dec 2025 14:15:05 -0700 Subject: [PATCH] FrogPilot param functions --- common/params.cc | 28 +++++++- common/params.h | 33 ++++++++- common/params_pyx.pyx | 35 ++++++++-- frogpilot/common/frogpilot_functions.py | 3 + frogpilot/frogpilot_process.py | 13 ++-- frogpilot/ui/frogpilot_ui.h | 1 + frogpilot/ui/qt/offroad/maps_settings.h | 1 + frogpilot/ui/qt/offroad/model_settings.h | 1 + frogpilot/ui/qt/offroad/navigation_settings.h | 1 + frogpilot/ui/qt/offroad/sounds_settings.h | 1 + frogpilot/ui/qt/offroad/theme_settings.h | 1 + frogpilot/ui/qt/offroad/utilities.cc | 70 +++++++++++++++++++ frogpilot/ui/qt/offroad/utilities.h | 8 +++ .../ui/qt/onroad/frogpilot_annotated_camera.h | 3 + launch_chffrplus.sh | 1 + opendbc_repo/opendbc/car/interfaces.py | 2 + selfdrive/ui/qt/home.h | 1 + selfdrive/ui/qt/offroad/software_settings.cc | 5 ++ selfdrive/ui/qt/onroad/buttons.h | 2 + selfdrive/ui/qt/window.h | 1 + selfdrive/ui/soundd.py | 3 + system/manager/manager.py | 4 ++ system/updated/updated.py | 1 + 23 files changed, 205 insertions(+), 14 deletions(-) diff --git a/common/params.cc b/common/params.cc index 7ce03158a..487afded6 100644 --- a/common/params.cc +++ b/common/params.cc @@ -91,11 +91,18 @@ private: } // namespace -Params::Params(const std::string &path) { +Params::Params(const std::string &path, bool memory) { params_prefix = "/" + util::getenv("OPENPILOT_PREFIX", "d"); - params_path = ensure_params_path(params_prefix, path); // FrogPilot variables + std::string params_folder; + if (memory) { + params_folder = "/dev/shm/params"; + } else { + cache_path = "/cache/params" + params_prefix + "/"; + params_folder = path; + } + params_path = ensure_params_path(params_prefix, params_folder); } Params::~Params() { @@ -173,6 +180,9 @@ int Params::remove(const std::string &key) { int result = unlink(getParamPath(key).c_str()); // FrogPilot variables + if (!cache_path.empty()) { + unlink((cache_path + key).c_str()); + } if (result != 0) { return result; @@ -222,6 +232,9 @@ void Params::clearAll(ParamKeyFlag key_flag) { unlink(getParamPath(de->d_name).c_str()); // FrogPilot variables + if (!cache_path.empty()) { + unlink((cache_path + de->d_name).c_str()); + } } } } @@ -249,3 +262,14 @@ void Params::asyncWriteThread() { } // FrogPilot variables +int Params::getTuningLevel(const std::string &key) { + return keys[key].tuning_level; +} + +std::optional Params::getStockValue(const std::string &key) { + ParamKeyAttributes &attributes = keys[key]; + if (attributes.stock_value) { + return attributes.stock_value; + } + return attributes.default_value; +} diff --git a/common/params.h b/common/params.h index d6b130307..f3505683b 100644 --- a/common/params.h +++ b/common/params.h @@ -37,11 +37,14 @@ struct ParamKeyAttributes { std::optional default_value = std::nullopt; // FrogPilot variables + std::optional stock_value = std::nullopt; + + int tuning_level = 0; }; class Params { public: - explicit Params(const std::string &path = {}); + explicit Params(const std::string &path = {}, bool memory = false); ~Params(); // Not copyable. Params(const Params&) = delete; @@ -81,6 +84,33 @@ public: } // FrogPilot variables + int getInt(const std::string &key, bool block = false) { + std::string value = get(key, block); + return value.empty() ? 0 : std::stoi(value); + } + float getFloat(const std::string &key, bool block = false) { + std::string value = get(key, block); + return value.empty() ? 0.0f : std::stof(value); + } + + int putInt(const std::string &key, int val) { + std::string str = std::to_string(val); + return put(key.c_str(), str.c_str(), str.size()); + } + int putFloat(const std::string &key, float val) { + std::string str = std::to_string(val); + return put(key.c_str(), str.c_str(), str.size()); + } + void putIntNonBlocking(const std::string &key, int val) { + putNonBlocking(key, std::to_string(val)); + } + void putFloatNonBlocking(const std::string &key, float val) { + putNonBlocking(key, std::to_string(val)); + } + + int getTuningLevel(const std::string &key); + + std::optional getStockValue(const std::string &key); private: void asyncWriteThread(); @@ -93,4 +123,5 @@ private: SafeQueue> queue; // FrogPilot variables + std::string cache_path; }; diff --git a/common/params_pyx.pyx b/common/params_pyx.pyx index 5e562b2be..4c98b7889 100644 --- a/common/params_pyx.pyx +++ b/common/params_pyx.pyx @@ -21,6 +21,7 @@ cdef extern from "common/params.h": ALL # FrogPilot variables + DONT_LOG cpdef enum ParamKeyType: STRING @@ -32,7 +33,7 @@ cdef extern from "common/params.h": BYTES cdef cppclass c_Params "Params": - c_Params(string) except + nogil + c_Params(string, bool) except + nogil string get(string, bool) nogil bool getBool(string, bool) nogil int remove(string) nogil @@ -48,6 +49,11 @@ cdef extern from "common/params.h": vector[string] allKeys() # FrogPilot variables + ParamKeyFlag getKeyFlag(string) nogil + + optional[string] getStockValue(string) nogil + + int getTuningLevel(string) nogil PYTHON_2_CPP = { (str, STRING): lambda v: v, @@ -80,20 +86,26 @@ cdef class Params: cdef str d # FrogPilot variables + cdef bool m + cdef bool return_defaults - def __cinit__(self, d=""): + def __cinit__(self, d="", *, memory=False, return_defaults=False): cdef string path = d.encode() # FrogPilot variables + cdef bool c_memory = memory with nogil: - self.p = new c_Params(path) + self.p = new c_Params(path, c_memory) self.d = d # FrogPilot variables + self.m = memory + + self.return_defaults = return_defaults or memory def __reduce__(self): - return (type(self), (self.d,)) + return (type(self), (self.d, self.m, self.return_defaults)) def __dealloc__(self): del self.p @@ -130,7 +142,7 @@ cdef class Params: with nogil: val = self.p.get(k, block) - default_val = (default.value() if default.has_value() else None) if return_default else None + default_val = (default.value() if default.has_value() else None) if (return_default or self.return_defaults and not block) else None if val == b"": if block: # If we got no value while running in blocked mode @@ -207,3 +219,16 @@ cdef class Params: return self._cpp2python(t, value, None, key) # FrogPilot variables + def get_key_flag(self, key): + return self.p.getKeyFlag(self.check_key(key)) + + def get_stock_value(self, key): + cdef string k = self.check_key(key) + cdef ParamKeyType t = self.p.getKeyType(k) + cdef optional[string] stock = self.p.getStockValue(k) + return self._cpp2python(t, stock.value(), None, key) if stock.has_value() else None + + def get_tuning_level(self, key): + cdef string k = self.check_key(key) + cdef optional[int] level = self.p.getTuningLevel(k) + return level.value() if level.has_value() else 0 diff --git a/frogpilot/common/frogpilot_functions.py b/frogpilot/common/frogpilot_functions.py index 2068c7127..80f550ed1 100644 --- a/frogpilot/common/frogpilot_functions.py +++ b/frogpilot/common/frogpilot_functions.py @@ -5,6 +5,7 @@ import time from pathlib import Path from openpilot.common.basedir import BASEDIR +from openpilot.common.params import Params from openpilot.common.time_helpers import system_time_valid from openpilot.system.hardware import HARDWARE @@ -12,6 +13,8 @@ from openpilot.frogpilot.common.frogpilot_utilities import run_cmd def frogpilot_boot_functions(): + params_memory = Params(memory=True) + def boot_thread(): while not system_time_valid(): print("Waiting for system time to become valid...") diff --git a/frogpilot/frogpilot_process.py b/frogpilot/frogpilot_process.py index 240d2ef99..39c7d7518 100644 --- a/frogpilot/frogpilot_process.py +++ b/frogpilot/frogpilot_process.py @@ -9,13 +9,13 @@ from openpilot.common.time_helpers import system_time_valid ASSET_CHECK_RATE = (1 / DT_MDL) -def check_assets(): +def check_assets(params_memory): def transition_offroad(time_validated, sm, params): def transition_onroad(): -def update_checks(now, params, boot_run=False): +def update_checks(now, params, params_memory, boot_run=False): while not (is_url_pingable("https://github.com") or is_url_pingable("https://gitlab.com")): time.sleep(60) @@ -31,7 +31,8 @@ def frogpilot_thread(): "onroadEvents", "pandaStates", "radarState", "selfdriveState"], poll="modelV2") - params = Params() + params = Params(return_defaults=True) + params_memory = Params(memory=True) run_update_checks = False started_previously = False @@ -57,13 +58,13 @@ def frogpilot_thread(): started_previously = started if rate_keeper.frame % ASSET_CHECK_RATE == 0: - check_assets() + check_assets(params_memory) run_update_checks |= now.second == 0 and (now.minute % 60 == 0) run_update_checks &= time_validated if run_update_checks: - thread_manager.run_with_lock(update_checks, (now, params)) + thread_manager.run_with_lock(update_checks, (now, params, params_memory)) run_update_checks = False elif not time_validated: @@ -71,7 +72,7 @@ def frogpilot_thread(): if not time_validated: continue - thread_manager.run_with_lock(update_checks, (now, params, True)) + thread_manager.run_with_lock(update_checks, (now, params, params_memory, True)) rate_keeper.keep_time() diff --git a/frogpilot/ui/frogpilot_ui.h b/frogpilot/ui/frogpilot_ui.h index c35588e2d..5738166f5 100644 --- a/frogpilot/ui/frogpilot_ui.h +++ b/frogpilot/ui/frogpilot_ui.h @@ -29,6 +29,7 @@ public: FrogPilotUIScene frogpilot_scene; Params params; + Params params_memory{"", true}; WifiManager *wifi; diff --git a/frogpilot/ui/qt/offroad/maps_settings.h b/frogpilot/ui/qt/offroad/maps_settings.h index 8e3e91447..2b5388e89 100644 --- a/frogpilot/ui/qt/offroad/maps_settings.h +++ b/frogpilot/ui/qt/offroad/maps_settings.h @@ -42,6 +42,7 @@ private: LabelControl *mapsSize; Params params; + Params params_memory{"", true}; QDateTime startTime; diff --git a/frogpilot/ui/qt/offroad/model_settings.h b/frogpilot/ui/qt/offroad/model_settings.h index d35370e0d..4c3ad48f6 100644 --- a/frogpilot/ui/qt/offroad/model_settings.h +++ b/frogpilot/ui/qt/offroad/model_settings.h @@ -41,6 +41,7 @@ private: FrogPilotSettingsWindow *parent; Params params; + Params params_memory{"", true}; QDir modelDir{"/data/models/"}; diff --git a/frogpilot/ui/qt/offroad/navigation_settings.h b/frogpilot/ui/qt/offroad/navigation_settings.h index 39d997184..27638cb12 100644 --- a/frogpilot/ui/qt/offroad/navigation_settings.h +++ b/frogpilot/ui/qt/offroad/navigation_settings.h @@ -38,6 +38,7 @@ private: LabelControl *ipLabel; Params params; + Params params_memory{"", true}; QLabel *imageLabel; diff --git a/frogpilot/ui/qt/offroad/sounds_settings.h b/frogpilot/ui/qt/offroad/sounds_settings.h index 6e9d3f7fc..ce048de30 100644 --- a/frogpilot/ui/qt/offroad/sounds_settings.h +++ b/frogpilot/ui/qt/offroad/sounds_settings.h @@ -31,4 +31,5 @@ private: FrogPilotSettingsWindow *parent; Params params; + Params params_memory{"", true}; }; diff --git a/frogpilot/ui/qt/offroad/theme_settings.h b/frogpilot/ui/qt/offroad/theme_settings.h index f146d100f..26ba6f4ed 100644 --- a/frogpilot/ui/qt/offroad/theme_settings.h +++ b/frogpilot/ui/qt/offroad/theme_settings.h @@ -64,4 +64,5 @@ private: QString wheelToDownload; Params params; + Params params_memory{"", true}; }; diff --git a/frogpilot/ui/qt/offroad/utilities.cc b/frogpilot/ui/qt/offroad/utilities.cc index 80ffdff49..a7b1e09ff 100644 --- a/frogpilot/ui/qt/offroad/utilities.cc +++ b/frogpilot/ui/qt/offroad/utilities.cc @@ -2,4 +2,74 @@ FrogPilotUtilitiesPanel::FrogPilotUtilitiesPanel(FrogPilotSettingsWindow *parent, bool forceOpen) : FrogPilotListWidget(parent), parent(parent) { forceOpenDescriptions = forceOpen; + + 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)) { + std::thread([parent, resetTogglesButton, this]() { + parent->keepScreenOn = true; + + resetTogglesButton->setEnabled(false); + resetTogglesButton->setValue(tr("Resetting...")); + + std::vector all_keys = params.allKeys(); + for (const std::string &key : all_keys) { + if (excluded_keys.count(key)) { + continue; + } + std::optional default_value = params.getKeyDefaultValue(key); + if (default_value.has_value()) { + params.put(key, default_value.value()); + } + } + + updateFrogPilotToggles(); + + resetTogglesButton->setValue(tr("Reset!")); + + util::sleep_for(2500); + + resetTogglesButton->setValue(""); + }).detach(); + } + }); + if (forceOpenDescriptions) { + resetTogglesButton->showDescription(); + } + addItem(resetTogglesButton); + + ButtonControl *resetTogglesButtonStock = new ButtonControl(tr("Reset Toggles to Stock openpilot"), tr("RESET"), tr("Reset all toggles to match stock openpilot.")); + QObject::connect(resetTogglesButtonStock, &ButtonControl::clicked, [parent, resetTogglesButtonStock, this]() { + if (ConfirmationDialog::confirm(tr("Are you sure you want to reset all toggles to match stock openpilot?"), tr("Reset"), this)) { + std::thread([parent, resetTogglesButtonStock, this]() { + parent->keepScreenOn = true; + + resetTogglesButtonStock->setEnabled(false); + resetTogglesButtonStock->setValue(tr("Resetting...")); + + std::vector all_keys = params.allKeys(); + for (const std::string &key : all_keys) { + if (excluded_keys.count(key)) { + continue; + } + std::optional stock_value = params.getStockValue(key); + if (stock_value.has_value()) { + params.put(key, stock_value.value()); + } + } + + updateFrogPilotToggles(); + + resetTogglesButtonStock->setValue(tr("Reset!")); + + util::sleep_for(2500); + + resetTogglesButtonStock->setValue(""); + }).detach(); + } + }); + if (forceOpenDescriptions) { + resetTogglesButtonStock->showDescription(); + } + addItem(resetTogglesButtonStock); } diff --git a/frogpilot/ui/qt/offroad/utilities.h b/frogpilot/ui/qt/offroad/utilities.h index da0a50c9c..01d1ac517 100644 --- a/frogpilot/ui/qt/offroad/utilities.h +++ b/frogpilot/ui/qt/offroad/utilities.h @@ -14,4 +14,12 @@ private: FrogPilotSettingsWindow *parent; Params params; + Params params_memory{"", true}; + + std::set excluded_keys = { + "AvailableModels", "AvailableModelNames", "FrogPilotStats", + "GithubSshKeys", "GithubUsername", "MapBoxRequests", + "ModelDrivesAndScores", "OverpassRequests", "SpeedLimits", + "SpeedLimitsFiltered", "UpdaterAvailableBranches", + }; }; diff --git a/frogpilot/ui/qt/onroad/frogpilot_annotated_camera.h b/frogpilot/ui/qt/onroad/frogpilot_annotated_camera.h index 527b02cc3..a1b3944a4 100644 --- a/frogpilot/ui/qt/onroad/frogpilot_annotated_camera.h +++ b/frogpilot/ui/qt/onroad/frogpilot_annotated_camera.h @@ -43,6 +43,9 @@ private: float speedConversion; float speedConversionMetrics; + Params params; + Params params_memory{"", true}; + QColor blackColor(int alpha = 255) { return QColor(0, 0, 0, alpha); } QColor redColor(int alpha = 255) { return QColor(201, 34, 49, alpha); } diff --git a/launch_chffrplus.sh b/launch_chffrplus.sh index 2f6056255..8dd2e507c 100755 --- a/launch_chffrplus.sh +++ b/launch_chffrplus.sh @@ -17,6 +17,7 @@ function agnos_init { sudo chmod 660 /dev/adsprpc-smd /dev/ion /dev/kgsl-3d0 # FrogPilot variables + sudo chmod 0777 /cache # Check if AGNOS update is required if [ $(< /VERSION) != "$AGNOS_VERSION" ]; then diff --git a/opendbc_repo/opendbc/car/interfaces.py b/opendbc_repo/opendbc/car/interfaces.py index 268de6cc2..a4028a514 100644 --- a/opendbc_repo/opendbc/car/interfaces.py +++ b/opendbc_repo/opendbc/car/interfaces.py @@ -16,6 +16,7 @@ from opendbc.car.common.conversions import Conversions as CV from opendbc.car.common.simple_kalman import KF1D, get_kalman_gain from opendbc.car.values import PLATFORMS from opendbc.can import CANParser +from openpilot.common.params import Params GearShifter = structs.CarState.GearShifter ButtonType = structs.CarState.ButtonEvent.Type @@ -111,6 +112,7 @@ class CarInterfaceBase(ABC): self.CC: CarControllerBase = self.CarController(dbc_names, CP) # FrogPilot variables + self.params_memory = Params(memory=True) def apply(self, c: structs.CarControl, now_nanos: int | None = None) -> tuple[structs.CarControl.Actuators, list[CanData]]: if now_nanos is None: diff --git a/selfdrive/ui/qt/home.h b/selfdrive/ui/qt/home.h index 4e5068d83..2a6af7ef6 100644 --- a/selfdrive/ui/qt/home.h +++ b/selfdrive/ui/qt/home.h @@ -71,6 +71,7 @@ private: QStackedLayout *slayout; // FrogPilot variables + Params params; private slots: void updateState(const UIState &s, const FrogPilotUIState &fs); diff --git a/selfdrive/ui/qt/offroad/software_settings.cc b/selfdrive/ui/qt/offroad/software_settings.cc index 346948f91..adf76a812 100644 --- a/selfdrive/ui/qt/offroad/software_settings.cc +++ b/selfdrive/ui/qt/offroad/software_settings.cc @@ -80,6 +80,11 @@ SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) { auto uninstallBtn = new ButtonControl(tr("Uninstall %1").arg(getBrand()), tr("UNINSTALL")); connect(uninstallBtn, &ButtonControl::clicked, [&]() { if (ConfirmationDialog::confirm(tr("Are you sure you want to uninstall?"), tr("Uninstall"), this)) { + if (FrogPilotConfirmationDialog::yesorno(tr("Do you want to perform a full factory reset? All saved assets and settings will be permanently deleted!"), this)) { + if (FrogPilotConfirmationDialog::yesorno(tr("This is a complete factory reset and cannot be undone. Are you absolutely sure you want to continue?"), this)) { + Params().clearAll(ParamKeyFlag::ALL); + } + } params.putBool("DoUninstall", true); } }); diff --git a/selfdrive/ui/qt/onroad/buttons.h b/selfdrive/ui/qt/onroad/buttons.h index ec31c937d..e08538d3f 100644 --- a/selfdrive/ui/qt/onroad/buttons.h +++ b/selfdrive/ui/qt/onroad/buttons.h @@ -29,6 +29,8 @@ private: // FrogPilot variables void showEvent(QShowEvent *event) override; + + Params params_memory{"", true}; }; void drawIcon(QPainter &p, const QPoint ¢er, const QPixmap &img, const QBrush &bg, float opacity); diff --git a/selfdrive/ui/qt/window.h b/selfdrive/ui/qt/window.h index 87e907f86..f1389c29f 100644 --- a/selfdrive/ui/qt/window.h +++ b/selfdrive/ui/qt/window.h @@ -24,4 +24,5 @@ private: OnboardingWindow *onboardingWindow; // FrogPilot variables + Params params; }; diff --git a/selfdrive/ui/soundd.py b/selfdrive/ui/soundd.py index c57973336..79f2c5857 100644 --- a/selfdrive/ui/soundd.py +++ b/selfdrive/ui/soundd.py @@ -7,6 +7,7 @@ import wave from cereal import car, messaging from openpilot.common.basedir import BASEDIR from openpilot.common.filter_simple import FirstOrderFilter +from openpilot.common.params import Params from openpilot.common.realtime import Ratekeeper from openpilot.common.utils import retry from openpilot.common.swaglog import cloudlog @@ -77,6 +78,8 @@ class Soundd: self.spl_filter_weighted = FirstOrderFilter(0, 2.5, FILTER_DT, initialized=False) # FrogPilot variables + self.params_memory = Params(memory=True) + self.update_frogpilot_sounds() def load_sounds(self): diff --git a/system/manager/manager.py b/system/manager/manager.py index 5e7018874..9923bff01 100755 --- a/system/manager/manager.py +++ b/system/manager/manager.py @@ -41,6 +41,7 @@ def manager_init() -> None: params.put_bool("RecordFront", True) # FrogPilot variables + params_cache = Params("/cache/params", return_defaults=True) # set unset params to their default value for k in params.all_keys(): @@ -138,6 +139,7 @@ def manager_thread() -> None: ignition_prev = False # FrogPilot variables + params_memory = Params(memory=True) while True: sm.update(1000) @@ -148,10 +150,12 @@ def manager_thread() -> None: params.clear_all(ParamKeyFlag.CLEAR_ON_ONROAD_TRANSITION) # FrogPilot variables + params_memory.clear_all(ParamKeyFlag.CLEAR_ON_ONROAD_TRANSITION) elif not started and started_prev: params.clear_all(ParamKeyFlag.CLEAR_ON_OFFROAD_TRANSITION) # FrogPilot variables + params_memory.clear_all(ParamKeyFlag.CLEAR_ON_OFFROAD_TRANSITION) ignition = any(ps.ignitionLine or ps.ignitionCan for ps in sm['pandaStates'] if ps.pandaType != log.PandaState.PandaType.unknown) if ignition and not ignition_prev: diff --git a/system/updated/updated.py b/system/updated/updated.py index 9b4b41983..47f385c3e 100755 --- a/system/updated/updated.py +++ b/system/updated/updated.py @@ -452,6 +452,7 @@ def main() -> None: first_run = True # FrogPilot variables + params_memory = Params(memory=True) while True: wait_helper.ready_event.clear()