Merge remote-tracking branch 'upstream/master' into toyota-lta

pull/27494/head
Shane Smiskol 3 years ago
commit 9bb66063f5
  1. 1
      .github/workflows/prebuilt.yaml
  2. 1
      .github/workflows/release.yaml
  3. 26
      .github/workflows/selfdrive_tests.yaml
  4. 4
      .github/workflows/tools_tests.yaml
  5. 12
      .pre-commit-config.yaml
  6. 1
      Dockerfile.openpilot
  7. 27
      Jenkinsfile
  8. 4
      README.md
  9. 23
      RELEASES.md
  10. 14
      SConstruct
  11. 2
      body
  12. 2
      cereal
  13. 4
      common/SConscript
  14. 24
      common/clutil.cc
  15. 17
      common/gpio.cc
  16. 9
      common/params.cc
  17. 2
      common/version.h
  18. 469
      docs/CARS.md
  19. 2
      docs/Makefile
  20. 12
      docs/assets/icon-youtube.svg
  21. 1
      docs/docker/Dockerfile
  22. 1
      docs/overview.rst
  23. 2
      laika_repo
  24. 2
      launch_chffrplus.sh
  25. 19
      lgtm.yml
  26. 2
      mypy.ini
  27. 2
      opendbc
  28. 2
      panda
  29. 337
      poetry.lock
  30. 5
      pyproject.toml
  31. 22
      release/build_release.sh
  32. 2
      release/check-submodules.sh
  33. 39
      release/files_common
  34. 6
      scripts/cell.sh
  35. 1
      selfdrive/assets/assets.qrc
  36. BIN
      selfdrive/assets/img_driver_face.png
  37. BIN
      selfdrive/assets/img_driver_face_static.png
  38. 5
      selfdrive/assets/navigation/default_marker.svg
  39. 29
      selfdrive/boardd/boardd.cc
  40. 101
      selfdrive/boardd/panda.cc
  41. 10
      selfdrive/boardd/panda.h
  42. 2
      selfdrive/boardd/panda_comms.cc
  43. 10
      selfdrive/boardd/panda_comms.h
  44. 6
      selfdrive/boardd/pandad.py
  45. 84
      selfdrive/boardd/spi.cc
  46. 2
      selfdrive/boardd/tests/test_boardd_loopback.py
  47. 37
      selfdrive/boardd/tests/test_boardd_usbprotocol.cc
  48. 3
      selfdrive/car/CARS_template.md
  49. 40
      selfdrive/car/__init__.py
  50. 2
      selfdrive/car/body/carcontroller.py
  51. 6
      selfdrive/car/body/interface.py
  52. 15
      selfdrive/car/car_helpers.py
  53. 6
      selfdrive/car/chrysler/carcontroller.py
  54. 4
      selfdrive/car/chrysler/carstate.py
  55. 21
      selfdrive/car/chrysler/interface.py
  56. 3
      selfdrive/car/chrysler/radar_interface.py
  57. 5
      selfdrive/car/chrysler/values.py
  58. 2
      selfdrive/car/docs.py
  59. 43
      selfdrive/car/docs_definitions.py
  60. 2
      selfdrive/car/ecu_addrs.py
  61. 99
      selfdrive/car/ford/carcontroller.py
  62. 10
      selfdrive/car/ford/carstate.py
  63. 136
      selfdrive/car/ford/fordcan.py
  64. 37
      selfdrive/car/ford/interface.py
  65. 2
      selfdrive/car/ford/radar_interface.py
  66. 96
      selfdrive/car/ford/values.py
  67. 5
      selfdrive/car/fw_query_definitions.py
  68. 51
      selfdrive/car/fw_versions.py
  69. 44
      selfdrive/car/gm/carcontroller.py
  70. 26
      selfdrive/car/gm/carstate.py
  71. 48
      selfdrive/car/gm/interface.py
  72. 8
      selfdrive/car/gm/radar_interface.py
  73. 18
      selfdrive/car/gm/values.py
  74. 2
      selfdrive/car/honda/carcontroller.py
  75. 2
      selfdrive/car/honda/carstate.py
  76. 16
      selfdrive/car/honda/interface.py
  77. 2
      selfdrive/car/honda/radar_interface.py
  78. 20
      selfdrive/car/honda/tests/test_honda.py
  79. 103
      selfdrive/car/honda/values.py
  80. 14
      selfdrive/car/hyundai/carcontroller.py
  81. 42
      selfdrive/car/hyundai/carstate.py
  82. 2
      selfdrive/car/hyundai/hyundaican.py
  83. 4
      selfdrive/car/hyundai/hyundaicanfd.py
  84. 49
      selfdrive/car/hyundai/interface.py
  85. 2
      selfdrive/car/hyundai/radar_interface.py
  86. 11
      selfdrive/car/hyundai/tests/test_hyundai.py
  87. 180
      selfdrive/car/hyundai/values.py
  88. 33
      selfdrive/car/interfaces.py
  89. 8
      selfdrive/car/mazda/carcontroller.py
  90. 6
      selfdrive/car/mazda/interface.py
  91. 2
      selfdrive/car/mock/interface.py
  92. 2
      selfdrive/car/nissan/carcontroller.py
  93. 6
      selfdrive/car/nissan/interface.py
  94. 2
      selfdrive/car/nissan/values.py
  95. 6
      selfdrive/car/subaru/carcontroller.py
  96. 6
      selfdrive/car/subaru/interface.py
  97. 2
      selfdrive/car/subaru/values.py
  98. 2
      selfdrive/car/tesla/carcontroller.py
  99. 5
      selfdrive/car/tesla/interface.py
  100. 11
      selfdrive/car/tests/routes.py
  101. Some files were not shown because too many files have changed in this diff Show More

@ -16,7 +16,6 @@ jobs:
build_prebuilt: build_prebuilt:
name: build prebuilt name: build prebuilt
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 60
if: github.repository == 'commaai/openpilot' if: github.repository == 'commaai/openpilot'
env: env:
IMAGE_NAME: openpilot-prebuilt IMAGE_NAME: openpilot-prebuilt

@ -8,7 +8,6 @@ jobs:
build_masterci: build_masterci:
name: build master-ci name: build master-ci
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 60
if: github.repository == 'commaai/openpilot' if: github.repository == 'commaai/openpilot'
steps: steps:
- name: Wait for green check mark - name: Wait for green check mark

@ -32,7 +32,6 @@ jobs:
build_release: build_release:
name: build release name: build release
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 30
env: env:
STRIPPED_DIR: /tmp/releasepilot STRIPPED_DIR: /tmp/releasepilot
steps: steps:
@ -61,12 +60,11 @@ jobs:
cp .pylintrc $STRIPPED_DIR cp .pylintrc $STRIPPED_DIR
cp mypy.ini $STRIPPED_DIR cp mypy.ini $STRIPPED_DIR
cd $STRIPPED_DIR cd $STRIPPED_DIR
${{ env.RUN }} "SKIP=test_translations pre-commit run --all" ${{ env.RUN }} "pre-commit run --all"
build_all: build_all:
name: build all name: build all
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 30
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
@ -84,7 +82,6 @@ jobs:
#build_mac: #build_mac:
# name: build macos # name: build macos
# runs-on: macos-latest # runs-on: macos-latest
# timeout-minutes: 60
# steps: # steps:
# - uses: actions/checkout@v3 # - uses: actions/checkout@v3
# with: # with:
@ -141,7 +138,6 @@ jobs:
docker_push: docker_push:
name: docker push name: docker push
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 22
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot'
needs: static_analysis # hack to ensure slow tests run first since this and static_analysis are fast needs: static_analysis # hack to ensure slow tests run first since this and static_analysis are fast
steps: steps:
@ -150,14 +146,12 @@ jobs:
submodules: true submodules: true
- name: Build Docker image - name: Build Docker image
run: eval "$BUILD" run: eval "$BUILD"
timeout-minutes: 13
- name: Push to container registry - name: Push to container registry
run: | run: |
$DOCKER_LOGIN $DOCKER_LOGIN
docker push $DOCKER_REGISTRY/$BASE_IMAGE:latest docker push $DOCKER_REGISTRY/$BASE_IMAGE:latest
- name: Build CL Docker image - name: Build CL Docker image
run: eval "$BUILD_CL" run: eval "$BUILD_CL"
timeout-minutes: 4
- name: Push to container registry - name: Push to container registry
run: | run: |
$DOCKER_LOGIN $DOCKER_LOGIN
@ -166,7 +160,6 @@ jobs:
static_analysis: static_analysis:
name: static analysis name: static analysis
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 20
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
@ -174,13 +167,11 @@ jobs:
- name: Build Docker image - name: Build Docker image
run: eval "$BUILD" run: eval "$BUILD"
- name: pre-commit - name: pre-commit
timeout-minutes: 5
run: ${{ env.RUN }} "pre-commit run --all" run: ${{ env.RUN }} "pre-commit run --all"
valgrind: valgrind:
name: valgrind name: valgrind
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 20
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
@ -198,7 +189,6 @@ jobs:
unit_tests: unit_tests:
name: unit tests name: unit tests
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 30
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
@ -207,7 +197,6 @@ jobs:
- name: Build openpilot - name: Build openpilot
run: ${{ env.RUN }} "scons -j$(nproc)" run: ${{ env.RUN }} "scons -j$(nproc)"
- name: Run unit tests - name: Run unit tests
timeout-minutes: 15
run: | run: |
${{ env.RUN }} "export SKIP_LONG_TESTS=1 && \ ${{ env.RUN }} "export SKIP_LONG_TESTS=1 && \
$UNIT_TEST common && \ $UNIT_TEST common && \
@ -219,6 +208,7 @@ jobs:
$UNIT_TEST selfdrive/car && \ $UNIT_TEST selfdrive/car && \
$UNIT_TEST selfdrive/locationd && \ $UNIT_TEST selfdrive/locationd && \
selfdrive/locationd/test/_test_locationd_lib.py && \ selfdrive/locationd/test/_test_locationd_lib.py && \
./selfdrive/locationd/test/test_glonass_runner && \
$UNIT_TEST selfdrive/athena && \ $UNIT_TEST selfdrive/athena && \
$UNIT_TEST selfdrive/thermald && \ $UNIT_TEST selfdrive/thermald && \
$UNIT_TEST system/hardware/tici && \ $UNIT_TEST system/hardware/tici && \
@ -241,7 +231,6 @@ jobs:
process_replay: process_replay:
name: process replay name: process replay
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 25
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
@ -261,6 +250,7 @@ jobs:
${{ env.RUN }} "CI=1 coverage run selfdrive/test/process_replay/test_processes.py -j$(nproc) && \ ${{ env.RUN }} "CI=1 coverage run selfdrive/test/process_replay/test_processes.py -j$(nproc) && \
coverage xml" coverage xml"
- name: Print diff - name: Print diff
id: print-diff
if: always() if: always()
run: cat selfdrive/test/process_replay/diff.txt run: cat selfdrive/test/process_replay/diff.txt
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2
@ -270,7 +260,7 @@ jobs:
name: process_replay_diff.txt name: process_replay_diff.txt
path: selfdrive/test/process_replay/diff.txt path: selfdrive/test/process_replay/diff.txt
- name: Upload reference logs - name: Upload reference logs
if: ${{ failure() && github.event_name == 'pull_request' && github.repository == 'commaai/openpilot' && env.AZURE_TOKEN != '' }} if: ${{ failure() && steps.print-diff.outcome == 'success' && github.event_name == 'pull_request' && github.repository == 'commaai/openpilot' && env.AZURE_TOKEN != '' }}
run: | run: |
${{ env.RUN }} "CI=1 AZURE_TOKEN='$AZURE_TOKEN' python selfdrive/test/process_replay/test_processes.py -j$(nproc) --upload-only" ${{ env.RUN }} "CI=1 AZURE_TOKEN='$AZURE_TOKEN' python selfdrive/test/process_replay/test_processes.py -j$(nproc) --upload-only"
- name: "Upload coverage to Codecov" - name: "Upload coverage to Codecov"
@ -279,7 +269,6 @@ jobs:
test_modeld: test_modeld:
name: model tests name: model tests
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 20
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
@ -292,12 +281,10 @@ jobs:
run: | run: |
${{ env.RUN }} "scons -j$(nproc)" ${{ env.RUN }} "scons -j$(nproc)"
- name: Run model replay with ONNX - name: Run model replay with ONNX
timeout-minutes: 2
run: | run: |
${{ env.RUN_CL }} "ONNXCPU=1 CI=1 NO_NAV=1 coverage run selfdrive/test/process_replay/model_replay.py && \ ${{ env.RUN_CL }} "ONNXCPU=1 CI=1 NO_NAV=1 coverage run selfdrive/test/process_replay/model_replay.py && \
coverage xml" coverage xml"
- name: Run unit tests - name: Run unit tests
timeout-minutes: 5
run: | run: |
${{ env.RUN_CL }} "$UNIT_TEST selfdrive/modeld && \ ${{ env.RUN_CL }} "$UNIT_TEST selfdrive/modeld && \
coverage xml" coverage xml"
@ -307,7 +294,6 @@ jobs:
test_longitudinal: test_longitudinal:
name: longitudinal name: longitudinal
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 20
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
@ -322,7 +308,6 @@ jobs:
cd selfdrive/test/longitudinal_maneuvers && \ cd selfdrive/test/longitudinal_maneuvers && \
coverage run ./test_longitudinal.py && \ coverage run ./test_longitudinal.py && \
coverage xml" coverage xml"
timeout-minutes: 2
- name: "Upload coverage to Codecov" - name: "Upload coverage to Codecov"
uses: codecov/codecov-action@v2 uses: codecov/codecov-action@v2
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2
@ -335,7 +320,6 @@ jobs:
test_cars: test_cars:
name: cars name: cars
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 20
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@ -354,7 +338,6 @@ jobs:
- name: Build openpilot - name: Build openpilot
run: ${{ env.RUN }} "scons -j$(nproc)" run: ${{ env.RUN }} "scons -j$(nproc)"
- name: Test car models - name: Test car models
timeout-minutes: 12
run: | run: |
${{ env.RUN }} "coverage run -m pytest selfdrive/car/tests/test_models.py && \ ${{ env.RUN }} "coverage run -m pytest selfdrive/car/tests/test_models.py && \
coverage xml && \ coverage xml && \
@ -368,7 +351,6 @@ jobs:
car_docs_diff: car_docs_diff:
name: PR comments name: PR comments
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 20
if: github.event_name == 'pull_request' if: github.event_name == 'pull_request'
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3

@ -30,7 +30,6 @@ jobs:
plotjuggler: plotjuggler:
name: plotjuggler name: plotjuggler
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 20
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
@ -38,7 +37,6 @@ jobs:
- name: Build Docker image - name: Build Docker image
run: eval "$BUILD" run: eval "$BUILD"
- name: Unit test - name: Unit test
timeout-minutes: 2
run: | run: |
${{ env.RUN }} "scons -j$(nproc) --directory=/tmp/openpilot/cereal && \ ${{ env.RUN }} "scons -j$(nproc) --directory=/tmp/openpilot/cereal && \
apt-get update && \ apt-get update && \
@ -49,7 +47,6 @@ jobs:
simulator: simulator:
name: simulator name: simulator
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 30
env: env:
IMAGE_NAME: openpilot-sim IMAGE_NAME: openpilot-sim
if: github.repository == 'commaai/openpilot' if: github.repository == 'commaai/openpilot'
@ -74,7 +71,6 @@ jobs:
docs: docs:
name: build docs name: build docs
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 25
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:

@ -7,7 +7,7 @@ repos:
rev: v4.1.0 rev: v4.1.0
hooks: hooks:
- id: check-ast - id: check-ast
exclude: '^(pyextra)/' exclude: '^(third_party)/'
- id: check-json - id: check-json
- id: check-xml - id: check-xml
- id: check-yaml - id: check-yaml
@ -19,7 +19,7 @@ repos:
rev: v2.2.1 rev: v2.2.1
hooks: hooks:
- id: codespell - id: codespell
exclude: '^(pyextra/)|(third_party/)|(body/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)|(include/)|(selfdrive/ui/translations/.*.ts)|(selfdrive/controls/lib/cluster)' exclude: '^(third_party/)|(body/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)|(selfdrive/ui/translations/.*.ts)|(poetry.lock)'
args: args:
# if you've got a short variable name that's getting flagged, add it here # if you've got a short variable name that's getting flagged, add it here
- -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup - -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup
@ -31,12 +31,12 @@ repos:
entry: mypy entry: mypy
language: system language: system
types: [python] types: [python]
exclude: '^(pyextra/)|(cereal/)|(opendbc/)|(panda/)|(laika/)|(laika_repo/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(xx/)' exclude: '^(third_party/)|(cereal/)|(opendbc/)|(panda/)|(laika/)|(laika_repo/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(xx/)'
- repo: https://github.com/PyCQA/flake8 - repo: https://github.com/PyCQA/flake8
rev: 4.0.1 rev: 4.0.1
hooks: hooks:
- id: flake8 - id: flake8
exclude: '^(pyextra/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(selfdrive/debug/)/' exclude: '^(third_party/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(selfdrive/debug/)/'
additional_dependencies: ['flake8-no-implicit-concat'] additional_dependencies: ['flake8-no-implicit-concat']
args: args:
- --indent-size=2 - --indent-size=2
@ -51,7 +51,7 @@ repos:
entry: pylint entry: pylint
language: system language: system
types: [python] types: [python]
exclude: '^(pyextra/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(laika_repo/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)' exclude: '^(third_party/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(laika_repo/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)'
args: args:
- -j0 - -j0
- -rn - -rn
@ -64,7 +64,7 @@ repos:
entry: cppcheck entry: cppcheck
language: system language: system
types: [c++] types: [c++]
exclude: '^(third_party/)|(pyextra/)|(cereal/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(tools/)|(selfdrive/modeld/thneed/debug/)|(selfdrive/modeld/test/)|(selfdrive/camerad/test/)|(installer/)' exclude: '^(third_party/)|(cereal/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(tools/)|(selfdrive/modeld/thneed/debug/)|(selfdrive/modeld/test/)|(selfdrive/camerad/test/)|(installer/)'
args: args:
- --error-exitcode=1 - --error-exitcode=1
- --language=c++ - --language=c++

@ -10,7 +10,6 @@ WORKDIR ${OPENPILOT_PATH}
COPY SConstruct ${OPENPILOT_PATH} COPY SConstruct ${OPENPILOT_PATH}
COPY ./pyextra ${OPENPILOT_PATH}/pyextra
COPY ./third_party ${OPENPILOT_PATH}/third_party COPY ./third_party ${OPENPILOT_PATH}/third_party
COPY ./site_scons ${OPENPILOT_PATH}/site_scons COPY ./site_scons ${OPENPILOT_PATH}/site_scons
COPY ./laika ${OPENPILOT_PATH}/laika COPY ./laika ${OPENPILOT_PATH}/laika

27
Jenkinsfile vendored

@ -13,6 +13,8 @@ export GIT_COMMIT=${env.GIT_COMMIT}
export AZURE_TOKEN='${env.AZURE_TOKEN}' export AZURE_TOKEN='${env.AZURE_TOKEN}'
export MAPBOX_TOKEN='${env.MAPBOX_TOKEN}' export MAPBOX_TOKEN='${env.MAPBOX_TOKEN}'
export GIT_SSH_COMMAND="ssh -i /data/gitkey"
source ~/.bash_profile source ~/.bash_profile
if [ -f /TICI ]; then if [ -f /TICI ]; then
source /etc/profile source /etc/profile
@ -56,14 +58,26 @@ pipeline {
} }
stages { stages {
stage('build release3') { stage('build release3-staging') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
when { when {
branch 'devel-staging' branch 'devel-staging'
} }
steps { steps {
phone_steps("tici-needs-can", [ phone_steps("tici-needs-can", [
["build release3-staging & dashcam3-staging", "PUSH=1 $SOURCE_DIR/release/build_release.sh"], ["build release3-staging & dashcam3-staging", "RELEASE_BRANCH=release3-staging DASHCAM_BRANCH=dashcam3-staging $SOURCE_DIR/release/build_release.sh"],
])
}
}
stage('build nightly') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
when {
branch 'master-ci'
}
steps {
phone_steps("tici-needs-can", [
["build nightly", "RELEASE_BRANCH=nightly $SOURCE_DIR/release/build_release.sh"],
]) ])
} }
} }
@ -81,6 +95,7 @@ pipeline {
parallel { parallel {
/*
stage('simulator') { stage('simulator') {
agent { agent {
dockerfile { dockerfile {
@ -90,7 +105,8 @@ pipeline {
} }
} }
steps { steps {
sh "git config --global --add safe.directory ${WORKSPACE}" sh "git config --global --add safe.directory '*'"
sh "git submodule update --init --recursive"
sh "git lfs pull" sh "git lfs pull"
lock(resource: "", label: "simulator", inversePrecedence: true, quantity: 1) { lock(resource: "", label: "simulator", inversePrecedence: true, quantity: 1) {
sh "${WORKSPACE}/tools/sim/build_container.sh" sh "${WORKSPACE}/tools/sim/build_container.sh"
@ -107,6 +123,7 @@ pipeline {
} }
} }
} }
*/
stage('build') { stage('build') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
@ -151,7 +168,7 @@ pipeline {
stage('camerad-ar') { stage('camerad-ar') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
steps { steps {
phone_steps("tici-ar0321", [ phone_steps("tici-ar0231", [
["build", "cd selfdrive/manager && ./build.py"], ["build", "cd selfdrive/manager && ./build.py"],
["test camerad", "python system/camerad/test/test_camerad.py"], ["test camerad", "python system/camerad/test/test_camerad.py"],
["test exposure", "python system/camerad/test/test_exposure.py"], ["test exposure", "python system/camerad/test/test_exposure.py"],
@ -189,7 +206,7 @@ pipeline {
steps { steps {
phone_steps("tici-common", [ phone_steps("tici-common", [
["build", "cd selfdrive/manager && ./build.py"], ["build", "cd selfdrive/manager && ./build.py"],
["model replay", "cd selfdrive/test/process_replay && ./model_replay.py"], ["model replay", "cd selfdrive/test/process_replay && NO_NAV=1 ./model_replay.py"],
]) ])
} }
} }

@ -103,7 +103,6 @@ Directory Structure
├── opendbc # Files showing how to interpret data from cars ├── opendbc # Files showing how to interpret data from cars
├── panda # Code used to communicate on CAN ├── panda # Code used to communicate on CAN
├── third_party # External libraries ├── third_party # External libraries
├── pyextra # Extra python packages
└── system # Generic services └── system # Generic services
├── camerad # Driver to capture images from the camera sensors ├── camerad # Driver to capture images from the camera sensors
├── clocksd # Broadcasts current time ├── clocksd # Broadcasts current time
@ -143,7 +142,4 @@ 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> <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/workflows/openpilot%20tests/badge.svg?event=push)](https://github.com/commaai/openpilot/actions)
[![Total alerts](https://img.shields.io/lgtm/alerts/g/commaai/openpilot.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/commaai/openpilot/alerts/)
[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/commaai/openpilot.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/commaai/openpilot/context:python)
[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/commaai/openpilot.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/commaai/openpilot/context:cpp)
[![codecov](https://codecov.io/gh/commaai/openpilot/branch/master/graph/badge.svg)](https://codecov.io/gh/commaai/openpilot) [![codecov](https://codecov.io/gh/commaai/openpilot/branch/master/graph/badge.svg)](https://codecov.io/gh/commaai/openpilot)

@ -1,12 +1,27 @@
Version 0.9.1 (2022-12-XX) Version 0.9.2 (2023-03-XX)
======================== ========================
* Adjust alert volume using ambient noise level * Draw MPC path instead of model predicted path, this is a more accurate representation of what the car will do.
* Removed driver monitoring timer resetting on interaction if face detected and distracted
* New German translation thanks to Vrabetz and CzokNorris! Version 0.9.1 (2023-02-28)
========================
* New driving model
* 30% improved height estimation resulting in better driving performance for tall cars
* Driver monitoring: removed timer resetting on user interaction if distracted
* UI updates
* Adjust alert volume using ambient noise level
* Driver monitoring icon shows driver's head pose
* German translation thanks to Vrabetz and CzokNorris!
* Cadillac Escalade 2017 support thanks to rickygilleland!
* Chevrolet Bolt EV 2022-23 support thanks to JasonJShuler! * Chevrolet Bolt EV 2022-23 support thanks to JasonJShuler!
* Genesis GV60 2023 support thanks to sunnyhaibin! * Genesis GV60 2023 support thanks to sunnyhaibin!
* Hyundai Tucson 2022-23 support * Hyundai Tucson 2022-23 support
* Kia K5 Hybrid 2020 support thanks to sunnyhaibin!
* Kia Niro Hybrid 2023 support thanks to sunnyhaibin!
* Kia Sorento 2022-23 support thanks to sunnyhaibin!
* Kia Sorento Plug-in Hybrid 2022 support thanks to sunnyhaibin! * Kia Sorento Plug-in Hybrid 2022 support thanks to sunnyhaibin!
* Toyota C-HR 2021 support thanks to eFiniLan!
* Toyota C-HR Hybrid 2022 support thanks to Korben00!
* Volkswagen Crafter and MAN TGE 2017-23 support thanks to jyoung8607!
Version 0.9.0 (2022-11-21) Version 0.9.0 (2022-11-21)
======================== ========================

@ -71,10 +71,10 @@ if arch == "aarch64" and AGNOS:
lenv = { lenv = {
"PATH": os.environ['PATH'], "PATH": os.environ['PATH'],
"LD_LIBRARY_PATH": [Dir(f"#third_party/acados/{arch}/lib").abspath], "LD_LIBRARY_PATH": [Dir(f"#third_party/acados/{arch}/lib").abspath],
"PYTHONPATH": Dir("#").abspath + ":" + Dir("#pyextra/").abspath, "PYTHONPATH": Dir("#").abspath,
"ACADOS_SOURCE_DIR": Dir("#third_party/acados/include/acados").abspath, "ACADOS_SOURCE_DIR": Dir("#third_party/acados/include/acados").abspath,
"ACADOS_PYTHON_INTERFACE_PATH": Dir("#pyextra/acados_template").abspath, "ACADOS_PYTHON_INTERFACE_PATH": Dir("#third_party/acados/acados_template").abspath,
"TERA_PATH": Dir("#").abspath + f"/third_party/acados/{arch}/t_renderer" "TERA_PATH": Dir("#").abspath + f"/third_party/acados/{arch}/t_renderer"
} }
@ -197,10 +197,6 @@ env = Environment(
"#third_party/libyuv/include", "#third_party/libyuv/include",
"#third_party/json11", "#third_party/json11",
"#third_party/curl/include", "#third_party/curl/include",
"#third_party/libgralloc/include",
"#third_party/android_frameworks_native/include",
"#third_party/android_hardware_libhardware/include",
"#third_party/android_system_core/include",
"#third_party/linux/include", "#third_party/linux/include",
"#third_party/snpe/include", "#third_party/snpe/include",
"#third_party/mapbox-gl-native-qt/include", "#third_party/mapbox-gl-native-qt/include",
@ -282,7 +278,7 @@ Export('envCython')
# Qt build environment # Qt build environment
qt_env = env.Clone() qt_env = env.Clone()
qt_modules = ["Widgets", "Gui", "Core", "Network", "Concurrent", "Multimedia", "Quick", "Qml", "QuickWidgets", "Location", "Positioning", "DBus"] qt_modules = ["Widgets", "Gui", "Core", "Network", "Concurrent", "Multimedia", "Quick", "Qml", "QuickWidgets", "Location", "Positioning", "DBus", "Xml"]
qt_libs = [] qt_libs = []
if arch == "Darwin": if arch == "Darwin":
@ -311,6 +307,7 @@ else:
qt_libs = [f"Qt5{m}" for m in qt_modules] qt_libs = [f"Qt5{m}" for m in qt_modules]
if arch == "larch64": if arch == "larch64":
qt_libs += ["GLESv2", "wayland-client"] qt_libs += ["GLESv2", "wayland-client"]
qt_env.PrependENVPath('PATH', Dir("#third_party/qt5/larch64/bin/").abspath)
elif arch != "Darwin": elif arch != "Darwin":
qt_libs += ["GL"] qt_libs += ["GL"]
@ -387,10 +384,10 @@ rednose_config = {
if arch != "larch64": if arch != "larch64":
rednose_config['to_build'].update({ rednose_config['to_build'].update({
'loc_4': ('#selfdrive/locationd/models/loc_kf.py', True, [], rednose_deps), '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_4': ('#rednose/helpers/lst_sq_computer.py', False, [], []),
'pos_computer_5': ('#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, [], []), 'feature_handler_5': ('#rednose/helpers/feature_handler.py', False, [], []),
'lane': ('#xx/pipeline/lib/ekf/lane_kf.py', True, [], rednose_deps),
}) })
Export('rednose_config') Export('rednose_config')
@ -422,7 +419,6 @@ SConscript(['common/transformations/SConscript'])
SConscript(['selfdrive/modeld/SConscript']) SConscript(['selfdrive/modeld/SConscript'])
SConscript(['selfdrive/controls/lib/cluster/SConscript'])
SConscript(['selfdrive/controls/lib/lateral_mpc_lib/SConscript']) SConscript(['selfdrive/controls/lib/lateral_mpc_lib/SConscript'])
SConscript(['selfdrive/controls/lib/longitudinal_mpc_lib/SConscript']) SConscript(['selfdrive/controls/lib/longitudinal_mpc_lib/SConscript'])

@ -1 +1 @@
Subproject commit dc780f858c1ef641471d09b72569e199e3e10acb Subproject commit e1805f65ee75fab4454c21eda8b42b49d4bdc48f

@ -1 +1 @@
Subproject commit 22b1431132b038253a24ab3fbbe3af36ef93b95b Subproject commit b88523f05ac958f87a8f6d57c3f4bb20da55f216

@ -10,11 +10,13 @@ common_libs = [
'statlog.cc', 'statlog.cc',
'swaglog.cc', 'swaglog.cc',
'util.cc', 'util.cc',
'gpio.cc',
'i2c.cc', 'i2c.cc',
'watchdog.cc', 'watchdog.cc',
] ]
if arch != "Darwin":
common_libs.append('gpio.cc')
_common = fxn('common', common_libs, LIBS="json11") _common = fxn('common', common_libs, LIBS="json11")
files = [ files = [

@ -5,6 +5,7 @@
#include <memory> #include <memory>
#include "common/util.h" #include "common/util.h"
#include "common/swaglog.h"
namespace { // helper functions namespace { // helper functions
@ -31,14 +32,14 @@ void cl_print_info(cl_platform_id platform, cl_device_id device) {
case CL_DEVICE_TYPE_ACCELERATOR: type_str = "CL_DEVICE_TYPE_ACCELERATOR"; break; case CL_DEVICE_TYPE_ACCELERATOR: type_str = "CL_DEVICE_TYPE_ACCELERATOR"; break;
} }
std::cout << "vendor: " << get_platform_info(platform, CL_PLATFORM_VENDOR) << std::endl LOGD("vendor: %s", get_platform_info(platform, CL_PLATFORM_VENDOR).c_str());
<< "platform version: " << get_platform_info(platform, CL_PLATFORM_VERSION) << std::endl LOGD("platform version: %s", get_platform_info(platform, CL_PLATFORM_VERSION).c_str());
<< "profile: " << get_platform_info(platform, CL_PLATFORM_PROFILE) << std::endl LOGD("profile: %s", get_platform_info(platform, CL_PLATFORM_PROFILE).c_str());
<< "extensions: " << get_platform_info(platform, CL_PLATFORM_EXTENSIONS) << std::endl LOGD("extensions: %s", get_platform_info(platform, CL_PLATFORM_EXTENSIONS).c_str());
<< "name :" << get_device_info(device, CL_DEVICE_NAME) << std::endl LOGD("name: %s", get_device_info(device, CL_DEVICE_NAME).c_str());
<< "device version :" << get_device_info(device, CL_DEVICE_VERSION) << std::endl LOGD("device version: %s", get_device_info(device, CL_DEVICE_VERSION).c_str());
<< "max work group size :" << work_group_size << std::endl LOGD("max work group size: %d", work_group_size);
<< "type = " << device_type << " = " << type_str << std::endl; LOGD("type = %d = ", device_type, type_str);
} }
void cl_print_build_errors(cl_program program, cl_device_id device) { void cl_print_build_errors(cl_program program, cl_device_id device) {
@ -49,7 +50,7 @@ void cl_print_build_errors(cl_program program, cl_device_id device) {
std::string log(log_size, '\0'); std::string log(log_size, '\0');
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, log_size, &log[0], NULL); clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, log_size, &log[0], NULL);
std::cout << "build failed; status=" << status << ", log:" << std::endl << log << std::endl; LOGE("build failed; status=%d, log: %s", status, log.c_str());
} }
} // namespace } // namespace
@ -61,14 +62,15 @@ cl_device_id cl_get_device_id(cl_device_type device_type) {
CL_CHECK(clGetPlatformIDs(num_platforms, &platform_ids[0], NULL)); CL_CHECK(clGetPlatformIDs(num_platforms, &platform_ids[0], NULL));
for (size_t i = 0; i < num_platforms; ++i) { for (size_t i = 0; i < num_platforms; ++i) {
std::cout << "platform[" << i << "] CL_PLATFORM_NAME: " << get_platform_info(platform_ids[i], CL_PLATFORM_NAME) << std::endl; LOGD("platform[%d] CL_PLATFORM_NAME: %s", i, get_platform_info(platform_ids[i], CL_PLATFORM_NAME).c_str());
// Get first device // Get first device
if (cl_device_id device_id = NULL; clGetDeviceIDs(platform_ids[i], device_type, 1, &device_id, NULL) == 0 && device_id) { if (cl_device_id device_id = NULL; clGetDeviceIDs(platform_ids[i], device_type, 1, &device_id, NULL) == 0 && device_id) {
cl_print_info(platform_ids[i], device_id); cl_print_info(platform_ids[i], device_id);
return device_id; return device_id;
} }
} }
std::cout << "No valid openCL platform found" << std::endl; LOGE("No valid openCL platform found");
assert(0); assert(0);
return nullptr; return nullptr;
} }

@ -1,5 +1,20 @@
#include "common/gpio.h" #include "common/gpio.h"
#ifdef __APPLE__
int gpio_init(int pin_nr, bool output) {
return 0;
}
int gpio_set(int pin_nr, bool high) {
return 0;
}
int gpiochip_get_ro_value_fd(const char* consumer_label, int gpiochiop_id, int pin_nr) {
return 0;
}
#else
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
@ -63,3 +78,5 @@ int gpiochip_get_ro_value_fd(const char* consumer_label, int gpiochiop_id, int p
close(fd); close(fd);
return rq.fd; return rq.fd;
} }
#endif

@ -104,13 +104,14 @@ std::unordered_map<std::string, uint32_t> keys = {
{"DisablePowerDown", PERSISTENT}, {"DisablePowerDown", PERSISTENT},
{"ExperimentalMode", PERSISTENT}, {"ExperimentalMode", PERSISTENT},
{"ExperimentalModeConfirmed", PERSISTENT}, {"ExperimentalModeConfirmed", PERSISTENT},
{"ExperimentalLongitudinalEnabled", PERSISTENT}, // WARNING: THIS MAY DISABLE AEB {"ExperimentalLongitudinalEnabled", PERSISTENT},
{"DisableUpdates", PERSISTENT}, {"DisableUpdates", PERSISTENT},
{"DisengageOnAccelerator", PERSISTENT}, {"DisengageOnAccelerator", PERSISTENT},
{"DongleId", PERSISTENT}, {"DongleId", PERSISTENT},
{"DoReboot", CLEAR_ON_MANAGER_START}, {"DoReboot", CLEAR_ON_MANAGER_START},
{"DoShutdown", CLEAR_ON_MANAGER_START}, {"DoShutdown", CLEAR_ON_MANAGER_START},
{"DoUninstall", CLEAR_ON_MANAGER_START}, {"DoUninstall", CLEAR_ON_MANAGER_START},
{"FirmwareObdQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
{"ForcePowerDown", CLEAR_ON_MANAGER_START}, {"ForcePowerDown", CLEAR_ON_MANAGER_START},
{"GitBranch", PERSISTENT}, {"GitBranch", PERSISTENT},
{"GitCommit", PERSISTENT}, {"GitCommit", PERSISTENT},
@ -134,9 +135,10 @@ std::unordered_map<std::string, uint32_t> keys = {
{"IsRhdDetected", PERSISTENT}, {"IsRhdDetected", PERSISTENT},
{"IsTakingSnapshot", CLEAR_ON_MANAGER_START}, {"IsTakingSnapshot", CLEAR_ON_MANAGER_START},
{"IsTestedBranch", CLEAR_ON_MANAGER_START}, {"IsTestedBranch", CLEAR_ON_MANAGER_START},
{"IsReleaseBranch", CLEAR_ON_MANAGER_START},
{"IsUpdateAvailable", CLEAR_ON_MANAGER_START}, {"IsUpdateAvailable", CLEAR_ON_MANAGER_START},
{"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF}, {"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF},
{"LaikadEphemeris", PERSISTENT | DONT_LOG}, {"LaikadEphemerisV2", PERSISTENT | DONT_LOG},
{"LanguageSetting", PERSISTENT}, {"LanguageSetting", PERSISTENT},
{"LastAthenaPingTime", CLEAR_ON_MANAGER_START}, {"LastAthenaPingTime", CLEAR_ON_MANAGER_START},
{"LastGPSPosition", PERSISTENT}, {"LastGPSPosition", PERSISTENT},
@ -153,6 +155,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"NavSettingTime24h", PERSISTENT}, {"NavSettingTime24h", PERSISTENT},
{"NavSettingLeftSide", PERSISTENT}, {"NavSettingLeftSide", PERSISTENT},
{"NavdRender", PERSISTENT}, {"NavdRender", PERSISTENT},
{"ObdMultiplexingDisabled", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
{"OpenpilotEnabledToggle", PERSISTENT}, {"OpenpilotEnabledToggle", PERSISTENT},
{"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF}, {"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF},
{"PandaSignatures", CLEAR_ON_MANAGER_START}, {"PandaSignatures", CLEAR_ON_MANAGER_START},
@ -169,7 +172,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"Timezone", PERSISTENT}, {"Timezone", PERSISTENT},
{"TrainingVersion", PERSISTENT}, {"TrainingVersion", PERSISTENT},
{"UbloxAvailable", PERSISTENT}, {"UbloxAvailable", PERSISTENT},
{"UpdateAvailable", CLEAR_ON_MANAGER_START}, {"UpdateAvailable", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
{"UpdateFailedCount", CLEAR_ON_MANAGER_START}, {"UpdateFailedCount", CLEAR_ON_MANAGER_START},
{"UpdaterState", CLEAR_ON_MANAGER_START}, {"UpdaterState", CLEAR_ON_MANAGER_START},
{"UpdaterFetchAvailable", CLEAR_ON_MANAGER_START}, {"UpdaterFetchAvailable", CLEAR_ON_MANAGER_START},

@ -1 +1 @@
#define COMMA_VERSION "0.9.1" #define COMMA_VERSION "0.9.2"

@ -4,239 +4,254 @@
A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system.
# 222 Supported Cars # 237 Supported Cars
|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness| |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|Video|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Acura&model=ILX 2016-19">Honda Nidec</a>||
|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Acura&model=RDX 2016-18">Honda Nidec</a>||
|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)](##)|Honda Bosch A| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Acura&model=RDX 2019-22">Honda Bosch A</a>||
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Audi&model=A3 2014-19">J533</a>||
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Audi&model=A3 Sportback e-tron 2017-18">J533</a>||
|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Audi&model=Q2 2018">J533</a>||
|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Audi&model=Q3 2019-23">J533</a>||
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Audi&model=RS3 2018">J533</a>||
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Audi&model=S3 2015-17">J533</a>||
|Cadillac|Escalade ESV 2016[<sup>3</sup>](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |Cadillac|Escalade 2017[<sup>3</sup>](#footnotes)|Driver Assist Package|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Cadillac&model=Escalade 2017">OBD-II</a>||
|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)](##)|GM| |Cadillac|Escalade ESV 2016[<sup>3</sup>](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Cadillac&model=Escalade ESV 2016">OBD-II</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)](##)|GM| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Chevrolet&model=Bolt EUV 2022-23">GM</a>|<a href="https://youtu.be/xvwzGMUA210" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Chevrolet&model=Bolt EV 2022-23">GM</a>||
|Chevrolet|Volt 2017-18[<sup>3</sup>](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Chevrolet&model=Silverado 1500 2020-21">GM</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)](##)|FCA| |Chevrolet|Volt 2017-18[<sup>3</sup>](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Chevrolet&model=Volt 2017-18">OBD-II</a>|<a href="https://youtu.be/QeMCN_4TFfQ" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| |Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Chrysler&model=Pacifica 2017-18">FCA</a>||
|Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| |Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Chrysler&model=Pacifica 2019-20">FCA</a>||
|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| |Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Chrysler&model=Pacifica 2021">FCA</a>||
|Chrysler|Pacifica Hybrid 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Chrysler&model=Pacifica Hybrid 2017-18">FCA</a>||
|comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None| |Chrysler|Pacifica Hybrid 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Chrysler&model=Pacifica Hybrid 2019-22">FCA</a>||
|Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F| |comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None||
|Genesis|G70 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F| |Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Genesis&model=G70 2018-19">Hyundai F</a>||
|Genesis|G80 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| |Genesis|G70 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Genesis&model=G70 2020">Hyundai F</a>||
|Genesis|G90 2017-18|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Genesis|G80 2017|All|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Genesis&model=G80 2017">Hyundai J</a>||
|Genesis|GV60 2023[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Genesis|G80 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Genesis&model=G80 2018-19">Hyundai H</a>||
|Genesis|GV70 2022-23[<sup>5</sup>](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| |Genesis|G90 2017-18|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Genesis&model=G90 2017-18">Hyundai C</a>||
|GMC|Acadia 2018[<sup>3</sup>](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |Genesis|GV60 (Advanced Trim) 2023[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Genesis&model=GV60 (Advanced Trim) 2023">Hyundai A</a>||
|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| |Genesis|GV60 (Performance Trim) 2023[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Genesis&model=GV60 (Performance Trim) 2023">Hyundai K</a>||
|Honda|Accord 2018-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| |Genesis|GV70 2022-23[<sup>5</sup>](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Genesis&model=GV70 2022-23">Hyundai L</a>||
|Honda|Accord Hybrid 2018-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| |GMC|Acadia 2018[<sup>3</sup>](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=GMC&model=Acadia 2018">OBD-II</a>|<a href="https://www.youtube.com/watch?v=0ZN6DdsBUZo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=GMC&model=Sierra 1500 2020-21">GM</a>|<a href="https://youtu.be/5HbNoBLzRwE" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Honda|Civic 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|2 mph[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| |Honda|Accord 2018-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Accord 2018-22">Honda Bosch A</a>|<a href="https://www.youtube.com/watch?v=mrUwlj3Mi58" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Honda|Civic 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch B| |Honda|Accord Hybrid 2018-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Accord Hybrid 2018-22">Honda Bosch A</a>||
|Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| |Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Civic 2016-18">Honda Nidec</a>|<a href="https://youtu.be/-IkImTe1NYE" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Honda|Civic Hatchback 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch B| |Honda|Civic 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|2 mph[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Civic 2019-21">Honda Bosch A</a>|<a href="https://www.youtube.com/watch?v=4Iz1Mz5LGF8" 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-full.svg)](##)|Honda Nidec| |Honda|Civic 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Civic 2022">Honda Bosch B</a>||
|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)](##)|Honda Bosch A| |Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Civic Hatchback 2017-21">Honda Bosch A</a>||
|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)](##)|Honda Bosch A| |Honda|Civic Hatchback 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Civic Hatchback 2022">Honda Bosch B</a>||
|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)](##)|Honda Bosch A| |Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Honda&model=CR-V 2015-16">Honda Nidec</a>||
|Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Honda&model=CR-V 2017-22">Honda Bosch A</a>||
|Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Honda&model=CR-V Hybrid 2017-19">Honda Bosch A</a>||
|Honda|HR-V 2019-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Honda&model=e 2020">Honda Bosch A</a>||
|Honda|Insight 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)](##)|Honda Bosch A| |Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Fit 2018-20">Honda Nidec</a>||
|Honda|Inspire 2018|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| |Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Freed 2020">Honda Nidec</a>||
|Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Honda|HR-V 2019-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Honda&model=HR-V 2019-22">Honda Nidec</a>||
|Honda|Passport 2019-21|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Honda|Insight 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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Insight 2019-22">Honda Bosch A</a>||
|Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Honda|Inspire 2018|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Inspire 2018">Honda Bosch A</a>||
|Honda|Ridgeline 2017-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Odyssey 2018-20">Honda Nidec</a>||
|Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B| |Honda|Passport 2019-21|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Passport 2019-21">Honda Nidec</a>||
|Hyundai|Elantra 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)](##)|Hyundai K| |Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Pilot 2016-22">Honda Nidec</a>||
|Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| |Honda|Ridgeline 2017-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Honda&model=Ridgeline 2017-22">Honda Nidec</a>||
|Hyundai|Elantra Hybrid 2021-23|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)](##)|Hyundai K| |Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Elantra 2017-19">Hyundai B</a>||
|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai J| |Hyundai|Elantra 2021-23|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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Elantra 2021-23">Hyundai K</a>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| |Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Elantra GT 2017-19">Hyundai E</a>||
|Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q| |Hyundai|Elantra Hybrid 2021-23|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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Elantra Hybrid 2021-23">Hyundai K</a>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|Ioniq 5 (with HDA II) 2022-23[<sup>5</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q| |Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Genesis 2015-16">Hyundai J</a>||
|Hyundai|Ioniq 5 (without HDA II) 2022-23[<sup>5</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=i30 2017-19">Hyundai E</a>||
|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Ioniq 5 (Southeast Asia only) 2022-23">Hyundai Q</a>||
|Hyundai|Ioniq Electric 2020|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| |Hyundai|Ioniq 5 (with HDA II) 2022-23[<sup>5</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Ioniq 5 (with HDA II) 2022-23">Hyundai Q</a>||
|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Hyundai|Ioniq 5 (without HDA II) 2022-23[<sup>5</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Ioniq 5 (without HDA II) 2022-23">Hyundai K</a>||
|Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| |Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Ioniq Electric 2019">Hyundai C</a>||
|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Hyundai|Ioniq Electric 2020|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Ioniq Electric 2020">Hyundai H</a>||
|Hyundai|Ioniq Plug-in Hybrid 2020-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| |Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Ioniq Hybrid 2017-19">Hyundai C</a>||
|Hyundai|Kona 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)](##)|Hyundai B| |Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Ioniq Hybrid 2020-22">Hyundai H</a>||
|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G| |Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Ioniq Plug-in Hybrid 2019">Hyundai C</a>||
|Hyundai|Kona Electric 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai O| |Hyundai|Ioniq Plug-in Hybrid 2020-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Ioniq Plug-in Hybrid 2020-21">Hyundai H</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)](##)|Hyundai I| |Hyundai|Kona 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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Kona 2020">Hyundai B</a>||
|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)](##)|Hyundai H| |Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Kona Electric 2018-21">Hyundai G</a>||
|Hyundai|Santa Cruz 2021-22[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Hyundai|Kona Electric 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Kona Electric 2022">Hyundai O</a>||
|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)](##)|Hyundai D| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Kona Hybrid 2020">Hyundai I</a>|<a href="https://youtu.be/0dwpAHiZgFo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|Santa Fe 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)](##)|Hyundai L| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Palisade 2020-22">Hyundai H</a>|<a href="https://youtu.be/TAnDqjF4fDY?t=456" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|Santa Fe 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)](##)|Hyundai L| |Hyundai|Santa Cruz 2022-23[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Santa Cruz 2022-23">Hyundai N</a>||
|Hyundai|Santa Fe 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)](##)|Hyundai L| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Santa Fe 2019-20">Hyundai D</a>||
|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)](##)|Hyundai E| |Hyundai|Santa Fe 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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Santa Fe 2021-22">Hyundai L</a>|<a href="https://youtu.be/VnHzSTygTS4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|Sonata 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)](##)|Hyundai A| |Hyundai|Santa Fe 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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Santa Fe Hybrid 2022">Hyundai L</a>||
|Hyundai|Sonata Hybrid 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)](##)|Hyundai A| |Hyundai|Santa Fe 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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Santa Fe Plug-in Hybrid 2022">Hyundai L</a>||
|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)](##)|Hyundai L| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Sonata 2018-19">Hyundai E</a>||
|Hyundai|Tucson 2022[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Sonata 2020-23">Hyundai A</a>|<a href="https://www.youtube.com/watch?v=ix63r9kE3Fw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|Tucson 2023[<sup>5</sup>](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Hyundai|Sonata Hybrid 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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Sonata Hybrid 2020-22">Hyundai A</a>||
|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)](##)|Hyundai L| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Tucson 2021">Hyundai L</a>||
|Hyundai|Tucson Hybrid 2022[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Hyundai|Tucson 2022[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Tucson 2022">Hyundai N</a>||
|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| |Hyundai|Tucson 2023[<sup>5</sup>](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Tucson 2023">Hyundai N</a>||
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Tucson Diesel 2019">Hyundai L</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)](##)|FCA| |Hyundai|Tucson Hybrid 2022[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Tucson Hybrid 2022">Hyundai N</a>||
|Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Hyundai&model=Veloster 2019-20">Hyundai E</a>||
|Kia|EV6 (Southeast Asia only) 2022-23[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai P| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Jeep&model=Grand Cherokee 2016-18">FCA</a>|<a href="https://www.youtube.com/watch?v=eLR9o2JkuRk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Kia|EV6 (with HDA II) 2022[<sup>5</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai P| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Jeep&model=Grand Cherokee 2019-21">FCA</a>|<a href="https://www.youtube.com/watch?v=jBe4lWnRSu4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Kia|EV6 (without HDA II) 2022[<sup>5</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| |Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Ceed 2019">Hyundai E</a>||
|Kia|Forte 2019-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)](##)|Hyundai G| |Kia|EV6 (Southeast Asia only) 2022-23[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=EV6 (Southeast Asia only) 2022-23">Hyundai P</a>||
|Kia|K5 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)](##)|Hyundai A| |Kia|EV6 (with HDA II) 2022[<sup>5</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=EV6 (with HDA II) 2022">Hyundai P</a>||
|Kia|Niro EV 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| |Kia|EV6 (without HDA II) 2022[<sup>5</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=EV6 (without HDA II) 2022">Hyundai L</a>||
|Kia|Niro EV 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F| |Kia|Forte 2019-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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Forte 2019-21">Hyundai G</a>||
|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)](##)|Hyundai C| |Kia|K5 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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=K5 2021-22">Hyundai A</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)](##)|Hyundai H| |Kia|K5 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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=K5 Hybrid 2020">Hyundai A</a>||
|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)](##)|Hyundai F| |Kia|Niro EV 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Niro EV 2019">Hyundai H</a>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|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)](##)|Hyundai H| |Kia|Niro EV 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Niro EV 2020">Hyundai F</a>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Kia|Niro Plug-in Hybrid 2018-19|All|openpilot available[<sup>1</sup>](#footnotes)|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Niro EV 2021">Hyundai C</a>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Niro EV 2022">Hyundai H</a>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|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)](##)|Hyundai G| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Niro Hybrid 2021">Hyundai F</a>||
|Kia|Seltos 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)](##)|Hyundai A| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Niro Hybrid 2022">Hyundai H</a>||
|Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Kia|Niro Hybrid 2023[<sup>5</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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Niro Hybrid 2023">Hyundai A</a>||
|Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| |Kia|Niro Plug-in Hybrid 2018-19|All|openpilot available[<sup>1</sup>](#footnotes)|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Niro Plug-in Hybrid 2018-19">Hyundai C</a>||
|Kia|Sorento Plug-in Hybrid 2022-23[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| |Kia|Niro Plug-in Hybrid 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Niro Plug-in Hybrid 2020">Hyundai D</a>||
|Kia|Sportage 2023[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Optima 2017">Hyundai B</a>||
|Kia|Sportage Hybrid 2023[<sup>5</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)](##)|Hyundai N| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Optima 2019-20">Hyundai G</a>||
|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Kia|Seltos 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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Seltos 2021">Hyundai A</a>||
|Kia|Stinger 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Sorento 2018">Hyundai C</a>|<a href="https://www.youtube.com/watch?v=Fkh3s6WHJz8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Kia|Telluride 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)](##)|Hyundai H| |Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Sorento 2019">Hyundai E</a>|<a href="https://www.youtube.com/watch?v=Fkh3s6WHJz8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|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)](##)|Toyota| |Kia|Sorento 2022-23[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Sorento 2022-23">Hyundai K</a>||
|Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Kia|Sorento Plug-in Hybrid 2022-23[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Sorento Plug-in Hybrid 2022-23">Hyundai A</a>||
|Lexus|ES 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-full.svg)](##)|Toyota| |Kia|Sportage 2023[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Sportage 2023">Hyundai N</a>||
|Lexus|ES Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Kia|Sportage Hybrid 2023[<sup>5</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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Sportage Hybrid 2023">Hyundai N</a>||
|Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Stinger 2018-20">Hyundai C</a>|<a href="https://www.youtube.com/watch?v=MJ94qoofYw0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|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)](##)|Toyota| |Kia|Stinger 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Stinger 2022">Hyundai K</a>||
|Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Kia|Telluride 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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Kia&model=Telluride 2020-22">Hyundai H</a>||
|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)](##)|Toyota| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=CT Hybrid 2017-18">Toyota</a>||
|Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=ES 2019-22">Toyota</a>||
|Lexus|RC 2017-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Lexus|ES 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-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=ES Hybrid 2017-18">Toyota</a>||
|Lexus|RX 2016|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)](##)|Toyota| |Lexus|ES Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=ES Hybrid 2019-23">Toyota</a>|<a href="https://youtu.be/BZ29osRVJeg?t=12" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Lexus|RX 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=IS 2017-19">Toyota</a>||
|Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=NX 2018-19">Toyota</a>||
|Lexus|RX Hybrid 2016|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)](##)|Toyota| |Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=NX 2020-21">Toyota</a>||
|Lexus|RX Hybrid 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=NX Hybrid 2018-19">Toyota</a>||
|Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=NX Hybrid 2020-21">Toyota</a>||
|Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Lexus|RC 2017-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=RC 2017-20">Toyota</a>||
|Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda| |Lexus|RX 2016|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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=RX 2016">Toyota</a>||
|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda| |Lexus|RX 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=RX 2017-19">Toyota</a>||
|Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan B| |Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=RX 2020-22">Toyota</a>||
|Nissan|Leaf 2018-22|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A| |Lexus|RX Hybrid 2016|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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=RX Hybrid 2016">Toyota</a>||
|Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A| |Lexus|RX Hybrid 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=RX Hybrid 2017-19">Toyota</a>||
|Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A| |Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=RX Hybrid 2020-21">Toyota</a>||
|Ram|1500 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Ram| |Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Lexus&model=UX Hybrid 2019-22">Toyota</a>||
|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=MAN&model=eTGE 2020-23">J533</a>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=MAN&model=TGE 2017-23">J533</a>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Mazda&model=CX-5 2022-23">Mazda</a>||
|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Mazda&model=CX-9 2021-23">Mazda</a>|<a href="https://youtu.be/dA3duO4a0O4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Nissan&model=Altima 2019-20">Nissan B</a>||
|Subaru|Forester 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Nissan|Leaf 2018-22|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Nissan&model=Leaf 2018-22">Nissan A</a>|<a href="https://youtu.be/vaMbtAh_0cY" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Subaru|Impreza 2017-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Nissan&model=Rogue 2018-20">Nissan A</a>||
|Subaru|Impreza 2020-22|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Nissan&model=X-Trail 2017">Nissan A</a>||
|Subaru|Legacy 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru B| |Ram|1500 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Ram&model=1500 2019-22">Ram</a>||
|Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru B| |SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=SEAT&model=Ateca 2018">J533</a>||
|Subaru|XV 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=SEAT&model=Leon 2014-20">J533</a>||
|Subaru|XV 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Subaru&model=Ascent 2019-21">Subaru A</a>||
|Škoda|Kamiq 2021[<sup>7</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[<sup>10</sup>](#footnotes)| |Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Subaru&model=Crosstrek 2018-19">Subaru A</a>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Subaru&model=Crosstrek 2020-23">Subaru A</a>||
|Škoda|Kodiaq 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Subaru|Forester 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Subaru&model=Forester 2019-21">Subaru A</a>||
|Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Subaru|Impreza 2017-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Subaru&model=Impreza 2017-19">Subaru A</a>||
|Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Subaru|Impreza 2020-22|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Subaru&model=Impreza 2020-22">Subaru A</a>||
|Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[<sup>10</sup>](#footnotes)| |Subaru|Legacy 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Subaru&model=Legacy 2020-22">Subaru B</a>||
|Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Subaru&model=Outback 2020-22">Subaru B</a>||
|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Subaru|XV 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Subaru&model=XV 2018-19">Subaru A</a>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Subaru|XV 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Subaru&model=XV 2020-21">Subaru A</a>||
|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)](##)|Toyota| |Škoda|Kamiq 2021[<sup>7</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Škoda&model=Kamiq 2021">J533</a>[<sup>10</sup>](#footnotes)||
|Toyota|Avalon 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)](##)|Toyota| |Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Škoda&model=Karoq 2019-21">J533</a>||
|Toyota|Avalon 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)](##)|Toyota| |Škoda|Kodiaq 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Škoda&model=Kodiaq 2018-19">J533</a>||
|Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Škoda&model=Octavia 2015, 2018-19">J533</a>||
|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)](##)|Toyota| |Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Škoda&model=Octavia RS 2016">J533</a>||
|Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Škoda&model=Scala 2020">J533</a>[<sup>10</sup>](#footnotes)||
|Toyota|C-HR 2017-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Škoda&model=Superb 2015-22">J533</a>||
|Toyota|C-HR Hybrid 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Alphard 2019-20">Toyota</a>||
|Toyota|Camry 2018-20|All|Stock|0 mph[<sup>6</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Alphard Hybrid 2021">Toyota</a>||
|Toyota|Camry 2021-22|All|openpilot|0 mph[<sup>6</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Avalon 2016">Toyota</a>||
|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Avalon 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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Avalon 2017-18">Toyota</a>||
|Toyota|Camry Hybrid 2021-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Avalon 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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Avalon 2019-21">Toyota</a>||
|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)](##)|Toyota| |Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Avalon 2022">Toyota</a>||
|Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Avalon Hybrid 2019-21">Toyota</a>||
|Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Avalon Hybrid 2022">Toyota</a>||
|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|C-HR 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=C-HR 2017-20">Toyota</a>||
|Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|C-HR 2021|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=C-HR 2021">Toyota</a>||
|Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=C-HR Hybrid 2017-20">Toyota</a>||
|Toyota|Highlander 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|C-HR Hybrid 2021-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=C-HR Hybrid 2021-22">Toyota</a>||
|Toyota|Highlander 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Camry 2018-20|All|Stock|0 mph[<sup>6</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Camry 2018-20">Toyota</a>|<a href="https://www.youtube.com/watch?v=fkcjviZY9CM" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|Highlander Hybrid 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Camry 2021-22|All|openpilot|0 mph[<sup>6</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Camry 2021-22">Toyota</a>||
|Toyota|Highlander Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Camry Hybrid 2018-20">Toyota</a>|<a href="https://www.youtube.com/watch?v=Q2DYY0AWKgk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Camry Hybrid 2021-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Camry Hybrid 2021-23">Toyota</a>||
|Toyota|Prius 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-empty.svg)](##)|Toyota| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Corolla 2017-19">Toyota</a>||
|Toyota|Prius 2017-20|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Corolla 2020-22">Toyota</a>|<a href="https://www.youtube.com/watch?v=_66pXk0CBYA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Corolla Cross (Non-US only) 2020-23">Toyota</a>||
|Toyota|Prius Prime 2017-20|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Corolla Cross Hybrid (Non-US only) 2020-22">Toyota</a>||
|Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Corolla Hatchback 2019-22">Toyota</a>|<a href="https://www.youtube.com/watch?v=_66pXk0CBYA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Corolla Hybrid 2020-22">Toyota</a>||
|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)](##)|Toyota| |Toyota|Corolla Hybrid (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Corolla Hybrid (Non-US only) 2020-23">Toyota</a>||
|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)](##)|Toyota| |Toyota|Highlander 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Highlander 2017-19">Toyota</a>|<a href="https://www.youtube.com/watch?v=0wS0wXSLzoo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Highlander 2020-23">Toyota</a>||
|Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Highlander Hybrid 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Highlander Hybrid 2017-19">Toyota</a>||
|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)](##)|Toyota| |Toyota|Highlander Hybrid 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Highlander Hybrid 2020-23">Toyota</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)](##)|Toyota| |Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Mirai 2021">Toyota</a>||
|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Prius 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-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Prius 2016">Toyota</a>|<a href="https://www.youtube.com/watch?v=8zopPJI8XQ0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Prius 2017-20|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Prius 2017-20">Toyota</a>|<a href="https://www.youtube.com/watch?v=8zopPJI8XQ0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|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)](##)|Toyota| |Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Prius 2021-22">Toyota</a>|<a href="https://www.youtube.com/watch?v=J58TvCpUd4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Arteon 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Toyota|Prius Prime 2017-20|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Prius Prime 2017-20">Toyota</a>|<a href="https://www.youtube.com/watch?v=8zopPJI8XQ0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Arteon eHybrid 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Prius Prime 2021-22">Toyota</a>|<a href="https://www.youtube.com/watch?v=J58TvCpUd4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Prius v 2017">Toyota</a>||
|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=RAV4 2016">Toyota</a>||
|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=RAV4 2017-18">Toyota</a>||
|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=RAV4 2019-21">Toyota</a>|<a href="https://www.youtube.com/watch?v=wJxjDd42gGA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=RAV4 2022">Toyota</a>||
|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=RAV4 Hybrid 2016">Toyota</a>|<a href="https://youtu.be/LhT5VzJVfNI?t=26" 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,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=RAV4 Hybrid 2017-18">Toyota</a>|<a href="https://youtu.be/LhT5VzJVfNI?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=RAV4 Hybrid 2019-21">Toyota</a>||
|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=RAV4 Hybrid 2022">Toyota</a>|<a href="https://youtu.be/U0nH9cnrFB0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |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)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Toyota&model=Sienna 2018-20">Toyota</a>|<a href="https://www.youtube.com/watch?v=q1UPOo4Sh68" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Volkswagen|Arteon 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Arteon 2018-22">J533</a>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Volkswagen|Arteon eHybrid 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Arteon eHybrid 2020-22">J533</a>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Arteon R 2020-22">J533</a>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Atlas 2018-23">J533</a>||
|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Atlas Cross Sport 2021-22">J533</a>||
|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=California 2021">J533</a>||
|Volkswagen|Passat 2015-22[<sup>8</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Caravelle 2020">J533</a>||
|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=CC 2018-22">J533</a>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Crafter 2017-23">J533</a>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Polo 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[<sup>10</sup>](#footnotes)| |Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=e-Crafter 2018-23">J533</a>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Polo GTI 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[<sup>10</sup>](#footnotes)| |Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=e-Golf 2014-20">J533</a>||
|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[<sup>10</sup>](#footnotes)| |Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Golf 2015-20">J533</a>||
|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[<sup>10</sup>](#footnotes)| |Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Golf Alltrack 2015-19">J533</a>||
|Volkswagen|Taos 2022|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Golf GTD 2015-20">J533</a>||
|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Golf GTE 2015-20">J533</a>||
|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Golf GTI 2015-21">J533</a>||
|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Golf R 2015-19">J533</a>||
|Volkswagen|Tiguan 2019-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Golf SportsVan 2015-20">J533</a>||
|Volkswagen|Touran 2017|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Grand California 2019-23">J533</a>|<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,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Jetta 2018-22">J533</a>||
|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Jetta GLI 2021-22">J533</a>||
|Volkswagen|Passat 2015-22[<sup>8</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Passat 2015-22">J533</a>||
|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Passat Alltrack 2015-22">J533</a>||
|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Passat GTE 2015-22">J533</a>||
|Volkswagen|Polo 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Polo 2020-22">J533</a>[<sup>10</sup>](#footnotes)||
|Volkswagen|Polo GTI 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Polo GTI 2020-22">J533</a>[<sup>10</sup>](#footnotes)||
|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=T-Cross 2021">J533</a>[<sup>10</sup>](#footnotes)||
|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=T-Roc 2021">J533</a>[<sup>10</sup>](#footnotes)||
|Volkswagen|Taos 2022|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Taos 2022">J533</a>||
|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Teramont 2018-22">J533</a>||
|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Teramont Cross Sport 2021-22">J533</a>||
|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Teramont X 2021-22">J533</a>||
|Volkswagen|Tiguan 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Tiguan 2018-23">J533</a>||
|Volkswagen|Touran 2017|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<a href="https://comma.ai/shop/comma-three.html?make=Volkswagen&model=Touran 2017">J533</a>||
<a id="footnotes"></a> <a id="footnotes"></a>
<sup>1</sup>Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`. <br /> <sup>1</sup>Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`. <br />
<sup>2</sup>By default, this car will use the stock Adaptive Cruise Control (ACC) for longitudinal control. If the Driver Support Unit (DSU) is disconnected, openpilot ACC will replace stock ACC. <b><i>NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).</i></b> <br /> <sup>2</sup>By default, this car will use the stock Adaptive Cruise Control (ACC) for longitudinal control. If the Driver Support Unit (DSU) is disconnected, openpilot ACC will replace stock ACC. <b><i>NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).</i></b> <br />
<sup>3</sup>Requires a <a href="https://github.com/commaai/openpilot/wiki/GM#hardware">community built ASCM harness</a>. <b><i>NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).</i></b> <br /> <sup>3</sup>Requires a <a href="https://github.com/commaai/openpilot/wiki/GM#hardware" target="_blank">community built ASCM harness</a>. <b><i>NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).</i></b> <br />
<sup>4</sup>2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph. <br /> <sup>4</sup>2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph. <br />
<sup>5</sup>Requires a <a href="https://comma.ai/shop/panda" target="_blank">red panda</a>, additional <a href="https://comma.ai/shop/harness-box" target="_blank">harness box</a>, additional <a href="https://comma.ai/shop/obd-c-cable" target="_blank">OBD-C cable</a>, USB-A to USB-A cable, and a USB-A to USB-C OTG dongle. <br /> <sup>5</sup>Requires a <a href="https://comma.ai/shop/panda" target="_blank">red panda</a> for this <a href="https://en.wikipedia.org/wiki/CAN_FD" target="_blank">CAN FD car</a>. All the hardware needed is sold in the <a href="https://comma.ai/shop/can-fd-panda-kit" target="_blank">CAN FD kit</a>. <br />
<sup>6</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>6</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>7</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br /> <sup>7</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br />
<sup>8</sup>Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets. <br /> <sup>8</sup>Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets. <br />

@ -41,7 +41,7 @@ clean:
@echo "Building rst files..." @echo "Building rst files..."
sphinx-apidoc -o "$(DOCSBUILDDIR)" ../ \ sphinx-apidoc -o "$(DOCSBUILDDIR)" ../ \
../xx ../laika_repo ../rednose_repo ../pyextra ../notebooks ../panda_jungle \ ../xx ../laika_repo ../rednose_repo ../notebooks ../panda_jungle \
../third_party \ ../third_party \
../panda/examples \ ../panda/examples \
../scripts \ ../scripts \

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="500.972 178.81 20 14.375" width="20" height="14.375" xmlns="http://www.w3.org/2000/svg" xmlns:bx="https://boxy-svg.com">
<defs>
<clipPath id="clip0_1674_1768">
<rect width="20" height="20" fill="white"/>
</clipPath>
</defs>
<g clip-path="url(#clip0_1674_1768)" transform="matrix(1, 0, 0, 1, 500.971771, 175.81041)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.582 5.2447C19.352 4.3611 18.6743 3.66531 17.8138 3.42916C16.2542 3 10 3 10 3C10 3 3.7458 3 2.18614 3.42916C1.32557 3.66531 0.647841 4.3611 0.417841 5.2447C0 6.84612 0 10.1875 0 10.1875C0 10.1875 0 13.5288 0.417841 15.1303C0.647841 16.0139 1.32557 16.7097 2.18614 16.946C3.7458 17.375 10 17.375 10 17.375C10 17.375 16.2542 17.375 17.8138 16.946C18.6743 16.7097 19.352 16.0139 19.582 15.1303C20 13.5288 20 10.1875 20 10.1875C20 10.1875 20 6.84612 19.582 5.2447ZM8.12509 13.6255V7.37549L13.1251 10.5006L8.12509 13.6255Z" fill="#FF0000"/>
</g>
<path d="M 425.503 122.113 L 428.63 127.117 L 422.376 127.117 L 425.503 122.113 Z" style="stroke: rgb(0, 0, 0); stroke-width: 0px; fill: rgb(255, 255, 255);" transform="matrix(0, 1, -1, 0, 636.212463, -239.192383)" bx:shape="triangle 422.376 122.113 6.254 5.004 0.5 0 1@278e08c4"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -11,7 +11,6 @@ WORKDIR ${OPENPILOT_PATH}
COPY SConstruct ${OPENPILOT_PATH} COPY SConstruct ${OPENPILOT_PATH}
COPY ./pyextra ${OPENPILOT_PATH}/pyextra
COPY ./third_party ${OPENPILOT_PATH}/third_party COPY ./third_party ${OPENPILOT_PATH}/third_party
COPY ./site_scons ${OPENPILOT_PATH}/site_scons COPY ./site_scons ${OPENPILOT_PATH}/site_scons
COPY ./laika ${OPENPILOT_PATH}/laika COPY ./laika ${OPENPILOT_PATH}/laika

@ -77,3 +77,4 @@ tools
Simulator <tools/sim/README.md> Simulator <tools/sim/README.md>
tools/ssh/README.md tools/ssh/README.md
Webcam <tools/webcam/README.md> Webcam <tools/webcam/README.md>
tools/cabana/README.md

@ -1 +1 @@
Subproject commit e1049cde0a68f7d4a70b1ebd76befdc0e163ad55 Subproject commit b740b71c82a748e3520b1599487d9a7aaf728670

@ -74,7 +74,7 @@ function launch {
# handle pythonpath # handle pythonpath
ln -sfn $(pwd) /data/pythonpath ln -sfn $(pwd) /data/pythonpath
export PYTHONPATH="$PWD:$PWD/pyextra" export PYTHONPATH="$PWD"
# hardware specific init # hardware specific init
agnos_init agnos_init

@ -1,19 +0,0 @@
path_classifiers:
library:
- external
- third_party
- pyextra
- tools/lib/mkvparse
extraction:
cpp:
after_prepare:
- "pip3 install --upgrade --user pkgconfig cython setuptools wheel"
- "pip3 install --upgrade --user jinja2 pyyaml cython pycapnp numpy sympy tqdm\
\ cffi logentries zmq scons"
- "export PATH=/opt/work/.local/bin:$PATH"
index:
build_command: "scons"
javascript:
index:
filters:
- exclude: "*"

@ -2,7 +2,7 @@
python_version = 3.8 python_version = 3.8
plugins = numpy.typing.mypy_plugin plugins = numpy.typing.mypy_plugin
files = body, common, docs, scripts, selfdrive, site_scons, system, tools files = body, common, docs, scripts, selfdrive, site_scons, system, tools
exclude = ^(pyextra/)|(cereal/)|(opendbc/)|(panda/)|(laika/)|(laika_repo/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(xx/) exclude = ^(cereal/)|(opendbc/)|(panda/)|(laika/)|(laika_repo/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(xx/)
; third-party packages ; third-party packages
ignore_missing_imports = True ignore_missing_imports = True

@ -1 +1 @@
Subproject commit 4a7ad636ff806146a93f7ae541e463a7dfa5696d Subproject commit 510bfc06954e31257f8d8de17adf92f9a68a1b71

@ -1 +1 @@
Subproject commit 5bd4c1dfd91991777ba3a3bd7444165afed3f09b Subproject commit 78b76e5463f8bd6077f100d84c44ce6b6b047c27

337
poetry.lock generated

@ -80,6 +80,14 @@ develop = ["imgaug (>=0.4.0)", "pytest"]
imgaug = ["imgaug (>=0.4.0)"] imgaug = ["imgaug (>=0.4.0)"]
tests = ["pytest"] tests = ["pytest"]
[[package]]
name = "antlr4-python3-runtime"
version = "4.9.3"
description = "ANTLR 4.9.3 runtime for Python 3.7"
category = "dev"
optional = false
python-versions = "*"
[[package]] [[package]]
name = "anyio" name = "anyio"
version = "3.6.2" version = "3.6.2"
@ -556,6 +564,34 @@ python-versions = ">=3.7"
[package.dependencies] [package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""} colorama = {version = "*", markers = "platform_system == \"Windows\""}
[[package]]
name = "click-plugins"
version = "1.1.1"
description = "An extension module for click to enable registering CLI commands via setuptools entry-points."
category = "dev"
optional = false
python-versions = "*"
[package.dependencies]
click = ">=4.0"
[package.extras]
dev = ["coveralls", "pytest (>=3.6)", "pytest-cov", "wheel"]
[[package]]
name = "cligj"
version = "0.7.2"
description = "Click params for commmand line interfaces to GeoJSON"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, <4"
[package.dependencies]
click = ">=4.0"
[package.extras]
test = ["pytest-cov"]
[[package]] [[package]]
name = "cloudpickle" name = "cloudpickle"
version = "2.2.0" version = "2.2.0"
@ -951,6 +987,29 @@ python-versions = ">=3.7"
docs = ["furo (>=2022.6.21)", "sphinx (>=5.1.1)", "sphinx-autodoc-typehints (>=1.19.1)"] docs = ["furo (>=2022.6.21)", "sphinx (>=5.1.1)", "sphinx-autodoc-typehints (>=1.19.1)"]
testing = ["covdefaults (>=2.2)", "coverage (>=6.4.2)", "pytest (>=7.1.2)", "pytest-cov (>=3)", "pytest-timeout (>=2.1)"] testing = ["covdefaults (>=2.2)", "coverage (>=6.4.2)", "pytest (>=7.1.2)", "pytest-cov (>=3)", "pytest-timeout (>=2.1)"]
[[package]]
name = "fiona"
version = "1.9.1"
description = "Fiona reads and writes spatial data files"
category = "dev"
optional = false
python-versions = ">=3.7"
[package.dependencies]
attrs = ">=19.2.0"
certifi = "*"
click = ">=8.0,<9.0"
click-plugins = ">=1.0"
cligj = ">=0.5"
munch = ">=2.3.2"
setuptools = "*"
[package.extras]
all = ["Fiona[calc,s3,test]"]
calc = ["shapely"]
s3 = ["boto3 (>=1.3.1)"]
test = ["Fiona[s3]", "pytest (>=7)", "pytest-cov", "pytz"]
[[package]] [[package]]
name = "flake8" name = "flake8"
version = "4.0.1" version = "4.0.1"
@ -1084,6 +1143,21 @@ python-versions = ">=3.7"
packaging = "*" packaging = "*"
SQLAlchemy = ">=1.4" SQLAlchemy = ">=1.4"
[[package]]
name = "geopandas"
version = "0.12.2"
description = "Geographic pandas extensions"
category = "dev"
optional = false
python-versions = ">=3.8"
[package.dependencies]
fiona = ">=1.8"
packaging = "*"
pandas = ">=1.0.0"
pyproj = ">=2.6.1.post1"
shapely = ">=1.7"
[[package]] [[package]]
name = "gevent" name = "gevent"
version = "22.10.1" version = "22.10.1"
@ -1352,6 +1426,14 @@ category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
[[package]]
name = "ioctl-opt"
version = "1.2.2"
description = "Functions to compute fnctl.ioctl's opt argument"
category = "main"
optional = false
python-versions = "*"
[[package]] [[package]]
name = "ipykernel" name = "ipykernel"
version = "6.16.1" version = "6.16.1"
@ -2309,27 +2391,18 @@ python-versions = ">=3.5"
[[package]] [[package]]
name = "networkx" name = "networkx"
version = "2.3" version = "2.8.8"
description = "Python package for creating and manipulating graphs and networks" description = "Python package for creating and manipulating graphs and networks"
category = "dev" category = "dev"
optional = false optional = false
python-versions = ">=3.5" python-versions = ">=3.8"
[package.dependencies]
decorator = ">=4.3.0"
[package.extras] [package.extras]
all = ["gdal", "lxml", "matplotlib", "nose", "numpy", "pandas", "pydot", "pygraphviz", "pyyaml", "scipy"] default = ["matplotlib (>=3.4)", "numpy (>=1.19)", "pandas (>=1.3)", "scipy (>=1.8)"]
gdal = ["gdal"] developer = ["mypy (>=0.982)", "pre-commit (>=2.20)"]
lxml = ["lxml"] doc = ["nb2plots (>=0.6)", "numpydoc (>=1.5)", "pillow (>=9.2)", "pydata-sphinx-theme (>=0.11)", "sphinx (>=5.2)", "sphinx-gallery (>=0.11)", "texext (>=0.6.6)"]
matplotlib = ["matplotlib"] extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.9)", "sympy (>=1.10)"]
nose = ["nose"] test = ["codecov (>=2.1)", "pytest (>=7.2)", "pytest-cov (>=4.0)"]
numpy = ["numpy"]
pandas = ["pandas"]
pydot = ["pydot"]
pygraphviz = ["pygraphviz"]
pyyaml = ["pyyaml"]
scipy = ["scipy"]
[[package]] [[package]]
name = "nodeenv" name = "nodeenv"
@ -2423,6 +2496,18 @@ rsa = ["cryptography (>=3.0.0)"]
signals = ["blinker (>=1.4.0)"] signals = ["blinker (>=1.4.0)"]
signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"]
[[package]]
name = "omegaconf"
version = "2.3.0"
description = "A flexible configuration library"
category = "dev"
optional = false
python-versions = ">=3.6"
[package.dependencies]
antlr4-python3-runtime = ">=4.9.0,<4.10.0"
PyYAML = ">=5.1.0"
[[package]] [[package]]
name = "onnx" name = "onnx"
version = "1.12.0" version = "1.12.0"
@ -2514,6 +2599,31 @@ python-versions = ">=3.6"
[package.dependencies] [package.dependencies]
requests = "*" requests = "*"
[[package]]
name = "osmnx"
version = "1.2.2"
description = "Retrieve, model, analyze, and visualize OpenStreetMap street networks and other spatial data"
category = "dev"
optional = false
python-versions = ">=3.8"
[package.dependencies]
geopandas = ">=0.11"
matplotlib = ">=3.5"
networkx = ">=2.8"
numpy = ">=1.22"
pandas = ">=1.4"
pyproj = ">=3.3"
requests = ">=2.28"
Rtree = ">=1.0"
Shapely = ">=1.8,<2.0"
[package.extras]
entropy = ["scipy"]
nearest-neighbor = ["scikit-learn", "scipy"]
raster = ["gdal", "rasterio"]
web-map = ["folium"]
[[package]] [[package]]
name = "packaging" name = "packaging"
version = "21.3" version = "21.3"
@ -3458,6 +3568,14 @@ python-versions = "*"
numpy = ">=1.11.0" numpy = ">=1.11.0"
scipy = ">=0.17.1" scipy = ">=0.17.1"
[[package]]
name = "rtree"
version = "1.0.1"
description = "R-Tree spatial index for Python GIS"
category = "dev"
optional = false
python-versions = ">=3.7"
[[package]] [[package]]
name = "s2sphere" name = "s2sphere"
version = "0.2.5" version = "0.2.5"
@ -3660,6 +3778,19 @@ typing-extensions = "*"
test = ["pytest (>=6.2)", "virtualenv (>20)"] test = ["pytest (>=6.2)", "virtualenv (>20)"]
toml = ["setuptools (>=42)"] toml = ["setuptools (>=42)"]
[[package]]
name = "shapely"
version = "1.8.5.post1"
description = "Geometric objects, predicates, and operations"
category = "dev"
optional = false
python-versions = ">=3.6"
[package.extras]
all = ["numpy", "pytest", "pytest-cov"]
test = ["pytest", "pytest-cov"]
vectorized = ["numpy"]
[[package]] [[package]]
name = "shellingham" name = "shellingham"
version = "1.5.0" version = "1.5.0"
@ -3881,6 +4012,17 @@ category = "main"
optional = false optional = false
python-versions = "*" python-versions = "*"
[[package]]
name = "spidev2"
version = "0.9.0"
description = "Pure-python interface to Linux spidev."
category = "main"
optional = false
python-versions = "*"
[package.dependencies]
ioctl-opt = "*"
[[package]] [[package]]
name = "sqlalchemy" name = "sqlalchemy"
version = "1.4.42" version = "1.4.42"
@ -4425,7 +4567,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "~3.8" python-versions = "~3.8"
content-hash = "d894380c87f5558e032708cc1230aed172ad3e1db9aa112e2e105bebefff4e20" content-hash = "9e9495c896e6fd0855803aeaf46513c6c22424b86be820759a8baf27d44e73ee"
[metadata.files] [metadata.files]
adal = [ adal = [
@ -4538,6 +4680,9 @@ albumentations = [
{file = "albumentations-1.3.0-py3-none-any.whl", hash = "sha256:294165d87d03bc8323e484927f0a5c1a3c64b0e7b9c32a979582a6c93c363bdf"}, {file = "albumentations-1.3.0-py3-none-any.whl", hash = "sha256:294165d87d03bc8323e484927f0a5c1a3c64b0e7b9c32a979582a6c93c363bdf"},
{file = "albumentations-1.3.0.tar.gz", hash = "sha256:be1af36832c8893314f2a5550e8ac19801e04770734c1b70fa3c996b41f37bed"}, {file = "albumentations-1.3.0.tar.gz", hash = "sha256:be1af36832c8893314f2a5550e8ac19801e04770734c1b70fa3c996b41f37bed"},
] ]
antlr4-python3-runtime = [
{file = "antlr4-python3-runtime-4.9.3.tar.gz", hash = "sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b"},
]
anyio = [ anyio = [
{file = "anyio-3.6.2-py3-none-any.whl", hash = "sha256:fbbe32bd270d2a2ef3ed1c5d45041250284e31fc0a4df4a5a6071842051a51e3"}, {file = "anyio-3.6.2-py3-none-any.whl", hash = "sha256:fbbe32bd270d2a2ef3ed1c5d45041250284e31fc0a4df4a5a6071842051a51e3"},
{file = "anyio-3.6.2.tar.gz", hash = "sha256:25ea0d673ae30af41a0c442f81cf3b38c7e79fdc7b60335a4c14e05eb0947421"}, {file = "anyio-3.6.2.tar.gz", hash = "sha256:25ea0d673ae30af41a0c442f81cf3b38c7e79fdc7b60335a4c14e05eb0947421"},
@ -4875,6 +5020,14 @@ click = [
{file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
{file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
] ]
click-plugins = [
{file = "click-plugins-1.1.1.tar.gz", hash = "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b"},
{file = "click_plugins-1.1.1-py2.py3-none-any.whl", hash = "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8"},
]
cligj = [
{file = "cligj-0.7.2-py3-none-any.whl", hash = "sha256:c1ca117dbce1fe20a5809dc96f01e1c2840f6dcc939b3ddbb1111bf330ba82df"},
{file = "cligj-0.7.2.tar.gz", hash = "sha256:a4bc13d623356b373c2c27c53dbd9c68cae5d526270bfa71f6c6fa69669c6b27"},
]
cloudpickle = [ cloudpickle = [
{file = "cloudpickle-2.2.0-py3-none-any.whl", hash = "sha256:7428798d5926d8fcbfd092d18d01a2a03daf8237d8fcdc8095d256b8490796f0"}, {file = "cloudpickle-2.2.0-py3-none-any.whl", hash = "sha256:7428798d5926d8fcbfd092d18d01a2a03daf8237d8fcdc8095d256b8490796f0"},
{file = "cloudpickle-2.2.0.tar.gz", hash = "sha256:3f4219469c55453cfe4737e564b67c2a149109dabf7f242478948b895f61106f"}, {file = "cloudpickle-2.2.0.tar.gz", hash = "sha256:3f4219469c55453cfe4737e564b67c2a149109dabf7f242478948b895f61106f"},
@ -5297,6 +5450,28 @@ filelock = [
{file = "filelock-3.8.0-py3-none-any.whl", hash = "sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4"}, {file = "filelock-3.8.0-py3-none-any.whl", hash = "sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4"},
{file = "filelock-3.8.0.tar.gz", hash = "sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc"}, {file = "filelock-3.8.0.tar.gz", hash = "sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc"},
] ]
fiona = [
{file = "Fiona-1.9.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:902b67b2d012c5797b5d7d3cb3b46dcf9a342cf90a7f7e53fb12c83738d19926"},
{file = "Fiona-1.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e2f4535ae2c8446e6b328745a44567478d5a077ed63c888b8c212dddb1e11925"},
{file = "Fiona-1.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3d7f3286fb59b93cefefb89014b6fa8413126e180e15c576db859ba936cf334"},
{file = "Fiona-1.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:692fe64c0f3a39742d6f7a8e420a8387f6aec3b6818b727d2dfc98a0c40e992d"},
{file = "Fiona-1.9.1-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:a017a39650df0cc541c57cf7de450bb4cee6fd9760eb716323b594c1074634a2"},
{file = "Fiona-1.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c3b52d49bc379fdcfd1250b38e7e00ab24ee14eb765376c793bbe251ffd09d6a"},
{file = "Fiona-1.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5dbb0ae851cd4417104c469335a01f938251a8639317f93d422c5c808150bd27"},
{file = "Fiona-1.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:4a6d8fcbbdafa8af8ac1904628b0267382ed9f9921933d061d7bfc5d3f3daf99"},
{file = "Fiona-1.9.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:74f056a84dc52a0b21a2cf024601a69105596f06f28d40b45049948be17b4df2"},
{file = "Fiona-1.9.1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:5b9f3f6c782bb4ae2c924eefd373cabdeaaa99f86477b9c7c71eb20c052ee7c5"},
{file = "Fiona-1.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:5d6183189a7e05e2498d38a1df3ab07e1353fa48e977cbc3a31203927bd06bca"},
{file = "Fiona-1.9.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:5f2c14beec98a330aee1fd81fa0447a6aa1d5e0a75d000c0052dbe1f23dd6cfd"},
{file = "Fiona-1.9.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:585a47ec21f2d198abc112158eaf12a6587a272beb7f001162d8c3b262676666"},
{file = "Fiona-1.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4368b4054f21518a19dea54ce9ac445c40418c6331c0c99d1531c3ddff05da"},
{file = "Fiona-1.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:839ed0db23198bb754f0d655d4eeaf5f9c141bef734557e77e95e4dc83e42e7f"},
{file = "Fiona-1.9.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:decca3956032ae2d2c19d2f7fa8a4553c43a6e66eb5abe9a05f6ddadcb1bfe5c"},
{file = "Fiona-1.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cb827fa0030d03d8080723137c74b865ec18dbade87c02ed60215491a315c6be"},
{file = "Fiona-1.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7e0f36484757baa8cd1c0602941e029ff992282776f9afae4c5b90f501ff005"},
{file = "Fiona-1.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:f98933b552adf0506799097934a6950de412288e7a50466144d04874d6f63fbc"},
{file = "Fiona-1.9.1.tar.gz", hash = "sha256:3a3725e94840a387fef48726d60db6a6791563f366939d22378a4661f8941be7"},
]
flake8 = [ flake8 = [
{file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"},
{file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"},
@ -5421,6 +5596,10 @@ geoalchemy2 = [
{file = "GeoAlchemy2-0.12.5-py2.py3-none-any.whl", hash = "sha256:3a59eb651df95b3dfee8e1d82f4d18c80b75f712860a0a3080defc6b0435070d"}, {file = "GeoAlchemy2-0.12.5-py2.py3-none-any.whl", hash = "sha256:3a59eb651df95b3dfee8e1d82f4d18c80b75f712860a0a3080defc6b0435070d"},
{file = "GeoAlchemy2-0.12.5.tar.gz", hash = "sha256:31c2502dce317b57b335e4eb87562d501fa39e46c728be514d9b86091e08dd67"}, {file = "GeoAlchemy2-0.12.5.tar.gz", hash = "sha256:31c2502dce317b57b335e4eb87562d501fa39e46c728be514d9b86091e08dd67"},
] ]
geopandas = [
{file = "geopandas-0.12.2-py3-none-any.whl", hash = "sha256:0a470e4bf6f5367e6fd83ab6b40405e0b805c8174665bbcb7c4077ed90202912"},
{file = "geopandas-0.12.2.tar.gz", hash = "sha256:0acdacddefa176525e4da6d9aeeece225da26055c4becdc6e97cf40fa97c27f4"},
]
gevent = [ gevent = [
{file = "gevent-22.10.1-cp27-cp27m-win32.whl", hash = "sha256:702a51b8f21bad1976b0893f90ade466e8c27039b846b611ad2beb8c6e6ac701"}, {file = "gevent-22.10.1-cp27-cp27m-win32.whl", hash = "sha256:702a51b8f21bad1976b0893f90ade466e8c27039b846b611ad2beb8c6e6ac701"},
{file = "gevent-22.10.1-cp27-cp27m-win_amd64.whl", hash = "sha256:af7baec79a5f8ad1cc132d3b14edd12661c628d8094e501b089b1fe2d3df7f6e"}, {file = "gevent-22.10.1-cp27-cp27m-win_amd64.whl", hash = "sha256:af7baec79a5f8ad1cc132d3b14edd12661c628d8094e501b089b1fe2d3df7f6e"},
@ -5624,6 +5803,9 @@ inputs = [
{file = "inputs-0.5-py2.py3-none-any.whl", hash = "sha256:13f894564e52134cf1e3862b1811da034875eb1f2b62e6021e3776e9669a96ec"}, {file = "inputs-0.5-py2.py3-none-any.whl", hash = "sha256:13f894564e52134cf1e3862b1811da034875eb1f2b62e6021e3776e9669a96ec"},
{file = "inputs-0.5.tar.gz", hash = "sha256:a31d5b96a3525f1232f326be9e7ce8ccaf873c6b1fb84d9f3c9bc3d79b23eae4"}, {file = "inputs-0.5.tar.gz", hash = "sha256:a31d5b96a3525f1232f326be9e7ce8ccaf873c6b1fb84d9f3c9bc3d79b23eae4"},
] ]
ioctl-opt = [
{file = "ioctl-opt-1.2.2.tar.gz", hash = "sha256:9628bbd6728f90d019759f54d20b741ddbf9f8db8d41976da4332492f669d643"},
]
ipykernel = [ ipykernel = [
{file = "ipykernel-6.16.1-py3-none-any.whl", hash = "sha256:32eb7bdc5af57185e9a42b0dcef66413ef91a0490b378eae46cbdf0d4e0b5912"}, {file = "ipykernel-6.16.1-py3-none-any.whl", hash = "sha256:32eb7bdc5af57185e9a42b0dcef66413ef91a0490b378eae46cbdf0d4e0b5912"},
{file = "ipykernel-6.16.1.tar.gz", hash = "sha256:3a27a550c1d682e7825f0f7732b0142b79ef1b21cd2e713cacac0c9847535f13"}, {file = "ipykernel-6.16.1.tar.gz", hash = "sha256:3a27a550c1d682e7825f0f7732b0142b79ef1b21cd2e713cacac0c9847535f13"},
@ -6348,7 +6530,8 @@ nest-asyncio = [
{file = "nest_asyncio-1.5.6.tar.gz", hash = "sha256:d267cc1ff794403f7df692964d1d2a3fa9418ffea2a3f6859a439ff482fef290"}, {file = "nest_asyncio-1.5.6.tar.gz", hash = "sha256:d267cc1ff794403f7df692964d1d2a3fa9418ffea2a3f6859a439ff482fef290"},
] ]
networkx = [ networkx = [
{file = "networkx-2.3.zip", hash = "sha256:8311ddef63cf5c5c5e7c1d0212dd141d9a1fe3f474915281b73597ed5f1d4e3d"}, {file = "networkx-2.8.8-py3-none-any.whl", hash = "sha256:e435dfa75b1d7195c7b8378c3859f0445cd88c6b0375c181ed66823a9ceb7524"},
{file = "networkx-2.8.8.tar.gz", hash = "sha256:230d388117af870fce5647a3c52401fcf753e94720e6ea6b4197a5355648885e"},
] ]
nodeenv = [ nodeenv = [
{file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"},
@ -6404,6 +6587,10 @@ oauthlib = [
{file = "oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"}, {file = "oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"},
{file = "oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918"}, {file = "oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918"},
] ]
omegaconf = [
{file = "omegaconf-2.3.0-py3-none-any.whl", hash = "sha256:7b4df175cdb08ba400f45cae3bdcae7ba8365db4d165fc65fd04b050ab63b46b"},
{file = "omegaconf-2.3.0.tar.gz", hash = "sha256:d5d4b6d29955cc50ad50c46dc269bcd92c6e00f5f90d23ab5fee7bfca4ba4cc7"},
]
onnx = [ onnx = [
{file = "onnx-1.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:bdbd2578424c70836f4d0f9dda16c21868ddb07cc8192f9e8a176908b43d694b"}, {file = "onnx-1.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:bdbd2578424c70836f4d0f9dda16c21868ddb07cc8192f9e8a176908b43d694b"},
{file = "onnx-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213e73610173f6b2e99f99a4b0636f80b379c417312079d603806e48ada4ca8b"}, {file = "onnx-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213e73610173f6b2e99f99a4b0636f80b379c417312079d603806e48ada4ca8b"},
@ -6429,6 +6616,7 @@ onnx = [
] ]
onnx2torch = [ onnx2torch = [
{file = "onnx2torch-1.5.4-py3-none-any.whl", hash = "sha256:fd1a0fe05072bfb9f3d86d9330299b130b41f11bd4ae634db17078974e711725"}, {file = "onnx2torch-1.5.4-py3-none-any.whl", hash = "sha256:fd1a0fe05072bfb9f3d86d9330299b130b41f11bd4ae634db17078974e711725"},
{file = "onnx2torch-1.5.4.tar.gz", hash = "sha256:df837b557a63540223d85fde4a1d679fde0ca8d8bb89d5379c030b01eddc9c24"},
] ]
onnxoptimizer = [ onnxoptimizer = [
{file = "onnxoptimizer-0.3.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:e73a5e2e3ca4db9bff54f7131768749c861677b97ee811a136fcf1a52783cf6e"}, {file = "onnxoptimizer-0.3.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:e73a5e2e3ca4db9bff54f7131768749c861677b97ee811a136fcf1a52783cf6e"},
@ -6471,6 +6659,10 @@ osmium = [
{file = "osmium-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e45b7c54ac756e9cb40e2ba68691df635804eb6aa2023088af66936a9c8e3782"}, {file = "osmium-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e45b7c54ac756e9cb40e2ba68691df635804eb6aa2023088af66936a9c8e3782"},
{file = "osmium-3.4.1.tar.gz", hash = "sha256:575dad72ab169cf585b9aeefb4f5f99ac250bf7da1986992afcbf169dc70c381"}, {file = "osmium-3.4.1.tar.gz", hash = "sha256:575dad72ab169cf585b9aeefb4f5f99ac250bf7da1986992afcbf169dc70c381"},
] ]
osmnx = [
{file = "osmnx-1.2.2-py2.py3-none-any.whl", hash = "sha256:94f2a3929e857d8c0da39ae552c6da3b1a3f4bcfea6de108696bda5ee3a7689d"},
{file = "osmnx-1.2.2.tar.gz", hash = "sha256:30924452ca02758ece3301f9fcfb1b80edf31e2be7abe7fa7e0fefddb5050408"},
]
packaging = [ packaging = [
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
@ -6810,6 +7002,7 @@ pycryptodome = [
{file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7c9ed8aa31c146bef65d89a1b655f5f4eab5e1120f55fc297713c89c9e56ff0b"}, {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7c9ed8aa31c146bef65d89a1b655f5f4eab5e1120f55fc297713c89c9e56ff0b"},
{file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:5099c9ca345b2f252f0c28e96904643153bae9258647585e5e6f649bb7a1844a"}, {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:5099c9ca345b2f252f0c28e96904643153bae9258647585e5e6f649bb7a1844a"},
{file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:2ec709b0a58b539a4f9d33fb8508264c3678d7edb33a68b8906ba914f71e8c13"}, {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:2ec709b0a58b539a4f9d33fb8508264c3678d7edb33a68b8906ba914f71e8c13"},
{file = "pycryptodome-3.15.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:2ae53125de5b0d2c95194d957db9bb2681da8c24d0fb0fe3b056de2bcaf5d837"},
{file = "pycryptodome-3.15.0-cp27-cp27m-win32.whl", hash = "sha256:fd2184aae6ee2a944aaa49113e6f5787cdc5e4db1eb8edb1aea914bd75f33a0c"}, {file = "pycryptodome-3.15.0-cp27-cp27m-win32.whl", hash = "sha256:fd2184aae6ee2a944aaa49113e6f5787cdc5e4db1eb8edb1aea914bd75f33a0c"},
{file = "pycryptodome-3.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:7e3a8f6ee405b3bd1c4da371b93c31f7027944b2bcce0697022801db93120d83"}, {file = "pycryptodome-3.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:7e3a8f6ee405b3bd1c4da371b93c31f7027944b2bcce0697022801db93120d83"},
{file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:b9c5b1a1977491533dfd31e01550ee36ae0249d78aae7f632590db833a5012b8"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:b9c5b1a1977491533dfd31e01550ee36ae0249d78aae7f632590db833a5012b8"},
@ -6817,12 +7010,14 @@ pycryptodome = [
{file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:2aa55aae81f935a08d5a3c2042eb81741a43e044bd8a81ea7239448ad751f763"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:2aa55aae81f935a08d5a3c2042eb81741a43e044bd8a81ea7239448ad751f763"},
{file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:c3640deff4197fa064295aaac10ab49a0d55ef3d6a54ae1499c40d646655c89f"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:c3640deff4197fa064295aaac10ab49a0d55ef3d6a54ae1499c40d646655c89f"},
{file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:045d75527241d17e6ef13636d845a12e54660aa82e823b3b3341bcf5af03fa79"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:045d75527241d17e6ef13636d845a12e54660aa82e823b3b3341bcf5af03fa79"},
{file = "pycryptodome-3.15.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:eb6fce570869e70cc8ebe68eaa1c26bed56d40ad0f93431ee61d400525433c54"},
{file = "pycryptodome-3.15.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9ee40e2168f1348ae476676a2e938ca80a2f57b14a249d8fe0d3cdf803e5a676"}, {file = "pycryptodome-3.15.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9ee40e2168f1348ae476676a2e938ca80a2f57b14a249d8fe0d3cdf803e5a676"},
{file = "pycryptodome-3.15.0-cp35-abi3-manylinux1_i686.whl", hash = "sha256:4c3ccad74eeb7b001f3538643c4225eac398c77d617ebb3e57571a897943c667"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux1_i686.whl", hash = "sha256:4c3ccad74eeb7b001f3538643c4225eac398c77d617ebb3e57571a897943c667"},
{file = "pycryptodome-3.15.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:1b22bcd9ec55e9c74927f6b1f69843cb256fb5a465088ce62837f793d9ffea88"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:1b22bcd9ec55e9c74927f6b1f69843cb256fb5a465088ce62837f793d9ffea88"},
{file = "pycryptodome-3.15.0-cp35-abi3-manylinux2010_i686.whl", hash = "sha256:57f565acd2f0cf6fb3e1ba553d0cb1f33405ec1f9c5ded9b9a0a5320f2c0bd3d"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2010_i686.whl", hash = "sha256:57f565acd2f0cf6fb3e1ba553d0cb1f33405ec1f9c5ded9b9a0a5320f2c0bd3d"},
{file = "pycryptodome-3.15.0-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:4b52cb18b0ad46087caeb37a15e08040f3b4c2d444d58371b6f5d786d95534c2"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:4b52cb18b0ad46087caeb37a15e08040f3b4c2d444d58371b6f5d786d95534c2"},
{file = "pycryptodome-3.15.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:092a26e78b73f2530b8bd6b3898e7453ab2f36e42fd85097d705d6aba2ec3e5e"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:092a26e78b73f2530b8bd6b3898e7453ab2f36e42fd85097d705d6aba2ec3e5e"},
{file = "pycryptodome-3.15.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:50ca7e587b8e541eb6c192acf92449d95377d1f88908c0a32ac5ac2703ebe28b"},
{file = "pycryptodome-3.15.0-cp35-abi3-win32.whl", hash = "sha256:e244ab85c422260de91cda6379e8e986405b4f13dc97d2876497178707f87fc1"}, {file = "pycryptodome-3.15.0-cp35-abi3-win32.whl", hash = "sha256:e244ab85c422260de91cda6379e8e986405b4f13dc97d2876497178707f87fc1"},
{file = "pycryptodome-3.15.0-cp35-abi3-win_amd64.whl", hash = "sha256:c77126899c4b9c9827ddf50565e93955cb3996813c18900c16b2ea0474e130e9"}, {file = "pycryptodome-3.15.0-cp35-abi3-win_amd64.whl", hash = "sha256:c77126899c4b9c9827ddf50565e93955cb3996813c18900c16b2ea0474e130e9"},
{file = "pycryptodome-3.15.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:9eaadc058106344a566dc51d3d3a758ab07f8edde013712bc8d22032a86b264f"}, {file = "pycryptodome-3.15.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:9eaadc058106344a566dc51d3d3a758ab07f8edde013712bc8d22032a86b264f"},
@ -7309,6 +7504,53 @@ requests-toolbelt = [
reverse-geocoder = [ reverse-geocoder = [
{file = "reverse_geocoder-1.5.1.tar.gz", hash = "sha256:2a2e781b5f69376d922b78fe8978f1350c84fce0ddb07e02c834ecf98b57c75c"}, {file = "reverse_geocoder-1.5.1.tar.gz", hash = "sha256:2a2e781b5f69376d922b78fe8978f1350c84fce0ddb07e02c834ecf98b57c75c"},
] ]
rtree = [
{file = "Rtree-1.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9855b8f11cdad99c56eb361b7b632a4fbd3d8cbe3f2081426b445f0cfb7fdca9"},
{file = "Rtree-1.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:18ce7e4d04b85c48f2d364835620b3b20e38e199639746e7b12f07a2303e18ff"},
{file = "Rtree-1.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:784efa6b7be9e99b33613ae8495931032689441eabb6120c9b3eb91188c33794"},
{file = "Rtree-1.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:157207191aebdacbbdbb369e698cfbfebce53bc97114e96c8af5bed3126475f1"},
{file = "Rtree-1.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5fb3671a8d440c24b1dd29ec621d4345ced7185e26f02abe98e85a6629fcb50"},
{file = "Rtree-1.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:11d16f51cf9205cd6995af36e24efe8f184270f667fb49bb69b09fc46b97e7d4"},
{file = "Rtree-1.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6db6a0a93e41594ffc14b053f386dd414ab5a82535bbd9aedafa6ac8dc0650d8"},
{file = "Rtree-1.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c6e29e5eb3083ad12ac5c1ce6e37465ea3428d894d3466cc9c9e2ee4bf768e53"},
{file = "Rtree-1.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:656b148589c0b5bab4a7db4d033634329f42a5feaac10ca40aceeca109d83c1f"},
{file = "Rtree-1.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7b2c15f9373ba314c83a8df5cb6d99b4e3af23c376c6b1317add995432dd0970"},
{file = "Rtree-1.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93c5e0bf31e76b4f92a6eec3d2891e938408774c75a8ed6ac3d2c8db04a2be33"},
{file = "Rtree-1.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6792de0e3c2fd3ad7e069445027603bec7a47000432f49c80246886311f4f152"},
{file = "Rtree-1.0.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:004e131b570dc360a49e7f3b60e7bc6517943a54df056587964d1cb903889e7e"},
{file = "Rtree-1.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:becd711fe97c2e09b1b7969e83080a3c8012bce2d30f6db879aade255fcba5c1"},
{file = "Rtree-1.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:015df09e1bc55ddf7c88799bf1515d058cd0ee78eacf4cd443a32876d3b3a863"},
{file = "Rtree-1.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c2973b76f61669a85e160b4ad09879c4089fc0e3f20fd99adf161ca298fe8374"},
{file = "Rtree-1.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e4335e131a58952635560a003458011d97f9ea6f3c010dc24906050b42ee2c03"},
{file = "Rtree-1.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:e7ca5d743f6a1dc62653dfac8ee7ce2e1ba91be7cf97916a7f60b7cbe48fb48d"},
{file = "Rtree-1.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2ee7165e9872a026ccb868c021711eba39cedf7d1820763c9de52d5324691a92"},
{file = "Rtree-1.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8de99f28af0f1783eefb80918959903b4b18112f6a12b48f296ecb162804e69d"},
{file = "Rtree-1.0.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a94e2f4bf74bd202ea8b67ea3d7c71e763ad41f79be1d6b72aa2c8d5a8e92c4"},
{file = "Rtree-1.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5120da3a1b96f3a7a17dd6af0afdd4e6f3cc9baa87e9ee0a272882f01f980bb"},
{file = "Rtree-1.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7e3d5f0e7b28250afbb290ab88b49aa0f121c9714d0da2080581783690347507"},
{file = "Rtree-1.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:296203e933b6ec0dd07f6a7456c4f1492def95b6993f20cc61c92b0fee0aecc5"},
{file = "Rtree-1.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:77908cd7acdd519a731979ebf5baff8afd102109c2f52864c1e6ee75d3ea2d87"},
{file = "Rtree-1.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:1a213e5d385278ca7668bc5b27083f8d6e39996a9bd59b6528f3a30009dae4ed"},
{file = "Rtree-1.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cfa8cffec5cb9fed494c4bb335ebdb69b3c26178b0b685f67f79296c6b3d800c"},
{file = "Rtree-1.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b31fd22d214160859d038da7cb2aaa27acb71efc24a7bcc75c84b5e502721549"},
{file = "Rtree-1.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d68a81ad419d5c2ea5fecc677e6c178666c057e2c7b24100a6c48392196f1e9"},
{file = "Rtree-1.0.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62f38020af47b765adc6b0bc7c4e810c6c3d1eab44ba339b592ff25a4c0dc0a7"},
{file = "Rtree-1.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50b658a6707f215a0056d52e9f83a97148c0af62dea07cf29b3789a2c429e78a"},
{file = "Rtree-1.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3573cbb0de872f54d0a0c29596a84e8ac3939c47ca3bece4a82e92775730a0d0"},
{file = "Rtree-1.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d5abe5a19d943a88bea14901970e4c53e4579fc2662404cdea6163bf4c04d49a"},
{file = "Rtree-1.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1e894112cef4de6c518bdea0b43eada65f12888c3645cc437c3a677aa023039f"},
{file = "Rtree-1.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:582854252b8fd5c8472478af060635434931fb55edd269bac128cbf2eef43620"},
{file = "Rtree-1.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b54057e8a8ad92c1d8e9eaa5cf32aad70dde454abbf9b638e9d6024520a52c02"},
{file = "Rtree-1.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:698de8ce6c62e159d93b35bacf64bcf3619077b5367bc88cd2cff5e0bc36169b"},
{file = "Rtree-1.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:273ee61783de3a1664e5f868feebf5eea4629447137751bfa4087b0f82093082"},
{file = "Rtree-1.0.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16900ee02cf5c198a42b03635268a80f606aa102f3f7618b89f75023d406da1c"},
{file = "Rtree-1.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ce4a6fdb63254a4c1efebe7a4f7a59b1c333c703bde4ae715d9ad88c833e10b"},
{file = "Rtree-1.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5b20f69e040a05503b22297af223f336fe7047909b57e4b207b98292f33a229f"},
{file = "Rtree-1.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:57128293dd625cb1f07726f32208097953e8854d70ab1fc55d6858733618b9ed"},
{file = "Rtree-1.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e898d7409ab645c25e06d4e058f99271182601d70b2887aba3351bf08e09a0c6"},
{file = "Rtree-1.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:ad9912faeddb1ddcec5e26b33089166d58a107af6862d8b7f1bb2b7c0002ab39"},
{file = "Rtree-1.0.1.tar.gz", hash = "sha256:222121699c303a64065d849bf7038b1ecabc37b65c7fa340bedb38ef0e805429"},
]
s2sphere = [ s2sphere = [
{file = "s2sphere-0.2.5-py2.py3-none-any.whl", hash = "sha256:d2340c9cf458ddc9a89afd1d8048a4195ce6fa6b0095ab900d4be5271e537401"}, {file = "s2sphere-0.2.5-py2.py3-none-any.whl", hash = "sha256:d2340c9cf458ddc9a89afd1d8048a4195ce6fa6b0095ab900d4be5271e537401"},
{file = "s2sphere-0.2.5.tar.gz", hash = "sha256:c2478c1ff7c601a59a7151a57b605435897514578fa6bdb8730721c182adbbaf"}, {file = "s2sphere-0.2.5.tar.gz", hash = "sha256:c2478c1ff7c601a59a7151a57b605435897514578fa6bdb8730721c182adbbaf"},
@ -7417,6 +7659,18 @@ setproctitle = [
{file = "setproctitle-1.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7f2719a398e1a2c01c2a63bf30377a34d0b6ef61946ab9cf4d550733af8f1ef1"}, {file = "setproctitle-1.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7f2719a398e1a2c01c2a63bf30377a34d0b6ef61946ab9cf4d550733af8f1ef1"},
{file = "setproctitle-1.3.2-cp310-cp310-win32.whl", hash = "sha256:e425be62524dc0c593985da794ee73eb8a17abb10fe692ee43bb39e201d7a099"}, {file = "setproctitle-1.3.2-cp310-cp310-win32.whl", hash = "sha256:e425be62524dc0c593985da794ee73eb8a17abb10fe692ee43bb39e201d7a099"},
{file = "setproctitle-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:e85e50b9c67854f89635a86247412f3ad66b132a4d8534ac017547197c88f27d"}, {file = "setproctitle-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:e85e50b9c67854f89635a86247412f3ad66b132a4d8534ac017547197c88f27d"},
{file = "setproctitle-1.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2a97d51c17d438cf5be284775a322d57b7ca9505bb7e118c28b1824ecaf8aeaa"},
{file = "setproctitle-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:587c7d6780109fbd8a627758063d08ab0421377c0853780e5c356873cdf0f077"},
{file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d17c8bd073cbf8d141993db45145a70b307385b69171d6b54bcf23e5d644de"},
{file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e932089c35a396dc31a5a1fc49889dd559548d14cb2237adae260382a090382e"},
{file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e4f8f12258a8739c565292a551c3db62cca4ed4f6b6126664e2381acb4931bf"},
{file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:570d255fd99c7f14d8f91363c3ea96bd54f8742275796bca67e1414aeca7d8c3"},
{file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a8e0881568c5e6beff91ef73c0ec8ac2a9d3ecc9edd6bd83c31ca34f770910c4"},
{file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4bba3be4c1fabf170595b71f3af46c6d482fbe7d9e0563999b49999a31876f77"},
{file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:37ece938110cab2bb3957e3910af8152ca15f2b6efdf4f2612e3f6b7e5459b80"},
{file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db684d6bbb735a80bcbc3737856385b55d53f8a44ce9b46e9a5682c5133a9bf7"},
{file = "setproctitle-1.3.2-cp311-cp311-win32.whl", hash = "sha256:ca58cd260ea02759238d994cfae844fc8b1e206c684beb8f38877dcab8451dfc"},
{file = "setproctitle-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:88486e6cce2a18a033013d17b30a594f1c5cb42520c49c19e6ade40b864bb7ff"},
{file = "setproctitle-1.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:92c626edc66169a1b09e9541b9c0c9f10488447d8a2b1d87c8f0672e771bc927"}, {file = "setproctitle-1.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:92c626edc66169a1b09e9541b9c0c9f10488447d8a2b1d87c8f0672e771bc927"},
{file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:710e16fa3bade3b026907e4a5e841124983620046166f355bbb84be364bf2a02"}, {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:710e16fa3bade3b026907e4a5e841124983620046166f355bbb84be364bf2a02"},
{file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f29b75e86260b0ab59adb12661ef9f113d2f93a59951373eb6d68a852b13e83"}, {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f29b75e86260b0ab59adb12661ef9f113d2f93a59951373eb6d68a852b13e83"},
@ -7474,6 +7728,50 @@ setuptools-scm = [
{file = "setuptools_scm-7.0.5-py3-none-any.whl", hash = "sha256:7930f720905e03ccd1e1d821db521bff7ec2ac9cf0ceb6552dd73d24a45d3b02"}, {file = "setuptools_scm-7.0.5-py3-none-any.whl", hash = "sha256:7930f720905e03ccd1e1d821db521bff7ec2ac9cf0ceb6552dd73d24a45d3b02"},
{file = "setuptools_scm-7.0.5.tar.gz", hash = "sha256:031e13af771d6f892b941adb6ea04545bbf91ebc5ce68c78aaf3fff6e1fb4844"}, {file = "setuptools_scm-7.0.5.tar.gz", hash = "sha256:031e13af771d6f892b941adb6ea04545bbf91ebc5ce68c78aaf3fff6e1fb4844"},
] ]
shapely = [
{file = "Shapely-1.8.5.post1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d048f93e42ba578b82758c15d8ae037d08e69d91d9872bca5a1895b118f4e2b0"},
{file = "Shapely-1.8.5.post1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99ab0ddc05e44acabdbe657c599fdb9b2d82e86c5493bdae216c0c4018a82dee"},
{file = "Shapely-1.8.5.post1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:99a2f0da0109e81e0c101a2b4cd8412f73f5f299e7b5b2deaf64cd2a100ac118"},
{file = "Shapely-1.8.5.post1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6fe855e7d45685926b6ba00aaeb5eba5862611f7465775dacd527e081a8ced6d"},
{file = "Shapely-1.8.5.post1-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec14ceca36f67cb48b34d02d7f65a9acae15cd72b48e303531893ba4a960f3ea"},
{file = "Shapely-1.8.5.post1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a2b2a65fa7f97115c1cd989fe9d6f39281ca2a8a014f1d4904c1a6e34d7f25"},
{file = "Shapely-1.8.5.post1-cp310-cp310-win32.whl", hash = "sha256:21776184516a16bf82a0c3d6d6a312b3cd15a4cabafc61ee01cf2714a82e8396"},
{file = "Shapely-1.8.5.post1-cp310-cp310-win_amd64.whl", hash = "sha256:a354199219c8d836f280b88f2c5102c81bb044ccea45bd361dc38a79f3873714"},
{file = "Shapely-1.8.5.post1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:783bad5f48e2708a0e2f695a34ed382e4162c795cb2f0368b39528ac1d6db7ed"},
{file = "Shapely-1.8.5.post1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a23ef3882d6aa203dd3623a3d55d698f59bfbd9f8a3bfed52c2da05a7f0f8640"},
{file = "Shapely-1.8.5.post1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ab38f7b5196ace05725e407cb8cab9ff66edb8e6f7bb36a398e8f73f52a7aaa2"},
{file = "Shapely-1.8.5.post1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d086591f744be483b34628b391d741e46f2645fe37594319e0a673cc2c26bcf"},
{file = "Shapely-1.8.5.post1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4728666fff8cccc65a07448cae72c75a8773fea061c3f4f139c44adc429b18c3"},
{file = "Shapely-1.8.5.post1-cp311-cp311-win32.whl", hash = "sha256:84010db15eb364a52b74ea8804ef92a6a930dfc1981d17a369444b6ddec66efd"},
{file = "Shapely-1.8.5.post1-cp311-cp311-win_amd64.whl", hash = "sha256:48dcfffb9e225c0481120f4bdf622131c8c95f342b00b158cdbe220edbbe20b6"},
{file = "Shapely-1.8.5.post1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2fd15397638df291c427a53d641d3e6fd60458128029c8c4f487190473a69a91"},
{file = "Shapely-1.8.5.post1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a74631e511153366c6dbe3229fa93f877e3c87ea8369cd00f1d38c76b0ed9ace"},
{file = "Shapely-1.8.5.post1-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:66bdac74fbd1d3458fa787191a90fa0ae610f09e2a5ec398c36f968cc0ed743f"},
{file = "Shapely-1.8.5.post1-cp36-cp36m-win32.whl", hash = "sha256:6d388c0c1bd878ed1af4583695690aa52234b02ed35f93a1c8486ff52a555838"},
{file = "Shapely-1.8.5.post1-cp36-cp36m-win_amd64.whl", hash = "sha256:be9423d5a3577ac2e92c7e758bd8a2b205f5e51a012177a590bc46fc51eb4834"},
{file = "Shapely-1.8.5.post1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5d7f85c2d35d39ff53c9216bc76b7641c52326f7e09aaad1789a3611a0f812f2"},
{file = "Shapely-1.8.5.post1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:adcf8a11b98af9375e32bff91de184f33a68dc48b9cb9becad4f132fa25cfa3c"},
{file = "Shapely-1.8.5.post1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:753ed0e21ab108bd4282405b9b659f2e985e8502b1a72b978eaa51d3496dee19"},
{file = "Shapely-1.8.5.post1-cp37-cp37m-win32.whl", hash = "sha256:65b21243d8f6bcd421210daf1fabb9de84de2c04353c5b026173b88d17c1a581"},
{file = "Shapely-1.8.5.post1-cp37-cp37m-win_amd64.whl", hash = "sha256:370b574c78dc5af3a198a6da5d9b3d7c04654bd2ef7e80e80a3a0992dfb2d9cd"},
{file = "Shapely-1.8.5.post1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:532a55ee2a6c52d23d6f7d1567c8f0473635f3b270262c44e1b0c88096827e22"},
{file = "Shapely-1.8.5.post1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3480657460e939f45a7d359ef0e172a081f249312557fe9aa78c4fd3a362d993"},
{file = "Shapely-1.8.5.post1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b65f5d530ba91e49ffc7c589255e878d2506a8b96ffce69d3b7c4500a9a9eaf8"},
{file = "Shapely-1.8.5.post1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:147066da0be41b147a61f8eb805dea3b13709dbc873a431ccd7306e24d712bc0"},
{file = "Shapely-1.8.5.post1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c2822111ddc5bcfb116e6c663e403579d0fe3f147d2a97426011a191c43a7458"},
{file = "Shapely-1.8.5.post1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b47bb6f9369e8bf3e6dbd33e6a25a47ee02b2874792a529fe04a49bf8bc0df6"},
{file = "Shapely-1.8.5.post1-cp38-cp38-win32.whl", hash = "sha256:2e0a8c2e55f1be1312b51c92b06462ea89e6bb703fab4b114e7a846d941cfc40"},
{file = "Shapely-1.8.5.post1-cp38-cp38-win_amd64.whl", hash = "sha256:0d885cb0cf670c1c834df3f371de8726efdf711f18e2a75da5cfa82843a7ab65"},
{file = "Shapely-1.8.5.post1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0b4ee3132ee90f07d63db3aea316c4c065ed7a26231458dda0874414a09d6ba3"},
{file = "Shapely-1.8.5.post1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:02dd5d7dc6e46515d88874134dc8fcdc65826bca93c3eecee59d1910c42c1b17"},
{file = "Shapely-1.8.5.post1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c6a9a4a31cd6e86d0fbe8473ceed83d4fe760b19d949fb557ef668defafea0f6"},
{file = "Shapely-1.8.5.post1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:38f0fbbcb8ca20c16451c966c1f527cc43968e121c8a048af19ed3e339a921cd"},
{file = "Shapely-1.8.5.post1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:78fb9d929b8ee15cfd424b6c10879ce1907f24e05fb83310fc47d2cd27088e40"},
{file = "Shapely-1.8.5.post1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89164e7a9776a19e29f01369a98529321994e2e4d852b92b7e01d4d9804c55bf"},
{file = "Shapely-1.8.5.post1-cp39-cp39-win32.whl", hash = "sha256:8e59817b0fe63d34baedaabba8c393c0090f061917d18fc0bcc2f621937a8f73"},
{file = "Shapely-1.8.5.post1-cp39-cp39-win_amd64.whl", hash = "sha256:e9c30b311de2513555ab02464ebb76115d242842b29c412f5a9aa0cac57be9f6"},
{file = "Shapely-1.8.5.post1.tar.gz", hash = "sha256:ef3be705c3eac282a28058e6c6e5503419b250f482320df2172abcbea642c831"},
]
shellingham = [ shellingham = [
{file = "shellingham-1.5.0-py2.py3-none-any.whl", hash = "sha256:a8f02ba61b69baaa13facdba62908ca8690a94b8119b69f5ec5873ea85f7391b"}, {file = "shellingham-1.5.0-py2.py3-none-any.whl", hash = "sha256:a8f02ba61b69baaa13facdba62908ca8690a94b8119b69f5ec5873ea85f7391b"},
{file = "shellingham-1.5.0.tar.gz", hash = "sha256:72fb7f5c63103ca2cb91b23dee0c71fe8ad6fbfd46418ef17dbe40db51592dad"}, {file = "shellingham-1.5.0.tar.gz", hash = "sha256:72fb7f5c63103ca2cb91b23dee0c71fe8ad6fbfd46418ef17dbe40db51592dad"},
@ -7611,6 +7909,9 @@ spidev = [
{file = "spidev-3.6-cp39-cp39-linux_armv7l.whl", hash = "sha256:280abc00a1ef7780ef62c3f294f52a2527b6c47d8c269fea98664970bcaf6da5"}, {file = "spidev-3.6-cp39-cp39-linux_armv7l.whl", hash = "sha256:280abc00a1ef7780ef62c3f294f52a2527b6c47d8c269fea98664970bcaf6da5"},
{file = "spidev-3.6.tar.gz", hash = "sha256:14dbc37594a4aaef85403ab617985d3c3ef464d62bc9b769ef552db53701115b"}, {file = "spidev-3.6.tar.gz", hash = "sha256:14dbc37594a4aaef85403ab617985d3c3ef464d62bc9b769ef552db53701115b"},
] ]
spidev2 = [
{file = "spidev2-0.9.0.tar.gz", hash = "sha256:152da2911a8660283ceac3a75dd869953379bcbcf079e5436af5aae736876086"},
]
sqlalchemy = [ sqlalchemy = [
{file = "SQLAlchemy-1.4.42-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:28e881266a172a4d3c5929182fde6bb6fba22ac93f137d5380cc78a11a9dd124"}, {file = "SQLAlchemy-1.4.42-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:28e881266a172a4d3c5929182fde6bb6fba22ac93f137d5380cc78a11a9dd124"},
{file = "SQLAlchemy-1.4.42-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ca9389a00f639383c93ed00333ed763812f80b5ae9e772ea32f627043f8c9c88"}, {file = "SQLAlchemy-1.4.42-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ca9389a00f639383c93ed00333ed763812f80b5ae9e772ea32f627043f8c9c88"},

@ -51,6 +51,7 @@ six = "^1.16.0"
smbus2 = "^0.4.2" smbus2 = "^0.4.2"
sounddevice = "^0.4.5" sounddevice = "^0.4.5"
spidev = { version = "^3.6", platform = "linux" } spidev = { version = "^3.6", platform = "linux" }
spidev2 = { version = "^0.9.0", platform = "linux" }
sympy = "^1.10.1" sympy = "^1.10.1"
timezonefinder = "^6.0.1" timezonefinder = "^6.0.1"
tqdm = "^4.64.0" tqdm = "^4.64.0"
@ -144,7 +145,7 @@ jupyterlab = "^3.4.4"
jupyterlab-vim = "^0.15.1" jupyterlab-vim = "^0.15.1"
Markdown = "^3.4.1" Markdown = "^3.4.1"
msgpack-python = "^0.5.6" msgpack-python = "^0.5.6"
networkx = "~2.3" networkx = "~2.8"
nvidia-ml-py3 = "^7.352.0" nvidia-ml-py3 = "^7.352.0"
onnx2torch = "^1.5.4" onnx2torch = "^1.5.4"
onnxoptimizer = "^0.3.1" onnxoptimizer = "^0.3.1"
@ -170,6 +171,8 @@ torchvision = { url = "https://download.pytorch.org/whl/cu113/torchvision-0.12.0
triton = "^1.1.1" triton = "^1.1.1"
Werkzeug = "^2.1.2" Werkzeug = "^2.1.2"
zerorpc = { git = "https://github.com/commaai/zerorpc-python.git", branch = "master" } zerorpc = { git = "https://github.com/commaai/zerorpc-python.git", branch = "master" }
omegaconf = "^2.3.0"
osmnx = "==1.2.2"
[build-system] [build-system]

@ -11,15 +11,19 @@ SOURCE_DIR="$(git rev-parse --show-toplevel)"
if [ -f /TICI ]; then if [ -f /TICI ]; then
FILES_SRC="release/files_tici" FILES_SRC="release/files_tici"
RELEASE_BRANCH=release3-staging
DASHCAM_BRANCH=dashcam3-staging
else else
exit 0 echo "no release files set"
exit 1
fi
if [ -z "$RELEASE_BRANCH" ]; then
echo "RELEASE_BRANCH is not set"
exit 1
fi fi
# set git identity # set git identity
source $DIR/identity.sh source $DIR/identity.sh
export GIT_SSH_COMMAND="ssh -i /data/gitkey"
echo "[-] Setting up repo T=$SECONDS" echo "[-] Setting up repo T=$SECONDS"
rm -rf $BUILD_DIR rm -rf $BUILD_DIR
@ -27,7 +31,6 @@ mkdir -p $BUILD_DIR
cd $BUILD_DIR cd $BUILD_DIR
git init git init
git remote add origin git@github.com:commaai/openpilot.git git remote add origin git@github.com:commaai/openpilot.git
git fetch origin $RELEASE_BRANCH
git checkout --orphan $RELEASE_BRANCH git checkout --orphan $RELEASE_BRANCH
# do the files copy # do the files copy
@ -48,7 +51,6 @@ echo "#define COMMA_VERSION \"$VERSION-release\"" > common/version.h
echo "[-] committing version $VERSION T=$SECONDS" echo "[-] committing version $VERSION T=$SECONDS"
git add -f . git add -f .
git commit -a -m "openpilot v$VERSION release" git commit -a -m "openpilot v$VERSION release"
git branch --set-upstream-to=origin/$RELEASE_BRANCH
# Build panda firmware # Build panda firmware
pushd panda/ pushd panda/
@ -105,10 +107,12 @@ RELEASE=1 selfdrive/test/test_onroad.py
selfdrive/car/tests/test_car_interfaces.py selfdrive/car/tests/test_car_interfaces.py
rm -rf $TEST_FILES rm -rf $TEST_FILES
if [ ! -z "$PUSH" ]; then if [ ! -z "$RELEASE_BRANCH" ]; then
echo "[-] pushing T=$SECONDS" echo "[-] pushing release T=$SECONDS"
git push -f origin $RELEASE_BRANCH git push -f origin $RELEASE_BRANCH:$RELEASE_BRANCH
fi
if [ ! -z "$DASHCAM_BRANCH" ]; then
# Create dashcam # Create dashcam
git rm selfdrive/car/*/carcontroller.py git rm selfdrive/car/*/carcontroller.py
git commit -m "create dashcam release from release" git commit -m "create dashcam release from release"

@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
while read hash submodule ref; do while read hash submodule ref; do
git -C $submodule fetch --depth 100 origin master git -C $submodule fetch --depth 1000 origin master
git -C $submodule branch -r --contains $hash | grep "origin/master" git -C $submodule branch -r --contains $hash | grep "origin/master"
if [ "$?" -eq 0 ]; then if [ "$?" -eq 0 ]; then
echo "$submodule ok" echo "$submodule ok"

@ -195,8 +195,6 @@ selfdrive/controls/lib/pid.py
selfdrive/controls/lib/radar_helpers.py selfdrive/controls/lib/radar_helpers.py
selfdrive/controls/lib/vehicle_model.py selfdrive/controls/lib/vehicle_model.py
selfdrive/controls/lib/cluster/*
selfdrive/controls/lib/lateral_mpc_lib/.gitignore selfdrive/controls/lib/lateral_mpc_lib/.gitignore
selfdrive/controls/lib/longitudinal_mpc_lib/.gitignore selfdrive/controls/lib/longitudinal_mpc_lib/.gitignore
selfdrive/controls/lib/lateral_mpc_lib/* selfdrive/controls/lib/lateral_mpc_lib/*
@ -230,13 +228,9 @@ selfdrive/locationd/SConscript
selfdrive/locationd/ubloxd.cc selfdrive/locationd/ubloxd.cc
selfdrive/locationd/ublox_msg.cc selfdrive/locationd/ublox_msg.cc
selfdrive/locationd/ublox_msg.h selfdrive/locationd/ublox_msg.h
selfdrive/locationd/generated/ubx.cpp selfdrive/locationd/generated/*
selfdrive/locationd/generated/ubx.h
selfdrive/locationd/generated/gps.cpp
selfdrive/locationd/generated/gps.h
selfdrive/locationd/laikad.py selfdrive/locationd/laikad.py
selfdrive/locationd/laikad_helpers.py
selfdrive/locationd/locationd.h selfdrive/locationd/locationd.h
selfdrive/locationd/locationd.cc selfdrive/locationd/locationd.cc
selfdrive/locationd/paramsd.py selfdrive/locationd/paramsd.py
@ -286,7 +280,6 @@ selfdrive/loggerd/deleter.py
selfdrive/loggerd/xattr_cache.py selfdrive/loggerd/xattr_cache.py
selfdrive/sensord/SConscript selfdrive/sensord/SConscript
selfdrive/sensord/libdiag.h
selfdrive/sensord/sensors_qcom2.cc selfdrive/sensord/sensors_qcom2.cc
selfdrive/sensord/sensors/*.cc selfdrive/sensord/sensors/*.cc
selfdrive/sensord/sensors/*.h selfdrive/sensord/sensors/*.h
@ -327,12 +320,17 @@ selfdrive/ui/qt/widgets/*.cc
selfdrive/ui/qt/widgets/*.h selfdrive/ui/qt/widgets/*.h
selfdrive/ui/qt/maps/*.cc selfdrive/ui/qt/maps/*.cc
selfdrive/ui/qt/maps/*.h selfdrive/ui/qt/maps/*.h
selfdrive/ui/qt/setup/*.cc
selfdrive/ui/qt/setup/*.h
selfdrive/ui/installer/*.cc
selfdrive/ui/installer/*.h
selfdrive/ui/installer/*.cc
system/camerad/SConscript system/camerad/SConscript
system/camerad/main.cc system/camerad/main.cc
system/camerad/snapshot/* system/camerad/snapshot/*
system/camerad/include/*
system/camerad/cameras/camera_common.h system/camerad/cameras/camera_common.h
system/camerad/cameras/camera_common.cc system/camerad/cameras/camera_common.cc
system/camerad/cameras/sensor2_i2c.h system/camerad/cameras/sensor2_i2c.h
@ -388,7 +386,6 @@ selfdrive/modeld/thneed/thneed.h
selfdrive/modeld/thneed/thneed_common.cc selfdrive/modeld/thneed/thneed_common.cc
selfdrive/modeld/thneed/thneed_qcom2.cc selfdrive/modeld/thneed/thneed_qcom2.cc
selfdrive/modeld/thneed/serialize.cc selfdrive/modeld/thneed/serialize.cc
selfdrive/modeld/thneed/include/*
selfdrive/modeld/runners/snpemodel.cc selfdrive/modeld/runners/snpemodel.cc
selfdrive/modeld/runners/snpemodel.h selfdrive/modeld/runners/snpemodel.h
@ -416,8 +413,11 @@ selfdrive/assets/offroad/*
selfdrive/assets/sounds/* selfdrive/assets/sounds/*
selfdrive/assets/training/* selfdrive/assets/training/*
third_party/.gitignore
third_party/SConscript third_party/SConscript
third_party/cluster/*
third_party/linux/** third_party/linux/**
third_party/opencl/** third_party/opencl/**
@ -440,15 +440,14 @@ third_party/snpe/dsp**
third_party/acados/x86_64/** third_party/acados/x86_64/**
third_party/acados/larch64/** third_party/acados/larch64/**
third_party/acados/include/** third_party/acados/include/**
third_party/acados/acados_template/**
third_party/bootstrap/**
third_party/qt5/larch64/bin/** third_party/qt5/larch64/bin/**
scripts/update_now.sh scripts/update_now.sh
scripts/stop_updater.sh scripts/stop_updater.sh
pyextra/.gitignore
pyextra/acados_template/**
rednose/.gitignore rednose/.gitignore
rednose/** rednose/**
laika/** laika/**
@ -581,17 +580,13 @@ opendbc/tesla_can.dbc
opendbc/tesla_radar.dbc opendbc/tesla_radar.dbc
opendbc/tesla_powertrain.dbc opendbc/tesla_powertrain.dbc
tinygrad_repo/openpilot/compile.py
tinygrad_repo/accel/opencl/* tinygrad_repo/accel/opencl/*
tinygrad_repo/tinygrad/llops/ops_opencl.py
tinygrad_repo/openpilot/compile.py
tinygrad_repo/extra/onnx.py tinygrad_repo/extra/onnx.py
tinygrad_repo/extra/thneed.py tinygrad_repo/extra/thneed.py
tinygrad_repo/extra/utils.py tinygrad_repo/extra/utils.py
tinygrad_repo/tinygrad/llops/ops_gpu.py tinygrad_repo/tinygrad/llops/ops_gpu.py
tinygrad_repo/tinygrad/llops/ops_opencl.py tinygrad_repo/tinygrad/shape/*
tinygrad_repo/tinygrad/helpers.py tinygrad_repo/tinygrad/nn/*
tinygrad_repo/tinygrad/mlops.py tinygrad_repo/tinygrad/*.py
tinygrad_repo/tinygrad/ops.py
tinygrad_repo/tinygrad/shapetracker.py
tinygrad_repo/tinygrad/tensor.py
tinygrad_repo/tinygrad/nn/__init__.py
tinygrad_repo/tinygrad/nn/optim.py

@ -1,5 +1,3 @@
#!/usr/bin/bash #!/usr/bin/bash
nmcli connection modify --temporary lte ipv4.route-metric 1 ipv6.route-metric 1
nmcli connection modify --temporary lte ipv4.route-metric 1 nmcli con up --wait --ask lte
nmcli connection modify --temporary lte ipv6.route-metric 1
nmcli con up lte

@ -1,5 +1,6 @@
<!DOCTYPE RCC><RCC version="1.0"> <!DOCTYPE RCC><RCC version="1.0">
<qresource> <qresource>
<file alias="bootstrap-icons.svg">../../third_party/bootstrap/bootstrap-icons.svg</file>
<file>img_continue_triangle.svg</file> <file>img_continue_triangle.svg</file>
<file>img_circled_check.svg</file> <file>img_circled_check.svg</file>
<file>img_circled_slash.svg</file> <file>img_circled_slash.svg</file>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg fill="red" width="72" height="80" viewBox="0 0 15 15" xmlns="http://www.w3.org/2000/svg" id="marker">
<path stroke="darkred" stroke-width="0.5" d="M7.5 1C5.42312 1 3 2.2883 3 5.56759C3 7.79276 6.46156 12.7117 7.5 14C8.42309 12.7117 12 7.90993 12 5.56759C12 2.2883 9.57688 1 7.5 1Z"/>
<circle cx="7.5" cy="5.5" r="2" fill="darkred"/>
</svg>

After

Width:  |  Height:  |  Size: 389 B

@ -7,6 +7,7 @@
#include <unistd.h> #include <unistd.h>
#include <algorithm> #include <algorithm>
#include <array>
#include <atomic> #include <atomic>
#include <bitset> #include <bitset>
#include <cassert> #include <cassert>
@ -48,8 +49,8 @@
#define MAX_IR_POWER 0.5f #define MAX_IR_POWER 0.5f
#define MIN_IR_POWER 0.0f #define MIN_IR_POWER 0.0f
#define CUTOFF_IL 200 #define CUTOFF_IL 400
#define SATURATE_IL 1600 #define SATURATE_IL 1000
#define NIBBLE_TO_HEX(n) ((n) < 10 ? (n) + '0' : ((n) - 10) + 'a') #define NIBBLE_TO_HEX(n) ((n) < 10 ? (n) + '0' : ((n) - 10) + 'a')
using namespace std::chrono_literals; using namespace std::chrono_literals;
@ -105,6 +106,8 @@ void sync_time(Panda *panda, SyncTimeDir dir) {
bool safety_setter_thread(std::vector<Panda *> pandas) { bool safety_setter_thread(std::vector<Panda *> pandas) {
LOGD("Starting safety setter thread"); LOGD("Starting safety setter thread");
Params p;
// there should be at least one panda connected // there should be at least one panda connected
if (pandas.size() == 0) { if (pandas.size() == 0) {
return false; return false;
@ -116,29 +119,26 @@ bool safety_setter_thread(std::vector<Panda *> pandas) {
pandas[i]->set_safety_model(cereal::CarParams::SafetyModel::ELM327, safety_param); pandas[i]->set_safety_model(cereal::CarParams::SafetyModel::ELM327, safety_param);
} }
Params p = Params(); // wait for FW query at OBD port to finish
// wait for VIN to be read
while (true) { while (true) {
if (do_exit || !check_all_connected(pandas) || !ignition) { if (do_exit || !check_all_connected(pandas) || !ignition) {
return false; return false;
} }
std::string value_vin = p.get("CarVin"); if (p.getBool("FirmwareObdQueryDone")) {
if (value_vin.size() > 0) { LOGW("finished FW query at OBD port");
// sanity check VIN format
assert(value_vin.size() == 17);
LOGW("got CarVin %s", value_vin.c_str());
break; break;
} }
util::sleep_for(20); util::sleep_for(20);
} }
// set to ELM327 for ECU knockouts // set to ELM327 to finish fingerprinting and for potential ECU knockouts
for (Panda *panda : pandas) { for (Panda *panda : pandas) {
panda->set_safety_model(cereal::CarParams::SafetyModel::ELM327, 1U); panda->set_safety_model(cereal::CarParams::SafetyModel::ELM327, 1U);
} }
p.putBool("ObdMultiplexingDisabled", true);
std::string params; std::string params;
LOGW("waiting for params to set safety model"); LOGW("waiting for params to set safety model");
while (true) { while (true) {
@ -225,9 +225,9 @@ void can_send_thread(std::vector<Panda *> pandas, bool fake_send) {
//Dont send if older than 1 second //Dont send if older than 1 second
if ((nanos_since_boot() - event.getLogMonoTime() < 1e9) && !fake_send) { if ((nanos_since_boot() - event.getLogMonoTime() < 1e9) && !fake_send) {
for (const auto& panda : pandas) { for (const auto& panda : pandas) {
LOGT("sending sendcan to panda: %s", (panda->hw_serial).c_str()); LOGT("sending sendcan to panda: %s", (panda->hw_serial()).c_str());
panda->can_send(event.getSendcan()); panda->can_send(event.getSendcan());
LOGT("sendcan sent to panda: %s", (panda->hw_serial).c_str()); LOGT("sendcan sent to panda: %s", (panda->hw_serial()).c_str());
} }
} }
} }
@ -540,9 +540,8 @@ void peripheral_control_thread(Panda *panda, bool no_fan_control) {
if (sm.updated("driverCameraState")) { if (sm.updated("driverCameraState")) {
auto event = sm["driverCameraState"]; auto event = sm["driverCameraState"];
int cur_integ_lines = event.getDriverCameraState().getIntegLines(); int cur_integ_lines = event.getDriverCameraState().getIntegLines();
float cur_gain = event.getDriverCameraState().getGain();
cur_integ_lines = integ_lines_filter.update(cur_integ_lines * cur_gain); cur_integ_lines = integ_lines_filter.update(cur_integ_lines);
last_front_frame_t = event.getLogMonoTime(); last_front_frame_t = event.getLogMonoTime();
if (cur_integ_lines <= CUTOFF_IL) { if (cur_integ_lines <= CUTOFF_IL) {

@ -10,11 +10,13 @@
#include "common/util.h" #include "common/util.h"
Panda::Panda(std::string serial, uint32_t bus_offset) : bus_offset(bus_offset) { Panda::Panda(std::string serial, uint32_t bus_offset) : bus_offset(bus_offset) {
// TODO: support SPI here one day... // try USB first, then SPI
if (serial.find("spi") != std::string::npos) { try {
handle = std::make_unique<PandaSpiHandle>(serial);
} else {
handle = std::make_unique<PandaUsbHandle>(serial); handle = std::make_unique<PandaUsbHandle>(serial);
} catch (std::exception &e) {
#ifndef __APPLE__
handle = std::make_unique<PandaSpiHandle>(serial);
#endif
} }
hw_type = get_hw_type(); hw_type = get_hw_type();
@ -26,6 +28,8 @@ Panda::Panda(std::string serial, uint32_t bus_offset) : bus_offset(bus_offset) {
(hw_type == cereal::PandaState::PandaType::DOS) || (hw_type == cereal::PandaState::PandaType::DOS) ||
(hw_type == cereal::PandaState::PandaType::TRES); (hw_type == cereal::PandaState::PandaType::TRES);
can_reset_communications();
return; return;
} }
@ -37,8 +41,22 @@ bool Panda::comms_healthy() {
return handle->comms_healthy; return handle->comms_healthy;
} }
std::string Panda::hw_serial() {
return handle->hw_serial;
}
std::vector<std::string> Panda::list() { std::vector<std::string> Panda::list() {
return PandaUsbHandle::list(); std::vector<std::string> serials = PandaUsbHandle::list();
#ifndef __APPLE__
for (auto s : PandaSpiHandle::list()) {
if (std::find(serials.begin(), serials.end(), s) == serials.end()) {
serials.push_back(s);
}
}
#endif
return serials;
} }
void Panda::set_safety_model(cereal::CarParams::SafetyModel safety_model, uint16_t safety_param) { void Panda::set_safety_model(cereal::CarParams::SafetyModel safety_model, uint16_t safety_param) {
@ -174,10 +192,6 @@ void Panda::pack_can_buffer(const capnp::List<cereal::CanData>::Reader &can_data
int32_t pos = 0; int32_t pos = 0;
uint8_t send_buf[2 * USB_TX_SOFT_LIMIT]; uint8_t send_buf[2 * USB_TX_SOFT_LIMIT];
uint32_t magic = CAN_TRANSACTION_MAGIC;
memcpy(&send_buf[0], &magic, sizeof(uint32_t));
pos += sizeof(uint32_t);
for (auto cmsg : can_data_list) { for (auto cmsg : can_data_list) {
// check if the message is intended for this panda // check if the message is intended for this panda
uint8_t bus = cmsg.getSrc(); uint8_t bus = cmsg.getSrc();
@ -194,20 +208,25 @@ void Panda::pack_can_buffer(const capnp::List<cereal::CanData>::Reader &can_data
header.extended = (cmsg.getAddress() >= 0x800) ? 1 : 0; header.extended = (cmsg.getAddress() >= 0x800) ? 1 : 0;
header.data_len_code = data_len_code; header.data_len_code = data_len_code;
header.bus = bus - bus_offset; header.bus = bus - bus_offset;
header.checksum = 0;
memcpy(&send_buf[pos], (uint8_t *)&header, sizeof(can_header)); memcpy(&send_buf[pos], (uint8_t *)&header, sizeof(can_header));
pos += sizeof(can_header); memcpy(&send_buf[pos + sizeof(can_header)], (uint8_t *)can_data.begin(), can_data.size());
memcpy(&send_buf[pos], (uint8_t *)can_data.begin(), can_data.size()); uint32_t msg_size = sizeof(can_header) + can_data.size();
pos += can_data.size();
// set checksum
((can_header *) &send_buf[pos])->checksum = calculate_checksum(&send_buf[pos], msg_size);
pos += msg_size;
if (pos >= USB_TX_SOFT_LIMIT) { if (pos >= USB_TX_SOFT_LIMIT) {
write_func(send_buf, pos); write_func(send_buf, pos);
pos = sizeof(uint32_t); pos = 0;
} }
} }
// send remaining packets // send remaining packets
if (pos > sizeof(uint32_t)) write_func(send_buf, pos); if (pos > 0) write_func(send_buf, pos);
} }
void Panda::can_send(capnp::List<cereal::CanData>::Reader can_data_list) { void Panda::can_send(capnp::List<cereal::CanData>::Reader can_data_list) {
@ -217,36 +236,38 @@ void Panda::can_send(capnp::List<cereal::CanData>::Reader can_data_list) {
} }
bool Panda::can_receive(std::vector<can_frame>& out_vec) { bool Panda::can_receive(std::vector<can_frame>& out_vec) {
uint8_t data[RECV_SIZE]; // Check if enough space left in buffer to store RECV_SIZE data
int recv = handle->bulk_read(0x81, (uint8_t*)data, RECV_SIZE); assert(receive_buffer_size + RECV_SIZE <= sizeof(receive_buffer));
int recv = handle->bulk_read(0x81, &receive_buffer[receive_buffer_size], RECV_SIZE);
if (!comms_healthy()) { if (!comms_healthy()) {
return false; return false;
} }
if (recv == RECV_SIZE) { if (recv == RECV_SIZE) {
LOGW("Panda receive buffer full"); LOGW("Panda receive buffer full");
} }
receive_buffer_size += recv;
return (recv <= 0) ? true : unpack_can_buffer(data, recv, out_vec); return (recv <= 0) ? true : unpack_can_buffer(receive_buffer, receive_buffer_size, out_vec);
} }
bool Panda::unpack_can_buffer(uint8_t *data, int size, std::vector<can_frame> &out_vec) { void Panda::can_reset_communications() {
if (size < sizeof(uint32_t)) { handle->control_write(0xc0, 0, 0);
return true; }
}
uint32_t magic; bool Panda::unpack_can_buffer(uint8_t *data, uint32_t &size, std::vector<can_frame> &out_vec) {
memcpy(&magic, &data[0], sizeof(uint32_t)); int pos = 0;
if (magic != CAN_TRANSACTION_MAGIC) {
LOGE("CAN recv: buffer didn't start with magic");
handle->comms_healthy = false;
return false;
}
int pos = sizeof(uint32_t); while (pos <= size - sizeof(can_header)) {
while (pos < size) {
can_header header; can_header header;
memcpy(&header, &data[pos], sizeof(can_header)); memcpy(&header, &data[pos], sizeof(can_header));
const uint8_t data_len = dlc_to_len[header.data_len_code];
if (pos + sizeof(can_header) + data_len > size) {
// we don't have all the data for this message yet
break;
}
can_frame &canData = out_vec.emplace_back(); can_frame &canData = out_vec.emplace_back();
canData.busTime = 0; canData.busTime = 0;
canData.address = header.addr; canData.address = header.addr;
@ -258,10 +279,28 @@ bool Panda::unpack_can_buffer(uint8_t *data, int size, std::vector<can_frame> &o
canData.src += CAN_RETURNED_BUS_OFFSET; canData.src += CAN_RETURNED_BUS_OFFSET;
} }
const uint8_t data_len = dlc_to_len[header.data_len_code]; if (calculate_checksum(&data[pos], sizeof(can_header) + data_len) != 0) {
LOGE("Panda CAN checksum failed");
size = 0;
return false;
}
canData.dat.assign((char *)&data[pos + sizeof(can_header)], data_len); canData.dat.assign((char *)&data[pos + sizeof(can_header)], data_len);
pos += sizeof(can_header) + data_len; pos += sizeof(can_header) + data_len;
} }
// move the overflowing data to the beginning of the buffer for the next round
memmove(data, &data[pos], size - pos);
size -= pos;
return true; return true;
} }
uint8_t Panda::calculate_checksum(uint8_t *data, uint32_t len) {
uint8_t checksum = 0U;
for (uint32_t i = 0U; i < len; i++) {
checksum ^= data[i];
}
return checksum;
}

@ -30,6 +30,7 @@ struct __attribute__((packed)) can_header {
uint8_t returned : 1; uint8_t returned : 1;
uint8_t extended : 1; uint8_t extended : 1;
uint32_t addr : 29; uint32_t addr : 29;
uint8_t checksum : 8;
}; };
struct can_frame { struct can_frame {
@ -47,13 +48,13 @@ private:
public: public:
Panda(std::string serial="", uint32_t bus_offset=0); Panda(std::string serial="", uint32_t bus_offset=0);
std::string hw_serial;
cereal::PandaState::PandaType hw_type = cereal::PandaState::PandaType::UNKNOWN; cereal::PandaState::PandaType hw_type = cereal::PandaState::PandaType::UNKNOWN;
bool has_rtc = false; bool has_rtc = false;
const uint32_t bus_offset; const uint32_t bus_offset;
bool connected(); bool connected();
bool comms_healthy(); bool comms_healthy();
std::string hw_serial();
// Static functions // Static functions
static std::vector<std::string> list(); static std::vector<std::string> list();
@ -80,11 +81,16 @@ public:
void set_canfd_non_iso(uint16_t bus, bool non_iso); void set_canfd_non_iso(uint16_t bus, bool non_iso);
void can_send(capnp::List<cereal::CanData>::Reader can_data_list); void can_send(capnp::List<cereal::CanData>::Reader can_data_list);
bool can_receive(std::vector<can_frame>& out_vec); bool can_receive(std::vector<can_frame>& out_vec);
void can_reset_communications();
protected: protected:
// for unit tests // for unit tests
uint8_t receive_buffer[RECV_SIZE + sizeof(can_header) + 64];
uint32_t receive_buffer_size = 0;
Panda(uint32_t bus_offset) : bus_offset(bus_offset) {} Panda(uint32_t bus_offset) : bus_offset(bus_offset) {}
void pack_can_buffer(const capnp::List<cereal::CanData>::Reader &can_data_list, void pack_can_buffer(const capnp::List<cereal::CanData>::Reader &can_data_list,
std::function<void(uint8_t *, size_t)> write_func); std::function<void(uint8_t *, size_t)> write_func);
bool unpack_can_buffer(uint8_t *data, int size, std::vector<can_frame> &out_vec); bool unpack_can_buffer(uint8_t *data, uint32_t &size, std::vector<can_frame> &out_vec);
uint8_t calculate_checksum(uint8_t *data, uint32_t len);
}; };

@ -44,7 +44,7 @@ PandaUsbHandle::PandaUsbHandle(std::string serial) : PandaCommsHandle(serial) {
ret = libusb_get_string_descriptor_ascii(dev_handle, desc.iSerialNumber, desc_serial, std::size(desc_serial)); ret = libusb_get_string_descriptor_ascii(dev_handle, desc.iSerialNumber, desc_serial, std::size(desc_serial));
if (ret < 0) { goto fail; } if (ret < 0) { goto fail; }
auto hw_serial = std::string((char *)desc_serial, ret); hw_serial = std::string((char *)desc_serial, ret);
if (serial.empty() || serial == hw_serial) { if (serial.empty() || serial == hw_serial) {
break; break;
} }

@ -5,7 +5,9 @@
#include <cstdint> #include <cstdint>
#include <vector> #include <vector>
#ifndef __APPLE__
#include <linux/spi/spidev.h> #include <linux/spi/spidev.h>
#endif
#include <libusb-1.0/libusb.h> #include <libusb-1.0/libusb.h>
@ -21,6 +23,7 @@ public:
virtual ~PandaCommsHandle() {}; virtual ~PandaCommsHandle() {};
virtual void cleanup() = 0; virtual void cleanup() = 0;
std::string hw_serial;
std::atomic<bool> connected = true; std::atomic<bool> connected = true;
std::atomic<bool> comms_healthy = true; std::atomic<bool> comms_healthy = true;
static std::vector<std::string> list(); static std::vector<std::string> list();
@ -30,9 +33,6 @@ public:
virtual int control_read(uint8_t request, uint16_t param1, uint16_t param2, unsigned char *data, uint16_t length, unsigned int timeout=TIMEOUT) = 0; virtual int control_read(uint8_t request, uint16_t param1, uint16_t param2, unsigned char *data, uint16_t length, unsigned int timeout=TIMEOUT) = 0;
virtual int bulk_write(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout=TIMEOUT) = 0; virtual int bulk_write(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout=TIMEOUT) = 0;
virtual int bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout=TIMEOUT) = 0; virtual int bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout=TIMEOUT) = 0;
protected:
std::recursive_mutex hw_lock;
}; };
class PandaUsbHandle : public PandaCommsHandle { class PandaUsbHandle : public PandaCommsHandle {
@ -50,9 +50,11 @@ public:
private: private:
libusb_context *ctx = NULL; libusb_context *ctx = NULL;
libusb_device_handle *dev_handle = NULL; libusb_device_handle *dev_handle = NULL;
std::recursive_mutex hw_lock;
void handle_usb_issue(int err, const char func[]); void handle_usb_issue(int err, const char func[]);
}; };
#ifndef __APPLE__
class PandaSpiHandle : public PandaCommsHandle { class PandaSpiHandle : public PandaCommsHandle {
public: public:
PandaSpiHandle(std::string serial); PandaSpiHandle(std::string serial);
@ -69,9 +71,11 @@ private:
int spi_fd = -1; int spi_fd = -1;
uint8_t tx_buf[SPI_BUF_SIZE]; uint8_t tx_buf[SPI_BUF_SIZE];
uint8_t rx_buf[SPI_BUF_SIZE]; uint8_t rx_buf[SPI_BUF_SIZE];
inline static std::recursive_mutex hw_lock;
int wait_for_ack(spi_ioc_transfer &transfer, uint8_t ack); int wait_for_ack(spi_ioc_transfer &transfer, uint8_t ack);
int bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t rx_len); int bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t rx_len);
int spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len); int spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len);
int spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len); int spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len);
}; };
#endif

@ -7,7 +7,7 @@ import subprocess
from typing import List, NoReturn from typing import List, NoReturn
from functools import cmp_to_key from functools import cmp_to_key
from panda import DEFAULT_FW_FN, DEFAULT_H7_FW_FN, MCU_TYPE_H7, Panda, PandaDFU from panda import Panda, PandaDFU
from common.basedir import BASEDIR from common.basedir import BASEDIR
from common.params import Params from common.params import Params
from system.hardware import HARDWARE from system.hardware import HARDWARE
@ -15,10 +15,8 @@ from system.swaglog import cloudlog
def get_expected_signature(panda: Panda) -> bytes: def get_expected_signature(panda: Panda) -> bytes:
fn = DEFAULT_H7_FW_FN if (panda.get_mcu_type() == MCU_TYPE_H7) else DEFAULT_FW_FN
try: try:
return Panda.get_signature_from_firmware(fn) return Panda.get_signature_from_firmware(panda.get_mcu_type().config.app_path)
except Exception: except Exception:
cloudlog.exception("Error computing expected signature") cloudlog.exception("Error computing expected signature")
return b"" return b""

@ -1,9 +1,13 @@
#ifndef __APPLE__
#include <sys/file.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <linux/spi/spidev.h> #include <linux/spi/spidev.h>
#include <cassert> #include <cassert>
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include <iomanip>
#include <sstream>
#include "common/util.h" #include "common/util.h"
#include "common/timing.h" #include "common/timing.h"
@ -27,41 +31,77 @@ struct __attribute__((packed)) spi_header {
const int SPI_MAX_RETRIES = 5; const int SPI_MAX_RETRIES = 5;
const int SPI_ACK_TIMEOUT = 50; // milliseconds const int SPI_ACK_TIMEOUT = 50; // milliseconds
const std::string SPI_DEVICE = "/dev/spidev0.0";
class LockEx {
public:
LockEx(int fd, std::recursive_mutex &m) : fd(fd), m(m) {
m.lock();
flock(fd, LOCK_EX);
};
~LockEx() {
m.unlock();
flock(fd, LOCK_UN);
}
private:
int fd;
std::recursive_mutex &m;
};
PandaSpiHandle::PandaSpiHandle(std::string serial) : PandaCommsHandle(serial) { PandaSpiHandle::PandaSpiHandle(std::string serial) : PandaCommsHandle(serial) {
LOGD("opening SPI panda: %s", serial.c_str()); int ret;
const int uid_len = 12;
uint8_t uid[uid_len] = {0};
int err;
uint32_t spi_mode = SPI_MODE_0; uint32_t spi_mode = SPI_MODE_0;
uint32_t spi_speed = 30000000; uint32_t spi_speed = 30000000;
uint8_t spi_bits_per_word = 8; uint8_t spi_bits_per_word = 8;
spi_fd = open(serial.c_str(), O_RDWR); spi_fd = open(SPI_DEVICE.c_str(), O_RDWR);
if (spi_fd < 0) { if (spi_fd < 0) {
LOGE("failed opening SPI device %d", err); LOGE("failed opening SPI device %d", spi_fd);
goto fail; goto fail;
} }
// SPI settings // SPI settings
err = util::safe_ioctl(spi_fd, SPI_IOC_WR_MODE, &spi_mode); ret = util::safe_ioctl(spi_fd, SPI_IOC_WR_MODE, &spi_mode);
if (err < 0) { if (ret < 0) {
LOGE("failed setting SPI mode %d", err); LOGE("failed setting SPI mode %d", ret);
goto fail; goto fail;
} }
err = util::safe_ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed); ret = util::safe_ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed);
if (err < 0) { if (ret < 0) {
LOGE("failed setting SPI speed"); LOGE("failed setting SPI speed");
goto fail; goto fail;
} }
err = util::safe_ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits_per_word); ret = util::safe_ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits_per_word);
if (err < 0) { if (ret < 0) {
LOGE("failed setting SPI bits per word"); LOGE("failed setting SPI bits per word");
goto fail; goto fail;
} }
// get hw UID/serial
ret = control_read(0xc3, 0, 0, uid, uid_len);
if (ret == uid_len) {
std::stringstream stream;
for (int i = 0; i < uid_len; i++) {
stream << std::hex << std::setw(2) << std::setfill('0') << int(uid[i]);
}
hw_serial = stream.str();
} else {
LOGD("failed to get serial %d", ret);
goto fail;
}
if (!serial.empty() && (serial != hw_serial)) {
goto fail;
}
return; return;
fail: fail:
@ -84,6 +124,7 @@ void PandaSpiHandle::cleanup() {
int PandaSpiHandle::control_write(uint8_t request, uint16_t param1, uint16_t param2, unsigned int timeout) { int PandaSpiHandle::control_write(uint8_t request, uint16_t param1, uint16_t param2, unsigned int timeout) {
LockEx lock(spi_fd, hw_lock);
ControlPacket_t packet = { ControlPacket_t packet = {
.request = request, .request = request,
.param1 = param1, .param1 = param1,
@ -94,6 +135,7 @@ int PandaSpiHandle::control_write(uint8_t request, uint16_t param1, uint16_t par
} }
int PandaSpiHandle::control_read(uint8_t request, uint16_t param1, uint16_t param2, unsigned char *data, uint16_t length, unsigned int timeout) { int PandaSpiHandle::control_read(uint8_t request, uint16_t param1, uint16_t param2, unsigned char *data, uint16_t length, unsigned int timeout) {
LockEx lock(spi_fd, hw_lock);
ControlPacket_t packet = { ControlPacket_t packet = {
.request = request, .request = request,
.param1 = param1, .param1 = param1,
@ -104,15 +146,15 @@ int PandaSpiHandle::control_read(uint8_t request, uint16_t param1, uint16_t para
} }
int PandaSpiHandle::bulk_write(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) { int PandaSpiHandle::bulk_write(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) {
LockEx lock(spi_fd, hw_lock);
return bulk_transfer(endpoint, data, length, NULL, 0); return bulk_transfer(endpoint, data, length, NULL, 0);
} }
int PandaSpiHandle::bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) { int PandaSpiHandle::bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) {
LockEx lock(spi_fd, hw_lock);
return bulk_transfer(endpoint, NULL, 0, data, length); return bulk_transfer(endpoint, NULL, 0, data, length);
} }
int PandaSpiHandle::bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t rx_len) { int PandaSpiHandle::bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t rx_len) {
std::lock_guard lk(hw_lock);
const int xfer_size = 0x40 * 15; const int xfer_size = 0x40 * 15;
int ret = 0; int ret = 0;
@ -143,7 +185,12 @@ int PandaSpiHandle::bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t t
} }
std::vector<std::string> PandaSpiHandle::list() { std::vector<std::string> PandaSpiHandle::list() {
// TODO: list all pandas available over SPI try {
PandaSpiHandle sh("");
return {sh.hw_serial};
} catch (std::exception &e) {
// no panda on SPI
}
return {}; return {};
} }
@ -167,7 +214,6 @@ int PandaSpiHandle::spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint1
int ret; int ret;
int count = SPI_MAX_RETRIES; int count = SPI_MAX_RETRIES;
std::lock_guard lk(hw_lock);
do { do {
// TODO: handle error // TODO: handle error
ret = spi_transfer(endpoint, tx_data, tx_len, rx_data, max_rx_len); ret = spi_transfer(endpoint, tx_data, tx_len, rx_data, max_rx_len);
@ -195,7 +241,7 @@ int PandaSpiHandle::wait_for_ack(spi_ioc_transfer &transfer, uint8_t ack) {
// handle timeout // handle timeout
if (millis_since_boot() - start_millis > SPI_ACK_TIMEOUT) { if (millis_since_boot() - start_millis > SPI_ACK_TIMEOUT) {
LOGE("SPI: timed out waiting for ACK"); LOGD("SPI: timed out waiting for ACK");
return -1; return -1;
} }
} }
@ -270,7 +316,10 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx
goto transfer_fail; goto transfer_fail;
} }
rx_data_len = *(uint16_t *)(rx_buf+1); rx_data_len = *(uint16_t *)(rx_buf+1);
assert(rx_data_len < SPI_BUF_SIZE); if (rx_data_len >= SPI_BUF_SIZE) {
LOGE("SPI: RX data len larger than buf size %d", rx_data_len);
goto transfer_fail;
}
// Read data // Read data
transfer.len = rx_data_len + 1; transfer.len = rx_data_len + 1;
@ -294,3 +343,4 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx
transfer_fail: transfer_fail:
return ret; return ret;
} }
#endif

@ -51,7 +51,7 @@ class TestBoardd(unittest.TestCase):
cp.safetyConfigs = [safety_config]*num_pandas cp.safetyConfigs = [safety_config]*num_pandas
params = Params() params = Params()
params.put("CarVin", b"0"*17) params.put_bool("FirmwareObdQueryDone", True)
params.put_bool("ControlsReady", True) params.put_bool("ControlsReady", True)
params.put("CarParams", cp.to_bytes()) params.put("CarParams", cp.to_bytes())

@ -16,7 +16,8 @@ int random_int(int min, int max) {
struct PandaTest : public Panda { struct PandaTest : public Panda {
PandaTest(uint32_t bus_offset, int can_list_size, cereal::PandaState::PandaType hw_type); PandaTest(uint32_t bus_offset, int can_list_size, cereal::PandaState::PandaType hw_type);
void test_can_send(); void test_can_send();
void test_can_recv(); void test_can_recv(uint32_t chunk_size = 0);
void test_chunked_can_recv();
std::map<int, std::string> test_data; std::map<int, std::string> test_data;
int can_list_size = 0; int can_list_size = 0;
@ -58,11 +59,7 @@ PandaTest::PandaTest(uint32_t bus_offset_, int can_list_size, cereal::PandaState
void PandaTest::test_can_send() { void PandaTest::test_can_send() {
std::vector<uint8_t> unpacked_data; std::vector<uint8_t> unpacked_data;
this->pack_can_buffer(can_data_list, [&](uint8_t *chunk, size_t size) { this->pack_can_buffer(can_data_list, [&](uint8_t *chunk, size_t size) {
uint32_t magic; unpacked_data.insert(unpacked_data.end(), chunk, &chunk[size]);
memcpy(&magic, &chunk[0], sizeof(uint32_t));
REQUIRE(magic == CAN_TRANSACTION_MAGIC);
unpacked_data.insert(unpacked_data.end(), &chunk[sizeof(uint32_t)], &chunk[size]);
}); });
REQUIRE(unpacked_data.size() == total_pakets_size); REQUIRE(unpacked_data.size() == total_pakets_size);
@ -77,16 +74,30 @@ void PandaTest::test_can_send() {
REQUIRE(header.addr == cnt); REQUIRE(header.addr == cnt);
REQUIRE(test_data.find(data_len) != test_data.end()); REQUIRE(test_data.find(data_len) != test_data.end());
const std::string &dat = test_data[data_len]; const std::string &dat = test_data[data_len];
REQUIRE(memcmp(dat.data(), &unpacked_data[pos + 5], dat.size()) == 0); REQUIRE(memcmp(dat.data(), &unpacked_data[pos + sizeof(can_header)], dat.size()) == 0);
++cnt; ++cnt;
} }
REQUIRE(cnt == can_list_size); REQUIRE(cnt == can_list_size);
} }
void PandaTest::test_can_recv() { void PandaTest::test_can_recv(uint32_t rx_chunk_size) {
std::vector<can_frame> frames; std::vector<can_frame> frames;
this->pack_can_buffer(can_data_list, [&](uint8_t *data, size_t size) { this->pack_can_buffer(can_data_list, [&](uint8_t *data, uint32_t size) {
this->unpack_can_buffer(data, size, frames); if (rx_chunk_size == 0) {
REQUIRE(this->unpack_can_buffer(data, size, frames));
} else {
this->receive_buffer_size = 0;
uint32_t pos = 0;
while(pos < size) {
uint32_t chunk_size = std::min(rx_chunk_size, size - pos);
memcpy(&this->receive_buffer[this->receive_buffer_size], &data[pos], chunk_size);
this->receive_buffer_size += chunk_size;
pos += chunk_size;
REQUIRE(this->unpack_can_buffer(this->receive_buffer, this->receive_buffer_size, frames));
}
}
}); });
REQUIRE(frames.size() == can_list_size); REQUIRE(frames.size() == can_list_size);
@ -109,6 +120,9 @@ TEST_CASE("send/recv CAN 2.0 packets") {
SECTION("can_receive") { SECTION("can_receive") {
test.test_can_recv(); test.test_can_recv();
} }
SECTION("chunked_can_receive") {
test.test_can_recv(0x40);
}
} }
TEST_CASE("send/recv CAN FD packets") { TEST_CASE("send/recv CAN FD packets") {
@ -122,4 +136,7 @@ TEST_CASE("send/recv CAN FD packets") {
SECTION("can_receive") { SECTION("can_receive") {
test.test_can_recv(); test.test_can_recv();
} }
SECTION("chunked_can_receive") {
test.test_can_recv(0x40);
}
} }

@ -1,5 +1,6 @@
{% set footnote_tag = '[<sup>{}</sup>](#footnotes)' -%} {% set footnote_tag = '[<sup>{}</sup>](#footnotes)' -%}
{% set star_icon = '[![star](assets/icon-star-{}.svg)](##)' -%} {% set star_icon = '[![star](assets/icon-star-{}.svg)](##)' -%}
{% set video_icon = '<a href="{}" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>' -%}
<!--- AUTOGENERATED FROM selfdrive/car/CARS_template.md, DO NOT EDIT. ---> <!--- AUTOGENERATED FROM selfdrive/car/CARS_template.md, DO NOT EDIT. --->
@ -12,7 +13,7 @@ A supported vehicle is one that just works when you install a comma three. All s
|{{Column | map(attribute='value') | join('|')}}| |{{Column | map(attribute='value') | join('|')}}|
|---|---|---|{% for _ in range((Column | length) - 3) %}{{':---:|'}}{% endfor +%} |---|---|---|{% for _ in range((Column | length) - 3) %}{{':---:|'}}{% endfor +%}
{% for car_info in all_car_info %} {% for car_info in all_car_info %}
|{% for column in Column %}{{car_info.get_column(column, star_icon, footnote_tag)}}|{% endfor %} |{% for column in Column %}{{car_info.get_column(column, star_icon, video_icon, footnote_tag)}}|{% endfor %}
{% endfor %} {% endfor %}

@ -73,7 +73,7 @@ def dbc_dict(pt_dbc, radar_dbc, chassis_dbc=None, body_dbc=None) -> Dict[str, st
return {'pt': pt_dbc, 'radar': radar_dbc, 'chassis': chassis_dbc, 'body': body_dbc} return {'pt': pt_dbc, 'radar': radar_dbc, 'chassis': chassis_dbc, 'body': body_dbc}
def apply_std_steer_torque_limits(apply_torque, apply_torque_last, driver_torque, LIMITS): def apply_driver_steer_torque_limits(apply_torque, apply_torque_last, driver_torque, LIMITS):
# limits due to driver torque # limits due to driver torque
driver_max_torque = LIMITS.STEER_MAX + (LIMITS.STEER_DRIVER_ALLOWANCE + driver_torque * LIMITS.STEER_DRIVER_FACTOR) * LIMITS.STEER_DRIVER_MULTIPLIER driver_max_torque = LIMITS.STEER_MAX + (LIMITS.STEER_DRIVER_ALLOWANCE + driver_torque * LIMITS.STEER_DRIVER_FACTOR) * LIMITS.STEER_DRIVER_MULTIPLIER
@ -93,29 +93,37 @@ def apply_std_steer_torque_limits(apply_torque, apply_torque_last, driver_torque
return int(round(float(apply_torque))) return int(round(float(apply_torque)))
def apply_toyota_steer_torque_limits(apply_torque, apply_torque_last, motor_torque, LIMITS): def apply_dist_to_meas_limits(val, val_last, val_meas,
# limits due to comparison of commanded torque VS motor reported torque STEER_DELTA_UP, STEER_DELTA_DOWN,
max_lim = min(max(motor_torque + LIMITS.STEER_ERROR_MAX, LIMITS.STEER_ERROR_MAX), LIMITS.STEER_MAX) STEER_ERROR_MAX, STEER_MAX):
min_lim = max(min(motor_torque - LIMITS.STEER_ERROR_MAX, -LIMITS.STEER_ERROR_MAX), -LIMITS.STEER_MAX) # limits due to comparison of commanded val VS measured val (torque/angle/curvature)
max_lim = min(max(val_meas + STEER_ERROR_MAX, STEER_ERROR_MAX), STEER_MAX)
min_lim = max(min(val_meas - STEER_ERROR_MAX, -STEER_ERROR_MAX), -STEER_MAX)
apply_torque = clip(apply_torque, min_lim, max_lim) val = clip(val, min_lim, max_lim)
# slow rate if steer torque increases in magnitude # slow rate if val increases in magnitude
if apply_torque_last > 0: if val_last > 0:
apply_torque = clip(apply_torque, val = clip(val,
max(apply_torque_last - LIMITS.STEER_DELTA_DOWN, -LIMITS.STEER_DELTA_UP), max(val_last - STEER_DELTA_DOWN, -STEER_DELTA_UP),
apply_torque_last + LIMITS.STEER_DELTA_UP) val_last + STEER_DELTA_UP)
else: else:
apply_torque = clip(apply_torque, val = clip(val,
apply_torque_last - LIMITS.STEER_DELTA_UP, val_last - STEER_DELTA_UP,
min(apply_torque_last + LIMITS.STEER_DELTA_DOWN, LIMITS.STEER_DELTA_UP)) min(val_last + STEER_DELTA_DOWN, STEER_DELTA_UP))
return int(round(float(apply_torque))) return float(val)
def apply_meas_steer_torque_limits(apply_torque, apply_torque_last, motor_torque, LIMITS):
return int(round(apply_dist_to_meas_limits(apply_torque, apply_torque_last, motor_torque,
LIMITS.STEER_DELTA_UP, LIMITS.STEER_DELTA_DOWN,
LIMITS.STEER_ERROR_MAX, LIMITS.STEER_MAX)))
def apply_std_steer_angle_limits(apply_angle, apply_angle_last, v_ego, LIMITS): def apply_std_steer_angle_limits(apply_angle, apply_angle_last, v_ego, LIMITS):
# pick angle rate limits based on wind up/down # pick angle rate limits based on wind up/down
steer_up = apply_angle_last * apply_angle > 0. and abs(apply_angle) > abs(apply_angle_last) steer_up = apply_angle_last * apply_angle >= 0. and abs(apply_angle) > abs(apply_angle_last)
rate_limits = LIMITS.ANGLE_RATE_LIMIT_UP if steer_up else LIMITS.ANGLE_RATE_LIMIT_DOWN rate_limits = LIMITS.ANGLE_RATE_LIMIT_UP if steer_up else LIMITS.ANGLE_RATE_LIMIT_DOWN
angle_rate_lim = interp(v_ego, rate_limits.speed_bp, rate_limits.angle_v) angle_rate_lim = interp(v_ego, rate_limits.speed_bp, rate_limits.angle_v)

@ -35,7 +35,7 @@ class CarController:
torque -= deadband torque -= deadband
return torque return torque
def update(self, CC, CS): def update(self, CC, CS, now_nanos):
torque_l = 0 torque_l = 0
torque_r = 0 torque_r = 0

@ -24,7 +24,7 @@ class CarInterface(CarInterfaceBase):
ret.wheelSpeedFactor = SPEED_FROM_RPM ret.wheelSpeedFactor = SPEED_FROM_RPM
ret.centerToFront = ret.wheelbase * 0.44 ret.centerToFront = ret.wheelbase * 0.44
ret.radarOffCan = True ret.radarUnavailable = True
ret.openpilotLongitudinalControl = True ret.openpilotLongitudinalControl = True
ret.steerControlType = car.CarParams.SteerControlType.angle ret.steerControlType = car.CarParams.SteerControlType.angle
@ -43,5 +43,5 @@ class CarInterface(CarInterfaceBase):
return ret return ret
def apply(self, c): def apply(self, c, now_nanos):
return self.CC.update(c, self.CS) return self.CC.update(c, self.CS, now_nanos)

@ -8,7 +8,7 @@ from system.version import is_comma_remote, is_tested_branch
from selfdrive.car.interfaces import get_interface_attr from selfdrive.car.interfaces import get_interface_attr
from selfdrive.car.fingerprints import eliminate_incompatible_cars, all_legacy_fingerprint_cars from selfdrive.car.fingerprints import eliminate_incompatible_cars, all_legacy_fingerprint_cars
from selfdrive.car.vin import get_vin, is_valid_vin, VIN_UNKNOWN from selfdrive.car.vin import get_vin, is_valid_vin, VIN_UNKNOWN
from selfdrive.car.fw_versions import get_fw_versions_ordered, match_fw_to_car, get_present_ecus from selfdrive.car.fw_versions import disable_obd_multiplexing, get_fw_versions_ordered, match_fw_to_car, get_present_ecus
from system.swaglog import cloudlog from system.swaglog import cloudlog
import cereal.messaging as messaging import cereal.messaging as messaging
from selfdrive.car import gen_empty_fingerprint from selfdrive.car import gen_empty_fingerprint
@ -99,7 +99,7 @@ def fingerprint(logcan, sendcan, num_pandas):
else: else:
cloudlog.warning("Getting VIN & FW versions") cloudlog.warning("Getting VIN & FW versions")
vin_rx_addr, vin = get_vin(logcan, sendcan, bus) vin_rx_addr, vin = get_vin(logcan, sendcan, bus)
ecu_rx_addrs = get_present_ecus(logcan, sendcan) ecu_rx_addrs = get_present_ecus(logcan, sendcan, num_pandas=num_pandas)
car_fw = get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, num_pandas=num_pandas) car_fw = get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, num_pandas=num_pandas)
cached = False cached = False
@ -113,7 +113,10 @@ def fingerprint(logcan, sendcan, num_pandas):
cloudlog.event("Malformed VIN", vin=vin, error=True) cloudlog.event("Malformed VIN", vin=vin, error=True)
vin = VIN_UNKNOWN vin = VIN_UNKNOWN
cloudlog.warning("VIN %s", vin) cloudlog.warning("VIN %s", vin)
Params().put("CarVin", vin)
params = Params()
params.put("CarVin", vin)
disable_obd_multiplexing(params)
finger = gen_empty_fingerprint() finger = gen_empty_fingerprint()
candidate_cars = {i: all_legacy_fingerprint_cars() for i in [0, 1]} # attempt fingerprint on both bus 0 and 1 candidate_cars = {i: all_legacy_fingerprint_cars() for i in [0, 1]} # attempt fingerprint on both bus 0 and 1
@ -173,17 +176,15 @@ def fingerprint(logcan, sendcan, num_pandas):
return car_fingerprint, finger, vin, car_fw, source, exact_match return car_fingerprint, finger, vin, car_fw, source, exact_match
def get_car(logcan, sendcan, num_pandas=1): def get_car(logcan, sendcan, experimental_long_allowed, num_pandas=1):
candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(logcan, sendcan, num_pandas) candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(logcan, sendcan, num_pandas)
if candidate is None: if candidate is None:
cloudlog.warning("car doesn't match any fingerprints: %r", fingerprints) cloudlog.warning("car doesn't match any fingerprints: %r", fingerprints)
candidate = "mock" candidate = "mock"
experimental_long = Params().get_bool("ExperimentalLongitudinalEnabled")
CarInterface, CarController, CarState = interfaces[candidate] CarInterface, CarController, CarState = interfaces[candidate]
CP = CarInterface.get_params(candidate, fingerprints, car_fw, experimental_long) CP = CarInterface.get_params(candidate, fingerprints, car_fw, experimental_long_allowed)
CP.carVin = vin CP.carVin = vin
CP.carFw = car_fw CP.carFw = car_fw
CP.fingerprintSource = source CP.fingerprintSource = source

@ -1,6 +1,6 @@
from opendbc.can.packer import CANPacker from opendbc.can.packer import CANPacker
from common.realtime import DT_CTRL from common.realtime import DT_CTRL
from selfdrive.car import apply_toyota_steer_torque_limits from selfdrive.car import apply_meas_steer_torque_limits
from selfdrive.car.chrysler.chryslercan import create_lkas_hud, create_lkas_command, create_cruise_buttons from selfdrive.car.chrysler.chryslercan import create_lkas_hud, create_lkas_command, create_cruise_buttons
from selfdrive.car.chrysler.values import RAM_CARS, CarControllerParams, ChryslerFlags from selfdrive.car.chrysler.values import RAM_CARS, CarControllerParams, ChryslerFlags
@ -19,7 +19,7 @@ class CarController:
self.packer = CANPacker(dbc_name) self.packer = CANPacker(dbc_name)
self.params = CarControllerParams(CP) self.params = CarControllerParams(CP)
def update(self, CC, CS): def update(self, CC, CS, now_nanos):
can_sends = [] can_sends = []
lkas_active = CC.latActive and self.lkas_control_bit_prev lkas_active = CC.latActive and self.lkas_control_bit_prev
@ -67,7 +67,7 @@ class CarController:
# steer torque # steer torque
new_steer = int(round(CC.actuators.steer * self.params.STEER_MAX)) new_steer = int(round(CC.actuators.steer * self.params.STEER_MAX))
apply_steer = apply_toyota_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorqueEps, self.params) apply_steer = apply_meas_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorqueEps, self.params)
if not lkas_active or not lkas_control_bit: if not lkas_active or not lkas_control_bit:
apply_steer = 0 apply_steer = 0
self.apply_steer_last = apply_steer self.apply_steer_last = apply_steer

@ -81,8 +81,9 @@ class CarState(CarStateBase):
if self.CP.carFingerprint in RAM_CARS: if self.CP.carFingerprint in RAM_CARS:
self.auto_high_beam = cp_cam.vl["DAS_6"]['AUTO_HIGH_BEAM_ON'] # Auto High Beam isn't Located in this message on chrysler or jeep currently located in 729 message self.auto_high_beam = cp_cam.vl["DAS_6"]['AUTO_HIGH_BEAM_ON'] # Auto High Beam isn't Located in this message on chrysler or jeep currently located in 729 message
ret.steerFaultTemporary = cp.vl["EPS_3"]["DASM_FAULT"] == 1 ret.steerFaultTemporary = cp.vl["EPS_3"]["DASM_FAULT"] == 1
else: else:
ret.steerFaultTemporary = cp.vl["EPS_2"]["LKAS_TEMPORARY_FAULT"] == 1
ret.steerFaultPermanent = cp.vl["EPS_2"]["LKAS_STATE"] == 4 ret.steerFaultPermanent = cp.vl["EPS_2"]["LKAS_STATE"] == 4
# blindspot sensors # blindspot sensors
@ -135,6 +136,7 @@ class CarState(CarStateBase):
("COUNTER", "EPS_2",), ("COUNTER", "EPS_2",),
("COLUMN_TORQUE", "EPS_2"), ("COLUMN_TORQUE", "EPS_2"),
("EPS_TORQUE_MOTOR", "EPS_2"), ("EPS_TORQUE_MOTOR", "EPS_2"),
("LKAS_TEMPORARY_FAULT", "EPS_2"),
("LKAS_STATE", "EPS_2"), ("LKAS_STATE", "EPS_2"),
("COUNTER", "CRUISE_BUTTONS"), ("COUNTER", "CRUISE_BUTTONS"),
] ]

@ -2,7 +2,7 @@
from cereal import car from cereal import car
from panda import Panda from panda import Panda
from selfdrive.car import STD_CARGO_KG, get_safety_config from selfdrive.car import STD_CARGO_KG, get_safety_config
from selfdrive.car.chrysler.values import CAR, DBC, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags from selfdrive.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags
from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.interfaces import CarInterfaceBase
@ -12,7 +12,8 @@ class CarInterface(CarInterfaceBase):
ret.carName = "chrysler" ret.carName = "chrysler"
ret.dashcamOnly = candidate in RAM_HD ret.dashcamOnly = candidate in RAM_HD
ret.radarOffCan = DBC[candidate]['radar'] is None # radar parsing needs some work, see https://github.com/commaai/openpilot/issues/26842
ret.radarUnavailable = True # DBC[candidate]['radar'] is None
ret.steerActuatorDelay = 0.1 ret.steerActuatorDelay = 0.1
ret.steerLimitTimer = 0.4 ret.steerLimitTimer = 0.4
@ -24,6 +25,7 @@ class CarInterface(CarInterfaceBase):
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_CHRYSLER_RAM_DT ret.safetyConfigs[0].safetyParam |= Panda.FLAG_CHRYSLER_RAM_DT
ret.minSteerSpeed = 3.8 # m/s ret.minSteerSpeed = 3.8 # m/s
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
if candidate not in RAM_CARS: if candidate not in RAM_CARS:
# Newer FW versions standard on the following platforms, or flashed by a dealer onto older platforms have a higher minimum steering speed. # Newer FW versions standard on the following platforms, or flashed by a dealer onto older platforms have a higher minimum steering speed.
new_eps_platform = candidate in (CAR.PACIFICA_2019_HYBRID, CAR.PACIFICA_2020, CAR.JEEP_CHEROKEE_2019) new_eps_platform = candidate in (CAR.PACIFICA_2019_HYBRID, CAR.PACIFICA_2020, CAR.JEEP_CHEROKEE_2019)
@ -36,6 +38,8 @@ class CarInterface(CarInterfaceBase):
ret.mass = 2242. + STD_CARGO_KG ret.mass = 2242. + STD_CARGO_KG
ret.wheelbase = 3.089 ret.wheelbase = 3.089
ret.steerRatio = 16.2 # Pacifica Hybrid 2017 ret.steerRatio = 16.2 # Pacifica Hybrid 2017
ret.lateralTuning.init('pid')
ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kiBP = [[9., 20.], [9., 20.]] ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kiBP = [[9., 20.], [9., 20.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.15, 0.30], [0.03, 0.05]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.15, 0.30], [0.03, 0.05]]
ret.lateralTuning.pid.kf = 0.00006 ret.lateralTuning.pid.kf = 0.00006
@ -46,6 +50,8 @@ class CarInterface(CarInterfaceBase):
ret.wheelbase = 2.71 ret.wheelbase = 2.71
ret.steerRatio = 16.7 ret.steerRatio = 16.7
ret.steerActuatorDelay = 0.2 ret.steerActuatorDelay = 0.2
ret.lateralTuning.init('pid')
ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kiBP = [[9., 20.], [9., 20.]] ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kiBP = [[9., 20.], [9., 20.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.15, 0.30], [0.03, 0.05]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.15, 0.30], [0.03, 0.05]]
ret.lateralTuning.pid.kf = 0.00006 ret.lateralTuning.pid.kf = 0.00006
@ -56,11 +62,10 @@ class CarInterface(CarInterfaceBase):
ret.wheelbase = 3.88 ret.wheelbase = 3.88
ret.steerRatio = 16.3 ret.steerRatio = 16.3
ret.mass = 2493. + STD_CARGO_KG ret.mass = 2493. + STD_CARGO_KG
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
ret.minSteerSpeed = 14.5 ret.minSteerSpeed = 14.5
for fw in car_fw: # Older EPS FW allow steer to zero
if fw.ecu == 'eps' and fw.fwVersion.startswith((b"68312176", b"68273275")): if any(fw.ecu == 'eps' and fw.fwVersion[:4] <= b"6831" for fw in car_fw):
ret.minSteerSpeed = 0. ret.minSteerSpeed = 0.
elif candidate == CAR.RAM_HD: elif candidate == CAR.RAM_HD:
ret.steerActuatorDelay = 0.2 ret.steerActuatorDelay = 0.2
@ -100,5 +105,5 @@ class CarInterface(CarInterfaceBase):
return ret return ret
def apply(self, c): def apply(self, c, now_nanos):
return self.CC.update(c, self.CS) return self.CC.update(c, self.CS, now_nanos)

@ -45,12 +45,13 @@ def _address_to_track(address):
class RadarInterface(RadarInterfaceBase): class RadarInterface(RadarInterfaceBase):
def __init__(self, CP): def __init__(self, CP):
super().__init__(CP) super().__init__(CP)
self.CP = CP
self.rcp = _create_radar_can_parser(CP.carFingerprint) self.rcp = _create_radar_can_parser(CP.carFingerprint)
self.updated_messages = set() self.updated_messages = set()
self.trigger_msg = LAST_MSG self.trigger_msg = LAST_MSG
def update(self, can_strings): def update(self, can_strings):
if self.rcp is None: if self.rcp is None or self.CP.radarUnavailable:
return super().update(None) return super().update(None)
vls = self.rcp.update_strings(can_strings) vls = self.rcp.update_strings(can_strings)

@ -56,6 +56,7 @@ RAM_DT = {CAR.RAM_1500, }
RAM_HD = {CAR.RAM_HD, } RAM_HD = {CAR.RAM_HD, }
RAM_CARS = RAM_DT | RAM_HD RAM_CARS = RAM_DT | RAM_HD
@dataclass @dataclass
class ChryslerCarInfo(CarInfo): class ChryslerCarInfo(CarInfo):
package: str = "Adaptive Cruise Control (ACC)" package: str = "Adaptive Cruise Control (ACC)"
@ -92,7 +93,7 @@ CAR_INFO: Dict[str, Optional[Union[ChryslerCarInfo, List[ChryslerCarInfo]]]] = {
FINGERPRINTS = { FINGERPRINTS = {
CAR.PACIFICA_2017_HYBRID: [{ CAR.PACIFICA_2017_HYBRID: [{
168: 8, 257: 5, 258: 8, 264: 8, 268: 8, 270: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 291: 8, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 515: 7, 516: 7, 517: 7, 518: 7, 520: 8, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 4, 571: 3, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 653: 8, 654: 8, 655: 8, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 701: 8, 704: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 746: 5, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 782: 8, 784: 8, 788:3, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 878: 8, 882: 8, 897: 8, 908: 8, 924: 3, 926: 3, 929: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 956: 8, 958: 8, 959: 8, 969: 4, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1082: 8, 1083: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1225: 8, 1235: 8, 1242: 8, 1246: 8, 1250: 8, 1284: 8, 1537: 8, 1538: 8, 1562: 8, 1568: 8, 1856: 8, 1858: 8, 1860: 8, 1865: 8, 1875: 8, 1882: 8, 1886: 8, 1890: 8, 1892: 8, 2016: 8, 2024: 8 168: 8, 257: 5, 258: 8, 264: 8, 268: 8, 270: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 291: 8, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 515: 7, 516: 7, 517: 7, 518: 7, 520: 8, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 4, 571: 3, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 653: 8, 654: 8, 655: 8, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 701: 8, 704: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 746: 5, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 782: 8, 784: 8, 788: 3, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 840: 8, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 878: 8, 882: 8, 897: 8, 908: 8, 924: 3, 926: 3, 929: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 956: 8, 958: 8, 959: 8, 969: 4, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1082: 8, 1083: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1225: 8, 1235: 8, 1242: 8, 1246: 8, 1250: 8, 1284: 8, 1537: 8, 1538: 8, 1562: 8, 1568: 8, 1856: 8, 1858: 8, 1860: 8, 1865: 8, 1875: 8, 1882: 8, 1886: 8, 1890: 8, 1892: 8, 2016: 8, 2024: 8
}], }],
CAR.PACIFICA_2018: [{ CAR.PACIFICA_2018: [{
55: 8, 257: 5, 258: 8, 264: 8, 268: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 516: 7, 517: 7, 520: 8, 524: 8, 526: 6, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 656: 4, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 746: 5, 752: 2, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 882: 8, 897: 8, 924: 8, 926: 3, 937: 8, 947: 8, 948: 8, 969: 4, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1098: 8, 1100: 8, 1537: 8, 1538: 8, 1562: 8 55: 8, 257: 5, 258: 8, 264: 8, 268: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 516: 7, 517: 7, 520: 8, 524: 8, 526: 6, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 656: 4, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 746: 5, 752: 2, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 882: 8, 897: 8, 924: 8, 926: 3, 937: 8, 947: 8, 948: 8, 969: 4, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1098: 8, 1100: 8, 1537: 8, 1538: 8, 1562: 8
@ -134,7 +135,7 @@ FINGERPRINTS = {
}], }],
CAR.JEEP_CHEROKEE_2019: [{ CAR.JEEP_CHEROKEE_2019: [{
# Jeep Grand Cherokee 2019, including most 2020 models # Jeep Grand Cherokee 2019, including most 2020 models
55: 8, 168: 8, 179: 8, 181: 8, 256: 4, 257: 5, 258: 8, 264: 8, 268: 8, 272: 6, 273: 6, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 341: 8, 344: 8, 352: 8, 362: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 530: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 618: 8, 624: 8, 625: 8, 632: 8, 639: 8, 640: 1, 656: 4, 658: 6, 660: 8, 671: 8, 672: 8, 676: 8, 678: 8, 680: 8, 683: 8, 684: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 738: 8, 746: 5, 752: 2, 754: 8, 760: 8, 761: 8, 764: 8, 766: 8, 773: 8, 776: 8, 779: 8, 782: 8, 783: 8, 784: 8, 785: 8, 792: 8, 799: 8, 800: 8, 804: 8, 806: 2, 808: 8, 810: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 831: 6, 832: 8, 838: 2, 840: 8, 844: 5, 847: 1, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 882: 8, 897: 8, 906: 8, 924: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 960: 4, 968: 8, 969: 4, 970: 8, 973: 8, 974: 5, 976: 8, 977: 4, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1062: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1223: 8, 1225: 8, 1227: 8, 1235: 8, 1242: 8, 1250: 8, 1251: 8, 1252: 8, 1254: 8, 1264: 8, 1284: 8, 1536: 8, 1537: 8, 1543: 8, 1545: 8, 1562: 8, 1568: 8, 1570: 8, 1572: 8, 1593: 8, 1856: 8, 1858: 8, 1860: 8, 1863: 8, 1865: 8, 1867: 8, 1875: 8, 1882: 8, 1890: 8, 1891: 8, 1892: 8, 1894: 8, 1896: 8, 1904: 8, 2015: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8 55: 8, 168: 8, 179: 8, 181: 8, 256: 4, 257: 5, 258: 8, 264: 8, 268: 8, 272: 6, 273: 6, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 341: 8, 344: 8, 352: 8, 362: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 530: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 618: 8, 624: 8, 625: 8, 632: 8, 639: 8, 640: 1, 656: 4, 658: 6, 660: 8, 671: 8, 672: 8, 676: 8, 678: 8, 680: 8, 683: 8, 684: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 738: 8, 746: 5, 752: 2, 754: 8, 760: 8, 761: 8, 764: 8, 766: 8, 773: 8, 776: 8, 779: 8, 782: 8, 783: 8, 784: 8, 785: 8, 792: 8, 799: 8, 800: 8, 804: 8, 806: 2, 808: 8, 810: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 831: 6, 832: 8, 838: 2, 840: 8, 844: 5, 847: 1, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 874: 2, 882: 8, 897: 8, 906: 8, 924: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 960: 4, 968: 8, 969: 4, 970: 8, 973: 8, 974: 5, 976: 8, 977: 4, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1062: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1223: 8, 1225: 8, 1227: 8, 1235: 8, 1242: 8, 1250: 8, 1251: 8, 1252: 8, 1254: 8, 1264: 8, 1284: 8, 1536: 8, 1537: 8, 1543: 8, 1545: 8, 1562: 8, 1568: 8, 1570: 8, 1572: 8, 1593: 8, 1856: 8, 1858: 8, 1860: 8, 1863: 8, 1865: 8, 1867: 8, 1875: 8, 1882: 8, 1890: 8, 1891: 8, 1892: 8, 1894: 8, 1896: 8, 1904: 8, 2015: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8
}], }],
} }

@ -29,7 +29,7 @@ def get_all_car_info() -> List[CarInfo]:
all_car_info: List[CarInfo] = [] all_car_info: List[CarInfo] = []
footnotes = get_all_footnotes() footnotes = get_all_footnotes()
for model, car_info in get_interface_attr("CAR_INFO", combine_brands=True).items(): for model, car_info in get_interface_attr("CAR_INFO", combine_brands=True).items():
CP = interfaces[model][0].get_params(model, fingerprint=gen_empty_fingerprint(), car_fw=[car.CarParams.CarFw(ecu="unknown")]) CP = interfaces[model][0].get_params(model, fingerprint=gen_empty_fingerprint(), car_fw=[car.CarParams.CarFw(ecu="unknown")], experimental_long=False)
if CP.dashcamOnly or car_info is None: if CP.dashcamOnly or car_info is None:
continue continue

@ -21,6 +21,7 @@ class Column(Enum):
STEERING_TORQUE = "Steering Torque" STEERING_TORQUE = "Steering Torque"
AUTO_RESUME = "Resume from stop" AUTO_RESUME = "Resume from stop"
HARNESS = "Harness" HARNESS = "Harness"
VIDEO = "Video"
class Star(Enum): class Star(Enum):
@ -125,20 +126,11 @@ class CarInfo:
harness: Enum = Harness.none harness: Enum = Harness.none
def init(self, CP: car.CarParams, all_footnotes: Dict[Enum, int]): def init(self, CP: car.CarParams, all_footnotes: Dict[Enum, int]):
# TODO: set all the min steer speeds in carParams and remove this
if self.min_steer_speed is not None:
assert CP.minSteerSpeed == 0, f"{CP.carFingerprint}: Minimum steer speed set in both CarInfo and CarParams"
else:
self.min_steer_speed = CP.minSteerSpeed
# TODO: set all the min enable speeds in carParams correctly and remove this
if self.min_enable_speed is None:
self.min_enable_speed = CP.minEnableSpeed
self.car_name = CP.carName self.car_name = CP.carName
self.car_fingerprint = CP.carFingerprint self.car_fingerprint = CP.carFingerprint
self.make, self.model, self.years = split_name(self.name) self.make, self.model, self.years = split_name(self.name)
# longitudinal column
op_long = "Stock" op_long = "Stock"
if CP.openpilotLongitudinalControl and not CP.enableDsu: if CP.openpilotLongitudinalControl and not CP.enableDsu:
op_long = "openpilot" op_long = "openpilot"
@ -149,6 +141,23 @@ class CarInfo:
else: else:
self.footnotes.append(CommonFootnote.EXP_LONG_AVAIL) self.footnotes.append(CommonFootnote.EXP_LONG_AVAIL)
# min steer & enable speed columns
# TODO: set all the min steer speeds in carParams and remove this
if self.min_steer_speed is not None:
assert CP.minSteerSpeed == 0, f"{CP.carFingerprint}: Minimum steer speed set in both CarInfo and CarParams"
else:
self.min_steer_speed = CP.minSteerSpeed
# TODO: set all the min enable speeds in carParams correctly and remove this
if self.min_enable_speed is None:
self.min_enable_speed = CP.minEnableSpeed
# harness column
harness_col = self.harness.value
if self.harness is not Harness.none:
model_years = self.model + (' ' + self.years if self.years else '')
harness_col = f'<a href="https://comma.ai/shop/comma-three.html?make={self.make}&model={model_years}">{harness_col}</a>'
self.row = { self.row = {
Column.MAKE: self.make, Column.MAKE: self.make,
Column.MODEL: self.model, Column.MODEL: self.model,
@ -158,7 +167,8 @@ class CarInfo:
Column.FSR_STEERING: f"{max(self.min_steer_speed * CV.MS_TO_MPH, 0):.0f} mph", Column.FSR_STEERING: f"{max(self.min_steer_speed * CV.MS_TO_MPH, 0):.0f} mph",
Column.STEERING_TORQUE: Star.EMPTY, Column.STEERING_TORQUE: Star.EMPTY,
Column.AUTO_RESUME: Star.FULL if CP.autoResumeSng else Star.EMPTY, Column.AUTO_RESUME: Star.FULL if CP.autoResumeSng else Star.EMPTY,
Column.HARNESS: self.harness.value, Column.HARNESS: harness_col,
Column.VIDEO: self.video_link if self.video_link is not None else "", # replaced with an image and link from template in get_column
} }
# Set steering torque star from max lateral acceleration # Set steering torque star from max lateral acceleration
@ -194,6 +204,13 @@ class CarInfo:
if self.row[Column.STEERING_TORQUE] != Star.FULL: if self.row[Column.STEERING_TORQUE] != Star.FULL:
sentence_builder += " This car may not be able to take tight turns on its own." sentence_builder += " This car may not be able to take tight turns on its own."
# experimental mode
exp_link = "<a href='https://blog.comma.ai/090release/#experimental-mode' target='_blank' class='link-light-new-regular-text'>Experimental mode</a>"
if CP.openpilotLongitudinalControl or CP.experimentalLongitudinalAvailable:
sentence_builder += f" Traffic light and stop sign handling is also available in {exp_link}."
else:
sentence_builder += f" {exp_link}, with traffic light and stop sign handling, is not currently available for this car, but may be added in a future software update."
return sentence_builder.format(car_model=f"{self.make} {self.model}", alc=alc, acc=acc) return sentence_builder.format(car_model=f"{self.make} {self.model}", alc=alc, acc=acc)
else: else:
@ -202,12 +219,14 @@ class CarInfo:
else: else:
raise Exception(f"This notCar does not have a detail sentence: {CP.carFingerprint}") raise Exception(f"This notCar does not have a detail sentence: {CP.carFingerprint}")
def get_column(self, column: Column, star_icon: str, footnote_tag: str) -> str: def get_column(self, column: Column, star_icon: str, video_icon: str, footnote_tag: str) -> str:
item: Union[str, Star] = self.row[column] item: Union[str, Star] = self.row[column]
if isinstance(item, Star): if isinstance(item, Star):
item = star_icon.format(item.value) item = star_icon.format(item.value)
elif column == Column.MODEL and len(self.years): elif column == Column.MODEL and len(self.years):
item += f" {self.years}" item += f" {self.years}"
elif column == Column.VIDEO and len(item) > 0:
item = video_icon.format(item)
footnotes = get_footnotes(self.footnotes, column) footnotes = get_footnotes(self.footnotes, column)
if len(footnotes): if len(footnotes):

@ -87,5 +87,5 @@ if __name__ == "__main__":
for addr, subaddr, bus in ecu_addrs: for addr, subaddr, bus in ecu_addrs:
msg = f" 0x{hex(addr)}" msg = f" 0x{hex(addr)}"
if subaddr is not None: if subaddr is not None:
msg += f" (sub-address: 0x{hex(subaddr)})" msg += f" (sub-address: {hex(subaddr)})"
print(msg) print(msg)

@ -1,28 +1,14 @@
import math
from cereal import car from cereal import car
from common.numpy_fast import clip, interp from common.numpy_fast import clip
from opendbc.can.packer import CANPacker from opendbc.can.packer import CANPacker
from selfdrive.car.ford import fordcan from selfdrive.car import apply_std_steer_angle_limits
from selfdrive.car.ford.values import CANBUS, CarControllerParams from selfdrive.car.ford.fordcan import create_acc_command, create_acc_ui_msg, create_button_msg, create_lat_ctl_msg, \
create_lat_ctl2_msg, create_lka_msg, create_lkas_ui_msg
from selfdrive.car.ford.values import CANBUS, CANFD_CARS, CarControllerParams
VisualAlert = car.CarControl.HUDControl.VisualAlert VisualAlert = car.CarControl.HUDControl.VisualAlert
def apply_ford_steer_angle_limits(apply_angle, apply_angle_last, vEgo):
# rate limit
steer_up = apply_angle_last * apply_angle > 0. and abs(apply_angle) > abs(apply_angle_last)
rate_limit = CarControllerParams.RATE_LIMIT_UP if steer_up else CarControllerParams.RATE_LIMIT_DOWN
max_angle_diff = interp(vEgo, rate_limit.speed_points, rate_limit.max_angle_diff_points)
apply_angle = clip(apply_angle, (apply_angle_last - max_angle_diff), (apply_angle_last + max_angle_diff))
# absolute limit (LatCtlPath_An_Actl)
apply_path_angle = math.radians(apply_angle) / CarControllerParams.LKAS_STEER_RATIO
apply_path_angle = clip(apply_path_angle, -0.5, 0.5235)
apply_angle = math.degrees(apply_path_angle) * CarControllerParams.LKAS_STEER_RATIO
return apply_angle
class CarController: class CarController:
def __init__(self, dbc_name, CP, VM): def __init__(self, dbc_name, CP, VM):
self.CP = CP self.CP = CP
@ -30,12 +16,12 @@ class CarController:
self.packer = CANPacker(dbc_name) self.packer = CANPacker(dbc_name)
self.frame = 0 self.frame = 0
self.apply_angle_last = 0 self.apply_curvature_last = 0
self.main_on_last = False self.main_on_last = False
self.lkas_enabled_last = False self.lkas_enabled_last = False
self.steer_alert_last = False self.steer_alert_last = False
def update(self, CC, CS): def update(self, CC, CS, now_nanos):
can_sends = [] can_sends = []
actuators = CC.actuators actuators = CC.actuators
@ -46,66 +32,69 @@ class CarController:
### acc buttons ### ### acc buttons ###
if CC.cruiseControl.cancel: if CC.cruiseControl.cancel:
can_sends.append(fordcan.create_button_command(self.packer, CS.buttons_stock_values, cancel=True)) can_sends.append(create_button_msg(self.packer, CS.buttons_stock_values, cancel=True))
can_sends.append(fordcan.create_button_command(self.packer, CS.buttons_stock_values, cancel=True, bus=CANBUS.main)) can_sends.append(create_button_msg(self.packer, CS.buttons_stock_values, cancel=True, bus=CANBUS.main))
elif CC.cruiseControl.resume and (self.frame % CarControllerParams.BUTTONS_STEP) == 0: elif CC.cruiseControl.resume and (self.frame % CarControllerParams.BUTTONS_STEP) == 0:
can_sends.append(fordcan.create_button_command(self.packer, CS.buttons_stock_values, resume=True)) can_sends.append(create_button_msg(self.packer, CS.buttons_stock_values, resume=True))
can_sends.append(fordcan.create_button_command(self.packer, CS.buttons_stock_values, resume=True, bus=CANBUS.main)) can_sends.append(create_button_msg(self.packer, CS.buttons_stock_values, resume=True, bus=CANBUS.main))
# if stock lane centering isn't off, send a button press to toggle it off # if stock lane centering isn't off, send a button press to toggle it off
# the stock system checks for steering pressed, and eventually disengages cruise control # the stock system checks for steering pressed, and eventually disengages cruise control
elif CS.acc_tja_status_stock_values["Tja_D_Stat"] != 0 and (self.frame % CarControllerParams.ACC_UI_STEP) == 0: elif CS.acc_tja_status_stock_values["Tja_D_Stat"] != 0 and (self.frame % CarControllerParams.ACC_UI_STEP) == 0:
can_sends.append(fordcan.create_button_command(self.packer, CS.buttons_stock_values, tja_toggle=True)) can_sends.append(create_button_msg(self.packer, CS.buttons_stock_values, tja_toggle=True))
### lateral control ### ### lateral control ###
if CC.latActive:
lca_rq = 1
apply_angle = apply_ford_steer_angle_limits(actuators.steeringAngleDeg, self.apply_angle_last, CS.out.vEgo)
else:
lca_rq = 0
apply_angle = 0.
# send steering commands at 20Hz # send steering commands at 20Hz
if (self.frame % CarControllerParams.STEER_STEP) == 0: if (self.frame % CarControllerParams.STEER_STEP) == 0:
# use LatCtlPath_An_Actl to actuate steering if CC.latActive:
path_angle = math.radians(apply_angle) / CarControllerParams.LKAS_STEER_RATIO # apply limits to curvature and clip to signal range
apply_curvature = apply_std_steer_angle_limits(actuators.curvature, self.apply_curvature_last, CS.out.vEgo, CarControllerParams)
# set slower ramp type when small steering angle change apply_curvature = clip(apply_curvature, -CarControllerParams.CURVATURE_MAX, CarControllerParams.CURVATURE_MAX)
# 0=Slow, 1=Medium, 2=Fast, 3=Immediately
steer_change = abs(CS.out.steeringAngleDeg - actuators.steeringAngleDeg)
if steer_change < 2.0:
ramp_type = 0
elif steer_change < 4.0:
ramp_type = 1
elif steer_change < 6.0:
ramp_type = 2
else: else:
ramp_type = 3 apply_curvature = 0.
precision = 1 # 0=Comfortable, 1=Precise (the stock system always uses comfortable)
self.apply_angle_last = apply_angle self.apply_curvature_last = apply_curvature
can_sends.append(fordcan.create_lka_command(self.packer, 0, 0)) can_sends.append(create_lka_msg(self.packer))
can_sends.append(fordcan.create_tja_command(self.packer, lca_rq, ramp_type, precision,
0, path_angle, 0, 0)) if self.CP.carFingerprint in CANFD_CARS:
# TODO: extended mode
mode = 1 if CC.latActive else 0
counter = self.frame // CarControllerParams.STEER_STEP
can_sends.append(create_lat_ctl2_msg(self.packer, mode, 0., 0., -apply_curvature, 0., counter))
else:
can_sends.append(create_lat_ctl_msg(self.packer, CC.latActive, 0., 0., -apply_curvature, 0.))
### longitudinal control ###
# send acc command at 50Hz
if self.CP.openpilotLongitudinalControl and (self.frame % CarControllerParams.ACC_CONTROL_STEP) == 0:
accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX)
precharge_brake = accel < -0.1
if accel > -0.5:
gas = accel
decel = False
else:
gas = -5.0
decel = True
can_sends.append(create_acc_command(self.packer, CC.longActive, gas, accel, precharge_brake, decel))
### ui ### ### ui ###
send_ui = (self.main_on_last != main_on) or (self.lkas_enabled_last != CC.latActive) or (self.steer_alert_last != steer_alert) send_ui = (self.main_on_last != main_on) or (self.lkas_enabled_last != CC.latActive) or (self.steer_alert_last != steer_alert)
# send lkas ui command at 1Hz or if ui state changes # send lkas ui command at 1Hz or if ui state changes
if (self.frame % CarControllerParams.LKAS_UI_STEP) == 0 or send_ui: if (self.frame % CarControllerParams.LKAS_UI_STEP) == 0 or send_ui:
can_sends.append(fordcan.create_lkas_ui_command(self.packer, main_on, CC.latActive, steer_alert, hud_control, CS.lkas_status_stock_values)) can_sends.append(create_lkas_ui_msg(self.packer, main_on, CC.latActive, steer_alert, hud_control, CS.lkas_status_stock_values))
# send acc ui command at 20Hz or if ui state changes # send acc ui command at 20Hz or if ui state changes
if (self.frame % CarControllerParams.ACC_UI_STEP) == 0 or send_ui: if (self.frame % CarControllerParams.ACC_UI_STEP) == 0 or send_ui:
can_sends.append(fordcan.create_acc_ui_command(self.packer, main_on, CC.latActive, hud_control, CS.acc_tja_status_stock_values)) can_sends.append(create_acc_ui_msg(self.packer, main_on, CC.latActive, hud_control, CS.acc_tja_status_stock_values))
self.main_on_last = main_on self.main_on_last = main_on
self.lkas_enabled_last = CC.latActive self.lkas_enabled_last = CC.latActive
self.steer_alert_last = steer_alert self.steer_alert_last = steer_alert
new_actuators = actuators.copy() new_actuators = actuators.copy()
new_actuators.steeringAngleDeg = self.apply_angle_last new_actuators.curvature = self.apply_curvature_last
self.frame += 1 self.frame += 1
return new_actuators, can_sends return new_actuators, can_sends

@ -14,7 +14,7 @@ class CarState(CarStateBase):
super().__init__(CP) super().__init__(CP)
can_define = CANDefine(DBC[CP.carFingerprint]["pt"]) can_define = CANDefine(DBC[CP.carFingerprint]["pt"])
if CP.transmissionType == TransmissionType.automatic: if CP.transmissionType == TransmissionType.automatic:
self.shifter_values = can_define.dv["Gear_Shift_by_Wire_FD1"]["TrnGear_D_RqDrv"] self.shifter_values = can_define.dv["Gear_Shift_by_Wire_FD1"]["TrnRng_D_RqGsm"]
def update(self, cp, cp_cam): def update(self, cp, cp_cam):
ret = car.CarState.new_message() ret = car.CarState.new_message()
@ -37,7 +37,7 @@ class CarState(CarStateBase):
# steering wheel # steering wheel
ret.steeringAngleDeg = cp.vl["SteeringPinion_Data"]["StePinComp_An_Est"] ret.steeringAngleDeg = cp.vl["SteeringPinion_Data"]["StePinComp_An_Est"]
ret.steeringTorque = cp.vl["EPAS_INFO"]["SteeringColumnTorque"] ret.steeringTorque = cp.vl["EPAS_INFO"]["SteeringColumnTorque"]
ret.steeringPressed = abs(ret.steeringTorque) > CarControllerParams.STEER_DRIVER_ALLOWANCE ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > CarControllerParams.STEER_DRIVER_ALLOWANCE, 5)
ret.steerFaultTemporary = cp.vl["EPAS_INFO"]["EPAS_Failure"] == 1 ret.steerFaultTemporary = cp.vl["EPAS_INFO"]["EPAS_Failure"] == 1
ret.steerFaultPermanent = cp.vl["EPAS_INFO"]["EPAS_Failure"] in (2, 3) ret.steerFaultPermanent = cp.vl["EPAS_INFO"]["EPAS_Failure"] in (2, 3)
# ret.espDisabled = False # TODO: find traction control signal # ret.espDisabled = False # TODO: find traction control signal
@ -51,7 +51,7 @@ class CarState(CarStateBase):
# gear # gear
if self.CP.transmissionType == TransmissionType.automatic: if self.CP.transmissionType == TransmissionType.automatic:
gear = self.shifter_values.get(cp.vl["Gear_Shift_by_Wire_FD1"]["TrnGear_D_RqDrv"], None) gear = self.shifter_values.get(cp.vl["Gear_Shift_by_Wire_FD1"]["TrnRng_D_RqGsm"])
ret.gearShifter = self.parse_gear_shifter(gear) ret.gearShifter = self.parse_gear_shifter(gear)
elif self.CP.transmissionType == TransmissionType.manual: elif self.CP.transmissionType == TransmissionType.manual:
ret.clutchPressed = cp.vl["Engine_Clutch_Data"]["CluPdlPos_Pc_Meas"] > 0 ret.clutchPressed = cp.vl["Engine_Clutch_Data"]["CluPdlPos_Pc_Meas"] > 0
@ -118,7 +118,7 @@ class CarState(CarStateBase):
("DrStatRl_B_Actl", "BodyInfo_3_FD1"), # BCM Door open, rear left ("DrStatRl_B_Actl", "BodyInfo_3_FD1"), # BCM Door open, rear left
("DrStatRr_B_Actl", "BodyInfo_3_FD1"), # BCM Door open, rear right ("DrStatRr_B_Actl", "BodyInfo_3_FD1"), # BCM Door open, rear right
("FirstRowBuckleDriver", "RCMStatusMessage2_FD1"), # RCM Seatbelt status, driver ("FirstRowBuckleDriver", "RCMStatusMessage2_FD1"), # RCM Seatbelt status, driver
("HeadLghtHiFlash_D_Stat", "Steering_Data_FD1"), # SCCM Passthru the remaining buttons ("HeadLghtHiFlash_D_Stat", "Steering_Data_FD1"), # SCCM Passthrough the remaining buttons
("WiprFront_D_Stat", "Steering_Data_FD1"), ("WiprFront_D_Stat", "Steering_Data_FD1"),
("LghtAmb_D_Sns", "Steering_Data_FD1"), ("LghtAmb_D_Sns", "Steering_Data_FD1"),
("AccButtnGapDecPress", "Steering_Data_FD1"), ("AccButtnGapDecPress", "Steering_Data_FD1"),
@ -171,7 +171,7 @@ class CarState(CarStateBase):
if CP.transmissionType == TransmissionType.automatic: if CP.transmissionType == TransmissionType.automatic:
signals += [ signals += [
("TrnGear_D_RqDrv", "Gear_Shift_by_Wire_FD1"), # GWM transmission gear position ("TrnRng_D_RqGsm", "Gear_Shift_by_Wire_FD1"), # GWM transmission gear position
] ]
checks += [ checks += [
("Gear_Shift_by_Wire_FD1", 10), ("Gear_Shift_by_Wire_FD1", 10),

@ -4,64 +4,120 @@ from selfdrive.car.ford.values import CANBUS
HUDControl = car.CarControl.HUDControl HUDControl = car.CarControl.HUDControl
def create_lka_command(packer, angle_deg: float, curvature: float): def calculate_lat_ctl2_checksum(mode: int, counter: int, dat: bytearray):
checksum = mode + counter
checksum += dat[2] + ((dat[3] & 0xE0) >> 5) # curvature
checksum += dat[6] + ((dat[7] & 0xE0) >> 5) # curvature rate
checksum += (dat[3] & 0x1F) + ((dat[4] & 0xFC) >> 2) # path angle
checksum += (dat[4] & 0x3) + dat[5] # path offset
return 0xFF - (checksum & 0xFF)
def create_lka_msg(packer):
""" """
Creates a CAN message for the Ford LKAS Command. Creates an empty CAN message for the Ford LKA Command.
This command can apply "Lane Keeping Aid" manoeuvres, which are subject to the PSCM lockout. This command can apply "Lane Keeping Aid" manoeuvres, which are subject to the PSCM lockout.
Frequency is 20Hz. Frequency is 20Hz.
""" """
values = { return packer.make_can_msg("Lane_Assist_Data1", CANBUS.main, {})
"LkaDrvOvrrd_D_Rq": 0, # driver override level? [0|3]
"LkaActvStats_D2_Req": 0, # action [0|7]
"LaRefAng_No_Req": angle_deg, # angle [-102.4|102.3] degrees
"LaRampType_B_Req": 0, # Ramp speed: 0=Smooth, 1=Quick
"LaCurvature_No_Calc": curvature, # curvature [-0.01024|0.01023] 1/meter
"LdwActvStats_D_Req": 0, # LDW status [0|7]
"LdwActvIntns_D_Req": 0, # LDW intensity [0|3], shake alert strength
}
return packer.make_can_msg("Lane_Assist_Data1", CANBUS.main, values)
def create_tja_command(packer, lca_rq: int, ramp_type: int, precision: int, path_offset: float, path_angle: float, curvature_rate: float, curvature: float): def create_lat_ctl_msg(packer, lat_active: bool, path_offset: float, path_angle: float, curvature: float,
curvature_rate: float):
""" """
Creates a CAN message for the Ford TJA/LCA Command. Creates a CAN message for the Ford TJA/LCA Command.
This command can apply "Lane Centering" manoeuvres: continuous lane centering for traffic jam This command can apply "Lane Centering" manoeuvres: continuous lane centering for traffic jam assist and highway
assist and highway driving. It is not subject to the PSCM lockout. driving. It is not subject to the PSCM lockout.
Ford lane centering command uses a third order polynomial to describe the road centerline. The Ford lane centering command uses a third order polynomial to describe the road centerline. The polynomial is defined
polynomial is defined by the following coefficients: by the following coefficients:
c0: lateral offset between the vehicle and the centerline c0: lateral offset between the vehicle and the centerline (positive is right)
c1: heading angle between the vehicle and the centerline c1: heading angle between the vehicle and the centerline (positive is right)
c2: curvature of the centerline c2: curvature of the centerline (positive is left)
c3: rate of change of curvature of the centerline c3: rate of change of curvature of the centerline
As the PSCM combines this information with other sensor data, such as the vehicle's yaw rate and As the PSCM combines this information with other sensor data, such as the vehicle's yaw rate and speed, the steering
speed, the steering angle cannot be easily controlled. angle cannot be easily controlled.
The PSCM should be configured to accept TJA/LCA commands before these commands will be processed. The PSCM should be configured to accept TJA/LCA commands before these commands will be processed. This can be done
This can be done using tools such as Forscan. using tools such as Forscan.
Frequency is 20Hz. Frequency is 20Hz.
""" """
values = { values = {
"LatCtlRng_L_Max": 0, # Unknown [0|126] meter "LatCtlRng_L_Max": 0, # Unknown [0|126] meter
"HandsOffCnfm_B_Rq": 0, # Unknown: 0=Inactive, 1=Active [0|1] "HandsOffCnfm_B_Rq": 0, # Unknown: 0=Inactive, 1=Active [0|1]
"LatCtl_D_Rq": lca_rq, # Mode: 0=None, 1=ContinuousPathFollowing, 2=InterventionLeft, 3=InterventionRight, 4-7=NotUsed [0|7] "LatCtl_D_Rq": 1 if lat_active else 0, # Mode: 0=None, 1=ContinuousPathFollowing, 2=InterventionLeft,
"LatCtlRampType_D_Rq": ramp_type, # Ramp speed: 0=Slow, 1=Medium, 2=Fast, 3=Immediate [0|3] # 3=InterventionRight, 4-7=NotUsed [0|7]
"LatCtlPrecision_D_Rq": precision, # Precision: 0=Comfortable, 1=Precise, 2/3=NotUsed [0|3] "LatCtlRampType_D_Rq": 0, # Ramp speed: 0=Slow, 1=Medium, 2=Fast, 3=Immediate [0|3]
"LatCtlPathOffst_L_Actl": path_offset, # Path offset [-5.12|5.11] meter # Makes no difference with curvature control
"LatCtlPath_An_Actl": path_angle, # Path angle [-0.5|0.5235] radians "LatCtlPrecision_D_Rq": 1, # Precision: 0=Comfortable, 1=Precise, 2/3=NotUsed [0|3]
"LatCtlCurv_NoRate_Actl": curvature_rate, # Curvature rate [-0.001024|0.00102375] 1/meter^2 # The stock system always uses comfortable
"LatCtlCurv_No_Actl": curvature, # Curvature [-0.02|0.02094] 1/meter "LatCtlPathOffst_L_Actl": path_offset, # Path offset [-5.12|5.11] meter
"LatCtlPath_An_Actl": path_angle, # Path angle [-0.5|0.5235] radians
"LatCtlCurv_NoRate_Actl": curvature_rate, # Curvature rate [-0.001024|0.00102375] 1/meter^2
"LatCtlCurv_No_Actl": curvature, # Curvature [-0.02|0.02094] 1/meter
} }
return packer.make_can_msg("LateralMotionControl", CANBUS.main, values) return packer.make_can_msg("LateralMotionControl", CANBUS.main, values)
def create_lkas_ui_command(packer, main_on: bool, enabled: bool, steer_alert: bool, hud_control, stock_values: dict): def create_lat_ctl2_msg(packer, mode: int, path_offset: float, path_angle: float, curvature: float,
curvature_rate: float, counter: int):
"""
Create a CAN message for the new Ford Lane Centering command.
This message is used on the CAN FD platform and replaces the old LateralMotionControl message. It is similar but has
additional signals for a counter and checksum.
Frequency is 20Hz.
"""
values = {
"LatCtl_D2_Rq": mode, # Mode: 0=None, 1=PathFollowingLimitedMode, 2=PathFollowingExtendedMode,
# 3=SafeRampOut, 4-7=NotUsed [0|7]
"LatCtlRampType_D_Rq": 0, # 0=Slow, 1=Medium, 2=Fast, 3=Immediate [0|3]
"LatCtlPrecision_D_Rq": 1, # 0=Comfortable, 1=Precise, 2/3=NotUsed [0|3]
"LatCtlPathOffst_L_Actl": path_offset, # [-5.12|5.11] meter
"LatCtlPath_An_Actl": path_angle, # [-0.5|0.5235] radians
"LatCtlCurv_No_Actl": curvature, # [-0.02|0.02094] 1/meter
"LatCtlCrv_NoRate2_Actl": curvature_rate, # [-0.001024|0.001023] 1/meter^2
"HandsOffCnfm_B_Rq": 0, # 0=Inactive, 1=Active [0|1]
"LatCtlPath_No_Cnt": counter, # [0|15]
"LatCtlPath_No_Cs": 0, # [0|255]
}
# calculate checksum
dat = packer.make_can_msg("LateralMotionControl2", CANBUS.main, values)[2]
values["LatCtlPath_No_Cs"] = calculate_lat_ctl2_checksum(mode, counter, dat)
return packer.make_can_msg("LateralMotionControl2", CANBUS.main, values)
def create_acc_command(packer, long_active: bool, gas: float, accel: float, precharge_brake: bool, decel: bool):
"""
Creates a CAN message for the Ford ACC Command.
This command can be used to enable ACC, to set the ACC gas/brake/decel values
and to disable ACC.
Frequency is 50Hz.
"""
values = {
"AccBrkTot_A_Rq": accel, # Brake total accel request: [-20|11.9449] m/s^2
"Cmbb_B_Enbl": 1 if long_active else 0, # Enabled: 0=No, 1=Yes
"AccPrpl_A_Rq": gas, # Acceleration request: [-5|5.23] m/s^2
"AccBrkPrchg_B_Rq": 1 if precharge_brake else 0, # Pre-charge brake request: 0=No, 1=Yes
"AccBrkDecel_B_Rq": 1 if decel else 0, # Deceleration request: 0=Inactive, 1=Active
}
return packer.make_can_msg("ACCDATA", CANBUS.main, values)
def create_lkas_ui_msg(packer, main_on: bool, enabled: bool, steer_alert: bool, hud_control, stock_values: dict):
""" """
Creates a CAN message for the Ford IPC IPMA/LKAS status. Creates a CAN message for the Ford IPC IPMA/LKAS status.
@ -107,16 +163,15 @@ def create_lkas_ui_command(packer, main_on: bool, enabled: bool, steer_alert: bo
values = { values = {
**stock_values, **stock_values,
"LaActvStats_D_Dsply": lines, # LKAS status (lines) [0|31] "LaActvStats_D_Dsply": lines, # LKAS status (lines) [0|31]
"LaHandsOff_D_Dsply": hands_on_wheel_dsply, # 0=HandsOn, 1=Level1 (w/o chime), 2=Level2 (w/ chime), 3=Suppressed "LaHandsOff_D_Dsply": hands_on_wheel_dsply, # 0=HandsOn, 1=Level1 (w/o chime), 2=Level2 (w/ chime), 3=Suppressed
} }
return packer.make_can_msg("IPMA_Data", CANBUS.main, values) return packer.make_can_msg("IPMA_Data", CANBUS.main, values)
def create_acc_ui_command(packer, main_on: bool, enabled: bool, hud_control, stock_values: dict): def create_acc_ui_msg(packer, main_on: bool, enabled: bool, hud_control, stock_values: dict):
""" """
Creates a CAN message for the Ford IPC adaptive cruise, forward collision warning and traffic jam Creates a CAN message for the Ford IPC adaptive cruise, forward collision warning and traffic jam assist status.
assist status.
Stock functionality is maintained by passing through unmodified signals. Stock functionality is maintained by passing through unmodified signals.
@ -148,7 +203,8 @@ def create_acc_ui_command(packer, main_on: bool, enabled: bool, hud_control, sto
return packer.make_can_msg("ACCDATA_3", CANBUS.main, values) return packer.make_can_msg("ACCDATA_3", CANBUS.main, values)
def create_button_command(packer, stock_values: dict, cancel = False, resume = False, tja_toggle = False, bus: int = CANBUS.camera): def create_button_msg(packer, stock_values: dict, cancel=False, resume=False, tja_toggle=False,
bus: int = CANBUS.camera):
""" """
Creates a CAN message for the Ford SCCM buttons/switches. Creates a CAN message for the Ford SCCM buttons/switches.

@ -2,39 +2,52 @@
from cereal import car from cereal import car
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
from selfdrive.car import STD_CARGO_KG, get_safety_config from selfdrive.car import STD_CARGO_KG, get_safety_config
from selfdrive.car.ford.values import CAR, Ecu, TransmissionType, GearShifter from selfdrive.car.ford.values import CAR, Ecu
from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.interfaces import CarInterfaceBase
CarParams = car.CarParams TransmissionType = car.CarParams.TransmissionType
GearShifter = car.CarState.GearShifter
class CarInterface(CarInterfaceBase): class CarInterface(CarInterfaceBase):
@staticmethod @staticmethod
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): def _get_params(ret, candidate, fingerprint, car_fw, experimental_long):
ret.carName = "ford" ret.carName = "ford"
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.ford)]
# These cars are dashcam only until the port is finished
ret.dashcamOnly = True ret.dashcamOnly = True
ret.safetyConfigs = [get_safety_config(CarParams.SafetyModel.ford)]
# Angle-based steering ret.radarUnavailable = True
ret.steerControlType = CarParams.SteerControlType.angle ret.steerControlType = car.CarParams.SteerControlType.angle
ret.steerActuatorDelay = 0.4 ret.steerActuatorDelay = 0.2
ret.steerLimitTimer = 1.0 ret.steerLimitTimer = 1.0
if candidate == CAR.ESCAPE_MK4: if candidate == CAR.BRONCO_SPORT_MK1:
ret.wheelbase = 2.67
ret.steerRatio = 17.7
ret.mass = 1625 + STD_CARGO_KG
elif candidate == CAR.ESCAPE_MK4:
ret.wheelbase = 2.71 ret.wheelbase = 2.71
ret.steerRatio = 14.3 # Copied from Focus ret.steerRatio = 16.7
ret.mass = 1750 + STD_CARGO_KG ret.mass = 1750 + STD_CARGO_KG
elif candidate == CAR.EXPLORER_MK6: elif candidate == CAR.EXPLORER_MK6:
ret.wheelbase = 3.025 ret.wheelbase = 3.025
ret.steerRatio = 16.8 # learned ret.steerRatio = 16.8
ret.mass = 2050 + STD_CARGO_KG ret.mass = 2050 + STD_CARGO_KG
elif candidate == CAR.FOCUS_MK4: elif candidate == CAR.FOCUS_MK4:
ret.wheelbase = 2.7 ret.wheelbase = 2.7
ret.steerRatio = 13.8 # learned ret.steerRatio = 15.0
ret.mass = 1350 + STD_CARGO_KG ret.mass = 1350 + STD_CARGO_KG
elif candidate == CAR.MAVERICK_MK1:
ret.wheelbase = 3.076
ret.steerRatio = 17.0
ret.mass = 1650 + STD_CARGO_KG
else: else:
raise ValueError(f"Unsupported car: {candidate}") raise ValueError(f"Unsupported car: {candidate}")
@ -65,5 +78,5 @@ class CarInterface(CarInterfaceBase):
return ret return ret
def apply(self, c): def apply(self, c, now_nanos):
return self.CC.update(c, self.CS) return self.CC.update(c, self.CS, now_nanos)

@ -47,7 +47,7 @@ class RadarInterface(RadarInterfaceBase):
self.updated_messages = set() self.updated_messages = set()
self.track_id = 0 self.track_id = 0
self.radar = DBC[CP.carFingerprint]['radar'] self.radar = DBC[CP.carFingerprint]['radar']
if self.radar is None: if self.radar is None or CP.radarUnavailable:
self.rcp = None self.rcp = None
elif self.radar == RADAR.DELPHI_ESR: elif self.radar == RADAR.DELPHI_ESR:
self.rcp = _create_delphi_esr_radar_can_parser() self.rcp = _create_delphi_esr_radar_can_parser()

@ -1,23 +1,21 @@
from collections import defaultdict, namedtuple from collections import defaultdict
from dataclasses import dataclass from dataclasses import dataclass
from enum import Enum from enum import Enum
from typing import Dict, List, Union from typing import Dict, List, Set, Union
from cereal import car from cereal import car
from selfdrive.car import dbc_dict from selfdrive.car import AngleRateLimit, dbc_dict
from selfdrive.car.docs_definitions import CarInfo, Harness from selfdrive.car.docs_definitions import CarInfo, Harness
from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries
Ecu = car.CarParams.Ecu Ecu = car.CarParams.Ecu
TransmissionType = car.CarParams.TransmissionType
GearShifter = car.CarState.GearShifter
AngleRateLimit = namedtuple('AngleRateLimit', ['speed_points', 'max_angle_diff_points'])
class CarControllerParams: class CarControllerParams:
# Messages: Lane_Assist_Data1, LateralMotionControl # Messages: Lane_Assist_Data1, LateralMotionControl
STEER_STEP = 5 STEER_STEP = 5
# Message: ACCDATA
ACC_CONTROL_STEP = 2
# Message: IPMA_Data # Message: IPMA_Data
LKAS_UI_STEP = 100 LKAS_UI_STEP = 100
# Message: ACCDATA_3 # Message: ACCDATA_3
@ -25,12 +23,17 @@ class CarControllerParams:
# Message: Steering_Data_FD1, but send twice as fast # Message: Steering_Data_FD1, but send twice as fast
BUTTONS_STEP = 10 / 2 BUTTONS_STEP = 10 / 2
LKAS_STEER_RATIO = 2.75 # Approximate ratio between LatCtlPath_An_Actl and steering angle in radians CURVATURE_MAX = 0.02 # Max curvature for steering command, m^-1
# TODO: remove this once we understand how the EPS calculates the steering angle better STEER_DRIVER_ALLOWANCE = 1.0 # Driver intervention threshold, Nm
STEER_DRIVER_ALLOWANCE = 0.8 # Driver intervention threshold in Nm
# Curvature rate limits
# TODO: unify field names used by curvature and angle control cars
# ~2 m/s^3 up, ~-3 m/s^3 down
ANGLE_RATE_LIMIT_UP = AngleRateLimit(speed_bp=[5, 15, 25], angle_v=[0.004, 0.00044, 0.00016])
ANGLE_RATE_LIMIT_DOWN = AngleRateLimit(speed_bp=[5, 15, 25], angle_v=[0.006, 0.00066, 0.00024])
RATE_LIMIT_UP = AngleRateLimit(speed_points=[0., 5., 15.], max_angle_diff_points=[5., .8, .15]) ACCEL_MAX = 2.0 # m/s^s max acceleration
RATE_LIMIT_DOWN = AngleRateLimit(speed_points=[0., 5., 15.], max_angle_diff_points=[5., 3.5, 0.4]) ACCEL_MIN = -3.5 # m/s^s max deceleration
def __init__(self, CP): def __init__(self, CP):
pass pass
@ -43,9 +46,14 @@ class CANBUS:
class CAR: class CAR:
BRONCO_SPORT_MK1 = "FORD BRONCO SPORT 1ST GEN"
ESCAPE_MK4 = "FORD ESCAPE 4TH GEN" ESCAPE_MK4 = "FORD ESCAPE 4TH GEN"
EXPLORER_MK6 = "FORD EXPLORER 6TH GEN" EXPLORER_MK6 = "FORD EXPLORER 6TH GEN"
FOCUS_MK4 = "FORD FOCUS 4TH GEN" FOCUS_MK4 = "FORD FOCUS 4TH GEN"
MAVERICK_MK1 = "FORD MAVERICK 1ST GEN"
CANFD_CARS: Set[str] = set()
class RADAR: class RADAR:
@ -63,12 +71,20 @@ class FordCarInfo(CarInfo):
CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = { CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = {
CAR.BRONCO_SPORT_MK1: FordCarInfo("Ford Bronco Sport 2021-22"),
CAR.ESCAPE_MK4: [ CAR.ESCAPE_MK4: [
FordCarInfo("Ford Escape 2020-21"), FordCarInfo("Ford Escape 2020-22"),
FordCarInfo("Ford Escape Plug-in Hybrid 2020-22"),
FordCarInfo("Ford Kuga 2020-21", "Driver Assistance Pack"), FordCarInfo("Ford Kuga 2020-21", "Driver Assistance Pack"),
FordCarInfo("Ford Kuga Plug-in Hybrid 2020-22", "Driver Assistance Pack"),
],
CAR.EXPLORER_MK6: [
FordCarInfo("Ford Explorer 2020-22"),
FordCarInfo("Lincoln Aviator 2021", "Co-Pilot360 Plus"),
FordCarInfo("Lincoln Aviator Plug-in Hybrid 2021", "Co-Pilot360 Plus"),
], ],
CAR.EXPLORER_MK6: FordCarInfo("Ford Explorer 2020-22"),
CAR.FOCUS_MK4: FordCarInfo("Ford Focus EU 2019", "Driver Assistance Pack"), CAR.FOCUS_MK4: FordCarInfo("Ford Focus EU 2019", "Driver Assistance Pack"),
CAR.MAVERICK_MK1: FordCarInfo("Ford Maverick 2022", "Co-Pilot360 Assist"),
} }
FW_QUERY_CONFIG = FwQueryConfig( FW_QUERY_CONFIG = FwQueryConfig(
@ -88,10 +104,35 @@ FW_QUERY_CONFIG = FwQueryConfig(
) )
FW_VERSIONS = { FW_VERSIONS = {
CAR.BRONCO_SPORT_MK1: {
(Ecu.eps, 0x730, None): [
b'LX6C-14D003-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'LX6C-14D003-AK\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.abs, 0x760, None): [
b'LX6C-2D053-RD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'LX6C-2D053-RE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.fwdRadar, 0x764, None): [
b'LB5T-14D049-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.fwdCamera, 0x706, None): [
b'M1PT-14F397-AC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.engine, 0x7E0, None): [
b'M1PA-14C204-GF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'N1PA-14C204-AC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.shiftByWire, 0x732, None): [
b'LX6P-14G395-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PZ1P-14G395-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
},
CAR.ESCAPE_MK4: { CAR.ESCAPE_MK4: {
(Ecu.eps, 0x730, None): [ (Ecu.eps, 0x730, None): [
b'LX6C-14D003-AF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LX6C-14D003-AF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'LX6C-14D003-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LX6C-14D003-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'LX6C-14D003-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.abs, 0x760, None): [ (Ecu.abs, 0x760, None): [
b'LX6C-2D053-NS\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LX6C-2D053-NS\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@ -109,10 +150,12 @@ FW_VERSIONS = {
b'LX6A-14C204-BJV\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LX6A-14C204-BJV\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'LX6A-14C204-ESG\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LX6A-14C204-ESG\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'MX6A-14C204-BEF\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'MX6A-14C204-BEF\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'NX6A-14C204-BLE\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.shiftByWire, 0x732, None): [ (Ecu.shiftByWire, 0x732, None): [
b'LX6P-14G395-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LX6P-14G395-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'LX6P-14G395-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LX6P-14G395-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PZ1P-14G395-AC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
}, },
CAR.EXPLORER_MK6: { CAR.EXPLORER_MK6: {
@ -132,13 +175,16 @@ FW_VERSIONS = {
(Ecu.fwdCamera, 0x706, None): [ (Ecu.fwdCamera, 0x706, None): [
b'LB5T-14F397-AE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LB5T-14F397-AE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'LB5T-14F397-AF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LB5T-14F397-AF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'LC5T-14F397-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.engine, 0x7E0, None): [ (Ecu.engine, 0x7E0, None): [
b'LB5A-14C204-EAC\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LB5A-14C204-EAC\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'MB5A-14C204-MD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'MB5A-14C204-MD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'MB5A-14C204-RC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'NB5A-14C204-HB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'NB5A-14C204-HB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.shiftByWire, 0x732, None): [ (Ecu.shiftByWire, 0x732, None): [
b'L1MP-14C561-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'L1MP-14G395-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'L1MP-14G395-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'L1MP-14G395-AE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'L1MP-14G395-AE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'L1MP-14G395-JB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'L1MP-14G395-JB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@ -163,4 +209,26 @@ FW_VERSIONS = {
(Ecu.shiftByWire, 0x732, None): [ (Ecu.shiftByWire, 0x732, None): [
], ],
}, },
CAR.MAVERICK_MK1: {
(Ecu.eps, 0x730, None): [
b'NZ6C-14D003-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.abs, 0x760, None): [
b'NZ6C-2D053-AG\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.fwdRadar, 0x764, None): [
b'NZ6T-14D049-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.fwdCamera, 0x706, None): [
b'NZ6T-14F397-AC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.engine, 0x7E0, None): [
b'NZ6A-14C204-AAA\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'NZ6A-14C204-PA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'NZ6A-14C204-ZA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.shiftByWire, 0x732, None): [
b'NZ6P-14G395-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
},
} }

@ -57,11 +57,16 @@ class Request:
whitelist_ecus: List[int] = field(default_factory=list) whitelist_ecus: List[int] = field(default_factory=list)
rx_offset: int = 0x8 rx_offset: int = 0x8
bus: int = 1 bus: int = 1
# FW responses from these queries will not be used for fingerprinting
logging: bool = False
# These requests are done once OBD multiplexing is disabled, after all others
non_obd: bool = False
@dataclass @dataclass
class FwQueryConfig: class FwQueryConfig:
requests: List[Request] requests: List[Request]
# TODO: make this automatic and remove hardcoded lists, or do fingerprinting with ecus
# Overrides and removes from essential ecus for specific models and ecus (exact matching) # Overrides and removes from essential ecus for specific models and ecus (exact matching)
non_essential_ecus: Dict[capnp.lib.capnp._EnumModule, List[str]] = field(default_factory=dict) non_essential_ecus: Dict[capnp.lib.capnp._EnumModule, List[str]] = field(default_factory=dict)
# Ecus added for data collection, not to be fingerprinted on # Ecus added for data collection, not to be fingerprinted on

@ -5,6 +5,7 @@ from tqdm import tqdm
import panda.python.uds as uds import panda.python.uds as uds
from cereal import car from cereal import car
from common.params import Params
from selfdrive.car.ecu_addrs import get_ecu_addrs from selfdrive.car.ecu_addrs import get_ecu_addrs
from selfdrive.car.interfaces import get_interface_attr from selfdrive.car.interfaces import get_interface_attr
from selfdrive.car.fingerprints import FW_VERSIONS from selfdrive.car.fingerprints import FW_VERSIONS
@ -29,10 +30,9 @@ def chunks(l, n=128):
def build_fw_dict(fw_versions, filter_brand=None): def build_fw_dict(fw_versions, filter_brand=None):
fw_versions_dict = defaultdict(set) fw_versions_dict = defaultdict(set)
for fw in fw_versions: for fw in fw_versions:
if filter_brand is None or fw.brand == filter_brand: if (filter_brand is None or fw.brand == filter_brand) and not fw.logging:
addr = fw.address
sub_addr = fw.subAddress if fw.subAddress != 0 else None sub_addr = fw.subAddress if fw.subAddress != 0 else None
fw_versions_dict[(addr, sub_addr)].add(fw.fwVersion) fw_versions_dict[(fw.address, sub_addr)].add(fw.fwVersion)
return dict(fw_versions_dict) return dict(fw_versions_dict)
@ -90,7 +90,7 @@ def match_fw_to_car_fuzzy(fw_versions_dict, log=True, exclude=None):
return set() return set()
def match_fw_to_car_exact(fw_versions_dict): def match_fw_to_car_exact(fw_versions_dict) -> Set[str]:
"""Do an exact FW match. Returns all cars that match the given """Do an exact FW match. Returns all cars that match the given
FW versions for a list of "essential" ECUs. If an ECU is not considered FW versions for a list of "essential" ECUs. If an ECU is not considered
essential the FW version can be missing to get a fingerprint, but if it's present it essential the FW version can be missing to get a fingerprint, but if it's present it
@ -146,12 +146,16 @@ def match_fw_to_car(fw_versions, allow_exact=True, allow_fuzzy=True):
return True, set() return True, set()
def get_present_ecus(logcan, sendcan): def get_present_ecus(logcan, sendcan, num_pandas=1) -> Set[Tuple[int, Optional[int], int]]:
queries = list() queries = list()
parallel_queries = list() parallel_queries = list()
responses = set() responses = set()
for brand, r in REQUESTS: for brand, r in REQUESTS:
# Skip query if no panda available
if r.bus > num_pandas * 4 - 1:
continue
for brand_versions in VERSIONS[brand].values(): for brand_versions in VERSIONS[brand].values():
for ecu_type, addr, sub_addr in brand_versions: for ecu_type, addr, sub_addr in brand_versions:
# Only query ecus in whitelist if whitelist is not empty # Only query ecus in whitelist if whitelist is not empty
@ -171,7 +175,7 @@ def get_present_ecus(logcan, sendcan):
queries.insert(0, parallel_queries) queries.insert(0, parallel_queries)
ecu_responses: Set[Tuple[int, Optional[int], int]] = set() ecu_responses = set()
for query in queries: for query in queries:
ecu_responses.update(get_ecu_addrs(logcan, sendcan, set(query), responses, timeout=0.1)) ecu_responses.update(get_ecu_addrs(logcan, sendcan, set(query), responses, timeout=0.1))
return ecu_responses return ecu_responses
@ -194,11 +198,21 @@ def get_brand_ecu_matches(ecu_rx_addrs):
return brand_matches return brand_matches
def disable_obd_multiplexing(params):
if not params.get_bool("ObdMultiplexingDisabled"):
params.put_bool("FirmwareObdQueryDone", True)
cloudlog.warning("Waiting for OBD multiplexing to be disabled")
params.get_bool("ObdMultiplexingDisabled", block=True)
cloudlog.warning("OBD multiplexing disabled")
def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, num_pandas=1, debug=False, progress=False): def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, num_pandas=1, debug=False, progress=False):
"""Queries for FW versions ordering brands by likelihood, breaks when exact match is found""" """Queries for FW versions ordering brands by likelihood, breaks when exact match is found"""
all_car_fw = [] all_car_fw = []
brand_matches = get_brand_ecu_matches(ecu_rx_addrs) brand_matches = get_brand_ecu_matches(ecu_rx_addrs)
matched_brand: Optional[str] = None
for brand in sorted(brand_matches, key=lambda b: len(brand_matches[b]), reverse=True): for brand in sorted(brand_matches, key=lambda b: len(brand_matches[b]), reverse=True):
car_fw = get_fw_versions(logcan, sendcan, query_brand=brand, timeout=timeout, num_pandas=num_pandas, debug=debug, progress=progress) car_fw = get_fw_versions(logcan, sendcan, query_brand=brand, timeout=timeout, num_pandas=num_pandas, debug=debug, progress=progress)
@ -206,12 +220,20 @@ def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, num_pand
# Try to match using FW returned from this brand only # Try to match using FW returned from this brand only
matches = match_fw_to_car_exact(build_fw_dict(car_fw)) matches = match_fw_to_car_exact(build_fw_dict(car_fw))
if len(matches) == 1: if len(matches) == 1:
matched_brand = brand
break break
disable_obd_multiplexing(Params())
# Do non-OBD queries for matched brand, or all if no match is found
for brand in FW_QUERY_CONFIGS.keys():
if brand == matched_brand or matched_brand is None:
all_car_fw.extend(get_fw_versions(logcan, sendcan, query_brand=brand, timeout=timeout, num_pandas=num_pandas, obd_multiplexed=False, debug=debug, progress=progress))
return all_car_fw return all_car_fw
def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, num_pandas=1, debug=False, progress=False): def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, num_pandas=1, obd_multiplexed=True, debug=False, progress=False):
versions = VERSIONS.copy() versions = VERSIONS.copy()
# Each brand can define extra ECUs to query for data collection # Each brand can define extra ECUs to query for data collection
@ -228,15 +250,19 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1,
# ECUs using a subaddress need be queried one by one, the rest can be done in parallel # ECUs using a subaddress need be queried one by one, the rest can be done in parallel
addrs = [] addrs = []
parallel_addrs = [] parallel_addrs = []
logging_addrs = []
ecu_types = {} ecu_types = {}
for brand, brand_versions in versions.items(): for brand, brand_versions in versions.items():
for c in brand_versions.values(): for candidate, ecu in brand_versions.items():
for ecu_type, addr, sub_addr in c.keys(): for ecu_type, addr, sub_addr in ecu.keys():
a = (brand, addr, sub_addr) a = (brand, addr, sub_addr)
if a not in ecu_types: if a not in ecu_types:
ecu_types[a] = ecu_type ecu_types[a] = ecu_type
if a not in logging_addrs and candidate == "debug":
logging_addrs.append(a)
if sub_addr is None: if sub_addr is None:
if a not in parallel_addrs: if a not in parallel_addrs:
parallel_addrs.append(a) parallel_addrs.append(a)
@ -255,6 +281,9 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1,
# Skip query if no panda available # Skip query if no panda available
if r.bus > num_pandas * 4 - 1: if r.bus > num_pandas * 4 - 1:
continue continue
# Or if request is not designated for current multiplexing mode
elif r.non_obd == obd_multiplexed:
continue
try: try:
addrs = [(a, s) for (b, a, s) in addr_chunk if b in (brand, 'any') and addrs = [(a, s) for (b, a, s) in addr_chunk if b in (brand, 'any') and
@ -265,13 +294,15 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1,
for (tx_addr, sub_addr), version in query.get_data(timeout).items(): for (tx_addr, sub_addr), version in query.get_data(timeout).items():
f = car.CarParams.CarFw.new_message() f = car.CarParams.CarFw.new_message()
f.ecu = ecu_types.get((brand, tx_addr, sub_addr), Ecu.unknown) ecu_key = (brand, tx_addr, sub_addr)
f.ecu = ecu_types.get(ecu_key, Ecu.unknown)
f.fwVersion = version f.fwVersion = version
f.address = tx_addr f.address = tx_addr
f.responseAddress = uds.get_rx_addr_for_tx_addr(tx_addr, r.rx_offset) f.responseAddress = uds.get_rx_addr_for_tx_addr(tx_addr, r.rx_offset)
f.request = r.request f.request = r.request
f.brand = brand f.brand = brand
f.bus = r.bus f.bus = r.bus
f.logging = r.logging or ecu_key in logging_addrs
if sub_addr is not None: if sub_addr is not None:
f.subAddress = sub_addr f.subAddress = sub_addr

@ -3,7 +3,7 @@ from common.conversions import Conversions as CV
from common.numpy_fast import interp from common.numpy_fast import interp
from common.realtime import DT_CTRL from common.realtime import DT_CTRL
from opendbc.can.packer import CANPacker from opendbc.can.packer import CANPacker
from selfdrive.car import apply_std_steer_torque_limits from selfdrive.car import apply_driver_steer_torque_limits
from selfdrive.car.gm import gmcan from selfdrive.car.gm import gmcan
from selfdrive.car.gm.values import DBC, CanBus, CarControllerParams, CruiseButtons from selfdrive.car.gm.values import DBC, CanBus, CarControllerParams, CruiseButtons
@ -13,6 +13,8 @@ LongCtrlState = car.CarControl.Actuators.LongControlState
# Camera cancels up to 0.1s after brake is pressed, ECM allows 0.5s # Camera cancels up to 0.1s after brake is pressed, ECM allows 0.5s
CAMERA_CANCEL_DELAY_FRAMES = 10 CAMERA_CANCEL_DELAY_FRAMES = 10
# Enforce a minimum interval between steering messages to avoid a fault
MIN_STEER_MSG_INTERVAL_MS = 15
class CarController: class CarController:
@ -28,7 +30,6 @@ class CarController:
self.cancel_counter = 0 self.cancel_counter = 0
self.lka_steering_cmd_counter = 0 self.lka_steering_cmd_counter = 0
self.sent_lka_steering_cmd = False
self.lka_icon_status_last = (False, False) self.lka_icon_status_last = (False, False)
self.params = CarControllerParams(self.CP) self.params = CarControllerParams(self.CP)
@ -37,7 +38,7 @@ class CarController:
self.packer_obj = CANPacker(DBC[self.CP.carFingerprint]['radar']) self.packer_obj = CANPacker(DBC[self.CP.carFingerprint]['radar'])
self.packer_ch = CANPacker(DBC[self.CP.carFingerprint]['chassis']) self.packer_ch = CANPacker(DBC[self.CP.carFingerprint]['chassis'])
def update(self, CC, CS): def update(self, CC, CS, now_nanos):
actuators = CC.actuators actuators = CC.actuators
hud_control = CC.hudControl hud_control = CC.hudControl
hud_alert = hud_control.visualAlert hud_alert = hud_control.visualAlert
@ -49,25 +50,30 @@ class CarController:
can_sends = [] can_sends = []
# Steering (Active: 50Hz, inactive: 10Hz) # Steering (Active: 50Hz, inactive: 10Hz)
# Attempt to sync with camera on startup at 50Hz, first few msgs are blocked steer_step = self.params.STEER_STEP if CC.latActive else self.params.INACTIVE_STEER_STEP
init_lka_counter = not self.sent_lka_steering_cmd and self.CP.networkLocation == NetworkLocation.fwdCamera
steer_step = self.params.INACTIVE_STEER_STEP if self.CP.networkLocation == NetworkLocation.fwdCamera:
if CC.latActive or init_lka_counter: # Also send at 50Hz:
steer_step = self.params.STEER_STEP # - on startup, first few msgs are blocked
# - until we're in sync with camera so counters align when relay closes, preventing a fault.
# Avoid GM EPS faults when transmitting messages too close together: skip this transmit if we just received the # openpilot can subtly drift, so this is activated throughout a drive to stay synced
# next Panda loopback confirmation in the current CS frame. out_of_sync = self.lka_steering_cmd_counter % 4 != (CS.cam_lka_steering_cmd_counter + 1) % 4
if CS.loopback_lka_steering_cmd_updated: if CS.loopback_lka_steering_cmd_ts_nanos == 0 or out_of_sync:
self.lka_steering_cmd_counter += 1 steer_step = self.params.STEER_STEP
self.sent_lka_steering_cmd = True
elif (self.frame - self.last_steer_frame) >= steer_step: self.lka_steering_cmd_counter += 1 if CS.loopback_lka_steering_cmd_updated else 0
# Avoid GM EPS faults when transmitting messages too close together: skip this transmit if we
# received the ASCMLKASteeringCmd loopback confirmation too recently
last_lka_steer_msg_ms = (now_nanos - CS.loopback_lka_steering_cmd_ts_nanos) * 1e-6
if (self.frame - self.last_steer_frame) >= steer_step and last_lka_steer_msg_ms > MIN_STEER_MSG_INTERVAL_MS:
# Initialize ASCMLKASteeringCmd counter using the camera until we get a msg on the bus # Initialize ASCMLKASteeringCmd counter using the camera until we get a msg on the bus
if init_lka_counter: if CS.loopback_lka_steering_cmd_ts_nanos == 0:
self.lka_steering_cmd_counter = CS.camera_lka_steering_cmd_counter + 1 self.lka_steering_cmd_counter = CS.pt_lka_steering_cmd_counter + 1
if CC.latActive: if CC.latActive:
new_steer = int(round(actuators.steer * self.params.STEER_MAX)) new_steer = int(round(actuators.steer * self.params.STEER_MAX))
apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params) apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params)
else: else:
apply_steer = 0 apply_steer = 0
@ -109,7 +115,7 @@ class CarController:
# Radar needs to know current speed and yaw rate (50hz), # Radar needs to know current speed and yaw rate (50hz),
# and that ADAS is alive (10hz) # and that ADAS is alive (10hz)
if not self.CP.radarOffCan: if not self.CP.radarUnavailable:
tt = self.frame * DT_CTRL tt = self.frame * DT_CTRL
time_and_headlights_step = 10 time_and_headlights_step = 10
if self.frame % time_and_headlights_step == 0: if self.frame % time_and_headlights_step == 0:

@ -17,8 +17,13 @@ class CarState(CarStateBase):
super().__init__(CP) super().__init__(CP)
can_define = CANDefine(DBC[CP.carFingerprint]["pt"]) can_define = CANDefine(DBC[CP.carFingerprint]["pt"])
self.shifter_values = can_define.dv["ECMPRDNL2"]["PRNDL2"] self.shifter_values = can_define.dv["ECMPRDNL2"]["PRNDL2"]
self.cluster_speed_hyst_gap = CV.KPH_TO_MS / 2.
self.cluster_min_speed = CV.KPH_TO_MS / 2.
self.loopback_lka_steering_cmd_updated = False self.loopback_lka_steering_cmd_updated = False
self.camera_lka_steering_cmd_counter = 0 self.loopback_lka_steering_cmd_ts_nanos = 0
self.pt_lka_steering_cmd_counter = 0
self.cam_lka_steering_cmd_counter = 0
self.buttons_counter = 0 self.buttons_counter = 0
def update(self, pt_cp, cam_cp, loopback_cp): def update(self, pt_cp, cam_cp, loopback_cp):
@ -32,8 +37,11 @@ class CarState(CarStateBase):
# Variables used for avoiding LKAS faults # Variables used for avoiding LKAS faults
self.loopback_lka_steering_cmd_updated = len(loopback_cp.vl_all["ASCMLKASteeringCmd"]["RollingCounter"]) > 0 self.loopback_lka_steering_cmd_updated = len(loopback_cp.vl_all["ASCMLKASteeringCmd"]["RollingCounter"]) > 0
if self.loopback_lka_steering_cmd_updated:
self.loopback_lka_steering_cmd_ts_nanos = loopback_cp.ts_nanos["ASCMLKASteeringCmd"]["RollingCounter"]
if self.CP.networkLocation == NetworkLocation.fwdCamera: if self.CP.networkLocation == NetworkLocation.fwdCamera:
self.camera_lka_steering_cmd_counter = cam_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] self.pt_lka_steering_cmd_counter = pt_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"]
self.cam_lka_steering_cmd_counter = cam_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"]
ret.wheelSpeeds = self.get_wheel_speeds( ret.wheelSpeeds = self.get_wheel_speeds(
pt_cp.vl["EBCMWheelSpdFront"]["FLWheelSpd"], pt_cp.vl["EBCMWheelSpdFront"]["FLWheelSpd"],
@ -93,7 +101,8 @@ class CarState(CarStateBase):
ret.parkingBrake = pt_cp.vl["VehicleIgnitionAlt"]["ParkBrake"] == 1 ret.parkingBrake = pt_cp.vl["VehicleIgnitionAlt"]["ParkBrake"] == 1
ret.cruiseState.available = pt_cp.vl["ECMEngineStatus"]["CruiseMainOn"] != 0 ret.cruiseState.available = pt_cp.vl["ECMEngineStatus"]["CruiseMainOn"] != 0
ret.espDisabled = pt_cp.vl["ESPStatus"]["TractionControlOn"] != 1 ret.espDisabled = pt_cp.vl["ESPStatus"]["TractionControlOn"] != 1
ret.accFaulted = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] == AccState.FAULTED ret.accFaulted = (pt_cp.vl["AcceleratorPedal2"]["CruiseState"] == AccState.FAULTED or
pt_cp.vl["EBCMFrictionBrakeStatus"]["FrictionBrakeUnavailable"] == 1)
ret.cruiseState.enabled = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] != AccState.OFF ret.cruiseState.enabled = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] != AccState.OFF
ret.cruiseState.standstill = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] == AccState.STANDSTILL ret.cruiseState.standstill = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] == AccState.STANDSTILL
@ -148,6 +157,7 @@ class CarState(CarStateBase):
("RLWheelSpd", "EBCMWheelSpdRear"), ("RLWheelSpd", "EBCMWheelSpdRear"),
("RRWheelSpd", "EBCMWheelSpdRear"), ("RRWheelSpd", "EBCMWheelSpdRear"),
("MovingBackward", "EBCMWheelSpdRear"), ("MovingBackward", "EBCMWheelSpdRear"),
("FrictionBrakeUnavailable", "EBCMFrictionBrakeStatus"),
("PRNDL2", "ECMPRDNL2"), ("PRNDL2", "ECMPRDNL2"),
("ManualMode", "ECMPRDNL2"), ("ManualMode", "ECMPRDNL2"),
("LKADriverAppldTrq", "PSCMStatus"), ("LKADriverAppldTrq", "PSCMStatus"),
@ -173,6 +183,7 @@ class CarState(CarStateBase):
("VehicleIgnitionAlt", 10), ("VehicleIgnitionAlt", 10),
("EBCMWheelSpdFront", 20), ("EBCMWheelSpdFront", 20),
("EBCMWheelSpdRear", 20), ("EBCMWheelSpdRear", 20),
("EBCMFrictionBrakeStatus", 20),
("AcceleratorPedal2", 33), ("AcceleratorPedal2", 33),
("ASCMSteeringButton", 33), ("ASCMSteeringButton", 33),
("ECMEngineStatus", 100), ("ECMEngineStatus", 100),
@ -180,6 +191,15 @@ class CarState(CarStateBase):
("ECMAcceleratorPos", 80), ("ECMAcceleratorPos", 80),
] ]
# Used to read back last counter sent to PT by camera
if CP.networkLocation == NetworkLocation.fwdCamera:
signals += [
("RollingCounter", "ASCMLKASteeringCmd"),
]
checks += [
("ASCMLKASteeringCmd", 0),
]
if CP.transmissionType == TransmissionType.direct: if CP.transmissionType == TransmissionType.direct:
signals.append(("RegenPaddle", "EBCMRegenPaddle")) signals.append(("RegenPaddle", "EBCMRegenPaddle"))
checks.append(("EBCMRegenPaddle", 50)) checks.append(("EBCMRegenPaddle", 50))

@ -5,7 +5,8 @@ from panda import Panda
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
from selfdrive.car import STD_CARGO_KG, create_button_event, scale_tire_stiffness, get_safety_config from selfdrive.car import STD_CARGO_KG, create_button_event, scale_tire_stiffness, get_safety_config
from selfdrive.car.gm.values import CAR, CruiseButtons, CarControllerParams, EV_CAR, CAMERA_ACC_CAR from selfdrive.car.gm.radar_interface import RADAR_HEADER_MSG
from selfdrive.car.gm.values import CAR, CruiseButtons, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, CanBus
from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.interfaces import CarInterfaceBase
ButtonType = car.CarState.ButtonEvent.Type ButtonType = car.CarState.ButtonEvent.Type
@ -48,6 +49,7 @@ class CarInterface(CarInterfaceBase):
ret.carName = "gm" ret.carName = "gm"
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.gm)] ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.gm)]
ret.autoResumeSng = False ret.autoResumeSng = False
use_off_car_defaults = len(fingerprint[0]) == 0 # Pick sensible carParams during offline doc generation/CI jobs
if candidate in EV_CAR: if candidate in EV_CAR:
ret.transmissionType = TransmissionType.direct ret.transmissionType = TransmissionType.direct
@ -63,32 +65,34 @@ class CarInterface(CarInterfaceBase):
if candidate in CAMERA_ACC_CAR: if candidate in CAMERA_ACC_CAR:
ret.experimentalLongitudinalAvailable = True ret.experimentalLongitudinalAvailable = True
ret.networkLocation = NetworkLocation.fwdCamera ret.networkLocation = NetworkLocation.fwdCamera
ret.radarOffCan = True # no radar ret.radarUnavailable = True # no radar
ret.pcmCruise = True ret.pcmCruise = True
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM
ret.minEnableSpeed = 5 * CV.KPH_TO_MS ret.minEnableSpeed = 5 * CV.KPH_TO_MS
ret.minSteerSpeed = 10 * CV.KPH_TO_MS
# Tuning for experimental long
ret.longitudinalTuning.kpV = [2.0, 1.5]
ret.longitudinalTuning.kiV = [0.72]
ret.stopAccel = -2.0
ret.stoppingDecelRate = 2.0 # reach brake quickly after enabling
ret.vEgoStopping = 0.25
ret.vEgoStarting = 0.25
ret.longitudinalActuatorDelayUpperBound = 0.5
if experimental_long: if experimental_long:
ret.pcmCruise = False ret.pcmCruise = False
ret.openpilotLongitudinalControl = True ret.openpilotLongitudinalControl = True
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM_LONG ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM_LONG
# Tuning
ret.longitudinalTuning.kpV = [2.0, 1.5]
ret.longitudinalTuning.kiV = [0.72]
ret.stopAccel = -2.0
ret.stoppingDecelRate = 2.0 # reach brake quickly after enabling
ret.vEgoStopping = 0.25
ret.vEgoStarting = 0.25
ret.longitudinalActuatorDelayUpperBound = 0.5
else: # ASCM, OBD-II harness else: # ASCM, OBD-II harness
ret.openpilotLongitudinalControl = True ret.openpilotLongitudinalControl = True
ret.networkLocation = NetworkLocation.gateway ret.networkLocation = NetworkLocation.gateway
ret.radarOffCan = False ret.radarUnavailable = RADAR_HEADER_MSG not in fingerprint[CanBus.OBSTACLE] and not use_off_car_defaults
ret.pcmCruise = False # stock non-adaptive cruise control is kept off ret.pcmCruise = False # stock non-adaptive cruise control is kept off
# supports stop and go, but initial engage must (conservatively) be above 18mph # supports stop and go, but initial engage must (conservatively) be above 18mph
ret.minEnableSpeed = 18 * CV.MPH_TO_MS ret.minEnableSpeed = 18 * CV.MPH_TO_MS
ret.minSteerSpeed = 7 * CV.MPH_TO_MS
# Tuning # Tuning
ret.longitudinalTuning.kpV = [2.4, 1.5] ret.longitudinalTuning.kpV = [2.4, 1.5]
@ -97,11 +101,10 @@ class CarInterface(CarInterfaceBase):
# These cars have been put into dashcam only due to both a lack of users and test coverage. # These cars have been put into dashcam only due to both a lack of users and test coverage.
# These cars likely still work fine. Once a user confirms each car works and a test route is # These cars likely still work fine. Once a user confirms each car works and a test route is
# added to selfdrive/car/tests/routes.py, we can remove it from this list. # added to selfdrive/car/tests/routes.py, we can remove it from this list.
ret.dashcamOnly = candidate in {CAR.CADILLAC_ATS, CAR.HOLDEN_ASTRA, CAR.MALIBU, CAR.BUICK_REGAL, CAR.EQUINOX} ret.dashcamOnly = candidate in {CAR.CADILLAC_ATS, CAR.HOLDEN_ASTRA, CAR.MALIBU, CAR.BUICK_REGAL, CAR.EQUINOX} or \
(ret.networkLocation == NetworkLocation.gateway and ret.radarUnavailable)
# Start with a baseline tuning for all GM vehicles. Override tuning as needed in each model section below. # Start with a baseline tuning for all GM vehicles. Override tuning as needed in each model section below.
# Some GMs need some tolerance above 10 kph to avoid a fault
ret.minSteerSpeed = 10.1 * CV.KPH_TO_MS
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.00]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.00]]
ret.lateralTuning.pid.kf = 0.00004 # full torque for 20 deg at 80mph means 0.00007818594 ret.lateralTuning.pid.kf = 0.00004 # full torque for 20 deg at 80mph means 0.00007818594
@ -159,6 +162,15 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 15.3 ret.steerRatio = 15.3
ret.centerToFront = ret.wheelbase * 0.5 ret.centerToFront = ret.wheelbase * 0.5
elif candidate == CAR.ESCALADE:
ret.minEnableSpeed = -1. # engage speed is decided by pcm
ret.mass = 5653. * CV.LB_TO_KG + STD_CARGO_KG # (5552+5815)/2
ret.wheelbase = 2.95 # 116 inches in meters
ret.steerRatio = 17.3
ret.centerToFront = ret.wheelbase * 0.5
ret.longitudinalActuatorDelayUpperBound = 0.5 # large delay to initially start braking
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.ESCALADE_ESV: elif candidate == CAR.ESCALADE_ESV:
ret.minEnableSpeed = -1. # engage speed is decided by pcm ret.minEnableSpeed = -1. # engage speed is decided by pcm
ret.mass = 2739. + STD_CARGO_KG ret.mass = 2739. + STD_CARGO_KG
@ -174,7 +186,7 @@ class CarInterface(CarInterfaceBase):
ret.mass = 1669. + STD_CARGO_KG ret.mass = 1669. + STD_CARGO_KG
ret.wheelbase = 2.63779 ret.wheelbase = 2.63779
ret.steerRatio = 16.8 ret.steerRatio = 16.8
ret.centerToFront = 2.15 # measured ret.centerToFront = ret.wheelbase * 0.4
tire_stiffness_factor = 1.0 tire_stiffness_factor = 1.0
ret.steerActuatorDelay = 0.2 ret.steerActuatorDelay = 0.2
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
@ -236,5 +248,5 @@ class CarInterface(CarInterfaceBase):
return ret return ret
def apply(self, c): def apply(self, c, now_nanos):
return self.CC.update(c, self.CS) return self.CC.update(c, self.CS, now_nanos)

@ -3,7 +3,7 @@ import math
from cereal import car from cereal import car
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
from opendbc.can.parser import CANParser from opendbc.can.parser import CANParser
from selfdrive.car.gm.values import DBC, CAR, CanBus from selfdrive.car.gm.values import DBC, CanBus
from selfdrive.car.interfaces import RadarInterfaceBase from selfdrive.car.interfaces import RadarInterfaceBase
RADAR_HEADER_MSG = 1120 RADAR_HEADER_MSG = 1120
@ -16,9 +16,6 @@ LAST_RADAR_MSG = RADAR_HEADER_MSG + NUM_SLOTS
def create_radar_can_parser(car_fingerprint): def create_radar_can_parser(car_fingerprint):
if car_fingerprint not in (CAR.VOLT, CAR.MALIBU, CAR.HOLDEN_ASTRA, CAR.ACADIA, CAR.CADILLAC_ATS, CAR.ESCALADE_ESV):
return None
# C1A-ARS3-A by Continental # C1A-ARS3-A by Continental
radar_targets = list(range(SLOT_1_MSG, SLOT_1_MSG + NUM_SLOTS)) radar_targets = list(range(SLOT_1_MSG, SLOT_1_MSG + NUM_SLOTS))
signals = list(zip(['FLRRNumValidTargets', signals = list(zip(['FLRRNumValidTargets',
@ -34,11 +31,12 @@ def create_radar_can_parser(car_fingerprint):
return CANParser(DBC[car_fingerprint]['radar'], signals, checks, CanBus.OBSTACLE) return CANParser(DBC[car_fingerprint]['radar'], signals, checks, CanBus.OBSTACLE)
class RadarInterface(RadarInterfaceBase): class RadarInterface(RadarInterfaceBase):
def __init__(self, CP): def __init__(self, CP):
super().__init__(CP) super().__init__(CP)
self.rcp = create_radar_can_parser(CP.carFingerprint) self.rcp = None if CP.radarUnavailable else create_radar_can_parser(CP.carFingerprint)
self.trigger_msg = LAST_RADAR_MSG self.trigger_msg = LAST_RADAR_MSG
self.updated_messages = set() self.updated_messages = set()

@ -11,10 +11,10 @@ Ecu = car.CarParams.Ecu
class CarControllerParams: class CarControllerParams:
STEER_MAX = 300 # GM limit is 3Nm. Used by carcontroller to generate LKA output STEER_MAX = 300 # GM limit is 3Nm. Used by carcontroller to generate LKA output
STEER_STEP = 2 # Active control frames per command (50hz) STEER_STEP = 3 # Active control frames per command (~33hz)
INACTIVE_STEER_STEP = 10 # Inactive control frames per command (10hz) INACTIVE_STEER_STEP = 10 # Inactive control frames per command (10hz)
STEER_DELTA_UP = 7 # Delta rates require review due to observed EPS weakness STEER_DELTA_UP = 10 # Delta rates require review due to observed EPS weakness
STEER_DELTA_DOWN = 17 STEER_DELTA_DOWN = 25
STEER_DRIVER_ALLOWANCE = 50 STEER_DRIVER_ALLOWANCE = 50
STEER_DRIVER_MULTIPLIER = 4 STEER_DRIVER_MULTIPLIER = 4
STEER_DRIVER_FACTOR = 100 STEER_DRIVER_FACTOR = 100
@ -67,6 +67,7 @@ class CAR:
MALIBU = "CHEVROLET MALIBU PREMIER 2017" MALIBU = "CHEVROLET MALIBU PREMIER 2017"
ACADIA = "GMC ACADIA DENALI 2018" ACADIA = "GMC ACADIA DENALI 2018"
BUICK_REGAL = "BUICK REGAL ESSENCE 2018" BUICK_REGAL = "BUICK REGAL ESSENCE 2018"
ESCALADE = "CADILLAC ESCALADE 2017"
ESCALADE_ESV = "CADILLAC ESCALADE ESV 2016" ESCALADE_ESV = "CADILLAC ESCALADE ESV 2016"
BOLT_EUV = "CHEVROLET BOLT EUV 2022" BOLT_EUV = "CHEVROLET BOLT EUV 2022"
SILVERADO = "CHEVROLET SILVERADO 1500 2020" SILVERADO = "CHEVROLET SILVERADO 1500 2020"
@ -75,7 +76,7 @@ class CAR:
class Footnote(Enum): class Footnote(Enum):
OBD_II = CarFootnote( OBD_II = CarFootnote(
'Requires a <a href="https://github.com/commaai/openpilot/wiki/GM#hardware">community built ASCM harness</a>. ' + 'Requires a <a href="https://github.com/commaai/openpilot/wiki/GM#hardware" target="_blank">community built ASCM harness</a>. ' +
'<b><i>NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).</i></b>', '<b><i>NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).</i></b>',
Column.MODEL) Column.MODEL)
@ -99,6 +100,7 @@ CAR_INFO: Dict[str, Union[GMCarInfo, List[GMCarInfo]]] = {
CAR.MALIBU: GMCarInfo("Chevrolet Malibu Premier 2017"), CAR.MALIBU: GMCarInfo("Chevrolet Malibu Premier 2017"),
CAR.ACADIA: GMCarInfo("GMC Acadia 2018", video_link="https://www.youtube.com/watch?v=0ZN6DdsBUZo"), CAR.ACADIA: GMCarInfo("GMC Acadia 2018", video_link="https://www.youtube.com/watch?v=0ZN6DdsBUZo"),
CAR.BUICK_REGAL: GMCarInfo("Buick Regal Essence 2018"), CAR.BUICK_REGAL: GMCarInfo("Buick Regal Essence 2018"),
CAR.ESCALADE: GMCarInfo("Cadillac Escalade 2017", "Driver Assist Package"),
CAR.ESCALADE_ESV: GMCarInfo("Cadillac Escalade ESV 2016", "Adaptive Cruise Control (ACC) & LKAS"), CAR.ESCALADE_ESV: GMCarInfo("Cadillac Escalade ESV 2016", "Adaptive Cruise Control (ACC) & LKAS"),
CAR.BOLT_EUV: [ CAR.BOLT_EUV: [
GMCarInfo("Chevrolet Bolt EUV 2022-23", "Premier or Premier Redline Trim without Super Cruise Package", "https://youtu.be/xvwzGMUA210"), GMCarInfo("Chevrolet Bolt EUV 2022-23", "Premier or Premier Redline Trim without Super Cruise Package", "https://youtu.be/xvwzGMUA210"),
@ -149,6 +151,10 @@ FINGERPRINTS = {
# Volt Premier w/ ACC 2018 # Volt Premier w/ ACC 2018
{ {
170: 8, 171: 8, 189: 7, 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 288: 5, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 389: 2, 390: 7, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 528: 4, 532: 6, 546: 7, 550: 8, 554: 3, 558: 8, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 566: 5, 567: 3, 568: 1, 573: 1, 577: 8, 578: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 715: 8, 717: 5, 761: 7, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 961: 8, 967: 4, 969: 8, 977: 8, 979: 7, 988: 6, 989: 8, 995: 7, 1001: 8, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1273: 3, 1275: 3, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1516: 8, 1601: 8, 1618: 8, 1905: 7, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1922: 7, 1927: 7, 1930: 7, 2016: 8, 2018: 8, 2020: 8, 2024: 8, 2028: 8 170: 8, 171: 8, 189: 7, 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 288: 5, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 389: 2, 390: 7, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 528: 4, 532: 6, 546: 7, 550: 8, 554: 3, 558: 8, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 566: 5, 567: 3, 568: 1, 573: 1, 577: 8, 578: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 715: 8, 717: 5, 761: 7, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 961: 8, 967: 4, 969: 8, 977: 8, 979: 7, 988: 6, 989: 8, 995: 7, 1001: 8, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1273: 3, 1275: 3, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1516: 8, 1601: 8, 1618: 8, 1905: 7, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1922: 7, 1927: 7, 1930: 7, 2016: 8, 2018: 8, 2020: 8, 2024: 8, 2028: 8
},
# Volt Premier 2018 w/ flashed firmware, no radar
{
170: 8, 171: 8, 189: 7, 190: 6, 192: 5, 193: 8, 197: 8, 199: 4, 201: 6, 209: 7, 211: 2, 241: 6, 288: 5, 289: 1, 290: 1, 298: 2, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 368: 8, 381: 2, 384: 8, 386: 5, 388: 8, 389: 2, 390: 7, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 458: 8, 479: 3, 481: 7, 485: 8, 489: 5, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 3, 508: 8, 512: 3, 528: 4, 530: 8, 532: 6, 537: 5, 539: 8, 542: 7, 546: 7, 550: 8, 554: 3, 558: 8, 560: 6, 562: 4, 563: 5, 564: 5, 565: 5, 566: 5, 567: 3, 568: 1, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 761: 7, 810: 8, 821: 4, 823: 7, 832: 8, 840: 5, 842: 5, 844: 8, 853: 8, 866: 4, 961: 8, 967: 4, 969: 8, 977: 8, 979: 7, 988: 6, 989: 8, 995: 7, 1001: 5, 1003: 5, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1273: 3, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1905: 7, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1922: 7, 1927: 7
}], }],
CAR.BUICK_REGAL : [ CAR.BUICK_REGAL : [
# Regal TourX Essence w/ ACC 2018 # Regal TourX Essence w/ ACC 2018
@ -174,6 +180,10 @@ FINGERPRINTS = {
{ {
190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 289: 8, 298: 8, 304: 1, 309: 8, 313: 8, 320: 3, 322: 7, 328: 1, 338: 6, 340: 6, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 393: 8, 398: 8, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 454: 8, 455: 7, 462: 4, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 510: 8, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 567: 5, 573: 1, 577: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 961: 8, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1217: 8, 1221: 5, 1225: 8, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1601: 8, 1906: 7, 1907: 7, 1912: 7, 1914: 7, 1919: 7, 1920: 7, 1930: 7, 2016: 8, 2024: 8 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 289: 8, 298: 8, 304: 1, 309: 8, 313: 8, 320: 3, 322: 7, 328: 1, 338: 6, 340: 6, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 393: 8, 398: 8, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 454: 8, 455: 7, 462: 4, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 510: 8, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 567: 5, 573: 1, 577: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 961: 8, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1217: 8, 1221: 5, 1225: 8, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1601: 8, 1906: 7, 1907: 7, 1912: 7, 1914: 7, 1919: 7, 1920: 7, 1930: 7, 2016: 8, 2024: 8
}], }],
CAR.ESCALADE: [
{
170: 8, 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 393: 7, 398: 8, 407: 4, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 454: 8, 455: 7, 460: 5, 462: 4, 463: 3, 479: 3, 481: 7, 485: 8, 487: 8, 489: 8, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 510: 8, 532: 6, 534: 2, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 715: 8, 717: 5, 719: 5, 761: 7, 801: 8, 804: 3, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 961: 8, 967: 4, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1217: 8, 1221: 5, 1223: 2, 1225: 7, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1609: 8, 1613: 8, 1649: 8, 1792: 8, 1798: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1858: 8, 1860: 8, 1863: 8, 1872: 8, 1875: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1906: 7, 1907: 7, 1912: 7, 1914: 7, 1917: 7, 1918: 7, 1919: 7, 1920: 7, 1930: 7, 1937: 8, 1953: 8, 1968: 8, 2001: 8, 2017: 8, 2018: 8, 2020: 8, 2026: 8
}],
CAR.ESCALADE_ESV: [ CAR.ESCALADE_ESV: [
{ {
309: 1, 848: 8, 849: 8, 850: 8, 851: 8, 852: 8, 853: 8, 854: 3, 1056: 6, 1057: 8, 1058: 8, 1059: 8, 1060: 8, 1061: 8, 1062: 8, 1063: 8, 1064: 8, 1065: 8, 1066: 8, 1067: 8, 1068: 8, 1120: 8, 1121: 8, 1122: 8, 1123: 8, 1124: 8, 1125: 8, 1126: 8, 1127: 8, 1128: 8, 1129: 8, 1130: 8, 1131: 8, 1132: 8, 1133: 8, 1134: 8, 1135: 8, 1136: 8, 1137: 8, 1138: 8, 1139: 8, 1140: 8, 1141: 8, 1142: 8, 1143: 8, 1146: 8, 1147: 8, 1148: 8, 1149: 8, 1150: 8, 1151: 8, 1216: 8, 1217: 8, 1218: 8, 1219: 8, 1220: 8, 1221: 8, 1222: 8, 1223: 8, 1224: 8, 1225: 8, 1226: 8, 1232: 8, 1233: 8, 1234: 8, 1235: 8, 1236: 8, 1237: 8, 1238: 8, 1239: 8, 1240: 8, 1241: 8, 1242: 8, 1787: 8, 1788: 8 309: 1, 848: 8, 849: 8, 850: 8, 851: 8, 852: 8, 853: 8, 854: 3, 1056: 6, 1057: 8, 1058: 8, 1059: 8, 1060: 8, 1061: 8, 1062: 8, 1063: 8, 1064: 8, 1065: 8, 1066: 8, 1067: 8, 1068: 8, 1120: 8, 1121: 8, 1122: 8, 1123: 8, 1124: 8, 1125: 8, 1126: 8, 1127: 8, 1128: 8, 1129: 8, 1130: 8, 1131: 8, 1132: 8, 1133: 8, 1134: 8, 1135: 8, 1136: 8, 1137: 8, 1138: 8, 1139: 8, 1140: 8, 1141: 8, 1142: 8, 1143: 8, 1146: 8, 1147: 8, 1148: 8, 1149: 8, 1150: 8, 1151: 8, 1216: 8, 1217: 8, 1218: 8, 1219: 8, 1220: 8, 1221: 8, 1222: 8, 1223: 8, 1224: 8, 1225: 8, 1226: 8, 1232: 8, 1233: 8, 1234: 8, 1235: 8, 1236: 8, 1237: 8, 1238: 8, 1239: 8, 1240: 8, 1241: 8, 1242: 8, 1787: 8, 1788: 8

@ -124,7 +124,7 @@ class CarController:
self.brake = 0.0 self.brake = 0.0
self.last_steer = 0.0 self.last_steer = 0.0
def update(self, CC, CS): def update(self, CC, CS, now_nanos):
actuators = CC.actuators actuators = CC.actuators
hud_control = CC.hudControl hud_control = CC.hudControl
hud_v_cruise = hud_control.setSpeed * CV.MS_TO_KPH if hud_control.speedVisible else 255 hud_v_cruise = hud_control.setSpeed * CV.MS_TO_KPH if hud_control.speedVisible else 255

@ -274,7 +274,7 @@ class CarState(CarStateBase):
ret.cruiseState.available = bool(cp.vl[self.main_on_sig_msg]["MAIN_ON"]) ret.cruiseState.available = bool(cp.vl[self.main_on_sig_msg]["MAIN_ON"])
# Gets rid of Pedal Grinding noise when brake is pressed at slow speeds for some models # Gets rid of Pedal Grinding noise when brake is pressed at slow speeds for some models
if self.CP.carFingerprint in (CAR.PILOT, CAR.PASSPORT, CAR.RIDGELINE): if self.CP.carFingerprint in (CAR.PILOT, CAR.RIDGELINE):
if ret.brake > 0.1: if ret.brake > 0.1:
ret.brakePressed = True ret.brakePressed = True

@ -21,6 +21,8 @@ class CarInterface(CarInterfaceBase):
def get_pid_accel_limits(CP, current_speed, cruise_speed): def get_pid_accel_limits(CP, current_speed, cruise_speed):
if CP.carFingerprint in HONDA_BOSCH: if CP.carFingerprint in HONDA_BOSCH:
return CarControllerParams.BOSCH_ACCEL_MIN, CarControllerParams.BOSCH_ACCEL_MAX return CarControllerParams.BOSCH_ACCEL_MIN, CarControllerParams.BOSCH_ACCEL_MAX
elif CP.enableGasInterceptor:
return CarControllerParams.NIDEC_ACCEL_MIN, CarControllerParams.NIDEC_ACCEL_MAX
else: else:
# NIDECs don't allow acceleration near cruise_speed, # NIDECs don't allow acceleration near cruise_speed,
# so limit limits of pid to prevent windup # so limit limits of pid to prevent windup
@ -34,7 +36,7 @@ class CarInterface(CarInterfaceBase):
if candidate in HONDA_BOSCH: if candidate in HONDA_BOSCH:
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hondaBosch)] ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hondaBosch)]
ret.radarOffCan = True ret.radarUnavailable = True
if candidate not in HONDA_BOSCH_RADARLESS: if candidate not in HONDA_BOSCH_RADARLESS:
# Disable the radar and let openpilot control longitudinal # Disable the radar and let openpilot control longitudinal
@ -231,11 +233,11 @@ class CarInterface(CarInterfaceBase):
else: else:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
elif candidate in (CAR.PILOT, CAR.PASSPORT): elif candidate == CAR.PILOT:
ret.mass = 4204. * CV.LB_TO_KG + STD_CARGO_KG # average weight ret.mass = 4278. * CV.LB_TO_KG + STD_CARGO_KG # average weight
ret.wheelbase = 2.82 ret.wheelbase = 2.86
ret.centerToFront = ret.wheelbase * 0.428 ret.centerToFront = ret.wheelbase * 0.428
ret.steerRatio = 17.25 # as spec ret.steerRatio = 16.0 # as spec
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
tire_stiffness_factor = 0.444 tire_stiffness_factor = 0.444
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.38], [0.11]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.38], [0.11]]
@ -348,5 +350,5 @@ class CarInterface(CarInterfaceBase):
# pass in a car.CarControl # pass in a car.CarControl
# to be called @ 100hz # to be called @ 100hz
def apply(self, c): def apply(self, c, now_nanos):
return self.CC.update(c, self.CS) return self.CC.update(c, self.CS, now_nanos)

@ -21,7 +21,7 @@ class RadarInterface(RadarInterfaceBase):
self.track_id = 0 self.track_id = 0
self.radar_fault = False self.radar_fault = False
self.radar_wrong_config = False self.radar_wrong_config = False
self.radar_off_can = CP.radarOffCan self.radar_off_can = CP.radarUnavailable
self.radar_ts = CP.radarTimeStep self.radar_ts = CP.radarTimeStep
self.delay = int(round(0.1 / CP.radarTimeStep)) # 0.1s delay of radar self.delay = int(round(0.1 / CP.radarTimeStep)) # 0.1s delay of radar

@ -0,0 +1,20 @@
#!/usr/bin/env python3
import re
import unittest
from selfdrive.car.honda.values import FW_VERSIONS
HONDA_FW_VERSION_RE = br"\d{5}-[A-Z0-9]{3}(-|,)[A-Z0-9]{4}(\x00){2}$"
class TestHondaFingerprint(unittest.TestCase):
def test_fw_version_format(self):
# Asserts all FW versions follow an expected format
for fw_by_ecu in FW_VERSIONS.values():
for fws in fw_by_ecu.values():
for fw in fws:
self.assertTrue(re.match(HONDA_FW_VERSION_RE, fw) is not None, fw)
if __name__ == "__main__":
unittest.main()

@ -4,9 +4,10 @@ from typing import Dict, List, Optional, Union
from cereal import car from cereal import car
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
from panda.python import uds
from selfdrive.car import dbc_dict from selfdrive.car import dbc_dict
from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column, Harness from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column, Harness
from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16
Ecu = car.CarParams.Ecu Ecu = car.CarParams.Ecu
VisualAlert = car.CarControl.HUDControl.VisualAlert VisualAlert = car.CarControl.HUDControl.VisualAlert
@ -91,7 +92,6 @@ class CAR:
ACURA_RDX = "ACURA RDX 2018" ACURA_RDX = "ACURA RDX 2018"
ACURA_RDX_3G = "ACURA RDX 2020" ACURA_RDX_3G = "ACURA RDX 2020"
PILOT = "HONDA PILOT 2017" PILOT = "HONDA PILOT 2017"
PASSPORT = "HONDA PASSPORT 2021"
RIDGELINE = "HONDA RIDGELINE 2017" RIDGELINE = "HONDA RIDGELINE 2017"
INSIGHT = "HONDA INSIGHT 2019" INSIGHT = "HONDA INSIGHT 2019"
HONDA_E = "HONDA E 2020" HONDA_E = "HONDA E 2020"
@ -142,19 +142,56 @@ CAR_INFO: Dict[str, Optional[Union[HondaCarInfo, List[HondaCarInfo]]]] = {
CAR.ODYSSEY_CHN: None, # Chinese version of Odyssey CAR.ODYSSEY_CHN: None, # Chinese version of Odyssey
CAR.ACURA_RDX: HondaCarInfo("Acura RDX 2016-18", "AcuraWatch Plus", min_steer_speed=12. * CV.MPH_TO_MS), CAR.ACURA_RDX: HondaCarInfo("Acura RDX 2016-18", "AcuraWatch Plus", min_steer_speed=12. * CV.MPH_TO_MS),
CAR.ACURA_RDX_3G: HondaCarInfo("Acura RDX 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS), CAR.ACURA_RDX_3G: HondaCarInfo("Acura RDX 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS),
CAR.PILOT: HondaCarInfo("Honda Pilot 2016-22", min_steer_speed=12. * CV.MPH_TO_MS), CAR.PILOT: [
CAR.PASSPORT: HondaCarInfo("Honda Passport 2019-21", "All", min_steer_speed=12. * CV.MPH_TO_MS), HondaCarInfo("Honda Pilot 2016-22", min_steer_speed=12. * CV.MPH_TO_MS),
HondaCarInfo("Honda Passport 2019-21", "All", min_steer_speed=12. * CV.MPH_TO_MS),
],
CAR.RIDGELINE: HondaCarInfo("Honda Ridgeline 2017-22", min_steer_speed=12. * CV.MPH_TO_MS), CAR.RIDGELINE: HondaCarInfo("Honda Ridgeline 2017-22", min_steer_speed=12. * CV.MPH_TO_MS),
CAR.INSIGHT: HondaCarInfo("Honda Insight 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS), CAR.INSIGHT: HondaCarInfo("Honda Insight 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS),
CAR.HONDA_E: HondaCarInfo("Honda e 2020", "All", min_steer_speed=3. * CV.MPH_TO_MS), CAR.HONDA_E: HondaCarInfo("Honda e 2020", "All", min_steer_speed=3. * CV.MPH_TO_MS),
} }
HONDA_VERSION_REQUEST = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \
p16(0xF112)
HONDA_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) + \
p16(0xF112)
FW_QUERY_CONFIG = FwQueryConfig( FW_QUERY_CONFIG = FwQueryConfig(
requests=[ requests=[
# Currently used to fingerprint
Request(
[StdQueries.UDS_VERSION_REQUEST],
[StdQueries.UDS_VERSION_RESPONSE],
bus=1,
),
# Data collection requests:
# Log extra identifiers for current ECUs
Request(
[HONDA_VERSION_REQUEST],
[HONDA_VERSION_RESPONSE],
bus=1,
logging=True,
),
# Nidec PT bus
Request( Request(
[StdQueries.UDS_VERSION_REQUEST], [StdQueries.UDS_VERSION_REQUEST],
[StdQueries.UDS_VERSION_RESPONSE], [StdQueries.UDS_VERSION_RESPONSE],
bus=0,
logging=True,
), ),
# Bosch PT bus
Request(
[StdQueries.UDS_VERSION_REQUEST],
[StdQueries.UDS_VERSION_RESPONSE],
bus=1,
logging=True,
non_obd=True,
),
],
extra_ecus=[
# The only other ECU on PT bus accessible by camera on radarless Civic
(Ecu.unknown, 0x18DAB3F1, None),
], ],
) )
@ -1067,6 +1104,8 @@ FW_VERSIONS = {
b'28101-5EZ-A060\x00\x00', b'28101-5EZ-A060\x00\x00',
b'28101-5EZ-A100\x00\x00', b'28101-5EZ-A100\x00\x00',
b'28101-5EZ-A210\x00\x00', b'28101-5EZ-A210\x00\x00',
b'28101-5EZ-A600\x00\x00',
b'28101-5EZ-A430\x00\x00',
], ],
(Ecu.programmedFuelInjection, 0x18da10f1, None): [ (Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-RLV-4060\x00\x00', b'37805-RLV-4060\x00\x00',
@ -1078,6 +1117,9 @@ FW_VERSIONS = {
b'37805-RLV-C520\x00\x00', b'37805-RLV-C520\x00\x00',
b'37805-RLV-C530\x00\x00', b'37805-RLV-C530\x00\x00',
b'37805-RLV-C910\x00\x00', b'37805-RLV-C910\x00\x00',
b'37805-RLV-B220\x00\x00',
b'37805-RLV-B210\x00\x00',
b'37805-RLV-L160\x00\x00',
], ],
(Ecu.gateway, 0x18daeff1, None): [ (Ecu.gateway, 0x18daeff1, None): [
b'38897-TG7-A030\x00\x00', b'38897-TG7-A030\x00\x00',
@ -1110,6 +1152,7 @@ FW_VERSIONS = {
b'36161-TGS-A130\x00\x00', b'36161-TGS-A130\x00\x00',
b'36161-TGT-A030\x00\x00', b'36161-TGT-A030\x00\x00',
b'36161-TGT-A130\x00\x00', b'36161-TGT-A130\x00\x00',
b'36161-TGS-A030\x00\x00',
], ],
(Ecu.srs, 0x18da53f1, None): [ (Ecu.srs, 0x18da53f1, None): [
b'77959-TG7-A020\x00\x00', b'77959-TG7-A020\x00\x00',
@ -1147,6 +1190,9 @@ FW_VERSIONS = {
b'78109-TGS-AP20\x00\x00', b'78109-TGS-AP20\x00\x00',
b'78109-TGT-AJ20\x00\x00', b'78109-TGT-AJ20\x00\x00',
b'78109-TGT-AK30\x00\x00', b'78109-TGT-AK30\x00\x00',
b'78109-TGS-AT20\x00\x00',
b'78109-TGS-AX20\x00\x00',
b'78109-TGS-AJ20\x00\x00',
], ],
(Ecu.vsa, 0x18da28f1, None): [ (Ecu.vsa, 0x18da28f1, None): [
b'57114-TG7-A130\x00\x00', b'57114-TG7-A130\x00\x00',
@ -1163,38 +1209,6 @@ FW_VERSIONS = {
b'57114-TGT-A530\x00\x00', b'57114-TGT-A530\x00\x00',
], ],
}, },
CAR.PASSPORT: {
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-RLV-B220\x00\x00',
b'37805-RLV-B210\x00\x00',
],
(Ecu.eps, 0x18da30f1, None): [
b'39990-TGS-A230\x00\x00',
],
(Ecu.fwdRadar, 0x18dab0f1, None): [
b'36161-TGS-A030\x00\x00',
b'36161-TGS-A130\x00\x00',
],
(Ecu.gateway, 0x18daeff1, None): [
b'38897-TG7-A040\x00\x00',
],
(Ecu.srs, 0x18da53f1, None): [
b'77959-TGS-A010\x00\x00',
],
(Ecu.shiftByWire, 0x18da0bf1, None): [
b'54008-TG7-A530\x00\x00',
],
(Ecu.transmission, 0x18da1ef1, None): [
b'28101-5EZ-A600\x00\x00',
],
(Ecu.combinationMeter, 0x18da60f1, None): [
b'78109-TGS-AT20\x00\x00',
b'78109-TGS-AX20\x00\x00',
],
(Ecu.vsa, 0x18da28f1, None): [
b'57114-TGS-A530\x00\x00',
],
},
CAR.ACURA_RDX: { CAR.ACURA_RDX: {
(Ecu.vsa, 0x18da28f1, None): [ (Ecu.vsa, 0x18da28f1, None): [
b'57114-TX5-A220\x00\x00', b'57114-TX5-A220\x00\x00',
@ -1436,6 +1450,7 @@ FW_VERSIONS = {
(Ecu.eps, 0x18DA30F1, None): [ (Ecu.eps, 0x18DA30F1, None): [
b'39990-T39-A130\x00\x00', b'39990-T39-A130\x00\x00',
b'39990-T43-J020\x00\x00', b'39990-T43-J020\x00\x00',
b'39990-T24-T120\x00\x00',
], ],
(Ecu.gateway, 0x18DAEFF1, None): [ (Ecu.gateway, 0x18DAEFF1, None): [
b'38897-T20-A020\x00\x00', b'38897-T20-A020\x00\x00',
@ -1443,11 +1458,13 @@ FW_VERSIONS = {
b'38897-T21-A010\x00\x00', b'38897-T21-A010\x00\x00',
b'38897-T20-A210\x00\x00', b'38897-T20-A210\x00\x00',
b'38897-T20-A310\x00\x00', b'38897-T20-A310\x00\x00',
b'38897-T24-Z120\x00\x00',
], ],
(Ecu.srs, 0x18DA53F1, None): [ (Ecu.srs, 0x18DA53F1, None): [
b'77959-T20-A970\x00\x00', b'77959-T20-A970\x00\x00',
b'77959-T47-A940\x00\x00', b'77959-T47-A940\x00\x00',
b'77959-T47-A950\x00\x00', b'77959-T47-A950\x00\x00',
b'77959-T20-M820\x00\x00',
], ],
(Ecu.combinationMeter, 0x18DA60F1, None): [ (Ecu.combinationMeter, 0x18DA60F1, None): [
b'78108-T21-A220\x00\x00', b'78108-T21-A220\x00\x00',
@ -1455,16 +1472,26 @@ FW_VERSIONS = {
b'78108-T23-A110\x00\x00', b'78108-T23-A110\x00\x00',
b'78108-T21-A230\x00\x00', b'78108-T21-A230\x00\x00',
b'78108-T22-A020\x00\x00', b'78108-T22-A020\x00\x00',
b'78108-T21-MB10\x00\x00',
],
(Ecu.fwdRadar, 0x18dab0f1, None): [
b'36161-T20-A070\x00\x00',
b'36161-T20-A080\x00\x00',
b'36161-T20-A060\x00\x00',
b'36161-T47-A070\x00\x00',
b'36161-T24-T070\x00\x00',
], ],
(Ecu.vsa, 0x18DA28F1, None): [ (Ecu.vsa, 0x18DA28F1, None): [
b'57114-T20-AB40\x00\x00', b'57114-T20-AB40\x00\x00',
b'57114-T43-JB30\x00\x00', b'57114-T43-JB30\x00\x00',
b'57114-T24-TB30\x00\x00',
], ],
(Ecu.transmission, 0x18da1ef1, None): [ (Ecu.transmission, 0x18da1ef1, None): [
b'28101-65D-A020\x00\x00', b'28101-65D-A020\x00\x00',
b'28101-65D-A120\x00\x00', b'28101-65D-A120\x00\x00',
b'28101-65H-A020\x00\x00', b'28101-65H-A020\x00\x00',
b'28101-65H-A120\x00\x00', b'28101-65H-A120\x00\x00',
b'28101-65J-N010\x00\x00',
], ],
(Ecu.programmedFuelInjection, 0x18da10f1, None): [ (Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-64L-A540\x00\x00', b'37805-64L-A540\x00\x00',
@ -1472,6 +1499,7 @@ FW_VERSIONS = {
b'37805-64S-A720\x00\x00', b'37805-64S-A720\x00\x00',
b'37805-64A-A540\x00\x00', b'37805-64A-A540\x00\x00',
b'37805-64A-A620\x00\x00', b'37805-64A-A620\x00\x00',
b'37805-64D-P510\x00\x00',
], ],
}, },
} }
@ -1495,7 +1523,6 @@ DBC = {
CAR.ODYSSEY: dbc_dict('honda_odyssey_exl_2018_generated', 'acura_ilx_2016_nidec'), CAR.ODYSSEY: dbc_dict('honda_odyssey_exl_2018_generated', 'acura_ilx_2016_nidec'),
CAR.ODYSSEY_CHN: dbc_dict('honda_odyssey_extreme_edition_2018_china_can_generated', 'acura_ilx_2016_nidec'), CAR.ODYSSEY_CHN: dbc_dict('honda_odyssey_extreme_edition_2018_china_can_generated', 'acura_ilx_2016_nidec'),
CAR.PILOT: dbc_dict('acura_ilx_2016_can_generated', 'acura_ilx_2016_nidec'), CAR.PILOT: dbc_dict('acura_ilx_2016_can_generated', 'acura_ilx_2016_nidec'),
CAR.PASSPORT: dbc_dict('acura_ilx_2016_can_generated', 'acura_ilx_2016_nidec'),
CAR.RIDGELINE: dbc_dict('acura_ilx_2016_can_generated', 'acura_ilx_2016_nidec'), CAR.RIDGELINE: dbc_dict('acura_ilx_2016_can_generated', 'acura_ilx_2016_nidec'),
CAR.INSIGHT: dbc_dict('honda_insight_ex_2019_can_generated', None), CAR.INSIGHT: dbc_dict('honda_insight_ex_2019_can_generated', None),
CAR.HONDA_E: dbc_dict('acura_rdx_2020_can_generated', None), CAR.HONDA_E: dbc_dict('acura_rdx_2020_can_generated', None),
@ -1510,7 +1537,7 @@ STEER_THRESHOLD = {
HONDA_NIDEC_ALT_PCM_ACCEL = {CAR.ODYSSEY} HONDA_NIDEC_ALT_PCM_ACCEL = {CAR.ODYSSEY}
HONDA_NIDEC_ALT_SCM_MESSAGES = {CAR.ACURA_ILX, CAR.ACURA_RDX, CAR.CRV, CAR.CRV_EU, CAR.FIT, CAR.FREED, CAR.HRV, CAR.ODYSSEY_CHN, HONDA_NIDEC_ALT_SCM_MESSAGES = {CAR.ACURA_ILX, CAR.ACURA_RDX, CAR.CRV, CAR.CRV_EU, CAR.FIT, CAR.FREED, CAR.HRV, CAR.ODYSSEY_CHN,
CAR.PILOT, CAR.PASSPORT, CAR.RIDGELINE} CAR.PILOT, CAR.RIDGELINE}
HONDA_BOSCH = {CAR.ACCORD, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_5G, HONDA_BOSCH = {CAR.ACCORD, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_5G,
CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G, CAR.HONDA_E, CAR.CIVIC_2022} CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G, CAR.HONDA_E, CAR.CIVIC_2022}
HONDA_BOSCH_ALT_BRAKE_SIGNAL = {CAR.ACCORD, CAR.CRV_5G, CAR.ACURA_RDX_3G} HONDA_BOSCH_ALT_BRAKE_SIGNAL = {CAR.ACCORD, CAR.CRV_5G, CAR.ACURA_RDX_3G}

@ -3,7 +3,7 @@ from common.conversions import Conversions as CV
from common.numpy_fast import clip from common.numpy_fast import clip
from common.realtime import DT_CTRL from common.realtime import DT_CTRL
from opendbc.can.packer import CANPacker from opendbc.can.packer import CANPacker
from selfdrive.car import apply_std_steer_torque_limits from selfdrive.car import apply_driver_steer_torque_limits
from selfdrive.car.hyundai import hyundaicanfd, hyundaican from selfdrive.car.hyundai import hyundaicanfd, hyundaican
from selfdrive.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CANFD_CAR, CAR from selfdrive.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CANFD_CAR, CAR
@ -54,13 +54,13 @@ class CarController:
self.car_fingerprint = CP.carFingerprint self.car_fingerprint = CP.carFingerprint
self.last_button_frame = 0 self.last_button_frame = 0
def update(self, CC, CS): def update(self, CC, CS, now_nanos):
actuators = CC.actuators actuators = CC.actuators
hud_control = CC.hudControl hud_control = CC.hudControl
# steering torque # steering torque
new_steer = int(round(actuators.steer * self.params.STEER_MAX)) new_steer = int(round(actuators.steer * self.params.STEER_MAX))
apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params) apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params)
if not CC.latActive: if not CC.latActive:
apply_steer = 0 apply_steer = 0
@ -169,7 +169,8 @@ class CarController:
if (self.frame - self.last_button_frame) * DT_CTRL > 0.1: if (self.frame - self.last_button_frame) * DT_CTRL > 0.1:
# send 25 messages at a time to increases the likelihood of resume being accepted # send 25 messages at a time to increases the likelihood of resume being accepted
can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.RES_ACCEL, self.CP.carFingerprint)] * 25) can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.RES_ACCEL, self.CP.carFingerprint)] * 25)
self.last_button_frame = self.frame if (self.frame - self.last_button_frame) * DT_CTRL >= 0.15:
self.last_button_frame = self.frame
if self.frame % 2 == 0 and self.CP.openpilotLongitudinalControl: if self.frame % 2 == 0 and self.CP.openpilotLongitudinalControl:
# TODO: unclear if this is needed # TODO: unclear if this is needed
@ -178,10 +179,7 @@ class CarController:
hud_control.leadVisible, set_speed_in_units, stopping, CC.cruiseControl.override)) hud_control.leadVisible, set_speed_in_units, stopping, CC.cruiseControl.override))
# 20 Hz LFA MFA message # 20 Hz LFA MFA message
if self.frame % 5 == 0 and self.car_fingerprint in (CAR.SONATA, CAR.PALISADE, CAR.IONIQ, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV_2021, if self.frame % 5 == 0 and self.CP.flags & HyundaiFlags.SEND_LFA.value:
CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KIA_CEED, CAR.KIA_SELTOS, CAR.KONA_EV, CAR.KONA_EV_2022,
CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.SANTA_FE_2022,
CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.GENESIS_G70_2020, CAR.SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022):
can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC.enabled)) can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC.enabled))
# 5 Hz ACC options # 5 Hz ACC options

@ -6,6 +6,7 @@ from cereal import car
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
from opendbc.can.parser import CANParser from opendbc.can.parser import CANParser
from opendbc.can.can_define import CANDefine from opendbc.can.can_define import CANDefine
from selfdrive.car.hyundai.hyundaicanfd import get_e_can_bus
from selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, FEATURES, CAMERA_SCC_CAR, CANFD_CAR, EV_CAR, HYBRID_CAR, Buttons, CarControllerParams from selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, FEATURES, CAMERA_SCC_CAR, CANFD_CAR, EV_CAR, HYBRID_CAR, Buttons, CarControllerParams
from selfdrive.car.interfaces import CarStateBase from selfdrive.car.interfaces import CarStateBase
@ -21,7 +22,9 @@ class CarState(CarStateBase):
self.cruise_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES) self.cruise_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
self.main_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES) self.main_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
self.gear_msg_canfd = "GEAR_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS else "GEAR_SHIFTER" self.gear_msg_canfd = "GEAR_ALT_2" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS_2 else \
"GEAR_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS else \
"GEAR_SHIFTER"
if CP.carFingerprint in CANFD_CAR: if CP.carFingerprint in CANFD_CAR:
self.shifter_values = can_define.dv[self.gear_msg_canfd]["GEAR"] self.shifter_values = can_define.dv[self.gear_msg_canfd]["GEAR"]
elif self.CP.carFingerprint in FEATURES["use_cluster_gears"]: elif self.CP.carFingerprint in FEATURES["use_cluster_gears"]:
@ -86,7 +89,7 @@ class CarState(CarStateBase):
50, cp.vl["CGW1"]["CF_Gway_TurnSigLh"], cp.vl["CGW1"]["CF_Gway_TurnSigRh"]) 50, cp.vl["CGW1"]["CF_Gway_TurnSigLh"], cp.vl["CGW1"]["CF_Gway_TurnSigRh"])
ret.steeringTorque = cp.vl["MDPS12"]["CR_Mdps_StrColTq"] ret.steeringTorque = cp.vl["MDPS12"]["CR_Mdps_StrColTq"]
ret.steeringTorqueEps = cp.vl["MDPS12"]["CR_Mdps_OutTq"] ret.steeringTorqueEps = cp.vl["MDPS12"]["CR_Mdps_OutTq"]
ret.steeringPressed = abs(ret.steeringTorque) > self.params.STEER_THRESHOLD ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
ret.steerFaultTemporary = cp.vl["MDPS12"]["CF_Mdps_ToiUnavail"] != 0 or cp.vl["MDPS12"]["CF_Mdps_ToiFlt"] != 0 ret.steerFaultTemporary = cp.vl["MDPS12"]["CF_Mdps_ToiUnavail"] != 0 or cp.vl["MDPS12"]["CF_Mdps_ToiFlt"] != 0
# cruise state # cruise state
@ -132,8 +135,8 @@ class CarState(CarStateBase):
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear)) ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
if not self.CP.openpilotLongitudinalControl: if not self.CP.openpilotLongitudinalControl:
aeb_src = "FCA11" if self.CP.carFingerprint in FEATURES["use_fca"] else "SCC12" aeb_src = "FCA11" if self.CP.flags & HyundaiFlags.USE_FCA.value else "SCC12"
aeb_sig = "FCA_CmdAct" if self.CP.carFingerprint in FEATURES["use_fca"] else "AEB_CmdAct" aeb_sig = "FCA_CmdAct" if self.CP.flags & HyundaiFlags.USE_FCA.value else "AEB_CmdAct"
aeb_warning = cp_cruise.vl[aeb_src]["CF_VSM_Warn"] != 0 aeb_warning = cp_cruise.vl[aeb_src]["CF_VSM_Warn"] != 0
aeb_braking = cp_cruise.vl[aeb_src]["CF_VSM_DecCmdAct"] != 0 or cp_cruise.vl[aeb_src][aeb_sig] != 0 aeb_braking = cp_cruise.vl[aeb_src]["CF_VSM_DecCmdAct"] != 0 or cp_cruise.vl[aeb_src][aeb_sig] != 0
ret.stockFcw = aeb_warning and not aeb_braking ret.stockFcw = aeb_warning and not aeb_braking
@ -156,6 +159,9 @@ class CarState(CarStateBase):
def update_canfd(self, cp, cp_cam): def update_canfd(self, cp, cp_cam):
ret = car.CarState.new_message() ret = car.CarState.new_message()
self.is_metric = cp.vl["CRUISE_BUTTONS_ALT"]["DISTANCE_UNIT"] != 1
speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
if self.CP.carFingerprint in (EV_CAR | HYBRID_CAR): if self.CP.carFingerprint in (EV_CAR | HYBRID_CAR):
if self.CP.carFingerprint in EV_CAR: if self.CP.carFingerprint in EV_CAR:
ret.gas = cp.vl["ACCELERATOR"]["ACCELERATOR_PEDAL"] / 255. ret.gas = cp.vl["ACCELERATOR"]["ACCELERATOR_PEDAL"] / 255.
@ -197,14 +203,18 @@ class CarState(CarStateBase):
ret.leftBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FL_INDICATOR"] != 0 ret.leftBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FL_INDICATOR"] != 0
ret.rightBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FR_INDICATOR"] != 0 ret.rightBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FR_INDICATOR"] != 0
ret.cruiseState.available = True # cruise state
self.is_metric = cp.vl["CRUISE_BUTTONS_ALT"]["DISTANCE_UNIT"] != 1 # CAN FD cars enable on main button press, set available if no TCS faults preventing engagement
if not self.CP.openpilotLongitudinalControl: ret.cruiseState.available = cp.vl["TCS"]["ACCEnable"] == 0
speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS if self.CP.openpilotLongitudinalControl:
# These are not used for engage/disengage since openpilot keeps track of state using the buttons
ret.cruiseState.enabled = cp.vl["TCS"]["ACC_REQ"] == 1
ret.cruiseState.standstill = False
else:
cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp
ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor
ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1
ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2) ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2)
ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1
ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor
self.cruise_info = copy.copy(cp_cruise_info.vl["SCC_CONTROL"]) self.cruise_info = copy.copy(cp_cruise_info.vl["SCC_CONTROL"])
cruise_btn_msg = "CRUISE_BUTTONS_ALT" if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else "CRUISE_BUTTONS" cruise_btn_msg = "CRUISE_BUTTONS_ALT" if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else "CRUISE_BUTTONS"
@ -307,7 +317,7 @@ class CarState(CarStateBase):
("SCC12", 50), ("SCC12", 50),
] ]
if CP.carFingerprint in FEATURES["use_fca"]: if CP.flags & HyundaiFlags.USE_FCA.value:
signals += [ signals += [
("FCA_CmdAct", "FCA11"), ("FCA_CmdAct", "FCA11"),
("CF_VSM_Warn", "FCA11"), ("CF_VSM_Warn", "FCA11"),
@ -398,7 +408,7 @@ class CarState(CarStateBase):
("SCC12", 50), ("SCC12", 50),
] ]
if CP.carFingerprint in FEATURES["use_fca"]: if CP.flags & HyundaiFlags.USE_FCA.value:
signals += [ signals += [
("FCA_CmdAct", "FCA11"), ("FCA_CmdAct", "FCA11"),
("CF_VSM_Warn", "FCA11"), ("CF_VSM_Warn", "FCA11"),
@ -418,7 +428,9 @@ class CarState(CarStateBase):
def get_can_parser_canfd(CP): def get_can_parser_canfd(CP):
cruise_btn_msg = "CRUISE_BUTTONS_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else "CRUISE_BUTTONS" cruise_btn_msg = "CRUISE_BUTTONS_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else "CRUISE_BUTTONS"
gear_msg = "GEAR_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS else "GEAR_SHIFTER" gear_msg = "GEAR_ALT_2" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS_2 else \
"GEAR_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS else \
"GEAR_SHIFTER"
signals = [ signals = [
("WHEEL_SPEED_1", "WHEEL_SPEEDS"), ("WHEEL_SPEED_1", "WHEEL_SPEEDS"),
("WHEEL_SPEED_2", "WHEEL_SPEEDS"), ("WHEEL_SPEED_2", "WHEEL_SPEEDS"),
@ -435,6 +447,7 @@ class CarState(CarStateBase):
("DriverBraking", "TCS"), ("DriverBraking", "TCS"),
("ACCEnable", "TCS"), ("ACCEnable", "TCS"),
("ACC_REQ", "TCS"),
("COUNTER", cruise_btn_msg), ("COUNTER", cruise_btn_msg),
("CRUISE_BUTTONS", cruise_btn_msg), ("CRUISE_BUTTONS", cruise_btn_msg),
@ -503,8 +516,7 @@ class CarState(CarStateBase):
("ACCELERATOR_BRAKE_ALT", 100), ("ACCELERATOR_BRAKE_ALT", 100),
] ]
bus = 5 if CP.flags & HyundaiFlags.CANFD_HDA2 else 4 return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, get_e_can_bus(CP))
return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, bus)
@staticmethod @staticmethod
def get_cam_can_parser_canfd(CP): def get_cam_can_parser_canfd(CP):

@ -21,7 +21,7 @@ def create_lkas11(packer, frame, car_fingerprint, apply_steer, steer_req,
CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KIA_SELTOS, CAR.ELANTRA_2021, CAR.GENESIS_G70_2020, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KIA_SELTOS, CAR.ELANTRA_2021, CAR.GENESIS_G70_2020,
CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_EV, CAR.KONA_HEV, CAR.KONA_EV_2022, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_EV, CAR.KONA_HEV, CAR.KONA_EV_2022,
CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022,
CAR.SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022): CAR.SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020):
values["CF_Lkas_LdwsActivemode"] = int(left_lane) + (int(right_lane) << 1) values["CF_Lkas_LdwsActivemode"] = int(left_lane) + (int(right_lane) << 1)
values["CF_Lkas_LdwsOpt_USM"] = 2 values["CF_Lkas_LdwsOpt_USM"] = 2

@ -72,8 +72,6 @@ def create_acc_control(packer, CP, enabled, accel_last, accel, stopping, gas_ove
else: else:
a_raw = accel a_raw = accel
a_val = clip(accel, accel_last - jn, accel_last + jn) a_val = clip(accel, accel_last - jn, accel_last + jn)
if stopping:
a_raw = 0
values = { values = {
"ACCMode": 0 if not enabled else (2 if gas_override else 1), "ACCMode": 0 if not enabled else (2 if gas_override else 1),
@ -83,6 +81,7 @@ def create_acc_control(packer, CP, enabled, accel_last, accel, stopping, gas_ove
"aReqRaw": a_raw, "aReqRaw": a_raw,
"VSetDis": set_speed, "VSetDis": set_speed,
"JerkLowerLimit": jerk if enabled else 1, "JerkLowerLimit": jerk if enabled else 1,
"JerkUpperLimit": 3.0,
"ACC_ObjDist": 1, "ACC_ObjDist": 1,
"ObjValid": 0, "ObjValid": 0,
@ -90,7 +89,6 @@ def create_acc_control(packer, CP, enabled, accel_last, accel, stopping, gas_ove
"SET_ME_2": 0x4, "SET_ME_2": 0x4,
"SET_ME_3": 0x3, "SET_ME_3": 0x3,
"SET_ME_TMP_64": 0x64, "SET_ME_TMP_64": 0x64,
"NEW_SIGNAL_10": 4,
"DISTANCE_SETTING": 4, "DISTANCE_SETTING": 4,
} }

@ -2,6 +2,7 @@
from cereal import car from cereal import car
from panda import Panda from panda import Panda
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
from selfdrive.car.hyundai.hyundaicanfd import get_e_can_bus
from selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CANFD_CAR, CAMERA_SCC_CAR, CANFD_RADAR_SCC_CAR, EV_CAR, HYBRID_CAR, LEGACY_SAFETY_MODE_CAR, Buttons from selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CANFD_CAR, CAMERA_SCC_CAR, CANFD_RADAR_SCC_CAR, EV_CAR, HYBRID_CAR, LEGACY_SAFETY_MODE_CAR, Buttons
from selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR from selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR
from selfdrive.car import STD_CARGO_KG, create_button_event, scale_tire_stiffness, get_safety_config from selfdrive.car import STD_CARGO_KG, create_button_event, scale_tire_stiffness, get_safety_config
@ -20,7 +21,7 @@ class CarInterface(CarInterfaceBase):
@staticmethod @staticmethod
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): def _get_params(ret, candidate, fingerprint, car_fw, experimental_long):
ret.carName = "hyundai" ret.carName = "hyundai"
ret.radarOffCan = RADAR_START_ADDR not in fingerprint[1] or DBC[ret.carFingerprint]["radar"] is None ret.radarUnavailable = RADAR_START_ADDR not in fingerprint[1] or DBC[ret.carFingerprint]["radar"] is None
# These cars have been put into dashcam only due to both a lack of users and test coverage. # These cars have been put into dashcam only due to both a lack of users and test coverage.
# These cars likely still work fine. Once a user confirms each car works and a test route is # These cars likely still work fine. Once a user confirms each car works and a test route is
@ -35,11 +36,22 @@ class CarInterface(CarInterfaceBase):
# non-HDA2 # non-HDA2
if 0x1cf not in fingerprint[4]: if 0x1cf not in fingerprint[4]:
ret.flags |= HyundaiFlags.CANFD_ALT_BUTTONS.value ret.flags |= HyundaiFlags.CANFD_ALT_BUTTONS.value
# ICE cars do not have 0x130; GEARS message on 0x40 instead # ICE cars do not have 0x130; GEARS message on 0x40 or 0x70 instead
if 0x130 not in fingerprint[4]: if 0x130 not in fingerprint[4]:
ret.flags |= HyundaiFlags.CANFD_ALT_GEARS.value if 0x40 not in fingerprint[4]:
ret.flags |= HyundaiFlags.CANFD_ALT_GEARS_2.value
else:
ret.flags |= HyundaiFlags.CANFD_ALT_GEARS.value
if candidate not in CANFD_RADAR_SCC_CAR: if candidate not in CANFD_RADAR_SCC_CAR:
ret.flags |= HyundaiFlags.CANFD_CAMERA_SCC.value ret.flags |= HyundaiFlags.CANFD_CAMERA_SCC.value
else:
# Send LFA message on cars with HDA
if 0x485 in fingerprint[2]:
ret.flags |= HyundaiFlags.SEND_LFA.value
# These cars use the FCA11 message for the AEB and FCW signals, all others use SCC12
if 0x38d in fingerprint[0] or 0x38d in fingerprint[2]:
ret.flags |= HyundaiFlags.USE_FCA.value
ret.steerActuatorDelay = 0.1 # Default delay ret.steerActuatorDelay = 0.1 # Default delay
ret.steerLimitTimer = 0.4 ret.steerLimitTimer = 0.4
@ -92,18 +104,13 @@ class CarInterface(CarInterfaceBase):
ret.wheelbase = 2.6 ret.wheelbase = 2.6
ret.steerRatio = 13.42 # Spec ret.steerRatio = 13.42 # Spec
tire_stiffness_factor = 0.385 tire_stiffness_factor = 0.385
elif candidate in (CAR.IONIQ, CAR.IONIQ_EV_LTD, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.IONIQ_HEV_2022): elif candidate in (CAR.IONIQ, CAR.IONIQ_EV_LTD, CAR.IONIQ_PHEV_2019, CAR.IONIQ_HEV_2022, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV):
ret.mass = 1490. + STD_CARGO_KG # weight per hyundai site https://www.hyundaiusa.com/ioniq-electric/specifications.aspx ret.mass = 1490. + STD_CARGO_KG # weight per hyundai site https://www.hyundaiusa.com/ioniq-electric/specifications.aspx
ret.wheelbase = 2.7 ret.wheelbase = 2.7
ret.steerRatio = 13.73 # Spec ret.steerRatio = 13.73 # Spec
tire_stiffness_factor = 0.385 tire_stiffness_factor = 0.385
if candidate not in (CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.IONIQ_HEV_2022): if candidate in (CAR.IONIQ, CAR.IONIQ_EV_LTD, CAR.IONIQ_PHEV_2019):
ret.minSteerSpeed = 32 * CV.MPH_TO_MS ret.minSteerSpeed = 32 * CV.MPH_TO_MS
elif candidate == CAR.IONIQ_PHEV_2019:
ret.mass = 1550. + STD_CARGO_KG # weight per hyundai site https://www.hyundaiusa.com/us/en/vehicles/2019-ioniq-plug-in-hybrid/compare-specs
ret.wheelbase = 2.7
ret.steerRatio = 13.73
ret.minSteerSpeed = 32 * CV.MPH_TO_MS
elif candidate == CAR.VELOSTER: elif candidate == CAR.VELOSTER:
ret.mass = 3558. * CV.LB_TO_KG ret.mass = 3558. * CV.LB_TO_KG
ret.wheelbase = 2.80 ret.wheelbase = 2.80
@ -129,8 +136,8 @@ class CarInterface(CarInterfaceBase):
ret.mass = 1985. + STD_CARGO_KG ret.mass = 1985. + STD_CARGO_KG
ret.wheelbase = 2.78 ret.wheelbase = 2.78
ret.steerRatio = 14.4 * 1.1 # 10% higher at the center seems reasonable ret.steerRatio = 14.4 * 1.1 # 10% higher at the center seems reasonable
elif candidate in (CAR.KIA_NIRO_EV, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021): elif candidate in (CAR.KIA_NIRO_EV, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.KIA_NIRO_HEV_2ND_GEN):
ret.mass = 1737. + STD_CARGO_KG ret.mass = 3452. * CV.LB_TO_KG + STD_CARGO_KG # average of all the cars
ret.wheelbase = 2.7 ret.wheelbase = 2.7
ret.steerRatio = 13.9 if CAR.KIA_NIRO_HEV_2021 else 13.73 # Spec ret.steerRatio = 13.9 if CAR.KIA_NIRO_HEV_2021 else 13.73 # Spec
tire_stiffness_factor = 0.385 tire_stiffness_factor = 0.385
@ -166,7 +173,7 @@ class CarInterface(CarInterfaceBase):
ret.wheelbase = 2.65 ret.wheelbase = 2.65
ret.steerRatio = 13.75 ret.steerRatio = 13.75
tire_stiffness_factor = 0.5 tire_stiffness_factor = 0.5
elif candidate == CAR.KIA_K5_2021: elif candidate in (CAR.KIA_K5_2021, CAR.KIA_K5_HEV_2020):
ret.mass = 3228. * CV.LB_TO_KG ret.mass = 3228. * CV.LB_TO_KG
ret.wheelbase = 2.85 ret.wheelbase = 2.85
ret.steerRatio = 13.27 # 2021 Kia K5 Steering Ratio (all trims) ret.steerRatio = 13.27 # 2021 Kia K5 Steering Ratio (all trims)
@ -185,10 +192,13 @@ class CarInterface(CarInterfaceBase):
ret.mass = 1767. + STD_CARGO_KG # SX Prestige trim support only ret.mass = 1767. + STD_CARGO_KG # SX Prestige trim support only
ret.wheelbase = 2.756 ret.wheelbase = 2.756
ret.steerRatio = 13.6 ret.steerRatio = 13.6
elif candidate == CAR.KIA_SORENTO_PHEV_4TH_GEN: elif candidate in (CAR.KIA_SORENTO_4TH_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN):
ret.mass = 4095.8 * CV.LB_TO_KG + STD_CARGO_KG # weight from EX and above trims, average of FWD and AWD versions (EX, X-Line EX AWD, SX, SX Pestige, X-Line SX Prestige AWD)
ret.wheelbase = 2.81 ret.wheelbase = 2.81
ret.steerRatio = 13.27 # steering ratio according to Kia News https://www.kiamedia.com/us/en/models/sorento-phev/2022/specifications ret.steerRatio = 13.5 # average of the platforms
if candidate == CAR.KIA_SORENTO_4TH_GEN:
ret.mass = 3957 * CV.LB_TO_KG + STD_CARGO_KG
else:
ret.mass = 4537 * CV.LB_TO_KG + STD_CARGO_KG
# Genesis # Genesis
elif candidate == CAR.GENESIS_GV60_EV_1ST_GEN: elif candidate == CAR.GENESIS_GV60_EV_1ST_GEN:
@ -238,8 +248,7 @@ class CarInterface(CarInterfaceBase):
# *** feature detection *** # *** feature detection ***
if candidate in CANFD_CAR: if candidate in CANFD_CAR:
bus = 5 if ret.flags & HyundaiFlags.CANFD_HDA2 else 4 ret.enableBsm = 0x1e5 in fingerprint[get_e_can_bus(ret)]
ret.enableBsm = 0x1e5 in fingerprint[bus]
else: else:
ret.enableBsm = 0x58b in fingerprint[0] ret.enableBsm = 0x58b in fingerprint[0]
@ -324,5 +333,5 @@ class CarInterface(CarInterfaceBase):
return ret return ret
def apply(self, c): def apply(self, c, now_nanos):
return self.CC.update(c, self.CS) return self.CC.update(c, self.CS, now_nanos)

@ -37,7 +37,7 @@ class RadarInterface(RadarInterfaceBase):
self.trigger_msg = RADAR_START_ADDR + RADAR_MSG_COUNT - 1 self.trigger_msg = RADAR_START_ADDR + RADAR_MSG_COUNT - 1
self.track_id = 0 self.track_id = 0
self.radar_off_can = CP.radarOffCan self.radar_off_can = CP.radarUnavailable
self.rcp = get_radar_can_parser(CP) self.rcp = get_radar_can_parser(CP)
def update(self, can_strings): def update(self, can_strings):

@ -2,24 +2,19 @@
import unittest import unittest
from cereal import car from cereal import car
from selfdrive.car.car_helpers import get_interface_attr from selfdrive.car.hyundai.values import CANFD_CAR, FW_QUERY_CONFIG, FW_VERSIONS
from selfdrive.car.fw_versions import FW_QUERY_CONFIGS
from selfdrive.car.hyundai.values import CANFD_CAR
Ecu = car.CarParams.Ecu Ecu = car.CarParams.Ecu
ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()} ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()}
VERSIONS = get_interface_attr("FW_VERSIONS", ignore_none=True)
class TestHyundaiFingerprint(unittest.TestCase): class TestHyundaiFingerprint(unittest.TestCase):
def test_auxiliary_request_ecu_whitelist(self): def test_auxiliary_request_ecu_whitelist(self):
# Asserts only auxiliary Ecus can exist in database for CAN-FD cars # Asserts only auxiliary Ecus can exist in database for CAN-FD cars
config = FW_QUERY_CONFIGS['hyundai'] whitelisted_ecus = {ecu for r in FW_QUERY_CONFIG.requests for ecu in r.whitelist_ecus if r.bus > 3}
whitelisted_ecus = {ecu for r in config.requests for ecu in r.whitelist_ecus if r.bus > 3}
for car_model in CANFD_CAR: for car_model in CANFD_CAR:
ecus = {fw[0] for fw in VERSIONS['hyundai'][car_model].keys()} ecus = {fw[0] for fw in FW_VERSIONS[car_model].keys()}
ecus_not_in_whitelist = ecus - whitelisted_ecus ecus_not_in_whitelist = ecus - whitelisted_ecus
ecu_strings = ", ".join([f'Ecu.{ECU_NAME[ecu]}' for ecu in ecus_not_in_whitelist]) ecu_strings = ", ".join([f'Ecu.{ECU_NAME[ecu]}' for ecu in ecus_not_in_whitelist])
self.assertEqual(len(ecus_not_in_whitelist), 0, f'{car_model}: Car model has ECUs not in auxiliary request whitelists: {ecu_strings}') self.assertEqual(len(ecus_not_in_whitelist), 0, f'{car_model}: Car model has ECUs not in auxiliary request whitelists: {ecu_strings}')

@ -35,7 +35,7 @@ class CarControllerParams:
# To determine the limit for your car, find the maximum value that the stock LKAS will request. # To determine the limit for your car, find the maximum value that the stock LKAS will request.
# If the max stock LKAS request is <384, add your car to this list. # If the max stock LKAS request is <384, add your car to this list.
elif CP.carFingerprint in (CAR.GENESIS_G80, CAR.GENESIS_G90, CAR.ELANTRA, CAR.HYUNDAI_GENESIS, CAR.IONIQ, elif CP.carFingerprint in (CAR.GENESIS_G80, CAR.GENESIS_G90, CAR.ELANTRA, CAR.IONIQ,
CAR.IONIQ_EV_LTD, CAR.SANTA_FE_PHEV_2022, CAR.SONATA_LF, CAR.KIA_FORTE, CAR.KIA_NIRO_PHEV, CAR.IONIQ_EV_LTD, CAR.SANTA_FE_PHEV_2022, CAR.SONATA_LF, CAR.KIA_FORTE, CAR.KIA_NIRO_PHEV,
CAR.KIA_OPTIMA_H, CAR.KIA_SORENTO): CAR.KIA_OPTIMA_H, CAR.KIA_SORENTO):
self.STEER_MAX = 255 self.STEER_MAX = 255
@ -58,8 +58,10 @@ class HyundaiFlags(IntFlag):
CANFD_CAMERA_SCC = 8 CANFD_CAMERA_SCC = 8
ALT_LIMITS = 16 ALT_LIMITS = 16
ENABLE_BLINKERS = 32 ENABLE_BLINKERS = 32
CANFD_ALT_GEARS_2 = 64
SEND_LFA = 128
USE_FCA = 256
class CAR: class CAR:
@ -96,15 +98,18 @@ class CAR:
# Kia # Kia
KIA_FORTE = "KIA FORTE E 2018 & GT 2021" KIA_FORTE = "KIA FORTE E 2018 & GT 2021"
KIA_K5_2021 = "KIA K5 2021" KIA_K5_2021 = "KIA K5 2021"
KIA_K5_HEV_2020 = "KIA K5 HYBRID 2020"
KIA_NIRO_EV = "KIA NIRO EV 2020" KIA_NIRO_EV = "KIA NIRO EV 2020"
KIA_NIRO_PHEV = "KIA NIRO HYBRID 2019" KIA_NIRO_PHEV = "KIA NIRO HYBRID 2019"
KIA_NIRO_HEV_2021 = "KIA NIRO HYBRID 2021" KIA_NIRO_HEV_2021 = "KIA NIRO HYBRID 2021"
KIA_NIRO_HEV_2ND_GEN = "KIA NIRO HYBRID 2ND GEN"
KIA_OPTIMA_G4 = "KIA OPTIMA 4TH GEN" KIA_OPTIMA_G4 = "KIA OPTIMA 4TH GEN"
KIA_OPTIMA_G4_FL = "KIA OPTIMA 4TH GEN FACELIFT" KIA_OPTIMA_G4_FL = "KIA OPTIMA 4TH GEN FACELIFT"
KIA_OPTIMA_H = "KIA OPTIMA HYBRID 2017 & SPORTS 2019" KIA_OPTIMA_H = "KIA OPTIMA HYBRID 2017 & SPORTS 2019"
KIA_SELTOS = "KIA SELTOS 2021" KIA_SELTOS = "KIA SELTOS 2021"
KIA_SPORTAGE_5TH_GEN = "KIA SPORTAGE 5TH GEN" KIA_SPORTAGE_5TH_GEN = "KIA SPORTAGE 5TH GEN"
KIA_SORENTO = "KIA SORENTO GT LINE 2018" KIA_SORENTO = "KIA SORENTO GT LINE 2018"
KIA_SORENTO_4TH_GEN = "KIA SORENTO 4TH GEN"
KIA_SORENTO_PHEV_4TH_GEN = "KIA SORENTO PLUG-IN HYBRID 4TH GEN" KIA_SORENTO_PHEV_4TH_GEN = "KIA SORENTO PLUG-IN HYBRID 4TH GEN"
KIA_SPORTAGE_HYBRID_5TH_GEN = "KIA SPORTAGE HYBRID 5TH GEN" KIA_SPORTAGE_HYBRID_5TH_GEN = "KIA SPORTAGE HYBRID 5TH GEN"
KIA_STINGER = "KIA STINGER GT2 2018" KIA_STINGER = "KIA STINGER GT2 2018"
@ -122,9 +127,10 @@ class CAR:
class Footnote(Enum): class Footnote(Enum):
# footnotes which mention "red panda" will be replaced with the CAN FD panda kit on the shop page
CANFD = CarFootnote( CANFD = CarFootnote(
"Requires a <a href=\"https://comma.ai/shop/panda\" target=\"_blank\">red panda</a>, additional <a href=\"https://comma.ai/shop/harness-box\" target=\"_blank\">harness box</a>, " + "Requires a <a href=\"https://comma.ai/shop/panda\" target=\"_blank\">red panda</a> for this <a href=\"https://en.wikipedia.org/wiki/CAN_FD\" target=\"_blank\">CAN FD car</a>. " +
"additional <a href=\"https://comma.ai/shop/obd-c-cable\" target=\"_blank\">OBD-C cable</a>, USB-A to USB-A cable, and a USB-A to USB-C OTG dongle.", "All the hardware needed is sold in the <a href=\"https://comma.ai/shop/can-fd-panda-kit\" target=\"_blank\">CAN FD kit</a>.",
Column.MODEL, shop_footnote=True) Column.MODEL, shop_footnote=True)
@ -143,9 +149,12 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
HyundaiCarInfo("Hyundai Elantra GT 2017-19", harness=Harness.hyundai_e), HyundaiCarInfo("Hyundai Elantra GT 2017-19", harness=Harness.hyundai_e),
HyundaiCarInfo("Hyundai i30 2017-19", harness=Harness.hyundai_e), HyundaiCarInfo("Hyundai i30 2017-19", harness=Harness.hyundai_e),
], ],
CAR.ELANTRA_2021: HyundaiCarInfo("Hyundai Elantra 2021-22", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k), CAR.ELANTRA_2021: HyundaiCarInfo("Hyundai Elantra 2021-23", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k),
CAR.ELANTRA_HEV_2021: HyundaiCarInfo("Hyundai Elantra Hybrid 2021-23", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k), CAR.ELANTRA_HEV_2021: HyundaiCarInfo("Hyundai Elantra Hybrid 2021-23", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k),
CAR.HYUNDAI_GENESIS: HyundaiCarInfo("Hyundai Genesis 2015-16", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_j), # TODO: check 2015 packages CAR.HYUNDAI_GENESIS: [
HyundaiCarInfo("Hyundai Genesis 2015-16", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_j), # TODO: check 2015 packages
HyundaiCarInfo("Genesis G80 2017", "All", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_j),
],
CAR.IONIQ: HyundaiCarInfo("Hyundai Ioniq Hybrid 2017-19", harness=Harness.hyundai_c), CAR.IONIQ: HyundaiCarInfo("Hyundai Ioniq Hybrid 2017-19", harness=Harness.hyundai_c),
CAR.IONIQ_HEV_2022: HyundaiCarInfo("Hyundai Ioniq Hybrid 2020-22", harness=Harness.hyundai_h), # TODO: confirm 2020-21 harness CAR.IONIQ_HEV_2022: HyundaiCarInfo("Hyundai Ioniq Hybrid 2020-22", harness=Harness.hyundai_h), # TODO: confirm 2020-21 harness
CAR.IONIQ_EV_LTD: HyundaiCarInfo("Hyundai Ioniq Electric 2019", harness=Harness.hyundai_c), CAR.IONIQ_EV_LTD: HyundaiCarInfo("Hyundai Ioniq Electric 2019", harness=Harness.hyundai_c),
@ -160,7 +169,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
CAR.SANTA_FE_2022: HyundaiCarInfo("Hyundai Santa Fe 2021-22", "All", "https://youtu.be/VnHzSTygTS4", harness=Harness.hyundai_l), CAR.SANTA_FE_2022: HyundaiCarInfo("Hyundai Santa Fe 2021-22", "All", "https://youtu.be/VnHzSTygTS4", harness=Harness.hyundai_l),
CAR.SANTA_FE_HEV_2022: HyundaiCarInfo("Hyundai Santa Fe Hybrid 2022", "All", harness=Harness.hyundai_l), CAR.SANTA_FE_HEV_2022: HyundaiCarInfo("Hyundai Santa Fe Hybrid 2022", "All", harness=Harness.hyundai_l),
CAR.SANTA_FE_PHEV_2022: HyundaiCarInfo("Hyundai Santa Fe Plug-in Hybrid 2022", "All", harness=Harness.hyundai_l), CAR.SANTA_FE_PHEV_2022: HyundaiCarInfo("Hyundai Santa Fe Plug-in Hybrid 2022", "All", harness=Harness.hyundai_l),
CAR.SONATA: HyundaiCarInfo("Hyundai Sonata 2020-22", "All", "https://www.youtube.com/watch?v=ix63r9kE3Fw", harness=Harness.hyundai_a), CAR.SONATA: HyundaiCarInfo("Hyundai Sonata 2020-23", "All", "https://www.youtube.com/watch?v=ix63r9kE3Fw", harness=Harness.hyundai_a),
CAR.SONATA_LF: HyundaiCarInfo("Hyundai Sonata 2018-19", harness=Harness.hyundai_e), CAR.SONATA_LF: HyundaiCarInfo("Hyundai Sonata 2018-19", harness=Harness.hyundai_e),
CAR.TUCSON: [ CAR.TUCSON: [
HyundaiCarInfo("Hyundai Tucson 2021", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_l), HyundaiCarInfo("Hyundai Tucson 2021", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_l),
@ -182,22 +191,27 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
HyundaiCarInfo("Hyundai Tucson 2023", "All", harness=Harness.hyundai_n), HyundaiCarInfo("Hyundai Tucson 2023", "All", harness=Harness.hyundai_n),
], ],
CAR.TUCSON_HYBRID_4TH_GEN: HyundaiCarInfo("Hyundai Tucson Hybrid 2022", "All", harness=Harness.hyundai_n), CAR.TUCSON_HYBRID_4TH_GEN: HyundaiCarInfo("Hyundai Tucson Hybrid 2022", "All", harness=Harness.hyundai_n),
CAR.SANTA_CRUZ_1ST_GEN: HyundaiCarInfo("Hyundai Santa Cruz 2021-22", harness=Harness.hyundai_n), CAR.SANTA_CRUZ_1ST_GEN: HyundaiCarInfo("Hyundai Santa Cruz 2022-23", harness=Harness.hyundai_n),
# Kia # Kia
CAR.KIA_FORTE: HyundaiCarInfo("Kia Forte 2019-21", harness=Harness.hyundai_g), CAR.KIA_FORTE: HyundaiCarInfo("Kia Forte 2019-21", harness=Harness.hyundai_g),
CAR.KIA_K5_2021: HyundaiCarInfo("Kia K5 2021-22", harness=Harness.hyundai_a), CAR.KIA_K5_2021: HyundaiCarInfo("Kia K5 2021-22", harness=Harness.hyundai_a),
CAR.KIA_K5_HEV_2020: HyundaiCarInfo("Kia K5 Hybrid 2020", harness=Harness.hyundai_a),
CAR.KIA_NIRO_EV: [ CAR.KIA_NIRO_EV: [
HyundaiCarInfo("Kia Niro EV 2019", "All", "https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_h), HyundaiCarInfo("Kia Niro EV 2019", "All", "https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_h),
HyundaiCarInfo("Kia Niro EV 2020", "All", "https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_f), HyundaiCarInfo("Kia Niro EV 2020", "All", "https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_f),
HyundaiCarInfo("Kia Niro EV 2021", "All", "https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_c), HyundaiCarInfo("Kia Niro EV 2021", "All", "https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_c),
HyundaiCarInfo("Kia Niro EV 2022", "All", "https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_h), HyundaiCarInfo("Kia Niro EV 2022", "All", "https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_h),
], ],
CAR.KIA_NIRO_PHEV: HyundaiCarInfo("Kia Niro Plug-in Hybrid 2018-19", "All", min_enable_speed=10. * CV.MPH_TO_MS, harness=Harness.hyundai_c), CAR.KIA_NIRO_PHEV: [
HyundaiCarInfo("Kia Niro Plug-in Hybrid 2018-19", "All", min_enable_speed=10. * CV.MPH_TO_MS, harness=Harness.hyundai_c),
HyundaiCarInfo("Kia Niro Plug-in Hybrid 2020", "All", harness=Harness.hyundai_d),
],
CAR.KIA_NIRO_HEV_2021: [ CAR.KIA_NIRO_HEV_2021: [
HyundaiCarInfo("Kia Niro Hybrid 2021", harness=Harness.hyundai_f), # TODO: could be hyundai_d, verify HyundaiCarInfo("Kia Niro Hybrid 2021", harness=Harness.hyundai_f), # TODO: could be hyundai_d, verify
HyundaiCarInfo("Kia Niro Hybrid 2022", harness=Harness.hyundai_h), HyundaiCarInfo("Kia Niro Hybrid 2022", harness=Harness.hyundai_h),
], ],
CAR.KIA_NIRO_HEV_2ND_GEN: HyundaiCarInfo("Kia Niro Hybrid 2023", harness=Harness.hyundai_a),
CAR.KIA_OPTIMA_G4: HyundaiCarInfo("Kia Optima 2017", "Advanced Smart Cruise Control", harness=Harness.hyundai_b), # TODO: may support 2016, 2018 CAR.KIA_OPTIMA_G4: HyundaiCarInfo("Kia Optima 2017", "Advanced Smart Cruise Control", harness=Harness.hyundai_b), # TODO: may support 2016, 2018
CAR.KIA_OPTIMA_G4_FL: HyundaiCarInfo("Kia Optima 2019-20", harness=Harness.hyundai_g), CAR.KIA_OPTIMA_G4_FL: HyundaiCarInfo("Kia Optima 2019-20", harness=Harness.hyundai_g),
CAR.KIA_OPTIMA_H: [ CAR.KIA_OPTIMA_H: [
@ -210,7 +224,8 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
HyundaiCarInfo("Kia Sorento 2018", "Advanced Smart Cruise Control", "https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_c), HyundaiCarInfo("Kia Sorento 2018", "Advanced Smart Cruise Control", "https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_c),
HyundaiCarInfo("Kia Sorento 2019", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_e), HyundaiCarInfo("Kia Sorento 2019", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_e),
], ],
CAR.KIA_SORENTO_PHEV_4TH_GEN: HyundaiCarInfo("Kia Sorento Plug-in Hybrid 2022-23", "Smart Cruise Control (SCC)", harness=Harness.hyundai_a), CAR.KIA_SORENTO_4TH_GEN: HyundaiCarInfo("Kia Sorento 2022-23", harness=Harness.hyundai_k),
CAR.KIA_SORENTO_PHEV_4TH_GEN: HyundaiCarInfo("Kia Sorento Plug-in Hybrid 2022-23", harness=Harness.hyundai_a),
CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: HyundaiCarInfo("Kia Sportage Hybrid 2023", harness=Harness.hyundai_n), CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: HyundaiCarInfo("Kia Sportage Hybrid 2023", harness=Harness.hyundai_n),
CAR.KIA_STINGER: HyundaiCarInfo("Kia Stinger 2018-20", video_link="https://www.youtube.com/watch?v=MJ94qoofYw0", harness=Harness.hyundai_c), CAR.KIA_STINGER: HyundaiCarInfo("Kia Stinger 2018-20", video_link="https://www.youtube.com/watch?v=MJ94qoofYw0", harness=Harness.hyundai_c),
CAR.KIA_STINGER_2022: HyundaiCarInfo("Kia Stinger 2022", "All", harness=Harness.hyundai_k), CAR.KIA_STINGER_2022: HyundaiCarInfo("Kia Stinger 2022", "All", harness=Harness.hyundai_k),
@ -222,11 +237,14 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
], ],
# Genesis # Genesis
CAR.GENESIS_GV60_EV_1ST_GEN: HyundaiCarInfo("Genesis GV60 2023", "All", harness=Harness.hyundai_k), CAR.GENESIS_GV60_EV_1ST_GEN: [
HyundaiCarInfo("Genesis GV60 (Advanced Trim) 2023", "All", harness=Harness.hyundai_a),
HyundaiCarInfo("Genesis GV60 (Performance Trim) 2023", "All", harness=Harness.hyundai_k),
],
CAR.GENESIS_G70: HyundaiCarInfo("Genesis G70 2018-19", "All", harness=Harness.hyundai_f), CAR.GENESIS_G70: HyundaiCarInfo("Genesis G70 2018-19", "All", harness=Harness.hyundai_f),
CAR.GENESIS_G70_2020: HyundaiCarInfo("Genesis G70 2020", "All", harness=Harness.hyundai_f), CAR.GENESIS_G70_2020: HyundaiCarInfo("Genesis G70 2020", "All", harness=Harness.hyundai_f),
CAR.GENESIS_GV70_1ST_GEN: HyundaiCarInfo("Genesis GV70 2022-23", "All", harness=Harness.hyundai_l), CAR.GENESIS_GV70_1ST_GEN: HyundaiCarInfo("Genesis GV70 2022-23", "All", harness=Harness.hyundai_l),
CAR.GENESIS_G80: HyundaiCarInfo("Genesis G80 2017-19", "All", harness=Harness.hyundai_h), CAR.GENESIS_G80: HyundaiCarInfo("Genesis G80 2018-19", "All", harness=Harness.hyundai_h),
CAR.GENESIS_G90: HyundaiCarInfo("Genesis G90 2017-18", "All", harness=Harness.hyundai_c), CAR.GENESIS_G90: HyundaiCarInfo("Genesis G90 2017-18", "All", harness=Harness.hyundai_c),
} }
@ -358,6 +376,13 @@ FW_QUERY_CONFIG = FwQueryConfig(
) )
FW_VERSIONS = { FW_VERSIONS = {
CAR.HYUNDAI_GENESIS: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00DH LKAS 1.1 -150210',
b'\xf1\x00DH LKAS 1.4 -140110',
b'\xf1\x00DH LKAS 1.5 -140425',
],
},
CAR.IONIQ: { CAR.IONIQ: {
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 ', b'\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 ',
@ -395,29 +420,32 @@ FW_VERSIONS = {
}, },
CAR.IONIQ_PHEV: { CAR.IONIQ_PHEV: {
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\000AEhe SCC FHCUP 1.00 1.02 99110-G2100 ', b'\xf1\x00AEhe SCC FHCUP 1.00 1.02 99110-G2100 ',
b'\xf1\x00AEhe SCC F-CUP 1.00 1.00 99110-G2200 ', b'\xf1\x00AEhe SCC F-CUP 1.00 1.00 99110-G2200 ',
b'\xf1\x00AEhe SCC F-CUP 1.00 1.00 99110-G2600 ', b'\xf1\x00AEhe SCC F-CUP 1.00 1.00 99110-G2600 ',
b'\xf1\x00AEhe SCC F-CUP 1.00 1.02 99110-G2100 ',
], ],
(Ecu.eps, 0x7d4, None): [ (Ecu.eps, 0x7d4, None): [
b'\xf1\000AE MDPS C 1.00 1.01 56310/G2510 4APHC101', b'\xf1\x00AE MDPS C 1.00 1.01 56310/G2510 4APHC101',
b'\xf1\x00AE MDPS C 1.00 1.01 56310/G2560 4APHC101', b'\xf1\x00AE MDPS C 1.00 1.01 56310/G2560 4APHC101',
b'\xf1\x00AE MDPS C 1.00 1.01 56310G2510\x00 4APHC101', b'\xf1\x00AE MDPS C 1.00 1.01 56310G2510\x00 4APHC101',
], ],
(Ecu.fwdCamera, 0x7c4, None): [ (Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\000AEP MFC AT USA LHD 1.00 1.01 95740-G2600 190819', b'\xf1\x00AEP MFC AT USA LHD 1.00 1.01 95740-G2600 190819',
b'\xf1\x00AEP MFC AT EUR RHD 1.00 1.01 95740-G2600 190819', b'\xf1\x00AEP MFC AT EUR RHD 1.00 1.01 95740-G2600 190819',
b'\xf1\x00AEP MFC AT USA LHD 1.00 1.00 95740-G2700 201027', b'\xf1\x00AEP MFC AT USA LHD 1.00 1.00 95740-G2700 201027',
], ],
(Ecu.engine, 0x7e0, None): [ (Ecu.engine, 0x7e0, None): [
b'\xf1\x816H6F6051\x00\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x816H6F6051\x00\x00\x00\x00\x00\x00\x00\x00',
b'\xf1\x816H6G6051\x00\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x816H6G6051\x00\x00\x00\x00\x00\x00\x00\x00',
b'\xf1\x816H6G5051\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
b'\xf1\x816U3J9051\000\000\xf1\0006U3H1_C2\000\0006U3J9051\000\000PAE0G16NL0\x82zT\xd2', b'\xf1\x816U3J9051\000\000\xf1\0006U3H1_C2\000\0006U3J9051\000\000PAE0G16NL0\x82zT\xd2',
b'\xf1\x816U3J8051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J8051\x00\x00PAETG16UL0\x00\x00\x00\x00', b'\xf1\x816U3J8051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J8051\x00\x00PAETG16UL0\x00\x00\x00\x00',
b'\xf1\x816U3J9051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL2\xad\xeb\xabt',
b'\xf1\x816U3J9051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL2\x00\x00\x00\x00', b'\xf1\x816U3J9051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL2\x00\x00\x00\x00',
b'\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL0\x00\x00\x00\x00',
b'\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL2\xad\xeb\xabt',
], ],
}, },
CAR.IONIQ_EV_2020: { CAR.IONIQ_EV_2020: {
@ -445,16 +473,19 @@ FW_VERSIONS = {
b'\xf1\x00AE MDPS C 1.00 1.04 56310/G7501 4AEEC104', b'\xf1\x00AE MDPS C 1.00 1.04 56310/G7501 4AEEC104',
b'\xf1\x00AE MDPS C 1.00 1.03 56310/G7300 4AEEC103', b'\xf1\x00AE MDPS C 1.00 1.03 56310/G7300 4AEEC103',
b'\xf1\x00AE MDPS C 1.00 1.03 56310G7300\x00 4AEEC103', b'\xf1\x00AE MDPS C 1.00 1.03 56310G7300\x00 4AEEC103',
b'\xf1\x00AE MDPS C 1.00 1.04 56310/G7301 4AEEC104',
], ],
(Ecu.fwdCamera, 0x7c4, None): [ (Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.00 95740-G7200 160418', b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.00 95740-G7200 160418',
b'\xf1\x00AEE MFC AT USA LHD 1.00 1.00 95740-G2400 180222', b'\xf1\x00AEE MFC AT USA LHD 1.00 1.00 95740-G2400 180222',
b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.00 95740-G2300 170703', b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.00 95740-G2300 170703',
b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.00 95740-G2400 180222',
], ],
}, },
CAR.IONIQ_HEV_2022: { CAR.IONIQ_HEV_2022: {
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00AEhe SCC F-CUP 1.00 1.00 99110-G2600 ', b'\xf1\x00AEhe SCC F-CUP 1.00 1.00 99110-G2600 ',
b'\xf1\x00AEhe SCC FHCUP 1.00 1.00 99110-G2600 ',
], ],
(Ecu.eps, 0x7d4, None): [ (Ecu.eps, 0x7d4, None): [
b'\xf1\x00AE MDPS C 1.00 1.01 56310G2510\x00 4APHC101', b'\xf1\x00AE MDPS C 1.00 1.01 56310G2510\x00 4APHC101',
@ -467,6 +498,7 @@ FW_VERSIONS = {
], ],
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
b'\xf1\x816U3J9051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00HAE0G16NL2\x00\x00\x00\x00', b'\xf1\x816U3J9051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00HAE0G16NL2\x00\x00\x00\x00',
b'\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00HAE0G16NL2\x96\xda\xd4\xee',
], ],
}, },
CAR.SONATA: { CAR.SONATA: {
@ -512,6 +544,8 @@ FW_VERSIONS = {
b'HM6M1_0a0_G20', b'HM6M1_0a0_G20',
b'HM6M2_0a0_BD0', b'HM6M2_0a0_BD0',
b'\xf1\x8739110-2S278\xf1\x82DNDVD5GMCCXXXL5B', b'\xf1\x8739110-2S278\xf1\x82DNDVD5GMCCXXXL5B',
b'\xf1\x8739110-2S041\xf1\x81HM6M1_0a0_M00',
b'\xf1\x81HM6M1_0a0_G20',
], ],
(Ecu.eps, 0x7d4, None): [ (Ecu.eps, 0x7d4, None): [
b'\xf1\x00DN8 MDPS C 1,00 1,01 56310L0010\x00 4DNAC101', # modified firmware b'\xf1\x00DN8 MDPS C 1,00 1,01 56310L0010\x00 4DNAC101', # modified firmware
@ -529,6 +563,7 @@ FW_VERSIONS = {
b'\xf1\x8756310L0210\x00\xf1\x00DN8 MDPS C 1.00 1.01 56310L0210\x00 4DNAC101', b'\xf1\x8756310L0210\x00\xf1\x00DN8 MDPS C 1.00 1.01 56310L0210\x00 4DNAC101',
b'\xf1\x8757700-L0000\xf1\x00DN8 MDPS R 1.00 1.00 57700-L0000 4DNAP100', b'\xf1\x8757700-L0000\xf1\x00DN8 MDPS R 1.00 1.00 57700-L0000 4DNAP100',
b'\xf1\x00DN8 MDPS R 1.00 1.00 57700-L0000 4DNAP101', b'\xf1\x00DN8 MDPS R 1.00 1.00 57700-L0000 4DNAP101',
b'\xf1\x00DN8 MDPS C 1.00 1.01 56310-L0210 4DNAC102',
], ],
(Ecu.fwdCamera, 0x7c4, None): [ (Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00DN8 MFC AT KOR LHD 1.00 1.02 99211-L1000 190422', b'\xf1\x00DN8 MFC AT KOR LHD 1.00 1.02 99211-L1000 190422',
@ -538,6 +573,7 @@ FW_VERSIONS = {
b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.03 99211-L0000 210603', b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.03 99211-L0000 210603',
b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.05 99211-L1000 201109', b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.05 99211-L1000 201109',
b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.06 99211-L1000 210325', b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.06 99211-L1000 210325',
b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.07 99211-L1000 211223',
], ],
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
b'\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v', b'\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v',
@ -548,6 +584,7 @@ FW_VERSIONS = {
b'\xf1\x00HT6WA250BLHT6WA910A1SDN8G25NB1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x00HT6WA250BLHT6WA910A1SDN8G25NB1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'\xf1\x00HT6WA250BLHT6WA910A1SDN8G25NB1\x00\x00\x00\x00\x00\x00\x96\xa1\xf1\x92', b'\xf1\x00HT6WA250BLHT6WA910A1SDN8G25NB1\x00\x00\x00\x00\x00\x00\x96\xa1\xf1\x92',
b'\xf1\x00HT6WA280BLHT6WAD10A1SDN8G25NB2\x00\x00\x00\x00\x00\x00\x08\xc9O:', b'\xf1\x00HT6WA280BLHT6WAD10A1SDN8G25NB2\x00\x00\x00\x00\x00\x00\x08\xc9O:',
b'\xf1\x00HT6WA280BLHT6WAD10A1SDN8G25NB4\x00\x00\x00\x00\x00\x00g!l[',
b'\xf1\x00T02601BL T02730A1 VDN8T25XXX730NS5\xf7_\x92\xf5', b'\xf1\x00T02601BL T02730A1 VDN8T25XXX730NS5\xf7_\x92\xf5',
b'\xf1\x00T02601BL T02832A1 VDN8T25XXX832NS8G\x0e\xfeE', b'\xf1\x00T02601BL T02832A1 VDN8T25XXX832NS8G\x0e\xfeE',
b'\xf1\x87954A02N060\x00\x00\x00\x00\x00\xf1\x81T02730A1 \xf1\x00T02601BL T02730A1 VDN8T25XXX730NS5\xf7_\x92\xf5', b'\xf1\x87954A02N060\x00\x00\x00\x00\x00\xf1\x81T02730A1 \xf1\x00T02601BL T02730A1 VDN8T25XXX730NS5\xf7_\x92\xf5',
@ -599,6 +636,7 @@ FW_VERSIONS = {
b'\xf1\x87SALFBA7460044GJ2gx\x87\x88Vf\x86hx\x88\x87\x88wwwwgw\x86wd?\xfa\xff\x86U_\xff\xaf\x1f\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB2\n\xdd^\xbc', b'\xf1\x87SALFBA7460044GJ2gx\x87\x88Vf\x86hx\x88\x87\x88wwwwgw\x86wd?\xfa\xff\x86U_\xff\xaf\x1f\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB2\n\xdd^\xbc',
b'\xf1\x87SAMFBA8105254GJ2wx\x87\x88Vf\x86hx\x88\x87\x88wwwwwwww\x86O\xfa\xff\x99\x88\x7f\xffZG\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB2\n\xdd^\xbc', b'\xf1\x87SAMFBA8105254GJ2wx\x87\x88Vf\x86hx\x88\x87\x88wwwwwwww\x86O\xfa\xff\x99\x88\x7f\xffZG\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB2\n\xdd^\xbc',
b'\xf1\x87SANFB45889451GC7wx\x87\x88gw\x87x\x88\x88x\x88\x87wxw\x87wxw\x87\x8f\xfc\xffeU\x8f\xff+Q\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB2\n\xdd^\xbc', b'\xf1\x87SANFB45889451GC7wx\x87\x88gw\x87x\x88\x88x\x88\x87wxw\x87wxw\x87\x8f\xfc\xffeU\x8f\xff+Q\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB2\n\xdd^\xbc',
b'\xf1\x00T02601BL T02900A1 VDN8T25XXX900NSA\xb9\x13\xf9p',
], ],
}, },
CAR.SONATA_LF: { CAR.SONATA_LF: {
@ -648,14 +686,16 @@ FW_VERSIONS = {
}, },
CAR.SANTA_FE: { CAR.SANTA_FE: {
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00TM__ SCC F-CUP 1.00 1.00 99110-S1210 ',
b'\xf1\x00TM__ SCC F-CUP 1.00 1.01 99110-S2000 ', b'\xf1\x00TM__ SCC F-CUP 1.00 1.01 99110-S2000 ',
b'\xf1\x00TM__ SCC F-CUP 1.00 1.02 99110-S2000 ', b'\xf1\x00TM__ SCC F-CUP 1.00 1.02 99110-S2000 ',
b'\xf1\x00TM__ SCC F-CUP 1.00 1.03 99110-S2000 ', b'\xf1\x00TM__ SCC F-CUP 1.00 1.03 99110-S2000 ',
], ],
(Ecu.abs, 0x7d1, None): [ (Ecu.abs, 0x7d1, None): [
b'\xf1\x00TM ESC \r 100\x18\x031 58910-S2650', b'\xf1\x00TM ESC \r 100\x18\x031 58910-S2650',
b'\xf1\x00TM ESC \r 105\x19\x05# 58910-S1500',
b'\xf1\x00TM ESC \r 103\x18\x11\x08 58910-S2650', b'\xf1\x00TM ESC \r 103\x18\x11\x08 58910-S2650',
b'\xf1\x00TM ESC \r 104\x19\a\b 58910-S2650', b'\xf1\x00TM ESC \r 104\x19\x07\x08 58910-S2650',
b'\xf1\x00TM ESC \x02 100\x18\x030 58910-S2600', b'\xf1\x00TM ESC \x02 100\x18\x030 58910-S2600',
b'\xf1\x00TM ESC \x02 102\x18\x07\x01 58910-S2600', b'\xf1\x00TM ESC \x02 102\x18\x07\x01 58910-S2600',
b'\xf1\x00TM ESC \x02 103\x18\x11\x07 58910-S2600', b'\xf1\x00TM ESC \x02 103\x18\x11\x07 58910-S2600',
@ -672,11 +712,15 @@ FW_VERSIONS = {
b'\xf1\x00TM MDPS C 1.00 1.00 56340-S2000 8409', b'\xf1\x00TM MDPS C 1.00 1.00 56340-S2000 8409',
b'\xf1\x00TM MDPS C 1.00 1.00 56340-S2000 8A12', b'\xf1\x00TM MDPS C 1.00 1.00 56340-S2000 8A12',
b'\xf1\x00TM MDPS C 1.00 1.01 56340-S2000 9129', b'\xf1\x00TM MDPS C 1.00 1.01 56340-S2000 9129',
b'\xf1\x00TM MDPS R 1.00 1.02 57700-S1100 4TMDP102'
], ],
(Ecu.fwdCamera, 0x7c4, None): [ (Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00TM MFC AT EUR LHD 1.00 1.01 99211-S1010 181207',
b'\xf1\x00TM MFC AT USA LHD 1.00 1.00 99211-S2000 180409', b'\xf1\x00TM MFC AT USA LHD 1.00 1.00 99211-S2000 180409',
], ],
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
b'\xf1\x00bcsh8p54 U833\x00\x00\x00\x00\x00\x00TTM4V22US3_<]\xf1',
b'\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM4T20NS5\x00\x00\x00\x00',
b'\xf1\x87LBJSGA7082574HG0\x87www\x98\x88\x88\x88\x99\xaa\xb9\x9afw\x86gx\x99\xa7\x89co\xf8\xffvU_\xffR\xaf\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2T20NS1\x00\xa6\xe0\x91', b'\xf1\x87LBJSGA7082574HG0\x87www\x98\x88\x88\x88\x99\xaa\xb9\x9afw\x86gx\x99\xa7\x89co\xf8\xffvU_\xffR\xaf\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2T20NS1\x00\xa6\xe0\x91',
b'\xf1\x87LBKSGA0458404HG0vfvg\x87www\x89\x99\xa8\x99y\xaa\xa7\x9ax\x88\xa7\x88t_\xf9\xff\x86w\x8f\xff\x15x\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2T20NS1\x00\x00\x00\x00', b'\xf1\x87LBKSGA0458404HG0vfvg\x87www\x89\x99\xa8\x99y\xaa\xa7\x9ax\x88\xa7\x88t_\xf9\xff\x86w\x8f\xff\x15x\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2T20NS1\x00\x00\x00\x00',
b'\xf1\x87LDJUEA6010814HG1\x87w\x87x\x86gvw\x88\x88\x98\x88gw\x86wx\x88\x97\x88\x85o\xf8\xff\x86f_\xff\xd37\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM4T20NS0\xf8\x19\x92g', b'\xf1\x87LDJUEA6010814HG1\x87w\x87x\x86gvw\x88\x88\x98\x88gw\x86wx\x88\x97\x88\x85o\xf8\xff\x86f_\xff\xd37\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM4T20NS0\xf8\x19\x92g',
@ -707,7 +751,6 @@ FW_VERSIONS = {
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00TM__ SCC F-CUP 1.00 1.00 99110-S1500 ', b'\xf1\x00TM__ SCC F-CUP 1.00 1.00 99110-S1500 ',
b'\xf1\x8799110S1500\xf1\x00TM__ SCC F-CUP 1.00 1.00 99110-S1500 ', b'\xf1\x8799110S1500\xf1\x00TM__ SCC F-CUP 1.00 1.00 99110-S1500 ',
b'\xf1\x8799110S1500\xf1\x00TM__ SCC FHCUP 1.00 1.00 99110-S1500 ',
b'\xf1\x00TM__ SCC FHCUP 1.00 1.00 99110-S1500 ', b'\xf1\x00TM__ SCC FHCUP 1.00 1.00 99110-S1500 ',
], ],
(Ecu.abs, 0x7d1, None): [ (Ecu.abs, 0x7d1, None): [
@ -741,6 +784,7 @@ FW_VERSIONS = {
b'\xf1\x00TMA MFC AT USA LHD 1.00 1.01 99211-S2500 210205', b'\xf1\x00TMA MFC AT USA LHD 1.00 1.01 99211-S2500 210205',
], ],
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
b'\xf1\x00T02601BL T02900A1 VTMPT25XXX900NSA\xf3\xf4Uj',
b'\xf1\x87SDMXCA9087684GN1VfvgUUeVwwgwwwwwffffU?\xfb\xff\x97\x88\x7f\xff+\xa4\xf1\x89HT6WAD00A1\xf1\x82STM4G25NH1\x00\x00\x00\x00\x00\x00', b'\xf1\x87SDMXCA9087684GN1VfvgUUeVwwgwwwwwffffU?\xfb\xff\x97\x88\x7f\xff+\xa4\xf1\x89HT6WAD00A1\xf1\x82STM4G25NH1\x00\x00\x00\x00\x00\x00',
b'\xf1\x00T02601BL T02730A1 VTMPT25XXX730NS2\xa6\x06\x88\xf7', b'\xf1\x00T02601BL T02730A1 VTMPT25XXX730NS2\xa6\x06\x88\xf7',
b'\xf1\x87SDMXCA8653204GN1EVugEUuWwwwwww\x87wwwwwv/\xfb\xff\xa8\x88\x9f\xff\xa5\x9c\xf1\x89HT6WAD00A1\xf1\x82STM4G25NH1\x00\x00\x00\x00\x00\x00', b'\xf1\x87SDMXCA8653204GN1EVugEUuWwwwwww\x87wwwwwv/\xfb\xff\xa8\x88\x9f\xff\xa5\x9c\xf1\x89HT6WAD00A1\xf1\x82STM4G25NH1\x00\x00\x00\x00\x00\x00',
@ -755,19 +799,23 @@ FW_VERSIONS = {
}, },
CAR.SANTA_FE_HEV_2022: { CAR.SANTA_FE_HEV_2022: {
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x8799110CL500\xf1\x00TMhe SCC FHCUP 1.00 1.00 99110-CL500 ', b'\xf1\x00TMhe SCC FHCUP 1.00 1.00 99110-CL500 ',
], ],
(Ecu.eps, 0x7d4, None): [ (Ecu.eps, 0x7d4, None): [
b'\xf1\x00TM MDPS C 1.00 1.02 56310-CLAC0 4TSHC102', b'\xf1\x00TM MDPS C 1.00 1.02 56310-CLAC0 4TSHC102',
b'\xf1\x00TM MDPS R 1.00 1.05 57700-CL000 4TSHP105',
], ],
(Ecu.fwdCamera, 0x7c4, None): [ (Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00TMH MFC AT EUR LHD 1.00 1.06 99211-S1500 220727',
b'\xf1\x00TMH MFC AT USA LHD 1.00 1.03 99211-S1500 210224', b'\xf1\x00TMH MFC AT USA LHD 1.00 1.03 99211-S1500 210224',
], ],
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
b'\xf1\x00PSBG2333 E16\x00\x00\x00\x00\x00\x00\x00TTM2H16UA3I\x94\xac\x8f',
b'\xf1\x87959102T250\x00\x00\x00\x00\x00\xf1\x81E14\x00\x00\x00\x00\x00\x00\x00\xf1\x00PSBG2333 E14\x00\x00\x00\x00\x00\x00\x00TTM2H16SA2\x80\xd7l\xb2', b'\xf1\x87959102T250\x00\x00\x00\x00\x00\xf1\x81E14\x00\x00\x00\x00\x00\x00\x00\xf1\x00PSBG2333 E14\x00\x00\x00\x00\x00\x00\x00TTM2H16SA2\x80\xd7l\xb2',
], ],
(Ecu.engine, 0x7e0, None): [ (Ecu.engine, 0x7e0, None): [
b'\xf1\x87391312MTC1', b'\xf1\x87391312MTC1',
b'\xf1\x87391312MTE0',
], ],
}, },
CAR.SANTA_FE_PHEV_2022: { CAR.SANTA_FE_PHEV_2022: {
@ -794,6 +842,7 @@ FW_VERSIONS = {
b'\xf1\x00CK__ SCC F_CUP 1.00 1.01 96400-J5100 ', b'\xf1\x00CK__ SCC F_CUP 1.00 1.01 96400-J5100 ',
b'\xf1\x00CK__ SCC F_CUP 1.00 1.03 96400-J5100 ', b'\xf1\x00CK__ SCC F_CUP 1.00 1.03 96400-J5100 ',
b'\xf1\x00CK__ SCC F_CUP 1.00 1.01 96400-J5000 ', b'\xf1\x00CK__ SCC F_CUP 1.00 1.01 96400-J5000 ',
b'\xf1\x00CK__ SCC F_CUP 1.00 1.02 96400-J5100 ',
], ],
(Ecu.engine, 0x7e0, None): [ (Ecu.engine, 0x7e0, None): [
b'\xf1\x81606DE051\x00\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x81606DE051\x00\x00\x00\x00\x00\x00\x00\x00',
@ -801,6 +850,7 @@ FW_VERSIONS = {
b'\xf1\x82CKJN3TMSDE0B\x00\x00\x00\x00', b'\xf1\x82CKJN3TMSDE0B\x00\x00\x00\x00',
b'\xf1\x82CKKN3TMD_H0A\x00\x00\x00\x00', b'\xf1\x82CKKN3TMD_H0A\x00\x00\x00\x00',
b'\xe0\x19\xff\xe7\xe7g\x01\xa2\x00\x0f\x00\x9e\x00\x06\x00\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\x00\x00\x0f\x0e\x0f\x0f\x0e\r\x00\x00\x7f\x02.\xff\x00\x00~p\x00\x00\x00\x00u\xff\xf9\xff\x00\x00\x00\x00V\t\xd5\x01\xc0\x00\x00\x00\x007\xfb\xfc\x0b\x8d\x00', b'\xe0\x19\xff\xe7\xe7g\x01\xa2\x00\x0f\x00\x9e\x00\x06\x00\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\x00\x00\x0f\x0e\x0f\x0f\x0e\r\x00\x00\x7f\x02.\xff\x00\x00~p\x00\x00\x00\x00u\xff\xf9\xff\x00\x00\x00\x00V\t\xd5\x01\xc0\x00\x00\x00\x007\xfb\xfc\x0b\x8d\x00',
b'\xf1\x81640H0051\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.eps, 0x7d4, None): [ (Ecu.eps, 0x7d4, None): [
b'\xf1\x00CK MDPS R 1.00 1.04 57700-J5200 4C2CL104', b'\xf1\x00CK MDPS R 1.00 1.04 57700-J5200 4C2CL104',
@ -808,6 +858,7 @@ FW_VERSIONS = {
b'\xf1\x00CK MDPS R 1.00 1.04 57700-J5420 4C4VL104', b'\xf1\x00CK MDPS R 1.00 1.04 57700-J5420 4C4VL104',
b'\xf1\x00CK MDPS R 1.00 1.06 57700-J5420 4C4VL106', b'\xf1\x00CK MDPS R 1.00 1.06 57700-J5420 4C4VL106',
b'\xf1\x00CK MDPS R 1.00 1.07 57700-J5220 4C2VL107', b'\xf1\x00CK MDPS R 1.00 1.07 57700-J5220 4C2VL107',
b'\xf1\x00CK MDPS R 1.00 1.06 57700-J5220 4C2VL106',
], ],
(Ecu.fwdCamera, 0x7c4, None): [ (Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00CK MFC AT USA LHD 1.00 1.03 95740-J5000 170822', b'\xf1\x00CK MFC AT USA LHD 1.00 1.03 95740-J5000 170822',
@ -815,6 +866,7 @@ FW_VERSIONS = {
b'\xf1\x00CK MFC AT EUR LHD 1.00 1.03 95740-J5000 170822', b'\xf1\x00CK MFC AT EUR LHD 1.00 1.03 95740-J5000 170822',
], ],
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
b'\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SCK0T33NB2\xb3\xee\xba\xdc',
b'\xf1\x87VCJLE17622572DK0vd6D\x99\x98y\x97vwVffUfvfC%CuT&Dx\x87o\xff{\x1c\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0', b'\xf1\x87VCJLE17622572DK0vd6D\x99\x98y\x97vwVffUfvfC%CuT&Dx\x87o\xff{\x1c\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0',
b'\xf1\x87VDHLG17000192DK2xdFffT\xa5VUD$DwT\x86wveVeeD&T\x99\xba\x8f\xff\xcc\x99\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0', b'\xf1\x87VDHLG17000192DK2xdFffT\xa5VUD$DwT\x86wveVeeD&T\x99\xba\x8f\xff\xcc\x99\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0',
b'\xf1\x87VDHLG17000192DK2xdFffT\xa5VUD$DwT\x86wveVeeD&T\x99\xba\x8f\xff\xcc\x99\xf1\x89E21\x00\x00\x00\x00\x00\x00\x00\xf1\x82SCK0T33NB0', b'\xf1\x87VDHLG17000192DK2xdFffT\xa5VUD$DwT\x86wveVeeD&T\x99\xba\x8f\xff\xcc\x99\xf1\x89E21\x00\x00\x00\x00\x00\x00\x00\xf1\x82SCK0T33NB0',
@ -1006,6 +1058,25 @@ FW_VERSIONS = {
b'\xf1\x81640H0051\x00\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x81640H0051\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
}, },
CAR.GENESIS_G80: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00DH__ SCC F-CUP 1.00 1.01 96400-B1120 ',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00DH LKAS AT USA LHD 1.01 1.03 95895-B1500 180713',
b'\xf1\x00DH LKAS AT USA LHD 1.01 1.02 95895-B1500 170810',
b'\xf1\x00DH LKAS AT USA LHD 1.01 1.01 95895-B1500 161014',
],
(Ecu.transmission, 0x7e1, None): [
b'\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SDH0T33NH4\xd7O\x9e\xc9',
b'\xf1\x00bcsh8p54 E18\x00\x00\x00\x00\x00\x00\x00TDH0G38NH3:-\xa9n',
b'\xf1\x00bcsh8p54 E18\x00\x00\x00\x00\x00\x00\x00SDH0G38NH2j\x9dA\x1c',
b'\xf1\x00bcsh8p54 E18\x00\x00\x00\x00\x00\x00\x00SDH0T33NH3\x97\xe6\xbc\xb8',
],
(Ecu.engine, 0x7e0, None): [
b'\xf1\x81640F0051\x00\x00\x00\x00\x00\x00\x00\x00',
],
},
CAR.GENESIS_G90: { CAR.GENESIS_G90: {
(Ecu.transmission, 0x7e1, None): [b'\xf1\x87VDGMD15866192DD3x\x88x\x89wuFvvfUf\x88vWwgwwwvfVgx\x87o\xff\xbc^\xf1\x81E14\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcshcm49 E14\x00\x00\x00\x00\x00\x00\x00SHI0G50NB1tc5\xb7'], (Ecu.transmission, 0x7e1, None): [b'\xf1\x87VDGMD15866192DD3x\x88x\x89wuFvvfUf\x88vWwgwwwvfVgx\x87o\xff\xbc^\xf1\x81E14\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcshcm49 E14\x00\x00\x00\x00\x00\x00\x00SHI0G50NB1tc5\xb7'],
(Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00HI__ SCC F-CUP 1.00 1.01 96400-D2100 '], (Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00HI__ SCC F-CUP 1.00 1.01 96400-D2100 '],
@ -1094,6 +1165,23 @@ FW_VERSIONS = {
b'\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00TDL4T16NB05\x94t\x18', b'\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00TDL4T16NB05\x94t\x18',
], ],
}, },
CAR.KIA_K5_HEV_2020: {
(Ecu.fwdRadar, 0x7D0, None): [
b'\xf1\x00DLhe SCC FHCUP 1.00 1.02 99110-L7000 ',
],
(Ecu.eps, 0x7D4, None): [
b'\xf1\x00DL3 MDPS C 1.00 1.02 56310-L7000 4DLHC102',
],
(Ecu.fwdCamera, 0x7C4, None): [
b'\xf1\x00DL3HMFC AT KOR LHD 1.00 1.02 99210-L2000 200309',
],
(Ecu.engine, 0x7E0, None): [
b'\xf1\x87391162JLA0',
],
(Ecu.transmission, 0x7E1, None): [
b'\xf1\x00PSBG2323 E08\x00\x00\x00\x00\x00\x00\x00TDL2H20KA2\xe3\xc6cz',
],
},
CAR.KONA_EV: { CAR.KONA_EV: {
(Ecu.abs, 0x7D1, None): [ (Ecu.abs, 0x7D1, None): [
b'\xf1\x00OS IEB \r 105\x18\t\x18 58520-K4000', b'\xf1\x00OS IEB \r 105\x18\t\x18 58520-K4000',
@ -1180,22 +1268,27 @@ FW_VERSIONS = {
(Ecu.engine, 0x7e0, None): [ (Ecu.engine, 0x7e0, None): [
b'\xf1\x816H6F4051\x00\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x816H6F4051\x00\x00\x00\x00\x00\x00\x00\x00',
b'\xf1\x816H6D1051\x00\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x816H6D1051\x00\x00\x00\x00\x00\x00\x00\x00',
b'\xf1\x816H6F6051\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
b"\xf1\x816U3J2051\x00\x00\xf1\x006U3H0_C2\x00\x006U3J2051\x00\x00PDE0G16NS2\xf4'\\\x91", b"\xf1\x816U3J2051\x00\x00\xf1\x006U3H0_C2\x00\x006U3J2051\x00\x00PDE0G16NS2\xf4'\\\x91",
b'\xf1\x816U3J2051\x00\x00\xf1\x006U3H0_C2\x00\x006U3J2051\x00\x00PDE0G16NS2\x00\x00\x00\x00', b'\xf1\x816U3J2051\x00\x00\xf1\x006U3H0_C2\x00\x006U3J2051\x00\x00PDE0G16NS2\x00\x00\x00\x00',
b'\xf1\x816U3H3051\x00\x00\xf1\x006U3H0_C2\x00\x006U3H3051\x00\x00PDE0G16NS1\x00\x00\x00\x00', b'\xf1\x816U3H3051\x00\x00\xf1\x006U3H0_C2\x00\x006U3H3051\x00\x00PDE0G16NS1\x00\x00\x00\x00',
b'\xf1\x816U3H3051\x00\x00\xf1\x006U3H0_C2\x00\x006U3H3051\x00\x00PDE0G16NS1\x13\xcd\x88\x92', b'\xf1\x816U3H3051\x00\x00\xf1\x006U3H0_C2\x00\x006U3H3051\x00\x00PDE0G16NS1\x13\xcd\x88\x92',
b'\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PDE0G16NL2&[\xc3\x01',
], ],
(Ecu.eps, 0x7D4, None): [ (Ecu.eps, 0x7D4, None): [
b'\xf1\x00DE MDPS C 1.00 1.09 56310G5301\x00 4DEHC109', b'\xf1\x00DE MDPS C 1.00 1.09 56310G5301\x00 4DEHC109',
b'\xf1\x00DE MDPS C 1.00 1.01 56310G5520\x00 4DEPC101',
], ],
(Ecu.fwdCamera, 0x7C4, None): [ (Ecu.fwdCamera, 0x7C4, None): [
b'\xf1\x00DEP MFC AT USA LHD 1.00 1.01 95740-G5010 170424', b'\xf1\x00DEP MFC AT USA LHD 1.00 1.01 95740-G5010 170424',
b'\xf1\x00DEP MFC AT USA LHD 1.00 1.00 95740-G5010 170117', b'\xf1\x00DEP MFC AT USA LHD 1.00 1.00 95740-G5010 170117',
b'\xf1\x00DEP MFC AT USA LHD 1.00 1.05 99211-G5000 190826',
], ],
(Ecu.fwdRadar, 0x7D0, None): [ (Ecu.fwdRadar, 0x7D0, None): [
b'\xf1\x00DEhe SCC H-CUP 1.01 1.02 96400-G5100 ', b'\xf1\x00DEhe SCC H-CUP 1.01 1.02 96400-G5100 ',
b'\xf1\x00DEhe SCC F-CUP 1.00 1.02 99110-G5100 ',
], ],
}, },
CAR.KIA_NIRO_HEV_2021: { CAR.KIA_NIRO_HEV_2021: {
@ -1307,25 +1400,26 @@ FW_VERSIONS = {
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00CN7_ SCC F-CUP 1.00 1.01 99110-AA000 ', b'\xf1\x00CN7_ SCC F-CUP 1.00 1.01 99110-AA000 ',
b'\xf1\x00CN7_ SCC FHCUP 1.00 1.01 99110-AA000 ', b'\xf1\x00CN7_ SCC FHCUP 1.00 1.01 99110-AA000 ',
b'\xf1\x00CN7_ SCC FNCUP 1.00 1.01 99110-AA000 ',
b'\xf1\x8799110AA000\xf1\x00CN7_ SCC FHCUP 1.00 1.01 99110-AA000 ', b'\xf1\x8799110AA000\xf1\x00CN7_ SCC FHCUP 1.00 1.01 99110-AA000 ',
b'\xf1\x8799110AA000\xf1\x00CN7_ SCC F-CUP 1.00 1.01 99110-AA000 ', b'\xf1\x8799110AA000\xf1\x00CN7_ SCC F-CUP 1.00 1.01 99110-AA000 ',
], ],
(Ecu.eps, 0x7d4, None): [ (Ecu.eps, 0x7d4, None): [
b'\xf1\x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x00CN7 MDPS C 1.00 1.06 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 4CNDC106', b'\xf1\x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x00CN7 MDPS C 1.00 1.06 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 4CNDC106',
b'\xf1\x8756310/AA070\xf1\x00CN7 MDPS C 1.00 1.06 56310/AA070 4CNDC106', b'\xf1\x8756310/AA070\xf1\x00CN7 MDPS C 1.00 1.06 56310/AA070 4CNDC106',
b'\xf1\x8756310AA050\x00\xf1\x00CN7 MDPS C 1.00 1.06 56310AA050\x00 4CNDC106',
b'\xf1\x8756310AA050\x00\xf1\x00CN7 MDPS C 1.00 1.06 56310AA050\x00 4CNDC106\xf1\xa01.06', b'\xf1\x8756310AA050\x00\xf1\x00CN7 MDPS C 1.00 1.06 56310AA050\x00 4CNDC106\xf1\xa01.06',
b'\xf1\x00CN7 MDPS C 1.00 1.06 56310AA050\x00 4CNDC106',
], ],
(Ecu.fwdCamera, 0x7c4, None): [ (Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.00 99210-AB000 200819', b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.00 99210-AB000 200819',
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.03 99210-AA000 200819', b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.03 99210-AA000 200819',
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.01 99210-AB000 210205', b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.01 99210-AB000 210205',
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.06 99210-AA000 220111', b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.06 99210-AA000 220111',
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.03 99210-AB000 220426',
], ],
(Ecu.abs, 0x7d1, None): [ (Ecu.abs, 0x7d1, None): [
b'\xf1\x00CN ESC \t 101 \x10\x03 58910-AB800', b'\xf1\x00CN ESC \t 101 \x10\x03 58910-AB800',
b'\xf1\x8758910-AA800\xf1\x00CN ESC \t 104 \x08\x03 58910-AA800', b'\xf1\x8758910-AA800\xf1\x00CN ESC \t 104 \x08\x03 58910-AA800',
b'\xf1\x8758910-AB800\xf1\x00CN ESC \t 101 \x10\x03 58910-AB800',
b'\xf1\x8758910-AA800\xf1\x00CN ESC \t 105 \x10\x03 58910-AA800', b'\xf1\x8758910-AA800\xf1\x00CN ESC \t 105 \x10\x03 58910-AA800',
b'\xf1\x8758910-AB800\xf1\x00CN ESC \t 101 \x10\x03 58910-AB800\xf1\xa01.01', b'\xf1\x8758910-AB800\xf1\x00CN ESC \t 101 \x10\x03 58910-AB800\xf1\xa01.01',
], ],
@ -1343,6 +1437,7 @@ FW_VERSIONS = {
b'\xf1\x81HM6M2_0a0_FF0', b'\xf1\x81HM6M2_0a0_FF0',
b'\xf1\x82CNCVD0AMFCXCSFFB', b'\xf1\x82CNCVD0AMFCXCSFFB',
b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x81HM6M2_0a0_G80', b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x81HM6M2_0a0_G80',
b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x81HM6M2_0a0_HC0',
], ],
}, },
CAR.ELANTRA_HEV_2021: { CAR.ELANTRA_HEV_2021: {
@ -1457,6 +1552,7 @@ FW_VERSIONS = {
b'\xf1\x00CV1 MFC AT EUR LHD 1.00 1.05 99210-CV000 211027', b'\xf1\x00CV1 MFC AT EUR LHD 1.00 1.05 99210-CV000 211027',
b'\xf1\x00CV1 MFC AT EUR LHD 1.00 1.06 99210-CV000 220328', b'\xf1\x00CV1 MFC AT EUR LHD 1.00 1.06 99210-CV000 220328',
b'\xf1\x00CV1 MFC AT EUR RHD 1.00 1.00 99210-CV100 220630', b'\xf1\x00CV1 MFC AT EUR RHD 1.00 1.00 99210-CV100 220630',
b'\xf1\x00CV1 MFC AT USA LHD 1.00 1.00 99210-CV100 220630',
], ],
}, },
CAR.IONIQ_5: { CAR.IONIQ_5: {
@ -1468,6 +1564,8 @@ FW_VERSIONS = {
b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.06 99211-GI000 210813', b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.06 99211-GI000 210813',
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.05 99211-GI010 220614', b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.05 99211-GI010 220614',
b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.01 99211-GI010 211007', b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.01 99211-GI010 211007',
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.01 99211-GI010 211007',
b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.02 99211-GI010 211206',
], ],
}, },
CAR.TUCSON_4TH_GEN: { CAR.TUCSON_4TH_GEN: {
@ -1499,9 +1597,11 @@ FW_VERSIONS = {
CAR.SANTA_CRUZ_1ST_GEN: { CAR.SANTA_CRUZ_1ST_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [ (Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-CW000 14M', b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-CW000 14M',
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-CW010 14X',
], ],
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00NX4__ 1.00 1.00 99110-K5000 ', b'\xf1\x00NX4__ 1.00 1.00 99110-K5000 ',
b'\xf1\x00NX4__ 1.01 1.00 99110-K5000 ',
], ],
}, },
CAR.KIA_SPORTAGE_5TH_GEN: { CAR.KIA_SPORTAGE_5TH_GEN: {
@ -1517,23 +1617,42 @@ FW_VERSIONS = {
CAR.GENESIS_GV70_1ST_GEN: { CAR.GENESIS_GV70_1ST_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [ (Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00JK1 MFC AT USA LHD 1.00 1.04 99211-AR000 210204', b'\xf1\x00JK1 MFC AT USA LHD 1.00 1.04 99211-AR000 210204',
b'\xf1\x00JK1 MFC AT USA LHD 1.00 1.01 99211-AR200 220125',
], ],
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00JK1_ SCC FHCUP 1.00 1.02 99110-AR000 ', b'\xf1\x00JK1_ SCC FHCUP 1.00 1.02 99110-AR000 ',
b'\xf1\x00JK1_ SCC FHCUP 1.00 1.00 99110-AR200 ',
], ],
}, },
CAR.GENESIS_GV60_EV_1ST_GEN: { CAR.GENESIS_GV60_EV_1ST_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [ (Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00JW1 MFC AT USA LHD 1.00 1.02 99211-CU100 211215', b'\xf1\x00JW1 MFC AT USA LHD 1.00 1.02 99211-CU100 211215',
b'\xf1\x00JW1 MFC AT USA LHD 1.00 1.02 99211-CU000 211215',
], ],
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00JW1_ RDR ----- 1.00 1.00 99110-CU000 ', b'\xf1\x00JW1_ RDR ----- 1.00 1.00 99110-CU000 ',
], ],
}, },
CAR.KIA_SORENTO_4TH_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00MQ4 MFC AT USA LHD 1.00 1.05 99210-R5000 210623',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00MQ4_ SCC FHCUP 1.00 1.06 99110-P2000 ',
],
},
CAR.KIA_NIRO_HEV_2ND_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00SG2HMFC AT USA LHD 1.01 1.08 99211-AT000 220531',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00SG2_ RDR ----- 1.00 1.01 99110-AT000 ',
],
},
} }
CHECKSUM = { CHECKSUM = {
"crc8": [CAR.SANTA_FE, CAR.SONATA, CAR.PALISADE, CAR.KIA_SELTOS, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022], "crc8": [CAR.SANTA_FE, CAR.SONATA, CAR.PALISADE, CAR.KIA_SELTOS, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.KIA_K5_HEV_2020],
"6B": [CAR.KIA_SORENTO, CAR.HYUNDAI_GENESIS], "6B": [CAR.KIA_SORENTO, CAR.HYUNDAI_GENESIS],
} }
@ -1541,25 +1660,23 @@ FEATURES = {
# which message has the gear # which message has the gear
"use_cluster_gears": {CAR.ELANTRA, CAR.KONA}, "use_cluster_gears": {CAR.ELANTRA, CAR.KONA},
"use_tcu_gears": {CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.SONATA_LF, CAR.VELOSTER, CAR.TUCSON}, "use_tcu_gears": {CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.SONATA_LF, CAR.VELOSTER, CAR.TUCSON},
"use_elect_gears": {CAR.KIA_NIRO_EV, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.KIA_OPTIMA_H, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.IONIQ, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.KONA_EV_2022}, "use_elect_gears": {CAR.KIA_NIRO_EV, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.KIA_OPTIMA_H, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.IONIQ, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.KONA_EV_2022, CAR.KIA_K5_HEV_2020},
# these cars use the FCA11 message for the AEB and FCW signals, all others use SCC12
"use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022, CAR.KIA_STINGER_2022},
} }
CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.GENESIS_GV60_EV_1ST_GEN} CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.GENESIS_GV60_EV_1ST_GEN, CAR.KIA_SORENTO_4TH_GEN, CAR.KIA_NIRO_HEV_2ND_GEN}
# The radar does SCC on these cars when HDA I, rather than the camera # The radar does SCC on these cars when HDA I, rather than the camera
CANFD_RADAR_SCC_CAR = {CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN} CANFD_RADAR_SCC_CAR = {CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.KIA_SORENTO_4TH_GEN}
# The camera does SCC on these cars, rather than the radar # The camera does SCC on these cars, rather than the radar
CAMERA_SCC_CAR = {CAR.KONA_EV_2022, } CAMERA_SCC_CAR = {CAR.KONA_EV_2022, }
HYBRID_CAR = {CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN} # these cars use a different gas signal HYBRID_CAR = {CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.KIA_K5_HEV_2020, CAR.KIA_NIRO_HEV_2ND_GEN} # these cars use a different gas signal
EV_CAR = {CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.KIA_NIRO_EV, CAR.KONA_EV_2022, CAR.KIA_EV6, CAR.IONIQ_5, CAR.GENESIS_GV60_EV_1ST_GEN} EV_CAR = {CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.KIA_NIRO_EV, CAR.KONA_EV_2022, CAR.KIA_EV6, CAR.IONIQ_5, CAR.GENESIS_GV60_EV_1ST_GEN}
# these cars require a special panda safety mode due to missing counters and checksums in the messages # these cars require a special panda safety mode due to missing counters and checksums in the messages
LEGACY_SAFETY_MODE_CAR = {CAR.HYUNDAI_GENESIS, CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.IONIQ_PHEV, CAR.IONIQ, CAR.KONA_EV, CAR.KIA_SORENTO, CAR.SONATA_LF, CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.VELOSTER, CAR.KIA_STINGER, CAR.GENESIS_G70, CAR.GENESIS_G80, CAR.KIA_CEED, CAR.ELANTRA, CAR.IONIQ_HEV_2022} LEGACY_SAFETY_MODE_CAR = {CAR.HYUNDAI_GENESIS, CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.IONIQ_PHEV, CAR.IONIQ, CAR.KONA_EV, CAR.KIA_SORENTO, CAR.SONATA_LF, CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.VELOSTER,
CAR.GENESIS_G70, CAR.GENESIS_G80, CAR.KIA_CEED, CAR.ELANTRA, CAR.IONIQ_HEV_2022}
# If 0x500 is present on bus 1 it probably has a Mando radar outputting radar points. # If 0x500 is present on bus 1 it probably has a Mando radar outputting radar points.
# If no points are outputted by default it might be possible to turn it on using selfdrive/debug/hyundai_enable_radar_points.py # If no points are outputted by default it might be possible to turn it on using selfdrive/debug/hyundai_enable_radar_points.py
@ -1580,6 +1697,7 @@ DBC = {
CAR.IONIQ_HEV_2022: dbc_dict('hyundai_kia_generic', None), CAR.IONIQ_HEV_2022: dbc_dict('hyundai_kia_generic', None),
CAR.KIA_FORTE: dbc_dict('hyundai_kia_generic', None), CAR.KIA_FORTE: dbc_dict('hyundai_kia_generic', None),
CAR.KIA_K5_2021: dbc_dict('hyundai_kia_generic', None), CAR.KIA_K5_2021: dbc_dict('hyundai_kia_generic', None),
CAR.KIA_K5_HEV_2020: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
CAR.KIA_NIRO_EV: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'), CAR.KIA_NIRO_EV: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
CAR.KIA_NIRO_PHEV: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'), CAR.KIA_NIRO_PHEV: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
CAR.KIA_NIRO_HEV_2021: dbc_dict('hyundai_kia_generic', None), CAR.KIA_NIRO_HEV_2021: dbc_dict('hyundai_kia_generic', None),
@ -1615,4 +1733,6 @@ DBC = {
CAR.GENESIS_GV70_1ST_GEN: dbc_dict('hyundai_canfd', None), CAR.GENESIS_GV70_1ST_GEN: dbc_dict('hyundai_canfd', None),
CAR.KIA_SORENTO_PHEV_4TH_GEN: dbc_dict('hyundai_canfd', None), CAR.KIA_SORENTO_PHEV_4TH_GEN: dbc_dict('hyundai_canfd', None),
CAR.GENESIS_GV60_EV_1ST_GEN: dbc_dict('hyundai_canfd', None), CAR.GENESIS_GV60_EV_1ST_GEN: dbc_dict('hyundai_canfd', None),
CAR.KIA_SORENTO_4TH_GEN: dbc_dict('hyundai_canfd', None),
CAR.KIA_NIRO_HEV_2ND_GEN: dbc_dict('hyundai_canfd', None),
} }

@ -88,13 +88,14 @@ class CarInterfaceBase(ABC):
return ACCEL_MIN, ACCEL_MAX return ACCEL_MIN, ACCEL_MAX
@classmethod @classmethod
def get_params(cls, candidate: str, fingerprint: Optional[Dict[int, Dict[int, int]]] = None, car_fw: Optional[List[car.CarParams.CarFw]] = None, experimental_long: bool = False): def get_non_essential_params(cls, candidate: str):
if fingerprint is None: """
fingerprint = gen_empty_fingerprint() Parameters essential to controlling the car may be incomplete or wrong without FW versions or fingerprints.
"""
if car_fw is None: return cls.get_params(candidate, gen_empty_fingerprint(), list(), False)
car_fw = list()
@classmethod
def get_params(cls, candidate: str, fingerprint: Dict[int, Dict[int, int]], car_fw: List[car.CarParams.CarFw], experimental_long: bool):
ret = CarInterfaceBase.get_std_params(candidate) ret = CarInterfaceBase.get_std_params(candidate)
ret = cls._get_params(ret, candidate, fingerprint, car_fw, experimental_long) ret = cls._get_params(ret, candidate, fingerprint, car_fw, experimental_long)
@ -232,7 +233,7 @@ class CarInterfaceBase(ABC):
return reader return reader
@abstractmethod @abstractmethod
def apply(self, c: car.CarControl) -> Tuple[car.CarControl.Actuators, List[bytes]]: def apply(self, c: car.CarControl, now_nanos: int) -> Tuple[car.CarControl.Actuators, List[bytes]]:
pass pass
def create_common_events(self, cs_out, extra_gears=None, pcm_enable=True, allow_enable=True, def create_common_events(self, cs_out, extra_gears=None, pcm_enable=True, allow_enable=True,
@ -400,15 +401,15 @@ class CarStateBase(ABC):
return GearShifter.unknown return GearShifter.unknown
d: Dict[str, car.CarState.GearShifter] = { d: Dict[str, car.CarState.GearShifter] = {
'P': GearShifter.park, 'PARK': GearShifter.park, 'P': GearShifter.park, 'PARK': GearShifter.park,
'R': GearShifter.reverse, 'REVERSE': GearShifter.reverse, 'R': GearShifter.reverse, 'REVERSE': GearShifter.reverse,
'N': GearShifter.neutral, 'NEUTRAL': GearShifter.neutral, 'N': GearShifter.neutral, 'NEUTRAL': GearShifter.neutral,
'E': GearShifter.eco, 'ECO': GearShifter.eco, 'E': GearShifter.eco, 'ECO': GearShifter.eco,
'T': GearShifter.manumatic, 'MANUAL': GearShifter.manumatic, 'T': GearShifter.manumatic, 'MANUAL': GearShifter.manumatic,
'D': GearShifter.drive, 'DRIVE': GearShifter.drive, 'D': GearShifter.drive, 'DRIVE': GearShifter.drive,
'S': GearShifter.sport, 'SPORT': GearShifter.sport, 'S': GearShifter.sport, 'SPORT': GearShifter.sport,
'L': GearShifter.low, 'LOW': GearShifter.low, 'L': GearShifter.low, 'LOW': GearShifter.low,
'B': GearShifter.brake, 'BRAKE': GearShifter.brake, 'B': GearShifter.brake, 'BRAKE': GearShifter.brake,
} }
return d.get(gear.upper(), GearShifter.unknown) return d.get(gear.upper(), GearShifter.unknown)

@ -1,6 +1,6 @@
from cereal import car from cereal import car
from opendbc.can.packer import CANPacker from opendbc.can.packer import CANPacker
from selfdrive.car import apply_std_steer_torque_limits from selfdrive.car import apply_driver_steer_torque_limits
from selfdrive.car.mazda import mazdacan from selfdrive.car.mazda import mazdacan
from selfdrive.car.mazda.values import CarControllerParams, Buttons from selfdrive.car.mazda.values import CarControllerParams, Buttons
@ -15,7 +15,7 @@ class CarController:
self.brake_counter = 0 self.brake_counter = 0
self.frame = 0 self.frame = 0
def update(self, CC, CS): def update(self, CC, CS, now_nanos):
can_sends = [] can_sends = []
apply_steer = 0 apply_steer = 0
@ -23,8 +23,8 @@ class CarController:
if CC.latActive: if CC.latActive:
# calculate steer and also set limits due to driver torque # calculate steer and also set limits due to driver torque
new_steer = int(round(CC.actuators.steer * CarControllerParams.STEER_MAX)) new_steer = int(round(CC.actuators.steer * CarControllerParams.STEER_MAX))
apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last,
CS.out.steeringTorque, CarControllerParams) CS.out.steeringTorque, CarControllerParams)
if CC.cruiseControl.cancel: if CC.cruiseControl.cancel:
# If brake is pressed, let us wait >70ms before trying to disable crz to avoid # If brake is pressed, let us wait >70ms before trying to disable crz to avoid

@ -14,7 +14,7 @@ class CarInterface(CarInterfaceBase):
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): def _get_params(ret, candidate, fingerprint, car_fw, experimental_long):
ret.carName = "mazda" ret.carName = "mazda"
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.mazda)] ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.mazda)]
ret.radarOffCan = True ret.radarUnavailable = True
ret.dashcamOnly = candidate not in (CAR.CX5_2022, CAR.CX9_2021) ret.dashcamOnly = candidate not in (CAR.CX5_2022, CAR.CX9_2021)
@ -69,5 +69,5 @@ class CarInterface(CarInterfaceBase):
return ret return ret
def apply(self, c): def apply(self, c, now_nanos):
return self.CC.update(c, self.CS) return self.CC.update(c, self.CS, now_nanos)

@ -57,7 +57,7 @@ class CarInterface(CarInterfaceBase):
return ret return ret
def apply(self, c): def apply(self, c, now_nanos):
# in mock no carcontrols # in mock no carcontrols
actuators = car.CarControl.Actuators.new_message() actuators = car.CarControl.Actuators.new_message()
return actuators, [] return actuators, []

@ -18,7 +18,7 @@ class CarController:
self.packer = CANPacker(dbc_name) self.packer = CANPacker(dbc_name)
def update(self, CC, CS): def update(self, CC, CS, now_nanos):
actuators = CC.actuators actuators = CC.actuators
hud_control = CC.hudControl hud_control = CC.hudControl
pcm_cancel_cmd = CC.cruiseControl.cancel pcm_cancel_cmd = CC.cruiseControl.cancel

@ -19,7 +19,7 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 17 ret.steerRatio = 17
ret.steerControlType = car.CarParams.SteerControlType.angle ret.steerControlType = car.CarParams.SteerControlType.angle
ret.radarOffCan = True ret.radarUnavailable = True
if candidate in (CAR.ROGUE, CAR.XTRAIL): if candidate in (CAR.ROGUE, CAR.XTRAIL):
ret.mass = 1610 + STD_CARGO_KG ret.mass = 1610 + STD_CARGO_KG
@ -56,5 +56,5 @@ class CarInterface(CarInterfaceBase):
return ret return ret
def apply(self, c): def apply(self, c, now_nanos):
return self.CC.update(c, self.CS) return self.CC.update(c, self.CS, now_nanos)

@ -39,7 +39,7 @@ class NissanCarInfo(CarInfo):
CAR_INFO: Dict[str, Optional[Union[NissanCarInfo, List[NissanCarInfo]]]] = { CAR_INFO: Dict[str, Optional[Union[NissanCarInfo, List[NissanCarInfo]]]] = {
CAR.XTRAIL: NissanCarInfo("Nissan X-Trail 2017"), CAR.XTRAIL: NissanCarInfo("Nissan X-Trail 2017"),
CAR.LEAF: NissanCarInfo("Nissan Leaf 2018-22"), CAR.LEAF: NissanCarInfo("Nissan Leaf 2018-22", video_link="https://youtu.be/vaMbtAh_0cY"),
CAR.LEAF_IC: None, # same platforms CAR.LEAF_IC: None, # same platforms
CAR.ROGUE: NissanCarInfo("Nissan Rogue 2018-20"), CAR.ROGUE: NissanCarInfo("Nissan Rogue 2018-20"),
CAR.ALTIMA: NissanCarInfo("Nissan Altima 2019-20", harness=Harness.nissan_b), CAR.ALTIMA: NissanCarInfo("Nissan Altima 2019-20", harness=Harness.nissan_b),

@ -1,5 +1,5 @@
from opendbc.can.packer import CANPacker from opendbc.can.packer import CANPacker
from selfdrive.car import apply_std_steer_torque_limits from selfdrive.car import apply_driver_steer_torque_limits
from selfdrive.car.subaru import subarucan from selfdrive.car.subaru import subarucan
from selfdrive.car.subaru.values import DBC, GLOBAL_GEN2, PREGLOBAL_CARS, CarControllerParams from selfdrive.car.subaru.values import DBC, GLOBAL_GEN2, PREGLOBAL_CARS, CarControllerParams
@ -19,7 +19,7 @@ class CarController:
self.p = CarControllerParams(CP) self.p = CarControllerParams(CP)
self.packer = CANPacker(DBC[CP.carFingerprint]['pt']) self.packer = CANPacker(DBC[CP.carFingerprint]['pt'])
def update(self, CC, CS): def update(self, CC, CS, now_nanos):
actuators = CC.actuators actuators = CC.actuators
hud_control = CC.hudControl hud_control = CC.hudControl
pcm_cancel_cmd = CC.cruiseControl.cancel pcm_cancel_cmd = CC.cruiseControl.cancel
@ -34,7 +34,7 @@ class CarController:
# limits due to driver torque # limits due to driver torque
new_steer = int(round(apply_steer)) new_steer = int(round(apply_steer))
apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.p) apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.p)
if not CC.latActive: if not CC.latActive:
apply_steer = 0 apply_steer = 0

@ -11,7 +11,7 @@ class CarInterface(CarInterfaceBase):
@staticmethod @staticmethod
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): def _get_params(ret, candidate, fingerprint, car_fw, experimental_long):
ret.carName = "subaru" ret.carName = "subaru"
ret.radarOffCan = True ret.radarUnavailable = True
ret.dashcamOnly = candidate in PREGLOBAL_CARS ret.dashcamOnly = candidate in PREGLOBAL_CARS
ret.autoResumeSng = False ret.autoResumeSng = False
@ -112,5 +112,5 @@ class CarInterface(CarInterfaceBase):
return ret return ret
def apply(self, c): def apply(self, c, now_nanos):
return self.CC.update(c, self.CS) return self.CC.update(c, self.CS, now_nanos)

@ -253,6 +253,7 @@ FW_VERSIONS = {
b'\xca!f@\x07', b'\xca!f@\x07',
b'\xca!fp\x07', b'\xca!fp\x07',
b'\xf3"f@\x07', b'\xf3"f@\x07',
b'\xe6!fp\x07',
], ],
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
b'\xe6\xf5\004\000\000', b'\xe6\xf5\004\000\000',
@ -262,6 +263,7 @@ FW_VERSIONS = {
b'\xf1\x00\xd7\x10@', b'\xf1\x00\xd7\x10@',
b'\xe6\xf5D0\x00', b'\xe6\xf5D0\x00',
b'\xe9\xf6F0\x00', b'\xe9\xf6F0\x00',
b'\xe9\xf5B0\x00',
], ],
}, },
CAR.FORESTER: { CAR.FORESTER: {

@ -14,7 +14,7 @@ class CarController:
self.pt_packer = CANPacker(DBC[CP.carFingerprint]['pt']) self.pt_packer = CANPacker(DBC[CP.carFingerprint]['pt'])
self.tesla_can = TeslaCAN(self.packer, self.pt_packer) self.tesla_can = TeslaCAN(self.packer, self.pt_packer)
def update(self, CC, CS): def update(self, CC, CS, now_nanos):
actuators = CC.actuators actuators = CC.actuators
pcm_cancel_cmd = CC.cruiseControl.cancel pcm_cancel_cmd = CC.cruiseControl.cancel

@ -23,7 +23,6 @@ class CarInterface(CarInterfaceBase):
ret.longitudinalTuning.kpV = [0] ret.longitudinalTuning.kpV = [0]
ret.longitudinalTuning.kiBP = [0] ret.longitudinalTuning.kiBP = [0]
ret.longitudinalTuning.kiV = [0] ret.longitudinalTuning.kiV = [0]
ret.stopAccel = 0.0
ret.longitudinalActuatorDelayUpperBound = 0.5 # s ret.longitudinalActuatorDelayUpperBound = 0.5 # s
ret.radarTimeStep = (1.0 / 8) # 8Hz ret.radarTimeStep = (1.0 / 8) # 8Hz
@ -59,5 +58,5 @@ class CarInterface(CarInterfaceBase):
return ret return ret
def apply(self, c): def apply(self, c, now_nanos):
return self.CC.update(c, self.CS) return self.CC.update(c, self.CS, now_nanos)

@ -18,6 +18,7 @@ from selfdrive.car.body.values import CAR as COMMA
non_tested_cars = [ non_tested_cars = [
FORD.ESCAPE_MK4, FORD.ESCAPE_MK4,
FORD.FOCUS_MK4, FORD.FOCUS_MK4,
FORD.MAVERICK_MK1,
GM.CADILLAC_ATS, GM.CADILLAC_ATS,
GM.HOLDEN_ASTRA, GM.HOLDEN_ASTRA,
GM.MALIBU, GM.MALIBU,
@ -25,6 +26,7 @@ non_tested_cars = [
HYUNDAI.GENESIS_G90, HYUNDAI.GENESIS_G90,
HYUNDAI.KIA_OPTIMA_H, HYUNDAI.KIA_OPTIMA_H,
HONDA.ODYSSEY_CHN, HONDA.ODYSSEY_CHN,
VOLKSWAGEN.CRAFTER_MK2, # need a route from an ACC-equipped Crafter
] ]
CarTestRoute = namedtuple('CarTestRoute', ['route', 'car_model', 'segment'], defaults=(None,)) CarTestRoute = namedtuple('CarTestRoute', ['route', 'car_model', 'segment'], defaults=(None,))
@ -42,11 +44,13 @@ routes = [
CarTestRoute("221c253375af4ee9|2022-06-15--18-38-24", CHRYSLER.RAM_1500), CarTestRoute("221c253375af4ee9|2022-06-15--18-38-24", CHRYSLER.RAM_1500),
CarTestRoute("8fb5eabf914632ae|2022-08-04--17-28-53", CHRYSLER.RAM_HD, segment=6), CarTestRoute("8fb5eabf914632ae|2022-08-04--17-28-53", CHRYSLER.RAM_HD, segment=6),
CarTestRoute("54827bf84c38b14f|2023-01-25--14-14-11", FORD.BRONCO_SPORT_MK1),
CarTestRoute("62241b0c7fea4589|2022-09-01--15-32-49", FORD.EXPLORER_MK6), CarTestRoute("62241b0c7fea4589|2022-09-01--15-32-49", FORD.EXPLORER_MK6),
#TestRoute("f1b4c567731f4a1b|2018-04-30--10-15-35", FORD.FUSION), #TestRoute("f1b4c567731f4a1b|2018-04-30--10-15-35", FORD.FUSION),
CarTestRoute("7cc2a8365b4dd8a9|2018-12-02--12-10-44", GM.ACADIA), CarTestRoute("7cc2a8365b4dd8a9|2018-12-02--12-10-44", GM.ACADIA),
CarTestRoute("aa20e335f61ba898|2019-02-05--16-59-04", GM.BUICK_REGAL), CarTestRoute("aa20e335f61ba898|2019-02-05--16-59-04", GM.BUICK_REGAL),
CarTestRoute("ef8f2185104d862e|2023-02-09--18-37-13", GM.ESCALADE),
CarTestRoute("46460f0da08e621e|2021-10-26--07-21-46", GM.ESCALADE_ESV), CarTestRoute("46460f0da08e621e|2021-10-26--07-21-46", GM.ESCALADE_ESV),
CarTestRoute("c950e28c26b5b168|2018-05-30--22-03-41", GM.VOLT), CarTestRoute("c950e28c26b5b168|2018-05-30--22-03-41", GM.VOLT),
CarTestRoute("f08912a233c1584f|2022-08-11--18-02-41", GM.BOLT_EUV, segment=1), CarTestRoute("f08912a233c1584f|2022-08-11--18-02-41", GM.BOLT_EUV, segment=1),
@ -72,7 +76,7 @@ routes = [
CarTestRoute("d83f36766f8012a5|2020-02-05--18-42-21", HONDA.CIVIC_BOSCH_DIESEL), CarTestRoute("d83f36766f8012a5|2020-02-05--18-42-21", HONDA.CIVIC_BOSCH_DIESEL),
CarTestRoute("f0890d16a07a236b|2021-05-25--17-27-22", HONDA.INSIGHT), CarTestRoute("f0890d16a07a236b|2021-05-25--17-27-22", HONDA.INSIGHT),
CarTestRoute("07d37d27996096b6|2020-03-04--21-57-27", HONDA.PILOT), CarTestRoute("07d37d27996096b6|2020-03-04--21-57-27", HONDA.PILOT),
CarTestRoute("684e8f96bd491a0e|2021-11-03--11-08-42", HONDA.PASSPORT), CarTestRoute("684e8f96bd491a0e|2021-11-03--11-08-42", HONDA.PILOT), # Passport
CarTestRoute("0a78dfbacc8504ef|2020-03-04--13-29-55", HONDA.CIVIC_BOSCH), CarTestRoute("0a78dfbacc8504ef|2020-03-04--13-29-55", HONDA.CIVIC_BOSCH),
CarTestRoute("f34a60d68d83b1e5|2020-10-06--14-35-55", HONDA.ACURA_RDX), CarTestRoute("f34a60d68d83b1e5|2020-10-06--14-35-55", HONDA.ACURA_RDX),
CarTestRoute("54fd8451b3974762|2021-04-01--14-50-10", HONDA.RIDGELINE), CarTestRoute("54fd8451b3974762|2021-04-01--14-50-10", HONDA.RIDGELINE),
@ -100,6 +104,7 @@ routes = [
CarTestRoute("db68bbe12250812c|2022-12-05--00-54-12", HYUNDAI.TUCSON_4TH_GEN), # 2023 CarTestRoute("db68bbe12250812c|2022-12-05--00-54-12", HYUNDAI.TUCSON_4TH_GEN), # 2023
CarTestRoute("36e10531feea61a4|2022-07-25--13-37-42", HYUNDAI.TUCSON_HYBRID_4TH_GEN), CarTestRoute("36e10531feea61a4|2022-07-25--13-37-42", HYUNDAI.TUCSON_HYBRID_4TH_GEN),
CarTestRoute("5875672fc1d4bf57|2020-07-23--21-33-28", HYUNDAI.KIA_SORENTO), CarTestRoute("5875672fc1d4bf57|2020-07-23--21-33-28", HYUNDAI.KIA_SORENTO),
CarTestRoute("1d0d000db3370fd0|2023-01-04--22-28-42", HYUNDAI.KIA_SORENTO_4TH_GEN, segment=5),
CarTestRoute("628935d7d3e5f4f7|2022-11-30--01-12-46", HYUNDAI.KIA_SORENTO_PHEV_4TH_GEN), CarTestRoute("628935d7d3e5f4f7|2022-11-30--01-12-46", HYUNDAI.KIA_SORENTO_PHEV_4TH_GEN),
CarTestRoute("9c917ba0d42ffe78|2020-04-17--12-43-19", HYUNDAI.PALISADE), CarTestRoute("9c917ba0d42ffe78|2020-04-17--12-43-19", HYUNDAI.PALISADE),
CarTestRoute("05a8f0197fdac372|2022-10-19--14-14-09", HYUNDAI.IONIQ_5), # HDA2 CarTestRoute("05a8f0197fdac372|2022-10-19--14-14-09", HYUNDAI.IONIQ_5), # HDA2
@ -119,9 +124,11 @@ routes = [
CarTestRoute("d545129f3ca90f28|2022-10-19--09-22-54", HYUNDAI.KIA_EV6), # HDA2 CarTestRoute("d545129f3ca90f28|2022-10-19--09-22-54", HYUNDAI.KIA_EV6), # HDA2
CarTestRoute("68d6a96e703c00c9|2022-09-10--16-09-39", HYUNDAI.KIA_EV6), # HDA1 CarTestRoute("68d6a96e703c00c9|2022-09-10--16-09-39", HYUNDAI.KIA_EV6), # HDA1
CarTestRoute("007d5e4ad9f86d13|2021-09-30--15-09-23", HYUNDAI.KIA_K5_2021), CarTestRoute("007d5e4ad9f86d13|2021-09-30--15-09-23", HYUNDAI.KIA_K5_2021),
CarTestRoute("c58dfc9fc16590e0|2023-01-14--13-51-48", HYUNDAI.KIA_K5_HEV_2020),
CarTestRoute("50c6c9b85fd1ff03|2020-10-26--17-56-06", HYUNDAI.KIA_NIRO_EV), CarTestRoute("50c6c9b85fd1ff03|2020-10-26--17-56-06", HYUNDAI.KIA_NIRO_EV),
CarTestRoute("173219cf50acdd7b|2021-07-05--10-27-41", HYUNDAI.KIA_NIRO_PHEV), CarTestRoute("173219cf50acdd7b|2021-07-05--10-27-41", HYUNDAI.KIA_NIRO_PHEV),
CarTestRoute("34a875f29f69841a|2021-07-29--13-02-09", HYUNDAI.KIA_NIRO_HEV_2021), CarTestRoute("34a875f29f69841a|2021-07-29--13-02-09", HYUNDAI.KIA_NIRO_HEV_2021),
CarTestRoute("db04d2c63990e3ba|2023-02-08--16-52-39", HYUNDAI.KIA_NIRO_HEV_2ND_GEN),
CarTestRoute("50a2212c41f65c7b|2021-05-24--16-22-06", HYUNDAI.KIA_FORTE), CarTestRoute("50a2212c41f65c7b|2021-05-24--16-22-06", HYUNDAI.KIA_FORTE),
CarTestRoute("192283cdbb7a58c2|2022-10-15--01-43-18", HYUNDAI.KIA_SPORTAGE_5TH_GEN), CarTestRoute("192283cdbb7a58c2|2022-10-15--01-43-18", HYUNDAI.KIA_SPORTAGE_5TH_GEN),
CarTestRoute("c5ac319aa9583f83|2021-06-01--18-18-31", HYUNDAI.ELANTRA), CarTestRoute("c5ac319aa9583f83|2021-06-01--18-18-31", HYUNDAI.ELANTRA),
@ -174,7 +181,9 @@ routes = [
CarTestRoute("0a0de17a1e6a2d15|2020-09-21--21-24-41", TOYOTA.PRIUS_TSS2), CarTestRoute("0a0de17a1e6a2d15|2020-09-21--21-24-41", TOYOTA.PRIUS_TSS2),
CarTestRoute("9b36accae406390e|2021-03-30--10-41-38", TOYOTA.MIRAI), CarTestRoute("9b36accae406390e|2021-03-30--10-41-38", TOYOTA.MIRAI),
CarTestRoute("cd9cff4b0b26c435|2021-05-13--15-12-39", TOYOTA.CHR), CarTestRoute("cd9cff4b0b26c435|2021-05-13--15-12-39", TOYOTA.CHR),
CarTestRoute("ea8fbe72b96a185c|2023-02-08--15-11-46", TOYOTA.CHR_TSS2),
CarTestRoute("57858ede0369a261|2021-05-18--20-34-20", TOYOTA.CHRH), CarTestRoute("57858ede0369a261|2021-05-18--20-34-20", TOYOTA.CHRH),
CarTestRoute("6719965b0e1d1737|2023-02-09--22-44-05", TOYOTA.CHRH_TSS2),
CarTestRoute("14623aae37e549f3|2021-10-24--01-20-49", TOYOTA.PRIUS_V), CarTestRoute("14623aae37e549f3|2021-10-24--01-20-49", TOYOTA.PRIUS_V),
CarTestRoute("202c40641158a6e5|2021-09-21--09-43-24", VOLKSWAGEN.ARTEON_MK1), CarTestRoute("202c40641158a6e5|2021-09-21--09-43-24", VOLKSWAGEN.ARTEON_MK1),

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

Loading…
Cancel
Save