Merge remote-tracking branch 'upstream/master' into hyundai-match-dash-speed

pull/25235/head
Shane Smiskol 3 years ago
commit b0003faca7
  1. 2
      cereal
  2. 19
      common/params.cc
  3. 2
      common/params.h
  4. 5
      common/params_pyx.pyx
  5. 8
      common/tests/test_params.py
  6. 110
      docs/CARS.md
  7. 2
      panda
  8. 8
      selfdrive/boardd/boardd.cc
  9. 2
      selfdrive/car/chrysler/values.py
  10. 2
      selfdrive/car/gm/values.py
  11. 2
      selfdrive/car/hyundai/values.py
  12. 3
      selfdrive/car/subaru/carstate.py
  13. 2
      selfdrive/car/tests/routes.py
  14. 2
      selfdrive/car/tests/test_models.py
  15. 2
      selfdrive/car/torque_data/override.yaml
  16. 14
      selfdrive/car/volkswagen/values.py
  17. 4
      selfdrive/sensord/tests/test_sensord.py
  18. 2
      selfdrive/test/process_replay/ref_commit
  19. 2
      selfdrive/ui/.gitignore
  20. 3
      selfdrive/ui/SConscript
  21. 81
      selfdrive/ui/qt/offroad/settings.cc
  22. 13
      selfdrive/ui/qt/offroad/settings.h
  23. 156
      selfdrive/ui/qt/offroad/software_settings.cc
  24. 8
      selfdrive/ui/qt/widgets/controls.cc
  25. 14
      selfdrive/ui/qt/widgets/controls.h
  26. 2
      selfdrive/ui/qt/widgets/offroad_alerts.cc
  27. 8
      selfdrive/ui/qt/widgets/ssh_keys.cc
  28. 2
      selfdrive/ui/qt/widgets/ssh_keys.h
  29. 2
      selfdrive/ui/tests/cycle_offroad_alerts.py
  30. 91
      selfdrive/ui/translations/main_ja.ts
  31. 91
      selfdrive/ui/translations/main_ko.ts
  32. 91
      selfdrive/ui/translations/main_pt-BR.ts
  33. 91
      selfdrive/ui/translations/main_zh-CHS.ts
  34. 91
      selfdrive/ui/translations/main_zh-CHT.ts
  35. 310
      selfdrive/updated.py
  36. 61
      system/camerad/cameras/camera_qcom2.cc
  37. 4
      system/camerad/cameras/camera_qcom2.h
  38. 6
      system/camerad/cameras/sensor2_i2c.h

@ -1 +1 @@
Subproject commit bd2f7fa56706bcec3c9906bd57c2ec46f0666ac5
Subproject commit 513dfc7ee001243cd68a57a9d92fe3170fc49c7d

@ -3,6 +3,7 @@
#include <dirent.h>
#include <sys/file.h>
#include <algorithm>
#include <csignal>
#include <unordered_map>
@ -154,18 +155,24 @@ std::unordered_map<std::string, uint32_t> keys = {
{"PrimeType", PERSISTENT},
{"RecordFront", PERSISTENT},
{"RecordFrontLock", PERSISTENT}, // for the internal fleet
{"ReleaseNotes", PERSISTENT},
{"ReplayControlsState", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
{"ShouldDoUpdate", CLEAR_ON_MANAGER_START},
{"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF},
{"SshEnabled", PERSISTENT},
{"SubscriberInfo", PERSISTENT},
{"SwitchToBranch", CLEAR_ON_MANAGER_START},
{"TermsVersion", PERSISTENT},
{"Timezone", PERSISTENT},
{"TrainingVersion", PERSISTENT},
{"UpdateAvailable", CLEAR_ON_MANAGER_START},
{"UpdateFailedCount", CLEAR_ON_MANAGER_START},
{"UpdaterState", CLEAR_ON_MANAGER_START},
{"UpdaterFetchAvailable", CLEAR_ON_MANAGER_START},
{"UpdaterTargetBranch", CLEAR_ON_MANAGER_START},
{"UpdaterAvailableBranches", CLEAR_ON_MANAGER_START},
{"UpdaterCurrentDescription", CLEAR_ON_MANAGER_START},
{"UpdaterCurrentReleaseNotes", CLEAR_ON_MANAGER_START},
{"UpdaterNewDescription", CLEAR_ON_MANAGER_START},
{"UpdaterNewReleaseNotes", CLEAR_ON_MANAGER_START},
{"Version", PERSISTENT},
{"VisionRadarToggle", PERSISTENT},
{"WideCameraOnly", PERSISTENT},
@ -197,6 +204,14 @@ Params::Params(const std::string &path) {
params_path = path.empty() ? default_param_path : ensure_params_path(prefix, path);
}
std::vector<std::string> Params::allKeys() const {
std::vector<std::string> ret;
for (auto &p : keys) {
ret.push_back(p.first);
}
return ret;
}
bool Params::checkKey(const std::string &key) {
return keys.find(key) != keys.end();
}

@ -2,6 +2,7 @@
#include <map>
#include <string>
#include <vector>
enum ParamKeyType {
PERSISTENT = 0x02,
@ -15,6 +16,7 @@ enum ParamKeyType {
class Params {
public:
Params(const std::string &path = {});
std::vector<std::string> allKeys() const;
bool checkKey(const std::string &key);
ParamKeyType getKeyType(const std::string &key);
inline std::string getParamPath(const std::string &key = {}) {

@ -2,6 +2,7 @@
# cython: language_level = 3
from libcpp cimport bool
from libcpp.string cimport string
from libcpp.vector cimport vector
import threading
cdef extern from "common/params.h":
@ -22,6 +23,7 @@ cdef extern from "common/params.h":
bool checkKey(string) nogil
string getParamPath(string) nogil
void clearAll(ParamKeyType)
vector[string] allKeys()
def ensure_bytes(v):
@ -99,6 +101,9 @@ cdef class Params:
cdef string key_bytes = ensure_bytes(key)
return self.p.getParamPath(key_bytes).decode("utf-8")
def all_keys(self):
return self.p.allKeys()
def put_nonblocking(key, val, d=""):
threading.Thread(target=lambda: Params(d).put(key, val)).start()

@ -98,6 +98,14 @@ class TestParams(unittest.TestCase):
assert q.get("CarParams") is None
assert q.get("CarParams", True) == b"1"
def test_params_all_keys(self):
keys = Params().all_keys()
# sanity checks
assert len(keys) > 20
assert len(keys) == len(set(keys))
assert b"CarParams" in keys
if __name__ == "__main__":
unittest.main()

@ -11,27 +11,27 @@ A supported vehicle is one that just works when you install a comma three. All s
|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|
|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|
|Acura|RDX 2019-22|All|openpilot|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
|Audi|A3 2014-19|ACC + Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Audi|A3 Sportback e-tron 2017-18|ACC + Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Audi|Q2 2018|ACC + Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Audi|Q3 2020-21|ACC + Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Audi|RS3 2018|ACC + Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Audi|S3 2015-17|ACC + Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Audi|Q3 2020-21|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Cadillac|Escalade ESV 2016[<sup>1</sup>](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|
|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|Stock|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|
|Chevrolet|Silverado 1500 2020-21|Safety Package II|Stock|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|
|Chevrolet|Volt 2017-18[<sup>1</sup>](#footnotes)|Adaptive Cruise Control|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|Chrysler|Pacifica 2019-20|Adaptive Cruise Control|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|Chevrolet|Volt 2017-18[<sup>1</sup>](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|Chrysler|Pacifica Hybrid 2019-22|Adaptive Cruise Control|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|Chrysler|Pacifica Hybrid 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None|
|Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|
|Genesis|G70 2020|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|
|Genesis|G80 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
|Genesis|G90 2017-18|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|
|GMC|Acadia 2018[<sup>1</sup>](#footnotes)|Adaptive Cruise Control|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|
|GMC|Acadia 2018[<sup>1</sup>](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|
|GMC|Sierra 1500 2020-21|Driver Alert Package II|Stock|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|
|Honda|Accord 2018-22|All|openpilot|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
|Honda|Accord Hybrid 2018-22|All|openpilot|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
@ -80,8 +80,8 @@ A supported vehicle is one that just works when you install a comma three. All s
|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|
|Hyundai|Tucson Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|
|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|Kia|Ceed 2019|Smart Cruise Control (SCC) & LKAS|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|
|Kia|EV6 2022|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai P|
|Kia|Forte 2018|Smart Cruise Control (SCC) & LKAS|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|
@ -122,9 +122,9 @@ A supported vehicle is one that just works when you install a comma three. All s
|Nissan|Leaf 2018-22|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|
|Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|
|Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|
|Ram|1500 2019-22|Adaptive Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Ram|
|SEAT|Ateca 2018|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|SEAT|Leon 2014-20|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Ram|1500 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Ram|
|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|
|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|
|Subaru|Crosstrek 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|
@ -135,13 +135,13 @@ A supported vehicle is one that just works when you install a comma three. All s
|Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru B|
|Subaru|XV 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|
|Subaru|XV 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|
|Škoda|Kamiq 2021[<sup>5</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Škoda|Karoq 2019-21[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Škoda|Kodiaq 2018-19|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Škoda|Octavia 2015, 2018-19|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Škoda|Octavia RS 2016|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Škoda|Scala 2020|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Škoda|Superb 2015-18|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Škoda|Kamiq 2021[<sup>5</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Škoda|Karoq 2019-21[<sup>7</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Škoda|Kodiaq 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Škoda|Superb 2015-18|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Toyota|Avalon 2016|Toyota Safety Sense P|Stock[<sup>3</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
@ -182,37 +182,37 @@ A supported vehicle is one that just works when you install a comma three. All s
|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|Sienna 2018-20|All|Stock[<sup>3</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Volkswagen|Arteon 2018-22[<sup>7,8</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Arteon eHybrid 2020-22[<sup>7,8</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Arteon R 2020-22[<sup>7,8</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Atlas 2018-23[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Atlas Cross Sport 2021-22[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|California 2021[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Caravelle 2020[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|CC 2018-22[<sup>7,8</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|e-Golf 2014-20|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Golf 2015-20[<sup>8</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Golf Alltrack 2015-19|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Golf GTD 2015-20|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Golf GTE 2015-20|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Golf GTI 2015-21|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Golf R 2015-19[<sup>8</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Golf SportsVan 2015-20|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Jetta 2018-22[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Jetta GLI 2021-22[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Passat 2015-22[<sup>6,7,8</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Passat Alltrack 2015-22[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Passat GTE 2015-22[<sup>7,8</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Polo 2020-22[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Polo GTI 2020-22[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|T-Cross 2021[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|T-Roc 2021[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Taos 2022[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Teramont 2018-22[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Teramont Cross Sport 2021-22[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Teramont X 2021-22[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Tiguan 2019-22[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Touran 2017|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Arteon 2018-22[<sup>7,8</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Arteon eHybrid 2020-22[<sup>7,8</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Arteon R 2020-22[<sup>7,8</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Atlas 2018-23[<sup>7</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Atlas Cross Sport 2021-22[<sup>7</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|California 2021[<sup>7</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Caravelle 2020[<sup>7</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|CC 2018-22[<sup>7,8</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Golf 2015-20[<sup>8</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Golf R 2015-19[<sup>8</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Jetta 2018-22[<sup>7</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Jetta GLI 2021-22[<sup>7</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Passat 2015-22[<sup>6,7,8</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Passat Alltrack 2015-22[<sup>7</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Passat GTE 2015-22[<sup>7,8</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Polo 2020-22[<sup>7</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Polo GTI 2020-22[<sup>7</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|T-Cross 2021[<sup>7</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|T-Roc 2021[<sup>7</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Taos 2022[<sup>7</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Teramont 2018-22[<sup>7</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Teramont Cross Sport 2021-22[<sup>7</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Teramont X 2021-22[<sup>7</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Tiguan 2019-22[<sup>7</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Touran 2017|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
<a id="footnotes"></a>
<sup>1</sup>Requires a <a href="https://github.com/commaai/openpilot/wiki/GM#hardware">community built ASCM harness</a>. <b><i>NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).</i></b> <br />

@ -1 +1 @@
Subproject commit 19983f13b37518298a3c282d5069c090b68f6864
Subproject commit 046fd58e8d64c58ed80769fcbec5ac2417a04c71

@ -346,14 +346,14 @@ std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *>
auto ps = pss[i];
ps.setUptime(health.uptime_pkt);
ps.setBlockedCnt(health.blocked_msg_cnt_pkt);
ps.setSafetyTxBlocked(health.safety_tx_blocked_pkt);
ps.setSafetyRxInvalid(health.safety_rx_invalid_pkt);
ps.setIgnitionLine(health.ignition_line_pkt);
ps.setIgnitionCan(health.ignition_can_pkt);
ps.setControlsAllowed(health.controls_allowed_pkt);
ps.setGasInterceptorDetected(health.gas_interceptor_detected_pkt);
ps.setCanRxErrs(health.can_rx_errs_pkt);
ps.setCanSendErrs(health.can_send_errs_pkt);
ps.setCanFwdErrs(health.can_fwd_errs_pkt);
ps.setTxBufferOverflow(health.tx_buffer_overflow_pkt);
ps.setRxBufferOverflow(health.rx_buffer_overflow_pkt);
ps.setGmlanSendErrs(health.gmlan_send_errs_pkt);
ps.setPandaType(panda->hw_type);
ps.setSafetyModel(cereal::CarParams::SafetyModel(health.safety_mode_pkt));

@ -52,7 +52,7 @@ RAM_CARS = RAM_DT | RAM_HD
@dataclass
class ChryslerCarInfo(CarInfo):
package: str = "Adaptive Cruise Control"
package: str = "Adaptive Cruise Control (ACC)"
harness: Enum = Harness.fca
CAR_INFO: Dict[str, Optional[Union[ChryslerCarInfo, List[ChryslerCarInfo]]]] = {

@ -71,7 +71,7 @@ class Footnote(Enum):
@dataclass
class GMCarInfo(CarInfo):
package: str = "Adaptive Cruise Control"
package: str = "Adaptive Cruise Control (ACC)"
harness: Enum = Harness.obd_ii
footnotes: List[Enum] = field(default_factory=lambda: [Footnote.OBD_II])

@ -29,6 +29,8 @@ class CarControllerParams:
self.STEER_DRIVER_ALLOWANCE = 250
self.STEER_DRIVER_MULTIPLIER = 2
self.STEER_THRESHOLD = 250
self.STEER_DELTA_UP = 2
self.STEER_DELTA_DOWN = 3
# To determine the limit for your car, find the maximum value that the stock LKAS will request.
# If the max stock LKAS request is <384, add your car to this list.

@ -32,9 +32,8 @@ class CarState(CarStateBase):
cp_wheels.vl["Wheel_Speeds"]["RR"],
)
ret.vEgoRaw = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4.
# Kalman filter, even though Subaru raw wheel speed is heaviliy filtered by default
ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
ret.standstill = ret.vEgoRaw < 0.01
ret.standstill = ret.vEgoRaw == 0
# continuous blinker signals for assisted lane change
ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(50, cp.vl["Dashlights"]["LEFT_BLINKER"],

@ -194,7 +194,7 @@ routes = [
CarTestRoute("c321c6b697c5a5ff|2020-06-23--11-04-33", SUBARU.FORESTER),
CarTestRoute("791340bc01ed993d|2019-03-10--16-28-08", SUBARU.IMPREZA),
CarTestRoute("8bf7e79a3ce64055|2021-05-24--09-36-27", SUBARU.IMPREZA_2020),
CarTestRoute("1bbe6bf2d62f58a8|2022-07-14--17-11-43", SUBARU.OUTBACK, segment=3),
CarTestRoute("1bbe6bf2d62f58a8|2022-07-14--17-11-43", SUBARU.OUTBACK, segment=10),
CarTestRoute("c56e69bbc74b8fad|2022-08-18--09-43-51", SUBARU.LEGACY, segment=3),
# Pre-global, dashcam
CarTestRoute("95441c38ae8c130e|2020-06-08--12-10-17", SUBARU.FORESTER_PREGLOBAL),

@ -234,7 +234,7 @@ class TestCarModelBase(unittest.TestCase):
checks['gasPressed'] += CS.gasPressed != self.safety.get_gas_pressed_prev()
checks['cruiseState'] += CS.cruiseState.enabled and not CS.cruiseState.available
if self.CP.carName not in ("hyundai", "volkswagen", "subaru", "gm", "body"):
if self.CP.carName not in ("hyundai", "volkswagen", "gm", "body"):
# TODO: fix standstill mismatches for other makes
checks['standstill'] += CS.standstill == self.safety.get_vehicle_moving()

@ -21,7 +21,7 @@ FORD FOCUS 4TH GEN: [.nan, 1.5, .nan]
COMMA BODY: [.nan, 1000, .nan]
# Totally new cars
KIA EV6 2022: [3.5, 2.5, 0.0]
KIA EV6 2022: [3.5, 3.0, 0.0]
RAM 1500 5TH GEN: [2.0, 2.0, 0.0]
RAM HD 5TH GEN: [1.4, 1.4, 0.0]
SUBARU OUTBACK 6TH GEN: [2.3, 2.3, 0.11]

@ -164,7 +164,7 @@ class Footnote(Enum):
@dataclass
class VWCarInfo(CarInfo):
package: str = "Driver Assistance"
package: str = "Adaptive Cruise Control (ACC) & Lane Assist"
harness: Enum = Harness.vw
@ -216,13 +216,13 @@ CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = {
],
CAR.TROC_MK1: VWCarInfo("Volkswagen T-Roc 2021", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
CAR.AUDI_A3_MK3: [
VWCarInfo("Audi A3 2014-19", "ACC + Lane Assist"),
VWCarInfo("Audi A3 Sportback e-tron 2017-18", "ACC + Lane Assist"),
VWCarInfo("Audi RS3 2018", "ACC + Lane Assist"),
VWCarInfo("Audi S3 2015-17", "ACC + Lane Assist"),
VWCarInfo("Audi A3 2014-19"),
VWCarInfo("Audi A3 Sportback e-tron 2017-18"),
VWCarInfo("Audi RS3 2018"),
VWCarInfo("Audi S3 2015-17"),
],
CAR.AUDI_Q2_MK1: VWCarInfo("Audi Q2 2018", "ACC + Lane Assist"),
CAR.AUDI_Q3_MK2: VWCarInfo("Audi Q3 2020-21", "ACC + Lane Assist"),
CAR.AUDI_Q2_MK1: VWCarInfo("Audi Q2 2018"),
CAR.AUDI_Q3_MK2: VWCarInfo("Audi Q3 2020-21"),
CAR.SEAT_ATECA_MK1: VWCarInfo("SEAT Ateca 2018"),
CAR.SEAT_LEON_MK3: VWCarInfo("SEAT Leon 2014-20"),
CAR.SKODA_KAMIQ_MK1: VWCarInfo("Škoda Kamiq 2021", footnotes=[Footnote.KAMIQ]),

@ -121,6 +121,10 @@ class TestSensord(unittest.TestCase):
cls.events = read_sensor_events(5)
managed_processes["sensord"].stop()
def tearDown(self):
# interrupt check might leave sensord running
managed_processes["sensord"].stop()
def test_sensors_present(self):
# verify correct sensors configuration

@ -1 +1 @@
3ad478bf44f50815d05acc5b12ff2f01a6cb42ff
ef5395e5f36550d2b485216eee5406bf6062e9c9

@ -1,6 +1,8 @@
moc_*
*.moc
translations/main_test_en.*
_mui
watch3
installer/installers/*

@ -56,7 +56,8 @@ qt_env.Program("qt/spinner", ["qt/spinner.cc"], LIBS=qt_libs)
# build main UI
qt_src = ["main.cc", "qt/sidebar.cc", "qt/onroad.cc", "qt/body.cc",
"qt/window.cc", "qt/home.cc", "qt/offroad/settings.cc",
"qt/offroad/onboarding.cc", "qt/offroad/driverview.cc"]
"qt/offroad/software_settings.cc", "qt/offroad/onboarding.cc",
"qt/offroad/driverview.cc"]
qt_env.Program("_ui", qt_src + [asset_obj], LIBS=qt_libs)
if GetOption('test'):
qt_src.remove("main.cc") # replaced by test_runner

@ -159,7 +159,7 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) {
addItem(dcamBtn);
auto resetCalibBtn = new ButtonControl(tr("Reset Calibration"), tr("RESET"), "");
connect(resetCalibBtn, &ButtonControl::showDescription, this, &DevicePanel::updateCalibDescription);
connect(resetCalibBtn, &ButtonControl::showDescriptionEvent, this, &DevicePanel::updateCalibDescription);
connect(resetCalibBtn, &ButtonControl::clicked, [&]() {
if (ConfirmationDialog::confirm(tr("Are you sure you want to reset calibration?"), this)) {
params.remove("CalibrationParams");
@ -282,85 +282,6 @@ void DevicePanel::poweroff() {
}
}
SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) {
gitBranchLbl = new LabelControl(tr("Git Branch"));
gitCommitLbl = new LabelControl(tr("Git Commit"));
osVersionLbl = new LabelControl(tr("OS Version"));
versionLbl = new LabelControl(tr("Version"), "", QString::fromStdString(params.get("ReleaseNotes")).trimmed());
lastUpdateLbl = new LabelControl(tr("Last Update Check"), "", tr("The last time openpilot successfully checked for an update. The updater only runs while the car is off."));
updateBtn = new ButtonControl(tr("Check for Update"), "");
connect(updateBtn, &ButtonControl::clicked, [=]() {
if (params.getBool("IsOffroad")) {
fs_watch->addPath(QString::fromStdString(params.getParamPath("LastUpdateTime")));
fs_watch->addPath(QString::fromStdString(params.getParamPath("UpdateFailedCount")));
updateBtn->setText(tr("CHECKING"));
updateBtn->setEnabled(false);
}
std::system("pkill -1 -f selfdrive.updated");
});
connect(uiState(), &UIState::offroadTransition, updateBtn, &QPushButton::setEnabled);
branchSwitcherBtn = new ButtonControl(tr("Switch Branch"), tr("ENTER"), tr("The new branch will be pulled the next time the updater runs."));
connect(branchSwitcherBtn, &ButtonControl::clicked, [=]() {
QString branch = InputDialog::getText(tr("Enter branch name"), this, tr("The new branch will be pulled the next time the updater runs."),
false, -1, QString::fromStdString(params.get("SwitchToBranch")));
if (branch.isEmpty()) {
params.remove("SwitchToBranch");
} else {
params.put("SwitchToBranch", branch.toStdString());
}
std::system("pkill -1 -f selfdrive.updated");
});
connect(uiState(), &UIState::offroadTransition, branchSwitcherBtn, &QPushButton::setEnabled);
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?"), this)) {
params.putBool("DoUninstall", true);
}
});
connect(uiState(), &UIState::offroadTransition, uninstallBtn, &QPushButton::setEnabled);
QWidget *widgets[] = {versionLbl, lastUpdateLbl, updateBtn, branchSwitcherBtn, gitBranchLbl, gitCommitLbl, osVersionLbl, uninstallBtn};
for (QWidget* w : widgets) {
if (w == branchSwitcherBtn && params.getBool("IsTestedBranch")) {
continue;
}
addItem(w);
}
fs_watch = new QFileSystemWatcher(this);
QObject::connect(fs_watch, &QFileSystemWatcher::fileChanged, [=](const QString path) {
if (path.contains("UpdateFailedCount") && std::atoi(params.get("UpdateFailedCount").c_str()) > 0) {
lastUpdateLbl->setText(tr("failed to fetch update"));
updateBtn->setText(tr("CHECK"));
updateBtn->setEnabled(true);
} else if (path.contains("LastUpdateTime")) {
updateLabels();
}
});
}
void SoftwarePanel::showEvent(QShowEvent *event) {
updateLabels();
}
void SoftwarePanel::updateLabels() {
QString lastUpdate = "";
auto tm = params.get("LastUpdateTime");
if (!tm.empty()) {
lastUpdate = timeAgo(QDateTime::fromString(QString::fromStdString(tm + "Z"), Qt::ISODate));
}
versionLbl->setText(getBrandVersion());
lastUpdateLbl->setText(lastUpdate);
updateBtn->setText(tr("CHECK"));
updateBtn->setEnabled(true);
gitBranchLbl->setText(QString::fromStdString(params.get("GitBranch")));
gitCommitLbl->setText(QString::fromStdString(params.get("GitCommit")).left(10));
osVersionLbl->setText(QString::fromStdString(Hardware::get_os_version()).trimmed());
}
void SettingsWindow::showEvent(QShowEvent *event) {
panel_widget->setCurrentIndex(0);
nav_btns->buttons()[0]->setChecked(true);

@ -71,14 +71,15 @@ public:
private:
void showEvent(QShowEvent *event) override;
void updateLabels();
void checkForUpdates();
LabelControl *gitBranchLbl;
LabelControl *gitCommitLbl;
LabelControl *osVersionLbl;
bool is_onroad = false;
QLabel *onroadLbl;
LabelControl *versionLbl;
LabelControl *lastUpdateLbl;
ButtonControl *updateBtn;
ButtonControl *branchSwitcherBtn;
ButtonControl *installBtn;
ButtonControl *downloadBtn;
ButtonControl *targetBranchBtn;
Params params;
QFileSystemWatcher *fs_watch;

@ -0,0 +1,156 @@
#include "selfdrive/ui/qt/offroad/settings.h"
#include <cassert>
#include <cmath>
#include <string>
#include <QDebug>
#include <QLabel>
#include "common/params.h"
#include "common/util.h"
#include "selfdrive/ui/ui.h"
#include "selfdrive/ui/qt/util.h"
#include "selfdrive/ui/qt/widgets/controls.h"
#include "selfdrive/ui/qt/widgets/input.h"
#include "system/hardware/hw.h"
void SoftwarePanel::checkForUpdates() {
std::system("pkill -SIGUSR1 -f selfdrive.updated");
}
SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) {
onroadLbl = new QLabel(tr("Updates are only downloaded while the car is off."));
onroadLbl->setStyleSheet("font-size: 50px; font-weight: 400; text-align: left; padding-top: 30px; padding-bottom: 30px;");
addItem(onroadLbl);
// current version
versionLbl = new LabelControl(tr("Current Version"), "");
addItem(versionLbl);
// download update btn
downloadBtn = new ButtonControl(tr("Download"), tr("CHECK"));
connect(downloadBtn, &ButtonControl::clicked, [=]() {
downloadBtn->setEnabled(false);
if (downloadBtn->text() == tr("CHECK")) {
checkForUpdates();
} else {
std::system("pkill -SIGHUP -f selfdrive.updated");
}
});
addItem(downloadBtn);
// install update btn
installBtn = new ButtonControl(tr("Install Update"), tr("INSTALL"));
connect(installBtn, &ButtonControl::clicked, [=]() {
installBtn->setEnabled(false);
params.putBool("DoShutdown", true);
});
addItem(installBtn);
// branch selecting
targetBranchBtn = new ButtonControl(tr("Target Branch"), tr("SELECT"));
connect(targetBranchBtn, &ButtonControl::clicked, [=]() {
auto current = params.get("GitBranch");
QStringList branches = QString::fromStdString(params.get("UpdaterAvailableBranches")).split(",");
for (QString b : {current.c_str(), "devel-staging", "devel", "master-ci", "master"}) {
auto i = branches.indexOf(b);
if (i >= 0) {
branches.removeAt(i);
branches.insert(0, b);
}
}
QString cur = QString::fromStdString(params.get("UpdaterTargetBranch"));
QString selection = MultiOptionDialog::getSelection(tr("Select a branch"), branches, cur, this);
if (!selection.isEmpty()) {
params.put("UpdaterTargetBranch", selection.toStdString());
targetBranchBtn->setValue(QString::fromStdString(params.get("UpdaterTargetBranch")));
checkForUpdates();
}
});
if (!params.getBool("IsTestedBranch")) {
addItem(targetBranchBtn);
}
// uninstall button
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?"), this)) {
params.putBool("DoUninstall", true);
}
});
addItem(uninstallBtn);
fs_watch = new QFileSystemWatcher(this);
QObject::connect(fs_watch, &QFileSystemWatcher::fileChanged, [=](const QString path) {
updateLabels();
});
connect(uiState(), &UIState::offroadTransition, [=](bool offroad) {
is_onroad = !offroad;
updateLabels();
});
updateLabels();
}
void SoftwarePanel::showEvent(QShowEvent *event) {
// nice for testing on PC
installBtn->setEnabled(true);
updateLabels();
}
void SoftwarePanel::updateLabels() {
// add these back in case the files got removed
fs_watch->addPath(QString::fromStdString(params.getParamPath("LastUpdateTime")));
fs_watch->addPath(QString::fromStdString(params.getParamPath("UpdateFailedCount")));
fs_watch->addPath(QString::fromStdString(params.getParamPath("UpdaterState")));
fs_watch->addPath(QString::fromStdString(params.getParamPath("UpdateAvailable")));
if (!isVisible()) {
return;
}
// updater only runs offroad
onroadLbl->setVisible(is_onroad);
downloadBtn->setVisible(!is_onroad);
// download update
QString updater_state = QString::fromStdString(params.get("UpdaterState"));
bool failed = std::atoi(params.get("UpdateFailedCount").c_str()) > 0;
if (updater_state != "idle") {
downloadBtn->setEnabled(false);
downloadBtn->setValue(updater_state);
} else {
if (failed) {
downloadBtn->setText("CHECK");
downloadBtn->setValue("failed to check for update");
} else if (params.getBool("UpdaterFetchAvailable")) {
downloadBtn->setText("DOWNLOAD");
downloadBtn->setValue("update available");
} else {
QString lastUpdate = "never";
auto tm = params.get("LastUpdateTime");
if (!tm.empty()) {
lastUpdate = timeAgo(QDateTime::fromString(QString::fromStdString(tm + "Z"), Qt::ISODate));
}
downloadBtn->setText("CHECK");
downloadBtn->setValue("up to date, last checked " + lastUpdate);
}
downloadBtn->setEnabled(true);
}
targetBranchBtn->setValue(QString::fromStdString(params.get("UpdaterTargetBranch")));
// current + new versions
versionLbl->setText(QString::fromStdString(params.get("UpdaterCurrentDescription")).left(40));
versionLbl->setDescription(QString::fromStdString(params.get("UpdaterCurrentReleaseNotes")));
installBtn->setVisible(!is_onroad && params.getBool("UpdateAvailable"));
installBtn->setValue(QString::fromStdString(params.get("UpdaterNewDescription")).left(35));
installBtn->setDescription(QString::fromStdString(params.get("UpdaterNewReleaseNotes")));
update();
}

@ -42,6 +42,12 @@ AbstractControl::AbstractControl(const QString &title, const QString &desc, cons
title_label->setStyleSheet("font-size: 50px; font-weight: 400; text-align: left");
hlayout->addWidget(title_label);
// value next to control button
value = new QLabel();
value->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
value->setStyleSheet("color: #aaaaaa");
hlayout->addWidget(value);
main_layout->addLayout(hlayout);
// description
@ -54,7 +60,7 @@ AbstractControl::AbstractControl(const QString &title, const QString &desc, cons
connect(title_label, &QPushButton::clicked, [=]() {
if (!description->isVisible()) {
emit showDescription();
emit showDescriptionEvent();
}
if (!description->text().isEmpty()) {

@ -45,8 +45,17 @@ public:
title_label->setText(title);
}
void setValue(const QString &val) {
value->setText(val);
}
public slots:
void showDescription() {
description->setVisible(true);
};
signals:
void showDescription();
void showDescriptionEvent();
protected:
AbstractControl(const QString &title, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr);
@ -54,6 +63,9 @@ protected:
QHBoxLayout *hlayout;
QPushButton *title_label;
private:
QLabel *value;
QLabel *description = nullptr;
};

@ -112,7 +112,7 @@ UpdateAlert::UpdateAlert(QWidget *parent) : AbstractAlert(true, parent) {
bool UpdateAlert::refresh() {
bool updateAvailable = params.getBool("UpdateAvailable");
if (updateAvailable) {
releaseNotes->setText(params.get("ReleaseNotes").c_str());
releaseNotes->setText(params.get("UpdaterNewReleaseNotes").c_str());
}
return updateAvailable;
}

@ -5,10 +5,6 @@
#include "selfdrive/ui/qt/widgets/input.h"
SshControl::SshControl() : ButtonControl(tr("SSH Keys"), "", tr("Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username.")) {
username_label.setAlignment(Qt::AlignRight | Qt::AlignVCenter);
username_label.setStyleSheet("color: #aaaaaa");
hlayout->insertWidget(1, &username_label);
QObject::connect(this, &ButtonControl::clicked, [=]() {
if (text() == tr("ADD")) {
QString username = InputDialog::getText(tr("Enter your GitHub username"), this);
@ -30,10 +26,10 @@ SshControl::SshControl() : ButtonControl(tr("SSH Keys"), "", tr("Warning: This g
void SshControl::refresh() {
QString param = QString::fromStdString(params.get("GithubSshKeys"));
if (param.length()) {
username_label.setText(QString::fromStdString(params.get("GithubUsername")));
setValue(QString::fromStdString(params.get("GithubUsername")));
setText(tr("REMOVE"));
} else {
username_label.setText("");
setValue("");
setText(tr("ADD"));
}
setEnabled(true);

@ -27,8 +27,6 @@ public:
private:
Params params;
QLabel username_label;
void refresh();
void getUserKeys(const QString &username);
};

@ -20,7 +20,7 @@ if __name__ == "__main__":
params.put_bool("UpdateAvailable", True)
r = open(os.path.join(BASEDIR, "RELEASES.md")).read()
r = r[:r.find('\n\n')] # Slice latest release notes
params.put("ReleaseNotes", r + "\n")
params.put("UpdaterNewReleaseNotes", r + "\n")
time.sleep(t)
params.put_bool("UpdateAvailable", False)

@ -193,7 +193,7 @@
<translation></translation>
</message>
<message>
<location line="+4"/>
<location line="+3"/>
<source>Select a language</source>
<translation></translation>
</message>
@ -418,7 +418,7 @@ prime subscription. Sign up now: https://connect.comma.ai</source>
https://connect.comma.ai</translation>
</message>
<message>
<location line="+57"/>
<location line="+58"/>
<source>No home
location set</source>
<translation>
@ -432,7 +432,7 @@ location set</source>
</translation>
</message>
<message>
<location line="+113"/>
<location line="+120"/>
<source>no recent destinations</source>
<translation></translation>
</message>
@ -718,7 +718,7 @@ location set</source>
<context>
<name>SettingsWindow</name>
<message>
<location filename="../qt/offroad/settings.cc" line="+101"/>
<location filename="../qt/offroad/settings.cc" line="+22"/>
<source>×</source>
<translation>×</translation>
</message>
@ -983,68 +983,47 @@ location set</source>
<context>
<name>SoftwarePanel</name>
<message>
<location filename="../qt/offroad/settings.cc" line="-130"/>
<source>Git Branch</source>
<translation>Git </translation>
<location filename="../qt/offroad/software_settings.cc" line="+24"/>
<source>Updates are only downloaded while the car is off.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Git Commit</source>
<translation>Git </translation>
</message>
<message>
<location line="+1"/>
<source>OS Version</source>
<translation>OS </translation>
<location line="+5"/>
<source>Current Version</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Version</source>
<translation></translation>
<location line="+4"/>
<source>Download</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Last Update Check</source>
<translation></translation>
<location line="+12"/>
<source>Install Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>The last time openpilot successfully checked for an update. The updater only runs while the car is off.</source>
<translation>openpilotが最後にアップデートの確認に成功してからの時間です</translation>
</message>
<message>
<location line="+1"/>
<source>Check for Update</source>
<translation></translation>
</message>
<message>
<location line="+5"/>
<source>CHECKING</source>
<translation></translation>
<source>INSTALL</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
<source>Switch Branch</source>
<translation></translation>
<location line="+8"/>
<source>Target Branch</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>ENTER</source>
<translation></translation>
<source>SELECT</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<location line="+2"/>
<source>The new branch will be pulled the next time the updater runs.</source>
<translation>updater </translation>
</message>
<message>
<location line="+0"/>
<source>Enter branch name</source>
<translation></translation>
<location line="+13"/>
<source>Select a branch</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+11"/>
<location line="+12"/>
<source>UNINSTALL</source>
<translation></translation>
</message>
@ -1059,13 +1038,8 @@ location set</source>
<translation></translation>
</message>
<message>
<location line="+17"/>
<source>failed to fetch update</source>
<translation></translation>
</message>
<message>
<location line="+1"/>
<location line="+21"/>
<location line="-47"/>
<location line="+3"/>
<source>CHECK</source>
<translation></translation>
</message>
@ -1083,7 +1057,7 @@ location set</source>
<translation>警告: これはGitHub SSH GitHub GitHub </translation>
</message>
<message>
<location line="+6"/>
<location line="+2"/>
<location line="+24"/>
<source>ADD</source>
<translation></translation>
@ -1153,7 +1127,7 @@ location set</source>
<context>
<name>TogglesPanel</name>
<message>
<location filename="../qt/offroad/settings.cc" line="-324"/>
<location filename="../qt/offroad/settings.cc" line="-303"/>
<source>Enable openpilot</source>
<translation>openpilot </translation>
</message>
@ -1290,12 +1264,11 @@ location set</source>
<name>WifiUI</name>
<message>
<location filename="../qt/offroad/networking.cc" line="+113"/>
<location line="+53"/>
<source>Scanning for networks...</source>
<translation>...</translation>
</message>
<message>
<location line="+26"/>
<location line="+80"/>
<source>CONNECTING...</source>
<translation>...</translation>
</message>

@ -193,7 +193,7 @@
<translation></translation>
</message>
<message>
<location line="+4"/>
<location line="+3"/>
<source>Select a language</source>
<translation> </translation>
</message>
@ -418,7 +418,7 @@ prime subscription. Sign up now: https://connect.comma.ai</source>
https://connect.comma.ai</translation>
</message>
<message>
<location line="+57"/>
<location line="+58"/>
<source>No home
location set</source>
<translation>
@ -432,7 +432,7 @@ location set</source>
</translation>
</message>
<message>
<location line="+113"/>
<location line="+120"/>
<source>no recent destinations</source>
<translation> </translation>
</message>
@ -718,7 +718,7 @@ location set</source>
<context>
<name>SettingsWindow</name>
<message>
<location filename="../qt/offroad/settings.cc" line="+101"/>
<location filename="../qt/offroad/settings.cc" line="+22"/>
<source>×</source>
<translation>×</translation>
</message>
@ -983,68 +983,47 @@ location set</source>
<context>
<name>SoftwarePanel</name>
<message>
<location filename="../qt/offroad/settings.cc" line="-130"/>
<source>Git Branch</source>
<translation>Git </translation>
</message>
<message>
<location line="+1"/>
<source>Git Commit</source>
<translation>Git </translation>
<location filename="../qt/offroad/software_settings.cc" line="+24"/>
<source>Updates are only downloaded while the car is off.</source>
<translation> .</translation>
</message>
<message>
<location line="+1"/>
<source>OS Version</source>
<translation>OS </translation>
<location line="+5"/>
<source>Current Version</source>
<translation> </translation>
</message>
<message>
<location line="+1"/>
<source>Version</source>
<translation></translation>
<location line="+4"/>
<source>Download</source>
<translation></translation>
</message>
<message>
<location line="+1"/>
<source>Last Update Check</source>
<translation> </translation>
<location line="+12"/>
<source>Install Update</source>
<translation> </translation>
</message>
<message>
<location line="+0"/>
<source>The last time openpilot successfully checked for an update. The updater only runs while the car is off.</source>
<translation> openpilot이 . .</translation>
</message>
<message>
<location line="+1"/>
<source>Check for Update</source>
<translation> </translation>
</message>
<message>
<location line="+5"/>
<source>CHECKING</source>
<translation></translation>
</message>
<message>
<location line="+7"/>
<source>Switch Branch</source>
<translation> </translation>
<source>INSTALL</source>
<translation></translation>
</message>
<message>
<location line="+0"/>
<source>ENTER</source>
<translation></translation>
<location line="+8"/>
<source>Target Branch</source>
<translation> </translation>
</message>
<message>
<location line="+0"/>
<location line="+2"/>
<source>The new branch will be pulled the next time the updater runs.</source>
<translation> .</translation>
<source>SELECT</source>
<translation></translation>
</message>
<message>
<location line="+0"/>
<source>Enter branch name</source>
<translation> </translation>
<location line="+13"/>
<source>Select a branch</source>
<translation> </translation>
</message>
<message>
<location line="+11"/>
<location line="+12"/>
<source>UNINSTALL</source>
<translation></translation>
</message>
@ -1059,13 +1038,8 @@ location set</source>
<translation>?</translation>
</message>
<message>
<location line="+17"/>
<source>failed to fetch update</source>
<translation> </translation>
</message>
<message>
<location line="+1"/>
<location line="+21"/>
<location line="-47"/>
<location line="+3"/>
<source>CHECK</source>
<translation></translation>
</message>
@ -1083,7 +1057,7 @@ location set</source>
<translation>경고: 허용으로 GitHub SSH . GitHub ID . comma에서는 GitHub ID를 .</translation>
</message>
<message>
<location line="+6"/>
<location line="+2"/>
<location line="+24"/>
<source>ADD</source>
<translation></translation>
@ -1153,7 +1127,7 @@ location set</source>
<context>
<name>TogglesPanel</name>
<message>
<location filename="../qt/offroad/settings.cc" line="-324"/>
<location filename="../qt/offroad/settings.cc" line="-303"/>
<source>Enable openpilot</source>
<translation>openpilot </translation>
</message>
@ -1290,12 +1264,11 @@ location set</source>
<name>WifiUI</name>
<message>
<location filename="../qt/offroad/networking.cc" line="+113"/>
<location line="+53"/>
<source>Scanning for networks...</source>
<translation> ...</translation>
</message>
<message>
<location line="+26"/>
<location line="+80"/>
<source>CONNECTING...</source>
<translation>...</translation>
</message>

@ -193,7 +193,7 @@
<translation>ALTERAR</translation>
</message>
<message>
<location line="+4"/>
<location line="+3"/>
<source>Select a language</source>
<translation>Selecione o Idioma</translation>
</message>
@ -419,7 +419,7 @@ prime subscription. Sign up now: https://connect.comma.ai</source>
uma assinatura prime Inscreva-se agora: https://connect.comma.ai</translation>
</message>
<message>
<location line="+57"/>
<location line="+58"/>
<source>No home
location set</source>
<translation>Sem local
@ -433,7 +433,7 @@ location set</source>
trabalho definido</translation>
</message>
<message>
<location line="+113"/>
<location line="+120"/>
<source>no recent destinations</source>
<translation>sem destinos recentes</translation>
</message>
@ -722,7 +722,7 @@ trabalho definido</translation>
<context>
<name>SettingsWindow</name>
<message>
<location filename="../qt/offroad/settings.cc" line="+101"/>
<location filename="../qt/offroad/settings.cc" line="+22"/>
<source>×</source>
<translation>×</translation>
</message>
@ -987,68 +987,47 @@ trabalho definido</translation>
<context>
<name>SoftwarePanel</name>
<message>
<location filename="../qt/offroad/settings.cc" line="-130"/>
<source>Git Branch</source>
<translation>Git Branch</translation>
</message>
<message>
<location line="+1"/>
<source>Git Commit</source>
<translation>Último Commit</translation>
<location filename="../qt/offroad/software_settings.cc" line="+24"/>
<source>Updates are only downloaded while the car is off.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>OS Version</source>
<translation>Versão do Sistema</translation>
<location line="+5"/>
<source>Current Version</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Version</source>
<translation>Versão</translation>
<location line="+4"/>
<source>Download</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Last Update Check</source>
<translation>Verificação da última atualização</translation>
<location line="+12"/>
<source>Install Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>The last time openpilot successfully checked for an update. The updater only runs while the car is off.</source>
<translation>A última vez que o openpilot verificou com sucesso uma atualização. O atualizador funciona com o carro desligado.</translation>
</message>
<message>
<location line="+1"/>
<source>Check for Update</source>
<translation>Verifique atualizações</translation>
</message>
<message>
<location line="+5"/>
<source>CHECKING</source>
<translation>VERIFICANDO</translation>
</message>
<message>
<location line="+7"/>
<source>Switch Branch</source>
<translation>Alterar Branch</translation>
<source>INSTALL</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>ENTER</source>
<translation>INSERIR</translation>
<location line="+8"/>
<source>Target Branch</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<location line="+2"/>
<source>The new branch will be pulled the next time the updater runs.</source>
<translation>A nova branch será aplicada ao verificar atualizações.</translation>
<source>SELECT</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>Enter branch name</source>
<translation>Inserir o nome da branch</translation>
<location line="+13"/>
<source>Select a branch</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+11"/>
<location line="+12"/>
<source>UNINSTALL</source>
<translation>DESINSTALAR</translation>
</message>
@ -1063,13 +1042,8 @@ trabalho definido</translation>
<translation>Tem certeza que quer desinstalar?</translation>
</message>
<message>
<location line="+17"/>
<source>failed to fetch update</source>
<translation>falha ao buscar atualização</translation>
</message>
<message>
<location line="+1"/>
<location line="+21"/>
<location line="-47"/>
<location line="+3"/>
<source>CHECK</source>
<translation>VERIFICAR</translation>
</message>
@ -1087,7 +1061,7 @@ trabalho definido</translation>
<translation>Aviso: isso concede acesso SSH a todas as chaves públicas nas configurações do GitHub. Nunca insira um nome de usuário do GitHub que não seja o seu. Um funcionário da comma NUNCA pedirá que você adicione seu nome de usuário do GitHub.</translation>
</message>
<message>
<location line="+6"/>
<location line="+2"/>
<location line="+24"/>
<source>ADD</source>
<translation>ADICIONAR</translation>
@ -1157,7 +1131,7 @@ trabalho definido</translation>
<context>
<name>TogglesPanel</name>
<message>
<location filename="../qt/offroad/settings.cc" line="-324"/>
<location filename="../qt/offroad/settings.cc" line="-303"/>
<source>Enable openpilot</source>
<translation>Ativar openpilot</translation>
</message>
@ -1294,12 +1268,11 @@ trabalho definido</translation>
<name>WifiUI</name>
<message>
<location filename="../qt/offroad/networking.cc" line="+113"/>
<location line="+53"/>
<source>Scanning for networks...</source>
<translation>Procurando redes...</translation>
</message>
<message>
<location line="+26"/>
<location line="+80"/>
<source>CONNECTING...</source>
<translation>CONECTANDO...</translation>
</message>

@ -193,7 +193,7 @@
<translation></translation>
</message>
<message>
<location line="+4"/>
<location line="+3"/>
<source>Select a language</source>
<translation></translation>
</message>
@ -418,7 +418,7 @@ prime subscription. Sign up now: https://connect.comma.ai</source>
https://connect.comma.ai</translation>
</message>
<message>
<location line="+57"/>
<location line="+58"/>
<source>No home
location set</source>
<translation></translation>
@ -430,7 +430,7 @@ location set</source>
<translation></translation>
</message>
<message>
<location line="+113"/>
<location line="+120"/>
<source>no recent destinations</source>
<translation></translation>
</message>
@ -716,7 +716,7 @@ location set</source>
<context>
<name>SettingsWindow</name>
<message>
<location filename="../qt/offroad/settings.cc" line="+101"/>
<location filename="../qt/offroad/settings.cc" line="+22"/>
<source>×</source>
<translation>×</translation>
</message>
@ -981,68 +981,47 @@ location set</source>
<context>
<name>SoftwarePanel</name>
<message>
<location filename="../qt/offroad/settings.cc" line="-130"/>
<source>Git Branch</source>
<translation>Git Branch</translation>
</message>
<message>
<location line="+1"/>
<source>Git Commit</source>
<translation>Git Commit</translation>
<location filename="../qt/offroad/software_settings.cc" line="+24"/>
<source>Updates are only downloaded while the car is off.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>OS Version</source>
<translation></translation>
<location line="+5"/>
<source>Current Version</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Version</source>
<translation></translation>
<location line="+4"/>
<source>Download</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Last Update Check</source>
<translation></translation>
<location line="+12"/>
<source>Install Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>The last time openpilot successfully checked for an update. The updater only runs while the car is off.</source>
<translation></translation>
</message>
<message>
<location line="+1"/>
<source>Check for Update</source>
<translation></translation>
</message>
<message>
<location line="+5"/>
<source>CHECKING</source>
<translation></translation>
</message>
<message>
<location line="+7"/>
<source>Switch Branch</source>
<translation></translation>
<source>INSTALL</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>ENTER</source>
<translation></translation>
<location line="+8"/>
<source>Target Branch</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<location line="+2"/>
<source>The new branch will be pulled the next time the updater runs.</source>
<translation></translation>
<source>SELECT</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>Enter branch name</source>
<translation></translation>
<location line="+13"/>
<source>Select a branch</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+11"/>
<location line="+12"/>
<source>UNINSTALL</source>
<translation></translation>
</message>
@ -1057,13 +1036,8 @@ location set</source>
<translation></translation>
</message>
<message>
<location line="+17"/>
<source>failed to fetch update</source>
<translation></translation>
</message>
<message>
<location line="+1"/>
<location line="+21"/>
<location line="-47"/>
<location line="+3"/>
<source>CHECK</source>
<translation></translation>
</message>
@ -1081,7 +1055,7 @@ location set</source>
<translation>SSH访问权限给您GitHub设置中的所有公钥GitHub用户名comma员工永远不会要求您添加他们的GitHub用户名</translation>
</message>
<message>
<location line="+6"/>
<location line="+2"/>
<location line="+24"/>
<source>ADD</source>
<translation></translation>
@ -1151,7 +1125,7 @@ location set</source>
<context>
<name>TogglesPanel</name>
<message>
<location filename="../qt/offroad/settings.cc" line="-324"/>
<location filename="../qt/offroad/settings.cc" line="-303"/>
<source>Enable openpilot</source>
<translation>openpilot</translation>
</message>
@ -1288,12 +1262,11 @@ location set</source>
<name>WifiUI</name>
<message>
<location filename="../qt/offroad/networking.cc" line="+113"/>
<location line="+53"/>
<source>Scanning for networks...</source>
<translation></translation>
</message>
<message>
<location line="+26"/>
<location line="+80"/>
<source>CONNECTING...</source>
<translation></translation>
</message>

@ -193,7 +193,7 @@
<translation></translation>
</message>
<message>
<location line="+4"/>
<location line="+3"/>
<source>Select a language</source>
<translation></translation>
</message>
@ -418,7 +418,7 @@ prime subscription. Sign up now: https://connect.comma.ai</source>
https://connect.comma.ai</translation>
</message>
<message>
<location line="+57"/>
<location line="+58"/>
<source>No home
location set</source>
<translation>
@ -432,7 +432,7 @@ location set</source>
</translation>
</message>
<message>
<location line="+113"/>
<location line="+120"/>
<source>no recent destinations</source>
<translation></translation>
</message>
@ -718,7 +718,7 @@ location set</source>
<context>
<name>SettingsWindow</name>
<message>
<location filename="../qt/offroad/settings.cc" line="+101"/>
<location filename="../qt/offroad/settings.cc" line="+22"/>
<source>×</source>
<translation>×</translation>
</message>
@ -983,68 +983,47 @@ location set</source>
<context>
<name>SoftwarePanel</name>
<message>
<location filename="../qt/offroad/settings.cc" line="-130"/>
<source>Git Branch</source>
<translation>Git </translation>
</message>
<message>
<location line="+1"/>
<source>Git Commit</source>
<translation>Git </translation>
<location filename="../qt/offroad/software_settings.cc" line="+24"/>
<source>Updates are only downloaded while the car is off.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>OS Version</source>
<translation></translation>
<location line="+5"/>
<source>Current Version</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Version</source>
<translation></translation>
<location line="+4"/>
<source>Download</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
<source>Last Update Check</source>
<translation></translation>
<location line="+12"/>
<source>Install Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>The last time openpilot successfully checked for an update. The updater only runs while the car is off.</source>
<translation></translation>
</message>
<message>
<location line="+1"/>
<source>Check for Update</source>
<translation></translation>
</message>
<message>
<location line="+5"/>
<source>CHECKING</source>
<translation></translation>
</message>
<message>
<location line="+7"/>
<source>Switch Branch</source>
<translation></translation>
<source>INSTALL</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>ENTER</source>
<translation></translation>
<location line="+8"/>
<source>Target Branch</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<location line="+2"/>
<source>The new branch will be pulled the next time the updater runs.</source>
<translation></translation>
<source>SELECT</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+0"/>
<source>Enter branch name</source>
<translation></translation>
<location line="+13"/>
<source>Select a branch</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+11"/>
<location line="+12"/>
<source>UNINSTALL</source>
<translation></translation>
</message>
@ -1059,13 +1038,8 @@ location set</source>
<translation></translation>
</message>
<message>
<location line="+17"/>
<source>failed to fetch update</source>
<translation></translation>
</message>
<message>
<location line="+1"/>
<location line="+21"/>
<location line="-47"/>
<location line="+3"/>
<source>CHECK</source>
<translation></translation>
</message>
@ -1083,7 +1057,7 @@ location set</source>
<translation> GitHub SSH GitHub comma GitHub </translation>
</message>
<message>
<location line="+6"/>
<location line="+2"/>
<location line="+24"/>
<source>ADD</source>
<translation></translation>
@ -1153,7 +1127,7 @@ location set</source>
<context>
<name>TogglesPanel</name>
<message>
<location filename="../qt/offroad/settings.cc" line="-324"/>
<location filename="../qt/offroad/settings.cc" line="-303"/>
<source>Enable openpilot</source>
<translation> openpilot</translation>
</message>
@ -1290,12 +1264,11 @@ location set</source>
<name>WifiUI</name>
<message>
<location filename="../qt/offroad/networking.cc" line="+113"/>
<location line="+53"/>
<source>Scanning for networks...</source>
<translation>...</translation>
</message>
<message>
<location line="+26"/>
<location line="+80"/>
<source>CONNECTING...</source>
<translation>...</translation>
</message>

@ -23,6 +23,7 @@
# disable this service.
import os
import re
import datetime
import subprocess
import psutil
@ -31,8 +32,9 @@ import signal
import fcntl
import time
import threading
from collections import defaultdict
from pathlib import Path
from typing import List, Tuple, Optional
from typing import List, Union, Optional
from markdown_it import MarkdownIt
from common.basedir import BASEDIR
@ -54,22 +56,27 @@ DAYS_NO_CONNECTIVITY_MAX = 14 # do not allow to engage after this many days
DAYS_NO_CONNECTIVITY_PROMPT = 10 # send an offroad prompt after this many days
class WaitTimeHelper:
def __init__(self, proc):
self.proc = proc
def __init__(self):
self.ready_event = threading.Event()
self.only_check_for_update = False
signal.signal(signal.SIGHUP, self.update_now)
signal.signal(signal.SIGUSR1, self.check_now)
def update_now(self, signum: int, frame) -> None:
cloudlog.info("caught SIGHUP, running update check immediately")
cloudlog.info("caught SIGHUP, attempting to downloading update")
self.only_check_for_update = False
self.ready_event.set()
def check_now(self, signum: int, frame) -> None:
cloudlog.info("caught SIGUSR1, checking for updates")
self.only_check_for_update = True
self.ready_event.set()
def sleep(self, t: float) -> None:
self.ready_event.wait(timeout=t)
def run(cmd: List[str], cwd: Optional[str] = None, low_priority: bool = False):
if low_priority:
cmd = ["nice", "-n", "19"] + cmd
def run(cmd: List[str], cwd: Optional[str] = None) -> str:
return subprocess.check_output(cmd, cwd=cwd, stderr=subprocess.STDOUT, encoding='utf8')
@ -82,59 +89,19 @@ def set_consistent_flag(consistent: bool) -> None:
consistent_file.unlink(missing_ok=True)
os.sync()
def set_params(new_version: bool, failed_count: int, exception: Optional[str]) -> None:
params = Params()
params.put("UpdateFailedCount", str(failed_count))
last_update = datetime.datetime.utcnow()
if failed_count == 0:
t = last_update.isoformat()
params.put("LastUpdateTime", t.encode('utf8'))
else:
try:
t = params.get("LastUpdateTime", encoding='utf8')
last_update = datetime.datetime.fromisoformat(t)
except (TypeError, ValueError):
pass
if exception is None:
params.remove("LastUpdateException")
else:
params.put("LastUpdateException", exception)
# Write out release notes for new versions
if new_version:
def parse_release_notes(basedir: str) -> bytes:
try:
with open(os.path.join(basedir, "RELEASES.md"), "rb") as f:
r = f.read().split(b'\n\n', 1)[0] # Slice latest release notes
try:
with open(os.path.join(FINALIZED, "RELEASES.md"), "rb") as f:
r = f.read().split(b'\n\n', 1)[0] # Slice latest release notes
try:
params.put("ReleaseNotes", MarkdownIt().render(r.decode("utf-8")))
except Exception:
params.put("ReleaseNotes", r + b"\n")
return bytes(MarkdownIt().render(r.decode("utf-8")), encoding="utf-8")
except Exception:
params.put("ReleaseNotes", "")
params.put_bool("UpdateAvailable", True)
# Handle user prompt
for alert in ("Offroad_UpdateFailed", "Offroad_ConnectivityNeeded", "Offroad_ConnectivityNeededPrompt"):
set_offroad_alert(alert, False)
now = datetime.datetime.utcnow()
dt = now - last_update
if failed_count > 15 and exception is not None:
if is_tested_branch():
extra_text = "Ensure the software is correctly installed"
else:
extra_text = exception
set_offroad_alert("Offroad_UpdateFailed", True, extra_text=extra_text)
elif dt.days > DAYS_NO_CONNECTIVITY_MAX and failed_count > 1:
set_offroad_alert("Offroad_ConnectivityNeeded", True)
elif dt.days > DAYS_NO_CONNECTIVITY_PROMPT:
remaining = max(DAYS_NO_CONNECTIVITY_MAX - dt.days, 1)
set_offroad_alert("Offroad_ConnectivityNeededPrompt", True, extra_text=f"{remaining} day{'' if remaining == 1 else 's'}.")
return r + b"\n"
except FileNotFoundError:
pass
except Exception:
cloudlog.exception("failed to parse release notes")
return b""
def setup_git_options(cwd: str) -> None:
# We sync FS object atimes (which NEOS doesn't use) and mtimes, but ctimes
@ -212,7 +179,7 @@ def init_overlay() -> None:
run(["sudo"] + mount_cmd)
run(["sudo", "chmod", "755", os.path.join(OVERLAY_METADATA, "work")])
git_diff = run(["git", "diff"], OVERLAY_MERGED, low_priority=True)
git_diff = run(["git", "diff"], OVERLAY_MERGED)
params.put("GitDiff", git_diff)
cloudlog.info(f"git diff output:\n{git_diff}")
@ -269,65 +236,161 @@ def handle_agnos_update() -> None:
set_offroad_alert("Offroad_NeosUpdate", False)
def check_git_fetch_result(fetch_txt: str) -> bool:
err_msg = "Failed to add the host to the list of known hosts (/data/data/com.termux/files/home/.ssh/known_hosts).\n"
return len(fetch_txt) > 0 and (fetch_txt != err_msg)
class Updater:
def __init__(self):
self.params = Params()
self.branches = defaultdict(lambda: None)
@property
def target_branch(self) -> str:
b: Union[str, None] = self.params.get("UpdaterTargetBranch", encoding='utf-8')
if b is None:
b = self.get_branch(BASEDIR)
self.params.put("UpdaterTargetBranch", b)
return b
@property
def update_ready(self) -> bool:
consistent_file = Path(os.path.join(FINALIZED, ".overlay_consistent"))
if consistent_file.is_file():
hash_mismatch = self.get_commit_hash(BASEDIR) != self.branches[self.target_branch]
branch_mismatch = self.get_branch(BASEDIR) != self.target_branch
on_target_branch = self.get_branch(FINALIZED) == self.target_branch
return ((hash_mismatch or branch_mismatch) and on_target_branch)
return False
@property
def update_available(self) -> bool:
if os.path.isdir(OVERLAY_MERGED):
hash_mismatch = self.get_commit_hash(OVERLAY_MERGED) != self.branches[self.target_branch]
branch_mismatch = self.get_branch(OVERLAY_MERGED) != self.target_branch
return hash_mismatch or branch_mismatch
return False
def get_branch(self, path: str) -> str:
return run(["git", "rev-parse", "--abbrev-ref", "HEAD"], path).rstrip()
def get_commit_hash(self, path: str = OVERLAY_MERGED) -> str:
return run(["git", "rev-parse", "HEAD"], path).rstrip()
def set_params(self, failed_count: int, exception: Optional[str]) -> None:
self.params.put("UpdateFailedCount", str(failed_count))
self.params.put_bool("UpdaterFetchAvailable", self.update_available)
self.params.put("UpdaterAvailableBranches", ','.join(self.branches.keys()))
last_update = datetime.datetime.utcnow()
if failed_count == 0:
t = last_update.isoformat()
self.params.put("LastUpdateTime", t.encode('utf8'))
else:
try:
t = self.params.get("LastUpdateTime", encoding='utf8')
last_update = datetime.datetime.fromisoformat(t)
except (TypeError, ValueError):
pass
def check_for_update() -> Tuple[bool, bool]:
setup_git_options(OVERLAY_MERGED)
try:
git_fetch_output = run(["git", "fetch", "--dry-run"], OVERLAY_MERGED, low_priority=True)
return True, check_git_fetch_result(git_fetch_output)
except subprocess.CalledProcessError:
return False, False
if exception is None:
self.params.remove("LastUpdateException")
else:
self.params.put("LastUpdateException", exception)
def fetch_update() -> bool:
cloudlog.info("attempting git fetch inside staging overlay")
# Write out current and new version info
def get_description(basedir: str) -> str:
version = ""
branch = ""
commit = ""
try:
branch = self.get_branch(basedir)
commit = self.get_commit_hash(basedir)
with open(os.path.join(basedir, "common", "version.h")) as f:
version = f.read().split('"')[1]
except Exception:
pass
return f"{version} / {branch} / {commit[:7]}"
self.params.put("UpdaterCurrentDescription", get_description(BASEDIR))
self.params.put("UpdaterCurrentReleaseNotes", parse_release_notes(BASEDIR))
self.params.put("UpdaterNewDescription", get_description(FINALIZED))
self.params.put("UpdaterNewReleaseNotes", parse_release_notes(FINALIZED))
self.params.put_bool("UpdateAvailable", self.update_ready)
# Handle user prompt
for alert in ("Offroad_UpdateFailed", "Offroad_ConnectivityNeeded", "Offroad_ConnectivityNeededPrompt"):
set_offroad_alert(alert, False)
now = datetime.datetime.utcnow()
dt = now - last_update
if failed_count > 15 and exception is not None:
if is_tested_branch():
extra_text = "Ensure the software is correctly installed. Uninstall and re-install if this error persists."
else:
extra_text = exception
set_offroad_alert("Offroad_UpdateFailed", True, extra_text=extra_text)
elif dt.days > DAYS_NO_CONNECTIVITY_MAX and failed_count > 1:
set_offroad_alert("Offroad_ConnectivityNeeded", True)
elif dt.days > DAYS_NO_CONNECTIVITY_PROMPT:
remaining = max(DAYS_NO_CONNECTIVITY_MAX - dt.days, 1)
set_offroad_alert("Offroad_ConnectivityNeededPrompt", True, extra_text=f"{remaining} day{'' if remaining == 1 else 's'}.")
def check_for_update(self) -> None:
cloudlog.info("checking for updates")
excluded_branches = ('release2', 'release2-staging', 'dashcam', 'dashcam-staging')
setup_git_options(OVERLAY_MERGED)
output = run(["git", "ls-remote", "--heads"], OVERLAY_MERGED)
self.branches = defaultdict(lambda: None)
for line in output.split('\n'):
ls_remotes_re = r'(?P<commit_sha>\b[0-9a-f]{5,40}\b)(\s+)(refs\/heads\/)(?P<branch_name>.*$)'
x = re.fullmatch(ls_remotes_re, line.strip())
if x is not None and x.group('branch_name') not in excluded_branches:
self.branches[x.group('branch_name')] = x.group('commit_sha')
cur_branch = self.get_branch(OVERLAY_MERGED)
cur_commit = self.get_commit_hash(OVERLAY_MERGED)
new_branch = self.target_branch
new_commit = self.branches[new_branch]
if (cur_branch, cur_commit) != (new_branch, new_commit):
cloudlog.info(f"update available, {cur_branch} ({cur_commit[:7]}) -> {new_branch} ({new_commit[:7]})")
else:
cloudlog.info(f"up to date on {cur_branch} ({cur_commit[:7]})")
setup_git_options(OVERLAY_MERGED)
def fetch_update(self) -> None:
cloudlog.info("attempting git fetch inside staging overlay")
git_fetch_output = run(["git", "fetch"], OVERLAY_MERGED, low_priority=True)
cloudlog.info("git fetch success: %s", git_fetch_output)
self.params.put("UpdaterState", "downloading...")
cur_hash = run(["git", "rev-parse", "HEAD"], OVERLAY_MERGED).rstrip()
upstream_hash = run(["git", "rev-parse", "@{u}"], OVERLAY_MERGED).rstrip()
new_version: bool = cur_hash != upstream_hash
git_fetch_result = check_git_fetch_result(git_fetch_output)
# TODO: cleanly interrupt this and invalidate old update
set_consistent_flag(False)
self.params.put_bool("UpdateAvailable", False)
new_branch = Params().get("SwitchToBranch", encoding='utf8')
if new_branch is not None:
new_version = True
setup_git_options(OVERLAY_MERGED)
cloudlog.info(f"comparing {cur_hash} to {upstream_hash}")
if new_version or git_fetch_result:
cloudlog.info("Running update")
branch = self.target_branch
git_fetch_output = run(["git", "fetch", "origin", branch], OVERLAY_MERGED)
cloudlog.info("git fetch success: %s", git_fetch_output)
if new_version:
cloudlog.info("git reset in progress")
cmds = [
["git", "reset", "--hard", "@{u}"],
["git", "clean", "-xdf"],
["git", "submodule", "init"],
["git", "submodule", "update"],
]
if new_branch is not None:
cloudlog.info(f"switching to branch {repr(new_branch)}")
cmds.insert(0, ["git", "checkout", "-f", new_branch])
r = [run(cmd, OVERLAY_MERGED, low_priority=True) for cmd in cmds]
cloudlog.info("git reset success: %s", '\n'.join(r))
cloudlog.info("git reset in progress")
cmds = [
["git", "checkout", "--force", "--no-recurse-submodules", branch],
["git", "reset", "--hard", f"origin/{branch}"],
["git", "clean", "-xdf"],
["git", "submodule", "init"],
["git", "submodule", "update"],
]
r = [run(cmd, OVERLAY_MERGED) for cmd in cmds]
cloudlog.info("git reset success: %s", '\n'.join(r))
if AGNOS:
handle_agnos_update()
# TODO: show agnos download progress
if AGNOS:
handle_agnos_update()
# Create the finalized, ready-to-swap update
self.params.put("UpdaterState", "finalizing update...")
finalize_update()
cloudlog.info("openpilot update successful!")
else:
cloudlog.info("nothing new from git at this time")
return new_version
cloudlog.info("finalize success!")
def main() -> None:
@ -359,8 +422,12 @@ def main() -> None:
overlay_init = Path(os.path.join(BASEDIR, ".overlay_init"))
overlay_init.unlink(missing_ok=True)
updater = Updater()
update_failed_count = 0 # TODO: Load from param?
wait_helper = WaitTimeHelper(proc)
# no fetch on the first time
wait_helper = WaitTimeHelper()
wait_helper.only_check_for_update = True
# Run the update loop
while True:
@ -368,21 +435,24 @@ def main() -> None:
# Attempt an update
exception = None
new_version = False
update_failed_count += 1
try:
# TODO: reuse overlay from previous updated instance if it looks clean
init_overlay()
# TODO: still needed? skip this and just fetch?
# Lightweight internt check
internet_ok, update_available = check_for_update()
if internet_ok and not update_available:
update_failed_count = 0
# ensure we have some params written soon after startup
updater.set_params(update_failed_count, exception)
update_failed_count += 1
# check for update
params.put("UpdaterState", "checking...")
updater.check_for_update()
# Fetch update
if internet_ok:
new_version = fetch_update()
update_failed_count = 0
# download update
if wait_helper.only_check_for_update:
cloudlog.info("skipping fetch this cycle")
else:
updater.fetch_update()
update_failed_count = 0
except subprocess.CalledProcessError as e:
cloudlog.event(
"update process failed",
@ -398,12 +468,14 @@ def main() -> None:
overlay_init.unlink(missing_ok=True)
try:
set_params(new_version, update_failed_count, exception)
params.put("UpdaterState", "idle")
updater.set_params(update_failed_count, exception)
except Exception:
cloudlog.exception("uncaught updated exception while setting params, shouldn't happen")
# infrequent attempts if we successfully updated recently
wait_helper.sleep(5*60 if update_failed_count > 0 else 90*60)
wait_helper.only_check_for_update = False
wait_helper.sleep(5*60 if update_failed_count > 0 else 1.5*60*60)
if __name__ == "__main__":

@ -61,39 +61,48 @@ const float DC_GAIN_OX03C10 = 7.32;
const float DC_GAIN_ON_GREY_AR0231= 0.2;
const float DC_GAIN_OFF_GREY_AR0231 = 0.3;
const float DC_GAIN_ON_GREY_OX03C10= 0.3;
const float DC_GAIN_OFF_GREY_OX03C10 = 0.375;
const float DC_GAIN_ON_GREY_OX03C10= 0.25;
const float DC_GAIN_OFF_GREY_OX03C10 = 0.35;
const int DC_GAIN_MIN_WEIGHT = 0;
const int DC_GAIN_MIN_WEIGHT_AR0231 = 0;
const int DC_GAIN_MAX_WEIGHT_AR0231 = 1;
const int DC_GAIN_MIN_WEIGHT_OX03C10 = 16;
const int DC_GAIN_MAX_WEIGHT_OX03C10 = 32;
const float TARGET_GREY_FACTOR_AR0231 = 1.0;
const float TARGET_GREY_FACTOR_OX03C10 = 0.02;
const float sensor_analog_gains_AR0231[] = {
1.0/8.0, 2.0/8.0, 2.0/7.0, 3.0/7.0, // 0, 1, 2, 3
3.0/6.0, 4.0/6.0, 4.0/5.0, 5.0/5.0, // 4, 5, 6, 7
5.0/4.0, 6.0/4.0, 6.0/3.0, 7.0/3.0, // 8, 9, 10, 11
7.0/2.0, 8.0/2.0, 8.0/1.0}; // 12, 13, 14, 15 = bypass
// similar gain curve to AR
const float sensor_analog_gains_OX03C10[] = {
1.0, 1.25, 1.3125, 1.5625,
1.6875, 2.0, 2.25, 2.625,
3.125, 3.625, 4.5, 5.0,
7.25, 8.5, 12.0, 15.5};
1.0, 1.125, 1.25, 1.3125, 1.5625,
1.6875, 2.0, 2.25, 2.625, 3.125,
3.625, 4.0, 4.5, 5.0, 5.5,
6.0, 6.5, 7.0, 7.5, 8.0,
8.5, 9.0, 9.5, 10.0, 10.5,
11.0, 11.5, 12.0, 12.5, 13.0,
13.5, 14.0, 14.5, 15.0, 15.5};
const uint32_t ox03c10_analog_gains_reg[] = {
0x100, 0x140, 0x150, 0x190,
0x1B0, 0x200, 0x240, 0x2A0,
0x320, 0x3A0, 0x480, 0x500,
0x740, 0x880, 0xC00, 0xF80};
0x100, 0x120, 0x140, 0x150, 0x190,
0x1B0, 0x200, 0x240, 0x2A0, 0x320,
0x3A0, 0x400, 0x480, 0x500, 0x580,
0x600, 0x680, 0x700, 0x780, 0x800,
0x880, 0x900, 0x980, 0xA00, 0xA80,
0xB00, 0xB80, 0xC00, 0xC80, 0xD00,
0xD80, 0xE00, 0xE80, 0xF00, 0xF80};
const int ANALOG_GAIN_MIN_IDX_AR0231 = 0x1; // 0.25x
const int ANALOG_GAIN_REC_IDX_AR0231 = 0x6; // 0.8x
const int ANALOG_GAIN_MAX_IDX_AR0231 = 0xD; // 4.0x
const int ANALOG_GAIN_MIN_IDX_OX03C10 = 0x0;
const int ANALOG_GAIN_REC_IDX_OX03C10 = 0x5; // 2x
const int ANALOG_GAIN_MAX_IDX_OX03C10 = 0xF;
const int ANALOG_GAIN_REC_IDX_OX03C10 = 0x6; // 2x
const int ANALOG_GAIN_MAX_IDX_OX03C10 = 0x22;
const int EXPOSURE_TIME_MIN_AR0231 = 2; // with HDR, fastest ss
const int EXPOSURE_TIME_MAX_AR0231 = 0x0855; // with HDR, slowest ss, 40ms
@ -517,6 +526,7 @@ void CameraState::enqueue_req_multi(int start, int n, bool dp) {
void CameraState::camera_set_parameters() {
if (camera_id == CAMERA_ID_AR0231) {
dc_gain_factor = DC_GAIN_AR0231;
dc_gain_min_weight = DC_GAIN_MIN_WEIGHT_AR0231;
dc_gain_max_weight = DC_GAIN_MAX_WEIGHT_AR0231;
dc_gain_on_grey = DC_GAIN_ON_GREY_AR0231;
dc_gain_off_grey = DC_GAIN_OFF_GREY_AR0231;
@ -529,8 +539,10 @@ void CameraState::camera_set_parameters() {
sensor_analog_gains[i] = sensor_analog_gains_AR0231[i];
}
min_ev = exposure_time_min * sensor_analog_gains[analog_gain_min_idx];
target_grey_factor = TARGET_GREY_FACTOR_AR0231;
} else if (camera_id == CAMERA_ID_OX03C10) {
dc_gain_factor = DC_GAIN_OX03C10;
dc_gain_min_weight = DC_GAIN_MIN_WEIGHT_OX03C10;
dc_gain_max_weight = DC_GAIN_MAX_WEIGHT_OX03C10;
dc_gain_on_grey = DC_GAIN_ON_GREY_OX03C10;
dc_gain_off_grey = DC_GAIN_OFF_GREY_OX03C10;
@ -543,6 +555,7 @@ void CameraState::camera_set_parameters() {
sensor_analog_gains[i] = sensor_analog_gains_OX03C10[i];
}
min_ev = (exposure_time_min + VS_TIME_MIN_OX03C10) * sensor_analog_gains[analog_gain_min_idx];
target_grey_factor = TARGET_GREY_FACTOR_OX03C10;
} else {
assert(false);
}
@ -551,7 +564,7 @@ void CameraState::camera_set_parameters() {
target_grey_fraction = 0.3;
dc_gain_enabled = false;
dc_gain_weight = DC_GAIN_MIN_WEIGHT;
dc_gain_weight = dc_gain_min_weight;
gain_idx = analog_gain_rec_idx;
exposure_time = 5;
cur_ev[0] = cur_ev[1] = cur_ev[2] = (1 + dc_gain_weight * (dc_gain_factor-1) / dc_gain_max_weight) * sensor_analog_gains[gain_idx] * exposure_time;
@ -1037,7 +1050,7 @@ void CameraState::set_camera_exposure(float grey_frac) {
const float cur_ev_ = cur_ev[buf.cur_frame_data.frame_id % 3];
// Scale target grey between 0.1 and 0.4 depending on lighting conditions
float new_target_grey = std::clamp(0.4 - 0.3 * log2(1.0 + cur_ev_) / log2(6000.0), 0.1, 0.4);
float new_target_grey = std::clamp(0.4 - 0.3 * log2(1.0 + target_grey_factor*cur_ev_) / log2(6000.0), 0.1, 0.4);
float target_grey = (1.0 - k_grey) * target_grey_fraction + k_grey * new_target_grey;
float desired_ev = std::clamp(cur_ev_ * target_grey / grey_frac, min_ev, max_ev);
@ -1053,14 +1066,14 @@ void CameraState::set_camera_exposure(float grey_frac) {
bool enable_dc_gain = dc_gain_enabled;
if (!enable_dc_gain && target_grey < dc_gain_on_grey) {
enable_dc_gain = true;
dc_gain_weight = DC_GAIN_MIN_WEIGHT;
dc_gain_weight = dc_gain_min_weight;
} else if (enable_dc_gain && target_grey > dc_gain_off_grey) {
enable_dc_gain = false;
dc_gain_weight = dc_gain_max_weight;
}
if (enable_dc_gain && dc_gain_weight < dc_gain_max_weight) {dc_gain_weight += 1;}
if (!enable_dc_gain && dc_gain_weight > DC_GAIN_MIN_WEIGHT) {dc_gain_weight -= 1;}
if (!enable_dc_gain && dc_gain_weight > dc_gain_min_weight) {dc_gain_weight -= 1;}
std::string gain_bytes, time_bytes;
if (env_ctrl_exp_from_params) {
@ -1145,10 +1158,12 @@ void CameraState::set_camera_exposure(float grey_frac) {
// t_HCG + t_LCG + t_VS on LPD, t_SPD on SPD
uint32_t hcg_time = std::max((dc_gain_weight * exposure_time / dc_gain_max_weight), 0);
uint32_t lcg_time = std::max(((dc_gain_max_weight - dc_gain_weight) * exposure_time / dc_gain_max_weight), 0);
uint32_t spd_time = std::max(hcg_time / 16, (uint32_t)exposure_time_min);
uint32_t vs_time = std::min(std::max(hcg_time / 64, VS_TIME_MIN_OX03C10), VS_TIME_MAX_OX03C10);
// uint32_t spd_time = std::max(hcg_time / 16, (uint32_t)exposure_time_min);
uint32_t vs_time = std::min(std::max((uint32_t)exposure_time / 128, VS_TIME_MIN_OX03C10), VS_TIME_MAX_OX03C10);
uint32_t spd_time = vs_time;
uint32_t real_gain = ox03c10_analog_gains_reg[new_g];
uint32_t min_gain = ox03c10_analog_gains_reg[0];
struct i2c_random_wr_payload exp_reg_array[] = {
{0x3501, hcg_time>>8}, {0x3502, hcg_time&0xFF},
@ -1157,9 +1172,9 @@ void CameraState::set_camera_exposure(float grey_frac) {
{0x35c1, vs_time>>8}, {0x35c2, vs_time&0xFF},
{0x3508, real_gain>>8}, {0x3509, real_gain&0xFF},
{0x3588, real_gain>>8}, {0x3589, real_gain&0xFF},
{0x3548, real_gain>>8}, {0x3549, real_gain&0xFF},
{0x35c8, real_gain>>8}, {0x35c9, real_gain&0xFF},
{0x3588, min_gain>>8}, {0x3589, min_gain&0xFF},
{0x3548, min_gain>>8}, {0x3549, min_gain&0xFF},
{0x35c8, min_gain>>8}, {0x35c9, min_gain&0xFF},
};
sensors_i2c(exp_reg_array, sizeof(exp_reg_array)/sizeof(struct i2c_random_wr_payload), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, false);
}

@ -31,11 +31,12 @@ public:
int exposure_time_max;
float dc_gain_factor;
int dc_gain_min_weight;
int dc_gain_max_weight;
float dc_gain_on_grey;
float dc_gain_off_grey;
float sensor_analog_gains[16];
float sensor_analog_gains[35];
int analog_gain_min_idx;
int analog_gain_max_idx;
int analog_gain_rec_idx;
@ -45,6 +46,7 @@ public:
float measured_grey_fraction;
float target_grey_fraction;
float target_grey_factor;
unique_fd sensor_fd;
unique_fd csiphy_fd;

@ -129,13 +129,13 @@ struct i2c_random_wr_payload init_array_ox03c10[] = {
{0x350a, 0x04}, {0x350b, 0x00}, {0x350c, 0x00}, // hcg digital gain
{0x3586, 0x40}, {0x3587, 0x00}, // lcg fine exposure
{0x358a, 0x04}, {0x358b, 0x00}, {0x358c, 0x00}, // lcg digital gain
{0x358a, 0x01}, {0x358b, 0x00}, {0x358c, 0x00}, // lcg digital gain
{0x3546, 0x20}, {0x3547, 0x00}, // spd fine exposure
{0x354a, 0x04}, {0x354b, 0x00}, {0x354c, 0x00}, // spd digital gain
{0x354a, 0x01}, {0x354b, 0x00}, {0x354c, 0x00}, // spd digital gain
{0x35c6, 0xb0}, {0x35c7, 0x00}, // vs fine exposure
{0x35ca, 0x04}, {0x35cb, 0x00}, {0x35cc, 0x00}, // vs digital gain
{0x35ca, 0x01}, {0x35cb, 0x00}, {0x35cc, 0x00}, // vs digital gain
// also RSVD
{0x3600, 0x8f}, {0x3605, 0x16}, {0x3609, 0xf0}, {0x360a, 0x01},

Loading…
Cancel
Save