auto type cast for `Params` (#35786)

* first

* fix

* fix

* this

* real

* time

* time

* more

* more

* fix

* subclass

* fix

* fix

* test

* fix

* ruff

* revert

* default

* json

* more

* test

* test

* d

* better

* better

* test

* one

* test

* space
pull/35795/head
Maxime Desroches 7 days ago committed by GitHub
parent 4d39d50858
commit 58d3038241
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 16
      common/params.cc
  2. 21
      common/params.h
  3. 3
      common/params.py
  4. 238
      common/params_keys.h
  5. 49
      common/params_pyx.pyx
  6. 39
      common/tests/test_params.py
  7. 5
      selfdrive/selfdrived/selfdrived.py
  8. 4
      selfdrive/selfdrived/tests/test_alerts.py
  9. 5
      selfdrive/test/test_updated.py
  10. 2
      selfdrive/ui/layouts/settings/firehose.py
  11. 8
      selfdrive/ui/widgets/offroad_alerts.py
  12. 2
      system/athena/athenad.py
  13. 6
      system/hardware/power_monitoring.py
  14. 2
      system/loggerd/logger.cc
  15. 37
      system/manager/manager.py
  16. 2
      system/updated/tests/test_base.py
  17. 14
      system/updated/updated.py

@ -115,8 +115,16 @@ bool Params::checkKey(const std::string &key) {
return keys.find(key) != keys.end(); return keys.find(key) != keys.end();
} }
ParamKeyFlag Params::getKeyFlag(const std::string &key) {
return static_cast<ParamKeyFlag>(keys[key].flags);
}
ParamKeyType Params::getKeyType(const std::string &key) { ParamKeyType Params::getKeyType(const std::string &key) {
return static_cast<ParamKeyType>(keys[key]); return keys[key].type;
}
std::string Params::getKeyDefaultValue(const std::string &key) {
return keys[key].default_value;
} }
int Params::put(const char* key, const char* value, size_t value_size) { int Params::put(const char* key, const char* value, size_t value_size) {
@ -195,17 +203,17 @@ std::map<std::string, std::string> Params::readAll() {
return util::read_files_in_dir(getParamPath()); return util::read_files_in_dir(getParamPath());
} }
void Params::clearAll(ParamKeyType key_type) { void Params::clearAll(ParamKeyFlag key_flag) {
FileLock file_lock(params_path + "/.lock"); FileLock file_lock(params_path + "/.lock");
// 1) delete params of key_type // 1) delete params of key_flag
// 2) delete files that are not defined in the keys. // 2) delete files that are not defined in the keys.
if (DIR *d = opendir(getParamPath().c_str())) { if (DIR *d = opendir(getParamPath().c_str())) {
struct dirent *de = NULL; struct dirent *de = NULL;
while ((de = readdir(d))) { while ((de = readdir(d))) {
if (de->d_type != DT_DIR) { if (de->d_type != DT_DIR) {
auto it = keys.find(de->d_name); auto it = keys.find(de->d_name);
if (it == keys.end() || (it->second & key_type)) { if (it == keys.end() || (it->second.flags & key_flag)) {
unlink(getParamPath(de->d_name).c_str()); unlink(getParamPath(de->d_name).c_str());
} }
} }

@ -9,7 +9,7 @@
#include "common/queue.h" #include "common/queue.h"
enum ParamKeyType { enum ParamKeyFlag {
PERSISTENT = 0x02, PERSISTENT = 0x02,
CLEAR_ON_MANAGER_START = 0x04, CLEAR_ON_MANAGER_START = 0x04,
CLEAR_ON_ONROAD_TRANSITION = 0x08, CLEAR_ON_ONROAD_TRANSITION = 0x08,
@ -20,6 +20,21 @@ enum ParamKeyType {
ALL = 0xFFFFFFFF ALL = 0xFFFFFFFF
}; };
enum ParamKeyType {
STRING = 0,
BOOL = 1,
INT = 2,
FLOAT = 3,
TIME = 4, // ISO 8601
JSON = 5
};
struct ParamKeyAttributes {
uint32_t flags;
ParamKeyType type;
std::string default_value = "";
};
class Params { class Params {
public: public:
explicit Params(const std::string &path = {}); explicit Params(const std::string &path = {});
@ -30,14 +45,16 @@ public:
std::vector<std::string> allKeys() const; std::vector<std::string> allKeys() const;
bool checkKey(const std::string &key); bool checkKey(const std::string &key);
ParamKeyFlag getKeyFlag(const std::string &key);
ParamKeyType getKeyType(const std::string &key); ParamKeyType getKeyType(const std::string &key);
std::string getKeyDefaultValue(const std::string &key);
inline std::string getParamPath(const std::string &key = {}) { inline std::string getParamPath(const std::string &key = {}) {
return params_path + params_prefix + (key.empty() ? "" : "/" + key); return params_path + params_prefix + (key.empty() ? "" : "/" + key);
} }
// Delete a value // Delete a value
int remove(const std::string &key); int remove(const std::string &key);
void clearAll(ParamKeyType type); void clearAll(ParamKeyFlag flag);
// helpers for reading values // helpers for reading values
std::string get(const std::string &key, bool block = false); std::string get(const std::string &key, bool block = false);

@ -1,5 +1,6 @@
from openpilot.common.params_pyx import Params, ParamKeyType, UnknownKeyName from openpilot.common.params_pyx import Params, ParamKeyFlag, ParamKeyType, UnknownKeyName
assert Params assert Params
assert ParamKeyFlag
assert ParamKeyType assert ParamKeyType
assert UnknownKeyName assert UnknownKeyName

@ -3,122 +3,124 @@
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
inline static std::unordered_map<std::string, uint32_t> keys = { #include "cereal/gen/cpp/log.capnp.h"
{"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG},
{"AdbEnabled", PERSISTENT}, inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"AlwaysOnDM", PERSISTENT}, {"AccessToken", {CLEAR_ON_MANAGER_START | DONT_LOG, STRING}},
{"ApiCache_Device", PERSISTENT}, {"AdbEnabled", {PERSISTENT, BOOL}},
{"ApiCache_FirehoseStats", PERSISTENT}, {"AlwaysOnDM", {PERSISTENT, BOOL}},
{"AssistNowToken", PERSISTENT}, {"ApiCache_Device", {PERSISTENT, STRING}},
{"AthenadPid", PERSISTENT}, {"ApiCache_FirehoseStats", {PERSISTENT, JSON}},
{"AthenadUploadQueue", PERSISTENT}, {"AssistNowToken", {PERSISTENT, STRING}},
{"AthenadRecentlyViewedRoutes", PERSISTENT}, {"AthenadPid", {PERSISTENT, STRING}},
{"BootCount", PERSISTENT}, {"AthenadUploadQueue", {PERSISTENT, JSON}},
{"CalibrationParams", PERSISTENT}, {"AthenadRecentlyViewedRoutes", {PERSISTENT, STRING}},
{"CameraDebugExpGain", CLEAR_ON_MANAGER_START}, {"BootCount", {PERSISTENT, INT}},
{"CameraDebugExpTime", CLEAR_ON_MANAGER_START}, {"CalibrationParams", {PERSISTENT, STRING}},
{"CarBatteryCapacity", PERSISTENT}, {"CameraDebugExpGain", {CLEAR_ON_MANAGER_START, STRING}},
{"CarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"CameraDebugExpTime", {CLEAR_ON_MANAGER_START, STRING}},
{"CarParamsCache", CLEAR_ON_MANAGER_START}, {"CarBatteryCapacity", {PERSISTENT, INT}},
{"CarParamsPersistent", PERSISTENT}, {"CarParams", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, STRING}},
{"CarParamsPrevRoute", PERSISTENT}, {"CarParamsCache", {CLEAR_ON_MANAGER_START, STRING}},
{"CompletedTrainingVersion", PERSISTENT}, {"CarParamsPersistent", {PERSISTENT, STRING}},
{"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"CarParamsPrevRoute", {PERSISTENT, STRING}},
{"CurrentBootlog", PERSISTENT}, {"CompletedTrainingVersion", {PERSISTENT, STRING, "0"}},
{"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"ControlsReady", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
{"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"CurrentBootlog", {PERSISTENT, STRING}},
{"DisablePowerDown", PERSISTENT}, {"CurrentRoute", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, STRING}},
{"DisableUpdates", PERSISTENT}, {"DisableLogging", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
{"DisengageOnAccelerator", PERSISTENT}, {"DisablePowerDown", {PERSISTENT, BOOL}},
{"DongleId", PERSISTENT}, {"DisableUpdates", {PERSISTENT, BOOL}},
{"DoReboot", CLEAR_ON_MANAGER_START}, {"DisengageOnAccelerator", {PERSISTENT, BOOL, "0"}},
{"DoShutdown", CLEAR_ON_MANAGER_START}, {"DongleId", {PERSISTENT, STRING}},
{"DoUninstall", CLEAR_ON_MANAGER_START}, {"DoReboot", {CLEAR_ON_MANAGER_START, BOOL}},
{"DriverTooDistracted", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"DoShutdown", {CLEAR_ON_MANAGER_START, BOOL}},
{"AlphaLongitudinalEnabled", PERSISTENT | DEVELOPMENT_ONLY}, {"DoUninstall", {CLEAR_ON_MANAGER_START, BOOL}},
{"ExperimentalMode", PERSISTENT}, {"DriverTooDistracted", {CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON, BOOL}},
{"ExperimentalModeConfirmed", PERSISTENT}, {"AlphaLongitudinalEnabled", {PERSISTENT | DEVELOPMENT_ONLY, BOOL}},
{"FirmwareQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"ExperimentalMode", {PERSISTENT, BOOL}},
{"ForcePowerDown", PERSISTENT}, {"ExperimentalModeConfirmed", {PERSISTENT, BOOL}},
{"GitBranch", PERSISTENT}, {"FirmwareQueryDone", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
{"GitCommit", PERSISTENT}, {"ForcePowerDown", {PERSISTENT, BOOL}},
{"GitCommitDate", PERSISTENT}, {"GitBranch", {PERSISTENT, STRING}},
{"GitDiff", PERSISTENT}, {"GitCommit", {PERSISTENT, STRING}},
{"GithubSshKeys", PERSISTENT}, {"GitCommitDate", {PERSISTENT, STRING}},
{"GithubUsername", PERSISTENT}, {"GitDiff", {PERSISTENT, STRING}},
{"GitRemote", PERSISTENT}, {"GithubSshKeys", {PERSISTENT, STRING}},
{"GsmApn", PERSISTENT}, {"GithubUsername", {PERSISTENT, STRING}},
{"GsmMetered", PERSISTENT}, {"GitRemote", {PERSISTENT, STRING}},
{"GsmRoaming", PERSISTENT}, {"GsmApn", {PERSISTENT, STRING}},
{"HardwareSerial", PERSISTENT}, {"GsmMetered", {PERSISTENT, BOOL, "1"}},
{"HasAcceptedTerms", PERSISTENT}, {"GsmRoaming", {PERSISTENT, BOOL}},
{"InstallDate", PERSISTENT}, {"HardwareSerial", {PERSISTENT, STRING}},
{"IsDriverViewEnabled", CLEAR_ON_MANAGER_START}, {"HasAcceptedTerms", {PERSISTENT, STRING, "0"}},
{"IsEngaged", PERSISTENT}, {"InstallDate", {PERSISTENT, TIME}},
{"IsLdwEnabled", PERSISTENT}, {"IsDriverViewEnabled", {CLEAR_ON_MANAGER_START, BOOL}},
{"IsMetric", PERSISTENT}, {"IsEngaged", {PERSISTENT, BOOL}},
{"IsOffroad", CLEAR_ON_MANAGER_START}, {"IsLdwEnabled", {PERSISTENT, BOOL}},
{"IsOnroad", PERSISTENT}, {"IsMetric", {PERSISTENT, BOOL}},
{"IsRhdDetected", PERSISTENT}, {"IsOffroad", {CLEAR_ON_MANAGER_START, BOOL}},
{"IsReleaseBranch", CLEAR_ON_MANAGER_START}, {"IsOnroad", {PERSISTENT, BOOL}},
{"IsTakingSnapshot", CLEAR_ON_MANAGER_START}, {"IsRhdDetected", {PERSISTENT, BOOL}},
{"IsTestedBranch", CLEAR_ON_MANAGER_START}, {"IsReleaseBranch", {CLEAR_ON_MANAGER_START, BOOL}},
{"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"IsTakingSnapshot", {CLEAR_ON_MANAGER_START, BOOL}},
{"LanguageSetting", PERSISTENT}, {"IsTestedBranch", {CLEAR_ON_MANAGER_START, BOOL}},
{"LastAthenaPingTime", CLEAR_ON_MANAGER_START}, {"JoystickDebugMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
{"LastGPSPosition", PERSISTENT}, {"LanguageSetting", {PERSISTENT, STRING, "main_en"}},
{"LastManagerExitReason", CLEAR_ON_MANAGER_START}, {"LastAthenaPingTime", {CLEAR_ON_MANAGER_START, INT}},
{"LastOffroadStatusPacket", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"LastGPSPosition", {PERSISTENT, STRING}},
{"LastPowerDropDetected", CLEAR_ON_MANAGER_START}, {"LastManagerExitReason", {CLEAR_ON_MANAGER_START, STRING}},
{"LastUpdateException", CLEAR_ON_MANAGER_START}, {"LastOffroadStatusPacket", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, JSON}},
{"LastUpdateTime", PERSISTENT}, {"LastPowerDropDetected", {CLEAR_ON_MANAGER_START, STRING}},
{"LiveDelay", PERSISTENT}, {"LastUpdateException", {CLEAR_ON_MANAGER_START, STRING}},
{"LiveParameters", PERSISTENT}, {"LastUpdateTime", {PERSISTENT, TIME}},
{"LiveParametersV2", PERSISTENT}, {"LiveDelay", {PERSISTENT, STRING}},
{"LiveTorqueParameters", PERSISTENT | DONT_LOG}, {"LiveParameters", {PERSISTENT, STRING}},
{"LocationFilterInitialState", PERSISTENT}, {"LiveParametersV2", {PERSISTENT, STRING}},
{"LongitudinalManeuverMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"LiveTorqueParameters", {PERSISTENT | DONT_LOG, STRING}},
{"LongitudinalPersonality", PERSISTENT}, {"LocationFilterInitialState", {PERSISTENT, STRING}},
{"NetworkMetered", PERSISTENT}, {"LongitudinalManeuverMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
{"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"LongitudinalPersonality", {PERSISTENT, INT, std::to_string(static_cast<int>(cereal::LongitudinalPersonality::STANDARD))}},
{"ObdMultiplexingEnabled", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"NetworkMetered", {PERSISTENT, BOOL}},
{"Offroad_CarUnrecognized", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"ObdMultiplexingChanged", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
{"Offroad_ConnectivityNeeded", CLEAR_ON_MANAGER_START}, {"ObdMultiplexingEnabled", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
{"Offroad_ConnectivityNeededPrompt", CLEAR_ON_MANAGER_START}, {"Offroad_CarUnrecognized", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
{"Offroad_IsTakingSnapshot", CLEAR_ON_MANAGER_START}, {"Offroad_ConnectivityNeeded", {CLEAR_ON_MANAGER_START, JSON}},
{"Offroad_NeosUpdate", CLEAR_ON_MANAGER_START}, {"Offroad_ConnectivityNeededPrompt", {CLEAR_ON_MANAGER_START, JSON}},
{"Offroad_NoFirmware", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"Offroad_IsTakingSnapshot", {CLEAR_ON_MANAGER_START, JSON}},
{"Offroad_Recalibration", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"Offroad_NeosUpdate", {CLEAR_ON_MANAGER_START, JSON}},
{"Offroad_StorageMissing", CLEAR_ON_MANAGER_START}, {"Offroad_NoFirmware", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
{"Offroad_TemperatureTooHigh", CLEAR_ON_MANAGER_START}, {"Offroad_Recalibration", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
{"Offroad_UnregisteredHardware", CLEAR_ON_MANAGER_START}, {"Offroad_StorageMissing", {CLEAR_ON_MANAGER_START, JSON}},
{"Offroad_UpdateFailed", CLEAR_ON_MANAGER_START}, {"Offroad_TemperatureTooHigh", {CLEAR_ON_MANAGER_START, JSON}},
{"OnroadCycleRequested", CLEAR_ON_MANAGER_START}, {"Offroad_UnregisteredHardware", {CLEAR_ON_MANAGER_START, JSON}},
{"OpenpilotEnabledToggle", PERSISTENT}, {"Offroad_UpdateFailed", {CLEAR_ON_MANAGER_START, JSON}},
{"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"OnroadCycleRequested", {CLEAR_ON_MANAGER_START, BOOL}},
{"PandaSomResetTriggered", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"OpenpilotEnabledToggle", {PERSISTENT, BOOL, "1"}},
{"PandaSignatures", CLEAR_ON_MANAGER_START}, {"PandaHeartbeatLost", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
{"PrimeType", PERSISTENT}, {"PandaSomResetTriggered", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
{"RecordAudio", PERSISTENT}, {"PandaSignatures", {CLEAR_ON_MANAGER_START, STRING}},
{"RecordFront", PERSISTENT}, {"PrimeType", {PERSISTENT, INT}},
{"RecordFrontLock", PERSISTENT}, // for the internal fleet {"RecordAudio", {PERSISTENT, BOOL}},
{"SecOCKey", PERSISTENT | DONT_LOG}, {"RecordFront", {PERSISTENT, BOOL}},
{"RouteCount", PERSISTENT}, {"RecordFrontLock", {PERSISTENT, BOOL}}, // for the internal fleet
{"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"SecOCKey", {PERSISTENT | DONT_LOG, STRING}},
{"SshEnabled", PERSISTENT}, {"RouteCount", {PERSISTENT, INT}},
{"TermsVersion", PERSISTENT}, {"SnoozeUpdate", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
{"TrainingVersion", PERSISTENT}, {"SshEnabled", {PERSISTENT, BOOL}},
{"UbloxAvailable", PERSISTENT}, {"TermsVersion", {PERSISTENT, STRING}},
{"UpdateAvailable", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"TrainingVersion", {PERSISTENT, STRING}},
{"UpdateFailedCount", CLEAR_ON_MANAGER_START}, {"UbloxAvailable", {PERSISTENT, BOOL}},
{"UpdaterAvailableBranches", PERSISTENT}, {"UpdateAvailable", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
{"UpdaterCurrentDescription", CLEAR_ON_MANAGER_START}, {"UpdateFailedCount", {CLEAR_ON_MANAGER_START, INT}},
{"UpdaterCurrentReleaseNotes", CLEAR_ON_MANAGER_START}, {"UpdaterAvailableBranches", {PERSISTENT, STRING}},
{"UpdaterFetchAvailable", CLEAR_ON_MANAGER_START}, {"UpdaterCurrentDescription", {CLEAR_ON_MANAGER_START, STRING}},
{"UpdaterNewDescription", CLEAR_ON_MANAGER_START}, {"UpdaterCurrentReleaseNotes", {CLEAR_ON_MANAGER_START, STRING}},
{"UpdaterNewReleaseNotes", CLEAR_ON_MANAGER_START}, {"UpdaterFetchAvailable", {CLEAR_ON_MANAGER_START, BOOL}},
{"UpdaterState", CLEAR_ON_MANAGER_START}, {"UpdaterNewDescription", {CLEAR_ON_MANAGER_START, STRING}},
{"UpdaterTargetBranch", CLEAR_ON_MANAGER_START}, {"UpdaterNewReleaseNotes", {CLEAR_ON_MANAGER_START, STRING}},
{"UpdaterLastFetchTime", PERSISTENT}, {"UpdaterState", {CLEAR_ON_MANAGER_START, STRING}},
{"Version", PERSISTENT}, {"UpdaterTargetBranch", {CLEAR_ON_MANAGER_START, STRING}},
{"UpdaterLastFetchTime", {PERSISTENT, TIME}},
{"Version", {PERSISTENT, STRING}},
}; };

@ -1,11 +1,13 @@
# distutils: language = c++ # distutils: language = c++
# cython: language_level = 3 # cython: language_level = 3
import datetime
import json
from libcpp cimport bool from libcpp cimport bool
from libcpp.string cimport string from libcpp.string cimport string
from libcpp.vector cimport vector from libcpp.vector cimport vector
cdef extern from "common/params.h": cdef extern from "common/params.h":
cpdef enum ParamKeyType: cpdef enum ParamKeyFlag:
PERSISTENT PERSISTENT
CLEAR_ON_MANAGER_START CLEAR_ON_MANAGER_START
CLEAR_ON_ONROAD_TRANSITION CLEAR_ON_ONROAD_TRANSITION
@ -14,6 +16,14 @@ cdef extern from "common/params.h":
CLEAR_ON_IGNITION_ON CLEAR_ON_IGNITION_ON
ALL ALL
cpdef enum ParamKeyType:
STRING
BOOL
INT
FLOAT
TIME
JSON
cdef cppclass c_Params "Params": cdef cppclass c_Params "Params":
c_Params(string) except + nogil c_Params(string) except + nogil
string get(string, bool) nogil string get(string, bool) nogil
@ -24,8 +34,10 @@ cdef extern from "common/params.h":
void putBoolNonBlocking(string, bool) nogil void putBoolNonBlocking(string, bool) nogil
int putBool(string, bool) nogil int putBool(string, bool) nogil
bool checkKey(string) nogil bool checkKey(string) nogil
ParamKeyType getKeyType(string) nogil
string getKeyDefaultValue(string) nogil
string getParamPath(string) nogil string getParamPath(string) nogil
void clearAll(ParamKeyType) void clearAll(ParamKeyFlag)
vector[string] allKeys() vector[string] allKeys()
@ -51,8 +63,8 @@ cdef class Params:
def __dealloc__(self): def __dealloc__(self):
del self.p del self.p
def clear_all(self, tx_type=ParamKeyType.ALL): def clear_all(self, tx_flag=ParamKeyFlag.ALL):
self.p.clearAll(tx_type) self.p.clearAll(tx_flag)
def check_key(self, key): def check_key(self, key):
key = ensure_bytes(key) key = ensure_bytes(key)
@ -60,8 +72,28 @@ cdef class Params:
raise UnknownKeyName(key) raise UnknownKeyName(key)
return key return key
def get(self, key, bool block=False, encoding=None): def cast(self, value, t, default):
try:
if t == STRING:
return value
elif t == BOOL:
return value == b"1"
elif t == INT:
return int(value)
elif t == FLOAT:
return float(value)
elif t == TIME:
return datetime.datetime.fromisoformat(value)
elif t == JSON:
return json.loads(value)
else:
return default
except (TypeError, ValueError):
return default
def get(self, key, bool block=False, encoding=None, default=None):
cdef string k = self.check_key(key) cdef string k = self.check_key(key)
cdef ParamKeyType t = self.p.getKeyType(ensure_bytes(key))
cdef string val cdef string val
with nogil: with nogil:
val = self.p.get(k, block) val = self.p.get(k, block)
@ -72,9 +104,9 @@ cdef class Params:
# it means we got an interrupt while waiting # it means we got an interrupt while waiting
raise KeyboardInterrupt raise KeyboardInterrupt
else: else:
return None return default
return val if encoding is None else val.decode(encoding) return self.cast(val if encoding is None else val.decode(encoding), t, default)
def get_bool(self, key, bool block=False): def get_bool(self, key, bool block=False):
cdef string k = self.check_key(key) cdef string k = self.check_key(key)
@ -122,3 +154,6 @@ cdef class Params:
def all_keys(self): def all_keys(self):
return self.p.allKeys() return self.p.allKeys()
def get_default_value(self, key):
return self.p.getKeyDefaultValue(self.check_key(key))

@ -1,10 +1,12 @@
import pytest import pytest
import datetime
import json
import os import os
import threading import threading
import time import time
import uuid import uuid
from openpilot.common.params import Params, ParamKeyType, UnknownKeyName from openpilot.common.params import Params, ParamKeyFlag, UnknownKeyName
class TestParams: class TestParams:
def setup_method(self): def setup_method(self):
@ -29,7 +31,7 @@ class TestParams:
f.write("test") f.write("test")
assert os.path.isfile(undefined_param) assert os.path.isfile(undefined_param)
self.params.clear_all(ParamKeyType.CLEAR_ON_MANAGER_START) self.params.clear_all(ParamKeyFlag.CLEAR_ON_MANAGER_START)
assert self.params.get("CarParams") is None assert self.params.get("CarParams") is None
assert self.params.get("DongleId") is not None assert self.params.get("DongleId") is not None
assert not os.path.isfile(undefined_param) assert not os.path.isfile(undefined_param)
@ -107,3 +109,36 @@ class TestParams:
assert len(keys) > 20 assert len(keys) > 20
assert len(keys) == len(set(keys)) assert len(keys) == len(set(keys))
assert b"CarParams" in keys assert b"CarParams" in keys
def test_params_default_init_value(self):
assert self.params.get_default_value("LanguageSetting")
assert self.params.get_default_value("LongitudinalPersonality")
assert not self.params.get_default_value("LiveParameters")
def test_params_get_type(self):
# json
self.params.put("ApiCache_FirehoseStats", json.dumps({"a": 0}))
assert self.params.get("ApiCache_FirehoseStats") == {"a": 0}
# int
self.params.put("BootCount", str(1441))
assert self.params.get("BootCount") == 1441
# bool
self.params.put("AdbEnabled", "1")
assert self.params.get("AdbEnabled")
# time
now = datetime.datetime.now(datetime.UTC)
self.params.put("InstallDate", str(now))
assert self.params.get("InstallDate", encoding="utf-8") == now
def test_params_get_default(self):
now = datetime.datetime.now(datetime.UTC)
self.params.remove("InstallDate")
assert self.params.get("InstallDate", encoding="utf-8") is None
assert self.params.get("InstallDate", encoding="utf-8", default=now) == now
self.params.put("BootCount", "1xx1")
assert self.params.get("BootCount", encoding="utf-8") is None
assert self.params.get("BootCount", encoding="utf-8", default=1441) == 1441

@ -478,10 +478,7 @@ class SelfdriveD:
self.CS_prev = CS self.CS_prev = CS
def read_personality_param(self): def read_personality_param(self):
try: return self.params.get('LongitudinalPersonality', default=log.LongitudinalPersonality.standard)
return int(self.params.get('LongitudinalPersonality'))
except (ValueError, TypeError):
return log.LongitudinalPersonality.standard
def params_thread(self, evt): def params_thread(self, evt):
while not evt.is_set(): while not evt.is_set():

@ -111,7 +111,7 @@ class TestAlerts:
alert = copy.copy(self.offroad_alerts[a]) alert = copy.copy(self.offroad_alerts[a])
set_offroad_alert(a, True) set_offroad_alert(a, True)
alert['extra'] = '' alert['extra'] = ''
assert json.dumps(alert) == params.get(a, encoding='utf8') assert alert == params.get(a, encoding='utf8')
# then delete it # then delete it
set_offroad_alert(a, False) set_offroad_alert(a, False)
@ -125,6 +125,6 @@ class TestAlerts:
alert = self.offroad_alerts[a] alert = self.offroad_alerts[a]
set_offroad_alert(a, True, extra_text="a"*i) set_offroad_alert(a, True, extra_text="a"*i)
written_alert = json.loads(params.get(a, encoding='utf8')) written_alert = params.get(a, encoding='utf8')
assert "a"*i == written_alert['extra'] assert "a"*i == written_alert['extra']
assert alert["text"] == written_alert['text'] assert alert["text"] == written_alert['text']

@ -162,8 +162,7 @@ class TestUpdated:
def _check_update_state(self, update_available): def _check_update_state(self, update_available):
# make sure LastUpdateTime is recent # make sure LastUpdateTime is recent
t = self._read_param("LastUpdateTime") last_update_time = self._read_param("LastUpdateTime", encoding="utf-8")
last_update_time = datetime.datetime.fromisoformat(t)
td = datetime.datetime.now(datetime.UTC).replace(tzinfo=None) - last_update_time td = datetime.datetime.now(datetime.UTC).replace(tzinfo=None) - last_update_time
assert td.total_seconds() < 10 assert td.total_seconds() < 10
self.params.remove("LastUpdateTime") self.params.remove("LastUpdateTime")
@ -174,7 +173,7 @@ class TestUpdated:
# check params # check params
update = self._read_param("UpdateAvailable") update = self._read_param("UpdateAvailable")
assert update == "1" == update_available, f"UpdateAvailable: {repr(update)}" assert update == "1" == update_available, f"UpdateAvailable: {repr(update)}"
assert self._read_param("UpdateFailedCount") == "0" assert self._read_param("UpdateFailedCount") == 0
# TODO: check that the finalized update actually matches remote # TODO: check that the finalized update actually matches remote
# check the .overlay_init and .overlay_consistent flags # check the .overlay_init and .overlay_consistent flags

@ -55,7 +55,7 @@ class FirehoseLayout(Widget):
if not stats: if not stats:
return 0 return 0
try: try:
return int(json.loads(stats).get("firehose", 0)) return int(stats.get("firehose", 0))
except Exception: except Exception:
cloudlog.exception(f"Failed to decode firehose stats: {stats}") cloudlog.exception(f"Failed to decode firehose stats: {stats}")
return 0 return 0

@ -190,14 +190,10 @@ class OffroadAlert(AbstractAlert):
for alert_data in self.sorted_alerts: for alert_data in self.sorted_alerts:
text = "" text = ""
bytes_data = self.params.get(alert_data.key) alert_json = self.params.get(alert_data.key)
if bytes_data: if alert_json:
try:
alert_json = json.loads(bytes_data)
text = alert_json.get("text", "").replace("{}", alert_json.get("extra", "")) text = alert_json.get("text", "").replace("{}", alert_json.get("extra", ""))
except json.JSONDecodeError:
text = ""
alert_data.text = text alert_data.text = text
alert_data.visible = bool(text) alert_data.visible = bool(text)

@ -151,7 +151,7 @@ class UploadQueueCache:
try: try:
upload_queue_json = Params().get("AthenadUploadQueue") upload_queue_json = Params().get("AthenadUploadQueue")
if upload_queue_json is not None: if upload_queue_json is not None:
for item in json.loads(upload_queue_json): for item in upload_queue_json:
upload_queue.put(UploadItem.from_dict(item)) upload_queue.put(UploadItem.from_dict(item))
except Exception: except Exception:
cloudlog.exception("athena.UploadQueueCache.initialize.exception") cloudlog.exception("athena.UploadQueueCache.initialize.exception")

@ -29,12 +29,10 @@ class PowerMonitoring:
self.car_voltage_instant_mV = 12e3 # Last value of peripheralState voltage self.car_voltage_instant_mV = 12e3 # Last value of peripheralState voltage
self.integration_lock = threading.Lock() self.integration_lock = threading.Lock()
car_battery_capacity_uWh = self.params.get("CarBatteryCapacity") car_battery_capacity_uWh = self.params.get("CarBatteryCapacity", default=0)
if car_battery_capacity_uWh is None:
car_battery_capacity_uWh = 0
# Reset capacity if it's low # Reset capacity if it's low
self.car_battery_capacity_uWh = max((CAR_BATTERY_CAPACITY_uWh / 10), int(car_battery_capacity_uWh)) self.car_battery_capacity_uWh = max((CAR_BATTERY_CAPACITY_uWh / 10), car_battery_capacity_uWh)
# Calculation tick # Calculation tick
def calculate(self, voltage: int | None, ignition: bool): def calculate(self, voltage: int | None, ignition: bool):

@ -59,7 +59,7 @@ kj::Array<capnp::word> logger_build_init_data() {
for (auto& [key, value] : params_map) { for (auto& [key, value] : params_map) {
auto lentry = lparams[j]; auto lentry = lparams[j];
lentry.setKey(key); lentry.setKey(key);
if ( !(params.getKeyType(key) & DONT_LOG) ) { if ( !(params.getKeyFlag(key) & DONT_LOG) ) {
lentry.setValue(capnp::Data::Reader((const kj::byte*)value.data(), value.size())); lentry.setValue(capnp::Data::Reader((const kj::byte*)value.data(), value.size()));
} }
j++; j++;

@ -8,7 +8,7 @@ import traceback
from cereal import log from cereal import log
import cereal.messaging as messaging import cereal.messaging as messaging
import openpilot.system.sentry as sentry import openpilot.system.sentry as sentry
from openpilot.common.params import Params, ParamKeyType from openpilot.common.params import Params, ParamKeyFlag
from openpilot.common.text_window import TextWindow from openpilot.common.text_window import TextWindow
from openpilot.system.hardware import HARDWARE from openpilot.system.hardware import HARDWARE
from openpilot.system.manager.helpers import unblock_stdout, write_onroad_params, save_bootlog from openpilot.system.manager.helpers import unblock_stdout, write_onroad_params, save_bootlog
@ -26,30 +26,21 @@ def manager_init() -> None:
build_metadata = get_build_metadata() build_metadata = get_build_metadata()
params = Params() params = Params()
params.clear_all(ParamKeyType.CLEAR_ON_MANAGER_START) params.clear_all(ParamKeyFlag.CLEAR_ON_MANAGER_START)
params.clear_all(ParamKeyType.CLEAR_ON_ONROAD_TRANSITION) params.clear_all(ParamKeyFlag.CLEAR_ON_ONROAD_TRANSITION)
params.clear_all(ParamKeyType.CLEAR_ON_OFFROAD_TRANSITION) params.clear_all(ParamKeyFlag.CLEAR_ON_OFFROAD_TRANSITION)
params.clear_all(ParamKeyType.CLEAR_ON_IGNITION_ON) params.clear_all(ParamKeyFlag.CLEAR_ON_IGNITION_ON)
if build_metadata.release_channel: if build_metadata.release_channel:
params.clear_all(ParamKeyType.DEVELOPMENT_ONLY) params.clear_all(ParamKeyFlag.DEVELOPMENT_ONLY)
default_params: list[tuple[str, str | bytes]] = [
("CompletedTrainingVersion", "0"),
("DisengageOnAccelerator", "0"),
("GsmMetered", "1"),
("HasAcceptedTerms", "0"),
("LanguageSetting", "main_en"),
("OpenpilotEnabledToggle", "1"),
("LongitudinalPersonality", str(log.LongitudinalPersonality.standard)),
]
if params.get_bool("RecordFrontLock"): if params.get_bool("RecordFrontLock"):
params.put_bool("RecordFront", True) params.put_bool("RecordFront", True)
# set unset params # set unset params to their default value
for k, v in default_params: for k in params.all_keys():
if params.get(k) is None: default_value = params.get_default_value(k)
params.put(k, v) if default_value and not params.get(k):
params.put(k, default_value)
# Create folders needed for msgq # Create folders needed for msgq
try: try:
@ -142,13 +133,13 @@ def manager_thread() -> None:
started = sm['deviceState'].started started = sm['deviceState'].started
if started and not started_prev: if started and not started_prev:
params.clear_all(ParamKeyType.CLEAR_ON_ONROAD_TRANSITION) params.clear_all(ParamKeyFlag.CLEAR_ON_ONROAD_TRANSITION)
elif not started and started_prev: elif not started and started_prev:
params.clear_all(ParamKeyType.CLEAR_ON_OFFROAD_TRANSITION) params.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) 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: if ignition and not ignition_prev:
params.clear_all(ParamKeyType.CLEAR_ON_IGNITION_ON) params.clear_all(ParamKeyFlag.CLEAR_ON_IGNITION_ON)
# update onroad params, which drives pandad's safety setter thread # update onroad params, which drives pandad's safety setter thread
if started != started_prev: if started != started_prev:

@ -152,7 +152,7 @@ class ParamsBaseUpdateTest(TestBaseUpdate):
def wait_for_failed(self): def wait_for_failed(self):
self.wait_for_condition(lambda: self.params.get("UpdateFailedCount", encoding="utf-8") is not None and \ self.wait_for_condition(lambda: self.params.get("UpdateFailedCount", encoding="utf-8") is not None and \
int(self.params.get("UpdateFailedCount", encoding="utf-8")) > 0) self.params.get("UpdateFailedCount", encoding="utf-8") > 0)
def wait_for_fetch_available(self): def wait_for_fetch_available(self):
self.wait_for_condition(lambda: self.params.get_bool("UpdaterFetchAvailable")) self.wait_for_condition(lambda: self.params.get_bool("UpdaterFetchAvailable"))

@ -63,14 +63,6 @@ def write_time_to_param(params, param) -> None:
t = datetime.datetime.now(datetime.UTC).replace(tzinfo=None) t = datetime.datetime.now(datetime.UTC).replace(tzinfo=None)
params.put(param, t.isoformat().encode('utf8')) params.put(param, t.isoformat().encode('utf8'))
def read_time_from_param(params, param) -> datetime.datetime | None:
t = params.get(param, encoding='utf8')
try:
return datetime.datetime.fromisoformat(t)
except (TypeError, ValueError):
pass
return None
def run(cmd: list[str], cwd: str = None) -> str: def run(cmd: list[str], cwd: str = None) -> str:
return subprocess.check_output(cmd, cwd=cwd, stderr=subprocess.STDOUT, encoding='utf8') return subprocess.check_output(cmd, cwd=cwd, stderr=subprocess.STDOUT, encoding='utf8')
@ -283,7 +275,7 @@ class Updater:
if update_success: if update_success:
write_time_to_param(self.params, "LastUpdateTime") write_time_to_param(self.params, "LastUpdateTime")
else: else:
t = read_time_from_param(self.params, "LastUpdateTime") t = self.params.get("LastUpdateTime", encoding="utf8")
if t is not None: if t is not None:
last_update = t last_update = t
@ -428,7 +420,7 @@ def main() -> None:
if Path(os.path.join(STAGING_ROOT, "old_openpilot")).is_dir(): if Path(os.path.join(STAGING_ROOT, "old_openpilot")).is_dir():
cloudlog.event("update installed") cloudlog.event("update installed")
if not params.get("InstallDate"): if not params.get("InstallDate", encoding="utf-8"):
t = datetime.datetime.now(datetime.UTC).replace(tzinfo=None).isoformat() t = datetime.datetime.now(datetime.UTC).replace(tzinfo=None).isoformat()
params.put("InstallDate", t.encode('utf8')) params.put("InstallDate", t.encode('utf8'))
@ -468,7 +460,7 @@ def main() -> None:
updater.check_for_update() updater.check_for_update()
# download update # download update
last_fetch = read_time_from_param(params, "UpdaterLastFetchTime") last_fetch = params.get("UpdaterLastFetchTime", encoding="utf8")
timed_out = last_fetch is None or (datetime.datetime.now(datetime.UTC).replace(tzinfo=None) - last_fetch > datetime.timedelta(days=3)) timed_out = last_fetch is None or (datetime.datetime.now(datetime.UTC).replace(tzinfo=None) - last_fetch > datetime.timedelta(days=3))
user_requested_fetch = wait_helper.user_request == UserRequest.FETCH user_requested_fetch = wait_helper.user_request == UserRequest.FETCH
if params.get_bool("NetworkMetered") and not timed_out and not user_requested_fetch: if params.get_bool("NetworkMetered") and not timed_out and not user_requested_fetch:

Loading…
Cancel
Save