From 771a8b7a55ad7132ce4c8d81754a5147c0e4833d Mon Sep 17 00:00:00 2001 From: Vehicle Researcher Date: Sun, 31 May 2020 13:22:43 -0700 Subject: [PATCH] Squashed 'panda/' changes from 869f12321..49ffbe99f 49ffbe99f disable non-universal checks in hyundai safety 3a85f4c25 use whole route when running safety replay from CLI 098f47a5b Fix leaf brake rx check (#547) b8267341a Add pre commit checks + CI (#545) 339976c3c document tx message addresses better (#543) a618e64d1 fix typing errors 9bece64e8 use mazda init 08db086d5 mazda cleanup 89658d0bd Mazda: safety tests add missing safety checks (#525) bdec1398e Fix length of 0x20b in NISSAN_TX_MSGS, wasn't cancelling ACC (#544) b48c74c2e Adding UNO to automated tests (#538) a5802cdd1 Hyundai: remove unused message from RX checks 9ebde2535 Reset state on safety mode init (#542) d4f3f15c3 Refactor addr check (#541) 5210e51b8 remove unused files 065706459 Hyundai checksum (#540) 07e668eca Fast CI (#539) 5307bf727 Fix multi message iso tp requests 0610ed1e2 Hyundai wheel speed counter is actually 4 bits spread over two signals 0d581aa5f dockerfile optimization eaefa2f6c fix docker file path 243a65f30 pull base image 0dd9470af only push to dockerhub from master 55b79b472 GitHub Actions (#535) b2c720bf4 Dos (#533) 01bf74024 remove 0x1BE checksum test 0bd06c9e0 remove 0x1BE check (breaks some vehicles) c31b899a5 honda bosch longitudinal safety 66250c41d Disable docker layer caching (#534) 6b19fa496 include nissan safety in release build db31886ad gate mazda safety behind debug flag e4558c073 Safety: message length check on RX and TX (#529) git-subtree-dir: panda git-subtree-split: 49ffbe99f65e64d23d27d9d3e37f68bc2368dccd --- .circleci/config.yml | 118 ---- .github/workflows/test.yaml | 128 ++++ .gitignore | 1 + .pre-commit-config.yaml | 30 + .pylintrc | 2 + Dockerfile.panda | 66 ++ README.md | 4 +- __init__.py | 4 +- board/board.h | 12 +- board/board_declarations.h | 1 + board/boards/dos.h | 224 +++++++ board/drivers/llcan.h | 1 + board/safety.h | 73 ++- board/safety/safety_chrysler.h | 24 +- board/safety/safety_gm.h | 21 +- board/safety/safety_honda.h | 84 ++- board/safety/safety_hyundai.h | 69 ++- board/safety/safety_mazda.h | 169 +++-- board/safety/safety_nissan.h | 46 +- board/safety/safety_subaru.h | 25 +- board/safety/safety_toyota.h | 19 +- board/safety/safety_volkswagen.h | 28 +- board/safety_declarations.h | 30 +- python/__init__.py | 13 +- python/uds.py | 50 +- requirements.txt | 3 +- tests/all_wifi_test.py | 4 +- tests/automated/2_health.py | 1 + tests/automated/8_gps.py | 2 +- tests/automated/helpers.py | 18 +- .../{Dockerfile => Dockerfile.panda_esp} | 12 +- tests/bulk_write_test.py | 11 +- tests/debug_console.py | 2 +- tests/elm_car_simulator.py | 8 +- tests/language/Dockerfile | 17 - tests/language/LICENSE | 201 ------ tests/language/list.txt | 451 -------------- tests/language/test_language.py | 28 - tests/linter_python/.pylintrc | 585 ------------------ tests/linter_python/Dockerfile | 19 - tests/linter_python/flake8_panda.sh | 8 - tests/linter_python/pylint_panda.sh | 11 - tests/misra/Dockerfile | 19 - tests/safety/Dockerfile | 50 -- tests/safety/common.py | 21 +- tests/safety/libpandasafety_py.py | 8 +- tests/safety/test.c | 36 +- tests/safety/test_chrysler.py | 2 +- tests/safety/test_gm.py | 5 +- tests/safety/test_honda.py | 173 ++++-- tests/safety/test_hyundai.py | 25 +- tests/safety/test_mazda.py | 113 ++++ tests/safety/test_nissan.py | 4 +- tests/safety/test_volkswagen_pq.py | 6 +- tests/safety_replay/Dockerfile | 46 -- tests/safety_replay/install_capnp.sh | 10 - tests/safety_replay/replay_drive.py | 7 +- tests/safety_replay/requirements_extra.txt | 7 - tests/safety_replay/test_safety_replay.py | 4 +- tests/throughput_test.py | 2 +- 60 files changed, 1229 insertions(+), 1932 deletions(-) delete mode 100644 .circleci/config.yml create mode 100644 .github/workflows/test.yaml create mode 100644 .pre-commit-config.yaml create mode 100644 .pylintrc create mode 100644 Dockerfile.panda create mode 100644 board/boards/dos.h rename tests/build/{Dockerfile => Dockerfile.panda_esp} (73%) delete mode 100644 tests/language/Dockerfile delete mode 100644 tests/language/LICENSE delete mode 100644 tests/language/list.txt delete mode 100755 tests/language/test_language.py delete mode 100644 tests/linter_python/.pylintrc delete mode 100644 tests/linter_python/Dockerfile delete mode 100755 tests/linter_python/flake8_panda.sh delete mode 100755 tests/linter_python/pylint_panda.sh delete mode 100644 tests/misra/Dockerfile delete mode 100644 tests/safety/Dockerfile create mode 100755 tests/safety/test_mazda.py delete mode 100644 tests/safety_replay/Dockerfile delete mode 100755 tests/safety_replay/install_capnp.sh delete mode 100644 tests/safety_replay/requirements_extra.txt diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 52e45606..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,118 +0,0 @@ -version: 2 -jobs: - safety: - machine: - docker_layer_caching: true - steps: - - checkout - - run: - name: Build image - command: "docker build -t panda_safety -f tests/safety/Dockerfile ." - - run: - name: Run safety test - command: | - docker run panda_safety /bin/bash -c "cd /openpilot/panda/tests/safety; PYTHONPATH=/openpilot ./test.sh" - - misra-c2012: - machine: - docker_layer_caching: true - steps: - - checkout - - run: - name: Build image - command: "docker build -t panda_misra -f tests/misra/Dockerfile ." - - run: - name: Run Misra C 2012 test - command: | - mkdir /tmp/misra - docker run -v /tmp/misra:/tmp/misra panda_misra /bin/bash -c "cd /panda/tests/misra; ./test_misra.sh" - - store_artifacts: - name: Store cppcheck test output - path: /tmp/misra/cppcheck_output.txt - - store_artifacts: - name: Store misra test output - path: /tmp/misra/misra_output.txt - - build: - machine: - docker_layer_caching: true - steps: - - checkout - - run: - name: Build image - command: "docker build -t panda_build -f tests/build/Dockerfile ." - - run: - name: Test python package installer - command: | - docker run panda_build /bin/bash -c "cd /panda; python setup.py install" - - run: - name: Build Panda STM image - command: | - docker run panda_build /bin/bash -c "cd /panda/board; make bin" - - run: - name: Build Panda STM bootstub image - command: | - docker run panda_build /bin/bash -c "cd /panda/board; make obj/bootstub.panda.bin" - - run: - name: Build Pedal STM image - command: | - docker run panda_build /bin/bash -c "cd /panda/board/pedal; make obj/comma.bin" - - run: - name: Build Pedal STM bootstub image - command: | - docker run panda_build /bin/bash -c "cd /panda/board/pedal; make obj/bootstub.bin" - - run: - name: Build ESP image - command: | - docker run panda_build /bin/bash -c "cd /panda/boardesp; ./get_sdk.sh; make user1.bin" - - safety_replay: - machine: - docker_layer_caching: true - steps: - - checkout - - run: - name: Build image - command: "docker build -t panda_safety_replay -f tests/safety_replay/Dockerfile ." - - run: - name: Replay drives - command: | - docker run panda_safety_replay /bin/bash -c "cd /openpilot/panda/tests/safety_replay; PYTHONPATH=/openpilot ./test_safety_replay.py" - - language_check: - machine: - docker_layer_caching: true - steps: - - checkout - - run: - name: Build image - command: "docker build -t language_check -f tests/language/Dockerfile ." - - run: - name: Check code for bad language - command: | - docker run language_check /bin/bash -c "cd /panda/tests/language; ./test_language.py" - - linter_python: - machine: - docker_layer_caching: true - steps: - - checkout - - run: - name: Build image - command: "docker build -t linter_python -f tests/linter_python/Dockerfile ." - - run: - name: Run linter python test - command: | - docker run linter_python /bin/bash -c "cd /panda/tests/linter_python; PYTHONPATH=/ ./flake8_panda.sh" - docker run linter_python /bin/bash -c "cd /panda/tests/linter_python; PYTHONPATH=/ ./pylint_panda.sh" - -workflows: - version: 2 - main: - jobs: - - safety - - misra-c2012 - - build - - safety_replay - - language_check - - linter_python diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 00000000..fea9aa2b --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,128 @@ +name: panda tests +on: [push, pull_request] + +env: + RUN: docker run --rm panda /bin/bash -c + PERSIST: docker run --name panda panda /bin/sh -c + BUILD: | + docker pull $(grep -ioP '(?<=^from)\s+\S+' Dockerfile.panda) || true + docker pull docker.io/commaai/panda:latest || true + docker build --cache-from docker.io/commaai/panda:latest -t panda -f Dockerfile.panda . + +jobs: + docker_push: + name: docker push + runs-on: ubuntu-16.04 + timeout-minutes: 45 + if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/panda' + steps: + - uses: actions/checkout@v2 + - name: Build Docker image + run: eval "$BUILD" + - name: Login to dockerhub + run: docker login -u wmelching -p ${{ secrets.DOCKERHUB_TOKEN }} + - name: Tag image + run: docker tag panda docker.io/commaai/panda:latest + - name: Push image + run: docker push docker.io/commaai/panda:latest + + build: + name: build + runs-on: ubuntu-16.04 + timeout-minutes: 45 + steps: + - uses: actions/checkout@v2 + - name: Build Docker image + run: eval "$BUILD" + - name: Test python package installer + run: $RUN "cd /tmp/openpilot/panda && python setup.py install" + - name: Build panda STM image + run: $RUN "cd /tmp/openpilot/panda/board && make bin" + - name: Build panda STM bootstub image + run: $RUN "cd /tmp/openpilot/panda/board && make obj/bootstub.panda.bin" + - name: Build pedal STM image + run: $RUN "cd /tmp/openpilot/panda/board/pedal && make obj/comma.bin" + - name: Build pedal STM bootstub image + run: $RUN "cd /tmp/openpilot/panda/board/pedal && make obj/bootstub.bin" + + build_esp: + name: build esp + runs-on: ubuntu-16.04 + timeout-minutes: 45 + steps: + - uses: actions/checkout@v2 + - name: Build docker image + run: | + docker pull $(grep -ioP '(?<=^from)\s+\S+' tests/build/Dockerfile.panda_esp) || true + docker pull docker.io/commaai/panda_esp:latest || true + docker build --cache-from docker.io/commaai/panda_esp:latest -t panda_esp -f tests/build/Dockerfile.panda_esp . + - name: Build ESP image + run: docker run --rm panda_esp /bin/sh -c "cd /panda/boardesp && make user1.bin" + - name: Push image + if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/panda' + run: | + docker login -u wmelching -p ${{ secrets.DOCKERHUB_TOKEN }} + docker tag panda_esp docker.io/commaai/panda_esp:latest + docker push docker.io/commaai/panda_esp:latest + + safety: + name: safety + runs-on: ubuntu-16.04 + timeout-minutes: 45 + steps: + - uses: actions/checkout@v2 + - name: Build Docker image + run: eval "$BUILD" + - name: Run safety tests + run: | + $RUN "cd /tmp/openpilot && \ + scons -c && \ + scons -j$(nproc) opendbc/ cereal/ && \ + cd panda/tests/safety && \ + ./test.sh" + + safety_replay: + name: safety replay + runs-on: ubuntu-16.04 + timeout-minutes: 45 + steps: + - uses: actions/checkout@v2 + - name: Build Docker image + run: eval "$BUILD" + - name: Run safety replay + run: $RUN "cd /tmp/openpilot/panda/tests/safety_replay && ./test_safety_replay.py" + + misra: + name: misra c2012 + runs-on: ubuntu-16.04 + timeout-minutes: 45 + steps: + - uses: actions/checkout@v2 + - name: Build Docker image + run: eval "$BUILD" + - name: Run Misra C 2012 analysis + run: $PERSIST "cd /tmp/openpilot/panda/tests/misra && ./test_misra.sh" + - name: Copy analysis outputs + run: docker cp panda:/tmp/misra /tmp + - uses: actions/upload-artifact@v2 + if: always() + with: + name: cppcheck.txt + path: /tmp/misra/cppcheck_output.txt + - uses: actions/upload-artifact@v2 + if: always() + with: + name: misra.txt + path: /tmp/misra/misra_output.txt + + python_linter: + name: python linter + runs-on: ubuntu-16.04 + timeout-minutes: 45 + steps: + - uses: actions/checkout@v2 + - name: Build Docker image + run: eval "$BUILD" + - name: Run static analysis + run: | + $RUN "cd /tmp/openpilot/panda && git init && git add -A && MYPYPATH=/tmp/openpilot pre-commit run --all" diff --git a/.gitignore b/.gitignore index 397996a0..503ce91c 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ examples/output.csv .DS_Store .vscode nosetests.xml +.mypy_cache/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..e8464da5 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,30 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: master + hooks: + - id: check-ast + - id: check-json + - id: check-xml + - id: check-yaml +- repo: https://github.com/pre-commit/mirrors-mypy + rev: master + hooks: + - id: mypy + exclude: '^(tests/automated)/' +- repo: https://github.com/PyCQA/flake8 + rev: master + hooks: + - id: flake8 + exclude: '^(tests/automated)/' + args: + - --select=F +- repo: local + hooks: + - id: pylint + name: pylint + entry: pylint + language: system + types: [python] + exclude: '^(tests/automated)/' + args: + - --disable=R,C,W diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 00000000..dbcc4852 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,2 @@ +[MASTER] +generated-members=usb1.* diff --git a/Dockerfile.panda b/Dockerfile.panda new file mode 100644 index 00000000..dbc01082 --- /dev/null +++ b/Dockerfile.panda @@ -0,0 +1,66 @@ +FROM ubuntu:16.04 +ENV PYTHONUNBUFFERED 1 +ENV PYTHONPATH /tmp/openpilot:$PYTHONPATH + +RUN apt-get update && apt-get install -y --no-install-recommends \ + autoconf \ + automake \ + bzip2 \ + capnproto \ + clang \ + curl \ + g++ \ + gcc-arm-none-eabi libnewlib-arm-none-eabi \ + git \ + libarchive-dev \ + libavformat-dev libavcodec-dev libavdevice-dev libavutil-dev libswscale-dev libavresample-dev libavfilter-dev \ + libbz2-dev \ + libcapnp-dev \ + libcurl4-openssl-dev \ + libffi-dev \ + libtool \ + libssl-dev \ + libsqlite3-dev \ + libusb-1.0-0 \ + libzmq3-dev \ + locales \ + make \ + pkg-config \ + python \ + python-dev \ + python-pip \ + unzip \ + wget \ + zlib1g-dev \ + && rm -rf /var/lib/apt/lists/* + +RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen +ENV LANG en_US.UTF-8 +ENV LANGUAGE en_US:en +ENV LC_ALL en_US.UTF-8 + +RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash +ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}" + +COPY requirements.txt /tmp/ +RUN pyenv install 3.7.3 && \ + pyenv global 3.7.3 && \ + pyenv rehash && \ + pip install --no-cache-dir --upgrade pip==18.0 && \ + pip install --no-cache-dir -r /tmp/requirements.txt + +RUN cd /tmp && \ + git clone https://github.com/commaai/openpilot.git tmppilot || true && \ + cd /tmp/tmppilot && \ + git pull && git checkout 44560b5bb74e451767725144c3fa5f1564481a20 && \ + git submodule update --init cereal opendbc && \ + mkdir /tmp/openpilot && \ + cp -pR SConstruct tools/ selfdrive/ common/ cereal/ opendbc/ /tmp/openpilot && \ + rm -rf /tmp/tmppilot + +RUN cd /tmp/openpilot && \ + pip install --no-cache-dir -r opendbc/requirements.txt && \ + pip install --no-cache-dir -r tools/requirements.txt + +COPY . /tmp/openpilot/panda +RUN rm -rf /tmp/openpilot/panda/.git diff --git a/README.md b/README.md index 9979295a..55b30f55 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ It uses an [STM32F413](http://www.st.com/en/microcontrollers/stm32f413-423.html? It is 2nd gen hardware, reusing code and parts from the [NEO](https://github.com/commaai/neo) interface board. -[![CircleCI](https://circleci.com/gh/commaai/panda.svg?style=svg)](https://circleci.com/gh/commaai/panda) +![panda tests](https://github.com/commaai/panda/workflows/panda%20tests/badge.svg) Usage (Python) ------ @@ -99,7 +99,7 @@ When compiled from an [EON Dev Kit](https://comma.ai/shop/products/eon-gold-dash conjuction with [openpilot](https://github.com/commaai/openpilot). The panda FW, through its safety model, provides and enforces the [openpilot Safety](https://github.com/commaai/openpilot/blob/devel/SAFETY.md). Due to its critical function, it's important that the application code rigor within the `board` folder is held to high standards. -These are the [CI regression tests](https://circleci.com/gh/commaai/panda) we have in place: +These are the [CI regression tests](https://github.com/commaai/panda/actions) we have in place: * A generic static code analysis is performed by [Cppcheck](https://github.com/danmar/cppcheck/). * In addition, [Cppcheck](https://github.com/danmar/cppcheck/) has a specific addon to check for [MISRA C:2012](https://www.misra.org.uk/MISRAHome/MISRAC2012/tabid/196/Default.aspx) violations. See [current coverage](https://github.com/commaai/panda/blob/master/tests/misra/coverage_table). * Compiler options are relatively strict: the flags `-Wall -Wextra -Wstrict-prototypes -Werror` are enforced on board and pedal makefiles. diff --git a/__init__.py b/__init__.py index 5374d5a9..deeea46e 100644 --- a/__init__.py +++ b/__init__.py @@ -1 +1,3 @@ -from .python import Panda, PandaWifiStreaming, PandaDFU, ESPROM, CesantaFlasher, flash_release, BASEDIR, ensure_st_up_to_date, build_st, PandaSerial # noqa: F401 +# flake8: noqa +# pylint: skip-file +from .python import Panda, PandaWifiStreaming, PandaDFU, ESPROM, CesantaFlasher, flash_release, BASEDIR, ensure_st_up_to_date, build_st, PandaSerial diff --git a/board/board.h b/board/board.h index 30e1fa4d..28516299 100644 --- a/board/board.h +++ b/board/board.h @@ -13,6 +13,7 @@ #include "boards/grey.h" #include "boards/black.h" #include "boards/uno.h" + #include "boards/dos.h" #else #include "boards/pedal.h" #endif @@ -22,7 +23,10 @@ void detect_board_type(void) { // SPI lines floating: white (TODO: is this reliable? Not really, we have to enable ESP/GPS to be able to detect this on the UART) set_gpio_output(GPIOC, 14, 1); set_gpio_output(GPIOC, 5, 1); - if((detect_with_pull(GPIOA, 4, PULL_DOWN)) || (detect_with_pull(GPIOA, 5, PULL_DOWN)) || (detect_with_pull(GPIOA, 6, PULL_DOWN)) || (detect_with_pull(GPIOA, 7, PULL_DOWN))){ + if(!detect_with_pull(GPIOB, 1, PULL_UP)){ + hw_type = HW_TYPE_DOS; + current_board = &board_dos; + } else if((detect_with_pull(GPIOA, 4, PULL_DOWN)) || (detect_with_pull(GPIOA, 5, PULL_DOWN)) || (detect_with_pull(GPIOA, 6, PULL_DOWN)) || (detect_with_pull(GPIOA, 7, PULL_DOWN))){ hw_type = HW_TYPE_WHITE_PANDA; current_board = &board_white; } else if(detect_with_pull(GPIOA, 13, PULL_DOWN)) { // Rev AB deprecated, so no pullup means black. In REV C, A13 is pulled up to 5V with a 10K @@ -78,7 +82,7 @@ bool board_has_gmlan(void) { } bool board_has_obd(void) { - return ((hw_type == HW_TYPE_BLACK_PANDA) || (hw_type == HW_TYPE_UNO)); + return ((hw_type == HW_TYPE_BLACK_PANDA) || (hw_type == HW_TYPE_UNO) || (hw_type == HW_TYPE_DOS)); } bool board_has_lin(void) { @@ -86,9 +90,9 @@ bool board_has_lin(void) { } bool board_has_rtc(void) { - return (hw_type == HW_TYPE_UNO); + return ((hw_type == HW_TYPE_UNO) || (hw_type == HW_TYPE_DOS)); } bool board_has_relay(void) { - return ((hw_type == HW_TYPE_BLACK_PANDA) || (hw_type == HW_TYPE_UNO)); + return ((hw_type == HW_TYPE_BLACK_PANDA) || (hw_type == HW_TYPE_UNO) || (hw_type == HW_TYPE_DOS)); } diff --git a/board/board_declarations.h b/board/board_declarations.h index d973551b..d5e9e06a 100644 --- a/board/board_declarations.h +++ b/board/board_declarations.h @@ -39,6 +39,7 @@ struct board { #define HW_TYPE_BLACK_PANDA 3U #define HW_TYPE_PEDAL 4U #define HW_TYPE_UNO 5U +#define HW_TYPE_DOS 6U // LED colors #define LED_RED 0U diff --git a/board/boards/dos.h b/board/boards/dos.h new file mode 100644 index 00000000..afccd373 --- /dev/null +++ b/board/boards/dos.h @@ -0,0 +1,224 @@ +// ///////////// // +// Dos + Harness // +// ///////////// // + +void dos_enable_can_transciever(uint8_t transciever, bool enabled) { + switch (transciever){ + case 1U: + set_gpio_output(GPIOC, 1, !enabled); + break; + case 2U: + set_gpio_output(GPIOC, 13, !enabled); + break; + case 3U: + set_gpio_output(GPIOA, 0, !enabled); + break; + case 4U: + set_gpio_output(GPIOB, 10, !enabled); + break; + default: + puts("Invalid CAN transciever ("); puth(transciever); puts("): enabling failed\n"); + break; + } +} + +void dos_enable_can_transcievers(bool enabled) { + for(uint8_t i=1U; i<=4U; i++){ + // Leave main CAN always on for CAN-based ignition detection + if((car_harness_status == HARNESS_STATUS_FLIPPED) ? (i == 3U) : (i == 1U)){ + uno_enable_can_transciever(i, true); + } else { + uno_enable_can_transciever(i, enabled); + } + } +} + +void dos_set_led(uint8_t color, bool enabled) { + switch (color){ + case LED_RED: + set_gpio_output(GPIOC, 9, !enabled); + break; + case LED_GREEN: + set_gpio_output(GPIOC, 7, !enabled); + break; + case LED_BLUE: + set_gpio_output(GPIOC, 6, !enabled); + break; + default: + break; + } +} + +void dos_set_gps_load_switch(bool enabled) { + UNUSED(enabled); +} + +void dos_set_bootkick(bool enabled){ + UNUSED(enabled); +} + +void dos_bootkick(void) {} + +void dos_set_phone_power(bool enabled){ + UNUSED(enabled); +} + +void dos_set_usb_power_mode(uint8_t mode) { + UNUSED(mode); +} + +void dos_set_esp_gps_mode(uint8_t mode) { + UNUSED(mode); +} + +void dos_set_can_mode(uint8_t mode){ + switch (mode) { + case CAN_MODE_NORMAL: + case CAN_MODE_OBD_CAN2: + if ((bool)(mode == CAN_MODE_NORMAL) != (bool)(car_harness_status == HARNESS_STATUS_FLIPPED)) { + // B12,B13: disable OBD mode + set_gpio_mode(GPIOB, 12, MODE_INPUT); + set_gpio_mode(GPIOB, 13, MODE_INPUT); + + // B5,B6: normal CAN2 mode + set_gpio_alternate(GPIOB, 5, GPIO_AF9_CAN2); + set_gpio_alternate(GPIOB, 6, GPIO_AF9_CAN2); + } else { + // B5,B6: disable normal CAN2 mode + set_gpio_mode(GPIOB, 5, MODE_INPUT); + set_gpio_mode(GPIOB, 6, MODE_INPUT); + + // B12,B13: OBD mode + set_gpio_alternate(GPIOB, 12, GPIO_AF9_CAN2); + set_gpio_alternate(GPIOB, 13, GPIO_AF9_CAN2); + } + break; + default: + puts("Tried to set unsupported CAN mode: "); puth(mode); puts("\n"); + break; + } +} + +void dos_usb_power_mode_tick(uint32_t uptime){ + UNUSED(uptime); + if(bootkick_timer != 0U){ + bootkick_timer--; + } else { + dos_set_bootkick(false); + } +} + +bool dos_check_ignition(void){ + // ignition is checked through harness + return harness_check_ignition(); +} + +void dos_set_usb_switch(bool phone){ + set_gpio_output(GPIOB, 3, phone); +} + +void dos_set_ir_power(uint8_t percentage){ + pwm_set(TIM4, 2, percentage); +} + +void dos_set_fan_power(uint8_t percentage){ + // Enable fan power only if percentage is non-zero. + set_gpio_output(GPIOA, 1, (percentage != 0U)); + fan_set_power(percentage); +} + +uint32_t dos_read_current(void){ + // No current sense on Dos + return 0U; +} + +void dos_init(void) { + common_init_gpio(); + + // A8,A15: normal CAN3 mode + set_gpio_alternate(GPIOA, 8, GPIO_AF11_CAN3); + set_gpio_alternate(GPIOA, 15, GPIO_AF11_CAN3); + + // C0: OBD_SBU1 (orientation detection) + // C3: OBD_SBU2 (orientation detection) + set_gpio_mode(GPIOC, 0, MODE_ANALOG); + set_gpio_mode(GPIOC, 3, MODE_ANALOG); + + // C10: OBD_SBU1_RELAY (harness relay driving output) + // C11: OBD_SBU2_RELAY (harness relay driving output) + set_gpio_mode(GPIOC, 10, MODE_OUTPUT); + set_gpio_mode(GPIOC, 11, MODE_OUTPUT); + set_gpio_output_type(GPIOC, 10, OUTPUT_TYPE_OPEN_DRAIN); + set_gpio_output_type(GPIOC, 11, OUTPUT_TYPE_OPEN_DRAIN); + set_gpio_output(GPIOC, 10, 1); + set_gpio_output(GPIOC, 11, 1); + + // C8: FAN PWM aka TIM3_CH3 + set_gpio_alternate(GPIOC, 8, GPIO_AF2_TIM3); + + // Initialize IR PWM and set to 0% + set_gpio_alternate(GPIOB, 7, GPIO_AF2_TIM4); + pwm_init(TIM4, 2); + dos_set_ir_power(0U); + + // Initialize fan and set to 0% + fan_init(); + dos_set_fan_power(0U); + + // Initialize harness + harness_init(); + + // Initialize RTC + rtc_init(); + + // Enable CAN transcievers + dos_enable_can_transcievers(true); + + // Disable LEDs + dos_set_led(LED_RED, false); + dos_set_led(LED_GREEN, false); + dos_set_led(LED_BLUE, false); + + // Set normal CAN mode + dos_set_can_mode(CAN_MODE_NORMAL); + + // flip CAN0 and CAN2 if we are flipped + if (car_harness_status == HARNESS_STATUS_FLIPPED) { + can_flip_buses(0, 2); + } + + // init multiplexer + can_set_obd(car_harness_status, false); +} + +const harness_configuration dos_harness_config = { + .has_harness = true, + .GPIO_SBU1 = GPIOC, + .GPIO_SBU2 = GPIOC, + .GPIO_relay_SBU1 = GPIOC, + .GPIO_relay_SBU2 = GPIOC, + .pin_SBU1 = 0, + .pin_SBU2 = 3, + .pin_relay_SBU1 = 10, + .pin_relay_SBU2 = 11, + .adc_channel_SBU1 = 10, + .adc_channel_SBU2 = 13 +}; + +const board board_dos = { + .board_type = "Dos", + .harness_config = &dos_harness_config, + .init = dos_init, + .enable_can_transciever = dos_enable_can_transciever, + .enable_can_transcievers = dos_enable_can_transcievers, + .set_led = dos_set_led, + .set_usb_power_mode = dos_set_usb_power_mode, + .set_esp_gps_mode = dos_set_esp_gps_mode, + .set_can_mode = dos_set_can_mode, + .usb_power_mode_tick = dos_usb_power_mode_tick, + .check_ignition = dos_check_ignition, + .read_current = dos_read_current, + .set_fan_power = dos_set_fan_power, + .set_ir_power = dos_set_ir_power, + .set_phone_power = dos_set_phone_power +}; diff --git a/board/drivers/llcan.h b/board/drivers/llcan.h index e467d67b..0e331526 100644 --- a/board/drivers/llcan.h +++ b/board/drivers/llcan.h @@ -14,6 +14,7 @@ #define GET_BYTE(msg, b) (((int)(b) > 3) ? (((msg)->RDHR >> (8U * ((unsigned int)(b) % 4U))) & 0xFFU) : (((msg)->RDLR >> (8U * (unsigned int)(b))) & 0xFFU)) #define GET_BYTES_04(msg) ((msg)->RDLR) #define GET_BYTES_48(msg) ((msg)->RDHR) +#define GET_FLAG(value, mask) (((__typeof__(mask))param & mask) == mask) #define CAN_INIT_TIMEOUT_MS 500U #define CAN_NAME_FROM_CANIF(CAN_DEV) (((CAN_DEV)==CAN1) ? "CAN1" : (((CAN_DEV) == CAN2) ? "CAN2" : "CAN3")) diff --git a/board/safety.h b/board/safety.h index d2d107d6..e419403e 100644 --- a/board/safety.h +++ b/board/safety.h @@ -72,10 +72,14 @@ void gen_crc_lookup_table(uint8_t poly, uint8_t crc_lut[]) { } } -bool msg_allowed(int addr, int bus, const AddrBus addr_list[], int len) { +bool msg_allowed(CAN_FIFOMailBox_TypeDef *to_send, const CanMsg msg_list[], int len) { + int addr = GET_ADDR(to_send); + int bus = GET_BUS(to_send); + int length = GET_LEN(to_send); + bool allowed = false; for (int i = 0; i < len; i++) { - if ((addr == addr_list[i].addr) && (bus == addr_list[i].bus)) { + if ((addr == msg_list[i].addr) && (bus == msg_list[i].bus) && (length == msg_list[i].len)) { allowed = true; break; } @@ -92,17 +96,29 @@ uint32_t get_ts_elapsed(uint32_t ts, uint32_t ts_last) { int get_addr_check_index(CAN_FIFOMailBox_TypeDef *to_push, AddrCheckStruct addr_list[], const int len) { int bus = GET_BUS(to_push); int addr = GET_ADDR(to_push); + int length = GET_LEN(to_push); int index = -1; for (int i = 0; i < len; i++) { - for (uint8_t j = 0U; addr_list[i].addr[j] != 0; j++) { - if ((addr == addr_list[i].addr[j]) && (bus == addr_list[i].bus)) { - index = i; - goto Return; + // if multiple msgs are allowed, determine which one is present on the bus + if (!addr_list[i].msg_seen) { + for (uint8_t j = 0U; addr_list[i].msg[j].addr != 0; j++) { + if ((addr == addr_list[i].msg[j].addr) && (bus == addr_list[i].msg[j].bus) && + (length == addr_list[i].msg[j].len)) { + addr_list[i].index = j; + addr_list[i].msg_seen = true; + break; + } } } + + int idx = addr_list[i].index; + if ((addr == addr_list[i].msg[idx].addr) && (bus == addr_list[i].msg[idx].bus) && + (length == addr_list[i].msg[idx].len)) { + index = i; + break; + } } -Return: return index; } @@ -115,7 +131,7 @@ void safety_tick(const safety_hooks *hooks) { // lag threshold is max of: 1s and MAX_MISSED_MSGS * expected timestep. // Quite conservative to not risk false triggers. // 2s of lag is worse case, since the function is called at 1Hz - bool lagging = elapsed_time > MAX(hooks->addr_check[i].expected_timestep * MAX_MISSED_MSGS, 1e6); + bool lagging = elapsed_time > MAX(hooks->addr_check[i].msg[hooks->addr_check[i].index].expected_timestep * MAX_MISSED_MSGS, 1e6); hooks->addr_check[i].lagging = lagging; if (lagging) { controls_allowed = 0; @@ -126,7 +142,7 @@ void safety_tick(const safety_hooks *hooks) { void update_counter(AddrCheckStruct addr_list[], int index, uint8_t counter) { if (index != -1) { - uint8_t expected_counter = (addr_list[index].last_counter + 1U) % (addr_list[index].max_counter + 1U); + uint8_t expected_counter = (addr_list[index].last_counter + 1U) % (addr_list[index].msg[addr_list[index].index].max_counter + 1U); addr_list[index].wrong_counters += (expected_counter == counter) ? -1 : 1; addr_list[index].wrong_counters = MAX(MIN(addr_list[index].wrong_counters, MAX_WRONG_COUNTERS), 0); addr_list[index].last_counter = counter; @@ -163,7 +179,7 @@ bool addr_safety_check(CAN_FIFOMailBox_TypeDef *to_push, if (index != -1) { // checksum check - if ((get_checksum != NULL) && (compute_checksum != NULL) && rx_checks[index].check_checksum) { + if ((get_checksum != NULL) && (compute_checksum != NULL) && rx_checks[index].msg[rx_checks[index].index].check_checksum) { uint8_t checksum = get_checksum(to_push); uint8_t checksum_comp = compute_checksum(to_push); rx_checks[index].valid_checksum = checksum_comp == checksum; @@ -172,7 +188,7 @@ bool addr_safety_check(CAN_FIFOMailBox_TypeDef *to_push, } // counter check (max_counter == 0 means skip check) - if ((get_counter != NULL) && (rx_checks[index].max_counter > 0U)) { + if ((get_counter != NULL) && (rx_checks[index].msg[rx_checks[index].index].max_counter > 0U)) { uint8_t counter = get_counter(to_push); update_counter(rx_checks, index, counter); } else { @@ -209,13 +225,13 @@ const safety_hook_config safety_hook_registry[] = { {SAFETY_CHRYSLER, &chrysler_hooks}, {SAFETY_SUBARU, &subaru_hooks}, {SAFETY_SUBARU_LEGACY, &subaru_legacy_hooks}, - {SAFETY_MAZDA, &mazda_hooks}, {SAFETY_VOLKSWAGEN_MQB, &volkswagen_mqb_hooks}, {SAFETY_VOLKSWAGEN_PQ, &volkswagen_pq_hooks}, + {SAFETY_NISSAN, &nissan_hooks}, {SAFETY_NOOUTPUT, &nooutput_hooks}, #ifdef ALLOW_DEBUG + {SAFETY_MAZDA, &mazda_hooks}, {SAFETY_TESLA, &tesla_hooks}, - {SAFETY_NISSAN, &nissan_hooks}, {SAFETY_ALLOUTPUT, &alloutput_hooks}, {SAFETY_GM_ASCM, &gm_ascm_hooks}, {SAFETY_FORD, &ford_hooks}, @@ -223,7 +239,29 @@ const safety_hook_config safety_hook_registry[] = { }; int set_safety_hooks(uint16_t mode, int16_t param) { - safety_mode_cnt = 0U; // reset safety mode timer + // reset state set by safety mode + safety_mode_cnt = 0U; + relay_malfunction = false; + gas_interceptor_detected = false; + gas_interceptor_prev = 0; + gas_pressed_prev = false; + brake_pressed_prev = false; + cruise_engaged_prev = false; + vehicle_speed = 0; + vehicle_moving = false; + desired_torque_last = 0; + rt_torque_last = 0; + ts_angle_last = 0; + desired_angle_last = 0; + ts_last = 0; + + torque_meas.max = 0; + torque_meas.max = 0; + torque_driver.min = 0; + torque_driver.max = 0; + angle_meas.min = 0; + angle_meas.max = 0; + int set_status = -1; // not set int hook_config_count = sizeof(safety_hook_registry) / sizeof(safety_hook_config); for (int i = 0; i < hook_config_count; i++) { @@ -231,7 +269,12 @@ int set_safety_hooks(uint16_t mode, int16_t param) { current_hooks = safety_hook_registry[i].hooks; current_safety_mode = safety_hook_registry[i].id; set_status = 0; // set - break; + } + + // reset message index and seen flags in addr struct + for (int j = 0; j < safety_hook_registry[i].hooks->addr_check_len; j++) { + safety_hook_registry[i].hooks->addr_check[j].index = 0; + safety_hook_registry[i].hooks->addr_check[j].msg_seen = false; } } if ((set_status == 0) && (current_hooks->init != NULL)) { diff --git a/board/safety/safety_chrysler.h b/board/safety/safety_chrysler.h index 82fcfb14..be3b9c52 100644 --- a/board/safety/safety_chrysler.h +++ b/board/safety/safety_chrysler.h @@ -6,20 +6,17 @@ const int CHRYSLER_MAX_RATE_DOWN = 3; const int CHRYSLER_MAX_TORQUE_ERROR = 80; // max torque cmd in excess of torque motor const int CHRYSLER_GAS_THRSLD = 30; // 7% more than 2m/s const int CHRYSLER_STANDSTILL_THRSLD = 10; // about 1m/s -const AddrBus CHRYSLER_TX_MSGS[] = {{571, 0}, {658, 0}, {678, 0}}; +const CanMsg CHRYSLER_TX_MSGS[] = {{571, 0, 3}, {658, 0, 6}, {678, 0, 8}}; -// TODO: do checksum and counter checks AddrCheckStruct chrysler_rx_checks[] = { - {.addr = {544}, .bus = 0, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}, - {.addr = {514}, .bus = 0, .check_checksum = false, .max_counter = 0U, .expected_timestep = 10000U}, - {.addr = {500}, .bus = 0, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}, - {.addr = {308}, .bus = 0, .check_checksum = false, .max_counter = 15U, .expected_timestep = 20000U}, - {.addr = {320}, .bus = 0, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}, + {.msg = {{544, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}}}, + {.msg = {{514, 0, 8, .check_checksum = false, .max_counter = 0U, .expected_timestep = 10000U}}}, + {.msg = {{500, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}}}, + {.msg = {{308, 0, 8, .check_checksum = false, .max_counter = 15U, .expected_timestep = 20000U}}}, + {.msg = {{320, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}}}, }; const int CHRYSLER_RX_CHECK_LEN = sizeof(chrysler_rx_checks) / sizeof(chrysler_rx_checks[0]); -int chrysler_speed = 0; - static uint8_t chrysler_get_checksum(CAN_FIFOMailBox_TypeDef *to_push) { int checksum_byte = GET_LEN(to_push) - 1; return (uint8_t)(GET_BYTE(to_push, checksum_byte)); @@ -98,14 +95,14 @@ static int chrysler_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { if (addr == 514) { int speed_l = (GET_BYTE(to_push, 0) << 4) + (GET_BYTE(to_push, 1) >> 4); int speed_r = (GET_BYTE(to_push, 2) << 4) + (GET_BYTE(to_push, 3) >> 4); - chrysler_speed = (speed_l + speed_r) / 2; - vehicle_moving = chrysler_speed > CHRYSLER_STANDSTILL_THRSLD; + vehicle_speed = (speed_l + speed_r) / 2; + vehicle_moving = (int)vehicle_speed > CHRYSLER_STANDSTILL_THRSLD; } // exit controls on rising edge of gas press if (addr == 308) { bool gas_pressed = (GET_BYTE(to_push, 5) & 0x7F) != 0; - if (!unsafe_allow_gas && gas_pressed && !gas_pressed_prev && (chrysler_speed > CHRYSLER_GAS_THRSLD)) { + if (!unsafe_allow_gas && gas_pressed && !gas_pressed_prev && ((int)vehicle_speed > CHRYSLER_GAS_THRSLD)) { controls_allowed = 0; } gas_pressed_prev = gas_pressed; @@ -132,9 +129,8 @@ static int chrysler_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int tx = 1; int addr = GET_ADDR(to_send); - int bus = GET_BUS(to_send); - if (!msg_allowed(addr, bus, CHRYSLER_TX_MSGS, sizeof(CHRYSLER_TX_MSGS) / sizeof(CHRYSLER_TX_MSGS[0]))) { + if (!msg_allowed(to_send, CHRYSLER_TX_MSGS, sizeof(CHRYSLER_TX_MSGS) / sizeof(CHRYSLER_TX_MSGS[0]))) { tx = 0; } diff --git a/board/safety/safety_gm.h b/board/safety/safety_gm.h index 264df313..1d617a26 100644 --- a/board/safety/safety_gm.h +++ b/board/safety/safety_gm.h @@ -18,18 +18,18 @@ const int GM_DRIVER_TORQUE_FACTOR = 4; const int GM_MAX_GAS = 3072; const int GM_MAX_REGEN = 1404; const int GM_MAX_BRAKE = 350; -const AddrBus GM_TX_MSGS[] = {{384, 0}, {1033, 0}, {1034, 0}, {715, 0}, {880, 0}, // pt bus - {161, 1}, {774, 1}, {776, 1}, {784, 1}, // obs bus - {789, 2}, // ch bus - {0x104c006c, 3}, {0x10400060, 3}}; // gmlan +const CanMsg GM_TX_MSGS[] = {{384, 0, 4}, {1033, 0, 7}, {1034, 0, 7}, {715, 0, 8}, {880, 0, 6}, // pt bus + {161, 1, 7}, {774, 1, 8}, {776, 1, 7}, {784, 1, 2}, // obs bus + {789, 2, 5}, // ch bus + {0x104c006c, 3, 3}, {0x10400060, 3, 5}}; // gmlan // TODO: do checksum and counter checks. Add correct timestep, 0.1s for now. AddrCheckStruct gm_rx_checks[] = { - {.addr = {388}, .bus = 0, .expected_timestep = 100000U}, - {.addr = {842}, .bus = 0, .expected_timestep = 100000U}, - {.addr = {481}, .bus = 0, .expected_timestep = 100000U}, - {.addr = {241}, .bus = 0, .expected_timestep = 100000U}, - {.addr = {417}, .bus = 0, .expected_timestep = 100000U}, + {.msg = {{388, 0, 8, .expected_timestep = 100000U}}}, + {.msg = {{842, 0, 5, .expected_timestep = 100000U}}}, + {.msg = {{481, 0, 7, .expected_timestep = 100000U}}}, + {.msg = {{241, 0, 6, .expected_timestep = 100000U}}}, + {.msg = {{417, 0, 7, .expected_timestep = 100000U}}}, }; const int GM_RX_CHECK_LEN = sizeof(gm_rx_checks) / sizeof(gm_rx_checks[0]); @@ -122,9 +122,8 @@ static int gm_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int tx = 1; int addr = GET_ADDR(to_send); - int bus = GET_BUS(to_send); - if (!msg_allowed(addr, bus, GM_TX_MSGS, sizeof(GM_TX_MSGS)/sizeof(GM_TX_MSGS[0]))) { + if (!msg_allowed(to_send, GM_TX_MSGS, sizeof(GM_TX_MSGS)/sizeof(GM_TX_MSGS[0]))) { tx = 0; } diff --git a/board/safety/safety_honda.h b/board/safety/safety_honda.h index 9f09da95..33d1ef86 100644 --- a/board/safety/safety_honda.h +++ b/board/safety/safety_honda.h @@ -6,9 +6,11 @@ // accel rising edge // brake rising edge // brake > 0mph -const AddrBus HONDA_N_TX_MSGS[] = {{0xE4, 0}, {0x194, 0}, {0x1FA, 0}, {0x200, 0}, {0x30C, 0}, {0x33D, 0}}; -const AddrBus HONDA_BG_TX_MSGS[] = {{0xE4, 2}, {0xE5, 2}, {0x296, 0}, {0x33D, 2}}; // Bosch Giraffe -const AddrBus HONDA_BH_TX_MSGS[] = {{0xE4, 0}, {0xE5, 0}, {0x296, 1}, {0x33D, 0}}; // Bosch Harness +const CanMsg HONDA_N_TX_MSGS[] = {{0xE4, 0, 5}, {0x194, 0, 4}, {0x1FA, 0, 8}, {0x200, 0, 6}, {0x30C, 0, 8}, {0x33D, 0, 5}}; +const CanMsg HONDA_BG_TX_MSGS[] = {{0xE4, 2, 5}, {0xE5, 2, 8}, {0x296, 0, 4}, {0x33D, 2, 5}}; // Bosch Giraffe +const CanMsg HONDA_BH_TX_MSGS[] = {{0xE4, 0, 5}, {0xE5, 0, 8}, {0x296, 1, 4}, {0x33D, 0, 5}}; // Bosch Harness +const CanMsg HONDA_BG_LONG_TX_MSGS[] = {{0xE4, 0, 5}, {0x1DF, 0, 8}, {0x1EF, 0, 8}, {0x1FA, 0, 8}, {0x30C, 0, 8}, {0x33D, 0, 5}, {0x39F, 0, 8}, {0x18DAB0F1, 0, 8}}; // Bosch Giraffe w/ gas and brakes +const CanMsg HONDA_BH_LONG_TX_MSGS[] = {{0xE4, 1, 5}, {0x1DF, 1, 8}, {0x1EF, 1, 8}, {0x1FA, 1, 8}, {0x30C, 1, 8}, {0x33D, 1, 5}, {0x39F, 1, 8}, {0x18DAB0F1, 1, 8}}; // Bosch Harness w/ gas and brakes // Roughly calculated using the offsets in openpilot +5%: // In openpilot: ((gas1_norm + gas2_norm)/2) > 15 @@ -18,26 +20,34 @@ const AddrBus HONDA_BH_TX_MSGS[] = {{0xE4, 0}, {0xE5, 0}, {0x296, 1}, {0x33D, 0} // In this safety: ((gas1 + (gas2/2))/2) > THRESHOLD const int HONDA_GAS_INTERCEPTOR_THRESHOLD = 344; #define HONDA_GET_INTERCEPTOR(msg) (((GET_BYTE((msg), 0) << 8) + GET_BYTE((msg), 1) + ((GET_BYTE((msg), 2) << 8) + GET_BYTE((msg), 3)) / 2 ) / 2) // avg between 2 tracks +const int HONDA_BOSCH_NO_GAS_VALUE = -30000; // value sent when not requesting gas +const int HONDA_BOSCH_GAS_MAX = 2000; +const int HONDA_BOSCH_ACCEL_MIN = -350; // max braking == -3.5m/s2 // Nidec and Bosch giraffe have pt on bus 0 AddrCheckStruct honda_rx_checks[] = { - {.addr = {0x1A6, 0x296}, .bus = 0, .check_checksum = true, .max_counter = 3U, .expected_timestep = 40000U}, - {.addr = { 0x158}, .bus = 0, .check_checksum = true, .max_counter = 3U, .expected_timestep = 10000U}, - {.addr = { 0x17C}, .bus = 0, .check_checksum = true, .max_counter = 3U, .expected_timestep = 10000U}, + {.msg = {{0x1A6, 0, 8, .check_checksum = true, .max_counter = 3U, .expected_timestep = 40000U}, + {0x296, 0, 4, .check_checksum = true, .max_counter = 3U, .expected_timestep = 40000U}}}, + {.msg = {{0x158, 0, 8, .check_checksum = true, .max_counter = 3U, .expected_timestep = 10000U}}}, + {.msg = {{0x17C, 0, 8, .check_checksum = true, .max_counter = 3U, .expected_timestep = 10000U}}}, }; const int HONDA_RX_CHECKS_LEN = sizeof(honda_rx_checks) / sizeof(honda_rx_checks[0]); // Bosch harness has pt on bus 1 AddrCheckStruct honda_bh_rx_checks[] = { - {.addr = {0x296}, .bus = 1, .check_checksum = true, .max_counter = 3U, .expected_timestep = 40000U}, - {.addr = {0x158}, .bus = 1, .check_checksum = true, .max_counter = 3U, .expected_timestep = 10000U}, - {.addr = {0x17C}, .bus = 1, .check_checksum = true, .max_counter = 3U, .expected_timestep = 10000U}, + {.msg = {{0x296, 1, 4, .check_checksum = true, .max_counter = 3U, .expected_timestep = 40000U}}}, + {.msg = {{0x158, 1, 8, .check_checksum = true, .max_counter = 3U, .expected_timestep = 10000U}}}, + {.msg = {{0x17C, 1, 8, .check_checksum = true, .max_counter = 3U, .expected_timestep = 10000U}}}, }; const int HONDA_BH_RX_CHECKS_LEN = sizeof(honda_bh_rx_checks) / sizeof(honda_bh_rx_checks[0]); +const uint16_t HONDA_PARAM_ALT_BRAKE = 1; +const uint16_t HONDA_PARAM_BOSCH_LONG = 2; + int honda_brake = 0; bool honda_alt_brake_msg = false; bool honda_fwd_brake = false; +bool honda_bosch_long = false; enum {HONDA_N_HW, HONDA_BG_HW, HONDA_BH_HW} honda_hw = HONDA_N_HW; @@ -191,12 +201,16 @@ static int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int addr = GET_ADDR(to_send); int bus = GET_BUS(to_send); - if (honda_hw == HONDA_BG_HW) { - tx = msg_allowed(addr, bus, HONDA_BG_TX_MSGS, sizeof(HONDA_BG_TX_MSGS)/sizeof(HONDA_BG_TX_MSGS[0])); - } else if (honda_hw == HONDA_BH_HW) { - tx = msg_allowed(addr, bus, HONDA_BH_TX_MSGS, sizeof(HONDA_BH_TX_MSGS)/sizeof(HONDA_BH_TX_MSGS[0])); + if ((honda_hw == HONDA_BG_HW) && !honda_bosch_long) { + tx = msg_allowed(to_send, HONDA_BG_TX_MSGS, sizeof(HONDA_BG_TX_MSGS)/sizeof(HONDA_BG_TX_MSGS[0])); + } else if ((honda_hw == HONDA_BG_HW) && honda_bosch_long) { + tx = msg_allowed(to_send, HONDA_BG_LONG_TX_MSGS, sizeof(HONDA_BG_LONG_TX_MSGS)/sizeof(HONDA_BG_LONG_TX_MSGS[0])); + } else if ((honda_hw == HONDA_BH_HW) && !honda_bosch_long) { + tx = msg_allowed(to_send, HONDA_BH_TX_MSGS, sizeof(HONDA_BH_TX_MSGS)/sizeof(HONDA_BH_TX_MSGS[0])); + } else if ((honda_hw == HONDA_BH_HW) && honda_bosch_long) { + tx = msg_allowed(to_send, HONDA_BH_LONG_TX_MSGS, sizeof(HONDA_BH_LONG_TX_MSGS)/sizeof(HONDA_BH_LONG_TX_MSGS[0])); } else { - tx = msg_allowed(addr, bus, HONDA_N_TX_MSGS, sizeof(HONDA_N_TX_MSGS)/sizeof(HONDA_N_TX_MSGS[0])); + tx = msg_allowed(to_send, HONDA_N_TX_MSGS, sizeof(HONDA_N_TX_MSGS)/sizeof(HONDA_N_TX_MSGS[0])); } if (relay_malfunction) { @@ -211,9 +225,10 @@ static int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { pedal_pressed = pedal_pressed || gas_pressed_prev || (gas_interceptor_prev > HONDA_GAS_INTERCEPTOR_THRESHOLD); } bool current_controls_allowed = controls_allowed && !(pedal_pressed); + int bus_pt = (honda_hw == HONDA_BH_HW)? 1 : 0; - // BRAKE: safety check - if ((addr == 0x1FA) && (bus == 0)) { + // BRAKE: safety check (nidec) + if ((addr == 0x1FA) && (bus == bus_pt)) { honda_brake = (GET_BYTE(to_send, 0) << 2) + ((GET_BYTE(to_send, 1) >> 6) & 0x3); if (!current_controls_allowed) { if (honda_brake != 0) { @@ -228,6 +243,31 @@ static int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { } } + // BRAKE/GAS: safety check (bosch) + if ((addr == 0x1DF) && (bus == bus_pt)) { + int accel = (GET_BYTE(to_send, 3) << 3) | ((GET_BYTE(to_send, 4) >> 5) & 0x7); + accel = to_signed(accel, 11); + if (!current_controls_allowed) { + if (accel != 0) { + tx = 0; + } + } + if (accel < HONDA_BOSCH_ACCEL_MIN) { + tx = 0; + } + + int gas = (GET_BYTE(to_send, 0) << 8) | GET_BYTE(to_send, 1); + gas = to_signed(gas, 16); + if (!current_controls_allowed) { + if (gas != HONDA_BOSCH_NO_GAS_VALUE) { + tx = 0; + } + } + if (gas > HONDA_BOSCH_GAS_MAX) { + tx = 0; + } + } + // STEER: safety check if ((addr == 0xE4) || (addr == 0x194)) { if (!current_controls_allowed) { @@ -245,7 +285,7 @@ static int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { } } - // GAS: safety check + // GAS: safety check (interceptor) if (addr == 0x200) { if (!current_controls_allowed) { if (GET_BYTE(to_send, 0) || GET_BYTE(to_send, 1)) { @@ -257,7 +297,6 @@ static int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { // FORCE CANCEL: safety check only relevant when spamming the cancel button in Bosch HW // ensuring that only the cancel button press is sent (VAL 2) when controls are off. // This avoids unintended engagements while still allowing resume spam - int bus_pt = (honda_hw == HONDA_BH_HW)? 1 : 0; if ((addr == 0x296) && !current_controls_allowed && (bus == bus_pt)) { if (((GET_BYTE(to_send, 0) >> 5) & 0x7) != 2) { tx = 0; @@ -275,6 +314,7 @@ static void honda_nidec_init(int16_t param) { gas_interceptor_detected = 0; honda_hw = HONDA_N_HW; honda_alt_brake_msg = false; + honda_bosch_long = false; } static void honda_bosch_giraffe_init(int16_t param) { @@ -282,7 +322,9 @@ static void honda_bosch_giraffe_init(int16_t param) { relay_malfunction_reset(); honda_hw = HONDA_BG_HW; // Checking for alternate brake override from safety parameter - honda_alt_brake_msg = (param == 1) ? true : false; + honda_alt_brake_msg = GET_FLAG(param, HONDA_PARAM_ALT_BRAKE); + // radar disabled so allow gas/brakes + honda_bosch_long = GET_FLAG(param, HONDA_PARAM_BOSCH_LONG); } static void honda_bosch_harness_init(int16_t param) { @@ -290,7 +332,9 @@ static void honda_bosch_harness_init(int16_t param) { relay_malfunction_reset(); honda_hw = HONDA_BH_HW; // Checking for alternate brake override from safety parameter - honda_alt_brake_msg = (param == 1) ? true : false; + honda_alt_brake_msg = GET_FLAG(param, HONDA_PARAM_ALT_BRAKE); + // radar disabled so allow gas/brakes + honda_bosch_long = GET_FLAG(param, HONDA_PARAM_BOSCH_LONG); } static int honda_nidec_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { diff --git a/board/safety/safety_hyundai.h b/board/safety/safety_hyundai.h index 61c3b7e8..278b7250 100644 --- a/board/safety/safety_hyundai.h +++ b/board/safety/safety_hyundai.h @@ -6,15 +6,28 @@ const int HYUNDAI_MAX_RATE_DOWN = 7; const int HYUNDAI_DRIVER_TORQUE_ALLOWANCE = 50; const int HYUNDAI_DRIVER_TORQUE_FACTOR = 2; const int HYUNDAI_STANDSTILL_THRSLD = 30; // ~1kph -const AddrBus HYUNDAI_TX_MSGS[] = {{832, 0}, {1265, 0}, {1157, 0}}; +const CanMsg HYUNDAI_TX_MSGS[] = { + {832, 0, 8}, // LKAS11 Bus 0 + {1265, 0, 4}, // CLU11 Bus 0 + {1157, 0, 4}, // LFAHDA_MFC Bus 0 + // {1056, 0, 8}, // SCC11, Bus 0 + // {1057, 0, 8}, // SCC12, Bus 0 + // {1290, 0, 8}, // SCC13, Bus 0 + // {905, 0, 8}, // SCC14, Bus 0 + // {1186, 0, 8} // 4a2SCC, Bus 0 + }; -// TODO: do checksum checks +// TODO: missing checksum for wheel speeds message,worst failure case is +// wheel speeds stuck at 0 and we don't disengage on brake press +// TODO: refactor addr check to cleanly re-enable commented out checks for cars that have them AddrCheckStruct hyundai_rx_checks[] = { - {.addr = {608}, .bus = 0, .max_counter = 3U, .expected_timestep = 10000U}, - {.addr = {897}, .bus = 0, .max_counter = 255U, .expected_timestep = 10000U}, - {.addr = {902}, .bus = 0, .max_counter = 3U, .expected_timestep = 10000U}, - {.addr = {916}, .bus = 0, .max_counter = 7U, .expected_timestep = 10000U}, - {.addr = {1057}, .bus = 0, .max_counter = 15U, .expected_timestep = 20000U}, + {.msg = {{608, 0, 8, .check_checksum = true, .max_counter = 3U, .expected_timestep = 10000U}}}, + // TODO: older hyundai models don't populate the counter bits in 902 + //{.msg = {{902, 0, 8, .max_counter = 15U, .expected_timestep = 10000U}}}, + {.msg = {{902, 0, 8, .max_counter = 0U, .expected_timestep = 10000U}}}, + //{.msg = {{916, 0, 8, .check_checksum = true, .max_counter = 7U, .expected_timestep = 10000U}}}, + {.msg = {{916, 0, 8, .check_checksum = false, .max_counter = 0U, .expected_timestep = 10000U}}}, + {.msg = {{1057, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}}}, }; const int HYUNDAI_RX_CHECK_LEN = sizeof(hyundai_rx_checks) / sizeof(hyundai_rx_checks[0]); @@ -24,10 +37,8 @@ static uint8_t hyundai_get_counter(CAN_FIFOMailBox_TypeDef *to_push) { uint8_t cnt; if (addr == 608) { cnt = (GET_BYTE(to_push, 7) >> 4) & 0x3; - } else if (addr == 897) { - cnt = GET_BYTE(to_push, 5); } else if (addr == 902) { - cnt = (GET_BYTE(to_push, 1) >> 6) & 0x3; + cnt = ((GET_BYTE(to_push, 3) >> 6) << 2) | (GET_BYTE(to_push, 1) >> 6); } else if (addr == 916) { cnt = (GET_BYTE(to_push, 1) >> 5) & 0x7; } else if (addr == 1057) { @@ -38,10 +49,42 @@ static uint8_t hyundai_get_counter(CAN_FIFOMailBox_TypeDef *to_push) { return cnt; } +static uint8_t hyundai_get_checksum(CAN_FIFOMailBox_TypeDef *to_push) { + int addr = GET_ADDR(to_push); + + uint8_t chksum; + if (addr == 608) { + chksum = GET_BYTE(to_push, 7) & 0xF; + } else if (addr == 916) { + chksum = GET_BYTE(to_push, 6) & 0xF; + } else if (addr == 1057) { + chksum = GET_BYTE(to_push, 7) >> 4; + } else { + chksum = 0; + } + return chksum; +} + +static uint8_t hyundai_compute_checksum(CAN_FIFOMailBox_TypeDef *to_push) { + int addr = GET_ADDR(to_push); + + uint8_t chksum = 0; + // same algorithm, but checksum is in a different place + for (int i = 0; i < 8; i++) { + uint8_t b = GET_BYTE(to_push, i); + if (((addr == 608) && (i == 7)) || ((addr == 916) && (i == 6)) || ((addr == 1057) && (i == 7))) { + b &= (addr == 1057) ? 0x0FU : 0xF0U; // remove checksum + } + chksum += (b % 16U) + (b / 16U); + } + return (16U - (chksum % 16U)) % 16U; +} + static int hyundai_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { bool valid = addr_safety_check(to_push, hyundai_rx_checks, HYUNDAI_RX_CHECK_LEN, - NULL, NULL, hyundai_get_counter); + hyundai_get_checksum, hyundai_compute_checksum, + hyundai_get_counter); bool unsafe_allow_gas = unsafe_mode & UNSAFE_DISABLE_DISENGAGE_ON_GAS; @@ -106,9 +149,8 @@ static int hyundai_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int tx = 1; int addr = GET_ADDR(to_send); - int bus = GET_BUS(to_send); - if (!msg_allowed(addr, bus, HYUNDAI_TX_MSGS, sizeof(HYUNDAI_TX_MSGS)/sizeof(HYUNDAI_TX_MSGS[0]))) { + if (!msg_allowed(to_send, HYUNDAI_TX_MSGS, sizeof(HYUNDAI_TX_MSGS)/sizeof(HYUNDAI_TX_MSGS[0]))) { tx = 0; } @@ -192,7 +234,6 @@ static int hyundai_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { return bus_fwd; } - const safety_hooks hyundai_hooks = { .init = nooutput_init, .rx = hyundai_rx_hook, diff --git a/board/safety/safety_mazda.h b/board/safety/safety_mazda.h index 8ee63849..236ce686 100644 --- a/board/safety/safety_mazda.h +++ b/board/safety/safety_mazda.h @@ -1,10 +1,10 @@ - // CAN msgs we care about -#define MAZDA_LKAS 0x243 -#define MAZDA_LANEINFO 0x440 -#define MAZDA_CRZ_CTRL 0x21c -#define MAZDA_WHEEL_SPEED 0x215 -#define MAZDA_STEER_TORQUE 0x240 +#define MAZDA_LKAS 0x243 +#define MAZDA_CRZ_CTRL 0x21c +#define MAZDA_CRZ_BTNS 0x09d +#define MAZDA_STEER_TORQUE 0x240 +#define MAZDA_ENGINE_DATA 0x202 +#define MAZDA_PEDALS 0x165 // CAN bus numbers #define MAZDA_MAIN 0 @@ -21,43 +21,102 @@ #define MAZDA_MAX_RATE_DOWN 25 #define MAZDA_DRIVER_TORQUE_ALLOWANCE 15 #define MAZDA_DRIVER_TORQUE_FACTOR 1 +#define MAZDA_MAX_TORQUE_ERROR 350 -int mazda_cruise_engaged_last = 0; -int mazda_rt_torque_last = 0; -int mazda_desired_torque_last = 0; -uint32_t mazda_ts_last = 0; -struct sample_t mazda_torque_driver; // last few driver torques measured +// lkas enable speed 52kph, disable at 45kph +#define MAZDA_LKAS_ENABLE_SPEED 5200 +#define MAZDA_LKAS_DISABLE_SPEED 4500 + +const CanMsg MAZDA_TX_MSGS[] = {{MAZDA_LKAS, 0, 8}, {MAZDA_CRZ_BTNS, 0, 8}}; +bool mazda_lkas_allowed = false; + +AddrCheckStruct mazda_rx_checks[] = { + {.msg = {{MAZDA_CRZ_CTRL, 0, 8, .expected_timestep = 20000U}}}, + {.msg = {{MAZDA_CRZ_BTNS, 0, 8, .expected_timestep = 100000U}}}, + {.msg = {{MAZDA_STEER_TORQUE, 0, 8, .expected_timestep = 12000U}}}, + {.msg = {{MAZDA_ENGINE_DATA, 0, 8, .expected_timestep = 10000U}}}, + {.msg = {{MAZDA_PEDALS, 0, 8, .expected_timestep = 20000U}}}, +}; +const int MAZDA_RX_CHECKS_LEN = sizeof(mazda_rx_checks) / sizeof(mazda_rx_checks[0]); // track msgs coming from OP so that we know what CAM msgs to drop and what to forward static int mazda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - int bus = GET_BUS(to_push); - int addr = GET_ADDR(to_push); + bool valid; - if ((addr == MAZDA_STEER_TORQUE) && (bus == MAZDA_MAIN)) { - int torque_driver_new = GET_BYTE(to_push, 0) - 127; - // update array of samples - update_sample(&mazda_torque_driver, torque_driver_new); - } + valid = addr_safety_check(to_push, mazda_rx_checks, MAZDA_RX_CHECKS_LEN, + NULL, NULL, NULL); + if (valid) { + int bus = GET_BUS(to_push); + int addr = GET_ADDR(to_push); - // enter controls on rising edge of ACC, exit controls on ACC off - if ((addr == MAZDA_CRZ_CTRL) && (bus == MAZDA_MAIN)) { - int cruise_engaged = GET_BYTE(to_push, 0) & 8; - if (cruise_engaged != 0) { - if (!mazda_cruise_engaged_last) { - controls_allowed = 1; + if (bus == MAZDA_MAIN) { + + if (addr == MAZDA_ENGINE_DATA) { + // sample speed: scale by 0.01 to get kph + int speed = (GET_BYTE(to_push, 2) << 8) | GET_BYTE(to_push, 3); + + vehicle_moving = speed > 10; // moving when speed > 0.1 kph + + // Enable LKAS at 52kph going up, disable at 45kph going down + if (speed > MAZDA_LKAS_ENABLE_SPEED) { + mazda_lkas_allowed = true; + } else if (speed < MAZDA_LKAS_DISABLE_SPEED) { + mazda_lkas_allowed = false; + } else { + // Misra-able appeasment block! + } + } + + if (addr == MAZDA_STEER_TORQUE) { + int torque_driver_new = GET_BYTE(to_push, 0) - 127; + // update array of samples + update_sample(&torque_driver, torque_driver_new); + } + + // enter controls on rising edge of ACC, exit controls on ACC off + if (addr == MAZDA_CRZ_CTRL) { + bool cruise_engaged = GET_BYTE(to_push, 0) & 8; + if (cruise_engaged) { + if (!cruise_engaged_prev) { + // do not engage until we hit the speed at which lkas is on + if (mazda_lkas_allowed) { + controls_allowed = 1; + } else { + controls_allowed = 0; + cruise_engaged = false; + } + } + } else { + controls_allowed = 0; + } + cruise_engaged_prev = cruise_engaged; + } + + // Exit controls on rising edge of gas press + if (addr == MAZDA_ENGINE_DATA) { + bool gas_pressed = (GET_BYTE(to_push, 4) || (GET_BYTE(to_push, 5) & 0xF0)); + if (gas_pressed && !gas_pressed_prev && !(unsafe_mode & UNSAFE_DISABLE_DISENGAGE_ON_GAS)) { + controls_allowed = 0; + } + gas_pressed_prev = gas_pressed; + } + + // Exit controls on rising edge of brake press + if (addr == MAZDA_PEDALS) { + bool brake_pressed = (GET_BYTE(to_push, 0) & 0x10); + if (brake_pressed && (!brake_pressed_prev || vehicle_moving)) { + controls_allowed = 0; + } + brake_pressed_prev = brake_pressed; + } + + // if we see lkas msg on MAZDA_MAIN bus then relay is closed + if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (addr == MAZDA_LKAS)) { + relay_malfunction_set(); } } - else { - controls_allowed = 0; - } - mazda_cruise_engaged_last = cruise_engaged; } - - // if we see wheel speed msgs on MAZDA_CAM bus then relay is closed - if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == MAZDA_CAM) && (addr == MAZDA_WHEEL_SPEED)) { - relay_malfunction_set(); - } - return 1; + return valid; } static int mazda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { @@ -65,12 +124,17 @@ static int mazda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int addr = GET_ADDR(to_send); int bus = GET_BUS(to_send); + if (!msg_allowed(to_send, MAZDA_TX_MSGS, sizeof(MAZDA_TX_MSGS)/sizeof(MAZDA_TX_MSGS[0]))) { + tx = 0; + } + if (relay_malfunction) { tx = 0; } // Check if msg is sent on the main BUS if (bus == MAZDA_MAIN) { + // steer cmd checks if (addr == MAZDA_LKAS) { int desired_torque = (((GET_BYTE(to_send, 0) & 0x0f) << 8) | GET_BYTE(to_send, 1)) - MAZDA_MAX_STEER; @@ -83,20 +147,21 @@ static int mazda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { violation |= max_limit_check(desired_torque, MAZDA_MAX_STEER, -MAZDA_MAX_STEER); // *** torque rate limit check *** - violation |= driver_limit_check(desired_torque, mazda_desired_torque_last, &mazda_torque_driver, + violation |= driver_limit_check(desired_torque, desired_torque_last, &torque_driver, MAZDA_MAX_STEER, MAZDA_MAX_RATE_UP, MAZDA_MAX_RATE_DOWN, MAZDA_DRIVER_TORQUE_ALLOWANCE, MAZDA_DRIVER_TORQUE_FACTOR); + // used next time - mazda_desired_torque_last = desired_torque; + desired_torque_last = desired_torque; // *** torque real time rate limit check *** - violation |= rt_rate_limit_check(desired_torque, mazda_rt_torque_last, MAZDA_MAX_RT_DELTA); + violation |= rt_rate_limit_check(desired_torque, rt_torque_last, MAZDA_MAX_RT_DELTA); // every RT_INTERVAL set the new limits - uint32_t ts_elapsed = get_ts_elapsed(ts, mazda_ts_last); + uint32_t ts_elapsed = get_ts_elapsed(ts, ts_last); if (ts_elapsed > ((uint32_t) MAZDA_RT_INTERVAL)) { - mazda_rt_torque_last = desired_torque; - mazda_ts_last = ts; + rt_torque_last = desired_torque; + ts_last = ts; } } @@ -107,9 +172,9 @@ static int mazda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { // reset to 0 if either controls is not allowed or there's a violation if (violation || !controls_allowed) { - mazda_desired_torque_last = 0; - mazda_rt_torque_last = 0; - mazda_ts_last = ts; + desired_torque_last = 0; + rt_torque_last = 0; + ts_last = ts; } if (violation) { @@ -126,24 +191,30 @@ static int mazda_fwd_hook(int bus, CAN_FIFOMailBox_TypeDef *to_fwd) { int addr = GET_ADDR(to_fwd); if (bus == MAZDA_MAIN) { bus_fwd = MAZDA_CAM; - } - else if (bus == MAZDA_CAM) { + } else if (bus == MAZDA_CAM) { if (!(addr == MAZDA_LKAS)) { bus_fwd = MAZDA_MAIN; } - } - else { + } else { bus_fwd = -1; } } return bus_fwd; } +static void mazda_init(int16_t param) { + UNUSED(param); + controls_allowed = false; + relay_malfunction_reset(); + mazda_lkas_allowed = false; +} + const safety_hooks mazda_hooks = { - .init = nooutput_init, + .init = mazda_init, .rx = mazda_rx_hook, .tx = mazda_tx_hook, .tx_lin = nooutput_tx_lin_hook, .fwd = mazda_fwd_hook, - // TODO: add addr safety checks + .addr_check = mazda_rx_checks, + .addr_check_len = sizeof(mazda_rx_checks) / sizeof(mazda_rx_checks[0]), }; diff --git a/board/safety/safety_nissan.h b/board/safety/safety_nissan.h index aca99d19..6579e1c4 100644 --- a/board/safety/safety_nissan.h +++ b/board/safety/safety_nissan.h @@ -11,24 +11,19 @@ const struct lookup_t NISSAN_LOOKUP_ANGLE_RATE_DOWN = { const int NISSAN_DEG_TO_CAN = 100; -const AddrBus NISSAN_TX_MSGS[] = {{0x169, 0}, {0x2b1, 0}, {0x4cc, 0}, {0x20b, 2}, {0x280, 2}}; +const CanMsg NISSAN_TX_MSGS[] = {{0x169, 0, 8}, {0x2b1, 0, 8}, {0x4cc, 0, 8}, {0x20b, 2, 6}, {0x280, 2, 8}}; AddrCheckStruct nissan_rx_checks[] = { - {.addr = {0x2}, .bus = 0, .expected_timestep = 10000U}, // STEER_ANGLE_SENSOR (100Hz) - {.addr = {0x285}, .bus = 0, .expected_timestep = 20000U}, // WHEEL_SPEEDS_REAR (50Hz) - {.addr = {0x30f}, .bus = 2, .expected_timestep = 100000U}, // CRUISE_STATE (10Hz) - {.addr = {0x15c, 0x239}, .bus = 0, .expected_timestep = 20000U}, // GAS_PEDAL (100Hz / 50Hz) - {.addr = {0x454, 0x1cc}, .bus = 0, .expected_timestep = 100000U}, // DOORS_LIGHTS (10Hz) / BRAKE (100Hz) + {.msg = {{0x2, 0, 5, .expected_timestep = 10000U}}}, // STEER_ANGLE_SENSOR (100Hz) + {.msg = {{0x285, 0, 8, .expected_timestep = 20000U}}}, // WHEEL_SPEEDS_REAR (50Hz) + {.msg = {{0x30f, 2, 3, .expected_timestep = 100000U}}}, // CRUISE_STATE (10Hz) + {.msg = {{0x15c, 0, 8, .expected_timestep = 20000U}, + {0x239, 0, 8, .expected_timestep = 20000U}}}, // GAS_PEDAL (100Hz / 50Hz) + {.msg = {{0x454, 0, 8, .expected_timestep = 100000U}, + {0x1cc, 0, 4, .expected_timestep = 10000U}}}, // DOORS_LIGHTS (10Hz) / BRAKE (100Hz) }; const int NISSAN_RX_CHECK_LEN = sizeof(nissan_rx_checks) / sizeof(nissan_rx_checks[0]); -float nissan_speed = 0; -//int nissan_controls_allowed_last = 0; -uint32_t nissan_ts_angle_last = 0; -int nissan_desired_angle_last = 0; - -struct sample_t nissan_angle_meas; // last 3 steer angles - static int nissan_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { @@ -50,14 +45,14 @@ static int nissan_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { angle_meas_new = to_signed(angle_meas_new, 16) * 10; // update array of samples - update_sample(&nissan_angle_meas, angle_meas_new); + update_sample(&angle_meas, angle_meas_new); } if (addr == 0x285) { // Get current speed // Factor 0.005 - nissan_speed = ((GET_BYTE(to_push, 2) << 8) | (GET_BYTE(to_push, 3))) * 0.005 / 3.6; - vehicle_moving = nissan_speed > 0.; + vehicle_speed = ((GET_BYTE(to_push, 2) << 8) | (GET_BYTE(to_push, 3))) * 0.005 / 3.6; + vehicle_moving = vehicle_speed > 0.; } // exit controls on rising edge of gas press @@ -119,10 +114,9 @@ static int nissan_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { static int nissan_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int tx = 1; int addr = GET_ADDR(to_send); - int bus = GET_BUS(to_send); bool violation = 0; - if (!msg_allowed(addr, bus, NISSAN_TX_MSGS, sizeof(NISSAN_TX_MSGS) / sizeof(NISSAN_TX_MSGS[0]))) { + if (!msg_allowed(to_send, NISSAN_TX_MSGS, sizeof(NISSAN_TX_MSGS) / sizeof(NISSAN_TX_MSGS[0]))) { tx = 0; } @@ -141,24 +135,22 @@ static int nissan_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { if (controls_allowed && lka_active) { // add 1 to not false trigger the violation float delta_angle_float; - delta_angle_float = (interpolate(NISSAN_LOOKUP_ANGLE_RATE_UP, nissan_speed) * NISSAN_DEG_TO_CAN) + 1.; + delta_angle_float = (interpolate(NISSAN_LOOKUP_ANGLE_RATE_UP, vehicle_speed) * NISSAN_DEG_TO_CAN) + 1.; int delta_angle_up = (int)(delta_angle_float); - delta_angle_float = (interpolate(NISSAN_LOOKUP_ANGLE_RATE_DOWN, nissan_speed) * NISSAN_DEG_TO_CAN) + 1.; + delta_angle_float = (interpolate(NISSAN_LOOKUP_ANGLE_RATE_DOWN, vehicle_speed) * NISSAN_DEG_TO_CAN) + 1.; int delta_angle_down = (int)(delta_angle_float); - int highest_desired_angle = nissan_desired_angle_last + ((nissan_desired_angle_last > 0) ? delta_angle_up : delta_angle_down); - int lowest_desired_angle = nissan_desired_angle_last - ((nissan_desired_angle_last >= 0) ? delta_angle_down : delta_angle_up); + int highest_desired_angle = desired_angle_last + ((desired_angle_last > 0) ? delta_angle_up : delta_angle_down); + int lowest_desired_angle = desired_angle_last - ((desired_angle_last >= 0) ? delta_angle_down : delta_angle_up); // check for violation; violation |= max_limit_check(desired_angle, highest_desired_angle, lowest_desired_angle); - - //nissan_controls_allowed_last = controls_allowed; } - nissan_desired_angle_last = desired_angle; + desired_angle_last = desired_angle; // desired steer angle should be the same as steer angle measured when controls are off if ((!controls_allowed) && - ((desired_angle < (nissan_angle_meas.min - 1)) || - (desired_angle > (nissan_angle_meas.max + 1)))) { + ((desired_angle < (angle_meas.min - 1)) || + (desired_angle > (angle_meas.max + 1)))) { violation = 1; } diff --git a/board/safety/safety_subaru.h b/board/safety/safety_subaru.h index 17bd699d..6d913c7a 100644 --- a/board/safety/safety_subaru.h +++ b/board/safety/safety_subaru.h @@ -9,23 +9,23 @@ const int SUBARU_DRIVER_TORQUE_ALLOWANCE = 60; const int SUBARU_DRIVER_TORQUE_FACTOR = 10; const int SUBARU_STANDSTILL_THRSLD = 20; // about 1kph -const AddrBus SUBARU_TX_MSGS[] = {{0x122, 0}, {0x221, 0}, {0x322, 0}}; -const AddrBus SUBARU_L_TX_MSGS[] = {{0x164, 0}, {0x221, 0}, {0x322, 0}}; +const CanMsg SUBARU_TX_MSGS[] = {{0x122, 0, 8}, {0x221, 0, 8}, {0x322, 0, 8}}; +const CanMsg SUBARU_L_TX_MSGS[] = {{0x164, 0, 8}, {0x221, 0, 8}, {0x322, 0, 8}}; const int SUBARU_TX_MSGS_LEN = sizeof(SUBARU_TX_MSGS) / sizeof(SUBARU_TX_MSGS[0]); const int SUBARU_L_TX_MSGS_LEN = sizeof(SUBARU_L_TX_MSGS) / sizeof(SUBARU_L_TX_MSGS[0]); AddrCheckStruct subaru_rx_checks[] = { - {.addr = { 0x40}, .bus = 0, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}, - {.addr = {0x119}, .bus = 0, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}, - {.addr = {0x139}, .bus = 0, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}, - {.addr = {0x13a}, .bus = 0, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}, - {.addr = {0x240}, .bus = 0, .check_checksum = true, .max_counter = 15U, .expected_timestep = 50000U}, + {.msg = {{ 0x40, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}}}, + {.msg = {{0x119, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}}}, + {.msg = {{0x139, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}}}, + {.msg = {{0x13a, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}}}, + {.msg = {{0x240, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 50000U}}}, }; // TODO: do checksum and counter checks after adding the signals to the outback dbc file AddrCheckStruct subaru_l_rx_checks[] = { - {.addr = {0x140}, .bus = 0, .expected_timestep = 10000U}, - {.addr = {0x371}, .bus = 0, .expected_timestep = 20000U}, - {.addr = {0x144}, .bus = 0, .expected_timestep = 50000U}, + {.msg = {{0x140, 0, 8, .expected_timestep = 10000U}}}, + {.msg = {{0x371, 0, 8, .expected_timestep = 20000U}}}, + {.msg = {{0x144, 0, 8, .expected_timestep = 50000U}}}, }; const int SUBARU_RX_CHECK_LEN = sizeof(subaru_rx_checks) / sizeof(subaru_rx_checks[0]); const int SUBARU_L_RX_CHECK_LEN = sizeof(subaru_l_rx_checks) / sizeof(subaru_l_rx_checks[0]); @@ -131,10 +131,9 @@ static int subaru_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { static int subaru_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int tx = 1; int addr = GET_ADDR(to_send); - int bus = GET_BUS(to_send); - if ((!msg_allowed(addr, bus, SUBARU_TX_MSGS, SUBARU_TX_MSGS_LEN) && subaru_global) || - (!msg_allowed(addr, bus, SUBARU_L_TX_MSGS, SUBARU_L_TX_MSGS_LEN) && !subaru_global)) { + if ((!msg_allowed(to_send, SUBARU_TX_MSGS, SUBARU_TX_MSGS_LEN) && subaru_global) || + (!msg_allowed(to_send, SUBARU_L_TX_MSGS, SUBARU_L_TX_MSGS_LEN) && !subaru_global)) { tx = 0; } diff --git a/board/safety/safety_toyota.h b/board/safety/safety_toyota.h index f69e4d3c..4aef23ef 100644 --- a/board/safety/safety_toyota.h +++ b/board/safety/safety_toyota.h @@ -29,16 +29,17 @@ const int TOYOTA_STANDSTILL_THRSLD = 100; // 1kph const int TOYOTA_GAS_INTERCEPTOR_THRSLD = 845; #define TOYOTA_GET_INTERCEPTOR(msg) (((GET_BYTE((msg), 0) << 8) + GET_BYTE((msg), 1) + (GET_BYTE((msg), 2) << 8) + GET_BYTE((msg), 3)) / 2) // avg between 2 tracks -const AddrBus TOYOTA_TX_MSGS[] = {{0x283, 0}, {0x2E6, 0}, {0x2E7, 0}, {0x33E, 0}, {0x344, 0}, {0x365, 0}, {0x366, 0}, {0x4CB, 0}, // DSU bus 0 - {0x128, 1}, {0x141, 1}, {0x160, 1}, {0x161, 1}, {0x470, 1}, // DSU bus 1 - {0x2E4, 0}, {0x411, 0}, {0x412, 0}, {0x343, 0}, {0x1D2, 0}, // LKAS + ACC - {0x200, 0}, {0x750, 0}}; // interceptor + Blindspot monitor +const CanMsg TOYOTA_TX_MSGS[] = {{0x283, 0, 7}, {0x2E6, 0, 8}, {0x2E7, 0, 8}, {0x33E, 0, 7}, {0x344, 0, 8}, {0x365, 0, 7}, {0x366, 0, 7}, {0x4CB, 0, 8}, // DSU bus 0 + {0x128, 1, 6}, {0x141, 1, 4}, {0x160, 1, 8}, {0x161, 1, 7}, {0x470, 1, 4}, // DSU bus 1 + {0x2E4, 0, 5}, {0x411, 0, 8}, {0x412, 0, 8}, {0x343, 0, 8}, {0x1D2, 0, 8}, // LKAS + ACC + {0x200, 0, 6}, {0x750, 0, 8}}; // interceptor + Blindspot monitor AddrCheckStruct toyota_rx_checks[] = { - {.addr = { 0xaa}, .bus = 0, .check_checksum = false, .expected_timestep = 12000U}, - {.addr = {0x260}, .bus = 0, .check_checksum = true, .expected_timestep = 20000U}, - {.addr = {0x1D2}, .bus = 0, .check_checksum = true, .expected_timestep = 30000U}, - {.addr = {0x224, 0x226}, .bus = 0, .check_checksum = false, .expected_timestep = 25000U}, + {.msg = {{ 0xaa, 0, 8, .check_checksum = false, .expected_timestep = 12000U}}}, + {.msg = {{0x260, 0, 8, .check_checksum = true, .expected_timestep = 20000U}}}, + {.msg = {{0x1D2, 0, 8, .check_checksum = true, .expected_timestep = 30000U}}}, + {.msg = {{0x224, 0, 8, .check_checksum = false, .expected_timestep = 25000U}, + {0x226, 0, 8, .check_checksum = false, .expected_timestep = 25000U}}}, }; const int TOYOTA_RX_CHECKS_LEN = sizeof(toyota_rx_checks) / sizeof(toyota_rx_checks[0]); @@ -153,7 +154,7 @@ static int toyota_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int addr = GET_ADDR(to_send); int bus = GET_BUS(to_send); - if (!msg_allowed(addr, bus, TOYOTA_TX_MSGS, sizeof(TOYOTA_TX_MSGS)/sizeof(TOYOTA_TX_MSGS[0]))) { + if (!msg_allowed(to_send, TOYOTA_TX_MSGS, sizeof(TOYOTA_TX_MSGS)/sizeof(TOYOTA_TX_MSGS[0]))) { tx = 0; } diff --git a/board/safety/safety_volkswagen.h b/board/safety/safety_volkswagen.h index 4063fa7d..419fb1a8 100644 --- a/board/safety/safety_volkswagen.h +++ b/board/safety/safety_volkswagen.h @@ -18,15 +18,15 @@ const int VOLKSWAGEN_DRIVER_TORQUE_FACTOR = 3; #define MSG_LDW_02 0x397 // TX by OP, Lane line recognition and text alerts // Transmit of GRA_ACC_01 is allowed on bus 0 and 2 to keep compatibility with gateway and camera integration -const AddrBus VOLKSWAGEN_MQB_TX_MSGS[] = {{MSG_HCA_01, 0}, {MSG_GRA_ACC_01, 0}, {MSG_GRA_ACC_01, 2}, {MSG_LDW_02, 0}}; +const CanMsg VOLKSWAGEN_MQB_TX_MSGS[] = {{MSG_HCA_01, 0, 8}, {MSG_GRA_ACC_01, 0, 8}, {MSG_GRA_ACC_01, 2, 8}, {MSG_LDW_02, 0, 8}}; const int VOLKSWAGEN_MQB_TX_MSGS_LEN = sizeof(VOLKSWAGEN_MQB_TX_MSGS) / sizeof(VOLKSWAGEN_MQB_TX_MSGS[0]); AddrCheckStruct volkswagen_mqb_rx_checks[] = { - {.addr = {MSG_ESP_19}, .bus = 0, .check_checksum = false, .max_counter = 0U, .expected_timestep = 10000U}, - {.addr = {MSG_EPS_01}, .bus = 0, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}, - {.addr = {MSG_ESP_05}, .bus = 0, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}, - {.addr = {MSG_TSK_06}, .bus = 0, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}, - {.addr = {MSG_MOTOR_20}, .bus = 0, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}, + {.msg = {{MSG_ESP_19, 0, 8, .check_checksum = false, .max_counter = 0U, .expected_timestep = 10000U}}}, + {.msg = {{MSG_EPS_01, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}}}, + {.msg = {{MSG_ESP_05, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}}}, + {.msg = {{MSG_TSK_06, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}}}, + {.msg = {{MSG_MOTOR_20, 0, 8, .check_checksum = true, .max_counter = 15U, .expected_timestep = 20000U}}}, }; const int VOLKSWAGEN_MQB_RX_CHECKS_LEN = sizeof(volkswagen_mqb_rx_checks) / sizeof(volkswagen_mqb_rx_checks[0]); @@ -40,14 +40,14 @@ const int VOLKSWAGEN_MQB_RX_CHECKS_LEN = sizeof(volkswagen_mqb_rx_checks) / size #define MSG_LDW_1 0x5BE // TX by OP, Lane line recognition and text alerts // Transmit of GRA_Neu is allowed on bus 0 and 2 to keep compatibility with gateway and camera integration -const AddrBus VOLKSWAGEN_PQ_TX_MSGS[] = {{MSG_HCA_1, 0}, {MSG_GRA_NEU, 0}, {MSG_GRA_NEU, 2}, {MSG_LDW_1, 0}}; +const CanMsg VOLKSWAGEN_PQ_TX_MSGS[] = {{MSG_HCA_1, 0, 5}, {MSG_GRA_NEU, 0, 4}, {MSG_GRA_NEU, 2, 4}, {MSG_LDW_1, 0, 8}}; const int VOLKSWAGEN_PQ_TX_MSGS_LEN = sizeof(VOLKSWAGEN_PQ_TX_MSGS) / sizeof(VOLKSWAGEN_PQ_TX_MSGS[0]); AddrCheckStruct volkswagen_pq_rx_checks[] = { - {.addr = {MSG_LENKHILFE_3}, .bus = 0, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}, - {.addr = {MSG_MOTOR_2}, .bus = 0, .check_checksum = false, .max_counter = 0U, .expected_timestep = 20000U}, - {.addr = {MSG_MOTOR_3}, .bus = 0, .check_checksum = false, .max_counter = 0U, .expected_timestep = 10000U}, - {.addr = {MSG_BREMSE_3}, .bus = 0, .check_checksum = false, .max_counter = 0U, .expected_timestep = 10000U}, + {.msg = {{MSG_LENKHILFE_3, 0, 6, .check_checksum = true, .max_counter = 15U, .expected_timestep = 10000U}}}, + {.msg = {{MSG_MOTOR_2, 0, 8, .check_checksum = false, .max_counter = 0U, .expected_timestep = 20000U}}}, + {.msg = {{MSG_MOTOR_3, 0, 8, .check_checksum = false, .max_counter = 0U, .expected_timestep = 10000U}}}, + {.msg = {{MSG_BREMSE_3, 0, 8, .check_checksum = false, .max_counter = 0U, .expected_timestep = 10000U}}}, }; const int VOLKSWAGEN_PQ_RX_CHECKS_LEN = sizeof(volkswagen_pq_rx_checks) / sizeof(volkswagen_pq_rx_checks[0]); @@ -311,10 +311,9 @@ static bool volkswagen_steering_check(int desired_torque) { static int volkswagen_mqb_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int addr = GET_ADDR(to_send); - int bus = GET_BUS(to_send); int tx = 1; - if (!msg_allowed(addr, bus, VOLKSWAGEN_MQB_TX_MSGS, VOLKSWAGEN_MQB_TX_MSGS_LEN) || relay_malfunction) { + if (!msg_allowed(to_send, VOLKSWAGEN_MQB_TX_MSGS, VOLKSWAGEN_MQB_TX_MSGS_LEN) || relay_malfunction) { tx = 0; } @@ -348,10 +347,9 @@ static int volkswagen_mqb_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { static int volkswagen_pq_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int addr = GET_ADDR(to_send); - int bus = GET_BUS(to_send); int tx = 1; - if (!msg_allowed(addr, bus, VOLKSWAGEN_PQ_TX_MSGS, VOLKSWAGEN_PQ_TX_MSGS_LEN) || relay_malfunction) { + if (!msg_allowed(to_send, VOLKSWAGEN_PQ_TX_MSGS, VOLKSWAGEN_PQ_TX_MSGS_LEN) || relay_malfunction) { tx = 0; } diff --git a/board/safety_declarations.h b/board/safety_declarations.h index be8be93b..eeaf50b7 100644 --- a/board/safety_declarations.h +++ b/board/safety_declarations.h @@ -17,17 +17,25 @@ struct lookup_t { typedef struct { int addr; int bus; -} AddrBus; + int len; +} CanMsg; + +typedef struct { + const int addr; + const int bus; + const int len; + const bool check_checksum; // true is checksum check is performed + const uint8_t max_counter; // maximum value of the counter. 0 means that the counter check is skipped + const uint32_t expected_timestep; // expected time between message updates [us] +} CanMsgCheck; // params and flags about checksum, counter and frequency checks for each monitored address typedef struct { // const params - const int addr[3]; // check either messages (e.g. honda steer). Array MUST terminate with a zero to know its length. - const int bus; // bus where to expect the addr. Temp hack: -1 means skip the bus check - const bool check_checksum; // true is checksum check is performed - const uint8_t max_counter; // maximum value of the counter. 0 means that the counter check is skipped - const uint32_t expected_timestep; // expected time between message updates [us] + const CanMsgCheck msg[3]; // check either messages (e.g. honda steer). Array MUST terminate with an empty struct to know its length. // dynamic flags + bool msg_seen; + int index; // if multiple messages are allowed to be checked, this stores the index of the first one seen. only msg[msg_index] will be used bool valid_checksum; // true if and only if checksum check is passed int wrong_counters; // counter of wrong counters, saturated between 0 and MAX_WRONG_COUNTERS uint8_t last_counter; // last counter value @@ -50,7 +58,7 @@ bool driver_limit_check(int val, int val_last, struct sample_t *val_driver, bool rt_rate_limit_check(int val, int val_last, const int MAX_RT_DELTA); float interpolate(struct lookup_t xy, float x); void gen_crc_lookup_table(uint8_t poly, uint8_t crc_lut[]); -bool msg_allowed(int addr, int bus, const AddrBus addr_list[], int len); +bool msg_allowed(CAN_FIFOMailBox_TypeDef *to_send, const CanMsg msg_list[], int len); int get_addr_check_index(CAN_FIFOMailBox_TypeDef *to_push, AddrCheckStruct addr_list[], const int len); void update_counter(AddrCheckStruct addr_list[], int index, uint8_t counter); void update_addr_timestamp(AddrCheckStruct addr_list[], int index); @@ -90,15 +98,21 @@ int gas_interceptor_prev = 0; bool gas_pressed_prev = false; bool brake_pressed_prev = false; bool cruise_engaged_prev = false; +float vehicle_speed = 0; bool vehicle_moving = false; -// for torque-based safety modes +// for safety modes with torque steering control int desired_torque_last = 0; // last desired steer torque int rt_torque_last = 0; // last desired torque for real time check struct sample_t torque_meas; // last 3 motor torques produced by the eps struct sample_t torque_driver; // last 3 driver torques measured uint32_t ts_last = 0; +// for safety modes with angle steering control +uint32_t ts_angle_last = 0; +int desired_angle_last = 0; +struct sample_t angle_meas; // last 3 steer angles + // This can be set with a USB command // It enables features we consider to be unsafe, but understand others may have different opinions // It is always 0 on mainline comma.ai openpilot diff --git a/python/__init__.py b/python/__init__.py index e8525a17..2f70c871 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -10,12 +10,13 @@ import time import traceback import subprocess import sys -from .dfu import PandaDFU -from .esptool import ESPROM, CesantaFlasher # noqa: F401 -from .flash_release import flash_release # noqa: F401 -from .update import ensure_st_up_to_date # noqa: F401 -from .serial import PandaSerial # noqa: F401 -from .isotp import isotp_send, isotp_recv +from .dfu import PandaDFU # pylint: disable=import-error +from .esptool import ESPROM, CesantaFlasher # noqa pylint: disable=import-error +from .flash_release import flash_release # noqa pylint: disable=import-error +from .update import ensure_st_up_to_date # noqa pylint: disable=import-error +from .serial import PandaSerial # noqa pylint: disable=import-error +from .isotp import isotp_send, isotp_recv # pylint: disable=import-error + __version__ = '0.0.9' diff --git a/python/uds.py b/python/uds.py index 548f1bcc..946afb79 100644 --- a/python/uds.py +++ b/python/uds.py @@ -2,7 +2,7 @@ import time import struct from collections import deque -from typing import Callable, NamedTuple, Tuple, List +from typing import Callable, NamedTuple, Tuple, List, Deque, Generator, Optional, cast from enum import IntEnum class SERVICE_TYPE(IntEnum): @@ -271,12 +271,12 @@ _negative_response_codes = { class CanClient(): - def __init__(self, can_send: Callable[[Tuple[int, bytes, int]], None], can_recv: Callable[[], List[Tuple[int, int, bytes, int]]], tx_addr: int, rx_addr: int, bus: int, sub_addr: int=None, debug: bool=False): + def __init__(self, can_send: Callable[[int, bytes, int], None], can_recv: Callable[[], List[Tuple[int, int, bytes, int]]], tx_addr: int, rx_addr: int, bus: int, sub_addr: int=None, debug: bool=False): self.tx = can_send self.rx = can_recv self.tx_addr = tx_addr self.rx_addr = rx_addr - self.rx_buff = deque() + self.rx_buff = deque() # type: Deque[bytes] self.sub_addr = sub_addr self.bus = bus self.debug = debug @@ -320,7 +320,7 @@ class CanClient(): if len(msgs) < 254: return - def recv(self, drain: bool=False) -> List[bytes]: + def recv(self, drain: bool=False) -> Generator[bytes, None, None]: # buffer rx messages in case two response messages are received at once # (e.g. response pending and success/failure response) self._recv_buffer(drain) @@ -372,7 +372,7 @@ class IsoTpMessage(): self._tx_first_frame() def _tx_first_frame(self) -> None: - if self.tx_len < 8: + if self.tx_len < self.max_len: # single frame (send all bytes) if self.debug: print("ISO-TP: TX - single frame") msg = (bytes([self.tx_len]) + self.tx_dat).ljust(self.max_len, b"\x00") @@ -380,10 +380,10 @@ class IsoTpMessage(): else: # first frame (send first 6 bytes) if self.debug: print("ISO-TP: TX - first frame") - msg = (struct.pack("!H", 0x1000 | self.tx_len) + self.tx_dat[:6]).ljust(self.max_len, b"\x00") + msg = (struct.pack("!H", 0x1000 | self.tx_len) + self.tx_dat[:self.max_len - 2]).ljust(self.max_len - 2, b"\x00") self._can_client.send([msg]) - def recv(self) -> bytes: + def recv(self) -> Optional[bytes]: start_time = time.time() try: while True: @@ -416,7 +416,7 @@ class IsoTpMessage(): self.rx_idx = 0 self.rx_done = False if self.debug: print(f"ISO-TP: RX - first frame - idx={self.rx_idx} done={self.rx_done}") - if self.debug: print(f"ISO-TP: TX - flow control continue") + if self.debug: print("ISO-TP: TX - flow control continue") # send flow control message (send all bytes) msg = b"\x30\x00\x00".ljust(self.max_len, b"\x00") self._can_client.send([msg]) @@ -505,6 +505,10 @@ class UdsClient(): isotp_msg.send(req) while True: resp = isotp_msg.recv() + + if resp is None: + continue + resp_sid = resp[0] if len(resp) > 0 else None # negative response @@ -518,7 +522,7 @@ class UdsClient(): try: error_desc = _negative_response_codes[error_code] except BaseException: - error_desc = resp[3:] + error_desc = resp[3:].hex() # wait for another message if response pending if error_code == 0x78: if self.debug: print("UDS-RX: response pending") @@ -534,7 +538,7 @@ class UdsClient(): resp_sfn = resp[1] if len(resp) > 1 else None if subfunction != resp_sfn: resp_sfn_hex = hex(resp_sfn) if resp_sfn is not None else None - raise InvalidSubFunctioneError('invalid response subfunction: {}'.format(hex(resp_sfn_hex))) + raise InvalidSubFunctioneError(f'invalid response subfunction: {resp_sfn_hex:x}') # return data (exclude service id and sub-function id) return resp[(1 if subfunction is None else 2):] @@ -595,7 +599,7 @@ class UdsClient(): def response_on_event(self, response_event_type: RESPONSE_EVENT_TYPE, store_event: bool, window_time: int, event_type_record: int, service_response_record: int): if store_event: - response_event_type |= 0x20 + response_event_type |= 0x20 # type: ignore # TODO: split record parameters into arrays data = bytes([window_time, event_type_record, service_response_record]) resp = self._uds_request(SERVICE_TYPE.RESPONSE_ON_EVENT, subfunction=response_event_type, data=data) @@ -613,9 +617,11 @@ class UdsClient(): } def link_control(self, link_control_type: LINK_CONTROL_TYPE, baud_rate_type: BAUD_RATE_TYPE=None): + data : Optional[bytes] + if link_control_type == LINK_CONTROL_TYPE.VERIFY_BAUDRATE_TRANSITION_WITH_FIXED_BAUDRATE: # baud_rate_type = BAUD_RATE_TYPE - data = bytes([baud_rate_type]) + data = bytes([cast(int, baud_rate_type)]) elif link_control_type == LINK_CONTROL_TYPE.VERIFY_BAUDRATE_TRANSITION_WITH_SPECIFIC_BAUDRATE: # baud_rate_type = custom value (3 bytes big-endian) data = struct.pack('!I', baud_rate_type)[1:] @@ -671,16 +677,16 @@ class UdsClient(): data = struct.pack('!H', dynamic_data_identifier) if dynamic_definition_type == DYNAMIC_DEFINITION_TYPE.DEFINE_BY_IDENTIFIER: for s in source_definitions: - data += struct.pack('!H', s["data_identifier"]) + bytes([s["position"], s["memory_size"]]) + data += struct.pack('!H', s.data_identifier) + bytes([s.position, s.memory_size]) elif dynamic_definition_type == DYNAMIC_DEFINITION_TYPE.DEFINE_BY_MEMORY_ADDRESS: data += bytes([memory_size_bytes<<4 | memory_address_bytes]) for s in source_definitions: - if s["memory_address"] >= 1<<(memory_address_bytes*8): - raise ValueError('invalid memory_address: {}'.format(s["memory_address"])) - data += struct.pack('!I', s["memory_address"])[4-memory_address_bytes:] - if s["memory_size"] >= 1<<(memory_size_bytes*8): - raise ValueError('invalid memory_size: {}'.format(s["memory_size"])) - data += struct.pack('!I', s["memory_size"])[4-memory_size_bytes:] + if s.memory_address >= 1<<(memory_address_bytes*8): + raise ValueError('invalid memory_address: {}'.format(s.memory_address)) + data += struct.pack('!I', s.memory_address)[4-memory_address_bytes:] + if s.memory_size >= 1<<(memory_size_bytes*8): + raise ValueError('invalid memory_size: {}'.format(s.memory_size)) + data += struct.pack('!I', s.memory_size)[4-memory_size_bytes:] elif dynamic_definition_type == DYNAMIC_DEFINITION_TYPE.CLEAR_DYNAMICALLY_DEFINED_DATA_IDENTIFIER: pass else: @@ -736,7 +742,7 @@ class UdsClient(): if dtc_report_type == DTC_REPORT_TYPE.DTC_SNAPSHOT_IDENTIFICATION or \ dtc_report_type == DTC_REPORT_TYPE.DTC_SNAPSHOT_RECORD_BY_DTC_NUMBER or \ dtc_report_type == DTC_REPORT_TYPE.DTC_SNAPSHOT_RECORD_BY_RECORD_NUMBER: - data += ord(dtc_snapshot_record_num) + data += bytes([dtc_snapshot_record_num]) # dtc_extended_record_num if dtc_report_type == DTC_REPORT_TYPE.DTC_EXTENDED_DATA_RECORD_BY_DTC_NUMBER or \ dtc_report_type == DTC_REPORT_TYPE.MIRROR_MEMORY_DTC_EXTENDED_DATA_RECORD_BY_DTC_NUMBER: @@ -784,7 +790,7 @@ class UdsClient(): data += struct.pack('!I', memory_size)[4-memory_size_bytes:] resp = self._uds_request(SERVICE_TYPE.REQUEST_DOWNLOAD, subfunction=None, data=data) - max_num_bytes_len = resp[0] >> 4 if len(resp) > 0 else None + max_num_bytes_len = resp[0] >> 4 if len(resp) > 0 else 0 if max_num_bytes_len >= 1 and max_num_bytes_len <= 4: max_num_bytes = struct.unpack('!I', (b"\x00"*(4-max_num_bytes_len))+resp[1:max_num_bytes_len+1])[0] else: @@ -809,7 +815,7 @@ class UdsClient(): data += struct.pack('!I', memory_size)[4-memory_size_bytes:] resp = self._uds_request(SERVICE_TYPE.REQUEST_UPLOAD, subfunction=None, data=data) - max_num_bytes_len = resp[0] >> 4 if len(resp) > 0 else None + max_num_bytes_len = resp[0] >> 4 if len(resp) > 0 else 0 if max_num_bytes_len >= 1 and max_num_bytes_len <= 4: max_num_bytes = struct.unpack('!I', (b"\x00"*(4-max_num_bytes_len))+resp[1:max_num_bytes_len+1])[0] else: diff --git a/requirements.txt b/requirements.txt index fb01edce..2f479710 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,6 +7,7 @@ nose parameterized requests flake8==3.7.9 -pylint==2.4.3 cffi==1.11.4 crcmod +pre-commit==2.4.0 +pylint==2.5.2 diff --git a/tests/all_wifi_test.py b/tests/all_wifi_test.py index 85dc173b..b1ca79cc 100755 --- a/tests/all_wifi_test.py +++ b/tests/all_wifi_test.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 import requests import json -from .automated.helpers import _connect_wifi +from .automated.helpers import _connect_wifi # pylint: disable=import-error from panda import Panda from nose.tools import assert_equal @@ -25,5 +25,3 @@ if __name__ == "__main__": assert_equal(str(dongle_id), wifi_dongle_id) assert_equal(latest_version, st_version) assert_equal(latest_version, esp_version) - - diff --git a/tests/automated/2_health.py b/tests/automated/2_health.py index da5eaec9..23af65d5 100644 --- a/tests/automated/2_health.py +++ b/tests/automated/2_health.py @@ -32,6 +32,7 @@ def test_orientation_detection(p): reset_pandas() p.reconnect() detected_harness_orientation = p.health()['car_harness_status'] + print(f"Detected orientation: {detected_harness_orientation}") if (i == 0 and detected_harness_orientation != 0) or detected_harness_orientation in seen_orientations: assert False seen_orientations.append(detected_harness_orientation) diff --git a/tests/automated/8_gps.py b/tests/automated/8_gps.py index fc387c99..76fdb238 100644 --- a/tests/automated/8_gps.py +++ b/tests/automated/8_gps.py @@ -14,7 +14,7 @@ def test_gps_version(p): for i in range(2): # Reset GPS p.set_esp_power(0) - time.sleep(0.5) + time.sleep(2) p.set_esp_power(1) time.sleep(1) diff --git a/tests/automated/helpers.py b/tests/automated/helpers.py index 6b963e95..a5e15060 100644 --- a/tests/automated/helpers.py +++ b/tests/automated/helpers.py @@ -13,7 +13,7 @@ from .wifi_helpers import _connect_wifi SPEED_NORMAL = 500 SPEED_GMLAN = 33.3 BUS_SPEEDS = [(0, SPEED_NORMAL), (1, SPEED_NORMAL), (2, SPEED_NORMAL), (3, SPEED_GMLAN)] -TIMEOUT = 30 +TIMEOUT = 45 GEN2_HW_TYPES = [Panda.HW_TYPE_BLACK_PANDA, Panda.HW_TYPE_UNO] GPS_HW_TYPES = [Panda.HW_TYPE_GREY_PANDA, Panda.HW_TYPE_BLACK_PANDA, Panda.HW_TYPE_UNO] @@ -41,16 +41,17 @@ init_panda_serials() test_all_types = parameterized([ param(panda_type=Panda.HW_TYPE_WHITE_PANDA), param(panda_type=Panda.HW_TYPE_GREY_PANDA), - param(panda_type=Panda.HW_TYPE_BLACK_PANDA) + param(panda_type=Panda.HW_TYPE_BLACK_PANDA), + param(panda_type=Panda.HW_TYPE_UNO) ]) test_all_pandas = parameterized( - list(map(lambda x: x[0], _panda_serials)) + list(map(lambda x: x[0], _panda_serials)) # type: ignore ) test_all_gen2_pandas = parameterized( - list(map(lambda x: x[0], filter(lambda x: x[1] in GEN2_HW_TYPES, _panda_serials))) + list(map(lambda x: x[0], filter(lambda x: x[1] in GEN2_HW_TYPES, _panda_serials))) # type: ignore ) test_all_gps_pandas = parameterized( - list(map(lambda x: x[0], filter(lambda x: x[1] in GPS_HW_TYPES, _panda_serials))) + list(map(lambda x: x[0], filter(lambda x: x[1] in GPS_HW_TYPES, _panda_serials))) # type: ignore ) test_white_and_grey = parameterized([ param(panda_type=Panda.HW_TYPE_WHITE_PANDA), @@ -65,6 +66,9 @@ test_grey = parameterized([ test_black = parameterized([ param(panda_type=Panda.HW_TYPE_BLACK_PANDA) ]) +test_uno = parameterized([ + param(panda_type=Panda.HW_TYPE_UNO) + ]) def connect_wifi(serial=None): p = Panda(serial=serial) @@ -112,7 +116,7 @@ def time_many_sends(p, bus, p_recv=None, msg_count=100, msg_id=None, two_pandas= def reset_pandas(): panda_jungle.set_panda_power(False) - time.sleep(2) + time.sleep(3) panda_jungle.set_panda_power(True) time.sleep(5) @@ -198,7 +202,7 @@ def panda_connect_and_init(fn): finally: # Close all connections for panda in pandas: - panda.close() + panda.close() return wrapper def clear_can_buffers(panda): diff --git a/tests/build/Dockerfile b/tests/build/Dockerfile.panda_esp similarity index 73% rename from tests/build/Dockerfile rename to tests/build/Dockerfile.panda_esp index 0f982160..63c2cae3 100644 --- a/tests/build/Dockerfile +++ b/tests/build/Dockerfile.panda_esp @@ -1,21 +1,13 @@ FROM ubuntu:16.04 -RUN apt-get update && apt-get install -y gcc-arm-none-eabi libnewlib-arm-none-eabi python python-pip gcc g++ git autoconf gperf bison flex automake texinfo wget help2man gawk libtool libtool-bin ncurses-dev unzip unrar-free libexpat-dev sed bzip2 locales curl zlib1g-dev libffi-dev libssl-dev +RUN apt-get update && apt-get install -y gcc-arm-none-eabi libnewlib-arm-none-eabi python python-pip gcc g++ git autoconf gperf bison flex automake texinfo wget help2man gawk libtool libtool-bin ncurses-dev unzip unrar-free libexpat-dev sed bzip2 locales curl zlib1g-dev libffi-dev libssl-dev python3 python3-pip RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 -RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash - -ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}" -RUN pyenv install 2.7.12 -RUN pyenv install 3.7.3 -RUN pyenv global 3.7.3 -RUN pyenv rehash - -RUN pip install pycrypto==2.6.1 +RUN pip3 install pycrypto==2.6.1 # Build esp toolchain RUN mkdir -p /panda/boardesp diff --git a/tests/bulk_write_test.py b/tests/bulk_write_test.py index 43a52bce..a99ab28b 100755 --- a/tests/bulk_write_test.py +++ b/tests/bulk_write_test.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 -import time import threading +import time +from typing import Any, List from panda import Panda @@ -18,18 +19,18 @@ if __name__ == "__main__": serials = Panda.list() if len(serials) != 2: raise Exception("Connect two pandas to perform this test!") - + sender = Panda(serials[0]) receiver = Panda(serials[1]) - + sender.set_safety_mode(Panda.SAFETY_ALLOUTPUT) receiver.set_safety_mode(Panda.SAFETY_ALLOUTPUT) - + # Start transmisson threading.Thread(target=flood_tx, args=(sender,)).start() # Receive as much as we can in a few second time period - rx = [] + rx: List[Any] = [] old_len = 0 start_time = time.time() while time.time() - start_time < 2 or len(rx) > old_len: diff --git a/tests/debug_console.py b/tests/debug_console.py index 7b354b14..cf43b393 100755 --- a/tests/debug_console.py +++ b/tests/debug_console.py @@ -28,7 +28,7 @@ if __name__ == "__main__": if os.getenv("BAUD") is not None: for panda in pandas: - panda.set_uart_baud(port_number, int(os.getenv("BAUD"))) + panda.set_uart_baud(port_number, int(os.getenv("BAUD"))) # type: ignore while True: for i, panda in enumerate(pandas): diff --git a/tests/elm_car_simulator.py b/tests/elm_car_simulator.py index 01b79c88..c44def04 100755 --- a/tests/elm_car_simulator.py +++ b/tests/elm_car_simulator.py @@ -299,10 +299,10 @@ class ELMCarSimulator(): if __name__ == "__main__": serial = os.getenv("SERIAL") if os.getenv("SERIAL") else None - kbaud = int(os.getenv("CANKBAUD")) if os.getenv("CANKBAUD") else 500 - bitwidth = int(os.getenv("CANBITWIDTH")) if os.getenv("CANBITWIDTH") else 0 - canenable = bool(int(os.getenv("CANENABLE"))) if os.getenv("CANENABLE") else True - linenable = bool(int(os.getenv("LINENABLE"))) if os.getenv("LINENABLE") else True + kbaud = int(os.getenv("CANKBAUD")) if os.getenv("CANKBAUD") else 500 # type: ignore + bitwidth = int(os.getenv("CANBITWIDTH")) if os.getenv("CANBITWIDTH") else 0 # type: ignore + canenable = bool(int(os.getenv("CANENABLE"))) if os.getenv("CANENABLE") else True # type: ignore + linenable = bool(int(os.getenv("LINENABLE"))) if os.getenv("LINENABLE") else True # type: ignore sim = ELMCarSimulator(serial, can_kbaud=kbaud, can=canenable, lin=linenable) if(bitwidth == 0): sim.can_mode_11b_29b() diff --git a/tests/language/Dockerfile b/tests/language/Dockerfile deleted file mode 100644 index 6a1d8bb7..00000000 --- a/tests/language/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM ubuntu:16.04 - -RUN apt-get update && apt-get install -y make python python-pip locales curl git zlib1g-dev libffi-dev bzip2 libssl-dev - -RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 - -RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash - -ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}" -RUN pyenv install 3.7.3 -RUN pyenv global 3.7.3 -RUN pyenv rehash - -COPY . /panda diff --git a/tests/language/LICENSE b/tests/language/LICENSE deleted file mode 100644 index 8dada3ed..00000000 --- a/tests/language/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tests/language/list.txt b/tests/language/list.txt deleted file mode 100644 index cfd25897..00000000 --- a/tests/language/list.txt +++ /dev/null @@ -1,451 +0,0 @@ -4r5e -5h1t -5hit -a55 -anal -anus -ar5e -arrse -arse -ass -ass-fucker -asses -assfucker -assfukka -asshole -assholes -asswhole -a_s_s -b!tch -b00bs -b17ch -b1tch -ballbag -balls -ballsack -bastard -beastial -beastiality -bellend -bestial -bestiality -bi+ch -biatch -bitch -bitcher -bitchers -bitches -bitchin -bitching -bloody -blow job -blowjob -blowjobs -boiolas -bollock -bollok -boner -boob -boobs -booobs -boooobs -booooobs -booooooobs -breasts -buceta -bugger -bum -bunny fucker -bullshit -butt -butthole -buttmuch -buttplug -c0ck -c0cksucker -carpet muncher -cawk -chink -cipa -cl1t -clit -clitoris -clits -cnut -cock -cock-sucker -cockface -cockhead -cockmunch -cockmuncher -cocks -cocksuck -cocksucked -cocksucker -cocksucking -cocksucks -cocksuka -cocksukka -cok -cokmuncher -coksucka -coon -cox -crap -cum -cummer -cumming -cums -cumshot -cunilingus -cunillingus -cunnilingus -cunt -cuntlick -cuntlicker -cuntlicking -cunts -cyalis -cyberfuc -cyberfuck -cyberfucked -cyberfucker -cyberfuckers -cyberfucking -d1ck -damn -dick -dickhead -dildo -dildos -dink -dinks -dirsa -dlck -dog-fucker -doggin -dogging -donkeyribber -doosh -duche -dyke -ejaculate -ejaculated -ejaculates -ejaculating -ejaculatings -ejaculation -ejakulate -f u c k -f u c k e r -f4nny -fag -fagging -faggitt -faggot -faggs -fagot -fagots -fags -fanny -fannyflaps -fannyfucker -fanyy -fatass -fcuk -fcuker -fcuking -feck -fecker -felching -fellate -fellatio -fingerfuck -fingerfucked -fingerfucker -fingerfuckers -fingerfucking -fingerfucks -fistfuck -fistfucked -fistfucker -fistfuckers -fistfucking -fistfuckings -fistfucks -flange -fook -fooker -fuck -fucka -fucked -fucker -fuckers -fuckhead -fuckheads -fuckin -fucking -fuckings -fuckingshitmotherfucker -fuckme -fucks -fuckwhit -fuckwit -fudge packer -fudgepacker -fuk -fuker -fukker -fukkin -fuks -fukwhit -fukwit -fux -fux0r -f_u_c_k -gangbang -gangbanged -gangbangs -gaylord -gaysex -goatse -God -god-dam -god-damned -goddamn -goddamned -hardcoresex -hell -heshe -hoar -hoare -hoer -homo -hore -horniest -horny -hotsex -jack-off -jackoff -jap -jerk-off -jism -jiz -jizm -jizz -kawk -knob -knobead -knobed -knobend -knobhead -knobjocky -knobjokey -kock -kondum -kondums -kum -kummer -kumming -kums -kunilingus -l3i+ch -l3itch -labia -lmfao -lust -lusting -m0f0 -m0fo -m45terbate -ma5terb8 -ma5terbate -masochist -master-bate -masterb8 -masterbat* -masterbat3 -masterbate -masterbation -masterbations -masturbate -mo-fo -mof0 -mofo -mothafuck -mothafucka -mothafuckas -mothafuckaz -mothafucked -mothafucker -mothafuckers -mothafuckin -mothafucking -mothafuckings -mothafucks -mother fucker -motherfuck -motherfucked -motherfucker -motherfuckers -motherfuckin -motherfucking -motherfuckings -motherfuckka -motherfucks -muff -mutha -muthafecker -muthafuckker -muther -mutherfucker -n1gga -n1gger -nazi -nigg3r -nigg4h -nigga -niggah -niggas -niggaz -nigger -niggers -nob -nob jokey -nobhead -nobjocky -nobjokey -numbnuts -nutsack -orgasim -orgasims -orgasm -orgasms -p0rn -pawn -pecker -penis -penisfucker -phonesex -phuck -phuk -phuked -phuking -phukked -phukking -phuks -phuq -pigfucker -pimpis -piss -pissed -pisser -pissers -pisses -pissflaps -pissin -pissing -pissoff -poop -porn -porno -pornography -pornos -prick -pricks -pron -pube -pusse -pussi -pussies -pussy -pussys -rectum -retard -rimjaw -rimming -s hit -s.o.b. -sadist -schlong -screwing -scroat -scrote -scrotum -semen -sex -sh!+ -sh!t -sh1t -shag -shagger -shaggin -shagging -shemale -shi+ -shit -shitdick -shite -shited -shitey -shitfuck -shitfull -shithead -shiting -shitings -shits -shitted -shitter -shitters -shitting -shittings -shitty -skank -slut -sluts -smegma -smut -snatch -son-of-a-bitch -spac -spunk -s_h_i_t -t1tt1e5 -t1tties -teets -teez -testical -testicle -tit -titfuck -tits -titt -tittie5 -tittiefucker -titties -tittyfuck -tittywank -titwank -tosser -turd -tw4t -twat -twathead -twatty -twunt -twunter -v14gra -v1gra -vagina -viagra -vulva -w00se -wang -wank -wanker -wanky -whoar -whore -willies -willy -xrated diff --git a/tests/language/test_language.py b/tests/language/test_language.py deleted file mode 100755 index 98b02904..00000000 --- a/tests/language/test_language.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python3 - -import subprocess -import sys - -checked_ext = ["h", "c", "py", "pyx", "cpp", "hpp", "md", "mk"] - -if __name__ == "__main__": - with open("list.txt", 'r') as handle: - - suffix_cmd = " " - for i in checked_ext: - suffix_cmd += "--include \*." + i + " " - - found_bad_language = False - for line in handle: - line = line.rstrip('\n').rstrip(" ") - try: - cmd = "cd ../../; grep -R -i -w " + suffix_cmd + " '" + line + "'" - res = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT) - print(res) - found_bad_language = True - except subprocess.CalledProcessError: - pass - if found_bad_language: - sys.exit("Failed: found bad language") - else: - print("Success") diff --git a/tests/linter_python/.pylintrc b/tests/linter_python/.pylintrc deleted file mode 100644 index 64a55daf..00000000 --- a/tests/linter_python/.pylintrc +++ /dev/null @@ -1,585 +0,0 @@ -[MASTER] - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code -extension-pkg-whitelist=scipy - -# Add files or directories to the blacklist. They should be base names, not -# paths. -ignore=CVS - -# Add files or directories matching the regex patterns to the blacklist. The -# regex matches against base names, not paths. -ignore-patterns= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= - -# Use multiple processes to speed up Pylint. -jobs=4 - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -load-plugins= - -# Pickle collected data for later comparisons. -persistent=yes - -# Specify a configuration file. -#rcfile= - -# When enabled, pylint would attempt to guess common misconfiguration and emit -# user-friendly hints instead of false-positive error messages -suggestion-mode=yes - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED -confidence= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once).You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use"--disable=all --enable=classes -# --disable=W" -disable=print-statement, - parameter-unpacking, - unpacking-in-except, - old-raise-syntax, - backtick, - long-suffix, - old-ne-operator, - old-octal-literal, - import-star-module-level, - non-ascii-bytes-literal, - raw-checker-failed, - bad-inline-option, - locally-disabled, - locally-enabled, - file-ignored, - suppressed-message, - useless-suppression, - deprecated-pragma, - apply-builtin, - basestring-builtin, - buffer-builtin, - cmp-builtin, - coerce-builtin, - execfile-builtin, - file-builtin, - long-builtin, - raw_input-builtin, - reduce-builtin, - standarderror-builtin, - unicode-builtin, - xrange-builtin, - coerce-method, - delslice-method, - getslice-method, - setslice-method, - no-absolute-import, - old-division, - dict-iter-method, - dict-view-method, - next-method-called, - metaclass-assignment, - indexing-exception, - raising-string, - reload-builtin, - oct-method, - hex-method, - nonzero-method, - cmp-method, - input-builtin, - round-builtin, - intern-builtin, - unichr-builtin, - map-builtin-not-iterating, - zip-builtin-not-iterating, - range-builtin-not-iterating, - filter-builtin-not-iterating, - using-cmp-argument, - eq-without-hash, - div-method, - idiv-method, - rdiv-method, - exception-message-attribute, - invalid-str-codec, - sys-max-int, - bad-python3-import, - deprecated-string-function, - deprecated-str-translate-call, - deprecated-itertools-function, - deprecated-types-field, - next-method-defined, - dict-items-not-iterating, - dict-keys-not-iterating, - dict-values-not-iterating, - bad-indentation, - line-too-long, - missing-docstring, - multiple-statements, - bad-continuation, - invalid-name, - too-many-arguments, - too-many-locals, - superfluous-parens, - bad-whitespace, - too-many-instance-attributes, - wrong-import-position, - ungrouped-imports, - wrong-import-order, - protected-access, - trailing-whitespace, - too-many-branches, - too-few-public-methods, - too-many-statements, - trailing-newlines, - attribute-defined-outside-init, - too-many-return-statements, - too-many-public-methods, - unused-argument, - old-style-class, - no-init, - len-as-condition, - unneeded-not, - no-self-use, - multiple-imports, - no-else-return, - logging-not-lazy, - fixme, - redefined-outer-name, - unused-variable, - unsubscriptable-object, - expression-not-assigned, - too-many-boolean-expressions, - consider-using-ternary, - invalid-unary-operand-type, - relative-import, - deprecated-lambda - - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time (only on the command line, not in the configuration file where -# it should appear only once). See also the "--disable" option for examples. -enable=c-extension-no-member - - -[REPORTS] - -# Python expression which should return a note less than 10 (10 is the highest -# note). You have access to the variables errors warning, statement which -# respectively contain the number of errors / warnings messages and the total -# number of statements analyzed. This is used by the global evaluation report -# (RP0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details -#msg-template= - -# Set the output format. Available formats are text, parseable, colorized, json -# and msvs (visual studio).You can also give a reporter class, eg -# mypackage.mymodule.MyReporterClass. -output-format=text - -# Tells whether to display a full report or only the messages -reports=no - -# Activate the evaluation score. -score=yes - - -[REFACTORING] - -# Maximum number of nested blocks for function / method body -max-nested-blocks=5 - -# Complete name of functions that never returns. When checking for -# inconsistent-return-statements if a never returning function is called then -# it will be considered as an explicit return statement and no message will be -# printed. -never-returning-functions=optparse.Values,sys.exit - - -[LOGGING] - -# Logging modules to check that the string format arguments are in logging -# function parameter format -logging-modules=logging - - -[SPELLING] - -# Limits count of emitted suggestions for spelling mistakes -max-spelling-suggestions=4 - -# Spelling dictionary name. Available dictionaries: none. To make it working -# install python-enchant package. -spelling-dict= - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to indicated private dictionary in -# --spelling-private-dict-file option instead of raising a message. -spelling-store-unknown-words=no - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -notes=FIXME, - XXX, - TODO - - -[SIMILARITIES] - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - -# Ignore imports when computing similarities. -ignore-imports=no - -# Minimum lines number of a similarity. -min-similarity-lines=4 - - -[TYPECHECK] - -# List of decorators that produce context managers, such as -# contextlib.contextmanager. Add to this list to register other decorators that -# produce valid context managers. -contextmanager-decorators=contextlib.contextmanager - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E1101 when accessed. Python regular -# expressions are accepted. -generated-members=capnp.* cereal.* pygame.* zmq.* setproctitle.* smbus2.* usb1.* serial.* cv2.* - -# Tells whether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes - -# This flag controls whether pylint should warn about no-member and similar -# checks whenever an opaque object is returned when inferring. The inference -# can return multiple potential results while evaluating a Python object, but -# some branches might not be evaluated, which results in partial inference. In -# that case, it might be useful to still emit no-member and other checks for -# the rest of the inferred objects. -ignore-on-opaque-inference=yes - -# List of class names for which member attributes should not be checked (useful -# for classes with dynamically set attributes). This supports the use of -# qualified names. -ignored-classes=optparse.Values,thread._local,_thread._local - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis. It -# supports qualified module names, as well as Unix pattern matching. -ignored-modules=flask setproctitle usb1 flask.ext.socketio smbus2 usb1.* - -# Show a hint with possible names when a member name was not found. The aspect -# of finding the hint is based on edit distance. -missing-member-hint=yes - -# The minimum edit distance a name should have in order to be considered a -# similar match for a missing member name. -missing-member-hint-distance=1 - -# The total number of similar names that should be taken in consideration when -# showing a hint for a missing member. -missing-member-max-choices=1 - - -[VARIABLES] - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= - -# Tells whether unused global variables should be treated as a violation. -allow-global-unused-variables=yes - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_, - _cb - -# A regular expression matching the name of dummy variables (i.e. expectedly -# not used). -dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ - -# Argument names that match this expression will be ignored. Default to name -# with leading underscore -ignored-argument-names=_.*|^ignored_|^unused_ - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# List of qualified module names which can have objects that can redefine -# builtins. -redefining-builtins-modules=six.moves,past.builtins,future.builtins - - -[FORMAT] - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -expected-line-ending-format= - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=4 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' - -# Maximum number of characters on a single line. -max-line-length=100 - -# Maximum number of lines in a module -max-module-lines=1000 - -# List of optional constructs for which whitespace checking is disabled. `dict- -# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. -# `trailing-comma` allows a space between comma and closing bracket: (a, ). -# `empty-line` allows space-only lines. -no-space-check=trailing-comma, - dict-separator - -# Allow the body of a class to be on the same line as the declaration if body -# contains single statement. -single-line-class-stmt=no - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - - -[BASIC] - -# Naming style matching correct argument names -argument-naming-style=snake_case - -# Regular expression matching correct argument names. Overrides argument- -# naming-style -#argument-rgx= - -# Naming style matching correct attribute names -attr-naming-style=snake_case - -# Regular expression matching correct attribute names. Overrides attr-naming- -# style -#attr-rgx= - -# Bad variable names which should always be refused, separated by a comma -bad-names=foo, - bar, - baz, - toto, - tutu, - tata - -# Naming style matching correct class attribute names -class-attribute-naming-style=any - -# Regular expression matching correct class attribute names. Overrides class- -# attribute-naming-style -#class-attribute-rgx= - -# Naming style matching correct class names -class-naming-style=PascalCase - -# Regular expression matching correct class names. Overrides class-naming-style -#class-rgx= - -# Naming style matching correct constant names -const-naming-style=UPPER_CASE - -# Regular expression matching correct constant names. Overrides const-naming- -# style -#const-rgx= - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 - -# Naming style matching correct function names -function-naming-style=snake_case - -# Regular expression matching correct function names. Overrides function- -# naming-style -#function-rgx= - -# Good variable names which should always be accepted, separated by a comma -good-names=i, - j, - k, - ex, - Run, - _ - -# Include a hint for the correct naming format with invalid-name -include-naming-hint=no - -# Naming style matching correct inline iteration names -inlinevar-naming-style=any - -# Regular expression matching correct inline iteration names. Overrides -# inlinevar-naming-style -#inlinevar-rgx= - -# Naming style matching correct method names -method-naming-style=snake_case - -# Regular expression matching correct method names. Overrides method-naming- -# style -#method-rgx= - -# Naming style matching correct module names -module-naming-style=snake_case - -# Regular expression matching correct module names. Overrides module-naming- -# style -#module-rgx= - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= - -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=^_ - -# List of decorators that produce properties, such as abc.abstractproperty. Add -# to this list to register other decorators that produce valid properties. -property-classes=abc.abstractproperty - -# Naming style matching correct variable names -variable-naming-style=snake_case - -# Regular expression matching correct variable names. Overrides variable- -# naming-style -#variable-rgx= - - -[DESIGN] - -# Maximum number of arguments for function / method -max-args=5 - -# Maximum number of attributes for a class (see R0902). -max-attributes=7 - -# Maximum number of boolean expressions in a if statement -max-bool-expr=5 - -# Maximum number of branch for function / method body -max-branches=12 - -# Maximum number of locals for function / method body -max-locals=15 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - -# Maximum number of return / yield for function / method body -max-returns=6 - -# Maximum number of statements in function / method body -max-statements=50 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=2 - - -[CLASSES] - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__, - __new__, - setUp - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict, - _fields, - _replace, - _source, - _make - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=mcs - - -[IMPORTS] - -# Allow wildcard imports from modules that define __all__. -allow-wildcard-with-all=no - -# Analyse import fallback blocks. This can be used to support both Python 2 and -# 3 compatible code, which means that the block might have code that exists -# only in one or another interpreter, leading to false positives when analysed. -analyse-fallback-blocks=no - -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=regsub, - TERMIOS, - Bastion, - rexec - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) -ext-import-graph= - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) -import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled) -int-import-graph= - -# Force import order to recognize a module as part of the standard -# compatibility libraries. -known-standard-library= - -# Force import order to recognize a module as part of a third party library. -known-third-party=enchant - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when being caught. Defaults to -# "Exception" -overgeneral-exceptions=Exception diff --git a/tests/linter_python/Dockerfile b/tests/linter_python/Dockerfile deleted file mode 100644 index 819d6921..00000000 --- a/tests/linter_python/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM ubuntu:16.04 - -RUN apt-get update && apt-get install -y make python python-pip locales curl git zlib1g-dev libffi-dev bzip2 libssl-dev - -RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 - -RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash - -ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}" -RUN pyenv install 3.7.3 -RUN pyenv global 3.7.3 -RUN pyenv rehash - -COPY requirements.txt /tmp/ -RUN pip install -r /tmp/requirements.txt -COPY . /panda diff --git a/tests/linter_python/flake8_panda.sh b/tests/linter_python/flake8_panda.sh deleted file mode 100755 index a1d02ea5..00000000 --- a/tests/linter_python/flake8_panda.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -RESULT=$(python3 -m flake8 --select=F $(find ../../ -type f | grep -v "/boardesp/" | grep -v "/cppcheck/" | grep "\.py$")) -if [[ $RESULT ]]; then - echo "Pyflakes found errors in the code. Please fix and try again" - echo "$RESULT" - exit 1 -fi diff --git a/tests/linter_python/pylint_panda.sh b/tests/linter_python/pylint_panda.sh deleted file mode 100755 index 1486bd83..00000000 --- a/tests/linter_python/pylint_panda.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -python3 -m pylint --disable=R,C,W $(find ../../ -type f | grep -v "/boardesp/" | grep -v "/cppcheck/" | grep "\.py$") - -exit_status=$? -(( res = exit_status & 3 )) - -if [[ $res != 0 ]]; then - echo "Pylint found errors in the code. Please fix and try again" - exit 1 -fi diff --git a/tests/misra/Dockerfile b/tests/misra/Dockerfile deleted file mode 100644 index 06882834..00000000 --- a/tests/misra/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM ubuntu:16.04 - -RUN apt-get update && apt-get install -y clang make python python-pip git curl locales zlib1g-dev libffi-dev bzip2 libssl-dev libbz2-dev libusb-1.0-0 - -RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 - -RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash - -ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}" -RUN pyenv install 3.7.3 -RUN pyenv global 3.7.3 -RUN pyenv rehash - -COPY requirements.txt /tmp/ -RUN pip install -r /tmp/requirements.txt -COPY . /panda diff --git a/tests/safety/Dockerfile b/tests/safety/Dockerfile deleted file mode 100644 index 524cfc39..00000000 --- a/tests/safety/Dockerfile +++ /dev/null @@ -1,50 +0,0 @@ -FROM ubuntu:16.04 - -RUN apt-get update && apt-get install -y \ - autoconf \ - clang \ - curl \ - git \ - libtool \ - libssl-dev \ - libusb-1.0-0 \ - libzmq3-dev \ - locales \ - make \ - python \ - python-pip \ - wget \ - zlib1g-dev - -RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 - -RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash - -ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}" -RUN pyenv install 3.7.3 -RUN pyenv global 3.7.3 -RUN pyenv rehash - -COPY requirements.txt /tmp/ -RUN pip install -r /tmp/requirements.txt - -WORKDIR /openpilot -RUN git clone https://github.com/commaai/opendbc.git || true -WORKDIR /openpilot/opendbc -RUN git pull && git checkout 7f3b1774dd248d4ebad91cc9de0fb1c561fab54b -WORKDIR /openpilot -RUN git clone https://github.com/commaai/cereal.git -WORKDIR /openpilot/cereal -RUN git pull && git checkout e370f79522ff7fc0b16f33f4fef420be48061206 -RUN /openpilot/cereal/install_capnp.sh - -RUN pip install -r /openpilot/opendbc/requirements.txt - -WORKDIR /openpilot -RUN cp /openpilot/opendbc/SConstruct /openpilot -COPY . /openpilot/panda - -RUN scons -c && scons -j$(nproc) diff --git a/tests/safety/common.py b/tests/safety/common.py index 8d81f115..4ca7d093 100644 --- a/tests/safety/common.py +++ b/tests/safety/common.py @@ -2,7 +2,8 @@ import abc import struct import unittest import numpy as np -from opendbc.can.packer import CANPacker # pylint: disable=import-error +from typing import Optional, List, Dict +from opendbc.can.packer import CANPacker # pylint: disable=import-error from panda.tests.safety import libpandasafety_py MAX_WRONG_COUNTERS = 5 @@ -32,8 +33,10 @@ def make_msg(bus, addr, length=8): return package_can_msg([addr, 0, b'\x00'*length, bus]) class CANPackerPanda(CANPacker): - def make_can_msg_panda(self, name_or_addr, bus, values, counter=-1): + def make_can_msg_panda(self, name_or_addr, bus, values, counter=-1, fix_checksum=None): msg = self.make_can_msg(name_or_addr, bus, values, counter=-1) + if fix_checksum is not None: + msg = fix_checksum(msg) return package_can_msg(msg) class PandaSafetyTestBase(unittest.TestCase): @@ -245,13 +248,13 @@ class TorqueSteeringSafetyTest(PandaSafetyTestBase): class PandaSafetyTest(PandaSafetyTestBase): - TX_MSGS = None - STANDSTILL_THRESHOLD = None + TX_MSGS: Optional[List[List[int]]] = None + STANDSTILL_THRESHOLD: Optional[float] = None GAS_PRESSED_THRESHOLD = 0 - RELAY_MALFUNCTION_ADDR = None - RELAY_MALFUNCTION_BUS = None - FWD_BLACKLISTED_ADDRS = {} # {bus: [addr]} - FWD_BUS_LOOKUP = {} + RELAY_MALFUNCTION_ADDR: Optional[int] = None + RELAY_MALFUNCTION_BUS: Optional[int] = None + FWD_BLACKLISTED_ADDRS: Dict[int, List[int]] = {} # {bus: [addr]} + FWD_BUS_LOOKUP: Dict[int, int] = {} @classmethod def setUpClass(cls): @@ -396,7 +399,7 @@ class PandaSafetyTest(PandaSafetyTestBase): def test_sample_speed(self): self.assertFalse(self.safety.get_vehicle_moving()) - + # not moving self.safety.safety_rx_hook(self._speed_msg(0)) self.assertFalse(self.safety.get_vehicle_moving()) diff --git a/tests/safety/libpandasafety_py.py b/tests/safety/libpandasafety_py.py index 9898e6df..7a250f1b 100644 --- a/tests/safety/libpandasafety_py.py +++ b/tests/safety/libpandasafety_py.py @@ -50,6 +50,7 @@ int get_torque_driver_min(void); int get_torque_driver_max(void); void set_desired_torque_last(int t); void set_rt_torque_last(int t); +void set_desired_angle_last(int t); bool get_cruise_engaged_prev(void); bool get_vehicle_moving(void); @@ -66,15 +67,10 @@ void init_tests(void); void init_tests_honda(void); void set_honda_fwd_brake(bool); void set_honda_alt_brake_msg(bool); +void set_honda_bosch_long(bool c); int get_honda_hw(void); -void init_tests_chrysler(void); - bool get_subaru_global(void); - -void init_tests_nissan(void); -void set_nissan_desired_angle_last(int t); - """) libpandasafety = ffi.dlopen(libpandasafety_fn) diff --git a/tests/safety/test.c b/tests/safety/test.c index 52d2ea7f..c0fd4bd7 100644 --- a/tests/safety/test.c +++ b/tests/safety/test.c @@ -71,6 +71,7 @@ void fault_recovered(uint32_t fault) { #define GET_BYTE(msg, b) (((int)(b) > 3) ? (((msg)->RDHR >> (8U * ((unsigned int)(b) % 4U))) & 0XFFU) : (((msg)->RDLR >> (8U * (unsigned int)(b))) & 0xFFU)) #define GET_BYTES_04(msg) ((msg)->RDLR) #define GET_BYTES_48(msg) ((msg)->RDHR) +#define GET_FLAG(value, mask) (((__typeof__(mask))param & mask) == mask) #define UNUSED(x) (void)(x) @@ -179,10 +180,18 @@ void set_desired_torque_last(int t){ desired_torque_last = t; } +void set_desired_angle_last(int t){ + desired_angle_last = t; +} + void set_honda_alt_brake_msg(bool c){ honda_alt_brake_msg = c; } +void set_honda_bosch_long(bool c){ + honda_bosch_long = c; +} + int get_honda_hw(void) { return honda_hw; } @@ -191,46 +200,19 @@ void set_honda_fwd_brake(bool c){ honda_fwd_brake = c; } -void set_nissan_desired_angle_last(int t){ - nissan_desired_angle_last = t; -} - void init_tests(void){ // get HW_TYPE from env variable set in test.sh hw_type = atoi(getenv("HW_TYPE")); safety_mode_cnt = 2U; // avoid ignoring relay_malfunction logic - gas_pressed_prev = false; - brake_pressed_prev = false; - desired_torque_last = 0; - rt_torque_last = 0; - ts_last = 0; - torque_driver.min = 0; - torque_driver.max = 0; - torque_meas.min = 0; - torque_meas.max = 0; - vehicle_moving = false; unsafe_mode = 0; set_timer(0); } -void init_tests_chrysler(void){ - init_tests(); - chrysler_speed = 0; -} - void init_tests_honda(void){ init_tests(); honda_fwd_brake = false; } -void init_tests_nissan(void){ - init_tests(); - nissan_angle_meas.min = 0; - nissan_angle_meas.max = 0; - nissan_desired_angle_last = 0; - set_timer(0); -} - void set_gmlan_digital_output(int to_set){ } diff --git a/tests/safety/test_chrysler.py b/tests/safety/test_chrysler.py index 369f1f98..f387d83b 100755 --- a/tests/safety/test_chrysler.py +++ b/tests/safety/test_chrysler.py @@ -30,7 +30,7 @@ class TestChryslerSafety(common.PandaSafetyTest, common.TorqueSteeringSafetyTest self.packer = CANPackerPanda("chrysler_pacifica_2017_hybrid") self.safety = libpandasafety_py.libpandasafety self.safety.set_safety_hooks(Panda.SAFETY_CHRYSLER, 0) - self.safety.init_tests_chrysler() + self.safety.init_tests() def _button_msg(self, cancel): values = {"ACC_CANCEL": cancel} diff --git a/tests/safety/test_gm.py b/tests/safety/test_gm.py index 53433552..5de95909 100644 --- a/tests/safety/test_gm.py +++ b/tests/safety/test_gm.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import unittest +from typing import Dict, List import numpy as np from panda import Panda from panda.tests.safety import libpandasafety_py @@ -27,8 +28,8 @@ class TestGmSafety(common.PandaSafetyTest): STANDSTILL_THRESHOLD = 0 RELAY_MALFUNCTION_ADDR = 384 RELAY_MALFUNCTION_BUS = 0 - FWD_BLACKLISTED_ADDRS = {} - FWD_BUS_LOOKUP = {} + FWD_BLACKLISTED_ADDRS: Dict[int, List[int]] = {} + FWD_BUS_LOOKUP: Dict[int, int] = {} def setUp(self): self.packer = CANPackerPanda("gm_global_a_powertrain") diff --git a/tests/safety/test_honda.py b/tests/safety/test_honda.py index 5cd2ba05..d322073a 100755 --- a/tests/safety/test_honda.py +++ b/tests/safety/test_honda.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import unittest +from typing import Optional import numpy as np from panda import Panda from panda.tests.safety import libpandasafety_py @@ -7,8 +8,6 @@ import panda.tests.safety.common as common from panda.tests.safety.common import CANPackerPanda, make_msg, \ MAX_WRONG_COUNTERS, UNSAFE_MODE -MAX_BRAKE = 255 - class Btn: CANCEL = 2 SET = 3 @@ -20,11 +19,14 @@ HONDA_BH_HW = 2 class TestHondaSafety(common.PandaSafetyTest): + MAX_BRAKE: float = 255 + PT_BUS: Optional[int] = None # must be set when inherited + STEER_BUS: Optional[int] = None # must be set when inherited + cnt_speed = 0 cnt_gas = 0 cnt_button = 0 - - PT_BUS = 0 + cnt_brake = 0 @classmethod def setUpClass(cls): @@ -58,15 +60,13 @@ class TestHondaSafety(common.PandaSafetyTest): self.__class__.cnt_gas += 1 return self.packer.make_can_msg_panda("POWERTRAIN_DATA", self.PT_BUS, values) - def _send_brake_msg(self, brake): - values = {} - if self.safety.get_honda_hw() == HONDA_N_HW: - values = {"COMPUTER_BRAKE": brake} - return self.packer.make_can_msg_panda("BRAKE_COMMAND", 0, values) - def _send_steer_msg(self, steer): values = {"STEER_TORQUE": steer} - return self.packer.make_can_msg_panda("STEERING_CONTROL", 0, values) + return self.packer.make_can_msg_panda("STEERING_CONTROL", self.STEER_BUS, values) + + def _send_brake_msg(self, brake): + # must be implemented when inherited + raise NotImplementedError() def test_resume_button(self): self.safety.set_controls_allowed(0) @@ -157,13 +157,14 @@ class TestHondaSafety(common.PandaSafetyTest): hw = self.safety.get_honda_hw() if hw == HONDA_N_HW: self.safety.set_honda_fwd_brake(False) - self.assertEqual(allow_ctrl, self._tx(self._send_brake_msg(MAX_BRAKE))) + self.assertEqual(allow_ctrl, self._tx(self._send_brake_msg(self.MAX_BRAKE))) self.assertEqual(allow_ctrl, self._tx(self._send_steer_msg(0x1000))) # reset status self.safety.set_controls_allowed(0) self.safety.set_unsafe_mode(UNSAFE_MODE.DEFAULT) - self._tx(self._send_brake_msg(0)) + if hw == HONDA_N_HW: + self._tx(self._send_brake_msg(0)) self._tx(self._send_steer_msg(0)) if pedal == 'brake': self._rx(self._speed_msg(0)) @@ -181,6 +182,9 @@ class TestHondaNidecSafety(TestHondaSafety, common.InterceptorSafetyTest): FWD_BLACKLISTED_ADDRS = {2: [0xE4, 0x194, 0x33D, 0x30C]} FWD_BUS_LOOKUP = {0: 2, 2: 0} + PT_BUS = 0 + STEER_BUS = 0 + INTERCEPTOR_THRESHOLD = 344 def setUp(self): @@ -197,6 +201,10 @@ class TestHondaNidecSafety(TestHondaSafety, common.InterceptorSafetyTest): ((gas2 & 0xff) << 24) | ((gas2 & 0xff00) << 8) return to_send + def _send_brake_msg(self, brake): + values = {"COMPUTER_BRAKE": brake} + return self.packer.make_can_msg_panda("BRAKE_COMMAND", 0, values) + def test_fwd_hook(self): # normal operation, not forwarding AEB self.FWD_BLACKLISTED_ADDRS[2].append(0x1FA) @@ -212,13 +220,13 @@ class TestHondaNidecSafety(TestHondaSafety, common.InterceptorSafetyTest): def test_brake_safety_check(self): for fwd_brake in [False, True]: self.safety.set_honda_fwd_brake(fwd_brake) - for brake in np.arange(0, MAX_BRAKE + 10, 1): + for brake in np.arange(0, self.MAX_BRAKE + 10, 1): for controls_allowed in [True, False]: self.safety.set_controls_allowed(controls_allowed) if fwd_brake: send = False # block openpilot brake msg when fwd'ing stock msg elif controls_allowed: - send = MAX_BRAKE >= brake >= 0 + send = self.MAX_BRAKE >= brake >= 0 else: send = brake == 0 self.assertEqual(send, self._tx(self._send_brake_msg(brake))) @@ -234,7 +242,7 @@ class TestHondaNidecSafety(TestHondaSafety, common.InterceptorSafetyTest): self.safety.set_controls_allowed(1) self.safety.set_honda_fwd_brake(False) - self.assertEqual(allow_ctrl, self._tx(self._send_brake_msg(MAX_BRAKE))) + self.assertEqual(allow_ctrl, self._tx(self._send_brake_msg(self.MAX_BRAKE))) self.assertEqual(allow_ctrl, self._tx(self._interceptor_msg(self.INTERCEPTOR_THRESHOLD, 0x200))) self.assertEqual(allow_ctrl, self._tx(self._send_steer_msg(0x1000))) @@ -247,35 +255,35 @@ class TestHondaNidecSafety(TestHondaSafety, common.InterceptorSafetyTest): self.safety.set_gas_interceptor_detected(False) -class TestHondaBoschHarnessSafety(TestHondaSafety): - TX_MSGS = [[0xE4, 0], [0xE5, 0], [0x296, 1], [0x33D, 0]] # Bosch Harness +class TestHondaBoschSafety(TestHondaSafety): STANDSTILL_THRESHOLD = 0 RELAY_MALFUNCTION_ADDR = 0xE4 - RELAY_MALFUNCTION_BUS = 0 - FWD_BLACKLISTED_ADDRS = {2: [0xE4, 0xE5, 0x33D]} - FWD_BUS_LOOKUP = {0: 2, 2: 0} - PT_BUS = 1 + @classmethod + def setUpClass(cls): + if cls.__name__ == "TestHondaBoschSafety": + cls.packer = None + cls.safety = None + raise unittest.SkipTest def setUp(self): self.packer = CANPackerPanda("honda_accord_s2t_2018_can_generated") self.safety = libpandasafety_py.libpandasafety - self.safety.set_safety_hooks(Panda.SAFETY_HONDA_BOSCH_HARNESS, 0) - self.safety.init_tests_honda() def _alt_brake_msg(self, brake): - to_send = make_msg(0, 0x1BE) - to_send[0].RDLR = 0x10 if brake else 0 - return to_send + values = {"BRAKE_PRESSED": brake, "COUNTER": self.cnt_brake % 4} + self.__class__.cnt_brake += 1 + return self.packer.make_can_msg_panda("BRAKE_MODULE", self.PT_BUS, values) - def test_spam_cancel_safety_check(self): - self.safety.set_controls_allowed(0) - self.assertTrue(self._tx(self._button_msg(Btn.CANCEL))) - self.assertFalse(self._tx(self._button_msg(Btn.RESUME))) - self.assertFalse(self._tx(self._button_msg(Btn.SET))) - # do not block resume if we are engaged already - self.safety.set_controls_allowed(1) - self.assertTrue(self._tx(self._button_msg(Btn.RESUME))) + # TODO: add back in once alternative brake checksum/counter validation is added + # def test_alt_brake_rx_hook(self): + # self.safety.set_honda_alt_brake_msg(1) + # self.safety.set_controls_allowed(1) + # to_push = self._alt_brake_msg(0) + # self.assertTrue(self._rx(to_push)) + # to_push[0].RDLR = to_push[0].RDLR & 0xFFF0FFFF # invalidate checksum + # self.assertFalse(self._rx(to_push)) + # self.assertFalse(self.safety.get_controls_allowed()) def test_alt_disengage_on_brake(self): self.safety.set_honda_alt_brake_msg(1) @@ -289,25 +297,108 @@ class TestHondaBoschHarnessSafety(TestHondaSafety): self.assertTrue(self.safety.get_controls_allowed()) +class TestHondaBoschHarnessSafety(TestHondaBoschSafety): + TX_MSGS = [[0xE4, 0], [0xE5, 0], [0x296, 1], [0x33D, 0]] # Bosch Harness + RELAY_MALFUNCTION_BUS = 0 + FWD_BLACKLISTED_ADDRS = {2: [0xE4, 0xE5, 0x33D]} + FWD_BUS_LOOKUP = {0: 2, 2: 0} + + PT_BUS = 1 + STEER_BUS = 0 + + def setUp(self): + super().setUp() + self.safety.set_safety_hooks(Panda.SAFETY_HONDA_BOSCH_HARNESS, 0) + self.safety.init_tests_honda() + + def test_spam_cancel_safety_check(self): + self.safety.set_controls_allowed(0) + self.assertTrue(self._tx(self._button_msg(Btn.CANCEL))) + self.assertFalse(self._tx(self._button_msg(Btn.RESUME))) + self.assertFalse(self._tx(self._button_msg(Btn.SET))) + # do not block resume if we are engaged already + self.safety.set_controls_allowed(1) + self.assertTrue(self._tx(self._button_msg(Btn.RESUME))) + + class TestHondaBoschGiraffeSafety(TestHondaBoschHarnessSafety): TX_MSGS = [[0xE4, 2], [0xE5, 2], [0x296, 0], [0x33D, 2]] # Bosch Giraffe - STANDSTILL_THRESHOLD = 0 - RELAY_MALFUNCTION_ADDR = 0xE4 RELAY_MALFUNCTION_BUS = 2 FWD_BLACKLISTED_ADDRS = {1: [0xE4, 0xE5, 0x33D]} FWD_BUS_LOOKUP = {1: 2, 2: 1} PT_BUS = 0 + STEER_BUS = 2 def setUp(self): super().setUp() - self.safety = libpandasafety_py.libpandasafety self.safety.set_safety_hooks(Panda.SAFETY_HONDA_BOSCH_GIRAFFE, 0) self.safety.init_tests_honda() - def _send_steer_msg(self, steer): - values = {"STEER_TORQUE": steer} - return self.packer.make_can_msg_panda("STEERING_CONTROL", 2, values) + +class TestHondaBoschLongSafety(TestHondaBoschSafety): + NO_GAS = -30000 + MAX_GAS = 2000 + MAX_BRAKE = -3.5 + + @classmethod + def setUpClass(cls): + if cls.__name__ == "TestHondaBoschLongSafety": + cls.packer = None + cls.safety = None + raise unittest.SkipTest + + def _send_gas_brake_msg(self, gas, accel): + values = { + "GAS_COMMAND": gas, + "ACCEL_COMMAND": accel, + "BRAKE_REQUEST": accel < 0, + } + return self.packer.make_can_msg_panda("ACC_CONTROL", self.PT_BUS, values) + + def test_gas_safety_check(self): + for controls_allowed in [True, False]: + for gas in np.arange(self.NO_GAS, self.MAX_GAS + 2000, 100): + accel = 0 if gas < 0 else gas / 1000 + self.safety.set_controls_allowed(controls_allowed) + send = gas <= self.MAX_GAS if controls_allowed else gas == self.NO_GAS + self.assertEqual(send, self.safety.safety_tx_hook(self._send_gas_brake_msg(gas, accel)), gas) + + def test_brake_safety_check(self): + for controls_allowed in [True, False]: + for accel in np.arange(0, self.MAX_BRAKE - 1, -0.1): + self.safety.set_controls_allowed(controls_allowed) + send = self.MAX_BRAKE <= accel <= 0 if controls_allowed else accel == 0 + self.assertEqual(send, self._tx(self._send_gas_brake_msg(self.NO_GAS, accel)), (controls_allowed, accel)) + +class TestHondaBoschLongHarnessSafety(TestHondaBoschLongSafety): + TX_MSGS = [[0xE4, 1], [0x1DF, 1], [0x1EF, 1], [0x1FA, 1], [0x30C, 1], [0x33D, 1], [0x39F, 1], [0x18DAB0F1, 1]] # Bosch Harness w/ gas and brakes + RELAY_MALFUNCTION_BUS = 0 + FWD_BLACKLISTED_ADDRS = {2: [0xE4, 0xE5, 0x33D]} + FWD_BUS_LOOKUP = {0: 2, 2: 0} + + PT_BUS = 1 + STEER_BUS = 1 + + def setUp(self): + super().setUp() + self.safety.set_safety_hooks(Panda.SAFETY_HONDA_BOSCH_HARNESS, 2) + self.safety.init_tests_honda() + + +class TestHondaBoschLongGiraffeSafety(TestHondaBoschLongSafety): + TX_MSGS = [[0xE4, 0], [0x1DF, 0], [0x1EF, 0], [0x1FA, 0], [0x30C, 0], [0x33D, 0], [0x39F, 0], [0x18DAB0F1, 0]] # Bosch Giraffe w/ gas and brakes + RELAY_MALFUNCTION_BUS = 2 + FWD_BLACKLISTED_ADDRS = {1: [0xE4, 0xE5, 0x33D]} + FWD_BUS_LOOKUP = {1: 2, 2: 1} + + PT_BUS = 0 + STEER_BUS = 0 + + def setUp(self): + super().setUp() + self.safety.set_safety_hooks(Panda.SAFETY_HONDA_BOSCH_GIRAFFE, 2) + self.safety.init_tests_honda() if __name__ == "__main__": diff --git a/tests/safety/test_hyundai.py b/tests/safety/test_hyundai.py index dad07edf..9f173253 100644 --- a/tests/safety/test_hyundai.py +++ b/tests/safety/test_hyundai.py @@ -16,6 +16,22 @@ RT_INTERVAL = 250000 DRIVER_TORQUE_ALLOWANCE = 50 DRIVER_TORQUE_FACTOR = 2 +# 4 bit checkusm used in some hyundai messages +# lives outside the can packer because we never send this msg +def checksum(msg): + addr, t, dat, bus = msg + + chksum = 0 + for i, b in enumerate(dat): + if addr in [608, 1057] and i == 7: + b &= 0x0F if addr == 1057 else 0xF0 + elif addr == 916 and i == 6: + b &= 0xF0 + chksum += sum(divmod(b, 16)) + chksum = (16 - chksum) % 16 + ret = bytearray(dat) + ret[6 if addr == 916 else 7] |= chksum << (4 if addr == 1057 else 0) + return addr, t, ret, bus class TestHyundaiSafety(common.PandaSafetyTest): TX_MSGS = [[832, 0], [1265, 0], [1157, 0]] @@ -43,24 +59,25 @@ class TestHyundaiSafety(common.PandaSafetyTest): def _gas_msg(self, val): values = {"CF_Ems_AclAct": val, "AliveCounter": self.cnt_gas % 4} self.__class__.cnt_gas += 1 - return self.packer.make_can_msg_panda("EMS16", 0, values) + return self.packer.make_can_msg_panda("EMS16", 0, values, fix_checksum=checksum) def _brake_msg(self, brake): values = {"DriverBraking": brake, "AliveCounterTCS": self.cnt_brake % 8} self.__class__.cnt_brake += 1 - return self.packer.make_can_msg_panda("TCS13", 0, values) + return self.packer.make_can_msg_panda("TCS13", 0, values, fix_checksum=checksum) def _speed_msg(self, speed): # panda safety doesn't scale, so undo the scaling values = {"WHL_SPD_%s"%s: speed*0.03125 for s in ["FL", "FR", "RL", "RR"]} - values["WHL_SPD_AliveCounter_LSB"] = self.cnt_speed % 4 + values["WHL_SPD_AliveCounter_LSB"] = (self.cnt_speed % 16) & 0x3 + values["WHL_SPD_AliveCounter_MSB"] = (self.cnt_speed % 16) >> 2 self.__class__.cnt_speed += 1 return self.packer.make_can_msg_panda("WHL_SPD11", 0, values) def _pcm_status_msg(self, enabled): values = {"ACCMode": enabled, "CR_VSM_Alive": self.cnt_cruise % 16} self.__class__.cnt_cruise += 1 - return self.packer.make_can_msg_panda("SCC12", 0, values) + return self.packer.make_can_msg_panda("SCC12", 0, values, fix_checksum=checksum) def _set_prev_torque(self, t): self.safety.set_desired_torque_last(t) diff --git a/tests/safety/test_mazda.py b/tests/safety/test_mazda.py new file mode 100755 index 00000000..f82816c1 --- /dev/null +++ b/tests/safety/test_mazda.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python3 +import unittest +from panda import Panda +from panda.tests.safety import libpandasafety_py +import panda.tests.safety.common as common +from panda.tests.safety.common import CANPackerPanda + +MAX_RATE_UP = 10 +MAX_RATE_DOWN = 25 +MAX_STEER = 2047 + +MAX_RT_DELTA = 940 +RT_INTERVAL = 250000 + +DRIVER_TORQUE_ALLOWANCE = 15 +DRIVER_TORQUE_FACTOR = 1 + + +class TestMazdaSafety(common.PandaSafetyTest): + + TX_MSGS = [[0x243, 0], [0x09d, 0]] + STANDSTILL_THRESHOLD = .1 + RELAY_MALFUNCTION_ADDR = 0x243 + RELAY_MALFUNCTION_BUS = 0 + FWD_BLACKLISTED_ADDRS = {2: [0x243]} + FWD_BUS_LOOKUP = {0: 2, 2: 0} + LKAS_ENABLE_SPEED = 52 + LKAS_DISABLE_SPEED = 45 + + def setUp(self): + self.packer = CANPackerPanda("mazda_cx5_gt_2017") + self.safety = libpandasafety_py.libpandasafety + self.safety.set_safety_hooks(Panda.SAFETY_MAZDA, 0) + self.safety.init_tests() + + def _torque_meas_msg(self, torque): + values = {"STEER_TORQUE_MOTOR": torque} + return self.packer.make_can_msg_panda("STEER_TORQUE", 0, values) + +# def _torque_driver_msg(self, torque): +# values = {"STEER_TORQUE_DRIVER": torque} +# return self.packer.make_can_msg_panda("STEER_TORQUE", 0, values) + + def _torque_msg(self, torque): + values = {"LKAS_REQUEST": torque} + return self.packer.make_can_msg_panda("CAM_LKAS", 0, values) + + def _speed_msg(self, s): + values = {"SPEED": s} + return self.packer.make_can_msg_panda("ENGINE_DATA", 0, values) + + def _brake_msg(self, pressed): + values = {"BRAKE_ON": pressed} + return self.packer.make_can_msg_panda("PEDALS", 0, values) + + def _gas_msg(self, pressed): + values = {"PEDAL_GAS": pressed} + return self.packer.make_can_msg_panda("ENGINE_DATA", 0, values) + + def _pcm_status_msg(self, cruise_on): + values = {"CRZ_ACTIVE": cruise_on} + return self.packer.make_can_msg_panda("CRZ_CTRL", 0, values) + + def test_enable_control_allowed_from_cruise(self): + self._rx(self._pcm_status_msg(False)) + self.assertFalse(self.safety.get_controls_allowed()) + + self._rx(self._speed_msg(self.LKAS_DISABLE_SPEED - 1)) + self._rx(self._speed_msg(self.LKAS_ENABLE_SPEED - 1)) + self._rx(self._pcm_status_msg(True)) + self.assertFalse(self.safety.get_controls_allowed()) + + self._rx(self._pcm_status_msg(False)) + + self._rx(self._speed_msg(self.LKAS_ENABLE_SPEED + 1)) + self._rx(self._speed_msg(self.LKAS_ENABLE_SPEED - 1)) + self._rx(self._pcm_status_msg(True)) + self.assertTrue(self.safety.get_controls_allowed()) + + self._rx(self._speed_msg(self.LKAS_ENABLE_SPEED + 1)) + self._rx(self._pcm_status_msg(True)) + self.assertTrue(self.safety.get_controls_allowed()) + + self._rx(self._speed_msg(self.LKAS_ENABLE_SPEED - 1)) + self.assertTrue(self.safety.get_controls_allowed()) + + # Enabled going down + self._rx(self._speed_msg(self.LKAS_DISABLE_SPEED - 1)) + self.assertTrue(self.safety.get_controls_allowed()) + + self._rx(self._pcm_status_msg(False)) + + # Disabled going up + self._rx(self._speed_msg(self.LKAS_DISABLE_SPEED + 1)) + self._rx(self._pcm_status_msg(True)) + self.assertFalse(self.safety.get_controls_allowed()) + + def test_cruise_engaged_prev(self): + self._rx(self._pcm_status_msg(False)) + self._rx(self._speed_msg(self.LKAS_ENABLE_SPEED - 1)) + self._rx(self._pcm_status_msg(True)) + self.assertFalse(self.safety.get_cruise_engaged_prev()) + + self._rx(self._speed_msg(self.LKAS_ENABLE_SPEED + 1)) + + for engaged in [True, False]: + self._rx(self._pcm_status_msg(engaged)) + self.assertEqual(engaged, self.safety.get_cruise_engaged_prev()) + self._rx(self._pcm_status_msg(not engaged)) + self.assertEqual(not engaged, self.safety.get_cruise_engaged_prev()) + +if __name__ == "__main__": + unittest.main() diff --git a/tests/safety/test_nissan.py b/tests/safety/test_nissan.py index 853899ae..a1af0982 100644 --- a/tests/safety/test_nissan.py +++ b/tests/safety/test_nissan.py @@ -29,7 +29,7 @@ class TestNissanSafety(common.PandaSafetyTest): self.packer = CANPackerPanda("nissan_x_trail_2017") self.safety = libpandasafety_py.libpandasafety self.safety.set_safety_hooks(Panda.SAFETY_NISSAN, 0) - self.safety.init_tests_nissan() + self.safety.init_tests() def _angle_meas_msg(self, angle): values = {"STEER_ANGLE": angle} @@ -37,7 +37,7 @@ class TestNissanSafety(common.PandaSafetyTest): def _set_prev_angle(self, t): t = int(t * -100) - self.safety.set_nissan_desired_angle_last(t) + self.safety.set_desired_angle_last(t) def _angle_meas_msg_array(self, angle): for i in range(6): diff --git a/tests/safety/test_volkswagen_pq.py b/tests/safety/test_volkswagen_pq.py index f30d19f3..11310e02 100644 --- a/tests/safety/test_volkswagen_pq.py +++ b/tests/safety/test_volkswagen_pq.py @@ -82,7 +82,7 @@ class TestVolkswagenPqSafety(common.PandaSafetyTest): # Driver steering input torque def _lenkhilfe_3_msg(self, torque): - to_send = make_msg(0, MSG_LENKHILFE_3) + to_send = make_msg(0, MSG_LENKHILFE_3, 6) t = abs(torque) to_send[0].RDLR = ((t & 0x3FF) << 16) if torque < 0: @@ -94,7 +94,7 @@ class TestVolkswagenPqSafety(common.PandaSafetyTest): # openpilot steering output torque def _hca_1_msg(self, torque): - to_send = make_msg(0, MSG_HCA_1) + to_send = make_msg(0, MSG_HCA_1, 5) t = abs(torque) << 5 # DBC scale from centi-Nm to PQ network (approximated) to_send[0].RDLR = (t & 0x7FFF) << 16 if torque < 0: @@ -120,7 +120,7 @@ class TestVolkswagenPqSafety(common.PandaSafetyTest): # Cruise control buttons def _gra_neu_msg(self, bit): - to_send = make_msg(2, MSG_GRA_NEU) + to_send = make_msg(2, MSG_GRA_NEU, 4) to_send[0].RDLR = 1 << bit to_send[0].RDLR |= volkswagen_pq_checksum(to_send[0], MSG_GRA_NEU, 8) return to_send diff --git a/tests/safety_replay/Dockerfile b/tests/safety_replay/Dockerfile deleted file mode 100644 index 09236e6a..00000000 --- a/tests/safety_replay/Dockerfile +++ /dev/null @@ -1,46 +0,0 @@ -FROM ubuntu:16.04 - -RUN apt-get update && apt-get install -y \ - bzip2 \ - clang \ - curl \ - git \ - libarchive-dev \ - libbz2-dev \ - libcurl4-openssl-dev \ - libffi-dev \ - libssl-dev \ - libusb-1.0-0 \ - locales \ - make \ - python \ - python-pip \ - zlib1g-dev - -RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 - -RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash - -ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}" -RUN pyenv install 3.7.3 -RUN pyenv global 3.7.3 -RUN pyenv rehash - -COPY requirements.txt /tmp/ -RUN pip install -r /tmp/requirements.txt -COPY tests/safety_replay/requirements_extra.txt requirements_extra.txt -RUN pip install -r requirements_extra.txt -COPY tests/safety_replay/install_capnp.sh install_capnp.sh -RUN ./install_capnp.sh - -RUN git clone https://github.com/commaai/openpilot.git || true -WORKDIR /openpilot -RUN git pull && git checkout f9257fc75f68c673f9e433985fbe739f23310bb4 -RUN git submodule update --init cereal - -COPY . /openpilot/panda - -WORKDIR /openpilot/panda/tests/safety_replay diff --git a/tests/safety_replay/install_capnp.sh b/tests/safety_replay/install_capnp.sh deleted file mode 100755 index 51559d39..00000000 --- a/tests/safety_replay/install_capnp.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -e - -apt-get install -y autoconf curl libtool -curl -O https://capnproto.org/capnproto-c++-0.6.1.tar.gz -tar xvf capnproto-c++-0.6.1.tar.gz -cd capnproto-c++-0.6.1 -./configure --prefix=/usr/local CPPFLAGS=-DPIC CFLAGS=-fPIC CXXFLAGS=-fPIC LDFLAGS=-fPIC --disable-shared --enable-static -make -j4 -make install - diff --git a/tests/safety_replay/replay_drive.py b/tests/safety_replay/replay_drive.py index 456723cb..d6c806dc 100755 --- a/tests/safety_replay/replay_drive.py +++ b/tests/safety_replay/replay_drive.py @@ -4,7 +4,6 @@ import os import sys from panda.tests.safety import libpandasafety_py from panda.tests.safety_replay.helpers import package_can_msg, init_segment -from tools.lib.logreader import LogReader # pylint: disable=import-error # replay a drive to check for safety violations def replay_drive(lr, safety_mode, param): @@ -65,9 +64,13 @@ def replay_drive(lr, safety_mode, param): return tx_controls_blocked == 0 and rx_invalid == 0 if __name__ == "__main__": + from tools.lib.route import Route + from tools.lib.logreader import MultiLogIterator # pylint: disable=import-error + mode = int(sys.argv[2]) param = 0 if len(sys.argv) < 4 else int(sys.argv[3]) - lr = LogReader(sys.argv[1]) + r = Route(sys.argv[1]) + lr = MultiLogIterator(r.log_paths(), wraparound=False) print("replaying drive %s with safety mode %d and param %d" % (sys.argv[1], mode, param)) diff --git a/tests/safety_replay/requirements_extra.txt b/tests/safety_replay/requirements_extra.txt deleted file mode 100644 index 8034efc8..00000000 --- a/tests/safety_replay/requirements_extra.txt +++ /dev/null @@ -1,7 +0,0 @@ -aenum -subprocess32 -libarchive -pycapnp -pycurl -tenacity -atomicwrites diff --git a/tests/safety_replay/test_safety_replay.py b/tests/safety_replay/test_safety_replay.py index 1ba800a7..90913b11 100755 --- a/tests/safety_replay/test_safety_replay.py +++ b/tests/safety_replay/test_safety_replay.py @@ -37,6 +37,6 @@ if __name__ == "__main__": if not replay_drive(lr, mode, int(param)): failed.append(route) - for f in failed: - print("\n**** failed on %s ****" % f) + for f in failed: # type: ignore + print(f"\n**** failed on {f} ****") assert len(failed) == 0, "\nfailed on %d logs" % len(failed) diff --git a/tests/throughput_test.py b/tests/throughput_test.py index 9f602124..c02f0f76 100755 --- a/tests/throughput_test.py +++ b/tests/throughput_test.py @@ -19,7 +19,7 @@ if __name__ == "__main__": p_in = Panda("WIFI") print(p_in.get_serial()) - p_in = PandaWifiStreaming() + p_in = PandaWifiStreaming() # type: ignore #while True: # p_in.can_recv()