Merge branch 'master' into mqb-long

mqb-long
Jason Young 3 years ago
commit 5dc347f812
  1. 2
      .github/PULL_REQUEST_TEMPLATE/car_bugfix.md
  2. 27
      .github/workflows/badges.yaml
  3. 261
      .github/workflows/selfdrive_tests.yaml
  4. 45
      .github/workflows/setup/action.yaml
  5. 40
      .github/workflows/tools_tests.yaml
  6. 1
      .gitignore
  7. 3
      .gitmodules
  8. 19
      .pre-commit-config.yaml
  9. 3
      Jenkinsfile
  10. 1
      Pipfile
  11. 1301
      Pipfile.lock
  12. 30
      README.md
  13. 24
      RELEASES.md
  14. 31
      SConstruct
  15. 2
      cereal
  16. 5
      common/clutil.cc
  17. 13
      common/gpio.py
  18. 5
      common/params.cc
  19. 2
      common/params_pyx.pyx
  20. 6
      common/tests/test_params.py
  21. 2
      common/tests/test_util.cc
  22. 2
      common/version.h
  23. 442
      docs/CARS.md
  24. 2
      docs/c_docs.rst
  25. 2
      opendbc
  26. 2
      release/build_release.sh
  27. 31
      release/files_common
  28. 2
      release/files_tici
  29. 6
      selfdrive/athena/athenad.py
  30. 2
      selfdrive/athena/manage_athenad.py
  31. 2
      selfdrive/athena/tests/helpers.py
  32. 2
      selfdrive/boardd/SConscript
  33. 92
      selfdrive/boardd/boardd.cc
  34. 4
      selfdrive/boardd/panda.cc
  35. 1
      selfdrive/boardd/panda.h
  36. 2
      selfdrive/boardd/pandad.py
  37. 333
      selfdrive/boardd/pigeon.cc
  38. 58
      selfdrive/boardd/pigeon.h
  39. 245
      selfdrive/boardd/tests/boardd_old.py
  40. 83
      selfdrive/boardd/tests/replay_many.py
  41. 77
      selfdrive/boardd/tests/test_boardd_api.py
  42. 28
      selfdrive/car/CARS_template.md
  43. 2
      selfdrive/car/__init__.py
  44. 4
      selfdrive/car/body/values.py
  45. 2
      selfdrive/car/car_helpers.py
  46. 39
      selfdrive/car/chrysler/carcontroller.py
  47. 4
      selfdrive/car/chrysler/carstate.py
  48. 2
      selfdrive/car/chrysler/interface.py
  49. 10
      selfdrive/car/chrysler/values.py
  50. 32
      selfdrive/car/docs.py
  51. 155
      selfdrive/car/docs_definitions.py
  52. 3
      selfdrive/car/ford/carstate.py
  53. 49
      selfdrive/car/ford/fordcan.py
  54. 114
      selfdrive/car/ford/radar_interface.py
  55. 13
      selfdrive/car/ford/values.py
  56. 19
      selfdrive/car/fw_versions.py
  57. 4
      selfdrive/car/gm/carcontroller.py
  58. 3
      selfdrive/car/gm/carstate.py
  59. 7
      selfdrive/car/gm/gmcan.py
  60. 17
      selfdrive/car/gm/interface.py
  61. 13
      selfdrive/car/gm/values.py
  62. 26
      selfdrive/car/honda/interface.py
  63. 2
      selfdrive/car/honda/values.py
  64. 30
      selfdrive/car/hyundai/carcontroller.py
  65. 103
      selfdrive/car/hyundai/carstate.py
  66. 18
      selfdrive/car/hyundai/hyundaican.py
  67. 23
      selfdrive/car/hyundai/hyundaicanfd.py
  68. 49
      selfdrive/car/hyundai/interface.py
  69. 104
      selfdrive/car/hyundai/values.py
  70. 16
      selfdrive/car/interfaces.py
  71. 14
      selfdrive/car/mazda/values.py
  72. 5
      selfdrive/car/nissan/interface.py
  73. 5
      selfdrive/car/nissan/nissancan.py
  74. 4
      selfdrive/car/nissan/values.py
  75. 6
      selfdrive/car/subaru/carstate.py
  76. 3
      selfdrive/car/subaru/interface.py
  77. 57
      selfdrive/car/subaru/values.py
  78. 371
      selfdrive/car/tests/routes.py
  79. 8
      selfdrive/car/tests/test_car_interfaces.py
  80. 2
      selfdrive/car/tests/test_docs.py
  81. 2
      selfdrive/car/tests/test_fingerprints.py
  82. 52
      selfdrive/car/tests/test_fw_fingerprint.py
  83. 27
      selfdrive/car/tests/test_models.py
  84. 3
      selfdrive/car/torque_data/override.yaml
  85. 2
      selfdrive/car/torque_data/substitute.yaml
  86. 68
      selfdrive/car/toyota/carcontroller.py
  87. 56
      selfdrive/car/toyota/carstate.py
  88. 1
      selfdrive/car/toyota/interface.py
  89. 2
      selfdrive/car/toyota/tunes.py
  90. 112
      selfdrive/car/toyota/values.py
  91. 4
      selfdrive/car/vin.py
  92. 19
      selfdrive/car/volkswagen/carcontroller.py
  93. 247
      selfdrive/car/volkswagen/carstate.py
  94. 50
      selfdrive/car/volkswagen/interface.py
  95. 84
      selfdrive/car/volkswagen/pqcan.py
  96. 71
      selfdrive/car/volkswagen/values.py
  97. 72
      selfdrive/controls/controlsd.py
  98. 2
      selfdrive/controls/lib/alertmanager.py
  99. 1
      selfdrive/controls/lib/drive_helpers.py
  100. 4
      selfdrive/controls/lib/events.py
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,6 +1,6 @@
--- ---
name: Car Bug fix name: Car Bug fix
about: For vehicle/brand specifc bug fixes about: For vehicle/brand specific bug fixes
title: '' title: ''
labels: 'car bug fix' labels: 'car bug fix'
assignees: '' assignees: ''

@ -7,12 +7,7 @@ on:
env: env:
BASE_IMAGE: openpilot-base BASE_IMAGE: openpilot-base
DOCKER_REGISTRY: ghcr.io/commaai DOCKER_REGISTRY: ghcr.io/commaai
RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/scons_cache:/tmp/scons_cache -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/openpilot_cache:/tmp/openpilot_cache $DOCKER_REGISTRY/$BASE_IMAGE:latest /bin/sh -c
BUILD: |
docker pull $(grep -iohP '(?<=^from)\s+\S+' Dockerfile.openpilot_base) || true
docker pull $DOCKER_REGISTRY/$BASE_IMAGE:latest || true
docker build --cache-from $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $BASE_IMAGE:latest -f Dockerfile.openpilot_base .
RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/scons_cache:/tmp/scons_cache -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/sh -c
jobs: jobs:
badges: badges:
@ -23,23 +18,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- uses: ./.github/workflows/setup
- name: Cache scons
id: scons-cache
# TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
env:
CACHE_SKIP_SAVE: true
with:
path: /tmp/scons_cache
key: scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
restore-keys: |
scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
scons-
- name: Build Docker image
run: eval "$BUILD"
- name: Push badges - name: Push badges
run: | run: |
${{ env.RUN }} "scons -j$(nproc) && python selfdrive/ui/translations/create_badges.py" ${{ env.RUN }} "scons -j$(nproc) && python selfdrive/ui/translations/create_badges.py"
@ -49,6 +28,6 @@ jobs:
git config user.email "badge-researcher@comma.ai" git config user.email "badge-researcher@comma.ai"
git config user.name "Badge Researcher" git config user.name "Badge Researcher"
git add translation_badge_*.svg git add translation_badge.svg
git commit -m "Add/Update badges" git commit -m "Add/Update badges"
git push -f origin HEAD git push -f origin HEAD

@ -17,7 +17,7 @@ env:
docker pull $DOCKER_REGISTRY/$BASE_IMAGE:latest || true docker pull $DOCKER_REGISTRY/$BASE_IMAGE:latest || true
docker build --cache-from $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $BASE_IMAGE:latest -f Dockerfile.openpilot_base . docker build --cache-from $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $BASE_IMAGE:latest -f Dockerfile.openpilot_base .
RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/scons_cache:/tmp/scons_cache -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/sh -c RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/scons_cache:/tmp/scons_cache -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/sh -c
BUILD_CL: | BUILD_CL: |
docker pull $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest || true docker pull $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest || true
@ -27,11 +27,10 @@ env:
UNIT_TEST: coverage run --append -m unittest discover UNIT_TEST: coverage run --append -m unittest discover
jobs: jobs:
# TODO: once actions/cache supports read only mode, use the cache for all jobs
build_release: build_release:
name: build release name: build release
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 50 timeout-minutes: 30
env: env:
STRIPPED_DIR: /tmp/releasepilot STRIPPED_DIR: /tmp/releasepilot
steps: steps:
@ -39,44 +38,31 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: true submodules: true
- name: Pull LFS - name: Build devel
run: git lfs pull run: TARGET_DIR=$STRIPPED_DIR release/build_devel.sh
- uses: ./.github/workflows/setup
with:
save-cache: true
- name: Check submodules - name: Check submodules
if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot' if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot'
run: release/check-submodules.sh run: release/check-submodules.sh
- name: Cache scons - name: Build openpilot and run checks
id: scons-cache
# TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
env:
CACHE_SKIP_SAVE: true
with:
path: /tmp/scons_cache
key: scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
restore-keys: |
scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
scons-
- name: Build devel
run: | run: |
TARGET_DIR=$STRIPPED_DIR release/build_devel.sh cd $STRIPPED_DIR
cp Dockerfile.openpilot_base $STRIPPED_DIR ${{ env.RUN }} "CI=1 python selfdrive/manager/build.py"
- name: Run tests
run: |
cd $STRIPPED_DIR
${{ env.RUN }} "release/check-dirty.sh && \
python -m unittest discover selfdrive/car"
- name: pre-commit
run: |
cd $GITHUB_WORKSPACE
cp .pre-commit-config.yaml $STRIPPED_DIR cp .pre-commit-config.yaml $STRIPPED_DIR
cp .pylintrc $STRIPPED_DIR cp .pylintrc $STRIPPED_DIR
cp mypy.ini $STRIPPED_DIR cp mypy.ini $STRIPPED_DIR
- name: Build Docker image cd $STRIPPED_DIR
run: | ${{ env.RUN }} "pre-commit run --all"
eval "$BUILD"
rm $STRIPPED_DIR/Dockerfile.openpilot_base
- name: Build openpilot and run checks
run: |
cd $STRIPPED_DIR
${{ env.RUN }} "CI=1 python selfdrive/manager/build.py && \
pre-commit run --all && \
rm .pre-commit-config.yaml && \
rm .pylintrc && \
rm mypy.ini && \
release/check-dirty.sh && \
python -m unittest discover selfdrive/car"
build_all: build_all:
name: build all name: build all
@ -86,27 +72,13 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Cache scons - uses: ./.github/workflows/setup
id: scons-cache
# TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
env:
CACHE_SKIP_SAVE: ${{ github.ref != 'refs/heads/master' || github.repository != 'commaai/openpilot' }}
with:
path: /tmp/scons_cache
key: scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-${{ steps.date.outputs.time }}
restore-keys: |
scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
scons-
- name: Build Docker image
run: eval "$BUILD"
- name: Build openpilot with all flags - name: Build openpilot with all flags
run: ${{ env.RUN }} "scons -j$(nproc) --extras --test && release/check-dirty.sh" run: ${{ env.RUN }} "scons -j$(nproc) --extras && release/check-dirty.sh"
- name: Cleanup scons cache - name: Cleanup scons cache
run: | run: |
${{ env.RUN }} "scons -j$(nproc) --extras --test && \ ${{ env.RUN }} "rm -rf /tmp/scons_cache/* && \
rm -rf /tmp/scons_cache/* && \ scons -j$(nproc) --extras --cache-populate"
scons -j$(nproc) --extras --test --cache-populate"
#build_mac: #build_mac:
# name: build macos # name: build macos
@ -165,41 +137,6 @@ jobs:
# done # done
# comm -13 <(echo "$EXISTING_CELLAR") <(echo "$new_cellar") | tee ~/github_brew_cache_entries.txt # comm -13 <(echo "$EXISTING_CELLAR") <(echo "$new_cellar") | tee ~/github_brew_cache_entries.txt
build_webcam:
name: build webcam
runs-on: ubuntu-20.04
timeout-minutes: 90
env:
IMAGE_NAME: openpilotwebcamci
steps:
- uses: actions/checkout@v3
with:
submodules: true
- name: Cache scons
id: scons-cache
# TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
env:
CACHE_SKIP_SAVE: true
with:
path: /tmp/scons_cache
key: scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
restore-keys: |
scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
scons-
- name: Build Docker image
run: |
eval "$BUILD"
docker pull $DOCKER_REGISTRY/$IMAGE_NAME:latest || true
docker build --cache-from $DOCKER_REGISTRY/$IMAGE_NAME:latest -t $DOCKER_REGISTRY/$IMAGE_NAME:latest -f tools/webcam/Dockerfile .
- name: Build openpilot
run: docker run --shm-size 1G --rm -v $PWD:/tmp/openpilot -e PYTHONPATH=/tmp/openpilot $DOCKER_REGISTRY/$IMAGE_NAME /bin/sh -c "cd /tmp/openpilot && USE_WEBCAM=1 scons -j$(nproc)"
- name: Push to container registry
if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot'
run: |
$DOCKER_LOGIN
docker push $DOCKER_REGISTRY/$IMAGE_NAME:latest
docker_push: docker_push:
name: docker push name: docker push
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
@ -244,30 +181,11 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Cache dependencies - uses: ./.github/workflows/setup
id: dependency-cache
uses: actions/cache@v2
with:
path: /tmp/comma_download_cache
key: ${{ hashFiles('.github/workflows/selfdrive_tests.yaml', 'selfdrive/test/test_valgrind_replay.py') }}
- name: Cache scons
id: scons-cache
# TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
env:
CACHE_SKIP_SAVE: true
with:
path: /tmp/scons_cache
key: scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
restore-keys: |
scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
scons-
- name: Build Docker image
run: eval "$BUILD"
- name: Run valgrind - name: Run valgrind
run: | run: |
${{ env.RUN }} "scons -j$(nproc) && \ ${{ env.RUN }} "scons -j$(nproc) && \
FILEREADER_CACHE=1 python selfdrive/test/test_valgrind_replay.py" python selfdrive/test/test_valgrind_replay.py"
- name: Print logs - name: Print logs
if: always() if: always()
run: cat selfdrive/test/valgrind_logs.txt run: cat selfdrive/test/valgrind_logs.txt
@ -277,32 +195,14 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 50 timeout-minutes: 50
steps: steps:
- name: Get current date
id: date
run: echo "::set-output name=time::$(date +'%s')"
- name: Output timestamp
run: echo $TIMESTAMP
env:
TIMESTAMP: ${{ steps.date.outputs.time }}
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Cache scons - uses: ./.github/workflows/setup
id: scons-cache
# TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
env:
CACHE_SKIP_SAVE: ${{ github.ref != 'refs/heads/master' || github.repository != 'commaai/openpilot' }}
with:
path: /tmp/scons_cache
key: scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-${{ steps.date.outputs.time }}
restore-keys: scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
- name: Build Docker image
run: eval "$BUILD"
- name: Run unit tests - name: Run unit tests
run: | run: |
${{ env.RUN }} "export SKIP_LONG_TESTS=1 && \ ${{ env.RUN }} "export SKIP_LONG_TESTS=1 && \
scons -j$(nproc) --test && \ scons -j$(nproc) && \
$UNIT_TEST common && \ $UNIT_TEST common && \
$UNIT_TEST opendbc/can && \ $UNIT_TEST opendbc/can && \
$UNIT_TEST selfdrive/boardd && \ $UNIT_TEST selfdrive/boardd && \
@ -339,30 +239,17 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Cache dependencies - uses: ./.github/workflows/setup
- name: Cache test routes
id: dependency-cache id: dependency-cache
uses: actions/cache@v2 uses: actions/cache@v3
with: with:
path: /tmp/comma_download_cache path: /tmp/comma_download_cache
key: ${{ hashFiles('.github/workflows/selfdrive_tests.yaml', 'selfdrive/test/process_replay/test_processes.py') }} key: proc-replay-${{ hashFiles('.github/workflows/selfdrive_tests.yaml', 'selfdrive/test/process_replay/ref_commit') }}
- name: Cache scons
id: scons-cache
# TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
env:
CACHE_SKIP_SAVE: true
with:
path: /tmp/scons_cache
key: scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
restore-keys: |
scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
scons-
- name: Build Docker image
run: eval "$BUILD"
- name: Run replay - name: Run replay
run: | run: |
${{ env.RUN }} "scons -j$(nproc) && \ ${{ env.RUN }} "scons -j$(nproc) && \
FILEREADER_CACHE=1 CI=1 coverage run selfdrive/test/process_replay/test_processes.py -j$(nproc) && \ CI=1 coverage run selfdrive/test/process_replay/test_processes.py -j$(nproc) && \
coverage xml" coverage xml"
- name: Print diff - name: Print diff
if: always() if: always()
@ -389,35 +276,16 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Pull LFS - uses: ./.github/workflows/setup
run: git lfs pull
- name: Cache dependencies
id: dependency-cache
uses: actions/cache@v2
with:
path: /tmp/comma_download_cache
key: ${{ hashFiles('.github/workflows/selfdrive_tests.yaml', 'selfdrive/test/process_replay/model_replay.py') }}
- name: Cache scons
id: scons-cache
# TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
env:
CACHE_SKIP_SAVE: true
with:
path: /tmp/scons_cache
key: scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
restore-keys: |
scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
scons-
- name: Build Docker image - name: Build Docker image
# Sim docker is needed to get the intel OPENCL drivers # Sim docker is needed to get the OpenCL drivers
run: eval "$BUILD_CL" run: eval "$BUILD_CL"
- name: Run replay - name: Run replay
run: | run: |
${{ env.RUN_CL }} "scons -j$(nproc) && \ ${{ env.RUN_CL }} "scons -j$(nproc) && \
ONNXCPU=1 FILEREADER_CACHE=1 CI=1 coverage run \ ONNXCPU=1 CI=1 coverage run \
selfdrive/test/process_replay/model_replay.py -j$(nproc) && \ selfdrive/test/process_replay/model_replay.py -j$(nproc) && \
coverage xml" coverage xml"
test_longitudinal: test_longitudinal:
name: longitudinal name: longitudinal
@ -427,20 +295,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Cache scons - uses: ./.github/workflows/setup
id: scons-cache
# TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
env:
CACHE_SKIP_SAVE: true
with:
path: /tmp/scons_cache
key: scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
restore-keys: |
scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
scons-
- name: Build Docker image
run: eval "$BUILD"
- name: Test longitudinal - name: Test longitudinal
run: | run: |
${{ env.RUN }} "mkdir -p selfdrive/test/out && \ ${{ env.RUN }} "mkdir -p selfdrive/test/out && \
@ -469,30 +324,17 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Cache dependencies - uses: ./.github/workflows/setup
- name: Cache test routes
id: dependency-cache id: dependency-cache
uses: actions/cache@v2 uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
with: with:
path: /tmp/comma_download_cache path: /tmp/comma_download_cache
key: car_models-${{ hashFiles('selfdrive/car/tests/test_models.py', 'selfdrive/car/tests/routes.py') }}-${{ matrix.job }} key: car_models-${{ hashFiles('selfdrive/car/tests/test_models.py', 'selfdrive/car/tests/routes.py') }}-${{ matrix.job }}
- name: Cache scons
id: scons-cache
# TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
env:
CACHE_SKIP_SAVE: true
with:
path: /tmp/scons_cache
key: scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
restore-keys: |
scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
scons-
- name: Build Docker image
run: eval "$BUILD"
- name: Test car models - name: Test car models
run: | run: |
${{ env.RUN }} "scons -j$(nproc) --test && \ ${{ env.RUN }} "scons -j$(nproc) && \
FILEREADER_CACHE=1 coverage run -m pytest selfdrive/car/tests/test_models.py && \ coverage run -m pytest selfdrive/car/tests/test_models.py && \
coverage xml && \ coverage xml && \
chmod -R 777 /tmp/comma_download_cache" chmod -R 777 /tmp/comma_download_cache"
env: env:
@ -530,20 +372,7 @@ jobs:
with: with:
submodules: true submodules: true
ref: ${{ github.event.pull_request.base.ref }} ref: ${{ github.event.pull_request.base.ref }}
- name: Cache scons - uses: ./.github/workflows/setup
id: scons-cache
# TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
env:
CACHE_SKIP_SAVE: true
with:
path: /tmp/scons_cache
key: scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
restore-keys: |
scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
scons-
- name: Build Docker image
run: eval "$BUILD"
- name: Get base car info - name: Get base car info
run: | run: |
${{ env.RUN }} "scons -j$(nproc) && python selfdrive/debug/dump_car_info.py --path /tmp/openpilot_cache/base_car_info" ${{ env.RUN }} "scons -j$(nproc) && python selfdrive/debug/dump_car_info.py --path /tmp/openpilot_cache/base_car_info"

@ -0,0 +1,45 @@
name: 'openpilot env setup'
env:
BASE_IMAGE: openpilot-base
DOCKER_REGISTRY: ghcr.io/commaai
BUILD: |
docker pull $(grep -iohP '(?<=^from)\s+\S+' Dockerfile.openpilot_base) || true
docker pull $DOCKER_REGISTRY/$BASE_IMAGE:latest || true
docker build --cache-from $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $BASE_IMAGE:latest -f Dockerfile.openpilot_base .
inputs:
save-cache:
default: false
required: false
runs:
using: "composite"
steps:
# do this after checkout to ensure our custom LFS config is used to pull from GitLab
- shell: bash
run: git lfs pull
# build cache
- id: date
shell: bash
run: echo "::set-output name=date::$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d')"
- shell: bash
run: echo "${{ steps.date.outputs.date }}"
- shell: bash
run: echo "CACHE_SKIP_SAVE=true" >> $GITHUB_ENV
if: github.ref != 'refs/heads/master' || inputs.save-cache == 'false'
- id: scons-cache
# TODO: change the version to the released version
# when https://github.com/actions/cache/pull/489 (or 571) is merged.
uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
with:
path: /tmp/scons_cache
key: scons-${{ steps.date.outputs.date }}-${{ github.sha }}
restore-keys: |
scons-${{ steps.date.outputs.date }}-
scons-
# build our docker image
- shell: bash
run: eval "$BUILD"

@ -21,46 +21,6 @@ env:
GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/comma_download_cache:/tmp/comma_download_cache $BASE_IMAGE /bin/sh -c GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/comma_download_cache:/tmp/comma_download_cache $BASE_IMAGE /bin/sh -c
jobs: jobs:
build_latest_ubuntu:
name: build latest ubuntu
runs-on: ubuntu-20.04
timeout-minutes: 60
steps:
- uses: actions/checkout@v3
with:
submodules: true
- name: Cache pyenv
id: ubuntu-latest-pyenv
uses: actions/cache@v3
with:
path: |
~/.pyenv
~/.local/share/virtualenvs/
key: ubuntu-latest-python-${{ hashFiles('tools/ubuntu_setup.sh') }}-
- name: Cache scons
id: ubuntu-latest-scons
uses: actions/cache@v3
with:
path: /tmp/scons_cache
key: ubuntu-latest-scons-${{ hashFiles('.github/workflows/tools_test.yaml') }}-
restore-keys: |
ubuntu-latest-scons-${{ hashFiles('.github/workflows/tools_test.yaml') }}-
ubuntu-latest-scons-
- name: tools/ubuntu_setup.sh
run: |
source tools/openpilot_env.sh
tools/ubuntu_setup.sh
- name: Build openpilot
run: |
source tools/openpilot_env.sh
pipenv run scons -j$(nproc) --extras --test
- name: Cleanup scons cache
run: |
source tools/openpilot_env.sh
rm -rf /tmp/scons_cache/*
pipenv run scons -j$(nproc) --extras --test --cache-populate
plotjuggler: plotjuggler:
name: plotjuggler name: plotjuggler
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04

1
.gitignore vendored

@ -36,6 +36,7 @@ a.out
config.json config.json
clcache clcache
compile_commands.json compile_commands.json
compare_runtime*.html
persist persist
board/obj/ board/obj/

3
.gitmodules vendored

@ -16,3 +16,6 @@
[submodule "body"] [submodule "body"]
path = body path = body
url = ../../commaai/body.git url = ../../commaai/body.git
[submodule "tinygrad"]
path = tinygrad_repo
url = https://github.com/geohot/tinygrad.git

@ -15,11 +15,20 @@ repos:
- id: check-symlinks - id: check-symlinks
- id: check-added-large-files - id: check-added-large-files
args: ['--maxkb=100'] args: ['--maxkb=100']
- repo: https://github.com/codespell-project/codespell
rev: v2.2.1
hooks:
- 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)'
args:
# 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
- --builtins clear,rare,informal,usage,code,names,en-GB_to_en-US
- repo: https://github.com/pre-commit/mirrors-mypy - repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.931 rev: v0.931
hooks: hooks:
- id: mypy - id: mypy
exclude: '^(pyextra/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)/' exclude: '^(pyextra/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)/|(tinygrad/)|(tinygrad_repo/)'
additional_dependencies: ['types-PyYAML', 'lxml', 'numpy', 'types-atomicwrites', 'types-pycurl', 'types-requests', 'types-certifi'] additional_dependencies: ['types-PyYAML', 'lxml', 'numpy', 'types-atomicwrites', 'types-pycurl', 'types-requests', 'types-certifi']
args: args:
- --warn-redundant-casts - --warn-redundant-casts
@ -31,7 +40,7 @@ repos:
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/)|(selfdrive/debug/)/' exclude: '^(pyextra/)|(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
@ -46,7 +55,11 @@ repos:
entry: pylint entry: pylint
language: system language: system
types: [python] types: [python]
exclude: '^(pyextra/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(laika_repo/)|(rednose_repo/)' exclude: '^(pyextra/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(laika_repo/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)'
args:
- -rn
- -sn
- --rcfile=.pylintrc
- repo: local - repo: local
hooks: hooks:
- id: cppcheck - id: cppcheck

3
Jenkinsfile vendored

@ -131,7 +131,8 @@ pipeline {
["test boardd loopback", "python selfdrive/boardd/tests/test_boardd_loopback.py"], ["test boardd loopback", "python selfdrive/boardd/tests/test_boardd_loopback.py"],
["test loggerd", "python selfdrive/loggerd/tests/test_loggerd.py"], ["test loggerd", "python selfdrive/loggerd/tests/test_loggerd.py"],
["test encoder", "LD_LIBRARY_PATH=/usr/local/lib python selfdrive/loggerd/tests/test_encoder.py"], ["test encoder", "LD_LIBRARY_PATH=/usr/local/lib python selfdrive/loggerd/tests/test_encoder.py"],
["test sensord", "python selfdrive/sensord/test/test_sensord.py"], ["test sensord", "python selfdrive/sensord/tests/test_sensord.py"],
["test pigeond", "python selfdrive/sensord/tests/test_pigeond.py"],
]) ])
} }
} }

@ -88,6 +88,7 @@ urllib3 = "*"
utm = "*" utm = "*"
websocket_client = "*" websocket_client = "*"
hatanaka = "==2.4" hatanaka = "==2.4"
PySide2 = "*"
[requires] [requires]
python_version = "3.8" python_version = "3.8"

1301
Pipfile.lock generated

File diff suppressed because it is too large Load Diff

@ -17,7 +17,7 @@ Table of Contents
What is openpilot? What is openpilot?
------ ------
[openpilot](http://github.com/commaai/openpilot) is an open source driver assistance system. Currently, openpilot performs the functions of Adaptive Cruise Control (ACC), Automated Lane Centering (ALC), Forward Collision Warning (FCW) and Lane Departure Warning (LDW) for a growing variety of [supported car makes, models and model years](docs/CARS.md). In addition, while openpilot is engaged, a camera based Driver Monitoring (DM) feature alerts distracted and asleep drivers. See more about [the vehicle integration](docs/INTEGRATION.md) and [limitations](docs/LIMITATIONS.md). [openpilot](http://github.com/commaai/openpilot) is an open source driver assistance system. Currently, openpilot performs the functions of Adaptive Cruise Control (ACC), Automated Lane Centering (ALC), Forward Collision Warning (FCW), and Lane Departure Warning (LDW) for a growing variety of [supported car makes, models, and model years](docs/CARS.md). In addition, while openpilot is engaged, a camera-based Driver Monitoring (DM) feature alerts distracted and asleep drivers. See more about [the vehicle integration](docs/INTEGRATION.md) and [limitations](docs/LIMITATIONS.md).
<table> <table>
<tr> <tr>
@ -40,9 +40,9 @@ Running on a dedicated device in a car
To use openpilot in a car, you need four things To use openpilot in a car, you need four things
* A supported device to run this software: a [comma three](https://comma.ai/shop/products/three). * A supported device to run this software: a [comma three](https://comma.ai/shop/products/three).
* This software. The setup procedure of the comma three allows the user to enter a url for custom software. * This software. The setup procedure of the comma three allows the user to enter a URL for custom software.
The url, openpilot.comma.ai will install the release version of openpilot. To install openpilot master, you can use installer.comma.ai/commaai/master, and replacing commaai with another github username can install a fork. The URL, openpilot.comma.ai will install the release version of openpilot. To install openpilot master, you can use installer.comma.ai/commaai/master, and replacing commaai with another GitHub username can install a fork.
* One of [the 150+ supported cars](docs/CARS.md). We support Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, and more. If your car is not supported, but has adaptive cruise control and lane keeping assist, it's likely able to run openpilot. * One of [the 200+ supported cars](docs/CARS.md). We support Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, and more. If your car is not supported but has adaptive cruise control and lane-keeping assist, it's likely able to run openpilot.
* A [car harness](https://comma.ai/shop/products/car-harness) to connect to your car. * A [car harness](https://comma.ai/shop/products/car-harness) to connect to your car.
We have detailed instructions for [how to mount the device in a car](https://comma.ai/setup). We have detailed instructions for [how to mount the device in a car](https://comma.ai/setup).
@ -50,13 +50,13 @@ We have detailed instructions for [how to mount the device in a car](https://com
Running on PC Running on PC
------ ------
All of openpilot's services can run as normal on a PC, even without special hardware or a car. To develop or experiment with openpilot you can run openpilot on recorded or simulated data. All openpilot services can run as usual on a PC without requiring special hardware or a car. You can also run openpilot on recorded or simulated data to develop or experiment with openpilot.
With openpilot's tools you can plot logs, replay drives and watch the full-res camera streams. See [the tools README](tools/README.md) for more information. With openpilot's tools, you can plot logs, replay drives, and watch the full-res camera streams. See [the tools README](tools/README.md) for more information.
You can also run openpilot in simulation [with the CARLA simulator](tools/sim/README.md). This allows openpilot to drive around a virtual car on your Ubuntu machine. The whole setup should only take a few minutes, but does require a decent GPU. You can also run openpilot in simulation [with the CARLA simulator](tools/sim/README.md). This allows openpilot to drive around a virtual car on your Ubuntu machine. The whole setup should only take a few minutes but does require a decent GPU.
A PC running openpilot can also control your vehicle if it is connected to a [a webcam](https://github.com/commaai/openpilot/tree/master/tools/webcam), a [black panda](https://comma.ai/shop/products/panda), and [a harness](https://comma.ai/shop/products/car-harness). A PC running openpilot can also control your vehicle if it is connected to a [webcam](https://github.com/commaai/openpilot/tree/master/tools/webcam), a [black panda](https://comma.ai/shop/products/panda), and a [harness](https://comma.ai/shop/products/car-harness).
Community and Contributing Community and Contributing
------ ------
@ -78,8 +78,8 @@ By default, openpilot uploads the driving data to our servers. You can also acce
openpilot is open source software: the user is free to disable data collection if they wish to do so. openpilot is open source software: the user is free to disable data collection if they wish to do so.
openpilot logs the road facing cameras, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs. openpilot logs the road-facing cameras, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs.
The driver facing camera is only logged if you explicitly opt-in in settings. The microphone is not recorded. The driver-facing camera is only logged if you explicitly opt-in in settings. The microphone is not recorded.
By using openpilot, you agree to [our Privacy Policy](https://comma.ai/privacy). You understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma for the use of this data. By using openpilot, you agree to [our Privacy Policy](https://comma.ai/privacy). You understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma for the use of this data.
@ -87,11 +87,11 @@ Safety and Testing
---- ----
* openpilot observes ISO26262 guidelines, see [SAFETY.md](docs/SAFETY.md) for more details. * openpilot observes ISO26262 guidelines, see [SAFETY.md](docs/SAFETY.md) for more details.
* openpilot has software in the loop [tests](.github/workflows/selfdrive_tests.yaml) that run on every commit. * openpilot has software-in-the-loop [tests](.github/workflows/selfdrive_tests.yaml) that run on every commit.
* The code enforcing the safety model lives in panda and is written in C, see [code rigor](https://github.com/commaai/panda#code-rigor) for more details. * The code enforcing the safety model lives in panda and is written in C, see [code rigor](https://github.com/commaai/panda#code-rigor) for more details.
* panda has software in the loop [safety tests](https://github.com/commaai/panda/tree/master/tests/safety). * panda has software-in-the-loop [safety tests](https://github.com/commaai/panda/tree/master/tests/safety).
* Internally, we have a hardware in the loop Jenkins test suite that builds and unit tests the various processes. * Internally, we have a hardware-in-the-loop Jenkins test suite that builds and unit tests the various processes.
* panda has additional hardware in the loop [tests](https://github.com/commaai/panda/blob/master/Jenkinsfile). * panda has additional hardware-in-the-loop [tests](https://github.com/commaai/panda/blob/master/Jenkinsfile).
* We run the latest openpilot in a testing closet containing 10 comma devices continuously replaying routes. * We run the latest openpilot in a testing closet containing 10 comma devices continuously replaying routes.
Directory Structure Directory Structure
@ -119,7 +119,7 @@ Directory Structure
├── debug # Tools to help you debug and do car ports ├── debug # Tools to help you debug and do car ports
├── locationd # Precise localization and vehicle parameter estimation ├── locationd # Precise localization and vehicle parameter estimation
├── loggerd # Logger and uploader of car data ├── loggerd # Logger and uploader of car data
├── manager # Deamon that starts/stops all other daemons as needed ├── manager # Daemon that starts/stops all other daemons as needed
├── modeld # Driving and monitoring model runners ├── modeld # Driving and monitoring model runners
├── monitoring # Daemon to determine driver attention ├── monitoring # Daemon to determine driver attention
├── navd # Turn-by-turn navigation ├── navd # Turn-by-turn navigation

@ -1,8 +1,24 @@
Version 0.8.16 (2022-XX-XX) Version 0.8.17 (2022-XX-XX)
======================== ========================
* New driving model
* Internal feature space accuracy increased tenfold during training, this makes the model dramatically more accurate.
Version 0.8.16 (2022-08-26)
========================
* New driving model
* Reduced turn cutting
* Auto-detect right hand drive setting with driver monitoring model
* Improved fan controller for comma three
* New translations
* Japanese thanks to cydia2020!
* Brazilian Portuguese thanks to AlexandreSato!
* Chevrolet Bolt EUV 2022-23 support thanks to JasonJShuler! * Chevrolet Bolt EUV 2022-23 support thanks to JasonJShuler!
* Chevrolet Silverado 1500 2020-21 support thanks to JasonJShuler!
* GMC Sierra 1500 2020-21 support thanks to JasonJShuler!
* Hyundai Ioniq 5 2022 support thanks to sunnyhaibin! * Hyundai Ioniq 5 2022 support thanks to sunnyhaibin!
* Hyundai Kona Electric 2022 support thanks to sunnyhaibin! * Hyundai Kona Electric 2022 support thanks to sunnyhaibin!
* Hyundai Tucson Hybrid 2022 support thanks to sunnyhaibin!
* Subaru Legacy 2020-22 support thanks to martinl!
* Subaru Outback 2020-22 support * Subaru Outback 2020-22 support
Version 0.8.15 (2022-07-20) Version 0.8.15 (2022-07-20)
@ -62,7 +78,7 @@ Version 0.8.14 (2022-06-01)
Version 0.8.13 (2022-02-18) Version 0.8.13 (2022-02-18)
======================== ========================
* Improved driver monitoring * Improved driver monitoring
* Retuned driver pose learner for relaxed driving positions * Re-tuned driver pose learner for relaxed driving positions
* Added reliance on driving model to be more scene adaptive * Added reliance on driving model to be more scene adaptive
* Matched strictness between comma two and comma three * Matched strictness between comma two and comma three
* Improved performance in turns by compensating for the road bank angle * Improved performance in turns by compensating for the road bank angle
@ -208,7 +224,7 @@ Version 0.8.4 (2021-05-17)
* Delay controls start until system is ready * Delay controls start until system is ready
* Fuzzy car identification, enabled with Community Features toggle * Fuzzy car identification, enabled with Community Features toggle
* Localizer optimized for increased precision and less CPU usage * Localizer optimized for increased precision and less CPU usage
* Retuned lateral control to be more aggressive when model is confident * Re-tuned lateral control to be more aggressive when model is confident
* Toyota Mirai 2021 support * Toyota Mirai 2021 support
* Lexus NX 300 2020 support thanks to goesreallyfast! * Lexus NX 300 2020 support thanks to goesreallyfast!
* Volkswagen Atlas 2018-19 support thanks to jyoung8607! * Volkswagen Atlas 2018-19 support thanks to jyoung8607!
@ -373,7 +389,7 @@ Version 0.7 (2019-12-13)
* Improve GM longitudinal control: proper computations for 15Hz radar * Improve GM longitudinal control: proper computations for 15Hz radar
* Move GM port, Toyota with DSU removed, comma pedal in community features; toggle switch required * Move GM port, Toyota with DSU removed, comma pedal in community features; toggle switch required
* Remove upload over cellular toggle: only upload qlog and qcamera files if not on wifi * Remove upload over cellular toggle: only upload qlog and qcamera files if not on wifi
* Refactor Panda code towards ISO26262 and SIL2 compliancy * Refactor Panda code towards ISO26262 and SIL2 compliance
* Forward stock FCW for Honda Nidec * Forward stock FCW for Honda Nidec
* Volkswagen port now standard: comma Harness intercepts stock camera * Volkswagen port now standard: comma Harness intercepts stock camera

@ -10,10 +10,6 @@ AGNOS = TICI
Decider('MD5-timestamp') Decider('MD5-timestamp')
AddOption('--test',
action='store_true',
help='build test files')
AddOption('--extras', AddOption('--extras',
action='store_true', action='store_true',
help='build misc extras, like setup and installer files') help='build misc extras, like setup and installer files')
@ -53,6 +49,17 @@ AddOption('--no-thneed',
dest='no_thneed', dest='no_thneed',
help='avoid using thneed') help='avoid using thneed')
AddOption('--pc-thneed',
action='store_true',
dest='pc_thneed',
help='use thneed on pc')
AddOption('--no-test',
action='store_false',
dest='test',
default=os.path.islink(Dir('#laika/').abspath),
help='skip building test files')
real_arch = arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip() real_arch = arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip()
if platform.system() == "Darwin": if platform.system() == "Darwin":
arch = "Darwin" arch = "Darwin"
@ -60,7 +67,6 @@ if platform.system() == "Darwin":
if arch == "aarch64" and AGNOS: if arch == "aarch64" and AGNOS:
arch = "larch64" arch = "larch64"
USE_WEBCAM = os.getenv("USE_WEBCAM") is not None
lenv = { lenv = {
"PATH": os.environ['PATH'], "PATH": os.environ['PATH'],
@ -69,7 +75,7 @@ lenv = {
"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("#pyextra/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"
} }
rpath = lenv["LD_LIBRARY_PATH"].copy() rpath = lenv["LD_LIBRARY_PATH"].copy()
@ -106,6 +112,9 @@ else:
# MacOS # MacOS
if arch == "Darwin": if arch == "Darwin":
if real_arch == "x86_64":
lenv["TERA_PATH"] = Dir("#").abspath + f"/third_party/acados/Darwin_x86_64/t_renderer"
brew_prefix = subprocess.check_output(['brew', '--prefix'], encoding='utf8').strip() brew_prefix = subprocess.check_output(['brew', '--prefix'], encoding='utf8').strip()
yuv_dir = "mac" if real_arch != "arm64" else "mac_arm64" yuv_dir = "mac" if real_arch != "arm64" else "mac_arm64"
libpath = [ libpath = [
@ -114,9 +123,13 @@ else:
f"{brew_prefix}/Library", f"{brew_prefix}/Library",
f"{brew_prefix}/opt/openssl/lib", f"{brew_prefix}/opt/openssl/lib",
f"{brew_prefix}/Cellar", f"{brew_prefix}/Cellar",
f"#third_party/acados/{arch}/lib",
"/System/Library/Frameworks/OpenGL.framework/Libraries", "/System/Library/Frameworks/OpenGL.framework/Libraries",
] ]
if real_arch == "x86_64":
libpath.append(f"#third_party/acados/Darwin_x86_64/lib")
else:
libpath.append(f"#third_party/acados/{arch}/lib")
cflags += ["-DGL_SILENCE_DEPRECATION"] cflags += ["-DGL_SILENCE_DEPRECATION"]
cxxflags += ["-DGL_SILENCE_DEPRECATION"] cxxflags += ["-DGL_SILENCE_DEPRECATION"]
cpppath += [ cpppath += [
@ -253,7 +266,7 @@ def abspath(x):
# rpath works elsewhere # rpath works elsewhere
return x[0].path.rsplit("/", 1)[1][:-3] return x[0].path.rsplit("/", 1)[1][:-3]
# Cython build enviroment # Cython build environment
py_include = sysconfig.get_paths()['include'] py_include = sysconfig.get_paths()['include']
envCython = env.Clone() envCython = env.Clone()
envCython["CPPPATH"] += [py_include, np.get_include()] envCython["CPPPATH"] += [py_include, np.get_include()]
@ -329,7 +342,7 @@ if GetOption("clazy"):
qt_env['ENV']['CLAZY_IGNORE_DIRS'] = qt_dirs[0] qt_env['ENV']['CLAZY_IGNORE_DIRS'] = qt_dirs[0]
qt_env['ENV']['CLAZY_CHECKS'] = ','.join(checks) qt_env['ENV']['CLAZY_CHECKS'] = ','.join(checks)
Export('env', 'qt_env', 'arch', 'real_arch', 'SHARED', 'USE_WEBCAM') Export('env', 'qt_env', 'arch', 'real_arch', 'SHARED')
SConscript(['common/SConscript']) SConscript(['common/SConscript'])
Import('_common', '_gpucommon') Import('_common', '_gpucommon')

@ -1 +1 @@
Subproject commit 5ab19700178f01c14f362735532ee2662ab755fc Subproject commit cea51afd67b5c56f7a18207ef91c5e45d6345526

@ -78,7 +78,8 @@ cl_program cl_program_from_file(cl_context ctx, cl_device_id device_id, const ch
} }
cl_program cl_program_from_source(cl_context ctx, cl_device_id device_id, const std::string& src, const char* args) { cl_program cl_program_from_source(cl_context ctx, cl_device_id device_id, const std::string& src, const char* args) {
cl_program prg = CL_CHECK_ERR(clCreateProgramWithSource(ctx, 1, (const char*[]){src.c_str()}, NULL, &err)); const char *csrc = src.c_str();
cl_program prg = CL_CHECK_ERR(clCreateProgramWithSource(ctx, 1, &csrc, NULL, &err));
if (int err = clBuildProgram(prg, 1, &device_id, args, NULL, NULL); err != 0) { if (int err = clBuildProgram(prg, 1, &device_id, args, NULL, NULL); err != 0) {
cl_print_build_errors(prg, device_id); cl_print_build_errors(prg, device_id);
assert(0); assert(0);
@ -87,7 +88,7 @@ cl_program cl_program_from_source(cl_context ctx, cl_device_id device_id, const
} }
cl_program cl_program_from_binary(cl_context ctx, cl_device_id device_id, const uint8_t* binary, size_t length, const char* args) { cl_program cl_program_from_binary(cl_context ctx, cl_device_id device_id, const uint8_t* binary, size_t length, const char* args) {
cl_program prg = CL_CHECK_ERR(clCreateProgramWithBinary(ctx, 1, &device_id, &length, (const uint8_t*[]){binary}, NULL, &err)); cl_program prg = CL_CHECK_ERR(clCreateProgramWithBinary(ctx, 1, &device_id, &length, &binary, NULL, &err));
if (int err = clBuildProgram(prg, 1, &device_id, args, NULL, NULL); err != 0) { if (int err = clBuildProgram(prg, 1, &device_id, args, NULL, NULL); err != 0) {
cl_print_build_errors(prg, device_id); cl_print_build_errors(prg, device_id);
assert(0); assert(0);

@ -1,3 +1,5 @@
from typing import Optional
def gpio_init(pin: int, output: bool) -> None: def gpio_init(pin: int, output: bool) -> None:
try: try:
with open(f"/sys/class/gpio/gpio{pin}/direction", 'wb') as f: with open(f"/sys/class/gpio/gpio{pin}/direction", 'wb') as f:
@ -5,10 +7,19 @@ def gpio_init(pin: int, output: bool) -> None:
except Exception as e: except Exception as e:
print(f"Failed to set gpio {pin} direction: {e}") print(f"Failed to set gpio {pin} direction: {e}")
def gpio_set(pin: int, high: bool) -> None: def gpio_set(pin: int, high: bool) -> None:
try: try:
with open(f"/sys/class/gpio/gpio{pin}/value", 'wb') as f: with open(f"/sys/class/gpio/gpio{pin}/value", 'wb') as f:
f.write(b"1" if high else b"0") f.write(b"1" if high else b"0")
except Exception as e: except Exception as e:
print(f"Failed to set gpio {pin} value: {e}") print(f"Failed to set gpio {pin} value: {e}")
def gpio_read(pin: int) -> Optional[bool]:
val = None
try:
with open(f"/sys/class/gpio/gpio{pin}/value", 'rb') as f:
val = bool(int(f.read().strip()))
except Exception as e:
print(f"Failed to set gpio {pin} value: {e}")
return val

@ -84,9 +84,12 @@ private:
std::unordered_map<std::string, uint32_t> keys = { std::unordered_map<std::string, uint32_t> keys = {
{"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG}, {"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG},
{"AssistNowToken", PERSISTENT},
{"AthenadPid", PERSISTENT}, {"AthenadPid", PERSISTENT},
{"AthenadUploadQueue", PERSISTENT}, {"AthenadUploadQueue", PERSISTENT},
{"CalibrationParams", PERSISTENT}, {"CalibrationParams", PERSISTENT},
{"CameraDebugExpGain", CLEAR_ON_MANAGER_START},
{"CameraDebugExpTime", CLEAR_ON_MANAGER_START},
{"CarBatteryCapacity", PERSISTENT}, {"CarBatteryCapacity", PERSISTENT},
{"CarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"CarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
{"CarParamsCache", CLEAR_ON_MANAGER_START}, {"CarParamsCache", CLEAR_ON_MANAGER_START},
@ -97,6 +100,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"DashcamOverride", PERSISTENT}, {"DashcamOverride", PERSISTENT},
{"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
{"DisablePowerDown", PERSISTENT}, {"DisablePowerDown", PERSISTENT},
{"EndToEndLong", PERSISTENT},
{"DisableRadar_Allow", PERSISTENT}, {"DisableRadar_Allow", PERSISTENT},
{"DisableRadar", PERSISTENT}, // WARNING: THIS DISABLES AEB {"DisableRadar", PERSISTENT}, // WARNING: THIS DISABLES AEB
{"DisableUpdates", PERSISTENT}, {"DisableUpdates", PERSISTENT},
@ -151,6 +155,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"RecordFront", PERSISTENT}, {"RecordFront", PERSISTENT},
{"RecordFrontLock", PERSISTENT}, // for the internal fleet {"RecordFrontLock", PERSISTENT}, // for the internal fleet
{"ReleaseNotes", PERSISTENT}, {"ReleaseNotes", PERSISTENT},
{"ReplayControlsState", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
{"ShouldDoUpdate", CLEAR_ON_MANAGER_START}, {"ShouldDoUpdate", CLEAR_ON_MANAGER_START},
{"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF}, {"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF},
{"SshEnabled", PERSISTENT}, {"SshEnabled", PERSISTENT},

@ -90,7 +90,7 @@ cdef class Params:
with nogil: with nogil:
self.p.putBool(k, val) self.p.putBool(k, val)
def delete(self, key): def remove(self, key):
cdef string k = self.check_key(key) cdef string k = self.check_key(key)
with nogil: with nogil:
self.p.remove(k) self.p.remove(k)

@ -59,13 +59,13 @@ class TestParams(unittest.TestCase):
with self.assertRaises(UnknownKeyName): with self.assertRaises(UnknownKeyName):
self.params.put_bool("swag", True) self.params.put_bool("swag", True)
def test_delete_not_there(self): def test_remove_not_there(self):
assert self.params.get("CarParams") is None assert self.params.get("CarParams") is None
self.params.delete("CarParams") self.params.remove("CarParams")
assert self.params.get("CarParams") is None assert self.params.get("CarParams") is None
def test_get_bool(self): def test_get_bool(self):
self.params.delete("IsMetric") self.params.remove("IsMetric")
self.assertFalse(self.params.get_bool("IsMetric")) self.assertFalse(self.params.get_bool("IsMetric"))
self.params.put_bool("IsMetric", True) self.params.put_bool("IsMetric", True)

@ -136,7 +136,7 @@ TEST_CASE("util::create_directories") {
REQUIRE(util::create_directories(dir + "/file", 0755) == false); REQUIRE(util::create_directories(dir + "/file", 0755) == false);
REQUIRE(util::create_directories(dir + "/file/1/2/3", 0755) == false); REQUIRE(util::create_directories(dir + "/file/1/2/3", 0755) == false);
} }
SECTION("end with slashs") { SECTION("end with slashes") {
REQUIRE(util::create_directories(dir + "/", 0755)); REQUIRE(util::create_directories(dir + "/", 0755));
} }
SECTION("empty") { SECTION("empty") {

@ -1 +1 @@
#define COMMA_VERSION "0.8.16" #define COMMA_VERSION "0.8.17"

@ -2,228 +2,217 @@
# Supported Cars # Supported Cars
A supported vehicle is one that just works when you install a comma device. Every car performs differently with openpilot, but all supported cars should 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.
## How We Rate The Cars # 205 Supported Cars
### Stop and Go |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|
- [![star](assets/icon-star-full.svg)](##) - openpilot operates down to 0 mph. |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|
- [![star](assets/icon-star-empty.svg)](##) - openpilot operates only above a minimum speed. See your car's manual for the minimum speed. |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|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|
### Steer to 0 |Acura|RDX 2019-22|All|Stock|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
- [![star](assets/icon-star-full.svg)](##) - openpilot can control the steering wheel down to 0 mph. |Audi|A3 2014-19|ACC + Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
- [![star](assets/icon-star-empty.svg)](##) - No steering control below certain speeds. See your car's manual for the minimum speed. |Audi|A3 Sportback e-tron 2017-18|ACC + Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Audi|Q2 2018|ACC + Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
### Steering Torque |Audi|Q3 2020-21|ACC + Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
- [![star](assets/icon-star-full.svg)](##) - Car has enough steering torque to comfortably take most highway turns. |Audi|RS3 2018|ACC + Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
- [![star](assets/icon-star-empty.svg)](##) - Limited ability to make tighter turns. |Audi|S3 2015-17|ACC + Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Cadillac|Escalade ESV 2016[<sup>1</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|
|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|Stock|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|
# 201 Supported Cars |Chevrolet|Silverado 1500 2020-21|Safety Package II|Stock|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|
|Chevrolet|Volt 2017-18[<sup>1</sup>](#footnotes)|Adaptive Cruise Control|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|
|Make|Model|Supported Package|openpilot ACC|Stop and Go|Steer to 0|Steering Torque| |Chrysler|Pacifica 2017-18|Adaptive Cruise Control|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|---|---|---|:---:|:---:|:---:|:---:| |Chrysler|Pacifica 2019-20|Adaptive Cruise Control|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|Acura|ILX 2016-19|AcuraWatch Plus|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|Acura|RDX 2016-18|AcuraWatch Plus|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|Acura|RDX 2019-22|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Chrysler|Pacifica Hybrid 2019-22|Adaptive Cruise Control|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|Audi|A3 2014-19|ACC + Lane Assist|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |comma|body|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None|
|Audi|A3 Sportback e-tron 2017-18|ACC + Lane Assist|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|
|Audi|Q2 2018|ACC + Lane Assist|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Genesis|G70 2020|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|
|Audi|Q3 2020-21|ACC + Lane Assist|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Genesis|G80 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
|Audi|RS3 2018|ACC + Lane Assist|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Genesis|G90 2017-18|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|
|Audi|S3 2015-17|ACC + Lane Assist|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |GMC|Acadia 2018[<sup>1</sup>](#footnotes)|Adaptive Cruise Control|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|
|Cadillac|Escalade ESV 2016[<sup>1</sup>](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |GMC|Sierra 1500 2020-21|Driver Alert Package II|Stock|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|
|Chevrolet|Bolt EUV 2022-23|Premier/Premier Redline Trim|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Honda|Accord 2018-22|All|Stock|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
|Chevrolet|Volt 2017-18[<sup>1</sup>](#footnotes)|Adaptive Cruise Control|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Honda|Accord Hybrid 2018-22|All|Stock|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|
|Chrysler|Pacifica 2019-20|Adaptive Cruise Control|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Honda|Civic 2019-21|All|Stock|0 mph|2 mph[<sup>2</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
|Chrysler|Pacifica 2021|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Honda|Civic 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch B|
|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Honda|Civic Hatchback 2017-21|Honda Sensing|Stock|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
|Chrysler|Pacifica Hybrid 2019-22|Adaptive Cruise Control|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|
|comma|body|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|
|Genesis|G70 2018-19|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Honda|CR-V 2017-22|Honda Sensing|Stock|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
|Genesis|G70 2020|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Honda|CR-V Hybrid 2017-19|Honda Sensing|Stock|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
|Genesis|G80 2017-19|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Honda|e 2020|All|Stock|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
|Genesis|G90 2017-18|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|
|GMC|Acadia 2018[<sup>1</sup>](#footnotes)|Adaptive Cruise Control|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|Accord 2018-22|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |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|Accord Hybrid 2018-22|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Honda|Insight 2019-22|All|Stock|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
|Honda|Civic 2016-18|Honda Sensing|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Honda|Inspire 2018|All|Stock|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
|Honda|Civic 2019-21|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)[<sup>2</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)| |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|Civic 2022|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|Civic Hatchback 2017-21|Honda Sensing|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |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|Civic Hatchback 2022|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|CR-V 2015-16|Touring Trim|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Hyundai|Elantra 2017-19|Smart Cruise Control (SCC) & LKAS|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|
|Honda|CR-V 2017-22|Honda Sensing|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Hyundai|Elantra 2021-22|Smart Cruise Control (SCC) & LKAS|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|
|Honda|CR-V Hybrid 2017-19|Honda Sensing|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Hyundai|Elantra Hybrid 2021-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|
|Honda|e 2020|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Hyundai|Genesis 2015-16|Smart Cruise Control (SCC) & LKAS|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai J|
|Honda|Fit 2018-20|Honda Sensing|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Hyundai|Ioniq 5 2022|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q|
|Honda|Freed 2020|Honda Sensing|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC) & LKAS|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|
|Honda|HR-V 2019-22|Honda Sensing|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Hyundai|Ioniq Electric 2020|Smart Cruise Control (SCC) & LKAS|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
|Honda|Insight 2019-22|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC) & LKAS|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|
|Honda|Inspire 2018|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC) & LFA|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
|Honda|Odyssey 2018-20|Honda Sensing|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC) & LKAS|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|
|Honda|Passport 2019-21|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Hyundai|Ioniq Plug-in Hybrid 2020-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
|Honda|Pilot 2016-22|Honda Sensing|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Hyundai|Kona 2020|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|
|Honda|Ridgeline 2017-22|Honda Sensing|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC) & LKAS|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G|
|Hyundai|Elantra 2017-19|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|Elantra 2021-22|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC) & LKAS|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai I|
|Hyundai|Elantra Hybrid 2021-22|Smart Cruise Control (SCC)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Hyundai|Palisade 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Hyundai|Santa Fe 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai D|
|Hyundai|Ioniq 5 2022|Highway Driving Assist II|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Hyundai|Santa Fe 2021-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|
|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Hyundai|Santa Fe Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|
|Hyundai|Ioniq Electric 2020|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Hyundai|Santa Fe Plug-in Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|
|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Hyundai|Sonata 2018-19|Smart Cruise Control (SCC) & LKAS|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|
|Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC) & LFA|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Hyundai|Sonata 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|
|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Hyundai|Sonata Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|
|Hyundai|Ioniq Plug-in Hybrid 2020-21|Smart Cruise Control (SCC)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Hyundai|Tucson 2021|Smart Cruise Control (SCC)|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|
|Hyundai|Kona 2020|Smart Cruise Control (SCC)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|
|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Hyundai|Tucson Hybrid 2022|All|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)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|Kona Hybrid 2020|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|Hyundai|Palisade 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
|Hyundai|Santa Fe 2019-20|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Ceed 2019|Smart Cruise Control (SCC) & LKAS|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|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|EV6 2022|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai P|
|Hyundai|Santa Fe Hybrid 2022|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Forte 2018|Smart Cruise Control (SCC) & LKAS|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|
|Hyundai|Santa Fe Plug-in Hybrid 2022|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Forte 2019-21|Smart Cruise Control (SCC) & LKAS|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G|
|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|K5 2021-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|
|Hyundai|Sonata 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Niro Electric 2019|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
|Hyundai|Sonata Hybrid 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Niro Electric 2020|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|
|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Niro Electric 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|
|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Niro Electric 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Niro Hybrid 2021|Smart Cruise Control (SCC) & LKAS|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Niro Hybrid 2022|Smart Cruise Control (SCC) & LKAS|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Niro Plug-in Hybrid 2018-19|Smart Cruise Control (SCC) & LKAS|openpilot|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|
|Kia|Ceed 2019|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Optima 2017|Smart Cruise Control (SCC) & LKAS|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|
|Kia|EV6 2022|Highway Driving Assist II|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Optima 2019|Smart Cruise Control (SCC) & LKAS|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G|
|Kia|Forte 2018|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Seltos 2021|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|
|Kia|Forte 2019-21|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Sorento 2018|Smart Cruise Control (SCC) & LKAS|Stock|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)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Sorento 2019|Smart Cruise Control (SCC) & LKAS|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|
|Kia|Niro Electric 2019|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Stinger 2018-20|Smart Cruise Control (SCC) & LKAS|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|
|Kia|Niro Electric 2020|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Telluride 2020|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
|Kia|Niro Electric 2021|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|CT Hybrid 2017-18|Lexus Safety System+|Stock[<sup>3</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Kia|Niro Electric 2022|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Kia|Niro Hybrid 2021|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|ES Hybrid 2017-18|Lexus Safety System+|Stock[<sup>3</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Kia|Niro Hybrid 2022|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|Niro Plug-in Hybrid 2018-19|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Kia|Optima 2017|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|NX 2018-19|All|Stock[<sup>3</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Kia|Optima 2019|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Kia|Seltos 2021|Smart Cruise Control (SCC)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|NX Hybrid 2018-19|All|Stock[<sup>3</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Kia|Sorento 2018|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Kia|Sorento 2019|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|RC 2017-20|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) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|RX 2016-19|All|Stock[<sup>3</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Kia|Telluride 2020|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Lexus|CT Hybrid 2017-18|Lexus Safety System+|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|RX Hybrid 2016-19|All|Stock[<sup>3</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Lexus|ES 2019-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|ES Hybrid 2017-18|Lexus Safety System+|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|ES Hybrid 2019-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Mazda|CX-5 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda|
|Lexus|IS 2017-19|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Mazda|CX-9 2021-22|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda|
|Lexus|NX 2018-19|All|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|NX 2020-21|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|NX Hybrid 2018-19|All|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|NX Hybrid 2020-21|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|RC 2017-20|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Ram|1500 2019-22|Adaptive Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Ram|
|Lexus|RX 2016-19|All|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |SEAT|Ateca 2018|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Lexus|RX 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |SEAT|Leon 2014-20|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Lexus|RX Hybrid 2016-19|All|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|
|Lexus|RX Hybrid 2020-21|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|
|Lexus|UX Hybrid 2019-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Subaru|Crosstrek 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|
|Mazda|CX-5 2022|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Subaru|Forester 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|
|Mazda|CX-9 2021-22|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|Altima 2019-20|ProPILOT Assist|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|Leaf 2018-22|ProPILOT Assist|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Subaru|Legacy 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru B|
|Nissan|Rogue 2018-20|ProPILOT Assist|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru B|
|Nissan|X-Trail 2017|ProPILOT Assist|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|
|Ram|1500 2019-22|Adaptive Cruise Control|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|
|SEAT|Ateca 2018|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Škoda|Kamiq 2021[<sup>5</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|SEAT|Leon 2014-20|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Škoda|Karoq 2019-21[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Subaru|Ascent 2019-21|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Škoda|Kodiaq 2018-19|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Škoda|Octavia 2015, 2018-19|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Subaru|Crosstrek 2020-21|EyeSight Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Škoda|Octavia RS 2016|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Subaru|Forester 2019-21|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Škoda|Scala 2020|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Subaru|Impreza 2017-19|EyeSight Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Škoda|Superb 2015-18|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Subaru|Impreza 2020-22|EyeSight Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Subaru|Outback 2020-22|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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 2018-19|EyeSight Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Toyota|Avalon 2016|Toyota Safety Sense P|Stock[<sup>3</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Subaru|XV 2020-21|EyeSight Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Avalon 2017-18|All|Stock[<sup>3</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Škoda|Kamiq 2021[<sup>5</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Avalon 2019-21|All|Stock[<sup>3</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Škoda|Karoq 2019-21[<sup>7</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Škoda|Kodiaq 2018-19|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Avalon Hybrid 2019-21|All|Stock[<sup>3</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Škoda|Octavia 2015, 2018-19|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Škoda|Octavia RS 2016|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|Scala 2020|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|
|Škoda|Superb 2015-18|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Camry 2018-20|All|Stock|0 mph[<sup>4</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|Alphard 2019-20|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Camry 2021-22|All|openpilot|0 mph[<sup>4</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Toyota|Alphard Hybrid 2021|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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 2016|Toyota Safety Sense P|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Camry Hybrid 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Toyota|Avalon 2017-18|All|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Corolla 2017-19|All|Stock[<sup>3</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|Avalon 2019-21|All|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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 2022|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Corolla Cross (Non-US only) 2020-21|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Toyota|Avalon Hybrid 2019-21|All|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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|Avalon Hybrid 2022|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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 2017-21|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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-19|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Highlander 2017-19|All|Stock[<sup>3</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|Camry 2018-20|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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 2021-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Highlander Hybrid 2017-19|All|Stock[<sup>3</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|Camry Hybrid 2018-20|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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 2021-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Toyota|Corolla 2017-19|All|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Prius 2016|Toyota Safety Sense P|Stock[<sup>3</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|Corolla 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Prius 2017-20|All|Stock[<sup>3</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|Corolla Cross (Non-US only) 2020-21|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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 Hybrid (Non-US only) 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Prius Prime 2017-20|All|Stock[<sup>3</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|Corolla Hatchback 2019-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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 Hybrid 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Prius v 2017|Toyota Safety Sense P|Stock[<sup>3</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|Highlander 2017-19|All|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|RAV4 2016|Toyota Safety Sense P|Stock[<sup>3</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|Highlander 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|RAV4 2017-18|All|Stock[<sup>3</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|Highlander Hybrid 2017-19|All|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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 Hybrid 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|Mirai 2021|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|Stock[<sup>3</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|Prius 2016|Toyota Safety Sense P|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|RAV4 Hybrid 2017-18|All|Stock[<sup>3</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|Prius 2017-20|All|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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 2021-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |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 Prime 2017-20|All|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Sienna 2018-20|All|Stock[<sup>3</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|Prius Prime 2021-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Arteon 2018-22[<sup>7,8</sup>](#footnotes)|Driver Assistance|Stock|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|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Arteon eHybrid 2020-22[<sup>7,8</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Toyota|RAV4 2016|Toyota Safety Sense P|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Arteon R 2020-22[<sup>7,8</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Toyota|RAV4 2017-18|All|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Atlas 2018-23[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Toyota|RAV4 2019-21|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Atlas Cross Sport 2021-22[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Toyota|RAV4 2022|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|California 2021[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Caravelle 2020[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Toyota|RAV4 Hybrid 2017-18|All|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|CC 2018-22[<sup>7,8</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Toyota|RAV4 Hybrid 2019-21|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|e-Golf 2014-20|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Toyota|RAV4 Hybrid 2022|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Golf 2015-20[<sup>8</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Toyota|Sienna 2018-20|All|[![star](assets/icon-star-half.svg)](##)[<sup>3</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Golf Alltrack 2015-19|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Arteon 2018-22[<sup>7,8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Golf GTD 2015-20|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Arteon eHybrid 2020-22[<sup>7,8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Golf GTE 2015-20|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Arteon R 2020-22[<sup>7,8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Golf GTI 2015-21|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Atlas 2018-22[<sup>7</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Golf R 2015-19[<sup>8</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Atlas Cross Sport 2021-22[<sup>7</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Golf SportsVan 2015-20|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|California 2021[<sup>7</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Jetta 2018-22[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Caravelle 2020[<sup>7</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Jetta GLI 2021-22[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|CC 2018-22[<sup>7,8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Passat 2015-22[<sup>6,7,8</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|e-Golf 2014-20|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Passat Alltrack 2015-22[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf 2015-20[<sup>8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Passat GTE 2015-22[<sup>7,8</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf Alltrack 2015-19|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Polo 2020-22[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf GTD 2015-20|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Polo GTI 2020-22[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf GTE 2015-20|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|T-Cross 2021[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf GTI 2015-21|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|T-Roc 2021[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf R 2015-19[<sup>8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Taos 2022[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf SportsVan 2015-20|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Teramont 2018-22[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Jetta 2018-22[<sup>7</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Teramont Cross Sport 2021-22[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Jetta GLI 2021-22[<sup>7</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Teramont X 2021-22[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Passat 2015-22[<sup>6,7,8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Tiguan 2019-22[<sup>7</sup>](#footnotes)|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Passat Alltrack 2015-22[<sup>7</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Touran 2017|Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW|
|Volkswagen|Passat GTE 2015-22[<sup>7,8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Polo 2020-22[<sup>7</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Polo GTI 2020-22[<sup>7</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|T-Cross 2021[<sup>7</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|T-Roc 2021[<sup>7</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Taos 2022[<sup>7</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Teramont 2018-22[<sup>7</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Teramont Cross Sport 2021-22[<sup>7</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Teramont X 2021-22[<sup>7</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Tiguan 2019-22[<sup>7</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Touran 2017|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
<a id="footnotes"></a> <a id="footnotes"></a>
<sup>1</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>1</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 />
@ -241,13 +230,13 @@ Although they're not upstream, the community has openpilot running on other make
# Don't see your car here? # Don't see your car here?
**openpilot can support many more cars than it currently does.** There are a few reasons your car may not be supported. **openpilot can support many more cars than it currently does.** There are a few reasons your car may not be supported.
If your car doesn't fit into any of the incompatibility criteria here, then there's a good chance it can be supported! We're adding support for new cars all the time. We don't have a roadmap for car support, and in fact, most car support comes from users like you! If your car doesn't fit into any of the incompatibility criteria here, then there's a good chance it can be supported! We're adding support for new cars all the time. **We don't have a roadmap for car support**, and in fact, most car support comes from users like you!
### Which cars are able to be supported? ### Which cars are able to be supported?
openpilot uses the existing steering, gas, and brake interfaces in your car. If your car lacks any one of these interfaces, openpilot will not be able to control the car. If your car has any form of [LKAS](https://en.wikipedia.org/wiki/Automated_Lane_Keeping_Systems)/[LCA](https://en.wikipedia.org/wiki/Lane_centering) and [ACC](https://en.wikipedia.org/wiki/Adaptive_cruise_control), then it almost certainly has these interfaces. These interfaces generally started shipping on cars around 2016. openpilot uses the existing steering, gas, and brake interfaces in your car. If your car lacks any one of these interfaces, openpilot will not be able to control the car. If your car has [ACC](https://en.wikipedia.org/wiki/Adaptive_cruise_control) and any form of [LKAS](https://en.wikipedia.org/wiki/Automated_Lane_Keeping_Systems)/[LCA](https://en.wikipedia.org/wiki/Lane_centering), then it almost certainly has these interfaces. These features generally started shipping on cars around 2016. Note that manufacturers will often make their own [marketing terms](https://en.wikipedia.org/wiki/Adaptive_cruise_control#Vehicle_models_supporting_adaptive_cruise_control) for these features, such as Hyundai's "Smart Cruise Control" branding of Adaptive Cruise Control.
If your car has the following packages or features, then it's a good candidate for support. If it does not, then it's unlikely able to be supported. If your car has the following packages or features, then it's a good candidate for support.
| Make | Required Package/Features | | Make | Required Package/Features |
| ---- | ------------------------- | | ---- | ------------------------- |
@ -265,8 +254,9 @@ All the cars that openpilot supports use a [CAN bus](https://en.wikipedia.org/wi
### Toyota Security ### Toyota Security
Specific new Toyota models are shipping with a new message authentication method that openpilot does not yet support. openpilot does not yet support these Toyota models due to a new message authentication method.
So far, this list includes: [Vote](https://comma.ai/shop/products/vote) if you'd like to see openpilot support on these models.
* Toyota RAV4 Prime 2021+ * Toyota RAV4 Prime 2021+
* Toyota Sienna 2021+ * Toyota Sienna 2021+
* Toyota Venza 2021+ * Toyota Venza 2021+
@ -275,4 +265,4 @@ So far, this list includes:
* Toyota Corolla Cross 2022+ (only US model) * Toyota Corolla Cross 2022+ (only US model)
* Lexus NX 2022+ * Lexus NX 2022+
* Toyota bZ4x 2023+ * Toyota bZ4x 2023+
* Subaru Solterra 2023+ * Subaru Solterra 2023+

@ -72,8 +72,6 @@ modeld
:project: selfdrive_modeld_transforms :project: selfdrive_modeld_transforms
.. autodoxygenindex:: .. autodoxygenindex::
:project: selfdrive_modeld_models :project: selfdrive_modeld_models
.. autodoxygenindex::
:project: selfdrive_modeld_thneed
.. autodoxygenindex:: .. autodoxygenindex::
:project: selfdrive_modeld_runners :project: selfdrive_modeld_runners

@ -1 +1 @@
Subproject commit c6665ed11b8d8c998e46f8dbee30e70a7d451e5e Subproject commit 83d4cb9fd871a563f4a0af0102992c0b52c94310

@ -78,7 +78,7 @@ find . -name 'moc_*' -delete
find . -name '__pycache__' -delete find . -name '__pycache__' -delete
rm -rf panda/board panda/certs panda/crypto rm -rf panda/board panda/certs panda/crypto
rm -rf .sconsign.dblite Jenkinsfile release/ rm -rf .sconsign.dblite Jenkinsfile release/
rm selfdrive/modeld/models/supercombo.dlc rm selfdrive/modeld/models/supercombo.onnx
# Move back signed panda fw # Move back signed panda fw
mkdir -p panda/board/obj mkdir -p panda/board/obj

@ -90,8 +90,6 @@ selfdrive/boardd/boardd_api_impl.pyx
selfdrive/boardd/can_list_to_can_capnp.cc selfdrive/boardd/can_list_to_can_capnp.cc
selfdrive/boardd/panda.cc selfdrive/boardd/panda.cc
selfdrive/boardd/panda.h selfdrive/boardd/panda.h
selfdrive/boardd/pigeon.cc
selfdrive/boardd/pigeon.h
selfdrive/boardd/set_time.py selfdrive/boardd/set_time.py
selfdrive/boardd/pandad.py selfdrive/boardd/pandad.py
@ -175,7 +173,6 @@ selfdrive/controls/lib/alerts_offroad.json
selfdrive/controls/lib/desire_helper.py selfdrive/controls/lib/desire_helper.py
selfdrive/controls/lib/drive_helpers.py selfdrive/controls/lib/drive_helpers.py
selfdrive/controls/lib/events.py selfdrive/controls/lib/events.py
selfdrive/controls/lib/lane_planner.py
selfdrive/controls/lib/latcontrol_angle.py selfdrive/controls/lib/latcontrol_angle.py
selfdrive/controls/lib/latcontrol_indi.py selfdrive/controls/lib/latcontrol_indi.py
selfdrive/controls/lib/latcontrol_torque.py selfdrive/controls/lib/latcontrol_torque.py
@ -282,6 +279,7 @@ selfdrive/sensord/sensors_qcom2.cc
selfdrive/sensord/sensors/*.cc selfdrive/sensord/sensors/*.cc
selfdrive/sensord/sensors/*.h selfdrive/sensord/sensors/*.h
selfdrive/sensord/sensord selfdrive/sensord/sensord
selfdrive/sensord/pigeond.py
selfdrive/thermald/thermald.py selfdrive/thermald/thermald.py
selfdrive/thermald/power_monitoring.py selfdrive/thermald/power_monitoring.py
@ -353,7 +351,7 @@ selfdrive/modeld/models/driving.cc
selfdrive/modeld/models/driving.h selfdrive/modeld/models/driving.h
selfdrive/modeld/models/dmonitoring.cc selfdrive/modeld/models/dmonitoring.cc
selfdrive/modeld/models/dmonitoring.h selfdrive/modeld/models/dmonitoring.h
selfdrive/modeld/models/supercombo.dlc selfdrive/modeld/models/supercombo.onnx
selfdrive/modeld/models/dmonitoring_model_q.dlc selfdrive/modeld/models/dmonitoring_model_q.dlc
selfdrive/modeld/transforms/loadyuv.cc selfdrive/modeld/transforms/loadyuv.cc
@ -364,12 +362,11 @@ selfdrive/modeld/transforms/transform.h
selfdrive/modeld/transforms/transform.cl selfdrive/modeld/transforms/transform.cl
selfdrive/modeld/thneed/*.py selfdrive/modeld/thneed/*.py
selfdrive/modeld/thneed/thneed.* selfdrive/modeld/thneed/thneed.h
selfdrive/modeld/thneed/thneed_common.cc
selfdrive/modeld/thneed/thneed_qcom2.cc
selfdrive/modeld/thneed/serialize.cc selfdrive/modeld/thneed/serialize.cc
selfdrive/modeld/thneed/compile.cc
selfdrive/modeld/thneed/optimizer.cc
selfdrive/modeld/thneed/include/* selfdrive/modeld/thneed/include/*
selfdrive/modeld/thneed/kernels/*.cl
selfdrive/modeld/runners/snpemodel.cc selfdrive/modeld/runners/snpemodel.cc
selfdrive/modeld/runners/snpemodel.h selfdrive/modeld/runners/snpemodel.h
@ -513,6 +510,8 @@ opendbc/gm_global_a_powertrain_generated.dbc
opendbc/gm_global_a_object.dbc opendbc/gm_global_a_object.dbc
opendbc/gm_global_a_chassis.dbc opendbc/gm_global_a_chassis.dbc
opendbc/FORD_CADS.dbc
opendbc/ford_fusion_2018_adas.dbc
opendbc/ford_lincoln_base_pt.dbc opendbc/ford_lincoln_base_pt.dbc
opendbc/honda_accord_2018_can_generated.dbc opendbc/honda_accord_2018_can_generated.dbc
@ -532,7 +531,7 @@ opendbc/honda_insight_ex_2019_can_generated.dbc
opendbc/acura_ilx_2016_nidec.dbc opendbc/acura_ilx_2016_nidec.dbc
opendbc/honda_civic_ex_2022_can_generated.dbc opendbc/honda_civic_ex_2022_can_generated.dbc
opendbc/kia_ev6.dbc opendbc/hyundai_canfd.dbc
opendbc/hyundai_kia_generic.dbc opendbc/hyundai_kia_generic.dbc
opendbc/hyundai_kia_mando_front_radar.dbc opendbc/hyundai_kia_mando_front_radar.dbc
@ -552,8 +551,22 @@ opendbc/toyota_nodsu_pt_generated.dbc
opendbc/toyota_adas.dbc opendbc/toyota_adas.dbc
opendbc/toyota_tss2_adas.dbc opendbc/toyota_tss2_adas.dbc
opendbc/vw_golf_mk4.dbc
opendbc/vw_mqb_2010.dbc opendbc/vw_mqb_2010.dbc
opendbc/tesla_can.dbc 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/extra/onnx.py
tinygrad_repo/extra/utils.py
tinygrad_repo/tinygrad/llops/ops_gpu.py
tinygrad_repo/tinygrad/llops/ops_opencl.py
tinygrad_repo/tinygrad/helpers.py
tinygrad_repo/tinygrad/mlops.py
tinygrad_repo/tinygrad/ops.py
tinygrad_repo/tinygrad/shapetracker.py
tinygrad_repo/tinygrad/tensor.py
tinygrad_repo/tinygrad/nn/__init__.py

@ -11,5 +11,7 @@ system/camerad/cameras/camera_qcom2.cc
system/camerad/cameras/camera_qcom2.h system/camerad/cameras/camera_qcom2.h
system/camerad/cameras/real_debayer.cl system/camerad/cameras/real_debayer.cl
selfdrive/sensord/rawgps/*
selfdrive/ui/qt/spinner_larch64 selfdrive/ui/qt/spinner_larch64
selfdrive/ui/qt/text_larch64 selfdrive/ui/qt/text_larch64

@ -739,14 +739,14 @@ def main():
break break
except (ConnectionError, TimeoutError, WebSocketException): except (ConnectionError, TimeoutError, WebSocketException):
conn_retries += 1 conn_retries += 1
params.delete("LastAthenaPingTime") params.remove("LastAthenaPingTime")
except socket.timeout: except socket.timeout:
params.delete("LastAthenaPingTime") params.remove("LastAthenaPingTime")
except Exception: except Exception:
cloudlog.exception("athenad.main.exception") cloudlog.exception("athenad.main.exception")
conn_retries += 1 conn_retries += 1
params.delete("LastAthenaPingTime") params.remove("LastAthenaPingTime")
time.sleep(backoff(conn_retries)) time.sleep(backoff(conn_retries))

@ -27,7 +27,7 @@ def main():
except Exception: except Exception:
cloudlog.exception("manage_athenad.exception") cloudlog.exception("manage_athenad.exception")
finally: finally:
params.delete(ATHENA_MGR_PID_PARAM) params.remove(ATHENA_MGR_PID_PARAM)
if __name__ == '__main__': if __name__ == '__main__':

@ -116,7 +116,7 @@ def with_http_server(func):
with Timeout(2, 'HTTP Server seeding failed'): with Timeout(2, 'HTTP Server seeding failed'):
while True: while True:
try: try:
requests.put(f'http://{host}:{port}/qlog.bz2', data='') requests.put(f'http://{host}:{port}/qlog.bz2', data='', timeout=10)
break break
except requests.exceptions.ConnectionError: except requests.exceptions.ConnectionError:
time.sleep(0.1) time.sleep(0.1)

@ -1,7 +1,7 @@
Import('env', 'envCython', 'common', 'cereal', 'messaging') Import('env', 'envCython', 'common', 'cereal', 'messaging')
libs = ['usb-1.0', common, cereal, messaging, 'pthread', 'zmq', 'capnp', 'kj'] libs = ['usb-1.0', common, cereal, messaging, 'pthread', 'zmq', 'capnp', 'kj']
env.Program('boardd', ['main.cc', 'boardd.cc', 'panda.cc', 'pigeon.cc'], LIBS=libs) env.Program('boardd', ['main.cc', 'boardd.cc', 'panda.cc'], LIBS=libs)
env.Library('libcan_list_to_can_capnp', ['can_list_to_can_capnp.cc']) env.Library('libcan_list_to_can_capnp', ['can_list_to_can_capnp.cc'])
envCython.Program('boardd_api_impl.so', 'boardd_api_impl.pyx', LIBS=["can_list_to_can_capnp", 'capnp', 'kj'] + envCython["LIBS"]) envCython.Program('boardd_api_impl.so', 'boardd_api_impl.pyx', LIBS=["can_list_to_can_capnp", 'capnp', 'kj'] + envCython["LIBS"])

@ -29,14 +29,12 @@
#include "common/util.h" #include "common/util.h"
#include "system/hardware/hw.h" #include "system/hardware/hw.h"
#include "selfdrive/boardd/pigeon.h"
// -- Multi-panda conventions -- // -- Multi-panda conventions --
// Ordering: // Ordering:
// - The internal panda will always be the first panda // - The internal panda will always be the first panda
// - Consecutive pandas will be sorted based on panda type, and then serial number // - Consecutive pandas will be sorted based on panda type, and then serial number
// Connecting: // Connecting:
// - If a panda connection is dropped, boardd wil reconnect to all pandas // - If a panda connection is dropped, boardd will reconnect to all pandas
// - If a panda is added, we will only reconnect when we are offroad // - If a panda is added, we will only reconnect when we are offroad
// CAN buses: // CAN buses:
// - Each panda will have it's block of 4 buses. E.g.: the second panda will use // - Each panda will have it's block of 4 buses. E.g.: the second panda will use
@ -46,7 +44,7 @@
// Safety: // Safety:
// - SafetyConfig is a list, which is mapped to the connected pandas // - SafetyConfig is a list, which is mapped to the connected pandas
// - If there are more pandas connected than there are SafetyConfigs, // - If there are more pandas connected than there are SafetyConfigs,
// the excess pandas will remain in "silent" ot "noOutput" mode // the excess pandas will remain in "silent" or "noOutput" mode
// Ignition: // Ignition:
// - If any of the ignition sources in any panda is high, ignition is high // - If any of the ignition sources in any panda is high, ignition is high
@ -197,13 +195,7 @@ Panda *usb_connect(std::string serial="", uint32_t index=0) {
if (getenv("BOARDD_LOOPBACK")) { if (getenv("BOARDD_LOOPBACK")) {
panda->set_loopback(true); panda->set_loopback(true);
} }
panda->enable_deepsleep(); //panda->enable_deepsleep();
// power on charging, only the first time. Panda can also change mode and it causes a brief disconneciton
#ifndef __x86_64__
static std::once_flag connected_once;
std::call_once(connected_once, &Panda::set_usb_power_mode, panda, cereal::PeripheralState::UsbPowerMode::CDP);
#endif
sync_time(panda.get(), SyncTimeDir::FROM_PANDA); sync_time(panda.get(), SyncTimeDir::FROM_PANDA);
return panda.release(); return panda.release();
@ -372,6 +364,7 @@ std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *>
ps.setAlternativeExperience(health.alternative_experience_pkt); ps.setAlternativeExperience(health.alternative_experience_pkt);
ps.setHarnessStatus(cereal::PandaState::HarnessStatus(health.car_harness_status_pkt)); ps.setHarnessStatus(cereal::PandaState::HarnessStatus(health.car_harness_status_pkt));
ps.setInterruptLoad(health.interrupt_load); ps.setInterruptLoad(health.interrupt_load);
ps.setFanPower(health.fan_power);
// Convert faults bitset to capnp list // Convert faults bitset to capnp list
std::bitset<sizeof(health.faults_pkt) * 8> fault_bits(health.faults_pkt); std::bitset<sizeof(health.faults_pkt) * 8> fault_bits(health.faults_pkt);
@ -392,13 +385,6 @@ std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *>
} }
void send_peripheral_state(PubMaster *pm, Panda *panda) { void send_peripheral_state(PubMaster *pm, Panda *panda) {
auto pandaState_opt = panda->get_state();
if (!pandaState_opt) {
return;
}
health_t pandaState = *pandaState_opt;
// build msg // build msg
MessageBuilder msg; MessageBuilder msg;
auto evt = msg.initEvent(); auto evt = msg.initEvent();
@ -416,7 +402,6 @@ void send_peripheral_state(PubMaster *pm, Panda *panda) {
} }
uint16_t fan_speed_rpm = panda->get_fan_speed(); uint16_t fan_speed_rpm = panda->get_fan_speed();
ps.setUsbPowerMode(cereal::PeripheralState::UsbPowerMode(pandaState.usb_power_mode_pkt));
ps.setFanSpeedRpm(fan_speed_rpm); ps.setFanSpeedRpm(fan_speed_rpm);
pm->send("peripheralState", msg); pm->send("peripheralState", msg);
@ -492,7 +477,6 @@ void peripheral_control_thread(Panda *panda) {
uint16_t prev_fan_speed = 999; uint16_t prev_fan_speed = 999;
uint16_t ir_pwr = 0; uint16_t ir_pwr = 0;
uint16_t prev_ir_pwr = 999; uint16_t prev_ir_pwr = 999;
bool prev_charging_disabled = false;
unsigned int cnt = 0; unsigned int cnt = 0;
FirstOrderFilter integ_lines_filter(0, 30.0, 0.05); FirstOrderFilter integ_lines_filter(0, 30.0, 0.05);
@ -501,23 +485,9 @@ void peripheral_control_thread(Panda *panda) {
cnt++; cnt++;
sm.update(1000); // TODO: what happens if EINTR is sent while in sm.update? sm.update(1000); // TODO: what happens if EINTR is sent while in sm.update?
if (!Hardware::PC() && sm.updated("deviceState")) {
// Charging mode
bool charging_disabled = sm["deviceState"].getDeviceState().getChargingDisabled();
if (charging_disabled != prev_charging_disabled) {
if (charging_disabled) {
panda->set_usb_power_mode(cereal::PeripheralState::UsbPowerMode::CLIENT);
LOGW("TURN OFF CHARGING!\n");
} else {
panda->set_usb_power_mode(cereal::PeripheralState::UsbPowerMode::CDP);
LOGW("TURN ON CHARGING!\n");
}
prev_charging_disabled = charging_disabled;
}
}
// Other pandas don't have fan/IR to control // Other pandas don't have fan/IR to control
if (panda->hw_type != cereal::PandaState::PandaType::UNO && panda->hw_type != cereal::PandaState::PandaType::DOS) continue; if (panda->hw_type != cereal::PandaState::PandaType::UNO && panda->hw_type != cereal::PandaState::PandaType::DOS) continue;
if (sm.updated("deviceState")) { if (sm.updated("deviceState")) {
// Fan speed // Fan speed
uint16_t fan_speed = sm["deviceState"].getDeviceState().getFanSpeedPercentDesired(); uint16_t fan_speed = sm["deviceState"].getDeviceState().getFanSpeedPercentDesired();
@ -542,6 +512,7 @@ void peripheral_control_thread(Panda *panda) {
ir_pwr = 100.0 * (MIN_IR_POWER + ((cur_integ_lines - CUTOFF_IL) * (MAX_IR_POWER - MIN_IR_POWER) / (SATURATE_IL - CUTOFF_IL))); ir_pwr = 100.0 * (MIN_IR_POWER + ((cur_integ_lines - CUTOFF_IL) * (MAX_IR_POWER - MIN_IR_POWER) / (SATURATE_IL - CUTOFF_IL)));
} }
} }
// Disable ir_pwr on front frame timeout // Disable ir_pwr on front frame timeout
uint64_t cur_t = nanos_since_boot(); uint64_t cur_t = nanos_since_boot();
if (cur_t - last_front_frame_t > 1e9) { if (cur_t - last_front_frame_t > 1e9) {
@ -560,56 +531,6 @@ void peripheral_control_thread(Panda *panda) {
} }
} }
static void pigeon_publish_raw(PubMaster &pm, const std::string &dat) {
// create message
MessageBuilder msg;
msg.initEvent().setUbloxRaw(capnp::Data::Reader((uint8_t*)dat.data(), dat.length()));
pm.send("ubloxRaw", msg);
}
void pigeon_thread(Panda *panda) {
util::set_thread_name("boardd_pigeon");
PubMaster pm({"ubloxRaw"});
bool ignition_last = false;
std::unique_ptr<Pigeon> pigeon(Hardware::TICI() ? Pigeon::connect("/dev/ttyHS0") : Pigeon::connect(panda));
while (!do_exit && panda->connected) {
bool need_reset = false;
bool ignition_local = ignition;
std::string recv = pigeon->receive();
// Check based on null bytes
if (ignition_local && recv.length() > 0 && recv[0] == (char)0x00) {
need_reset = true;
LOGW("received invalid ublox message while onroad, resetting panda GPS");
}
if (recv.length() > 0) {
pigeon_publish_raw(pm, recv);
}
// init pigeon on rising ignition edge
// since it was turned off in low power mode
if((ignition_local && !ignition_last) || need_reset) {
pigeon_active = true;
pigeon->init();
} else if (!ignition_local && ignition_last) {
// power off on falling edge of ignition
LOGD("powering off pigeon\n");
pigeon->stop();
pigeon->set_power(false);
pigeon_active = false;
}
ignition_last = ignition_local;
// 10ms - 100 Hz
util::sleep_for(10);
}
}
void boardd_main_thread(std::vector<std::string> serials) { void boardd_main_thread(std::vector<std::string> serials) {
PubMaster pm({"pandaStates", "peripheralState"}); PubMaster pm({"pandaStates", "peripheralState"});
LOGW("attempting to connect"); LOGW("attempting to connect");
@ -648,7 +569,6 @@ void boardd_main_thread(std::vector<std::string> serials) {
threads.emplace_back(panda_state_thread, &pm, pandas, getenv("STARTED") != nullptr); threads.emplace_back(panda_state_thread, &pm, pandas, getenv("STARTED") != nullptr);
threads.emplace_back(peripheral_control_thread, peripheral_panda); threads.emplace_back(peripheral_control_thread, peripheral_panda);
threads.emplace_back(pigeon_thread, peripheral_panda);
threads.emplace_back(can_send_thread, pandas, getenv("FAKESEND") != nullptr); threads.emplace_back(can_send_thread, pandas, getenv("FAKESEND") != nullptr);
threads.emplace_back(can_recv_thread, pandas); threads.emplace_back(can_recv_thread, pandas);

@ -342,10 +342,6 @@ void Panda::enable_deepsleep() {
usb_write(0xfb, 0, 0); usb_write(0xfb, 0, 0);
} }
void Panda::set_usb_power_mode(cereal::PeripheralState::UsbPowerMode power_mode) {
usb_write(0xe6, (uint16_t)power_mode, 0);
}
void Panda::send_heartbeat(bool engaged) { void Panda::send_heartbeat(bool engaged) {
usb_write(0xf3, engaged, 0); usb_write(0xf3, engaged, 0);
} }

@ -86,7 +86,6 @@ class Panda {
std::optional<std::string> get_serial(); std::optional<std::string> get_serial();
void set_power_saving(bool power_saving); void set_power_saving(bool power_saving);
void enable_deepsleep(); void enable_deepsleep();
void set_usb_power_mode(cereal::PeripheralState::UsbPowerMode power_mode);
void send_heartbeat(bool engaged); void send_heartbeat(bool engaged);
void set_can_speed_kbps(uint16_t bus, uint16_t speed); void set_can_speed_kbps(uint16_t bus, uint16_t speed);
void set_data_speed_kbps(uint16_t bus, uint16_t speed); void set_data_speed_kbps(uint16_t bus, uint16_t speed);

@ -83,7 +83,7 @@ def main() -> NoReturn:
while True: while True:
try: try:
params.delete("PandaSignatures") params.remove("PandaSignatures")
# Flash all Pandas in DFU mode # Flash all Pandas in DFU mode
for p in PandaDFU.list(): for p in PandaDFU.list():

@ -1,333 +0,0 @@
#include "selfdrive/boardd/pigeon.h"
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <cassert>
#include <cerrno>
#include <optional>
#include "common/gpio.h"
#include "common/swaglog.h"
#include "common/util.h"
#include "selfdrive/locationd/ublox_msg.h"
// Termios on macos doesn't define all baud rate constants
#ifndef B460800
#define B460800 0010004
#endif
using namespace std::string_literals;
extern ExitHandler do_exit;
const std::string ack = "\xb5\x62\x05\x01\x02\x00";
const std::string nack = "\xb5\x62\x05\x00\x02\x00";
const std::string sos_save_ack = "\xb5\x62\x09\x14\x08\x00\x02\x00\x00\x00\x01\x00\x00\x00";
const std::string sos_save_nack = "\xb5\x62\x09\x14\x08\x00\x02\x00\x00\x00\x00\x00\x00\x00";
Pigeon * Pigeon::connect(Panda * p) {
PandaPigeon * pigeon = new PandaPigeon();
pigeon->connect(p);
return pigeon;
}
Pigeon * Pigeon::connect(const char * tty) {
TTYPigeon * pigeon = new TTYPigeon();
pigeon->connect(tty);
return pigeon;
}
bool Pigeon::wait_for_ack(const std::string &ack_, const std::string &nack_, int timeout_ms) {
std::string s;
const double start_t = millis_since_boot();
while (!do_exit) {
s += receive();
if (s.find(ack_) != std::string::npos) {
LOGD("Received ACK from ublox");
return true;
} else if (s.find(nack_) != std::string::npos) {
LOGE("Received NACK from ublox");
return false;
} else if (s.size() > 0x1000 || ((millis_since_boot() - start_t) > timeout_ms)) {
LOGE("No response from ublox");
return false;
}
util::sleep_for(1); // Allow other threads to be scheduled
}
return false;
}
bool Pigeon::wait_for_ack() {
return wait_for_ack(ack, nack);
}
bool Pigeon::send_with_ack(const std::string &cmd) {
send(cmd);
return wait_for_ack();
}
sos_restore_response Pigeon::wait_for_backup_restore_status(int timeout_ms) {
std::string s;
const double start_t = millis_since_boot();
while (!do_exit) {
s += receive();
size_t position = s.find("\xb5\x62\x09\x14\x08\x00\x03");
if (position != std::string::npos && s.size() >= (position + 11)) {
return static_cast<sos_restore_response>(s[position + 10]);
} else if (s.size() > 0x1000 || ((millis_since_boot() - start_t) > timeout_ms)) {
LOGE("No backup restore response from ublox");
return error;
}
util::sleep_for(1); // Allow other threads to be scheduled
}
return error;
}
void Pigeon::init() {
for (int i = 0; i < 10; i++) {
if (do_exit) return;
LOGW("panda GPS start");
// power off pigeon
set_power(false);
util::sleep_for(100);
// 9600 baud at init
set_baud(9600);
// power on pigeon
set_power(true);
util::sleep_for(500);
// baud rate upping
send("\x24\x50\x55\x42\x58\x2C\x34\x31\x2C\x31\x2C\x30\x30\x30\x37\x2C\x30\x30\x30\x33\x2C\x34\x36\x30\x38\x30\x30\x2C\x30\x2A\x31\x35\x0D\x0A"s);
util::sleep_for(100);
// set baud rate to 460800
set_baud(460800);
// init from ubloxd
// To generate this data, run selfdrive/locationd/test/ubloxd.py
if (!send_with_ack("\xB5\x62\x06\x00\x14\x00\x03\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x1E\x7F"s)) continue;
if (!send_with_ack("\xB5\x62\x06\x00\x14\x00\x00\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\x35"s)) continue;
if (!send_with_ack("\xB5\x62\x06\x00\x14\x00\x01\x00\x00\x00\xC0\x08\x00\x00\x00\x08\x07\x00\x01\x00\x01\x00\x00\x00\x00\x00\xF4\x80"s)) continue;
if (!send_with_ack("\xB5\x62\x06\x00\x14\x00\x04\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1D\x85"s)) continue;
if (!send_with_ack("\xB5\x62\x06\x00\x00\x00\x06\x18"s)) continue;
if (!send_with_ack("\xB5\x62\x06\x00\x01\x00\x01\x08\x22"s)) continue;
if (!send_with_ack("\xB5\x62\x06\x00\x01\x00\x03\x0A\x24"s)) continue;
if (!send_with_ack("\xB5\x62\x06\x08\x06\x00\x64\x00\x01\x00\x00\x00\x79\x10"s)) continue;
if (!send_with_ack("\xB5\x62\x06\x24\x24\x00\x05\x00\x04\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x5A\x63"s)) continue;
if (!send_with_ack("\xB5\x62\x06\x1E\x14\x00\x00\x00\x00\x00\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3C\x37"s)) continue;
if (!send_with_ack("\xB5\x62\x06\x39\x08\x00\xFF\xAD\x62\xAD\x1E\x63\x00\x00\x83\x0C"s)) continue;
if (!send_with_ack("\xB5\x62\x06\x24\x00\x00\x2A\x84"s)) continue;
if (!send_with_ack("\xB5\x62\x06\x23\x00\x00\x29\x81"s)) continue;
if (!send_with_ack("\xB5\x62\x06\x1E\x00\x00\x24\x72"s)) continue;
if (!send_with_ack("\xB5\x62\x06\x39\x00\x00\x3F\xC3"s)) continue;
if (!send_with_ack("\xB5\x62\x06\x01\x03\x00\x01\x07\x01\x13\x51"s)) continue;
if (!send_with_ack("\xB5\x62\x06\x01\x03\x00\x02\x15\x01\x22\x70"s)) continue;
if (!send_with_ack("\xB5\x62\x06\x01\x03\x00\x02\x13\x01\x20\x6C"s)) continue;
if (!send_with_ack("\xB5\x62\x06\x01\x03\x00\x0A\x09\x01\x1E\x70"s)) continue;
if (!send_with_ack("\xB5\x62\x06\x01\x03\x00\x0A\x0B\x01\x20\x74"s)) continue;
// check the backup restore status
send("\xB5\x62\x09\x14\x00\x00\x1D\x60"s);
sos_restore_response restore_status = wait_for_backup_restore_status();
switch(restore_status) {
case restored:
LOGW("almanac backup restored");
// clear the backup
send_with_ack("\xB5\x62\x06\x01\x03\x00\x0A\x0B\x01\x20\x74"s);
break;
case no_backup:
LOGW("no almanac backup found");
break;
default:
LOGE("failed to restore almanac backup, status: %d", restore_status);
}
auto time = util::get_time();
if (util::time_valid(time)) {
LOGW("Sending current time to ublox");
send(ublox::build_ubx_mga_ini_time_utc(time));
}
LOGW("panda GPS on");
return;
}
LOGE("failed to initialize panda GPS");
}
void Pigeon::stop() {
LOGW("Storing almanac in ublox flash");
// Controlled GNSS stop
send("\xB5\x62\x06\x04\x04\x00\x00\x00\x08\x00\x16\x74"s);
// Store almanac in flash
send("\xB5\x62\x09\x14\x04\x00\x00\x00\x00\x00\x21\xEC"s);
if (wait_for_ack(sos_save_ack, sos_save_nack)) {
LOGW("Done storing almanac");
} else {
LOGE("Error storing almanac");
}
}
void PandaPigeon::connect(Panda * p) {
panda = p;
}
void PandaPigeon::set_baud(int baud) {
panda->usb_write(0xe2, 1, 0);
panda->usb_write(0xe4, 1, baud/300);
}
void PandaPigeon::send(const std::string &s) {
int len = s.length();
const char * dat = s.data();
unsigned char a[0x20+1];
a[0] = 1;
for (int i=0; i<len; i+=0x20) {
int ll = std::min(0x20, len-i);
memcpy(&a[1], &dat[i], ll);
panda->usb_bulk_write(2, a, ll+1);
}
}
std::string PandaPigeon::receive() {
std::string r;
r.reserve(0x1000 + 0x40);
unsigned char dat[0x40];
while (r.length() < 0x1000) {
int len = panda->usb_read(0xe0, 1, 0, dat, sizeof(dat));
if (len <= 0) break;
r.append((char*)dat, len);
}
return r;
}
void PandaPigeon::set_power(bool power) {
panda->usb_write(0xd9, power, 0);
}
PandaPigeon::~PandaPigeon() {
}
void handle_tty_issue(int err, const char func[]) {
LOGE_100("tty error %d \"%s\" in %s", err, strerror(err), func);
}
void TTYPigeon::connect(const char * tty) {
pigeon_tty_fd = HANDLE_EINTR(open(tty, O_RDWR));
if (pigeon_tty_fd < 0) {
handle_tty_issue(errno, __func__);
assert(pigeon_tty_fd >= 0);
}
int err = tcgetattr(pigeon_tty_fd, &pigeon_tty);
assert(err == 0);
// configure tty
pigeon_tty.c_cflag &= ~PARENB; // disable parity
pigeon_tty.c_cflag &= ~CSTOPB; // single stop bit
pigeon_tty.c_cflag |= CS8; // 8 bits per byte
pigeon_tty.c_cflag &= ~CRTSCTS; // no RTS/CTS flow control
pigeon_tty.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
pigeon_tty.c_lflag &= ~ICANON; // disable canonical mode
pigeon_tty.c_lflag &= ~ISIG; // disable interpretation of INTR, QUIT and SUSP
pigeon_tty.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off software flow ctrl
pigeon_tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // disable any special handling of received bytes
pigeon_tty.c_oflag &= ~OPOST; // prevent special interpretation of output bytes
pigeon_tty.c_oflag &= ~ONLCR; // prevent conversion of newline to carriage return/line feed
// configure blocking behavior
pigeon_tty.c_cc[VMIN] = 0; // min amount of characters returned
pigeon_tty.c_cc[VTIME] = 0; // max blocking time in s/10 (0=inf)
err = tcsetattr(pigeon_tty_fd, TCSANOW, &pigeon_tty);
assert(err == 0);
}
void TTYPigeon::set_baud(int baud) {
speed_t baud_const = 0;
switch(baud) {
case 9600:
baud_const = B9600;
break;
case 460800:
baud_const = B460800;
break;
default:
assert(false);
}
// make sure everything is tx'ed before changing baud
int err = tcdrain(pigeon_tty_fd);
assert(err == 0);
// change baud
err = tcgetattr(pigeon_tty_fd, &pigeon_tty);
assert(err == 0);
err = cfsetspeed(&pigeon_tty, baud_const);
assert(err == 0);
err = tcsetattr(pigeon_tty_fd, TCSANOW, &pigeon_tty);
assert(err == 0);
// flush
err = tcflush(pigeon_tty_fd, TCIOFLUSH);
assert(err == 0);
}
void TTYPigeon::send(const std::string &s) {
int err = HANDLE_EINTR(write(pigeon_tty_fd, s.data(), s.length()));
if(err < 0) { handle_tty_issue(err, __func__); }
err = tcdrain(pigeon_tty_fd);
if(err < 0) { handle_tty_issue(err, __func__); }
}
std::string TTYPigeon::receive() {
std::string r;
r.reserve(0x1000 + 0x40);
char dat[0x40];
while (r.length() < 0x1000) {
int len = read(pigeon_tty_fd, dat, sizeof(dat));
if(len < 0) {
handle_tty_issue(len, __func__);
} else if (len == 0) {
break;
} else {
r.append(dat, len);
}
}
return r;
}
void TTYPigeon::set_power(bool power) {
#ifdef QCOM2
int err = 0;
err += gpio_init(GPIO_UBLOX_RST_N, true);
err += gpio_init(GPIO_UBLOX_SAFEBOOT_N, true);
err += gpio_init(GPIO_UBLOX_PWR_EN, true);
err += gpio_set(GPIO_UBLOX_RST_N, power);
err += gpio_set(GPIO_UBLOX_SAFEBOOT_N, power);
err += gpio_set(GPIO_UBLOX_PWR_EN, power);
assert(err == 0);
#endif
}
TTYPigeon::~TTYPigeon() {
close(pigeon_tty_fd);
}

@ -1,58 +0,0 @@
#pragma once
#include <termios.h>
#include <atomic>
#include <string>
#include "selfdrive/boardd/panda.h"
enum sos_restore_response : int {
unknown = 0,
failed = 1,
restored = 2,
no_backup = 3,
error = -1
};
class Pigeon {
public:
static Pigeon* connect(Panda * p);
static Pigeon* connect(const char * tty);
virtual ~Pigeon(){};
void init();
void stop();
bool wait_for_ack();
bool wait_for_ack(const std::string &ack, const std::string &nack, int timeout_ms = 1000);
bool send_with_ack(const std::string &cmd);
sos_restore_response wait_for_backup_restore_status(int timeout_ms = 1000);
virtual void set_baud(int baud) = 0;
virtual void send(const std::string &s) = 0;
virtual std::string receive() = 0;
virtual void set_power(bool power) = 0;
};
class PandaPigeon : public Pigeon {
Panda * panda = NULL;
public:
~PandaPigeon();
void connect(Panda * p);
void set_baud(int baud);
void send(const std::string &s);
std::string receive();
void set_power(bool power);
};
class TTYPigeon : public Pigeon {
int pigeon_tty_fd = -1;
struct termios pigeon_tty;
public:
~TTYPigeon();
void connect(const char* tty);
void set_baud(int baud);
void send(const std::string &s);
std::string receive();
void set_power(bool power);
};

@ -1,245 +0,0 @@
#!/usr/bin/env python3
# pylint: skip-file
# This file is not used by openpilot. Only boardd.cc is used.
# The python version is slower, but has more options for development.
# TODO: merge the extra functionalities of this file (like MOCK) in boardd.c and
# delete this python version of boardd
import os
import struct
import time
import cereal.messaging as messaging
from common.realtime import Ratekeeper
from system.swaglog import cloudlog
from selfdrive.boardd.boardd import can_capnp_to_can_list
from cereal import car
SafetyModel = car.CarParams.SafetyModel
# USB is optional
try:
import usb1
from usb1 import USBErrorIO, USBErrorOverflow # pylint: disable=no-name-in-module
except Exception:
pass
# *** serialization functions ***
def can_list_to_can_capnp(can_msgs, msgtype='can'):
dat = messaging.new_message(msgtype, len(can_msgs))
for i, can_msg in enumerate(can_msgs):
if msgtype == 'sendcan':
cc = dat.sendcan[i]
else:
cc = dat.can[i]
cc.address = can_msg[0]
cc.busTime = can_msg[1]
cc.dat = bytes(can_msg[2])
cc.src = can_msg[3]
return dat
# *** can driver ***
def can_health():
while 1:
try:
dat = handle.controlRead(usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE, 0xd2, 0, 0, 0x16)
break
except (USBErrorIO, USBErrorOverflow):
cloudlog.exception("CAN: BAD HEALTH, RETRYING")
v, i = struct.unpack("II", dat[0:8])
ign_line, ign_can = struct.unpack("BB", dat[20:22])
return {"voltage": v, "current": i, "ignition_line": bool(ign_line), "ignition_can": bool(ign_can)}
def __parse_can_buffer(dat):
ret = []
for j in range(0, len(dat), 0x10):
ddat = dat[j:j+0x10]
f1, f2 = struct.unpack("II", ddat[0:8])
ret.append((f1 >> 21, f2 >> 16, ddat[8:8 + (f2 & 0xF)], (f2 >> 4) & 0xFF))
return ret
def can_send_many(arr):
snds = []
for addr, _, dat, alt in arr:
if addr < 0x800: # only support 11 bit addr
snd = struct.pack("II", ((addr << 21) | 1), len(dat) | (alt << 4)) + dat
snd = snd.ljust(0x10, b'\x00')
snds.append(snd)
while 1:
try:
handle.bulkWrite(3, b''.join(snds))
break
except (USBErrorIO, USBErrorOverflow):
cloudlog.exception("CAN: BAD SEND MANY, RETRYING")
def can_recv():
dat = b""
while 1:
try:
dat = handle.bulkRead(1, 0x10*256)
break
except (USBErrorIO, USBErrorOverflow):
cloudlog.exception("CAN: BAD RECV, RETRYING")
return __parse_can_buffer(dat)
def can_init():
global handle, context
handle = None
cloudlog.info("attempting can init")
context = usb1.USBContext()
#context.setDebug(9)
for device in context.getDeviceList(skip_on_error=True):
if device.getVendorID() == 0xbbaa and device.getProductID() == 0xddcc:
handle = device.open()
handle.claimInterface(0)
handle.controlWrite(0x40, 0xdc, SafetyModel.allOutput, 0, b'')
if handle is None:
cloudlog.warning("CAN NOT FOUND")
exit(-1)
cloudlog.info("got handle")
cloudlog.info("can init done")
def boardd_mock_loop():
can_init()
handle.controlWrite(0x40, 0xdc, SafetyModel.allOutput, 0, b'')
logcan = messaging.sub_sock('can')
sendcan = messaging.pub_sock('sendcan')
while 1:
tsc = messaging.drain_sock(logcan, wait_for_one=True)
snds = map(lambda x: can_capnp_to_can_list(x.can), tsc)
snd = []
for s in snds:
snd += s
snd = list(filter(lambda x: x[-1] <= 2, snd))
snd_0 = len(list(filter(lambda x: x[-1] == 0, snd)))
snd_1 = len(list(filter(lambda x: x[-1] == 1, snd)))
snd_2 = len(list(filter(lambda x: x[-1] == 2, snd)))
can_send_many(snd)
# recv @ 100hz
can_msgs = can_recv()
got_0 = len(list(filter(lambda x: x[-1] == 0+0x80, can_msgs)))
got_1 = len(list(filter(lambda x: x[-1] == 1+0x80, can_msgs)))
got_2 = len(list(filter(lambda x: x[-1] == 2+0x80, can_msgs)))
print("sent %3d (%3d/%3d/%3d) got %3d (%3d/%3d/%3d)" %
(len(snd), snd_0, snd_1, snd_2, len(can_msgs), got_0, got_1, got_2))
m = can_list_to_can_capnp(can_msgs, msgtype='sendcan')
sendcan.send(m.to_bytes())
def boardd_test_loop():
can_init()
cnt = 0
while 1:
can_send_many([[0xbb, 0, "\xaa\xaa\xaa\xaa", 0], [0xaa, 0, "\xaa\xaa\xaa\xaa"+struct.pack("!I", cnt), 1]])
#can_send_many([[0xaa,0,"\xaa\xaa\xaa\xaa",0]])
#can_send_many([[0xaa,0,"\xaa\xaa\xaa\xaa",1]])
# recv @ 100hz
can_msgs = can_recv()
print("got %d" % (len(can_msgs)))
time.sleep(0.01)
cnt += 1
# *** main loop ***
def boardd_loop(rate=100):
rk = Ratekeeper(rate)
can_init()
# *** publishes can and health
logcan = messaging.pub_sock('can')
health_sock = messaging.pub_sock('pandaStates')
# *** subscribes to can send
sendcan = messaging.sub_sock('sendcan')
# drain sendcan to delete any stale messages from previous runs
messaging.drain_sock(sendcan)
while 1:
# health packet @ 2hz
if (rk.frame % (rate // 2)) == 0:
health = can_health()
msg = messaging.new_message('pandaStates', 1)
# store the health to be logged
msg.pandaState[0].voltage = health['voltage']
msg.pandaState[0].current = health['current']
msg.pandaState[0].ignitionLine = health['ignition_line']
msg.pandaState[0].ignitionCan = health['ignition_can']
msg.pandaState[0].controlsAllowed = True
health_sock.send(msg.to_bytes())
# recv @ 100hz
can_msgs = can_recv()
# publish to logger
# TODO: refactor for speed
if len(can_msgs) > 0:
dat = can_list_to_can_capnp(can_msgs).to_bytes()
logcan.send(dat)
# send can if we have a packet
tsc = messaging.recv_sock(sendcan)
if tsc is not None:
can_send_many(can_capnp_to_can_list(tsc.sendcan))
rk.keep_time()
# *** main loop ***
def boardd_proxy_loop(rate=100, address="192.168.2.251"):
rk = Ratekeeper(rate)
can_init()
# *** subscribes can
logcan = messaging.sub_sock('can', addr=address)
# *** publishes to can send
sendcan = messaging.pub_sock('sendcan')
# drain sendcan to delete any stale messages from previous runs
messaging.drain_sock(sendcan)
while 1:
# recv @ 100hz
can_msgs = can_recv()
#for m in can_msgs:
# print("R: {0} {1}".format(hex(m[0]), str(m[2]).encode("hex")))
# publish to logger
# TODO: refactor for speed
if len(can_msgs) > 0:
dat = can_list_to_can_capnp(can_msgs, "sendcan")
sendcan.send(dat)
# send can if we have a packet
tsc = messaging.recv_sock(logcan)
if tsc is not None:
cl = can_capnp_to_can_list(tsc.can)
#for m in cl:
# print("S: {0} {1}".format(hex(m[0]), str(m[2]).encode("hex")))
can_send_many(cl)
rk.keep_time()
def main():
if os.getenv("MOCK") is not None:
boardd_mock_loop()
elif os.getenv("PROXY") is not None:
boardd_proxy_loop()
elif os.getenv("BOARDTEST") is not None:
boardd_test_loop()
else:
boardd_loop()
if __name__ == "__main__":
main()

@ -1,83 +0,0 @@
#!/usr/bin/env python3
import os
import sys
import time
import signal
import traceback
import usb1
from panda import Panda, PandaDFU
from multiprocessing import Pool
jungle = "JUNGLE" in os.environ
if jungle:
from panda_jungle import PandaJungle # pylint: disable=import-error
import cereal.messaging as messaging
from selfdrive.boardd.boardd import can_capnp_to_can_list
def initializer():
"""Ignore CTRL+C in the worker process.
source: https://stackoverflow.com/a/44869451 """
signal.signal(signal.SIGINT, signal.SIG_IGN)
def send_thread(sender_serial):
while True:
try:
if jungle:
sender = PandaJungle(sender_serial)
else:
sender = Panda(sender_serial)
sender.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
sender.set_can_loopback(False)
can_sock = messaging.sub_sock('can')
while True:
tsc = messaging.recv_one(can_sock)
snd = can_capnp_to_can_list(tsc.can)
snd = list(filter(lambda x: x[-1] <= 2, snd))
try:
sender.can_send_many(snd)
except usb1.USBErrorTimeout:
pass
# Drain panda message buffer
sender.can_recv()
except Exception:
traceback.print_exc()
time.sleep(1)
if __name__ == "__main__":
if jungle:
serials = PandaJungle.list()
else:
serials = Panda.list()
num_senders = len(serials)
if num_senders == 0:
print("No senders found. Exiting")
sys.exit(1)
else:
print("%d senders found. Starting broadcast" % num_senders)
if "FLASH" in os.environ:
for s in PandaDFU.list():
PandaDFU(s).recover()
time.sleep(1)
for s in serials:
Panda(s).recover()
Panda(s).flash()
pool = Pool(num_senders, initializer=initializer)
pool.map_async(send_thread, serials)
while True:
try:
time.sleep(10)
except KeyboardInterrupt:
pool.terminate()
pool.join()
raise

@ -1,77 +0,0 @@
import random
import numpy as np
import selfdrive.boardd.tests.boardd_old as boardd_old
import selfdrive.boardd.boardd as boardd
from common.realtime import sec_since_boot
from cereal import log
import unittest
def generate_random_can_data_list():
can_list = []
cnt = random.randint(1, 64)
for _ in range(cnt):
can_data = np.random.bytes(random.randint(1, 8))
can_list.append([random.randint(0, 128), random.randint(0, 128), can_data, random.randint(0, 128)])
return can_list, cnt
class TestBoarddApiMethods(unittest.TestCase):
def test_correctness(self):
for i in range(1000):
can_list, _ = generate_random_can_data_list()
# Sendcan
# Old API
m_old = boardd_old.can_list_to_can_capnp(can_list, 'sendcan').to_bytes()
# new API
m = boardd.can_list_to_can_capnp(can_list, 'sendcan')
ev_old = log.Event.from_bytes(m_old)
ev = log.Event.from_bytes(m)
self.assertEqual(ev_old.which(), ev.which())
self.assertEqual(len(ev.sendcan), len(ev_old.sendcan))
for i in range(len(ev.sendcan)):
attrs = ['address', 'busTime', 'dat', 'src']
for attr in attrs:
self.assertEqual(getattr(ev.sendcan[i], attr, 'new'), getattr(ev_old.sendcan[i], attr, 'old'))
# Can
m_old = boardd_old.can_list_to_can_capnp(can_list, 'can').to_bytes()
# new API
m = boardd.can_list_to_can_capnp(can_list, 'can')
ev_old = log.Event.from_bytes(m_old)
ev = log.Event.from_bytes(m)
self.assertEqual(ev_old.which(), ev.which())
self.assertEqual(len(ev.can), len(ev_old.can))
for i in range(len(ev.can)):
attrs = ['address', 'busTime', 'dat', 'src']
for attr in attrs:
self.assertEqual(getattr(ev.can[i], attr, 'new'), getattr(ev_old.can[i], attr, 'old'))
def test_performance(self):
can_list, _ = generate_random_can_data_list()
recursions = 1000
n1 = sec_since_boot()
for _ in range(recursions):
boardd_old.can_list_to_can_capnp(can_list, 'sendcan').to_bytes()
n2 = sec_since_boot()
elapsed_old = n2 - n1
# print('Old API, elapsed time: {} secs'.format(elapsed_old))
n1 = sec_since_boot()
for _ in range(recursions):
boardd.can_list_to_can_capnp(can_list)
n2 = sec_since_boot()
elapsed_new = n2 - n1
# print('New API, elapsed time: {} secs'.format(elapsed_new))
self.assertTrue(elapsed_new < elapsed_old / 2)
if __name__ == '__main__':
unittest.main()

@ -5,24 +5,12 @@
# Supported Cars # Supported Cars
A supported vehicle is one that just works when you install a comma device. Every car performs differently with openpilot, but all supported cars should 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.
## How We Rate The Cars
{% for star_row in STAR_DESCRIPTIONS.values() %}
{% for name, stars in star_row.items() %}
### {{name}}
{% for star, description in stars %}
- {{star_icon.format(star)}} - {{description}}
{% endfor %}
{% endfor %}
{% endfor %}
# {{all_car_info | length}} Supported Cars # {{all_car_info | length}} Supported Cars
|{{Column | map(attribute='value') | join('|')}}| |{{Column | map(attribute='value') | join('|')}}|
|---|---|---|:---:|:---:|:---:|:---:| |---|---|---|{% 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, footnote_tag)}}|{% endfor %}
@ -39,13 +27,13 @@ Although they're not upstream, the community has openpilot running on other make
# Don't see your car here? # Don't see your car here?
**openpilot can support many more cars than it currently does.** There are a few reasons your car may not be supported. **openpilot can support many more cars than it currently does.** There are a few reasons your car may not be supported.
If your car doesn't fit into any of the incompatibility criteria here, then there's a good chance it can be supported! We're adding support for new cars all the time. We don't have a roadmap for car support, and in fact, most car support comes from users like you! If your car doesn't fit into any of the incompatibility criteria here, then there's a good chance it can be supported! We're adding support for new cars all the time. **We don't have a roadmap for car support**, and in fact, most car support comes from users like you!
### Which cars are able to be supported? ### Which cars are able to be supported?
openpilot uses the existing steering, gas, and brake interfaces in your car. If your car lacks any one of these interfaces, openpilot will not be able to control the car. If your car has any form of [LKAS](https://en.wikipedia.org/wiki/Automated_Lane_Keeping_Systems)/[LCA](https://en.wikipedia.org/wiki/Lane_centering) and [ACC](https://en.wikipedia.org/wiki/Adaptive_cruise_control), then it almost certainly has these interfaces. These interfaces generally started shipping on cars around 2016. openpilot uses the existing steering, gas, and brake interfaces in your car. If your car lacks any one of these interfaces, openpilot will not be able to control the car. If your car has [ACC](https://en.wikipedia.org/wiki/Adaptive_cruise_control) and any form of [LKAS](https://en.wikipedia.org/wiki/Automated_Lane_Keeping_Systems)/[LCA](https://en.wikipedia.org/wiki/Lane_centering), then it almost certainly has these interfaces. These features generally started shipping on cars around 2016. Note that manufacturers will often make their own [marketing terms](https://en.wikipedia.org/wiki/Adaptive_cruise_control#Vehicle_models_supporting_adaptive_cruise_control) for these features, such as Hyundai's "Smart Cruise Control" branding of Adaptive Cruise Control.
If your car has the following packages or features, then it's a good candidate for support. If it does not, then it's unlikely able to be supported. If your car has the following packages or features, then it's a good candidate for support.
| Make | Required Package/Features | | Make | Required Package/Features |
| ---- | ------------------------- | | ---- | ------------------------- |
@ -63,8 +51,9 @@ All the cars that openpilot supports use a [CAN bus](https://en.wikipedia.org/wi
### Toyota Security ### Toyota Security
Specific new Toyota models are shipping with a new message authentication method that openpilot does not yet support. openpilot does not yet support these Toyota models due to a new message authentication method.
So far, this list includes: [Vote](https://comma.ai/shop/products/vote) if you'd like to see openpilot support on these models.
* Toyota RAV4 Prime 2021+ * Toyota RAV4 Prime 2021+
* Toyota Sienna 2021+ * Toyota Sienna 2021+
* Toyota Venza 2021+ * Toyota Venza 2021+
@ -74,3 +63,4 @@ So far, this list includes:
* Lexus NX 2022+ * Lexus NX 2022+
* Toyota bZ4x 2023+ * Toyota bZ4x 2023+
* Subaru Solterra 2023+ * Subaru Solterra 2023+

@ -38,7 +38,7 @@ def create_button_enable_events(buttonEvents: capnp.lib.capnp._DynamicListBuilde
def gen_empty_fingerprint(): def gen_empty_fingerprint():
return {i: {} for i in range(0, 4)} return {i: {} for i in range(0, 8)}
# FIXME: hardcoding honda civic 2016 touring params so they can be used to # FIXME: hardcoding honda civic 2016 touring params so they can be used to

@ -2,7 +2,7 @@ from typing import Dict
from cereal import car from cereal import car
from selfdrive.car import dbc_dict from selfdrive.car import dbc_dict
from selfdrive.car.docs_definitions import CarInfo, Harness from selfdrive.car.docs_definitions import CarInfo
Ecu = car.CarParams.Ecu Ecu = car.CarParams.Ecu
SPEED_FROM_RPM = 0.008587 SPEED_FROM_RPM = 0.008587
@ -18,7 +18,7 @@ class CAR:
BODY = "COMMA BODY" BODY = "COMMA BODY"
CAR_INFO: Dict[str, CarInfo] = { CAR_INFO: Dict[str, CarInfo] = {
CAR.BODY: CarInfo("comma body", package="All", harness=Harness.none), CAR.BODY: CarInfo("comma body", package="All"),
} }
FW_VERSIONS = { FW_VERSIONS = {

@ -82,7 +82,7 @@ def fingerprint(logcan, sendcan):
ecu_rx_addrs = set() ecu_rx_addrs = set()
if not fixed_fingerprint and not skip_fw_query: if not fixed_fingerprint and not skip_fw_query:
# Vin query only reliably works thorugh OBDII # Vin query only reliably works through OBDII
bus = 1 bus = 1
cached_params = Params().get("CarParamsCache") cached_params = Params().get("CarParamsCache")

@ -22,23 +22,8 @@ class CarController:
def update(self, CC, CS): def update(self, CC, CS):
can_sends = [] can_sends = []
# TODO: can we make this more sane? why is it different for all the cars?
lkas_control_bit = self.lkas_control_bit_prev
if CS.out.vEgo > self.CP.minSteerSpeed:
lkas_control_bit = True
elif self.CP.carFingerprint in (CAR.PACIFICA_2019_HYBRID, CAR.PACIFICA_2020, CAR.JEEP_CHEROKEE_2019):
if CS.out.vEgo < (self.CP.minSteerSpeed - 3.0):
lkas_control_bit = False
elif self.CP.carFingerprint in RAM_CARS:
if CS.out.vEgo < (self.CP.minSteerSpeed - 0.5):
lkas_control_bit = False
# EPS faults if LKAS re-enables too quickly
lkas_control_bit = lkas_control_bit and (self.frame - self.last_lkas_falling_edge > 200)
lkas_active = CC.latActive and self.lkas_control_bit_prev lkas_active = CC.latActive and self.lkas_control_bit_prev
# *** control msgs ***
# cruise buttons # cruise buttons
if (self.frame - self.last_button_frame)*DT_CTRL > 0.05: if (self.frame - self.last_button_frame)*DT_CTRL > 0.05:
das_bus = 2 if self.CP.carFingerprint in RAM_CARS else 0 das_bus = 2 if self.CP.carFingerprint in RAM_CARS else 0
@ -61,19 +46,35 @@ class CarController:
# steering # steering
if self.frame % 2 == 0: if self.frame % 2 == 0:
# TODO: can we make this more sane? why is it different for all the cars?
lkas_control_bit = self.lkas_control_bit_prev
if CS.out.vEgo > self.CP.minSteerSpeed:
lkas_control_bit = True
elif self.CP.carFingerprint in (CAR.PACIFICA_2019_HYBRID, CAR.PACIFICA_2020, CAR.JEEP_CHEROKEE_2019):
if CS.out.vEgo < (self.CP.minSteerSpeed - 3.0):
lkas_control_bit = False
elif self.CP.carFingerprint in RAM_CARS:
if CS.out.vEgo < (self.CP.minSteerSpeed - 0.5):
lkas_control_bit = False
# EPS faults if LKAS re-enables too quickly
lkas_control_bit = lkas_control_bit and (self.frame - self.last_lkas_falling_edge > 200)
if not lkas_control_bit and self.lkas_control_bit_prev:
self.last_lkas_falling_edge = self.frame
self.lkas_control_bit_prev = lkas_control_bit
# 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_toyota_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorqueEps, self.params)
if not lkas_active: 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
can_sends.append(create_lkas_command(self.packer, self.CP, int(apply_steer), lkas_control_bit)) can_sends.append(create_lkas_command(self.packer, self.CP, int(apply_steer), lkas_control_bit))
self.frame += 1 self.frame += 1
if not lkas_control_bit and self.lkas_control_bit_prev:
self.last_lkas_falling_edge = self.frame
self.lkas_control_bit_prev = lkas_control_bit
new_actuators = CC.actuators.copy() new_actuators = CC.actuators.copy()
new_actuators.steer = self.apply_steer_last / self.params.STEER_MAX new_actuators.steer = self.apply_steer_last / self.params.STEER_MAX

@ -58,8 +58,8 @@ class CarState(CarStateBase):
) )
# button presses # button presses
ret.leftBlinker = cp.vl["STEERING_LEVERS"]["TURN_SIGNALS"] == 1 ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_stalk(200, cp.vl["STEERING_LEVERS"]["TURN_SIGNALS"] == 1,
ret.rightBlinker = cp.vl["STEERING_LEVERS"]["TURN_SIGNALS"] == 2 cp.vl["STEERING_LEVERS"]["TURN_SIGNALS"] == 2)
ret.genericToggle = cp.vl["STEERING_LEVERS"]["HIGH_BEAM_PRESSED"] == 1 ret.genericToggle = cp.vl["STEERING_LEVERS"]["HIGH_BEAM_PRESSED"] == 1
# steering wheel # steering wheel

@ -60,7 +60,7 @@ class CarInterface(CarInterfaceBase):
ret.minSteerSpeed = 14.5 ret.minSteerSpeed = 14.5
if car_fw is not None: if car_fw is not None:
for fw in car_fw: for fw in car_fw:
if fw.ecu == 'eps' and fw.fwVersion in (b"68312176AE", b"68312176AG", b"68273275AG"): if fw.ecu == 'eps' and fw.fwVersion[:8] in (b"68312176", b"68273275"):
ret.minSteerSpeed = 0. ret.minSteerSpeed = 0.
elif candidate == CAR.RAM_HD: elif candidate == CAR.RAM_HD:

@ -130,6 +130,11 @@ FINGERPRINTS = {
} }
FW_VERSIONS = { FW_VERSIONS = {
CAR.PACIFICA_2019_HYBRID: {
(Ecu.hcp, 0x7e2, None): [],
(Ecu.abs, 0x7e4, None): [],
},
CAR.RAM_1500: { CAR.RAM_1500: {
(Ecu.combinationMeter, 0x742, None): [ (Ecu.combinationMeter, 0x742, None): [
b'68294063AH', b'68294063AH',
@ -144,7 +149,7 @@ FW_VERSIONS = {
b'68428609AB', b'68428609AB',
b'68500728AA', b'68500728AA',
], ],
(Ecu.esp, 0x747, None): [ (Ecu.abs, 0x747, None): [
b'68432418AD', b'68432418AD',
b'68432418AB', b'68432418AB',
b'68436004AE', b'68436004AE',
@ -170,6 +175,7 @@ FW_VERSIONS = {
b'68448163AJ', b'68448163AJ',
b'68500630AD', b'68500630AD',
b'68539650AD', b'68539650AD',
b'68378758AM ',
], ],
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
b'68360078AL', b'68360078AL',
@ -199,7 +205,7 @@ FW_VERSIONS = {
b'68428503AA', b'68428503AA',
b'68428505AA', b'68428505AA',
], ],
(Ecu.esp, 0x747, None): [ (Ecu.abs, 0x747, None): [
b'68334977AH', b'68334977AH',
b'68504022AB', b'68504022AB',
b'68530686AB', b'68530686AB',

@ -8,16 +8,16 @@ from natsort import natsorted
from typing import Dict, List from typing import Dict, List
from common.basedir import BASEDIR from common.basedir import BASEDIR
from selfdrive.car.docs_definitions import STAR_DESCRIPTIONS, StarColumns, TierColumns, CarInfo, Column, Star from selfdrive.car import gen_empty_fingerprint
from selfdrive.car.docs_definitions import CarInfo, Column
from selfdrive.car.car_helpers import interfaces, get_interface_attr from selfdrive.car.car_helpers import interfaces, get_interface_attr
from selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR as HKG_RADAR_START_ADDR from selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR as HKG_RADAR_START_ADDR
def get_all_footnotes(only_tier_cols: bool = False) -> Dict[Enum, int]: def get_all_footnotes() -> Dict[Enum, int]:
all_footnotes = [] all_footnotes = []
hide_cols = set(StarColumns) - set(TierColumns) if only_tier_cols else []
for footnotes in get_interface_attr("Footnote", ignore_none=True).values(): for footnotes in get_interface_attr("Footnote", ignore_none=True).values():
all_footnotes.extend([fn for fn in footnotes if fn.value.column not in hide_cols]) all_footnotes.extend(footnotes)
return {fn: idx + 1 for idx, fn in enumerate(all_footnotes)} return {fn: idx + 1 for idx, fn in enumerate(all_footnotes)}
@ -25,12 +25,13 @@ CARS_MD_OUT = os.path.join(BASEDIR, "docs", "CARS.md")
CARS_MD_TEMPLATE = os.path.join(BASEDIR, "selfdrive", "car", "CARS_template.md") CARS_MD_TEMPLATE = os.path.join(BASEDIR, "selfdrive", "car", "CARS_template.md")
def get_all_car_info(only_tier_cols: bool = False) -> List[CarInfo]: def get_all_car_info() -> List[CarInfo]:
all_car_info: List[CarInfo] = [] all_car_info: List[CarInfo] = []
footnotes = get_all_footnotes(only_tier_cols) 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():
# Hyundai exception: those with radar have openpilot longitudinal # Hyundai exception: those with radar have openpilot longitudinal
fingerprint = {0: {}, 1: {HKG_RADAR_START_ADDR: 8}, 2: {}, 3: {}} fingerprint = gen_empty_fingerprint()
fingerprint[1] = {HKG_RADAR_START_ADDR: 8}
CP = interfaces[model][0].get_params(model, fingerprint=fingerprint, disable_radar=True) CP = interfaces[model][0].get_params(model, fingerprint=fingerprint, disable_radar=True)
if CP.dashcamOnly or car_info is None: if CP.dashcamOnly or car_info is None:
@ -57,21 +58,13 @@ def group_by_make(all_car_info: List[CarInfo]) -> Dict[str, List[CarInfo]]:
return dict(sorted_car_info) return dict(sorted_car_info)
def generate_cars_md(all_car_info: List[CarInfo], template_fn: str, only_tier_cols: bool) -> str: def generate_cars_md(all_car_info: List[CarInfo], template_fn: str) -> str:
with open(template_fn, "r") as f: with open(template_fn, "r") as f:
template = jinja2.Template(f.read(), trim_blocks=True, lstrip_blocks=True) template = jinja2.Template(f.read(), trim_blocks=True, lstrip_blocks=True)
cols = list(Column) footnotes = [fn.value.text for fn in get_all_footnotes()]
if only_tier_cols:
hide_cols = set(StarColumns) - set(TierColumns)
cols = [c for c in cols if c not in hide_cols]
for car in all_car_info:
for c in hide_cols:
del car.row[c]
footnotes = [fn.value.text for fn in get_all_footnotes(only_tier_cols)]
cars_md: str = template.render(all_car_info=all_car_info, group_by_make=group_by_make, cars_md: str = template.render(all_car_info=all_car_info, group_by_make=group_by_make,
footnotes=footnotes, Star=Star, Column=cols, STAR_DESCRIPTIONS=STAR_DESCRIPTIONS) footnotes=footnotes, Column=Column)
return cars_md return cars_md
@ -79,11 +72,10 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Auto generates supported cars documentation", parser = argparse.ArgumentParser(description="Auto generates supported cars documentation",
formatter_class=argparse.ArgumentDefaultsHelpFormatter) formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("--tier-columns", action="store_true", help="Include only columns that count in the tier")
parser.add_argument("--template", default=CARS_MD_TEMPLATE, help="Override default template filename") parser.add_argument("--template", default=CARS_MD_TEMPLATE, help="Override default template filename")
parser.add_argument("--out", default=CARS_MD_OUT, help="Override default generated filename") parser.add_argument("--out", default=CARS_MD_OUT, help="Override default generated filename")
args = parser.parse_args() args = parser.parse_args()
with open(args.out, 'w') as f: with open(args.out, 'w') as f:
f.write(generate_cars_md(get_all_car_info(args.tier_columns), args.template, args.tier_columns)) f.write(generate_cars_md(get_all_car_info(), args.template))
print(f"Generated and written to {args.out}") print(f"Generated and written to {args.out}")

@ -2,7 +2,7 @@ import re
from collections import namedtuple from collections import namedtuple
from dataclasses import dataclass, field from dataclasses import dataclass, field
from enum import Enum from enum import Enum
from typing import Dict, List, Optional, Tuple, Union, no_type_check from typing import Dict, List, Optional, Tuple, Union
from cereal import car from cereal import car
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
@ -10,25 +10,17 @@ from common.conversions import Conversions as CV
GOOD_TORQUE_THRESHOLD = 1.0 # m/s^2 GOOD_TORQUE_THRESHOLD = 1.0 # m/s^2
MODEL_YEARS_RE = r"(?<= )((\d{4}-\d{2})|(\d{4}))(,|$)" MODEL_YEARS_RE = r"(?<= )((\d{4}-\d{2})|(\d{4}))(,|$)"
# Makes that lack auto-resume with stock long, and auto resume in any configuration
NO_AUTO_RESUME_STOCK_LONG = {"toyota", "gm"}
NO_AUTO_RESUME = NO_AUTO_RESUME_STOCK_LONG | {"nissan", "subaru"}
class Tier(Enum):
GOLD = 0
SILVER = 1
BRONZE = 2
class Column(Enum): class Column(Enum):
MAKE = "Make" MAKE = "Make"
MODEL = "Model" MODEL = "Model"
PACKAGE = "Supported Package" PACKAGE = "Supported Package"
LONGITUDINAL = "openpilot ACC" LONGITUDINAL = "ACC"
FSR_LONGITUDINAL = "Stop and Go" FSR_LONGITUDINAL = "No ACC accel below"
FSR_STEERING = "Steer to 0" FSR_STEERING = "No ALC below"
STEERING_TORQUE = "Steering Torque" STEERING_TORQUE = "Steering Torque"
AUTO_RESUME = "Resume from stop"
HARNESS = "Harness"
class Star(Enum): class Star(Enum):
@ -37,9 +29,46 @@ class Star(Enum):
EMPTY = "empty" EMPTY = "empty"
StarColumns = list(Column)[3:] class Harness(Enum):
TierColumns = (Column.FSR_LONGITUDINAL, Column.FSR_STEERING, Column.STEERING_TORQUE) nidec = "Honda Nidec"
CarFootnote = namedtuple("CarFootnote", ["text", "column", "star"], defaults=[None]) bosch_a = "Honda Bosch A"
bosch_b = "Honda Bosch B"
toyota = "Toyota"
subaru_a = "Subaru A"
subaru_b = "Subaru B"
fca = "FCA"
ram = "Ram"
vw = "VW"
j533 = "J533"
hyundai_a = "Hyundai A"
hyundai_b = "Hyundai B"
hyundai_c = "Hyundai C"
hyundai_d = "Hyundai D"
hyundai_e = "Hyundai E"
hyundai_f = "Hyundai F"
hyundai_g = "Hyundai G"
hyundai_h = "Hyundai H"
hyundai_i = "Hyundai I"
hyundai_j = "Hyundai J"
hyundai_k = "Hyundai K"
hyundai_l = "Hyundai L"
hyundai_m = "Hyundai M"
hyundai_n = "Hyundai N"
hyundai_o = "Hyundai O"
hyundai_p = "Hyundai P"
hyundai_q = "Hyundai Q"
custom = "Developer"
obd_ii = "OBD-II"
gm = "GM"
nissan_a = "Nissan A"
nissan_b = "Nissan B"
mazda = "Mazda"
ford_q3 = "Ford Q3"
ford_q4 = "Ford Q4"
none = "None"
CarFootnote = namedtuple("CarFootnote", ["text", "column"], defaults=[None])
def get_footnotes(footnotes: List[Enum], column: Column) -> List[Enum]: def get_footnotes(footnotes: List[Enum], column: Column) -> List[Enum]:
@ -83,7 +112,7 @@ class CarInfo:
footnotes: List[Enum] = field(default_factory=list) footnotes: List[Enum] = field(default_factory=list)
min_steer_speed: Optional[float] = None min_steer_speed: Optional[float] = None
min_enable_speed: Optional[float] = None min_enable_speed: Optional[float] = None
harness: Optional[Enum] = 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 # TODO: set all the min steer speeds in carParams and remove this
@ -103,11 +132,12 @@ class CarInfo:
Column.MAKE: self.make, Column.MAKE: self.make,
Column.MODEL: self.model, Column.MODEL: self.model,
Column.PACKAGE: self.package, Column.PACKAGE: self.package,
# StarColumns Column.LONGITUDINAL: "openpilot" if CP.openpilotLongitudinalControl and not CP.radarOffCan else "Stock",
Column.LONGITUDINAL: Star.FULL if CP.openpilotLongitudinalControl and not CP.radarOffCan else Star.EMPTY, Column.FSR_LONGITUDINAL: f"{max(self.min_enable_speed * CV.MS_TO_MPH, 0):.0f} mph",
Column.FSR_LONGITUDINAL: Star.FULL if self.min_enable_speed <= 0. else Star.EMPTY, Column.FSR_STEERING: f"{max(self.min_steer_speed * CV.MS_TO_MPH, 0):.0f} mph",
Column.FSR_STEERING: Star.FULL if self.min_steer_speed <= 0. else Star.EMPTY,
Column.STEERING_TORQUE: Star.EMPTY, Column.STEERING_TORQUE: Star.EMPTY,
Column.AUTO_RESUME: Star.FULL if CP.autoResumeSng else Star.EMPTY,
Column.HARNESS: self.harness.value,
} }
# Set steering torque star from max lateral acceleration # Set steering torque star from max lateral acceleration
@ -115,26 +145,7 @@ class CarInfo:
if CP.maxLateralAccel >= GOOD_TORQUE_THRESHOLD: if CP.maxLateralAccel >= GOOD_TORQUE_THRESHOLD:
self.row[Column.STEERING_TORQUE] = Star.FULL self.row[Column.STEERING_TORQUE] = Star.FULL
if CP.notCar:
for col in StarColumns:
self.row[col] = Star.FULL
self.all_footnotes = all_footnotes self.all_footnotes = all_footnotes
for column in StarColumns:
# Demote if footnote specifies a star
for fn in get_footnotes(self.footnotes, column):
if fn.value.star is not None:
self.row[column] = fn.value.star
# openpilot ACC star doesn't count for tiers
full_stars = [s for col, s in self.row.items() if col in TierColumns].count(Star.FULL)
if full_stars == len(TierColumns):
self.tier = Tier.GOLD
elif full_stars == len(TierColumns) - 1:
self.tier = Tier.SILVER
else:
self.tier = Tier.BRONZE
self.year_list = get_year_list(self.years) self.year_list = get_year_list(self.years)
self.detail_sentence = self.get_detail_sentence(CP) self.detail_sentence = self.get_detail_sentence(CP)
@ -153,7 +164,7 @@ class CarInfo:
acc = "" acc = ""
if self.min_enable_speed > 0: if self.min_enable_speed > 0:
acc = f" <strong>while driving above {self.min_enable_speed * CV.MS_TO_MPH:.0f} mph</strong>" acc = f" <strong>while driving above {self.min_enable_speed * CV.MS_TO_MPH:.0f} mph</strong>"
elif CP.carName not in NO_AUTO_RESUME or (CP.carName in NO_AUTO_RESUME_STOCK_LONG and CP.openpilotLongitudinalControl): elif CP.autoResumeSng:
acc = " <strong>that automatically resumes from a stop</strong>" acc = " <strong>that automatically resumes from a stop</strong>"
if self.row[Column.STEERING_TORQUE] != Star.FULL: if self.row[Column.STEERING_TORQUE] != Star.FULL:
@ -167,10 +178,9 @@ 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}")
@no_type_check
def get_column(self, column: Column, star_icon: str, footnote_tag: str) -> str: def get_column(self, column: Column, star_icon: str, footnote_tag: str) -> str:
item: Union[str, Star] = self.row[column] item: Union[str, Star] = self.row[column]
if column in StarColumns: 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}"
@ -181,60 +191,3 @@ class CarInfo:
item += footnote_tag.format(f'{",".join(map(str, sups))}') item += footnote_tag.format(f'{",".join(map(str, sups))}')
return item return item
class Harness(Enum):
nidec = "Honda Nidec"
bosch_a = "Honda Bosch A"
bosch_b = "Honda Bosch B"
toyota = "Toyota"
subaru_a = "Subaru A"
subaru_b = "Subaru B"
fca = "FCA"
ram = "Ram"
vw = "VW"
j533 = "J533"
hyundai_a = "Hyundai A"
hyundai_b = "Hyundai B"
hyundai_c = "Hyundai C"
hyundai_d = "Hyundai D"
hyundai_e = "Hyundai E"
hyundai_f = "Hyundai F"
hyundai_g = "Hyundai G"
hyundai_h = "Hyundai H"
hyundai_i = "Hyundai I"
hyundai_j = "Hyundai J"
hyundai_k = "Hyundai K"
hyundai_l = "Hyundai L"
hyundai_m = "Hyundai M"
hyundai_n = "Hyundai N"
hyundai_o = "Hyundai O"
hyundai_p = "Hyundai P"
hyundai_q = "Hyundai Q"
custom = "Developer"
obd_ii = "OBD-II"
gm = "GM"
nissan_a = "Nissan A"
nissan_b = "Nissan B"
mazda = "Mazda"
none = "None"
STAR_DESCRIPTIONS = {
"Gas & Brakes": { # icon and row name
Column.FSR_LONGITUDINAL.value: [
[Star.FULL.value, "openpilot operates down to 0 mph."],
[Star.EMPTY.value, "openpilot operates only above a minimum speed. See your car's manual for the minimum speed."],
],
},
"Steering": {
Column.FSR_STEERING.value: [
[Star.FULL.value, "openpilot can control the steering wheel down to 0 mph."],
[Star.EMPTY.value, "No steering control below certain speeds. See your car's manual for the minimum speed."],
],
Column.STEERING_TORQUE.value: [
[Star.FULL.value, "Car has enough steering torque to comfortably take most highway turns."],
[Star.EMPTY.value, "Limited ability to make tighter turns."],
],
},
}

@ -203,7 +203,8 @@ class CarState(CarStateBase):
("DasStats_D_Dsply", "IPMA_Data"), # DAS status ("DasStats_D_Dsply", "IPMA_Data"), # DAS status
("DasWarn_D_Dsply", "IPMA_Data"), # DAS warning ("DasWarn_D_Dsply", "IPMA_Data"), # DAS warning
("AhbHiBeam_D_Rq", "IPMA_Data"), # AHB status ("AhbHiBeam_D_Rq", "IPMA_Data"), # AHB status
("Set_Me_X1", "IPMA_Data"), ("Passthru_63", "IPMA_Data"),
("Passthru_48", "IPMA_Data"),
] ]
checks = [ checks = [

@ -51,7 +51,7 @@ def create_tja_command(packer, lca_rq: int, ramp_type: int, precision: int, path
return packer.make_can_msg("LateralMotionControl", 0, values) return packer.make_can_msg("LateralMotionControl", 0, values)
def create_lkas_ui_command(packer, main_on: bool, enabled: bool, steer_alert: bool, stock_values): def create_lkas_ui_command(packer, main_on: bool, enabled: bool, steer_alert: bool, 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.
@ -72,25 +72,14 @@ def create_lkas_ui_command(packer, main_on: bool, enabled: bool, steer_alert: bo
lines = 30 lines = 30
values = { values = {
"FeatConfigIpmaActl": stock_values["FeatConfigIpmaActl"], # [0|65535] **stock_values,
"FeatNoIpmaActl": stock_values["FeatNoIpmaActl"], # [0|65535] "LaActvStats_D_Dsply": lines, # LKAS status (lines) [0|31]
"PersIndexIpma_D_Actl": stock_values["PersIndexIpma_D_Actl"], # [0|7] "LaHandsOff_D_Dsply": 2 if steer_alert else 0, # 0=HandsOn, 1=Level1 (w/o chime), 2=Level2 (w/ chime), 3=Suppressed
"AhbcRampingV_D_Rq": stock_values["AhbcRampingV_D_Rq"], # AHB ramping [0|3]
"LaActvStats_D_Dsply": lines, # LKAS status (lines) [0|31]
"LaDenyStats_B_Dsply": stock_values["LaDenyStats_B_Dsply"], # LKAS error [0|1]
"LaHandsOff_D_Dsply": 2 if steer_alert else 0, # 0=HandsOn, 1=Level1 (w/o chime), 2=Level2 (w/ chime), 3=Suppressed
"CamraDefog_B_Req": stock_values["CamraDefog_B_Req"], # Windshield heater? [0|1]
"CamraStats_D_Dsply": stock_values["CamraStats_D_Dsply"], # Camera status [0|3]
"DasAlrtLvl_D_Dsply": stock_values["DasAlrtLvl_D_Dsply"], # DAS alert level [0|7]
"DasStats_D_Dsply": stock_values["DasStats_D_Dsply"], # DAS status [0|3]
"DasWarn_D_Dsply": stock_values["DasWarn_D_Dsply"], # DAS warning [0|3]
"AhbHiBeam_D_Rq": stock_values["AhbHiBeam_D_Rq"], # AHB status [0|3]
"Set_Me_X1": stock_values["Set_Me_X1"], # [0|15]
} }
return packer.make_can_msg("IPMA_Data", 0, values) return packer.make_can_msg("IPMA_Data", 0, values)
def create_acc_ui_command(packer, main_on: bool, enabled: bool, stock_values): def create_acc_ui_command(packer, main_on: bool, enabled: bool, stock_values: dict):
""" """
Creates a CAN message for the Ford IPC adaptive cruise, forward collision Creates a CAN message for the Ford IPC adaptive cruise, forward collision
warning and traffic jam assist status. warning and traffic jam assist status.
@ -101,32 +90,8 @@ def create_acc_ui_command(packer, main_on: bool, enabled: bool, stock_values):
""" """
values = { values = {
"HaDsply_No_Cs": stock_values["HaDsply_No_Cs"], # [0|255] **stock_values,
"HaDsply_No_Cnt": stock_values["HaDsply_No_Cnt"], # [0|15] "Tja_D_Stat": 2 if enabled else (1 if main_on else 0), # TJA status: 0=Off, 1=Standby, 2=Active, 3=InterventionLeft, 4=InterventionRight, 5=WarningLeft, 6=WarningRight, 7=NotUsed [0|7]
"AccStopStat_D_Dsply": stock_values["AccStopStat_D_Dsply"], # ACC stopped status message: 0=NoDisplay, 1=ResumeReady, 2=Stopped, 3=PressResume [0|3]
"AccTrgDist2_D_Dsply": stock_values["AccTrgDist2_D_Dsply"], # ACC target distance [0|15]
"AccStopRes_B_Dsply": stock_values["AccStopRes_B_Dsply"], # [0|1]
"TjaWarn_D_Rq": stock_values["TjaWarn_D_Rq"], # TJA warning: 0=NoWarning, 1=Cancel, 2=HardTakeOverLevel1, 3=HardTakeOverLevel2 [0|7]
"Tja_D_Stat": 2 if enabled else (1 if main_on else 0), # TJA status: 0=Off, 1=Standby, 2=Active, 3=InterventionLeft, 4=InterventionRight, 5=WarningLeft, 6=WarningRight, 7=NotUsed [0|7]
"TjaMsgTxt_D_Dsply": stock_values["TjaMsgTxt_D_Dsply"], # TJA text [0|7]
"IaccLamp_D_Rq": stock_values["IaccLamp_D_Rq"], # iACC status icon [0|3]
"AccMsgTxt_D2_Rq": stock_values["AccMsgTxt_D2_Rq"], # ACC text [0|15]
"FcwDeny_B_Dsply": stock_values["FcwDeny_B_Dsply"], # FCW disabled [0|1]
"FcwMemStat_B_Actl": stock_values["FcwMemStat_B_Actl"], # FCW enabled setting [0|1]
"AccTGap_B_Dsply": stock_values["AccTGap_B_Dsply"], # ACC time gap display setting [0|1]
"CadsAlignIncplt_B_Actl": stock_values["CadsAlignIncplt_B_Actl"], # Radar alignment? [0|1]
"AccFllwMde_B_Dsply": stock_values["AccFllwMde_B_Dsply"], # ACC follow mode display setting [0|1]
"CadsRadrBlck_B_Actl": stock_values["CadsRadrBlck_B_Actl"], # Radar blocked? [0|1]
"CmbbPostEvnt_B_Dsply": stock_values["CmbbPostEvnt_B_Dsply"], # AEB event status [0|1]
"AccStopMde_B_Dsply": stock_values["AccStopMde_B_Dsply"], # ACC stop mode display setting [0|1]
"FcwMemSens_D_Actl": stock_values["FcwMemSens_D_Actl"], # FCW sensitivity setting [0|3]
"FcwMsgTxt_D_Rq": stock_values["FcwMsgTxt_D_Rq"], # FCW text [0|7]
"AccWarn_D_Dsply": stock_values["AccWarn_D_Dsply"], # ACC warning [0|3]
"FcwVisblWarn_B_Rq": stock_values["FcwVisblWarn_B_Rq"], # FCW alert: 0=Off, 1=On [0|1]
"FcwAudioWarn_B_Rq": stock_values["FcwAudioWarn_B_Rq"], # FCW audio: 0=Off, 1=On [0|1]
"AccTGap_D_Dsply": stock_values["AccTGap_D_Dsply"], # ACC time gap: 1=Time_Gap_1, 2=Time_Gap_2, ..., 5=Time_Gap_5 [0|7]
"AccMemEnbl_B_RqDrv": stock_values["AccMemEnbl_B_RqDrv"], # ACC setting: 0=NormalCruise, 1=AdaptiveCruise [0|1]
"FdaMem_B_Stat": stock_values["FdaMem_B_Stat"], # FDA enabled setting [0|1]
} }
return packer.make_can_msg("ACCDATA_3", 0, values) return packer.make_can_msg("ACCDATA_3", 0, values)

@ -1,33 +1,63 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from math import cos, sin
from cereal import car from cereal import car
from common.conversions import Conversions as CV
from opendbc.can.parser import CANParser from opendbc.can.parser import CANParser
from selfdrive.car.ford.values import CANBUS, DBC from common.conversions import Conversions as CV
from selfdrive.car.ford.values import CANBUS, DBC, RADAR
from selfdrive.car.interfaces import RadarInterfaceBase from selfdrive.car.interfaces import RadarInterfaceBase
RADAR_MSGS = list(range(0x500, 0x540)) DELPHI_ESR_RADAR_MSGS = list(range(0x500, 0x540))
DELPHI_MRR_RADAR_START_ADDR = 0x120
DELPHI_MRR_RADAR_MSG_COUNT = 64
def _create_radar_can_parser(car_fingerprint):
if DBC[car_fingerprint]['radar'] is None:
return None
msg_n = len(RADAR_MSGS) def _create_delphi_esr_radar_can_parser():
msg_n = len(DELPHI_ESR_RADAR_MSGS)
signals = list(zip(['X_Rel'] * msg_n + ['Angle'] * msg_n + ['V_Rel'] * msg_n, signals = list(zip(['X_Rel'] * msg_n + ['Angle'] * msg_n + ['V_Rel'] * msg_n,
RADAR_MSGS * 3)) DELPHI_ESR_RADAR_MSGS * 3))
checks = list(zip(RADAR_MSGS, [20] * msg_n)) checks = list(zip(DELPHI_ESR_RADAR_MSGS, [20] * msg_n))
return CANParser(RADAR.DELPHI_ESR, signals, checks, CANBUS.radar)
def _create_delphi_mrr_radar_can_parser():
signals = []
checks = []
for i in range(1, DELPHI_MRR_RADAR_MSG_COUNT + 1):
msg = f"MRR_Detection_{i:03d}"
signals += [
(f"CAN_DET_VALID_LEVEL_{i:02d}", msg),
(f"CAN_DET_AZIMUTH_{i:02d}", msg),
(f"CAN_DET_RANGE_{i:02d}", msg),
(f"CAN_DET_RANGE_RATE_{i:02d}", msg),
(f"CAN_DET_AMPLITUDE_{i:02d}", msg),
(f"CAN_SCAN_INDEX_2LSB_{i:02d}", msg),
]
checks += [(msg, 20)]
return CANParser(RADAR.DELPHI_MRR, signals, checks, CANBUS.radar)
return CANParser(DBC[car_fingerprint]['radar'], signals, checks, CANBUS.radar)
class RadarInterface(RadarInterfaceBase): class RadarInterface(RadarInterfaceBase):
def __init__(self, CP): def __init__(self, CP):
super().__init__(CP) super().__init__(CP)
self.validCnt = {key: 0 for key in RADAR_MSGS}
self.track_id = 0
self.rcp = _create_radar_can_parser(CP.carFingerprint)
self.trigger_msg = 0x53f
self.updated_messages = set() self.updated_messages = set()
self.track_id = 0
self.radar = DBC[CP.carFingerprint]['radar']
if self.radar is None:
self.rcp = None
elif self.radar == RADAR.DELPHI_ESR:
self.rcp = _create_delphi_esr_radar_can_parser()
self.trigger_msg = DELPHI_ESR_RADAR_MSGS[-1]
self.valid_cnt = {key: 0 for key in DELPHI_ESR_RADAR_MSGS}
elif self.radar == RADAR.DELPHI_MRR:
self.rcp = _create_delphi_mrr_radar_can_parser()
self.trigger_msg = DELPHI_MRR_RADAR_START_ADDR + DELPHI_MRR_RADAR_MSG_COUNT - 1
else:
raise ValueError(f"Unsupported radar: {self.radar}")
def update(self, can_strings): def update(self, can_strings):
if self.rcp is None: if self.rcp is None:
@ -45,20 +75,30 @@ class RadarInterface(RadarInterfaceBase):
errors.append("canError") errors.append("canError")
ret.errors = errors ret.errors = errors
if self.radar == RADAR.DELPHI_ESR:
self._update_delphi_esr()
elif self.radar == RADAR.DELPHI_MRR:
self._update_delphi_mrr()
ret.points = list(self.pts.values())
self.updated_messages.clear()
return ret
def _update_delphi_esr(self):
for ii in sorted(self.updated_messages): for ii in sorted(self.updated_messages):
cpt = self.rcp.vl[ii] cpt = self.rcp.vl[ii]
if cpt['X_Rel'] > 0.00001: if cpt['X_Rel'] > 0.00001:
self.validCnt[ii] = 0 # reset counter self.valid_cnt[ii] = 0 # reset counter
if cpt['X_Rel'] > 0.00001: if cpt['X_Rel'] > 0.00001:
self.validCnt[ii] += 1 self.valid_cnt[ii] += 1
else: else:
self.validCnt[ii] = max(self.validCnt[ii] - 1, 0) self.valid_cnt[ii] = max(self.valid_cnt[ii] - 1, 0)
#print ii, self.validCnt[ii], cpt['VALID'], cpt['X_Rel'], cpt['Angle'] #print ii, self.valid_cnt[ii], cpt['VALID'], cpt['X_Rel'], cpt['Angle']
# radar point only valid if there have been enough valid measurements # radar point only valid if there have been enough valid measurements
if self.validCnt[ii] > 0: if self.valid_cnt[ii] > 0:
if ii not in self.pts: if ii not in self.pts:
self.pts[ii] = car.RadarData.RadarPoint.new_message() self.pts[ii] = car.RadarData.RadarPoint.new_message()
self.pts[ii].trackId = self.track_id self.pts[ii].trackId = self.track_id
@ -73,6 +113,36 @@ class RadarInterface(RadarInterfaceBase):
if ii in self.pts: if ii in self.pts:
del self.pts[ii] del self.pts[ii]
ret.points = list(self.pts.values()) def _update_delphi_mrr(self):
self.updated_messages.clear() for ii in range(1, DELPHI_MRR_RADAR_MSG_COUNT + 1):
return ret msg = self.rcp.vl[f"MRR_Detection_{ii:03d}"]
# SCAN_INDEX rotates through 0..3 on each message
# treat these as separate points
scanIndex = msg[f"CAN_SCAN_INDEX_2LSB_{ii:02d}"]
i = (ii - 1) * 4 + scanIndex
if i not in self.pts:
self.pts[i] = car.RadarData.RadarPoint.new_message()
self.pts[i].trackId = self.track_id
self.pts[i].aRel = float('nan')
self.pts[i].yvRel = float('nan')
self.track_id += 1
valid = bool(msg[f"CAN_DET_VALID_LEVEL_{ii:02d}"])
amplitude = msg[f"CAN_DET_AMPLITUDE_{ii:02d}"] # dBsm [-64|63]
if valid and 0 < amplitude <= 15:
azimuth = msg[f"CAN_DET_AZIMUTH_{ii:02d}"] # rad [-3.1416|3.13964]
dist = msg[f"CAN_DET_RANGE_{ii:02d}"] # m [0|255.984]
distRate = msg[f"CAN_DET_RANGE_RATE_{ii:02d}"] # m/s [-128|127.984]
# *** openpilot radar point ***
self.pts[i].dRel = cos(azimuth) * dist # m from front of car
self.pts[i].yRel = -sin(azimuth) * dist # in car frame's y axis, left is positive
self.pts[i].vRel = distRate # m/s
self.pts[i].measured = True
else:
del self.pts[i]

@ -24,6 +24,11 @@ class CarControllerParams:
STEER_RATE_LIMIT_DOWN = AngleRateLimit(speed_points=[0., 5., 15.], max_angle_diff_points=[5., 3.5, 0.4]) STEER_RATE_LIMIT_DOWN = AngleRateLimit(speed_points=[0., 5., 15.], max_angle_diff_points=[5., 3.5, 0.4])
class RADAR:
DELPHI_ESR = 'ford_fusion_2018_adas'
DELPHI_MRR = 'FORD_CADS'
class CANBUS: class CANBUS:
main = 0 main = 0
radar = 1 radar = 1
@ -46,7 +51,7 @@ FW_VERSIONS = {
(Ecu.eps, 0x730, None): [ (Ecu.eps, 0x730, None): [
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',
], ],
(Ecu.esp, 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',
], ],
(Ecu.fwdRadar, 0x764, None): [ (Ecu.fwdRadar, 0x764, None): [
@ -63,7 +68,7 @@ FW_VERSIONS = {
(Ecu.eps, 0x730, None): [ (Ecu.eps, 0x730, None): [
b'JX6C-14D003-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'JX6C-14D003-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x760, None): [ (Ecu.abs, 0x760, None): [
b'JX61-2D053-CJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'JX61-2D053-CJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.fwdRadar, 0x764, None): [ (Ecu.fwdRadar, 0x764, None): [
@ -80,6 +85,6 @@ FW_VERSIONS = {
DBC = { DBC = {
CAR.ESCAPE_MK4: dbc_dict('ford_lincoln_base_pt', None), CAR.ESCAPE_MK4: dbc_dict('ford_lincoln_base_pt', RADAR.DELPHI_MRR),
CAR.FOCUS_MK4: dbc_dict('ford_lincoln_base_pt', None), CAR.FOCUS_MK4: dbc_dict('ford_lincoln_base_pt', RADAR.DELPHI_MRR),
} }

@ -16,7 +16,7 @@ from selfdrive.car.toyota.values import CAR as TOYOTA
from system.swaglog import cloudlog from system.swaglog import cloudlog
Ecu = car.CarParams.Ecu Ecu = car.CarParams.Ecu
ESSENTIAL_ECUS = [Ecu.engine, Ecu.eps, Ecu.esp, Ecu.fwdRadar, Ecu.fwdCamera, Ecu.vsa] ESSENTIAL_ECUS = [Ecu.engine, Ecu.eps, Ecu.abs, Ecu.fwdRadar, Ecu.fwdCamera, Ecu.vsa]
def p16(val): def p16(val):
@ -97,6 +97,11 @@ CHRYSLER_VERSION_REQUEST = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \
CHRYSLER_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) + \ CHRYSLER_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) + \
p16(0xf132) p16(0xf132)
CHRYSLER_SOFTWARE_VERSION_REQUEST = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \
p16(uds.DATA_IDENTIFIER_TYPE.SYSTEM_SUPPLIER_ECU_SOFTWARE_NUMBER)
CHRYSLER_SOFTWARE_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) + \
p16(uds.DATA_IDENTIFIER_TYPE.SYSTEM_SUPPLIER_ECU_SOFTWARE_NUMBER)
CHRYSLER_RX_OFFSET = -0x280 CHRYSLER_RX_OFFSET = -0x280
FORD_VERSION_REQUEST = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \ FORD_VERSION_REQUEST = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \
@ -208,12 +213,20 @@ REQUESTS: List[Request] = [
"chrysler", "chrysler",
[CHRYSLER_VERSION_REQUEST], [CHRYSLER_VERSION_REQUEST],
[CHRYSLER_VERSION_RESPONSE], [CHRYSLER_VERSION_RESPONSE],
whitelist_ecus=[Ecu.abs, Ecu.eps, Ecu.srs, Ecu.gateway, Ecu.fwdRadar, Ecu.fwdCamera, Ecu.combinationMeter],
rx_offset=CHRYSLER_RX_OFFSET, rx_offset=CHRYSLER_RX_OFFSET,
), ),
Request( Request(
"chrysler", "chrysler",
[CHRYSLER_VERSION_REQUEST], [CHRYSLER_VERSION_REQUEST],
[CHRYSLER_VERSION_RESPONSE], [CHRYSLER_VERSION_RESPONSE],
whitelist_ecus=[Ecu.abs, Ecu.hcp, Ecu.engine, Ecu.transmission],
),
Request(
"chrysler",
[CHRYSLER_SOFTWARE_VERSION_REQUEST],
[CHRYSLER_SOFTWARE_VERSION_RESPONSE],
whitelist_ecus=[Ecu.engine, Ecu.transmission],
), ),
# Ford # Ford
Request( Request(
@ -227,7 +240,7 @@ REQUESTS: List[Request] = [
[TESTER_PRESENT_REQUEST, FORD_VERSION_REQUEST], [TESTER_PRESENT_REQUEST, FORD_VERSION_REQUEST],
[TESTER_PRESENT_RESPONSE, FORD_VERSION_RESPONSE], [TESTER_PRESENT_RESPONSE, FORD_VERSION_RESPONSE],
bus=0, bus=0,
whitelist_ecus=[Ecu.eps, Ecu.esp, Ecu.fwdRadar, Ecu.fwdCamera], whitelist_ecus=[Ecu.eps, Ecu.abs, Ecu.fwdRadar, Ecu.fwdCamera],
), ),
] ]
@ -315,7 +328,7 @@ def match_fw_to_car_exact(fw_versions_dict):
ecu_type = ecu[0] ecu_type = ecu[0]
addr = ecu[1:] addr = ecu[1:]
found_versions = fw_versions_dict.get(addr, set()) found_versions = fw_versions_dict.get(addr, set())
if ecu_type == Ecu.esp and candidate in (TOYOTA.RAV4, TOYOTA.COROLLA, TOYOTA.HIGHLANDER, TOYOTA.SIENNA, TOYOTA.LEXUS_IS) and not len(found_versions): if ecu_type == Ecu.abs and candidate in (TOYOTA.RAV4, TOYOTA.COROLLA, TOYOTA.HIGHLANDER, TOYOTA.SIENNA, TOYOTA.LEXUS_IS) and not len(found_versions):
continue continue
# On some Toyota models, the engine can show on two different addresses # On some Toyota models, the engine can show on two different addresses

@ -109,10 +109,10 @@ class CarController:
else: else:
# Stock longitudinal, integrated at camera # Stock longitudinal, integrated at camera
if (self.frame - self.last_button_frame) * DT_CTRL > 0.1: if (self.frame - self.last_button_frame) * DT_CTRL > 0.04:
if CC.cruiseControl.cancel: if CC.cruiseControl.cancel:
self.last_button_frame = self.frame self.last_button_frame = self.frame
can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.CAMERA, CruiseButtons.CANCEL)) can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.CAMERA, CS.buttons_counter, CruiseButtons.CANCEL))
# Show green icon when LKA torque is applied, and # Show green icon when LKA torque is applied, and
# alarming orange icon when approaching torque limit. # alarming orange icon when approaching torque limit.

@ -16,12 +16,14 @@ class CarState(CarStateBase):
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.lka_steering_cmd_counter = 0 self.lka_steering_cmd_counter = 0
self.buttons_counter = 0
def update(self, pt_cp, cam_cp, loopback_cp): def update(self, pt_cp, cam_cp, loopback_cp):
ret = car.CarState.new_message() ret = car.CarState.new_message()
self.prev_cruise_buttons = self.cruise_buttons self.prev_cruise_buttons = self.cruise_buttons
self.cruise_buttons = pt_cp.vl["ASCMSteeringButton"]["ACCButtons"] self.cruise_buttons = pt_cp.vl["ASCMSteeringButton"]["ACCButtons"]
self.buttons_counter = pt_cp.vl["ASCMSteeringButton"]["RollingCounter"]
ret.wheelSpeeds = self.get_wheel_speeds( ret.wheelSpeeds = self.get_wheel_speeds(
pt_cp.vl["EBCMWheelSpdFront"]["FLWheelSpd"], pt_cp.vl["EBCMWheelSpdFront"]["FLWheelSpd"],
@ -109,6 +111,7 @@ class CarState(CarStateBase):
("AcceleratorPedal2", "AcceleratorPedal2"), ("AcceleratorPedal2", "AcceleratorPedal2"),
("CruiseState", "AcceleratorPedal2"), ("CruiseState", "AcceleratorPedal2"),
("ACCButtons", "ASCMSteeringButton"), ("ACCButtons", "ASCMSteeringButton"),
("RollingCounter", "ASCMSteeringButton"),
("SteeringWheelAngle", "PSCMSteeringAngle"), ("SteeringWheelAngle", "PSCMSteeringAngle"),
("SteeringWheelRate", "PSCMSteeringAngle"), ("SteeringWheelRate", "PSCMSteeringAngle"),
("FLWheelSpd", "EBCMWheelSpdFront"), ("FLWheelSpd", "EBCMWheelSpdFront"),

@ -1,7 +1,10 @@
from selfdrive.car import make_can_msg from selfdrive.car import make_can_msg
def create_buttons(packer, bus, button): def create_buttons(packer, bus, idx, button):
values = {"ACCButtons": button} values = {
"ACCButtons": button,
"RollingCounter": idx,
}
return packer.make_can_msg("ASCMSteeringButton", bus, values) return packer.make_can_msg("ASCMSteeringButton", bus, values)
def create_steering_control(packer, bus, apply_steer, idx, lkas_active): def create_steering_control(packer, bus, apply_steer, idx, lkas_active):

@ -4,7 +4,7 @@ from math import fabs
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 import STD_CARGO_KG, create_button_enable_events, create_button_event, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config from selfdrive.car import STD_CARGO_KG, create_button_event, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config
from selfdrive.car.gm.values import CAR, CruiseButtons, CarControllerParams, EV_CAR, CAMERA_ACC_CAR from selfdrive.car.gm.values import CAR, CruiseButtons, CarControllerParams, EV_CAR, CAMERA_ACC_CAR
from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.interfaces import CarInterfaceBase
@ -49,6 +49,7 @@ class CarInterface(CarInterfaceBase):
ret = CarInterfaceBase.get_std_params(candidate, fingerprint) ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
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
if candidate in EV_CAR: if candidate in EV_CAR:
ret.transmissionType = TransmissionType.direct ret.transmissionType = TransmissionType.direct
@ -73,7 +74,7 @@ class CarInterface(CarInterfaceBase):
ret.dashcamOnly = candidate in {CAR.CADILLAC_ATS, CAR.HOLDEN_ASTRA, CAR.MALIBU, CAR.BUICK_REGAL} ret.dashcamOnly = candidate in {CAR.CADILLAC_ATS, CAR.HOLDEN_ASTRA, CAR.MALIBU, CAR.BUICK_REGAL}
# 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.
ret.minSteerSpeed = 7 * CV.MPH_TO_MS ret.minSteerSpeed = 10 * 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
@ -160,6 +161,15 @@ class CarInterface(CarInterfaceBase):
ret.steerActuatorDelay = 0.2 ret.steerActuatorDelay = 0.2
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.SILVERADO:
ret.minEnableSpeed = -1
ret.mass = 2200. + STD_CARGO_KG
ret.wheelbase = 3.75
ret.steerRatio = 16.3
ret.centerToFront = ret.wheelbase * 0.5
tire_stiffness_factor = 1.0
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
# TODO: get actual value, for now starting with reasonable value for # TODO: get actual value, for now starting with reasonable value for
# civic and scaling by mass and wheelbase # civic and scaling by mass and wheelbase
ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase)
@ -195,9 +205,6 @@ class CarInterface(CarInterfaceBase):
if ret.vEgo < self.CP.minSteerSpeed: if ret.vEgo < self.CP.minSteerSpeed:
events.add(car.CarEvent.EventName.belowSteerSpeed) events.add(car.CarEvent.EventName.belowSteerSpeed)
# handle button presses
events.events.extend(create_button_enable_events(ret.buttonEvents, pcm_cruise=self.CP.pcmCruise))
ret.events = events.to_msg() ret.events = events.to_msg()
return ret return ret

@ -59,6 +59,7 @@ class CAR:
BUICK_REGAL = "BUICK REGAL ESSENCE 2018" BUICK_REGAL = "BUICK REGAL ESSENCE 2018"
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"
class Footnote(Enum): class Footnote(Enum):
@ -83,7 +84,11 @@ CAR_INFO: Dict[str, Union[GMCarInfo, List[GMCarInfo]]] = {
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_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: GMCarInfo("Chevrolet Bolt EUV 2022-23", "Premier/Premier Redline Trim", video_link="https://youtu.be/xvwzGMUA210", footnotes=[], harness=Harness.gm), CAR.BOLT_EUV: GMCarInfo("Chevrolet Bolt EUV 2022-23", "Premier or Premier Redline Trim without Super Cruise Package", video_link="https://youtu.be/xvwzGMUA210", footnotes=[], harness=Harness.gm),
CAR.SILVERADO: [
GMCarInfo("Chevrolet Silverado 1500 2020-21", "Safety Package II", footnotes=[], harness=Harness.gm),
GMCarInfo("GMC Sierra 1500 2020-21", "Driver Alert Package II", footnotes=[], harness=Harness.gm),
],
} }
@ -157,6 +162,10 @@ FINGERPRINTS = {
{ {
189: 7, 190: 7, 193: 8, 197: 8, 201: 8, 209: 7, 211: 3, 241: 6, 257: 8, 288: 5, 289: 8, 298: 8, 304: 3, 309: 8, 311: 8, 313: 8, 320: 4, 322: 7, 328: 1, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 451: 8, 452: 8, 453: 6, 458: 5, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 500: 6, 501: 8, 528: 5, 532: 6, 560: 8, 562: 8, 563: 5, 565: 5, 566: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 789: 5, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 848: 4, 869: 4, 880: 6, 977: 8, 1001: 8, 1017: 8, 1020: 8, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1265: 8, 1280: 4, 1296: 4, 1300: 8, 1930: 7 189: 7, 190: 7, 193: 8, 197: 8, 201: 8, 209: 7, 211: 3, 241: 6, 257: 8, 288: 5, 289: 8, 298: 8, 304: 3, 309: 8, 311: 8, 313: 8, 320: 4, 322: 7, 328: 1, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 451: 8, 452: 8, 453: 6, 458: 5, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 500: 6, 501: 8, 528: 5, 532: 6, 560: 8, 562: 8, 563: 5, 565: 5, 566: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 789: 5, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 848: 4, 869: 4, 880: 6, 977: 8, 1001: 8, 1017: 8, 1020: 8, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1265: 8, 1280: 4, 1296: 4, 1300: 8, 1930: 7
}], }],
CAR.SILVERADO: [
{
190: 6, 193: 8, 197: 8, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 8, 288: 5, 289: 8, 298: 8, 304: 3, 309: 8, 311: 8, 313: 8, 320: 4, 322: 7, 328: 1, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 413: 8, 451: 8, 452: 8, 453: 6, 455: 7, 460: 5, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 500: 6, 501: 8, 528: 5, 532: 6, 534: 2, 560: 8, 562: 8, 563: 5, 565: 5, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 715: 8, 717: 5, 761: 7, 789: 5, 800: 6, 801: 8, 810: 8, 840: 5, 842: 5, 844: 8, 848: 4, 869: 4, 880: 6, 977: 8, 1001: 8, 1011: 6, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1271: 8, 1280: 4, 1296: 4, 1300: 8, 1930: 7
}],
} }
DBC: Dict[str, Dict[str, str]] = defaultdict(lambda: dbc_dict('gm_global_a_powertrain_generated', 'gm_global_a_object', chassis_dbc='gm_global_a_chassis')) DBC: Dict[str, Dict[str, str]] = defaultdict(lambda: dbc_dict('gm_global_a_powertrain_generated', 'gm_global_a_object', chassis_dbc='gm_global_a_chassis'))
@ -164,6 +173,6 @@ DBC: Dict[str, Dict[str, str]] = defaultdict(lambda: dbc_dict('gm_global_a_power
EV_CAR = {CAR.VOLT, CAR.BOLT_EUV} EV_CAR = {CAR.VOLT, CAR.BOLT_EUV}
# We're integrated at the camera with VOACC on these cars (instead of ASCM w/ OBD-II harness) # We're integrated at the camera with VOACC on these cars (instead of ASCM w/ OBD-II harness)
CAMERA_ACC_CAR = {CAR.BOLT_EUV} CAMERA_ACC_CAR = {CAR.BOLT_EUV, CAR.SILVERADO}
STEER_THRESHOLD = 1.0 STEER_THRESHOLD = 1.0

@ -4,7 +4,7 @@ from panda import Panda
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
from common.numpy_fast import interp from common.numpy_fast import interp
from selfdrive.car.honda.values import CarControllerParams, CruiseButtons, HondaFlags, CAR, HONDA_BOSCH, HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_ALT_BRAKE_SIGNAL, HONDA_BOSCH_RADARLESS from selfdrive.car.honda.values import CarControllerParams, CruiseButtons, HondaFlags, CAR, HONDA_BOSCH, HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_ALT_BRAKE_SIGNAL, HONDA_BOSCH_RADARLESS
from selfdrive.car import STD_CARGO_KG, CivicParams, create_button_enable_events, create_button_event, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config from selfdrive.car import STD_CARGO_KG, CivicParams, create_button_event, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config
from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.interfaces import CarInterfaceBase
from selfdrive.car.disable_ecu import disable_ecu from selfdrive.car.disable_ecu import disable_ecu
@ -86,7 +86,6 @@ class CarInterface(CarInterfaceBase):
eps_modified = True eps_modified = True
if candidate == CAR.CIVIC: if candidate == CAR.CIVIC:
stop_and_go = True
ret.mass = CivicParams.MASS ret.mass = CivicParams.MASS
ret.wheelbase = CivicParams.WHEELBASE ret.wheelbase = CivicParams.WHEELBASE
ret.centerToFront = CivicParams.CENTER_TO_FRONT ret.centerToFront = CivicParams.CENTER_TO_FRONT
@ -106,7 +105,6 @@ class CarInterface(CarInterfaceBase):
tire_stiffness_factor = 1. tire_stiffness_factor = 1.
elif candidate in (CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CIVIC_2022): elif candidate in (CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CIVIC_2022):
stop_and_go = True
ret.mass = CivicParams.MASS ret.mass = CivicParams.MASS
ret.wheelbase = CivicParams.WHEELBASE ret.wheelbase = CivicParams.WHEELBASE
ret.centerToFront = CivicParams.CENTER_TO_FRONT ret.centerToFront = CivicParams.CENTER_TO_FRONT
@ -116,7 +114,6 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]]
elif candidate in (CAR.ACCORD, CAR.ACCORDH): elif candidate in (CAR.ACCORD, CAR.ACCORDH):
stop_and_go = True
ret.mass = 3279. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 3279. * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 2.83 ret.wheelbase = 2.83
ret.centerToFront = ret.wheelbase * 0.39 ret.centerToFront = ret.wheelbase * 0.39
@ -130,7 +127,6 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]]
elif candidate == CAR.ACURA_ILX: elif candidate == CAR.ACURA_ILX:
stop_and_go = False
ret.mass = 3095. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 3095. * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 2.67 ret.wheelbase = 2.67
ret.centerToFront = ret.wheelbase * 0.37 ret.centerToFront = ret.wheelbase * 0.37
@ -140,7 +136,6 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]]
elif candidate in (CAR.CRV, CAR.CRV_EU): elif candidate in (CAR.CRV, CAR.CRV_EU):
stop_and_go = False
ret.mass = 3572. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 3572. * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 2.62 ret.wheelbase = 2.62
ret.centerToFront = ret.wheelbase * 0.41 ret.centerToFront = ret.wheelbase * 0.41
@ -151,7 +146,6 @@ class CarInterface(CarInterfaceBase):
ret.wheelSpeedFactor = 1.025 ret.wheelSpeedFactor = 1.025
elif candidate == CAR.CRV_5G: elif candidate == CAR.CRV_5G:
stop_and_go = True
ret.mass = 3410. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 3410. * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 2.66 ret.wheelbase = 2.66
ret.centerToFront = ret.wheelbase * 0.41 ret.centerToFront = ret.wheelbase * 0.41
@ -169,7 +163,6 @@ class CarInterface(CarInterfaceBase):
ret.wheelSpeedFactor = 1.025 ret.wheelSpeedFactor = 1.025
elif candidate == CAR.CRV_HYBRID: elif candidate == CAR.CRV_HYBRID:
stop_and_go = True
ret.mass = 1667. + STD_CARGO_KG # mean of 4 models in kg ret.mass = 1667. + STD_CARGO_KG # mean of 4 models in kg
ret.wheelbase = 2.66 ret.wheelbase = 2.66
ret.centerToFront = ret.wheelbase * 0.41 ret.centerToFront = ret.wheelbase * 0.41
@ -180,7 +173,6 @@ class CarInterface(CarInterfaceBase):
ret.wheelSpeedFactor = 1.025 ret.wheelSpeedFactor = 1.025
elif candidate == CAR.FIT: elif candidate == CAR.FIT:
stop_and_go = False
ret.mass = 2644. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 2644. * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 2.53 ret.wheelbase = 2.53
ret.centerToFront = ret.wheelbase * 0.39 ret.centerToFront = ret.wheelbase * 0.39
@ -190,7 +182,6 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.05]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.05]]
elif candidate == CAR.FREED: elif candidate == CAR.FREED:
stop_and_go = False
ret.mass = 3086. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 3086. * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 2.74 ret.wheelbase = 2.74
# the remaining parameters were copied from FIT # the remaining parameters were copied from FIT
@ -201,7 +192,6 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.05]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.05]]
elif candidate == CAR.HRV: elif candidate == CAR.HRV:
stop_and_go = False
ret.mass = 3125 * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 3125 * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 2.61 ret.wheelbase = 2.61
ret.centerToFront = ret.wheelbase * 0.41 ret.centerToFront = ret.wheelbase * 0.41
@ -212,7 +202,6 @@ class CarInterface(CarInterfaceBase):
ret.wheelSpeedFactor = 1.025 ret.wheelSpeedFactor = 1.025
elif candidate == CAR.ACURA_RDX: elif candidate == CAR.ACURA_RDX:
stop_and_go = False
ret.mass = 3935. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 3935. * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 2.68 ret.wheelbase = 2.68
ret.centerToFront = ret.wheelbase * 0.38 ret.centerToFront = ret.wheelbase * 0.38
@ -222,7 +211,6 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]]
elif candidate == CAR.ACURA_RDX_3G: elif candidate == CAR.ACURA_RDX_3G:
stop_and_go = True
ret.mass = 4068. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 4068. * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 2.75 ret.wheelbase = 2.75
ret.centerToFront = ret.wheelbase * 0.41 ret.centerToFront = ret.wheelbase * 0.41
@ -232,7 +220,6 @@ class CarInterface(CarInterfaceBase):
tire_stiffness_factor = 0.677 tire_stiffness_factor = 0.677
elif candidate == CAR.ODYSSEY: elif candidate == CAR.ODYSSEY:
stop_and_go = False
ret.mass = 4471. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 4471. * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 3.00 ret.wheelbase = 3.00
ret.centerToFront = ret.wheelbase * 0.41 ret.centerToFront = ret.wheelbase * 0.41
@ -242,7 +229,6 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.28], [0.08]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.28], [0.08]]
elif candidate == CAR.ODYSSEY_CHN: elif candidate == CAR.ODYSSEY_CHN:
stop_and_go = False
ret.mass = 1849.2 + STD_CARGO_KG # mean of 4 models in kg ret.mass = 1849.2 + STD_CARGO_KG # mean of 4 models in kg
ret.wheelbase = 2.90 ret.wheelbase = 2.90
ret.centerToFront = ret.wheelbase * 0.41 # from CAR.ODYSSEY ret.centerToFront = ret.wheelbase * 0.41 # from CAR.ODYSSEY
@ -252,7 +238,6 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.28], [0.08]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.28], [0.08]]
elif candidate in (CAR.PILOT, CAR.PASSPORT): elif candidate in (CAR.PILOT, CAR.PASSPORT):
stop_and_go = False
ret.mass = 4204. * CV.LB_TO_KG + STD_CARGO_KG # average weight ret.mass = 4204. * CV.LB_TO_KG + STD_CARGO_KG # average weight
ret.wheelbase = 2.82 ret.wheelbase = 2.82
ret.centerToFront = ret.wheelbase * 0.428 ret.centerToFront = ret.wheelbase * 0.428
@ -262,7 +247,6 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.38], [0.11]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.38], [0.11]]
elif candidate == CAR.RIDGELINE: elif candidate == CAR.RIDGELINE:
stop_and_go = False
ret.mass = 4515. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 4515. * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 3.18 ret.wheelbase = 3.18
ret.centerToFront = ret.wheelbase * 0.41 ret.centerToFront = ret.wheelbase * 0.41
@ -272,7 +256,6 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.38], [0.11]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.38], [0.11]]
elif candidate == CAR.INSIGHT: elif candidate == CAR.INSIGHT:
stop_and_go = True
ret.mass = 2987. * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 2987. * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 2.7 ret.wheelbase = 2.7
ret.centerToFront = ret.wheelbase * 0.39 ret.centerToFront = ret.wheelbase * 0.39
@ -282,7 +265,6 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]]
elif candidate == CAR.HONDA_E: elif candidate == CAR.HONDA_E:
stop_and_go = True
ret.mass = 3338.8 * CV.LB_TO_KG + STD_CARGO_KG ret.mass = 3338.8 * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 2.5 ret.wheelbase = 2.5
ret.centerToFront = ret.wheelbase * 0.5 ret.centerToFront = ret.wheelbase * 0.5
@ -311,7 +293,8 @@ class CarInterface(CarInterfaceBase):
# min speed to enable ACC. if car can do stop and go, then set enabling speed # min speed to enable ACC. if car can do stop and go, then set enabling speed
# to a negative value, so it won't matter. Otherwise, add 0.5 mph margin to not # to a negative value, so it won't matter. Otherwise, add 0.5 mph margin to not
# conflict with PCM acc # conflict with PCM acc
ret.minEnableSpeed = -1. if (stop_and_go or ret.enableGasInterceptor) else 25.5 * CV.MPH_TO_MS stop_and_go = candidate in (HONDA_BOSCH | {CAR.CIVIC}) or ret.enableGasInterceptor
ret.minEnableSpeed = -1. if stop_and_go else 25.5 * CV.MPH_TO_MS
# TODO: get actual value, for now starting with reasonable value for # TODO: get actual value, for now starting with reasonable value for
# civic and scaling by mass and wheelbase # civic and scaling by mass and wheelbase
@ -369,9 +352,6 @@ class CarInterface(CarInterfaceBase):
if self.CS.CP.minEnableSpeed > 0 and ret.vEgo < 0.001: if self.CS.CP.minEnableSpeed > 0 and ret.vEgo < 0.001:
events.add(EventName.manualRestart) events.add(EventName.manualRestart)
# handle button presses
events.events.extend(create_button_enable_events(ret.buttonEvents, self.CP.pcmCruise))
ret.events = events.to_msg() ret.events = events.to_msg()
return ret return ret

@ -113,7 +113,7 @@ CAR_INFO: Dict[str, Optional[Union[HondaCarInfo, List[HondaCarInfo]]]] = {
HondaCarInfo("Honda Inspire 2018", "All", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a), HondaCarInfo("Honda Inspire 2018", "All", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a),
], ],
CAR.ACCORDH: HondaCarInfo("Honda Accord Hybrid 2018-22", "All", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a), CAR.ACCORDH: HondaCarInfo("Honda Accord Hybrid 2018-22", "All", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a),
CAR.CIVIC: HondaCarInfo("Honda Civic 2016-18", harness=Harness.nidec), CAR.CIVIC: HondaCarInfo("Honda Civic 2016-18", harness=Harness.nidec, video_link="https://youtu.be/-IkImTe1NYE"),
CAR.CIVIC_BOSCH: [ CAR.CIVIC_BOSCH: [
HondaCarInfo("Honda Civic 2019-21", "All", video_link="https://www.youtube.com/watch?v=4Iz1Mz5LGF8", footnotes=[Footnote.CIVIC_DIESEL], min_steer_speed=2. * CV.MPH_TO_MS, harness=Harness.bosch_a), HondaCarInfo("Honda Civic 2019-21", "All", video_link="https://www.youtube.com/watch?v=4Iz1Mz5LGF8", footnotes=[Footnote.CIVIC_DIESEL], min_steer_speed=2. * CV.MPH_TO_MS, harness=Harness.bosch_a),
HondaCarInfo("Honda Civic Hatchback 2017-21", harness=Harness.bosch_a), HondaCarInfo("Honda Civic Hatchback 2017-21", harness=Harness.bosch_a),

@ -5,7 +5,7 @@ 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_std_steer_torque_limits
from selfdrive.car.hyundai import hyundaicanfd, hyundaican from selfdrive.car.hyundai import hyundaicanfd, hyundaican
from selfdrive.car.hyundai.values import Buttons, CarControllerParams, CANFD_CAR, CAR from selfdrive.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CANFD_CAR, CAR
VisualAlert = car.CarControl.HUDControl.VisualAlert VisualAlert = car.CarControl.HUDControl.VisualAlert
LongCtrlState = car.CarControl.Actuators.LongControlState LongCtrlState = car.CarControl.Actuators.LongControlState
@ -15,6 +15,7 @@ def process_hud_alert(enabled, fingerprint, hud_control):
sys_warning = (hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw)) sys_warning = (hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw))
# initialize to no line visible # initialize to no line visible
# TODO: this is not accurate for all cars
sys_state = 1 sys_state = 1
if hud_control.leftLaneVisible and hud_control.rightLaneVisible or sys_warning: # HUD alert only display when LKAS status is active if hud_control.leftLaneVisible and hud_control.rightLaneVisible or sys_warning: # HUD alert only display when LKAS status is active
sys_state = 3 if enabled or sys_warning else 4 sys_state = 3 if enabled or sys_warning else 4
@ -71,22 +72,33 @@ class CarController:
if self.CP.carFingerprint in CANFD_CAR: if self.CP.carFingerprint in CANFD_CAR:
# steering control # steering control
can_sends.append(hyundaicanfd.create_lkas(self.packer, CC.enabled, CC.latActive, apply_steer)) can_sends.append(hyundaicanfd.create_lkas(self.packer, self.CP, CC.enabled, CC.latActive, apply_steer))
if self.frame % 5 == 0: # block LFA on HDA2
if self.frame % 5 == 0 and (self.CP.flags & HyundaiFlags.CANFD_HDA2):
can_sends.append(hyundaicanfd.create_cam_0x2a4(self.packer, CS.cam_0x2a4)) can_sends.append(hyundaicanfd.create_cam_0x2a4(self.packer, CS.cam_0x2a4))
# cruise cancel # LFA and HDA icons
if self.frame % 2 == 0 and not (self.CP.flags & HyundaiFlags.CANFD_HDA2):
can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, CC.enabled))
# button presses
if (self.frame - self.last_button_frame) * DT_CTRL > 0.25: if (self.frame - self.last_button_frame) * DT_CTRL > 0.25:
# cruise cancel
if CC.cruiseControl.cancel: if CC.cruiseControl.cancel:
for _ in range(20): if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
can_sends.append(hyundaicanfd.create_buttons(self.packer, CS.buttons_counter+1, Buttons.CANCEL)) can_sends.append(hyundaicanfd.create_cruise_info(self.packer, CS.cruise_info_copy, True))
self.last_button_frame = self.frame self.last_button_frame = self.frame
else:
for _ in range(20):
can_sends.append(hyundaicanfd.create_buttons(self.packer, CS.buttons_counter+1, Buttons.CANCEL))
self.last_button_frame = self.frame
# cruise standstill resume # cruise standstill resume
elif CC.cruiseControl.resume: elif CC.cruiseControl.resume:
can_sends.append(hyundaicanfd.create_buttons(self.packer, CS.buttons_counter+1, Buttons.RES_ACCEL)) if not (self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS):
self.last_button_frame = self.frame can_sends.append(hyundaicanfd.create_buttons(self.packer, CS.buttons_counter+1, Buttons.RES_ACCEL))
self.last_button_frame = self.frame
else: else:
# tester present - w/ no response (keeps radar disabled) # tester present - w/ no response (keeps radar disabled)

@ -5,7 +5,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.values import DBC, FEATURES, CAMERA_SCC_CAR, CANFD_CAR, EV_CAR, HYBRID_CAR, Buttons, CarControllerParams from selfdrive.car.hyundai.values import HyundaiFlags, 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
PREV_BUTTON_SAMPLES = 8 PREV_BUTTON_SAMPLES = 8
@ -20,7 +20,7 @@ class CarState(CarStateBase):
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)
if CP.carFingerprint in CANFD_CAR: if CP.carFingerprint in CANFD_CAR:
self.shifter_values = can_define.dv["ACCELERATOR"]["GEAR"] self.shifter_values = can_define.dv["GEAR_SHIFTER"]["GEAR"]
elif self.CP.carFingerprint in FEATURES["use_cluster_gears"]: elif self.CP.carFingerprint in FEATURES["use_cluster_gears"]:
self.shifter_values = can_define.dv["CLU15"]["CF_Clu_Gear"] self.shifter_values = can_define.dv["CLU15"]["CF_Clu_Gear"]
elif self.CP.carFingerprint in FEATURES["use_tcu_gears"]: elif self.CP.carFingerprint in FEATURES["use_tcu_gears"]:
@ -136,14 +136,17 @@ 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()
ret.gas = cp.vl["ACCELERATOR"]["ACCELERATOR_PEDAL"] / 255. if self.CP.flags & HyundaiFlags.CANFD_HDA2:
ret.gasPressed = ret.gas > 1e-3 ret.gas = cp.vl["ACCELERATOR"]["ACCELERATOR_PEDAL"] / 255.
else:
ret.gas = cp.vl["ACCELERATOR_ALT"]["ACCELERATOR_PEDAL"] / 1023.
ret.gasPressed = ret.gas > 1e-5
ret.brakePressed = cp.vl["BRAKE"]["BRAKE_PRESSED"] == 1 ret.brakePressed = cp.vl["BRAKE"]["BRAKE_PRESSED"] == 1
ret.doorOpen = cp.vl["DOORS_SEATBELTS"]["DRIVER_DOOR_OPEN"] == 1 ret.doorOpen = cp.vl["DOORS_SEATBELTS"]["DRIVER_DOOR_OPEN"] == 1
ret.seatbeltUnlatched = cp.vl["DOORS_SEATBELTS"]["DRIVER_SEATBELT_LATCHED"] == 0 ret.seatbeltUnlatched = cp.vl["DOORS_SEATBELTS"]["DRIVER_SEATBELT_LATCHED"] == 0
gear = cp.vl["ACCELERATOR"]["GEAR"] gear = cp.vl["GEAR_SHIFTER"]["GEAR"]
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear)) ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
# TODO: figure out positions # TODO: figure out positions
@ -168,16 +171,19 @@ class CarState(CarStateBase):
ret.cruiseState.available = True ret.cruiseState.available = True
ret.cruiseState.enabled = cp.vl["SCC1"]["CRUISE_ACTIVE"] == 1 ret.cruiseState.enabled = cp.vl["SCC1"]["CRUISE_ACTIVE"] == 1
ret.cruiseState.standstill = cp.vl["CRUISE_INFO"]["CRUISE_STANDSTILL"] == 1 cp_cruise_info = cp if self.CP.flags & HyundaiFlags.CANFD_HDA2 else cp_cam
speed_factor = CV.MPH_TO_MS if cp.vl["CLUSTER_INFO"]["DISTANCE_UNIT"] == 1 else CV.KPH_TO_MS speed_factor = CV.MPH_TO_MS if cp.vl["CLUSTER_INFO"]["DISTANCE_UNIT"] == 1 else CV.KPH_TO_MS
ret.cruiseState.speed = cp.vl["CRUISE_INFO"]["SET_SPEED"] * speed_factor ret.cruiseState.speed = cp_cruise_info.vl["CRUISE_INFO"]["SET_SPEED"] * speed_factor
ret.cruiseState.standstill = cp_cruise_info.vl["CRUISE_INFO"]["CRUISE_STANDSTILL"] == 1
self.cruise_buttons.extend(cp.vl_all["CRUISE_BUTTONS"]["CRUISE_BUTTONS"]) cruise_btn_msg = "CRUISE_BUTTONS_ALT" if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else "CRUISE_BUTTONS"
self.main_buttons.extend(cp.vl_all["CRUISE_BUTTONS"]["ADAPTIVE_CRUISE_MAIN_BTN"]) self.cruise_buttons.extend(cp.vl_all[cruise_btn_msg]["CRUISE_BUTTONS"])
self.buttons_counter = cp.vl["CRUISE_BUTTONS"]["COUNTER"] self.main_buttons.extend(cp.vl_all[cruise_btn_msg]["ADAPTIVE_CRUISE_MAIN_BTN"])
self.buttons_counter = cp.vl[cruise_btn_msg]["COUNTER"]
self.cruise_info_copy = copy.copy(cp_cruise_info.vl["CRUISE_INFO"])
self.cam_0x2a4 = copy.copy(cp_cam.vl["CAM_0x2a4"]) if self.CP.flags & HyundaiFlags.CANFD_HDA2:
self.cam_0x2a4 = copy.copy(cp_cam.vl["CAM_0x2a4"])
return ret return ret
@ -319,9 +325,7 @@ class CarState(CarStateBase):
@staticmethod @staticmethod
def get_cam_can_parser(CP): def get_cam_can_parser(CP):
if CP.carFingerprint in CANFD_CAR: if CP.carFingerprint in CANFD_CAR:
signals = [(f"BYTE{i}", "CAM_0x2a4") for i in range(3, 24)] return CarState.get_cam_can_parser_canfd(CP)
checks = [("CAM_0x2a4", 20)]
return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, 6)
signals = [ signals = [
# signal_name, signal_address # signal_name, signal_address
@ -374,14 +378,15 @@ class CarState(CarStateBase):
@staticmethod @staticmethod
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"
signals = [ signals = [
("WHEEL_SPEED_1", "WHEEL_SPEEDS"), ("WHEEL_SPEED_1", "WHEEL_SPEEDS"),
("WHEEL_SPEED_2", "WHEEL_SPEEDS"), ("WHEEL_SPEED_2", "WHEEL_SPEEDS"),
("WHEEL_SPEED_3", "WHEEL_SPEEDS"), ("WHEEL_SPEED_3", "WHEEL_SPEEDS"),
("WHEEL_SPEED_4", "WHEEL_SPEEDS"), ("WHEEL_SPEED_4", "WHEEL_SPEEDS"),
("ACCELERATOR_PEDAL", "ACCELERATOR"), ("GEAR", "GEAR_SHIFTER"),
("GEAR", "ACCELERATOR"),
("BRAKE_PRESSED", "BRAKE"), ("BRAKE_PRESSED", "BRAKE"),
("STEERING_RATE", "STEERING_SENSORS"), ("STEERING_RATE", "STEERING_SENSORS"),
@ -390,11 +395,9 @@ class CarState(CarStateBase):
("STEERING_OUT_TORQUE", "MDPS"), ("STEERING_OUT_TORQUE", "MDPS"),
("CRUISE_ACTIVE", "SCC1"), ("CRUISE_ACTIVE", "SCC1"),
("SET_SPEED", "CRUISE_INFO"), ("COUNTER", cruise_btn_msg),
("CRUISE_STANDSTILL", "CRUISE_INFO"), ("CRUISE_BUTTONS", cruise_btn_msg),
("COUNTER", "CRUISE_BUTTONS"), ("ADAPTIVE_CRUISE_MAIN_BTN", cruise_btn_msg),
("CRUISE_BUTTONS", "CRUISE_BUTTONS"),
("ADAPTIVE_CRUISE_MAIN_BTN", "CRUISE_BUTTONS"),
("DISTANCE_UNIT", "CLUSTER_INFO"), ("DISTANCE_UNIT", "CLUSTER_INFO"),
@ -407,16 +410,64 @@ class CarState(CarStateBase):
checks = [ checks = [
("WHEEL_SPEEDS", 100), ("WHEEL_SPEEDS", 100),
("ACCELERATOR", 100), ("GEAR_SHIFTER", 100),
("BRAKE", 100), ("BRAKE", 100),
("STEERING_SENSORS", 100), ("STEERING_SENSORS", 100),
("MDPS", 100), ("MDPS", 100),
("SCC1", 50), ("SCC1", 50),
("CRUISE_INFO", 50), (cruise_btn_msg, 50),
("CRUISE_BUTTONS", 50),
("CLUSTER_INFO", 4), ("CLUSTER_INFO", 4),
("BLINKERS", 4), ("BLINKERS", 4),
("DOORS_SEATBELTS", 4), ("DOORS_SEATBELTS", 4),
] ]
return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, 5) if CP.flags & HyundaiFlags.CANFD_HDA2:
signals += [
("ACCELERATOR_PEDAL", "ACCELERATOR"),
("GEAR", "ACCELERATOR"),
("SET_SPEED", "CRUISE_INFO"),
("CRUISE_STANDSTILL", "CRUISE_INFO"),
]
checks += [
("CRUISE_INFO", 50),
("ACCELERATOR", 100),
]
else:
signals += [
("ACCELERATOR_PEDAL", "ACCELERATOR_ALT"),
]
checks += [
("ACCELERATOR_ALT", 100),
]
bus = 5 if CP.flags & HyundaiFlags.CANFD_HDA2 else 4
return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, bus)
@staticmethod
def get_cam_can_parser_canfd(CP):
if CP.flags & HyundaiFlags.CANFD_HDA2:
signals = [(f"BYTE{i}", "CAM_0x2a4") for i in range(3, 24)]
checks = [("CAM_0x2a4", 20)]
else:
signals = [
("COUNTER", "CRUISE_INFO"),
("NEW_SIGNAL_1", "CRUISE_INFO"),
("CRUISE_MAIN", "CRUISE_INFO"),
("CRUISE_STATUS", "CRUISE_INFO"),
("CRUISE_INACTIVE", "CRUISE_INFO"),
("NEW_SIGNAL_2", "CRUISE_INFO"),
("CRUISE_STANDSTILL", "CRUISE_INFO"),
("NEW_SIGNAL_3", "CRUISE_INFO"),
("BYTE11", "CRUISE_INFO"),
("SET_SPEED", "CRUISE_INFO"),
("NEW_SIGNAL_4", "CRUISE_INFO"),
]
signals += [(f"BYTE{i}", "CRUISE_INFO") for i in range(3, 7)]
signals += [(f"BYTE{i}", "CRUISE_INFO") for i in range(13, 31)]
checks = [
("CRUISE_INFO", 50),
]
return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, 6)

@ -37,12 +37,26 @@ def create_lkas11(packer, frame, car_fingerprint, apply_steer, steer_req,
# Note: the warning is hidden while the blinkers are on # Note: the warning is hidden while the blinkers are on
values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0 values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0
# Likely cars lacking the ability to show individual lane lines in the dash
elif car_fingerprint in (CAR.KIA_OPTIMA,):
# SysWarning 4 = keep hands on wheel + beep
values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0
# SysState 0 = no icons
# SysState 1-2 = white car + lanes
# SysState 3 = green car + lanes, green steering wheel
# SysState 4 = green car + lanes
values["CF_Lkas_LdwsSysState"] = 3 if enabled else 1
values["CF_Lkas_LdwsOpt_USM"] = 2 # non-2 changes above SysState definition
# these have no effect
values["CF_Lkas_LdwsActivemode"] = 0
values["CF_Lkas_FcwOpt_USM"] = 0
elif car_fingerprint == CAR.HYUNDAI_GENESIS: elif car_fingerprint == CAR.HYUNDAI_GENESIS:
# This field is actually LdwsActivemode # This field is actually LdwsActivemode
# Genesis and Optima fault when forwarding while engaged # Genesis and Optima fault when forwarding while engaged
values["CF_Lkas_LdwsActivemode"] = 2 values["CF_Lkas_LdwsActivemode"] = 2
elif car_fingerprint == CAR.KIA_OPTIMA:
values["CF_Lkas_LdwsActivemode"] = 0
dat = packer.make_can_msg("LKAS11", 0, values)[2] dat = packer.make_can_msg("LKAS11", 0, values)[2]

@ -1,4 +1,7 @@
def create_lkas(packer, enabled, lat_active, apply_steer): from selfdrive.car.hyundai.values import HyundaiFlags
def create_lkas(packer, CP, enabled, lat_active, apply_steer):
values = { values = {
"LKA_MODE": 2, "LKA_MODE": 2,
"LKA_ICON": 2 if enabled else 1, "LKA_ICON": 2 if enabled else 1,
@ -10,7 +13,9 @@ def create_lkas(packer, enabled, lat_active, apply_steer):
"NEW_SIGNAL_1": 0, "NEW_SIGNAL_1": 0,
"NEW_SIGNAL_2": 0, "NEW_SIGNAL_2": 0,
} }
return packer.make_can_msg("LKAS", 4, values)
msg = "LKAS" if CP.flags & HyundaiFlags.CANFD_HDA2 else "LFA"
return packer.make_can_msg(msg, 4, values)
def create_cam_0x2a4(packer, camera_values): def create_cam_0x2a4(packer, camera_values):
camera_values.update({ camera_values.update({
@ -25,3 +30,17 @@ def create_buttons(packer, cnt, btn):
"CRUISE_BUTTONS": btn, "CRUISE_BUTTONS": btn,
} }
return packer.make_can_msg("CRUISE_BUTTONS", 5, values) return packer.make_can_msg("CRUISE_BUTTONS", 5, values)
def create_cruise_info(packer, cruise_info_copy, cancel):
values = cruise_info_copy
if cancel:
values["CRUISE_STATUS"] = 0
values["CRUISE_INACTIVE"] = 1
return packer.make_can_msg("CRUISE_INFO", 4, values)
def create_lfahda_cluster(packer, enabled):
values = {
"HDA_ICON": 1 if enabled else 0,
"LFA_ICON": 2 if enabled else 0,
}
return packer.make_can_msg("LFAHDA_CLUSTER", 4, values)

@ -2,9 +2,9 @@
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.values import CAR, DBC, CANFD_CAR, CAMERA_SCC_CAR, EV_CAR, HYBRID_CAR, LEGACY_SAFETY_MODE_CAR, Buttons, CarControllerParams from selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CANFD_CAR, CAMERA_SCC_CAR, EV_CAR, HYBRID_CAR, LEGACY_SAFETY_MODE_CAR, Buttons, CarControllerParams
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_enable_events, create_button_event, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config from selfdrive.car import STD_CARGO_KG, create_button_event, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config
from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.interfaces import CarInterfaceBase
from selfdrive.car.disable_ecu import disable_ecu from selfdrive.car.disable_ecu import disable_ecu
@ -115,13 +115,11 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.indi.actuatorEffectivenessV = [2.3] ret.lateralTuning.indi.actuatorEffectivenessV = [2.3]
ret.minSteerSpeed = 60 * CV.KPH_TO_MS ret.minSteerSpeed = 60 * CV.KPH_TO_MS
elif candidate in (CAR.KONA, CAR.KONA_EV, CAR.KONA_HEV, CAR.KONA_EV_2022): elif candidate in (CAR.KONA, CAR.KONA_EV, CAR.KONA_HEV, CAR.KONA_EV_2022):
ret.lateralTuning.pid.kf = 0.00005
ret.mass = {CAR.KONA_EV: 1685., CAR.KONA_HEV: 1425., CAR.KONA_EV_2022: 1743.}.get(candidate, 1275.) + STD_CARGO_KG ret.mass = {CAR.KONA_EV: 1685., CAR.KONA_HEV: 1425., CAR.KONA_EV_2022: 1743.}.get(candidate, 1275.) + STD_CARGO_KG
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
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
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_EV_2020, CAR.IONIQ_PHEV, CAR.IONIQ_HEV_2022):
ret.lateralTuning.pid.kf = 0.00006 ret.lateralTuning.pid.kf = 0.00006
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
@ -162,6 +160,12 @@ class CarInterface(CarInterfaceBase):
tire_stiffness_factor = 0.385 tire_stiffness_factor = 0.385
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.25], [0.05]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
elif candidate == CAR.TUCSON_HYBRID_4TH_GEN:
ret.mass = 1680. + STD_CARGO_KG # average of all 3 trims
ret.wheelbase = 2.756
ret.steerRatio = 16.
tire_stiffness_factor = 0.385
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
# Kia # Kia
elif candidate == CAR.KIA_SORENTO: elif candidate == CAR.KIA_SORENTO:
@ -171,7 +175,7 @@ class CarInterface(CarInterfaceBase):
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
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.25], [0.05]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
elif candidate in (CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV, CAR.KIA_NIRO_HEV_2021): elif candidate in (CAR.KIA_NIRO_EV, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021):
ret.lateralTuning.pid.kf = 0.00006 ret.lateralTuning.pid.kf = 0.00006
ret.mass = 1737. + STD_CARGO_KG ret.mass = 1737. + STD_CARGO_KG
ret.wheelbase = 2.7 ret.wheelbase = 2.7
@ -179,7 +183,7 @@ class CarInterface(CarInterfaceBase):
tire_stiffness_factor = 0.385 tire_stiffness_factor = 0.385
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.25], [0.05]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]]
if candidate == CAR.KIA_NIRO_HEV: if candidate == CAR.KIA_NIRO_PHEV:
ret.minSteerSpeed = 32 * CV.MPH_TO_MS ret.minSteerSpeed = 32 * CV.MPH_TO_MS
elif candidate == CAR.KIA_SELTOS: elif candidate == CAR.KIA_SELTOS:
ret.mass = 1337. + STD_CARGO_KG ret.mass = 1337. + STD_CARGO_KG
@ -286,7 +290,19 @@ class CarInterface(CarInterfaceBase):
if candidate in CANFD_CAR: if candidate in CANFD_CAR:
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.noOutput), ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.noOutput),
get_safety_config(car.CarParams.SafetyModel.hyundaiCanfd)] get_safety_config(car.CarParams.SafetyModel.hyundaiCanfd)]
# detect HDA2 with LKAS message
if 0x50 in fingerprint[6]:
ret.flags |= HyundaiFlags.CANFD_HDA2.value
ret.safetyConfigs[1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_HDA2
else:
# non-HDA2
if 0x1cf not in fingerprint[4]:
ret.flags |= HyundaiFlags.CANFD_ALT_BUTTONS.value
ret.safetyConfigs[1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_ALT_BUTTONS
else: else:
ret.enableBsm = 0x58b in fingerprint[0]
if candidate in LEGACY_SAFETY_MODE_CAR: if candidate in LEGACY_SAFETY_MODE_CAR:
# 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
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hyundaiLegacy)] ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hyundaiLegacy)]
@ -316,8 +332,6 @@ class CarInterface(CarInterfaceBase):
ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront, ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront,
tire_stiffness_factor=tire_stiffness_factor) tire_stiffness_factor=tire_stiffness_factor)
ret.enableBsm = 0x58b in fingerprint[0]
return ret return ret
@staticmethod @staticmethod
@ -328,6 +342,14 @@ class CarInterface(CarInterfaceBase):
def _update(self, c): def _update(self, c):
ret = self.CS.update(self.cp, self.cp_cam) ret = self.CS.update(self.cp, self.cp_cam)
if self.CS.CP.openpilotLongitudinalControl and self.CS.cruise_buttons[-1] != self.CS.prev_cruise_buttons:
buttonEvents = [create_button_event(self.CS.cruise_buttons[-1], self.CS.prev_cruise_buttons, BUTTONS_DICT)]
# Handle CF_Clu_CruiseSwState changing buttons mid-press
if self.CS.cruise_buttons[-1] != 0 and self.CS.prev_cruise_buttons != 0:
buttonEvents.append(create_button_event(0, self.CS.prev_cruise_buttons, BUTTONS_DICT))
ret.buttonEvents = buttonEvents
# On some newer model years, the CANCEL button acts as a pause/resume button based on the PCM state # On some newer model years, the CANCEL button acts as a pause/resume button based on the PCM state
# To avoid re-engaging when openpilot cancels, check user engagement intention via buttons # To avoid re-engaging when openpilot cancels, check user engagement intention via buttons
# Main button also can trigger an engagement on these cars # Main button also can trigger an engagement on these cars
@ -337,15 +359,6 @@ class CarInterface(CarInterfaceBase):
if self.CS.brake_error: if self.CS.brake_error:
events.add(EventName.brakeUnavailable) events.add(EventName.brakeUnavailable)
if self.CS.CP.openpilotLongitudinalControl and self.CS.cruise_buttons[-1] != self.CS.prev_cruise_buttons:
buttonEvents = [create_button_event(self.CS.cruise_buttons[-1], self.CS.prev_cruise_buttons, BUTTONS_DICT)]
# Handle CF_Clu_CruiseSwState changing buttons mid-press
if self.CS.cruise_buttons[-1] != 0 and self.CS.prev_cruise_buttons != 0:
buttonEvents.append(create_button_event(0, self.CS.prev_cruise_buttons, BUTTONS_DICT))
ret.buttonEvents = buttonEvents
events.events.extend(create_button_enable_events(ret.buttonEvents))
# low speed steer alert hysteresis logic (only for cars with steer cut off above 10 m/s) # low speed steer alert hysteresis logic (only for cars with steer cut off above 10 m/s)
if ret.vEgo < (self.CP.minSteerSpeed + 2.) and self.CP.minSteerSpeed > 10.: if ret.vEgo < (self.CP.minSteerSpeed + 2.) and self.CP.minSteerSpeed > 10.:
self.low_speed_alert = True self.low_speed_alert = True

@ -1,3 +1,4 @@
from enum import IntFlag
from dataclasses import dataclass from dataclasses import dataclass
from typing import Dict, List, Optional, Union from typing import Dict, List, Optional, Union
@ -29,7 +30,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.ELANTRA_GT_I30, CAR.IONIQ, elif CP.carFingerprint in (CAR.GENESIS_G80, CAR.GENESIS_G90, CAR.ELANTRA, CAR.HYUNDAI_GENESIS, CAR.ELANTRA_GT_I30, CAR.IONIQ,
CAR.IONIQ_EV_LTD, CAR.SANTA_FE_PHEV_2022, CAR.SONATA_LF, CAR.KIA_FORTE, CAR.KIA_NIRO_HEV, 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_STINGER): CAR.KIA_OPTIMA_H, CAR.KIA_SORENTO, CAR.KIA_STINGER):
self.STEER_MAX = 255 self.STEER_MAX = 255
@ -38,6 +39,11 @@ class CarControllerParams:
self.STEER_MAX = 384 self.STEER_MAX = 384
class HyundaiFlags(IntFlag):
CANFD_HDA2 = 1
CANFD_ALT_BUTTONS = 2
class CAR: class CAR:
# Hyundai # Hyundai
ELANTRA = "HYUNDAI ELANTRA 2017" ELANTRA = "HYUNDAI ELANTRA 2017"
@ -66,12 +72,13 @@ class CAR:
VELOSTER = "HYUNDAI VELOSTER 2019" VELOSTER = "HYUNDAI VELOSTER 2019"
SONATA_HYBRID = "HYUNDAI SONATA HYBRID 2021" SONATA_HYBRID = "HYUNDAI SONATA HYBRID 2021"
IONIQ_5 = "HYUNDAI IONIQ 5 2022" IONIQ_5 = "HYUNDAI IONIQ 5 2022"
TUCSON_HYBRID_4TH_GEN = "HYUNDAI TUCSON HYBRID 4TH GEN"
# 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_NIRO_EV = "KIA NIRO EV 2020" KIA_NIRO_EV = "KIA NIRO EV 2020"
KIA_NIRO_HEV = "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_OPTIMA = "KIA OPTIMA SX 2019 & 2016" KIA_OPTIMA = "KIA OPTIMA SX 2019 & 2016"
KIA_OPTIMA_H = "KIA OPTIMA HYBRID 2017 & SPORTS 2019" KIA_OPTIMA_H = "KIA OPTIMA HYBRID 2017 & SPORTS 2019"
@ -112,7 +119,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
CAR.KONA_EV_2022: HyundaiCarInfo("Hyundai Kona Electric 2022", "Smart Cruise Control (SCC)", harness=Harness.hyundai_o), CAR.KONA_EV_2022: HyundaiCarInfo("Hyundai Kona Electric 2022", "Smart Cruise Control (SCC)", harness=Harness.hyundai_o),
CAR.KONA_HEV: HyundaiCarInfo("Hyundai Kona Hybrid 2020", video_link="https://youtu.be/0dwpAHiZgFo", harness=Harness.hyundai_i), CAR.KONA_HEV: HyundaiCarInfo("Hyundai Kona Hybrid 2020", video_link="https://youtu.be/0dwpAHiZgFo", harness=Harness.hyundai_i),
CAR.SANTA_FE: HyundaiCarInfo("Hyundai Santa Fe 2019-20", "All", harness=Harness.hyundai_d), CAR.SANTA_FE: HyundaiCarInfo("Hyundai Santa Fe 2019-20", "All", harness=Harness.hyundai_d),
CAR.SANTA_FE_2022: HyundaiCarInfo("Hyundai Santa Fe 2021-22", "All", harness=Harness.hyundai_l), CAR.SANTA_FE_2022: HyundaiCarInfo("Hyundai Santa Fe 2021-22", "All", video_link="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", video_link="https://www.youtube.com/watch?v=ix63r9kE3Fw", harness=Harness.hyundai_a), CAR.SONATA: HyundaiCarInfo("Hyundai Sonata 2020-22", "All", video_link="https://www.youtube.com/watch?v=ix63r9kE3Fw", harness=Harness.hyundai_a),
@ -128,11 +135,12 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
CAR.VELOSTER: HyundaiCarInfo("Hyundai Veloster 2019-20", "Smart Cruise Control (SCC)", min_enable_speed=5. * CV.MPH_TO_MS, harness=Harness.hyundai_e), CAR.VELOSTER: HyundaiCarInfo("Hyundai Veloster 2019-20", "Smart Cruise Control (SCC)", min_enable_speed=5. * CV.MPH_TO_MS, harness=Harness.hyundai_e),
CAR.SONATA_HYBRID: HyundaiCarInfo("Hyundai Sonata Hybrid 2020-22", "All", harness=Harness.hyundai_a), CAR.SONATA_HYBRID: HyundaiCarInfo("Hyundai Sonata Hybrid 2020-22", "All", harness=Harness.hyundai_a),
CAR.IONIQ_5: HyundaiCarInfo("Hyundai Ioniq 5 2022", "Highway Driving Assist II", harness=Harness.hyundai_q), CAR.IONIQ_5: HyundaiCarInfo("Hyundai Ioniq 5 2022", "Highway Driving Assist II", harness=Harness.hyundai_q),
CAR.TUCSON_HYBRID_4TH_GEN: HyundaiCarInfo("Hyundai Tucson Hybrid 2022", "All", harness=Harness.hyundai_n),
# Kia # Kia
CAR.KIA_FORTE: [ CAR.KIA_FORTE: [
HyundaiCarInfo("Kia Forte 2018", harness=Harness.hyundai_b), HyundaiCarInfo("Kia Forte 2018", harness=Harness.hyundai_b),
HyundaiCarInfo("Kia Forte 2019-21", "All", harness=Harness.hyundai_g), HyundaiCarInfo("Kia Forte 2019-21", harness=Harness.hyundai_g),
], ],
CAR.KIA_K5_2021: HyundaiCarInfo("Kia K5 2021-22", "Smart Cruise Control (SCC)", harness=Harness.hyundai_a), CAR.KIA_K5_2021: HyundaiCarInfo("Kia K5 2021-22", "Smart Cruise Control (SCC)", harness=Harness.hyundai_a),
CAR.KIA_NIRO_EV: [ CAR.KIA_NIRO_EV: [
@ -141,7 +149,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
HyundaiCarInfo("Kia Niro Electric 2021", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_c), HyundaiCarInfo("Kia Niro Electric 2021", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_c),
HyundaiCarInfo("Kia Niro Electric 2022", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_h), HyundaiCarInfo("Kia Niro Electric 2022", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_h),
], ],
CAR.KIA_NIRO_HEV: HyundaiCarInfo("Kia Niro Plug-in Hybrid 2018-19", min_enable_speed=10. * CV.MPH_TO_MS, harness=Harness.hyundai_c), CAR.KIA_NIRO_PHEV: HyundaiCarInfo("Kia Niro Plug-in Hybrid 2018-19", min_enable_speed=10. * CV.MPH_TO_MS, harness=Harness.hyundai_c),
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),
@ -390,7 +398,7 @@ FW_VERSIONS = {
b'\xf1\x8799110L0000\xf1\x00DN8_ SCC F-CUP 1.00 1.00 99110-L0000 ', b'\xf1\x8799110L0000\xf1\x00DN8_ SCC F-CUP 1.00 1.00 99110-L0000 ',
b'\xf1\x8799110L0000\xf1\x00DN8_ SCC FHCUP 1.00 1.00 99110-L0000 ', b'\xf1\x8799110L0000\xf1\x00DN8_ SCC FHCUP 1.00 1.00 99110-L0000 ',
], ],
(Ecu.esp, 0x7d1, None): [ (Ecu.abs, 0x7d1, None): [
b'\xf1\x00DN ESC \x07 106 \x07\x01 58910-L0100', b'\xf1\x00DN ESC \x07 106 \x07\x01 58910-L0100',
b'\xf1\x00DN ESC \x01 102\x19\x04\x13 58910-L1300', b'\xf1\x00DN ESC \x01 102\x19\x04\x13 58910-L1300',
b'\xf1\x00DN ESC \x03 100 \x08\x01 58910-L0300', b'\xf1\x00DN ESC \x03 100 \x08\x01 58910-L0300',
@ -510,7 +518,7 @@ FW_VERSIONS = {
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00LF__ SCC F-CUP 1.00 1.00 96401-C2200 ', b'\xf1\x00LF__ SCC F-CUP 1.00 1.00 96401-C2200 ',
], ],
(Ecu.esp, 0x7d1, None): [ (Ecu.abs, 0x7d1, None): [
b'\xf1\x00LF ESC \f 11 \x17\x01\x13 58920-C2610', b'\xf1\x00LF ESC \f 11 \x17\x01\x13 58920-C2610',
b'\xf1\x00LF ESC \t 11 \x17\x01\x13 58920-C2610', b'\xf1\x00LF ESC \t 11 \x17\x01\x13 58920-C2610',
], ],
@ -557,7 +565,7 @@ FW_VERSIONS = {
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.esp, 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 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\a\b 58910-S2650',
@ -613,14 +621,16 @@ FW_VERSIONS = {
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\x8799110S1500\xf1\x00TM__ SCC FHCUP 1.00 1.00 99110-S1500 ',
b'\xf1\x00TM__ SCC FHCUP 1.00 1.00 99110-S1500 ',
], ],
(Ecu.esp, 0x7d1, None): [ (Ecu.abs, 0x7d1, None): [
b'\xf1\x00TM ESC \x02 101 \x08\x04 58910-S2GA0', b'\xf1\x00TM ESC \x02 101 \x08\x04 58910-S2GA0',
b'\xf1\x00TM ESC \x03 101 \x08\x02 58910-S2DA0', b'\xf1\x00TM ESC \x03 101 \x08\x02 58910-S2DA0',
b'\xf1\x8758910-S2DA0\xf1\x00TM ESC \x03 101 \x08\x02 58910-S2DA0', b'\xf1\x8758910-S2DA0\xf1\x00TM ESC \x03 101 \x08\x02 58910-S2DA0',
b'\xf1\x8758910-S2GA0\xf1\x00TM ESC \x02 101 \x08\x04 58910-S2GA0', b'\xf1\x8758910-S2GA0\xf1\x00TM ESC \x02 101 \x08\x04 58910-S2GA0',
b'\xf1\x8758910-S1DA0\xf1\x00TM ESC \x1e 102 \x08\x08 58910-S1DA0', b'\xf1\x8758910-S1DA0\xf1\x00TM ESC \x1e 102 \x08\x08 58910-S1DA0',
b'\xf1\x8758910-S2GA0\xf1\x00TM ESC \x04 102!\x04\x05 58910-S2GA0', b'\xf1\x8758910-S2GA0\xf1\x00TM ESC \x04 102!\x04\x05 58910-S2GA0',
b'\xf1\x00TM ESC \x04 102!\x04\x05 58910-S2GA0',
], ],
(Ecu.engine, 0x7e0, None): [ (Ecu.engine, 0x7e0, None): [
b'\xf1\x82TACVN5GMI3XXXH0A', b'\xf1\x82TACVN5GMI3XXXH0A',
@ -629,6 +639,7 @@ FW_VERSIONS = {
b'\xf1\x82TMCFD5MMCXXXXG0A', b'\xf1\x82TMCFD5MMCXXXXG0A',
b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x82TMDWN5TMD3TXXJ1A', b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x82TMDWN5TMD3TXXJ1A',
b'\xf1\x81HM6M2_0a0_G00', b'\xf1\x81HM6M2_0a0_G00',
b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x81HM6M1_0a0_J10',
], ],
(Ecu.eps, 0x7d4, None): [ (Ecu.eps, 0x7d4, None): [
b'\xf1\x00TM MDPS C 1.00 1.02 56370-S2AA0 0B19', b'\xf1\x00TM MDPS C 1.00 1.02 56370-S2AA0 0B19',
@ -648,6 +659,8 @@ FW_VERSIONS = {
b'\xf1\x87KMMYBU034207SB72x\x89\x88\x98h\x88\x98\x89\x87fhvvfWf33_\xff\x87\xff\x8f\xfa\x81\xe5\xf1\x89HT6TAF00A1\xf1\x82STM0M25GS1\x00\x00\x00\x00\x00\x00', b'\xf1\x87KMMYBU034207SB72x\x89\x88\x98h\x88\x98\x89\x87fhvvfWf33_\xff\x87\xff\x8f\xfa\x81\xe5\xf1\x89HT6TAF00A1\xf1\x82STM0M25GS1\x00\x00\x00\x00\x00\x00',
b'\xf1\x87954A02N250\x00\x00\x00\x00\x00\xf1\x81T02730A1 \xf1\x00T02601BL T02730A1 VTMPT25XXX730NS2\xa6', b'\xf1\x87954A02N250\x00\x00\x00\x00\x00\xf1\x81T02730A1 \xf1\x00T02601BL T02730A1 VTMPT25XXX730NS2\xa6',
b'\xf1\x00HT6TA290BLHT6TAF00A1STM0M25GS1\x00\x00\x00\x00\x00\x006\xd8\x97\x15', b'\xf1\x00HT6TA290BLHT6TAF00A1STM0M25GS1\x00\x00\x00\x00\x00\x006\xd8\x97\x15',
b'\xf1\x00T02601BL T02900A1 VTMPT25XXX900NS8\xb7\xaa\xfe\xfc',
b'\xf1\x87954A02N250\x00\x00\x00\x00\x00\xf1\x81T02900A1 \xf1\x00T02601BL T02900A1 VTMPT25XXX900NS8\xb7\xaa\xfe\xfc',
], ],
}, },
CAR.SANTA_FE_HEV_2022: { CAR.SANTA_FE_HEV_2022: {
@ -690,6 +703,7 @@ FW_VERSIONS = {
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
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 ',
], ],
(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',
@ -707,6 +721,7 @@ FW_VERSIONS = {
(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',
b'\xf1\x00CK MFC AT USA LHD 1.00 1.04 95740-J5000 180504', b'\xf1\x00CK MFC AT USA LHD 1.00 1.04 95740-J5000 180504',
b'\xf1\x00CK MFC AT EUR LHD 1.00 1.03 95740-J5000 170822',
], ],
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
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',
@ -716,6 +731,7 @@ FW_VERSIONS = {
b'\xf1\x87VDHLG17118862DK2\x8awWwgu\x96wVfUVwv\x97xWvfvUTGTx\x87o\xff\xc9\xed\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\x87VDHLG17118862DK2\x8awWwgu\x96wVfUVwv\x97xWvfvUTGTx\x87o\xff\xc9\xed\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\x87VDKLJ18675252DK6\x89vhgwwwwveVU\x88w\x87w\x99vgf\x97vXfgw_\xff\xc2\xfb\xf1\x89E25\x00\x00\x00\x00\x00\x00\x00\xf1\x82TCK0T33NB2', b'\xf1\x87VDKLJ18675252DK6\x89vhgwwwwveVU\x88w\x87w\x99vgf\x97vXfgw_\xff\xc2\xfb\xf1\x89E25\x00\x00\x00\x00\x00\x00\x00\xf1\x82TCK0T33NB2',
b'\xf1\x87WAJTE17552812CH4vfFffvfVeT5DwvvVVdFeegeg\x88\x88o\xff\x1a]\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00TCK2T20NB1\x19\xd2\x00\x94', b'\xf1\x87WAJTE17552812CH4vfFffvfVeT5DwvvVVdFeegeg\x88\x88o\xff\x1a]\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00TCK2T20NB1\x19\xd2\x00\x94',
b'\xf1\x87VDHLG17274082DK2wfFf\x89x\x98wUT5T\x88v\x97xgeGefTGTVvO\xff\x1c\x14\xf1\x81E19\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E19\x00\x00\x00\x00\x00\x00\x00SCK0T33UB2\xee[\x97S',
], ],
}, },
CAR.PALISADE: { CAR.PALISADE: {
@ -728,7 +744,7 @@ FW_VERSIONS = {
b'\xf1\x00LX2_ SCC FHCUP 1.00 1.05 99110-S8100 ', b'\xf1\x00LX2_ SCC FHCUP 1.00 1.05 99110-S8100 ',
b'\xf1\x00ON__ FCA FHCUP 1.00 1.02 99110-S9100 ', b'\xf1\x00ON__ FCA FHCUP 1.00 1.02 99110-S9100 ',
], ],
(Ecu.esp, 0x7d1, None): [ (Ecu.abs, 0x7d1, None): [
b'\xf1\x00LX ESC \x01 103\x19\t\x10 58910-S8360', b'\xf1\x00LX ESC \x01 103\x19\t\x10 58910-S8360',
b'\xf1\x00LX ESC \x01 1031\t\x10 58910-S8360', b'\xf1\x00LX ESC \x01 1031\t\x10 58910-S8360',
b'\xf1\x00LX ESC \x0b 101\x19\x03\x17 58910-S8330', b'\xf1\x00LX ESC \x0b 101\x19\x03\x17 58910-S8330',
@ -810,6 +826,7 @@ FW_VERSIONS = {
b"\xf1\x87LBLUFN622950KF36\xa8\x88\x88\x88\x87w\x87xh\x99\x96\x89\x88\x99\x98\x89\x88\x99\x98\x89\x87o\xf6\xff\x98\x88o\xffx'\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB3\xd1\xc3\xf8\xa8", b"\xf1\x87LBLUFN622950KF36\xa8\x88\x88\x88\x87w\x87xh\x99\x96\x89\x88\x99\x98\x89\x88\x99\x98\x89\x87o\xf6\xff\x98\x88o\xffx'\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB3\xd1\xc3\xf8\xa8",
b'\xf1\x87LDMVBN950669KF37\x97www\x96fffy\x99\xa7\x99\xa9\x99\xaa\x99g\x88\x96x\xb8\x8f\xf9\xffTD/\xff\xa7\xcb\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB5\xb9\x94\xe8\x89', b'\xf1\x87LDMVBN950669KF37\x97www\x96fffy\x99\xa7\x99\xa9\x99\xaa\x99g\x88\x96x\xb8\x8f\xf9\xffTD/\xff\xa7\xcb\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB5\xb9\x94\xe8\x89',
b'\xf1\x87LDLVAA4478824HH1\x87wwwvfvg\x89\x99\xa8\x99w\x88\x87x\x89\x99\xa8\x99\xa6o\xfa\xfffU/\xffu\x92\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00TON4G38NB2[v\\\xb6', b'\xf1\x87LDLVAA4478824HH1\x87wwwvfvg\x89\x99\xa8\x99w\x88\x87x\x89\x99\xa8\x99\xa6o\xfa\xfffU/\xffu\x92\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00TON4G38NB2[v\\\xb6',
b'\xf1\x87LDMVBN871852KF37\xb9\x99\x99\x99\xa8\x88\x88\x88y\x99\xa7\x99x\x99\xa7\x89\x88\x88\x98\x88\x89o\xf7\xff\xaa\x88o\xff\x0e\xed\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB5\xb9\x94\xe8\x89',
], ],
}, },
CAR.VELOSTER: { CAR.VELOSTER: {
@ -817,7 +834,7 @@ FW_VERSIONS = {
b'\xf1\x00JS__ SCC H-CUP 1.00 1.02 95650-J3200 ', b'\xf1\x00JS__ SCC H-CUP 1.00 1.02 95650-J3200 ',
b'\xf1\x00JS__ SCC HNCUP 1.00 1.02 95650-J3100 ', b'\xf1\x00JS__ SCC HNCUP 1.00 1.02 95650-J3100 ',
], ],
(Ecu.esp, 0x7d1, None): [ (Ecu.abs, 0x7d1, None): [
b'\xf1\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x00\x00\x00\x00\x00\x00\x00',
b'\xf1\x816V8RAC00121.ELF\xf1\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x816V8RAC00121.ELF\xf1\x00\x00\x00\x00\x00\x00\x00',
], ],
@ -878,7 +895,7 @@ FW_VERSIONS = {
}, },
CAR.KONA: { CAR.KONA: {
(Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00OS__ SCC F-CUP 1.00 1.00 95655-J9200 ', ], (Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00OS__ SCC F-CUP 1.00 1.00 95655-J9200 ', ],
(Ecu.esp, 0x7d1, None): [b'\xf1\x816V5RAK00018.ELF\xf1\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.abs, 0x7d1, None): [b'\xf1\x816V5RAK00018.ELF\xf1\x00\x00\x00\x00\x00\x00\x00', ],
(Ecu.engine, 0x7e0, None): [b'"\x01TOS-0NU06F301J02', ], (Ecu.engine, 0x7e0, None): [b'"\x01TOS-0NU06F301J02', ],
(Ecu.eps, 0x7d4, None): [b'\xf1\x00OS MDPS C 1.00 1.05 56310J9030\x00 4OSDC105', ], (Ecu.eps, 0x7d4, None): [b'\xf1\x00OS MDPS C 1.00 1.05 56310J9030\x00 4OSDC105', ],
(Ecu.fwdCamera, 0x7c4, None): [b'\xf1\x00OS9 LKAS AT USA LHD 1.00 1.00 95740-J9300 g21', ], (Ecu.fwdCamera, 0x7c4, None): [b'\xf1\x00OS9 LKAS AT USA LHD 1.00 1.00 95740-J9300 g21', ],
@ -893,7 +910,7 @@ FW_VERSIONS = {
b'\xf1\x816U2V7051\000\000\xf1\0006U2V0_C2\000\0006U2V7051\000\000DCD0T14US1\000\000\000\000', b'\xf1\x816U2V7051\000\000\xf1\0006U2V0_C2\000\0006U2V7051\000\000DCD0T14US1\000\000\000\000',
b'\xf1\x816U2V7051\x00\x00\xf1\x006U2V0_C2\x00\x006U2V7051\x00\x00DCD0T14US1U\x867Z', b'\xf1\x816U2V7051\x00\x00\xf1\x006U2V0_C2\x00\x006U2V7051\x00\x00DCD0T14US1U\x867Z',
], ],
(Ecu.esp, 0x7D1, None): [b'\xf1\000CD ESC \003 102\030\b\005 58920-J7350', ], (Ecu.abs, 0x7D1, None): [b'\xf1\000CD ESC \003 102\030\b\005 58920-J7350', ],
}, },
CAR.KIA_FORTE: { CAR.KIA_FORTE: {
(Ecu.eps, 0x7D4, None): [ (Ecu.eps, 0x7D4, None): [
@ -911,7 +928,7 @@ FW_VERSIONS = {
b'\x01TBDM1NU06F200H01', b'\x01TBDM1NU06F200H01',
b'391182B945\x00', b'391182B945\x00',
], ],
(Ecu.esp, 0x7d1, None): [ (Ecu.abs, 0x7d1, None): [
b'\xf1\x816VGRAH00018.ELF\xf1\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x816VGRAH00018.ELF\xf1\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
@ -935,7 +952,7 @@ FW_VERSIONS = {
b'\xf1\x00DL3 MFC AT USA LHD 1.00 1.03 99210-L3000 200915', b'\xf1\x00DL3 MFC AT USA LHD 1.00 1.03 99210-L3000 200915',
b'\xf1\x00DL3 MFC AT USA LHD 1.00 1.04 99210-L3000 210208', b'\xf1\x00DL3 MFC AT USA LHD 1.00 1.04 99210-L3000 210208',
], ],
(Ecu.esp, 0x7D1, None): [ (Ecu.abs, 0x7D1, None): [
b'\xf1\000DL ESC \006 101 \004\002 58910-L3200', b'\xf1\000DL ESC \006 101 \004\002 58910-L3200',
b'\xf1\x8758910-L3200\xf1\000DL ESC \006 101 \004\002 58910-L3200', b'\xf1\x8758910-L3200\xf1\000DL ESC \006 101 \004\002 58910-L3200',
b'\xf1\x8758910-L3800\xf1\x00DL ESC \t 101 \x07\x02 58910-L3800', b'\xf1\x8758910-L3800\xf1\x00DL ESC \t 101 \x07\x02 58910-L3800',
@ -955,7 +972,7 @@ FW_VERSIONS = {
], ],
}, },
CAR.KONA_EV: { CAR.KONA_EV: {
(Ecu.esp, 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',
b'\xf1\x00OS IEB \x01 212 \x11\x13 58520-K4000', b'\xf1\x00OS IEB \x01 212 \x11\x13 58520-K4000',
b'\xf1\x00OS IEB \x02 212 \x11\x13 58520-K4000', b'\xf1\x00OS IEB \x02 212 \x11\x13 58520-K4000',
@ -982,7 +999,7 @@ FW_VERSIONS = {
], ],
}, },
CAR.KONA_EV_2022: { CAR.KONA_EV_2022: {
(Ecu.esp, 0x7D1, None): [ (Ecu.abs, 0x7D1, None): [
b'\xf1\x8758520-K4010\xf1\x00OS IEB \x02 101 \x11\x13 58520-K4010', b'\xf1\x8758520-K4010\xf1\x00OS IEB \x02 101 \x11\x13 58520-K4010',
b'\xf1\x8758520-K4010\xf1\x00OS IEB \x04 101 \x11\x13 58520-K4010', b'\xf1\x8758520-K4010\xf1\x00OS IEB \x04 101 \x11\x13 58520-K4010',
b'\xf1\x8758520-K4010\xf1\x00OS IEB \x03 101 \x11\x13 58520-K4010', b'\xf1\x8758520-K4010\xf1\x00OS IEB \x03 101 \x11\x13 58520-K4010',
@ -1010,6 +1027,7 @@ FW_VERSIONS = {
b'\xf1\x00DEev SCC F-CUP 1.00 1.02 96400-Q4000 ', b'\xf1\x00DEev SCC F-CUP 1.00 1.02 96400-Q4000 ',
b'\xf1\x00DEev SCC F-CUP 1.00 1.02 96400-Q4100 ', b'\xf1\x00DEev SCC F-CUP 1.00 1.02 96400-Q4100 ',
b'\xf1\x00DEev SCC F-CUP 1.00 1.03 96400-Q4100 ', b'\xf1\x00DEev SCC F-CUP 1.00 1.03 96400-Q4100 ',
b'\xf1\x00DEev SCC FHCUP 1.00 1.03 96400-Q4000 ',
b'\xf1\x8799110Q4000\xf1\x00DEev SCC F-CUP 1.00 1.00 99110-Q4000 ', b'\xf1\x8799110Q4000\xf1\x00DEev SCC F-CUP 1.00 1.00 99110-Q4000 ',
b'\xf1\x8799110Q4100\xf1\x00DEev SCC F-CUP 1.00 1.00 99110-Q4100 ', b'\xf1\x8799110Q4100\xf1\x00DEev SCC F-CUP 1.00 1.00 99110-Q4100 ',
b'\xf1\x8799110Q4500\xf1\x00DEev SCC F-CUP 1.00 1.00 99110-Q4500 ', b'\xf1\x8799110Q4500\xf1\x00DEev SCC F-CUP 1.00 1.00 99110-Q4500 ',
@ -1029,9 +1047,10 @@ FW_VERSIONS = {
b'\xf1\x00DEE MFC AT USA LHD 1.00 1.03 95740-Q4000 180821', b'\xf1\x00DEE MFC AT USA LHD 1.00 1.03 95740-Q4000 180821',
b'\xf1\x00DEE MFC AT USA LHD 1.00 1.01 99211-Q4500 210428', b'\xf1\x00DEE MFC AT USA LHD 1.00 1.01 99211-Q4500 210428',
b'\xf1\x00DEE MFC AT EUR LHD 1.00 1.03 95740-Q4000 180821', b'\xf1\x00DEE MFC AT EUR LHD 1.00 1.03 95740-Q4000 180821',
b'\xf1\x00DEE MFC AT KOR LHD 1.00 1.03 95740-Q4000 180821',
], ],
}, },
CAR.KIA_NIRO_HEV: { CAR.KIA_NIRO_PHEV: {
(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',
@ -1074,7 +1093,7 @@ FW_VERSIONS = {
}, },
CAR.KIA_SELTOS: { CAR.KIA_SELTOS: {
(Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x8799110Q5100\xf1\000SP2_ SCC FHCUP 1.01 1.05 99110-Q5100 ',], (Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x8799110Q5100\xf1\000SP2_ SCC FHCUP 1.01 1.05 99110-Q5100 ',],
(Ecu.esp, 0x7d1, None): [ (Ecu.abs, 0x7d1, None): [
b'\xf1\x8758910-Q5450\xf1\000SP ESC \a 101\031\t\005 58910-Q5450', b'\xf1\x8758910-Q5450\xf1\000SP ESC \a 101\031\t\005 58910-Q5450',
b'\xf1\x8758910-Q5450\xf1\000SP ESC \t 101\031\t\005 58910-Q5450', b'\xf1\x8758910-Q5450\xf1\000SP ESC \t 101\031\t\005 58910-Q5450',
], ],
@ -1102,7 +1121,7 @@ FW_VERSIONS = {
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00JF__ SCC F-CUP 1.00 1.00 96400-D4110 ', b'\xf1\x00JF__ SCC F-CUP 1.00 1.00 96400-D4110 ',
], ],
(Ecu.esp, 0x7d1, None): [ (Ecu.abs, 0x7d1, None): [
b'\xf1\x00JF ESC \x0b 11 \x18\x030 58920-D5180', b'\xf1\x00JF ESC \x0b 11 \x18\x030 58920-D5180',
], ],
(Ecu.engine, 0x7e0, None): [ (Ecu.engine, 0x7e0, None): [
@ -1137,11 +1156,13 @@ FW_VERSIONS = {
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',
], ],
(Ecu.esp, 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-AB800\xf1\x00CN ESC \t 101 \x10\x03 58910-AB800',
b'\xf1\x8758910-AA800\xf1\x00CN ESC \t 105 \x10\x03 58910-AA800',
], ],
(Ecu.transmission, 0x7e1, None): [ (Ecu.transmission, 0x7e1, None): [
b'\xf1\x00HT6WA280BLHT6VA640A1CCN0N20NS5\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x00HT6WA280BLHT6VA640A1CCN0N20NS5\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@ -1156,7 +1177,7 @@ FW_VERSIONS = {
b'\xf1\x82CNCWD0AMFCXCSFFA', b'\xf1\x82CNCWD0AMFCXCSFFA',
b'\xf1\x82CNCWD0AMFCXCSFFB', b'\xf1\x82CNCWD0AMFCXCSFFB',
b'\xf1\x82CNCVD0AMFCXCSFFB', b'\xf1\x82CNCVD0AMFCXCSFFB',
b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x82CNDWD0AMFCXCSG8A', b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x81HM6M2_0a0_G80',
], ],
}, },
CAR.ELANTRA_HEV_2021: { CAR.ELANTRA_HEV_2021: {
@ -1183,7 +1204,7 @@ FW_VERSIONS = {
] ]
}, },
CAR.KONA_HEV: { CAR.KONA_HEV: {
(Ecu.esp, 0x7d1, None): [ (Ecu.abs, 0x7d1, None): [
b'\xf1\x00OS IEB \x01 104 \x11 58520-CM000', b'\xf1\x00OS IEB \x01 104 \x11 58520-CM000',
], ],
(Ecu.fwdRadar, 0x7d0, None): [ (Ecu.fwdRadar, 0x7d0, None): [
@ -1237,7 +1258,7 @@ FW_VERSIONS = {
(Ecu.fwdCamera, 0x7c4, None): [ (Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00UMP LKAS AT USA LHD 1.01 1.01 95740-C6550 d01' b'\xf1\x00UMP LKAS AT USA LHD 1.01 1.01 95740-C6550 d01'
], ],
(Ecu.esp, 0x7d1, None): [ (Ecu.abs, 0x7d1, None): [
b'\xf1\x00UM ESC \x0c 12 \x18\x05\x06 58910-C6330' b'\xf1\x00UM ESC \x0c 12 \x18\x05\x06 58910-C6330'
], ],
(Ecu.fwdRadar, 0x7D0, None): [ (Ecu.fwdRadar, 0x7D0, None): [
@ -1251,7 +1272,7 @@ FW_VERSIONS = {
], ],
}, },
CAR.KIA_EV6: { CAR.KIA_EV6: {
(Ecu.esp, 0x7d1, None): [ (Ecu.abs, 0x7d1, None): [
b'\xf1\x8758520CV100\xf1\x00CV IEB \x02 101!\x10\x18 58520-CV100', b'\xf1\x8758520CV100\xf1\x00CV IEB \x02 101!\x10\x18 58520-CV100',
], ],
(Ecu.eps, 0x7d4, None): [ (Ecu.eps, 0x7d4, None): [
@ -1266,9 +1287,11 @@ FW_VERSIONS = {
], ],
}, },
CAR.IONIQ_5: { CAR.IONIQ_5: {
(Ecu.esp, 0x7d1, None): [ (Ecu.abs, 0x7d1, None): [
b'\xf1\x00NE1 IEB \x07 106!\x11) 58520-GI010', b'\xf1\x00NE1 IEB \x07 106!\x11) 58520-GI010',
b'\xf1\x8758520GI010\xf1\x00NE1 IEB \x07 106!\x11) 58520-GI010', b'\xf1\x8758520GI010\xf1\x00NE1 IEB \x07 106!\x11) 58520-GI010',
b'\xf1\x00NE1 IEB \x08 104!\x04\x05 58520-GI000',
b'\xf1\x8758520GI000\xf1\x00NE1 IEB \x08 104!\x04\x05 58520-GI000',
], ],
(Ecu.eps, 0x7d4, None): [ (Ecu.eps, 0x7d4, None): [
b'\xf1\x00NE MDPS R 1.00 1.06 57700GI000 4NEDR106', b'\xf1\x00NE MDPS R 1.00 1.06 57700GI000 4NEDR106',
@ -1280,6 +1303,22 @@ FW_VERSIONS = {
], ],
(Ecu.fwdCamera, 0x7c4, None): [ (Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.02 99211-GI010 211206', b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.02 99211-GI010 211206',
b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.06 99211-GI000 210813',
],
},
CAR.TUCSON_HYBRID_4TH_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9240 14Q',
],
(Ecu.eps, 0x7d4, None): [
b'\xf1\x00NX4 MDPS C 1.00 1.01 56300-P0100 2228',
],
(Ecu.engine, 0x7e0, None): [
b'\xf1\x87391312MND0',
],
(Ecu.transmission, 0x7e1, None): [
b'\xf1\x00PSBG2441 G19_Rev\x00\x00\x00SNX4T16XXHS01NS2lS\xdfa',
b'\xf1\x8795441-3D220\x00\xf1\x81G19_Rev\x00\x00\x00\xf1\x00PSBG2441 G19_Rev\x00\x00\x00SNX4T16XXHS01NS2lS\xdfa',
], ],
}, },
} }
@ -1293,18 +1332,18 @@ FEATURES = {
# which message has the gear # which message has the gear
"use_cluster_gears": {CAR.ELANTRA, CAR.ELANTRA_GT_I30, CAR.KONA}, "use_cluster_gears": {CAR.ELANTRA, CAR.ELANTRA_GT_I30, CAR.KONA},
"use_tcu_gears": {CAR.KIA_OPTIMA, CAR.SONATA_LF, CAR.VELOSTER, CAR.TUCSON}, "use_tcu_gears": {CAR.KIA_OPTIMA, CAR.SONATA_LF, CAR.VELOSTER, CAR.TUCSON},
"use_elect_gears": {CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV, 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},
# these cars use the FCA11 message for the AEB and FCW signals, all others use SCC12 # 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.ELANTRA_GT_I30, 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}, "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.ELANTRA_GT_I30, 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},
} }
CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5} CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_HYBRID_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_HEV, 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} # 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} # 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} EV_CAR = {CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.KIA_NIRO_EV, CAR.KONA_EV_2022}
# 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
@ -1331,7 +1370,7 @@ DBC = {
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_NIRO_EV: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar'), CAR.KIA_NIRO_EV: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar'),
CAR.KIA_NIRO_HEV: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar'), CAR.KIA_NIRO_PHEV: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar'),
CAR.KIA_NIRO_HEV_2021: dbc_dict('hyundai_kia_generic', None), CAR.KIA_NIRO_HEV_2021: dbc_dict('hyundai_kia_generic', None),
CAR.KIA_OPTIMA: dbc_dict('hyundai_kia_generic', None), CAR.KIA_OPTIMA: dbc_dict('hyundai_kia_generic', None),
CAR.KIA_OPTIMA_H: dbc_dict('hyundai_kia_generic', None), CAR.KIA_OPTIMA_H: dbc_dict('hyundai_kia_generic', None),
@ -1352,7 +1391,8 @@ DBC = {
CAR.PALISADE: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar'), CAR.PALISADE: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar'),
CAR.VELOSTER: dbc_dict('hyundai_kia_generic', None), CAR.VELOSTER: dbc_dict('hyundai_kia_generic', None),
CAR.KIA_CEED: dbc_dict('hyundai_kia_generic', None), CAR.KIA_CEED: dbc_dict('hyundai_kia_generic', None),
CAR.KIA_EV6: dbc_dict('kia_ev6', None), CAR.KIA_EV6: dbc_dict('hyundai_canfd', None),
CAR.SONATA_HYBRID: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar'), CAR.SONATA_HYBRID: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar'),
CAR.IONIQ_5: dbc_dict('kia_ev6', None), CAR.TUCSON_HYBRID_4TH_GEN: dbc_dict('hyundai_canfd', None),
CAR.IONIQ_5: dbc_dict('hyundai_canfd', None),
} }

@ -9,7 +9,7 @@ from common.basedir import BASEDIR
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
from common.kalman.simple_kalman import KF1D from common.kalman.simple_kalman import KF1D
from common.realtime import DT_CTRL from common.realtime import DT_CTRL
from selfdrive.car import gen_empty_fingerprint from selfdrive.car import create_button_enable_events, gen_empty_fingerprint
from selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX from selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX
from selfdrive.controls.lib.events import Events from selfdrive.controls.lib.events import Events
from selfdrive.controls.lib.vehicle_model import VehicleModel from selfdrive.controls.lib.vehicle_model import VehicleModel
@ -107,11 +107,14 @@ class CarInterfaceBase(ABC):
ret = car.CarParams.new_message() ret = car.CarParams.new_message()
ret.carFingerprint = candidate ret.carFingerprint = candidate
# Car docs fields
ret.maxLateralAccel = get_torque_params(candidate)['MAX_LAT_ACCEL_MEASURED']
ret.autoResumeSng = True # describes whether car can resume from a stop automatically
# standard ALC params # standard ALC params
ret.steerControlType = car.CarParams.SteerControlType.torque ret.steerControlType = car.CarParams.SteerControlType.torque
ret.minSteerSpeed = 0. ret.minSteerSpeed = 0.
ret.wheelSpeedFactor = 1.0 ret.wheelSpeedFactor = 1.0
ret.maxLateralAccel = get_torque_params(candidate)['MAX_LAT_ACCEL_MEASURED']
ret.pcmCruise = True # openpilot's state is tied to the PCM's cruise state on most cars ret.pcmCruise = True # openpilot's state is tied to the PCM's cruise state on most cars
ret.minEnableSpeed = -1. # enable is done by stock ACC, so ignore this ret.minEnableSpeed = -1. # enable is done by stock ACC, so ignore this
@ -213,6 +216,9 @@ class CarInterfaceBase(ABC):
if cs_out.accFaulted: if cs_out.accFaulted:
events.add(EventName.accFaulted) events.add(EventName.accFaulted)
# Handle button presses
events.events.extend(create_button_enable_events(cs_out.buttonEvents, pcm_cruise=self.CP.pcmCruise))
# Handle permanent and temporary steering faults # Handle permanent and temporary steering faults
self.steering_unpressed = 0 if cs_out.steeringPressed else self.steering_unpressed + 1 self.steering_unpressed = 0 if cs_out.steeringPressed else self.steering_unpressed + 1
if cs_out.steerFaultTemporary: if cs_out.steerFaultTemporary:
@ -265,12 +271,12 @@ class CarStateBase(ABC):
self.left_blinker_prev = False self.left_blinker_prev = False
self.right_blinker_prev = False self.right_blinker_prev = False
# Q = np.matrix([[10.0, 0.0], [0.0, 100.0]]) # Q = np.matrix([[0.0, 0.0], [0.0, 100.0]])
# R = 1e3 # R = 0.3
self.v_ego_kf = KF1D(x0=[[0.0], [0.0]], self.v_ego_kf = KF1D(x0=[[0.0], [0.0]],
A=[[1.0, DT_CTRL], [0.0, 1.0]], A=[[1.0, DT_CTRL], [0.0, 1.0]],
C=[1.0, 0.0], C=[1.0, 0.0],
K=[[0.12287673], [0.29666309]]) K=[[0.17406039], [1.65925647]])
def update_speed_kf(self, v_ego_raw): def update_speed_kf(self, v_ego_raw):
if abs(v_ego_raw - self.v_ego_kf.x[0][0]) > 2.0: # Prevent large accelerations when car starts at non zero speed if abs(v_ego_raw - self.v_ego_kf.x[0][0]) > 2.0: # Prevent large accelerations when car starts at non zero speed

@ -40,7 +40,7 @@ CAR_INFO: Dict[str, Union[MazdaCarInfo, List[MazdaCarInfo]]] = {
CAR.CX9: MazdaCarInfo("Mazda CX-9 2016-20"), CAR.CX9: MazdaCarInfo("Mazda CX-9 2016-20"),
CAR.MAZDA3: MazdaCarInfo("Mazda 3 2017-18"), CAR.MAZDA3: MazdaCarInfo("Mazda 3 2017-18"),
CAR.MAZDA6: MazdaCarInfo("Mazda 6 2017-20"), CAR.MAZDA6: MazdaCarInfo("Mazda 6 2017-20"),
CAR.CX9_2021: MazdaCarInfo("Mazda CX-9 2021-22"), CAR.CX9_2021: MazdaCarInfo("Mazda CX-9 2021-22", video_link="https://youtu.be/dA3duO4a0O4"),
CAR.CX5_2022: MazdaCarInfo("Mazda CX-5 2022"), CAR.CX5_2022: MazdaCarInfo("Mazda CX-5 2022"),
} }
@ -72,7 +72,7 @@ FW_VERSIONS = {
(Ecu.fwdRadar, 0x764, None): [ (Ecu.fwdRadar, 0x764, None): [
b'K131-67XK2-F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'K131-67XK2-F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x760, None): [ (Ecu.abs, 0x760, None): [
b'KSD5-437K2-A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'KSD5-437K2-A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.fwdCamera, 0x706, None): [ (Ecu.fwdCamera, 0x706, None): [
@ -116,7 +116,7 @@ FW_VERSIONS = {
b'K131-67XK2-E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'K131-67XK2-E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'K131-67XK2-F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'K131-67XK2-F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x760, None): [ (Ecu.abs, 0x760, None): [
b'K123-437K2-E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'K123-437K2-E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'KBJ5-437K2-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'KBJ5-437K2-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'KL2K-437K2-A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'KL2K-437K2-A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@ -173,7 +173,7 @@ FW_VERSIONS = {
b'TK80-67XK2-E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'TK80-67XK2-E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'TK80-67XK2-F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'TK80-67XK2-F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x760, None): [ (Ecu.abs, 0x760, None): [
b'TA0B-437K2-C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'TA0B-437K2-C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'TK79-437K2-E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'TK79-437K2-E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'TK79-437K2-F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'TK79-437K2-F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@ -217,7 +217,7 @@ FW_VERSIONS = {
b'GHP9-67Y10---41\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'GHP9-67Y10---41\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'K131-67XK2-C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'K131-67XK2-C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x760, None): [ (Ecu.abs, 0x760, None): [
b'B45A-437AS-0-08\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'B45A-437AS-0-08\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.fwdCamera, 0x706, None): [ (Ecu.fwdCamera, 0x706, None): [
@ -248,7 +248,7 @@ FW_VERSIONS = {
b'K131-67XK2-A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'K131-67XK2-A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'K131-67XK2-E\000\000\000\000\000\000\000\000\000\000\000\000', b'K131-67XK2-E\000\000\000\000\000\000\000\000\000\000\000\000',
], ],
(Ecu.esp, 0x760, None): [ (Ecu.abs, 0x760, None): [
b'GBVH-437K2-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'GBVH-437K2-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'GDDM-437K2-A\000\000\000\000\000\000\000\000\000\000\000\000', b'GDDM-437K2-A\000\000\000\000\000\000\000\000\000\000\000\000',
], ],
@ -275,7 +275,7 @@ FW_VERSIONS = {
b'K131-67XK2-E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'K131-67XK2-E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'K131-67XK2-F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'K131-67XK2-F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x760, None): [ (Ecu.abs, 0x760, None): [
b'TA0B-437K2-C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'TA0B-437K2-C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.fwdCamera, 0x706, None): [ (Ecu.fwdCamera, 0x706, None): [

@ -13,28 +13,27 @@ class CarInterface(CarInterfaceBase):
ret = CarInterfaceBase.get_std_params(candidate, fingerprint) ret = CarInterfaceBase.get_std_params(candidate, fingerprint)
ret.carName = "nissan" ret.carName = "nissan"
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.nissan)] ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.nissan)]
ret.autoResumeSng = False
ret.steerLimitTimer = 1.0 ret.steerLimitTimer = 1.0
ret.steerActuatorDelay = 0.1 ret.steerActuatorDelay = 0.1
ret.steerRatio = 17
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
ret.wheelbase = 2.705 ret.wheelbase = 2.705
ret.centerToFront = ret.wheelbase * 0.44 ret.centerToFront = ret.wheelbase * 0.44
ret.steerRatio = 17
elif candidate in (CAR.LEAF, CAR.LEAF_IC): elif candidate in (CAR.LEAF, CAR.LEAF_IC):
ret.mass = 1610 + STD_CARGO_KG ret.mass = 1610 + STD_CARGO_KG
ret.wheelbase = 2.705 ret.wheelbase = 2.705
ret.centerToFront = ret.wheelbase * 0.44 ret.centerToFront = ret.wheelbase * 0.44
ret.steerRatio = 17
elif candidate == CAR.ALTIMA: elif candidate == CAR.ALTIMA:
# Altima has EPS on C-CAN unlike the others that have it on V-CAN # Altima has EPS on C-CAN unlike the others that have it on V-CAN
ret.safetyConfigs[0].safetyParam = 1 # EPS is on alternate bus ret.safetyConfigs[0].safetyParam = 1 # EPS is on alternate bus
ret.mass = 1492 + STD_CARGO_KG ret.mass = 1492 + STD_CARGO_KG
ret.wheelbase = 2.824 ret.wheelbase = 2.824
ret.centerToFront = ret.wheelbase * 0.44 ret.centerToFront = ret.wheelbase * 0.44
ret.steerRatio = 17
ret.steerControlType = car.CarParams.SteerControlType.angle ret.steerControlType = car.CarParams.SteerControlType.angle
ret.radarOffCan = True ret.radarOffCan = True

@ -24,10 +24,7 @@ def create_steering_control(packer, apply_steer, frame, steer_on, lkas_max_torqu
def create_acc_cancel_cmd(packer, car_fingerprint, cruise_throttle_msg): def create_acc_cancel_cmd(packer, car_fingerprint, cruise_throttle_msg):
values = copy.copy(cruise_throttle_msg) values = copy.copy(cruise_throttle_msg)
can_bus = 2 can_bus = 1 if car_fingerprint == CAR.ALTIMA else 2
if car_fingerprint == CAR.ALTIMA:
can_bus = 1
values["CANCEL_BUTTON"] = 1 values["CANCEL_BUTTON"] = 1
values["NO_BUTTON_PRESSED"] = 0 values["NO_BUTTON_PRESSED"] = 0

@ -95,7 +95,7 @@ FW_VERSIONS = {
b'5SH1BDB\x04\x18\x00\x00\x00\x00\x00_-?\x04\x91\xf2\x00\x00\x00\x80', b'5SH1BDB\x04\x18\x00\x00\x00\x00\x00_-?\x04\x91\xf2\x00\x00\x00\x80',
b'5SK0ADB\x04\x18\x00\x00\x00\x00\x00_(5\x07\x9aQ\x00\x00\x00\x80', b'5SK0ADB\x04\x18\x00\x00\x00\x00\x00_(5\x07\x9aQ\x00\x00\x00\x80',
], ],
(Ecu.esp, 0x740, None): [ (Ecu.abs, 0x740, None): [
b'476605SH1D', b'476605SH1D',
b'476605SK2A', b'476605SK2A',
], ],
@ -112,7 +112,7 @@ FW_VERSIONS = {
(Ecu.fwdCamera, 0x707, None): [ (Ecu.fwdCamera, 0x707, None): [
b'284N86FR2A', b'284N86FR2A',
], ],
(Ecu.esp, 0x740, None): [ (Ecu.abs, 0x740, None): [
b'6FU1BD\x11\x02\x00\x02e\x95e\x80iX#\x01\x00\x00\x00\x00\x00\x80', b'6FU1BD\x11\x02\x00\x02e\x95e\x80iX#\x01\x00\x00\x00\x00\x00\x80',
b'6FU0AD\x11\x02\x00\x02e\x95e\x80iQ#\x01\x00\x00\x00\x00\x00\x80', b'6FU0AD\x11\x02\x00\x02e\x95e\x80iQ#\x01\x00\x00\x00\x00\x00\x80',
], ],

@ -4,7 +4,7 @@ from opendbc.can.can_define import CANDefine
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
from selfdrive.car.interfaces import CarStateBase from selfdrive.car.interfaces import CarStateBase
from opendbc.can.parser import CANParser from opendbc.can.parser import CANParser
from selfdrive.car.subaru.values import DBC, STEER_THRESHOLD, CAR, GLOBAL_GEN2, PREGLOBAL_CARS from selfdrive.car.subaru.values import DBC, CAR, GLOBAL_GEN2, PREGLOBAL_CARS
class CarState(CarStateBase): class CarState(CarStateBase):
@ -50,7 +50,9 @@ class CarState(CarStateBase):
ret.steeringAngleDeg = cp.vl["Steering_Torque"]["Steering_Angle"] ret.steeringAngleDeg = cp.vl["Steering_Torque"]["Steering_Angle"]
ret.steeringTorque = cp.vl["Steering_Torque"]["Steer_Torque_Sensor"] ret.steeringTorque = cp.vl["Steering_Torque"]["Steer_Torque_Sensor"]
ret.steeringTorqueEps = cp.vl["Steering_Torque"]["Steer_Torque_Output"] ret.steeringTorqueEps = cp.vl["Steering_Torque"]["Steer_Torque_Output"]
ret.steeringPressed = abs(ret.steeringTorque) > STEER_THRESHOLD[self.car_fingerprint]
steer_threshold = 75 if self.CP.carFingerprint in PREGLOBAL_CARS else 80
ret.steeringPressed = abs(ret.steeringTorque) > steer_threshold
cp_cruise = cp_body if self.car_fingerprint in GLOBAL_GEN2 else cp cp_cruise = cp_body if self.car_fingerprint in GLOBAL_GEN2 else cp
ret.cruiseState.enabled = cp_cruise.vl["CruiseControl"]["Cruise_Activated"] != 0 ret.cruiseState.enabled = cp_cruise.vl["CruiseControl"]["Cruise_Activated"] != 0

@ -15,6 +15,7 @@ class CarInterface(CarInterfaceBase):
ret.carName = "subaru" ret.carName = "subaru"
ret.radarOffCan = True ret.radarOffCan = True
ret.dashcamOnly = candidate in PREGLOBAL_CARS ret.dashcamOnly = candidate in PREGLOBAL_CARS
ret.autoResumeSng = False
if candidate in PREGLOBAL_CARS: if candidate in PREGLOBAL_CARS:
ret.enableBsm = 0x25c in fingerprint[0] ret.enableBsm = 0x25c in fingerprint[0]
@ -71,7 +72,7 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 14., 23.], [0., 14., 23.]] ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 14., 23.], [0., 14., 23.]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.01, 0.065, 0.2], [0.001, 0.015, 0.025]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.01, 0.065, 0.2], [0.001, 0.015, 0.025]]
elif candidate == CAR.OUTBACK: elif candidate in (CAR.OUTBACK, CAR.LEGACY):
ret.mass = 1568. + STD_CARGO_KG ret.mass = 1568. + STD_CARGO_KG
ret.wheelbase = 2.67 ret.wheelbase = 2.67
ret.centerToFront = ret.wheelbase * 0.5 ret.centerToFront = ret.wheelbase * 0.5

@ -35,6 +35,7 @@ class CAR:
IMPREZA_2020 = "SUBARU IMPREZA SPORT 2020" IMPREZA_2020 = "SUBARU IMPREZA SPORT 2020"
FORESTER = "SUBARU FORESTER 2019" FORESTER = "SUBARU FORESTER 2019"
OUTBACK = "SUBARU OUTBACK 6TH GEN" OUTBACK = "SUBARU OUTBACK 6TH GEN"
LEGACY = "SUBARU LEGACY 7TH GEN"
# Pre-global # Pre-global
FORESTER_PREGLOBAL = "SUBARU FORESTER 2017 - 2018" FORESTER_PREGLOBAL = "SUBARU FORESTER 2017 - 2018"
@ -52,6 +53,7 @@ class SubaruCarInfo(CarInfo):
CAR_INFO: Dict[str, Union[SubaruCarInfo, List[SubaruCarInfo]]] = { CAR_INFO: Dict[str, Union[SubaruCarInfo, List[SubaruCarInfo]]] = {
CAR.ASCENT: SubaruCarInfo("Subaru Ascent 2019-21", "All"), CAR.ASCENT: SubaruCarInfo("Subaru Ascent 2019-21", "All"),
CAR.OUTBACK: SubaruCarInfo("Subaru Outback 2020-22", "All", harness=Harness.subaru_b), CAR.OUTBACK: SubaruCarInfo("Subaru Outback 2020-22", "All", harness=Harness.subaru_b),
CAR.LEGACY: SubaruCarInfo("Subaru Legacy 2020-22", "All", harness=Harness.subaru_b),
CAR.IMPREZA: [ CAR.IMPREZA: [
SubaruCarInfo("Subaru Impreza 2017-19"), SubaruCarInfo("Subaru Impreza 2017-19"),
SubaruCarInfo("Subaru Crosstrek 2018-19", video_link="https://youtu.be/Agww7oE1k-s?t=26"), SubaruCarInfo("Subaru Crosstrek 2018-19", video_link="https://youtu.be/Agww7oE1k-s?t=26"),
@ -72,7 +74,7 @@ CAR_INFO: Dict[str, Union[SubaruCarInfo, List[SubaruCarInfo]]] = {
FW_VERSIONS = { FW_VERSIONS = {
CAR.ASCENT: { CAR.ASCENT: {
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'\xa5 \x19\x02\x00', b'\xa5 \x19\x02\x00',
b'\xa5 !\002\000', b'\xa5 !\002\000',
b'\xf1\x82\xa5 \x19\x02\x00', b'\xf1\x82\xa5 \x19\x02\x00',
@ -101,8 +103,30 @@ FW_VERSIONS = {
b'\x01\xfe\xf7\x00\x00', b'\x01\xfe\xf7\x00\x00',
], ],
}, },
CAR.LEGACY: {
(Ecu.abs, 0x7b0, None): [
b'\xa1\\ x04\x01',
b'\xa1 \x03\x03'
],
(Ecu.eps, 0x746, None): [
b'\x9b\xc0\x11\x00',
b'\x9b\xc0\x11\x02'
],
(Ecu.fwdCamera, 0x787, None): [
b'\x00\x00e\x80\x00\x1f@ \x19\x00',
b'\x00\x00e\x9a\x00\x00\x00\x00\x00\x00'
],
(Ecu.engine, 0x7e0, None): [
b'\xde\"a0\x07',
b'\xe2"aq\x07'
],
(Ecu.transmission, 0x7e1, None): [
b'\xa5\xf6\x05@\x00',
b'\xa7\xf6\x04@\x00'
],
},
CAR.IMPREZA: { CAR.IMPREZA: {
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'\x7a\x94\x3f\x90\x00', b'\x7a\x94\x3f\x90\x00',
b'\xa2 \x185\x00', b'\xa2 \x185\x00',
b'\xa2 \x193\x00', b'\xa2 \x193\x00',
@ -177,7 +201,7 @@ FW_VERSIONS = {
], ],
}, },
CAR.IMPREZA_2020: { CAR.IMPREZA_2020: {
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'\xa2 \0314\000', b'\xa2 \0314\000',
b'\xa2 \0313\000', b'\xa2 \0313\000',
b'\xa2 !i\000', b'\xa2 !i\000',
@ -215,7 +239,7 @@ FW_VERSIONS = {
], ],
}, },
CAR.FORESTER: { CAR.FORESTER: {
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'\xa3 \x18\x14\x00', b'\xa3 \x18\x14\x00',
b'\xa3 \024\000', b'\xa3 \024\000',
b'\xa3 \031\024\000', b'\xa3 \031\024\000',
@ -250,7 +274,7 @@ FW_VERSIONS = {
], ],
}, },
CAR.FORESTER_PREGLOBAL: { CAR.FORESTER_PREGLOBAL: {
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'\x7d\x97\x14\x40', b'\x7d\x97\x14\x40',
b'\xf1\x00\xbb\x0c\x04', b'\xf1\x00\xbb\x0c\x04',
], ],
@ -279,7 +303,7 @@ FW_VERSIONS = {
], ],
}, },
CAR.LEGACY_PREGLOBAL: { CAR.LEGACY_PREGLOBAL: {
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'k\x97D\x00', b'k\x97D\x00',
b'[\xba\xc4\x03', b'[\xba\xc4\x03',
b'{\x97D\x00', b'{\x97D\x00',
@ -309,7 +333,7 @@ FW_VERSIONS = {
], ],
}, },
CAR.OUTBACK_PREGLOBAL: { CAR.OUTBACK_PREGLOBAL: {
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'{\x9a\xac\x00', b'{\x9a\xac\x00',
b'k\x97\xac\x00', b'k\x97\xac\x00',
b'\x5b\xf7\xbc\x03', b'\x5b\xf7\xbc\x03',
@ -363,7 +387,7 @@ FW_VERSIONS = {
], ],
}, },
CAR.OUTBACK_PREGLOBAL_2018: { CAR.OUTBACK_PREGLOBAL_2018: {
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'\x8b\x97\xac\x00', b'\x8b\x97\xac\x00',
b'\x8b\x9a\xac\x00', b'\x8b\x9a\xac\x00',
b'\x9b\x97\xac\x00', b'\x9b\x97\xac\x00',
@ -406,7 +430,7 @@ FW_VERSIONS = {
], ],
}, },
CAR.OUTBACK: { CAR.OUTBACK: {
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'\xa1 \x06\x01', b'\xa1 \x06\x01',
b'\xa1 \a\x00', b'\xa1 \a\x00',
b'\xa1 \b\001', b'\xa1 \b\001',
@ -448,29 +472,18 @@ FW_VERSIONS = {
}, },
} }
STEER_THRESHOLD = {
CAR.ASCENT: 80,
CAR.IMPREZA: 80,
CAR.IMPREZA_2020: 80,
CAR.FORESTER: 80,
CAR.OUTBACK: 80,
CAR.FORESTER_PREGLOBAL: 75,
CAR.LEGACY_PREGLOBAL: 75,
CAR.OUTBACK_PREGLOBAL: 75,
CAR.OUTBACK_PREGLOBAL_2018: 75,
}
DBC = { DBC = {
CAR.ASCENT: dbc_dict('subaru_global_2017_generated', None), CAR.ASCENT: dbc_dict('subaru_global_2017_generated', None),
CAR.IMPREZA: dbc_dict('subaru_global_2017_generated', None), CAR.IMPREZA: dbc_dict('subaru_global_2017_generated', None),
CAR.IMPREZA_2020: dbc_dict('subaru_global_2017_generated', None), CAR.IMPREZA_2020: dbc_dict('subaru_global_2017_generated', None),
CAR.FORESTER: dbc_dict('subaru_global_2017_generated', None), CAR.FORESTER: dbc_dict('subaru_global_2017_generated', None),
CAR.OUTBACK: dbc_dict('subaru_global_2017_generated', None), CAR.OUTBACK: dbc_dict('subaru_global_2017_generated', None),
CAR.LEGACY: dbc_dict('subaru_global_2017_generated', None),
CAR.FORESTER_PREGLOBAL: dbc_dict('subaru_forester_2017_generated', None), CAR.FORESTER_PREGLOBAL: dbc_dict('subaru_forester_2017_generated', None),
CAR.LEGACY_PREGLOBAL: dbc_dict('subaru_outback_2015_generated', None), CAR.LEGACY_PREGLOBAL: dbc_dict('subaru_outback_2015_generated', None),
CAR.OUTBACK_PREGLOBAL: dbc_dict('subaru_outback_2015_generated', None), CAR.OUTBACK_PREGLOBAL: dbc_dict('subaru_outback_2015_generated', None),
CAR.OUTBACK_PREGLOBAL_2018: dbc_dict('subaru_outback_2019_generated', None), CAR.OUTBACK_PREGLOBAL_2018: dbc_dict('subaru_outback_2019_generated', None),
} }
GLOBAL_GEN2 = (CAR.OUTBACK, ) GLOBAL_GEN2 = (CAR.OUTBACK, CAR.LEGACY)
PREGLOBAL_CARS = (CAR.FORESTER_PREGLOBAL, CAR.LEGACY_PREGLOBAL, CAR.OUTBACK_PREGLOBAL, CAR.OUTBACK_PREGLOBAL_2018) PREGLOBAL_CARS = (CAR.FORESTER_PREGLOBAL, CAR.LEGACY_PREGLOBAL, CAR.OUTBACK_PREGLOBAL, CAR.OUTBACK_PREGLOBAL_2018)

@ -26,198 +26,201 @@ non_tested_cars = [
HYUNDAI.KIA_OPTIMA_H, HYUNDAI.KIA_OPTIMA_H,
] ]
TestRoute = namedtuple('TestRoute', ['route', 'car_model', 'segment'], defaults=(None,)) CarTestRoute = namedtuple('CarTestRoute', ['route', 'car_model', 'segment'], defaults=(None,))
routes = [ routes = [
TestRoute("efdf9af95e71cd84|2022-05-13--19-03-31", COMMA.BODY), CarTestRoute("efdf9af95e71cd84|2022-05-13--19-03-31", COMMA.BODY),
TestRoute("0c94aa1e1296d7c6|2021-05-05--19-48-37", CHRYSLER.JEEP_CHEROKEE), CarTestRoute("0c94aa1e1296d7c6|2021-05-05--19-48-37", CHRYSLER.JEEP_CHEROKEE),
TestRoute("91dfedae61d7bd75|2021-05-22--20-07-52", CHRYSLER.JEEP_CHEROKEE_2019), CarTestRoute("91dfedae61d7bd75|2021-05-22--20-07-52", CHRYSLER.JEEP_CHEROKEE_2019),
TestRoute("420a8e183f1aed48|2020-03-05--07-15-29", CHRYSLER.PACIFICA_2017_HYBRID), CarTestRoute("420a8e183f1aed48|2020-03-05--07-15-29", CHRYSLER.PACIFICA_2017_HYBRID),
TestRoute("43a685a66291579b|2021-05-27--19-47-29", CHRYSLER.PACIFICA_2018), CarTestRoute("43a685a66291579b|2021-05-27--19-47-29", CHRYSLER.PACIFICA_2018),
TestRoute("378472f830ee7395|2021-05-28--07-38-43", CHRYSLER.PACIFICA_2018_HYBRID), CarTestRoute("378472f830ee7395|2021-05-28--07-38-43", CHRYSLER.PACIFICA_2018_HYBRID),
TestRoute("8190c7275a24557b|2020-01-29--08-33-58", CHRYSLER.PACIFICA_2019_HYBRID), CarTestRoute("8190c7275a24557b|2020-01-29--08-33-58", CHRYSLER.PACIFICA_2019_HYBRID),
TestRoute("3d84727705fecd04|2021-05-25--08-38-56", CHRYSLER.PACIFICA_2020), CarTestRoute("3d84727705fecd04|2021-05-25--08-38-56", CHRYSLER.PACIFICA_2020),
TestRoute("221c253375af4ee9|2022-06-15--18-38-24", CHRYSLER.RAM_1500), CarTestRoute("221c253375af4ee9|2022-06-15--18-38-24", CHRYSLER.RAM_1500),
TestRoute("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),
#TestRoute("f1b4c567731f4a1b|2018-04-30--10-15-35", FORD.FUSION), #TestRoute("f1b4c567731f4a1b|2018-04-30--10-15-35", FORD.FUSION),
TestRoute("7cc2a8365b4dd8a9|2018-12-02--12-10-44", GM.ACADIA), CarTestRoute("7cc2a8365b4dd8a9|2018-12-02--12-10-44", GM.ACADIA),
TestRoute("aa20e335f61ba898|2019-02-05--16-59-04", GM.BUICK_REGAL), CarTestRoute("aa20e335f61ba898|2019-02-05--16-59-04", GM.BUICK_REGAL),
TestRoute("46460f0da08e621e|2021-10-26--07-21-46", GM.ESCALADE_ESV), CarTestRoute("46460f0da08e621e|2021-10-26--07-21-46", GM.ESCALADE_ESV),
TestRoute("c950e28c26b5b168|2018-05-30--22-03-41", GM.VOLT), CarTestRoute("c950e28c26b5b168|2018-05-30--22-03-41", GM.VOLT),
TestRoute("f08912a233c1584f|2022-08-11--18-02-41", GM.BOLT_EUV), CarTestRoute("f08912a233c1584f|2022-08-11--18-02-41", GM.BOLT_EUV),
CarTestRoute("38aa7da107d5d252|2022-08-15--16-01-12", GM.SILVERADO),
TestRoute("0e7a2ba168465df5|2020-10-18--14-14-22", HONDA.ACURA_RDX_3G),
TestRoute("a74b011b32b51b56|2020-07-26--17-09-36", HONDA.CIVIC), CarTestRoute("0e7a2ba168465df5|2020-10-18--14-14-22", HONDA.ACURA_RDX_3G),
TestRoute("a859a044a447c2b0|2020-03-03--18-42-45", HONDA.CRV_EU), CarTestRoute("a74b011b32b51b56|2020-07-26--17-09-36", HONDA.CIVIC),
TestRoute("68aac44ad69f838e|2021-05-18--20-40-52", HONDA.CRV), CarTestRoute("a859a044a447c2b0|2020-03-03--18-42-45", HONDA.CRV_EU),
TestRoute("14fed2e5fa0aa1a5|2021-05-25--14-59-42", HONDA.CRV_HYBRID), CarTestRoute("68aac44ad69f838e|2021-05-18--20-40-52", HONDA.CRV),
TestRoute("52f3e9ae60c0d886|2021-05-23--15-59-43", HONDA.FIT), CarTestRoute("14fed2e5fa0aa1a5|2021-05-25--14-59-42", HONDA.CRV_HYBRID),
TestRoute("2c4292a5cd10536c|2021-08-19--21-32-15", HONDA.FREED), CarTestRoute("52f3e9ae60c0d886|2021-05-23--15-59-43", HONDA.FIT),
TestRoute("03be5f2fd5c508d1|2020-04-19--18-44-15", HONDA.HRV), CarTestRoute("2c4292a5cd10536c|2021-08-19--21-32-15", HONDA.FREED),
TestRoute("917b074700869333|2021-05-24--20-40-20", HONDA.ACURA_ILX), CarTestRoute("03be5f2fd5c508d1|2020-04-19--18-44-15", HONDA.HRV),
TestRoute("81722949a62ea724|2019-04-06--15-19-25", HONDA.ODYSSEY_CHN), CarTestRoute("917b074700869333|2021-05-24--20-40-20", HONDA.ACURA_ILX),
TestRoute("08a3deb07573f157|2020-03-06--16-11-19", HONDA.ACCORD), # 1.5T CarTestRoute("81722949a62ea724|2019-04-06--15-19-25", HONDA.ODYSSEY_CHN),
TestRoute("1da5847ac2488106|2021-05-24--19-31-50", HONDA.ACCORD), # 2.0T CarTestRoute("08a3deb07573f157|2020-03-06--16-11-19", HONDA.ACCORD), # 1.5T
TestRoute("085ac1d942c35910|2021-03-25--20-11-15", HONDA.ACCORD), # 2021 with new style HUD msgs CarTestRoute("1da5847ac2488106|2021-05-24--19-31-50", HONDA.ACCORD), # 2.0T
TestRoute("07585b0da3c88459|2021-05-26--18-52-04", HONDA.ACCORDH), CarTestRoute("085ac1d942c35910|2021-03-25--20-11-15", HONDA.ACCORD), # 2021 with new style HUD msgs
TestRoute("f29e2b57a55e7ad5|2021-03-24--20-52-38", HONDA.ACCORDH), # 2021 with new style HUD msgs CarTestRoute("07585b0da3c88459|2021-05-26--18-52-04", HONDA.ACCORDH),
TestRoute("1ad763dd22ef1a0e|2020-02-29--18-37-03", HONDA.CRV_5G), CarTestRoute("f29e2b57a55e7ad5|2021-03-24--20-52-38", HONDA.ACCORDH), # 2021 with new style HUD msgs
TestRoute("0a96f86fcfe35964|2020-02-05--07-25-51", HONDA.ODYSSEY), CarTestRoute("1ad763dd22ef1a0e|2020-02-29--18-37-03", HONDA.CRV_5G),
TestRoute("d83f36766f8012a5|2020-02-05--18-42-21", HONDA.CIVIC_BOSCH_DIESEL), CarTestRoute("0a96f86fcfe35964|2020-02-05--07-25-51", HONDA.ODYSSEY),
TestRoute("f0890d16a07a236b|2021-05-25--17-27-22", HONDA.INSIGHT), CarTestRoute("d83f36766f8012a5|2020-02-05--18-42-21", HONDA.CIVIC_BOSCH_DIESEL),
TestRoute("07d37d27996096b6|2020-03-04--21-57-27", HONDA.PILOT), CarTestRoute("f0890d16a07a236b|2021-05-25--17-27-22", HONDA.INSIGHT),
TestRoute("684e8f96bd491a0e|2021-11-03--11-08-42", HONDA.PASSPORT), CarTestRoute("07d37d27996096b6|2020-03-04--21-57-27", HONDA.PILOT),
TestRoute("0a78dfbacc8504ef|2020-03-04--13-29-55", HONDA.CIVIC_BOSCH), CarTestRoute("684e8f96bd491a0e|2021-11-03--11-08-42", HONDA.PASSPORT),
TestRoute("f34a60d68d83b1e5|2020-10-06--14-35-55", HONDA.ACURA_RDX), CarTestRoute("0a78dfbacc8504ef|2020-03-04--13-29-55", HONDA.CIVIC_BOSCH),
TestRoute("54fd8451b3974762|2021-04-01--14-50-10", HONDA.RIDGELINE), CarTestRoute("f34a60d68d83b1e5|2020-10-06--14-35-55", HONDA.ACURA_RDX),
TestRoute("2d5808fae0b38ac6|2021-09-01--17-14-11", HONDA.HONDA_E), CarTestRoute("54fd8451b3974762|2021-04-01--14-50-10", HONDA.RIDGELINE),
TestRoute("f44aa96ace22f34a|2021-12-22--06-22-31", HONDA.CIVIC_2022), CarTestRoute("2d5808fae0b38ac6|2021-09-01--17-14-11", HONDA.HONDA_E),
CarTestRoute("f44aa96ace22f34a|2021-12-22--06-22-31", HONDA.CIVIC_2022),
TestRoute("6fe86b4e410e4c37|2020-07-22--16-27-13", HYUNDAI.HYUNDAI_GENESIS),
TestRoute("70c5bec28ec8e345|2020-08-08--12-22-23", HYUNDAI.GENESIS_G70), CarTestRoute("6fe86b4e410e4c37|2020-07-22--16-27-13", HYUNDAI.HYUNDAI_GENESIS),
TestRoute("6b301bf83f10aa90|2020-11-22--16-45-07", HYUNDAI.GENESIS_G80), CarTestRoute("70c5bec28ec8e345|2020-08-08--12-22-23", HYUNDAI.GENESIS_G70),
TestRoute("4dbd55df87507948|2022-03-01--09-45-38", HYUNDAI.SANTA_FE), CarTestRoute("6b301bf83f10aa90|2020-11-22--16-45-07", HYUNDAI.GENESIS_G80),
TestRoute("bf43d9df2b660eb0|2021-09-23--14-16-37", HYUNDAI.SANTA_FE_2022), CarTestRoute("4dbd55df87507948|2022-03-01--09-45-38", HYUNDAI.SANTA_FE),
TestRoute("37398f32561a23ad|2021-11-18--00-11-35", HYUNDAI.SANTA_FE_HEV_2022), CarTestRoute("bf43d9df2b660eb0|2021-09-23--14-16-37", HYUNDAI.SANTA_FE_2022),
TestRoute("656ac0d830792fcc|2021-12-28--14-45-56", HYUNDAI.SANTA_FE_PHEV_2022), CarTestRoute("37398f32561a23ad|2021-11-18--00-11-35", HYUNDAI.SANTA_FE_HEV_2022),
TestRoute("e0e98335f3ebc58f|2021-03-07--16-38-29", HYUNDAI.KIA_CEED), CarTestRoute("656ac0d830792fcc|2021-12-28--14-45-56", HYUNDAI.SANTA_FE_PHEV_2022, segment=1),
TestRoute("7653b2bce7bcfdaa|2020-03-04--15-34-32", HYUNDAI.KIA_OPTIMA), CarTestRoute("e0e98335f3ebc58f|2021-03-07--16-38-29", HYUNDAI.KIA_CEED),
TestRoute("c75a59efa0ecd502|2021-03-11--20-52-55", HYUNDAI.KIA_SELTOS), CarTestRoute("7653b2bce7bcfdaa|2020-03-04--15-34-32", HYUNDAI.KIA_OPTIMA),
TestRoute("5b7c365c50084530|2020-04-15--16-13-24", HYUNDAI.SONATA), CarTestRoute("c75a59efa0ecd502|2021-03-11--20-52-55", HYUNDAI.KIA_SELTOS),
TestRoute("b2a38c712dcf90bd|2020-05-18--18-12-48", HYUNDAI.SONATA_LF), CarTestRoute("5b7c365c50084530|2020-04-15--16-13-24", HYUNDAI.SONATA),
TestRoute("fb3fd42f0baaa2f8|2022-03-30--15-25-05", HYUNDAI.TUCSON), CarTestRoute("b2a38c712dcf90bd|2020-05-18--18-12-48", HYUNDAI.SONATA_LF),
TestRoute("5875672fc1d4bf57|2020-07-23--21-33-28", HYUNDAI.KIA_SORENTO), CarTestRoute("fb3fd42f0baaa2f8|2022-03-30--15-25-05", HYUNDAI.TUCSON),
TestRoute("9c917ba0d42ffe78|2020-04-17--12-43-19", HYUNDAI.PALISADE), CarTestRoute("36e10531feea61a4|2022-07-25--13-37-42", HYUNDAI.TUCSON_HYBRID_4TH_GEN),
TestRoute("22de8111a8c5463c|2022-07-29--13-34-49", HYUNDAI.IONIQ_5), CarTestRoute("5875672fc1d4bf57|2020-07-23--21-33-28", HYUNDAI.KIA_SORENTO),
TestRoute("3f29334d6134fcd4|2022-03-30--22-00-50", HYUNDAI.IONIQ_PHEV_2019), CarTestRoute("9c917ba0d42ffe78|2020-04-17--12-43-19", HYUNDAI.PALISADE),
TestRoute("fa8db5869167f821|2021-06-10--22-50-10", HYUNDAI.IONIQ_PHEV), CarTestRoute("22de8111a8c5463c|2022-07-29--13-34-49", HYUNDAI.IONIQ_5),
TestRoute("2c5cf2dd6102e5da|2020-12-17--16-06-44", HYUNDAI.IONIQ_EV_2020), CarTestRoute("3f29334d6134fcd4|2022-03-30--22-00-50", HYUNDAI.IONIQ_PHEV_2019),
TestRoute("610ebb9faaad6b43|2020-06-13--15-28-36", HYUNDAI.IONIQ_EV_LTD), CarTestRoute("fa8db5869167f821|2021-06-10--22-50-10", HYUNDAI.IONIQ_PHEV),
TestRoute("2c5cf2dd6102e5da|2020-06-26--16-00-08", HYUNDAI.IONIQ), CarTestRoute("2c5cf2dd6102e5da|2020-12-17--16-06-44", HYUNDAI.IONIQ_EV_2020),
TestRoute("ab59fe909f626921|2021-10-18--18-34-28", HYUNDAI.IONIQ_HEV_2022), CarTestRoute("610ebb9faaad6b43|2020-06-13--15-28-36", HYUNDAI.IONIQ_EV_LTD),
TestRoute("22d955b2cd499c22|2020-08-10--19-58-21", HYUNDAI.KONA), CarTestRoute("2c5cf2dd6102e5da|2020-06-26--16-00-08", HYUNDAI.IONIQ),
TestRoute("efc48acf44b1e64d|2021-05-28--21-05-04", HYUNDAI.KONA_EV), CarTestRoute("ab59fe909f626921|2021-10-18--18-34-28", HYUNDAI.IONIQ_HEV_2022),
TestRoute("ff973b941a69366f|2022-07-28--22-01-19", HYUNDAI.KONA_EV_2022, segment=11), CarTestRoute("22d955b2cd499c22|2020-08-10--19-58-21", HYUNDAI.KONA),
TestRoute("49f3c13141b6bc87|2021-07-28--08-05-13", HYUNDAI.KONA_HEV), CarTestRoute("efc48acf44b1e64d|2021-05-28--21-05-04", HYUNDAI.KONA_EV),
TestRoute("5dddcbca6eb66c62|2020-07-26--13-24-19", HYUNDAI.KIA_STINGER), CarTestRoute("ff973b941a69366f|2022-07-28--22-01-19", HYUNDAI.KONA_EV_2022, segment=11),
TestRoute("d624b3d19adce635|2020-08-01--14-59-12", HYUNDAI.VELOSTER), CarTestRoute("49f3c13141b6bc87|2021-07-28--08-05-13", HYUNDAI.KONA_HEV),
TestRoute("d824e27e8c60172c|2022-05-19--16-15-28", HYUNDAI.KIA_EV6), CarTestRoute("5dddcbca6eb66c62|2020-07-26--13-24-19", HYUNDAI.KIA_STINGER),
TestRoute("007d5e4ad9f86d13|2021-09-30--15-09-23", HYUNDAI.KIA_K5_2021), CarTestRoute("d624b3d19adce635|2020-08-01--14-59-12", HYUNDAI.VELOSTER),
TestRoute("50c6c9b85fd1ff03|2020-10-26--17-56-06", HYUNDAI.KIA_NIRO_EV), CarTestRoute("d824e27e8c60172c|2022-05-19--16-15-28", HYUNDAI.KIA_EV6),
TestRoute("173219cf50acdd7b|2021-07-05--10-27-41", HYUNDAI.KIA_NIRO_HEV), CarTestRoute("007d5e4ad9f86d13|2021-09-30--15-09-23", HYUNDAI.KIA_K5_2021),
TestRoute("34a875f29f69841a|2021-07-29--13-02-09", HYUNDAI.KIA_NIRO_HEV_2021), CarTestRoute("50c6c9b85fd1ff03|2020-10-26--17-56-06", HYUNDAI.KIA_NIRO_EV),
TestRoute("50a2212c41f65c7b|2021-05-24--16-22-06", HYUNDAI.KIA_FORTE), CarTestRoute("173219cf50acdd7b|2021-07-05--10-27-41", HYUNDAI.KIA_NIRO_PHEV),
TestRoute("c5ac319aa9583f83|2021-06-01--18-18-31", HYUNDAI.ELANTRA), CarTestRoute("34a875f29f69841a|2021-07-29--13-02-09", HYUNDAI.KIA_NIRO_HEV_2021),
TestRoute("82e9cdd3f43bf83e|2021-05-15--02-42-51", HYUNDAI.ELANTRA_2021), CarTestRoute("50a2212c41f65c7b|2021-05-24--16-22-06", HYUNDAI.KIA_FORTE),
TestRoute("715ac05b594e9c59|2021-06-20--16-21-07", HYUNDAI.ELANTRA_HEV_2021), CarTestRoute("c5ac319aa9583f83|2021-06-01--18-18-31", HYUNDAI.ELANTRA),
TestRoute("7120aa90bbc3add7|2021-08-02--07-12-31", HYUNDAI.SONATA_HYBRID), CarTestRoute("82e9cdd3f43bf83e|2021-05-15--02-42-51", HYUNDAI.ELANTRA_2021),
TestRoute("715ac05b594e9c59|2021-10-27--23-24-56", HYUNDAI.GENESIS_G70_2020), CarTestRoute("715ac05b594e9c59|2021-06-20--16-21-07", HYUNDAI.ELANTRA_HEV_2021),
CarTestRoute("7120aa90bbc3add7|2021-08-02--07-12-31", HYUNDAI.SONATA_HYBRID),
TestRoute("00c829b1b7613dea|2021-06-24--09-10-10", TOYOTA.ALPHARD_TSS2), CarTestRoute("715ac05b594e9c59|2021-10-27--23-24-56", HYUNDAI.GENESIS_G70_2020),
TestRoute("912119ebd02c7a42|2022-03-19--07-24-50", TOYOTA.ALPHARDH_TSS2),
TestRoute("000cf3730200c71c|2021-05-24--10-42-05", TOYOTA.AVALON), CarTestRoute("00c829b1b7613dea|2021-06-24--09-10-10", TOYOTA.ALPHARD_TSS2),
TestRoute("0bb588106852abb7|2021-05-26--12-22-01", TOYOTA.AVALON_2019), CarTestRoute("912119ebd02c7a42|2022-03-19--07-24-50", TOYOTA.ALPHARDH_TSS2),
TestRoute("87bef2930af86592|2021-05-30--09-40-54", TOYOTA.AVALONH_2019), CarTestRoute("000cf3730200c71c|2021-05-24--10-42-05", TOYOTA.AVALON),
TestRoute("e9966711cfb04ce3|2022-01-11--07-59-43", TOYOTA.AVALON_TSS2), CarTestRoute("0bb588106852abb7|2021-05-26--12-22-01", TOYOTA.AVALON_2019),
TestRoute("eca1080a91720a54|2022-03-17--13-32-29", TOYOTA.AVALONH_TSS2), CarTestRoute("87bef2930af86592|2021-05-30--09-40-54", TOYOTA.AVALONH_2019),
TestRoute("6cdecc4728d4af37|2020-02-23--15-44-18", TOYOTA.CAMRY), CarTestRoute("e9966711cfb04ce3|2022-01-11--07-59-43", TOYOTA.AVALON_TSS2),
TestRoute("3456ad0cd7281b24|2020-12-13--17-45-56", TOYOTA.CAMRY_TSS2), CarTestRoute("eca1080a91720a54|2022-03-17--13-32-29", TOYOTA.AVALONH_TSS2),
TestRoute("ffccc77938ddbc44|2021-01-04--16-55-41", TOYOTA.CAMRYH_TSS2), CarTestRoute("6cdecc4728d4af37|2020-02-23--15-44-18", TOYOTA.CAMRY),
TestRoute("54034823d30962f5|2021-05-24--06-37-34", TOYOTA.CAMRYH), CarTestRoute("3456ad0cd7281b24|2020-12-13--17-45-56", TOYOTA.CAMRY_TSS2),
TestRoute("4e45c89c38e8ec4d|2021-05-02--02-49-28", TOYOTA.COROLLA), CarTestRoute("ffccc77938ddbc44|2021-01-04--16-55-41", TOYOTA.CAMRYH_TSS2),
TestRoute("5f5afb36036506e4|2019-05-14--02-09-54", TOYOTA.COROLLA_TSS2), CarTestRoute("54034823d30962f5|2021-05-24--06-37-34", TOYOTA.CAMRYH),
TestRoute("5ceff72287a5c86c|2019-10-19--10-59-02", TOYOTA.COROLLAH_TSS2), CarTestRoute("4e45c89c38e8ec4d|2021-05-02--02-49-28", TOYOTA.COROLLA),
TestRoute("d2525c22173da58b|2021-04-25--16-47-04", TOYOTA.PRIUS), CarTestRoute("5f5afb36036506e4|2019-05-14--02-09-54", TOYOTA.COROLLA_TSS2),
TestRoute("b14c5b4742e6fc85|2020-07-28--19-50-11", TOYOTA.RAV4), CarTestRoute("5ceff72287a5c86c|2019-10-19--10-59-02", TOYOTA.COROLLAH_TSS2),
TestRoute("32a7df20486b0f70|2020-02-06--16-06-50", TOYOTA.RAV4H), CarTestRoute("d2525c22173da58b|2021-04-25--16-47-04", TOYOTA.PRIUS),
TestRoute("cdf2f7de565d40ae|2019-04-25--03-53-41", TOYOTA.RAV4_TSS2), CarTestRoute("b14c5b4742e6fc85|2020-07-28--19-50-11", TOYOTA.RAV4),
TestRoute("a5c341bb250ca2f0|2022-05-18--16-05-17", TOYOTA.RAV4_TSS2_2022), CarTestRoute("32a7df20486b0f70|2020-02-06--16-06-50", TOYOTA.RAV4H),
TestRoute("7e34a988419b5307|2019-12-18--19-13-30", TOYOTA.RAV4H_TSS2), CarTestRoute("cdf2f7de565d40ae|2019-04-25--03-53-41", TOYOTA.RAV4_TSS2),
TestRoute("2475fb3eb2ffcc2e|2022-04-29--12-46-23", TOYOTA.RAV4H_TSS2_2022), CarTestRoute("a5c341bb250ca2f0|2022-05-18--16-05-17", TOYOTA.RAV4_TSS2_2022),
TestRoute("e6a24be49a6cd46e|2019-10-29--10-52-42", TOYOTA.LEXUS_ES_TSS2), CarTestRoute("7e34a988419b5307|2019-12-18--19-13-30", TOYOTA.RAV4H_TSS2),
TestRoute("25057fa6a5a63dfb|2020-03-04--08-44-23", TOYOTA.LEXUS_CTH), CarTestRoute("2475fb3eb2ffcc2e|2022-04-29--12-46-23", TOYOTA.RAV4H_TSS2_2022),
TestRoute("f49e8041283f2939|2019-05-30--11-51-51", TOYOTA.LEXUS_ESH_TSS2), CarTestRoute("e6a24be49a6cd46e|2019-10-29--10-52-42", TOYOTA.LEXUS_ES_TSS2),
TestRoute("37041c500fd30100|2020-12-30--12-17-24", TOYOTA.LEXUS_ESH), CarTestRoute("da23c367491f53e2|2021-05-21--09-09-11", TOYOTA.LEXUS_CTH, segment=3),
TestRoute("32696cea52831b02|2021-11-19--18-13-30", TOYOTA.LEXUS_RC), CarTestRoute("f49e8041283f2939|2019-05-30--11-51-51", TOYOTA.LEXUS_ESH_TSS2),
TestRoute("886fcd8408d570e9|2020-01-29--05-11-22", TOYOTA.LEXUS_RX), CarTestRoute("37041c500fd30100|2020-12-30--12-17-24", TOYOTA.LEXUS_ESH),
TestRoute("886fcd8408d570e9|2020-01-29--02-18-55", TOYOTA.LEXUS_RX), CarTestRoute("32696cea52831b02|2021-11-19--18-13-30", TOYOTA.LEXUS_RC),
TestRoute("d27ad752e9b08d4f|2021-05-26--19-39-51", TOYOTA.LEXUS_RXH), CarTestRoute("886fcd8408d570e9|2020-01-29--02-18-55", TOYOTA.LEXUS_RX),
TestRoute("01b22eb2ed121565|2020-02-02--11-25-51", TOYOTA.LEXUS_RX_TSS2), CarTestRoute("d27ad752e9b08d4f|2021-05-26--19-39-51", TOYOTA.LEXUS_RXH),
TestRoute("b74758c690a49668|2020-05-20--15-58-57", TOYOTA.LEXUS_RXH_TSS2), CarTestRoute("01b22eb2ed121565|2020-02-02--11-25-51", TOYOTA.LEXUS_RX_TSS2),
TestRoute("ec429c0f37564e3c|2020-02-01--17-28-12", TOYOTA.LEXUS_NXH), CarTestRoute("b74758c690a49668|2020-05-20--15-58-57", TOYOTA.LEXUS_RXH_TSS2),
TestRoute("964c09eb11ca8089|2020-11-03--22-04-00", TOYOTA.LEXUS_NX), CarTestRoute("ec429c0f37564e3c|2020-02-01--17-28-12", TOYOTA.LEXUS_NXH),
TestRoute("3fd5305f8b6ca765|2021-04-28--19-26-49", TOYOTA.LEXUS_NX_TSS2), CarTestRoute("964c09eb11ca8089|2020-11-03--22-04-00", TOYOTA.LEXUS_NX),
TestRoute("09ae96064ed85a14|2022-06-09--12-22-31", TOYOTA.LEXUS_NXH_TSS2), CarTestRoute("3fd5305f8b6ca765|2021-04-28--19-26-49", TOYOTA.LEXUS_NX_TSS2),
TestRoute("0a302ffddbb3e3d3|2020-02-08--16-19-08", TOYOTA.HIGHLANDER_TSS2), CarTestRoute("09ae96064ed85a14|2022-06-09--12-22-31", TOYOTA.LEXUS_NXH_TSS2),
TestRoute("437e4d2402abf524|2021-05-25--07-58-50", TOYOTA.HIGHLANDERH_TSS2), CarTestRoute("0a302ffddbb3e3d3|2020-02-08--16-19-08", TOYOTA.HIGHLANDER_TSS2),
TestRoute("3183cd9b021e89ce|2021-05-25--10-34-44", TOYOTA.HIGHLANDER), CarTestRoute("437e4d2402abf524|2021-05-25--07-58-50", TOYOTA.HIGHLANDERH_TSS2),
TestRoute("80d16a262e33d57f|2021-05-23--20-01-43", TOYOTA.HIGHLANDERH), CarTestRoute("3183cd9b021e89ce|2021-05-25--10-34-44", TOYOTA.HIGHLANDER),
TestRoute("eb6acd681135480d|2019-06-20--20-00-00", TOYOTA.SIENNA), CarTestRoute("80d16a262e33d57f|2021-05-23--20-01-43", TOYOTA.HIGHLANDERH),
TestRoute("2e07163a1ba9a780|2019-08-25--13-15-13", TOYOTA.LEXUS_IS), CarTestRoute("eb6acd681135480d|2019-06-20--20-00-00", TOYOTA.SIENNA),
TestRoute("0a0de17a1e6a2d15|2020-09-21--21-24-41", TOYOTA.PRIUS_TSS2), CarTestRoute("2e07163a1ba9a780|2019-08-25--13-15-13", TOYOTA.LEXUS_IS),
TestRoute("9b36accae406390e|2021-03-30--10-41-38", TOYOTA.MIRAI), CarTestRoute("0a0de17a1e6a2d15|2020-09-21--21-24-41", TOYOTA.PRIUS_TSS2),
TestRoute("cd9cff4b0b26c435|2021-05-13--15-12-39", TOYOTA.CHR), CarTestRoute("9b36accae406390e|2021-03-30--10-41-38", TOYOTA.MIRAI),
TestRoute("57858ede0369a261|2021-05-18--20-34-20", TOYOTA.CHRH), CarTestRoute("cd9cff4b0b26c435|2021-05-13--15-12-39", TOYOTA.CHR),
TestRoute("14623aae37e549f3|2021-10-24--01-20-49", TOYOTA.PRIUS_V), CarTestRoute("57858ede0369a261|2021-05-18--20-34-20", TOYOTA.CHRH),
CarTestRoute("14623aae37e549f3|2021-10-24--01-20-49", TOYOTA.PRIUS_V),
TestRoute("202c40641158a6e5|2021-09-21--09-43-24", VOLKSWAGEN.ARTEON_MK1),
TestRoute("2c68dda277d887ac|2021-05-11--15-22-20", VOLKSWAGEN.ATLAS_MK1), CarTestRoute("202c40641158a6e5|2021-09-21--09-43-24", VOLKSWAGEN.ARTEON_MK1),
TestRoute("cae14e88932eb364|2021-03-26--14-43-28", VOLKSWAGEN.GOLF_MK7), CarTestRoute("2c68dda277d887ac|2021-05-11--15-22-20", VOLKSWAGEN.ATLAS_MK1),
TestRoute("58a7d3b707987d65|2021-03-25--17-26-37", VOLKSWAGEN.JETTA_MK7), CarTestRoute("cae14e88932eb364|2021-03-26--14-43-28", VOLKSWAGEN.GOLF_MK7),
TestRoute("4d134e099430fba2|2021-03-26--00-26-06", VOLKSWAGEN.PASSAT_MK8), CarTestRoute("58a7d3b707987d65|2021-03-25--17-26-37", VOLKSWAGEN.JETTA_MK7),
TestRoute("0cd0b7f7e31a3853|2021-11-03--19-30-22", VOLKSWAGEN.POLO_MK6), CarTestRoute("4d134e099430fba2|2021-03-26--00-26-06", VOLKSWAGEN.PASSAT_MK8),
TestRoute("7d82b2f3a9115f1f|2021-10-21--15-39-42", VOLKSWAGEN.TAOS_MK1), CarTestRoute("3cfdec54aa035f3f|2022-07-19--23-45-10", VOLKSWAGEN.PASSAT_NMS),
TestRoute("2744c89a8dda9a51|2021-07-24--21-28-06", VOLKSWAGEN.TCROSS_MK1), CarTestRoute("0cd0b7f7e31a3853|2021-11-03--19-30-22", VOLKSWAGEN.POLO_MK6),
TestRoute("2cef8a0b898f331a|2021-03-25--20-13-57", VOLKSWAGEN.TIGUAN_MK2), CarTestRoute("7d82b2f3a9115f1f|2021-10-21--15-39-42", VOLKSWAGEN.TAOS_MK1),
TestRoute("a589dcc642fdb10a|2021-06-14--20-54-26", VOLKSWAGEN.TOURAN_MK2), CarTestRoute("2744c89a8dda9a51|2021-07-24--21-28-06", VOLKSWAGEN.TCROSS_MK1),
TestRoute("a459f4556782eba1|2021-09-19--09-48-00", VOLKSWAGEN.TRANSPORTER_T61), CarTestRoute("2cef8a0b898f331a|2021-03-25--20-13-57", VOLKSWAGEN.TIGUAN_MK2),
TestRoute("0cd0b7f7e31a3853|2021-11-18--00-38-32", VOLKSWAGEN.TROC_MK1), CarTestRoute("a589dcc642fdb10a|2021-06-14--20-54-26", VOLKSWAGEN.TOURAN_MK2),
TestRoute("07667b885add75fd|2021-01-23--19-48-42", VOLKSWAGEN.AUDI_A3_MK3), CarTestRoute("a459f4556782eba1|2021-09-19--09-48-00", VOLKSWAGEN.TRANSPORTER_T61),
TestRoute("6c6b466346192818|2021-06-06--14-17-47", VOLKSWAGEN.AUDI_Q2_MK1), CarTestRoute("0cd0b7f7e31a3853|2021-11-18--00-38-32", VOLKSWAGEN.TROC_MK1),
TestRoute("0cd0b7f7e31a3853|2021-12-03--03-12-05", VOLKSWAGEN.AUDI_Q3_MK2), CarTestRoute("07667b885add75fd|2021-01-23--19-48-42", VOLKSWAGEN.AUDI_A3_MK3),
TestRoute("8f205bdd11bcbb65|2021-03-26--01-00-17", VOLKSWAGEN.SEAT_ATECA_MK1), CarTestRoute("6c6b466346192818|2021-06-06--14-17-47", VOLKSWAGEN.AUDI_Q2_MK1),
TestRoute("fc6b6c9a3471c846|2021-05-27--13-39-56", VOLKSWAGEN.SEAT_LEON_MK3), CarTestRoute("0cd0b7f7e31a3853|2021-12-03--03-12-05", VOLKSWAGEN.AUDI_Q3_MK2),
TestRoute("12d6ae3057c04b0d|2021-09-15--00-04-07", VOLKSWAGEN.SKODA_KAMIQ_MK1), CarTestRoute("8f205bdd11bcbb65|2021-03-26--01-00-17", VOLKSWAGEN.SEAT_ATECA_MK1),
TestRoute("12d6ae3057c04b0d|2021-09-04--21-21-21", VOLKSWAGEN.SKODA_KAROQ_MK1), CarTestRoute("fc6b6c9a3471c846|2021-05-27--13-39-56", VOLKSWAGEN.SEAT_LEON_MK3),
TestRoute("90434ff5d7c8d603|2021-03-15--12-07-31", VOLKSWAGEN.SKODA_KODIAQ_MK1), CarTestRoute("12d6ae3057c04b0d|2021-09-15--00-04-07", VOLKSWAGEN.SKODA_KAMIQ_MK1),
TestRoute("66e5edc3a16459c5|2021-05-25--19-00-29", VOLKSWAGEN.SKODA_OCTAVIA_MK3), CarTestRoute("12d6ae3057c04b0d|2021-09-04--21-21-21", VOLKSWAGEN.SKODA_KAROQ_MK1),
TestRoute("026b6d18fba6417f|2021-03-26--09-17-04", VOLKSWAGEN.SKODA_SCALA_MK1), CarTestRoute("90434ff5d7c8d603|2021-03-15--12-07-31", VOLKSWAGEN.SKODA_KODIAQ_MK1),
TestRoute("b2e9858e29db492b|2021-03-26--16-58-42", VOLKSWAGEN.SKODA_SUPERB_MK3), CarTestRoute("66e5edc3a16459c5|2021-05-25--19-00-29", VOLKSWAGEN.SKODA_OCTAVIA_MK3),
CarTestRoute("026b6d18fba6417f|2021-03-26--09-17-04", VOLKSWAGEN.SKODA_SCALA_MK1),
TestRoute("3c8f0c502e119c1c|2020-06-30--12-58-02", SUBARU.ASCENT), CarTestRoute("b2e9858e29db492b|2021-03-26--16-58-42", VOLKSWAGEN.SKODA_SUPERB_MK3),
TestRoute("c321c6b697c5a5ff|2020-06-23--11-04-33", SUBARU.FORESTER),
TestRoute("791340bc01ed993d|2019-03-10--16-28-08", SUBARU.IMPREZA), CarTestRoute("3c8f0c502e119c1c|2020-06-30--12-58-02", SUBARU.ASCENT),
TestRoute("8bf7e79a3ce64055|2021-05-24--09-36-27", SUBARU.IMPREZA_2020), CarTestRoute("c321c6b697c5a5ff|2020-06-23--11-04-33", SUBARU.FORESTER),
TestRoute("1bbe6bf2d62f58a8|2022-07-14--17-11-43", SUBARU.OUTBACK, segment=3), CarTestRoute("791340bc01ed993d|2019-03-10--16-28-08", SUBARU.IMPREZA),
CarTestRoute("8bf7e79a3ce64055|2021-05-24--09-36-27", SUBARU.IMPREZA_2020),
CarTestRoute("1bbe6bf2d62f58a8|2022-07-14--17-11-43", SUBARU.OUTBACK, segment=3),
CarTestRoute("c56e69bbc74b8fad|2022-08-18--09-43-51", SUBARU.LEGACY, segment=3),
# Pre-global, dashcam # Pre-global, dashcam
TestRoute("95441c38ae8c130e|2020-06-08--12-10-17", SUBARU.FORESTER_PREGLOBAL), CarTestRoute("95441c38ae8c130e|2020-06-08--12-10-17", SUBARU.FORESTER_PREGLOBAL),
TestRoute("df5ca7660000fba8|2020-06-16--17-37-19", SUBARU.LEGACY_PREGLOBAL), CarTestRoute("df5ca7660000fba8|2020-06-16--17-37-19", SUBARU.LEGACY_PREGLOBAL),
TestRoute("5ab784f361e19b78|2020-06-08--16-30-41", SUBARU.OUTBACK_PREGLOBAL), CarTestRoute("5ab784f361e19b78|2020-06-08--16-30-41", SUBARU.OUTBACK_PREGLOBAL),
TestRoute("e19eb5d5353b1ac1|2020-08-09--14-37-56", SUBARU.OUTBACK_PREGLOBAL_2018), CarTestRoute("e19eb5d5353b1ac1|2020-08-09--14-37-56", SUBARU.OUTBACK_PREGLOBAL_2018),
TestRoute("fbbfa6af821552b9|2020-03-03--08-09-43", NISSAN.XTRAIL), CarTestRoute("fbbfa6af821552b9|2020-03-03--08-09-43", NISSAN.XTRAIL),
TestRoute("5b7c365c50084530|2020-03-25--22-10-13", NISSAN.LEAF), CarTestRoute("5b7c365c50084530|2020-03-25--22-10-13", NISSAN.LEAF),
TestRoute("22c3dcce2dd627eb|2020-12-30--16-38-48", NISSAN.LEAF_IC), CarTestRoute("22c3dcce2dd627eb|2020-12-30--16-38-48", NISSAN.LEAF_IC),
TestRoute("059ab9162e23198e|2020-05-30--09-41-01", NISSAN.ROGUE), CarTestRoute("059ab9162e23198e|2020-05-30--09-41-01", NISSAN.ROGUE),
TestRoute("b72d3ec617c0a90f|2020-12-11--15-38-17", NISSAN.ALTIMA), CarTestRoute("b72d3ec617c0a90f|2020-12-11--15-38-17", NISSAN.ALTIMA),
TestRoute("32a319f057902bb3|2020-04-27--15-18-58", MAZDA.CX5), CarTestRoute("32a319f057902bb3|2020-04-27--15-18-58", MAZDA.CX5),
TestRoute("10b5a4b380434151|2020-08-26--17-11-45", MAZDA.CX9), CarTestRoute("10b5a4b380434151|2020-08-26--17-11-45", MAZDA.CX9),
TestRoute("74f1038827005090|2020-08-26--20-05-50", MAZDA.MAZDA3), CarTestRoute("74f1038827005090|2020-08-26--20-05-50", MAZDA.MAZDA3),
TestRoute("fb53c640f499b73d|2021-06-01--04-17-56", MAZDA.MAZDA6), CarTestRoute("fb53c640f499b73d|2021-06-01--04-17-56", MAZDA.MAZDA6),
TestRoute("f6d5b1a9d7a1c92e|2021-07-08--06-56-59", MAZDA.CX9_2021), CarTestRoute("f6d5b1a9d7a1c92e|2021-07-08--06-56-59", MAZDA.CX9_2021),
TestRoute("a4af1602d8e668ac|2022-02-03--12-17-07", MAZDA.CX5_2022), CarTestRoute("a4af1602d8e668ac|2022-02-03--12-17-07", MAZDA.CX5_2022),
TestRoute("6c14ee12b74823ce|2021-06-30--11-49-02", TESLA.AP1_MODELS), CarTestRoute("6c14ee12b74823ce|2021-06-30--11-49-02", TESLA.AP1_MODELS),
TestRoute("bb50caf5f0945ab1|2021-06-19--17-20-18", TESLA.AP2_MODELS), CarTestRoute("bb50caf5f0945ab1|2021-06-19--17-20-18", TESLA.AP2_MODELS),
# Segments that test specific issues # Segments that test specific issues
# Controls mismatch due to interceptor threshold # Controls mismatch due to interceptor threshold
TestRoute("cfb32f0fb91b173b|2022-04-06--14-54-45", HONDA.CIVIC, segment=21), CarTestRoute("cfb32f0fb91b173b|2022-04-06--14-54-45", HONDA.CIVIC, segment=21),
TestRoute("5a8762b91fc70467|2022-04-14--21-26-20", TOYOTA.RAV4, segment=2), CarTestRoute("5a8762b91fc70467|2022-04-14--21-26-20", TOYOTA.RAV4, segment=2),
# Controls mismatch due to standstill threshold # Controls mismatch due to standstill threshold
TestRoute("bec2dcfde6a64235|2022-04-08--14-21-32", HONDA.CRV_HYBRID, segment=22), CarTestRoute("bec2dcfde6a64235|2022-04-08--14-21-32", HONDA.CRV_HYBRID, segment=22),
] ]

@ -5,6 +5,7 @@ import importlib
from parameterized import parameterized from parameterized import parameterized
from cereal import car from cereal import car
from selfdrive.car import gen_empty_fingerprint
from selfdrive.car.fingerprints import all_known_cars from selfdrive.car.fingerprints import all_known_cars
from selfdrive.car.car_helpers import interfaces from selfdrive.car.car_helpers import interfaces
from selfdrive.car.fingerprints import _FINGERPRINTS as FINGERPRINTS from selfdrive.car.fingerprints import _FINGERPRINTS as FINGERPRINTS
@ -19,11 +20,8 @@ class TestCarInterfaces(unittest.TestCase):
fingerprint = {} fingerprint = {}
CarInterface, CarController, CarState = interfaces[car_name] CarInterface, CarController, CarState = interfaces[car_name]
fingerprints = { fingerprints = gen_empty_fingerprint()
0: fingerprint, fingerprints.update({k: fingerprint for k in fingerprints.keys()})
1: fingerprint,
2: fingerprint,
}
car_fw = [] car_fw = []

@ -13,7 +13,7 @@ class TestCarDocs(unittest.TestCase):
self.all_cars = get_all_car_info() self.all_cars = get_all_car_info()
def test_generator(self): def test_generator(self):
generated_cars_md = generate_cars_md(self.all_cars, CARS_MD_TEMPLATE, False) generated_cars_md = generate_cars_md(self.all_cars, CARS_MD_TEMPLATE)
with open(CARS_MD_OUT, "r") as f: with open(CARS_MD_OUT, "r") as f:
current_cars_md = f.read() current_cars_md = f.read()

@ -94,4 +94,4 @@ if __name__ == "__main__":
print("TEST FAILED") print("TEST FAILED")
sys.exit(1) sys.exit(1)
else: else:
print("TEST SUCESSFUL") print("TEST SUCCESSFUL")

@ -37,44 +37,40 @@ class TestFwFingerprint(unittest.TestCase):
self.assertFingerprints(matches, car_model) self.assertFingerprints(matches, car_model)
def test_no_duplicate_fw_versions(self): def test_no_duplicate_fw_versions(self):
passed = True
for car_model, ecus in FW_VERSIONS.items(): for car_model, ecus in FW_VERSIONS.items():
for ecu, ecu_fw in ecus.items(): with self.subTest(car_model=car_model):
duplicates = {fw for fw in ecu_fw if ecu_fw.count(fw) > 1} for ecu, ecu_fw in ecus.items():
if len(duplicates): with self.subTest(ecu):
print(car_model, ECU_NAME[ecu[0]], duplicates) duplicates = {fw for fw in ecu_fw if ecu_fw.count(fw) > 1}
passed = False self.assertFalse(len(duplicates), f"{car_model}: Duplicate FW versions: Ecu.{ECU_NAME[ecu[0]]}, {duplicates}")
self.assertTrue(passed, "Duplicate FW versions found")
def test_blacklisted_ecus(self): def test_blacklisted_ecus(self):
passed = True
blacklisted_addrs = (0x7c4, 0x7d0) # includes A/C ecu and an unknown ecu blacklisted_addrs = (0x7c4, 0x7d0) # includes A/C ecu and an unknown ecu
for car_model, ecus in FW_VERSIONS.items(): for car_model, ecus in FW_VERSIONS.items():
CP = interfaces[car_model][0].get_params(car_model) with self.subTest(car_model=car_model):
if CP.carName == 'subaru': CP = interfaces[car_model][0].get_params(car_model)
for ecu in ecus.keys(): if CP.carName == 'subaru':
if ecu[1] in blacklisted_addrs: for ecu in ecus.keys():
print(f'{car_model}: Blacklisted ecu: (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])})') self.assertNotIn(ecu[1], blacklisted_addrs, f'{car_model}: Blacklisted ecu: (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])})')
passed = False
self.assertTrue(passed, "Blacklisted FW versions found") elif CP.carName == "chrysler":
# Some HD trucks have a combined TCM and ECM
if CP.carFingerprint.startswith("RAM HD"):
for ecu in ecus.keys():
self.assertNotEqual(ecu[0], Ecu.transmission, f"{car_model}: Blacklisted ecu: (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])})")
def test_fw_request_ecu_whitelist(self): def test_fw_request_ecu_whitelist(self):
passed = True for brand in set(r.brand for r in REQUESTS):
brands = set(r.brand for r in REQUESTS) with self.subTest(brand=brand):
for brand in brands: whitelisted_ecus = [ecu for r in REQUESTS for ecu in r.whitelist_ecus if r.brand == brand]
whitelisted_ecus = [ecu for r in REQUESTS for ecu in r.whitelist_ecus if r.brand == brand] brand_ecus = set([fw[0] for car_fw in VERSIONS[brand].values() for fw in car_fw])
brand_ecus = set([fw[0] for car_fw in VERSIONS[brand].values() for fw in car_fw])
# each ecu in brand's fw versions needs to be whitelisted at least once # each ecu in brand's fw versions needs to be whitelisted at least once
ecus_not_whitelisted = set(brand_ecus) - set(whitelisted_ecus) ecus_not_whitelisted = set(brand_ecus) - set(whitelisted_ecus)
if len(whitelisted_ecus) and len(ecus_not_whitelisted):
ecu_strings = ", ".join([f'Ecu.{ECU_NAME[ecu]}' for ecu in ecus_not_whitelisted])
print(f'{brand.title()}: FW query whitelist missing ecus: {ecu_strings}')
passed = False
self.assertTrue(passed, "Not all ecus in FW versions found in query whitelists") ecu_strings = ", ".join([f'Ecu.{ECU_NAME[ecu]}' for ecu in ecus_not_whitelisted])
self.assertFalse(len(whitelisted_ecus) and len(ecus_not_whitelisted),
f'{brand.title()}: FW query whitelist missing ecus: {ecu_strings}')
if __name__ == "__main__": if __name__ == "__main__":

@ -15,7 +15,7 @@ from selfdrive.car.car_helpers import interfaces
from selfdrive.car.gm.values import CAR as GM from selfdrive.car.gm.values import CAR as GM
from selfdrive.car.honda.values import CAR as HONDA, HONDA_BOSCH from selfdrive.car.honda.values import CAR as HONDA, HONDA_BOSCH
from selfdrive.car.hyundai.values import CAR as HYUNDAI from selfdrive.car.hyundai.values import CAR as HYUNDAI
from selfdrive.car.tests.routes import non_tested_cars, routes, TestRoute from selfdrive.car.tests.routes import non_tested_cars, routes, CarTestRoute
from selfdrive.test.openpilotci import get_url from selfdrive.test.openpilotci import get_url
from tools.lib.logreader import LogReader from tools.lib.logreader import LogReader
from tools.lib.route import Route from tools.lib.route import Route
@ -38,7 +38,7 @@ routes_by_car = defaultdict(set)
for r in routes: for r in routes:
routes_by_car[r.car_model].add(r) routes_by_car[r.car_model].add(r)
test_cases: List[Tuple[str, Optional[TestRoute]]] = [] test_cases: List[Tuple[str, Optional[CarTestRoute]]] = []
for i, c in enumerate(sorted(all_known_cars())): for i, c in enumerate(sorted(all_known_cars())):
if i % NUM_JOBS == JOB_ID: if i % NUM_JOBS == JOB_ID:
test_cases.extend((c, r) for r in routes_by_car.get(c, (None, ))) test_cases.extend((c, r) for r in routes_by_car.get(c, (None, )))
@ -81,6 +81,7 @@ class TestCarModelBase(unittest.TestCase):
except Exception: except Exception:
continue continue
car_fw = []
can_msgs = [] can_msgs = []
fingerprint = defaultdict(dict) fingerprint = defaultdict(dict)
for msg in lr: for msg in lr:
@ -90,6 +91,7 @@ class TestCarModelBase(unittest.TestCase):
fingerprint[m.src][m.address] = len(m.dat) fingerprint[m.src][m.address] = len(m.dat)
can_msgs.append(msg) can_msgs.append(msg)
elif msg.which() == "carParams": elif msg.which() == "carParams":
car_fw = msg.carParams.carFw
if msg.carParams.openpilotLongitudinalControl: if msg.carParams.openpilotLongitudinalControl:
disable_radar = True disable_radar = True
if cls.car_model is None and not cls.ci: if cls.car_model is None and not cls.ci:
@ -103,7 +105,7 @@ class TestCarModelBase(unittest.TestCase):
cls.can_msgs = sorted(can_msgs, key=lambda msg: msg.logMonoTime) cls.can_msgs = sorted(can_msgs, key=lambda msg: msg.logMonoTime)
cls.CarInterface, cls.CarController, cls.CarState = interfaces[cls.car_model] cls.CarInterface, cls.CarController, cls.CarState = interfaces[cls.car_model]
cls.CP = cls.CarInterface.get_params(cls.car_model, fingerprint, [], disable_radar) cls.CP = cls.CarInterface.get_params(cls.car_model, fingerprint, car_fw, disable_radar)
assert cls.CP assert cls.CP
assert cls.CP.carFingerprint == cls.car_model assert cls.CP.carFingerprint == cls.car_model
@ -135,22 +137,26 @@ class TestCarModelBase(unittest.TestCase):
elif tuning == 'indi': elif tuning == 'indi':
self.assertTrue(len(self.CP.lateralTuning.indi.outerLoopGainV)) self.assertTrue(len(self.CP.lateralTuning.indi.outerLoopGainV))
else: else:
raise Exception("unkown tuning") raise Exception("unknown tuning")
def test_car_interface(self): def test_car_interface(self):
# TODO: also check for checkusm and counter violations from can parser # TODO: also check for checksum violations from can parser
can_invalid_cnt = 0 can_invalid_cnt = 0
can_valid = False
CC = car.CarControl.new_message() CC = car.CarControl.new_message()
for i, msg in enumerate(self.can_msgs): for i, msg in enumerate(self.can_msgs):
CS = self.CI.update(CC, (msg.as_builder().to_bytes(),)) CS = self.CI.update(CC, (msg.as_builder().to_bytes(),))
self.CI.apply(CC) self.CI.apply(CC)
# wait 2s for low frequency msgs to be seen if CS.canValid:
if i > 200: can_valid = True
# wait max of 2s for low frequency msgs to be seen
if i > 200 or can_valid:
can_invalid_cnt += not CS.canValid can_invalid_cnt += not CS.canValid
self.assertLess(can_invalid_cnt, 50) self.assertEqual(can_invalid_cnt, 0)
def test_radar_interface(self): def test_radar_interface(self):
os.environ['NO_RADAR_SLEEP'] = "1" os.environ['NO_RADAR_SLEEP'] = "1"
@ -228,6 +234,9 @@ class TestCarModelBase(unittest.TestCase):
checks['gasPressed'] += CS.gasPressed != self.safety.get_gas_pressed_prev() checks['gasPressed'] += CS.gasPressed != self.safety.get_gas_pressed_prev()
checks['cruiseState'] += CS.cruiseState.enabled and not CS.cruiseState.available checks['cruiseState'] += CS.cruiseState.enabled and not CS.cruiseState.available
if self.CP.carName in ("honda", "toyota"):
# TODO: fix standstill mismatches for other makes
checks['standstill'] += CS.standstill == self.safety.get_vehicle_moving()
# TODO: remove this exception once this mismatch is resolved # TODO: remove this exception once this mismatch is resolved
brake_pressed = CS.brakePressed brake_pressed = CS.brakePressed
@ -257,8 +266,6 @@ class TestCarModelBase(unittest.TestCase):
if self.CP.carName == "honda": if self.CP.carName == "honda":
checks['mainOn'] += CS.cruiseState.available != self.safety.get_acc_main_on() checks['mainOn'] += CS.cruiseState.available != self.safety.get_acc_main_on()
# TODO: fix standstill mismatches for other makes
checks['standstill'] += CS.standstill == self.safety.get_vehicle_moving()
CS_prev = CS CS_prev = CS

@ -25,6 +25,9 @@ RAM 1500 5TH GEN: [2.0, 2.0, 0.0]
RAM HD 5TH GEN: [1.4, 1.4, 0.0] RAM HD 5TH GEN: [1.4, 1.4, 0.0]
SUBARU OUTBACK 6TH GEN: [2.3, 2.3, 0.11] SUBARU OUTBACK 6TH GEN: [2.3, 2.3, 0.11]
CHEVROLET BOLT EUV 2022: [2.0, 2.0, 0.05] CHEVROLET BOLT EUV 2022: [2.0, 2.0, 0.05]
CHEVROLET SILVERADO 1500 2020: [1.9, 1.9, 0.112]
VOLKSWAGEN PASSAT NMS: [2.5, 2.5, 0.1]
HYUNDAI TUCSON HYBRID 4TH GEN: [2.5, 2.5, 0.0]
# Dashcam or fallback configured as ideal car # Dashcam or fallback configured as ideal car
mock: [10.0, 10, 0.0] mock: [10.0, 10, 0.0]

@ -69,6 +69,8 @@ VOLKSWAGEN POLO 6TH GEN: VOLKSWAGEN GOLF 7TH GEN
SEAT LEON 3RD GEN: VOLKSWAGEN GOLF 7TH GEN SEAT LEON 3RD GEN: VOLKSWAGEN GOLF 7TH GEN
SEAT ATECA 1ST GEN: VOLKSWAGEN GOLF 7TH GEN SEAT ATECA 1ST GEN: VOLKSWAGEN GOLF 7TH GEN
SUBARU LEGACY 7TH GEN: SUBARU OUTBACK 6TH GEN
# Old subarus don't have much data guessing it's like low torque impreza # Old subarus don't have much data guessing it's like low torque impreza
SUBARU OUTBACK 2018 - 2019: SUBARU IMPREZA LIMITED 2019 SUBARU OUTBACK 2018 - 2019: SUBARU IMPREZA LIMITED 2019
SUBARU OUTBACK 2015 - 2017: SUBARU IMPREZA LIMITED 2019 SUBARU OUTBACK 2015 - 2017: SUBARU IMPREZA LIMITED 2019

@ -10,6 +10,13 @@ from opendbc.can.packer import CANPacker
VisualAlert = car.CarControl.HUDControl.VisualAlert VisualAlert = car.CarControl.HUDControl.VisualAlert
# EPS faults if you apply torque while the steering rate is above 100 deg/s for too long
MAX_STEER_RATE = 100 # deg/s
MAX_STEER_RATE_FRAMES = 18 # tx control frames needed before torque can be cut
# EPS allows user torque above threshold for 50 frames before permanently faulting
MAX_USER_TORQUE = 500
class CarController: class CarController:
def __init__(self, dbc_name, CP, VM): def __init__(self, dbc_name, CP, VM):
@ -20,6 +27,7 @@ class CarController:
self.alert_active = False self.alert_active = False
self.last_standstill = False self.last_standstill = False
self.standstill_req = False self.standstill_req = False
self.steer_rate_counter = 0
self.packer = CANPacker(dbc_name) self.packer = CANPacker(dbc_name)
self.gas = 0 self.gas = 0
@ -29,6 +37,7 @@ class CarController:
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
lat_active = CC.latActive and abs(CS.out.steeringTorque) < MAX_USER_TORQUE
# gas and brake # gas and brake
if self.CP.enableGasInterceptor and CC.longActive: if self.CP.enableGasInterceptor and CC.longActive:
@ -52,11 +61,19 @@ class CarController:
new_steer = int(round(actuators.steer * CarControllerParams.STEER_MAX)) new_steer = int(round(actuators.steer * CarControllerParams.STEER_MAX))
apply_steer = apply_toyota_steer_torque_limits(new_steer, self.last_steer, CS.out.steeringTorqueEps, self.torque_rate_limits) apply_steer = apply_toyota_steer_torque_limits(new_steer, self.last_steer, CS.out.steeringTorqueEps, self.torque_rate_limits)
if not CC.latActive: # Count up to MAX_STEER_RATE_FRAMES, at which point we need to cut torque to avoid a steering fault
if lat_active and abs(CS.out.steeringRateDeg) >= MAX_STEER_RATE:
self.steer_rate_counter += 1
else:
self.steer_rate_counter = 0
apply_steer_req = 1
if not lat_active:
apply_steer = 0 apply_steer = 0
apply_steer_req = 0 apply_steer_req = 0
else: elif self.steer_rate_counter > MAX_STEER_RATE_FRAMES:
apply_steer_req = 1 apply_steer_req = 0
self.steer_rate_counter = 0
# TODO: probably can delete this. CS.pcm_acc_status uses a different signal # TODO: probably can delete this. CS.pcm_acc_status uses a different signal
# than CS.cruiseState.enabled. confirm they're not meaningfully different # than CS.cruiseState.enabled. confirm they're not meaningfully different
@ -109,28 +126,29 @@ class CarController:
can_sends.append(create_gas_interceptor_command(self.packer, interceptor_gas_cmd, self.frame // 2)) can_sends.append(create_gas_interceptor_command(self.packer, interceptor_gas_cmd, self.frame // 2))
self.gas = interceptor_gas_cmd self.gas = interceptor_gas_cmd
# ui mesg is at 1Hz but we send asap if: if self.CP.carFingerprint != CAR.PRIUS_V:
# - there is something to display # ui mesg is at 1Hz but we send asap if:
# - there is something to stop displaying # - there is something to display
fcw_alert = hud_control.visualAlert == VisualAlert.fcw # - there is something to stop displaying
steer_alert = hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw) fcw_alert = hud_control.visualAlert == VisualAlert.fcw
steer_alert = hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw)
send_ui = False
if ((fcw_alert or steer_alert) and not self.alert_active) or \ send_ui = False
(not (fcw_alert or steer_alert) and self.alert_active): if ((fcw_alert or steer_alert) and not self.alert_active) or \
send_ui = True (not (fcw_alert or steer_alert) and self.alert_active):
self.alert_active = not self.alert_active send_ui = True
elif pcm_cancel_cmd: self.alert_active = not self.alert_active
# forcing the pcm to disengage causes a bad fault sound so play a good sound instead elif pcm_cancel_cmd:
send_ui = True # forcing the pcm to disengage causes a bad fault sound so play a good sound instead
send_ui = True
if (self.frame % 100 == 0 or send_ui) and (self.CP.carFingerprint != CAR.PRIUS_V):
can_sends.append(create_ui_command(self.packer, steer_alert, pcm_cancel_cmd, hud_control.leftLaneVisible, if self.frame % 100 == 0 or send_ui:
hud_control.rightLaneVisible, hud_control.leftLaneDepart, can_sends.append(create_ui_command(self.packer, steer_alert, pcm_cancel_cmd, hud_control.leftLaneVisible,
hud_control.rightLaneDepart, CC.enabled)) hud_control.rightLaneVisible, hud_control.leftLaneDepart,
hud_control.rightLaneDepart, CC.enabled))
if (self.frame % 100 == 0 or send_ui) and self.CP.enableDsu:
can_sends.append(create_fcw_command(self.packer, fcw_alert)) if (self.frame % 100 == 0 or send_ui) and self.CP.enableDsu:
can_sends.append(create_fcw_command(self.packer, fcw_alert))
# *** static msgs *** # *** static msgs ***
for addr, cars, bus, fr_step, vl in STATIC_DSU_MSGS: for addr, cars, bus, fr_step, vl in STATIC_DSU_MSGS:

@ -53,7 +53,7 @@ class CarState(CarStateBase):
ret.vEgoRaw = mean([ret.wheelSpeeds.fl, ret.wheelSpeeds.fr, ret.wheelSpeeds.rl, ret.wheelSpeeds.rr]) ret.vEgoRaw = mean([ret.wheelSpeeds.fl, ret.wheelSpeeds.fr, ret.wheelSpeeds.rl, ret.wheelSpeeds.rr])
ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw) ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
ret.standstill = ret.vEgoRaw < 0.001 ret.standstill = ret.vEgoRaw == 0
ret.steeringAngleDeg = cp.vl["STEER_ANGLE_SENSOR"]["STEER_ANGLE"] + cp.vl["STEER_ANGLE_SENSOR"]["STEER_FRACTION"] ret.steeringAngleDeg = cp.vl["STEER_ANGLE_SENSOR"]["STEER_ANGLE"] + cp.vl["STEER_ANGLE_SENSOR"]["STEER_FRACTION"]
torque_sensor_angle_deg = cp.vl["STEER_TORQUE_SENSOR"]["STEER_ANGLE"] torque_sensor_angle_deg = cp.vl["STEER_TORQUE_SENSOR"]["STEER_ANGLE"]
@ -90,16 +90,23 @@ class CarState(CarStateBase):
if self.CP.carFingerprint in (CAR.LEXUS_IS, CAR.LEXUS_RC): if self.CP.carFingerprint in (CAR.LEXUS_IS, CAR.LEXUS_RC):
ret.cruiseState.available = cp.vl["DSU_CRUISE"]["MAIN_ON"] != 0 ret.cruiseState.available = cp.vl["DSU_CRUISE"]["MAIN_ON"] != 0
ret.cruiseState.speed = cp.vl["DSU_CRUISE"]["SET_SPEED"] * CV.KPH_TO_MS ret.cruiseState.speed = cp.vl["DSU_CRUISE"]["SET_SPEED"] * CV.KPH_TO_MS
cluster_set_speed = cp.vl["PCM_CRUISE_ALT"]["UI_SET_SPEED"]
else: else:
ret.cruiseState.available = cp.vl["PCM_CRUISE_2"]["MAIN_ON"] != 0 ret.cruiseState.available = cp.vl["PCM_CRUISE_2"]["MAIN_ON"] != 0
ret.cruiseState.speed = cp.vl["PCM_CRUISE_2"]["SET_SPEED"] * CV.KPH_TO_MS ret.cruiseState.speed = cp.vl["PCM_CRUISE_2"]["SET_SPEED"] * CV.KPH_TO_MS
cluster_set_speed = cp.vl["PCM_CRUISE_SM"]["UI_SET_SPEED"]
if self.CP.carFingerprint in RADAR_ACC_CAR: # UI_SET_SPEED is always non-zero when main is on, hide until first enable
self.acc_type = cp.vl["ACC_CONTROL"]["ACC_TYPE"] if ret.cruiseState.speed != 0:
ret.stockFcw = bool(cp.vl["ACC_HUD"]["FCW"]) is_metric = cp.vl["BODY_CONTROL_STATE_2"]["UNITS"] in (1, 2)
elif self.CP.carFingerprint in TSS2_CAR: conversion_factor = CV.KPH_TO_MS if is_metric else CV.MPH_TO_MS
self.acc_type = cp_cam.vl["ACC_CONTROL"]["ACC_TYPE"] ret.cruiseState.speedCluster = cluster_set_speed * conversion_factor
ret.stockFcw = bool(cp_cam.vl["ACC_HUD"]["FCW"])
cp_acc = cp_cam if self.CP.carFingerprint in (TSS2_CAR - RADAR_ACC_CAR) else cp
if self.CP.carFingerprint in (TSS2_CAR | RADAR_ACC_CAR):
self.acc_type = cp_acc.vl["ACC_CONTROL"]["ACC_TYPE"]
ret.stockFcw = bool(cp_acc.vl["ACC_HUD"]["FCW"])
# some TSS2 cars have low speed lockout permanently set, so ignore on those cars # some TSS2 cars have low speed lockout permanently set, so ignore on those cars
# these cars are identified by an ACC_TYPE value of 2. # these cars are identified by an ACC_TYPE value of 2.
@ -120,10 +127,11 @@ class CarState(CarStateBase):
ret.cruiseState.nonAdaptive = cp.vl["PCM_CRUISE"]["CRUISE_STATE"] in (1, 2, 3, 4, 5, 6) ret.cruiseState.nonAdaptive = cp.vl["PCM_CRUISE"]["CRUISE_STATE"] in (1, 2, 3, 4, 5, 6)
ret.genericToggle = bool(cp.vl["LIGHT_STALK"]["AUTO_HIGH_BEAM"]) ret.genericToggle = bool(cp.vl["LIGHT_STALK"]["AUTO_HIGH_BEAM"])
ret.stockAeb = bool(cp_cam.vl["PRE_COLLISION"]["PRECOLLISION_ACTIVE"] and cp_cam.vl["PRE_COLLISION"]["FORCE"] < -1e-5)
ret.espDisabled = cp.vl["ESP_CONTROL"]["TC_DISABLED"] != 0 ret.espDisabled = cp.vl["ESP_CONTROL"]["TC_DISABLED"] != 0
if not self.CP.enableDsu:
ret.stockAeb = bool(cp_acc.vl["PRE_COLLISION"]["PRECOLLISION_ACTIVE"] and cp_acc.vl["PRE_COLLISION"]["FORCE"] < -1e-5)
if self.CP.enableBsm: if self.CP.enableBsm:
ret.leftBlindspot = (cp.vl["BSM"]["L_ADJACENT"] == 1) or (cp.vl["BSM"]["L_APPROACHING"] == 1) ret.leftBlindspot = (cp.vl["BSM"]["L_ADJACENT"] == 1) or (cp.vl["BSM"]["L_APPROACHING"] == 1)
ret.rightBlindspot = (cp.vl["BSM"]["R_ADJACENT"] == 1) or (cp.vl["BSM"]["R_APPROACHING"] == 1) ret.rightBlindspot = (cp.vl["BSM"]["R_ADJACENT"] == 1) or (cp.vl["BSM"]["R_APPROACHING"] == 1)
@ -147,6 +155,7 @@ class CarState(CarStateBase):
("DOOR_OPEN_RR", "BODY_CONTROL_STATE"), ("DOOR_OPEN_RR", "BODY_CONTROL_STATE"),
("SEATBELT_DRIVER_UNLATCHED", "BODY_CONTROL_STATE"), ("SEATBELT_DRIVER_UNLATCHED", "BODY_CONTROL_STATE"),
("PARKING_BRAKE", "BODY_CONTROL_STATE"), ("PARKING_BRAKE", "BODY_CONTROL_STATE"),
("UNITS", "BODY_CONTROL_STATE_2"),
("TC_DISABLED", "ESP_CONTROL"), ("TC_DISABLED", "ESP_CONTROL"),
("BRAKE_HOLD_ACTIVE", "ESP_CONTROL"), ("BRAKE_HOLD_ACTIVE", "ESP_CONTROL"),
("STEER_FRACTION", "STEER_ANGLE_SENSOR"), ("STEER_FRACTION", "STEER_ANGLE_SENSOR"),
@ -154,6 +163,7 @@ class CarState(CarStateBase):
("CRUISE_ACTIVE", "PCM_CRUISE"), ("CRUISE_ACTIVE", "PCM_CRUISE"),
("CRUISE_STATE", "PCM_CRUISE"), ("CRUISE_STATE", "PCM_CRUISE"),
("GAS_RELEASED", "PCM_CRUISE"), ("GAS_RELEASED", "PCM_CRUISE"),
("UI_SET_SPEED", "PCM_CRUISE_SM"),
("STEER_TORQUE_DRIVER", "STEER_TORQUE_SENSOR"), ("STEER_TORQUE_DRIVER", "STEER_TORQUE_SENSOR"),
("STEER_TORQUE_EPS", "STEER_TORQUE_SENSOR"), ("STEER_TORQUE_EPS", "STEER_TORQUE_SENSOR"),
("STEER_ANGLE", "STEER_TORQUE_SENSOR"), ("STEER_ANGLE", "STEER_TORQUE_SENSOR"),
@ -168,12 +178,14 @@ class CarState(CarStateBase):
("LIGHT_STALK", 1), ("LIGHT_STALK", 1),
("BLINKERS_STATE", 0.15), ("BLINKERS_STATE", 0.15),
("BODY_CONTROL_STATE", 3), ("BODY_CONTROL_STATE", 3),
("BODY_CONTROL_STATE_2", 2),
("ESP_CONTROL", 3), ("ESP_CONTROL", 3),
("EPS_STATUS", 25), ("EPS_STATUS", 25),
("BRAKE_MODULE", 40), ("BRAKE_MODULE", 40),
("WHEEL_SPEEDS", 80), ("WHEEL_SPEEDS", 80),
("STEER_ANGLE_SENSOR", 80), ("STEER_ANGLE_SENSOR", 80),
("PCM_CRUISE", 33), ("PCM_CRUISE", 33),
("PCM_CRUISE_SM", 1),
("STEER_TORQUE_SENSOR", 50), ("STEER_TORQUE_SENSOR", 50),
] ]
@ -187,7 +199,9 @@ class CarState(CarStateBase):
if CP.carFingerprint in (CAR.LEXUS_IS, CAR.LEXUS_RC): if CP.carFingerprint in (CAR.LEXUS_IS, CAR.LEXUS_RC):
signals.append(("MAIN_ON", "DSU_CRUISE")) signals.append(("MAIN_ON", "DSU_CRUISE"))
signals.append(("SET_SPEED", "DSU_CRUISE")) signals.append(("SET_SPEED", "DSU_CRUISE"))
signals.append(("UI_SET_SPEED", "PCM_CRUISE_ALT"))
checks.append(("DSU_CRUISE", 5)) checks.append(("DSU_CRUISE", 5))
checks.append(("PCM_CRUISE_ALT", 1))
else: else:
signals.append(("MAIN_ON", "PCM_CRUISE_2")) signals.append(("MAIN_ON", "PCM_CRUISE_2"))
signals.append(("SET_SPEED", "PCM_CRUISE_2")) signals.append(("SET_SPEED", "PCM_CRUISE_2"))
@ -219,27 +233,31 @@ class CarState(CarStateBase):
("ACC_HUD", 1), ("ACC_HUD", 1),
] ]
if CP.carFingerprint not in (TSS2_CAR - RADAR_ACC_CAR) and not CP.enableDsu:
signals += [
("FORCE", "PRE_COLLISION"),
("PRECOLLISION_ACTIVE", "PRE_COLLISION"),
]
checks += [
("PRE_COLLISION", 33),
]
return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, 0) return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, 0)
@staticmethod @staticmethod
def get_cam_can_parser(CP): def get_cam_can_parser(CP):
signals = [ signals = []
("FORCE", "PRE_COLLISION"), checks = []
("PRECOLLISION_ACTIVE", "PRE_COLLISION"),
]
# use steering message to check if panda is connected to frc
checks = [
("STEERING_LKA", 42),
("PRE_COLLISION", 0), # TODO: figure out why freq is inconsistent
]
if CP.carFingerprint in (TSS2_CAR - RADAR_ACC_CAR): if CP.carFingerprint in (TSS2_CAR - RADAR_ACC_CAR):
signals += [ signals += [
("PRECOLLISION_ACTIVE", "PRE_COLLISION"),
("FORCE", "PRE_COLLISION"),
("ACC_TYPE", "ACC_CONTROL"), ("ACC_TYPE", "ACC_CONTROL"),
("FCW", "ACC_HUD"), ("FCW", "ACC_HUD"),
] ]
checks += [ checks += [
("PRE_COLLISION", 33),
("ACC_CONTROL", 33), ("ACC_CONTROL", 33),
("ACC_HUD", 1), ("ACC_HUD", 1),
] ]

@ -218,6 +218,7 @@ class CarInterface(CarInterfaceBase):
ret.openpilotLongitudinalControl = smartDsu or ret.enableDsu or candidate in (TSS2_CAR - RADAR_ACC_CAR) ret.openpilotLongitudinalControl = smartDsu or ret.enableDsu or candidate in (TSS2_CAR - RADAR_ACC_CAR)
if not ret.openpilotLongitudinalControl: if not ret.openpilotLongitudinalControl:
ret.autoResumeSng = False
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_TOYOTA_STOCK_LONGITUDINAL ret.safetyConfigs[0].safetyParam |= Panda.FLAG_TOYOTA_STOCK_LONGITUDINAL
# we can't use the fingerprint to detect this reliably, since # we can't use the fingerprint to detect this reliably, since

@ -38,7 +38,7 @@ def set_long_tune(tune, name):
# Default longitudinal tune # Default longitudinal tune
elif name == LongTunes.TSS: elif name == LongTunes.TSS:
tune.deadzoneBP = [0., 9.] tune.deadzoneBP = [0., 9.]
tune.deadzoneV = [0., .15] tune.deadzoneV = [.0, .15]
tune.kpBP = [0., 5., 35.] tune.kpBP = [0., 5., 35.]
tune.kiBP = [0., 35.] tune.kiBP = [0., 35.]
tune.kpV = [3.6, 2.4, 1.5] tune.kpV = [3.6, 2.4, 1.5]

@ -6,7 +6,7 @@ from typing import Dict, List, Union
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 dbc_dict from selfdrive.car import dbc_dict
from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column, Harness, Star from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column, Harness
Ecu = car.CarParams.Ecu Ecu = car.CarParams.Ecu
MIN_ACC_SPEED = 19. * CV.MPH_TO_MS MIN_ACC_SPEED = 19. * CV.MPH_TO_MS
@ -89,7 +89,7 @@ class Footnote(Enum):
DSU = CarFootnote( DSU = CarFootnote(
"When the Driver Support Unit (DSU) is disconnected, openpilot Adaptive Cruise Control (ACC) will replace " + "When the Driver Support Unit (DSU) is disconnected, openpilot Adaptive Cruise Control (ACC) will replace " +
"stock Adaptive Cruise Control (ACC). <b><i>NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).</i></b>", "stock Adaptive Cruise Control (ACC). <b><i>NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).</i></b>",
Column.LONGITUDINAL, star=Star.HALF) Column.LONGITUDINAL)
CAMRY = CarFootnote( CAMRY = CarFootnote(
"openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.", "openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.",
Column.FSR_LONGITUDINAL) Column.FSR_LONGITUDINAL)
@ -114,7 +114,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = {
CAR.AVALON_TSS2: ToyotaCarInfo("Toyota Avalon 2022"), CAR.AVALON_TSS2: ToyotaCarInfo("Toyota Avalon 2022"),
CAR.AVALONH_TSS2: ToyotaCarInfo("Toyota Avalon Hybrid 2022"), CAR.AVALONH_TSS2: ToyotaCarInfo("Toyota Avalon Hybrid 2022"),
CAR.CAMRY: ToyotaCarInfo("Toyota Camry 2018-20", video_link="https://www.youtube.com/watch?v=fkcjviZY9CM", footnotes=[Footnote.CAMRY]), CAR.CAMRY: ToyotaCarInfo("Toyota Camry 2018-20", video_link="https://www.youtube.com/watch?v=fkcjviZY9CM", footnotes=[Footnote.CAMRY]),
CAR.CAMRYH: ToyotaCarInfo("Toyota Camry Hybrid 2018-20", video_link="https://www.youtube.com/watch?v=Q2DYY0AWKgk", footnotes=[Footnote.CAMRY]), CAR.CAMRYH: ToyotaCarInfo("Toyota Camry Hybrid 2018-20", video_link="https://www.youtube.com/watch?v=Q2DYY0AWKgk"),
CAR.CAMRY_TSS2: ToyotaCarInfo("Toyota Camry 2021-22", footnotes=[Footnote.CAMRY]), CAR.CAMRY_TSS2: ToyotaCarInfo("Toyota Camry 2021-22", footnotes=[Footnote.CAMRY]),
CAR.CAMRYH_TSS2: ToyotaCarInfo("Toyota Camry Hybrid 2021-22"), CAR.CAMRYH_TSS2: ToyotaCarInfo("Toyota Camry Hybrid 2021-22"),
CAR.CHR: ToyotaCarInfo("Toyota C-HR 2017-21"), CAR.CHR: ToyotaCarInfo("Toyota C-HR 2017-21"),
@ -200,7 +200,7 @@ STATIC_DSU_MSGS = [
FW_VERSIONS = { FW_VERSIONS = {
CAR.AVALON: { CAR.AVALON: {
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152607060\x00\x00\x00\x00\x00\x00', b'F152607060\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.dsu, 0x791, None): [ (Ecu.dsu, 0x791, None): [
@ -225,7 +225,7 @@ FW_VERSIONS = {
], ],
}, },
CAR.AVALON_2019: { CAR.AVALON_2019: {
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152607140\x00\x00\x00\x00\x00\x00', b'F152607140\x00\x00\x00\x00\x00\x00',
b'F152607171\x00\x00\x00\x00\x00\x00', b'F152607171\x00\x00\x00\x00\x00\x00',
b'F152607110\x00\x00\x00\x00\x00\x00', b'F152607110\x00\x00\x00\x00\x00\x00',
@ -253,7 +253,7 @@ FW_VERSIONS = {
], ],
}, },
CAR.AVALONH_2019: { CAR.AVALONH_2019: {
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152641040\x00\x00\x00\x00\x00\x00', b'F152641040\x00\x00\x00\x00\x00\x00',
b'F152641061\x00\x00\x00\x00\x00\x00', b'F152641061\x00\x00\x00\x00\x00\x00',
b'F152641050\x00\x00\x00\x00\x00\x00', b'F152641050\x00\x00\x00\x00\x00\x00',
@ -280,7 +280,7 @@ FW_VERSIONS = {
], ],
}, },
CAR.AVALON_TSS2: { CAR.AVALON_TSS2: {
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'\x01F152607240\x00\x00\x00\x00\x00\x00', b'\x01F152607240\x00\x00\x00\x00\x00\x00',
b'\x01F152607280\x00\x00\x00\x00\x00\x00', b'\x01F152607280\x00\x00\x00\x00\x00\x00',
], ],
@ -300,7 +300,7 @@ FW_VERSIONS = {
], ],
}, },
CAR.AVALONH_TSS2: { CAR.AVALONH_TSS2: {
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152641080\x00\x00\x00\x00\x00\x00', b'F152641080\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.eps, 0x7a1, None): [ (Ecu.eps, 0x7a1, None): [
@ -356,7 +356,7 @@ FW_VERSIONS = {
b'8821F0608200 ', b'8821F0608200 ',
b'8821F0609100 ', b'8821F0609100 ',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152606210\x00\x00\x00\x00\x00\x00', b'F152606210\x00\x00\x00\x00\x00\x00',
b'F152606230\x00\x00\x00\x00\x00\x00', b'F152606230\x00\x00\x00\x00\x00\x00',
b'F152606270\x00\x00\x00\x00\x00\x00', b'F152606270\x00\x00\x00\x00\x00\x00',
@ -420,7 +420,7 @@ FW_VERSIONS = {
b'\x028966306S0100\x00\x00\x00\x00897CF3305001\x00\x00\x00\x00', b'\x028966306S0100\x00\x00\x00\x00897CF3305001\x00\x00\x00\x00',
b'\x028966306S1100\x00\x00\x00\x00897CF3305001\x00\x00\x00\x00', b'\x028966306S1100\x00\x00\x00\x00897CF3305001\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152633214\x00\x00\x00\x00\x00\x00', b'F152633214\x00\x00\x00\x00\x00\x00',
b'F152633660\x00\x00\x00\x00\x00\x00', b'F152633660\x00\x00\x00\x00\x00\x00',
b'F152633712\x00\x00\x00\x00\x00\x00', b'F152633712\x00\x00\x00\x00\x00\x00',
@ -486,7 +486,7 @@ FW_VERSIONS = {
(Ecu.eps, 0x7a1, None): [ (Ecu.eps, 0x7a1, None): [
b'8965B33630\x00\x00\x00\x00\x00\x00', b'8965B33630\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'\x01F152606370\x00\x00\x00\x00\x00\x00', b'\x01F152606370\x00\x00\x00\x00\x00\x00',
b'\x01F152606390\x00\x00\x00\x00\x00\x00', b'\x01F152606390\x00\x00\x00\x00\x00\x00',
b'\x01F152606400\x00\x00\x00\x00\x00\x00', b'\x01F152606400\x00\x00\x00\x00\x00\x00',
@ -512,7 +512,7 @@ FW_VERSIONS = {
(Ecu.eps, 0x7a1, None): [ (Ecu.eps, 0x7a1, None): [
b'8965B33630\x00\x00\x00\x00\x00\x00', b'8965B33630\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152633D00\x00\x00\x00\x00\x00\x00', b'F152633D00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.engine, 0x700, None): [ (Ecu.engine, 0x700, None): [
@ -547,7 +547,7 @@ FW_VERSIONS = {
b'8821FF406000 ', b'8821FF406000 ',
b'8821FF407100 ', b'8821FF407100 ',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152610020\x00\x00\x00\x00\x00\x00', b'F152610020\x00\x00\x00\x00\x00\x00',
b'F152610153\x00\x00\x00\x00\x00\x00', b'F152610153\x00\x00\x00\x00\x00\x00',
b'F152610210\x00\x00\x00\x00\x00\x00', b'F152610210\x00\x00\x00\x00\x00\x00',
@ -599,7 +599,7 @@ FW_VERSIONS = {
b'\x0289663F431000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x0289663F431000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00',
b'\x0189663F438000\x00\x00\x00\x00', b'\x0189663F438000\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152610012\x00\x00\x00\x00\x00\x00', b'F152610012\x00\x00\x00\x00\x00\x00',
b'F152610013\x00\x00\x00\x00\x00\x00', b'F152610013\x00\x00\x00\x00\x00\x00',
b'F152610014\x00\x00\x00\x00\x00\x00', b'F152610014\x00\x00\x00\x00\x00\x00',
@ -658,7 +658,7 @@ FW_VERSIONS = {
b'881510201100\x00\x00\x00\x00', b'881510201100\x00\x00\x00\x00',
b'881510201200\x00\x00\x00\x00', b'881510201200\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152602190\x00\x00\x00\x00\x00\x00', b'F152602190\x00\x00\x00\x00\x00\x00',
b'F152602191\x00\x00\x00\x00\x00\x00', b'F152602191\x00\x00\x00\x00\x00\x00',
], ],
@ -687,6 +687,7 @@ FW_VERSIONS = {
b'\x01896630ZP2000\x00\x00\x00\x00', b'\x01896630ZP2000\x00\x00\x00\x00',
b'\x01896630ZQ5000\x00\x00\x00\x00', b'\x01896630ZQ5000\x00\x00\x00\x00',
b'\x01896630ZU9000\x00\x00\x00\x00', b'\x01896630ZU9000\x00\x00\x00\x00',
b'\x01896630ZX4000\x00\x00\x00\x00',
b'\x018966312L8000\x00\x00\x00\x00', b'\x018966312L8000\x00\x00\x00\x00',
b'\x018966312M0000\x00\x00\x00\x00', b'\x018966312M0000\x00\x00\x00\x00',
b'\x018966312M9000\x00\x00\x00\x00', b'\x018966312M9000\x00\x00\x00\x00',
@ -717,6 +718,7 @@ FW_VERSIONS = {
b'\x03312N6000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203402\x00\x00\x00\x00', b'\x03312N6000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203402\x00\x00\x00\x00',
b'\x03312N6100\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203302\x00\x00\x00\x00', b'\x03312N6100\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203302\x00\x00\x00\x00',
b'\x03312N6100\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203402\x00\x00\x00\x00', b'\x03312N6100\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203402\x00\x00\x00\x00',
b'\x03312N6200\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203302\x00\x00\x00\x00',
b'\x02312K4000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02312K4000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00',
b'\x02312U5000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02312U5000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
@ -733,7 +735,7 @@ FW_VERSIONS = {
b'\x018965B12510\x00\x00\x00\x00\x00\x00', b'\x018965B12510\x00\x00\x00\x00\x00\x00',
b'\x018965B1256000\x00\x00\x00\x00', b'\x018965B1256000\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'\x01F152602280\x00\x00\x00\x00\x00\x00', b'\x01F152602280\x00\x00\x00\x00\x00\x00',
b'\x01F152602560\x00\x00\x00\x00\x00\x00', b'\x01F152602560\x00\x00\x00\x00\x00\x00',
b'\x01F152602590\x00\x00\x00\x00\x00\x00', b'\x01F152602590\x00\x00\x00\x00\x00\x00',
@ -782,6 +784,7 @@ FW_VERSIONS = {
b'\x01896637626000\x00\x00\x00\x00', b'\x01896637626000\x00\x00\x00\x00',
b'\x01896637648000\x00\x00\x00\x00', b'\x01896637648000\x00\x00\x00\x00',
b'\x01896637643000\x00\x00\x00\x00', b'\x01896637643000\x00\x00\x00\x00',
b'\x02896630A21000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00',
b'\x02896630ZJ5000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896630ZJ5000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00',
b'\x02896630ZN8000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896630ZN8000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00',
b'\x02896630ZQ3000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896630ZQ3000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00',
@ -810,7 +813,7 @@ FW_VERSIONS = {
b'\x018965B12520\x00\x00\x00\x00\x00\x00', b'\x018965B12520\x00\x00\x00\x00\x00\x00',
b'\x018965B12530\x00\x00\x00\x00\x00\x00', b'\x018965B12530\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152612590\x00\x00\x00\x00\x00\x00', b'F152612590\x00\x00\x00\x00\x00\x00',
b'F152612691\x00\x00\x00\x00\x00\x00', b'F152612691\x00\x00\x00\x00\x00\x00',
b'F152612692\x00\x00\x00\x00\x00\x00', b'F152612692\x00\x00\x00\x00\x00\x00',
@ -826,6 +829,7 @@ FW_VERSIONS = {
b'F152612A10\x00\x00\x00\x00\x00\x00', b'F152612A10\x00\x00\x00\x00\x00\x00',
b'F152612D00\x00\x00\x00\x00\x00\x00', b'F152612D00\x00\x00\x00\x00\x00\x00',
b'F152616011\x00\x00\x00\x00\x00\x00', b'F152616011\x00\x00\x00\x00\x00\x00',
b'F152616060\x00\x00\x00\x00\x00\x00',
b'F152642540\x00\x00\x00\x00\x00\x00', b'F152642540\x00\x00\x00\x00\x00\x00',
b'F152676293\x00\x00\x00\x00\x00\x00', b'F152676293\x00\x00\x00\x00\x00\x00',
b'F152676303\x00\x00\x00\x00\x00\x00', b'F152676303\x00\x00\x00\x00\x00\x00',
@ -881,7 +885,7 @@ FW_VERSIONS = {
b'8965B48150\x00\x00\x00\x00\x00\x00', b'8965B48150\x00\x00\x00\x00\x00\x00',
b'8965B48210\x00\x00\x00\x00\x00\x00', b'8965B48210\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [b'F15260E011\x00\x00\x00\x00\x00\x00'], (Ecu.abs, 0x7b0, None): [b'F15260E011\x00\x00\x00\x00\x00\x00'],
(Ecu.dsu, 0x791, None): [ (Ecu.dsu, 0x791, None): [
b'881510E01100\x00\x00\x00\x00', b'881510E01100\x00\x00\x00\x00',
b'881510E01200\x00\x00\x00\x00', b'881510E01200\x00\x00\x00\x00',
@ -899,7 +903,7 @@ FW_VERSIONS = {
(Ecu.eps, 0x7a1, None): [ (Ecu.eps, 0x7a1, None): [
b'8965B48160\x00\x00\x00\x00\x00\x00', b'8965B48160\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152648541\x00\x00\x00\x00\x00\x00', b'F152648541\x00\x00\x00\x00\x00\x00',
b'F152648542\x00\x00\x00\x00\x00\x00', b'F152648542\x00\x00\x00\x00\x00\x00',
], ],
@ -924,7 +928,7 @@ FW_VERSIONS = {
b'8965B48310\x00\x00\x00\x00\x00\x00', b'8965B48310\x00\x00\x00\x00\x00\x00',
b'8965B48320\x00\x00\x00\x00\x00\x00', b'8965B48320\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'\x01F15260E051\x00\x00\x00\x00\x00\x00', b'\x01F15260E051\x00\x00\x00\x00\x00\x00',
b'\x01F15260E061\x00\x00\x00\x00\x00\x00', b'\x01F15260E061\x00\x00\x00\x00\x00\x00',
b'\x01F15260E110\x00\x00\x00\x00\x00\x00', b'\x01F15260E110\x00\x00\x00\x00\x00\x00',
@ -943,7 +947,9 @@ FW_VERSIONS = {
b'\x01896630EB2200\x00\x00\x00\x00', b'\x01896630EB2200\x00\x00\x00\x00',
b'\x01896630EC4000\x00\x00\x00\x00', b'\x01896630EC4000\x00\x00\x00\x00',
b'\x01896630ED9000\x00\x00\x00\x00', b'\x01896630ED9000\x00\x00\x00\x00',
b'\x01896630ED9100\x00\x00\x00\x00',
b'\x01896630EE1000\x00\x00\x00\x00', b'\x01896630EE1000\x00\x00\x00\x00',
b'\x01896630EE1100\x00\x00\x00\x00',
], ],
(Ecu.fwdRadar, 0x750, 0xf): [ (Ecu.fwdRadar, 0x750, 0xf): [
b'\x018821F3301400\x00\x00\x00\x00', b'\x018821F3301400\x00\x00\x00\x00',
@ -961,7 +967,7 @@ FW_VERSIONS = {
b'8965B48241\x00\x00\x00\x00\x00\x00', b'8965B48241\x00\x00\x00\x00\x00\x00',
b'8965B48310\x00\x00\x00\x00\x00\x00', b'8965B48310\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'\x01F15264872300\x00\x00\x00\x00', b'\x01F15264872300\x00\x00\x00\x00',
b'\x01F15264872400\x00\x00\x00\x00', b'\x01F15264872400\x00\x00\x00\x00',
b'\x01F15264872500\x00\x00\x00\x00', b'\x01F15264872500\x00\x00\x00\x00',
@ -971,15 +977,16 @@ FW_VERSIONS = {
b'\x01F152648J6000\x00\x00\x00\x00', b'\x01F152648J6000\x00\x00\x00\x00',
], ],
(Ecu.engine, 0x700, None): [ (Ecu.engine, 0x700, None): [
b'\x01896630EE4000\x00\x00\x00\x00',
b'\x01896630EE6000\x00\x00\x00\x00',
b'\x01896630E67000\x00\x00\x00\x00', b'\x01896630E67000\x00\x00\x00\x00',
b'\x01896630EA1000\x00\x00\x00\x00', b'\x01896630EA1000\x00\x00\x00\x00',
b'\x01896630EA1000\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', b'\x01896630EE4000\x00\x00\x00\x00',
b'\x01896630EE4100\x00\x00\x00\x00',
b'\x01896630EE6000\x00\x00\x00\x00',
b'\x02896630E66000\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', b'\x02896630E66000\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00',
b'\x02896630E66100\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00',
b'\x01896630EA1000\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00',
b'\x02896630EB3000\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', b'\x02896630EB3000\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00',
b'\x02896630EB3100\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', b'\x02896630EB3100\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00',
b'\x02896630E66100\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00',
], ],
(Ecu.fwdRadar, 0x750, 0xf): [ (Ecu.fwdRadar, 0x750, 0xf): [
b'\x018821F3301400\x00\x00\x00\x00', b'\x018821F3301400\x00\x00\x00\x00',
@ -1008,7 +1015,7 @@ FW_VERSIONS = {
b'\x02353P7000\x00\x00\x00\x00\x00\x00\x00\x00530J5000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02353P7000\x00\x00\x00\x00\x00\x00\x00\x00530J5000\x00\x00\x00\x00\x00\x00\x00\x00',
b'\x02353P9000\x00\x00\x00\x00\x00\x00\x00\x00553C1000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02353P9000\x00\x00\x00\x00\x00\x00\x00\x00553C1000\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152653300\x00\x00\x00\x00\x00\x00', b'F152653300\x00\x00\x00\x00\x00\x00',
b'F152653301\x00\x00\x00\x00\x00\x00', b'F152653301\x00\x00\x00\x00\x00\x00',
b'F152653310\x00\x00\x00\x00\x00\x00', b'F152653310\x00\x00\x00\x00\x00\x00',
@ -1092,7 +1099,7 @@ FW_VERSIONS = {
b'8965B47050\x00\x00\x00\x00\x00\x00', b'8965B47050\x00\x00\x00\x00\x00\x00',
b'8965B47060\x00\x00\x00\x00\x00\x00', # This is the EPS with good angle sensor b'8965B47060\x00\x00\x00\x00\x00\x00', # This is the EPS with good angle sensor
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152647290\x00\x00\x00\x00\x00\x00', b'F152647290\x00\x00\x00\x00\x00\x00',
b'F152647300\x00\x00\x00\x00\x00\x00', b'F152647300\x00\x00\x00\x00\x00\x00',
b'F152647310\x00\x00\x00\x00\x00\x00', b'F152647310\x00\x00\x00\x00\x00\x00',
@ -1133,7 +1140,7 @@ FW_VERSIONS = {
], ],
}, },
CAR.PRIUS_V: { CAR.PRIUS_V: {
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152647280\x00\x00\x00\x00\x00\x00', b'F152647280\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.engine, 0x7e0, None): [ (Ecu.engine, 0x7e0, None): [
@ -1166,7 +1173,7 @@ FW_VERSIONS = {
b'8965B42082\x00\x00\x00\x00\x00\x00', b'8965B42082\x00\x00\x00\x00\x00\x00',
b'8965B42083\x00\x00\x00\x00\x00\x00', b'8965B42083\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F15260R102\x00\x00\x00\x00\x00\x00', b'F15260R102\x00\x00\x00\x00\x00\x00',
b'F15260R103\x00\x00\x00\x00\x00\x00', b'F15260R103\x00\x00\x00\x00\x00\x00',
b'F152642493\x00\x00\x00\x00\x00\x00', b'F152642493\x00\x00\x00\x00\x00\x00',
@ -1203,7 +1210,7 @@ FW_VERSIONS = {
b'8965B42162\x00\x00\x00\x00\x00\x00', b'8965B42162\x00\x00\x00\x00\x00\x00',
b'8965B42163\x00\x00\x00\x00\x00\x00', b'8965B42163\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152642090\x00\x00\x00\x00\x00\x00', b'F152642090\x00\x00\x00\x00\x00\x00',
b'F152642110\x00\x00\x00\x00\x00\x00', b'F152642110\x00\x00\x00\x00\x00\x00',
b'F152642120\x00\x00\x00\x00\x00\x00', b'F152642120\x00\x00\x00\x00\x00\x00',
@ -1263,8 +1270,9 @@ FW_VERSIONS = {
b'\x02896634A18100\x00\x00\x00\x00897CF1201001\x00\x00\x00\x00', b'\x02896634A18100\x00\x00\x00\x00897CF1201001\x00\x00\x00\x00',
b'\x02896634A43000\x00\x00\x00\x00897CF4201001\x00\x00\x00\x00', b'\x02896634A43000\x00\x00\x00\x00897CF4201001\x00\x00\x00\x00',
b'\x02896634A47000\x00\x00\x00\x00897CF4201001\x00\x00\x00\x00', b'\x02896634A47000\x00\x00\x00\x00897CF4201001\x00\x00\x00\x00',
b'\x028966342Z8000\x00\x00\x00\x00897CF1201001\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'\x01F15260R210\x00\x00\x00\x00\x00\x00', b'\x01F15260R210\x00\x00\x00\x00\x00\x00',
b'\x01F15260R220\x00\x00\x00\x00\x00\x00', b'\x01F15260R220\x00\x00\x00\x00\x00\x00',
b'\x01F15260R290\x00\x00\x00\x00\x00\x00', b'\x01F15260R290\x00\x00\x00\x00\x00\x00',
@ -1305,7 +1313,7 @@ FW_VERSIONS = {
], ],
}, },
CAR.RAV4_TSS2_2022: { CAR.RAV4_TSS2_2022: {
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'\x01F15260R350\x00\x00\x00\x00\x00\x00', b'\x01F15260R350\x00\x00\x00\x00\x00\x00',
b'\x01F15260R361\x00\x00\x00\x00\x00\x00', b'\x01F15260R361\x00\x00\x00\x00\x00\x00',
], ],
@ -1345,7 +1353,7 @@ FW_VERSIONS = {
b'\x02896634A14001\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', b'\x02896634A14001\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00',
b'\x02896634A14101\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', b'\x02896634A14101\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152642291\x00\x00\x00\x00\x00\x00', b'F152642291\x00\x00\x00\x00\x00\x00',
b'F152642290\x00\x00\x00\x00\x00\x00', b'F152642290\x00\x00\x00\x00\x00\x00',
b'F152642322\x00\x00\x00\x00\x00\x00', b'F152642322\x00\x00\x00\x00\x00\x00',
@ -1384,7 +1392,7 @@ FW_VERSIONS = {
], ],
}, },
CAR.RAV4H_TSS2_2022: { CAR.RAV4H_TSS2_2022: {
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'\x01F15264283100\x00\x00\x00\x00', b'\x01F15264283100\x00\x00\x00\x00',
b'\x01F15264286200\x00\x00\x00\x00', b'\x01F15264286200\x00\x00\x00\x00',
b'\x01F15264286100\x00\x00\x00\x00', b'\x01F15264286100\x00\x00\x00\x00',
@ -1432,7 +1440,7 @@ FW_VERSIONS = {
b'8965B45080\x00\x00\x00\x00\x00\x00', b'8965B45080\x00\x00\x00\x00\x00\x00',
b'8965B45082\x00\x00\x00\x00\x00\x00', b'8965B45082\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152608130\x00\x00\x00\x00\x00\x00', b'F152608130\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.dsu, 0x791, None): [ (Ecu.dsu, 0x791, None): [
@ -1451,7 +1459,7 @@ FW_VERSIONS = {
(Ecu.dsu, 0x791, None): [ (Ecu.dsu, 0x791, None): [
b'881517601100\x00\x00\x00\x00', b'881517601100\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152676144\x00\x00\x00\x00\x00\x00', b'F152676144\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.engine, 0x7e0, None): [ (Ecu.engine, 0x7e0, None): [
@ -1473,7 +1481,7 @@ FW_VERSIONS = {
b'\x018966333X6000\x00\x00\x00\x00', b'\x018966333X6000\x00\x00\x00\x00',
b'\x01896633T07000\x00\x00\x00\x00', b'\x01896633T07000\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'\x01F152606281\x00\x00\x00\x00\x00\x00', b'\x01F152606281\x00\x00\x00\x00\x00\x00',
b'\x01F152606340\x00\x00\x00\x00\x00\x00', b'\x01F152606340\x00\x00\x00\x00\x00\x00',
b'\x01F152606461\x00\x00\x00\x00\x00\x00', b'\x01F152606461\x00\x00\x00\x00\x00\x00',
@ -1510,7 +1518,7 @@ FW_VERSIONS = {
b'\x02896633T09000\x00\x00\x00\x00897CF3307001\x00\x00\x00\x00', b'\x02896633T09000\x00\x00\x00\x00897CF3307001\x00\x00\x00\x00',
b'\x01896633T38000\x00\x00\x00\x00', b'\x01896633T38000\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152633423\x00\x00\x00\x00\x00\x00', b'F152633423\x00\x00\x00\x00\x00\x00',
b'F152633680\x00\x00\x00\x00\x00\x00', b'F152633680\x00\x00\x00\x00\x00\x00',
b'F152633681\x00\x00\x00\x00\x00\x00', b'F152633681\x00\x00\x00\x00\x00\x00',
@ -1543,7 +1551,7 @@ FW_VERSIONS = {
(Ecu.engine, 0x7e0, None): [ (Ecu.engine, 0x7e0, None): [
b'\x02333M4200\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02333M4200\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152633171\x00\x00\x00\x00\x00\x00', b'F152633171\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.dsu, 0x791, None): [ (Ecu.dsu, 0x791, None): [
@ -1569,7 +1577,7 @@ FW_VERSIONS = {
b'\x01896637854000\x00\x00\x00\x00', b'\x01896637854000\x00\x00\x00\x00',
b'\x01896637878000\x00\x00\x00\x00', b'\x01896637878000\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152678130\x00\x00\x00\x00\x00\x00', b'F152678130\x00\x00\x00\x00\x00\x00',
b'F152678140\x00\x00\x00\x00\x00\x00', b'F152678140\x00\x00\x00\x00\x00\x00',
], ],
@ -1596,7 +1604,7 @@ FW_VERSIONS = {
b'\x018966378B3000\x00\x00\x00\x00', b'\x018966378B3000\x00\x00\x00\x00',
b'\x018966378G3000\x00\x00\x00\x00', b'\x018966378G3000\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'\x01F152678221\x00\x00\x00\x00\x00\x00', b'\x01F152678221\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.eps, 0x7a1, None): [ (Ecu.eps, 0x7a1, None): [
@ -1616,7 +1624,7 @@ FW_VERSIONS = {
(Ecu.engine, 0x7e0, None): [ (Ecu.engine, 0x7e0, None): [
b'\x0237887000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x0237887000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152678210\x00\x00\x00\x00\x00\x00', b'F152678210\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.eps, 0x7a1, None): [ (Ecu.eps, 0x7a1, None): [
@ -1637,7 +1645,7 @@ FW_VERSIONS = {
b'\x0237882000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x0237882000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00',
b'\x0237886000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x0237886000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152678160\x00\x00\x00\x00\x00\x00', b'F152678160\x00\x00\x00\x00\x00\x00',
b'F152678170\x00\x00\x00\x00\x00\x00', b'F152678170\x00\x00\x00\x00\x00\x00',
b'F152678171\x00\x00\x00\x00\x00\x00', b'F152678171\x00\x00\x00\x00\x00\x00',
@ -1664,7 +1672,7 @@ FW_VERSIONS = {
(Ecu.engine, 0x7e0, None): [ (Ecu.engine, 0x7e0, None): [
b'\x0232484000\x00\x00\x00\x00\x00\x00\x00\x0052422000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x0232484000\x00\x00\x00\x00\x00\x00\x00\x0052422000\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152624221\x00\x00\x00\x00\x00\x00', b'F152624221\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.dsu, 0x791, None): [ (Ecu.dsu, 0x791, None): [
@ -1700,7 +1708,7 @@ FW_VERSIONS = {
b'\x018966348R8500\x00\x00\x00\x00', b'\x018966348R8500\x00\x00\x00\x00',
b'\x018966348W1300\x00\x00\x00\x00', b'\x018966348W1300\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152648472\x00\x00\x00\x00\x00\x00', b'F152648472\x00\x00\x00\x00\x00\x00',
b'F152648473\x00\x00\x00\x00\x00\x00', b'F152648473\x00\x00\x00\x00\x00\x00',
b'F152648492\x00\x00\x00\x00\x00\x00', b'F152648492\x00\x00\x00\x00\x00\x00',
@ -1747,7 +1755,7 @@ FW_VERSIONS = {
b'\x02348V6000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02348V6000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00',
b'\x02348Z3000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02348Z3000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152648361\x00\x00\x00\x00\x00\x00', b'F152648361\x00\x00\x00\x00\x00\x00',
b'F152648501\x00\x00\x00\x00\x00\x00', b'F152648501\x00\x00\x00\x00\x00\x00',
b'F152648502\x00\x00\x00\x00\x00\x00', b'F152648502\x00\x00\x00\x00\x00\x00',
@ -1795,7 +1803,7 @@ FW_VERSIONS = {
b'\x01896634D43000\x00\x00\x00\x00', b'\x01896634D43000\x00\x00\x00\x00',
b'\x01896634D44000\x00\x00\x00\x00', b'\x01896634D44000\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'\x01F15260E031\x00\x00\x00\x00\x00\x00', b'\x01F15260E031\x00\x00\x00\x00\x00\x00',
b'\x01F15260E041\x00\x00\x00\x00\x00\x00', b'\x01F15260E041\x00\x00\x00\x00\x00\x00',
b'\x01F152648781\x00\x00\x00\x00\x00\x00', b'\x01F152648781\x00\x00\x00\x00\x00\x00',
@ -1825,7 +1833,7 @@ FW_VERSIONS = {
b'\x0234D16000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x0234D16000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00',
b'\x02348X4000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02348X4000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152648831\x00\x00\x00\x00\x00\x00', b'F152648831\x00\x00\x00\x00\x00\x00',
b'F152648891\x00\x00\x00\x00\x00\x00', b'F152648891\x00\x00\x00\x00\x00\x00',
b'F152648D00\x00\x00\x00\x00\x00\x00', b'F152648D00\x00\x00\x00\x00\x00\x00',
@ -1855,7 +1863,7 @@ FW_VERSIONS = {
b'\x038966347C5000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4707101\x00\x00\x00\x00', b'\x038966347C5000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4707101\x00\x00\x00\x00',
b'\x038966347C5100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4707101\x00\x00\x00\x00', b'\x038966347C5100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4707101\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152647500\x00\x00\x00\x00\x00\x00', b'F152647500\x00\x00\x00\x00\x00\x00',
b'F152647510\x00\x00\x00\x00\x00\x00', b'F152647510\x00\x00\x00\x00\x00\x00',
b'F152647520\x00\x00\x00\x00\x00\x00', b'F152647520\x00\x00\x00\x00\x00\x00',
@ -1875,8 +1883,8 @@ FW_VERSIONS = {
], ],
}, },
CAR.MIRAI: { CAR.MIRAI: {
(Ecu.esp, 0x7D1, None): [b'\x01898A36203000\x00\x00\x00\x00',], (Ecu.abs, 0x7D1, None): [b'\x01898A36203000\x00\x00\x00\x00',],
(Ecu.esp, 0x7B0, None): [ # a second ESP ECU (Ecu.abs, 0x7B0, None): [ # a second ABS ECU
b'\x01F15266203200\x00\x00\x00\x00', b'\x01F15266203200\x00\x00\x00\x00',
b'\x01F15266203500\x00\x00\x00\x00', b'\x01F15266203500\x00\x00\x00\x00',
], ],
@ -1909,7 +1917,7 @@ FW_VERSIONS = {
(Ecu.eps, 0x7a1, None): [ (Ecu.eps, 0x7a1, None): [
b'8965B58040\x00\x00\x00\x00\x00\x00', b'8965B58040\x00\x00\x00\x00\x00\x00',
], ],
(Ecu.esp, 0x7b0, None): [ (Ecu.abs, 0x7b0, None): [
b'F152658341\x00\x00\x00\x00\x00\x00' b'F152658341\x00\x00\x00\x00\x00\x00'
], ],
(Ecu.fwdRadar, 0x750, 0xf): [ (Ecu.fwdRadar, 0x750, 0xf): [

@ -5,7 +5,6 @@ import traceback
import cereal.messaging as messaging import cereal.messaging as messaging
import panda.python.uds as uds import panda.python.uds as uds
from panda.python.uds import FUNCTIONAL_ADDRS
from selfdrive.car.isotp_parallel_query import IsoTpParallelQuery from selfdrive.car.isotp_parallel_query import IsoTpParallelQuery
from system.swaglog import cloudlog from system.swaglog import cloudlog
@ -24,10 +23,11 @@ def is_valid_vin(vin: str):
def get_vin(logcan, sendcan, bus, timeout=0.1, retry=5, debug=False): def get_vin(logcan, sendcan, bus, timeout=0.1, retry=5, debug=False):
addrs = [0x7e0, 0x7e2, 0x18da10f1, 0x18da0ef1] # engine, VMCU, 29-bit engine, PGM-FI
for i in range(retry): for i in range(retry):
for request, response in ((UDS_VIN_REQUEST, UDS_VIN_RESPONSE), (OBD_VIN_REQUEST, OBD_VIN_RESPONSE)): for request, response in ((UDS_VIN_REQUEST, UDS_VIN_RESPONSE), (OBD_VIN_REQUEST, OBD_VIN_RESPONSE)):
try: try:
query = IsoTpParallelQuery(sendcan, logcan, bus, FUNCTIONAL_ADDRS, [request, ], [response, ], functional_addr=True, debug=debug) query = IsoTpParallelQuery(sendcan, logcan, bus, addrs, [request, ], [response, ], debug=debug)
for (addr, rx_addr), vin in query.get_data(timeout).items(): for (addr, rx_addr), vin in query.get_data(timeout).items():
# Honda Bosch response starts with a length, trim to correct length # Honda Bosch response starts with a length, trim to correct length

@ -3,8 +3,8 @@ from opendbc.can.packer import CANPacker
from common.numpy_fast import clip from common.numpy_fast import clip
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
from selfdrive.car import apply_std_steer_torque_limits from selfdrive.car import apply_std_steer_torque_limits
from selfdrive.car.volkswagen import mqbcan from selfdrive.car.volkswagen import mqbcan, pqcan
from selfdrive.car.volkswagen.values import CANBUS, CarControllerParams from selfdrive.car.volkswagen.values import CANBUS, PQ_CARS, CarControllerParams
VisualAlert = car.CarControl.HUDControl.VisualAlert VisualAlert = car.CarControl.HUDControl.VisualAlert
LongCtrlState = car.CarControl.Actuators.LongControlState LongCtrlState = car.CarControl.Actuators.LongControlState
@ -14,7 +14,7 @@ class CarController:
def __init__(self, dbc_name, CP, VM): def __init__(self, dbc_name, CP, VM):
self.CP = CP self.CP = CP
self.CCP = CarControllerParams(CP) self.CCP = CarControllerParams(CP)
self.CCS = mqbcan self.CCS = pqcan if CP.carFingerprint in PQ_CARS else mqbcan
self.packer_pt = CANPacker(dbc_name) self.packer_pt = CANPacker(dbc_name)
self.apply_steer_last = 0 self.apply_steer_last = 0
@ -122,6 +122,13 @@ class CarController:
self.apply_steer_last = apply_steer self.apply_steer_last = apply_steer
can_sends.append(self.CCS.create_steering_control(self.packer_pt, CANBUS.pt, apply_steer, hcaEnabled)) can_sends.append(self.CCS.create_steering_control(self.packer_pt, CANBUS.pt, apply_steer, hcaEnabled))
# **** Acceleration Controls ******************************************** #
if self.frame % self.CCP.ACC_CONTROL_STEP == 0 and self.CP.openpilotLongitudinalControl:
tsk_status = self.CCS.tsk_status_value(CS.out.cruiseState.available, CS.out.accFaulted, CC.longActive)
accel = clip(actuators.accel, self.CCP.ACCEL_MIN, self.CCP.ACCEL_MAX) if CC.longActive else 0
can_sends.extend(self.CCS.create_acc_accel_control(self.packer_pt, CANBUS.pt, tsk_status, accel))
# **** HUD Controls ***************************************************** # # **** HUD Controls ***************************************************** #
if self.frame % self.CCP.LDW_STEP == 0: if self.frame % self.CCP.LDW_STEP == 0:
@ -131,6 +138,12 @@ class CarController:
can_sends.append(self.CCS.create_lka_hud_control(self.packer_pt, CANBUS.pt, CS.ldw_stock_values, CC.enabled, can_sends.append(self.CCS.create_lka_hud_control(self.packer_pt, CANBUS.pt, CS.ldw_stock_values, CC.enabled,
CS.out.steeringPressed, hud_alert, hud_control)) CS.out.steeringPressed, hud_alert, hud_control))
if self.frame % self.CCP.ACC_HUD_STEP == 0 and self.CP.openpilotLongitudinalControl:
acc_hud_status = self.CCS.acc_hud_status_value(CS.out.cruiseState.available, CS.out.accFaulted, CC.longActive)
set_speed = hud_control.setSpeed * CV.MS_TO_KPH # FIXME: follow the recent displayed-speed updates, also use mph_kmh toggle to fix display rounding problem?
can_sends.append(self.CCS.create_acc_hud_control(self.packer_pt, CANBUS.pt, acc_hud_status, set_speed,
hud_control.leadVisible))
# **** Stock ACC Button Controls **************************************** # # **** Stock ACC Button Controls **************************************** #
if self.CP.pcmCruise and self.frame % self.CCP.GRA_ACC_STEP == 0: if self.CP.pcmCruise and self.frame % self.CCP.GRA_ACC_STEP == 0:

@ -3,7 +3,7 @@ from cereal import car
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
from selfdrive.car.interfaces import CarStateBase from selfdrive.car.interfaces import CarStateBase
from opendbc.can.parser import CANParser from opendbc.can.parser import CANParser
from selfdrive.car.volkswagen.values import DBC, CANBUS, NetworkLocation, TransmissionType, GearShifter, \ from selfdrive.car.volkswagen.values import DBC, CANBUS, PQ_CARS, NetworkLocation, TransmissionType, GearShifter, \
CarControllerParams CarControllerParams
@ -29,6 +29,9 @@ class CarState(CarStateBase):
return button_events return button_events
def update(self, pt_cp, cam_cp, ext_cp, trans_type): def update(self, pt_cp, cam_cp, ext_cp, trans_type):
if self.CP.carFingerprint in PQ_CARS:
return self.update_pq(pt_cp, cam_cp, ext_cp, trans_type)
ret = car.CarState.new_message() ret = car.CarState.new_message()
# Update vehicle speed and acceleration from ABS wheel speeds. # Update vehicle speed and acceleration from ABS wheel speeds.
ret.wheelSpeeds = self.get_wheel_speeds( ret.wheelSpeeds = self.get_wheel_speeds(
@ -142,8 +145,111 @@ class CarState(CarStateBase):
return ret return ret
def update_pq(self, pt_cp, cam_cp, ext_cp, trans_type):
ret = car.CarState.new_message()
# Update vehicle speed and acceleration from ABS wheel speeds.
ret.wheelSpeeds = self.get_wheel_speeds(
pt_cp.vl["Bremse_3"]["Radgeschw__VL_4_1"],
pt_cp.vl["Bremse_3"]["Radgeschw__VR_4_1"],
pt_cp.vl["Bremse_3"]["Radgeschw__HL_4_1"],
pt_cp.vl["Bremse_3"]["Radgeschw__HR_4_1"],
)
# vEgo obtained from Bremse_1 vehicle speed rather than Bremse_3 wheel speeds because Bremse_3 isn't present on NSF
ret.vEgoRaw = pt_cp.vl["Bremse_1"]["Geschwindigkeit_neu__Bremse_1_"] * CV.KPH_TO_MS
ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
ret.standstill = ret.vEgo < 0.1
# Update steering angle, rate, yaw rate, and driver input torque. VW send
# the sign/direction in a separate signal so they must be recombined.
ret.steeringAngleDeg = pt_cp.vl["Lenkhilfe_3"]["LH3_BLW"] * (1, -1)[int(pt_cp.vl["Lenkhilfe_3"]["LH3_BLWSign"])]
ret.steeringRateDeg = pt_cp.vl["Lenkwinkel_1"]["Lenkradwinkel_Geschwindigkeit"] * (1, -1)[int(pt_cp.vl["Lenkwinkel_1"]["Lenkradwinkel_Geschwindigkeit_S"])]
ret.steeringTorque = pt_cp.vl["Lenkhilfe_3"]["LH3_LM"] * (1, -1)[int(pt_cp.vl["Lenkhilfe_3"]["LH3_LMSign"])]
ret.steeringPressed = abs(ret.steeringTorque) > self.CCP.STEER_DRIVER_ALLOWANCE
ret.yawRate = pt_cp.vl["Bremse_5"]["Giergeschwindigkeit"] * (1, -1)[int(pt_cp.vl["Bremse_5"]["Vorzeichen_der_Giergeschwindigk"])] * CV.DEG_TO_RAD
# Verify EPS readiness to accept steering commands
hca_status = self.CCP.hca_status_values.get(pt_cp.vl["Lenkhilfe_2"]["LH2_Sta_HCA"])
ret.steerFaultPermanent = hca_status in ("DISABLED", "FAULT")
ret.steerFaultTemporary = hca_status in ("INITIALIZING", "REJECTED")
# Update gas, brakes, and gearshift.
ret.gas = pt_cp.vl["Motor_3"]["Fahrpedal_Rohsignal"] / 100.0
ret.gasPressed = ret.gas > 0
ret.brake = pt_cp.vl["Bremse_5"]["Bremsdruck"] / 250.0 # FIXME: this is pressure in Bar, not sure what OP expects
ret.brakePressed = bool(pt_cp.vl["Motor_2"]["Bremstestschalter"])
ret.parkingBrake = bool(pt_cp.vl["Kombi_1"]["Bremsinfo"])
# Update gear and/or clutch position data.
if trans_type == TransmissionType.automatic:
ret.gearShifter = self.parse_gear_shifter(self.CCP.shifter_values.get(pt_cp.vl["Getriebe_1"]["Waehlhebelposition__Getriebe_1_"], None))
elif trans_type == TransmissionType.manual:
ret.clutchPressed = not pt_cp.vl["Motor_1"]["Kupplungsschalter"]
reverse_light = bool(pt_cp.vl["Gate_Komf_1"]["GK1_Rueckfahr"])
if reverse_light:
ret.gearShifter = GearShifter.reverse
else:
ret.gearShifter = GearShifter.drive
# Update door and trunk/hatch lid open status.
ret.doorOpen = any([pt_cp.vl["Gate_Komf_1"]["GK1_Fa_Tuerkont"],
pt_cp.vl["Gate_Komf_1"]["BSK_BT_geoeffnet"],
pt_cp.vl["Gate_Komf_1"]["BSK_HL_geoeffnet"],
pt_cp.vl["Gate_Komf_1"]["BSK_HR_geoeffnet"],
pt_cp.vl["Gate_Komf_1"]["BSK_HD_Hauptraste"]])
# Update seatbelt fastened status.
ret.seatbeltUnlatched = not bool(pt_cp.vl["Airbag_1"]["Gurtschalter_Fahrer"])
# Consume blind-spot monitoring info/warning LED states, if available.
# Infostufe: BSM LED on, Warnung: BSM LED flashing
if self.CP.enableBsm:
ret.leftBlindspot = bool(ext_cp.vl["SWA_1"]["SWA_Infostufe_SWA_li"]) or bool(ext_cp.vl["SWA_1"]["SWA_Warnung_SWA_li"])
ret.rightBlindspot = bool(ext_cp.vl["SWA_1"]["SWA_Infostufe_SWA_re"]) or bool(ext_cp.vl["SWA_1"]["SWA_Warnung_SWA_re"])
# Consume factory LDW data relevant for factory SWA (Lane Change Assist)
# and capture it for forwarding to the blind spot radar controller
self.ldw_stock_values = cam_cp.vl["LDW_Status"] if self.CP.networkLocation == NetworkLocation.fwdCamera else {}
# Stock FCW is considered active if the release bit for brake-jerk warning
# is set. Stock AEB considered active if the partial braking or target
# braking release bits are set.
# Refer to VW Self Study Program 890253: Volkswagen Driver Assistance
# Systems, chapters on Front Assist with Braking and City Emergency
# Braking for the 2016 Passat NMS
# TODO: deferred until we can collect data on pre-MY2016 behavior, AWV message may be shorter with fewer signals
ret.stockFcw = False
ret.stockAeb = False
# Update ACC radar status.
ret.cruiseState.available = bool(pt_cp.vl["Motor_5"]["GRA_Hauptschalter"])
ret.cruiseState.enabled = bool(pt_cp.vl["Motor_2"]["GRA_Status"])
if self.CP.pcmCruise:
ret.accFaulted = ext_cp.vl["ACC_GRA_Anziege"]["ACA_StaACC"] in (6, 7)
# TODO: update opendbc with PQ TSK state for OP long accFaulted
# Update ACC setpoint. When the setpoint reads as 255, the driver has not
# yet established an ACC setpoint, so treat it as zero.
ret.cruiseState.speed = ext_cp.vl["ACC_GRA_Anziege"]["ACA_V_Wunsch"] * CV.KPH_TO_MS
if ret.cruiseState.speed > 70: # 255 kph in m/s == no current setpoint
ret.cruiseState.speed = 0
# Update button states for turn signals and ACC controls, capture all ACC button state/config for passthrough
ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_stalk(300, pt_cp.vl["Gate_Komf_1"]["GK1_Blinker_li"],
pt_cp.vl["Gate_Komf_1"]["GK1_Blinker_re"])
ret.buttonEvents = self.create_button_events(pt_cp, self.CCP.BUTTONS)
self.gra_stock_values = pt_cp.vl["GRA_Neu"]
# Additional safety checks performed in CarInterface.
ret.espDisabled = bool(pt_cp.vl["Bremse_1"]["ESP_Passiv_getastet"])
return ret
@staticmethod @staticmethod
def get_can_parser(CP): def get_can_parser(CP):
if CP.carFingerprint in PQ_CARS:
return CarState.get_can_parser_pq(CP)
signals = [ signals = [
# sig_name, sig_address # sig_name, sig_address
("LWI_Lenkradwinkel", "LWI_01"), # Absolute steering angle ("LWI_Lenkradwinkel", "LWI_01"), # Absolute steering angle
@ -231,6 +337,9 @@ class CarState(CarStateBase):
@staticmethod @staticmethod
def get_cam_can_parser(CP): def get_cam_can_parser(CP):
if CP.carFingerprint in PQ_CARS:
return CarState.get_cam_can_parser_pq(CP)
signals = [] signals = []
checks = [] checks = []
@ -257,6 +366,123 @@ class CarState(CarStateBase):
return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, CANBUS.cam) return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, CANBUS.cam)
@staticmethod
def get_can_parser_pq(CP):
signals = [
# sig_name, sig_address, default
("LH3_BLW", "Lenkhilfe_3"), # Absolute steering angle
("LH3_BLWSign", "Lenkhilfe_3"), # Steering angle sign
("LH3_LM", "Lenkhilfe_3"), # Absolute driver torque input
("LH3_LMSign", "Lenkhilfe_3"), # Driver torque input sign
("LH2_Sta_HCA", "Lenkhilfe_2"), # Steering rack HCA status
("Lenkradwinkel_Geschwindigkeit", "Lenkwinkel_1"), # Absolute steering rate
("Lenkradwinkel_Geschwindigkeit_S", "Lenkwinkel_1"), # Steering rate sign
("Geschwindigkeit_neu__Bremse_1_", "Bremse_1"), # Vehicle speed from ABS
("Radgeschw__VL_4_1", "Bremse_3"), # ABS wheel speed, front left
("Radgeschw__VR_4_1", "Bremse_3"), # ABS wheel speed, front right
("Radgeschw__HL_4_1", "Bremse_3"), # ABS wheel speed, rear left
("Radgeschw__HR_4_1", "Bremse_3"), # ABS wheel speed, rear right
("Giergeschwindigkeit", "Bremse_5"), # Absolute yaw rate
("Vorzeichen_der_Giergeschwindigk", "Bremse_5"), # Yaw rate sign
("Gurtschalter_Fahrer", "Airbag_1"), # Seatbelt status, driver
("Gurtschalter_Beifahrer", "Airbag_1"), # Seatbelt status, passenger
("Bremstestschalter", "Motor_2"), # Brake pedal pressed (brake light test switch)
("Bremslichtschalter", "Motor_2"), # Brakes applied (brake light switch)
("Bremsdruck", "Bremse_5"), # Brake pressure applied
("Vorzeichen_Bremsdruck", "Bremse_5"), # Brake pressure applied sign (???)
("Fahrpedal_Rohsignal", "Motor_3"), # Accelerator pedal value
("ESP_Passiv_getastet", "Bremse_1"), # Stability control disabled
("GRA_Hauptschalter", "Motor_5"), # ACC main switch
("GRA_Status", "Motor_2"), # ACC engagement status
("GK1_Fa_Tuerkont", "Gate_Komf_1"), # Door open, driver
("BSK_BT_geoeffnet", "Gate_Komf_1"), # Door open, passenger
("BSK_HL_geoeffnet", "Gate_Komf_1"), # Door open, rear left
("BSK_HR_geoeffnet", "Gate_Komf_1"), # Door open, rear right
("BSK_HD_Hauptraste", "Gate_Komf_1"), # Trunk or hatch open
("GK1_Blinker_li", "Gate_Komf_1"), # Left turn signal on
("GK1_Blinker_re", "Gate_Komf_1"), # Right turn signal on
("Bremsinfo", "Kombi_1"), # Manual handbrake applied
("GRA_Hauptschalt", "GRA_Neu"), # ACC button, on/off
("GRA_Typ_Hauptschalt", "GRA_Neu"), # ACC button, momentary vs latching
("GRA_Kodierinfo", "GRA_Neu"), # ACC button, configuration
("GRA_Abbrechen", "GRA_Neu"), # ACC button, cancel
("GRA_Neu_Setzen", "GRA_Neu"), # ACC button, set
("GRA_Up_lang", "GRA_Neu"), # ACC button, increase or accel, long press
("GRA_Down_lang", "GRA_Neu"), # ACC button, decrease or decel, long press
("GRA_Up_kurz", "GRA_Neu"), # ACC button, increase or accel, short press
("GRA_Down_kurz", "GRA_Neu"), # ACC button, decrease or decel, short press
("GRA_Recall", "GRA_Neu"), # ACC button, resume
("GRA_Zeitluecke", "GRA_Neu"), # ACC button, time gap adj
("COUNTER", "GRA_Neu"), # ACC button, message counter
("GRA_Sender", "GRA_Neu"), # ACC button, CAN message originator
]
checks = [
# sig_address, frequency
("Bremse_1", 100), # From J104 ABS/ESP controller
("Bremse_3", 100), # From J104 ABS/ESP controller
("Lenkhilfe_3", 100), # From J500 Steering Assist with integrated sensors
("Lenkwinkel_1", 100), # From J500 Steering Assist with integrated sensors
("Motor_3", 100), # From J623 Engine control module
("Airbag_1", 50), # From J234 Airbag control module
("Bremse_5", 50), # From J104 ABS/ESP controller
("GRA_Neu", 50), # From J??? steering wheel control buttons
("Kombi_1", 50), # From J285 Instrument cluster
("Motor_2", 50), # From J623 Engine control module
("Motor_5", 50), # From J623 Engine control module
("Lenkhilfe_2", 20), # From J500 Steering Assist with integrated sensors
("Gate_Komf_1", 10), # From J533 CAN gateway
]
if CP.transmissionType == TransmissionType.automatic:
signals += [("Waehlhebelposition__Getriebe_1_", "Getriebe_1", 0)] # Auto trans gear selector position
checks += [("Getriebe_1", 100)] # From J743 Auto transmission control module
elif CP.transmissionType == TransmissionType.manual:
signals += [("Kupplungsschalter", "Motor_1", 0), # Clutch switch
("GK1_Rueckfahr", "Gate_Komf_1", 0)] # Reverse light from BCM
checks += [("Motor_1", 100)] # From J623 Engine control module
if CP.networkLocation == NetworkLocation.fwdCamera:
# Extended CAN devices other than the camera are here on CANBUS.pt
signals += PqExtraSignals.fwd_radar_signals
checks += PqExtraSignals.fwd_radar_checks
if CP.enableBsm:
signals += PqExtraSignals.bsm_radar_signals
checks += PqExtraSignals.bsm_radar_checks
return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, CANBUS.pt)
@staticmethod
def get_cam_can_parser_pq(CP):
signals = []
checks = []
if CP.networkLocation == NetworkLocation.fwdCamera:
signals += [
# sig_name, sig_address
("LDW_SW_Warnung_links", "LDW_Status"), # Blind spot in warning mode on left side due to lane departure
("LDW_SW_Warnung_rechts", "LDW_Status"), # Blind spot in warning mode on right side due to lane departure
("LDW_Seite_DLCTLC", "LDW_Status"), # Direction of most likely lane departure (left or right)
("LDW_DLC", "LDW_Status"), # Lane departure, distance to line crossing
("LDW_TLC", "LDW_Status"), # Lane departure, time to line crossing
]
checks += [
# sig_address, frequency
("LDW_Status", 10) # From R242 Driver assistance camera
]
if CP.networkLocation == NetworkLocation.gateway:
# Radars are here on CANBUS.cam
signals += PqExtraSignals.fwd_radar_signals
checks += PqExtraSignals.fwd_radar_checks
if CP.enableBsm:
signals += PqExtraSignals.bsm_radar_signals
checks += PqExtraSignals.bsm_radar_checks
return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, CANBUS.cam)
class MqbExtraSignals: class MqbExtraSignals:
# Additional signal and message lists for optional or bus-portable controllers # Additional signal and message lists for optional or bus-portable controllers
fwd_radar_signals = [ fwd_radar_signals = [
@ -285,3 +511,22 @@ class MqbExtraSignals:
bsm_radar_checks = [ bsm_radar_checks = [
("SWA_01", 20), # From J1086 Lane Change Assist ("SWA_01", 20), # From J1086 Lane Change Assist
] ]
class PqExtraSignals:
# Additional signal and message lists for optional or bus-portable controllers
fwd_radar_signals = [
("ACA_StaACC", "ACC_GRA_Anziege", 0), # ACC drivetrain coordinator status
("ACA_V_Wunsch", "ACC_GRA_Anziege", 0), # ACC set speed
]
fwd_radar_checks = [
("ACC_GRA_Anziege", 25), # From J428 ACC radar control module
]
bsm_radar_signals = [
("SWA_Infostufe_SWA_li", "SWA_1", 0), # Blind spot object info, left
("SWA_Warnung_SWA_li", "SWA_1", 0), # Blind spot object warning, left
("SWA_Infostufe_SWA_re", "SWA_1", 0), # Blind spot object info, right
("SWA_Warnung_SWA_re", "SWA_1", 0), # Blind spot object warning, right
]
bsm_radar_checks = [
("SWA_1", 20), # From J1086 Lane Change Assist
]

@ -1,11 +1,10 @@
from cereal import car from cereal import car
from common.params import Params
from panda import Panda from panda import Panda
from selfdrive.car import STD_CARGO_KG, create_button_enable_events, scale_rot_inertia, scale_tire_stiffness, \ from common.conversions import Conversions as CV
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, \
gen_empty_fingerprint, get_safety_config gen_empty_fingerprint, get_safety_config
from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.interfaces import CarInterfaceBase
from selfdrive.car.volkswagen.values import CAR, CANBUS, NetworkLocation, TransmissionType, GearShifter from selfdrive.car.volkswagen.values import CAR, PQ_CARS, CANBUS, NetworkLocation, TransmissionType, GearShifter
EventName = car.CarEvent.EventName EventName = car.CarEvent.EventName
@ -27,7 +26,36 @@ class CarInterface(CarInterfaceBase):
ret.carName = "volkswagen" ret.carName = "volkswagen"
ret.radarOffCan = True ret.radarOffCan = True
if True: # pylint: disable=using-constant-test if candidate in PQ_CARS:
# Set global PQ35/PQ46/NMS parameters
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.volkswagenPq)]
ret.enableBsm = 0x3BA in fingerprint[0] # SWA_1
if 0x440 in fingerprint[0]: # Getriebe_1
ret.transmissionType = TransmissionType.automatic
else:
ret.transmissionType = TransmissionType.manual
if any(msg in fingerprint[1] for msg in (0x1A0, 0xC2)): # Bremse_1, Lenkwinkel_1
ret.networkLocation = NetworkLocation.gateway
else:
ret.networkLocation = NetworkLocation.fwdCamera
# The PQ port is in dashcam-only mode due to a fixed six-minute maximum timer on HCA steering. An unsupported
# EPS flash update to work around this timer, and enable steering down to zero, is available from:
# https://github.com/pd0wm/pq-flasher
# It is documented in a four-part blog series:
# https://blog.willemmelching.nl/carhacking/2022/01/02/vw-part1/
# Panda ALLOW_DEBUG firmware required.
ret.dashcamOnly = True
if disable_radar and ret.networkLocation == NetworkLocation.gateway:
# Proof-of-concept, prep for E2E only. No radar points available. Follow-to-stop not yet supported, but should
# be simple to add when a suitable test car becomes available. Panda ALLOW_DEBUG firmware required.
ret.openpilotLongitudinalControl = True
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_VOLKSWAGEN_LONG_CONTROL
else:
# Set global MQB parameters # Set global MQB parameters
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.volkswagen)] ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.volkswagen)]
ret.enableBsm = 0x30F in fingerprint[0] # SWA_01 ret.enableBsm = 0x30F in fingerprint[0] # SWA_01
@ -44,7 +72,7 @@ class CarInterface(CarInterfaceBase):
else: else:
ret.networkLocation = NetworkLocation.fwdCamera ret.networkLocation = NetworkLocation.fwdCamera
if Params().get_bool("DisableRadar") and ret.networkLocation == NetworkLocation.gateway: if disable_radar and ret.networkLocation == NetworkLocation.gateway:
ret.openpilotLongitudinalControl = True ret.openpilotLongitudinalControl = True
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_VOLKSWAGEN_LONG_CONTROL ret.safetyConfigs[0].safetyParam |= Panda.FLAG_VOLKSWAGEN_LONG_CONTROL
if ret.transmissionType == TransmissionType.manual: if ret.transmissionType == TransmissionType.manual:
@ -94,6 +122,14 @@ class CarInterface(CarInterfaceBase):
ret.mass = 1551 + STD_CARGO_KG ret.mass = 1551 + STD_CARGO_KG
ret.wheelbase = 2.79 ret.wheelbase = 2.79
elif candidate == CAR.PASSAT_NMS:
ret.mass = 1503 + STD_CARGO_KG
ret.wheelbase = 2.80
ret.minEnableSpeed = 20 * CV.KPH_TO_MS # ACC "basic", no FtS
ret.minSteerSpeed = 50 * CV.KPH_TO_MS
ret.steerActuatorDelay = 0.2
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.POLO_MK6: elif candidate == CAR.POLO_MK6:
ret.mass = 1230 + STD_CARGO_KG ret.mass = 1230 + STD_CARGO_KG
ret.wheelbase = 2.55 ret.wheelbase = 2.55
@ -170,6 +206,7 @@ class CarInterface(CarInterfaceBase):
else: else:
raise ValueError(f"unsupported car {candidate}") raise ValueError(f"unsupported car {candidate}")
ret.autoResumeSng = ret.minEnableSpeed == -1
ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase)
ret.centerToFront = ret.wheelbase * 0.45 ret.centerToFront = ret.wheelbase * 0.45
ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront, ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront,
@ -197,7 +234,6 @@ class CarInterface(CarInterfaceBase):
if c.enabled and ret.vEgo < self.CP.minEnableSpeed: if c.enabled and ret.vEgo < self.CP.minEnableSpeed:
events.add(EventName.speedTooLow) events.add(EventName.speedTooLow)
events.events.extend(create_button_enable_events(ret.buttonEvents, pcm_cruise=self.CP.pcmCruise))
ret.events = events.to_msg() ret.events = events.to_msg()
return ret return ret

@ -0,0 +1,84 @@
def create_steering_control(packer, bus, apply_steer, lkas_enabled):
values = {
"LM_Offset": abs(apply_steer),
"LM_OffSign": 1 if apply_steer < 0 else 0,
"HCA_Status": 5 if (lkas_enabled and apply_steer != 0) else 3,
"Vib_Freq": 16,
}
return packer.make_can_msg("HCA_1", bus, values)
def create_lka_hud_control(packer, bus, ldw_stock_values, enabled, steering_pressed, hud_alert, hud_control):
values = ldw_stock_values.copy()
values.update({
"LDW_Lampe_gelb": 1 if enabled and steering_pressed else 0,
"LDW_Lampe_gruen": 1 if enabled and not steering_pressed else 0,
"LDW_Lernmodus_links": 3 if hud_control.leftLaneDepart else 1 + hud_control.leftLaneVisible,
"LDW_Lernmodus_rechts": 3 if hud_control.rightLaneDepart else 1 + hud_control.rightLaneVisible,
"LDW_Textbits": hud_alert,
})
return packer.make_can_msg("LDW_Status", bus, values)
def create_acc_buttons_control(packer, bus, gra_stock_values, idx, cancel=False, resume=False):
values = gra_stock_values.copy()
values.update({
"COUNTER": idx,
"GRA_Abbrechen": cancel,
"GRA_Recall": resume,
})
return packer.make_can_msg("GRA_Neu", bus, values)
def tsk_status_value(main_switch_on, acc_faulted, long_active):
if long_active:
tsk_status = 1
elif main_switch_on:
tsk_status = 2
else:
tsk_status = 0
return tsk_status
def acc_hud_status_value(main_switch_on, acc_faulted, long_active):
if acc_faulted:
hud_status = 6
elif long_active:
hud_status = 3
elif main_switch_on:
hud_status = 2
else:
hud_status = 0
return hud_status
def create_acc_accel_control(packer, bus, adr_status, accel):
values = {
"ACS_Sta_ADR": adr_status,
"ACS_StSt_Info": adr_status != 1,
"ACS_Typ_ACC": 0, # TODO: this is ACC "basic", find a way to detect FtS support (1)
"ACS_Sollbeschl": accel if adr_status == 1 else 3.01,
"ACS_zul_Regelabw": 0.2 if adr_status == 1 else 1.27,
"ACS_max_AendGrad": 3.0 if adr_status == 1 else 5.08,
}
return packer.make_can_msg("ACC_System", bus, values)
def create_acc_hud_control(packer, bus, acc_status, set_speed, lead_visible):
values = {
"ACA_StaACC": acc_status,
"ACA_Zeitluecke": 2,
"ACA_V_Wunsch": set_speed,
"ACA_gemZeitl": 8 if lead_visible else 0,
}
# TODO: ACA_ID_StaACC, ACA_AnzDisplay, ACA_kmh_mph, ACA_PrioDisp, ACA_Aend_Zeitluecke
return packer.make_can_msg("ACC_GRA_Anziege", bus, values)

@ -33,7 +33,36 @@ class CarControllerParams:
can_define = CANDefine(DBC[CP.carFingerprint]["pt"]) can_define = CANDefine(DBC[CP.carFingerprint]["pt"])
if True: # pylint: disable=using-constant-test if CP.carFingerprint in PQ_CARS:
self.LDW_STEP = 5 # LDW_1 message frequency 20Hz
self.ACC_HUD_STEP = 4 # ACC_GRA_Anziege frequency 25Hz
self.STEER_DRIVER_ALLOWANCE = 80 # Driver intervention threshold 0.8 Nm
self.STEER_DELTA_UP = 6 # Max HCA reached in 1.00s (STEER_MAX / (50Hz * 1.00))
self.STEER_DELTA_DOWN = 10 # Min HCA reached in 0.60s (STEER_MAX / (50Hz * 0.60))
if CP.transmissionType == TransmissionType.automatic:
self.shifter_values = can_define.dv["Getriebe_1"]["Waehlhebelposition__Getriebe_1_"]
self.hca_status_values = can_define.dv["Lenkhilfe_2"]["LH2_Sta_HCA"]
self.BUTTONS = [
Button(car.CarState.ButtonEvent.Type.setCruise, "GRA_Neu", "GRA_Neu_Setzen", [1]),
Button(car.CarState.ButtonEvent.Type.resumeCruise, "GRA_Neu", "GRA_Recall", [1]),
Button(car.CarState.ButtonEvent.Type.accelCruise, "GRA_Neu", "GRA_Up_kurz", [1]),
Button(car.CarState.ButtonEvent.Type.decelCruise, "GRA_Neu", "GRA_Down_kurz", [1]),
Button(car.CarState.ButtonEvent.Type.cancel, "GRA_Neu", "GRA_Abbrechen", [1]),
Button(car.CarState.ButtonEvent.Type.gapAdjustCruise, "GRA_Neu", "GRA_Zeitluecke", [1]),
]
self.LDW_MESSAGES = {
"none": 0, # Nothing to display
"laneAssistUnavail": 1, # "Lane Assist currently not available."
"laneAssistUnavailSysError": 2, # "Lane Assist system error"
"laneAssistUnavailNoSensorView": 3, # "Lane Assist not available. No sensor view."
"laneAssistTakeOver": 4, # "Lane Assist: Please Take Over Steering"
"laneAssistDeactivTrailer": 5, # "Lane Assist: no function with trailer"
}
else:
self.LDW_STEP = 10 # LDW_02 message frequency 10Hz self.LDW_STEP = 10 # LDW_02 message frequency 10Hz
self.ACC_HUD_STEP = 6 # ACC_02/ACC_04 message frequency 16Hz self.ACC_HUD_STEP = 6 # ACC_02/ACC_04 message frequency 16Hz
self.STEER_DRIVER_ALLOWANCE = 80 # Driver intervention threshold 0.8 Nm self.STEER_DRIVER_ALLOWANCE = 80 # Driver intervention threshold 0.8 Nm
@ -84,6 +113,7 @@ class CAR:
GOLF_MK7 = "VOLKSWAGEN GOLF 7TH GEN" # Chassis 5G/AU/BA/BE, Mk7 VW Golf and variants GOLF_MK7 = "VOLKSWAGEN GOLF 7TH GEN" # Chassis 5G/AU/BA/BE, Mk7 VW Golf and variants
JETTA_MK7 = "VOLKSWAGEN JETTA 7TH GEN" # Chassis BU, Mk7 VW Jetta JETTA_MK7 = "VOLKSWAGEN JETTA 7TH GEN" # Chassis BU, Mk7 VW Jetta
PASSAT_MK8 = "VOLKSWAGEN PASSAT 8TH GEN" # Chassis 3G, Mk8 VW Passat and variants PASSAT_MK8 = "VOLKSWAGEN PASSAT 8TH GEN" # Chassis 3G, Mk8 VW Passat and variants
PASSAT_NMS = "VOLKSWAGEN PASSAT NMS" # Chassis A3, North America/China/Mideast NMS Passat, incl. facelift
POLO_MK6 = "VOLKSWAGEN POLO 6TH GEN" # Chassis AW, Mk6 VW Polo POLO_MK6 = "VOLKSWAGEN POLO 6TH GEN" # Chassis AW, Mk6 VW Polo
TAOS_MK1 = "VOLKSWAGEN TAOS 1ST GEN" # Chassis B2, Mk1 VW Taos and Tharu TAOS_MK1 = "VOLKSWAGEN TAOS 1ST GEN" # Chassis B2, Mk1 VW Taos and Tharu
TCROSS_MK1 = "VOLKSWAGEN T-CROSS 1ST GEN" # Chassis C1, Mk1 VW T-Cross SWB and LWB variants TCROSS_MK1 = "VOLKSWAGEN T-CROSS 1ST GEN" # Chassis C1, Mk1 VW T-Cross SWB and LWB variants
@ -104,7 +134,12 @@ class CAR:
SKODA_OCTAVIA_MK3 = "SKODA OCTAVIA 3RD GEN" # Chassis NE, Mk3 Skoda Octavia and variants SKODA_OCTAVIA_MK3 = "SKODA OCTAVIA 3RD GEN" # Chassis NE, Mk3 Skoda Octavia and variants
PQ_CARS = {CAR.PASSAT_NMS}
DBC: Dict[str, Dict[str, str]] = defaultdict(lambda: dbc_dict("vw_mqb_2010", None)) DBC: Dict[str, Dict[str, str]] = defaultdict(lambda: dbc_dict("vw_mqb_2010", None))
for car_type in PQ_CARS:
DBC[car_type] = dbc_dict("vw_golf_mk4", None)
class Footnote(Enum): class Footnote(Enum):
@ -140,7 +175,7 @@ CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = {
VWCarInfo("Volkswagen CC 2018-22", footnotes=[Footnote.VW_HARNESS, Footnote.VW_VARIANT], harness=Harness.j533, video_link="https://youtu.be/FAomFKPFlDA"), VWCarInfo("Volkswagen CC 2018-22", footnotes=[Footnote.VW_HARNESS, Footnote.VW_VARIANT], harness=Harness.j533, video_link="https://youtu.be/FAomFKPFlDA"),
], ],
CAR.ATLAS_MK1: [ CAR.ATLAS_MK1: [
VWCarInfo("Volkswagen Atlas 2018-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), VWCarInfo("Volkswagen Atlas 2018-23", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
VWCarInfo("Volkswagen Atlas Cross Sport 2021-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), VWCarInfo("Volkswagen Atlas Cross Sport 2021-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
VWCarInfo("Volkswagen Teramont 2018-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), VWCarInfo("Volkswagen Teramont 2018-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
VWCarInfo("Volkswagen Teramont Cross Sport 2021-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), VWCarInfo("Volkswagen Teramont Cross Sport 2021-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
@ -165,6 +200,7 @@ CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = {
VWCarInfo("Volkswagen Passat Alltrack 2015-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), VWCarInfo("Volkswagen Passat Alltrack 2015-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
VWCarInfo("Volkswagen Passat GTE 2015-22", footnotes=[Footnote.VW_HARNESS, Footnote.VW_VARIANT], harness=Harness.j533), VWCarInfo("Volkswagen Passat GTE 2015-22", footnotes=[Footnote.VW_HARNESS, Footnote.VW_VARIANT], harness=Harness.j533),
], ],
CAR.PASSAT_NMS: VWCarInfo("Volkswagen Passat NMS 2017-22", harness=Harness.j533),
CAR.POLO_MK6: [ CAR.POLO_MK6: [
VWCarInfo("Volkswagen Polo 2020-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), VWCarInfo("Volkswagen Polo 2020-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
VWCarInfo("Volkswagen Polo GTI 2020-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), VWCarInfo("Volkswagen Polo GTI 2020-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533),
@ -240,6 +276,7 @@ FW_VERSIONS = {
b'\xf1\x8703H906026AA\xf1\x899970', b'\xf1\x8703H906026AA\xf1\x899970',
b'\xf1\x8703H906026AJ\xf1\x890638', b'\xf1\x8703H906026AJ\xf1\x890638',
b'\xf1\x8703H906026AT\xf1\x891922', b'\xf1\x8703H906026AT\xf1\x891922',
b'\xf1\x8703H906026BC\xf1\x892664',
b'\xf1\x8703H906026F \xf1\x896696', b'\xf1\x8703H906026F \xf1\x896696',
b'\xf1\x8703H906026F \xf1\x899970', b'\xf1\x8703H906026F \xf1\x899970',
b'\xf1\x8703H906026J \xf1\x896026', b'\xf1\x8703H906026J \xf1\x896026',
@ -252,12 +289,14 @@ FW_VERSIONS = {
b'\xf1\x8709G927158DR\xf1\x893536', b'\xf1\x8709G927158DR\xf1\x893536',
b'\xf1\x8709G927158DR\xf1\x893742', b'\xf1\x8709G927158DR\xf1\x893742',
b'\xf1\x8709G927158FT\xf1\x893835', b'\xf1\x8709G927158FT\xf1\x893835',
b'\xf1\x8709G927158GL\xf1\x893939',
], ],
(Ecu.srs, 0x715, None): [ (Ecu.srs, 0x715, None): [
b'\xf1\x873Q0959655BC\xf1\x890503\xf1\x82\0161914151912001103111122031200', b'\xf1\x873Q0959655BC\xf1\x890503\xf1\x82\0161914151912001103111122031200',
b'\xf1\x873Q0959655BN\xf1\x890713\xf1\x82\0162214152212001105141122052900', b'\xf1\x873Q0959655BN\xf1\x890713\xf1\x82\0162214152212001105141122052900',
b'\xf1\x873Q0959655DB\xf1\x890720\xf1\x82\0162214152212001105141122052900', b'\xf1\x873Q0959655DB\xf1\x890720\xf1\x82\0162214152212001105141122052900',
b'\xf1\x873Q0959655DM\xf1\x890732\xf1\x82\x0e1114151112001105161122052J00', b'\xf1\x873Q0959655DM\xf1\x890732\xf1\x82\x0e1114151112001105161122052J00',
b'\xf1\x873Q0959655DM\xf1\x890732\xf1\x82\x0e1115151112001105171122052J00',
], ],
(Ecu.eps, 0x712, None): [ (Ecu.eps, 0x712, None): [
b'\xf1\x873QF909144B \xf1\x891582\xf1\x82\00571B60924A1', b'\xf1\x873QF909144B \xf1\x891582\xf1\x82\00571B60924A1',
@ -265,6 +304,7 @@ FW_VERSIONS = {
b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820528B6090105', b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820528B6090105',
], ],
(Ecu.fwdRadar, 0x757, None): [ (Ecu.fwdRadar, 0x757, None): [
b'\xf1\x872Q0907572AA\xf1\x890396',
b'\xf1\x872Q0907572R \xf1\x890372', b'\xf1\x872Q0907572R \xf1\x890372',
b'\xf1\x872Q0907572T \xf1\x890383', b'\xf1\x872Q0907572T \xf1\x890383',
b'\xf1\x875Q0907572H \xf1\x890620', b'\xf1\x875Q0907572H \xf1\x890620',
@ -334,6 +374,8 @@ FW_VERSIONS = {
b'\xf1\x870D9300012 \xf1\x894937', b'\xf1\x870D9300012 \xf1\x894937',
b'\xf1\x870D9300012 \xf1\x895045', b'\xf1\x870D9300012 \xf1\x895045',
b'\xf1\x870D9300014M \xf1\x895004', b'\xf1\x870D9300014M \xf1\x895004',
b'\xf1\x870D9300014Q \xf1\x895006',
b'\xf1\x870D9300020Q \xf1\x895201',
b'\xf1\x870D9300020S \xf1\x895201', b'\xf1\x870D9300020S \xf1\x895201',
b'\xf1\x870D9300040A \xf1\x893613', b'\xf1\x870D9300040A \xf1\x893613',
b'\xf1\x870D9300040S \xf1\x894311', b'\xf1\x870D9300040S \xf1\x894311',
@ -385,6 +427,7 @@ FW_VERSIONS = {
b'\xf1\x873Q0909144L \xf1\x895081\xf1\x82\x0571A0JA15A1', b'\xf1\x873Q0909144L \xf1\x895081\xf1\x82\x0571A0JA15A1',
b'\xf1\x873Q0909144M \xf1\x895082\xf1\x82\x0571A01A18A1', b'\xf1\x873Q0909144M \xf1\x895082\xf1\x82\x0571A01A18A1',
b'\xf1\x873Q0909144M \xf1\x895082\xf1\x82\x0571A0JA16A1', b'\xf1\x873Q0909144M \xf1\x895082\xf1\x82\x0571A0JA16A1',
b'\xf1\x873QM909144 \xf1\x895072\xf1\x82\x0571A01714A1',
b'\xf1\x875Q0909143K \xf1\x892033\xf1\x820519A9040203', b'\xf1\x875Q0909143K \xf1\x892033\xf1\x820519A9040203',
b'\xf1\x875Q0909144AA\xf1\x891081\xf1\x82\x0521A00441A1', b'\xf1\x875Q0909144AA\xf1\x891081\xf1\x82\x0521A00441A1',
b'\xf1\x875Q0909144AA\xf1\x891081\xf1\x82\x0521A00608A1', b'\xf1\x875Q0909144AA\xf1\x891081\xf1\x82\x0521A00608A1',
@ -519,6 +562,26 @@ FW_VERSIONS = {
b'\xf1\x875Q0907572R \xf1\x890771', b'\xf1\x875Q0907572R \xf1\x890771',
], ],
}, },
CAR.PASSAT_NMS: {
(Ecu.engine, 0x7e0, None): [
b'\xf1\x8706K906016C \xf1\x899609',
b'\xf1\x8706K906016G \xf1\x891124',
b'\xf1\x8706K906071BJ\xf1\x894891',
],
(Ecu.transmission, 0x7e1, None): [
b'\xf1\x8709G927158AB\xf1\x893318',
b'\xf1\x8709G927158BD\xf1\x893121',
b'\xf1\x8709G927158FQ\xf1\x893745',
],
(Ecu.srs, 0x715, None): [
b'\xf1\x87561959655 \xf1\x890210\xf1\x82\02212121111113000102011--121012--101312',
b'\xf1\x87561959655C \xf1\x890508\xf1\x82\02215141111121100314919--153015--304831',
],
(Ecu.fwdRadar, 0x757, None): [
b'\xf1\x87561907567A \xf1\x890132',
b'\xf1\x877N0907572C \xf1\x890211\xf1\x82\00152',
],
},
CAR.POLO_MK6: { CAR.POLO_MK6: {
(Ecu.engine, 0x7e0, None): [ (Ecu.engine, 0x7e0, None): [
b'\xf1\x8704C906025H \xf1\x895177', b'\xf1\x8704C906025H \xf1\x895177',
@ -682,6 +745,7 @@ FW_VERSIONS = {
b'\xf1\x8704E906023BL\xf1\x895190', b'\xf1\x8704E906023BL\xf1\x895190',
b'\xf1\x8704E906027CJ\xf1\x897798', b'\xf1\x8704E906027CJ\xf1\x897798',
b'\xf1\x8704L997022N \xf1\x899459', b'\xf1\x8704L997022N \xf1\x899459',
b'\xf1\x875G0906259A \xf1\x890004',
b'\xf1\x875G0906259L \xf1\x890002', b'\xf1\x875G0906259L \xf1\x890002',
b'\xf1\x875G0906259Q \xf1\x890002', b'\xf1\x875G0906259Q \xf1\x890002',
b'\xf1\x878V0906259F \xf1\x890002', b'\xf1\x878V0906259F \xf1\x890002',
@ -694,6 +758,7 @@ FW_VERSIONS = {
b'\xf1\x870CW300044T \xf1\x895245', b'\xf1\x870CW300044T \xf1\x895245',
b'\xf1\x870CW300048 \xf1\x895201', b'\xf1\x870CW300048 \xf1\x895201',
b'\xf1\x870D9300012 \xf1\x894912', b'\xf1\x870D9300012 \xf1\x894912',
b'\xf1\x870D9300012K \xf1\x894513',
b'\xf1\x870D9300013B \xf1\x894931', b'\xf1\x870D9300013B \xf1\x894931',
b'\xf1\x870D9300041N \xf1\x894512', b'\xf1\x870D9300041N \xf1\x894512',
b'\xf1\x870D9300043T \xf1\x899699', b'\xf1\x870D9300043T \xf1\x899699',
@ -710,6 +775,7 @@ FW_VERSIONS = {
b'\xf1\x875Q0959655AM\xf1\x890315\xf1\x82\x1311111111111111311411011231129321212100', b'\xf1\x875Q0959655AM\xf1\x890315\xf1\x82\x1311111111111111311411011231129321212100',
b'\xf1\x875Q0959655AM\xf1\x890318\xf1\x82\x1311111111111112311411011531159321212100', b'\xf1\x875Q0959655AM\xf1\x890318\xf1\x82\x1311111111111112311411011531159321212100',
b'\xf1\x875Q0959655BJ\xf1\x890339\xf1\x82\x1311110011131100311111011731179321342100', b'\xf1\x875Q0959655BJ\xf1\x890339\xf1\x82\x1311110011131100311111011731179321342100',
b'\xf1\x875Q0959655J \xf1\x890825\xf1\x82\x13111112111111--241115141112221291163221',
b'\xf1\x875Q0959655J \xf1\x890825\xf1\x82\023111112111111--171115141112221291163221', b'\xf1\x875Q0959655J \xf1\x890825\xf1\x82\023111112111111--171115141112221291163221',
b'\xf1\x875Q0959655J \xf1\x890830\xf1\x82\023121111111211--261117141112231291163221', b'\xf1\x875Q0959655J \xf1\x890830\xf1\x82\023121111111211--261117141112231291163221',
b'\xf1\x875Q0959655J \xf1\x890830\xf1\x82\x13121111111111--341117141212231291163221', b'\xf1\x875Q0959655J \xf1\x890830\xf1\x82\x13121111111111--341117141212231291163221',
@ -723,6 +789,7 @@ FW_VERSIONS = {
b'\xf1\x875Q0909144AB\xf1\x891082\xf1\x82\00521G0G809A1', b'\xf1\x875Q0909144AB\xf1\x891082\xf1\x82\00521G0G809A1',
b'\xf1\x875Q0909144P \xf1\x891043\xf1\x82\00503G00303A0', b'\xf1\x875Q0909144P \xf1\x891043\xf1\x82\00503G00303A0',
b'\xf1\x875Q0909144P \xf1\x891043\xf1\x82\00503G00803A0', b'\xf1\x875Q0909144P \xf1\x891043\xf1\x82\00503G00803A0',
b'\xf1\x875Q0909144P \xf1\x891043\xf1\x82\x0503G0G803A0',
b'\xf1\x875Q0909144R \xf1\x891061\xf1\x82\00516G00804A1', b'\xf1\x875Q0909144R \xf1\x891061\xf1\x82\00516G00804A1',
b'\xf1\x875Q0909144T \xf1\x891072\xf1\x82\00521G00807A1', b'\xf1\x875Q0909144T \xf1\x891072\xf1\x82\00521G00807A1',
], ],

@ -15,8 +15,8 @@ from system.swaglog import cloudlog
from system.version import get_short_branch from system.version import get_short_branch
from selfdrive.boardd.boardd import can_list_to_can_capnp from selfdrive.boardd.boardd import can_list_to_can_capnp
from selfdrive.car.car_helpers import get_car, get_startup_event, get_one_can from selfdrive.car.car_helpers import get_car, get_startup_event, get_one_can
from selfdrive.controls.lib.lane_planner import CAMERA_OFFSET from selfdrive.controls.lib.lateral_planner import CAMERA_OFFSET
from selfdrive.controls.lib.drive_helpers import update_v_cruise, initialize_v_cruise from selfdrive.controls.lib.drive_helpers import V_CRUISE_INITIAL, update_v_cruise, initialize_v_cruise
from selfdrive.controls.lib.drive_helpers import get_lag_adjusted_curvature from selfdrive.controls.lib.drive_helpers import get_lag_adjusted_curvature
from selfdrive.controls.lib.latcontrol import LatControl from selfdrive.controls.lib.latcontrol import LatControl
from selfdrive.controls.lib.longcontrol import LongControl from selfdrive.controls.lib.longcontrol import LongControl
@ -50,6 +50,7 @@ LaneChangeState = log.LateralPlan.LaneChangeState
LaneChangeDirection = log.LateralPlan.LaneChangeDirection LaneChangeDirection = log.LateralPlan.LaneChangeDirection
EventName = car.CarEvent.EventName EventName = car.CarEvent.EventName
ButtonEvent = car.CarState.ButtonEvent ButtonEvent = car.CarState.ButtonEvent
ButtonType = car.CarState.ButtonEvent.Type
SafetyModel = car.CarParams.SafetyModel SafetyModel = car.CarParams.SafetyModel
IGNORED_SAFETY_MODES = (SafetyModel.silent, SafetyModel.noOutput) IGNORED_SAFETY_MODES = (SafetyModel.silent, SafetyModel.noOutput)
@ -160,14 +161,14 @@ class Controls:
self.state = State.disabled self.state = State.disabled
self.enabled = False self.enabled = False
self.active = False self.active = False
self.can_rcv_error = False self.can_rcv_timeout = False
self.soft_disable_timer = 0 self.soft_disable_timer = 0
self.v_cruise_kph = 255 self.v_cruise_kph = V_CRUISE_INITIAL
self.v_cruise_cluster_kph = 255 self.v_cruise_cluster_kph = V_CRUISE_INITIAL
self.v_cruise_kph_last = 0 self.v_cruise_kph_last = 0
self.mismatch_counter = 0 self.mismatch_counter = 0
self.cruise_mismatch_counter = 0 self.cruise_mismatch_counter = 0
self.can_rcv_error_counter = 0 self.can_rcv_timeout_counter = 0
self.last_blinker_frame = 0 self.last_blinker_frame = 0
self.distance_traveled = 0 self.distance_traveled = 0
self.last_functional_fan_frame = 0 self.last_functional_fan_frame = 0
@ -203,6 +204,16 @@ class Controls:
self.rk = Ratekeeper(100, print_delay_threshold=None) self.rk = Ratekeeper(100, print_delay_threshold=None)
self.prof = Profiler(False) # off by default self.prof = Profiler(False) # off by default
def set_initial_state(self):
if REPLAY:
controls_state = Params().get("ReplayControlsState")
if controls_state is not None:
controls_state = log.ControlsState.from_bytes(controls_state)
self.v_cruise_kph = controls_state.vCruise
if self.sm['pandaStates'][0].controlsAllowed:
self.state = State.enabled
def update_events(self, CS): def update_events(self, CS):
"""Compute carEvents from carState""" """Compute carEvents from carState"""
@ -218,6 +229,11 @@ class Controls:
self.events.add(EventName.controlsInitializing) self.events.add(EventName.controlsInitializing)
return return
# Block resume if cruise never previously enabled
resume_pressed = any(be.type in (ButtonType.accelCruise, ButtonType.resumeCruise) for be in CS.buttonEvents)
if not self.CP.pcmCruise and self.v_cruise_kph == V_CRUISE_INITIAL and resume_pressed:
self.events.add(EventName.resumeBlocked)
# Disable on rising edge of accelerator or brake. Also disable on brake when speed > 0 # Disable on rising edge of accelerator or brake. Also disable on brake when speed > 0
if (CS.gasPressed and not self.CS_prev.gasPressed and self.disengage_on_accelerator) or \ if (CS.gasPressed and not self.CS_prev.gasPressed and self.disengage_on_accelerator) or \
(CS.brakePressed and (not self.CS_prev.brakePressed or not CS.standstill)): (CS.brakePressed and (not self.CS_prev.brakePressed or not CS.standstill)):
@ -323,19 +339,19 @@ class Controls:
# generic catch-all. ideally, a more specific event should be added above instead # generic catch-all. ideally, a more specific event should be added above instead
has_disable_events = self.events.any(ET.NO_ENTRY) and (self.events.any(ET.SOFT_DISABLE) or self.events.any(ET.IMMEDIATE_DISABLE)) has_disable_events = self.events.any(ET.NO_ENTRY) and (self.events.any(ET.SOFT_DISABLE) or self.events.any(ET.IMMEDIATE_DISABLE))
no_system_errors = (not has_disable_events) or (len(self.events) == num_events) no_system_errors = (not has_disable_events) or (len(self.events) == num_events)
if (not self.sm.all_checks() or self.can_rcv_error) and no_system_errors: if (not self.sm.all_checks() or self.can_rcv_timeout) and no_system_errors:
if not self.sm.all_alive(): if not self.sm.all_alive():
self.events.add(EventName.commIssue) self.events.add(EventName.commIssue)
elif not self.sm.all_freq_ok(): elif not self.sm.all_freq_ok():
self.events.add(EventName.commIssueAvgFreq) self.events.add(EventName.commIssueAvgFreq)
else: # invalid or can_rcv_error. else: # invalid or can_rcv_timeout.
self.events.add(EventName.commIssue) self.events.add(EventName.commIssue)
logs = { logs = {
'invalid': [s for s, valid in self.sm.valid.items() if not valid], 'invalid': [s for s, valid in self.sm.valid.items() if not valid],
'not_alive': [s for s, alive in self.sm.alive.items() if not alive], 'not_alive': [s for s, alive in self.sm.alive.items() if not alive],
'not_freq_ok': [s for s, freq_ok in self.sm.freq_ok.items() if not freq_ok], 'not_freq_ok': [s for s, freq_ok in self.sm.freq_ok.items() if not freq_ok],
'can_error': self.can_rcv_error, 'can_rcv_timeout': self.can_rcv_timeout,
} }
if logs != self.logged_comm_issue: if logs != self.logged_comm_issue:
cloudlog.event("commIssue", error=True, **logs) cloudlog.event("commIssue", error=True, **logs)
@ -417,19 +433,17 @@ class Controls:
if all_valid or timed_out or SIMULATION: if all_valid or timed_out or SIMULATION:
if not self.read_only: if not self.read_only:
self.CI.init(self.CP, self.can_sock, self.pm.sock['sendcan']) self.CI.init(self.CP, self.can_sock, self.pm.sock['sendcan'])
self.initialized = True
if REPLAY and self.sm['pandaStates'][0].controlsAllowed:
self.state = State.enabled
self.initialized = True
self.set_initial_state()
Params().put_bool("ControlsReady", True) Params().put_bool("ControlsReady", True)
# Check for CAN timeout # Check for CAN timeout
if not can_strs: if not can_strs:
self.can_rcv_error_counter += 1 self.can_rcv_timeout_counter += 1
self.can_rcv_error = True self.can_rcv_timeout = True
else: else:
self.can_rcv_error = False self.can_rcv_timeout = False
# When the panda and controlsd do not agree on controls_allowed # When the panda and controlsd do not agree on controls_allowed
# we want to disengage openpilot. However the status from the panda goes through # we want to disengage openpilot. However the status from the panda goes through
@ -452,18 +466,18 @@ class Controls:
self.v_cruise_kph_last = self.v_cruise_kph self.v_cruise_kph_last = self.v_cruise_kph
# if stock cruise is completely disabled, then we can use our own set speed logic if CS.cruiseState.available:
if not self.CP.pcmCruise: # if stock cruise is completely disabled, then we can use our own set speed logic
self.v_cruise_kph = update_v_cruise(self.v_cruise_kph, CS.vEgo, CS.gasPressed, CS.buttonEvents, if not self.CP.pcmCruise:
self.button_timers, self.enabled, self.is_metric) self.v_cruise_kph = update_v_cruise(self.v_cruise_kph, CS.vEgo, CS.gasPressed, CS.buttonEvents,
self.v_cruise_cluster_kph = self.v_cruise_kph self.button_timers, self.enabled, self.is_metric)
else: self.v_cruise_cluster_kph = self.v_cruise_kph
if CS.cruiseState.available: else:
self.v_cruise_kph = CS.cruiseState.speed * CV.MS_TO_KPH self.v_cruise_kph = CS.cruiseState.speed * CV.MS_TO_KPH
self.v_cruise_cluster_kph = CS.cruiseState.speedCluster * CV.MS_TO_KPH self.v_cruise_cluster_kph = CS.cruiseState.speedCluster * CV.MS_TO_KPH
else: else:
self.v_cruise_kph = 0 self.v_cruise_kph = V_CRUISE_INITIAL
self.v_cruise_cluster_kph = 0 self.v_cruise_cluster_kph = V_CRUISE_INITIAL
# decrement the soft disable timer at every step, as it's reset on # decrement the soft disable timer at every step, as it's reset on
# entrance in SOFT_DISABLING state # entrance in SOFT_DISABLING state
@ -695,8 +709,8 @@ class Controls:
model_v2 = self.sm['modelV2'] model_v2 = self.sm['modelV2']
desire_prediction = model_v2.meta.desirePrediction desire_prediction = model_v2.meta.desirePrediction
if len(desire_prediction) and ldw_allowed: if len(desire_prediction) and ldw_allowed:
right_lane_visible = self.sm['lateralPlan'].rProb > 0.5 right_lane_visible = model_v2.laneLineProbs[2] > 0.5
left_lane_visible = self.sm['lateralPlan'].lProb > 0.5 left_lane_visible = model_v2.laneLineProbs[1] > 0.5
l_lane_change_prob = desire_prediction[Desire.laneChangeLeft - 1] l_lane_change_prob = desire_prediction[Desire.laneChangeLeft - 1]
r_lane_change_prob = desire_prediction[Desire.laneChangeRight - 1] r_lane_change_prob = desire_prediction[Desire.laneChangeRight - 1]
@ -771,7 +785,7 @@ class Controls:
controlsState.cumLagMs = -self.rk.remaining * 1000. controlsState.cumLagMs = -self.rk.remaining * 1000.
controlsState.startMonoTime = int(start_time * 1e9) controlsState.startMonoTime = int(start_time * 1e9)
controlsState.forceDecel = bool(force_decel) controlsState.forceDecel = bool(force_decel)
controlsState.canErrorCounter = self.can_rcv_error_counter controlsState.canErrorCounter = self.can_rcv_timeout_counter
lat_tuning = self.CP.lateralTuning.which() lat_tuning = self.CP.lateralTuning.which()
if self.joystick_mode: if self.joystick_mode:

@ -22,7 +22,7 @@ def set_offroad_alert(alert: str, show_alert: bool, extra_text: Optional[str] =
a['text'] += extra_text a['text'] += extra_text
Params().put(alert, json.dumps(a)) Params().put(alert, json.dumps(a))
else: else:
Params().delete(alert) Params().remove(alert)
@dataclass @dataclass

@ -11,6 +11,7 @@ from selfdrive.modeld.constants import T_IDXS
V_CRUISE_MAX = 145 # kph V_CRUISE_MAX = 145 # kph
V_CRUISE_MIN = 8 # kph V_CRUISE_MIN = 8 # kph
V_CRUISE_ENABLE_MIN = 40 # kph V_CRUISE_ENABLE_MIN = 40 # kph
V_CRUISE_INITIAL = 255 # kph
LAT_MPC_N = 16 LAT_MPC_N = 16
LON_MPC_N = 32 LON_MPC_N = 32

@ -635,6 +635,10 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = {
ET.NO_ENTRY: wrong_car_mode_alert, ET.NO_ENTRY: wrong_car_mode_alert,
}, },
EventName.resumeBlocked: {
ET.NO_ENTRY: NoEntryAlert("Press Set to Engage"),
},
EventName.wrongCruiseMode: { EventName.wrongCruiseMode: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage), ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: NoEntryAlert("Adaptive Cruise Disabled"), ET.NO_ENTRY: NoEntryAlert("Adaptive Cruise Disabled"),

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

Loading…
Cancel
Save