Merge branch 'master' into mqb-long

mqb-long
Jason Young 3 years ago
commit 11faf8696f
  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. 114
      docs/CARS.md
  7. 8
      selfdrive/boardd/boardd.cc
  8. 2
      selfdrive/car/chrysler/values.py
  9. 2
      selfdrive/car/gm/values.py
  10. 2
      selfdrive/car/hyundai/values.py
  11. 7
      selfdrive/car/subaru/carstate.py
  12. 2
      selfdrive/car/tests/routes.py
  13. 2
      selfdrive/car/tests/test_models.py
  14. 2
      selfdrive/car/torque_data/override.yaml
  15. 1
      selfdrive/car/volkswagen/interface.py
  16. 109
      selfdrive/car/volkswagen/values.py
  17. 2
      selfdrive/manager/test/test_manager.py
  18. 4
      selfdrive/sensord/tests/test_sensord.py
  19. 2
      selfdrive/test/process_replay/ref_commit
  20. 2
      selfdrive/ui/.gitignore
  21. 3
      selfdrive/ui/SConscript
  22. 81
      selfdrive/ui/qt/offroad/settings.cc
  23. 13
      selfdrive/ui/qt/offroad/settings.h
  24. 156
      selfdrive/ui/qt/offroad/software_settings.cc
  25. 8
      selfdrive/ui/qt/widgets/controls.cc
  26. 14
      selfdrive/ui/qt/widgets/controls.h
  27. 2
      selfdrive/ui/qt/widgets/offroad_alerts.cc
  28. 8
      selfdrive/ui/qt/widgets/ssh_keys.cc
  29. 2
      selfdrive/ui/qt/widgets/ssh_keys.h
  30. 2
      selfdrive/ui/tests/cycle_offroad_alerts.py
  31. 91
      selfdrive/ui/translations/main_ja.ts
  32. 91
      selfdrive/ui/translations/main_ko.ts
  33. 91
      selfdrive/ui/translations/main_pt-BR.ts
  34. 91
      selfdrive/ui/translations/main_zh-CHS.ts
  35. 91
      selfdrive/ui/translations/main_zh-CHT.ts
  36. 348
      selfdrive/updated.py
  37. 61
      system/camerad/cameras/camera_qcom2.cc
  38. 4
      system/camerad/cameras/camera_qcom2.h
  39. 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|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Audi|A3 Sportback e-tron 2017-18|ACC + Lane Assist|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Audi|Q2 2018|ACC + Lane Assist|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Audi|Q3 2020-21|ACC + Lane Assist|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Audi|RS3 2018|ACC + Lane Assist|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Audi|S3 2015-17|ACC + Lane Assist|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|SEAT|Leon 2014-20|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|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|openpilot|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|openpilot|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|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Škoda|Karoq 2019-21|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Škoda|Kodiaq 2018-19|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Škoda|Octavia 2015, 2018-19|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Škoda|Octavia RS 2016|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Škoda|Scala 2020|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Škoda|Superb 2015-18|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Škoda|Kamiq 2021[<sup>5</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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</sup>](#footnotes)|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Arteon eHybrid 2020-22[<sup>7</sup>](#footnotes)|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Arteon R 2020-22[<sup>7</sup>](#footnotes)|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Atlas 2018-23|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Atlas Cross Sport 2021-22|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|California 2021|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Caravelle 2020|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|CC 2018-22[<sup>7</sup>](#footnotes)|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|e-Golf 2014-20|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf 2015-20[<sup>7</sup>](#footnotes)|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf Alltrack 2015-19|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf GTD 2015-20|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf GTE 2015-20|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf GTI 2015-21|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf R 2015-19[<sup>7</sup>](#footnotes)|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf SportsVan 2015-20|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Jetta 2018-22|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Jetta GLI 2021-22|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Passat 2015-22[<sup>6,7</sup>](#footnotes)|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Passat Alltrack 2015-22|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Passat GTE 2015-22[<sup>7</sup>](#footnotes)|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Polo 2020-22|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Polo GTI 2020-22|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|T-Cross 2021|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|T-Roc 2021|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Taos 2022|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Teramont 2018-22|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Teramont Cross Sport 2021-22|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Teramont X 2021-22|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Tiguan 2019-22|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Touran 2017|Driver Assistance|openpilot[<sup>8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Arteon 2018-22[<sup>7,8</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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|openpilot|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 />
@ -221,8 +221,8 @@ A supported vehicle is one that just works when you install a comma three. All s
<sup>4</sup>openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control. <br />
<sup>5</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br />
<sup>6</sup>Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets. <br />
<sup>7</sup>Includes versions with extra rear cargo space (may be called Variant, Estate, SportWagen, Shooting Brake, etc.) <br />
<sup>8</sup>Requires gateway (J533) harness. Camera harness integrations can only use stock ACC at this time. <br />
<sup>7</sup>Model-years 2021 and beyond may have a new camera harness design, which isn't yet available from the comma store. Before ordering, remove the Lane Assist camera cover and check to see if the connector is black (older design) or light brown (newer design). In the interim, if your car has a J533 connector CAN gateway inside the dashboard, choose "VW J533 Development" from the vehicle drop-down for a suitable harness. (Some newer models are also observed to not have a J533 connector.) <br />
<sup>8</sup>Includes versions with extra rear cargo space (may be called Variant, Estate, SportWagen, Shooting Brake, etc.) <br />
## Community Maintained Cars
Although they're not upstream, the community has openpilot running on other makes and models. See the 'Community Supported Models' section of each make [on our wiki](https://wiki.comma.ai/).

@ -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"],
@ -50,7 +49,7 @@ class CarState(CarStateBase):
ret.steeringAngleDeg = cp.vl["Steering_Torque"]["Steering_Angle"]
ret.steeringTorque = cp.vl["Steering_Torque"]["Steer_Torque_Sensor"]
ret.steeringTorqueEps = cp.vl["Steering_Torque"]["Steer_Torque_Output"]
steer_threshold = 75 if self.CP.carFingerprint in PREGLOBAL_CARS else 80
ret.steeringPressed = abs(ret.steeringTorque) > steer_threshold
@ -313,4 +312,4 @@ class CarState(CarStateBase):
checks += CarState.get_global_es_distance_signals()[1]
return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, 1)
return None
return None

@ -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]

@ -90,6 +90,7 @@ class CarInterface(CarInterfaceBase):
ret.pcmCruise = not ret.openpilotLongitudinalControl
ret.experimentalLongitudinalAvailable = ret.networkLocation == NetworkLocation.gateway
ret.experimentalLongitudinalAvailable &= bool(fingerprint[0]) # FIXME: hack to deal with CI/doc/harness stuff later
ret.stoppingControl = True
ret.startingState = True
ret.startAccel = 1.0

@ -150,88 +150,93 @@ class Footnote(Enum):
PASSAT = CarFootnote(
"Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets.",
Column.MODEL)
VW_HARNESS = CarFootnote(
"Model-years 2021 and beyond may have a new camera harness design, which isn't yet available from the comma " +
"store. Before ordering, remove the Lane Assist camera cover and check to see if the connector is black " +
"(older design) or light brown (newer design). In the interim, if your car has a J533 connector CAN gateway " +
"inside the dashboard, choose \"VW J533 Development\" from the vehicle drop-down for a suitable harness. " +
"(Some newer models are also observed to not have a J533 connector.)",
Column.MODEL)
VW_VARIANT = CarFootnote(
"Includes versions with extra rear cargo space (may be called Variant, Estate, SportWagen, Shooting Brake, etc.)",
Column.MODEL)
VW_LONG = CarFootnote(
"Requires gateway (J533) harness. Camera harness integrations can only use stock ACC at this time.",
Column.LONGITUDINAL)
@dataclass
class VWCarInfo(CarInfo):
package: str = "Driver Assistance"
harness: Enum = Harness.j533
package: str = "Adaptive Cruise Control (ACC) & Lane Assist"
harness: Enum = Harness.vw
CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = {
CAR.ARTEON_MK1: [
VWCarInfo("Volkswagen Arteon 2018-22", footnotes=[Footnote.VW_LONG, Footnote.VW_VARIANT], video_link="https://youtu.be/FAomFKPFlDA"),
VWCarInfo("Volkswagen Arteon R 2020-22", footnotes=[Footnote.VW_LONG, Footnote.VW_VARIANT], video_link="https://youtu.be/FAomFKPFlDA"),
VWCarInfo("Volkswagen Arteon eHybrid 2020-22", footnotes=[Footnote.VW_LONG, Footnote.VW_VARIANT], video_link="https://youtu.be/FAomFKPFlDA"),
VWCarInfo("Volkswagen CC 2018-22", footnotes=[Footnote.VW_LONG, Footnote.VW_VARIANT], video_link="https://youtu.be/FAomFKPFlDA"),
VWCarInfo("Volkswagen Arteon 2018-22", footnotes=[Footnote.VW_HARNESS, Footnote.VW_VARIANT], harness=Harness.j533, video_link="https://youtu.be/FAomFKPFlDA"),
VWCarInfo("Volkswagen Arteon R 2020-22", footnotes=[Footnote.VW_HARNESS, Footnote.VW_VARIANT], harness=Harness.j533, video_link="https://youtu.be/FAomFKPFlDA"),
VWCarInfo("Volkswagen Arteon eHybrid 2020-22", footnotes=[Footnote.VW_HARNESS, Footnote.VW_VARIANT], harness=Harness.j533, video_link="https://youtu.be/FAomFKPFlDA"),
VWCarInfo("Volkswagen CC 2018-22", footnotes=[Footnote.VW_HARNESS, Footnote.VW_VARIANT], harness=Harness.j533, video_link="https://youtu.be/FAomFKPFlDA"),
],
CAR.ATLAS_MK1: [
VWCarInfo("Volkswagen Atlas 2018-23", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Volkswagen Atlas Cross Sport 2021-22", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Volkswagen Teramont 2018-22", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Volkswagen Teramont Cross Sport 2021-22", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Volkswagen Teramont X 2021-22", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Volkswagen Atlas 2018-23", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
VWCarInfo("Volkswagen Atlas Cross Sport 2021-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
VWCarInfo("Volkswagen Teramont 2018-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
VWCarInfo("Volkswagen Teramont Cross Sport 2021-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
VWCarInfo("Volkswagen Teramont X 2021-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
],
CAR.GOLF_MK7: [
VWCarInfo("Volkswagen e-Golf 2014-20", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Volkswagen Golf 2015-20", footnotes=[Footnote.VW_LONG, Footnote.VW_VARIANT]),
VWCarInfo("Volkswagen Golf Alltrack 2015-19", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Volkswagen Golf GTD 2015-20", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Volkswagen Golf GTE 2015-20", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Volkswagen Golf GTI 2015-21", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Volkswagen Golf R 2015-19", footnotes=[Footnote.VW_LONG, Footnote.VW_VARIANT]),
VWCarInfo("Volkswagen Golf SportsVan 2015-20", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Volkswagen e-Golf 2014-20"),
VWCarInfo("Volkswagen Golf 2015-20", footnotes=[Footnote.VW_VARIANT]),
VWCarInfo("Volkswagen Golf Alltrack 2015-19"),
VWCarInfo("Volkswagen Golf GTD 2015-20"),
VWCarInfo("Volkswagen Golf GTE 2015-20"),
VWCarInfo("Volkswagen Golf GTI 2015-21"),
VWCarInfo("Volkswagen Golf R 2015-19", footnotes=[Footnote.VW_VARIANT]),
VWCarInfo("Volkswagen Golf SportsVan 2015-20"),
],
CAR.JETTA_MK7: [
VWCarInfo("Volkswagen Jetta 2018-22", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Volkswagen Jetta GLI 2021-22", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Volkswagen Jetta 2018-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
VWCarInfo("Volkswagen Jetta GLI 2021-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
],
CAR.PASSAT_MK8: [
VWCarInfo("Volkswagen Passat 2015-22", footnotes=[Footnote.VW_LONG, Footnote.PASSAT, Footnote.VW_VARIANT]),
VWCarInfo("Volkswagen Passat Alltrack 2015-22", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Volkswagen Passat GTE 2015-22", footnotes=[Footnote.VW_LONG, Footnote.VW_VARIANT]),
VWCarInfo("Volkswagen Passat 2015-22", footnotes=[Footnote.VW_HARNESS, Footnote.PASSAT, Footnote.VW_VARIANT], harness=Harness.j533),
VWCarInfo("Volkswagen Passat Alltrack 2015-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
VWCarInfo("Volkswagen Passat GTE 2015-22", footnotes=[Footnote.VW_HARNESS, Footnote.VW_VARIANT], harness=Harness.j533),
],
CAR.PASSAT_NMS: VWCarInfo("Volkswagen Passat NMS 2017-22", footnotes=[Footnote.VW_LONG]),
CAR.PASSAT_NMS: VWCarInfo("Volkswagen Passat NMS 2017-22", harness=Harness.j533),
CAR.POLO_MK6: [
VWCarInfo("Volkswagen Polo 2020-22", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Volkswagen Polo GTI 2020-22", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Volkswagen Polo 2020-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
VWCarInfo("Volkswagen Polo GTI 2020-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
],
CAR.TAOS_MK1: VWCarInfo("Volkswagen Taos 2022", footnotes=[Footnote.VW_LONG]),
CAR.TCROSS_MK1: VWCarInfo("Volkswagen T-Cross 2021", footnotes=[Footnote.VW_LONG]),
CAR.TIGUAN_MK2: VWCarInfo("Volkswagen Tiguan 2019-22", footnotes=[Footnote.VW_LONG]),
CAR.TOURAN_MK2: VWCarInfo("Volkswagen Touran 2017", footnotes=[Footnote.VW_LONG]),
CAR.TAOS_MK1: VWCarInfo("Volkswagen Taos 2022", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
CAR.TCROSS_MK1: VWCarInfo("Volkswagen T-Cross 2021", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
CAR.TIGUAN_MK2: VWCarInfo("Volkswagen Tiguan 2019-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
CAR.TOURAN_MK2: VWCarInfo("Volkswagen Touran 2017"),
CAR.TRANSPORTER_T61: [
VWCarInfo("Volkswagen Caravelle 2020", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Volkswagen California 2021", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Volkswagen Caravelle 2020", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
VWCarInfo("Volkswagen California 2021", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
],
CAR.TROC_MK1: VWCarInfo("Volkswagen T-Roc 2021", footnotes=[Footnote.VW_LONG]),
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", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Audi A3 Sportback e-tron 2017-18", "ACC + Lane Assist", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Audi RS3 2018", "ACC + Lane Assist", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Audi S3 2015-17", "ACC + Lane Assist", footnotes=[Footnote.VW_LONG]),
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", footnotes=[Footnote.VW_LONG]),
CAR.AUDI_Q3_MK2: VWCarInfo("Audi Q3 2020-21", "ACC + Lane Assist", footnotes=[Footnote.VW_LONG]),
CAR.SEAT_ATECA_MK1: VWCarInfo("SEAT Ateca 2018", footnotes=[Footnote.VW_LONG]),
CAR.SEAT_LEON_MK3: VWCarInfo("SEAT Leon 2014-20", footnotes=[Footnote.VW_LONG]),
CAR.SKODA_KAMIQ_MK1: VWCarInfo("Škoda Kamiq 2021", footnotes=[Footnote.VW_LONG, Footnote.KAMIQ]),
CAR.SKODA_KAROQ_MK1: VWCarInfo("Škoda Karoq 2019-21", footnotes=[Footnote.VW_LONG]),
CAR.SKODA_KODIAQ_MK1: VWCarInfo("Škoda Kodiaq 2018-19", footnotes=[Footnote.VW_LONG]),
CAR.SKODA_SCALA_MK1: VWCarInfo("Škoda Scala 2020", footnotes=[Footnote.VW_LONG]),
CAR.SKODA_SUPERB_MK3: VWCarInfo("Škoda Superb 2015-18", footnotes=[Footnote.VW_LONG]),
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]),
CAR.SKODA_KAROQ_MK1: VWCarInfo("Škoda Karoq 2019-21", footnotes=[Footnote.VW_HARNESS]),
CAR.SKODA_KODIAQ_MK1: VWCarInfo("Škoda Kodiaq 2018-19"),
CAR.SKODA_SCALA_MK1: VWCarInfo("Škoda Scala 2020"),
CAR.SKODA_SUPERB_MK3: VWCarInfo("Škoda Superb 2015-18"),
CAR.SKODA_OCTAVIA_MK3: [
VWCarInfo("Škoda Octavia 2015, 2018-19", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Škoda Octavia RS 2016", footnotes=[Footnote.VW_LONG]),
VWCarInfo("Škoda Octavia 2015, 2018-19"),
VWCarInfo("Škoda Octavia RS 2016"),
],
}
# All supported cars should return FW from the engine, srs, eps, and fwdRadar. Cars
# with a manual trans won't return transmission firmware, but all other cars will.
#

@ -12,7 +12,7 @@ from system.hardware import HARDWARE
os.environ['FAKEUPLOAD'] = "1"
MAX_STARTUP_TIME = 3
ALL_PROCESSES = [p.name for p in managed_processes.values() if (type(p) is not DaemonProcess) and p.enabled and (p.name not in ['updated', 'pandad'])]
ALL_PROCESSES = [p.name for p in managed_processes.values() if (type(p) is not DaemonProcess) and p.enabled and (p.name not in ['pandad', ])]
class TestManager(unittest.TestCase):

@ -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>
<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> .</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 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,38 +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.shutdown = False
signal.signal(signal.SIGTERM, self.graceful_shutdown)
signal.signal(signal.SIGINT, self.graceful_shutdown)
self.only_check_for_update = False
signal.signal(signal.SIGHUP, self.update_now)
signal.signal(signal.SIGUSR1, self.check_now)
def graceful_shutdown(self, signum: int, frame) -> None:
# umount -f doesn't appear effective in avoiding "device busy" on NEOS,
# so don't actually die until the next convenient opportunity in main().
cloudlog.info("caught SIGINT/SIGTERM, dismounting overlay at next opportunity")
# forward the signal to all our child processes
child_procs = self.proc.children(recursive=True)
for p in child_procs:
p.send_signal(signum)
self.shutdown = True
def update_now(self, signum: int, frame) -> None:
cloudlog.info("caught SIGHUP, attempting to downloading update")
self.only_check_for_update = False
self.ready_event.set()
def update_now(self, signum: int, frame) -> None:
cloudlog.info("caught SIGHUP, running update check immediately")
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')
@ -98,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
@ -228,12 +179,12 @@ 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}")
def finalize_update(wait_helper: WaitTimeHelper) -> None:
def finalize_update() -> None:
"""Take the current OverlayFS merged view and finalize a copy outside of
OverlayFS, ready to be swapped-in at BASEDIR. Copy using shutil.copytree"""
@ -258,14 +209,11 @@ def finalize_update(wait_helper: WaitTimeHelper) -> None:
except subprocess.CalledProcessError:
cloudlog.exception(f"Failed git cleanup, took {time.monotonic() - t:.3f} s")
if wait_helper.shutdown:
cloudlog.info("got interrupted finalizing overlay")
else:
set_consistent_flag(True)
cloudlog.info("done finalizing overlay")
set_consistent_flag(True)
cloudlog.info("done finalizing overlay")
def handle_agnos_update(wait_helper: WaitTimeHelper) -> None:
def handle_agnos_update() -> None:
from system.hardware.tici.agnos import flash_agnos_update, get_target_slot_number
cur_version = HARDWARE.get_os_version()
@ -288,65 +236,161 @@ def handle_agnos_update(wait_helper: WaitTimeHelper) -> 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(wait_helper: WaitTimeHelper) -> 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(wait_helper)
# TODO: show agnos download progress
if AGNOS:
handle_agnos_update()
# Create the finalized, ready-to-swap update
finalize_update(wait_helper)
cloudlog.info("openpilot update successful!")
else:
cloudlog.info("nothing new from git at this time")
return new_version
self.params.put("UpdaterState", "finalizing update...")
finalize_update()
cloudlog.info("finalize success!")
def main() -> None:
@ -378,30 +422,37 @@ 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 not wait_helper.shutdown:
while True:
wait_helper.ready_event.clear()
# 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(wait_helper)
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",
@ -416,16 +467,15 @@ def main() -> None:
exception = str(e)
overlay_init.unlink(missing_ok=True)
if not wait_helper.shutdown:
try:
set_params(new_version, update_failed_count, exception)
except Exception:
cloudlog.exception("uncaught updated exception while setting params, shouldn't happen")
try:
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)
dismount_overlay()
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