From e8b20b7f81ff612450b03fbc924506d3d37589f1 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 21 Jul 2023 18:35:29 -0700 Subject: [PATCH 01/20] CI: fix no DNS after tests killed (#29090) * CI: fix no DNS after tests killed * fix --- Jenkinsfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 85c1d55e68..b4d4cfd4a0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -18,6 +18,12 @@ export GIT_SSH_COMMAND="ssh -i /data/gitkey" source ~/.bash_profile if [ -f /TICI ]; then source /etc/profile + + if ! systemctl is-active --quiet systemd-resolved; then + echo "restarting resolved" + sudo systemctl start systemd-resolved + sleep 3 + fi fi if [ -f /data/openpilot/launch_env.sh ]; then source /data/openpilot/launch_env.sh From ee4fcff0c90954d825d1a428ae166a7f825115ce Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Fri, 21 Jul 2023 18:36:51 -0700 Subject: [PATCH 02/20] Fix mypy path error (#29091) --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cd654e40c4..5736ca7ffc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -32,6 +32,7 @@ repos: entry: mypy language: system types: [python] + args: ['--explicit-package-bases'] exclude: '^(third_party/)|(cereal/)|(opendbc/)|(panda/)|(laika/)|(laika_repo/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(xx/)' - repo: https://github.com/PyCQA/flake8 rev: 6.0.0 From 97eec45d42a67c3e840a6a08fab2e421b2825de7 Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Fri, 21 Jul 2023 21:57:27 -0700 Subject: [PATCH 03/20] Test scons multithreaded random build (#29082) * random build * name * 2 pass * clean after * fail on this * fix deps * format * var * try without lfs --- Jenkinsfile | 22 +++++++++++++++++++ .../controls/lib/lateral_mpc_lib/SConscript | 7 +++--- .../lib/longitudinal_mpc_lib/SConscript | 7 +++--- tools/cabana/SConscript | 9 ++++---- 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index b4d4cfd4a0..4203c7f196 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -134,6 +134,28 @@ pipeline { } */ + stage('scons build test') { + agent { + dockerfile { + filename 'Dockerfile.openpilot_base' + args '--user=root' + } + } + steps { + sh "git config --global --add safe.directory '*'" + sh "git submodule update --init --depth=1 --recursive" + sh "scons --clean && scons --no-cache -j42" + sh "scons --clean && scons --no-cache --random -j42" + } + + post { + always { + sh "rm -rf ${WORKSPACE}/* || true" + sh "rm -rf .* || true" + } + } + } + stage('tizi-tests') { agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } steps { diff --git a/selfdrive/controls/lib/lateral_mpc_lib/SConscript b/selfdrive/controls/lib/lateral_mpc_lib/SConscript index 745ed99d10..af9283f073 100644 --- a/selfdrive/controls/lib/lateral_mpc_lib/SConscript +++ b/selfdrive/controls/lib/lateral_mpc_lib/SConscript @@ -57,9 +57,10 @@ source_list = ['lat_mpc.py', lenv = env.Clone() lenv.Clean(generated_files, Dir(gen)) -lenv.Command(generated_files, - source_list, - f"cd {Dir('.').abspath} && python3 lat_mpc.py") +generated_lat = lenv.Command(generated_files, + source_list, + f"cd {Dir('.').abspath} && python3 lat_mpc.py") +lenv.Depends(generated_lat, "#common") lenv["CFLAGS"].append("-DACADOS_WITH_QPOASES") lenv["CXXFLAGS"].append("-DACADOS_WITH_QPOASES") diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript index 7f5daf157c..64d5aa963a 100644 --- a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript +++ b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript @@ -64,9 +64,10 @@ source_list = ['long_mpc.py', lenv = env.Clone() lenv.Clean(generated_files, Dir(gen)) -lenv.Command(generated_files, - source_list, - f"cd {Dir('.').abspath} && python3 long_mpc.py") +generated_long = lenv.Command(generated_files, + source_list, + f"cd {Dir('.').abspath} && python3 long_mpc.py") +lenv.Depends(generated_long, "#cereal") lenv["CFLAGS"].append("-DACADOS_WITH_QPOASES") lenv["CXXFLAGS"].append("-DACADOS_WITH_QPOASES") diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index f12888b792..d726872718 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -29,7 +29,7 @@ cabana_env.Depends(assets, Glob('/assets/*', exclude=[assets, assets_src, "asset prev_moc_path = cabana_env['QT_MOCHPREFIX'] cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_' -cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'streams/pandastream.cc', 'streams/devicestream.cc', 'streams/livestream.cc', 'streams/abstractstream.cc', 'streams/replaystream.cc', 'binaryview.cc', 'historylog.cc', 'videowidget.cc', 'signalview.cc', +cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'streams/pandastream.cc', 'streams/devicestream.cc', 'streams/livestream.cc', 'streams/abstractstream.cc', 'streams/replaystream.cc', 'binaryview.cc', 'historylog.cc', 'videowidget.cc', 'signalview.cc', 'dbc/dbc.cc', 'dbc/dbcfile.cc', 'dbc/dbcmanager.cc', 'chart/chartswidget.cc', 'chart/chart.cc', 'chart/signalselector.cc', 'chart/tiplabel.cc', 'chart/sparkline.cc', 'commands.cc', 'messageswidget.cc', 'streamselector.cc', 'settings.cc', 'util.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc', 'tools/findsignal.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) @@ -38,6 +38,7 @@ cabana_env.Program('cabana', ['cabana.cc', cabana_lib, assets], LIBS=cabana_libs if GetOption('test'): cabana_env.Program('tests/test_cabana', ['tests/test_runner.cc', 'tests/test_cabana.cc', cabana_lib], LIBS=[cabana_libs]) -def generate_dbc_json(target, source, env): - env.Execute('tools/cabana/dbc/generate_dbc_json.py --out tools/cabana/dbc/car_fingerprint_to_dbc.json') -cabana_env.Command('generate_dbc_json', [], generate_dbc_json) +generate_dbc = cabana_env.Command('generate_dbc_json', + [], + "python3 tools/cabana/dbc/generate_dbc_json.py --out tools/cabana/dbc/car_fingerprint_to_dbc.json") +cabana_env.Depends(generate_dbc, ["#common", "#selfdrive/boardd", "#opendbc", "#cereal"]) From 980ba1312fc587b735c71887251e16dd20f6cec3 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 23 Jul 2023 03:24:16 +0800 Subject: [PATCH 04/20] ui/map: remove unused variables (#29098) --- selfdrive/ui/qt/maps/map.h | 2 -- selfdrive/ui/qt/maps/map_settings.cc | 1 - selfdrive/ui/qt/maps/map_settings.h | 1 - 3 files changed, 4 deletions(-) diff --git a/selfdrive/ui/qt/maps/map.h b/selfdrive/ui/qt/maps/map.h index 83b0118f96..e419a9e5c0 100644 --- a/selfdrive/ui/qt/maps/map.h +++ b/selfdrive/ui/qt/maps/map.h @@ -49,8 +49,6 @@ private: void pinchTriggered(QPinchGesture *gesture); void setError(const QString &err_str); - bool m_sourceAdded = false; - bool loaded_once = false; bool allow_open = true; diff --git a/selfdrive/ui/qt/maps/map_settings.cc b/selfdrive/ui/qt/maps/map_settings.cc index 104b9d400d..8229252188 100644 --- a/selfdrive/ui/qt/maps/map_settings.cc +++ b/selfdrive/ui/qt/maps/map_settings.cc @@ -8,7 +8,6 @@ #include "selfdrive/ui/qt/widgets/scrollview.h" MapSettings::MapSettings(bool closeable, QWidget *parent) : QFrame(parent) { - close_icon = loadPixmap("../assets/icons/close.svg", {100, 100}); setContentsMargins(0, 0, 0, 0); auto *frame = new QVBoxLayout(this); diff --git a/selfdrive/ui/qt/maps/map_settings.h b/selfdrive/ui/qt/maps/map_settings.h index 5cb90a23a8..1bef04ac5d 100644 --- a/selfdrive/ui/qt/maps/map_settings.h +++ b/selfdrive/ui/qt/maps/map_settings.h @@ -62,7 +62,6 @@ private: DestinationWidget *home_widget; DestinationWidget *work_widget; std::vector widgets; - QPixmap close_icon; signals: void closeSettings(); From 128f261173dfd08484047f2222620eb8e3d5ff33 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 22 Jul 2023 14:12:28 -0700 Subject: [PATCH 05/20] remove unused python packages (#29099) --- poetry.lock | 24 ++++++++++-------------- pyproject.toml | 3 --- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/poetry.lock b/poetry.lock index a4ac56004f..e1d0df6b6d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2668,14 +2668,6 @@ python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.* [package.dependencies] setuptools = "*" -[[package]] -name = "nose" -version = "1.3.7" -description = "nose extends unittest to make testing easier" -category = "main" -optional = false -python-versions = "*" - [[package]] name = "notebook" version = "6.5.4" @@ -5148,7 +5140,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.11" -content-hash = "571bb6cff08ad22a78f005a7635909a399a495596ca387d59dfc4d8028f7484c" +content-hash = "4d0cc4b21d5c400e874754367d7dcf9ada3b39c94cbafa27984d695daae5ee84" [metadata.files] adal = [ @@ -6180,6 +6172,14 @@ fastcluster = [ {file = "fastcluster-1.2.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9020899b67fe492d0ed87a3e993ec9962c5a0b51ea2df71d86b1766f065f1cef"}, {file = "fastcluster-1.2.6-cp310-cp310-win32.whl", hash = "sha256:6cf156d4203708348522393c523c2e61c81f5a6a500e0411dcba2b064551ea2f"}, {file = "fastcluster-1.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:1801c9daa9aa5bbbb0830efe8bd3034b4b7a417e4b8dd353683999be29797df2"}, + {file = "fastcluster-1.2.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ce70c743490f6778b463524d1767a9ecccd31c8bd2dbb5739bb2174168c15d39"}, + {file = "fastcluster-1.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ac1b84d4b28456a379a71451d13995eb3242143452ce9c861f8913360de842a3"}, + {file = "fastcluster-1.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:55b49f6033c45a28f93540847b495ed0f718b5c3f4fef446cf77e3726662e1d5"}, + {file = "fastcluster-1.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1c776a4ec7594f47cd2e1e2da73a30134f1d402d7c93a81e3cb7c3d8e191173"}, + {file = "fastcluster-1.2.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aca61d16435bb7aea3901939d7d7d7e36aff9bb538123e649166a3014b280054"}, + {file = "fastcluster-1.2.6-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04ea4a68e0675072ca761bad33322a0e998cb43693fd41165bc420d7db40429a"}, + {file = "fastcluster-1.2.6-cp311-cp311-win32.whl", hash = "sha256:773043d5db2790e1ff2a4e1eae0b6a60afb2a93ad2c74897a56c80bc800db04f"}, + {file = "fastcluster-1.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:841d128daa6597d13781793eb482b0b566bbd58d2a9d1e2cf1b58838773beb14"}, {file = "fastcluster-1.2.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cf5acfe1156849279ebd44a8d1fbcbe8b8e21334f7538eda782ae31e7dade9e2"}, {file = "fastcluster-1.2.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb27c13225f5f77f3c5986a27ca27277cce7db12844330cf535019cd38021257"}, {file = "fastcluster-1.2.6-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fe543b6d45da27e84e5af6248722475b88943d8ef40d835cbabbb0ba5ee786b"}, @@ -7629,11 +7629,6 @@ nodeenv = [ {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, ] -nose = [ - {file = "nose-1.3.7-py2-none-any.whl", hash = "sha256:dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a"}, - {file = "nose-1.3.7-py3-none-any.whl", hash = "sha256:9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac"}, - {file = "nose-1.3.7.tar.gz", hash = "sha256:f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98"}, -] notebook = [ {file = "notebook-6.5.4-py3-none-any.whl", hash = "sha256:dd17e78aefe64c768737b32bf171c1c766666a21cc79a44d37a1700771cab56f"}, {file = "notebook-6.5.4.tar.gz", hash = "sha256:517209568bd47261e2def27a140e97d49070602eea0d226a696f42a7f16c9a4e"}, @@ -7977,6 +7972,7 @@ pillow-avif-plugin = [ {file = "pillow_avif_plugin-1.3.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a9b8e8943a8b9f860d2b03e0b9c9839bc59db22c5a0a55d66a534a3d4cea00b"}, {file = "pillow_avif_plugin-1.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98dbb6b21ab5b7e0d80134721e756c956d4de2c6cb5c48bb32f78f97339425cb"}, {file = "pillow_avif_plugin-1.3.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c4d0b80ff0819de1ba6d401796bc900be252468621b6e734560eee2ea154dbb4"}, + {file = "pillow_avif_plugin-1.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:c4ff1d331df8ca0f0c5c90d3f05b3a05325c40c9f330e0ad58eb70f7ede20157"}, {file = "pillow_avif_plugin-1.3.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:0a02a436494e380fc99d5ff48be2ef15d42ce655614b9ebd80e106615eb3a594"}, {file = "pillow_avif_plugin-1.3.1-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:fe8250efd581e362a135d63bbca62b0c78ef1e474582da4013c3a995bc1f40c2"}, {file = "pillow_avif_plugin-1.3.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:39e93224a3d0132a64e7d978e48b74f020c65fcb3a141641084d2a4357ed6ceb"}, diff --git a/pyproject.toml b/pyproject.toml index f757918ec2..1c9b0988e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,13 +26,11 @@ hexdump = "^3.3" Jinja2 = "^3.1.2" json-rpc = "^1.13.0" libusb1 = "^3.0.0" -nose = "^1.3.7" numpy = "==1.23.0" # locked pending deprecation fixes in xx onnx = "^1.14.0" onnxruntime-gpu = { version = "^1.15.1", platform = "linux", markers = "platform_machine == 'x86_64'" } pillow = "^9.2.0" poetry = "==1.2.2" -protobuf = "==3.20.3" psutil = "^5.9.1" pycapnp = "^1.3.0" pycryptodome = "^3.15.0" @@ -46,7 +44,6 @@ requests = "^2.28.1" scons = "^4.5.2" sentry-sdk = "^1.6.0" setproctitle = "^1.2.3" -six = "^1.16.0" smbus2 = "^0.4.2" sounddevice = "^0.4.5" spidev = { version = "^3.6", platform = "linux" } From d92c9aef23fc789d50bfd03ae09a3abbf23a8429 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 22 Jul 2023 17:15:58 -0700 Subject: [PATCH 06/20] tici: speedup power save setting (#29100) * speedup * update type --------- Co-authored-by: Comma Device --- Jenkinsfile | 3 +- common/gpio.py | 22 +++++++---- system/hardware/tici/hardware.py | 42 +++++++++++++-------- system/hardware/tici/tests/test_hardware.py | 31 +++++++++++++++ system/sensord/tests/test_sensord.py | 4 +- 5 files changed, 76 insertions(+), 26 deletions(-) create mode 100755 system/hardware/tici/tests/test_hardware.py diff --git a/Jenkinsfile b/Jenkinsfile index 4203c7f196..438149ef60 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -166,7 +166,8 @@ pipeline { ["test sensord", "cd system/sensord/tests && python -m unittest test_sensord.py"], ["test camerad", "python system/camerad/test/test_camerad.py"], ["test exposure", "python system/camerad/test/test_exposure.py"], - ["test amp", "python system/hardware/tici/tests/test_amplifier.py"], + ["test amp", "pytest system/hardware/tici/tests/test_amplifier.py"], + ["test hw", "pytest system/hardware/tici/tests/test_hardware.py"], ["test rawgpsd", "python system/sensord/rawgps/test_rawgps.py"], ]) } diff --git a/common/gpio.py b/common/gpio.py index 711fcff85d..f400ccc53a 100644 --- a/common/gpio.py +++ b/common/gpio.py @@ -1,4 +1,4 @@ -import glob +from functools import cache from typing import Optional, List def gpio_init(pin: int, output: bool) -> None: @@ -25,12 +25,20 @@ def gpio_read(pin: int) -> Optional[bool]: return val -def get_irq_for_action(action: str) -> List[int]: - ret = [] - for fn in glob.glob('/sys/kernel/irq/*/actions'): - with open(fn) as f: +@cache +def get_irq_action(irq: int) -> List[str]: + try: + with open(f"/sys/kernel/irq/{irq}/actions") as f: actions = f.read().strip().split(',') - if action in actions: - irq = int(fn.split('/')[-2]) + return actions + except FileNotFoundError: + return [] + +def get_irqs_for_action(action: str) -> List[str]: + ret = [] + with open("/proc/interrupts") as f: + for l in f.readlines(): + irq = l.split(':')[0].strip() + if irq.isdigit() and action in get_irq_action(irq): ret.append(irq) return ret diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py index 780d870dcd..018bc30004 100644 --- a/system/hardware/tici/hardware.py +++ b/system/hardware/tici/hardware.py @@ -8,7 +8,7 @@ from functools import cached_property, lru_cache from pathlib import Path from cereal import log -from common.gpio import gpio_set, gpio_init, get_irq_for_action +from common.gpio import gpio_set, gpio_init, get_irqs_for_action from system.hardware.base import HardwareBase, ThermalConfig from system.hardware.tici import iwlist from system.hardware.tici.pins import GPIO @@ -61,17 +61,27 @@ MM_MODEM_ACCESS_TECHNOLOGY_LTE = 1 << 14 def sudo_write(val, path): - os.system(f"sudo su -c 'echo {val} > {path}'") + try: + with open(path, 'w') as f: + f.write(str(val)) + except PermissionError: + os.system(f"sudo chmod a+w {path}") + try: + with open(path, 'w') as f: + f.write(str(val)) + except PermissionError: + # fallback for debugfs files + os.system(f"sudo su -c 'echo {val} > {path}'") def affine_irq(val, action): - irq = get_irq_for_action(action) - if len(irq) == 0: + irqs = get_irqs_for_action(action) + if len(irqs) == 0: print(f"No IRQs found for '{action}'") return - for i in irq: - sudo_write(str(val), f"/proc/irq/{i}/smp_affinity_list") + for i in irqs: + sudo_write(str(val), f"/proc/irq/{i}/smp_affinity_list") class Tici(HardwareBase): @cached_property @@ -438,17 +448,17 @@ class Tici(HardwareBase): # *** IRQ config *** - # GPU - affine_irq(5, "kgsl-3d0") - # boardd core affine_irq(4, "spi_geni") # SPI affine_irq(4, "xhci-hcd:usb3") # aux panda USB (or potentially anything else on USB) if "tici" in self.get_device_type(): - affine_irq(4, "xhci-hcd:usb1") # internal panda USB + affine_irq(4, "xhci-hcd:usb1") # internal panda USB (also modem) + + # GPU + affine_irq(5, "kgsl-3d0") # camerad core - camera_irqs = ("cci", "cpas_camnoc", "cpas-cdm", "csid", "ife", "csid", "csid-lite", "ife-lite") + camera_irqs = ("cci", "cpas_camnoc", "cpas-cdm", "csid", "ife", "csid-lite", "ife-lite") for n in camera_irqs: affine_irq(5, n) @@ -472,14 +482,14 @@ class Tici(HardwareBase): # *** IRQ config *** - # move these off the default core - affine_irq(1, "msm_drm") - affine_irq(1, "msm_vidc") - affine_irq(1, "i2c_geni") - # mask off big cluster from default affinity sudo_write("f", "/proc/irq/default_smp_affinity") + # move these off the default core + affine_irq(1, "msm_drm") # display + affine_irq(1, "msm_vidc") # encoders + affine_irq(1, "i2c_geni") # sensors + # *** GPU config *** # https://github.com/commaai/agnos-kernel-sdm845/blob/master/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi#L216 sudo_write("1", "/sys/class/kgsl/kgsl-3d0/min_pwrlevel") diff --git a/system/hardware/tici/tests/test_hardware.py b/system/hardware/tici/tests/test_hardware.py new file mode 100755 index 0000000000..d910b13ec4 --- /dev/null +++ b/system/hardware/tici/tests/test_hardware.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +import time +import unittest +import numpy as np + +from system.hardware import TICI +from system.hardware.tici.hardware import Tici + +HARDWARE = Tici() + +class TestHardware(unittest.TestCase): + + @classmethod + def setUpClass(cls): + if not TICI: + raise unittest.SkipTest + + def test_power_save_time(self): + ts = [] + for _ in range(5): + for on in (True, False): + st = time.monotonic() + HARDWARE.set_power_save(on) + ts.append(time.monotonic() - st) + + assert 0.1 < np.mean(ts) < 0.2 + assert max(ts) < 0.3 + + +if __name__ == "__main__": + unittest.main() diff --git a/system/sensord/tests/test_sensord.py b/system/sensord/tests/test_sensord.py index b515ce16ab..eea527ed63 100755 --- a/system/sensord/tests/test_sensord.py +++ b/system/sensord/tests/test_sensord.py @@ -7,7 +7,7 @@ from collections import namedtuple, defaultdict import cereal.messaging as messaging from cereal import log -from common.gpio import get_irq_for_action +from common.gpio import get_irqs_for_action from system.hardware import TICI from selfdrive.manager.process_config import managed_processes @@ -113,7 +113,7 @@ class TestSensord(unittest.TestCase): cls.events = read_sensor_events(cls.sample_secs) # determine sensord's irq - cls.sensord_irq = get_irq_for_action("sensord")[0] + cls.sensord_irq = get_irqs_for_action("sensord")[0] finally: # teardown won't run if this doesn't succeed managed_processes["sensord"].stop() From 34389acbbfdd5ab6e58e40c0819f986552f22a59 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 22 Jul 2023 23:10:31 -0700 Subject: [PATCH 07/20] CI: run plotjuggler test on mac (#29102) * CI: run plotjuggler test on mac * source * python path --- .github/workflows/selfdrive_tests.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 5fecdc5b51..17f0907fe4 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -136,6 +136,11 @@ jobs: run: | source tools/openpilot_env.sh poetry run scons -j$(nproc) + - name: Run tests + run: | + source tools/openpilot_env.sh + export PYTHONPATH=$PWD + poetry run tools/plotjuggler/test_plotjuggler.py - name: Pre Cache - Cleanup scons cache if: github.ref == 'refs/heads/master' run: | From 12ed894362dd22513a21de6689a31511b791e37b Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sun, 23 Jul 2023 09:28:22 -0700 Subject: [PATCH 08/20] dmonitoringmodeld: initialize model first (#29080) * hacky fix * even better * ordering * clean up * fix model replay * add comment * catch sigint --- common/params.cc | 1 + selfdrive/modeld/dmonitoringmodeld.cc | 3 +++ selfdrive/modeld/navmodeld.cc | 8 ++++++++ selfdrive/test/process_replay/model_replay.py | 2 ++ 4 files changed, 14 insertions(+) diff --git a/common/params.cc b/common/params.cc index fb672cd8aa..509d419d64 100644 --- a/common/params.cc +++ b/common/params.cc @@ -107,6 +107,7 @@ std::unordered_map keys = { {"DisablePowerDown", PERSISTENT}, {"DisableUpdates", PERSISTENT}, {"DisengageOnAccelerator", PERSISTENT}, + {"DmModelInitialized", CLEAR_ON_ONROAD_TRANSITION}, {"DongleId", PERSISTENT}, {"DoReboot", CLEAR_ON_MANAGER_START}, {"DoShutdown", CLEAR_ON_MANAGER_START}, diff --git a/selfdrive/modeld/dmonitoringmodeld.cc b/selfdrive/modeld/dmonitoringmodeld.cc index a647a42699..bd3564714a 100644 --- a/selfdrive/modeld/dmonitoringmodeld.cc +++ b/selfdrive/modeld/dmonitoringmodeld.cc @@ -5,6 +5,7 @@ #include #include "cereal/visionipc/visionipc_client.h" +#include "common/params.h" #include "common/swaglog.h" #include "common/util.h" #include "selfdrive/modeld/models/dmonitoring.h" @@ -49,6 +50,8 @@ int main(int argc, char **argv) { DMonitoringModelState model; dmonitoring_init(&model); + Params().putBool("DmModelInitialized", true); + LOGW("connecting to driver stream"); VisionIpcClient vipc_client = VisionIpcClient("camerad", VISION_STREAM_DRIVER, true); while (!do_exit && !vipc_client.connect(false)) { diff --git a/selfdrive/modeld/navmodeld.cc b/selfdrive/modeld/navmodeld.cc index 96578119e2..bd78e7a48b 100644 --- a/selfdrive/modeld/navmodeld.cc +++ b/selfdrive/modeld/navmodeld.cc @@ -5,6 +5,7 @@ #include #include "cereal/visionipc/visionipc_client.h" +#include "common/params.h" #include "common/swaglog.h" #include "common/util.h" #include "selfdrive/modeld/models/nav.h" @@ -41,6 +42,13 @@ void run_model(NavModelState &model, VisionIpcClient &vipc_client) { int main(int argc, char **argv) { setpriority(PRIO_PROCESS, 0, -15); + // there exists a race condition when two processes try to create a + // SNPE model runner at the same time, wait for dmonitoringmodeld to finish + LOGW("waiting for dmonitoringmodeld to initialize"); + if (!Params().getBool("DmModelInitialized", true)) { + return 0; + } + // init the models NavModelState model; navmodel_init(&model); diff --git a/selfdrive/test/process_replay/model_replay.py b/selfdrive/test/process_replay/model_replay.py index e9789489e7..56bb3e1b3e 100755 --- a/selfdrive/test/process_replay/model_replay.py +++ b/selfdrive/test/process_replay/model_replay.py @@ -6,6 +6,7 @@ from collections import defaultdict from typing import Any import cereal.messaging as messaging +from common.params import Params from common.spinner import Spinner from system.hardware import PC from selfdrive.manager.process_config import managed_processes @@ -62,6 +63,7 @@ def nav_model_replay(lr): try: assert "MAPBOX_TOKEN" in os.environ os.environ['MAP_RENDER_TEST_MODE'] = '1' + Params().put_bool('DmModelInitialized', True) managed_processes['mapsd'].start() managed_processes['navmodeld'].start() From 5831f9e5a0d74a03a1b6ebc7b87f6d76d0fc38ae Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 23 Jul 2023 11:54:51 -0700 Subject: [PATCH 09/20] common/gpio: switch to lru_cache for 3.8 compatiblity --- common/gpio.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/gpio.py b/common/gpio.py index f400ccc53a..e31c8c52e6 100644 --- a/common/gpio.py +++ b/common/gpio.py @@ -1,4 +1,4 @@ -from functools import cache +from functools import lru_cache from typing import Optional, List def gpio_init(pin: int, output: bool) -> None: @@ -25,7 +25,7 @@ def gpio_read(pin: int) -> Optional[bool]: return val -@cache +@lru_cache(maxsize=None) def get_irq_action(irq: int) -> List[str]: try: with open(f"/sys/kernel/irq/{irq}/actions") as f: From c0c00e1997a6919701a183b9d4757a74b17ac141 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 24 Jul 2023 03:33:06 +0800 Subject: [PATCH 10/20] loggerd: check `userFlag` outside the while loop (#29095) * improve check userFlag * rename to ServiceState * setxattr once --- system/loggerd/loggerd.cc | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/system/loggerd/loggerd.cc b/system/loggerd/loggerd.cc index ced9595896..9cad9d7f2e 100644 --- a/system/loggerd/loggerd.cc +++ b/system/loggerd/loggerd.cc @@ -173,6 +173,9 @@ int handle_encoder_msg(LoggerdState *s, Message *msg, std::string &name, struct } void handle_user_flag(LoggerdState *s) { + static int prev_segment = -1; + if (s->rotate_segment == prev_segment) return; + LOGW("preserving %s", s->segment_path); #ifdef __APPLE__ @@ -183,16 +186,17 @@ void handle_user_flag(LoggerdState *s) { if (ret) { LOGE("setxattr %s failed for %s: %s", PRESERVE_ATTR_NAME, s->segment_path, strerror(errno)); } + prev_segment = s->rotate_segment.load(); } void loggerd_thread() { // setup messaging - typedef struct QlogState { + typedef struct ServiceState { std::string name; int counter, freq; - bool encoder; - } QlogState; - std::unordered_map qlog_states; + bool encoder, user_flag; + } ServiceState; + std::unordered_map service_state; std::unordered_map remote_encoders; std::unique_ptr ctx(Context::create()); @@ -207,11 +211,12 @@ void loggerd_thread() { SubSocket * sock = SubSocket::create(ctx.get(), it.name); assert(sock != NULL); poller->registerSocket(sock); - qlog_states[sock] = { + service_state[sock] = { .name = it.name, .counter = 0, .freq = it.decimation, .encoder = encoder, + .user_flag = (strcmp(it.name, "userFlag") == 0), }; } @@ -236,20 +241,19 @@ void loggerd_thread() { for (auto sock : poller->poll(1000)) { if (do_exit) break; + ServiceState &service = service_state[sock]; + if (service.user_flag) { + handle_user_flag(&s); + } + // drain socket int count = 0; - QlogState &qs = qlog_states[sock]; Message *msg = nullptr; while (!do_exit && (msg = sock->receive(true))) { - const bool in_qlog = qs.freq != -1 && (qs.counter++ % qs.freq == 0); - - if (qs.name == "userFlag") { - handle_user_flag(&s); - } - - if (qs.encoder) { + const bool in_qlog = service.freq != -1 && (service.counter++ % service.freq == 0); + if (service.encoder) { s.last_camera_seen_tms = millis_since_boot(); - bytes_count += handle_encoder_msg(&s, msg, qs.name, remote_encoders[sock], encoder_infos_dict[qs.name]); + bytes_count += handle_encoder_msg(&s, msg, service.name, remote_encoders[sock], encoder_infos_dict[service.name]); } else { logger_log(&s.logger, (uint8_t *)msg->getData(), msg->getSize(), in_qlog); bytes_count += msg->getSize(); @@ -265,7 +269,7 @@ void loggerd_thread() { count++; if (count >= 200) { - LOGD("large volume of '%s' messages", qs.name.c_str()); + LOGD("large volume of '%s' messages", service.name.c_str()); break; } } @@ -282,7 +286,7 @@ void loggerd_thread() { } // messaging cleanup - for (auto &[sock, qs] : qlog_states) delete sock; + for (auto &[sock, service] : service_state) delete sock; } int main(int argc, char** argv) { From 5fb2f7072bec37ab4da3ca6558834a9e2fffcb9b Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 23 Jul 2023 15:38:47 -0700 Subject: [PATCH 11/20] rawgpsd: speedup tests (#29110) * rawgpsd: speedup tests * fix that one * little more * prevent subtle bugs --------- Co-authored-by: Comma Device --- Jenkinsfile | 2 +- system/sensord/rawgps/test_rawgps.py | 53 +++++++++++++++------------- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 438149ef60..00bd537b2f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -168,7 +168,7 @@ pipeline { ["test exposure", "python system/camerad/test/test_exposure.py"], ["test amp", "pytest system/hardware/tici/tests/test_amplifier.py"], ["test hw", "pytest system/hardware/tici/tests/test_hardware.py"], - ["test rawgpsd", "python system/sensord/rawgps/test_rawgps.py"], + ["test rawgpsd", "pytest system/sensord/rawgps/test_rawgps.py"], ]) } } diff --git a/system/sensord/rawgps/test_rawgps.py b/system/sensord/rawgps/test_rawgps.py index f87a552d66..682cdecbd5 100755 --- a/system/sensord/rawgps/test_rawgps.py +++ b/system/sensord/rawgps/test_rawgps.py @@ -19,12 +19,12 @@ GOOD_SIGNAL = bool(int(os.getenv("GOOD_SIGNAL", '0'))) class TestRawgpsd(unittest.TestCase): @classmethod def setUpClass(cls): - os.system("sudo systemctl restart systemd-resolved") - os.system("sudo systemctl restart ModemManager lte") - wait_for_modem() if not TICI: raise unittest.SkipTest - cls.sm = messaging.SubMaster(['qcomGnss', 'gpsLocation', 'gnssMeasurements']) + + os.system("sudo systemctl start systemd-resolved") + os.system("sudo systemctl restart ModemManager lte") + wait_for_modem() @classmethod def tearDownClass(cls): @@ -34,40 +34,44 @@ class TestRawgpsd(unittest.TestCase): def setUp(self): at_cmd("AT+QGPSDEL=0") + self.sm = messaging.SubMaster(['qcomGnss', 'gpsLocation', 'gnssMeasurements']) def tearDown(self): managed_processes['rawgpsd'].stop() os.system("sudo systemctl restart systemd-resolved") - def _wait_for_output(self, t=10): - time.sleep(t) - self.sm.update() + def _wait_for_output(self, t): + dt = 0.1 + for _ in range(t*int(1/dt)): + self.sm.update(0) + if self.sm.updated['qcomGnss']: + break + time.sleep(dt) + return self.sm.updated['qcomGnss'] def test_no_crash_double_command(self): at_cmd("AT+QGPSDEL=0") at_cmd("AT+QGPSDEL=0") def test_wait_for_modem(self): - os.system("sudo systemctl stop ModemManager lte") + os.system("sudo systemctl stop ModemManager") managed_processes['rawgpsd'].start() - self._wait_for_output(10) - assert not self.sm.updated['qcomGnss'] + assert not self._wait_for_output(5) - os.system("sudo systemctl restart ModemManager lte") - self._wait_for_output(30) - assert self.sm.updated['qcomGnss'] + os.system("sudo systemctl restart ModemManager") + assert self._wait_for_output(30) def test_startup_time(self): - for i in range(2): - if i == 1: + for internet in (True, False): + if not internet: os.system("sudo systemctl stop systemd-resolved") - managed_processes['rawgpsd'].start() - self._wait_for_output(10) - assert self.sm.updated['qcomGnss'] - managed_processes['rawgpsd'].stop() + with self.subTest(internet=internet): + managed_processes['rawgpsd'].start() + assert self._wait_for_output(10) + managed_processes['rawgpsd'].stop() def test_turns_off_gnss(self): - for s in (0.1, 0.5, 1, 5): + for s in (0.1, 1, 5): managed_processes['rawgpsd'].start() time.sleep(s) managed_processes['rawgpsd'].stop() @@ -95,8 +99,7 @@ class TestRawgpsd(unittest.TestCase): def test_assistance_loading(self): managed_processes['rawgpsd'].start() - self._wait_for_output(10) - assert self.sm.updated['qcomGnss'] + assert self._wait_for_output(10) managed_processes['rawgpsd'].stop() self.check_assistance(True) @@ -104,8 +107,7 @@ class TestRawgpsd(unittest.TestCase): os.system("sudo systemctl stop systemd-resolved") managed_processes['rawgpsd'].start() - self._wait_for_output(10) - assert self.sm.updated['qcomGnss'] + assert self._wait_for_output(10) managed_processes['rawgpsd'].stop() self.check_assistance(False) @@ -115,8 +117,9 @@ class TestRawgpsd(unittest.TestCase): managed_processes['rawgpsd'].start() self._wait_for_output(17) assert self.sm.updated['qcomGnss'] + os.system("sudo systemctl restart systemd-resolved") - self._wait_for_output(15) + time.sleep(15) managed_processes['rawgpsd'].stop() self.check_assistance(True) From 9113816e1dd08f7368bcc311d2514dc91033540c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 23 Jul 2023 15:59:26 -0700 Subject: [PATCH 12/20] rawgpsd: fix double setup (#29108) * rawgpsd: fix double setup * speedup test * update that one * minimal diff --------- Co-authored-by: Comma Device --- system/sensord/rawgps/rawgpsd.py | 21 ++++++++++++--------- system/sensord/rawgps/test_rawgps.py | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/system/sensord/rawgps/rawgpsd.py b/system/sensord/rawgps/rawgpsd.py index 3f8fd8c67a..956da086e1 100755 --- a/system/sensord/rawgps/rawgpsd.py +++ b/system/sensord/rawgps/rawgpsd.py @@ -162,7 +162,9 @@ def inject_assistance(): returncode=e.returncode ) -def setup_quectel(diag: ModemDiag): +def setup_quectel(diag: ModemDiag) -> bool: + ret = False + # enable OEMDRE in the NV # TODO: it has to reboot for this to take effect DIAG_NV_READ_F = 38 @@ -186,7 +188,9 @@ def setup_quectel(diag: ModemDiag): at_cmd("AT+QGPSXTRA=1") at_cmd("AT+QGPSSUPLURL=\"NULL\"") if os.path.exists(ASSIST_DATA_FILE): + ret = True inject_assistance() + os.remove(ASSIST_DATA_FILE) #at_cmd("AT+QGPSXTRADATA?") time_str = datetime.utcnow().strftime("%Y/%m/%d,%H:%M:%S") at_cmd(f"AT+QGPSXTRATIME=0,\"{time_str}\",1,1,1000") @@ -213,6 +217,8 @@ def setup_quectel(diag: ModemDiag): 0,0 )) + return ret + def teardown_quectel(diag): at_cmd("AT+QGPSCFG=\"outport\",\"none\"") if gps_enabled(): @@ -260,8 +266,8 @@ def main() -> NoReturn: # connect to modem diag = ModemDiag() - setup_quectel(diag) - want_assistance = True + r = setup_quectel(diag) + want_assistance = not r current_gps_time = utc_to_gpst(GPSTime.from_datetime(datetime.utcnow())) cloudlog.warning("quectel setup done") gpio_init(GPIO.UBLOX_PWR_EN, True) @@ -270,12 +276,9 @@ def main() -> NoReturn: pm = messaging.PubMaster(['qcomGnss', 'gpsLocation']) while 1: - if os.path.exists(ASSIST_DATA_FILE): - if want_assistance: - setup_quectel(diag) - want_assistance = False - else: - os.remove(ASSIST_DATA_FILE) + if os.path.exists(ASSIST_DATA_FILE) and want_assistance: + setup_quectel(diag) + want_assistance = False opcode, payload = diag.recv() if opcode != DIAG_LOG_F: diff --git a/system/sensord/rawgps/test_rawgps.py b/system/sensord/rawgps/test_rawgps.py index 682cdecbd5..8c2e246764 100755 --- a/system/sensord/rawgps/test_rawgps.py +++ b/system/sensord/rawgps/test_rawgps.py @@ -67,7 +67,7 @@ class TestRawgpsd(unittest.TestCase): os.system("sudo systemctl stop systemd-resolved") with self.subTest(internet=internet): managed_processes['rawgpsd'].start() - assert self._wait_for_output(10) + assert self._wait_for_output(7) managed_processes['rawgpsd'].stop() def test_turns_off_gnss(self): From e2ae98e71881608061cddf60a317d93450cd6098 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 23 Jul 2023 16:23:56 -0700 Subject: [PATCH 13/20] bump body: --- body | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/body b/body index 5f5b8a9dff..05021c559e 160000 --- a/body +++ b/body @@ -1 +1 @@ -Subproject commit 5f5b8a9dff671cbf9369eb10e18b41ca619566ba +Subproject commit 05021c559e78fd7c539abceeedcc47f981b05455 From bcfb9d694061e5aef5e0e6bb3d756407b57315a2 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 24 Jul 2023 08:45:19 +0800 Subject: [PATCH 14/20] ui/settings: use existing params instance (#29109) use exsting params --- selfdrive/ui/qt/offroad/settings.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 6d880134c8..bb15e9d5bd 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -234,7 +234,7 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) { QString selection = MultiOptionDialog::getSelection(tr("Select a language"), langs.keys(), langs.key(uiState()->language), this); if (!selection.isEmpty()) { // put language setting, exit Qt UI, and trigger fast restart - Params().put("LanguageSetting", langs[selection].toStdString()); + params.put("LanguageSetting", langs[selection].toStdString()); qApp->exit(18); watchdog_kick(0); } @@ -278,7 +278,7 @@ void DevicePanel::updateCalibDescription() { QString desc = tr("openpilot requires the device to be mounted within 4° left or right and " "within 5° up or 8° down. openpilot is continuously calibrating, resetting is rarely required."); - std::string calib_bytes = Params().get("CalibrationParams"); + std::string calib_bytes = params.get("CalibrationParams"); if (!calib_bytes.empty()) { try { AlignedBuffer aligned_buf; @@ -303,7 +303,7 @@ void DevicePanel::reboot() { if (ConfirmationDialog::confirm(tr("Are you sure you want to reboot?"), tr("Reboot"), this)) { // Check engaged again in case it changed while the dialog was open if (!uiState()->engaged()) { - Params().putBool("DoReboot", true); + params.putBool("DoReboot", true); } } } else { @@ -316,7 +316,7 @@ void DevicePanel::poweroff() { if (ConfirmationDialog::confirm(tr("Are you sure you want to power off?"), tr("Power Off"), this)) { // Check engaged again in case it changed while the dialog was open if (!uiState()->engaged()) { - Params().putBool("DoShutdown", true); + params.putBool("DoShutdown", true); } } } else { From a31b1dcf16857ac94ce337fd5b6e1b4ab6b7d991 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sun, 23 Jul 2023 18:34:35 -0700 Subject: [PATCH 15/20] disable_ecu: support sub-addresses (#29112) allow sub_addrs --- selfdrive/car/disable_ecu.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/selfdrive/car/disable_ecu.py b/selfdrive/car/disable_ecu.py index ed98e14dc1..36ebe12fa8 100755 --- a/selfdrive/car/disable_ecu.py +++ b/selfdrive/car/disable_ecu.py @@ -7,22 +7,22 @@ EXT_DIAG_RESPONSE = b'\x50\x03' COM_CONT_RESPONSE = b'' -def disable_ecu(logcan, sendcan, bus=0, addr=0x7d0, com_cont_req=b'\x28\x83\x01', timeout=0.1, retry=10, debug=False): +def disable_ecu(logcan, sendcan, bus=0, addr=0x7d0, sub_addr=None, com_cont_req=b'\x28\x83\x01', timeout=0.1, retry=10, debug=False): """Silence an ECU by disabling sending and receiving messages using UDS 0x28. The ECU will stay silent as long as openpilot keeps sending Tester Present. This is used to disable the radar in some cars. Openpilot will emulate the radar. WARNING: THIS DISABLES AEB!""" - cloudlog.warning(f"ecu disable {hex(addr)} ...") + cloudlog.warning(f"ecu disable {hex(addr), sub_addr} ...") for i in range(retry): try: - query = IsoTpParallelQuery(sendcan, logcan, bus, [addr], [EXT_DIAG_REQUEST], [EXT_DIAG_RESPONSE], debug=debug) + query = IsoTpParallelQuery(sendcan, logcan, bus, [(addr, sub_addr)], [EXT_DIAG_REQUEST], [EXT_DIAG_RESPONSE], debug=debug) for _, _ in query.get_data(timeout).items(): cloudlog.warning("communication control disable tx/rx ...") - query = IsoTpParallelQuery(sendcan, logcan, bus, [addr], [com_cont_req], [COM_CONT_RESPONSE], debug=debug) + query = IsoTpParallelQuery(sendcan, logcan, bus, [(addr, sub_addr)], [com_cont_req], [COM_CONT_RESPONSE], debug=debug) query.get_data(0) cloudlog.warning("ecu disabled") From 787d3b17147fc21bf3c93f7555a0e9aafe24a731 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 23 Jul 2023 20:36:13 -0700 Subject: [PATCH 16/20] tici: restart ModemManager if probing fails (#29114) * tici: restart ModemManager if probing fails * add comment --------- Co-authored-by: Comma Device --- selfdrive/thermald/thermald.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index 40b259a8d4..60961d3d80 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -103,6 +103,8 @@ def hw_state_thread(end_event, hw_queue): modem_version = None modem_nv = None modem_configured = False + modem_restarted = False + modem_missing_count = 0 while not end_event.is_set(): # these are expensive calls. update every 10s @@ -120,6 +122,16 @@ def hw_state_thread(end_event, hw_queue): if (modem_version is not None) and (modem_nv is not None): cloudlog.event("modem version", version=modem_version, nv=modem_nv) + else: + if not modem_restarted: + # TODO: we may be able to remove this with a MM update + # ModemManager's probing on startup can fail + # rarely, restart the service to probe again. + modem_missing_count += 1 + if modem_missing_count > 3: + modem_restarted = True + cloudlog.event("restarting ModemManager") + os.system("sudo systemctl restart --no-block ModemManager") tx, rx = HARDWARE.get_modem_data_usage() From 14001be60575eddce59bd23c16a97fc896ae299f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 23 Jul 2023 22:10:36 -0700 Subject: [PATCH 17/20] rawgpsd: retry injecting assistance data (#29115) * rawgpsd: retry injecting assistance data * sleep a bit --------- Co-authored-by: Comma Device --- system/sensord/rawgps/rawgpsd.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/system/sensord/rawgps/rawgpsd.py b/system/sensord/rawgps/rawgpsd.py index 956da086e1..5db6ad1cf5 100755 --- a/system/sensord/rawgps/rawgpsd.py +++ b/system/sensord/rawgps/rawgpsd.py @@ -149,18 +149,22 @@ def downloader_loop(event): time.sleep(10) def inject_assistance(): - try: - cmd = f"mmcli -m any --timeout 30 --location-inject-assistance-data={ASSIST_DATA_FILE}" - subprocess.check_output(cmd, stderr=subprocess.PIPE, shell=True) - cloudlog.info("successfully loaded assistance data") - except subprocess.CalledProcessError as e: - cloudlog.event( - "rawgps.assistance_loading_failed", - error=True, - cmd=e.cmd, - output=e.output, - returncode=e.returncode - ) + for _ in range(5): + try: + cmd = f"mmcli -m any --timeout 30 --location-inject-assistance-data={ASSIST_DATA_FILE}" + subprocess.check_output(cmd, stderr=subprocess.PIPE, shell=True) + cloudlog.info("successfully loaded assistance data") + return + except subprocess.CalledProcessError as e: + cloudlog.event( + "rawgps.assistance_loading_failed", + error=True, + cmd=e.cmd, + output=e.output, + returncode=e.returncode + ) + time.sleep(0.2) + cloudlog.error("failed to load assistance after retry") def setup_quectel(diag: ModemDiag) -> bool: ret = False From 3614ed942b925970db76bf6c87e34f894cfc422c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 24 Jul 2023 09:29:58 -0700 Subject: [PATCH 18/20] Update RELEASES.md --- RELEASES.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 6b5751507b..7c2c960beb 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,14 +1,14 @@ Version 0.9.4 (2023-XX-XX) ======================== * Navigate on openpilot - * When navigation has a destination openpilot will input the map information into the model, generally improving behavior + * When navigation has a destination, openpilot will input the map information into the model, generally improving behavior * When navigating on openpilot, openpilot will keep left or right appropriately at forks/exits and take turns - * When navigating on openpilot, lane change behavior is unchanged and still activated by the driver + * When navigating on openpilot, lane change behavior is unchanged and still activated by the driver + * When navigate on openpilot is active, the path on the map is green * UI updates * Navigation settings moved to home screen and map -* UI alerts rework * Border color always shows engagement status. Blue means disengaged, green means engaged, and grey means engaged with human overriding - * Alerts are shown inside the border. Black/grey means info, orange means warning, and red means critical alert + * Alerts are shown inside the border. Black means info, orange means warning, and red means critical alert * Bookmarked segments are preserved on the device's storage * Ford Focus 2018 support * Kia Carnival 2023 support thanks to sunnyhaibin! From 4d10ba8af8fca860b6ccf11ff6fb3358a16ac4cc Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Mon, 24 Jul 2023 17:43:30 +0100 Subject: [PATCH 19/20] athena: stricter socket timeout when onroad (#29017) --- selfdrive/athena/athenad.py | 27 +++++++++++++++++++-- selfdrive/athena/tests/test_athenad_ping.py | 18 +++++++++++--- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/selfdrive/athena/athenad.py b/selfdrive/athena/athenad.py index a53d5778d4..35a9eaf192 100755 --- a/selfdrive/athena/athenad.py +++ b/selfdrive/athena/athenad.py @@ -42,6 +42,10 @@ from selfdrive.statsd import STATS_DIR from system.swaglog import SWAGLOG_DIR, cloudlog from system.version import get_commit, get_origin, get_short_branch, get_version + +# missing in pysocket +TCP_USER_TIMEOUT = 18 + ATHENA_HOST = os.getenv('ATHENA_HOST', 'wss://athena.comma.ai') HANDLER_THREADS = int(os.getenv('HANDLER_THREADS', "4")) LOCAL_PORT_WHITELIST = {8022} @@ -141,6 +145,7 @@ def handle_long_poll(ws: WebSocket, exit_event: Optional[threading.Event]) -> No end_event = threading.Event() threads = [ + threading.Thread(target=ws_manage, args=(ws, end_event), name='ws_manage'), threading.Thread(target=ws_recv, args=(ws, end_event), name='ws_recv'), threading.Thread(target=ws_send, args=(ws, end_event), name='ws_send'), threading.Thread(target=upload_handler, args=(end_event,), name='upload_handler'), @@ -154,8 +159,7 @@ def handle_long_poll(ws: WebSocket, exit_event: Optional[threading.Event]) -> No for thread in threads: thread.start() try: - while not end_event.is_set(): - time.sleep(0.1) + while not end_event.wait(0.1): if exit_event is not None and exit_event.is_set(): end_event.set() except (KeyboardInterrupt, SystemExit): @@ -756,6 +760,25 @@ def ws_send(ws: WebSocket, end_event: threading.Event) -> None: end_event.set() +def ws_manage(ws: WebSocket, end_event: threading.Event) -> None: + params = Params() + onroad_prev = None + sock = ws.sock + + while True: + onroad = params.get_bool("IsOnroad") + if onroad != onroad_prev: + onroad_prev = onroad + + sock.setsockopt(socket.IPPROTO_TCP, TCP_USER_TIMEOUT, 16000 if onroad else 0) + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 7 if onroad else 30) + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 7 if onroad else 10) + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 2 if onroad else 3) + + if end_event.wait(5): + break + + def backoff(retries: int) -> int: return random.randrange(0, min(128, int(2 ** retries))) diff --git a/selfdrive/athena/tests/test_athenad_ping.py b/selfdrive/athena/tests/test_athenad_ping.py index d85ac60897..f768fbebaa 100755 --- a/selfdrive/athena/tests/test_athenad_ping.py +++ b/selfdrive/athena/tests/test_athenad_ping.py @@ -37,6 +37,9 @@ class TestAthenadPing(unittest.TestCase): def _received_ping(self) -> bool: return self._get_ping_time() is not None + def _set_onroad(self, onroad: bool) -> None: + self.params.put_bool("IsOnroad", onroad) + @classmethod def setUpClass(cls) -> None: cls.params = Params() @@ -63,8 +66,7 @@ class TestAthenadPing(unittest.TestCase): self.exit_event.set() self.athenad.join() - @unittest.skipIf(not TICI, "only run on desk") - def test_timeout(self) -> None: + def assertTimeout(self, reconnect_time: float) -> None: self.athenad.start() time.sleep(1) @@ -84,7 +86,7 @@ class TestAthenadPing(unittest.TestCase): wifi_radio(False) print("waiting for reconnect attempt") start_time = time.monotonic() - with Timeout(180, "no reconnect attempt"): + with Timeout(reconnect_time, "no reconnect attempt"): while not athenad.create_connection.called: time.sleep(0.1) print(f"reconnect attempt after {time.monotonic() - start_time:.2f}s") @@ -97,6 +99,16 @@ class TestAthenadPing(unittest.TestCase): time.sleep(0.1) print("ping received") + @unittest.skipIf(not TICI, "only run on desk") + def test_offroad(self) -> None: + self._set_onroad(False) + self.assertTimeout(100) # expect approx 90s + + @unittest.skipIf(not TICI, "only run on desk") + def test_onroad(self) -> None: + self._set_onroad(True) + self.assertTimeout(30) # expect 20-30s + if __name__ == "__main__": unittest.main() From 1776c16f9a61dbb1e322f15d0f1f3c0a9eb936d8 Mon Sep 17 00:00:00 2001 From: Erich Moraga <33645296+ErichMoraga@users.noreply.github.com> Date: Mon, 24 Jul 2023 11:49:20 -0500 Subject: [PATCH 20/20] Toyota: add fwdCamera ECU version for 2022 Lexus RX Hybrid (#29060) --- docs/CARS.md | 2 +- selfdrive/car/toyota/values.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 3afb9eda5b..96eecd4860 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -153,7 +153,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Lexus|RX Hybrid 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Lexus|RX Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| -|Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| +|Lexus|RX Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Lexus|UX Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 RJ45 cable (7 ft)
- 1 Toyota connector
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |Lincoln|Aviator 2020-21|Co-Pilot360 Plus|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 Ford Q3 connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| |MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,12](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
View- 1 J533 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
|| diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index c36f0c906c..58e3464e3c 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -197,7 +197,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { ToyotaCarInfo("Lexus RX Hybrid 2017-19"), ], CAR.LEXUS_RX_TSS2: ToyotaCarInfo("Lexus RX 2020-22"), - CAR.LEXUS_RXH_TSS2: ToyotaCarInfo("Lexus RX Hybrid 2020-21"), + CAR.LEXUS_RXH_TSS2: ToyotaCarInfo("Lexus RX Hybrid 2020-22"), } # (addr, cars, bus, 1/freq*100, vl) @@ -2129,15 +2129,16 @@ FW_VERSIONS = { b'F152648811\x00\x00\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ - b'8965B48271\x00\x00\x00\x00\x00\x00', b'8965B48261\x00\x00\x00\x00\x00\x00', + b'8965B48271\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ b'\x018821F3301400\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ - b'\x028646F4810200\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', b'\x028646F4810100\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', + b'\x028646F4810200\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', + b'\x028646F4810300\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', ], }, CAR.PRIUS_TSS2: {