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
- uses: ./.github/workflows/setup-pre-commit
- uses: ./.github/workflows/setup-with-retry
- name: Build openpilot
run: ${{ env.RUN }} "scons -j$(nproc)"
- name: pre-commit
timeout-minutes: 4
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' && \
./selfdrive/ui/tests/create_test_translations.sh && \
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"
uses: codecov/codecov-action@v4
with:

3
.gitignore vendored

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

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

10
Jenkinsfile vendored

@ -192,7 +192,7 @@ node {
'HW + Unit Tests': {
deviceStage("tici-hardware", "tici-common", ["UNSAFE=1"], [
["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 encoder", "LD_LIBRARY_PATH=/usr/local/lib pytest system/loggerd/tests/test_encoder.py"],
["test pigeond", "pytest system/ubloxd/tests/test_pigeond.py"],
@ -202,7 +202,7 @@ node {
'loopback': {
deviceStage("loopback", "tici-loopback", ["UNSAFE=1"], [
["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': {
@ -236,9 +236,9 @@ node {
'tizi': {
deviceStage("tizi", "tizi", ["UNSAFE=1"], [
["build openpilot", "cd system/manager && ./build.py"],
["test boardd loopback", "SINGLE_PANDA=1 pytest selfdrive/boardd/tests/test_boardd_loopback.py"],
["test boardd spi", "pytest selfdrive/boardd/tests/test_boardd_spi.py"],
["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py"],
["test pandad loopback", "SINGLE_PANDA=1 pytest selfdrive/pandad/tests/test_pandad_loopback.py"],
["test pandad spi", "pytest selfdrive/pandad/tests/test_pandad_spi.py"],
["test pandad", "pytest selfdrive/pandad/tests/test_pandad.py"],
["test amp", "pytest system/hardware/tici/tests/test_amplifier.py"],
["test hw", "pytest system/hardware/tici/tests/test_hardware.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
* 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
* Support for hybrid variants of supported Ford models
* 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
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
* Temporarily remove mapd functionalities to improve stability
* 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
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)
===========================
* 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
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)
===========================
* Performance improvements, removal of more numpy
* Fix boardd process priority
* Fix pandad process priority
* Make counter timer reset on use of steering wheel
Version 0.2 (2016-12-12)

@ -226,7 +226,7 @@ env = Environment(
"#cereal",
"#third_party",
"#opendbc/can",
"#selfdrive/boardd",
"#selfdrive/pandad",
"#common",
"#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
DT_CTRL = 0.01 # controlsd
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
@ -23,7 +23,7 @@ class Priority:
CTRL_LOW = 51 # plannerd & radard
# CORE 3
# - boardd = 55
# - pandad = 55
CTRL_HIGH = 53

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

@ -1,5 +1,3 @@
#!/usr/bin/env python3
import numpy as np
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.
# 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|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
@ -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 (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 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 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>||
@ -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 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 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 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>||

@ -77,10 +77,10 @@ sensorsd
.. autodoxygenindex::
:project: system_sensord_sensors
boardd
pandad
^^^^^^
.. autodoxygenindex::
:project: selfdrive_boardd
:project: selfdrive_pandad
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
oid sha256:0e15c700ef7dd958815caaec9f2747c560fe1a77990275354bdfe2ff3ac38457
size 613262
oid sha256:84ac396fe236ffaf09f9a865fa3bae19ac961db726bdc19b79e52c2f45db6abe
size 618064

@ -20,7 +20,7 @@ markers = [
]
testpaths = [
"common",
"selfdrive/boardd",
"selfdrive/pandad",
"selfdrive/car",
"selfdrive/controls",
"selfdrive/locationd",
@ -29,10 +29,9 @@ testpaths = [
"selfdrive/test/longitudinal_maneuvers",
"selfdrive/test/process_replay/test_fuzzy.py",
"system/updated",
"system/thermald",
"system/athena",
"system/camerad",
"system/hardware/tici",
"system/hardware",
"system/loggerd",
"system/proclogd",
"system/tests",
@ -140,7 +139,8 @@ inputs = "*"
Jinja2 = "*"
lru-dict = "*"
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 = "*"
mypy = "*"
myst-parser = "*"
@ -164,6 +164,7 @@ pytest-timeout = "*"
pytest-randomly = "*"
pytest-asyncio = "*"
pytest-mock = "*"
pytest-repeat = "*"
rerun-sdk = "*"
ruff = "*"
sphinx = "*"

@ -48,7 +48,6 @@ cp -pR --parents $(./release/release_files.py) $TARGET_DIR/
# in the directory
cd $TARGET_DIR
rm -f panda/board/obj/panda.bin.signed
git submodule status
# include source commit hash and build date in commit
GIT_HASH=$(git --git-dir=$SOURCE_DIR/.git rev-parse HEAD)
@ -64,6 +63,13 @@ date: $DATETIME
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
BIG_FILES="$(find . -type f -not -path './.git/*' -size +95M)"
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
@ -29,7 +31,7 @@ git checkout --orphan $RELEASE_BRANCH
# do the files copy
echo "[-] copying files T=$SECONDS"
cd $SOURCE_DIR
cp -pR --parents $(./release/release_files.py) $TARGET_DIR/
cp -pR --parents $(./release/release_files.py) $BUILD_DIR/
# in the directory
cd $BUILD_DIR
@ -46,7 +48,7 @@ git commit -a -m "openpilot v$VERSION release"
# Build
export PYTHONPATH="$BUILD_DIR"
scons -j$(nproc)
scons -j$(nproc) --minimal
# release panda fw
CERT=/data/pandaextra/certs/release RELEASE=1 scons -j$(nproc) panda/

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

@ -1,4 +1,4 @@
SConscript(['boardd/SConscript'])
SConscript(['pandad/SConscript'])
SConscript(['controls/lib/lateral_mpc_lib/SConscript'])
SConscript(['controls/lib/longitudinal_mpc_lib/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.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.interfaces import CarInterfaceBase
from openpilot.selfdrive.controls.lib.events import Events
@ -153,7 +153,7 @@ class Car:
# Initialize CarInterface, once controls are ready
# 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'])
# signal boardd to switch to car safety mode
# signal pandad to switch to car safety mode
self.params.put_bool_nonblocking("ControlsReady", True)
if self.sm.all_alive(['carControl']):

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

@ -6,7 +6,7 @@ import cereal.messaging as messaging
from panda.python.uds import SERVICE_TYPE
from openpilot.selfdrive.car import make_can_msg
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

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

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

@ -352,7 +352,7 @@ if __name__ == "__main__":
pandaStates_sock = messaging.sub_sock('pandaStates')
sendcan = messaging.pub_sock('sendcan')
# Set up params for boardd
# Set up params for pandad
params = Params()
params.remove("FirmwareQueryDone")
params.put_bool("IsOnroad", False)
@ -374,7 +374,7 @@ if __name__ == "__main__":
t = time.time()
print("Getting vin...")
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"Getting VIN took {time.time() - t:.3f} s")
print()

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

@ -11,43 +11,6 @@ Ecu = car.CarParams.Ecu
FW_VERSIONS = {
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): [
b'54008-TVC-A910\x00\x00',
b'54008-TWA-A910\x00\x00',
@ -161,38 +124,6 @@ FW_VERSIONS = {
],
},
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): [
b'28101-5CG-A040\x00\x00',
b'28101-5CG-A050\x00\x00',
@ -242,61 +173,6 @@ FW_VERSIONS = {
],
},
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): [
b'28101-5CG-A920\x00\x00',
b'28101-5CG-AB10\x00\x00',
@ -400,10 +276,6 @@ FW_VERSIONS = {
],
},
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): [
b'28101-59Y-G220\x00\x00',
b'28101-59Y-G620\x00\x00',
@ -449,41 +321,6 @@ FW_VERSIONS = {
],
},
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): [
b'28101-5RG-A020\x00\x00',
b'28101-5RG-A030\x00\x00',
@ -559,10 +396,6 @@ FW_VERSIONS = {
],
},
CAR.HONDA_CRV_EU: {
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-R5Z-G740\x00\x00',
b'37805-R5Z-G780\x00\x00',
],
(Ecu.vsa, 0x18da28f1, None): [
b'57114-T1V-G920\x00\x00',
],
@ -663,24 +496,6 @@ FW_VERSIONS = {
b'38897-THR-A010\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): [
b'39990-THR-A020\x00\x00',
b'39990-THR-A030\x00\x00',
@ -765,39 +580,6 @@ FW_VERSIONS = {
b'28101-5EZ-A700\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): [
b'38897-TG7-A030\x00\x00',
b'38897-TG7-A040\x00\x00',
@ -875,26 +657,6 @@ FW_VERSIONS = {
],
},
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): [
b'57114-TJB-A030\x00\x00',
b'57114-TJB-A040\x00\x00',
@ -1049,10 +811,6 @@ FW_VERSIONS = {
b'28101-6EH-A010\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): [
b'46114-3W0-A020\x00\x00',
],
@ -1133,14 +891,5 @@ FW_VERSIONS = {
b'28101-65H-A120\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
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.
# 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={
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,
@ -306,6 +307,7 @@ FW_QUERY_CONFIG = FwQueryConfig(
},
extra_ecus=[
(Ecu.combinationMeter, 0x18da60f1, None),
(Ecu.programmedFuelInjection, 0x18da10f1, None),
# 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
# 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: [{
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: [{
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-G7500 ',
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): [
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',
],
(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.03 95740-G2500 190516',
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: {
@ -749,6 +750,7 @@ FW_VERSIONS = {
],
(Ecu.fwdRadar, 0x7d0, None): [
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: {
@ -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-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.07 99210-AA000 220426',
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.08 99210-AA000 220728',
],
(Ecu.abs, 0x7d1, None): [
@ -1001,6 +1004,7 @@ FW_VERSIONS = {
(Ecu.fwdCamera, 0x7c4, None): [
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.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: {
(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 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 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 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-P1070 690',
],

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

@ -314,7 +314,7 @@ class CAR(Platforms):
flags=HyundaiFlags.EV,
)
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,
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
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,
)
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
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(
requests=[
# TODO: add back whitelists

@ -6,6 +6,7 @@ from abc import abstractmethod, ABC
from enum import StrEnum
from typing import Any, NamedTuple
from collections.abc import Callable
from functools import cache
from cereal import car
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_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):
lateral_acceleration: float
@ -43,29 +56,34 @@ class LatControlInputs(NamedTuple):
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:
sub = tomllib.load(f)
if candidate in sub:
candidate = sub[candidate]
with open(TORQUE_PARAMS_PATH, 'rb') as f:
params = tomllib.load(f)
with open(TORQUE_OVERRIDE_PATH, 'rb') as f:
override = tomllib.load(f)
# Ensure no overlap
if sum([candidate in x for x in [sub, params, override]]) > 1:
raise RuntimeError(f'{candidate} is defined twice in torque config')
torque_params = {}
for candidate in (sub.keys() | params.keys() | override.keys()) - {'legend'}:
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:
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'])}
sub_candidate = sub.get(candidate, candidate)
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
@ -166,7 +184,7 @@ class CarInterfaceBase(ABC):
ret.carFingerprint = candidate
# 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
# standard ALC params
@ -199,7 +217,7 @@ class CarInterfaceBase(ABC):
@staticmethod
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.torque.useSteeringAngle = use_steering_angle
@ -422,19 +440,7 @@ class CarStateBase(ABC):
def parse_gear_shifter(gear: str | None) -> car.CarState.GearShifter:
if gear is None:
return 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)
return GEAR_SHIFTER_MAP.get(gear.upper(), GearShifter.unknown)
@staticmethod
def get_can_parser(CP):

@ -4,7 +4,7 @@ from functools import partial
import cereal.messaging as messaging
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 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',
],
(Ecu.engine, 0x7e0, None): [
b'\xa7"@0\x07',
b'\xa7"@p\x07',
b'\xa7)\xa0q\x07',
b'\xba"@@\x07',
@ -319,6 +320,7 @@ FW_VERSIONS = {
(Ecu.transmission, 0x7e1, None): [
b'\x1a\xf6F`\x00',
b'\xda\xf2`\x80\x00',
b'\xda\xf2`p\x00',
b'\xda\xfd\xe0\x80\x00',
b'\xdc\xf2@`\x00',
b'\xdc\xf2``\x00',

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

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

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

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

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

@ -3,6 +3,7 @@ from collections import defaultdict
import importlib
from parameterized import parameterized_class
import pytest
import sys
from openpilot.common.realtime import DT_CTRL
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_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)])
class TestLateralLimits:
@ -44,7 +43,7 @@ class TestLateralLimits:
CarControllerParams = importlib.import_module(f'selfdrive.car.{CP.carName}.values').CarControllerParams
cls.control_params = CarControllerParams(CP)
cls.torque_params = get_torque_params(cls.car_model)
cls.torque_params = get_torque_params()[cls.car_model]
@staticmethod
def calculate_0_5s_jerk(control_params, torque_params):
@ -64,9 +63,36 @@ class TestLateralLimits:
def test_jerk_limits(self):
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 down_jerk <= MAX_LAT_JERK_DOWN
def test_max_lateral_accel(self):
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 os
import importlib

@ -1,5 +1,3 @@
#!/usr/bin/env python3
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]
"LEXUS_IS_TSS2" = [2.0, 2.0, 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_HEV_6TH_GEN" = [1.8, 1.8, 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]
"JEEP_GRAND_CHEROKEE_2019" = [2.30972, 1.289689569171081, 0.117048]
"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_NIRO_EV" = [2.9215954981365337, 2.1500583840260044, 0.09236802474810267]
"KIA_SORENTO" = [2.464854685101844, 1.5335274218367956, 0.12056170567599558]

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

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

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

@ -214,10 +214,11 @@ class CAR(Platforms):
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 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"),
],
VolkswagenCarSpecs(mass=1733, wheelbase=2.84),
chassis_codes={"AN"},
chassis_codes={"AN", "3H"},
wmis={WMI.VOLKSWAGEN_EUROPE_CAR},
)
VOLKSWAGEN_ATLAS_MK1 = VolkswagenMQBPlatformConfig(

@ -279,7 +279,7 @@ class Controls:
else:
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:
self.events.add(EventName.controlsMismatch)

@ -51,7 +51,7 @@ class Events:
def __init__(self):
self.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
def names(self) -> list[int]:
@ -66,7 +66,7 @@ class Events:
bisect.insort(self.events, event_name)
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()
def contains(self, event_type: str) -> bool:
@ -85,7 +85,7 @@ class Events:
if not isinstance(alert, Alert):
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.event_type = et
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.modeld.constants import ModelConstants
CONTROL_N_T_IDX = ModelConstants.T_IDXS[:CONTROL_N]
LongCtrlState = car.CarControl.Actuators.LongControlState
@ -68,19 +70,19 @@ class LongControl:
# Interp control trajectory
speeds = long_plan.speeds
if len(speeds) == CONTROL_N:
v_target_now = interp(t_since_plan, ModelConstants.T_IDXS[:CONTROL_N], speeds)
a_target_now = interp(t_since_plan, ModelConstants.T_IDXS[:CONTROL_N], long_plan.accels)
v_target_now = interp(t_since_plan, CONTROL_N_T_IDX, speeds)
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
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
v_target = min(v_target_lower, v_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:
v_target = 0.0
v_target_now = 0.0

@ -62,9 +62,9 @@ class LongitudinalPlanner:
@staticmethod
def parse_model(model_msg, model_error):
if (len(model_msg.position.x) == 33 and
len(model_msg.velocity.x) == 33 and
len(model_msg.acceleration.x) == 33):
if (len(model_msg.position.x) == ModelConstants.IDX_N and
len(model_msg.velocity.x) == ModelConstants.IDX_N and
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
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)

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

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

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

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

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

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

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

@ -4,7 +4,7 @@ from parameterized import parameterized
from cereal import log, car
import cereal.messaging as messaging
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.toyota.values import CAR as TOYOTA
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()]
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"):
params.put_bool("ObdMultiplexingChanged", True)

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

@ -12,11 +12,11 @@ parser.add_argument('--debug', action='store_true')
args = parser.parse_args()
try:
check_output(["pidof", "boardd"])
print("boardd is running, please kill openpilot before running this script! (aborted)")
check_output(["pidof", "pandad"])
print("pandad is running, please kill openpilot before running this script! (aborted)")
sys.exit(1)
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
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.
Monitor multiple processes simuteneously.
Sample usage:
root@localhost:/data/openpilot$ python selfdrive/debug/cpu_usage_stat.py boardd,ubloxd
('Add monitored proc:', './boardd')
root@localhost:/data/openpilot$ python selfdrive/debug/cpu_usage_stat.py pandad,ubloxd
('Add monitored proc:', './pandad')
('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%
'''
import psutil

@ -1,11 +1,12 @@
#!/usr/bin/env python3
import argparse
from openpilot.tools.lib.live_logreader import live_logreader
from openpilot.tools.lib.logreader import LogReader, ReadMode
from panda.python import uds
def main(route: str, addrs: list[int]):
def main(route: str | None, addrs: list[int]):
"""
TODO:
- highlight TX vs RX clearly
@ -13,7 +14,10 @@ def main(route: str, addrs: list[int]):
- 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
prev_mono_time = 0
@ -28,7 +32,7 @@ def main(route: str, addrs: list[int]):
if msg.which() in ("can", 'sendcan'):
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:
print()
prev_mono_time = msg.logMonoTime
@ -38,8 +42,8 @@ def main(route: str, addrs: list[int]):
if __name__ == "__main__":
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('addrs', nargs='*', help='List of tx address to view (0x7e0 for engine)')
parser.add_argument('route', nargs='?', help='Route name, live if not specified')
parser.add_argument('--addrs', nargs='*', default=[], help='List of tx address to view (0x7e0 for engine)')
args = parser.parse_args()
addrs = [int(addr, base=16) if addr.startswith('0x') else int(addr) for addr in args.addrs]

@ -4,7 +4,7 @@
# Instructions:
# - connect to a Panda
# - run selfdrive/boardd/boardd
# - run selfdrive/pandad/pandad
# - launching this script
# 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,

@ -79,11 +79,11 @@ if __name__ == "__main__":
args = parser.parse_args()
try:
check_output(["pidof", "boardd"])
print("boardd is running, please kill openpilot before running this script! (aborted)")
check_output(["pidof", "pandad"])
print("pandad is running, please kill openpilot before running this script! (aborted)")
sys.exit(1)
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
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()
try:
check_output(["pidof", "boardd"])
print("boardd is running, please kill openpilot before running this script! (aborted)")
check_output(["pidof", "pandad"])
print("pandad is running, please kill openpilot before running this script! (aborted)")
sys.exit(1)
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
panda = Panda()

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

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

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

@ -1,13 +1,10 @@
#include "selfdrive/modeld/models/commonmodel.h"
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstring>
#include "common/clutil.h"
#include "common/mat.h"
#include "common/timing.h"
ModelFrame::ModelFrame(cl_device_id device_id, cl_context context) {
input_frames = std::make_unique<float[]>(buf_size);
@ -52,21 +49,6 @@ ModelFrame::~ModelFrame() {
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) {
return 1 / (1 + expf(-input));
}

@ -13,20 +13,11 @@
#endif
#include "common/mat.h"
#include "cereal/messaging/messaging.h"
#include "selfdrive/modeld/transforms/loadyuv.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);
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 {
public:
ModelFrame(cl_device_id device_id, cl_context context);

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

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

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

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import json
import random
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']
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'])
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'):
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
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
def can_capnp_to_can_list(can, src_filter=None):

@ -1,5 +1,5 @@
#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) {
MessageBuilder msg;

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

@ -1,4 +1,4 @@
#include "selfdrive/boardd/panda.h"
#include "selfdrive/pandad/panda.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) {
// TODO: also reset CAN comms?
LOGE("Panda CAN checksum failed");
size = 0;
can_reset_communications();
return false;
}

@ -13,7 +13,7 @@
#include "cereal/gen/cpp/log.capnp.h"
#include "panda/board/health.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 USBPACKET_MAX_SIZE (0x40)

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

@ -56,6 +56,13 @@ private:
};
#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 {
public:
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_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);
spi_header header;
uint32_t xfer_count = 0;
};
#endif

@ -1,4 +1,4 @@
#include "selfdrive/boardd/boardd.h"
#include "selfdrive/pandad/pandad.h"
#include <algorithm>
#include <array>
@ -25,7 +25,7 @@
// - The internal panda will always be the first panda
// - Consecutive pandas will be sorted based on panda type, and then serial number
// 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
// CAN buses:
// - 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) {
util::set_thread_name("boardd_can_send");
util::set_thread_name("pandad_can_send");
AlignedBuffer aligned_buf;
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) {
util::set_thread_name("boardd_can_recv");
util::set_thread_name("pandad_can_recv");
PubMaster pm({"can"});
// run at 100Hz
RateKeeper rk("boardd_can_recv", 100);
RateKeeper rk("pandad_can_recv", 100);
std::vector<can_frame> raw_can_data;
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) {
util::set_thread_name("boardd_panda_state");
util::set_thread_name("pandad_panda_state");
Params params;
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) {
util::set_thread_name("boardd_peripheral_control");
util::set_thread_name("pandad_peripheral_control");
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) {
LOGW("launching boardd");
void pandad_main_thread(std::vector<std::string> serials) {
LOGW("launching pandad");
if (serials.size() == 0) {
serials = Panda::list();

@ -3,7 +3,7 @@
#include <string>
#include <vector>
#include "selfdrive/boardd/panda.h"
#include "selfdrive/pandad/panda.h"
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
# simple boardd wrapper that updates the panda first
# simple pandad wrapper that updates the panda first
import os
import usb1
import time
@ -157,10 +157,10 @@ def main() -> NoReturn:
first_run = False
# run boardd with all connected serials as arguments
os.environ['MANAGER_DAEMON'] = 'boardd'
os.chdir(os.path.join(BASEDIR, "selfdrive/boardd"))
subprocess.run(["./boardd", *panda_serials], check=True)
# run pandad with all connected serials as arguments
os.environ['MANAGER_DAEMON'] = 'pandad'
os.chdir(os.path.join(BASEDIR, "selfdrive/pandad"))
subprocess.run(["./pandad", *panda_serials], check=True)
if __name__ == "__main__":
main()

@ -13,7 +13,7 @@
#include "common/timing.h"
#include "common/swaglog.h"
#include "panda/board/comms_definitions.h"
#include "selfdrive/boardd/panda_comms.h"
#include "selfdrive/pandad/panda_comms.h"
#define SPI_SYNC 0x5AU
@ -28,13 +28,6 @@ enum SpiError {
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 std::string SPI_DEVICE = "/dev/spidev0.0";
@ -55,6 +48,11 @@ private:
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) {
int ret;
@ -178,7 +176,7 @@ int PandaSpiHandle::bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t t
}
if (d < 0) {
LOGE("SPI: bulk transfer failed with %d", d);
SPILOG(LOGE, "SPI: bulk transfer failed with %d", d);
comms_healthy = false;
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);
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;
@ -270,20 +268,20 @@ int PandaSpiHandle::wait_for_ack(uint8_t ack, uint8_t tx, unsigned int timeout,
while (true) {
int ret = lltransfer(transfer);
if (ret < 0) {
LOGE("SPI: failed to send ACK request");
SPILOG(LOGE, "SPI: failed to send ACK request");
return ret;
}
if (rx_buf[0] == ack) {
break;
} else if (rx_buf[0] == SPI_NACK) {
LOGD("SPI: got NACK");
SPILOG(LOGD, "SPI: got NACK");
return SpiError::NACK;
}
// handle 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;
}
}
@ -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(max_rx_len < SPI_BUF_SIZE);
spi_header header = {
xfer_count++;
header = {
.sync = SPI_SYNC,
.endpoint = endpoint,
.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;
ret = lltransfer(transfer);
if (ret < 0) {
LOGE("SPI: failed to send header");
SPILOG(LOGE, "SPI: failed to send header");
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;
ret = lltransfer(transfer);
if (ret < 0) {
LOGE("SPI: failed to send data");
SPILOG(LOGE, "SPI: failed to send data");
return ret;
}
@ -383,7 +382,7 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx
// Read data
rx_data_len = *(uint16_t *)(rx_buf+1);
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;
}
@ -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);
ret = lltransfer(transfer);
if (ret < 0) {
LOGE("SPI: failed to read rx data");
SPILOG(LOGE, "SPI: failed to read rx data");
return ret;
}
if (!check_checksum(rx_buf, rx_data_len + 4)) {
LOGE("SPI: bad checksum");
SPILOG(LOGE, "SPI: bad checksum");
return -1;
}

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import os
import pytest
import time
@ -40,7 +39,7 @@ class TestPandad:
managed_processes['pandad'].stop()
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
@ -102,7 +101,7 @@ class TestPandad:
ts.append(dt)
# 5s for USB (due to enumeration)
# - 0.2s pandad -> boardd
# - 0.2s pandad -> pandad
# - plus some buffer
assert 0.1 < (sum(ts)/len(ts)) < (0.5 if self.spi else 5.0)
print("startup times", ts, sum(ts) / len(ts))

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import os
import copy
import random
@ -9,19 +8,21 @@ from pprint import pprint
import cereal.messaging as messaging
from cereal import car, log
from openpilot.common.retry import retry
from openpilot.common.params import Params
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.system.hardware import TICI
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.put_bool("IsOnroad", False)
with Timeout(90, "boardd didn't start"):
with Timeout(90, "pandad didn't start"):
sm = messaging.SubMaster(['pandaStates'])
while sm.recv_frame['pandaStates'] < 1 or len(sm['pandaStates']) == 0 or \
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}). \
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()
safety_config = car.CarParams.SafetyConfig.new_message()
@ -71,7 +72,7 @@ class TestBoarddLoopback:
@with_processes(['pandad'])
def test_loopback(self):
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')
can = messaging.sub_sock('can', conflate=False, timeout=100)
sm = messaging.SubMaster(['pandaStates'])
@ -79,7 +80,7 @@ class TestBoarddLoopback:
n = 200
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)

@ -1,15 +1,16 @@
#!/usr/bin/env python3
import os
import time
import numpy as np
import pytest
import random
import cereal.messaging as messaging
from cereal.services import SERVICE_LIST
from openpilot.system.hardware import HARDWARE
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
class TestBoarddSpi:
@ -18,38 +19,67 @@ class TestBoarddSpi:
if HARDWARE.get_device_type() == 'tici':
pytest.skip("only for spi pandas")
os.environ['STARTED'] = '1'
os.environ['BOARDD_LOOPBACK'] = '1'
os.environ['SPI_ERR_PROB'] = '0.001'
if not JUNGLE_SPAM:
os.environ['BOARDD_LOOPBACK'] = '1'
@phone_only
@with_processes(['pandad'])
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')}
time.sleep(2)
for s in socks.values():
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()
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 m in messaging.drain_sock(sock):
ts[service].append(m.logMonoTime)
# sanity check for corruption
assert m.valid
assert m.valid or (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":
assert len(m.pandaStates) == 1
ps = m.pandaStates[0]
assert ps.uptime < 100
assert ps.uptime < 1000
assert ps.pandaType == "tres"
assert ps.ignitionLine
assert not ps.ignitionCan
assert ps.voltage < 14000
assert 4000 < ps.voltage < 14000
elif service == "peripheralState":
ps = m.peripheralState
assert ps.pandaType == "tres"
@ -67,6 +97,10 @@ class TestBoarddSpi:
with subtests.test(msg="timing check", service=service):
edt = 1e3 / SERVICE_LIST[service].frequency
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 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 "cereal/messaging/messaging.h"
#include "common/util.h"
#include "selfdrive/boardd/panda.h"
#include "selfdrive/pandad/panda.h"
struct PandaTest : public Panda {
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