Merge remote-tracking branch 'upstream/master' into boardd-no-fault

old-commit-hash: 438c8438bf7dcbe54fcbf0832159e971d1090bd1
pull/32103/head
Shane Smiskol 1 year ago
commit 830c538b61
  1. 4
      .github/workflows/selfdrive_tests.yaml
  2. 3
      .gitignore
  3. 4
      .pre-commit-config.yaml
  4. 10
      Jenkinsfile
  5. 13
      RELEASES.md
  6. 2
      SConstruct
  7. 2
      cereal
  8. 4
      common/realtime.py
  9. 2
      common/transformations/tests/test_coordinates.py
  10. 2
      common/transformations/tests/test_orientation.py
  11. 5
      docs/CARS.md
  12. 4
      docs/c_docs.rst
  13. 2
      panda
  14. 4
      poetry.lock
  15. 9
      pyproject.toml
  16. 8
      release/build_devel.sh
  17. 8
      release/build_release.sh
  18. 7
      release/release_files.py
  19. 2
      selfdrive/SConscript
  20. 3
      selfdrive/boardd/.gitignore
  21. 4
      selfdrive/car/card.py
  22. 2
      selfdrive/car/chrysler/fingerprints.py
  23. 2
      selfdrive/car/ecu_addrs.py
  24. 1
      selfdrive/car/ford/tests/test_ford.py
  25. 2
      selfdrive/car/fw_query_definitions.py
  26. 4
      selfdrive/car/fw_versions.py
  27. 1
      selfdrive/car/gm/tests/test_gm.py
  28. 251
      selfdrive/car/honda/fingerprints.py
  29. 1
      selfdrive/car/honda/tests/test_honda.py
  30. 2
      selfdrive/car/honda/values.py
  31. 12
      selfdrive/car/hyundai/fingerprints.py
  32. 1
      selfdrive/car/hyundai/tests/test_hyundai.py
  33. 6
      selfdrive/car/hyundai/values.py
  34. 64
      selfdrive/car/interfaces.py
  35. 2
      selfdrive/car/isotp_parallel_query.py
  36. 2
      selfdrive/car/subaru/fingerprints.py
  37. 1
      selfdrive/car/tests/test_can_fingerprint.py
  38. 1
      selfdrive/car/tests/test_car_interfaces.py
  39. 1
      selfdrive/car/tests/test_docs.py
  40. 1
      selfdrive/car/tests/test_fingerprints.py
  41. 1
      selfdrive/car/tests/test_fw_fingerprint.py
  42. 34
      selfdrive/car/tests/test_lateral_limits.py
  43. 1
      selfdrive/car/tests/test_models.py
  44. 2
      selfdrive/car/tests/test_platform_configs.py
  45. 2
      selfdrive/car/torque_data/override.toml
  46. 2
      selfdrive/car/torque_data/params.toml
  47. 1
      selfdrive/car/toyota/fingerprints.py
  48. 1
      selfdrive/car/toyota/tests/test_toyota.py
  49. 1
      selfdrive/car/volkswagen/tests/test_volkswagen.py
  50. 3
      selfdrive/car/volkswagen/values.py
  51. 2
      selfdrive/controls/controlsd.py
  52. 6
      selfdrive/controls/lib/events.py
  53. 12
      selfdrive/controls/lib/longcontrol.py
  54. 6
      selfdrive/controls/lib/longitudinal_planner.py
  55. 1
      selfdrive/controls/lib/tests/test_alertmanager.py
  56. 1
      selfdrive/controls/lib/tests/test_latcontrol.py
  57. 1
      selfdrive/controls/lib/tests/test_vehicle_model.py
  58. 1
      selfdrive/controls/tests/test_alerts.py
  59. 1
      selfdrive/controls/tests/test_cruise_speed.py
  60. 1
      selfdrive/controls/tests/test_following_distance.py
  61. 1
      selfdrive/controls/tests/test_leads.py
  62. 4
      selfdrive/controls/tests/test_startup.py
  63. 2
      selfdrive/controls/tests/test_state_machine.py
  64. 6
      selfdrive/debug/clear_dtc.py
  65. 6
      selfdrive/debug/cpu_usage_stat.py
  66. 14
      selfdrive/debug/debug_fw_fingerprinting_offline.py
  67. 2
      selfdrive/debug/get_fingerprint.py
  68. 6
      selfdrive/debug/hyundai_enable_radar_points.py
  69. 6
      selfdrive/debug/read_dtc_status.py
  70. 1
      selfdrive/locationd/test/test_calibrationd.py
  71. 1
      selfdrive/locationd/test/test_locationd.py
  72. 1
      selfdrive/locationd/test/test_locationd_scenarios.py
  73. 18
      selfdrive/modeld/models/commonmodel.cc
  74. 9
      selfdrive/modeld/models/commonmodel.h
  75. 1
      selfdrive/modeld/tests/test_modeld.py
  76. 1
      selfdrive/monitoring/test_monitoring.py
  77. 1
      selfdrive/navd/tests/test_map_renderer.py
  78. 1
      selfdrive/navd/tests/test_navd.py
  79. 3
      selfdrive/pandad/.gitignore
  80. 6
      selfdrive/pandad/SConscript
  81. 2
      selfdrive/pandad/__init__.py
  82. 2
      selfdrive/pandad/can_list_to_can_capnp.cc
  83. 8
      selfdrive/pandad/main.cc
  84. 4
      selfdrive/pandad/panda.cc
  85. 2
      selfdrive/pandad/panda.h
  86. 2
      selfdrive/pandad/panda_comms.cc
  87. 10
      selfdrive/pandad/panda_comms.h
  88. 18
      selfdrive/pandad/pandad.cc
  89. 4
      selfdrive/pandad/pandad.h
  90. 10
      selfdrive/pandad/pandad.py
  91. 0
      selfdrive/pandad/pandad_api_impl.pyx
  92. 37
      selfdrive/pandad/spi.cc
  93. 0
      selfdrive/pandad/tests/__init__.py
  94. 0
      selfdrive/pandad/tests/bootstub.panda.bin
  95. 0
      selfdrive/pandad/tests/bootstub.panda_h7.bin
  96. 0
      selfdrive/pandad/tests/bootstub.panda_h7_spiv0.bin
  97. 5
      selfdrive/pandad/tests/test_pandad.py
  98. 15
      selfdrive/pandad/tests/test_pandad_loopback.py
  99. 54
      selfdrive/pandad/tests/test_pandad_spi.py
  100. 2
      selfdrive/pandad/tests/test_pandad_usbprotocol.cc
  101. Some files were not shown because too many files have changed in this diff Show More

@ -116,6 +116,8 @@ jobs:
submodules: true submodules: true
- uses: ./.github/workflows/setup-pre-commit - uses: ./.github/workflows/setup-pre-commit
- uses: ./.github/workflows/setup-with-retry - uses: ./.github/workflows/setup-with-retry
- name: Build openpilot
run: ${{ env.RUN }} "scons -j$(nproc)"
- name: pre-commit - name: pre-commit
timeout-minutes: 4 timeout-minutes: 4
run: ${{ env.RUN }} "unset PYTHONWARNINGS && pre-commit run --all && chmod -R 777 /tmp/pre-commit" run: ${{ env.RUN }} "unset PYTHONWARNINGS && pre-commit run --all && chmod -R 777 /tmp/pre-commit"
@ -143,7 +145,7 @@ jobs:
$PYTEST --timeout 60 -m 'not slow' && \ $PYTEST --timeout 60 -m 'not slow' && \
./selfdrive/ui/tests/create_test_translations.sh && \ ./selfdrive/ui/tests/create_test_translations.sh && \
QT_QPA_PLATFORM=offscreen ./selfdrive/ui/tests/test_translations && \ QT_QPA_PLATFORM=offscreen ./selfdrive/ui/tests/test_translations && \
./selfdrive/ui/tests/test_translations.py" pytest ./selfdrive/ui/tests/test_translations.py"
- name: "Upload coverage to Codecov" - name: "Upload coverage to Codecov"
uses: codecov/codecov-action@v4 uses: codecov/codecov-action@v4
with: with:

3
.gitignore vendored

@ -40,8 +40,7 @@ compile_commands.json
compare_runtime*.html compare_runtime*.html
persist persist
board/obj/ selfdrive/pandad/pandad
selfdrive/boardd/boardd
selfdrive/logcatd/logcatd selfdrive/logcatd/logcatd
selfdrive/mapd/default_speeds_by_region.json selfdrive/mapd/default_speeds_by_region.json
system/proclogd/proclogd system/proclogd/proclogd

@ -86,8 +86,8 @@ repos:
hooks: hooks:
- id: test_translations - id: test_translations
name: test translations name: test translations
entry: selfdrive/ui/tests/test_translations.py entry: pytest selfdrive/ui/tests/test_translations.py
language: script language: system
pass_filenames: false pass_filenames: false
files: '^selfdrive/ui/translations/' files: '^selfdrive/ui/translations/'
- repo: https://github.com/python-poetry/poetry - repo: https://github.com/python-poetry/poetry

10
Jenkinsfile vendored

@ -192,7 +192,7 @@ node {
'HW + Unit Tests': { 'HW + Unit Tests': {
deviceStage("tici-hardware", "tici-common", ["UNSAFE=1"], [ deviceStage("tici-hardware", "tici-common", ["UNSAFE=1"], [
["build", "cd system/manager && ./build.py"], ["build", "cd system/manager && ./build.py"],
["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py"], ["test pandad", "pytest selfdrive/pandad/tests/test_pandad.py"],
["test power draw", "pytest -s system/hardware/tici/tests/test_power_draw.py"], ["test power draw", "pytest -s system/hardware/tici/tests/test_power_draw.py"],
["test encoder", "LD_LIBRARY_PATH=/usr/local/lib pytest system/loggerd/tests/test_encoder.py"], ["test encoder", "LD_LIBRARY_PATH=/usr/local/lib pytest system/loggerd/tests/test_encoder.py"],
["test pigeond", "pytest system/ubloxd/tests/test_pigeond.py"], ["test pigeond", "pytest system/ubloxd/tests/test_pigeond.py"],
@ -202,7 +202,7 @@ node {
'loopback': { 'loopback': {
deviceStage("loopback", "tici-loopback", ["UNSAFE=1"], [ deviceStage("loopback", "tici-loopback", ["UNSAFE=1"], [
["build openpilot", "cd system/manager && ./build.py"], ["build openpilot", "cd system/manager && ./build.py"],
["test boardd loopback", "pytest selfdrive/boardd/tests/test_boardd_loopback.py"], ["test pandad loopback", "pytest selfdrive/pandad/tests/test_pandad_loopback.py"],
]) ])
}, },
'camerad': { 'camerad': {
@ -236,9 +236,9 @@ node {
'tizi': { 'tizi': {
deviceStage("tizi", "tizi", ["UNSAFE=1"], [ deviceStage("tizi", "tizi", ["UNSAFE=1"], [
["build openpilot", "cd system/manager && ./build.py"], ["build openpilot", "cd system/manager && ./build.py"],
["test boardd loopback", "SINGLE_PANDA=1 pytest selfdrive/boardd/tests/test_boardd_loopback.py"], ["test pandad loopback", "SINGLE_PANDA=1 pytest selfdrive/pandad/tests/test_pandad_loopback.py"],
["test boardd spi", "pytest selfdrive/boardd/tests/test_boardd_spi.py"], ["test pandad spi", "pytest selfdrive/pandad/tests/test_pandad_spi.py"],
["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py"], ["test pandad", "pytest selfdrive/pandad/tests/test_pandad.py"],
["test amp", "pytest 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 hw", "pytest system/hardware/tici/tests/test_hardware.py"],
["test qcomgpsd", "pytest system/qcomgpsd/tests/test_qcomgpsd.py"], ["test qcomgpsd", "pytest system/qcomgpsd/tests/test_qcomgpsd.py"],

@ -1,9 +1,12 @@
Version 0.9.7 (2024-05-XX) Version 0.9.7 (2024-06-11)
======================== ========================
* New driving model * New driving model
* Inputs the past curvature for smoother and more accurate lateral control
* Simplified neural network architecture in the model's last layers
* Minor fixes to desire augmentation and weight decay
* Adjust driving personality with the follow distance button * Adjust driving personality with the follow distance button
* Support for hybrid variants of supported Ford models
* Added toggle to enable driver monitoring even when openpilot is not engaged * Added toggle to enable driver monitoring even when openpilot is not engaged
* Support for hybrid variants of supported Ford models
* Fingerprinting without the OBD-II port on all cars * Fingerprinting without the OBD-II port on all cars
Version 0.9.6 (2024-02-27) Version 0.9.6 (2024-02-27)
@ -634,7 +637,7 @@ Version 0.5.13 (2019-05-31)
* Reduce CPU utilization by 20% and improve stability * Reduce CPU utilization by 20% and improve stability
* Temporarily remove mapd functionalities to improve stability * Temporarily remove mapd functionalities to improve stability
* Add openpilot record-only mode for unsupported cars * Add openpilot record-only mode for unsupported cars
* Synchronize controlsd to boardd to reduce latency * Synchronize controlsd to pandad to reduce latency
* Remove panda support for Subaru giraffe * Remove panda support for Subaru giraffe
Version 0.5.12 (2019-05-16) Version 0.5.12 (2019-05-16)
@ -970,7 +973,7 @@ Version 0.2.8 (2017-02-27)
Version 0.2.7 (2017-02-08) Version 0.2.7 (2017-02-08)
=========================== ===========================
* Better performance and pictures at night * Better performance and pictures at night
* Fix ptr alignment issue in boardd * Fix ptr alignment issue in pandad
* Fix brake error light, fix crash if too cold * Fix brake error light, fix crash if too cold
Version 0.2.6 (2017-01-31) Version 0.2.6 (2017-01-31)
@ -1002,7 +1005,7 @@ Version 0.2.2 (2017-01-10)
Version 0.2.1 (2016-12-14) Version 0.2.1 (2016-12-14)
=========================== ===========================
* Performance improvements, removal of more numpy * Performance improvements, removal of more numpy
* Fix boardd process priority * Fix pandad process priority
* Make counter timer reset on use of steering wheel * Make counter timer reset on use of steering wheel
Version 0.2 (2016-12-12) Version 0.2 (2016-12-12)

@ -226,7 +226,7 @@ env = Environment(
"#cereal", "#cereal",
"#third_party", "#third_party",
"#opendbc/can", "#opendbc/can",
"#selfdrive/boardd", "#selfdrive/pandad",
"#common", "#common",
"#rednose/helpers", "#rednose/helpers",
], ],

@ -1 +1 @@
Subproject commit 51cbf6294efb356347b2c18b3df9904d11a7ff43 Subproject commit d0ceac712f531c125923cbdc4ec7bedbdc5a7baf

@ -12,7 +12,7 @@ from openpilot.system.hardware import PC
# time step for each process # time step for each process
DT_CTRL = 0.01 # controlsd DT_CTRL = 0.01 # controlsd
DT_MDL = 0.05 # model DT_MDL = 0.05 # model
DT_TRML = 0.5 # thermald and manager DT_HW = 0.5 # hardwared and manager
DT_DMON = 0.05 # driver monitoring DT_DMON = 0.05 # driver monitoring
@ -23,7 +23,7 @@ class Priority:
CTRL_LOW = 51 # plannerd & radard CTRL_LOW = 51 # plannerd & radard
# CORE 3 # CORE 3
# - boardd = 55 # - pandad = 55
CTRL_HIGH = 53 CTRL_HIGH = 53

@ -1,5 +1,3 @@
#!/usr/bin/env python3
import numpy as np import numpy as np
import openpilot.common.transformations.coordinates as coord import openpilot.common.transformations.coordinates as coord

@ -1,5 +1,3 @@
#!/usr/bin/env python3
import numpy as np import numpy as np
from openpilot.common.transformations.orientation import euler2quat, quat2euler, euler2rot, rot2euler, \ from openpilot.common.transformations.orientation import euler2quat, quat2euler, euler2rot, rot2euler, \

@ -4,7 +4,7 @@
A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified. A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified.
# 287 Supported Cars # 288 Supported Cars
|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|<a href="##"><img width=2000></a>Hardware Needed<br>&nbsp;|Video| |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|<a href="##"><img width=2000></a>Hardware Needed<br>&nbsp;|Video|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
@ -93,7 +93,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (Southeast Asia only) 2022-23">Buy Here</a></sub></details>|| |Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (Southeast Asia only) 2022-23">Buy Here</a></sub></details>||
|Hyundai|Ioniq 5 (with HDA II) 2022-23[<sup>5</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (with HDA II) 2022-23">Buy Here</a></sub></details>|| |Hyundai|Ioniq 5 (with HDA II) 2022-23[<sup>5</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (with HDA II) 2022-23">Buy Here</a></sub></details>||
|Hyundai|Ioniq 5 (without HDA II) 2022-23[<sup>5</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (without HDA II) 2022-23">Buy Here</a></sub></details>|| |Hyundai|Ioniq 5 (without HDA II) 2022-23[<sup>5</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (without HDA II) 2022-23">Buy Here</a></sub></details>||
|Hyundai|Ioniq 6 (with HDA II) 2023[<sup>5</sup>](#footnotes)|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 6 (with HDA II) 2023">Buy Here</a></sub></details>|| |Hyundai|Ioniq 6 (with HDA II) 2023-24[<sup>5</sup>](#footnotes)|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 6 (with HDA II) 2023-24">Buy Here</a></sub></details>||
|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Electric 2019">Buy Here</a></sub></details>|| |Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Electric 2019">Buy Here</a></sub></details>||
|Hyundai|Ioniq Electric 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Electric 2020">Buy Here</a></sub></details>|| |Hyundai|Ioniq Electric 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Electric 2020">Buy Here</a></sub></details>||
|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Hybrid 2017-19">Buy Here</a></sub></details>|| |Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Hybrid 2017-19">Buy Here</a></sub></details>||
@ -263,6 +263,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon eHybrid 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon eHybrid 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Arteon R 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon R 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>| |Volkswagen|Arteon R 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon R 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Arteon Shooting Brake 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon Shooting Brake 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Atlas 2018-23">Buy Here</a></sub></details>|| |Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Atlas 2018-23">Buy Here</a></sub></details>||
|Volkswagen|Atlas Cross Sport 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Atlas Cross Sport 2020-22">Buy Here</a></sub></details>|| |Volkswagen|Atlas Cross Sport 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Atlas Cross Sport 2020-22">Buy Here</a></sub></details>||
|Volkswagen|California 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=California 2021-23">Buy Here</a></sub></details>|| |Volkswagen|California 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=California 2021-23">Buy Here</a></sub></details>||

@ -77,10 +77,10 @@ sensorsd
.. autodoxygenindex:: .. autodoxygenindex::
:project: system_sensord_sensors :project: system_sensord_sensors
boardd pandad
^^^^^^ ^^^^^^
.. autodoxygenindex:: .. autodoxygenindex::
:project: selfdrive_boardd :project: selfdrive_pandad
rednose rednose

@ -1 +1 @@
Subproject commit d37d25e0575f9f76d3ab0aaded832646ddc6459d Subproject commit faa18026692f7714ee537261fe649dafe4882579

4
poetry.lock generated

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:0e15c700ef7dd958815caaec9f2747c560fe1a77990275354bdfe2ff3ac38457 oid sha256:84ac396fe236ffaf09f9a865fa3bae19ac961db726bdc19b79e52c2f45db6abe
size 613262 size 618064

@ -20,7 +20,7 @@ markers = [
] ]
testpaths = [ testpaths = [
"common", "common",
"selfdrive/boardd", "selfdrive/pandad",
"selfdrive/car", "selfdrive/car",
"selfdrive/controls", "selfdrive/controls",
"selfdrive/locationd", "selfdrive/locationd",
@ -29,10 +29,9 @@ testpaths = [
"selfdrive/test/longitudinal_maneuvers", "selfdrive/test/longitudinal_maneuvers",
"selfdrive/test/process_replay/test_fuzzy.py", "selfdrive/test/process_replay/test_fuzzy.py",
"system/updated", "system/updated",
"system/thermald",
"system/athena", "system/athena",
"system/camerad", "system/camerad",
"system/hardware/tici", "system/hardware",
"system/loggerd", "system/loggerd",
"system/proclogd", "system/proclogd",
"system/tests", "system/tests",
@ -140,7 +139,8 @@ inputs = "*"
Jinja2 = "*" Jinja2 = "*"
lru-dict = "*" lru-dict = "*"
matplotlib = "*" matplotlib = "*"
metadrive-simulator = { version = "0.4.2.3", markers = "platform_machine != 'aarch64'" } # no linux/aarch64 wheels for certain dependencies # No release for this fix https://github.com/metadriverse/metadrive/issues/632. Pinned to this commit until next release
metadrive-simulator = {git = "https://github.com/metadriverse/metadrive.git", rev ="233a3a1698be7038ec3dd050ca10b547b4b3324c", markers = "platform_machine != 'aarch64'" } # no linux/aarch64 wheels for certain dependencies
mpld3 = "*" mpld3 = "*"
mypy = "*" mypy = "*"
myst-parser = "*" myst-parser = "*"
@ -164,6 +164,7 @@ pytest-timeout = "*"
pytest-randomly = "*" pytest-randomly = "*"
pytest-asyncio = "*" pytest-asyncio = "*"
pytest-mock = "*" pytest-mock = "*"
pytest-repeat = "*"
rerun-sdk = "*" rerun-sdk = "*"
ruff = "*" ruff = "*"
sphinx = "*" sphinx = "*"

@ -48,7 +48,6 @@ cp -pR --parents $(./release/release_files.py) $TARGET_DIR/
# in the directory # in the directory
cd $TARGET_DIR cd $TARGET_DIR
rm -f panda/board/obj/panda.bin.signed rm -f panda/board/obj/panda.bin.signed
git submodule status
# include source commit hash and build date in commit # include source commit hash and build date in commit
GIT_HASH=$(git --git-dir=$SOURCE_DIR/.git rev-parse HEAD) GIT_HASH=$(git --git-dir=$SOURCE_DIR/.git rev-parse HEAD)
@ -64,6 +63,13 @@ date: $DATETIME
master commit: $GIT_HASH master commit: $GIT_HASH
" "
# should be no submodules or LFS files
git submodule status
if [ ! -z "$(git lfs ls-files)" ]; then
echo "LFS files detected!"
exit 1
fi
# ensure files are within GitHub's limit # ensure files are within GitHub's limit
BIG_FILES="$(find . -type f -not -path './.git/*' -size +95M)" BIG_FILES="$(find . -type f -not -path './.git/*' -size +95M)"
if [ ! -z "$BIG_FILES" ]; then if [ ! -z "$BIG_FILES" ]; then

@ -1,4 +1,6 @@
#!/usr/bin/bash -e #!/usr/bin/bash
set -e
set -x
# git diff --name-status origin/release3-staging | grep "^A" | less # git diff --name-status origin/release3-staging | grep "^A" | less
@ -29,7 +31,7 @@ git checkout --orphan $RELEASE_BRANCH
# do the files copy # do the files copy
echo "[-] copying files T=$SECONDS" echo "[-] copying files T=$SECONDS"
cd $SOURCE_DIR cd $SOURCE_DIR
cp -pR --parents $(./release/release_files.py) $TARGET_DIR/ cp -pR --parents $(./release/release_files.py) $BUILD_DIR/
# in the directory # in the directory
cd $BUILD_DIR cd $BUILD_DIR
@ -46,7 +48,7 @@ git commit -a -m "openpilot v$VERSION release"
# Build # Build
export PYTHONPATH="$BUILD_DIR" export PYTHONPATH="$BUILD_DIR"
scons -j$(nproc) scons -j$(nproc) --minimal
# release panda fw # release panda fw
CERT=/data/pandaextra/certs/release RELEASE=1 scons -j$(nproc) panda/ CERT=/data/pandaextra/certs/release RELEASE=1 scons -j$(nproc) panda/

@ -27,11 +27,16 @@ blacklist = [
".devcontainer/", ".devcontainer/",
"Darwin/", "Darwin/",
".vscode", ".vscode",
# no LFS
".lfsconfig",
".gitattributes",
] ]
# gets you through the blacklist # gets you through the blacklist
whitelist = [ whitelist = [
"tools/lib/", "tools/lib/",
"tools/bodyteleop/",
"tinygrad_repo/openpilot/compile2.py", "tinygrad_repo/openpilot/compile2.py",
"tinygrad_repo/extra/onnx.py", "tinygrad_repo/extra/onnx.py",
@ -50,7 +55,7 @@ whitelist = [
"tinygrad_repo/tinygrad/runtime/ops_disk.py", "tinygrad_repo/tinygrad/runtime/ops_disk.py",
"tinygrad_repo/tinygrad/runtime/ops_gpu.py", "tinygrad_repo/tinygrad/runtime/ops_gpu.py",
"tinygrad_repo/tinygrad/shape/*", "tinygrad_repo/tinygrad/shape/*",
"tinygrad_repo/tinygrad/*.py", "tinygrad_repo/tinygrad/.*.py",
] ]
if __name__ == "__main__": if __name__ == "__main__":

@ -1,4 +1,4 @@
SConscript(['boardd/SConscript']) SConscript(['pandad/SConscript'])
SConscript(['controls/lib/lateral_mpc_lib/SConscript']) SConscript(['controls/lib/lateral_mpc_lib/SConscript'])
SConscript(['controls/lib/longitudinal_mpc_lib/SConscript']) SConscript(['controls/lib/longitudinal_mpc_lib/SConscript'])
SConscript(['locationd/SConscript']) SConscript(['locationd/SConscript'])

@ -1,3 +0,0 @@
boardd
boardd_api_impl.cpp
tests/test_boardd_usbprotocol

@ -11,7 +11,7 @@ from panda import ALTERNATIVE_EXPERIENCE
from openpilot.common.params import Params from openpilot.common.params import Params
from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper, DT_CTRL from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper, DT_CTRL
from openpilot.selfdrive.boardd.boardd import can_list_to_can_capnp from openpilot.selfdrive.pandad import can_list_to_can_capnp
from openpilot.selfdrive.car.car_helpers import get_car, get_one_can from openpilot.selfdrive.car.car_helpers import get_car, get_one_can
from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.interfaces import CarInterfaceBase
from openpilot.selfdrive.controls.lib.events import Events from openpilot.selfdrive.controls.lib.events import Events
@ -153,7 +153,7 @@ class Car:
# Initialize CarInterface, once controls are ready # Initialize CarInterface, once controls are ready
# TODO: this can make us miss at least a few cycles when doing an ECU knockout # TODO: this can make us miss at least a few cycles when doing an ECU knockout
self.CI.init(self.CP, self.can_sock, self.pm.sock['sendcan']) self.CI.init(self.CP, self.can_sock, self.pm.sock['sendcan'])
# signal boardd to switch to car safety mode # signal pandad to switch to car safety mode
self.params.put_bool_nonblocking("ControlsReady", True) self.params.put_bool_nonblocking("ControlsReady", True)
if self.sm.all_alive(['carControl']): if self.sm.all_alive(['carControl']):

@ -557,6 +557,7 @@ FW_VERSIONS = {
b'68467936AC ', b'68467936AC ',
b'68500630AD', b'68500630AD',
b'68500630AE', b'68500630AE',
b'68500631AE',
b'68502719AC ', b'68502719AC ',
b'68502722AC ', b'68502722AC ',
b'68502733AC ', b'68502733AC ',
@ -603,6 +604,7 @@ FW_VERSIONS = {
b'68484467AC', b'68484467AC',
b'68484471AC', b'68484471AC',
b'68502994AD', b'68502994AD',
b'68502996AD',
b'68520867AE', b'68520867AE',
b'68520867AF', b'68520867AF',
b'68520870AC', b'68520870AC',

@ -6,7 +6,7 @@ import cereal.messaging as messaging
from panda.python.uds import SERVICE_TYPE from panda.python.uds import SERVICE_TYPE
from openpilot.selfdrive.car import make_can_msg from openpilot.selfdrive.car import make_can_msg
from openpilot.selfdrive.car.fw_query_definitions import EcuAddrBusType from openpilot.selfdrive.car.fw_query_definitions import EcuAddrBusType
from openpilot.selfdrive.boardd.boardd import can_list_to_can_capnp from openpilot.selfdrive.pandad import can_list_to_can_capnp
from openpilot.common.swaglog import cloudlog from openpilot.common.swaglog import cloudlog

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import random import random
from collections.abc import Iterable from collections.abc import Iterable

@ -85,7 +85,7 @@ class Request:
auxiliary: bool = False auxiliary: bool = False
# FW responses from these queries will not be used for fingerprinting # FW responses from these queries will not be used for fingerprinting
logging: bool = False logging: bool = False
# boardd toggles OBD multiplexing on/off as needed # pandad toggles OBD multiplexing on/off as needed
obd_multiplexing: bool = True obd_multiplexing: bool = True

@ -352,7 +352,7 @@ if __name__ == "__main__":
pandaStates_sock = messaging.sub_sock('pandaStates') pandaStates_sock = messaging.sub_sock('pandaStates')
sendcan = messaging.pub_sock('sendcan') sendcan = messaging.pub_sock('sendcan')
# Set up params for boardd # Set up params for pandad
params = Params() params = Params()
params.remove("FirmwareQueryDone") params.remove("FirmwareQueryDone")
params.put_bool("IsOnroad", False) params.put_bool("IsOnroad", False)
@ -374,7 +374,7 @@ if __name__ == "__main__":
t = time.time() t = time.time()
print("Getting vin...") print("Getting vin...")
set_obd_multiplexing(params, True) set_obd_multiplexing(params, True)
vin_rx_addr, vin_rx_bus, vin = get_vin(logcan, sendcan, (0, 1), retry=10, debug=args.debug) vin_rx_addr, vin_rx_bus, vin = get_vin(logcan, sendcan, (0, 1), debug=args.debug)
print(f'RX: {hex(vin_rx_addr)}, BUS: {vin_rx_bus}, VIN: {vin}') print(f'RX: {hex(vin_rx_addr)}, BUS: {vin_rx_bus}, VIN: {vin}')
print(f"Getting VIN took {time.time() - t:.3f} s") print(f"Getting VIN took {time.time() - t:.3f} s")
print() print()

@ -1,4 +1,3 @@
#!/usr/bin/env python3
from parameterized import parameterized from parameterized import parameterized
from openpilot.selfdrive.car.gm.fingerprints import FINGERPRINTS from openpilot.selfdrive.car.gm.fingerprints import FINGERPRINTS

@ -11,43 +11,6 @@ Ecu = car.CarParams.Ecu
FW_VERSIONS = { FW_VERSIONS = {
CAR.HONDA_ACCORD: { CAR.HONDA_ACCORD: {
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-6A0-8720\x00\x00',
b'37805-6A0-9520\x00\x00',
b'37805-6A0-9620\x00\x00',
b'37805-6A0-9720\x00\x00',
b'37805-6A0-A540\x00\x00',
b'37805-6A0-A550\x00\x00',
b'37805-6A0-A640\x00\x00',
b'37805-6A0-A650\x00\x00',
b'37805-6A0-A740\x00\x00',
b'37805-6A0-A750\x00\x00',
b'37805-6A0-A840\x00\x00',
b'37805-6A0-A850\x00\x00',
b'37805-6A0-A930\x00\x00',
b'37805-6A0-AF30\x00\x00',
b'37805-6A0-AG30\x00\x00',
b'37805-6A0-AJ10\x00\x00',
b'37805-6A0-C540\x00\x00',
b'37805-6A0-CG20\x00\x00',
b'37805-6A1-H650\x00\x00',
b'37805-6B2-A550\x00\x00',
b'37805-6B2-A560\x00\x00',
b'37805-6B2-A650\x00\x00',
b'37805-6B2-A660\x00\x00',
b'37805-6B2-A720\x00\x00',
b'37805-6B2-A810\x00\x00',
b'37805-6B2-A820\x00\x00',
b'37805-6B2-A920\x00\x00',
b'37805-6B2-A960\x00\x00',
b'37805-6B2-AA10\x00\x00',
b'37805-6B2-C520\x00\x00',
b'37805-6B2-C540\x00\x00',
b'37805-6B2-C560\x00\x00',
b'37805-6B2-M520\x00\x00',
b'37805-6B2-Y810\x00\x00',
b'37805-6M4-B730\x00\x00',
],
(Ecu.shiftByWire, 0x18da0bf1, None): [ (Ecu.shiftByWire, 0x18da0bf1, None): [
b'54008-TVC-A910\x00\x00', b'54008-TVC-A910\x00\x00',
b'54008-TWA-A910\x00\x00', b'54008-TWA-A910\x00\x00',
@ -161,38 +124,6 @@ FW_VERSIONS = {
], ],
}, },
CAR.HONDA_CIVIC: { CAR.HONDA_CIVIC: {
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-5AA-A640\x00\x00',
b'37805-5AA-A650\x00\x00',
b'37805-5AA-A670\x00\x00',
b'37805-5AA-A680\x00\x00',
b'37805-5AA-A810\x00\x00',
b'37805-5AA-C640\x00\x00',
b'37805-5AA-C680\x00\x00',
b'37805-5AA-C820\x00\x00',
b'37805-5AA-L650\x00\x00',
b'37805-5AA-L660\x00\x00',
b'37805-5AA-L680\x00\x00',
b'37805-5AA-L690\x00\x00',
b'37805-5AA-L810\x00\x00',
b'37805-5AG-Q710\x00\x00',
b'37805-5AJ-A610\x00\x00',
b'37805-5AJ-A620\x00\x00',
b'37805-5AJ-L610\x00\x00',
b'37805-5BA-A310\x00\x00',
b'37805-5BA-A510\x00\x00',
b'37805-5BA-A740\x00\x00',
b'37805-5BA-A760\x00\x00',
b'37805-5BA-A930\x00\x00',
b'37805-5BA-A960\x00\x00',
b'37805-5BA-C640\x00\x00',
b'37805-5BA-C860\x00\x00',
b'37805-5BA-L410\x00\x00',
b'37805-5BA-L760\x00\x00',
b'37805-5BA-L930\x00\x00',
b'37805-5BA-L940\x00\x00',
b'37805-5BA-L960\x00\x00',
],
(Ecu.transmission, 0x18da1ef1, None): [ (Ecu.transmission, 0x18da1ef1, None): [
b'28101-5CG-A040\x00\x00', b'28101-5CG-A040\x00\x00',
b'28101-5CG-A050\x00\x00', b'28101-5CG-A050\x00\x00',
@ -242,61 +173,6 @@ FW_VERSIONS = {
], ],
}, },
CAR.HONDA_CIVIC_BOSCH: { CAR.HONDA_CIVIC_BOSCH: {
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-5AA-A940\x00\x00',
b'37805-5AA-A950\x00\x00',
b'37805-5AA-C950\x00\x00',
b'37805-5AA-L940\x00\x00',
b'37805-5AA-L950\x00\x00',
b'37805-5AG-Z910\x00\x00',
b'37805-5AJ-A750\x00\x00',
b'37805-5AJ-L750\x00\x00',
b'37805-5AK-T530\x00\x00',
b'37805-5AN-A750\x00\x00',
b'37805-5AN-A830\x00\x00',
b'37805-5AN-A840\x00\x00',
b'37805-5AN-A930\x00\x00',
b'37805-5AN-A940\x00\x00',
b'37805-5AN-A950\x00\x00',
b'37805-5AN-AG20\x00\x00',
b'37805-5AN-AH20\x00\x00',
b'37805-5AN-AJ30\x00\x00',
b'37805-5AN-AK10\x00\x00',
b'37805-5AN-AK20\x00\x00',
b'37805-5AN-AR10\x00\x00',
b'37805-5AN-AR20\x00\x00',
b'37805-5AN-C650\x00\x00',
b'37805-5AN-CH20\x00\x00',
b'37805-5AN-E630\x00\x00',
b'37805-5AN-E720\x00\x00',
b'37805-5AN-E820\x00\x00',
b'37805-5AN-J820\x00\x00',
b'37805-5AN-L840\x00\x00',
b'37805-5AN-L930\x00\x00',
b'37805-5AN-L940\x00\x00',
b'37805-5AN-LF20\x00\x00',
b'37805-5AN-LH20\x00\x00',
b'37805-5AN-LJ20\x00\x00',
b'37805-5AN-LR20\x00\x00',
b'37805-5AN-LS20\x00\x00',
b'37805-5AW-G720\x00\x00',
b'37805-5AZ-E850\x00\x00',
b'37805-5AZ-G540\x00\x00',
b'37805-5AZ-G740\x00\x00',
b'37805-5AZ-G840\x00\x00',
b'37805-5BB-A530\x00\x00',
b'37805-5BB-A540\x00\x00',
b'37805-5BB-A620\x00\x00',
b'37805-5BB-A630\x00\x00',
b'37805-5BB-A640\x00\x00',
b'37805-5BB-C540\x00\x00',
b'37805-5BB-C630\x00\x00',
b'37805-5BB-C640\x00\x00',
b'37805-5BB-L540\x00\x00',
b'37805-5BB-L630\x00\x00',
b'37805-5BB-L640\x00\x00',
b'37805-5BF-J130\x00\x00',
],
(Ecu.transmission, 0x18da1ef1, None): [ (Ecu.transmission, 0x18da1ef1, None): [
b'28101-5CG-A920\x00\x00', b'28101-5CG-A920\x00\x00',
b'28101-5CG-AB10\x00\x00', b'28101-5CG-AB10\x00\x00',
@ -400,10 +276,6 @@ FW_VERSIONS = {
], ],
}, },
CAR.HONDA_CIVIC_BOSCH_DIESEL: { CAR.HONDA_CIVIC_BOSCH_DIESEL: {
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-59N-G630\x00\x00',
b'37805-59N-G830\x00\x00',
],
(Ecu.transmission, 0x18da1ef1, None): [ (Ecu.transmission, 0x18da1ef1, None): [
b'28101-59Y-G220\x00\x00', b'28101-59Y-G220\x00\x00',
b'28101-59Y-G620\x00\x00', b'28101-59Y-G620\x00\x00',
@ -449,41 +321,6 @@ FW_VERSIONS = {
], ],
}, },
CAR.HONDA_CRV_5G: { CAR.HONDA_CRV_5G: {
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-5PA-3060\x00\x00',
b'37805-5PA-3080\x00\x00',
b'37805-5PA-3180\x00\x00',
b'37805-5PA-4050\x00\x00',
b'37805-5PA-4150\x00\x00',
b'37805-5PA-6520\x00\x00',
b'37805-5PA-6530\x00\x00',
b'37805-5PA-6630\x00\x00',
b'37805-5PA-6640\x00\x00',
b'37805-5PA-7630\x00\x00',
b'37805-5PA-9530\x00\x00',
b'37805-5PA-9630\x00\x00',
b'37805-5PA-9640\x00\x00',
b'37805-5PA-9730\x00\x00',
b'37805-5PA-9830\x00\x00',
b'37805-5PA-9840\x00\x00',
b'37805-5PA-A650\x00\x00',
b'37805-5PA-A670\x00\x00',
b'37805-5PA-A680\x00\x00',
b'37805-5PA-A850\x00\x00',
b'37805-5PA-A870\x00\x00',
b'37805-5PA-A880\x00\x00',
b'37805-5PA-A890\x00\x00',
b'37805-5PA-AB10\x00\x00',
b'37805-5PA-AD10\x00\x00',
b'37805-5PA-AF20\x00\x00',
b'37805-5PA-AF30\x00\x00',
b'37805-5PA-AH20\x00\x00',
b'37805-5PA-BF10\x00\x00',
b'37805-5PA-C680\x00\x00',
b'37805-5PD-Q630\x00\x00',
b'37805-5PF-F730\x00\x00',
b'37805-5PF-M630\x00\x00',
],
(Ecu.transmission, 0x18da1ef1, None): [ (Ecu.transmission, 0x18da1ef1, None): [
b'28101-5RG-A020\x00\x00', b'28101-5RG-A020\x00\x00',
b'28101-5RG-A030\x00\x00', b'28101-5RG-A030\x00\x00',
@ -559,10 +396,6 @@ FW_VERSIONS = {
], ],
}, },
CAR.HONDA_CRV_EU: { CAR.HONDA_CRV_EU: {
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-R5Z-G740\x00\x00',
b'37805-R5Z-G780\x00\x00',
],
(Ecu.vsa, 0x18da28f1, None): [ (Ecu.vsa, 0x18da28f1, None): [
b'57114-T1V-G920\x00\x00', b'57114-T1V-G920\x00\x00',
], ],
@ -663,24 +496,6 @@ FW_VERSIONS = {
b'38897-THR-A010\x00\x00', b'38897-THR-A010\x00\x00',
b'38897-THR-A020\x00\x00', b'38897-THR-A020\x00\x00',
], ],
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-5MR-3050\x00\x00',
b'37805-5MR-3150\x00\x00',
b'37805-5MR-3250\x00\x00',
b'37805-5MR-4070\x00\x00',
b'37805-5MR-4080\x00\x00',
b'37805-5MR-4170\x00\x00',
b'37805-5MR-4180\x00\x00',
b'37805-5MR-A240\x00\x00',
b'37805-5MR-A250\x00\x00',
b'37805-5MR-A310\x00\x00',
b'37805-5MR-A740\x00\x00',
b'37805-5MR-A750\x00\x00',
b'37805-5MR-A840\x00\x00',
b'37805-5MR-C620\x00\x00',
b'37805-5MR-D530\x00\x00',
b'37805-5MR-K730\x00\x00',
],
(Ecu.eps, 0x18da30f1, None): [ (Ecu.eps, 0x18da30f1, None): [
b'39990-THR-A020\x00\x00', b'39990-THR-A020\x00\x00',
b'39990-THR-A030\x00\x00', b'39990-THR-A030\x00\x00',
@ -765,39 +580,6 @@ FW_VERSIONS = {
b'28101-5EZ-A700\x00\x00', b'28101-5EZ-A700\x00\x00',
b'28103-5EY-A110\x00\x00', b'28103-5EY-A110\x00\x00',
], ],
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-RLV-4060\x00\x00',
b'37805-RLV-4070\x00\x00',
b'37805-RLV-5140\x00\x00',
b'37805-RLV-5230\x00\x00',
b'37805-RLV-5250\x00\x00',
b'37805-RLV-A630\x00\x00',
b'37805-RLV-A830\x00\x00',
b'37805-RLV-A840\x00\x00',
b'37805-RLV-B210\x00\x00',
b'37805-RLV-B220\x00\x00',
b'37805-RLV-B420\x00\x00',
b'37805-RLV-B430\x00\x00',
b'37805-RLV-B620\x00\x00',
b'37805-RLV-B710\x00\x00',
b'37805-RLV-B720\x00\x00',
b'37805-RLV-C430\x00\x00',
b'37805-RLV-C510\x00\x00',
b'37805-RLV-C520\x00\x00',
b'37805-RLV-C530\x00\x00',
b'37805-RLV-C910\x00\x00',
b'37805-RLV-F120\x00\x00',
b'37805-RLV-L080\x00\x00',
b'37805-RLV-L090\x00\x00',
b'37805-RLV-L150\x00\x00',
b'37805-RLV-L160\x00\x00',
b'37805-RLV-L180\x00\x00',
b'37805-RLV-L350\x00\x00',
b'37805-RLV-L410\x00\x00',
b'37805-RLV-L430\x00\x00',
b'37805-RLV-L830\x00\x00',
b'37805-RLV-L850\x00\x00',
],
(Ecu.gateway, 0x18daeff1, None): [ (Ecu.gateway, 0x18daeff1, None): [
b'38897-TG7-A030\x00\x00', b'38897-TG7-A030\x00\x00',
b'38897-TG7-A040\x00\x00', b'38897-TG7-A040\x00\x00',
@ -875,26 +657,6 @@ FW_VERSIONS = {
], ],
}, },
CAR.ACURA_RDX_3G: { CAR.ACURA_RDX_3G: {
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-5YF-A130\x00\x00',
b'37805-5YF-A230\x00\x00',
b'37805-5YF-A320\x00\x00',
b'37805-5YF-A330\x00\x00',
b'37805-5YF-A420\x00\x00',
b'37805-5YF-A430\x00\x00',
b'37805-5YF-A750\x00\x00',
b'37805-5YF-A760\x00\x00',
b'37805-5YF-A770\x00\x00',
b'37805-5YF-A850\x00\x00',
b'37805-5YF-A860\x00\x00',
b'37805-5YF-A870\x00\x00',
b'37805-5YF-AD20\x00\x00',
b'37805-5YF-C210\x00\x00',
b'37805-5YF-C220\x00\x00',
b'37805-5YF-C410\x00\x00',
b'37805-5YF-C420\x00\x00',
b'37805-5YF-C430\x00\x00',
],
(Ecu.vsa, 0x18da28f1, None): [ (Ecu.vsa, 0x18da28f1, None): [
b'57114-TJB-A030\x00\x00', b'57114-TJB-A030\x00\x00',
b'57114-TJB-A040\x00\x00', b'57114-TJB-A040\x00\x00',
@ -1049,10 +811,6 @@ FW_VERSIONS = {
b'28101-6EH-A010\x00\x00', b'28101-6EH-A010\x00\x00',
b'28101-6JC-M310\x00\x00', b'28101-6JC-M310\x00\x00',
], ],
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-6CT-A710\x00\x00',
b'37805-6HZ-M630\x00\x00',
],
(Ecu.electricBrakeBooster, 0x18da2bf1, None): [ (Ecu.electricBrakeBooster, 0x18da2bf1, None): [
b'46114-3W0-A020\x00\x00', b'46114-3W0-A020\x00\x00',
], ],
@ -1133,14 +891,5 @@ FW_VERSIONS = {
b'28101-65H-A120\x00\x00', b'28101-65H-A120\x00\x00',
b'28101-65J-N010\x00\x00', b'28101-65J-N010\x00\x00',
], ],
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-64A-A540\x00\x00',
b'37805-64A-A620\x00\x00',
b'37805-64D-P510\x00\x00',
b'37805-64L-A540\x00\x00',
b'37805-64S-A540\x00\x00',
b'37805-64S-A720\x00\x00',
b'37805-64S-AA10\x00\x00',
],
}, },
} }

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import re import re
from openpilot.selfdrive.car.honda.fingerprints import FW_VERSIONS from openpilot.selfdrive.car.honda.fingerprints import FW_VERSIONS

@ -299,6 +299,7 @@ FW_QUERY_CONFIG = FwQueryConfig(
], ],
# We lose these ECUs without the comma power on these cars. # We lose these ECUs without the comma power on these cars.
# Note that we still attempt to match with them when they are present # Note that we still attempt to match with them when they are present
# This is or'd with (ALL_ECUS - ESSENTIAL_ECUS) from fw_versions.py
non_essential_ecus={ non_essential_ecus={
Ecu.eps: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_CIVIC_2022, CAR.HONDA_E, CAR.HONDA_HRV_3G], Ecu.eps: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_CIVIC_2022, CAR.HONDA_E, CAR.HONDA_HRV_3G],
Ecu.vsa: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_CIVIC, CAR.HONDA_CIVIC_BOSCH, CAR.HONDA_CIVIC_2022, CAR.HONDA_CRV_5G, CAR.HONDA_CRV_HYBRID, Ecu.vsa: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_CIVIC, CAR.HONDA_CIVIC_BOSCH, CAR.HONDA_CIVIC_2022, CAR.HONDA_CRV_5G, CAR.HONDA_CRV_HYBRID,
@ -306,6 +307,7 @@ FW_QUERY_CONFIG = FwQueryConfig(
}, },
extra_ecus=[ extra_ecus=[
(Ecu.combinationMeter, 0x18da60f1, None), (Ecu.combinationMeter, 0x18da60f1, None),
(Ecu.programmedFuelInjection, 0x18da10f1, None),
# The only other ECU on PT bus accessible by camera on radarless Civic # The only other ECU on PT bus accessible by camera on radarless Civic
# This is likely a manufacturer-specific sub-address implementation: the camera responds to this and 0x18dab0f1 # This is likely a manufacturer-specific sub-address implementation: the camera responds to this and 0x18dab0f1
# Unclear what the part number refers to: 8S103 is 'Camera Set Mono', while 36160 is 'Camera Monocular - Honda' # Unclear what the part number refers to: 8S103 is 'Camera Set Mono', while 36160 is 'Camera Monocular - Honda'

@ -23,9 +23,6 @@ FINGERPRINTS = {
CAR.GENESIS_G90: [{ CAR.GENESIS_G90: [{
67: 8, 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 358: 6, 359: 8, 544: 8, 593: 8, 608: 8, 688: 5, 809: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1162: 4, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1265: 4, 1280: 1, 1281: 3, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1370: 8, 1371: 8, 1378: 4, 1384: 8, 1407: 8, 1419: 8, 1425: 2, 1427: 6, 1434: 2, 1456: 4, 1470: 8, 1988: 8, 2000: 8, 2003: 8, 2004: 8, 2005: 8, 2008: 8, 2011: 8, 2012: 8, 2013: 8 67: 8, 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 358: 6, 359: 8, 544: 8, 593: 8, 608: 8, 688: 5, 809: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1162: 4, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1265: 4, 1280: 1, 1281: 3, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1370: 8, 1371: 8, 1378: 4, 1384: 8, 1407: 8, 1419: 8, 1425: 2, 1427: 6, 1434: 2, 1456: 4, 1470: 8, 1988: 8, 2000: 8, 2003: 8, 2004: 8, 2005: 8, 2008: 8, 2011: 8, 2012: 8, 2013: 8
}], }],
CAR.HYUNDAI_IONIQ_EV_2020: [{
127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 524: 8, 544: 7, 593: 8, 688: 5, 832: 8, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 8, 1151: 6, 1155: 8, 1156: 8, 1157: 4, 1164: 8, 1168: 7, 1173: 8, 1183: 8, 1186: 2, 1191: 2, 1225: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1379: 8, 1407: 8, 1419: 8, 1426: 8, 1427: 6, 1429: 8, 1430: 8, 1456: 4, 1470: 8, 1473: 8, 1507: 8, 1535: 8, 1988: 8, 1996: 8, 2000: 8, 2004: 8, 2005: 8, 2008: 8, 2012: 8, 2013: 8
}],
CAR.HYUNDAI_KONA_EV: [{ CAR.HYUNDAI_KONA_EV: [{
127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 544: 8, 549: 8, 593: 8, 688: 5, 832: 8, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 8, 1151: 6, 1168: 7, 1173: 8, 1183: 8, 1186: 2, 1191: 2, 1225: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1307: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1378: 4, 1407: 8, 1419: 8, 1426: 8, 1427: 6, 1429: 8, 1430: 8, 1456: 4, 1470: 8, 1473: 8, 1507: 8, 1535: 8, 2000: 8, 2004: 8, 2008: 8, 2012: 8, 1157: 4, 1193: 8, 1379: 8, 1988: 8, 1996: 8 127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 544: 8, 549: 8, 593: 8, 688: 5, 832: 8, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 8, 1151: 6, 1168: 7, 1173: 8, 1183: 8, 1186: 2, 1191: 2, 1225: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1307: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1378: 4, 1407: 8, 1419: 8, 1426: 8, 1427: 6, 1429: 8, 1430: 8, 1456: 4, 1470: 8, 1473: 8, 1507: 8, 1535: 8, 2000: 8, 2004: 8, 2008: 8, 2012: 8, 1157: 4, 1193: 8, 1379: 8, 1988: 8, 1996: 8
}], }],
@ -135,9 +132,12 @@ FW_VERSIONS = {
b'\xf1\x00AEev SCC F-CUP 1.00 1.00 99110-G7200 ', b'\xf1\x00AEev SCC F-CUP 1.00 1.00 99110-G7200 ',
b'\xf1\x00AEev SCC F-CUP 1.00 1.00 99110-G7500 ', b'\xf1\x00AEev SCC F-CUP 1.00 1.00 99110-G7500 ',
b'\xf1\x00AEev SCC F-CUP 1.00 1.01 99110-G7000 ', b'\xf1\x00AEev SCC F-CUP 1.00 1.01 99110-G7000 ',
b'\xf1\x00AEev SCC F-CUP 1.00 1.01 99110-G7100 ',
b'\xf1\x00AEev SCC FHCUP 1.00 1.01 99110-G7100 ',
], ],
(Ecu.eps, 0x7d4, None): [ (Ecu.eps, 0x7d4, None): [
b'\xf1\x00AE MDPS C 1.00 1.01 56310/G7310 4APEC101', b'\xf1\x00AE MDPS C 1.00 1.01 56310/G7310 4APEC101',
b'\xf1\x00AE MDPS C 1.00 1.01 56310/G7510 4APEC101',
b'\xf1\x00AE MDPS C 1.00 1.01 56310/G7560 4APEC101', b'\xf1\x00AE MDPS C 1.00 1.01 56310/G7560 4APEC101',
], ],
(Ecu.fwdCamera, 0x7c4, None): [ (Ecu.fwdCamera, 0x7c4, None): [
@ -146,6 +146,7 @@ FW_VERSIONS = {
b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.01 95740-G2600 190819', b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.01 95740-G2600 190819',
b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.03 95740-G2500 190516', b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.03 95740-G2500 190516',
b'\xf1\x00AEE MFC AT EUR RHD 1.00 1.01 95740-G2600 190819', b'\xf1\x00AEE MFC AT EUR RHD 1.00 1.01 95740-G2600 190819',
b'\xf1\x00AEE MFC AT USA LHD 1.00 1.01 95740-G2600 190819',
], ],
}, },
CAR.HYUNDAI_IONIQ_EV_LTD: { CAR.HYUNDAI_IONIQ_EV_LTD: {
@ -749,6 +750,7 @@ FW_VERSIONS = {
], ],
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00DEhe SCC F-CUP 1.00 1.00 99110-G5600 ', b'\xf1\x00DEhe SCC F-CUP 1.00 1.00 99110-G5600 ',
b'\xf1\x00DEhe SCC FHCUP 1.00 1.00 99110-G5600 ',
], ],
}, },
CAR.KIA_NIRO_HEV_2021: { CAR.KIA_NIRO_HEV_2021: {
@ -877,6 +879,7 @@ FW_VERSIONS = {
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.03 99210-AA000 200819', b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.03 99210-AA000 200819',
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.03 99210-AB000 220426', b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.03 99210-AB000 220426',
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.06 99210-AA000 220111', b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.06 99210-AA000 220111',
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.07 99210-AA000 220426',
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.08 99210-AA000 220728', b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.08 99210-AA000 220728',
], ],
(Ecu.abs, 0x7d1, None): [ (Ecu.abs, 0x7d1, None): [
@ -1001,6 +1004,7 @@ FW_VERSIONS = {
(Ecu.fwdCamera, 0x7c4, None): [ (Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00CE MFC AT CAN LHD 1.00 1.04 99211-KL000 221213', b'\xf1\x00CE MFC AT CAN LHD 1.00 1.04 99211-KL000 221213',
b'\xf1\x00CE MFC AT EUR LHD 1.00 1.03 99211-KL000 221011', b'\xf1\x00CE MFC AT EUR LHD 1.00 1.03 99211-KL000 221011',
b'\xf1\x00CE MFC AT EUR LHD 1.00 1.04 99211-KL000 221213',
b'\xf1\x00CE MFC AT USA LHD 1.00 1.04 99211-KL000 221213', b'\xf1\x00CE MFC AT USA LHD 1.00 1.04 99211-KL000 221213',
], ],
}, },
@ -1039,10 +1043,10 @@ FW_VERSIONS = {
CAR.KIA_SPORTAGE_5TH_GEN: { CAR.KIA_SPORTAGE_5TH_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [ (Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00NQ5 FR_CMR AT AUS RHD 1.00 1.00 99211-P1040 663', b'\xf1\x00NQ5 FR_CMR AT AUS RHD 1.00 1.00 99211-P1040 663',
b'\xf1\x00NQ5 FR_CMR AT EUR LHD 1.00 1.00 99211-P1040 663',
b'\xf1\x00NQ5 FR_CMR AT GEN LHD 1.00 1.00 99211-P1060 665', b'\xf1\x00NQ5 FR_CMR AT GEN LHD 1.00 1.00 99211-P1060 665',
b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1030 662', b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1030 662',
b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1040 663', b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1040 663',
b'\xf1\x00NQ5 FR_CMR AT EUR LHD 1.00 1.00 99211-P1040 663',
b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1060 665', b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1060 665',
b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1070 690', b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1070 690',
], ],

@ -1,4 +1,3 @@
#!/usr/bin/env python3
from hypothesis import settings, given, strategies as st from hypothesis import settings, given, strategies as st
import pytest import pytest

@ -314,7 +314,7 @@ class CAR(Platforms):
flags=HyundaiFlags.EV, flags=HyundaiFlags.EV,
) )
HYUNDAI_IONIQ_6 = HyundaiCanFDPlatformConfig( HYUNDAI_IONIQ_6 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Ioniq 6 (with HDA II) 2023", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p]))], [HyundaiCarDocs("Hyundai Ioniq 6 (with HDA II) 2023-24", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p]))],
HYUNDAI_IONIQ_5.specs, HYUNDAI_IONIQ_5.specs,
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_NO_RADAR_DISABLE, flags=HyundaiFlags.EV | HyundaiFlags.CANFD_NO_RADAR_DISABLE,
) )
@ -515,7 +515,7 @@ class CAR(Platforms):
# TODO: From 3.3T Sport Advanced 2022 & Prestige 2023 Trim, 2.0T is unknown # TODO: From 3.3T Sport Advanced 2022 & Prestige 2023 Trim, 2.0T is unknown
HyundaiCarDocs("Genesis G70 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_l])), HyundaiCarDocs("Genesis G70 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_l])),
], ],
CarSpecs(mass=3673 * CV.LB_TO_KG, wheelbase=2.83, steerRatio=12.9), GENESIS_G70.specs,
flags=HyundaiFlags.MANDO_RADAR, flags=HyundaiFlags.MANDO_RADAR,
) )
GENESIS_GV70_1ST_GEN = HyundaiCanFDPlatformConfig( GENESIS_GV70_1ST_GEN = HyundaiCanFDPlatformConfig(
@ -648,6 +648,8 @@ PLATFORM_CODE_ECUS = [Ecu.fwdRadar, Ecu.fwdCamera, Ecu.eps]
# TODO: there are date codes in the ABS firmware versions in hex # TODO: there are date codes in the ABS firmware versions in hex
DATE_FW_ECUS = [Ecu.fwdCamera] DATE_FW_ECUS = [Ecu.fwdCamera]
# Note: an ECU on CAN FD cars may sometimes send 0x30080aaaaaaaaaaa (flow control continue) while we
# are attempting to query ECUs. This currently does not seem to affect fingerprinting from the camera
FW_QUERY_CONFIG = FwQueryConfig( FW_QUERY_CONFIG = FwQueryConfig(
requests=[ requests=[
# TODO: add back whitelists # TODO: add back whitelists

@ -6,6 +6,7 @@ from abc import abstractmethod, ABC
from enum import StrEnum from enum import StrEnum
from typing import Any, NamedTuple from typing import Any, NamedTuple
from collections.abc import Callable from collections.abc import Callable
from functools import cache
from cereal import car from cereal import car
from openpilot.common.basedir import BASEDIR from openpilot.common.basedir import BASEDIR
@ -32,6 +33,18 @@ TORQUE_PARAMS_PATH = os.path.join(BASEDIR, 'selfdrive/car/torque_data/params.tom
TORQUE_OVERRIDE_PATH = os.path.join(BASEDIR, 'selfdrive/car/torque_data/override.toml') TORQUE_OVERRIDE_PATH = os.path.join(BASEDIR, 'selfdrive/car/torque_data/override.toml')
TORQUE_SUBSTITUTE_PATH = os.path.join(BASEDIR, 'selfdrive/car/torque_data/substitute.toml') TORQUE_SUBSTITUTE_PATH = os.path.join(BASEDIR, 'selfdrive/car/torque_data/substitute.toml')
GEAR_SHIFTER_MAP: dict[str, car.CarState.GearShifter] = {
'P': GearShifter.park, 'PARK': GearShifter.park,
'R': GearShifter.reverse, 'REVERSE': GearShifter.reverse,
'N': GearShifter.neutral, 'NEUTRAL': GearShifter.neutral,
'E': GearShifter.eco, 'ECO': GearShifter.eco,
'T': GearShifter.manumatic, 'MANUAL': GearShifter.manumatic,
'D': GearShifter.drive, 'DRIVE': GearShifter.drive,
'S': GearShifter.sport, 'SPORT': GearShifter.sport,
'L': GearShifter.low, 'LOW': GearShifter.low,
'B': GearShifter.brake, 'BRAKE': GearShifter.brake,
}
class LatControlInputs(NamedTuple): class LatControlInputs(NamedTuple):
lateral_acceleration: float lateral_acceleration: float
@ -43,29 +56,34 @@ class LatControlInputs(NamedTuple):
TorqueFromLateralAccelCallbackType = Callable[[LatControlInputs, car.CarParams.LateralTorqueTuning, float, float, bool, bool], float] TorqueFromLateralAccelCallbackType = Callable[[LatControlInputs, car.CarParams.LateralTorqueTuning, float, float, bool, bool], float]
def get_torque_params(candidate): @cache
def get_torque_params():
with open(TORQUE_SUBSTITUTE_PATH, 'rb') as f: with open(TORQUE_SUBSTITUTE_PATH, 'rb') as f:
sub = tomllib.load(f) sub = tomllib.load(f)
if candidate in sub:
candidate = sub[candidate]
with open(TORQUE_PARAMS_PATH, 'rb') as f: with open(TORQUE_PARAMS_PATH, 'rb') as f:
params = tomllib.load(f) params = tomllib.load(f)
with open(TORQUE_OVERRIDE_PATH, 'rb') as f: with open(TORQUE_OVERRIDE_PATH, 'rb') as f:
override = tomllib.load(f) override = tomllib.load(f)
# Ensure no overlap torque_params = {}
if sum([candidate in x for x in [sub, params, override]]) > 1: for candidate in (sub.keys() | params.keys() | override.keys()) - {'legend'}:
raise RuntimeError(f'{candidate} is defined twice in torque config') if sum([candidate in x for x in [sub, params, override]]) > 1:
raise RuntimeError(f'{candidate} is defined twice in torque config')
if candidate in override: sub_candidate = sub.get(candidate, candidate)
out = override[candidate]
elif candidate in params:
out = params[candidate]
else:
raise NotImplementedError(f"Did not find torque params for {candidate}")
return {key: out[i] for i, key in enumerate(params['legend'])}
if sub_candidate in override:
out = override[sub_candidate]
elif sub_candidate in params:
out = params[sub_candidate]
else:
raise NotImplementedError(f"Did not find torque params for {sub_candidate}")
torque_params[sub_candidate] = {key: out[i] for i, key in enumerate(params['legend'])}
if candidate in sub:
torque_params[candidate] = torque_params[sub_candidate]
return torque_params
# generic car and radar interfaces # generic car and radar interfaces
@ -166,7 +184,7 @@ class CarInterfaceBase(ABC):
ret.carFingerprint = candidate ret.carFingerprint = candidate
# Car docs fields # Car docs fields
ret.maxLateralAccel = get_torque_params(candidate)['MAX_LAT_ACCEL_MEASURED'] ret.maxLateralAccel = get_torque_params()[candidate]['MAX_LAT_ACCEL_MEASURED']
ret.autoResumeSng = True # describes whether car can resume from a stop automatically ret.autoResumeSng = True # describes whether car can resume from a stop automatically
# standard ALC params # standard ALC params
@ -199,7 +217,7 @@ class CarInterfaceBase(ABC):
@staticmethod @staticmethod
def configure_torque_tune(candidate, tune, steering_angle_deadzone_deg=0.0, use_steering_angle=True): def configure_torque_tune(candidate, tune, steering_angle_deadzone_deg=0.0, use_steering_angle=True):
params = get_torque_params(candidate) params = get_torque_params()[candidate]
tune.init('torque') tune.init('torque')
tune.torque.useSteeringAngle = use_steering_angle tune.torque.useSteeringAngle = use_steering_angle
@ -422,19 +440,7 @@ class CarStateBase(ABC):
def parse_gear_shifter(gear: str | None) -> car.CarState.GearShifter: def parse_gear_shifter(gear: str | None) -> car.CarState.GearShifter:
if gear is None: if gear is None:
return GearShifter.unknown return GearShifter.unknown
return GEAR_SHIFTER_MAP.get(gear.upper(), GearShifter.unknown)
d: dict[str, car.CarState.GearShifter] = {
'P': GearShifter.park, 'PARK': GearShifter.park,
'R': GearShifter.reverse, 'REVERSE': GearShifter.reverse,
'N': GearShifter.neutral, 'NEUTRAL': GearShifter.neutral,
'E': GearShifter.eco, 'ECO': GearShifter.eco,
'T': GearShifter.manumatic, 'MANUAL': GearShifter.manumatic,
'D': GearShifter.drive, 'DRIVE': GearShifter.drive,
'S': GearShifter.sport, 'SPORT': GearShifter.sport,
'L': GearShifter.low, 'LOW': GearShifter.low,
'B': GearShifter.brake, 'BRAKE': GearShifter.brake,
}
return d.get(gear.upper(), GearShifter.unknown)
@staticmethod @staticmethod
def get_can_parser(CP): def get_can_parser(CP):

@ -4,7 +4,7 @@ from functools import partial
import cereal.messaging as messaging import cereal.messaging as messaging
from openpilot.common.swaglog import cloudlog from openpilot.common.swaglog import cloudlog
from openpilot.selfdrive.boardd.boardd import can_list_to_can_capnp from openpilot.selfdrive.pandad import can_list_to_can_capnp
from openpilot.selfdrive.car.fw_query_definitions import AddrType from openpilot.selfdrive.car.fw_query_definitions import AddrType
from panda.python.uds import CanClient, IsoTpMessage, FUNCTIONAL_ADDRS, get_rx_addr_for_tx_addr from panda.python.uds import CanClient, IsoTpMessage, FUNCTIONAL_ADDRS, get_rx_addr_for_tx_addr

@ -311,6 +311,7 @@ FW_VERSIONS = {
b'\x00\x00d\xd3\x1f@ \t', b'\x00\x00d\xd3\x1f@ \t',
], ],
(Ecu.engine, 0x7e0, None): [ (Ecu.engine, 0x7e0, None): [
b'\xa7"@0\x07',
b'\xa7"@p\x07', b'\xa7"@p\x07',
b'\xa7)\xa0q\x07', b'\xa7)\xa0q\x07',
b'\xba"@@\x07', b'\xba"@@\x07',
@ -319,6 +320,7 @@ FW_VERSIONS = {
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
b'\x1a\xf6F`\x00', b'\x1a\xf6F`\x00',
b'\xda\xf2`\x80\x00', b'\xda\xf2`\x80\x00',
b'\xda\xf2`p\x00',
b'\xda\xfd\xe0\x80\x00', b'\xda\xfd\xe0\x80\x00',
b'\xdc\xf2@`\x00', b'\xdc\xf2@`\x00',
b'\xdc\xf2``\x00', b'\xdc\xf2``\x00',

@ -1,4 +1,3 @@
#!/usr/bin/env python3
from parameterized import parameterized from parameterized import parameterized
from cereal import log, messaging from cereal import log, messaging

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import os import os
import math import math
import hypothesis.strategies as st import hypothesis.strategies as st

@ -1,4 +1,3 @@
#!/usr/bin/env python3
from collections import defaultdict from collections import defaultdict
import os import os
import pytest import pytest

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import os import os
import sys import sys

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import pytest import pytest
import random import random
import time import time

@ -3,6 +3,7 @@ from collections import defaultdict
import importlib import importlib
from parameterized import parameterized_class from parameterized import parameterized_class
import pytest import pytest
import sys
from openpilot.common.realtime import DT_CTRL from openpilot.common.realtime import DT_CTRL
from openpilot.selfdrive.car.car_helpers import interfaces from openpilot.selfdrive.car.car_helpers import interfaces
@ -20,8 +21,6 @@ MAX_LAT_JERK_UP_TOLERANCE = 0.5 # m/s^3
# jerk is measured over half a second # jerk is measured over half a second
JERK_MEAS_T = 0.5 JERK_MEAS_T = 0.5
car_model_jerks: defaultdict[str, dict[str, float]] = defaultdict(dict)
@parameterized_class('car_model', [(c,) for c in sorted(CAR_MODELS)]) @parameterized_class('car_model', [(c,) for c in sorted(CAR_MODELS)])
class TestLateralLimits: class TestLateralLimits:
@ -44,7 +43,7 @@ class TestLateralLimits:
CarControllerParams = importlib.import_module(f'selfdrive.car.{CP.carName}.values').CarControllerParams CarControllerParams = importlib.import_module(f'selfdrive.car.{CP.carName}.values').CarControllerParams
cls.control_params = CarControllerParams(CP) cls.control_params = CarControllerParams(CP)
cls.torque_params = get_torque_params(cls.car_model) cls.torque_params = get_torque_params()[cls.car_model]
@staticmethod @staticmethod
def calculate_0_5s_jerk(control_params, torque_params): def calculate_0_5s_jerk(control_params, torque_params):
@ -64,9 +63,36 @@ class TestLateralLimits:
def test_jerk_limits(self): def test_jerk_limits(self):
up_jerk, down_jerk = self.calculate_0_5s_jerk(self.control_params, self.torque_params) up_jerk, down_jerk = self.calculate_0_5s_jerk(self.control_params, self.torque_params)
car_model_jerks[self.car_model] = {"up_jerk": up_jerk, "down_jerk": down_jerk}
assert up_jerk <= MAX_LAT_JERK_UP + MAX_LAT_JERK_UP_TOLERANCE assert up_jerk <= MAX_LAT_JERK_UP + MAX_LAT_JERK_UP_TOLERANCE
assert down_jerk <= MAX_LAT_JERK_DOWN assert down_jerk <= MAX_LAT_JERK_DOWN
def test_max_lateral_accel(self): def test_max_lateral_accel(self):
assert self.torque_params["MAX_LAT_ACCEL_MEASURED"] <= MAX_LAT_ACCEL assert self.torque_params["MAX_LAT_ACCEL_MEASURED"] <= MAX_LAT_ACCEL
class LatAccelReport:
car_model_jerks: defaultdict[str, dict[str, float]] = defaultdict(dict)
def pytest_sessionfinish(self):
print(f"\n\n---- Lateral limit report ({len(CAR_MODELS)} cars) ----\n")
max_car_model_len = max([len(car_model) for car_model in self.car_model_jerks])
for car_model, _jerks in sorted(self.car_model_jerks.items(), key=lambda i: i[1]['up_jerk'], reverse=True):
violation = _jerks["up_jerk"] > MAX_LAT_JERK_UP + MAX_LAT_JERK_UP_TOLERANCE or \
_jerks["down_jerk"] > MAX_LAT_JERK_DOWN
violation_str = " - VIOLATION" if violation else ""
print(f"{car_model:{max_car_model_len}} - up jerk: {round(_jerks['up_jerk'], 2):5} " +
f"m/s^3, down jerk: {round(_jerks['down_jerk'], 2):5} m/s^3{violation_str}")
@pytest.fixture(scope="class", autouse=True)
def class_setup(self, request):
yield
cls = request.cls
if hasattr(cls, "control_params"):
up_jerk, down_jerk = TestLateralLimits.calculate_0_5s_jerk(cls.control_params, cls.torque_params)
self.car_model_jerks[cls.car_model] = {"up_jerk": up_jerk, "down_jerk": down_jerk}
if __name__ == '__main__':
sys.exit(pytest.main([__file__, '-n0', '--no-summary'], plugins=[LatAccelReport()])) # noqa: TID251

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import capnp import capnp
import os import os
import importlib import importlib

@ -1,5 +1,3 @@
#!/usr/bin/env python3
from openpilot.selfdrive.car.values import PLATFORMS from openpilot.selfdrive.car.values import PLATFORMS

@ -61,7 +61,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"GMC_ACADIA" = [1.6, 1.6, 0.2] "GMC_ACADIA" = [1.6, 1.6, 0.2]
"LEXUS_IS_TSS2" = [2.0, 2.0, 0.1] "LEXUS_IS_TSS2" = [2.0, 2.0, 0.1]
"HYUNDAI_KONA_EV_2ND_GEN" = [2.5, 2.5, 0.1] "HYUNDAI_KONA_EV_2ND_GEN" = [2.5, 2.5, 0.1]
"HYUNDAI_IONIQ_6" = [2.5, 2.5, 0.1] "HYUNDAI_IONIQ_6" = [2.5, 2.5, 0.005]
"HYUNDAI_AZERA_6TH_GEN" = [1.8, 1.8, 0.1] "HYUNDAI_AZERA_6TH_GEN" = [1.8, 1.8, 0.1]
"HYUNDAI_AZERA_HEV_6TH_GEN" = [1.8, 1.8, 0.1] "HYUNDAI_AZERA_HEV_6TH_GEN" = [1.8, 1.8, 0.1]
"KIA_K8_HEV_1ST_GEN" = [2.5, 2.5, 0.1] "KIA_K8_HEV_1ST_GEN" = [2.5, 2.5, 0.1]

@ -40,7 +40,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"HYUNDAI_TUCSON_4TH_GEN" = [2.960174, 2.860284, 0.108745] "HYUNDAI_TUCSON_4TH_GEN" = [2.960174, 2.860284, 0.108745]
"JEEP_GRAND_CHEROKEE_2019" = [2.30972, 1.289689569171081, 0.117048] "JEEP_GRAND_CHEROKEE_2019" = [2.30972, 1.289689569171081, 0.117048]
"JEEP_GRAND_CHEROKEE" = [2.27116, 1.4057367824262523, 0.11725947414922003] "JEEP_GRAND_CHEROKEE" = [2.27116, 1.4057367824262523, 0.11725947414922003]
"KIA_EV6" = [3.2, 2.093457, 0.05] "KIA_EV6" = [3.2, 2.093457, 0.005]
"KIA_K5_2021" = [2.405339728085138, 1.460032270828705, 0.11650989850813716] "KIA_K5_2021" = [2.405339728085138, 1.460032270828705, 0.11650989850813716]
"KIA_NIRO_EV" = [2.9215954981365337, 2.1500583840260044, 0.09236802474810267] "KIA_NIRO_EV" = [2.9215954981365337, 2.1500583840260044, 0.09236802474810267]
"KIA_SORENTO" = [2.464854685101844, 1.5335274218367956, 0.12056170567599558] "KIA_SORENTO" = [2.464854685101844, 1.5335274218367956, 0.12056170567599558]

@ -214,6 +214,7 @@ FW_VERSIONS = {
b'8646F0601400 ', b'8646F0601400 ',
b'8646F0603400 ', b'8646F0603400 ',
b'8646F0603500 ', b'8646F0603500 ',
b'8646F0604000 ',
b'8646F0604100 ', b'8646F0604100 ',
b'8646F0605000 ', b'8646F0605000 ',
b'8646F0606000 ', b'8646F0606000 ',

@ -1,4 +1,3 @@
#!/usr/bin/env python3
from hypothesis import given, settings, strategies as st from hypothesis import given, settings, strategies as st
from cereal import car from cereal import car

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import random import random
import re import re

@ -214,10 +214,11 @@ class CAR(Platforms):
VWCarDocs("Volkswagen Arteon 2018-23", video_link="https://youtu.be/FAomFKPFlDA"), VWCarDocs("Volkswagen Arteon 2018-23", video_link="https://youtu.be/FAomFKPFlDA"),
VWCarDocs("Volkswagen Arteon R 2020-23", video_link="https://youtu.be/FAomFKPFlDA"), VWCarDocs("Volkswagen Arteon R 2020-23", video_link="https://youtu.be/FAomFKPFlDA"),
VWCarDocs("Volkswagen Arteon eHybrid 2020-23", video_link="https://youtu.be/FAomFKPFlDA"), VWCarDocs("Volkswagen Arteon eHybrid 2020-23", video_link="https://youtu.be/FAomFKPFlDA"),
VWCarDocs("Volkswagen Arteon Shooting Brake 2020-23", video_link="https://youtu.be/FAomFKPFlDA"),
VWCarDocs("Volkswagen CC 2018-22", video_link="https://youtu.be/FAomFKPFlDA"), VWCarDocs("Volkswagen CC 2018-22", video_link="https://youtu.be/FAomFKPFlDA"),
], ],
VolkswagenCarSpecs(mass=1733, wheelbase=2.84), VolkswagenCarSpecs(mass=1733, wheelbase=2.84),
chassis_codes={"AN"}, chassis_codes={"AN", "3H"},
wmis={WMI.VOLKSWAGEN_EUROPE_CAR}, wmis={WMI.VOLKSWAGEN_EUROPE_CAR},
) )
VOLKSWAGEN_ATLAS_MK1 = VolkswagenMQBPlatformConfig( VOLKSWAGEN_ATLAS_MK1 = VolkswagenMQBPlatformConfig(

@ -279,7 +279,7 @@ class Controls:
else: else:
safety_mismatch = pandaState.safetyModel not in IGNORED_SAFETY_MODES safety_mismatch = pandaState.safetyModel not in IGNORED_SAFETY_MODES
# safety mismatch allows some time for boardd to set the safety mode and publish it back from panda # safety mismatch allows some time for pandad to set the safety mode and publish it back from panda
if (safety_mismatch and self.sm.frame*DT_CTRL > 10.) or pandaState.safetyRxChecksInvalid or self.mismatch_counter >= 200: if (safety_mismatch and self.sm.frame*DT_CTRL > 10.) or pandaState.safetyRxChecksInvalid or self.mismatch_counter >= 200:
self.events.add(EventName.controlsMismatch) self.events.add(EventName.controlsMismatch)

@ -51,7 +51,7 @@ class Events:
def __init__(self): def __init__(self):
self.events: list[int] = [] self.events: list[int] = []
self.static_events: list[int] = [] self.static_events: list[int] = []
self.events_prev = dict.fromkeys(EVENTS.keys(), 0) self.event_counters = dict.fromkeys(EVENTS.keys(), 0)
@property @property
def names(self) -> list[int]: def names(self) -> list[int]:
@ -66,7 +66,7 @@ class Events:
bisect.insort(self.events, event_name) bisect.insort(self.events, event_name)
def clear(self) -> None: def clear(self) -> None:
self.events_prev = {k: (v + 1 if k in self.events else 0) for k, v in self.events_prev.items()} self.event_counters = {k: (v + 1 if k in self.events else 0) for k, v in self.event_counters.items()}
self.events = self.static_events.copy() self.events = self.static_events.copy()
def contains(self, event_type: str) -> bool: def contains(self, event_type: str) -> bool:
@ -85,7 +85,7 @@ class Events:
if not isinstance(alert, Alert): if not isinstance(alert, Alert):
alert = alert(*callback_args) alert = alert(*callback_args)
if DT_CTRL * (self.events_prev[e] + 1) >= alert.creation_delay: if DT_CTRL * (self.event_counters[e] + 1) >= alert.creation_delay:
alert.alert_type = f"{EVENT_NAME[e]}/{et}" alert.alert_type = f"{EVENT_NAME[e]}/{et}"
alert.event_type = et alert.event_type = et
ret.append(alert) ret.append(alert)

@ -5,6 +5,8 @@ from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N, apply_dead
from openpilot.selfdrive.controls.lib.pid import PIDController from openpilot.selfdrive.controls.lib.pid import PIDController
from openpilot.selfdrive.modeld.constants import ModelConstants from openpilot.selfdrive.modeld.constants import ModelConstants
CONTROL_N_T_IDX = ModelConstants.T_IDXS[:CONTROL_N]
LongCtrlState = car.CarControl.Actuators.LongControlState LongCtrlState = car.CarControl.Actuators.LongControlState
@ -68,19 +70,19 @@ class LongControl:
# Interp control trajectory # Interp control trajectory
speeds = long_plan.speeds speeds = long_plan.speeds
if len(speeds) == CONTROL_N: if len(speeds) == CONTROL_N:
v_target_now = interp(t_since_plan, ModelConstants.T_IDXS[:CONTROL_N], speeds) v_target_now = interp(t_since_plan, CONTROL_N_T_IDX, speeds)
a_target_now = interp(t_since_plan, ModelConstants.T_IDXS[:CONTROL_N], long_plan.accels) a_target_now = interp(t_since_plan, CONTROL_N_T_IDX, long_plan.accels)
v_target_lower = interp(self.CP.longitudinalActuatorDelayLowerBound + t_since_plan, ModelConstants.T_IDXS[:CONTROL_N], speeds) v_target_lower = interp(self.CP.longitudinalActuatorDelayLowerBound + t_since_plan, CONTROL_N_T_IDX, speeds)
a_target_lower = 2 * (v_target_lower - v_target_now) / self.CP.longitudinalActuatorDelayLowerBound - a_target_now a_target_lower = 2 * (v_target_lower - v_target_now) / self.CP.longitudinalActuatorDelayLowerBound - a_target_now
v_target_upper = interp(self.CP.longitudinalActuatorDelayUpperBound + t_since_plan, ModelConstants.T_IDXS[:CONTROL_N], speeds) v_target_upper = interp(self.CP.longitudinalActuatorDelayUpperBound + t_since_plan, CONTROL_N_T_IDX, speeds)
a_target_upper = 2 * (v_target_upper - v_target_now) / self.CP.longitudinalActuatorDelayUpperBound - a_target_now a_target_upper = 2 * (v_target_upper - v_target_now) / self.CP.longitudinalActuatorDelayUpperBound - a_target_now
v_target = min(v_target_lower, v_target_upper) v_target = min(v_target_lower, v_target_upper)
a_target = min(a_target_lower, a_target_upper) a_target = min(a_target_lower, a_target_upper)
v_target_1sec = interp(self.CP.longitudinalActuatorDelayUpperBound + t_since_plan + 1.0, ModelConstants.T_IDXS[:CONTROL_N], speeds) v_target_1sec = interp(self.CP.longitudinalActuatorDelayUpperBound + t_since_plan + 1.0, CONTROL_N_T_IDX, speeds)
else: else:
v_target = 0.0 v_target = 0.0
v_target_now = 0.0 v_target_now = 0.0

@ -62,9 +62,9 @@ class LongitudinalPlanner:
@staticmethod @staticmethod
def parse_model(model_msg, model_error): def parse_model(model_msg, model_error):
if (len(model_msg.position.x) == 33 and if (len(model_msg.position.x) == ModelConstants.IDX_N and
len(model_msg.velocity.x) == 33 and len(model_msg.velocity.x) == ModelConstants.IDX_N and
len(model_msg.acceleration.x) == 33): len(model_msg.acceleration.x) == ModelConstants.IDX_N):
x = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.position.x) - model_error * T_IDXS_MPC x = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.position.x) - model_error * T_IDXS_MPC
v = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.velocity.x) - model_error v = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.velocity.x) - model_error
a = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.acceleration.x) a = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.acceleration.x)

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import random import random
from openpilot.selfdrive.controls.lib.events import Alert, EVENTS from openpilot.selfdrive.controls.lib.events import Alert, EVENTS

@ -1,4 +1,3 @@
#!/usr/bin/env python3
from parameterized import parameterized from parameterized import parameterized
from cereal import car, log from cereal import car, log

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import pytest import pytest
import math import math

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import copy import copy
import json import json
import os import os

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import pytest import pytest
import itertools import itertools
import numpy as np import numpy as np

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import pytest import pytest
import itertools import itertools
from parameterized import parameterized_class from parameterized import parameterized_class

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import cereal.messaging as messaging import cereal.messaging as messaging
from openpilot.selfdrive.test.process_replay import replay_process_with_name from openpilot.selfdrive.test.process_replay import replay_process_with_name

@ -4,7 +4,7 @@ from parameterized import parameterized
from cereal import log, car from cereal import log, car
import cereal.messaging as messaging import cereal.messaging as messaging
from openpilot.common.params import Params from openpilot.common.params import Params
from openpilot.selfdrive.boardd.boardd_api_impl import can_list_to_can_capnp from openpilot.selfdrive.pandad.pandad_api_impl import can_list_to_can_capnp
from openpilot.selfdrive.car.fingerprints import _FINGERPRINTS from openpilot.selfdrive.car.fingerprints import _FINGERPRINTS
from openpilot.selfdrive.car.toyota.values import CAR as TOYOTA from openpilot.selfdrive.car.toyota.values import CAR as TOYOTA
from openpilot.selfdrive.car.mazda.values import CAR as MAZDA from openpilot.selfdrive.car.mazda.values import CAR as MAZDA
@ -105,7 +105,7 @@ def test_startup_alert(expected_event, car_model, fw_versions, brand):
msgs = [[addr, 0, b'\x00'*length, 0] for addr, length in finger.items()] msgs = [[addr, 0, b'\x00'*length, 0] for addr, length in finger.items()]
for _ in range(1000): for _ in range(1000):
# card waits for boardd to echo back that it has changed the multiplexing mode # card waits for pandad to echo back that it has changed the multiplexing mode
if not params.get_bool("ObdMultiplexingChanged"): if not params.get_bool("ObdMultiplexingChanged"):
params.put_bool("ObdMultiplexingChanged", True) params.put_bool("ObdMultiplexingChanged", True)

@ -1,5 +1,3 @@
#!/usr/bin/env python3
from cereal import car, log from cereal import car, log
from openpilot.common.realtime import DT_CTRL from openpilot.common.realtime import DT_CTRL
from openpilot.selfdrive.car.car_helpers import interfaces from openpilot.selfdrive.car.car_helpers import interfaces

@ -12,11 +12,11 @@ parser.add_argument('--debug', action='store_true')
args = parser.parse_args() args = parser.parse_args()
try: try:
check_output(["pidof", "boardd"]) check_output(["pidof", "pandad"])
print("boardd is running, please kill openpilot before running this script! (aborted)") print("pandad is running, please kill openpilot before running this script! (aborted)")
sys.exit(1) sys.exit(1)
except CalledProcessError as e: except CalledProcessError as e:
if e.returncode != 1: # 1 == no process found (boardd not running) if e.returncode != 1: # 1 == no process found (pandad not running)
raise e raise e
panda = Panda() panda = Panda()

@ -9,10 +9,10 @@ System tools like top/htop can only show current cpu usage values, so I write th
Calculate minumium/maximum/accumulated_average cpu usage as long term inspections. Calculate minumium/maximum/accumulated_average cpu usage as long term inspections.
Monitor multiple processes simuteneously. Monitor multiple processes simuteneously.
Sample usage: Sample usage:
root@localhost:/data/openpilot$ python selfdrive/debug/cpu_usage_stat.py boardd,ubloxd root@localhost:/data/openpilot$ python selfdrive/debug/cpu_usage_stat.py pandad,ubloxd
('Add monitored proc:', './boardd') ('Add monitored proc:', './pandad')
('Add monitored proc:', 'python locationd/ubloxd.py') ('Add monitored proc:', 'python locationd/ubloxd.py')
boardd: 1.96%, min: 1.96%, max: 1.96%, acc: 1.96% pandad: 1.96%, min: 1.96%, max: 1.96%, acc: 1.96%
ubloxd.py: 0.39%, min: 0.39%, max: 0.39%, acc: 0.39% ubloxd.py: 0.39%, min: 0.39%, max: 0.39%, acc: 0.39%
''' '''
import psutil import psutil

@ -1,11 +1,12 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import argparse import argparse
from openpilot.tools.lib.live_logreader import live_logreader
from openpilot.tools.lib.logreader import LogReader, ReadMode from openpilot.tools.lib.logreader import LogReader, ReadMode
from panda.python import uds from panda.python import uds
def main(route: str, addrs: list[int]): def main(route: str | None, addrs: list[int]):
""" """
TODO: TODO:
- highlight TX vs RX clearly - highlight TX vs RX clearly
@ -13,7 +14,10 @@ def main(route: str, addrs: list[int]):
- print as fixed width table, easier to read - print as fixed width table, easier to read
""" """
lr = LogReader(route, default_mode=ReadMode.RLOG, sort_by_time=True) if route is None:
lr = live_logreader()
else:
lr = LogReader(route, default_mode=ReadMode.RLOG, sort_by_time=True)
start_mono_time = None start_mono_time = None
prev_mono_time = 0 prev_mono_time = 0
@ -28,7 +32,7 @@ def main(route: str, addrs: list[int]):
if msg.which() in ("can", 'sendcan'): if msg.which() in ("can", 'sendcan'):
for can in getattr(msg, msg.which()): for can in getattr(msg, msg.which()):
if can.address in addrs: if can.address in addrs or not len(addrs):
if msg.logMonoTime != prev_mono_time: if msg.logMonoTime != prev_mono_time:
print() print()
prev_mono_time = msg.logMonoTime prev_mono_time = msg.logMonoTime
@ -38,8 +42,8 @@ def main(route: str, addrs: list[int]):
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser(description='View back and forth ISO-TP communication between various ECUs given an address') parser = argparse.ArgumentParser(description='View back and forth ISO-TP communication between various ECUs given an address')
parser.add_argument('route', help='Route name') parser.add_argument('route', nargs='?', help='Route name, live if not specified')
parser.add_argument('addrs', nargs='*', help='List of tx address to view (0x7e0 for engine)') parser.add_argument('--addrs', nargs='*', default=[], help='List of tx address to view (0x7e0 for engine)')
args = parser.parse_args() args = parser.parse_args()
addrs = [int(addr, base=16) if addr.startswith('0x') else int(addr) for addr in args.addrs] addrs = [int(addr, base=16) if addr.startswith('0x') else int(addr) for addr in args.addrs]

@ -4,7 +4,7 @@
# Instructions: # Instructions:
# - connect to a Panda # - connect to a Panda
# - run selfdrive/boardd/boardd # - run selfdrive/pandad/pandad
# - launching this script # - launching this script
# Note: it's very important that the car is in stock mode, in order to collect a complete fingerprint # Note: it's very important that the car is in stock mode, in order to collect a complete fingerprint
# - since some messages are published at low frequency, keep this script running for at least 30s, # - since some messages are published at low frequency, keep this script running for at least 30s,

@ -79,11 +79,11 @@ if __name__ == "__main__":
args = parser.parse_args() args = parser.parse_args()
try: try:
check_output(["pidof", "boardd"]) check_output(["pidof", "pandad"])
print("boardd is running, please kill openpilot before running this script! (aborted)") print("pandad is running, please kill openpilot before running this script! (aborted)")
sys.exit(1) sys.exit(1)
except CalledProcessError as e: except CalledProcessError as e:
if e.returncode != 1: # 1 == no process found (boardd not running) if e.returncode != 1: # 1 == no process found (pandad not running)
raise e raise e
confirm = input("power on the vehicle keeping the engine off (press start button twice) then type OK to continue: ").upper().strip() confirm = input("power on the vehicle keeping the engine off (press start button twice) then type OK to continue: ").upper().strip()

@ -13,11 +13,11 @@ parser.add_argument('--debug', action='store_true')
args = parser.parse_args() args = parser.parse_args()
try: try:
check_output(["pidof", "boardd"]) check_output(["pidof", "pandad"])
print("boardd is running, please kill openpilot before running this script! (aborted)") print("pandad is running, please kill openpilot before running this script! (aborted)")
sys.exit(1) sys.exit(1)
except CalledProcessError as e: except CalledProcessError as e:
if e.returncode != 1: # 1 == no process found (boardd not running) if e.returncode != 1: # 1 == no process found (pandad not running)
raise e raise e
panda = Panda() panda = Panda()

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import random import random
import numpy as np import numpy as np

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import pytest import pytest
import json import json
import random import random

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import pytest import pytest
import numpy as np import numpy as np
from collections import defaultdict from collections import defaultdict

@ -1,13 +1,10 @@
#include "selfdrive/modeld/models/commonmodel.h" #include "selfdrive/modeld/models/commonmodel.h"
#include <algorithm>
#include <cassert> #include <cassert>
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include "common/clutil.h" #include "common/clutil.h"
#include "common/mat.h"
#include "common/timing.h"
ModelFrame::ModelFrame(cl_device_id device_id, cl_context context) { ModelFrame::ModelFrame(cl_device_id device_id, cl_context context) {
input_frames = std::make_unique<float[]>(buf_size); input_frames = std::make_unique<float[]>(buf_size);
@ -52,21 +49,6 @@ ModelFrame::~ModelFrame() {
CL_CHECK(clReleaseCommandQueue(q)); CL_CHECK(clReleaseCommandQueue(q));
} }
void softmax(const float* input, float* output, size_t len) {
const float max_val = *std::max_element(input, input + len);
float denominator = 0;
for (int i = 0; i < len; i++) {
float const v_exp = expf(input[i] - max_val);
denominator += v_exp;
output[i] = v_exp;
}
const float inv_denominator = 1. / denominator;
for (int i = 0; i < len; i++) {
output[i] *= inv_denominator;
}
}
float sigmoid(float input) { float sigmoid(float input) {
return 1 / (1 + expf(-input)); return 1 / (1 + expf(-input));
} }

@ -13,20 +13,11 @@
#endif #endif
#include "common/mat.h" #include "common/mat.h"
#include "cereal/messaging/messaging.h"
#include "selfdrive/modeld/transforms/loadyuv.h" #include "selfdrive/modeld/transforms/loadyuv.h"
#include "selfdrive/modeld/transforms/transform.h" #include "selfdrive/modeld/transforms/transform.h"
const bool send_raw_pred = getenv("SEND_RAW_PRED") != NULL;
void softmax(const float* input, float* output, size_t len);
float sigmoid(float input); float sigmoid(float input);
template<class T, size_t size>
constexpr const kj::ArrayPtr<const T> to_kj_array_ptr(const std::array<T, size> &arr) {
return kj::ArrayPtr(arr.data(), arr.size());
}
class ModelFrame { class ModelFrame {
public: public:
ModelFrame(cl_device_id device_id, cl_context context); ModelFrame(cl_device_id device_id, cl_context context);

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import numpy as np import numpy as np
import random import random

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import numpy as np import numpy as np
from cereal import car, log from cereal import car, log

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import time import time
import numpy as np import numpy as np
import os import os

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import json import json
import random import random
import numpy as np import numpy as np

@ -0,0 +1,3 @@
pandad
pandad_api_impl.cpp
tests/test_pandad_usbprotocol

@ -3,9 +3,9 @@ Import('env', 'envCython', 'common', 'cereal', 'messaging')
libs = ['usb-1.0', common, cereal, messaging, 'pthread', 'zmq', 'capnp', 'kj'] libs = ['usb-1.0', common, cereal, messaging, 'pthread', 'zmq', 'capnp', 'kj']
panda = env.Library('panda', ['panda.cc', 'panda_comms.cc', 'spi.cc']) panda = env.Library('panda', ['panda.cc', 'panda_comms.cc', 'spi.cc'])
env.Program('boardd', ['main.cc', 'boardd.cc'], LIBS=[panda] + libs) env.Program('pandad', ['main.cc', 'pandad.cc'], LIBS=[panda] + libs)
env.Library('libcan_list_to_can_capnp', ['can_list_to_can_capnp.cc']) env.Library('libcan_list_to_can_capnp', ['can_list_to_can_capnp.cc'])
envCython.Program('boardd_api_impl.so', 'boardd_api_impl.pyx', LIBS=["can_list_to_can_capnp", 'capnp', 'kj'] + envCython["LIBS"]) envCython.Program('pandad_api_impl.so', 'pandad_api_impl.pyx', LIBS=["can_list_to_can_capnp", 'capnp', 'kj'] + envCython["LIBS"])
if GetOption('extras'): if GetOption('extras'):
env.Program('tests/test_boardd_usbprotocol', ['tests/test_boardd_usbprotocol.cc'], LIBS=[panda] + libs) env.Program('tests/test_pandad_usbprotocol', ['tests/test_pandad_usbprotocol.cc'], LIBS=[panda] + libs)

@ -1,5 +1,5 @@
# Cython, now uses scons to build # Cython, now uses scons to build
from openpilot.selfdrive.boardd.boardd_api_impl import can_list_to_can_capnp from openpilot.selfdrive.pandad.pandad_api_impl import can_list_to_can_capnp
assert can_list_to_can_capnp assert can_list_to_can_capnp
def can_capnp_to_can_list(can, src_filter=None): def can_capnp_to_can_list(can, src_filter=None):

@ -1,5 +1,5 @@
#include "cereal/messaging/messaging.h" #include "cereal/messaging/messaging.h"
#include "selfdrive/boardd/panda.h" #include "selfdrive/pandad/panda.h"
void can_list_to_can_capnp_cpp(const std::vector<can_frame> &can_list, std::string &out, bool sendCan, bool valid) { void can_list_to_can_capnp_cpp(const std::vector<can_frame> &can_list, std::string &out, bool sendCan, bool valid) {
MessageBuilder msg; MessageBuilder msg;

@ -1,22 +1,22 @@
#include <cassert> #include <cassert>
#include "selfdrive/boardd/boardd.h" #include "selfdrive/pandad/pandad.h"
#include "common/swaglog.h" #include "common/swaglog.h"
#include "common/util.h" #include "common/util.h"
#include "system/hardware/hw.h" #include "system/hardware/hw.h"
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
LOGW("starting boardd"); LOGW("starting pandad");
if (!Hardware::PC()) { if (!Hardware::PC()) {
int err; int err;
err = util::set_realtime_priority(54); err = util::set_realtime_priority(54);
assert(err == 0); assert(err == 0);
err = util::set_core_affinity({4}); err = util::set_core_affinity({3});
assert(err == 0); assert(err == 0);
} }
std::vector<std::string> serials(argv + 1, argv + argc); std::vector<std::string> serials(argv + 1, argv + argc);
boardd_main_thread(serials); pandad_main_thread(serials);
return 0; return 0;
} }

@ -1,4 +1,4 @@
#include "selfdrive/boardd/panda.h" #include "selfdrive/pandad/panda.h"
#include <unistd.h> #include <unistd.h>
@ -246,9 +246,9 @@ bool Panda::unpack_can_buffer(uint8_t *data, uint32_t &size, std::vector<can_fra
} }
if (calculate_checksum(&data[pos], sizeof(can_header) + data_len) != 0) { if (calculate_checksum(&data[pos], sizeof(can_header) + data_len) != 0) {
// TODO: also reset CAN comms?
LOGE("Panda CAN checksum failed"); LOGE("Panda CAN checksum failed");
size = 0; size = 0;
can_reset_communications();
return false; return false;
} }

@ -13,7 +13,7 @@
#include "cereal/gen/cpp/log.capnp.h" #include "cereal/gen/cpp/log.capnp.h"
#include "panda/board/health.h" #include "panda/board/health.h"
#include "panda/board/can_definitions.h" #include "panda/board/can_definitions.h"
#include "selfdrive/boardd/panda_comms.h" #include "selfdrive/pandad/panda_comms.h"
#define USB_TX_SOFT_LIMIT (0x100U) #define USB_TX_SOFT_LIMIT (0x100U)
#define USBPACKET_MAX_SIZE (0x40) #define USBPACKET_MAX_SIZE (0x40)

@ -1,4 +1,4 @@
#include "selfdrive/boardd/panda.h" #include "selfdrive/pandad/panda.h"
#include <cassert> #include <cassert>
#include <stdexcept> #include <stdexcept>

@ -56,6 +56,13 @@ private:
}; };
#ifndef __APPLE__ #ifndef __APPLE__
struct __attribute__((packed)) spi_header {
uint8_t sync;
uint8_t endpoint;
uint16_t tx_len;
uint16_t max_rx_len;
};
class PandaSpiHandle : public PandaCommsHandle { class PandaSpiHandle : public PandaCommsHandle {
public: public:
PandaSpiHandle(std::string serial); PandaSpiHandle(std::string serial);
@ -79,5 +86,8 @@ private:
int spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len, unsigned int timeout); int spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len, unsigned int timeout);
int spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len, unsigned int timeout); int spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len, unsigned int timeout);
int lltransfer(spi_ioc_transfer &t); int lltransfer(spi_ioc_transfer &t);
spi_header header;
uint32_t xfer_count = 0;
}; };
#endif #endif

@ -1,4 +1,4 @@
#include "selfdrive/boardd/boardd.h" #include "selfdrive/pandad/pandad.h"
#include <algorithm> #include <algorithm>
#include <array> #include <array>
@ -25,7 +25,7 @@
// - The internal panda will always be the first panda // - The internal panda will always be the first panda
// - Consecutive pandas will be sorted based on panda type, and then serial number // - Consecutive pandas will be sorted based on panda type, and then serial number
// Connecting: // Connecting:
// - If a panda connection is dropped, boardd will reconnect to all pandas // - If a panda connection is dropped, pandad will reconnect to all pandas
// - If a panda is added, we will only reconnect when we are offroad // - If a panda is added, we will only reconnect when we are offroad
// CAN buses: // CAN buses:
// - Each panda will have it's block of 4 buses. E.g.: the second panda will use // - Each panda will have it's block of 4 buses. E.g.: the second panda will use
@ -163,7 +163,7 @@ Panda *connect(std::string serial="", uint32_t index=0) {
} }
void can_send_thread(std::vector<Panda *> pandas, bool fake_send) { void can_send_thread(std::vector<Panda *> pandas, bool fake_send) {
util::set_thread_name("boardd_can_send"); util::set_thread_name("pandad_can_send");
AlignedBuffer aligned_buf; AlignedBuffer aligned_buf;
std::unique_ptr<Context> context(Context::create()); std::unique_ptr<Context> context(Context::create());
@ -198,12 +198,12 @@ void can_send_thread(std::vector<Panda *> pandas, bool fake_send) {
} }
void can_recv_thread(std::vector<Panda *> pandas) { void can_recv_thread(std::vector<Panda *> pandas) {
util::set_thread_name("boardd_can_recv"); util::set_thread_name("pandad_can_recv");
PubMaster pm({"can"}); PubMaster pm({"can"});
// run at 100Hz // run at 100Hz
RateKeeper rk("boardd_can_recv", 100); RateKeeper rk("pandad_can_recv", 100);
std::vector<can_frame> raw_can_data; std::vector<can_frame> raw_can_data;
while (!do_exit && check_all_connected(pandas)) { while (!do_exit && check_all_connected(pandas)) {
@ -405,7 +405,7 @@ void send_peripheral_state(PubMaster *pm, Panda *panda) {
} }
void panda_state_thread(std::vector<Panda *> pandas, bool spoofing_started) { void panda_state_thread(std::vector<Panda *> pandas, bool spoofing_started) {
util::set_thread_name("boardd_panda_state"); util::set_thread_name("pandad_panda_state");
Params params; Params params;
SubMaster sm({"controlsState"}); SubMaster sm({"controlsState"});
@ -503,7 +503,7 @@ void panda_state_thread(std::vector<Panda *> pandas, bool spoofing_started) {
void peripheral_control_thread(Panda *panda, bool no_fan_control) { void peripheral_control_thread(Panda *panda, bool no_fan_control) {
util::set_thread_name("boardd_peripheral_control"); util::set_thread_name("pandad_peripheral_control");
SubMaster sm({"deviceState", "driverCameraState"}); SubMaster sm({"deviceState", "driverCameraState"});
@ -554,8 +554,8 @@ void peripheral_control_thread(Panda *panda, bool no_fan_control) {
} }
} }
void boardd_main_thread(std::vector<std::string> serials) { void pandad_main_thread(std::vector<std::string> serials) {
LOGW("launching boardd"); LOGW("launching pandad");
if (serials.size() == 0) { if (serials.size() == 0) {
serials = Panda::list(); serials = Panda::list();

@ -3,7 +3,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "selfdrive/boardd/panda.h" #include "selfdrive/pandad/panda.h"
bool safety_setter_thread(std::vector<Panda *> pandas); bool safety_setter_thread(std::vector<Panda *> pandas);
void boardd_main_thread(std::vector<std::string> serials); void pandad_main_thread(std::vector<std::string> serials);

@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# simple boardd wrapper that updates the panda first # simple pandad wrapper that updates the panda first
import os import os
import usb1 import usb1
import time import time
@ -157,10 +157,10 @@ def main() -> NoReturn:
first_run = False first_run = False
# run boardd with all connected serials as arguments # run pandad with all connected serials as arguments
os.environ['MANAGER_DAEMON'] = 'boardd' os.environ['MANAGER_DAEMON'] = 'pandad'
os.chdir(os.path.join(BASEDIR, "selfdrive/boardd")) os.chdir(os.path.join(BASEDIR, "selfdrive/pandad"))
subprocess.run(["./boardd", *panda_serials], check=True) subprocess.run(["./pandad", *panda_serials], check=True)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

@ -13,7 +13,7 @@
#include "common/timing.h" #include "common/timing.h"
#include "common/swaglog.h" #include "common/swaglog.h"
#include "panda/board/comms_definitions.h" #include "panda/board/comms_definitions.h"
#include "selfdrive/boardd/panda_comms.h" #include "selfdrive/pandad/panda_comms.h"
#define SPI_SYNC 0x5AU #define SPI_SYNC 0x5AU
@ -28,13 +28,6 @@ enum SpiError {
ACK_TIMEOUT = -3, ACK_TIMEOUT = -3,
}; };
struct __attribute__((packed)) spi_header {
uint8_t sync;
uint8_t endpoint;
uint16_t tx_len;
uint16_t max_rx_len;
};
const unsigned int SPI_ACK_TIMEOUT = 500; // milliseconds const unsigned int SPI_ACK_TIMEOUT = 500; // milliseconds
const std::string SPI_DEVICE = "/dev/spidev0.0"; const std::string SPI_DEVICE = "/dev/spidev0.0";
@ -55,6 +48,11 @@ private:
std::recursive_mutex &m; std::recursive_mutex &m;
}; };
#define SPILOG(fn, fmt, ...) do { \
fn(fmt, ## __VA_ARGS__); \
fn(" %d / 0x%x / %d / %d", \
xfer_count, header.endpoint, header.tx_len, header.max_rx_len); \
} while (0)
PandaSpiHandle::PandaSpiHandle(std::string serial) : PandaCommsHandle(serial) { PandaSpiHandle::PandaSpiHandle(std::string serial) : PandaCommsHandle(serial) {
int ret; int ret;
@ -178,7 +176,7 @@ int PandaSpiHandle::bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t t
} }
if (d < 0) { if (d < 0) {
LOGE("SPI: bulk transfer failed with %d", d); SPILOG(LOGE, "SPI: bulk transfer failed with %d", d);
comms_healthy = false; comms_healthy = false;
return d; return d;
} }
@ -247,7 +245,7 @@ int PandaSpiHandle::spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint1
} while (ret < 0 && connected && !timed_out); } while (ret < 0 && connected && !timed_out);
if (ret < 0) { if (ret < 0) {
LOGE("transfer failed, after %d tries, %.2fms", timeout_count, millis_since_boot() - start_time); SPILOG(LOGE, "transfer failed, after %d tries, %.2fms", timeout_count, millis_since_boot() - start_time);
} }
return ret; return ret;
@ -270,20 +268,20 @@ int PandaSpiHandle::wait_for_ack(uint8_t ack, uint8_t tx, unsigned int timeout,
while (true) { while (true) {
int ret = lltransfer(transfer); int ret = lltransfer(transfer);
if (ret < 0) { if (ret < 0) {
LOGE("SPI: failed to send ACK request"); SPILOG(LOGE, "SPI: failed to send ACK request");
return ret; return ret;
} }
if (rx_buf[0] == ack) { if (rx_buf[0] == ack) {
break; break;
} else if (rx_buf[0] == SPI_NACK) { } else if (rx_buf[0] == SPI_NACK) {
LOGD("SPI: got NACK"); SPILOG(LOGD, "SPI: got NACK");
return SpiError::NACK; return SpiError::NACK;
} }
// handle timeout // handle timeout
if (millis_since_boot() - start_millis > timeout) { if (millis_since_boot() - start_millis > timeout) {
LOGD("SPI: timed out waiting for ACK"); SPILOG(LOGW, "SPI: timed out waiting for ACK");
return SpiError::ACK_TIMEOUT; return SpiError::ACK_TIMEOUT;
} }
} }
@ -334,7 +332,8 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx
assert(tx_len < SPI_BUF_SIZE); assert(tx_len < SPI_BUF_SIZE);
assert(max_rx_len < SPI_BUF_SIZE); assert(max_rx_len < SPI_BUF_SIZE);
spi_header header = { xfer_count++;
header = {
.sync = SPI_SYNC, .sync = SPI_SYNC,
.endpoint = endpoint, .endpoint = endpoint,
.tx_len = tx_len, .tx_len = tx_len,
@ -352,7 +351,7 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx
transfer.len = sizeof(header) + 1; transfer.len = sizeof(header) + 1;
ret = lltransfer(transfer); ret = lltransfer(transfer);
if (ret < 0) { if (ret < 0) {
LOGE("SPI: failed to send header"); SPILOG(LOGE, "SPI: failed to send header");
return ret; return ret;
} }
@ -370,7 +369,7 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx
transfer.len = tx_len + 1; transfer.len = tx_len + 1;
ret = lltransfer(transfer); ret = lltransfer(transfer);
if (ret < 0) { if (ret < 0) {
LOGE("SPI: failed to send data"); SPILOG(LOGE, "SPI: failed to send data");
return ret; return ret;
} }
@ -383,7 +382,7 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx
// Read data // Read data
rx_data_len = *(uint16_t *)(rx_buf+1); rx_data_len = *(uint16_t *)(rx_buf+1);
if (rx_data_len >= SPI_BUF_SIZE) { if (rx_data_len >= SPI_BUF_SIZE) {
LOGE("SPI: RX data len larger than buf size %d", rx_data_len); SPILOG(LOGE, "SPI: RX data len larger than buf size %d", rx_data_len);
return -1; return -1;
} }
@ -391,11 +390,11 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx
transfer.rx_buf = (uint64_t)(rx_buf + 2 + 1); transfer.rx_buf = (uint64_t)(rx_buf + 2 + 1);
ret = lltransfer(transfer); ret = lltransfer(transfer);
if (ret < 0) { if (ret < 0) {
LOGE("SPI: failed to read rx data"); SPILOG(LOGE, "SPI: failed to read rx data");
return ret; return ret;
} }
if (!check_checksum(rx_buf, rx_data_len + 4)) { if (!check_checksum(rx_buf, rx_data_len + 4)) {
LOGE("SPI: bad checksum"); SPILOG(LOGE, "SPI: bad checksum");
return -1; return -1;
} }

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import os import os
import pytest import pytest
import time import time
@ -40,7 +39,7 @@ class TestPandad:
managed_processes['pandad'].stop() managed_processes['pandad'].stop()
if len(sm['pandaStates']) == 0 or sm['pandaStates'][0].pandaType == log.PandaState.PandaType.unknown: if len(sm['pandaStates']) == 0 or sm['pandaStates'][0].pandaType == log.PandaState.PandaType.unknown:
raise Exception("boardd failed to start") raise Exception("pandad failed to start")
return dt return dt
@ -102,7 +101,7 @@ class TestPandad:
ts.append(dt) ts.append(dt)
# 5s for USB (due to enumeration) # 5s for USB (due to enumeration)
# - 0.2s pandad -> boardd # - 0.2s pandad -> pandad
# - plus some buffer # - plus some buffer
assert 0.1 < (sum(ts)/len(ts)) < (0.5 if self.spi else 5.0) assert 0.1 < (sum(ts)/len(ts)) < (0.5 if self.spi else 5.0)
print("startup times", ts, sum(ts) / len(ts)) print("startup times", ts, sum(ts) / len(ts))

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import os import os
import copy import copy
import random import random
@ -9,19 +8,21 @@ from pprint import pprint
import cereal.messaging as messaging import cereal.messaging as messaging
from cereal import car, log from cereal import car, log
from openpilot.common.retry import retry
from openpilot.common.params import Params from openpilot.common.params import Params
from openpilot.common.timeout import Timeout from openpilot.common.timeout import Timeout
from openpilot.selfdrive.boardd.boardd import can_list_to_can_capnp from openpilot.selfdrive.pandad import can_list_to_can_capnp
from openpilot.selfdrive.car import make_can_msg from openpilot.selfdrive.car import make_can_msg
from openpilot.system.hardware import TICI from openpilot.system.hardware import TICI
from openpilot.selfdrive.test.helpers import phone_only, with_processes from openpilot.selfdrive.test.helpers import phone_only, with_processes
def setup_boardd(num_pandas): @retry(attempts=3)
def setup_pandad(num_pandas):
params = Params() params = Params()
params.put_bool("IsOnroad", False) params.put_bool("IsOnroad", False)
with Timeout(90, "boardd didn't start"): with Timeout(90, "pandad didn't start"):
sm = messaging.SubMaster(['pandaStates']) sm = messaging.SubMaster(['pandaStates'])
while sm.recv_frame['pandaStates'] < 1 or len(sm['pandaStates']) == 0 or \ while sm.recv_frame['pandaStates'] < 1 or len(sm['pandaStates']) == 0 or \
any(ps.pandaType == log.PandaState.PandaType.unknown for ps in sm['pandaStates']): any(ps.pandaType == log.PandaState.PandaType.unknown for ps in sm['pandaStates']):
@ -31,7 +32,7 @@ def setup_boardd(num_pandas):
assert num_pandas == found_pandas, "connected pandas ({found_pandas}) doesn't match expected panda count ({num_pandas}). \ assert num_pandas == found_pandas, "connected pandas ({found_pandas}) doesn't match expected panda count ({num_pandas}). \
connect another panda for multipanda tests." connect another panda for multipanda tests."
# boardd safety setting relies on these params # pandad safety setting relies on these params
cp = car.CarParams.new_message() cp = car.CarParams.new_message()
safety_config = car.CarParams.SafetyConfig.new_message() safety_config = car.CarParams.SafetyConfig.new_message()
@ -71,7 +72,7 @@ class TestBoarddLoopback:
@with_processes(['pandad']) @with_processes(['pandad'])
def test_loopback(self): def test_loopback(self):
num_pandas = 2 if TICI and "SINGLE_PANDA" not in os.environ else 1 num_pandas = 2 if TICI and "SINGLE_PANDA" not in os.environ else 1
setup_boardd(num_pandas) setup_pandad(num_pandas)
sendcan = messaging.pub_sock('sendcan') sendcan = messaging.pub_sock('sendcan')
can = messaging.sub_sock('can', conflate=False, timeout=100) can = messaging.sub_sock('can', conflate=False, timeout=100)
sm = messaging.SubMaster(['pandaStates']) sm = messaging.SubMaster(['pandaStates'])
@ -79,7 +80,7 @@ class TestBoarddLoopback:
n = 200 n = 200
for i in range(n): for i in range(n):
print(f"boardd loopback {i}/{n}") print(f"pandad loopback {i}/{n}")
sent_msgs = send_random_can_messages(sendcan, random.randrange(20, 100), num_pandas) sent_msgs = send_random_can_messages(sendcan, random.randrange(20, 100), num_pandas)

@ -1,15 +1,16 @@
#!/usr/bin/env python3
import os import os
import time import time
import numpy as np import numpy as np
import pytest import pytest
import random
import cereal.messaging as messaging import cereal.messaging as messaging
from cereal.services import SERVICE_LIST from cereal.services import SERVICE_LIST
from openpilot.system.hardware import HARDWARE from openpilot.system.hardware import HARDWARE
from openpilot.selfdrive.test.helpers import phone_only, with_processes from openpilot.selfdrive.test.helpers import phone_only, with_processes
from openpilot.selfdrive.boardd.tests.test_boardd_loopback import setup_boardd from openpilot.selfdrive.pandad.tests.test_pandad_loopback import setup_pandad, send_random_can_messages
JUNGLE_SPAM = "JUNGLE_SPAM" in os.environ
@pytest.mark.tici @pytest.mark.tici
class TestBoarddSpi: class TestBoarddSpi:
@ -18,38 +19,67 @@ class TestBoarddSpi:
if HARDWARE.get_device_type() == 'tici': if HARDWARE.get_device_type() == 'tici':
pytest.skip("only for spi pandas") pytest.skip("only for spi pandas")
os.environ['STARTED'] = '1' os.environ['STARTED'] = '1'
os.environ['BOARDD_LOOPBACK'] = '1'
os.environ['SPI_ERR_PROB'] = '0.001' os.environ['SPI_ERR_PROB'] = '0.001'
if not JUNGLE_SPAM:
os.environ['BOARDD_LOOPBACK'] = '1'
@phone_only @phone_only
@with_processes(['pandad']) @with_processes(['pandad'])
def test_spi_corruption(self, subtests): def test_spi_corruption(self, subtests):
setup_boardd(1) setup_pandad(1)
sendcan = messaging.pub_sock('sendcan')
socks = {s: messaging.sub_sock(s, conflate=False, timeout=100) for s in ('can', 'pandaStates', 'peripheralState')} socks = {s: messaging.sub_sock(s, conflate=False, timeout=100) for s in ('can', 'pandaStates', 'peripheralState')}
time.sleep(2) time.sleep(2)
for s in socks.values(): for s in socks.values():
messaging.drain_sock_raw(s) messaging.drain_sock_raw(s)
total_recv_count = 0
total_sent_count = 0
sent_msgs = {bus: list() for bus in range(3)}
st = time.monotonic() st = time.monotonic()
ts = {s: list() for s in socks.keys()} ts = {s: list() for s in socks.keys()}
for _ in range(20): for _ in range(int(os.getenv("TEST_TIME", "20"))):
# send some CAN messages
if not JUNGLE_SPAM:
sent = send_random_can_messages(sendcan, random.randrange(2, 20))
for k, v in sent.items():
sent_msgs[k].extend(list(v))
total_sent_count += len(v)
for service, sock in socks.items(): for service, sock in socks.items():
for m in messaging.drain_sock(sock): for m in messaging.drain_sock(sock):
ts[service].append(m.logMonoTime) ts[service].append(m.logMonoTime)
# sanity check for corruption # sanity check for corruption
assert m.valid assert m.valid or (service == "can")
if service == "can": if service == "can":
assert len(m.can) == 0 for msg in m.can:
if JUNGLE_SPAM:
# PandaJungle.set_generated_can(True)
i = msg.address - 0x200
assert msg.address >= 0x200
assert msg.src == (i%3)
assert msg.dat == b"\xff"*(i%8)
total_recv_count += 1
continue
if msg.src > 4:
continue
key = (msg.address, msg.dat)
assert key in sent_msgs[msg.src], f"got unexpected msg: {msg.src=} {msg.address=} {msg.dat=}"
# TODO: enable this
#sent_msgs[msg.src].remove(key)
total_recv_count += 1
elif service == "pandaStates": elif service == "pandaStates":
assert len(m.pandaStates) == 1 assert len(m.pandaStates) == 1
ps = m.pandaStates[0] ps = m.pandaStates[0]
assert ps.uptime < 100 assert ps.uptime < 1000
assert ps.pandaType == "tres" assert ps.pandaType == "tres"
assert ps.ignitionLine assert ps.ignitionLine
assert not ps.ignitionCan assert not ps.ignitionCan
assert ps.voltage < 14000 assert 4000 < ps.voltage < 14000
elif service == "peripheralState": elif service == "peripheralState":
ps = m.peripheralState ps = m.peripheralState
assert ps.pandaType == "tres" assert ps.pandaType == "tres"
@ -67,6 +97,10 @@ class TestBoarddSpi:
with subtests.test(msg="timing check", service=service): with subtests.test(msg="timing check", service=service):
edt = 1e3 / SERVICE_LIST[service].frequency edt = 1e3 / SERVICE_LIST[service].frequency
assert edt*0.9 < np.mean(dts) < edt*1.1 assert edt*0.9 < np.mean(dts) < edt*1.1
assert np.max(dts) < edt*3 assert np.max(dts) < edt*20
assert np.min(dts) < edt assert np.min(dts) < edt
assert len(dts) >= ((et-0.5)*SERVICE_LIST[service].frequency*0.8) assert len(dts) >= ((et-0.5)*SERVICE_LIST[service].frequency*0.8)
with subtests.test(msg="CAN traffic"):
print(f"Sent {total_sent_count} CAN messages, got {total_recv_count} back. {total_recv_count/(total_sent_count+1e-4):.2%} received")
assert total_recv_count > 20

@ -4,7 +4,7 @@
#include "catch2/catch.hpp" #include "catch2/catch.hpp"
#include "cereal/messaging/messaging.h" #include "cereal/messaging/messaging.h"
#include "common/util.h" #include "common/util.h"
#include "selfdrive/boardd/panda.h" #include "selfdrive/pandad/panda.h"
struct PandaTest : public Panda { struct PandaTest : public Panda {
PandaTest(uint32_t bus_offset, int can_list_size, cereal::PandaState::PandaType hw_type); PandaTest(uint32_t bus_offset, int can_list_size, cereal::PandaState::PandaType hw_type);

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save