openpilot v0.9.6 release

date: 2024-02-21T23:02:42
master commit: 0b4d08fab8
pull/32615/head
Vehicle Researcher 1 year ago
parent b2f2dabe71
commit fa724893fb
  1. 1
      .gitignore
  2. 82
      Jenkinsfile
  3. 127
      README.md
  4. 20
      RELEASES.md
  5. 57
      SConstruct
  6. 8
      body/board/SConscript
  7. 4
      body/board/inc/stm32f4xx.h
  8. 1
      cereal/__init__.py
  9. 7
      cereal/car.capnp
  10. 63
      cereal/log.capnp
  11. 160
      cereal/messaging/__init__.py
  12. 5
      cereal/services.py
  13. 13
      cereal/visionipc/visionipc_client.cc
  14. 3
      cereal/visionipc/visionipc_client.h
  15. 20
      cereal/visionipc/visionipc_server.cc
  16. 2
      cereal/visionipc/visionipc_server.h
  17. 10
      common/SConscript
  18. 4
      common/api/__init__.py
  19. 7
      common/basedir.py
  20. 49
      common/ffi_wrapper.py
  21. 87
      common/file_helpers.py
  22. 1
      common/kalman/.gitignore
  23. 5
      common/kalman/SConscript
  24. 12
      common/kalman/simple_kalman.py
  25. 18
      common/kalman/simple_kalman_impl.pxd
  26. 37
      common/kalman/simple_kalman_impl.pyx
  27. 23
      common/kalman/simple_kalman_old.py
  28. 0
      common/kalman/tests/__init__.py
  29. 87
      common/kalman/tests/test_simple_kalman.py
  30. 4
      common/logging_extra.py
  31. 38
      common/modeldata.h
  32. 47
      common/params.cc
  33. 21
      common/params.h
  34. 5
      common/params.py
  35. 25
      common/params_pyx.pyx
  36. 52
      common/prefix.py
  37. 45
      common/profiler.py
  38. 2
      common/realtime.py
  39. 30
      common/retry.py
  40. 54
      common/simple_kalman.py
  41. 47
      common/statlog.cc
  42. 10
      common/statlog.h
  43. 75
      common/swaglog.cc
  44. 0
      common/swaglog.py
  45. 2
      common/time.py
  46. 2
      common/transformations/transformations.pxd
  47. 7
      common/transformations/transformations.pyx
  48. 34
      common/util.h
  49. 2
      common/version.h
  50. 192
      docs/CARS.md
  51. 69
      docs/CONTRIBUTING.md
  52. 20
      launch_chffrplus.sh
  53. 6
      launch_env.sh
  54. 2
      launch_openpilot.sh
  55. 14
      opendbc/can/common.h
  56. 2
      opendbc/can/common.pxd
  57. 4
      opendbc/can/packer_pyx.pyx
  58. 74
      opendbc/can/parser.cc
  59. 4
      opendbc/can/parser_pyx.pyx
  60. 74
      opendbc/chrysler_pacifica_2017_hybrid_generated.dbc
  61. 65
      opendbc/chrysler_ram_dt_generated.dbc
  62. 57
      opendbc/chrysler_ram_hd_generated.dbc
  63. 14
      opendbc/gm_global_a_powertrain_generated.dbc
  64. 3
      opendbc/honda_civic_touring_2016_can_generated.dbc
  65. 4
      opendbc/hyundai_kia_generic.dbc
  66. 8
      opendbc/subaru_global_2017_generated.dbc
  67. 1
      opendbc/subaru_global_2020_hybrid_generated.dbc
  68. 4
      opendbc/toyota_nodsu_pt_generated.dbc
  69. 7
      opendbc/vw_golf_mk4.dbc
  70. 18
      panda/SConscript
  71. 10
      panda/board/README.md
  72. 5
      panda/board/SConscript
  73. 15
      panda/board/boards/black.h
  74. 12
      panda/board/boards/board_declarations.h
  75. 130
      panda/board/boards/cuatro.h
  76. 19
      panda/board/boards/dos.h
  77. 13
      panda/board/boards/grey.h
  78. 96
      panda/board/boards/pedal.h
  79. 19
      panda/board/boards/red.h
  80. 8
      panda/board/boards/red_chiplet.h
  81. 40
      panda/board/boards/red_v2.h
  82. 13
      panda/board/boards/tres.h
  83. 23
      panda/board/boards/uno.h
  84. 4
      panda/board/boards/unused_funcs.h
  85. 25
      panda/board/boards/white.h
  86. 1
      panda/board/bootstub.c
  87. 2
      panda/board/can_comms.h
  88. 2
      panda/board/can_definitions.h
  89. 4
      panda/board/comms_definitions.h
  90. 4
      panda/board/config.h
  91. 2
      panda/board/crc.h
  92. 50
      panda/board/drivers/bxcan.h
  93. 14
      panda/board/drivers/can_common.h
  94. 13
      panda/board/drivers/fdcan.h
  95. 83
      panda/board/drivers/gmlan_alt.h
  96. 10
      panda/board/drivers/gpio.h
  97. 5
      panda/board/drivers/harness.h
  98. 4
      panda/board/drivers/interrupts.h
  99. 119
      panda/board/drivers/kline_init.h
  100. 12
      panda/board/drivers/spi.h
  101. Some files were not shown because too many files have changed in this diff Show More

1
.gitignore vendored

@ -46,7 +46,6 @@ selfdrive/boardd/boardd
selfdrive/logcatd/logcatd
selfdrive/mapd/default_speeds_by_region.json
system/proclogd/proclogd
selfdrive/ui/_ui
selfdrive/ui/translations/alerts_generated.h
selfdrive/ui/translations/tmp
selfdrive/test/longitudinal_maneuvers/out

82
Jenkinsfile vendored

@ -1,10 +1,23 @@
def retryWithDelay(int maxRetries, int delay, Closure body) {
for (int i = 0; i < maxRetries; i++) {
try {
return body()
} catch (Exception e) {
sleep(delay)
}
}
throw Exception("Failed after ${maxRetries} retries")
}
def device(String ip, String step_label, String cmd) {
withCredentials([file(credentialsId: 'id_rsa', variable: 'key_file')]) {
def ssh_cmd = """
ssh -tt -o StrictHostKeyChecking=no -i ${key_file} 'comma@${ip}' /usr/bin/bash <<'END'
ssh -tt -o ConnectTimeout=5 -o ServerAliveInterval=5 -o ServerAliveCountMax=2 -o BatchMode=yes -o StrictHostKeyChecking=no -i ${key_file} 'comma@${ip}' /usr/bin/bash <<'END'
set -e
shopt -s huponexit # kill all child processes when the shell exits
export CI=1
export PYTHONWARNINGS=error
export LOGPRINT=debug
@ -14,7 +27,8 @@ export GIT_BRANCH=${env.GIT_BRANCH}
export GIT_COMMIT=${env.GIT_COMMIT}
export AZURE_TOKEN='${env.AZURE_TOKEN}'
export MAPBOX_TOKEN='${env.MAPBOX_TOKEN}'
export PYTEST_ADDOPTS="-c selfdrive/test/pytest-tici.ini --rootdir ."
# only use 1 thread for tici tests since most require HIL
export PYTEST_ADDOPTS="-n 0"
export GIT_SSH_COMMAND="ssh -i /data/gitkey"
@ -23,7 +37,9 @@ source ~/.bash_profile
if [ -f /TICI ]; then
source /etc/profile
rm -rf /tmp/tmp*
rm -rf ~/.commacache
rm -rf /dev/shm/*
if ! systemctl is-active --quiet systemd-resolved; then
echo "restarting resolved"
@ -55,16 +71,17 @@ END"""
}
}
def deviceStage(String stageName, String deviceType, List env, def steps) {
def deviceStage(String stageName, String deviceType, List extra_env, def steps) {
stage(stageName) {
if (currentBuild.result != null) {
return
}
def extra = env.collect { "export ${it}" }.join('\n');
def extra = extra_env.collect { "export ${it}" }.join('\n');
def branch = env.BRANCH_NAME ?: 'master';
lock(resource: "", label: deviceType, inversePrecedence: true, variable: 'device_ip', quantity: 1, resourceSelectStrategy: 'random') {
docker.image('ghcr.io/commaai/alpine-ssh').inside('--user=root') {
lock(resource: "", label: deviceType, inversePrecedence: true, variable: 'device_ip', quantity: 1) {
timeout(time: 20, unit: 'MINUTES') {
retry (3) {
device(device_ip, "git checkout", extra + "\n" + readFile("selfdrive/test/setup_device_ci.sh"))
@ -87,17 +104,21 @@ def pcStage(String stageName, Closure body) {
checkout scm
def dockerArgs = "--user=batman -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/scons_cache:/tmp/scons_cache -e PYTHONPATH=${env.WORKSPACE}";
docker.build("openpilot-base:build-${env.GIT_COMMIT}", "-f Dockerfile.openpilot_base .").inside(dockerArgs) {
def dockerArgs = "--user=batman -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/scons_cache:/tmp/scons_cache -e PYTHONPATH=${env.WORKSPACE} --cpus=8 --memory 16g -e PYTEST_ADDOPTS='-n8'";
def openpilot_base = retryWithDelay (3, 15) {
return docker.build("openpilot-base:build-${env.GIT_COMMIT}", "-f Dockerfile.openpilot_base .")
}
lock(resource: "", label: 'pc', inversePrecedence: true, quantity: 1) {
openpilot_base.inside(dockerArgs) {
timeout(time: 20, unit: 'MINUTES') {
try {
// TODO: remove these after all jenkins jobs are running as batman (merged with master)
sh "sudo chown -R batman:batman /tmp/scons_cache"
sh "sudo chown -R batman:batman /tmp/comma_download_cache"
retryWithDelay (3, 15) {
sh "git config --global --add safe.directory '*'"
sh "git submodule update --init --recursive"
sh "git lfs pull"
}
body()
} finally {
sh "rm -rf ${env.WORKSPACE}/* || true"
@ -107,6 +128,7 @@ def pcStage(String stageName, Closure body) {
}
}
}
}
}
def setupCredentials() {
@ -119,6 +141,7 @@ def setupCredentials() {
}
}
node {
env.CI = "1"
env.PYTHONWARNINGS = "error"
@ -130,7 +153,7 @@ node {
env.GIT_COMMIT = checkout(scm).GIT_COMMIT
def excludeBranches = ['master-ci', 'devel', 'devel-staging', 'release3', 'release3-staging',
'dashcam3', 'dashcam3-staging', 'testing-closet*', 'hotfix-*']
'testing-closet*', 'hotfix-*']
def excludeRegex = excludeBranches.join('|').replaceAll('\\*', '.*')
if (env.BRANCH_NAME != 'master') {
@ -142,7 +165,7 @@ node {
try {
if (env.BRANCH_NAME == 'devel-staging') {
deviceStage("build release3-staging", "tici-needs-can", [], [
["build release3-staging & dashcam3-staging", "RELEASE_BRANCH=release3-staging DASHCAM_BRANCH=dashcam3-staging $SOURCE_DIR/release/build_release.sh"],
["build release3-staging", "RELEASE_BRANCH=release3-staging $SOURCE_DIR/release/build_release.sh"],
])
}
@ -156,8 +179,9 @@ node {
parallel (
// tici tests
'onroad tests': {
deviceStage("onroad", "tici-needs-can", ["SKIP_COPY=1"], [
["build master-ci", "cd $SOURCE_DIR/release && TARGET_DIR=$TEST_DIR ./build_devel.sh"],
deviceStage("onroad", "tici-needs-can", [], [
// TODO: ideally, this test runs in master-ci, but it takes 5+m to build it
//["build master-ci", "cd $SOURCE_DIR/release && TARGET_DIR=$TEST_DIR $SOURCE_DIR/scripts/retry.sh ./build_devel.sh"],
["build openpilot", "cd selfdrive/manager && ./build.py"],
["check dirty", "release/check-dirty.sh"],
["onroad tests", "pytest selfdrive/test/test_onroad.py -s"],
@ -165,18 +189,17 @@ node {
])
},
'HW + Unit Tests': {
deviceStage("tici", "tici-common", ["UNSAFE=1"], [
deviceStage("tici-hardware", "tici-common", ["UNSAFE=1"], [
["build", "cd selfdrive/manager && ./build.py"],
["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py"],
["test power draw", "./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 pigeond", "pytest system/sensord/tests/test_pigeond.py"],
["test manager", "pytest selfdrive/manager/test/test_manager.py"],
["test nav", "pytest selfdrive/navd/tests/"],
])
},
'loopback': {
deviceStage("tici", "tici-loopback", ["UNSAFE=1"], [
deviceStage("loopback", "tici-loopback", ["UNSAFE=1"], [
["build openpilot", "cd selfdrive/manager && ./build.py"],
["test boardd loopback", "pytest selfdrive/boardd/tests/test_boardd_loopback.py"],
])
@ -204,7 +227,7 @@ node {
])
},
'replay': {
deviceStage("tici", "tici-replay", ["UNSAFE=1"], [
deviceStage("model-replay", "tici-replay", ["UNSAFE=1"], [
["build", "cd selfdrive/manager && ./build.py"],
["model replay", "selfdrive/test/process_replay/model_replay.py"],
])
@ -216,27 +239,10 @@ node {
["test pandad", "pytest selfdrive/boardd/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 rawgpsd", "pytest system/sensord/rawgps/test_rawgps.py"],
["test qcomgpsd", "pytest system/qcomgpsd/tests/test_qcomgpsd.py"],
])
},
// *** PC tests ***
'PC tests': {
pcStage("PC tests") {
// tests that our build system's dependencies are configured properly,
// needs a machine with lots of cores
sh label: "test multi-threaded build", script: "scons --no-cache --random -j42"
}
},
'car tests': {
pcStage("car tests") {
sh label: "build", script: "selfdrive/manager/build.py"
sh label: "test_models.py", script: "INTERNAL_SEG_CNT=250 INTERNAL_SEG_LIST=selfdrive/car/tests/test_models_segs.txt FILEREADER_CACHE=1 \
pytest -n42 --dist=loadscope selfdrive/car/tests/test_models.py"
sh label: "test_car_interfaces.py", script: "MAX_EXAMPLES=100 pytest -n42 --dist=load selfdrive/car/tests/test_car_interfaces.py"
}
},
)
}
} catch (Exception e) {

@ -1,18 +1,4 @@
![openpilot on the comma 3X](https://github.com/commaai/openpilot/assets/4038174/f1081737-8718-4241-a22a-3ceba526361a)
Table of Contents
=======================
* [What is openpilot?](#what-is-openpilot)
* [Running in a car](#running-on-a-dedicated-device-in-a-car)
* [Running on PC](#running-on-pc)
* [Community and Contributing](#community-and-contributing)
* [User Data and comma Account](#user-data-and-comma-account)
* [Safety and Testing](#safety-and-testing)
* [Directory Structure](#directory-structure)
* [Licensing](#licensing)
---
[![openpilot on the comma 3X](https://github.com/commaai/openpilot/assets/8762862/f09e6d29-db2d-4179-80c2-51e8d92bdb5c)](https://comma.ai/shop/comma-3x)
What is openpilot?
------
@ -21,59 +7,47 @@ What is openpilot?
<table>
<tr>
<td><a href="https://youtu.be/NmBfgOanCyk" title="Video By Greer Viau"><img src="https://i.imgur.com/1w8c6d2.jpg"></a></td>
<td><a href="https://youtu.be/VHKyqZ7t8Gw" title="Video By Logan LeGrand"><img src="https://i.imgur.com/LnBucik.jpg"></a></td>
<td><a href="https://youtu.be/VxiR4iyBruo" title="Video By Charlie Kim"><img src="https://i.imgur.com/4Qoy48c.jpg"></a></td>
<td><a href="https://youtu.be/-IkImTe1NYE" title="Video By Aragon"><img src="https://i.imgur.com/04VNzPf.jpg"></a></td>
</tr>
<tr>
<td><a href="https://youtu.be/iIUICQkdwFQ" title="Video By Logan LeGrand"><img src="https://i.imgur.com/b1LHQTy.jpg"></a></td>
<td><a href="https://youtu.be/XOsa0FsVIsg" title="Video By PinoyDrives"><img src="https://i.imgur.com/6FG0Bd8.jpg"></a></td>
<td><a href="https://youtu.be/bCwcJ98R_Xw" title="Video By JS"><img src="https://i.imgur.com/zO18CbW.jpg"></a></td>
<td><a href="https://youtu.be/BQ0tF3MTyyc" title="Video By Tsai-Fi"><img src="https://i.imgur.com/eZzelq3.jpg"></a></td>
<td><a href="https://youtu.be/NmBfgOanCyk" title="Video By Greer Viau"><img src="https://github.com/commaai/openpilot/assets/8762862/2f7112ae-f748-4f39-b617-fabd689c3772"></a></td>
<td><a href="https://youtu.be/VHKyqZ7t8Gw" title="Video By Logan LeGrand"><img src="https://github.com/commaai/openpilot/assets/8762862/92351544-2833-40d7-9e0b-7ef7ae37ec4c"></a></td>
<td><a href="https://youtu.be/SUIZYzxtMQs" title="A drive to Taco Bell"><img src="https://github.com/commaai/openpilot/assets/8762862/05ceefc5-2628-439c-a9b2-89ce77dc6f63"></a></td>
</tr>
</table>
Running on a dedicated device in a car
To start using openpilot in a car
------
To use openpilot in a car, you need four things
1. **Supported Device:** A comma 3/3X. You can purchase these devices from (https://comma.ai/shop/comma-3x)
2. **Software:** The setup procedure for the comma 3/3X allows users to enter a URL for custom software.
To install the release version of openpilot, use the URL `openpilot.comma.ai`.
To install openpilot master (for more advanced users), use the URL `installer.comma.ai/commaai/master`. You can replace "commaai" with another GitHub username to install a fork.
3. **Supported Car:** Ensure that you have one of [the 250+ supported cars](docs/CARS.md). openpilot supports a wide range of car makes including Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, Ford, and many more.
If your car is not officially listed as supported but has adaptive cruise control and lane-keeping assist, it's likely capable of running openpilot.
To use openpilot in a car, you need four things:
1. **Supported Device:** a comma 3/3X, available at [comma.ai/shop](https://comma.ai/shop/comma-3x).
2. **Software:** The setup procedure for the comma 3/3X allows users to enter a URL for custom software. Use the URL `openpilot.comma.ai` to install the release version.
3. **Supported Car:** Ensure that you have one of [the 250+ supported cars](docs/CARS.md).
4. **Car Harness:** You will also need a [car harness](https://comma.ai/shop/car-harness) to connect your comma 3/3X to your car.
We have detailed instructions for [how to install the harness and device in a car](https://comma.ai/setup).
Running on PC
------
All openpilot services can run as usual on a PC without requiring special hardware or a car. You can also run openpilot on recorded or simulated data to develop or experiment with openpilot.
With openpilot's tools, you can plot logs, replay drives, and watch the full-res camera streams. See [the tools README](tools/README.md) for more information.
You can also run openpilot in simulation [with the CARLA simulator](tools/sim/README.md). This allows openpilot to drive around a virtual car on your Ubuntu machine. The whole setup should only take a few minutes but does require a decent GPU.
We have detailed instructions for [how to install the harness and device in a car](https://comma.ai/setup). Note that it's possible to run openpilot on [other hardware](https://blog.comma.ai/self-driving-car-for-free/), although it's not plug-and-play.
A PC running openpilot can also control your vehicle if it is connected to a [webcam](https://github.com/commaai/openpilot/tree/master/tools/webcam), a [black panda](https://comma.ai/shop/products/panda), and a [harness](https://comma.ai/shop/products/car-harness).
Community and Contributing
To start developing openpilot
------
openpilot is developed by [comma](https://comma.ai/) and by users like you. We welcome both pull requests and issues on [GitHub](http://github.com/commaai/openpilot). Bug fixes and new car ports are encouraged. Check out [the contributing docs](docs/CONTRIBUTING.md).
openpilot is developed by [comma](https://comma.ai/) and by users like you. We welcome both pull requests and issues on [GitHub](http://github.com/commaai/openpilot).
Documentation related to openpilot development can be found on [docs.comma.ai](https://docs.comma.ai). Information about running openpilot (e.g. FAQ, fingerprinting, troubleshooting, custom forks, community hardware) should go on the [wiki](https://github.com/commaai/openpilot/wiki).
* Join the [community Discord](https://discord.comma.ai)
* Check out [the contributing docs](docs/CONTRIBUTING.md)
* Check out the [openpilot tools](tools/)
* Read about the [development workflow](docs/WORKFLOW.md)
* Code documentation lives at https://docs.comma.ai
* Information about running openpilot lives on the [community wiki](https://github.com/commaai/openpilot/wiki)
You can add support for your car by following guides we have written for [Brand](https://blog.comma.ai/how-to-write-a-car-port-for-openpilot/) and [Model](https://blog.comma.ai/openpilot-port-guide-for-toyota-models/) ports. Generally, a car with adaptive cruise control and lane keep assist is a good candidate. [Join our Discord](https://discord.comma.ai) to discuss car ports: most car makes have a dedicated channel.
Want to get paid to work on openpilot? [comma is hiring](https://comma.ai/jobs#open-positions) and offers lots of [bounties](docs/BOUNTIES.md) for external contributors.
Want to get paid to work on openpilot? [comma is hiring](https://comma.ai/jobs#open-positions).
Safety and Testing
----
And [follow us on Twitter](https://twitter.com/comma_ai).
* openpilot observes [ISO26262](https://en.wikipedia.org/wiki/ISO_26262) guidelines, see [SAFETY.md](docs/SAFETY.md) for more details.
* openpilot has software-in-the-loop [tests](.github/workflows/selfdrive_tests.yaml) that run on every commit.
* The code enforcing the safety model lives in panda and is written in C, see [code rigor](https://github.com/commaai/panda#code-rigor) for more details.
* panda has software-in-the-loop [safety tests](https://github.com/commaai/panda/tree/master/tests/safety).
* Internally, we have a hardware-in-the-loop Jenkins test suite that builds and unit tests the various processes.
* panda has additional hardware-in-the-loop [tests](https://github.com/commaai/panda/blob/master/Jenkinsfile).
* We run the latest openpilot in a testing closet containing 10 comma devices continuously replaying routes.
User Data and comma Account
------
@ -87,49 +61,6 @@ The driver-facing camera is only logged if you explicitly opt-in in settings. Th
By using openpilot, you agree to [our Privacy Policy](https://comma.ai/privacy). You understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma for the use of this data.
Safety and Testing
----
* openpilot observes ISO26262 guidelines, see [SAFETY.md](docs/SAFETY.md) for more details.
* openpilot has software-in-the-loop [tests](.github/workflows/selfdrive_tests.yaml) that run on every commit.
* The code enforcing the safety model lives in panda and is written in C, see [code rigor](https://github.com/commaai/panda#code-rigor) for more details.
* panda has software-in-the-loop [safety tests](https://github.com/commaai/panda/tree/master/tests/safety).
* Internally, we have a hardware-in-the-loop Jenkins test suite that builds and unit tests the various processes.
* panda has additional hardware-in-the-loop [tests](https://github.com/commaai/panda/blob/master/Jenkinsfile).
* We run the latest openpilot in a testing closet containing 10 comma devices continuously replaying routes.
Directory Structure
------
.
├── cereal # The messaging spec and libs used for all logs
├── common # Library like functionality we've developed here
├── docs # Documentation
├── opendbc # Files showing how to interpret data from cars
├── panda # Code used to communicate on CAN
├── third_party # External libraries
└── system # Generic services
├── camerad # Driver to capture images from the camera sensors
├── hardware # Hardware abstraction classes
├── logcatd # systemd journal as a service
├── loggerd # Logger and uploader of car data
├── proclogd # Logs information from /proc
├── sensord # IMU interface code
└── ubloxd # u-blox GNSS module interface code
└── selfdrive # Code needed to drive the car
├── assets # Fonts, images, and sounds for UI
├── athena # Allows communication with the app
├── boardd # Daemon to talk to the board
├── car # Car specific code to read states and control actuators
├── controls # Planning and controls
├── debug # Tools to help you debug and do car ports
├── locationd # Precise localization and vehicle parameter estimation
├── manager # Daemon that starts/stops all other daemons as needed
├── modeld # Driving and monitoring model runners
├── monitoring # Daemon to determine driver attention
├── navd # Turn-by-turn navigation
├── test # Unit tests, system tests, and a car simulator
└── ui # The UI
Licensing
------
@ -145,5 +76,5 @@ NO WARRANTY EXPRESSED OR IMPLIED.**
<img src="https://d1qb2nb5cznatu.cloudfront.net/startups/i/1061157-bc7e9bf3b246ece7322e6ffe653f6af8-medium_jpg.jpg?buster=1458363130" width="75"></img> <img src="https://cdn-images-1.medium.com/max/1600/1*C87EjxGeMPrkTuVRVWVg4w.png" width="225"></img>
[![openpilot tests](https://github.com/commaai/openpilot/workflows/openpilot%20tests/badge.svg?event=push)](https://github.com/commaai/openpilot/actions)
![openpilot tests](https://github.com/commaai/openpilot/actions/workflows/selfdrive_tests.yaml/badge.svg)
[![codecov](https://codecov.io/gh/commaai/openpilot/branch/master/graph/badge.svg)](https://codecov.io/gh/commaai/openpilot)

@ -1,3 +1,23 @@
Version 0.9.6 (2024-02-27)
========================
* New driving model
* Vision model trained on more data
* Improved driving performance
* Directly outputs curvature for lateral control
* New driver monitoring model
* Trained on larger dataset
* AGNOS 9
* comma body streaming and controls over WebRTC
* Improved fuzzy fingerprinting for many makes and models
* Alpha longitudinal support for new Toyota models
* Chevrolet Equinox 2019-22 support thanks to JasonJShuler and nworb-cire!
* Dodge Durango 2020-21 support
* Hyundai Staria 2023 support thanks to sunnyhaibin!
* Kia Niro Plug-in Hybrid 2022 support thanks to sunnyhaibin!
* Lexus LC 2024 support thanks to nelsonjchen!
* Toyota RAV4 2023-24 support
* Toyota RAV4 Hybrid 2023-24 support
Version 0.9.5 (2023-11-17)
========================
* New driving model

@ -9,11 +9,16 @@ import SCons.Errors
SCons.Warnings.warningAsException(True)
# pending upstream fix - https://github.com/SCons/scons/issues/4461
#SetOption('warn', 'all')
TICI = os.path.isfile('/TICI')
AGNOS = TICI
Decider('MD5-timestamp')
SetOption('num_jobs', int(os.cpu_count()/2))
AddOption('--kaitai',
action='store_true',
help='Regenerate kaitai struct parsers')
@ -116,10 +121,7 @@ else:
cflags = []
cxxflags = []
cpppath = []
rpath += [
Dir("#cereal").abspath,
Dir("#common").abspath
]
rpath += []
# MacOS
if arch == "Darwin":
@ -143,9 +145,6 @@ else:
libpath = [
f"#third_party/acados/{arch}/lib",
f"#third_party/libyuv/{arch}/lib",
f"#third_party/mapbox-gl-native-qt/{arch}",
"#cereal",
"#common",
"/usr/lib",
"/usr/local/lib",
]
@ -208,11 +207,12 @@ env = Environment(
"#third_party/json11",
"#third_party/linux/include",
"#third_party/snpe/include",
"#third_party/mapbox-gl-native-qt/include",
"#third_party/qrcode",
"#third_party",
"#cereal",
"#opendbc/can",
"#third_party/maplibre-native-qt/include",
f"#third_party/maplibre-native-qt/{arch}/include"
],
CC='clang',
@ -229,10 +229,13 @@ env = Environment(
"#opendbc/can",
"#selfdrive/boardd",
"#common",
"#rednose/helpers",
],
CYTHONCFILESUFFIX=".cpp",
COMPILATIONDB_USE_ABSPATH=True,
tools=["default", "cython", "compilation_db"],
REDNOSE_ROOT="#",
tools=["default", "cython", "compilation_db", "rednose_filter"],
toolpath=["#rednose_repo/site_scons/site_tools"],
)
if arch == "Darwin":
@ -294,8 +297,11 @@ else:
qt_env['QTDIR'] = qt_install_prefix
qt_dirs = [
f"{qt_install_headers}",
f"{qt_install_headers}/QtGui/5.12.8/QtGui",
]
qt_gui_path = os.path.join(qt_install_headers, "QtGui")
qt_gui_dirs = [d for d in os.listdir(qt_gui_path) if os.path.isdir(os.path.join(qt_gui_path, d))]
qt_dirs += [f"{qt_install_headers}/QtGui/{qt_gui_dirs[0]}/QtGui", ] if qt_gui_dirs else []
qt_dirs += [f"{qt_install_headers}/Qt{m}" for m in qt_modules]
qt_libs = [f"Qt5{m}" for m in qt_modules]
@ -312,7 +318,7 @@ try:
except SCons.Errors.UserError:
qt_env.Tool('qt')
qt_env['CPPPATH'] += qt_dirs + ["#selfdrive/ui/qt/"]
qt_env['CPPPATH'] += qt_dirs# + ["#selfdrive/ui/qt/"]
qt_flags = [
"-D_REENTRANT",
"-DQT_NO_DEBUG",
@ -325,7 +331,8 @@ qt_flags = [
"-DQT_MESSAGELOGCONTEXT",
]
qt_env['CXXFLAGS'] += qt_flags
qt_env['LIBPATH'] += ['#selfdrive/ui']
qt_env['LIBPATH'] += ['#selfdrive/ui', f"#third_party/maplibre-native-qt/{arch}/lib"]
qt_env['RPATH'] += [Dir(f"#third_party/maplibre-native-qt/{arch}/lib").srcnode().abspath]
qt_env['LIBS'] = qt_libs
if GetOption("clazy"):
@ -367,31 +374,7 @@ SConscript([
'panda/SConscript',
])
# Build rednose library and ekf models
rednose_deps = [
"#selfdrive/locationd/models/constants.py",
"#selfdrive/locationd/models/gnss_helpers.py",
]
rednose_config = {
'generated_folder': '#selfdrive/locationd/models/generated',
'to_build': {
'gnss': ('#selfdrive/locationd/models/gnss_kf.py', True, [], rednose_deps),
'live': ('#selfdrive/locationd/models/live_kf.py', True, ['live_kf_constants.h'], rednose_deps),
'car': ('#selfdrive/locationd/models/car_kf.py', True, [], rednose_deps),
},
}
if arch != "larch64":
rednose_config['to_build'].update({
'loc_4': ('#selfdrive/locationd/models/loc_kf.py', True, [], rednose_deps),
'lane': ('#selfdrive/locationd/models/lane_kf.py', True, [], rednose_deps),
'pos_computer_4': ('#rednose/helpers/lst_sq_computer.py', False, [], []),
'pos_computer_5': ('#rednose/helpers/lst_sq_computer.py', False, [], []),
'feature_handler_5': ('#rednose/helpers/feature_handler.py', False, [], []),
})
Export('rednose_config')
# Build rednose library
SConscript(['rednose/SConscript'])
# Build system services

@ -31,7 +31,7 @@ if os.getenv("RELEASE"):
assert os.path.exists(cert_fn), 'Certificate file not found. Please specify absolute path'
else:
BUILD_TYPE = "DEBUG"
cert_fn = File("../certs/debug").srcnode().abspath
cert_fn = File("../certs/debug").srcnode().relpath
common_flags += ["-DALLOW_DEBUG"]
if os.getenv("DEBUG"):
@ -99,7 +99,7 @@ def to_c_uint32(x):
def get_key_header(name):
from Crypto.PublicKey import RSA
public_fn = File(f'../certs/{name}.pub').srcnode().abspath
public_fn = f'../certs/{name}.pub'
rsa = RSA.importKey(open(public_fn).read())
assert(rsa.size_in_bits() == 1024)
@ -132,7 +132,7 @@ with open("obj/cert.h", "w") as f:
for project_name in build_projects:
project = build_projects[project_name]
linkerscript_fn = File(project["LINKER_SCRIPT"]).srcnode().abspath
linkerscript_fn = File(project["LINKER_SCRIPT"]).srcnode().relpath
flags = [
"-Wall",
@ -193,5 +193,5 @@ for project_name in build_projects:
main_bin = project_env.Objcopy(f"obj/{project_name}.bin", main_elf)
# Sign main
sign_py = File("../crypto/sign.py").srcnode().abspath
sign_py = File("../crypto/sign.py").srcnode().relpath
panda_bin_signed = project_env.Command(f"obj/{project_name}.bin.signed", main_bin, f"SETLEN=1 {sign_py} $SOURCE $TARGET {cert_fn}")

@ -8,8 +8,8 @@
* is using in the C source code, usually in main.c. This file contains:
* - Configuration section that allows to select:
* - The STM32F4xx device used in the target application
* - To use or not the peripherals drivers in application code(i.e.
* code will be based on direct access to peripherals registers
* - To use or not the peripheral's drivers in application code(i.e.
* code will be based on direct access to peripheral's registers
* rather than drivers API), this option is controlled by
* "#define USE_HAL_DRIVER"
*

@ -1,4 +1,3 @@
# pylint: skip-file
import os
import capnp

@ -51,7 +51,6 @@ struct CarEvent @0x9b1657f34caf3ad3 {
parkBrake @29;
manualRestart @30;
lowSpeedLockout @31;
plannerError @32;
joystickDebug @34;
steerTempUnavailableSilent @35;
resumeRequired @36;
@ -142,6 +141,7 @@ struct CarEvent @0x9b1657f34caf3ad3 {
startupFuzzyFingerprintDEPRECATED @97;
noTargetDEPRECATED @25;
brakeUnavailableDEPRECATED @2;
plannerErrorDEPRECATED @32;
}
}
@ -484,6 +484,7 @@ struct CarParams {
openpilotLongitudinalControl @37 :Bool; # is openpilot doing the longitudinal control?
carVin @38 :Text; # VIN number queried during fingerprinting
dashcamOnly @41: Bool;
passive @73: Bool; # is openpilot in control?
transmissionType @43 :TransmissionType;
carFw @44 :List(CarFw);
@ -595,12 +596,14 @@ struct CarParams {
body @27;
hyundaiCanfd @28;
volkswagenMqbEvo @29;
chryslerCusw @30;
}
enum SteerControlType {
torque @0;
angle @1;
curvature @2;
curvatureDEPRECATED @2;
}
enum TransmissionType {

@ -33,6 +33,7 @@ struct InitData {
deviceType @3 :DeviceType;
version @4 :Text;
gitCommit @10 :Text;
gitCommitDate @21 :Text;
gitBranch @11 :Text;
gitRemote @13 :Text;
@ -130,8 +131,9 @@ struct InitData {
struct FrameData {
frameId @0 :UInt32;
encodeId @1 :UInt32; # DEPRECATED
frameIdSensor @25 :UInt32;
requestId @28 :UInt32;
encodeId @1 :UInt32;
frameType @7 :FrameType;
@ -166,6 +168,7 @@ struct FrameData {
unknown @0;
ar0231 @1;
ox03c10 @2;
os04c10 @3;
}
frameLengthDEPRECATED @3 :Int32;
@ -297,6 +300,29 @@ struct GpsLocationData {
}
}
enum Desire {
none @0;
turnLeft @1;
turnRight @2;
laneChangeLeft @3;
laneChangeRight @4;
keepLeft @5;
keepRight @6;
}
enum LaneChangeState {
off @0;
preLaneChange @1;
laneChangeStarting @2;
laneChangeFinishing @3;
}
enum LaneChangeDirection {
none @0;
left @1;
right @2;
}
struct CanData {
address @0 :UInt32;
busTime @1 :UInt16;
@ -331,7 +357,6 @@ struct DeviceState @0xa4d8b5af2aa492eb {
cpuTempC @26 :List(Float32);
gpuTempC @27 :List(Float32);
memoryTempC @28 :Float32;
ambientTempC @30 :Float32;
nvmeTempC @35 :List(Float32);
modemTempC @36 :List(Float32);
pmicTempC @39 :List(Float32);
@ -404,11 +429,11 @@ struct DeviceState @0xa4d8b5af2aa492eb {
chargingErrorDEPRECATED @17 :Bool;
chargingDisabledDEPRECATED @18 :Bool;
usbOnlineDEPRECATED @12 :Bool;
ambientTempCDEPRECATED @30 :Float32;
}
struct PandaState @0xa7649e2575e4591e {
ignitionLine @2 :Bool;
gasInterceptorDetected @4 :Bool;
rxBufferOverflow @7 :UInt32;
txBufferOverflow @8 :UInt32;
gmlanSendErrs @9 :UInt32;
@ -494,6 +519,7 @@ struct PandaState @0xa7649e2575e4591e {
redPanda @7;
redPandaV2 @8;
tres @9;
cuatro @10;
}
enum HarnessStatus {
@ -541,6 +567,7 @@ struct PandaState @0xa7649e2575e4591e {
}
}
gasInterceptorDetectedDEPRECATED @4 :Bool;
startedSignalDetectedDEPRECATED @5 :Bool;
hasGpsDEPRECATED @6 :Bool;
fanSpeedRpmDEPRECATED @11 :UInt16;
@ -666,7 +693,6 @@ struct ControlsState @0x97ff69c53601abf1 {
aTarget @35 :Float32;
curvature @37 :Float32; # path curvature from vehicle model
desiredCurvature @61 :Float32; # lag adjusted curvatures used by lateral controllers
desiredCurvatureRate @62 :Float32;
forceDecel @51 :Bool;
# UI alerts
@ -688,8 +714,8 @@ struct ControlsState @0x97ff69c53601abf1 {
angleState @58 :LateralAngleState;
debugState @59 :LateralDebugState;
torqueState @60 :LateralTorqueState;
curvatureState @65 :LateralCurvatureState;
curvatureStateDEPRECATED @65 :LateralCurvatureState;
lqrStateDEPRECATED @55 :LateralLQRState;
}
@ -824,6 +850,7 @@ struct ControlsState @0x97ff69c53601abf1 {
steerOverrideDEPRECATED @20 :Bool;
steeringAngleDesiredDegDEPRECATED @29 :Float32;
canMonoTimesDEPRECATED @21 :List(UInt64);
desiredCurvatureRateDEPRECATED @62 :Float32;
}
# All SI units and in device frame
@ -875,7 +902,8 @@ struct ModelDataV2 {
locationMonoTime @24 :UInt64;
# e2e lateral planner
lateralPlannerSolution @25: LateralPlannerSolution;
lateralPlannerSolutionDEPRECATED @25: LateralPlannerSolution;
action @26: Action;
struct LeadDataV2 {
prob @0 :Float32; # probability that car is your lead at time t
@ -913,6 +941,9 @@ struct ModelDataV2 {
desireState @5 :List(Float32);
disengagePredictions @6 :DisengagePredictions;
hardBrakePredicted @7 :Bool;
laneChangeState @8 :LaneChangeState;
laneChangeDirection @9 :LaneChangeDirection;
# deprecated
brakeDisengageProbDEPRECATED @2 :Float32;
@ -954,6 +985,9 @@ struct ModelDataV2 {
yawRateStd @7 :List(Float32);
}
struct Action {
desiredCurvature @0 :Float32;
}
}
struct EncodeIndex {
@ -1844,11 +1878,12 @@ struct QcomGnss @0xde94674b07ae51c1 {
}
struct Clocks {
bootTimeNanos @0 :UInt64;
monotonicNanos @1 :UInt64;
monotonicRawNanos @2 :UInt64;
wallTimeNanos @3 :UInt64;
modemUptimeMillis @4 :UInt64;
wallTimeNanos @3 :UInt64; # unix epoch time
bootTimeNanosDEPRECATED @0 :UInt64;
monotonicNanosDEPRECATED @1 :UInt64;
monotonicRawNanosDEPRECATD @2 :UInt64;
modemUptimeMillisDEPRECATED @4 :UInt64;
}
struct LiveMpcData {
@ -2167,6 +2202,8 @@ struct EncodeData {
data @1 :Data;
header @2 :Data;
unixTimestampNanos @3 :UInt64;
width @4 :UInt32;
height @5 :UInt32;
}
struct UserFlag {
@ -2214,7 +2251,6 @@ struct Event {
carState @22 :Car.CarState;
carControl @23 :Car.CarControl;
longitudinalPlan @24 :LongitudinalPlan;
lateralPlan @64 :LateralPlan;
uiPlan @106 :UiPlan;
ubloxGnss @34 :UbloxGnss;
ubloxRaw @39 :Data;
@ -2226,7 +2262,7 @@ struct Event {
liveTorqueParameters @94 :LiveTorqueParametersData;
cameraOdometry @63 :CameraOdometry;
thumbnail @66: Thumbnail;
carEvents @68: List(Car.CarEvent);
onroadEvents @68: List(Car.CarEvent);
carParams @69: Car.CarParams;
driverMonitoringState @71: DriverMonitoringState;
liveLocationKalman @72 :LiveLocationKalman;
@ -2335,5 +2371,6 @@ struct Event {
pandaStateDEPRECATED @12 :PandaState;
driverStateDEPRECATED @59 :DriverStateDEPRECATED;
sensorEventsDEPRECATED @11 :List(SensorEventData);
lateralPlanDEPRECATED @64 :LateralPlan;
}
}

@ -22,7 +22,6 @@ assert delete_fake_prefix
assert wait_for_one_event
NO_TRAVERSAL_LIMIT = 2**64-1
AVG_FREQ_HISTORY = 100
context = Context()
@ -41,10 +40,13 @@ def log_from_bytes(dat: bytes) -> capnp.lib.capnp._DynamicStructReader:
return msg
def new_message(service: Optional[str] = None, size: Optional[int] = None) -> capnp.lib.capnp._DynamicStructBuilder:
dat = log.Event.new_message()
dat.logMonoTime = int(time.monotonic() * 1e9)
dat.valid = True
def new_message(service: Optional[str], size: Optional[int] = None, **kwargs) -> capnp.lib.capnp._DynamicStructBuilder:
args = {
'valid': False,
'logMonoTime': int(time.monotonic() * 1e9),
**kwargs
}
dat = log.Event.new_message(**args)
if service is not None:
if size is None:
dat.init(service)
@ -114,14 +116,14 @@ def recv_sock(sock: SubSocket, wait: bool = False) -> Optional[capnp.lib.capnp._
while 1:
if wait and dat is None:
rcv = sock.receive()
recv = sock.receive()
else:
rcv = sock.receive(non_blocking=True)
recv = sock.receive(non_blocking=True)
if rcv is None: # Timeout hit
if recv is None: # Timeout hit
break
dat = rcv
dat = recv
if dat is not None:
dat = log_from_bytes(dat)
@ -152,53 +154,76 @@ def recv_one_retry(sock: SubSocket) -> capnp.lib.capnp._DynamicStructReader:
class SubMaster:
def __init__(self, services: List[str], poll: Optional[List[str]] = None,
def __init__(self, services: List[str], poll: Optional[str] = None,
ignore_alive: Optional[List[str]] = None, ignore_avg_freq: Optional[List[str]] = None,
addr: str = "127.0.0.1"):
ignore_valid: Optional[List[str]] = None, addr: str = "127.0.0.1", frequency: Optional[float] = None):
self.frame = -1
self.seen = {s: False for s in services}
self.updated = {s: False for s in services}
self.rcv_time = {s: 0. for s in services}
self.rcv_frame = {s: 0 for s in services}
self.recv_time = {s: 0. for s in services}
self.recv_frame = {s: 0 for s in services}
self.alive = {s: False for s in services}
self.freq_ok = {s: False for s in services}
self.recv_dts: Dict[str, Deque[float]] = {s: deque(maxlen=AVG_FREQ_HISTORY) for s in services}
self.recv_dts: Dict[str, Deque[float]] = {}
self.sock = {}
self.freq = {}
self.data = {}
self.valid = {}
self.logMonoTime = {}
self.max_freq = {}
self.min_freq = {}
self.poller = Poller()
self.non_polled_services = [s for s in services if poll is not None and
len(poll) and s not in poll]
polled_services = set([poll, ] if poll is not None else services)
self.non_polled_services = set(services) - polled_services
self.ignore_average_freq = [] if ignore_avg_freq is None else ignore_avg_freq
self.ignore_alive = [] if ignore_alive is None else ignore_alive
self.simulation = bool(int(os.getenv("SIMULATION", "0")))
self.ignore_valid = [] if ignore_valid is None else ignore_valid
if bool(int(os.getenv("SIMULATION", "0"))):
self.ignore_alive = services
self.ignore_average_freq = services
# if freq and poll aren't specified, assume the max to be conservative
assert frequency is None or poll is None, "Do not specify 'frequency' - frequency of the polled service will be used."
self.update_freq = frequency or max([SERVICE_LIST[s].frequency for s in polled_services])
for s in services:
if addr is not None:
p = self.poller if s not in self.non_polled_services else None
self.sock[s] = sub_sock(s, poller=p, addr=addr, conflate=True)
self.freq[s] = SERVICE_LIST[s].frequency
try:
data = new_message(s)
except capnp.lib.capnp.KjException: # pylint: disable=c-extension-no-member
except capnp.lib.capnp.KjException:
data = new_message(s, 0) # lists
self.data[s] = getattr(data, s)
self.data[s] = getattr(data.as_reader(), s)
self.logMonoTime[s] = 0
self.valid[s] = data.valid
self.valid[s] = True # FIXME: this should default to False
freq = max(min([SERVICE_LIST[s].frequency, self.update_freq]), 1.)
if s == poll:
max_freq = freq
min_freq = freq
else:
max_freq = min(freq, self.update_freq)
if SERVICE_LIST[s].frequency >= 2*self.update_freq:
min_freq = self.update_freq
elif self.update_freq >= 2*SERVICE_LIST[s].frequency:
min_freq = freq
else:
min_freq = min(freq, freq / 2.)
self.max_freq[s] = max_freq*1.2
self.min_freq[s] = min_freq*0.8
self.recv_dts[s] = deque(maxlen=int(10*freq))
def __getitem__(self, s: str) -> capnp.lib.capnp._DynamicStructReader:
return self.data[s]
def _check_avg_freq(self, s):
return self.rcv_time[s] > 1e-5 and self.freq[s] > 1e-5 and (s not in self.non_polled_services) \
and (s not in self.ignore_average_freq)
def _check_avg_freq(self, s: str) -> bool:
return SERVICE_LIST[s].frequency > 0.99 and (s not in self.ignore_average_freq) and (s not in self.ignore_alive)
def update(self, timeout: int = 1000) -> None:
def update(self, timeout: int = 100) -> None:
msgs = []
for sock in self.poller.poll(timeout):
msgs.append(recv_one_or_none(sock))
@ -216,64 +241,57 @@ class SubMaster:
continue
s = msg.which()
self.seen[s] = True
self.updated[s] = True
if self._check_avg_freq(s):
self.recv_dts[s].append(cur_time - self.rcv_time[s])
self.rcv_time[s] = cur_time
self.rcv_frame[s] = self.frame
if self.recv_time[s] > 1e-5:
self.recv_dts[s].append(cur_time - self.recv_time[s])
self.recv_time[s] = cur_time
self.recv_frame[s] = self.frame
self.data[s] = getattr(msg, s)
self.logMonoTime[s] = msg.logMonoTime
self.valid[s] = msg.valid
if self.simulation:
self.freq_ok[s] = True
self.alive[s] = True
if not self.simulation:
for s in self.data:
# arbitrary small number to avoid float comparison. If freq is 0, we can skip the check
if self.freq[s] > 1e-5:
if SERVICE_LIST[s].frequency > 1e-5:
# alive if delay is within 10x the expected frequency
self.alive[s] = (cur_time - self.rcv_time[s]) < (10. / self.freq[s])
# TODO: check if update frequency is high enough to not drop messages
# freq_ok if average frequency is higher than 90% of expected frequency
if self._check_avg_freq(s):
if len(self.recv_dts[s]) > 0:
avg_dt = sum(self.recv_dts[s]) / len(self.recv_dts[s])
expected_dt = 1 / (self.freq[s] * 0.90)
self.freq_ok[s] = (avg_dt < expected_dt)
else:
self.freq_ok[s] = False
else:
self.freq_ok[s] = True
self.alive[s] = (cur_time - self.recv_time[s]) < (10. / SERVICE_LIST[s].frequency)
# check average frequency; slow to fall, quick to recover
dts = self.recv_dts[s]
assert dts.maxlen is not None
recent_dts = list(dts)[-int(dts.maxlen / 10):]
try:
avg_freq = 1 / (sum(dts) / len(dts))
avg_freq_recent = 1 / (sum(recent_dts) / len(recent_dts))
except ZeroDivisionError:
avg_freq = 0
avg_freq_recent = 0
avg_freq_ok = self.min_freq[s] <= avg_freq <= self.max_freq[s]
recent_freq_ok = self.min_freq[s] <= avg_freq_recent <= self.max_freq[s]
self.freq_ok[s] = avg_freq_ok or recent_freq_ok
else:
self.freq_ok[s] = True
self.alive[s] = True
def all_alive(self, service_list=None) -> bool:
if service_list is None: # check all
service_list = self.alive.keys()
def all_alive(self, service_list: Optional[List[str]] = None) -> bool:
if service_list is None:
service_list = list(self.sock.keys())
return all(self.alive[s] for s in service_list if s not in self.ignore_alive)
def all_freq_ok(self, service_list=None) -> bool:
if service_list is None: # check all
service_list = self.alive.keys()
return all(self.freq_ok[s] for s in service_list if s not in self.ignore_alive)
def all_valid(self, service_list=None) -> bool:
if service_list is None: # check all
service_list = self.valid.keys()
return all(self.valid[s] for s in service_list)
def all_checks(self, service_list=None) -> bool:
if service_list is None: # check all
service_list = self.alive.keys()
return self.all_alive(service_list=service_list) \
and self.all_freq_ok(service_list=service_list) \
and self.all_valid(service_list=service_list)
def all_freq_ok(self, service_list: Optional[List[str]] = None) -> bool:
if service_list is None:
service_list = list(self.sock.keys())
return all(self.freq_ok[s] for s in service_list if self._check_avg_freq(s))
def all_valid(self, service_list: Optional[List[str]] = None) -> bool:
if service_list is None:
service_list = list(self.sock.keys())
return all(self.valid[s] for s in service_list if s not in self.ignore_valid)
def all_checks(self, service_list: Optional[List[str]] = None) -> bool:
return self.all_alive(service_list) and self.all_freq_ok(service_list) and self.all_valid(service_list)
class PubMaster:

@ -53,14 +53,13 @@ services: dict[str, tuple] = {
"ubloxGnss": (True, 10.),
"qcomGnss": (True, 2.),
"gnssMeasurements": (True, 10., 10),
"clocks": (True, 1., 1),
"clocks": (True, 0.1, 1),
"ubloxRaw": (True, 20.),
"liveLocationKalman": (True, 20., 5),
"liveParameters": (True, 20., 5),
"cameraOdometry": (True, 20., 5),
"lateralPlan": (True, 20., 5),
"thumbnail": (True, 0.2, 1),
"carEvents": (True, 1., 1),
"onroadEvents": (True, 1., 1),
"carParams": (True, 0.02, 1),
"roadCameraState": (True, 20., 20),
"driverCameraState": (True, 20., 20),

@ -3,24 +3,19 @@
#include <iostream>
#include <thread>
#include <unistd.h>
#include "cereal/visionipc/ipc.h"
#include "cereal/visionipc/visionipc_client.h"
#include "cereal/visionipc/visionipc_server.h"
#include "cereal/logger/logger.h"
static int connect_to_vipc_server(const std::string &name, bool blocking) {
char* prefix = std::getenv("OPENPILOT_PREFIX");
std::string path = "/tmp/";
if (prefix) {
path = path + std::string(prefix) + "_";
}
path = path + "visionipc_" + name;
int socket_fd = ipc_connect(path.c_str());
const std::string ipc_path = get_ipc_path(name);
int socket_fd = ipc_connect(ipc_path.c_str());
while (socket_fd < 0 && blocking) {
std::cout << "VisionIpcClient connecting" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
socket_fd = ipc_connect(path.c_str());
socket_fd = ipc_connect(ipc_path.c_str());
}
return socket_fd;
}

@ -2,11 +2,8 @@
#include <set>
#include <string>
#include <vector>
#include <unistd.h>
#include "cereal/messaging/messaging.h"
#include "cereal/visionipc/visionipc.h"
#include "cereal/visionipc/visionbuf.h"
class VisionIpcClient {

@ -22,6 +22,14 @@ std::string get_endpoint_name(std::string name, VisionStreamType type){
}
}
std::string get_ipc_path(const std::string& name) {
std::string path = "/tmp/";
if (char* prefix = std::getenv("OPENPILOT_PREFIX")) {
path += std::string(prefix) + "_";
}
return path + "visionipc_" + name;
}
VisionIpcServer::VisionIpcServer(std::string name, cl_device_id device_id, cl_context ctx) : name(name), device_id(device_id), ctx(ctx) {
msg_ctx = Context::create();
@ -83,14 +91,8 @@ void VisionIpcServer::start_listener(){
void VisionIpcServer::listener(){
std::cout << "Starting listener for: " << name << std::endl;
char* prefix = std::getenv("OPENPILOT_PREFIX");
std::string path = "/tmp/";
if (prefix) {
path = path + std::string(prefix) + "_";
}
path = path + "visionipc_" + name;
int sock = ipc_bind(path.c_str());
const std::string ipc_path = get_ipc_path(name);
int sock = ipc_bind(ipc_path.c_str());
assert(sock >= 0);
while (!should_exit){
@ -160,7 +162,7 @@ void VisionIpcServer::listener(){
std::cout << "Stopping listener for: " << name << std::endl;
close(sock);
unlink(path.c_str());
unlink(ipc_path.c_str());
}

@ -6,10 +6,10 @@
#include <map>
#include "cereal/messaging/messaging.h"
#include "cereal/visionipc/visionipc.h"
#include "cereal/visionipc/visionbuf.h"
std::string get_endpoint_name(std::string name, VisionStreamType type);
std::string get_ipc_path(const std::string &name);
class VisionIpcServer {
private:

@ -2,7 +2,6 @@ Import('env', 'envCython', 'arch')
common_libs = [
'params.cc',
'statlog.cc',
'swaglog.cc',
'util.cc',
'i2c.cc',
@ -24,18 +23,17 @@ Export('_common', '_gpucommon')
if GetOption('extras'):
env.Program('tests/test_common',
['tests/test_runner.cc', 'tests/test_util.cc', 'tests/test_swaglog.cc', 'tests/test_ratekeeper.cc'],
['tests/test_runner.cc', 'tests/test_params.cc', 'tests/test_util.cc', 'tests/test_swaglog.cc'],
LIBS=[_common, 'json11', 'zmq', 'pthread'])
# Cython bindings
params_python = envCython.Program('params_pyx.so', 'params_pyx.pyx', LIBS=envCython['LIBS'] + [_common, 'zmq', 'json11'])
SConscript([
'kalman/SConscript',
'transformations/SConscript'
'transformations/SConscript',
])
Import('simple_kalman_python', 'transformations_python')
common_python = [params_python, simple_kalman_python, transformations_python]
Import('transformations_python')
common_python = [params_python, transformations_python]
Export('common_python')

@ -2,7 +2,7 @@ import jwt
import os
import requests
from datetime import datetime, timedelta
from openpilot.common.basedir import PERSIST
from openpilot.system.hardware.hw import Paths
from openpilot.system.version import get_version
API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com')
@ -10,7 +10,7 @@ API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com')
class Api():
def __init__(self, dongle_id):
self.dongle_id = dongle_id
with open(PERSIST+'/comma/id_rsa') as f:
with open(Paths.persist_root()+'/comma/id_rsa') as f:
self.private_key = f.read()
def get(self, *args, **kwargs):

@ -1,11 +1,4 @@
import os
from pathlib import Path
from openpilot.system.hardware import PC
BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../"))
if PC:
PERSIST = os.path.join(str(Path.home()), ".comma", "persist")
else:
PERSIST = "/persist"

@ -1,55 +1,8 @@
import os
import sys
import fcntl
import hashlib
import platform
from cffi import FFI
def suffix():
if platform.system() == "Darwin":
return ".dylib"
else:
return ".so"
def ffi_wrap(name, c_code, c_header, tmpdir="/tmp/ccache", cflags="", libraries=None):
if libraries is None:
libraries = []
cache = name + "_" + hashlib.sha1(c_code.encode('utf-8')).hexdigest()
try:
os.mkdir(tmpdir)
except OSError:
pass
fd = os.open(tmpdir, 0)
fcntl.flock(fd, fcntl.LOCK_EX)
try:
sys.path.append(tmpdir)
try:
mod = __import__(cache)
except Exception:
print(f"cache miss {cache}")
compile_code(cache, c_code, c_header, tmpdir, cflags, libraries)
mod = __import__(cache)
finally:
os.close(fd)
return mod.ffi, mod.lib
def compile_code(name, c_code, c_header, directory, cflags="", libraries=None):
if libraries is None:
libraries = []
ffibuilder = FFI()
ffibuilder.set_source(name, c_code, source_extension='.cpp', libraries=libraries)
ffibuilder.cdef(c_header)
os.environ['OPT'] = "-fwrapv -O2 -DNDEBUG -std=c++1z"
os.environ['CFLAGS'] = cflags
ffibuilder.compile(verbose=True, debug=False, tmpdir=directory)
def wrap_compiled(name, directory):
sys.path.append(directory)
mod = __import__(name)
return mod.ffi, mod.lib

@ -1,60 +1,7 @@
import os
import shutil
import tempfile
from atomicwrites import AtomicWriter
def mkdirs_exists_ok(path):
if path.startswith(('http://', 'https://')):
raise ValueError('URL path')
try:
os.makedirs(path)
except OSError:
if not os.path.isdir(path):
raise
def rm_not_exists_ok(path):
try:
os.remove(path)
except OSError:
if os.path.exists(path):
raise
def rm_tree_or_link(path):
if os.path.islink(path):
os.unlink(path)
elif os.path.isdir(path):
shutil.rmtree(path)
def get_tmpdir_on_same_filesystem(path):
normpath = os.path.normpath(path)
parts = normpath.split("/")
if len(parts) > 1 and parts[1] == "scratch":
return "/scratch/tmp"
elif len(parts) > 2 and parts[2] == "runner":
return f"/{parts[1]}/runner/tmp"
return "/tmp"
class NamedTemporaryDir():
def __init__(self, temp_dir=None):
self._path = tempfile.mkdtemp(dir=temp_dir)
@property
def name(self):
return self._path
def close(self):
shutil.rmtree(self._path)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self.close()
import contextlib
from typing import Optional
class CallbackReader:
@ -76,24 +23,16 @@ class CallbackReader:
return chunk
def _get_fileobject_func(writer, temp_dir):
def _get_fileobject():
return writer.get_fileobject(dir=temp_dir)
return _get_fileobject
def atomic_write_on_fs_tmp(path, **kwargs):
"""Creates an atomic writer using a temporary file in a temporary directory
on the same filesystem as path.
"""
# TODO(mgraczyk): This use of AtomicWriter relies on implementation details to set the temp
# directory.
writer = AtomicWriter(path, **kwargs)
return writer._open(_get_fileobject_func(writer, get_tmpdir_on_same_filesystem(path)))
@contextlib.contextmanager
def atomic_write_in_dir(path: str, mode: str = 'w', buffering: int = -1, encoding: Optional[str] = None, newline: Optional[str] = None,
overwrite: bool = False):
"""Write to a file atomically using a temporary file in the same directory as the destination file."""
dir_name = os.path.dirname(path)
if not overwrite and os.path.exists(path):
raise FileExistsError(f"File '{path}' already exists. To overwrite it, set 'overwrite' to True.")
def atomic_write_in_dir(path, **kwargs):
"""Creates an atomic writer using a temporary file in the same directory
as the destination file.
"""
writer = AtomicWriter(path, **kwargs)
return writer._open(_get_fileobject_func(writer, os.path.dirname(path)))
with tempfile.NamedTemporaryFile(mode=mode, buffering=buffering, encoding=encoding, newline=newline, dir=dir_name, delete=False) as tmp_file:
yield tmp_file
tmp_file_name = tmp_file.name
os.replace(tmp_file_name, path)

@ -1 +0,0 @@
simple_kalman_impl.c

@ -1,5 +0,0 @@
Import('envCython')
simple_kalman_python = envCython.Program('simple_kalman_impl.so', 'simple_kalman_impl.pyx')
Export('simple_kalman_python')

@ -1,12 +0,0 @@
from openpilot.common.kalman.simple_kalman_impl import KF1D as KF1D
assert KF1D
import numpy as np
def get_kalman_gain(dt, A, C, Q, R, iterations=100):
P = np.zeros_like(Q)
for _ in range(iterations):
P = A.dot(P).dot(A.T) + dt * Q
S = C.dot(P).dot(C.T) + R
K = P.dot(C.T).dot(np.linalg.inv(S))
P = (np.eye(len(P)) - K.dot(C)).dot(P)
return K

@ -1,18 +0,0 @@
# cython: language_level = 3
cdef class KF1D:
cdef public:
double x0_0
double x1_0
double K0_0
double K1_0
double A0_0
double A0_1
double A1_0
double A1_1
double C0_0
double C0_1
double A_K_0
double A_K_1
double A_K_2
double A_K_3

@ -1,37 +0,0 @@
# distutils: language = c++
# cython: language_level=3
cdef class KF1D:
def __init__(self, x0, A, C, K):
self.x0_0 = x0[0][0]
self.x1_0 = x0[1][0]
self.A0_0 = A[0][0]
self.A0_1 = A[0][1]
self.A1_0 = A[1][0]
self.A1_1 = A[1][1]
self.C0_0 = C[0]
self.C0_1 = C[1]
self.K0_0 = K[0][0]
self.K1_0 = K[1][0]
self.A_K_0 = self.A0_0 - self.K0_0 * self.C0_0
self.A_K_1 = self.A0_1 - self.K0_0 * self.C0_1
self.A_K_2 = self.A1_0 - self.K1_0 * self.C0_0
self.A_K_3 = self.A1_1 - self.K1_0 * self.C0_1
def update(self, meas):
cdef double x0_0 = self.A_K_0 * self.x0_0 + self.A_K_1 * self.x1_0 + self.K0_0 * meas
cdef double x1_0 = self.A_K_2 * self.x0_0 + self.A_K_3 * self.x1_0 + self.K1_0 * meas
self.x0_0 = x0_0
self.x1_0 = x1_0
return [self.x0_0, self.x1_0]
@property
def x(self):
return [[self.x0_0], [self.x1_0]]
@x.setter
def x(self, x):
self.x0_0 = x[0][0]
self.x1_0 = x[1][0]

@ -1,23 +0,0 @@
import numpy as np
class KF1D:
# this EKF assumes constant covariance matrix, so calculations are much simpler
# the Kalman gain also needs to be precomputed using the control module
def __init__(self, x0, A, C, K):
self.x = x0
self.A = A
self.C = np.atleast_2d(C)
self.K = K
self.A_K = self.A - np.dot(self.K, self.C)
# K matrix needs to be pre-computed as follow:
# import control
# (x, l, K) = control.dare(np.transpose(self.A), np.transpose(self.C), Q, R)
# self.K = np.transpose(K)
def update(self, meas):
self.x = np.dot(self.A_K, self.x) + np.dot(self.K, meas)
return self.x

@ -1,87 +0,0 @@
import unittest
import random
import timeit
import numpy as np
from openpilot.common.kalman.simple_kalman import KF1D
from openpilot.common.kalman.simple_kalman_old import KF1D as KF1D_old
class TestSimpleKalman(unittest.TestCase):
def setUp(self):
dt = 0.01
x0_0 = 0.0
x1_0 = 0.0
A0_0 = 1.0
A0_1 = dt
A1_0 = 0.0
A1_1 = 1.0
C0_0 = 1.0
C0_1 = 0.0
K0_0 = 0.12287673
K1_0 = 0.29666309
self.kf_old = KF1D_old(x0=np.array([[x0_0], [x1_0]]),
A=np.array([[A0_0, A0_1], [A1_0, A1_1]]),
C=np.array([C0_0, C0_1]),
K=np.array([[K0_0], [K1_0]]))
self.kf = KF1D(x0=[[x0_0], [x1_0]],
A=[[A0_0, A0_1], [A1_0, A1_1]],
C=[C0_0, C0_1],
K=[[K0_0], [K1_0]])
def test_getter_setter(self):
self.kf.x = [[1.0], [1.0]]
self.assertEqual(self.kf.x, [[1.0], [1.0]])
def update_returns_state(self):
x = self.kf.update(100)
self.assertEqual(x, self.kf.x)
def test_old_equal_new(self):
for _ in range(1000):
v_wheel = random.uniform(0, 200)
x_old = self.kf_old.update(v_wheel)
x = self.kf.update(v_wheel)
# Compare the output x, verify that the error is less than 1e-4
np.testing.assert_almost_equal(x_old[0], x[0])
np.testing.assert_almost_equal(x_old[1], x[1])
def test_new_is_faster(self):
setup = """
import numpy as np
from openpilot.common.kalman.simple_kalman import KF1D
from openpilot.common.kalman.simple_kalman_old import KF1D as KF1D_old
dt = 0.01
x0_0 = 0.0
x1_0 = 0.0
A0_0 = 1.0
A0_1 = dt
A1_0 = 0.0
A1_1 = 1.0
C0_0 = 1.0
C0_1 = 0.0
K0_0 = 0.12287673
K1_0 = 0.29666309
kf_old = KF1D_old(x0=np.array([[x0_0], [x1_0]]),
A=np.array([[A0_0, A0_1], [A1_0, A1_1]]),
C=np.array([C0_0, C0_1]),
K=np.array([[K0_0], [K1_0]]))
kf = KF1D(x0=[[x0_0], [x1_0]],
A=[[A0_0, A0_1], [A1_0, A1_1]],
C=[C0_0, C0_1],
K=[[K0_0], [K1_0]])
"""
kf_speed = timeit.timeit("kf.update(1234)", setup=setup, number=10000)
kf_old_speed = timeit.timeit("kf_old.update(1234)", setup=setup, number=10000)
self.assertTrue(kf_speed < kf_old_speed / 4)
if __name__ == "__main__":
unittest.main()

@ -65,7 +65,7 @@ class SwagFormatter(logging.Formatter):
return record_dict
def format(self, record): # noqa: A003
def format(self, record):
if self.swaglogger is None:
raise Exception("must set swaglogger before calling format()")
return json_robust_dumps(self.format_dict(record))
@ -95,7 +95,7 @@ class SwagLogFileFormatter(SwagFormatter):
k += "$a"
return k, v
def format(self, record): # noqa: A003
def format(self, record):
if isinstance(record, str):
v = json.loads(record)
else:

@ -1,38 +0,0 @@
#pragma once
#include <array>
#include "common/mat.h"
#include "system/hardware/hw.h"
const int TRAJECTORY_SIZE = 33;
const int LAT_MPC_N = 16;
const int LON_MPC_N = 32;
const float MIN_DRAW_DISTANCE = 10.0;
const float MAX_DRAW_DISTANCE = 100.0;
const float RYG_GREEN = 0.01165;
const float RYG_YELLOW = 0.06157;
template <typename T, size_t size>
constexpr std::array<T, size> build_idxs(float max_val) {
std::array<T, size> result{};
for (int i = 0; i < size; ++i) {
result[i] = max_val * ((i / (double)(size - 1)) * (i / (double)(size - 1)));
}
return result;
}
constexpr auto T_IDXS = build_idxs<double, TRAJECTORY_SIZE>(10.0);
constexpr auto T_IDXS_FLOAT = build_idxs<float, TRAJECTORY_SIZE>(10.0);
constexpr auto X_IDXS = build_idxs<double, TRAJECTORY_SIZE>(192.0);
constexpr auto X_IDXS_FLOAT = build_idxs<float, TRAJECTORY_SIZE>(192.0);
const mat3 FCAM_INTRINSIC_MATRIX = (mat3){{2648.0, 0.0, 1928.0 / 2,
0.0, 2648.0, 1208.0 / 2,
0.0, 0.0, 1.0}};
// tici ecam focal probably wrong? magnification is not consistent across frame
// Need to retrain model before this can be changed
const mat3 ECAM_INTRINSIC_MATRIX = (mat3){{567.0, 0.0, 1928.0 / 2,
0.0, 567.0, 1208.0 / 2,
0.0, 0.0, 1.0}};

@ -4,9 +4,11 @@
#include <sys/file.h>
#include <algorithm>
#include <cassert>
#include <csignal>
#include <unordered_map>
#include "common/queue.h"
#include "common/swaglog.h"
#include "common/util.h"
#include "system/hardware/hw.h"
@ -92,6 +94,8 @@ std::unordered_map<std::string, uint32_t> keys = {
{"AssistNowToken", PERSISTENT},
{"AthenadPid", PERSISTENT},
{"AthenadUploadQueue", PERSISTENT},
{"AthenadRecentlyViewedRoutes", PERSISTENT},
{"BootCount", PERSISTENT},
{"CalibrationParams", PERSISTENT},
{"CameraDebugExpGain", CLEAR_ON_MANAGER_START},
{"CameraDebugExpTime", CLEAR_ON_MANAGER_START},
@ -114,13 +118,14 @@ std::unordered_map<std::string, uint32_t> keys = {
{"DoReboot", CLEAR_ON_MANAGER_START},
{"DoShutdown", CLEAR_ON_MANAGER_START},
{"DoUninstall", CLEAR_ON_MANAGER_START},
{"ExperimentalLongitudinalEnabled", PERSISTENT},
{"ExperimentalLongitudinalEnabled", PERSISTENT | DEVELOPMENT_ONLY},
{"ExperimentalMode", PERSISTENT},
{"ExperimentalModeConfirmed", PERSISTENT},
{"FirmwareQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"ForcePowerDown", PERSISTENT},
{"GitBranch", PERSISTENT},
{"GitCommit", PERSISTENT},
{"GitCommitDate", PERSISTENT},
{"GitDiff", PERSISTENT},
{"GithubSshKeys", PERSISTENT},
{"GithubUsername", PERSISTENT},
@ -142,16 +147,13 @@ std::unordered_map<std::string, uint32_t> keys = {
{"IsReleaseBranch", CLEAR_ON_MANAGER_START},
{"IsTakingSnapshot", CLEAR_ON_MANAGER_START},
{"IsTestedBranch", CLEAR_ON_MANAGER_START},
{"IsUpdateAvailable", CLEAR_ON_MANAGER_START},
{"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"LaikadEphemerisV3", PERSISTENT | DONT_LOG},
{"LanguageSetting", PERSISTENT},
{"LastAthenaPingTime", CLEAR_ON_MANAGER_START},
{"LastGPSPosition", PERSISTENT},
{"LastManagerExitReason", CLEAR_ON_MANAGER_START},
{"LastOffroadStatusPacket", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"LastPowerDropDetected", CLEAR_ON_MANAGER_START},
{"LastSystemShutdown", CLEAR_ON_MANAGER_START},
{"LastUpdateException", CLEAR_ON_MANAGER_START},
{"LastUpdateTime", PERSISTENT},
{"LiveParameters", PERSISTENT},
@ -162,7 +164,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"NavPastDestinations", PERSISTENT},
{"NavSettingLeftSide", PERSISTENT},
{"NavSettingTime24h", PERSISTENT},
{"NavdRender", PERSISTENT},
{"NetworkMetered", PERSISTENT},
{"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"ObdMultiplexingEnabled", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"Offroad_BadNvme", CLEAR_ON_MANAGER_START},
@ -182,22 +184,19 @@ std::unordered_map<std::string, uint32_t> keys = {
{"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"PandaSomResetTriggered", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"PandaSignatures", CLEAR_ON_MANAGER_START},
{"Passive", PERSISTENT},
{"PrimeType", PERSISTENT},
{"RecordFront", PERSISTENT},
{"RecordFrontLock", PERSISTENT}, // for the internal fleet
{"ReplayControlsState", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"ShouldDoUpdate", CLEAR_ON_MANAGER_START},
{"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"SshEnabled", PERSISTENT},
{"SubscriberInfo", PERSISTENT},
{"TermsVersion", PERSISTENT},
{"Timezone", PERSISTENT},
{"TrainingVersion", PERSISTENT},
{"UbloxAvailable", PERSISTENT},
{"UpdateAvailable", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"UpdateFailedCount", CLEAR_ON_MANAGER_START},
{"UpdaterAvailableBranches", CLEAR_ON_MANAGER_START},
{"UpdaterAvailableBranches", PERSISTENT},
{"UpdaterCurrentDescription", CLEAR_ON_MANAGER_START},
{"UpdaterCurrentReleaseNotes", CLEAR_ON_MANAGER_START},
{"UpdaterFetchAvailable", CLEAR_ON_MANAGER_START},
@ -205,17 +204,24 @@ std::unordered_map<std::string, uint32_t> keys = {
{"UpdaterNewReleaseNotes", CLEAR_ON_MANAGER_START},
{"UpdaterState", CLEAR_ON_MANAGER_START},
{"UpdaterTargetBranch", CLEAR_ON_MANAGER_START},
{"UpdaterLastFetchTime", PERSISTENT},
{"Version", PERSISTENT},
{"VisionRadarToggle", PERSISTENT},
{"WheeledBody", PERSISTENT},
};
} // namespace
Params::Params(const std::string &path) {
prefix = "/" + util::getenv("OPENPILOT_PREFIX", "d");
params_path = ensure_params_path(prefix, path);
params_prefix = "/" + util::getenv("OPENPILOT_PREFIX", "d");
params_path = ensure_params_path(params_prefix, path);
}
Params::~Params() {
if (future.valid()) {
future.wait();
}
assert(queue.empty());
}
std::vector<std::string> Params::allKeys() const {
@ -328,3 +334,20 @@ void Params::clearAll(ParamKeyType key_type) {
fsync_dir(getParamPath());
}
void Params::putNonBlocking(const std::string &key, const std::string &val) {
queue.push(std::make_pair(key, val));
// start thread on demand
if (!future.valid() || future.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready) {
future = std::async(std::launch::async, &Params::asyncWriteThread, this);
}
}
void Params::asyncWriteThread() {
// TODO: write the latest one if a key has multiple values in the queue.
std::pair<std::string, std::string> p;
while (queue.try_pop(p, 0)) {
// Params::put is Thread-Safe
put(p.first, p.second);
}
}

@ -1,21 +1,28 @@
#pragma once
#include <future>
#include <map>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "common/queue.h"
enum ParamKeyType {
PERSISTENT = 0x02,
CLEAR_ON_MANAGER_START = 0x04,
CLEAR_ON_ONROAD_TRANSITION = 0x08,
CLEAR_ON_OFFROAD_TRANSITION = 0x10,
DONT_LOG = 0x20,
DEVELOPMENT_ONLY = 0x40,
ALL = 0xFFFFFFFF
};
class Params {
public:
explicit Params(const std::string &path = {});
~Params();
// Not copyable.
Params(const Params&) = delete;
Params& operator=(const Params&) = delete;
@ -24,7 +31,7 @@ public:
bool checkKey(const std::string &key);
ParamKeyType getKeyType(const std::string &key);
inline std::string getParamPath(const std::string &key = {}) {
return params_path + prefix + (key.empty() ? "" : "/" + key);
return params_path + params_prefix + (key.empty() ? "" : "/" + key);
}
// Delete a value
@ -46,8 +53,18 @@ public:
inline int putBool(const std::string &key, bool val) {
return put(key.c_str(), val ? "1" : "0", 1);
}
void putNonBlocking(const std::string &key, const std::string &val);
inline void putBoolNonBlocking(const std::string &key, bool val) {
putNonBlocking(key, val ? "1" : "0");
}
private:
void asyncWriteThread();
std::string params_path;
std::string prefix;
std::string params_prefix;
// for nonblocking write
std::future<void> future;
SafeQueue<std::pair<std::string, std::string>> queue;
};

@ -1,10 +1,7 @@
from openpilot.common.params_pyx import Params, ParamKeyType, UnknownKeyName, put_nonblocking, \
put_bool_nonblocking
from openpilot.common.params_pyx import Params, ParamKeyType, UnknownKeyName
assert Params
assert ParamKeyType
assert UnknownKeyName
assert put_nonblocking
assert put_bool_nonblocking
if __name__ == "__main__":
import sys

@ -3,7 +3,6 @@
from libcpp cimport bool
from libcpp.string cimport string
from libcpp.vector cimport vector
import threading
cdef extern from "common/params.h":
cpdef enum ParamKeyType:
@ -11,6 +10,7 @@ cdef extern from "common/params.h":
CLEAR_ON_MANAGER_START
CLEAR_ON_ONROAD_TRANSITION
CLEAR_ON_OFFROAD_TRANSITION
DEVELOPMENT_ONLY
ALL
cdef cppclass c_Params "Params":
@ -19,6 +19,8 @@ cdef extern from "common/params.h":
bool getBool(string, bool) nogil
int remove(string) nogil
int put(string, string) nogil
void putNonBlocking(string, string) nogil
void putBoolNonBlocking(string, bool) nogil
int putBool(string, bool) nogil
bool checkKey(string) nogil
string getParamPath(string) nogil
@ -27,7 +29,7 @@ cdef extern from "common/params.h":
def ensure_bytes(v):
return v.encode() if isinstance(v, str) else v;
return v.encode() if isinstance(v, str) else v
class UnknownKeyName(Exception):
pass
@ -79,7 +81,7 @@ cdef class Params:
"""
Warning: This function blocks until the param is written to disk!
In very rare cases this can take over a second, and your code will hang.
Use the put_nonblocking helper function in time sensitive code, but
Use the put_nonblocking, put_bool_nonblocking in time sensitive code, but
in general try to avoid writing params as much as possible.
"""
cdef string k = self.check_key(key)
@ -92,6 +94,17 @@ cdef class Params:
with nogil:
self.p.putBool(k, val)
def put_nonblocking(self, key, dat):
cdef string k = self.check_key(key)
cdef string dat_bytes = ensure_bytes(dat)
with nogil:
self.p.putNonBlocking(k, dat_bytes)
def put_bool_nonblocking(self, key, bool val):
cdef string k = self.check_key(key)
with nogil:
self.p.putBoolNonBlocking(k, val)
def remove(self, key):
cdef string k = self.check_key(key)
with nogil:
@ -103,9 +116,3 @@ cdef class Params:
def all_keys(self):
return self.p.allKeys()
def put_nonblocking(key, val, d=""):
threading.Thread(target=lambda: Params(d).put(key, val)).start()
def put_bool_nonblocking(key, bool val, d=""):
threading.Thread(target=lambda: Params(d).put_bool(key, val)).start()

@ -0,0 +1,52 @@
import os
import shutil
import uuid
from typing import Optional
from openpilot.common.params import Params
from openpilot.system.hardware.hw import Paths
from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT
class OpenpilotPrefix:
def __init__(self, prefix: Optional[str] = None, clean_dirs_on_exit: bool = True, shared_download_cache: bool = False):
self.prefix = prefix if prefix else str(uuid.uuid4().hex[0:15])
self.msgq_path = os.path.join('/dev/shm', self.prefix)
self.clean_dirs_on_exit = clean_dirs_on_exit
self.shared_download_cache = shared_download_cache
def __enter__(self):
self.original_prefix = os.environ.get('OPENPILOT_PREFIX', None)
os.environ['OPENPILOT_PREFIX'] = self.prefix
try:
os.mkdir(self.msgq_path)
except FileExistsError:
pass
os.makedirs(Paths.log_root(), exist_ok=True)
if self.shared_download_cache:
os.environ["COMMA_CACHE"] = DEFAULT_DOWNLOAD_CACHE_ROOT
return self
def __exit__(self, exc_type, exc_obj, exc_tb):
if self.clean_dirs_on_exit:
self.clean_dirs()
try:
del os.environ['OPENPILOT_PREFIX']
if self.original_prefix is not None:
os.environ['OPENPILOT_PREFIX'] = self.original_prefix
except KeyError:
pass
return False
def clean_dirs(self):
symlink_path = Params().get_param_path()
if os.path.exists(symlink_path):
shutil.rmtree(os.path.realpath(symlink_path), ignore_errors=True)
os.remove(symlink_path)
shutil.rmtree(self.msgq_path, ignore_errors=True)
shutil.rmtree(Paths.log_root(), ignore_errors=True)
if not os.environ.get("COMMA_CACHE", False):
shutil.rmtree(Paths.download_cache_root(), ignore_errors=True)
shutil.rmtree(Paths.comma_home(), ignore_errors=True)

@ -1,45 +0,0 @@
import time
class Profiler():
def __init__(self, enabled=False):
self.enabled = enabled
self.cp = {}
self.cp_ignored = []
self.iter = 0
self.start_time = time.time()
self.last_time = self.start_time
self.tot = 0.
def reset(self, enabled=False):
self.enabled = enabled
self.cp = {}
self.cp_ignored = []
self.iter = 0
self.start_time = time.time()
self.last_time = self.start_time
def checkpoint(self, name, ignore=False):
# ignore flag needed when benchmarking threads with ratekeeper
if not self.enabled:
return
tt = time.time()
if name not in self.cp:
self.cp[name] = 0.
if ignore:
self.cp_ignored.append(name)
self.cp[name] += tt - self.last_time
if not ignore:
self.tot += tt - self.last_time
self.last_time = tt
def display(self):
if not self.enabled:
return
self.iter += 1
print("******* Profiling %d *******" % self.iter)
for n, ms in sorted(self.cp.items(), key=lambda x: -x[1]):
if n in self.cp_ignored:
print("%30s: %9.2f avg: %7.2f percent: %3.0f IGNORED" % (n, ms*1000.0, ms*1000.0/self.iter, ms/self.tot*100))
else:
print("%30s: %9.2f avg: %7.2f percent: %3.0f" % (n, ms*1000.0, ms*1000.0/self.iter, ms/self.tot*100))
print(f"Iter clock: {self.tot / self.iter:2.6f} TOTAL: {self.tot:2.2f}")

@ -78,7 +78,7 @@ class Ratekeeper:
time.sleep(self._remaining)
return lagged
# this only monitor the cumulative lag, but does not enforce a rate
# Monitors the cumulative lag, but does not enforce a rate
def monitor_time(self) -> bool:
prev = self._last_monitor_time
self._last_monitor_time = time.monotonic()

@ -0,0 +1,30 @@
import time
import functools
from openpilot.common.swaglog import cloudlog
def retry(attempts=3, delay=1.0, ignore_failure=False):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for _ in range(attempts):
try:
return func(*args, **kwargs)
except Exception:
cloudlog.exception(f"{func.__name__} failed, trying again")
time.sleep(delay)
if ignore_failure:
cloudlog.error(f"{func.__name__} failed after retry")
else:
raise Exception(f"{func.__name__} failed after retry")
return wrapper
return decorator
if __name__ == "__main__":
@retry(attempts=10)
def abc():
raise ValueError("abc failed :(")
abc()

@ -0,0 +1,54 @@
import numpy as np
def get_kalman_gain(dt, A, C, Q, R, iterations=100):
P = np.zeros_like(Q)
for _ in range(iterations):
P = A.dot(P).dot(A.T) + dt * Q
S = C.dot(P).dot(C.T) + R
K = P.dot(C.T).dot(np.linalg.inv(S))
P = (np.eye(len(P)) - K.dot(C)).dot(P)
return K
class KF1D:
# this EKF assumes constant covariance matrix, so calculations are much simpler
# the Kalman gain also needs to be precomputed using the control module
def __init__(self, x0, A, C, K):
self.x0_0 = x0[0][0]
self.x1_0 = x0[1][0]
self.A0_0 = A[0][0]
self.A0_1 = A[0][1]
self.A1_0 = A[1][0]
self.A1_1 = A[1][1]
self.C0_0 = C[0]
self.C0_1 = C[1]
self.K0_0 = K[0][0]
self.K1_0 = K[1][0]
self.A_K_0 = self.A0_0 - self.K0_0 * self.C0_0
self.A_K_1 = self.A0_1 - self.K0_0 * self.C0_1
self.A_K_2 = self.A1_0 - self.K1_0 * self.C0_0
self.A_K_3 = self.A1_1 - self.K1_0 * self.C0_1
# K matrix needs to be pre-computed as follow:
# import control
# (x, l, K) = control.dare(np.transpose(self.A), np.transpose(self.C), Q, R)
# self.K = np.transpose(K)
def update(self, meas):
#self.x = np.dot(self.A_K, self.x) + np.dot(self.K, meas)
x0_0 = self.A_K_0 * self.x0_0 + self.A_K_1 * self.x1_0 + self.K0_0 * meas
x1_0 = self.A_K_2 * self.x0_0 + self.A_K_3 * self.x1_0 + self.K1_0 * meas
self.x0_0 = x0_0
self.x1_0 = x1_0
return [self.x0_0, self.x1_0]
@property
def x(self):
return [[self.x0_0], [self.x1_0]]
def set_x(self, x):
self.x0_0 = x[0][0]
self.x1_0 = x[1][0]

@ -1,47 +0,0 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "common/statlog.h"
#include "common/util.h"
#include <cstdarg>
#include <stdio.h>
#include <mutex>
#include <zmq.h>
class StatlogState : public LogState {
public:
StatlogState() : LogState("ipc:///tmp/stats") {}
};
static StatlogState s = {};
static void log(const char* metric_type, const char* metric, const char* fmt, ...) {
std::lock_guard lk(s.lock);
if (!s.initialized) s.initialize();
char* value_buf = nullptr;
va_list args;
va_start(args, fmt);
int ret = vasprintf(&value_buf, fmt, args);
va_end(args);
if (ret > 0 && value_buf) {
char* line_buf = nullptr;
ret = asprintf(&line_buf, "%s:%s|%s", metric, value_buf, metric_type);
if (ret > 0 && line_buf) {
zmq_send(s.sock, line_buf, ret, ZMQ_NOBLOCK);
free(line_buf);
}
free(value_buf);
}
}
void statlog_log(const char* metric_type, const char* metric, int value) {
log(metric_type, metric, "%d", value);
}
void statlog_log(const char* metric_type, const char* metric, float value) {
log(metric_type, metric, "%f", value);
}

@ -1,10 +0,0 @@
#pragma once
#define STATLOG_GAUGE "g"
#define STATLOG_SAMPLE "sa"
void statlog_log(const char* metric_type, const char* metric, int value);
void statlog_log(const char* metric_type, const char* metric, float value);
#define statlog_gauge(metric, value) statlog_log(STATLOG_GAUGE, metric, value)
#define statlog_sample(metric, value) statlog_log(STATLOG_SAMPLE, metric, value)

@ -5,30 +5,29 @@
#include "common/swaglog.h"
#include <cassert>
#include <cstdarg>
#include <cstring>
#include <limits>
#include <mutex>
#include <string>
#include <zmq.h>
#include <stdarg.h>
#include "third_party/json11/json11.hpp"
#include "common/util.h"
#include "common/version.h"
#include "system/hardware/hw.h"
class SwaglogState : public LogState {
public:
SwaglogState() : LogState(Path::swaglog_ipc().c_str()) {}
class SwaglogState {
public:
SwaglogState() {
zctx = zmq_ctx_new();
sock = zmq_socket(zctx, ZMQ_PUSH);
json11::Json::object ctx_j;
// Timeout on shutdown for messages to be received by the logging process
int timeout = 100;
zmq_setsockopt(sock, ZMQ_LINGER, &timeout, sizeof(timeout));
zmq_connect(sock, Path::swaglog_ipc().c_str());
inline void initialize() {
ctx_j = json11::Json::object {};
print_level = CLOUDLOG_WARNING;
const char* print_lvl = getenv("LOGPRINT");
if (print_lvl) {
if (const char* print_lvl = getenv("LOGPRINT")) {
if (strcmp(print_lvl, "debug") == 0) {
print_level = CLOUDLOG_DEBUG;
} else if (strcmp(print_lvl, "info") == 0) {
@ -38,39 +37,53 @@ class SwaglogState : public LogState {
}
}
// openpilot bindings
char* dongle_id = getenv("DONGLE_ID");
if (dongle_id) {
ctx_j = json11::Json::object{};
if (char* dongle_id = getenv("DONGLE_ID")) {
ctx_j["dongle_id"] = dongle_id;
}
char* daemon_name = getenv("MANAGER_DAEMON");
if (daemon_name) {
if (char* git_origin = getenv("GIT_ORIGIN")) {
ctx_j["origin"] = git_origin;
}
if (char* git_branch = getenv("GIT_BRANCH")) {
ctx_j["branch"] = git_branch;
}
if (char* git_commit = getenv("GIT_COMMIT")) {
ctx_j["commit"] = git_commit;
}
if (char* daemon_name = getenv("MANAGER_DAEMON")) {
ctx_j["daemon"] = daemon_name;
}
ctx_j["version"] = COMMA_VERSION;
ctx_j["dirty"] = !getenv("CLEAN");
// device type
ctx_j["device"] = Hardware::get_name();
LogState::initialize();
}
};
static SwaglogState s = {};
bool LOG_TIMESTAMPS = getenv("LOG_TIMESTAMPS");
uint32_t NO_FRAME_ID = std::numeric_limits<uint32_t>::max();
~SwaglogState() {
zmq_close(sock);
zmq_ctx_destroy(zctx);
}
static void log(int levelnum, const char* filename, int lineno, const char* func, const char* msg, const std::string& log_s) {
if (levelnum >= s.print_level) {
void log(int levelnum, const char* filename, int lineno, const char* func, const char* msg, const std::string& log_s) {
std::lock_guard lk(lock);
if (levelnum >= print_level) {
printf("%s: %s\n", filename, msg);
}
zmq_send(s.sock, log_s.data(), log_s.length(), ZMQ_NOBLOCK);
}
zmq_send(sock, log_s.data(), log_s.length(), ZMQ_NOBLOCK);
}
std::mutex lock;
void* zctx = nullptr;
void* sock = nullptr;
int print_level;
json11::Json::object ctx_j;
};
bool LOG_TIMESTAMPS = getenv("LOG_TIMESTAMPS");
uint32_t NO_FRAME_ID = std::numeric_limits<uint32_t>::max();
static void cloudlog_common(int levelnum, const char* filename, int lineno, const char* func,
char* msg_buf, const json11::Json::object &msg_j={}) {
std::lock_guard lk(s.lock);
if (!s.initialized) s.initialize();
static SwaglogState s;
json11::Json::object log_j = json11::Json::object {
{"ctx", s.ctx_j},
@ -89,7 +102,7 @@ static void cloudlog_common(int levelnum, const char* filename, int lineno, cons
std::string log_s;
log_s += (char)levelnum;
((json11::Json)log_j).dump(log_s);
log(levelnum, filename, lineno, func, msg_buf, log_s);
s.log(levelnum, filename, lineno, func, msg_buf, log_s);
free(msg_buf);
}

@ -1,6 +1,6 @@
import datetime
MIN_DATE = datetime.datetime(year=2023, month=6, day=1)
MIN_DATE = datetime.datetime(year=2024, month=1, day=28)
def system_time_valid():
return datetime.datetime.now() > MIN_DATE

@ -1,4 +1,4 @@
#cython: language_level=3
# cython: language_level=3
from libcpp cimport bool
cdef extern from "orientation.cc":

@ -17,7 +17,6 @@ from openpilot.common.transformations.transformations cimport ecef2geodetic as e
from openpilot.common.transformations.transformations cimport LocalCoord_c
import cython
import numpy as np
cimport numpy as np
@ -34,14 +33,14 @@ cdef Matrix3 numpy2matrix(np.ndarray[double, ndim=2, mode="fortran"] m):
return Matrix3(<double*>m.data)
cdef ECEF list2ecef(ecef):
cdef ECEF e;
cdef ECEF e
e.x = ecef[0]
e.y = ecef[1]
e.z = ecef[2]
return e
cdef NED list2ned(ned):
cdef NED n;
cdef NED n
n.n = ned[0]
n.e = ned[1]
n.d = ned[2]
@ -61,7 +60,7 @@ def euler2quat_single(euler):
def quat2euler_single(quat):
cdef Quaternion q = Quaternion(quat[0], quat[1], quat[2], quat[3])
cdef Vector3 e = quat2euler_c(q);
cdef Vector3 e = quat2euler_c(q)
return [e(0), e(1), e(2)]
def quat2rot_single(quat):

@ -3,7 +3,6 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <zmq.h>
#include <algorithm>
#include <atomic>
@ -180,36 +179,3 @@ void update_max_atomic(std::atomic<T>& max, T const& value) {
T prev = max;
while (prev < value && !max.compare_exchange_weak(prev, value)) {}
}
class LogState {
public:
bool initialized = false;
std::mutex lock;
void *zctx = nullptr;
void *sock = nullptr;
int print_level;
std::string endpoint;
LogState(std::string _endpoint) {
endpoint = _endpoint;
}
inline void initialize() {
zctx = zmq_ctx_new();
sock = zmq_socket(zctx, ZMQ_PUSH);
// Timeout on shutdown for messages to be received by the logging process
int timeout = 100;
zmq_setsockopt(sock, ZMQ_LINGER, &timeout, sizeof(timeout));
zmq_connect(sock, endpoint.c_str());
initialized = true;
}
~LogState() {
if (initialized) {
zmq_close(sock);
zmq_ctx_destroy(zctx);
}
}
};

@ -1 +1 @@
#define COMMA_VERSION "0.9.5"
#define COMMA_VERSION "0.9.6"

@ -4,37 +4,40 @@
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.
# 268 Supported Cars
# 279 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|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec 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=Acura&model=ILX 2016-19">Buy Here</a></sub></details>||
|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec 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=Acura&model=RDX 2016-18">Buy Here</a></sub></details>||
|Acura|RDX 2019-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A 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=Acura&model=RDX 2019-22">Buy Here</a></sub></details>||
|Audi|A3 2014-19|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=Audi&model=A3 2014-19">Buy Here</a></sub></details>||
|Audi|A3 Sportback e-tron 2017-18|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=Audi&model=A3 Sportback e-tron 2017-18">Buy Here</a></sub></details>||
|Audi|Q2 2018|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=Audi&model=Q2 2018">Buy Here</a></sub></details>||
|Audi|Q3 2019-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=Audi&model=Q3 2019-23">Buy Here</a></sub></details>||
|Audi|RS3 2018|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=Audi&model=RS3 2018">Buy Here</a></sub></details>||
|Audi|S3 2015-17|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=Audi&model=S3 2015-17">Buy Here</a></sub></details>||
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Audi&model=A3 2014-19">Buy Here</a></sub></details>||
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Audi&model=A3 Sportback e-tron 2017-18">Buy Here</a></sub></details>||
|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Audi&model=Q2 2018">Buy Here</a></sub></details>||
|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Audi&model=Q3 2019-23">Buy Here</a></sub></details>||
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Audi&model=RS3 2018">Buy Here</a></sub></details>||
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Audi&model=S3 2015-17">Buy Here</a></sub></details>||
|Buick|LaCrosse 2017-19[<sup>4</sup>](#footnotes)|Driver Confidence Package 2|openpilot|18 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-II connector<br>- 1 comma 3X<br>- 2 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=Buick&model=LaCrosse 2017-19">Buy Here</a></sub></details>||
|Cadillac|Escalade 2017[<sup>4</sup>](#footnotes)|Driver Assist Package|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-II connector<br>- 1 comma 3X<br>- 2 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=Cadillac&model=Escalade 2017">Buy Here</a></sub></details>||
|Cadillac|Escalade ESV 2016[<sup>4</sup>](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-II connector<br>- 1 comma 3X<br>- 2 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=Cadillac&model=Escalade ESV 2016">Buy Here</a></sub></details>||
|Cadillac|Escalade ESV 2019[<sup>4</sup>](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-II connector<br>- 1 comma 3X<br>- 2 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=Cadillac&model=Escalade ESV 2019">Buy Here</a></sub></details>||
|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<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=Chevrolet&model=Bolt EUV 2022-23">Buy Here</a></sub></details>|<a href="https://youtu.be/xvwzGMUA210" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<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=Chevrolet&model=Bolt EV 2022-23">Buy Here</a></sub></details>||
|Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<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=Chevrolet&model=Equinox 2019-22">Buy Here</a></sub></details>||
|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<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=Chevrolet&model=Silverado 1500 2020-21">Buy Here</a></sub></details>||
|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<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=Chevrolet&model=Trailblazer 2021-22">Buy Here</a></sub></details>||
|Chevrolet|Volt 2017-18[<sup>4</sup>](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-II connector<br>- 1 comma 3X<br>- 2 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=Chevrolet&model=Volt 2017-18">Buy Here</a></sub></details>|<a href="https://youtu.be/QeMCN_4TFfQ" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA 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=Chrysler&model=Pacifica 2017-18">Buy Here</a></sub></details>||
|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA 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=Chrysler&model=Pacifica 2019-20">Buy Here</a></sub></details>||
|Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA 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=Chrysler&model=Pacifica 2021">Buy Here</a></sub></details>||
|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA 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=Chrysler&model=Pacifica Hybrid 2017-18">Buy Here</a></sub></details>||
|Chrysler|Pacifica 2021-23|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA 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=Chrysler&model=Pacifica 2021-23">Buy Here</a></sub></details>||
|Chrysler|Pacifica Hybrid 2017|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA 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=Chrysler&model=Pacifica Hybrid 2017">Buy Here</a></sub></details>||
|Chrysler|Pacifica Hybrid 2018|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA 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=Chrysler&model=Pacifica Hybrid 2018">Buy Here</a></sub></details>||
|Chrysler|Pacifica Hybrid 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA 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=Chrysler&model=Pacifica Hybrid 2019-23">Buy Here</a></sub></details>||
|comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None||
|Dodge|Durango 2020-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA 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=Dodge&model=Durango 2020-21">Buy Here</a></sub></details>||
|Ford|Bronco Sport 2021-22|Co-Pilot360 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 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Bronco Sport 2021-22">Buy Here</a></sub></details>||
|Ford|Escape 2020-22|Co-Pilot360 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 Ford Q3 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=Ford&model=Escape 2020-22">Buy Here</a></sub></details>||
|Ford|Explorer 2020-22|Co-Pilot360 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 Ford Q3 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=Ford&model=Explorer 2020-22">Buy Here</a></sub></details>||
|Ford|Explorer 2020-23|Co-Pilot360 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 Ford Q3 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=Ford&model=Explorer 2020-23">Buy Here</a></sub></details>||
|Ford|Focus 2018[<sup>3</sup>](#footnotes)|Adaptive Cruise Control with Lane Centering|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 Ford Q3 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=Ford&model=Focus 2018">Buy Here</a></sub></details>||
|Ford|Kuga 2020-22|Adaptive Cruise Control with Lane Centering|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 Ford Q3 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=Ford&model=Kuga 2020-22">Buy Here</a></sub></details>||
|Ford|Maverick 2022|LARIAT Luxury|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 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Maverick 2022">Buy Here</a></sub></details>||
@ -60,7 +63,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Honda|Civic Hatchback 2022-23|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 Honda Bosch B 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=Honda&model=Civic Hatchback 2022-23">Buy Here</a></sub></details>|<a href="https://youtu.be/ytiOT5lcp6Q" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec 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=Honda&model=CR-V 2015-16">Buy Here</a></sub></details>||
|Honda|CR-V 2017-22|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A 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=Honda&model=CR-V 2017-22">Buy Here</a></sub></details>||
|Honda|CR-V Hybrid 2017-19|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A 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=Honda&model=CR-V Hybrid 2017-19">Buy Here</a></sub></details>||
|Honda|CR-V Hybrid 2017-20|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A 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=Honda&model=CR-V Hybrid 2017-20">Buy Here</a></sub></details>||
|Honda|e 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A 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=Honda&model=e 2020">Buy Here</a></sub></details>||
|Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec 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=Honda&model=Fit 2018-20">Buy Here</a></sub></details>||
|Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec 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=Honda&model=Freed 2020">Buy Here</a></sub></details>||
@ -71,8 +74,9 @@ A supported vehicle is one that just works when you install a comma device. All
|Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec 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=Honda&model=Odyssey 2018-20">Buy Here</a></sub></details>||
|Honda|Passport 2019-23|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec 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=Honda&model=Passport 2019-23">Buy Here</a></sub></details>||
|Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec 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=Honda&model=Pilot 2016-22">Buy Here</a></sub></details>||
|Honda|Ridgeline 2017-23|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec 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=Honda&model=Ridgeline 2017-23">Buy Here</a></sub></details>||
|Honda|Ridgeline 2017-24|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec 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=Honda&model=Ridgeline 2017-24">Buy Here</a></sub></details>||
|Hyundai|Azera 2022|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 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=Azera 2022">Buy Here</a></sub></details>||
|Hyundai|Azera Hybrid 2019|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 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=Azera Hybrid 2019">Buy Here</a></sub></details>||
|Hyundai|Azera Hybrid 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 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=Azera Hybrid 2020">Buy Here</a></sub></details>||
|Hyundai|Custin 2023|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 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=Custin 2023">Buy Here</a></sub></details>||
|Hyundai|Elantra 2017-18|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B 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=Elantra 2017-18">Buy Here</a></sub></details>||
@ -96,25 +100,26 @@ A supported vehicle is one that just works when you install a comma device. All
|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|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 G 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=Kona Electric 2018-21">Buy Here</a></sub></details>||
|Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai O 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=Kona Electric 2022-23">Buy Here</a></sub></details>||
|Hyundai|Kona Electric (with HDA II, Korea only) 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R 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=Kona Electric (with HDA II, Korea only) 2023">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=U2fOCmcQ8hw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|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 I 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=Kona Hybrid 2020">Buy Here</a></sub></details>|<a href="https://youtu.be/0dwpAHiZgFo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|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 I 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=Kona Hybrid 2020">Buy Here</a></sub></details>||
|Hyundai|Palisade 2020-22|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=Palisade 2020-22">Buy Here</a></sub></details>|<a href="https://youtu.be/TAnDqjF4fDY?t=456" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|Santa Cruz 2022-23[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N 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=Santa Cruz 2022-23">Buy Here</a></sub></details>||
|Hyundai|Santa Fe 2019-20|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 D 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=Santa Fe 2019-20">Buy Here</a></sub></details>||
|Hyundai|Santa Cruz 2022-23[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|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 N 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=Santa Cruz 2022-23">Buy Here</a></sub></details>||
|Hyundai|Santa Fe 2019-20|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 D 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=Santa Fe 2019-20">Buy Here</a></sub></details>|<a href="https://youtu.be/bjDR0YjM__s" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|Santa Fe 2021-23|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 L 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=Santa Fe 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/VnHzSTygTS4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|Santa Fe Hybrid 2022-23|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 L 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=Santa Fe Hybrid 2022-23">Buy Here</a></sub></details>||
|Hyundai|Santa Fe Plug-in Hybrid 2022-23|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 L 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=Santa Fe Plug-in Hybrid 2022-23">Buy Here</a></sub></details>||
|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E 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=Sonata 2018-19">Buy Here</a></sub></details>||
|Hyundai|Sonata 2020-23|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 A 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=Sonata 2020-23">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=ix63r9kE3Fw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|Sonata Hybrid 2020-23|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 A 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=Sonata Hybrid 2020-23">Buy Here</a></sub></details>||
|Hyundai|Staria 2023[<sup>6</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 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=Staria 2023">Buy Here</a></sub></details>||
|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L 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=Tucson 2021">Buy Here</a></sub></details>||
|Hyundai|Tucson 2022[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N 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=Tucson 2022">Buy Here</a></sub></details>||
|Hyundai|Tucson 2023[<sup>6</sup>](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N 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=Tucson 2023">Buy Here</a></sub></details>||
|Hyundai|Tucson 2022[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|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 N 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=Tucson 2022">Buy Here</a></sub></details>||
|Hyundai|Tucson 2023[<sup>6</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 N 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=Tucson 2023">Buy Here</a></sub></details>||
|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|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 L 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=Tucson Diesel 2019">Buy Here</a></sub></details>||
|Hyundai|Tucson Hybrid 2022-24[<sup>6</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 N 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=Tucson Hybrid 2022-24">Buy Here</a></sub></details>||
|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E 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=Veloster 2019-20">Buy Here</a></sub></details>||
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA 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=Jeep&model=Grand Cherokee 2016-18">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=eLR9o2JkuRk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA 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=Jeep&model=Grand Cherokee 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=jBe4lWnRSu4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Kia|Carnival 2023-24[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A 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=Kia&model=Carnival 2023-24">Buy Here</a></sub></details>||
|Kia|Carnival 2022-24[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A 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=Kia&model=Carnival 2022-24">Buy Here</a></sub></details>||
|Kia|Carnival (China only) 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|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=Kia&model=Carnival (China only) 2023">Buy Here</a></sub></details>||
|Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E 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=Kia&model=Ceed 2019">Buy Here</a></sub></details>||
|Kia|EV6 (Southeast Asia only) 2022-23[<sup>6</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 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=Kia&model=EV6 (Southeast Asia only) 2022-23">Buy Here</a></sub></details>||
@ -130,10 +135,13 @@ A supported vehicle is one that just works when you install a comma device. All
|Kia|Niro EV 2021|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 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=Kia&model=Niro EV 2021">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Kia|Niro EV 2022|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=Kia&model=Niro EV 2022">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Kia|Niro EV 2023[<sup>6</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 A 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=Kia&model=Niro EV 2023">Buy Here</a></sub></details>||
|Kia|Niro Hybrid 2021-22|Smart Cruise Control (SCC)|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 F 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=Kia&model=Niro Hybrid 2021-22">Buy Here</a></sub></details>||
|Kia|Niro Hybrid 2021|Smart Cruise Control (SCC)|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 D 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=Kia&model=Niro Hybrid 2021">Buy Here</a></sub></details>||
|Kia|Niro Hybrid 2022|Smart Cruise Control (SCC)|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 F 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=Kia&model=Niro Hybrid 2022">Buy Here</a></sub></details>||
|Kia|Niro Hybrid 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|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 A 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=Kia&model=Niro Hybrid 2023">Buy Here</a></sub></details>||
|Kia|Niro Plug-in Hybrid 2018-19|All|Stock|10 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=Kia&model=Niro Plug-in Hybrid 2018-19">Buy Here</a></sub></details>||
|Kia|Niro Plug-in Hybrid 2020|All|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai D 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=Kia&model=Niro Plug-in Hybrid 2020">Buy Here</a></sub></details>||
|Kia|Niro Plug-in Hybrid 2021|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 D 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=Kia&model=Niro Plug-in Hybrid 2021">Buy Here</a></sub></details>||
|Kia|Niro Plug-in Hybrid 2022|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 F 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=Kia&model=Niro Plug-in Hybrid 2022">Buy Here</a></sub></details>||
|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B 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=Kia&model=Optima 2017">Buy Here</a></sub></details>||
|Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G 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=Kia&model=Optima 2019-20">Buy Here</a></sub></details>||
|Kia|Optima Hybrid 2019|Smart Cruise Control (SCC)|Stock|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=Kia&model=Optima Hybrid 2019">Buy Here</a></sub></details>||
@ -143,7 +151,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Kia|Sorento 2021-23[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|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=Kia&model=Sorento 2021-23">Buy Here</a></sub></details>||
|Kia|Sorento Hybrid 2021-23[<sup>6</sup>](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A 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=Kia&model=Sorento Hybrid 2021-23">Buy Here</a></sub></details>||
|Kia|Sorento Plug-in Hybrid 2022-23[<sup>6</sup>](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A 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=Kia&model=Sorento Plug-in Hybrid 2022-23">Buy Here</a></sub></details>||
|Kia|Sportage 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N 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=Kia&model=Sportage 2023">Buy Here</a></sub></details>||
|Kia|Sportage 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|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 N 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=Kia&model=Sportage 2023">Buy Here</a></sub></details>||
|Kia|Sportage Hybrid 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|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 N 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=Kia&model=Sportage Hybrid 2023">Buy Here</a></sub></details>||
|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|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 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=Kia&model=Stinger 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=MJ94qoofYw0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Kia|Stinger 2022-23|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 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=Kia&model=Stinger 2022-23">Buy Here</a></sub></details>||
@ -151,11 +159,12 @@ A supported vehicle is one that just works when you install a comma device. All
|Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Lexus&model=CT Hybrid 2017-18">Buy Here</a></sub></details>||
|Lexus|ES 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Lexus&model=ES 2017-18">Buy Here</a></sub></details>||
|Lexus|ES 2019-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Lexus&model=ES 2019-24">Buy Here</a></sub></details>||
|Lexus|ES Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Lexus&model=ES Hybrid 2017-18">Buy Here</a></sub></details>||
|Lexus|ES Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Lexus&model=ES Hybrid 2019-23">Buy Here</a></sub></details>|<a href="https://youtu.be/BZ29osRVJeg?t=12" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Lexus|ES Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Lexus&model=ES Hybrid 2017-18">Buy Here</a></sub></details>||
|Lexus|ES Hybrid 2019-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Lexus&model=ES Hybrid 2019-24">Buy Here</a></sub></details>|<a href="https://youtu.be/BZ29osRVJeg?t=12" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Lexus|GS F 2016|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Lexus&model=GS F 2016">Buy Here</a></sub></details>||
|Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Lexus&model=IS 2017-19">Buy Here</a></sub></details>||
|Lexus|IS 2022-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Lexus&model=IS 2022-23">Buy Here</a></sub></details>||
|Lexus|LC 2024|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Lexus&model=LC 2024">Buy Here</a></sub></details>||
|Lexus|NX 2018-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Lexus&model=NX 2018-19">Buy Here</a></sub></details>||
|Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Lexus&model=NX 2020-21">Buy Here</a></sub></details>||
|Lexus|NX Hybrid 2018-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Lexus&model=NX Hybrid 2018-19">Buy Here</a></sub></details>||
@ -169,35 +178,35 @@ A supported vehicle is one that just works when you install a comma device. All
|Lexus|RX Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Lexus&model=RX Hybrid 2020-22">Buy Here</a></sub></details>||
|Lexus|UX Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Lexus&model=UX Hybrid 2019-23">Buy Here</a></sub></details>||
|Lincoln|Aviator 2020-21|Co-Pilot360 Plus|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 Ford Q3 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=Lincoln&model=Aviator 2020-21">Buy Here</a></sub></details>||
|MAN|eTGE 2020-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=MAN&model=eTGE 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|MAN|TGE 2017-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=MAN&model=TGE 2017-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=MAN&model=eTGE 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=MAN&model=TGE 2017-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Mazda|CX-5 2022-24|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Mazda 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=Mazda&model=CX-5 2022-24">Buy Here</a></sub></details>||
|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Mazda 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=Mazda&model=CX-9 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/dA3duO4a0O4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan B connector<br>- 1 RJ45 cable (7 ft)<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=Nissan&model=Altima 2019-20">Buy Here</a></sub></details>||
|Nissan|Leaf 2018-23|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 RJ45 cable (7 ft)<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=Nissan&model=Leaf 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/vaMbtAh_0cY" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 RJ45 cable (7 ft)<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=Nissan&model=Rogue 2018-20">Buy Here</a></sub></details>||
|Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 RJ45 cable (7 ft)<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=Nissan&model=X-Trail 2017">Buy Here</a></sub></details>||
|Ram|1500 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Ram connector<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=Ram&model=1500 2019-23">Buy Here</a></sub></details>||
|SEAT|Ateca 2018|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=SEAT&model=Ateca 2018">Buy Here</a></sub></details>||
|SEAT|Leon 2014-20|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=SEAT&model=Leon 2014-20">Buy Here</a></sub></details>||
|Subaru|Ascent 2019-21|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<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=Subaru&model=Ascent 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<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=Subaru&model=Crosstrek 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<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=Subaru&model=Crosstrek 2020-23">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|Forester 2019-21|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<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=Subaru&model=Forester 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|Impreza 2017-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<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=Subaru&model=Impreza 2017-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|Impreza 2020-22|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<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=Subaru&model=Impreza 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Ram|1500 2019-24|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Ram connector<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=Ram&model=1500 2019-24">Buy Here</a></sub></details>||
|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=SEAT&model=Ateca 2018">Buy Here</a></sub></details>||
|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=SEAT&model=Leon 2014-20">Buy Here</a></sub></details>||
|Subaru|Ascent 2019-21|All[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<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=Subaru&model=Ascent 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<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=Subaru&model=Crosstrek 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<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=Subaru&model=Crosstrek 2020-23">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|Forester 2019-21|All[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<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=Subaru&model=Forester 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|Impreza 2017-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<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=Subaru&model=Impreza 2017-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|Impreza 2020-22|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<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=Subaru&model=Impreza 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|Legacy 2020-22|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru B connector<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=Subaru&model=Legacy 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|Outback 2020-22|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru B connector<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=Subaru&model=Outback 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|XV 2018-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<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=Subaru&model=XV 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Subaru|XV 2020-21|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<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=Subaru&model=XV 2020-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Škoda|Fabia 2022-23[<sup>11</sup>](#footnotes)|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=Škoda&model=Fabia 2022-23">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Škoda|Kamiq 2021-23[<sup>9,11</sup>](#footnotes)|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=Škoda&model=Kamiq 2021-23">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Škoda|Karoq 2019-23[<sup>11</sup>](#footnotes)|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=Škoda&model=Karoq 2019-23">Buy Here</a></sub></details>||
|Škoda|Kodiaq 2017-23[<sup>11</sup>](#footnotes)|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=Škoda&model=Kodiaq 2017-23">Buy Here</a></sub></details>||
|Škoda|Octavia 2015-19[<sup>11</sup>](#footnotes)|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=Škoda&model=Octavia 2015-19">Buy Here</a></sub></details>||
|Škoda|Octavia RS 2016[<sup>11</sup>](#footnotes)|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=Škoda&model=Octavia RS 2016">Buy Here</a></sub></details>||
|Škoda|Scala 2020-23[<sup>11</sup>](#footnotes)|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=Škoda&model=Scala 2020-23">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Škoda|Superb 2015-22[<sup>11</sup>](#footnotes)|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=Škoda&model=Superb 2015-22">Buy Here</a></sub></details>||
|Subaru|XV 2018-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<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=Subaru&model=XV 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Subaru|XV 2020-21|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<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=Subaru&model=XV 2020-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Škoda|Fabia 2022-23[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Škoda&model=Fabia 2022-23">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|Škoda|Kamiq 2021-23[<sup>10,12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Škoda&model=Kamiq 2021-23">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|Škoda|Karoq 2019-23[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Škoda&model=Karoq 2019-23">Buy Here</a></sub></details>||
|Škoda|Kodiaq 2017-23[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Škoda&model=Kodiaq 2017-23">Buy Here</a></sub></details>||
|Škoda|Octavia 2015-19[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Škoda&model=Octavia 2015-19">Buy Here</a></sub></details>||
|Škoda|Octavia RS 2016[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Škoda&model=Octavia RS 2016">Buy Here</a></sub></details>||
|Škoda|Scala 2020-23[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Škoda&model=Scala 2020-23">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|Škoda|Superb 2015-22[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Škoda&model=Superb 2015-22">Buy Here</a></sub></details>||
|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=Alphard 2019-20">Buy Here</a></sub></details>||
|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=Alphard Hybrid 2021">Buy Here</a></sub></details>||
|Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=Avalon 2016">Buy Here</a></sub></details>||
@ -207,11 +216,11 @@ A supported vehicle is one that just works when you install a comma device. All
|Toyota|Avalon Hybrid 2019-21|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=Avalon Hybrid 2019-21">Buy Here</a></sub></details>||
|Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=Avalon Hybrid 2022">Buy Here</a></sub></details>||
|Toyota|C-HR 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=C-HR 2017-20">Buy Here</a></sub></details>||
|Toyota|C-HR 2021|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=C-HR 2021">Buy Here</a></sub></details>||
|Toyota|C-HR 2021|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 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=C-HR 2021">Buy Here</a></sub></details>||
|Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=C-HR Hybrid 2017-20">Buy Here</a></sub></details>||
|Toyota|C-HR Hybrid 2021-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=C-HR Hybrid 2021-22">Buy Here</a></sub></details>||
|Toyota|Camry 2018-20|All|Stock|0 mph[<sup>8</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=Camry 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=fkcjviZY9CM" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|Camry 2021-24|All|openpilot|0 mph[<sup>8</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=Camry 2021-24">Buy Here</a></sub></details>||
|Toyota|C-HR Hybrid 2021-22|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 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=C-HR Hybrid 2021-22">Buy Here</a></sub></details>||
|Toyota|Camry 2018-20|All|Stock|0 mph[<sup>9</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=Camry 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=fkcjviZY9CM" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|Camry 2021-24|All|openpilot|0 mph[<sup>9</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=Camry 2021-24">Buy Here</a></sub></details>||
|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=Camry Hybrid 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Q2DYY0AWKgk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|Camry Hybrid 2021-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=Camry Hybrid 2021-24">Buy Here</a></sub></details>||
|Toyota|Corolla 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=Corolla 2017-19">Buy Here</a></sub></details>||
@ -235,47 +244,49 @@ A supported vehicle is one that just works when you install a comma device. All
|Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=RAV4 2016">Buy Here</a></sub></details>||
|Toyota|RAV4 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=RAV4 2017-18">Buy Here</a></sub></details>||
|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=RAV4 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=wJxjDd42gGA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=RAV4 2022">Buy Here</a></sub></details>||
|Toyota|RAV4 2022|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 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=RAV4 2022">Buy Here</a></sub></details>||
|Toyota|RAV4 2023-24|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 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=RAV4 2023-24">Buy Here</a></sub></details>||
|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=RAV4 Hybrid 2016">Buy Here</a></sub></details>|<a href="https://youtu.be/LhT5VzJVfNI?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=RAV4 Hybrid 2017-18">Buy Here</a></sub></details>|<a href="https://youtu.be/LhT5VzJVfNI?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=RAV4 Hybrid 2019-21">Buy Here</a></sub></details>||
|Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=RAV4 Hybrid 2022">Buy Here</a></sub></details>|<a href="https://youtu.be/U0nH9cnrFB0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|RAV4 Hybrid 2022|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 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=RAV4 Hybrid 2022">Buy Here</a></sub></details>|<a href="https://youtu.be/U0nH9cnrFB0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|RAV4 Hybrid 2023-24|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 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=RAV4 Hybrid 2023-24">Buy Here</a></sub></details>||
|Toyota|Sienna 2018-20|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<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=Toyota&model=Sienna 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=q1UPOo4Sh68" 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 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|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>||
|Volkswagen|Caravelle 2020|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=Caravelle 2020">Buy Here</a></sub></details>||
|Volkswagen|CC 2018-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=CC 2018-22">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Crafter 2017-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=Crafter 2017-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|e-Crafter 2018-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=e-Crafter 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|e-Golf 2014-20|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=e-Golf 2014-20">Buy Here</a></sub></details>||
|Volkswagen|Golf 2015-20|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-empty.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=Golf 2015-20">Buy Here</a></sub></details>||
|Volkswagen|Golf Alltrack 2015-19|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-empty.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=Golf Alltrack 2015-19">Buy Here</a></sub></details>||
|Volkswagen|Golf GTD 2015-20|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=Golf GTD 2015-20">Buy Here</a></sub></details>||
|Volkswagen|Golf GTE 2015-20|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=Golf GTE 2015-20">Buy Here</a></sub></details>||
|Volkswagen|Golf GTI 2015-21|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-empty.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=Golf GTI 2015-21">Buy Here</a></sub></details>||
|Volkswagen|Golf R 2015-19|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=Golf R 2015-19">Buy Here</a></sub></details>||
|Volkswagen|Golf SportsVan 2015-20|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=Golf SportsVan 2015-20">Buy Here</a></sub></details>||
|Volkswagen|Grand California 2019-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=Grand California 2019-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Jetta 2018-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=Jetta 2018-22">Buy Here</a></sub></details>||
|Volkswagen|Jetta GLI 2021-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=Jetta GLI 2021-22">Buy Here</a></sub></details>||
|Volkswagen|Passat 2015-22[<sup>10</sup>](#footnotes)|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=Passat 2015-22">Buy Here</a></sub></details>||
|Volkswagen|Passat Alltrack 2015-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=Passat Alltrack 2015-22">Buy Here</a></sub></details>||
|Volkswagen|Passat GTE 2015-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=Passat GTE 2015-22">Buy Here</a></sub></details>||
|Volkswagen|Polo 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=Polo 2018-23">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Volkswagen|Polo GTI 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=Polo GTI 2018-23">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Volkswagen|T-Cross 2021|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=T-Cross 2021">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Volkswagen|T-Roc 2018-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=T-Roc 2018-22">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Volkswagen|Taos 2022-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=Taos 2022-23">Buy Here</a></sub></details>||
|Volkswagen|Teramont 2018-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=Teramont 2018-22">Buy Here</a></sub></details>||
|Volkswagen|Teramont Cross Sport 2021-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=Teramont Cross Sport 2021-22">Buy Here</a></sub></details>||
|Volkswagen|Teramont X 2021-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=Teramont X 2021-22">Buy Here</a></sub></details>||
|Volkswagen|Tiguan 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=Tiguan 2018-23">Buy Here</a></sub></details>||
|Volkswagen|Tiguan eHybrid 2021-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=Tiguan eHybrid 2021-23">Buy Here</a></sub></details>||
|Volkswagen|Touran 2016-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=Touran 2016-23">Buy Here</a></sub></details>||
|Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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,13</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,13</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|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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,13</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,13</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|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Caravelle 2020">Buy Here</a></sub></details>||
|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=CC 2018-22">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Crafter 2017-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=e-Crafter 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=e-Golf 2014-20">Buy Here</a></sub></details>||
|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.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=Golf 2015-20">Buy Here</a></sub></details>||
|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.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=Golf Alltrack 2015-19">Buy Here</a></sub></details>||
|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Golf GTD 2015-20">Buy Here</a></sub></details>||
|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Golf GTE 2015-20">Buy Here</a></sub></details>||
|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.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=Golf GTI 2015-21">Buy Here</a></sub></details>||
|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Golf R 2015-19">Buy Here</a></sub></details>||
|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Golf SportsVan 2015-20">Buy Here</a></sub></details>||
|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Grand California 2019-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Jetta 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Jetta 2018-24">Buy Here</a></sub></details>||
|Volkswagen|Jetta GLI 2021-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Jetta GLI 2021-24">Buy Here</a></sub></details>||
|Volkswagen|Passat 2015-22[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Passat 2015-22">Buy Here</a></sub></details>||
|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Passat Alltrack 2015-22">Buy Here</a></sub></details>||
|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Passat GTE 2015-22">Buy Here</a></sub></details>||
|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Polo 2018-23">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Polo GTI 2018-23">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=T-Cross 2021">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|Volkswagen|T-Roc 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=T-Roc 2018-22">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|Volkswagen|Taos 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Taos 2022-23">Buy Here</a></sub></details>||
|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Teramont 2018-22">Buy Here</a></sub></details>||
|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Teramont Cross Sport 2021-22">Buy Here</a></sub></details>||
|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Teramont X 2021-22">Buy Here</a></sub></details>||
|Volkswagen|Tiguan 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Tiguan 2018-24">Buy Here</a></sub></details>||
|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Tiguan eHybrid 2021-23">Buy Here</a></sub></details>||
|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</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=Touran 2016-23">Buy Here</a></sub></details>||
### Footnotes
<sup>1</sup>openpilot Longitudinal Control (Alpha) is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`. <br />
@ -285,12 +296,13 @@ A supported vehicle is one that just works when you install a comma device. All
<sup>5</sup>2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph. <br />
<sup>6</sup>Requires a <a href="https://comma.ai/shop/can-fd-panda-kit" target="_blank">CAN FD panda kit</a> if not using comma 3X for this <a href="https://en.wikipedia.org/wiki/CAN_FD" target="_blank">CAN FD car</a>. <br />
<sup>7</sup>In the non-US market, openpilot requires the car to come equipped with EyeSight with Lane Keep Assistance. <br />
<sup>8</sup>openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control. <br />
<sup>9</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br />
<sup>10</sup>Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets. <br />
<sup>11</sup>Some Škoda vehicles are equipped with heated windshields, which are known to block GPS signal needed for some comma 3X functionality. <br />
<sup>12</sup>Only available for vehicles using a gateway (J533) harness. At this time, vehicles using a camera harness are limited to using stock ACC. <br />
<sup>13</sup>Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot in software, but doesn't yet have a harness available from the comma store. <br />
<sup>8</sup>Enabling longitudinal control (alpha) will disable all EyeSight functionality, including AEB, LDW, and RAB. <br />
<sup>9</sup>openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control. <br />
<sup>10</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br />
<sup>11</sup>Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets. <br />
<sup>12</sup>Some Škoda vehicles are equipped with heated windshields, which are known to block GPS signal needed for some comma 3X functionality. <br />
<sup>13</sup>Only available for vehicles using a gateway (J533) harness. At this time, vehicles using a camera harness are limited to using stock ACC. <br />
<sup>14</sup>Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot in software, but doesn't yet have a harness available from the comma store. <br />
## Community Maintained Cars
Although they're not upstream, the community has openpilot running on other makes and models. See the 'Community Supported Models' section of each make [on our wiki](https://wiki.comma.ai/).

@ -1,26 +1,50 @@
# How to contribute
Our software is open source so you can solve your own problems without needing help from others. And if you solve a problem and are so kind, you can upstream it for the rest of the world to use. Check out our [post about externalization](https://blog.comma.ai/a-2020-theme-externalization/).
Most open source development activity is coordinated through our [GitHub Discussions](https://github.com/commaai/openpilot/discussions) and [Discord](https://discord.comma.ai). A lot of documentation is available at https://docs.comma.ai and on our [blog](https://blog.comma.ai/).
Our software is open source so you can solve your own problems without needing help from others. And if you solve a problem and are so kind, you can upstream it for the rest of the world to use. Check out our [post about externalization](https://blog.comma.ai/a-2020-theme-externalization/). Development activity is coordinated through our GitHub Issues, [GitHub Discussions](https://github.com/commaai/openpilot/discussions), and [Discord](https://discord.comma.ai).
### Getting Started
* Setup your [development environment](../tools/)
* Join our [Discord](https://discord.comma.ai)
* Make sure you have a [GitHub account](https://github.com/signup/free)
* Fork [our repositories](https://github.com/commaai) on GitHub
* Setup your [development environment](../tools/)
* Read about the [development workflow](WORKFLOW.md)
* Join our [Discord](https://discord.comma.ai)
* Docs are at https://docs.comma.ai and https://blog.comma.ai
## What contributions are we looking for?
**openpilot's priorities are [safety](SAFETY.md), stability, quality, and features, in that order.** openpilot is part of comma's mission to *solve self-driving cars while delivering shippable intermediaries*, and **all** development is towards that goal.
### What gets merged?
The probability of a pull request being merged is a function of its value to the project and the effort it will take us to get it merged.
If a PR offers *some* value but will take lots of time to get merged, it will be closed.
Simple, well-tested bug fixes are the easiest to merge, and new features are the hardest to get merged.
All of these are examples of good PRs:
* typo fix: https://github.com/commaai/openpilot/pull/30678
* removing unused code: https://github.com/commaai/openpilot/pull/30573
* simple car model port: https://github.com/commaai/openpilot/pull/30245
* car brand port: https://github.com/commaai/openpilot/pull/23331
### What doesn't get merged?
* **arbitrary style changes**: code is art, and it's up to the author to make it beautiful
* **500+ line PRs**: clean it up, break it up into smaller PRs, or both
* **PRs without a clear goal**: every PR must have a singular and clear goal
* **UI design changes**: we do not have a good review process for this yet
* **New features**: We believe openpilot is mostly feature-complete, and the rest is a matter of refinement and fixing bugs. As a result of this, most feature PRs will be immediately closed, however the beauty of open source is that forks can and do offer features that upstream openpilot doesn't.
### First contribution
Try out some of these first pull requests ideas to dive into the codebase:
* Increase our [mypy](http://mypy-lang.org/) coverage
* Write some documentation
* Tackle an open [good first issue](https://github.com/commaai/openpilot/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
Check out any [good first issue](https://github.com/commaai/openpilot/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) to get started.
### What do I need to contribute?
A lot of openpilot work requires only a PC, and some requires a comma device.
Most car-related contributions require access to that car, plus a comma device installed in the car.
## Pull Requests
Pull requests should be against the master branch. Welcomed contributions include bug reports, car ports, and any [open issue](https://github.com/commaai/openpilot/issues). If you're unsure about a contribution, feel free to open a discussion, issue, or draft PR to discuss the problem you're trying to solve.
Pull requests should be against the master branch. If you're unsure about a contribution, feel free to open a discussion, issue, or draft PR to discuss the problem you're trying to solve.
A good pull request has all of the following:
* a clearly stated purpose
@ -31,18 +55,11 @@ A good pull request has all of the following:
* if you've improved your car's tuning, post before and after plots
* passes the CI tests
### Car Ports
We've released a [Model Port guide](https://blog.comma.ai/openpilot-port-guide-for-toyota-models/) for porting to Toyota/Lexus models.
If you port openpilot to a substantially new car brand, see this more generic [Brand Port guide](https://blog.comma.ai/how-to-write-a-car-port-for-openpilot/).
## Testing
### Automated Testing
All PRs and commits are automatically checked by GitHub Actions. Check out `.github/workflows/` for what GitHub Actions runs. Any new tests should be added to GitHub Actions.
### Code Style and Linting
## Contributing without Code
Code is automatically checked for style by GitHub Actions as part of the automated tests. You can also run these tests yourself by running `pre-commit run --all`.
* Report bugs in GitHub issues.
* Report driving issues in the `#driving-feedback` Discord channel.
* Consider opting into driver camera uploads to improve the driver monitoring model.
* Connect your device to Wi-Fi regularly, so that we can pull data for training better driving models.
* Run the `nightly` branch and report issues. This branch is like `master` but it's built just like a release.
* Annotate images in the [comma10k dateset](https://github.com/commaai/comma10k).

@ -9,17 +9,17 @@ source "$BASEDIR/launch_env.sh"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
function agnos_init {
# wait longer for weston to come up
if [ -f "$BASEDIR/prebuilt" ]; then
sleep 3
fi
# TODO: move this to agnos
sudo rm -f /data/etc/NetworkManager/system-connections/*.nmmeta
# set success flag for current boot slot
sudo abctl --set_success
# TODO: do this without udev in AGNOS
# udev does this, but sometimes we startup faster
sudo chgrp gpu /dev/adsprpc-smd /dev/ion /dev/kgsl-3d0
sudo chmod 660 /dev/adsprpc-smd /dev/ion /dev/kgsl-3d0
# Check if AGNOS update is required
if [ $(< /VERSION) != "$AGNOS_VERSION" ]; then
AGNOS_PY="$DIR/system/hardware/tici/agnos.py"
@ -35,9 +35,6 @@ function launch {
# Remove orphaned git lock if it exists on boot
[ -f "$DIR/.git/index.lock" ] && rm -f $DIR/.git/index.lock
# Pull time from panda
$DIR/selfdrive/boardd/set_time.py
# Check to see if there's a valid overlay-based update available. Conditions
# are as follows:
#
@ -77,14 +74,19 @@ function launch {
export PYTHONPATH="$PWD"
# hardware specific init
if [ -f /AGNOS ]; then
agnos_init
fi
# write tmux scrollback to a file
tmux capture-pane -pq -S-1000 > /tmp/launch_log
# start manager
cd selfdrive/manager
./build.py && ./manager.py
if [ ! -f $DIR/prebuilt ]; then
./build.py
fi
./manager.py
# if broken, keep on screen error
while true; do sleep 1; done

@ -7,11 +7,7 @@ export OPENBLAS_NUM_THREADS=1
export VECLIB_MAXIMUM_THREADS=1
if [ -z "$AGNOS_VERSION" ]; then
export AGNOS_VERSION="8.2"
fi
if [ -z "$PASSIVE" ]; then
export PASSIVE="1"
export AGNOS_VERSION="9.7"
fi
export STAGING_ROOT="/data/safe_staging"

@ -1,5 +1,3 @@
#!/usr/bin/bash
export PASSIVE="0"
exec ./launch_chffrplus.sh

@ -54,7 +54,7 @@ public:
bool ignore_checksum = false;
bool ignore_counter = false;
bool parse(uint64_t sec, const std::vector<uint8_t> &dat);
bool parse(uint64_t nanos, const std::vector<uint8_t> &dat);
bool update_counter_generic(int64_t v, int cnt_size);
};
@ -69,9 +69,9 @@ private:
public:
bool can_valid = false;
bool bus_timeout = false;
uint64_t first_sec = 0;
uint64_t last_sec = 0;
uint64_t last_nonempty_sec = 0;
uint64_t first_nanos = 0;
uint64_t last_nanos = 0;
uint64_t last_nonempty_nanos = 0;
uint64_t bus_timeout_threshold = 0;
uint64_t can_invalid_cnt = CAN_INVALID_CNT;
@ -81,10 +81,10 @@ public:
#ifndef DYNAMIC_CAPNP
void update_string(const std::string &data, bool sendcan);
void update_strings(const std::vector<std::string> &data, std::vector<SignalValue> &vals, bool sendcan);
void UpdateCans(uint64_t sec, const capnp::List<cereal::CanData>::Reader& cans);
void UpdateCans(uint64_t nanos, const capnp::List<cereal::CanData>::Reader& cans);
#endif
void UpdateCans(uint64_t sec, const capnp::DynamicStruct::Reader& cans);
void UpdateValid(uint64_t sec);
void UpdateCans(uint64_t nanos, const capnp::DynamicStruct::Reader& cans);
void UpdateValid(uint64_t nanos);
void query_latest(std::vector<SignalValue> &vals, uint64_t last_ts = 0);
};

@ -62,7 +62,7 @@ cdef extern from "common_dbc.h":
cdef extern from "common.h":
cdef const DBC* dbc_lookup(const string)
cdef const DBC* dbc_lookup(const string) except +
cdef cppclass CANParser:
bool can_valid

@ -26,6 +26,10 @@ cdef class CANPacker:
msg = self.dbc[0].msgs[i]
self.name_to_address[string(msg.name)] = msg.address
def __dealloc__(self):
if self.packer:
del self.packer
cdef vector[uint8_t] pack(self, addr, values):
cdef vector[SignalPackValue] values_thing
values_thing.reserve(len(values))

@ -33,7 +33,11 @@ int64_t get_raw_value(const std::vector<uint8_t> &msg, const Signal &sig) {
}
bool MessageState::parse(uint64_t sec, const std::vector<uint8_t> &dat) {
bool MessageState::parse(uint64_t nanos, const std::vector<uint8_t> &dat) {
std::vector<double> tmp_vals(parse_sigs.size());
bool checksum_failed = false;
bool counter_failed = false;
for (int i = 0; i < parse_sigs.size(); i++) {
const auto &sig = parse_sigs[i];
@ -44,50 +48,48 @@ bool MessageState::parse(uint64_t sec, const std::vector<uint8_t> &dat) {
//DEBUG("parse 0x%X %s -> %ld\n", address, sig.name, tmp);
bool checksum_failed = false;
if (!ignore_checksum) {
if (sig.calc_checksum != nullptr && sig.calc_checksum(address, sig, dat) != tmp) {
checksum_failed = true;
}
}
bool counter_failed = false;
if (!ignore_counter) {
if (sig.type == SignalType::COUNTER) {
counter_failed = !update_counter_generic(tmp, sig.size);
if (sig.type == SignalType::COUNTER && !update_counter_generic(tmp, sig.size)) {
counter_failed = true;
}
}
tmp_vals[i] = tmp * sig.factor + sig.offset;
}
// only update values if both checksum and counter are valid
if (checksum_failed || counter_failed) {
LOGE("0x%X message checks failed, checksum failed %d, counter failed %d", address, checksum_failed, counter_failed);
return false;
}
// TODO: these may get updated if the invalid or checksum gets checked later
vals[i] = tmp * sig.factor + sig.offset;
for (int i = 0; i < parse_sigs.size(); i++) {
vals[i] = tmp_vals[i];
all_vals[i].push_back(vals[i]);
}
last_seen_nanos = sec;
last_seen_nanos = nanos;
return true;
}
bool MessageState::update_counter_generic(int64_t v, int cnt_size) {
uint8_t old_counter = counter;
counter = v;
if (((old_counter+1) & ((1 << cnt_size) -1)) != v) {
counter_fail += 1;
if (((counter + 1) & ((1 << cnt_size) -1)) != v) {
counter_fail = std::min(counter_fail + 1, MAX_BAD_COUNTER);
if (counter_fail > 1) {
INFO("0x%X COUNTER FAIL #%d -- %d -> %d\n", address, counter_fail, old_counter, (int)v);
}
if (counter_fail >= MAX_BAD_COUNTER) {
return false;
INFO("0x%X COUNTER FAIL #%d -- %d -> %d\n", address, counter_fail, counter, (int)v);
}
} else if (counter_fail > 0) {
counter_fail--;
}
return true;
counter = v;
return counter_fail < MAX_BAD_COUNTER;
}
@ -182,29 +184,29 @@ void CANParser::update_string(const std::string &data, bool sendcan) {
capnp::FlatArrayMessageReader cmsg(aligned_buf.slice(0, buf_size));
cereal::Event::Reader event = cmsg.getRoot<cereal::Event>();
if (first_sec == 0) {
first_sec = event.getLogMonoTime();
if (first_nanos == 0) {
first_nanos = event.getLogMonoTime();
}
last_sec = event.getLogMonoTime();
last_nanos = event.getLogMonoTime();
auto cans = sendcan ? event.getSendcan() : event.getCan();
UpdateCans(last_sec, cans);
UpdateCans(last_nanos, cans);
UpdateValid(last_sec);
UpdateValid(last_nanos);
}
void CANParser::update_strings(const std::vector<std::string> &data, std::vector<SignalValue> &vals, bool sendcan) {
uint64_t current_sec = 0;
uint64_t current_nanos = 0;
for (const auto &d : data) {
update_string(d, sendcan);
if (current_sec == 0) {
current_sec = last_sec;
if (current_nanos == 0) {
current_nanos = last_nanos;
}
}
query_latest(vals, current_sec);
query_latest(vals, current_nanos);
}
void CANParser::UpdateCans(uint64_t sec, const capnp::List<cereal::CanData>::Reader& cans) {
void CANParser::UpdateCans(uint64_t nanos, const capnp::List<cereal::CanData>::Reader& cans) {
//DEBUG("got %d messages\n", cans.size());
bool bus_empty = true;
@ -238,18 +240,18 @@ void CANParser::UpdateCans(uint64_t sec, const capnp::List<cereal::CanData>::Rea
std::vector<uint8_t> data(dat.size(), 0);
memcpy(data.data(), dat.begin(), dat.size());
state_it->second.parse(sec, data);
state_it->second.parse(nanos, data);
}
// update bus timeout
if (!bus_empty) {
last_nonempty_sec = sec;
last_nonempty_nanos = nanos;
}
bus_timeout = (sec - last_nonempty_sec) > bus_timeout_threshold;
bus_timeout = (nanos - last_nonempty_nanos) > bus_timeout_threshold;
}
#endif
void CANParser::UpdateCans(uint64_t sec, const capnp::DynamicStruct::Reader& cmsg) {
void CANParser::UpdateCans(uint64_t nanos, const capnp::DynamicStruct::Reader& cmsg) {
// assume message struct is `cereal::CanData` and parse
assert(cmsg.has("address") && cmsg.has("src") && cmsg.has("dat") && cmsg.has("busTime"));
@ -268,11 +270,11 @@ void CANParser::UpdateCans(uint64_t sec, const capnp::DynamicStruct::Reader& cms
if (dat.size() > 64) return; // shouldn't ever happen
std::vector<uint8_t> data(dat.size(), 0);
memcpy(data.data(), dat.begin(), dat.size());
state_it->second.parse(sec, data);
state_it->second.parse(nanos, data);
}
void CANParser::UpdateValid(uint64_t sec) {
const bool show_missing = (last_sec - first_sec) > 8e9;
void CANParser::UpdateValid(uint64_t nanos) {
const bool show_missing = (last_nanos - first_nanos) > 8e9;
bool _valid = true;
bool _counters_valid = true;
@ -284,7 +286,7 @@ void CANParser::UpdateValid(uint64_t sec) {
}
const bool missing = state.last_seen_nanos == 0;
const bool timed_out = (sec - state.last_seen_nanos) > state.check_threshold;
const bool timed_out = (nanos - state.last_seen_nanos) > state.check_threshold;
if (state.check_threshold > 0 && (missing || timed_out)) {
if (show_missing && !bus_timeout) {
if (missing) {
@ -302,7 +304,7 @@ void CANParser::UpdateValid(uint64_t sec) {
void CANParser::query_latest(std::vector<SignalValue> &vals, uint64_t last_ts) {
if (last_ts == 0) {
last_ts = last_sec;
last_ts = last_nanos;
}
for (auto& kv : message_states) {
auto& state = kv.second;

@ -66,6 +66,10 @@ cdef class CANParser:
self.can = new cpp_CANParser(bus, dbc_name, message_v)
self.update_strings([])
def __dealloc__(self):
if self.can:
del self.can
def update_strings(self, strings, sendcan=False):
for v in self.vl_all.values():
for l in v.values(): # no-cython-lint

@ -22,18 +22,47 @@ BO_ 280 ECM_TRQ: 8 XXX
BO_ 284 ESP_8: 8 XXX
SG_ BRK_PRESSURE : 3|12@0+ (1,0) [0|1] "" XXX
SG_ Vehicle_Stopped : 7|1@0+ (1,0) [0|1] "" XXX
SG_ BRAKE_PEDAL : 19|12@0+ (1,0) [0|1] "" XXX
SG_ Vehicle_Speed : 39|16@0+ (0.0078125,0) [0|511.984375] "km/h" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
BO_ 288 ECM_2: 7 XXX
SG_ ACC_TORQUE_REQ_ENABLE : 5|1@1+ (1,0) [0|0] "" XXX
SG_ ESC_TORQUE_REQ_ENABLE : 6|1@1+ (1,0) [0|0] "" XXX
SG_ TCM_TORQUE_REQ_ENABLE : 7|1@1+ (1,0) [0|0] "" XXX
SG_ Accelerator_Position : 16|8@1+ (0.4,0) [0|100] "%" XXX
SG_ CRUISE_OVERRIDE : 31|1@1+ (1,0) [0|0] "" XXX
SG_ COUNTER : 47|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 55|8@0+ (1,0) [0|0] "" XXX
BO_ 320 ESP_1: 8 XXX
SG_ Brake_State : 0|2@1+ (1,0) [0|0] "" XXX
SG_ Brake_Pedal_State : 2|2@1+ (1,0) [0|0] "" XXX
SG_ ACC_Engaged : 15|1@0+ (1,0) [0|1] "" XXX
SG_ ACC_Enabled : 23|1@0+ (1,0) [0|1] "" XXX
SG_ Vehicle_Speed : 33|10@0+ (0.5,0) [0|511] "km/h" XXX
SG_ ACC_OFF_REQ : 39|2@0+ (1,0) [0|0] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
SG_ BRAKE_PRESSED_ACC : 6|1@0+ (1,0) [0|3] "" XXX
BO_ 268 ESP_2: 8 ESC
SG_ ESC_TORQUE_REQ : 4|13@0+ (0.25,-500) [-500|1547.5] "Nm" XXX
SG_ ACC_TORQUE_REQ_ENABLE : 5|1@1+ (1,0) [0|0] "" XXX
SG_ ESC_TORQUE_REQ_MAX : 6|1@1+ (1,0) [0|0] "" XXX
SG_ ESC_TORQUE_REQ_MIN : 7|1@1+ (1,0) [0|0] "" XXX
SG_ ACC_TORQUE_REQ : 20|13@0+ (0.25,-500) [-500|1547.5] "Nm" XXX
SG_ TCS_ACTIVE : 21|1@1+ (1,0) [0|0] "" XXX
SG_ ACC_TORQUE_REQ_MAX : 22|1@1+ (1,0) [0|0] "" XXX
SG_ ACC_BRK_PREP : 40|1@1+ (1,0) [0|0] "" XXX
SG_ DISABLE_FUEL_SHUTOFF : 47|1@1+ (1,0) [0|0] "" XXX
SG_ DAS_REQ_ACTIVE : 48|3@1+ (1,0) [0|0] "" XXX
SG_ COLLISION_BRK_PREP : 51|1@1+ (1,0) [0|0] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|0] "" XXX
BO_ 344 ESP_6: 8 XXX
SG_ WHEEL_SPEED_FL : 5|14@0+ (0.5,0) [0|8191] "rpm" XXX
SG_ WHEEL_SPEED_FR : 21|14@0+ (0.5,0) [0|8191] "rpm" XXX
@ -59,11 +88,9 @@ BO_ 500 DAS_3: 8 XXX
SG_ DISABLE_FUEL_SHUTOFF : 23|1@1+ (1,0) [0|0] "" XXX
SG_ GR_MAX_REQ : 32|4@1+ (1,0) [0|0] "" XXX
SG_ ACC_DECEL_REQ : 36|3@1+ (1,0) [0|0] "" XXX
SG_ STS : 46|2@1+ (1,0) [0|0] "" XXX
SG_ ACC_FAULTED : 47|1@0+ (1,0) [0|1] "" XXX
SG_ ACC_FAULTED : 46|2@1+ (1,0) [0|0] "" XXX
SG_ COLLISION_BRK_PREP : 48|1@1+ (1,0) [0|0] "" XXX
SG_ ACC_BRK_PREP : 49|1@1+ (1,0) [0|0] "" XXX
SG_ BRAKE_BOOL_1 : 36|1@0+ (1,0) [0|3] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
@ -74,6 +101,11 @@ BO_ 501 DAS_4: 8 XXX
SG_ ACC_DISTANCE_CONFIG_2 : 41|2@0+ (1,0) [0|3] "" XXX
SG_ SPEED_DIGITAL : 63|8@0+ (1,0) [0|255] "mph" XXX
SG_ ACC_STATE : 38|3@0+ (1,0) [0|7] "" XXX
SG_ FCW_OFF : 25|2@0+ (1,0) [0|3] "" XXX
SG_ FCW_ERROR : 27|2@0+ (1,0) [0|3] "" XXX
SG_ FCW_BRAKE_ENABLED : 29|1@0+ (1,0) [0|1] "" XXX
SG_ FCW_BRAKE_DISABLED : 47|1@0+ (1,0) [0|1] "" XXX
SG_ ACC_FAULTED : 50|1@0+ (1,0) [0|1] "" XXX
BO_ 544 EPS_2: 8 XXX
SG_ LKAS_STATE : 23|4@0+ (1,0) [0|15] "" XXX
@ -103,12 +135,28 @@ BO_ 571 CRUISE_BUTTONS: 3 XXX
SG_ COUNTER : 15|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 23|8@0+ (1,0) [0|255] "" XXX
BO_ 625 DAS_5: 8 XXX
SG_ FCW_STATE : 2|1@1+ (1,0) [0|0] "" XXX
SG_ FCW_DISTANCE : 3|2@1+ (1,0) [0|0] "" XXX
SG_ ACCFCW_MESSAGE : 12|4@1+ (1,0) [0|0] "" XXX
SG_ SET_SPEED_KPH : 24|8@1+ (1,0) [0|250] "km/h" XXX
SG_ WHEEL_TORQUE_REQUEST : 38|15@0+ (1,-7767) [-7767|24999] "Nm" XXX
SG_ WHEEL_TORQUE_REQUEST_ACTIVE : 39|1@1+ (1,0) [0|0] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
BO_ 669 EPB_1: 3 XXX
SG_ PARKING_BRAKE_STATUS : 11|3@0+ (1,0) [0|7] "" XXX
SG_ COUNTER : 15|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 23|8@0+ (1,0) [0|255] "" XXX
BO_ 678 DAS_6: 8 XXX
SG_ LKAS_ICON_COLOR : 1|2@0+ (1,0) [0|3] "" XXX
SG_ LKAS_LANE_LINES : 19|4@0+ (1,0) [0|1] "" XXX
SG_ LKAS_ALERTS : 27|4@0+ (1,0) [0|1] "" XXX
SG_ CAR_MODEL : 15|8@0+ (1,0) [0|255] "" XXX
SG_ AUTO_HIGH_BEAM_ON : 47|1@1+ (1,0) [0|0] "" XXX
SG_ LKAS_DISABLED : 56|1@1+ (1,0) [0|0] "" XXX
BO_ 720 BSM_1: 6 XXX
SG_ RIGHT_STATUS : 5|1@0+ (1,0) [0|1] "" XXX
@ -124,11 +172,14 @@ BO_ 820 BCM_1: 8 XXX
SG_ DOOR_OPEN_RL : 19|1@0+ (1,0) [0|1] "" XXX
SG_ DOOR_OPEN_RR : 20|1@0+ (1,0) [0|1] "" XXX
SG_ DOOR_OPEN_TRUNK : 22|1@0+ (1,0) [0|1] "" XXX
SG_ PARKING_BRAKE_SWITCH : 23|1@0+ (1,0) [0|1] "" XXX
SG_ TURN_LIGHT_LEFT : 31|1@0+ (1,0) [0|1] "" XXX
SG_ TURN_LIGHT_RIGHT : 30|1@0+ (1,0) [0|1] "" XXX
SG_ HIGH_BEAM_DISPLAY : 58|1@0+ (1,0) [0|1] "" XXX
VAL_ 320 ACC_OFF_REQ 2 "PERMANENT" 1 "TEMPORARY" 0 "NONE"
VAL_ 368 Gear_State 4 "D" 2 "N" 1 "R" 0 "P" ;
VAL_ 669 PARKING_BRAKE_STATUS 3 "RELEASING" 2 "APPLYING" 1 "APPLIED" 0 "OFF" ;
CM_ SG_ 258 STEERING_ANGLE_HP "Steering angle high precision";
CM_ SG_ 264 ENGINE_TORQUE "Effective engine torque";
@ -209,12 +260,6 @@ BO_ 608 PARKSENSE_SIGNAL: 8 XXX
BO_ 729 LKAS_HEARTBIT: 5 XXX
SG_ LKAS_STATUS_OK : 31|16@0+ (1,0) [0|65535] "" XXX
BO_ 288 ACCEL_RELATED_120: 7 XXX
SG_ COUNTER : 47|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 55|8@0+ (1,0) [0|255] "" XXX
SG_ ACCEL : 23|8@0+ (1,0) [0|255] "" XXX
SG_ GAS_ENGINE_RPM_MAYBE : 31|16@0+ (1,0) [0|65535] "" XXX
BO_ 257 ACCEL_RELATED_101: 5 XXX
SG_ ENERGY_OR_RPM : 31|8@0+ (1,0) [0|255] "" XXX
@ -278,17 +323,6 @@ BO_ 324 SPEED_2: 8 XXX
BO_ 832 UNKNOWN_340: 8 XXX
SG_ SPEED_DIGITAL : 63|8@0+ (1,0) [0|255] "mph" XXX
BO_ 625 ACC_1: 8 XXX
SG_ SPEED : 31|8@0+ (1,0) [0|255] "km/h" XXX
SG_ ACCEL_PERHAPS : 39|16@0+ (1,0) [0|255] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
BO_ 268 ACC_10c: 8 XXX
SG_ BRAKE_PERHAPS : 48|1@0+ (1,0) [0|3] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
CM_ SG_ 653 BRAKE_PRESSURE "max seems to be 148";
CM_ SG_ 746 PRNDL "5=L, 4=D, 3=N, 2=R, 1=P";
CM_ SG_ 320 BRAKE_PRESSED_2 "Value is 5 when brake is pressed by human, 1 when ACC brake";

@ -24,18 +24,47 @@ BO_ 181 ECM_TRQ: 8 XXX
BO_ 121 ESP_8: 8 XXX
SG_ BRK_PRESSURE : 3|12@0+ (1,0) [0|1] "" XXX
SG_ Vehicle_Stopped : 7|1@0+ (1,0) [0|1] "" XXX
SG_ BRAKE_PEDAL : 19|12@0+ (1,0) [0|1] "" XXX
SG_ Vehicle_Speed : 39|16@0+ (0.0078125,0) [0|511.984375] "km/h" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
BO_ 123 ECM_2: 7 XXX
SG_ ACC_TORQUE_REQ_ENABLE : 5|1@1+ (1,0) [0|0] "" XXX
SG_ ESC_TORQUE_REQ_ENABLE : 6|1@1+ (1,0) [0|0] "" XXX
SG_ TCM_TORQUE_REQ_ENABLE : 7|1@1+ (1,0) [0|0] "" XXX
SG_ Accelerator_Position : 16|8@1+ (0.4,0) [0|100] "%" XXX
SG_ CRUISE_OVERRIDE : 31|1@1+ (1,0) [0|0] "" XXX
SG_ COUNTER : 47|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 55|8@0+ (1,0) [0|0] "" XXX
BO_ 131 ESP_1: 8 XXX
SG_ Brake_State : 0|2@1+ (1,0) [0|0] "" XXX
SG_ Brake_Pedal_State : 2|2@1+ (1,0) [0|0] "" XXX
SG_ ACC_Engaged : 15|1@0+ (1,0) [0|1] "" XXX
SG_ ACC_Enabled : 23|1@0+ (1,0) [0|1] "" XXX
SG_ Vehicle_Speed : 33|10@0+ (0.5,0) [0|511] "km/h" XXX
SG_ ACC_OFF_REQ : 39|2@0+ (1,0) [0|0] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
SG_ BRAKE_PRESSED_ACC : 6|1@0+ (1,0) [0|3] "" XXX
BO_ 113 ESP_2: 8 ESC
SG_ ESC_TORQUE_REQ : 4|13@0+ (0.25,-500) [-500|1547.5] "Nm" XXX
SG_ ACC_TORQUE_REQ_ENABLE : 5|1@1+ (1,0) [0|0] "" XXX
SG_ ESC_TORQUE_REQ_MAX : 6|1@1+ (1,0) [0|0] "" XXX
SG_ ESC_TORQUE_REQ_MIN : 7|1@1+ (1,0) [0|0] "" XXX
SG_ ACC_TORQUE_REQ : 20|13@0+ (0.25,-500) [-500|1547.5] "Nm" XXX
SG_ TCS_ACTIVE : 21|1@1+ (1,0) [0|0] "" XXX
SG_ ACC_TORQUE_REQ_MAX : 22|1@1+ (1,0) [0|0] "" XXX
SG_ ACC_BRK_PREP : 40|1@1+ (1,0) [0|0] "" XXX
SG_ DISABLE_FUEL_SHUTOFF : 47|1@1+ (1,0) [0|0] "" XXX
SG_ DAS_REQ_ACTIVE : 48|3@1+ (1,0) [0|0] "" XXX
SG_ COLLISION_BRK_PREP : 51|1@1+ (1,0) [0|0] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|0] "" XXX
BO_ 139 ESP_6: 8 XXX
SG_ WHEEL_SPEED_FL : 5|14@0+ (0.5,0) [0|8191] "rpm" XXX
SG_ WHEEL_SPEED_FR : 21|14@0+ (0.5,0) [0|8191] "rpm" XXX
@ -61,11 +90,9 @@ BO_ 153 DAS_3: 8 XXX
SG_ DISABLE_FUEL_SHUTOFF : 23|1@1+ (1,0) [0|0] "" XXX
SG_ GR_MAX_REQ : 32|4@1+ (1,0) [0|0] "" XXX
SG_ ACC_DECEL_REQ : 36|3@1+ (1,0) [0|0] "" XXX
SG_ STS : 46|2@1+ (1,0) [0|0] "" XXX
SG_ ACC_FAULTED : 47|1@0+ (1,0) [0|1] "" XXX
SG_ ACC_FAULTED : 46|2@1+ (1,0) [0|0] "" XXX
SG_ COLLISION_BRK_PREP : 48|1@1+ (1,0) [0|0] "" XXX
SG_ ACC_BRK_PREP : 49|1@1+ (1,0) [0|0] "" XXX
SG_ BRAKE_BOOL_1 : 36|1@0+ (1,0) [0|3] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
@ -76,6 +103,11 @@ BO_ 232 DAS_4: 8 XXX
SG_ ACC_DISTANCE_CONFIG_2 : 41|2@0+ (1,0) [0|3] "" XXX
SG_ SPEED_DIGITAL : 63|8@0+ (1,0) [0|255] "mph" XXX
SG_ ACC_STATE : 38|3@0+ (1,0) [0|7] "" XXX
SG_ FCW_OFF : 25|2@0+ (1,0) [0|3] "" XXX
SG_ FCW_ERROR : 27|2@0+ (1,0) [0|3] "" XXX
SG_ FCW_BRAKE_ENABLED : 29|1@0+ (1,0) [0|1] "" XXX
SG_ FCW_BRAKE_DISABLED : 47|1@0+ (1,0) [0|1] "" XXX
SG_ ACC_FAULTED : 50|1@0+ (1,0) [0|1] "" XXX
BO_ 49 EPS_2: 8 XXX
SG_ LKAS_STATE : 23|4@0+ (1,0) [0|15] "" XXX
@ -105,12 +137,28 @@ BO_ 177 CRUISE_BUTTONS: 3 XXX
SG_ COUNTER : 15|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 23|8@0+ (1,0) [0|255] "" XXX
BO_ 163 DAS_5: 8 XXX
SG_ FCW_STATE : 2|1@1+ (1,0) [0|0] "" XXX
SG_ FCW_DISTANCE : 3|2@1+ (1,0) [0|0] "" XXX
SG_ ACCFCW_MESSAGE : 12|4@1+ (1,0) [0|0] "" XXX
SG_ SET_SPEED_KPH : 24|8@1+ (1,0) [0|250] "km/h" XXX
SG_ WHEEL_TORQUE_REQUEST : 38|15@0+ (1,-7767) [-7767|24999] "Nm" XXX
SG_ WHEEL_TORQUE_REQUEST_ACTIVE : 39|1@1+ (1,0) [0|0] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
BO_ 213 EPB_1: 3 XXX
SG_ PARKING_BRAKE_STATUS : 11|3@0+ (1,0) [0|7] "" XXX
SG_ COUNTER : 15|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 23|8@0+ (1,0) [0|255] "" XXX
BO_ 250 DAS_6: 8 XXX
SG_ LKAS_ICON_COLOR : 1|2@0+ (1,0) [0|3] "" XXX
SG_ LKAS_LANE_LINES : 19|4@0+ (1,0) [0|1] "" XXX
SG_ LKAS_ALERTS : 27|4@0+ (1,0) [0|1] "" XXX
SG_ CAR_MODEL : 15|8@0+ (1,0) [0|255] "" XXX
SG_ AUTO_HIGH_BEAM_ON : 47|1@1+ (1,0) [0|0] "" XXX
SG_ LKAS_DISABLED : 56|1@1+ (1,0) [0|0] "" XXX
BO_ 720 BSM_1: 6 XXX
SG_ RIGHT_STATUS : 5|1@0+ (1,0) [0|1] "" XXX
@ -126,11 +174,14 @@ BO_ 657 BCM_1: 8 XXX
SG_ DOOR_OPEN_RL : 19|1@0+ (1,0) [0|1] "" XXX
SG_ DOOR_OPEN_RR : 20|1@0+ (1,0) [0|1] "" XXX
SG_ DOOR_OPEN_TRUNK : 22|1@0+ (1,0) [0|1] "" XXX
SG_ PARKING_BRAKE_SWITCH : 23|1@0+ (1,0) [0|1] "" XXX
SG_ TURN_LIGHT_LEFT : 31|1@0+ (1,0) [0|1] "" XXX
SG_ TURN_LIGHT_RIGHT : 30|1@0+ (1,0) [0|1] "" XXX
SG_ HIGH_BEAM_DISPLAY : 58|1@0+ (1,0) [0|1] "" XXX
VAL_ 131 ACC_OFF_REQ 2 "PERMANENT" 1 "TEMPORARY" 0 "NONE"
VAL_ 147 Gear_State 4 "D" 2 "N" 1 "R" 0 "P" ;
VAL_ 213 PARKING_BRAKE_STATUS 3 "RELEASING" 2 "APPLYING" 1 "APPLIED" 0 "OFF" ;
CM_ SG_ 258 STEERING_ANGLE_HP "Steering angle high precision";
CM_ SG_ 264 ENGINE_TORQUE "Effective engine torque";
@ -148,10 +199,14 @@ BO_ 53 PCM_2: 8 XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
BO_ 133 TCM_1: 8 XXX
SG_ DESIRED_GEAR : 15|4@0+ (1,0) [0|1] "" XXX
SG_ SHIFT_PENDING : 2|1@0+ (1,0) [0|1] "" XXX
SG_ SPEED_TURBINE : 27|12@0+ (0.04,0) [0|1] "km/h" XXX
SG_ ACTUAL_GEAR : 11|4@0+ (1,0) [0|15] "" XXX
SG_ DESIRED_GEAR : 15|4@0+ (1,0) [0|1] "" XXX
SG_ TC_LOCKED : 17|1@1+ (1,0) [0|0] "" XXX
SG_ OUTPUT_SPEED : 31|16@0+ (1,0) [0|65534] "rpm" XXX
SG_ INPUT_SPEED : 47|16@0+ (1,0) [0|65534] "rpm" XXX
SG_ OUTPUT_SPEED_SIGN : 57|2@0+ (1,0) [0|3] "" XXX
SG_ COUNTER : 61|4@0+ (1,0) [0|15] "" XXX
BO_ 135 ABS_2: 8 XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|1] "" XXX

@ -24,18 +24,47 @@ BO_ 280 ECM_TRQ: 8 XXX
BO_ 284 ESP_8: 8 XXX
SG_ BRK_PRESSURE : 3|12@0+ (1,0) [0|1] "" XXX
SG_ Vehicle_Stopped : 7|1@0+ (1,0) [0|1] "" XXX
SG_ BRAKE_PEDAL : 19|12@0+ (1,0) [0|1] "" XXX
SG_ Vehicle_Speed : 39|16@0+ (0.0078125,0) [0|511.984375] "km/h" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
BO_ 288 ECM_2: 7 XXX
SG_ ACC_TORQUE_REQ_ENABLE : 5|1@1+ (1,0) [0|0] "" XXX
SG_ ESC_TORQUE_REQ_ENABLE : 6|1@1+ (1,0) [0|0] "" XXX
SG_ TCM_TORQUE_REQ_ENABLE : 7|1@1+ (1,0) [0|0] "" XXX
SG_ Accelerator_Position : 16|8@1+ (0.4,0) [0|100] "%" XXX
SG_ CRUISE_OVERRIDE : 31|1@1+ (1,0) [0|0] "" XXX
SG_ COUNTER : 47|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 55|8@0+ (1,0) [0|0] "" XXX
BO_ 320 ESP_1: 8 XXX
SG_ Brake_State : 0|2@1+ (1,0) [0|0] "" XXX
SG_ Brake_Pedal_State : 2|2@1+ (1,0) [0|0] "" XXX
SG_ ACC_Engaged : 15|1@0+ (1,0) [0|1] "" XXX
SG_ ACC_Enabled : 23|1@0+ (1,0) [0|1] "" XXX
SG_ Vehicle_Speed : 33|10@0+ (0.5,0) [0|511] "km/h" XXX
SG_ ACC_OFF_REQ : 39|2@0+ (1,0) [0|0] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
SG_ BRAKE_PRESSED_ACC : 6|1@0+ (1,0) [0|3] "" XXX
BO_ 268 ESP_2: 8 ESC
SG_ ESC_TORQUE_REQ : 4|13@0+ (0.25,-500) [-500|1547.5] "Nm" XXX
SG_ ACC_TORQUE_REQ_ENABLE : 5|1@1+ (1,0) [0|0] "" XXX
SG_ ESC_TORQUE_REQ_MAX : 6|1@1+ (1,0) [0|0] "" XXX
SG_ ESC_TORQUE_REQ_MIN : 7|1@1+ (1,0) [0|0] "" XXX
SG_ ACC_TORQUE_REQ : 20|13@0+ (0.25,-500) [-500|1547.5] "Nm" XXX
SG_ TCS_ACTIVE : 21|1@1+ (1,0) [0|0] "" XXX
SG_ ACC_TORQUE_REQ_MAX : 22|1@1+ (1,0) [0|0] "" XXX
SG_ ACC_BRK_PREP : 40|1@1+ (1,0) [0|0] "" XXX
SG_ DISABLE_FUEL_SHUTOFF : 47|1@1+ (1,0) [0|0] "" XXX
SG_ DAS_REQ_ACTIVE : 48|3@1+ (1,0) [0|0] "" XXX
SG_ COLLISION_BRK_PREP : 51|1@1+ (1,0) [0|0] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|0] "" XXX
BO_ 344 ESP_6: 8 XXX
SG_ WHEEL_SPEED_FL : 5|14@0+ (0.5,0) [0|8191] "rpm" XXX
SG_ WHEEL_SPEED_FR : 21|14@0+ (0.5,0) [0|8191] "rpm" XXX
@ -61,11 +90,9 @@ BO_ 500 DAS_3: 8 XXX
SG_ DISABLE_FUEL_SHUTOFF : 23|1@1+ (1,0) [0|0] "" XXX
SG_ GR_MAX_REQ : 32|4@1+ (1,0) [0|0] "" XXX
SG_ ACC_DECEL_REQ : 36|3@1+ (1,0) [0|0] "" XXX
SG_ STS : 46|2@1+ (1,0) [0|0] "" XXX
SG_ ACC_FAULTED : 47|1@0+ (1,0) [0|1] "" XXX
SG_ ACC_FAULTED : 46|2@1+ (1,0) [0|0] "" XXX
SG_ COLLISION_BRK_PREP : 48|1@1+ (1,0) [0|0] "" XXX
SG_ ACC_BRK_PREP : 49|1@1+ (1,0) [0|0] "" XXX
SG_ BRAKE_BOOL_1 : 36|1@0+ (1,0) [0|3] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
@ -76,6 +103,11 @@ BO_ 501 DAS_4: 8 XXX
SG_ ACC_DISTANCE_CONFIG_2 : 41|2@0+ (1,0) [0|3] "" XXX
SG_ SPEED_DIGITAL : 63|8@0+ (1,0) [0|255] "mph" XXX
SG_ ACC_STATE : 38|3@0+ (1,0) [0|7] "" XXX
SG_ FCW_OFF : 25|2@0+ (1,0) [0|3] "" XXX
SG_ FCW_ERROR : 27|2@0+ (1,0) [0|3] "" XXX
SG_ FCW_BRAKE_ENABLED : 29|1@0+ (1,0) [0|1] "" XXX
SG_ FCW_BRAKE_DISABLED : 47|1@0+ (1,0) [0|1] "" XXX
SG_ ACC_FAULTED : 50|1@0+ (1,0) [0|1] "" XXX
BO_ 544 EPS_2: 8 XXX
SG_ LKAS_STATE : 23|4@0+ (1,0) [0|15] "" XXX
@ -105,12 +137,28 @@ BO_ 570 CRUISE_BUTTONS: 3 XXX
SG_ COUNTER : 15|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 23|8@0+ (1,0) [0|255] "" XXX
BO_ 625 DAS_5: 8 XXX
SG_ FCW_STATE : 2|1@1+ (1,0) [0|0] "" XXX
SG_ FCW_DISTANCE : 3|2@1+ (1,0) [0|0] "" XXX
SG_ ACCFCW_MESSAGE : 12|4@1+ (1,0) [0|0] "" XXX
SG_ SET_SPEED_KPH : 24|8@1+ (1,0) [0|250] "km/h" XXX
SG_ WHEEL_TORQUE_REQUEST : 38|15@0+ (1,-7767) [-7767|24999] "Nm" XXX
SG_ WHEEL_TORQUE_REQUEST_ACTIVE : 39|1@1+ (1,0) [0|0] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
BO_ 669 EPB_1: 3 XXX
SG_ PARKING_BRAKE_STATUS : 11|3@0+ (1,0) [0|7] "" XXX
SG_ COUNTER : 15|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 23|8@0+ (1,0) [0|255] "" XXX
BO_ 629 DAS_6: 8 XXX
SG_ LKAS_ICON_COLOR : 1|2@0+ (1,0) [0|3] "" XXX
SG_ LKAS_LANE_LINES : 19|4@0+ (1,0) [0|1] "" XXX
SG_ LKAS_ALERTS : 27|4@0+ (1,0) [0|1] "" XXX
SG_ CAR_MODEL : 15|8@0+ (1,0) [0|255] "" XXX
SG_ AUTO_HIGH_BEAM_ON : 47|1@1+ (1,0) [0|0] "" XXX
SG_ LKAS_DISABLED : 56|1@1+ (1,0) [0|0] "" XXX
BO_ 720 BSM_1: 6 XXX
SG_ RIGHT_STATUS : 5|1@0+ (1,0) [0|1] "" XXX
@ -126,11 +174,14 @@ BO_ 820 BCM_1: 8 XXX
SG_ DOOR_OPEN_RL : 19|1@0+ (1,0) [0|1] "" XXX
SG_ DOOR_OPEN_RR : 20|1@0+ (1,0) [0|1] "" XXX
SG_ DOOR_OPEN_TRUNK : 22|1@0+ (1,0) [0|1] "" XXX
SG_ PARKING_BRAKE_SWITCH : 23|1@0+ (1,0) [0|1] "" XXX
SG_ TURN_LIGHT_LEFT : 31|1@0+ (1,0) [0|1] "" XXX
SG_ TURN_LIGHT_RIGHT : 30|1@0+ (1,0) [0|1] "" XXX
SG_ HIGH_BEAM_DISPLAY : 58|1@0+ (1,0) [0|1] "" XXX
VAL_ 320 ACC_OFF_REQ 2 "PERMANENT" 1 "TEMPORARY" 0 "NONE"
VAL_ 368 Gear_State 4 "D" 2 "N" 1 "R" 0 "P" ;
VAL_ 669 PARKING_BRAKE_STATUS 3 "RELEASING" 2 "APPLYING" 1 "APPLIED" 0 "OFF" ;
CM_ SG_ 258 STEERING_ANGLE_HP "Steering angle high precision";
CM_ SG_ 264 ENGINE_TORQUE "Effective engine torque";

@ -125,6 +125,10 @@ BO_ 320 BCMTurnSignals: 3 K9_BCM
SG_ HighBeamsActive : 7|1@0+ (1,0) [0|1] "" XXX
SG_ HighBeamsTemporary : 5|1@0+ (1,0) [0|1] "" XXX
BO_ 322 BCMBlindSpotMonitor: 7 K9_BCM
SG_ LeftBSM : 6|1@0+ (1,0) [0|1] "" XXX
SG_ RightBSM : 7|1@0+ (1,0) [0|1] "" XXX
BO_ 328 PSCM_148: 1 K43_PSCM
BO_ 381 ESPStatus: 6 K20_ECM
@ -246,10 +250,8 @@ BO_ 840 EBCMWheelSpdFront: 5 K17_EBCM
BO_ 842 EBCMWheelSpdRear: 5 K17_EBCM
SG_ RLWheelSpd : 7|16@0+ (0.0311,0) [0|255] "km/h" NEO
SG_ RRWheelSpd : 23|16@0+ (0.0311,0) [0|255] "km/h" NEO
SG_ MovingForward : 32|1@0+ (1,0) [0|1] "" XXX
SG_ MovingBackward : 33|1@0+ (1,0) [0|1] "" XXX
SG_ MovingForward2 : 35|1@1+ (1,0) [0|1] "" XXX
SG_ MovingBackward2 : 36|1@0+ (1,0) [0|1] "" XXX
SG_ RRWheelDir : 34|3@0+ (1,0) [0|7] "" NEO
SG_ RLWheelDir : 37|3@0+ (1,0) [0|7] "" NEO
BO_ 869 ASCM_365: 4 K124_ASCM
@ -317,6 +319,8 @@ CM_ BU_ K124_ASCM "Active Safety Control Module";
CM_ SG_ 381 MSG17D_AccPower "Need to investigate";
CM_ BO_ 190 "Length varies from 6 to 8 bytes by car";
CM_ SG_ 190 GasPedalAndAcc "ACC baseline is 62";
CM_ SG_ 322 LeftBSM "For some cars, this can only be when the blinker is also active";
CM_ SG_ 322 RightBSM "For some cars, this can only be when the blinker is also active";
CM_ SG_ 352 ImmobilizerInfo "Non-zero when ignition or accessory mode";
CM_ SG_ 451 GasPedalAndAcc2 "ACC baseline is 62";
CM_ SG_ 481 ACCAlwaysOne "Usually 1 if the car is equipped with ACC";
@ -347,6 +351,8 @@ VAL_ 452 CruiseState 4 "Standstill" 3 "Faulted" 1 "Active" 0 "Off" ;
VAL_ 309 PRNDL 3 "R" 2 "D" 1 "N" 0 "P" ;
VAL_ 309 ESPButton 1 "Active" 0 "Inactive" ;
VAL_ 384 LKASteeringCmdActive 1 "Active" 0 "Inactive" ;
VAL_ 842 RRWheelDir 0 "Stationary" 1 "Forward" 2 "Reverse" 3 "Unsupported" 4 "Fault";
VAL_ 842 RLWheelDir 0 "Stationary" 1 "Forward" 2 "Reverse" 3 "Unsupported" 4 "Fault";
VAL_ 880 ACCCruiseState 2 "Adaptive" 3 "Adaptive" 4 "Non-adaptive" 5 "Non-adaptive" ;
VAL_ 880 ACCLeadCar 1 "Present" 0 "Not Present" ;
VAL_ 880 ACCGapLevel 3 "Far" 2 "Med" 1 "Near" 0 "Inactive" ;

@ -374,10 +374,9 @@ BO_ 1302 ODOMETER: 8 XXX
SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" EON
CM_ SG_ 401 GEAR "10 = reverse, 11 = transition";
CM_ SG_ 450 EPB_STATE "3 \"engaged\" 2 \"disengaging\" 1 \"engaging\" 0 \"disengaged\"";
CM_ SG_ 806 REVERSE_LIGHT "Might be reverse gear selected and not the lights";
VAL_ 399 STEER_STATUS 6 "tmp_fault" 5 "fault_1" 4 "no_torque_alert_2" 3 "low_speed_lockout" 2 "no_torque_alert_1" 0 "normal" ;
VAL_ 399 STEER_STATUS 7 "permanent_fault" 6 "tmp_fault" 5 "fault_1" 4 "no_torque_alert_2" 3 "low_speed_lockout" 2 "no_torque_alert_1" 0 "normal" ;
VAL_ 401 GEAR_SHIFTER 32 "L" 16 "S" 8 "D" 4 "N" 2 "R" 1 "P" ;
VAL_ 401 GEAR 7 "L" 10 "S" 4 "D" 3 "N" 2 "R" 1 "P" ;
VAL_ 450 EPB_STATE 3 "engaged" 2 "disengaging" 1 "engaging" 0 "disengaged" ;

@ -109,6 +109,10 @@ BO_ 1265 CLU11: 4 CLU
SG_ CF_Clu_AmpInfo : 25|1@1+ (1.0,0.0) [0.0|1.0] "" BCM
SG_ CF_Clu_AliveCnt1 : 28|4@1+ (1.0,0.0) [0.0|15.0] "" AHLS,EMS,EPB,LDWS_LKAS,MDPS,SCC
BO_ 1260 Sign_Detection: 8 XXX
SG_ SpeedLim_Nav_Cam : 40|8@1+ (1,0) [0|255] "km/h / mph" XXX
SG_ SpeedLim_Nav_Cam2 : 48|8@1+ (1,0) [0|255] "km/h / mph" XXX
BO_ 1492 TMU_GW_PE_01: 8 CLU
SG_ TMU_IVRActivity : 0|2@1+ (1.0,0.0) [0.0|3.0] "" DATC
SG_ TMU_PhoneActivity : 2|2@1+ (1.0,0.0) [0.0|3.0] "" DATC

@ -279,6 +279,7 @@ BO_ 289 ES_STATIC_2: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ SET_3 : 15|2@1+ (1,0) [0|3] "" XXX
SG_ Cruise_Fault : 18|1@0+ (1,0) [0|1] "" XXX
CM_ SG_ 64 Throttle_Combo "Throttle Cruise + Pedal";
CM_ SG_ 313 Brake_Lights "Driver or Cruise Brake on";
@ -322,8 +323,8 @@ BO_ 545 ES_Distance: 8 XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ Signal1 : 12|3@1+ (1,0) [0|7] "" XXX
SG_ Cruise_Fault : 15|1@1+ (1,0) [0|1] "" XXX
SG_ Cruise_Throttle : 16|12@1+ (1,0) [0|4095] "" XXX
SG_ Signal2 : 28|4@1+ (1,0) [0|15] "" XXX
SG_ Cruise_Throttle : 16|13@1+ (1,0) [0|4095] "" XXX
SG_ Signal2 : 29|3@1+ (1,0) [0|15] "" XXX
SG_ Car_Follow : 32|1@1+ (1,0) [0|1] "" XXX
SG_ Low_Speed_Follow : 33|1@1+ (1,0) [0|1] "" XXX
SG_ Cruise_Soft_Disable : 34|1@1+ (1,0) [0|1] "" XXX
@ -344,8 +345,7 @@ BO_ 546 ES_Status: 8 XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ Signal1 : 12|3@1+ (1,0) [0|1] "" XXX
SG_ Cruise_Fault : 15|1@1+ (1,0) [0|1] "" XXX
SG_ Cruise_RPM : 16|12@1+ (1,0) [0|4095] "" XXX
SG_ Signal2 : 28|1@0+ (1,0) [0|1] "" XXX
SG_ Cruise_RPM : 16|13@1+ (1,0) [0|4095] "" XXX
SG_ Cruise_Activated : 29|1@0+ (1,0) [0|1] "" XXX
SG_ Brake_Lights : 30|1@1+ (1,0) [0|1] "" XXX
SG_ Cruise_Hold : 31|1@1+ (1,0) [0|1] "" XXX

@ -279,6 +279,7 @@ BO_ 289 ES_STATIC_2: 8 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ SET_3 : 15|2@1+ (1,0) [0|3] "" XXX
SG_ Cruise_Fault : 18|1@0+ (1,0) [0|1] "" XXX
CM_ SG_ 64 Throttle_Combo "Throttle Cruise + Pedal";
CM_ SG_ 313 Brake_Lights "Driver or Cruise Brake on";

@ -562,7 +562,7 @@ BO_ 401 STEERING_LTA: 8 XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
SG_ SETME_X3 : 29|2@0+ (1,0) [0|3] "" XXX
SG_ PERCENTAGE : 39|8@0+ (1,0) [0|255] "" XXX
SG_ SETME_X64 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ TORQUE_WIND_DOWN : 47|8@0+ (1,0) [0|255] "" XXX
SG_ ANGLE : 55|8@0- (0.5,0) [0|255] "" XXX
SG_ STEER_ANGLE_CMD : 15|16@0- (0.0573,0) [-540|540] "" XXX
SG_ STEER_REQUEST_2 : 25|1@0+ (1,0) [0|1] "" XXX
@ -603,7 +603,7 @@ BO_ 1014 BSM: 8 XXX
SG_ APPROACHING_ENABLED : 15|1@0+ (1,0) [0|1] "" XXX
CM_ SG_ 401 PERCENTAGE "driver override percentage (0-100), very close to steeringPressed in OP";
CM_ SG_ 401 SETME_X64 "ramps to 0 smoothly then back on falling edge of STEER_REQUEST if BIT isn't 1";
CM_ SG_ 401 TORQUE_WIND_DOWN "used to wind down torque on user override";
CM_ SG_ 401 ANGLE "angle of car relative to lane center on LTA camera";
CM_ SG_ 401 STEER_ANGLE_CMD "desired angle, OEM steers up to 95 degrees, no angle limit but torque will bottom out";
CM_ SG_ 401 CLEAR_HOLD_STEERING_ALERT "set to 1 when user clears LKAS_HUD->LDA_ALERT ('Hold Steering') by applying torque to steering wheel";

@ -1518,8 +1518,15 @@ CM_ SG_ 912 BSK_HD_Hauptraste "Status of trunk lid main detent";
CM_ SG_ 1088 Zaehler_Getriebe_1 "Counter Getriebe_1";
CM_ SG_ 1088 Waehlhebelposition__Getriebe_1_ "Gear Selector Position";
CM_ SG_ 1088 inneres_Soll_Motormoment "Desired Inner Torque";
CM_ SG_ 1088 Gang_eingelegt "Gear Engaged";
CM_ SG_ 1088 Schaltabsicht "Shift Intent";
CM_ SG_ 1088 Kuehlleistung "Cooling Power";
CM_ SG_ 1088 Wandlerverlustmoment "Converter Torque Loss";
CM_ SG_ 1088 Getriebe_Notlauf "Transmission_Notlauf";
CM_ SG_ 1088 Zielgang_oder_eingelegter_Gang "target_gear_or_gear_in_engagement";
CM_ SG_ 1088 Uebertragungsfunktion "transfer function";
CM_ SG_ 1088 EGS_Anforderung "EGS Requirement";
CM_ SG_ 1088 Schaltung_aktiv__Getriebe_1_ "Shift Activity";
CM_ SG_ 1056 Fehlerstatus_Aussentemp__4_1 "ambient temp error";
CM_ SG_ 1056 Fehlerstatus_Oeltemperatur_4_1 "oil temp error";

@ -7,7 +7,7 @@ BUILDER = "DEV"
common_flags = []
panda_root = Dir('.').abspath
panda_root = Dir('.')
if os.getenv("RELEASE"):
BUILD_TYPE = "RELEASE"
@ -16,7 +16,7 @@ if os.getenv("RELEASE"):
assert os.path.exists(cert_fn), 'Certificate file not found. Please specify absolute path'
else:
BUILD_TYPE = "DEBUG"
cert_fn = File("./certs/debug").srcnode().abspath
cert_fn = File("./certs/debug").srcnode().relpath
common_flags += ["-DALLOW_DEBUG"]
if os.getenv("DEBUG"):
@ -35,7 +35,7 @@ def get_version(builder, build_type):
def get_key_header(name):
from Crypto.PublicKey import RSA
public_fn = File(f'./certs/{name}.pub').srcnode().abspath
public_fn = File(f'./certs/{name}.pub').srcnode().get_path()
with open(public_fn) as f:
rsa = RSA.importKey(f.read())
assert(rsa.size_in_bits() == 1024)
@ -63,7 +63,7 @@ def to_c_uint32(x):
def build_project(project_name, project, extra_flags):
linkerscript_fn = File(project["LINKER_SCRIPT"]).srcnode().abspath
linkerscript_fn = File(project["LINKER_SCRIPT"]).srcnode().relpath
flags = project["PROJECT_FLAGS"] + extra_flags + common_flags + [
"-Wall",
@ -75,7 +75,7 @@ def build_project(project_name, project, extra_flags):
"-nostdlib",
"-fno-builtin",
"-std=gnu11",
"-fmax-errors=3",
"-fmax-errors=1",
f"-T{linkerscript_fn}",
]
@ -101,7 +101,8 @@ def build_project(project_name, project, extra_flags):
ASCOM="$AS $ASFLAGS -o $TARGET -c $SOURCES",
BUILDERS={
'Objcopy': Builder(generator=objcopy, suffix='.bin', src_suffix='.elf')
}
},
tools=["default", "compilation_db"],
)
startup = env.Object(f"obj/startup_{project_name}", project["STARTUP_FILE"])
@ -123,7 +124,7 @@ def build_project(project_name, project, extra_flags):
main_bin = env.Objcopy(f"obj/{project_name}.bin", main_elf)
# Sign main
sign_py = File(f"{panda_root}/crypto/sign.py").srcnode().abspath
sign_py = File(f"{panda_root}/crypto/sign.py").srcnode().relpath
env.Command(f"obj/{project_name}.bin.signed", main_bin, f"SETLEN=1 {sign_py} $SOURCE $TARGET {cert_fn}")
@ -179,9 +180,6 @@ with open("board/obj/cert.h", "w") as f:
# panda fw
SConscript('board/SConscript')
# pedal fw
SConscript('board/pedal/SConscript')
# panda jungle fw
SConscript('board/jungle/SConscript')

@ -1,13 +1,14 @@
Programming
----
**Panda**
## Programming
```
./flash.py # flash application
./recover.py # flash bootstub
```
## Debugging
To print out the serial console from the STM32, run `tests/debug_console.py`
Troubleshooting
----
@ -16,5 +17,4 @@ If panda is blinking fast with green LED, use `flash.py`.
Otherwise if LED is off and panda can't be seen with `lsusb` command, use [panda paw](https://comma.ai/shop/products/panda-paw) to go into DFU mode.
If your device has an internal panda and none of the above works, try running `../tests/reflash_internal_panda.py`.

@ -12,7 +12,10 @@ for project_name, project in build_projects.items():
flags = [
"-DPANDA",
]
if ("ENABLE_SPI" in os.environ or "h7" in project_name) and not project_name.startswith('pedal'):
if ("ENABLE_SPI" in os.environ or "h7" in project_name):
flags.append('-DENABLE_SPI')
if "H723" in os.environ:
flags.append('-DSTM32H723')
build_project(project_name, project, flags)

@ -1,6 +1,6 @@
// ///////////////////// //
// Black Panda + Harness //
// ///////////////////// //
// /////////////////////////////// //
// Black Panda (STM32F4) + Harness //
// /////////////////////////////// //
void black_enable_can_transceiver(uint8_t transceiver, bool enabled) {
switch (transceiver){
@ -136,7 +136,7 @@ void black_init(void) {
// Set normal CAN mode
black_set_can_mode(CAN_MODE_NORMAL);
// flip CAN0 and CAN2 if we are flipped
// change CAN mapping when flipped
if (harness.status == HARNESS_STATUS_FLIPPED) {
can_flip_buses(0, 2);
}
@ -163,12 +163,9 @@ const harness_configuration black_harness_config = {
};
const board board_black = {
.board_type = "Black",
.set_bootkick = unused_set_bootkick,
.harness_config = &black_harness_config,
.has_hw_gmlan = false,
.has_obd = true,
.has_lin = false,
.has_spi = false,
.has_canfd = false,
.has_rtc_battery = false,
@ -183,10 +180,10 @@ const board board_black = {
.set_led = black_set_led,
.set_can_mode = black_set_can_mode,
.check_ignition = black_check_ignition,
.read_current = unused_read_current,
.read_voltage_mV = white_read_voltage_mV,
.read_current_mA = unused_read_current,
.set_fan_enabled = unused_set_fan_enabled,
.set_ir_power = unused_set_ir_power,
.set_phone_power = unused_set_phone_power,
.set_siren = unused_set_siren,
.read_som_gpio = unused_read_som_gpio
};

@ -12,20 +12,17 @@ typedef void (*board_enable_can_transceivers)(bool enabled);
typedef void (*board_set_led)(uint8_t color, bool enabled);
typedef void (*board_set_can_mode)(uint8_t mode);
typedef bool (*board_check_ignition)(void);
typedef uint32_t (*board_read_current)(void);
typedef uint32_t (*board_read_voltage_mV)(void);
typedef uint32_t (*board_read_current_mA)(void);
typedef void (*board_set_ir_power)(uint8_t percentage);
typedef void (*board_set_fan_enabled)(bool enabled);
typedef void (*board_set_phone_power)(bool enabled);
typedef void (*board_set_siren)(bool enabled);
typedef void (*board_set_bootkick)(BootState state);
typedef bool (*board_read_som_gpio)(void);
struct board {
const char *board_type;
const harness_configuration *harness_config;
const bool has_hw_gmlan;
const bool has_obd;
const bool has_lin;
const bool has_spi;
const bool has_canfd;
const bool has_rtc_battery;
@ -40,10 +37,10 @@ struct board {
board_set_led set_led;
board_set_can_mode set_can_mode;
board_check_ignition check_ignition;
board_read_current read_current;
board_read_voltage_mV read_voltage_mV;
board_read_current_mA read_current_mA;
board_set_ir_power set_ir_power;
board_set_fan_enabled set_fan_enabled;
board_set_phone_power set_phone_power;
board_set_siren set_siren;
board_set_bootkick set_bootkick;
board_read_som_gpio read_som_gpio;
@ -61,6 +58,7 @@ struct board {
#define HW_TYPE_RED_PANDA 7U
#define HW_TYPE_RED_PANDA_V2 8U
#define HW_TYPE_TRES 9U
#define HW_TYPE_CUATRO 10U
// LED colors
#define LED_RED 0U

@ -0,0 +1,130 @@
// ////////////////////////// //
// Cuatro (STM32H7) + Harness //
// ////////////////////////// //
void cuatro_set_led(uint8_t color, bool enabled) {
switch (color) {
case LED_RED:
set_gpio_output(GPIOD, 15, !enabled);
break;
case LED_GREEN:
set_gpio_output(GPIOD, 14, !enabled);
break;
case LED_BLUE:
set_gpio_output(GPIOE, 2, !enabled);
break;
default:
break;
}
}
void cuatro_enable_can_transceiver(uint8_t transceiver, bool enabled) {
switch (transceiver) {
case 1U:
set_gpio_output(GPIOB, 7, !enabled);
break;
case 2U:
set_gpio_output(GPIOB, 10, !enabled);
break;
case 3U:
set_gpio_output(GPIOD, 8, !enabled);
break;
case 4U:
set_gpio_output(GPIOB, 11, !enabled);
break;
default:
break;
}
}
void cuatro_enable_can_transceivers(bool enabled) {
uint8_t main_bus = (harness.status == HARNESS_STATUS_FLIPPED) ? 3U : 1U;
for (uint8_t i=1U; i<=4U; i++) {
// Leave main CAN always on for CAN-based ignition detection
if (i == main_bus) {
cuatro_enable_can_transceiver(i, true);
} else {
cuatro_enable_can_transceiver(i, enabled);
}
}
}
uint32_t cuatro_read_voltage_mV(void) {
return adc_get_mV(8) * 11U;
}
uint32_t cuatro_read_current_mA(void) {
return adc_get_mV(3) * 2U;
}
void cuatro_init(void) {
red_chiplet_init();
// Power readout
set_gpio_mode(GPIOC, 5, MODE_ANALOG);
set_gpio_mode(GPIOA, 6, MODE_ANALOG);
// CAN transceiver enables
set_gpio_pullup(GPIOB, 7, PULL_NONE);
set_gpio_mode(GPIOB, 7, MODE_OUTPUT);
set_gpio_pullup(GPIOD, 8, PULL_NONE);
set_gpio_mode(GPIOD, 8, MODE_OUTPUT);
// FDCAN3, different pins on this package than the rest of the reds
set_gpio_pullup(GPIOD, 12, PULL_NONE);
set_gpio_alternate(GPIOD, 12, GPIO_AF5_FDCAN3);
set_gpio_pullup(GPIOD, 13, PULL_NONE);
set_gpio_alternate(GPIOD, 13, GPIO_AF5_FDCAN3);
// C2: SOM GPIO used as input (fan control at boot)
set_gpio_mode(GPIOC, 2, MODE_INPUT);
set_gpio_pullup(GPIOC, 2, PULL_DOWN);
// SOM bootkick + reset lines
set_gpio_mode(GPIOC, 12, MODE_OUTPUT);
tres_set_bootkick(BOOT_BOOTKICK);
// SOM debugging UART
gpio_uart7_init();
uart_init(&uart_ring_som_debug, 115200);
// SPI init
gpio_spi_init();
// fan setup
set_gpio_alternate(GPIOC, 8, GPIO_AF2_TIM3);
// Initialize IR PWM and set to 0%
set_gpio_alternate(GPIOC, 9, GPIO_AF2_TIM3);
pwm_init(TIM3, 4);
tres_set_ir_power(0U);
// Clock source
clock_source_init();
}
const board board_cuatro = {
.harness_config = &red_chiplet_harness_config,
.has_obd = true,
.has_spi = true,
.has_canfd = true,
.has_rtc_battery = true,
.fan_max_rpm = 6600U,
.avdd_mV = 1800U,
.fan_stall_recovery = false,
.fan_enable_cooldown_time = 3U,
.init = cuatro_init,
.init_bootloader = unused_init_bootloader,
.enable_can_transceiver = cuatro_enable_can_transceiver,
.enable_can_transceivers = cuatro_enable_can_transceivers,
.set_led = cuatro_set_led,
.set_can_mode = red_chiplet_set_can_mode,
.check_ignition = red_check_ignition,
.read_voltage_mV = cuatro_read_voltage_mV,
.read_current_mA = cuatro_read_current_mA,
.set_fan_enabled = tres_set_fan_enabled,
.set_ir_power = tres_set_ir_power,
.set_siren = unused_set_siren,
.set_bootkick = tres_set_bootkick,
.read_som_gpio = tres_read_som_gpio
};

@ -1,6 +1,6 @@
// ///////////// //
// Dos + Harness //
// ///////////// //
// /////////////////////// //
// Dos (STM32F4) + Harness //
// /////////////////////// //
void dos_enable_can_transceiver(uint8_t transceiver, bool enabled) {
switch (transceiver){
@ -90,10 +90,6 @@ bool dos_check_ignition(void){
return harness_check_ignition();
}
void dos_set_usb_switch(bool phone){
set_gpio_output(GPIOB, 3, phone);
}
void dos_set_ir_power(uint8_t percentage){
pwm_set(TIM4, 2, percentage);
}
@ -168,7 +164,7 @@ void dos_init(void) {
// Set normal CAN mode
dos_set_can_mode(CAN_MODE_NORMAL);
// flip CAN0 and CAN2 if we are flipped
// change CAN mapping when flipped
if (harness.status == HARNESS_STATUS_FLIPPED) {
can_flip_buses(0, 2);
}
@ -192,11 +188,8 @@ const harness_configuration dos_harness_config = {
};
const board board_dos = {
.board_type = "Dos",
.harness_config = &dos_harness_config,
.has_hw_gmlan = false,
.has_obd = true,
.has_lin = false,
#ifdef ENABLE_SPI
.has_spi = true,
#else
@ -215,10 +208,10 @@ const board board_dos = {
.set_led = dos_set_led,
.set_can_mode = dos_set_can_mode,
.check_ignition = dos_check_ignition,
.read_current = unused_read_current,
.read_voltage_mV = white_read_voltage_mV,
.read_current_mA = unused_read_current,
.set_fan_enabled = dos_set_fan_enabled,
.set_ir_power = dos_set_ir_power,
.set_phone_power = unused_set_phone_power,
.set_siren = dos_set_siren,
.set_bootkick = dos_set_bootkick,
.read_som_gpio = dos_read_som_gpio

@ -1,16 +1,13 @@
// ////////// //
// Grey Panda //
// ////////// //
// //////////////////// //
// Grey Panda (STM32F4) //
// //////////////////// //
// Most hardware functionality is similar to white panda
const board board_grey = {
.board_type = "Grey",
.set_bootkick = unused_set_bootkick,
.harness_config = &white_harness_config,
.has_hw_gmlan = true,
.has_obd = false,
.has_lin = true,
.has_spi = false,
.has_canfd = false,
.has_rtc_battery = false,
@ -25,10 +22,10 @@ const board board_grey = {
.set_led = white_set_led,
.set_can_mode = white_set_can_mode,
.check_ignition = white_check_ignition,
.read_current = white_read_current,
.read_voltage_mV = white_read_voltage_mV,
.read_current_mA = white_read_current_mA,
.set_fan_enabled = unused_set_fan_enabled,
.set_ir_power = unused_set_ir_power,
.set_phone_power = unused_set_phone_power,
.set_siren = unused_set_siren,
.read_som_gpio = unused_read_som_gpio
};

@ -1,96 +0,0 @@
// ///// //
// Pedal //
// ///// //
void pedal_enable_can_transceiver(uint8_t transceiver, bool enabled) {
switch (transceiver){
case 1:
set_gpio_output(GPIOB, 3, !enabled);
break;
default:
print("Invalid CAN transceiver ("); puth(transceiver); print("): enabling failed\n");
break;
}
}
void pedal_enable_can_transceivers(bool enabled) {
pedal_enable_can_transceiver(1U, enabled);
}
void pedal_set_led(uint8_t color, bool enabled) {
switch (color){
case LED_RED:
set_gpio_output(GPIOB, 10, !enabled);
break;
case LED_GREEN:
set_gpio_output(GPIOB, 11, !enabled);
break;
default:
break;
}
}
void pedal_set_can_mode(uint8_t mode){
switch (mode) {
case CAN_MODE_NORMAL:
break;
default:
print("Tried to set unsupported CAN mode: "); puth(mode); print("\n");
break;
}
}
bool pedal_check_ignition(void){
// not supported on pedal
return false;
}
void pedal_init(void) {
common_init_gpio();
// C0, C1: Throttle inputs
set_gpio_mode(GPIOC, 0, MODE_ANALOG);
set_gpio_mode(GPIOC, 1, MODE_ANALOG);
// DAC outputs on A4 and A5
// apparently they don't need GPIO setup
// Enable transceiver
pedal_enable_can_transceivers(true);
// Disable LEDs
pedal_set_led(LED_RED, false);
pedal_set_led(LED_GREEN, false);
}
const harness_configuration pedal_harness_config = {
.has_harness = false
};
const board board_pedal = {
.board_type = "Pedal",
.set_bootkick = unused_set_bootkick,
.harness_config = &pedal_harness_config,
.has_hw_gmlan = false,
.has_obd = false,
.has_lin = false,
.has_spi = false,
.has_canfd = false,
.has_rtc_battery = false,
.fan_max_rpm = 0U,
.avdd_mV = 3300U,
.fan_stall_recovery = false,
.fan_enable_cooldown_time = 0U,
.init = pedal_init,
.init_bootloader = unused_init_bootloader,
.enable_can_transceiver = pedal_enable_can_transceiver,
.enable_can_transceivers = pedal_enable_can_transceivers,
.set_led = pedal_set_led,
.set_can_mode = pedal_set_can_mode,
.check_ignition = pedal_check_ignition,
.read_current = unused_read_current,
.set_fan_enabled = unused_set_fan_enabled,
.set_ir_power = unused_set_ir_power,
.set_phone_power = unused_set_phone_power,
.set_siren = unused_set_siren,
.read_som_gpio = unused_read_som_gpio
};

@ -1,6 +1,6 @@
// ///////////////////// //
// Red Panda + Harness //
// ///////////////////// //
// ///////////////////////////// //
// Red Panda (STM32H7) + Harness //
// ///////////////////////////// //
void red_enable_can_transceiver(uint8_t transceiver, bool enabled) {
switch (transceiver) {
@ -96,6 +96,10 @@ bool red_check_ignition(void) {
return harness_check_ignition();
}
uint32_t red_read_voltage_mV(void){
return adc_get_mV(2) * 11U; // TODO: is this correct?
}
void red_init(void) {
common_init_gpio();
@ -150,7 +154,7 @@ void red_init(void) {
// Set normal CAN mode
red_set_can_mode(CAN_MODE_NORMAL);
// flip CAN0 and CAN2 if we are flipped
// change CAN mapping when flipped
if (harness.status == HARNESS_STATUS_FLIPPED) {
can_flip_buses(0, 2);
}
@ -171,12 +175,9 @@ const harness_configuration red_harness_config = {
};
const board board_red = {
.board_type = "Red",
.set_bootkick = unused_set_bootkick,
.harness_config = &red_harness_config,
.has_hw_gmlan = false,
.has_obd = true,
.has_lin = false,
.has_spi = false,
.has_canfd = true,
.has_rtc_battery = false,
@ -191,10 +192,10 @@ const board board_red = {
.set_led = red_set_led,
.set_can_mode = red_set_can_mode,
.check_ignition = red_check_ignition,
.read_current = unused_read_current,
.read_voltage_mV = red_read_voltage_mV,
.read_current_mA = unused_read_current,
.set_fan_enabled = unused_set_fan_enabled,
.set_ir_power = unused_set_ir_power,
.set_phone_power = unused_set_phone_power,
.set_siren = unused_set_siren,
.read_som_gpio = unused_read_som_gpio
};

@ -1,6 +1,6 @@
// ///////////////////// //
// Red Panda chiplet + Harness //
// ///////////////////// //
// ///////////////////////////////////// //
// Red Panda chiplet (STM32H7) + Harness //
// ///////////////////////////////////// //
// Most hardware functionality is similar to red panda
@ -133,7 +133,7 @@ void red_chiplet_init(void) {
// Set normal CAN mode
red_chiplet_set_can_mode(CAN_MODE_NORMAL);
// flip CAN0 and CAN2 if we are flipped
// change CAN mapping when flipped
if (harness.status == HARNESS_STATUS_FLIPPED) {
can_flip_buses(0, 2);
}

@ -1,40 +0,0 @@
// ///////////////////// //
// Red Panda V2 with chiplet + Harness //
// ///////////////////// //
void red_panda_v2_init(void) {
// common chiplet init
red_chiplet_init();
// Turn on USB load switch
red_chiplet_set_fan_or_usb_load_switch(true);
}
const board board_red_v2 = {
.board_type = "Red_v2",
.set_bootkick = unused_set_bootkick,
.harness_config = &red_chiplet_harness_config,
.has_hw_gmlan = false,
.has_obd = true,
.has_lin = false,
.has_spi = false,
.has_canfd = true,
.has_rtc_battery = true,
.fan_max_rpm = 0U,
.avdd_mV = 3300U,
.fan_stall_recovery = false,
.fan_enable_cooldown_time = 0U,
.init = red_panda_v2_init,
.init_bootloader = unused_init_bootloader,
.enable_can_transceiver = red_chiplet_enable_can_transceiver,
.enable_can_transceivers = red_chiplet_enable_can_transceivers,
.set_led = red_set_led,
.set_can_mode = red_chiplet_set_can_mode,
.check_ignition = red_check_ignition,
.read_current = unused_read_current,
.set_fan_enabled = unused_set_fan_enabled,
.set_ir_power = unused_set_ir_power,
.set_phone_power = unused_set_phone_power,
.set_siren = unused_set_siren,
.read_som_gpio = unused_read_som_gpio
};

@ -1,6 +1,6 @@
// /////////////////
// Tres + Harness //
// /////////////////
// ///////////////////////////
// Tres (STM32H7) + Harness //
// ///////////////////////////
bool tres_ir_enabled;
bool tres_fan_enabled;
@ -71,11 +71,8 @@ void tres_init(void) {
}
const board board_tres = {
.board_type = "Tres",
.harness_config = &red_chiplet_harness_config,
.has_hw_gmlan = false,
.has_obd = true,
.has_lin = false,
.has_spi = true,
.has_canfd = true,
.has_rtc_battery = true,
@ -90,10 +87,10 @@ const board board_tres = {
.set_led = red_set_led,
.set_can_mode = red_chiplet_set_can_mode,
.check_ignition = red_check_ignition,
.read_current = unused_read_current,
.read_voltage_mV = red_read_voltage_mV,
.read_current_mA = unused_read_current,
.set_fan_enabled = tres_set_fan_enabled,
.set_ir_power = tres_set_ir_power,
.set_phone_power = unused_set_phone_power,
.set_siren = fake_siren_set,
.set_bootkick = tres_set_bootkick,
.read_som_gpio = tres_read_som_gpio

@ -1,6 +1,6 @@
// ///////////// //
// Uno + Harness //
// ///////////// //
// /////////////////////// //
// Uno (STM32F4) + Harness //
// /////////////////////// //
void uno_enable_can_transceiver(uint8_t transceiver, bool enabled) {
switch (transceiver){
@ -58,10 +58,6 @@ void uno_set_bootkick(BootState state) {
}
}
void uno_set_phone_power(bool enabled){
set_gpio_output(GPIOB, 4, enabled);
}
void uno_set_can_mode(uint8_t mode) {
uno_enable_can_transceiver(2U, false);
uno_enable_can_transceiver(4U, false);
@ -141,7 +137,7 @@ void uno_init(void) {
set_gpio_alternate(GPIOC, 8, GPIO_AF2_TIM3);
// Turn on phone regulator
uno_set_phone_power(true);
set_gpio_output(GPIOB, 4, true);
// Initialize IR PWM and set to 0%
set_gpio_alternate(GPIOB, 7, GPIO_AF2_TIM4);
@ -165,13 +161,13 @@ void uno_init(void) {
// Set normal CAN mode
uno_set_can_mode(CAN_MODE_NORMAL);
// flip CAN0 and CAN2 if we are flipped
// change CAN mapping when flipped
if (harness.status == HARNESS_STATUS_FLIPPED) {
can_flip_buses(0, 2);
}
// Switch to phone usb mode if harness connection is powered by less than 7V
if((adc_get_mV(ADCCHAN_VIN) * VIN_READOUT_DIVIDER) < 7000U){
if(white_read_voltage_mV() < 7000U){
uno_set_usb_switch(true);
} else {
uno_set_usb_switch(false);
@ -203,11 +199,8 @@ const harness_configuration uno_harness_config = {
};
const board board_uno = {
.board_type = "Uno",
.harness_config = &uno_harness_config,
.has_hw_gmlan = false,
.has_obd = true,
.has_lin = false,
.has_spi = false,
.has_canfd = false,
.has_rtc_battery = true,
@ -222,10 +215,10 @@ const board board_uno = {
.set_led = uno_set_led,
.set_can_mode = uno_set_can_mode,
.check_ignition = uno_check_ignition,
.read_current = unused_read_current,
.read_voltage_mV = white_read_voltage_mV,
.read_current_mA = unused_read_current,
.set_fan_enabled = uno_set_fan_enabled,
.set_ir_power = uno_set_ir_power,
.set_phone_power = uno_set_phone_power,
.set_siren = unused_set_siren,
.set_bootkick = uno_set_bootkick,
.read_som_gpio = unused_read_som_gpio

@ -9,10 +9,6 @@ void unused_set_fan_enabled(bool enabled) {
UNUSED(enabled);
}
void unused_set_phone_power(bool enabled) {
UNUSED(enabled);
}
void unused_set_siren(bool enabled) {
UNUSED(enabled);
}

@ -1,6 +1,6 @@
// /////////// //
// White Panda //
// /////////// //
// ///////////////////// //
// White Panda (STM32F4) //
// ///////////////////// //
void white_enable_can_transceiver(uint8_t transceiver, bool enabled) {
switch (transceiver){
@ -124,8 +124,13 @@ void white_set_can_mode(uint8_t mode){
}
}
uint32_t white_read_current(void){
return adc_get_raw(ADCCHAN_CURRENT);
uint32_t white_read_voltage_mV(void){
return adc_get_mV(12) * 11U;
}
uint32_t white_read_current_mA(void){
// This isn't in mA, but we're keeping it for backwards compatibility
return adc_get_raw(13);
}
bool white_check_ignition(void){
@ -197,10 +202,9 @@ void white_grey_init(void) {
white_set_can_mode(CAN_MODE_NORMAL);
// Init usb power mode
uint32_t voltage = adc_get_mV(ADCCHAN_VIN) * VIN_READOUT_DIVIDER;
// Init in CDP mode only if panda is powered by 12V.
// Otherwise a PC would not be able to flash a standalone panda
if (voltage > 8000U) { // 8V threshold
if (white_read_voltage_mV() > 8000U) { // 8V threshold
white_set_usb_power_mode(USB_POWER_CDP);
} else {
white_set_usb_power_mode(USB_POWER_CLIENT);
@ -222,12 +226,9 @@ const harness_configuration white_harness_config = {
};
const board board_white = {
.board_type = "White",
.set_bootkick = unused_set_bootkick,
.harness_config = &white_harness_config,
.has_hw_gmlan = true,
.has_obd = false,
.has_lin = true,
.has_spi = false,
.has_canfd = false,
.has_rtc_battery = false,
@ -242,10 +243,10 @@ const board board_white = {
.set_led = white_set_led,
.set_can_mode = white_set_can_mode,
.check_ignition = white_check_ignition,
.read_current = white_read_current,
.read_voltage_mV = white_read_voltage_mV,
.read_current_mA = white_read_current_mA,
.set_fan_enabled = unused_set_fan_enabled,
.set_ir_power = unused_set_ir_power,
.set_phone_power = unused_set_phone_power,
.set_siren = unused_set_siren,
.read_som_gpio = unused_read_som_gpio
};

@ -19,6 +19,7 @@
#include "obj/gitversion.h"
#include "flasher.h"
// cppcheck-suppress unusedFunction ; used in headers not included in cppcheck
void __initialize_hardware_early(void) {
early_initialization();
}

@ -56,7 +56,7 @@ int comms_can_read(uint8_t *data, uint32_t max_len) {
asm_buffer can_write_buffer = {.ptr = 0U, .tail_size = 0U};
// send on CAN
void comms_can_write(uint8_t *data, uint32_t len) {
void comms_can_write(const uint8_t *data, uint32_t len) {
uint32_t pos = 0U;
// Assembling can message with data from buffer

@ -8,7 +8,7 @@ const uint8_t PANDA_BUS_CNT = 4U;
#define CANPACKET_HEAD_SIZE 6U
#if !defined(STM32F4) && !defined(STM32F2)
#if !defined(STM32F4)
#define CANFD
#define CANPACKET_DATA_SIZE_MAX 64U
#else

@ -6,7 +6,7 @@ typedef struct {
} __attribute__((packed)) ControlPacket_t;
int comms_control_handler(ControlPacket_t *req, uint8_t *resp);
void comms_endpoint2_write(uint8_t *data, uint32_t len);
void comms_can_write(uint8_t *data, uint32_t len);
void comms_endpoint2_write(const uint8_t *data, uint32_t len);
void comms_can_write(const uint8_t *data, uint32_t len);
int comms_can_read(uint8_t *data, uint32_t max_len);
void comms_can_reset(void);

@ -16,8 +16,6 @@
#define MAX_CAN_MSGS_PER_USB_BULK_TRANSFER 51U
#define MAX_CAN_MSGS_PER_SPI_BULK_TRANSFER 170U
#define VIN_READOUT_DIVIDER 11U
// USB definitions
#define USB_VID 0xBBAAU
@ -38,7 +36,7 @@
// platform includes
#ifdef STM32H7
#include "stm32h7/stm32h7_config.h"
#elif defined(STM32F2) || defined(STM32F4)
#elif defined(STM32F4)
#include "stm32fx/stm32fx_config.h"
#else
// TODO: uncomment this, cppcheck complains

@ -1,6 +1,6 @@
#pragma once
uint8_t crc_checksum(uint8_t *dat, int len, const uint8_t poly) {
uint8_t crc_checksum(const uint8_t *dat, int len, const uint8_t poly) {
uint8_t crc = 0xFFU;
int i;
int j;

@ -23,56 +23,6 @@ bool can_set_speed(uint8_t can_number) {
return ret;
}
// TODO: Cleanup with new abstraction
void can_set_gmlan(uint8_t bus) {
if(current_board->has_hw_gmlan){
// first, disable GMLAN on prev bus
uint8_t prev_bus = bus_config[3].can_num_lookup;
if (bus != prev_bus) {
switch (prev_bus) {
case 1:
case 2:
print("Disable GMLAN on CAN");
puth(prev_bus + 1U);
print("\n");
current_board->set_can_mode(CAN_MODE_NORMAL);
bus_config[prev_bus].bus_lookup = prev_bus;
bus_config[prev_bus].can_num_lookup = prev_bus;
bus_config[3].can_num_lookup = -1;
bool ret = can_init(prev_bus);
UNUSED(ret);
break;
default:
// GMLAN was not set on either BUS 1 or 2
break;
}
}
// now enable GMLAN on the new bus
switch (bus) {
case 1:
case 2:
print("Enable GMLAN on CAN");
puth(bus + 1U);
print("\n");
current_board->set_can_mode((bus == 1U) ? CAN_MODE_GMLAN_CAN2 : CAN_MODE_GMLAN_CAN3);
bus_config[bus].bus_lookup = 3;
bus_config[bus].can_num_lookup = -1;
bus_config[3].can_num_lookup = bus;
bool ret = can_init(bus);
UNUSED(ret);
break;
case 0xFF: //-1 unsigned
break;
default:
print("GMLAN can only be set on CAN2 or CAN3\n");
break;
}
} else {
print("GMLAN not available on black panda\n");
}
}
void update_can_health_pkt(uint8_t can_number, uint32_t ir_reg) {
CAN_TypeDef *CANx = CANIF_FROM_CAN_NUM(can_number);
uint32_t esr_reg = CANx->ESR;

@ -28,8 +28,8 @@ extern int can_live;
extern int pending_can_live;
// must reinit after changing these
extern int can_loopback;
extern int can_silent;
extern bool can_loopback;
// Ignition detected from CAN meessages
bool ignition_can = false;
@ -40,8 +40,8 @@ uint32_t ignition_can_cnt = 0U;
int can_live = 0;
int pending_can_live = 0;
int can_loopback = 0;
int can_silent = ALL_CAN_SILENT;
bool can_loopback = false;
// ******************* functions prototypes *********************
bool can_init(uint8_t can_number);
@ -95,7 +95,7 @@ bool can_pop(can_ring *q, CANPacket_t *elem) {
return ret;
}
bool can_push(can_ring *q, CANPacket_t *elem) {
bool can_push(can_ring *q, const CANPacket_t *elem) {
bool ret = false;
uint32_t next_w_ptr;
@ -133,7 +133,7 @@ bool can_push(can_ring *q, CANPacket_t *elem) {
return ret;
}
uint32_t can_slots_empty(can_ring *q) {
uint32_t can_slots_empty(const can_ring *q) {
uint32_t ret = 0;
ENTER_CRITICAL();
@ -238,7 +238,7 @@ bool can_tx_check_min_slots_free(uint32_t min) {
(can_slots_empty(&can_txgmlan_q) >= min);
}
uint8_t calculate_checksum(uint8_t *dat, uint32_t len) {
uint8_t calculate_checksum(const uint8_t *dat, uint32_t len) {
uint8_t checksum = 0U;
for (uint32_t i = 0U; i < len; i++) {
checksum ^= dat[i];
@ -277,10 +277,10 @@ void can_send(CANPacket_t *to_push, uint8_t bus_number, bool skip_tx_hook) {
}
}
bool is_speed_valid(uint32_t speed, const uint32_t *speeds, uint8_t len) {
bool is_speed_valid(uint32_t speed, const uint32_t *all_speeds, uint8_t len) {
bool ret = false;
for (uint8_t i = 0U; i < len; i++) {
if (speeds[i] == speed) {
if (all_speeds[i] == speed) {
ret = true;
}
}

@ -35,11 +35,6 @@ bool can_set_speed(uint8_t can_number) {
return ret;
}
void can_set_gmlan(uint8_t bus) {
UNUSED(bus);
print("GMLAN not available on red panda\n");
}
void update_can_health_pkt(uint8_t can_number, uint32_t ir_reg) {
FDCAN_GlobalTypeDef *FDCANx = CANIF_FROM_CAN_NUM(can_number);
uint32_t psr_reg = FDCANx->PSR;
@ -106,13 +101,15 @@ void process_can(uint8_t can_number) {
uint32_t TxFIFOSA = FDCAN_START_ADDRESS + (can_number * FDCAN_OFFSET) + (FDCAN_RX_FIFO_0_EL_CNT * FDCAN_RX_FIFO_0_EL_SIZE);
// get the index of the next TX FIFO element (0 to FDCAN_TX_FIFO_EL_CNT - 1)
uint8_t tx_index = (FDCANx->TXFQS >> FDCAN_TXFQS_TFQPI_Pos) & 0x1F;
uint32_t tx_index = (FDCANx->TXFQS >> FDCAN_TXFQS_TFQPI_Pos) & 0x1F;
// only send if we have received a packet
canfd_fifo *fifo;
fifo = (canfd_fifo *)(TxFIFOSA + (tx_index * FDCAN_TX_FIFO_EL_SIZE));
fifo->header[0] = (to_send.extended << 30) | ((to_send.extended != 0U) ? (to_send.addr) : (to_send.addr << 18));
fifo->header[1] = (to_send.data_len_code << 16) | (bus_config[can_number].canfd_enabled << 21) | (bus_config[can_number].brs_enabled << 20);
uint32_t canfd_enabled_header = bus_config[can_number].canfd_enabled ? (1UL << 21) : 0UL;
uint32_t brs_enabled_header = bus_config[can_number].brs_enabled ? (1UL << 20) : 0UL;
fifo->header[1] = (to_send.data_len_code << 16) | canfd_enabled_header | brs_enabled_header;
uint8_t data_len_w = (dlc_to_len[to_send.data_len_code] / 4U);
data_len_w += ((dlc_to_len[to_send.data_len_code] % 4U) > 0U) ? 1U : 0U;
@ -163,7 +160,7 @@ void can_rx(uint8_t can_number) {
pending_can_live = 1;
// get the index of the next RX FIFO element (0 to FDCAN_RX_FIFO_0_EL_CNT - 1)
uint8_t rx_fifo_idx = (uint8_t)((FDCANx->RXF0S >> FDCAN_RXF0S_F0GI_Pos) & 0x3F);
uint32_t rx_fifo_idx = (uint8_t)((FDCANx->RXF0S >> FDCAN_RXF0S_F0GI_Pos) & 0x3F);
// Recommended to offset get index by at least +1 if RX FIFO is in overwrite mode and full (datasheet)
if((FDCANx->RXF0S & FDCAN_RXF0S_F0F) == FDCAN_RXF0S_F0F) {

@ -12,7 +12,7 @@
int gmlan_alt_mode = DISABLED;
// returns out_len
int do_bitstuff(char *out, char *in, int in_len) {
int do_bitstuff(char *out, const char *in, int in_len) {
int last_bit = -1;
int bit_cnt = 0;
int j = 0;
@ -22,18 +22,18 @@ int do_bitstuff(char *out, char *in, int in_len) {
j++;
// do the stuffing
if (bit == last_bit) {
if (bit == (char)last_bit) {
bit_cnt++;
if (bit_cnt == 5) {
// 5 in a row the same, do stuff
last_bit = !bit;
last_bit = !bit ? 1 : 0;
out[j] = last_bit;
j++;
bit_cnt = 1;
}
} else {
// this is a new bit
last_bit = bit;
last_bit = (int)bit;
bit_cnt = 1;
}
}
@ -57,7 +57,7 @@ int append_crc(char *in, int in_len) {
return in_len_copy;
}
int append_bits(char *in, int in_len, char *app, int app_len) {
int append_bits(char *in, int in_len, const char *app, int app_len) {
int in_len_copy = in_len;
for (int i = 0; i < app_len; i++) {
in[in_len_copy] = app[i];
@ -75,7 +75,7 @@ int append_int(char *in, int in_len, int val, int val_len) {
return in_len_copy;
}
int get_bit_message(char *out, CANPacket_t *to_bang) {
int get_bit_message(char *out, const CANPacket_t *to_bang) {
char pkt[MAX_BITS_CAN_PACKET];
char footer[] = {
1, // CRC delimiter
@ -95,7 +95,7 @@ int get_bit_message(char *out, CANPacket_t *to_bang) {
// extended identifier
len = append_int(pkt, len, GET_ADDR(to_bang) >> 18, 11); // Identifier
len = append_int(pkt, len, 3, 2); // SRR+IDE
len = append_int(pkt, len, (GET_ADDR(to_bang)) & ((1U << 18) - 1U), 18); // Identifier
len = append_int(pkt, len, (GET_ADDR(to_bang)) & ((1UL << 18) - 1U), 18); // Identifier
len = append_int(pkt, len, 0, 3); // RTR+r1+r0
} else {
// standard identifier
@ -121,23 +121,23 @@ int get_bit_message(char *out, CANPacket_t *to_bang) {
return len;
}
void GMLAN_BITBANG_IRQ_Handler(void);
void TIM12_IRQ_Handler(void);
void setup_timer(void) {
// register interrupt
REGISTER_INTERRUPT(GMLAN_BITBANG_TIMER_IRQ, GMLAN_BITBANG_IRQ_Handler, 40000U, FAULT_INTERRUPT_RATE_GMLAN)
REGISTER_INTERRUPT(TIM8_BRK_TIM12_IRQn, TIM12_IRQ_Handler, 40000U, FAULT_INTERRUPT_RATE_GMLAN)
// setup
register_set(&(GMLAN_BITBANG_TIMER->PSC), (APB1_TIMER_FREQ-1U), 0xFFFFU); // Tick on 1 us
register_set(&(GMLAN_BITBANG_TIMER->CR1), TIM_CR1_CEN, 0x3FU); // Enable
register_set(&(GMLAN_BITBANG_TIMER->ARR), (30U-1U), 0xFFFFU); // 33.3 kbps
register_set(&(TIM12->PSC), (APB1_TIMER_FREQ-1U), 0xFFFFU); // Tick on 1 us
register_set(&(TIM12->CR1), TIM_CR1_CEN, 0x3FU); // Enable
register_set(&(TIM12->ARR), (30U-1U), 0xFFFFU); // 33.3 kbps
// in case it's disabled
NVIC_EnableIRQ(GMLAN_BITBANG_TIMER_IRQ);
NVIC_EnableIRQ(TIM8_BRK_TIM12_IRQn);
// run the interrupt
register_set(&(GMLAN_BITBANG_TIMER->DIER), TIM_DIER_UIE, 0x5F5FU); // Update interrupt
GMLAN_BITBANG_TIMER->SR = 0;
register_set(&(TIM12->DIER), TIM_DIER_UIE, 0x5F5FU); // Update interrupt
TIM12->SR = 0;
}
int gmlan_timeout_counter = GMLAN_TICKS_PER_TIMEOUT_TICKLE; //GMLAN transceiver times out every 17ms held high; tickle every 15ms
@ -147,37 +147,11 @@ int inverted_bit_to_send = GMLAN_HIGH;
int gmlan_switch_below_timeout = -1;
int gmlan_switch_timeout_enable = 0;
void gmlan_switch_init(int timeout_enable) {
gmlan_switch_timeout_enable = timeout_enable;
gmlan_alt_mode = GPIO_SWITCH;
gmlan_switch_below_timeout = 1;
set_gpio_mode(GPIOB, 13, MODE_OUTPUT);
setup_timer();
inverted_bit_to_send = GMLAN_LOW; //We got initialized, set the output low
}
void set_gmlan_digital_output(int to_set) {
inverted_bit_to_send = to_set;
/*
print("Writing ");
puth(inverted_bit_to_send);
print("\n");
*/
}
void reset_gmlan_switch_timeout(void) {
can_timeout_counter = GMLAN_TICKS_PER_SECOND;
gmlan_switch_below_timeout = 1;
gmlan_alt_mode = GPIO_SWITCH;
}
void set_bitbanged_gmlan(int val) {
if (val != 0) {
register_set_bits(&(GPIOB->ODR), (1U << 13));
register_set_bits(&(GPIOB->ODR), (1UL << 13));
} else {
register_clear_bits(&(GPIOB->ODR), (1U << 13));
register_clear_bits(&(GPIOB->ODR), (1UL << 13));
}
}
@ -191,9 +165,9 @@ int gmlan_fail_count = 0;
#define REQUIRED_SILENT_TIME 10
#define MAX_FAIL_COUNT 10
void GMLAN_BITBANG_IRQ_Handler(void) {
void TIM12_IRQ_Handler(void) {
if (gmlan_alt_mode == BITBANG) {
if ((GMLAN_BITBANG_TIMER->SR & TIM_SR_UIF) && (gmlan_sendmax != -1)) {
if ((TIM12->SR & TIM_SR_UIF) && (gmlan_sendmax != -1)) {
int read = get_gpio_input(GPIOB, 12);
if (gmlan_silent_count < REQUIRED_SILENT_TIME) {
if (read == 0) {
@ -205,7 +179,7 @@ void GMLAN_BITBANG_IRQ_Handler(void) {
bool retry = 0;
// in send loop
if ((gmlan_sending > 0) && // not first bit
((read == 0) && (pkt_stuffed[gmlan_sending-1] == 1)) && // bus wrongly dominant
((read == 0) && (pkt_stuffed[gmlan_sending-1] == (char)1)) && // bus wrongly dominant
(gmlan_sending != (gmlan_sendmax - 11))) { //not ack bit
print("GMLAN ERR: bus driven at ");
puth(gmlan_sending);
@ -235,13 +209,13 @@ void GMLAN_BITBANG_IRQ_Handler(void) {
if ((gmlan_sending == gmlan_sendmax) || (gmlan_fail_count == MAX_FAIL_COUNT)) {
set_bitbanged_gmlan(1); // recessive
set_gpio_mode(GPIOB, 13, MODE_INPUT);
register_clear_bits(&(GMLAN_BITBANG_TIMER->DIER), TIM_DIER_UIE); // No update interrupt
register_set(&(GMLAN_BITBANG_TIMER->CR1), 0U, 0x3FU); // Disable timer
register_clear_bits(&(TIM12->DIER), TIM_DIER_UIE); // No update interrupt
register_set(&(TIM12->CR1), 0U, 0x3FU); // Disable timer
gmlan_sendmax = -1; // exit
}
}
} else if (gmlan_alt_mode == GPIO_SWITCH) {
if ((GMLAN_BITBANG_TIMER->SR & TIM_SR_UIF) && (gmlan_switch_below_timeout != -1)) {
if ((TIM12->SR & TIM_SR_UIF) && (gmlan_switch_below_timeout != -1)) {
if ((can_timeout_counter == 0) && gmlan_switch_timeout_enable) {
//it has been more than 1 second since timeout was reset; disable timer and restore the GMLAN output
set_gpio_output(GPIOB, 13, GMLAN_LOW);
@ -265,13 +239,15 @@ void GMLAN_BITBANG_IRQ_Handler(void) {
} else {
// Invalid GMLAN mode. Do not put a print statement here, way too fast to keep up with
}
GMLAN_BITBANG_TIMER->SR = 0;
TIM12->SR = 0;
}
bool bitbang_gmlan(CANPacket_t *to_bang) {
bool bitbang_gmlan(const CANPacket_t *to_bang) {
gmlan_send_ok = true;
gmlan_alt_mode = BITBANG;
#ifdef HW_TYPE_DOS
if (hw_type == HW_TYPE_DOS) {
if (gmlan_sendmax == -1) {
int len = get_bit_message(pkt_stuffed, to_bang);
gmlan_fail_count = 0;
@ -285,5 +261,10 @@ bool bitbang_gmlan(CANPacket_t *to_bang) {
// 33kbps
setup_timer();
}
}
#else
UNUSED(to_bang);
#endif
return gmlan_send_ok;
}

@ -27,9 +27,9 @@ void set_gpio_mode(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int mode) {
void set_gpio_output(GPIO_TypeDef *GPIO, unsigned int pin, bool enabled) {
ENTER_CRITICAL();
if (enabled) {
register_set_bits(&(GPIO->ODR), (1U << pin));
register_set_bits(&(GPIO->ODR), (1UL << pin));
} else {
register_clear_bits(&(GPIO->ODR), (1U << pin));
register_clear_bits(&(GPIO->ODR), (1UL << pin));
}
set_gpio_mode(GPIO, pin, MODE_OUTPUT);
EXIT_CRITICAL();
@ -38,7 +38,7 @@ void set_gpio_output(GPIO_TypeDef *GPIO, unsigned int pin, bool enabled) {
void set_gpio_output_type(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int output_type){
ENTER_CRITICAL();
if(output_type == OUTPUT_TYPE_OPEN_DRAIN) {
register_set_bits(&(GPIO->OTYPER), (1U << pin));
register_set_bits(&(GPIO->OTYPER), (1UL << pin));
} else {
register_clear_bits(&(GPIO->OTYPER), (1U << pin));
}
@ -64,8 +64,8 @@ void set_gpio_pullup(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int mode) {
EXIT_CRITICAL();
}
int get_gpio_input(GPIO_TypeDef *GPIO, unsigned int pin) {
return (GPIO->IDR & (1U << pin)) == (1U << pin);
int get_gpio_input(const GPIO_TypeDef *GPIO, unsigned int pin) {
return (GPIO->IDR & (1UL << pin)) == (1UL << pin);
}
void gpio_set_all_output(const gpio_t *pins, uint8_t num_pins, bool enabled) {

@ -39,7 +39,7 @@ void set_intercept_relay(bool intercept, bool ignition_relay) {
}
// wait until we're not reading the analog voltages anymore
while (harness.sbu_adc_lock == true) {}
while (harness.sbu_adc_lock) {}
if (harness.status == HARNESS_STATUS_NORMAL) {
set_gpio_output(current_board->harness_config->GPIO_relay_SBU1, current_board->harness_config->pin_relay_SBU1, !ignition_relay);
@ -59,7 +59,7 @@ bool harness_check_ignition(void) {
bool ret = false;
// wait until we're not reading the analog voltages anymore
while (harness.sbu_adc_lock == true) {}
while (harness.sbu_adc_lock) {}
switch(harness.status){
case HARNESS_STATUS_NORMAL:
@ -95,6 +95,7 @@ uint8_t harness_detect_orientation(void) {
ret = HARNESS_STATUS_FLIPPED;
} else {
// orientation normal (PANDA_SBU2->HARNESS_SBU1(relay), PANDA_SBU1->HARNESS_SBU2(ign))
// (SBU1->SBU2 is the normal orientation connection per USB-C cable spec)
ret = HARNESS_STATUS_NORMAL;
}
} else {

@ -78,8 +78,8 @@ void interrupt_timer_handler(void) {
// Calculate interrupt load
// The bootstub does not have the FPU enabled, so can't do float operations.
#if !defined(PEDAL) && !defined(BOOTSTUB)
interrupt_load = ((busy_time + idle_time) > 0U) ? ((float) busy_time) / (busy_time + idle_time) : 0.0f;
#if !defined(BOOTSTUB)
interrupt_load = ((busy_time + idle_time) > 0U) ? ((float) (((float) busy_time) / (busy_time + idle_time))) : 0.0f;
#endif
idle_time = 0U;
busy_time = 0U;

@ -1,119 +0,0 @@
void TIM5_IRQ_Handler(void);
void setup_timer5(void) {
// register interrupt
REGISTER_INTERRUPT(TIM5_IRQn, TIM5_IRQ_Handler, 1050000U, FAULT_INTERRUPT_RATE_KLINE_INIT)
// setup
register_set(&(TIM5->PSC), (48-1), 0xFFFFU); // Tick on 1 us
register_set(&(TIM5->CR1), TIM_CR1_CEN, 0x3FU); // Enable
register_set(&(TIM5->ARR), (5000-1), 0xFFFFFFFFU); // Reset every 5 ms
// in case it's disabled
NVIC_EnableIRQ(TIM5_IRQn);
// run the interrupt
register_set(&(TIM5->DIER), TIM_DIER_UIE, 0x5F5FU); // Update interrupt
TIM5->SR = 0;
}
bool k_init = false;
bool l_init = false;
void setup_kline(bool bitbang) {
if (bitbang) {
if (k_init) {
set_gpio_output(GPIOC, 12, true);
}
if (l_init) {
set_gpio_output(GPIOC, 10, true);
}
} else {
if (k_init) {
set_gpio_mode(GPIOC, 12, MODE_ALTERNATE);
}
if (l_init) {
set_gpio_mode(GPIOC, 10, MODE_ALTERNATE);
}
}
}
void set_bitbanged_kline(bool marking) {
// tickle needs to be super fast (so logic level doesn't change)
ENTER_CRITICAL();
if (k_init) {
register_set_bits(&(GPIOC->ODR), (1U << 12));
if (!marking) {
register_clear_bits(&(GPIOC->ODR), (1U << 12));
}
}
if (l_init) {
register_set_bits(&(GPIOC->ODR), (1U << 10));
if (!marking) {
register_clear_bits(&(GPIOC->ODR), (1U << 10));
}
}
EXIT_CRITICAL();
// blink blue LED each time line is pulled low
current_board->set_led(LED_BLUE, marking);
}
uint16_t kline_data = 0;
uint16_t kline_data_len = 0;
uint16_t kline_bit_count = 0;
uint16_t kline_tick_count = 0;
uint16_t kline_ticks_per_bit = 0;
void TIM5_IRQ_Handler(void) {
if ((TIM5->SR & TIM_SR_UIF) && (kline_data != 0U)) {
if (kline_bit_count < kline_data_len) {
bool marking = (kline_data & (1U << kline_bit_count)) != 0U;
set_bitbanged_kline(marking);
} else {
register_clear_bits(&(TIM5->DIER), TIM_DIER_UIE); // No update interrupt
register_set(&(TIM5->CR1), 0U, 0x3FU); // Disable timer
setup_kline(false);
kline_data = 0U;
USB_WritePacket(NULL, 0, 0); // required call (so send nothing)
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
}
kline_tick_count++;
if ((kline_tick_count % kline_ticks_per_bit) == 0U) {
kline_bit_count++;
}
}
TIM5->SR = 0;
}
bool bitbang_five_baud_addr(bool k, bool l, uint8_t addr) {
bool result = false;
if (kline_data == 0U) {
k_init = k;
l_init = l;
kline_data = (addr << 1) + 0x200U; // add start/stop bits
kline_data_len = 10U;
kline_bit_count = 0;
kline_tick_count = 0;
kline_ticks_per_bit = 40U; // 200ms == 5bps
setup_kline(true);
setup_timer5();
result = true;
}
return result;
}
bool bitbang_wakeup(bool k, bool l) {
bool result = false;
if (kline_data == 0U) {
k_init = k;
l_init = l;
kline_data = 2U; // low then high
kline_data_len = 2U;
kline_bit_count = 0;
kline_tick_count = 0;
kline_ticks_per_bit = 5U; // 25ms == 40bps
setup_kline(true);
setup_timer5();
result = true;
}
return result;
}

@ -43,6 +43,8 @@ uint16_t spi_data_len_miso;
uint16_t spi_checksum_error_count = 0;
bool spi_can_tx_ready = false;
const char version_text[] = "VERSION";
#define SPI_HEADER_SIZE 7U
// low level SPI prototypes
@ -64,7 +66,7 @@ uint16_t spi_version_packet(uint8_t *out) {
// VERSION + 2 byte data length + data + CRC8
// echo "VERSION"
(void)memcpy(out, "VERSION", 7);
(void)memcpy(out, version_text, 7);
// write response
uint16_t data_len = 0;
@ -109,7 +111,7 @@ void spi_init(void) {
llspi_mosi_dma(spi_buf_rx, SPI_HEADER_SIZE);
}
bool check_checksum(uint8_t *data, uint16_t len) {
bool validate_checksum(const uint8_t *data, uint16_t len) {
// TODO: can speed this up by casting the bulk to uint32_t and xor-ing the bytes afterwards
uint8_t checksum = SPI_CHECKSUM_START;
for(uint16_t i = 0U; i < len; i++){
@ -128,11 +130,11 @@ void spi_rx_done(void) {
spi_data_len_mosi = (spi_buf_rx[3] << 8) | spi_buf_rx[2];
spi_data_len_miso = (spi_buf_rx[5] << 8) | spi_buf_rx[4];
if (memcmp(spi_buf_rx, "VERSION", 7) == 0) {
if (memcmp(spi_buf_rx, version_text, 7) == 0) {
response_len = spi_version_packet(spi_buf_tx);
next_rx_state = SPI_STATE_HEADER_NACK;;
} else if (spi_state == SPI_STATE_HEADER) {
checksum_valid = check_checksum(spi_buf_rx, SPI_HEADER_SIZE);
checksum_valid = validate_checksum(spi_buf_rx, SPI_HEADER_SIZE);
if ((spi_buf_rx[0] == SPI_SYNC_BYTE) && checksum_valid) {
// response: ACK and start receiving data portion
spi_buf_tx[0] = SPI_HACK;
@ -148,7 +150,7 @@ void spi_rx_done(void) {
} else if (spi_state == SPI_STATE_DATA_RX) {
// We got everything! Based on the endpoint specified, call the appropriate handler
bool response_ack = false;
checksum_valid = check_checksum(&(spi_buf_rx[SPI_HEADER_SIZE]), spi_data_len_mosi + 1U);
checksum_valid = validate_checksum(&(spi_buf_rx[SPI_HEADER_SIZE]), spi_data_len_mosi + 1U);
if (checksum_valid) {
if (spi_endpoint == 0U) {
if (spi_data_len_mosi >= sizeof(ControlPacket_t)) {

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

Loading…
Cancel
Save