diff --git a/.coveragerc-app b/.coveragerc-app deleted file mode 100644 index 18c81e3b48..0000000000 --- a/.coveragerc-app +++ /dev/null @@ -1,3 +0,0 @@ -[run] -concurrency=multiprocessing - diff --git a/.editorconfig b/.editorconfig index e0da061025..879e6eebca 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,7 +5,7 @@ end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true -[{*.py, *.pyx, *pxd}] +[{*.py, *.pyx, *.pxd}] charset = utf-8 indent_style = space indent_size = 2 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 47b8af1905..a16eacbc69 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,26 +1,31 @@ --- name: Bug report -about: Create a report to help us improve openpilot +about: For issues with running openpilot on your comma device title: '' -labels: '' +labels: 'bug' assignees: '' - --- **Describe the bug** -A clear and concise description of what the bug is. + + **How to reproduce or log data** -Steps to reproduce the behavior, or a explorer/cabana link to the exact drive and timestamp of when the bug occurred. + + **Expected behavior** -A clear and concise description of what you expected to happen. + + **Device/Version information (please complete the following information):** - - Device: [e.g. EON/EON Gold] - - Dongle ID: [e.g. 77611a1fac303767, can be found in Settings -> Device -> Dongle ID] - - Version: [e.g. 0.6.4], or commit hash when on devel - - Car make/model [e.g. Toyota Prius 2016] + - Device: [e.g. EON/EON Gold/comma two] + - Dongle ID: [e.g. 77611a1fac303767, can be found in Settings -> Device -> Dongle ID or my.comma.ai/useradmin] + - Route: [e.g. 77611a1fac303767|2020-05-11--16-37-07, can be found in my.comma.ai/useradmin] + - Timestamp: [When in the route the bug occurs (e.g. 4min 30s into the drive)] + - Version: [commit hash when on a non-release branch, or version number when on devel or release2 (e.g. 0.7.6)] + - Car make/model: [e.g. Toyota Prius 2016] **Additional context** -Add any other context about the problem here. + + diff --git a/.github/ISSUE_TEMPLATE/bug_report_pc.md b/.github/ISSUE_TEMPLATE/bug_report_pc.md new file mode 100644 index 0000000000..c1471ec61c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report_pc.md @@ -0,0 +1,25 @@ +--- +name: PC Bug report +about: For issues with running openpilot on PC +title: '' +labels: 'PC' +assignees: '' +--- + +**Describe the bug** + + + +**How to reproduce or log data** + + + +**Expected behavior** + + + +**Additional context** + + + +Operating system: [e.g. Ubuntu 16.04] diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..fcb4dcd2a6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Community Wiki + url: https://github.com/commaai/openpilot/wiki + about: Check out our community wiki + - name: Community Discord + urli: https://discord.comma.ai + about: Check out our community discord diff --git a/.github/ISSUE_TEMPLATE/enhancement.md b/.github/ISSUE_TEMPLATE/enhancement.md new file mode 100644 index 0000000000..96a6047703 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/enhancement.md @@ -0,0 +1,8 @@ +--- +name: Enhancement +about: For suggestions for openpilot enhancements +title: '' +labels: 'enhancement' +assignees: '' +--- + diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 0000000000..2cd62791f9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,17 @@ +--- +name: Question +about: For questions about openpilot +title: '' +labels: 'question' +assignees: '' +--- + + diff --git a/.github/PULL_REQUEST_TEMPLATE/bugfix.md b/.github/PULL_REQUEST_TEMPLATE/bugfix.md new file mode 100644 index 0000000000..e28661db3b --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/bugfix.md @@ -0,0 +1,15 @@ +--- +name: Bug fix +about: For openpilot bug fixes +title: '' +labels: 'bugfix' +assignees: '' +--- + +**Description** + + + +**Verification** + + diff --git a/.github/PULL_REQUEST_TEMPLATE/car_bugfix.md b/.github/PULL_REQUEST_TEMPLATE/car_bugfix.md new file mode 100644 index 0000000000..d0c8bc58e4 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/car_bugfix.md @@ -0,0 +1,19 @@ +--- +name: Car Bug fix +about: For vehicle/brand specifc bug fixes +title: '' +labels: 'car bug fix' +assignees: '' +--- + +**Description** + + + +**Verification** + + + +**Route** + +Route: [a route with the bug fix] diff --git a/.github/PULL_REQUEST_TEMPLATE/car_port.md b/.github/PULL_REQUEST_TEMPLATE/car_port.md new file mode 100644 index 0000000000..b81c293885 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/car_port.md @@ -0,0 +1,14 @@ +--- +name: Car port +about: For new car ports +title: '' +labels: 'car port' +assignees: '' +--- + +**Checklist** + +- [ ] added to README +- [ ] test route added to [test_car_models](../../selfdrive/test/test_car_models.py) +- [ ] route with openpilot: +- [ ] route with stock system: diff --git a/.github/PULL_REQUEST_TEMPLATE/fingerprint.md b/.github/PULL_REQUEST_TEMPLATE/fingerprint.md new file mode 100644 index 0000000000..466d4f98f4 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/fingerprint.md @@ -0,0 +1,11 @@ +--- +name: Fingerprint +about: For adding fingerprints to existing cars +title: '' +labels: 'fingerprint' +assignees: '' +--- + +Discord username: [] + +Route: [] diff --git a/.github/PULL_REQUEST_TEMPLATE/refactor.md b/.github/PULL_REQUEST_TEMPLATE/refactor.md new file mode 100644 index 0000000000..1ee21c1bba --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/refactor.md @@ -0,0 +1,15 @@ +--- +name: Refactor +about: For code refactors +title: '' +labels: 'refactor' +assignees: '' +--- + +**Description** + + + +**Verification** + + diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..def16ca23e --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +version: 2 +updates: +- package-ecosystem: pip + directory: "/" + schedule: + interval: daily + time: '15:00' + open-pull-requests-limit: 10 diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..d09fb55490 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,38 @@ + + + + + + + + + diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index e8f4ad5511..7d0ae1f456 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -1,37 +1,25 @@ -name: Openpilot Tests -on: [push, pull_request] +name: openpilot tests +on: + push: + pull_request: + schedule: + - cron: '0 * * * *' env: RUN: docker run --shm-size 1G --rm tmppilot /bin/sh -c PERSIST: docker run --shm-size 1G --name tmppilot tmppilot /bin/sh -c - LOAD: docker load -i tmppilot.tar.gz/tmppilot.tar.gz CI_RUN: docker run -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID --rm tmppilotci /bin/bash -c UNIT_TEST: coverage run --append -m unittest discover + BUILD: | + docker pull $(grep -ioP '(?<=^from)\s+\S+' Dockerfile.openpilot) || true + docker pull docker.io/commaai/openpilotci:latest || true + docker build --cache-from docker.io/commaai/openpilotci:latest -t tmppilot -f Dockerfile.openpilot . jobs: - build: - name: build - runs-on: ubuntu-16.04 - steps: - - uses: actions/checkout@v2 - with: - submodules: true - - name: Build docker image - run: | - docker pull $(grep -ioP '(?<=^from)\s+\S+' Dockerfile.openpilot) || true - docker pull docker.io/commaai/openpilot:latest || true - - docker build --cache-from docker.io/commaai/openpilot:latest -t tmppilot -f Dockerfile.openpilot . - docker save tmppilot:latest | gzip > tmppilot.tar.gz - - uses: actions/upload-artifact@v2 - with: - name: tmppilot.tar.gz - path: tmppilot.tar.gz - build_release: name: build release runs-on: ubuntu-16.04 - timeout-minutes: 30 + timeout-minutes: 50 env: TEST_DIR: tmppilot steps: @@ -44,111 +32,151 @@ jobs: cp -pR --parents $(cat release/files_common) $TEST_DIR cp Dockerfile.openpilot $TEST_DIR - # copy submodules - cp -pR panda/ opendbc/ cereal/ $TEST_DIR - # need this to build on x86 cp -pR --parents phonelibs/libyuv phonelibs/snpe \ external/bin selfdrive/modeld/runners $TEST_DIR # need these so docker copy won't fail - cp Pipfile Pipfile.lock flake8_openpilot.sh pylint_openpilot.sh .pylintrc \ - .coveragerc-app $TEST_DIR + cp Pipfile Pipfile.lock .pylintrc .pre-commit-config.yaml $TEST_DIR cd $TEST_DIR - mkdir pyextra laika laika_repo tools release - - name: Build + mkdir laika laika_repo tools + - name: Build Docker image + run: cd $TEST_DIR && eval "$BUILD" + - name: Build openpilot and run quick check run: | - cd $TEST_DIR - docker pull $(grep -ioP '(?<=^from)\s+\S+' Dockerfile.openpilot) || true - docker pull docker.io/commaai/openpilot:latest || true - docker build --cache-from docker.io/commaai/openpilot:latest -t tmppilot -f Dockerfile.openpilot . + $RUN "cd /tmp/openpilot && \ + scons -j$(nproc) && \ + $UNIT_TEST selfdrive/car" - push: - name: push + build_mac: + name: build macos + runs-on: macos-10.15 + timeout-minutes: 35 + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Cache dependencies + id: dependency-cache + uses: actions/cache@v2 + with: + path: | + ~/.pyenv + ~/Library/Caches/pip + ~/Library/Caches/pipenv + ~/Library/Caches/Homebrew + key: ${{ hashFiles('tools/mac_setup.sh') }} + - name: Install dependencies + run: ./tools/mac_setup.sh + - name: Build openpilot + run: eval "$(pyenv init -)" && scons -j$(nproc) + - name: Brew cleanup + run: brew cleanup # keeps our cache small + + docker_push: + name: docker push runs-on: ubuntu-16.04 - needs: build + timeout-minutes: 50 if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' + needs: static_analysis # hack to ensure slow tests run first since this and static_analysis are fast steps: - - uses: actions/download-artifact@v1 + - uses: actions/checkout@v2 with: - name: tmppilot.tar.gz - - name: Load image - run: $LOAD - - name: Login to dockerhub - run: docker login -u wmelching -p ${{ secrets.DOCKERHUB_TOKEN }} - - name: Tag image - run: docker tag tmppilot docker.io/commaai/openpilot:latest - - name: Push image - run: docker push docker.io/commaai/openpilot:latest + submodules: true + - name: Build Docker image + run: eval "$BUILD" + - name: Push to dockerhub + run: | + docker login -u wmelching -p ${{ secrets.COMMA_DOCKERHUB_TOKEN}} + docker tag tmppilot docker.io/commaai/openpilotci:latest + docker push docker.io/commaai/openpilotci:latest - linter: - name: linter + docker_push_prebuilt: + name: docker push prebuilt runs-on: ubuntu-16.04 - needs: build + timeout-minutes: 50 + if: github.event_name == 'schedule' && github.repository == 'commaai/openpilot' + needs: [static_analysis, unit_tests, process_replay, test_longitudinal, test_car_models] steps: - - uses: actions/download-artifact@v1 + - uses: actions/checkout@v2 with: - name: tmppilot.tar.gz - - name: Load image - run: $LOAD - - name: flake8 - run: $RUN "cd /tmp/openpilot/ && ./flake8_openpilot.sh" - - name: pylint - run: $RUN "cd /tmp/openpilot/ && ./pylint_openpilot.sh" + submodules: true + - name: Build Docker image + run: echo "RUN cd /tmp/openpilot && scons -c && scons -j3" >> Dockerfile.openpilot && eval "$BUILD" + - name: Push to dockerhub + run: | + docker login -u wmelching -p ${{ secrets.COMMA_DOCKERHUB_TOKEN}} + docker tag tmppilot docker.io/commaai/openpilot:latest + docker push docker.io/commaai/openpilot:latest + + static_analysis: + name: static analysis + runs-on: ubuntu-16.04 + timeout-minutes: 50 + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Build Docker image + run: eval "$BUILD" + - name: pre-commit + run: $RUN "cd /tmp/openpilot/ && git init && git add -A && pre-commit run --all" unit_tests: name: unit tests runs-on: ubuntu-16.04 - needs: build + timeout-minutes: 50 steps: - - uses: actions/download-artifact@v1 + - uses: actions/checkout@v2 with: - name: tmppilot.tar.gz - - name: Load image - run: $LOAD + submodules: true + - name: Build Docker image + run: eval "$BUILD" - name: Run unit tests run: | $PERSIST "cd /tmp/openpilot && \ + scons -j$(nproc) && \ coverage run selfdrive/test/test_fingerprints.py && \ $UNIT_TEST common && \ $UNIT_TEST opendbc/can && \ $UNIT_TEST selfdrive/boardd && \ $UNIT_TEST selfdrive/controls && \ + $UNIT_TEST selfdrive/monitoring && \ $UNIT_TEST selfdrive/loggerd && \ $UNIT_TEST selfdrive/car && \ $UNIT_TEST selfdrive/locationd && \ $UNIT_TEST selfdrive/athena && \ + $UNIT_TEST selfdrive/thermald && \ $UNIT_TEST tools/lib/tests" - name: Upload coverage to Codecov run: | docker commit tmppilot tmppilotci - $CI_RUN "cd /tmp/openpilot && bash <(curl -s https://codecov.io/bash) -Z -F unit_tests" + $CI_RUN "cd /tmp/openpilot && bash <(curl -s https://codecov.io/bash) -v -F unit_tests" process_replay: name: process replay runs-on: ubuntu-16.04 - needs: build - timeout-minutes: 30 + timeout-minutes: 50 steps: - - uses: actions/download-artifact@v1 + - uses: actions/checkout@v2 with: - name: tmppilot.tar.gz - - name: Load image - run: $LOAD + submodules: true + - name: Build Docker image + run: eval "$BUILD" - name: Run replay run: | - $PERSIST "cd /tmp/openpilot && CI=1 coverage run selfdrive/test/process_replay/test_processes.py" + $PERSIST "cd /tmp/openpilot && \ + scons -j$(nproc) && \ + CI=1 coverage run selfdrive/test/process_replay/test_processes.py" - name: Upload coverage to Codecov run: | docker commit tmppilot tmppilotci - $CI_RUN "cd /tmp/openpilot && bash <(curl -s https://codecov.io/bash) -Z -F process_replay" - - name: Copy diff + $CI_RUN "cd /tmp/openpilot && bash <(curl -s https://codecov.io/bash) -v -F process_replay" + - name: Print diff if: always() run: | docker cp tmppilot:/tmp/openpilot/selfdrive/test/process_replay/diff.txt diff.txt - - name: Print diff - if: always() - run: cat diff.txt + cat diff.txt - uses: actions/upload-artifact@v2 if: always() with: @@ -158,17 +186,20 @@ jobs: test_longitudinal: name: longitudinal runs-on: ubuntu-16.04 - needs: build - timeout-minutes: 30 + timeout-minutes: 50 steps: - - uses: actions/download-artifact@v1 + - uses: actions/checkout@v2 with: - name: tmppilot.tar.gz - - name: Load image - run: $LOAD + submodules: true + - name: Build Docker image + run: eval "$BUILD" - name: Test longitudinal run: | - $PERSIST "cd /tmp/openpilot/selfdrive/test/longitudinal_maneuvers && OPTEST=1 ./test_longitudinal.py" + $PERSIST "mkdir -p /tmp/openpilot/selfdrive/test/out && \ + cd /tmp/openpilot/ && \ + scons -j$(nproc) && \ + cd selfdrive/test/longitudinal_maneuvers && \ + OPTEST=1 ./test_longitudinal.py" - name: Copy artifacts if: always() run: | @@ -183,18 +214,21 @@ jobs: test_car_models: name: test car models runs-on: ubuntu-16.04 - needs: build - timeout-minutes: 30 + timeout-minutes: 50 steps: - - uses: actions/download-artifact@v1 + - uses: actions/checkout@v2 with: - name: tmppilot.tar.gz - - name: Load image - run: $LOAD + submodules: true + - name: Build Docker image + run: eval "$BUILD" - name: Test car models run: | - $PERSIST "mkdir -p /data/params && cd /tmp/openpilot && coverage run --parallel-mode --concurrency=multiprocessing --rcfile=./.coveragerc-app selfdrive/test/test_car_models.py && coverage combine" + $PERSIST "cd /tmp/openpilot && \ + scons -j$(nproc) && \ + coverage run --parallel-mode -m nose --processes=4 --process-timeout=60 \ + selfdrive/test/test_models.py && \ + coverage combine" - name: Upload coverage to Codecov run: | docker commit tmppilot tmppilotci - $CI_RUN "cd /tmp/openpilot && bash <(curl -s https://codecov.io/bash) -Z -F test_car_models" + $CI_RUN "cd /tmp/openpilot && bash <(curl -s https://codecov.io/bash) -v -F test_car_models" diff --git a/.github/workflows/update-pipfile.yml b/.github/workflows/update-pipfile.yml new file mode 100644 index 0000000000..15bab0ec38 --- /dev/null +++ b/.github/workflows/update-pipfile.yml @@ -0,0 +1,23 @@ +name: "Update Pipfile.lock" +on: + schedule: + - cron: '00 15 * * 1' # Every monday on 15:00 UTC + +jobs: + piplock: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + - run: pip install wheel + - run: pip install pipenv + - run: pipenv lock + - uses: actions/upload-artifact@v2 + with: + name: "Pipfile lock" + path: Pipfile.lock + - uses: peter-evans/create-pull-request@v2 + with: + title: "Update Pipfile.lock (dependencies)" + branch: update-pipfile + commit-message: "[Bot] Update Pipfile.lock dependencies" diff --git a/.gitignore b/.gitignore index c6efe5cf35..b8d9a39b4a 100644 --- a/.gitignore +++ b/.gitignore @@ -54,9 +54,15 @@ openpilot notebooks xx panda_jungle +apks +openpilot-apks .coverage* coverage.xml htmlcov pandaextra +.mypy_cache/ +flycheck_* + +cppcheck_report.txt diff --git a/.gitmodules b/.gitmodules index 3d228f5cd3..1e6110b7a6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,13 +7,9 @@ [submodule "laika_repo"] path = laika_repo url = ../../commaai/laika.git -[submodule "apks"] - path = apks - url = ../../commaai/openpilot-apks.git [submodule "cereal"] path = cereal url = ../../commaai/cereal.git - [submodule "rednose_repo"] path = rednose_repo url = ../../commaai/rednose.git diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..1cd805de4a --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,47 @@ +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 + - id: check-merge-conflict + - id: check-symlinks +- repo: https://github.com/pre-commit/mirrors-mypy + rev: master + hooks: + - id: mypy + exclude: '^(pyextra)|(external)|(cereal)|(rednose)|(panda)|(laika)|(opendbc)|(laika_repo)|(rednose_repo)/' + additional_dependencies: ['git+https://github.com/numpy/numpy-stubs'] +- repo: https://github.com/PyCQA/flake8 + rev: master + hooks: + - id: flake8 + exclude: '^(pyextra)|(external)|(cereal)|(rednose)|(panda)|(laika)|(opendbc)|(laika_repo)|(rednose_repo)|(selfdrive/debug)/' + args: + - --select=F,E112,E113,E304,E501,E502,E701,E702,E703,E71,E72,E731,W191,W6 + - --max-line-length=240 + - --statistics +- repo: local + hooks: + - id: pylint + name: pylint + entry: pylint + language: system + types: [python] + exclude: '^(pyextra)|(external)|(cereal)|(rednose)|(panda)|(laika)|(laika_repo)|(rednose_repo)/' +- repo: local + hooks: + - id: cppcheck + name: cppcheck + entry: cppcheck + language: system + types: [c++] + exclude: '^(phonelibs)|(external)|(cereal)|(opendbc)|(panda)|(tools)|(selfdrive/modeld/thneed/debug)|(selfdrive/modeld/test)|(selfdrive/camerad/test)/|(installer)' + args: + - --error-exitcode=1 + - --language=c++ + - --quiet + - --force + - -j8 diff --git a/.pylintrc b/.pylintrc index 64a55daf8f..be7701c906 100644 --- a/.pylintrc +++ b/.pylintrc @@ -3,7 +3,7 @@ # 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 +extension-pkg-whitelist=scipy cereal.messaging.messaging_pyx # Add files or directories to the blacklist. They should be base names, not # paths. @@ -54,121 +54,7 @@ confidence= # --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 +disable=C,R,W0613,W0511,W0212,W0201,W0311,W0106,W0603,W0621,W0703,E1136 # Enable the message, report, category or checker with the given id(s). You can diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dc42a314a5..b8564c1e85 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ Our software is open source so you can solve your own problems without needing help from others. And if you solve a problem and are so kind, you can upstream it for the rest of the world to use. -Most open source development activity is coordinated through our [Discord](https://discord.comma.ai). A lot of documentation is available on our [medium](https://medium.com/@comma_ai/) +Most open source development activity is coordinated through our [Discord](https://discord.comma.ai). A lot of documentation is available on our [medium](https://medium.com/@comma_ai/). ## Getting Started @@ -18,11 +18,11 @@ You can test your changes on your machine by running `run_docker_tests.sh`. This ### Automated Testing -All PRs are automatically checked by Github Actions. Check out `.github/workflows/` for what Github Actions runs. Any new tests sould be added to Github Actions. +All PRs and commits are automatically checked by Github Actions. Check out `.github/workflows/` for what Github Actions runs. Any new tests sould be added to Github Actions. ### Code Style and Linting -Code is automatically checked for style by Github Actions as part of the automated tests. You can also run these tests yourself by running `pylint_openpilot.sh` and `flake8_openpilot.sh`. +Code is automatically checked for style by Github Actions as part of the automated tests. You can also run these tests yourself by running `pre-commit run --all`. ## Car Ports (openpilot) @@ -48,3 +48,4 @@ Modules that are in seperate repositories include: * laika * opendbc * panda +* rednose diff --git a/Dockerfile.openpilot b/Dockerfile.openpilot index a9f58f752c..8577282126 100644 --- a/Dockerfile.openpilot +++ b/Dockerfile.openpilot @@ -1,7 +1,8 @@ FROM ubuntu:16.04 ENV PYTHONUNBUFFERED 1 +ENV PYTHONPATH /tmp/openpilot:${PYTHONPATH} -RUN apt-get update && apt-get install -y \ +RUN apt-get update && apt-get install -y --no-install-recommends \ autoconf \ build-essential \ bzip2 \ @@ -9,9 +10,11 @@ RUN apt-get update && apt-get install -y \ libcapnp-dev \ clang \ cmake \ + cppcheck \ curl \ ffmpeg \ git \ + iputils-ping \ libarchive-dev \ libbz2-dev \ libcurl4-openssl-dev \ @@ -22,12 +25,10 @@ RUN apt-get update && apt-get install -y \ libglfw3-dev \ libglib2.0-0 \ liblzma-dev \ - libmysqlclient-dev \ libomp-dev \ libopencv-dev \ libssl-dev \ libsqlite3-dev \ - libtool \ libusb-1.0-0-dev \ libczmq-dev \ libzmq3-dev \ @@ -37,11 +38,10 @@ RUN apt-get update && apt-get install -y \ opencl-headers \ python-dev \ python-pip \ - screen \ + qt5-default \ sudo \ - vim \ - wget - + wget \ + && 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 @@ -49,49 +49,51 @@ 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.8.2 -RUN pyenv global 3.8.2 -RUN pyenv rehash - -RUN pip install pipenv==2018.11.26 -COPY Pipfile /tmp/ -COPY Pipfile.lock /tmp/ - -RUN python --version -RUN cd /tmp && pipenv install --system --deploy - -# Install subset of dev dependencies needed for CI -RUN pip install matplotlib==3.1.1 dictdiffer==0.8.0 fastcluster==1.1.25 aenum==2.2.1 lru-dict==1.1.6 scipy==1.4.1 tenacity==5.1.1 azure-common==1.1.23 azure-nspkg==3.0.2 azure-storage-blob==2.1.0 azure-storage-common==2.1.0 azure-storage-nspkg==3.1.0 pycurl==7.43.0.3 coverage==5.1 - -ENV PATH="/tmp/openpilot/external/bin:${PATH}" -ENV PYTHONPATH /tmp/openpilot:${PYTHONPATH} +COPY Pipfile Pipfile.lock /tmp/ +RUN pyenv install 3.8.2 && \ + pyenv global 3.8.2 && \ + pyenv rehash && \ + pip install --no-cache-dir --upgrade pip==20.1.1 && \ + pip install --no-cache-dir pipenv==2018.11.26 && \ + cd /tmp && \ + pipenv install --system --deploy --clear && \ + pip uninstall -y pipenv && \ + pip install --no-cache-dir \ + matplotlib==3.1.1 \ + dictdiffer==0.8.0 \ + fastcluster==1.1.25 \ + aenum==2.2.1 \ + lru-dict==1.1.6 \ + scipy==1.4.1 \ + tenacity==5.1.1 \ + azure-common==1.1.23 \ + azure-nspkg==3.0.2 \ + azure-storage-blob==2.1.0 \ + azure-storage-common==2.1.0 \ + azure-storage-nspkg==3.1.0 \ + pycurl==7.43.0.3 \ + coverage==5.1 \ + pre-commit==2.4.0 \ + parameterized==0.7.4 RUN mkdir -p /tmp/openpilot -COPY ./flake8_openpilot.sh /tmp/openpilot/ -COPY ./pylint_openpilot.sh /tmp/openpilot/ -COPY ./.pylintrc /tmp/openpilot/ - -COPY ./.coveragerc-app /tmp/openpilot/ +COPY SConstruct \ + .pylintrc \ + .pre-commit-config.yaml \ + /tmp/openpilot/ COPY ./pyextra /tmp/openpilot/pyextra COPY ./phonelibs /tmp/openpilot/phonelibs -COPY ./external /tmp/openpilot/external COPY ./laika /tmp/openpilot/laika COPY ./laika_repo /tmp/openpilot/laika_repo +COPY ./rednose /tmp/openpilot/rednose COPY ./tools /tmp/openpilot/tools COPY ./release /tmp/openpilot/release COPY ./common /tmp/openpilot/common COPY ./opendbc /tmp/openpilot/opendbc COPY ./cereal /tmp/openpilot/cereal COPY ./panda /tmp/openpilot/panda -COPY ./rednose /tmp/openpilot/rednose COPY ./selfdrive /tmp/openpilot/selfdrive - -COPY SConstruct /tmp/openpilot/SConstruct - -RUN mkdir -p /tmp/openpilot/selfdrive/test/out -RUN cd /tmp/openpilot && scons -j$(nproc) diff --git a/Jenkinsfile b/Jenkinsfile index d34cd70375..dd0e2c12fa 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,25 +1,147 @@ -pipeline { - agent { - docker { - image 'python:3.7.3' - args '--user=root' - } +def phone(String ip, String step_label, String cmd) { + def ci_env = "CI=1 TEST_DIR=${env.TEST_DIR} GIT_BRANCH=${env.GIT_BRANCH} GIT_COMMIT=${env.GIT_COMMIT}" + + withCredentials([file(credentialsId: 'id_rsa_public', variable: 'key_file')]) { + sh label: step_label, + script: """ + ssh -tt -o StrictHostKeyChecking=no -i ${key_file} -p 8022 root@${ip} '${ci_env} /usr/bin/bash -le' <<'EOF' +echo \$\$ > /dev/cpuset/app/tasks || true +echo \$PPID > /dev/cpuset/app/tasks || true +mkdir -p /dev/shm +chmod 777 /dev/shm +cd ${env.TEST_DIR} || true +${cmd} +exit 0 +EOF""" + } +} +def phone_steps(String device_type, steps) { + lock(resource: "", label: device_type, inversePrecedence: true, variable: 'device_ip', quantity: 1) { + timeout(time: 60, unit: 'MINUTES') { + phone(device_ip, "kill old processes", "pkill -f comma || true") + phone(device_ip, "git checkout", readFile("selfdrive/test/setup_device_ci.sh"),) + steps.each { item -> + phone(device_ip, item[0], item[1]) + } + } } +} + +pipeline { + agent none environment { COMMA_JWT = credentials('athena-test-jwt') + TEST_DIR = "/data/openpilot" } + stages { - stage('EON Build/Test') { + + stage('Release Build') { + agent { + docker { + image 'python:3.7.3' + args '--user=root' + } + } + when { + branch 'devel-staging' + } steps { - lock(resource: "", label: 'eon', inversePrecedence: true, variable: 'eon_name', quantity: 1){ - timeout(time: 30, unit: 'MINUTES') { - dir(path: 'release') { - sh 'pip install paramiko' - sh 'python remote_build.py' + phone_steps("eon-build", [ + ["build release2-staging and dashcam-staging", "cd release && PUSH=1 ./build_release2.sh"], + ]) + } + } + + stage('openpilot tests') { + when { + not { + anyOf { + branch 'master-ci'; branch 'devel'; branch 'devel-staging'; branch 'release2'; branch 'release2-staging'; branch 'dashcam'; branch 'dashcam-staging' + } + } + } + + + stages { + + /* + stage('PC tests') { + agent { + dockerfile { + filename 'Dockerfile.openpilot' + args '--privileged --shm-size=1G --user=root' + } + } + stages { + stage('Build') { + steps { + sh 'scons -j$(nproc)' + } + } + } + post { + always { + // fix permissions since docker runs as another user + sh "chmod -R 777 ." + } + } + } + */ + + stage('On-device Tests') { + agent { + docker { + image 'python:3.7.3' + args '--user=root' + } + } + + stages { + stage('parallel tests') { + parallel { + + stage('Devel Build') { + environment { + CI_PUSH = "${env.BRANCH_NAME == 'master' ? 'master-ci' : ' '}" + } + steps { + phone_steps("eon", [ + ["build devel", "cd release && CI_PUSH=${env.CI_PUSH} ./build_devel.sh"], + ["test openpilot", "nosetests -s selfdrive/test/test_openpilot.py"], + ["test cpu usage", "cd selfdrive/test/ && ./test_cpu_usage.py"], + ["test car interfaces", "cd selfdrive/car/tests/ && ./test_car_interfaces.py"], + ["test spinner build", "cd selfdrive/ui/spinner && make clean && make"], + ["test text window build", "cd selfdrive/ui/text && make clean && make"], + ]) + } + } + + stage('Replay Tests') { + steps { + phone_steps("eon2", [ + ["camerad/modeld replay", "cd selfdrive/test/process_replay && ./camera_replay.py"], + ]) + } + } + + stage('HW + Unit Tests') { + steps { + phone_steps("eon", [ + ["build cereal", "SCONS_CACHE=1 scons -j4 cereal/"], + ["test sounds", "nosetests -s selfdrive/test/test_sounds.py"], + ["test boardd loopback", "nosetests -s selfdrive/boardd/tests/test_boardd_loopback.py"], + //["test updater", "python installer/updater/test_updater.py"], + ]) + } + } + + } } } } + } } } diff --git a/Pipfile b/Pipfile index 9d1f3a3bba..331be0c46f 100644 --- a/Pipfile +++ b/Pipfile @@ -6,20 +6,18 @@ verify_ssl = true [dev-packages] opencv-python= "*" ipython = "*" -networkx = "==2.3" +networkx = "~=2.3" azure-core = "*" azure-common = "*" -azure-nspkg = "==3.0.2" -azure-storage-blob = "==2.1.0" -azure-storage-common = "==2.1.0" -azure-storage-nspkg = "==3.1.0" +azure-nspkg = "~=3.0" +azure-storage-blob = "~=2.1" +azure-storage-common = "~=2.1" +azure-storage-nspkg = "~=3.1" boto = "*" "boto3" = "*" control = "*" datadog = "*" -dlib = "*" elasticsearch = "*" -pycocotools = {git = "https://github.com/cocodataset/cocoapi.git",subdirectory = "PythonAPI"} gunicorn = "*" "h5py" = "*" hexdump = "*" @@ -41,9 +39,9 @@ redis = "*" "s2sphere" = "*" "subprocess32" = "*" tenacity = "*" -tensorflow-gpu = "==2.2.0" +tensorflow = "==2.2" keras_applications = "*" -PyMySQL = "==0.9.2" +PyMySQL = "~=0.9" Werkzeug = "*" "backports.lzma" = "*" Flask-Cors = "*" @@ -69,9 +67,12 @@ paramiko = "*" aiohttp = "*" lru-dict = "*" scikit-image = "*" -pygame = "==2.0.0.dev6" +pygame = "==2.0.0.dev8" pprofile = "*" pyprof2calltree = "*" +pre-commit = "*" +mypy = "*" +parameterized = "*" [packages] atomicwrites = "*" @@ -90,7 +91,7 @@ requests = "*" setproctitle = "*" six = "*" smbus2 = "*" -sympy = "*" +sympy = "!=1.6.1" tqdm = "*" Cython = "*" PyYAML = "*" @@ -107,10 +108,10 @@ pylint = "*" pillow = "*" scons = "*" cysignals = "*" -pycryptodome = "*" -"Jinja2" = "*" -PyJWT = "*" +pycryptodome = "*" +"Jinja2" = "*" +PyJWT = "*" pyserial = "*" [requires] -python_version = "3.8.2" +python_version = "3.8" diff --git a/Pipfile.lock b/Pipfile.lock index fbd754bd5f..4a91f0a357 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,11 +1,11 @@ { "_meta": { "hash": { - "sha256": "2fca285af32720e957e1fc42d7c512e9b9a2e93b416602f77d8129d7fd8efedc" + "sha256": "d19d5f456b6901c49898a3f7d372874e59b09ac32a57c03a28b0a633fe5d6108" }, "pipfile-spec": 6, "requires": { - "python_version": "3.8.2" + "python_version": "3.8" }, "sources": [ { @@ -18,11 +18,11 @@ "default": { "astroid": { "hashes": [ - "sha256:4c17cea3e592c21b6e222f673868961bad77e1f985cb1694ed077475a89229c1", - "sha256:d8506842a3faf734b81599c8b98dcc423de863adcc1999248480b18bd31a0f38" + "sha256:2f4078c2a41bf377eea06d71c9d2ba4eb8f6b1af2135bec27bbbb7d8f12bb703", + "sha256:bc58d83eb610252fd8de6363e39d4f1d0619c894b0ed24603b881c02e64c7386" ], "markers": "python_version >= '3.5'", - "version": "==2.4.1" + "version": "==2.4.2" }, "atomicwrites": { "hashes": [ @@ -34,44 +34,44 @@ }, "certifi": { "hashes": [ - "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304", - "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519" + "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3", + "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41" ], - "version": "==2020.4.5.1" + "version": "==2020.6.20" }, "cffi": { "hashes": [ - "sha256:001bf3242a1bb04d985d63e138230802c6c8d4db3668fb545fb5005ddf5bb5ff", - "sha256:00789914be39dffba161cfc5be31b55775de5ba2235fe49aa28c148236c4e06b", - "sha256:028a579fc9aed3af38f4892bdcc7390508adabc30c6af4a6e4f611b0c680e6ac", - "sha256:14491a910663bf9f13ddf2bc8f60562d6bc5315c1f09c704937ef17293fb85b0", - "sha256:1cae98a7054b5c9391eb3249b86e0e99ab1e02bb0cc0575da191aedadbdf4384", - "sha256:2089ed025da3919d2e75a4d963d008330c96751127dd6f73c8dc0c65041b4c26", - "sha256:2d384f4a127a15ba701207f7639d94106693b6cd64173d6c8988e2c25f3ac2b6", - "sha256:337d448e5a725bba2d8293c48d9353fc68d0e9e4088d62a9571def317797522b", - "sha256:399aed636c7d3749bbed55bc907c3288cb43c65c4389964ad5ff849b6370603e", - "sha256:3b911c2dbd4f423b4c4fcca138cadde747abdb20d196c4a48708b8a2d32b16dd", - "sha256:3d311bcc4a41408cf5854f06ef2c5cab88f9fded37a3b95936c9879c1640d4c2", - "sha256:62ae9af2d069ea2698bf536dcfe1e4eed9090211dbaafeeedf5cb6c41b352f66", - "sha256:66e41db66b47d0d8672d8ed2708ba91b2f2524ece3dee48b5dfb36be8c2f21dc", - "sha256:675686925a9fb403edba0114db74e741d8181683dcf216be697d208857e04ca8", - "sha256:7e63cbcf2429a8dbfe48dcc2322d5f2220b77b2e17b7ba023d6166d84655da55", - "sha256:8a6c688fefb4e1cd56feb6c511984a6c4f7ec7d2a1ff31a10254f3c817054ae4", - "sha256:8c0ffc886aea5df6a1762d0019e9cb05f825d0eec1f520c51be9d198701daee5", - "sha256:95cd16d3dee553f882540c1ffe331d085c9e629499ceadfbda4d4fde635f4b7d", - "sha256:99f748a7e71ff382613b4e1acc0ac83bf7ad167fb3802e35e90d9763daba4d78", - "sha256:b8c78301cefcf5fd914aad35d3c04c2b21ce8629b5e4f4e45ae6812e461910fa", - "sha256:c420917b188a5582a56d8b93bdd8e0f6eca08c84ff623a4c16e809152cd35793", - "sha256:c43866529f2f06fe0edc6246eb4faa34f03fe88b64a0a9a942561c8e22f4b71f", - "sha256:cab50b8c2250b46fe738c77dbd25ce017d5e6fb35d3407606e7a4180656a5a6a", - "sha256:cef128cb4d5e0b3493f058f10ce32365972c554572ff821e175dbc6f8ff6924f", - "sha256:cf16e3cf6c0a5fdd9bc10c21687e19d29ad1fe863372b5543deaec1039581a30", - "sha256:e56c744aa6ff427a607763346e4170629caf7e48ead6921745986db3692f987f", - "sha256:e577934fc5f8779c554639376beeaa5657d54349096ef24abe8c74c5d9c117c3", - "sha256:f2b0fa0c01d8a0c7483afd9f31d7ecf2d71760ca24499c8697aeb5ca37dc090c" - ], - "index": "pypi", - "version": "==1.14.0" + "sha256:267adcf6e68d77ba154334a3e4fc921b8e63cbb38ca00d33d40655d4228502bc", + "sha256:26f33e8f6a70c255767e3c3f957ccafc7f1f706b966e110b855bfe944511f1f9", + "sha256:3cd2c044517f38d1b577f05927fb9729d3396f1d44d0c659a445599e79519792", + "sha256:4a03416915b82b81af5502459a8a9dd62a3c299b295dcdf470877cb948d655f2", + "sha256:4ce1e995aeecf7cc32380bc11598bfdfa017d592259d5da00fc7ded11e61d022", + "sha256:4f53e4128c81ca3212ff4cf097c797ab44646a40b42ec02a891155cd7a2ba4d8", + "sha256:4fa72a52a906425416f41738728268072d5acfd48cbe7796af07a923236bcf96", + "sha256:66dd45eb9530e3dde8f7c009f84568bc7cac489b93d04ac86e3111fb46e470c2", + "sha256:6923d077d9ae9e8bacbdb1c07ae78405a9306c8fd1af13bfa06ca891095eb995", + "sha256:833401b15de1bb92791d7b6fb353d4af60dc688eaa521bd97203dcd2d124a7c1", + "sha256:8416ed88ddc057bab0526d4e4e9f3660f614ac2394b5e019a628cdfff3733849", + "sha256:892daa86384994fdf4856cb43c93f40cbe80f7f95bb5da94971b39c7f54b3a9c", + "sha256:98be759efdb5e5fa161e46d404f4e0ce388e72fbf7d9baf010aff16689e22abe", + "sha256:a6d28e7f14ecf3b2ad67c4f106841218c8ab12a0683b1528534a6c87d2307af3", + "sha256:b1d6ebc891607e71fd9da71688fcf332a6630b7f5b7f5549e6e631821c0e5d90", + "sha256:b2a2b0d276a136146e012154baefaea2758ef1f56ae9f4e01c612b0831e0bd2f", + "sha256:b87dfa9f10a470eee7f24234a37d1d5f51e5f5fa9eeffda7c282e2b8f5162eb1", + "sha256:bac0d6f7728a9cc3c1e06d4fcbac12aaa70e9379b3025b27ec1226f0e2d404cf", + "sha256:c991112622baee0ae4d55c008380c32ecfd0ad417bcd0417ba432e6ba7328caa", + "sha256:cda422d54ee7905bfc53ee6915ab68fe7b230cacf581110df4272ee10462aadc", + "sha256:d3148b6ba3923c5850ea197a91a42683f946dba7e8eb82dfa211ab7e708de939", + "sha256:d6033b4ffa34ef70f0b8086fd4c3df4bf801fee485a8a7d4519399818351aa8e", + "sha256:ddff0b2bd7edcc8c82d1adde6dbbf5e60d57ce985402541cd2985c27f7bec2a0", + "sha256:e23cb7f1d8e0f93addf0cae3c5b6f00324cccb4a7949ee558d7b6ca973ab8ae9", + "sha256:effd2ba52cee4ceff1a77f20d2a9f9bf8d50353c854a282b8760ac15b9833168", + "sha256:f90c2267101010de42f7273c94a1f026e56cbc043f9330acd8a80e64300aba33", + "sha256:f960375e9823ae6a07072ff7f8a85954e5a6434f97869f50d0e41649a1c8144f", + "sha256:fcf32bf76dc25e30ed793145a57426064520890d7c02866eb93d3e4abe516948" + ], + "index": "pypi", + "version": "==1.14.1" }, "chardet": { "hashes": [ @@ -100,28 +100,28 @@ }, "cryptography": { "hashes": [ - "sha256:091d31c42f444c6f519485ed528d8b451d1a0c7bf30e8ca583a0cac44b8a0df6", - "sha256:18452582a3c85b96014b45686af264563e3e5d99d226589f057ace56196ec78b", - "sha256:1dfa985f62b137909496e7fc182dac687206d8d089dd03eaeb28ae16eec8e7d5", - "sha256:1e4014639d3d73fbc5ceff206049c5a9a849cefd106a49fa7aaaa25cc0ce35cf", - "sha256:22e91636a51170df0ae4dcbd250d318fd28c9f491c4e50b625a49964b24fe46e", - "sha256:3b3eba865ea2754738616f87292b7f29448aec342a7c720956f8083d252bf28b", - "sha256:651448cd2e3a6bc2bb76c3663785133c40d5e1a8c1a9c5429e4354201c6024ae", - "sha256:726086c17f94747cedbee6efa77e99ae170caebeb1116353c6cf0ab67ea6829b", - "sha256:844a76bc04472e5135b909da6aed84360f522ff5dfa47f93e3dd2a0b84a89fa0", - "sha256:88c881dd5a147e08d1bdcf2315c04972381d026cdb803325c03fe2b4a8ed858b", - "sha256:96c080ae7118c10fcbe6229ab43eb8b090fccd31a09ef55f83f690d1ef619a1d", - "sha256:a0c30272fb4ddda5f5ffc1089d7405b7a71b0b0f51993cb4e5dbb4590b2fc229", - "sha256:bb1f0281887d89617b4c68e8db9a2c42b9efebf2702a3c5bf70599421a8623e3", - "sha256:c447cf087cf2dbddc1add6987bbe2f767ed5317adb2d08af940db517dd704365", - "sha256:c4fd17d92e9d55b84707f4fd09992081ba872d1a0c610c109c18e062e06a2e55", - "sha256:d0d5aeaedd29be304848f1c5059074a740fa9f6f26b84c5b63e8b29e73dfc270", - "sha256:daf54a4b07d67ad437ff239c8a4080cfd1cc7213df57d33c97de7b4738048d5e", - "sha256:e993468c859d084d5579e2ebee101de8f5a27ce8e2159959b6673b418fd8c785", - "sha256:f118a95c7480f5be0df8afeb9a11bd199aa20afab7a96bcf20409b411a3a85f0" - ], - "index": "pypi", - "version": "==2.9.2" + "sha256:0c608ff4d4adad9e39b5057de43657515c7da1ccb1807c3a27d4cf31fc923b4b", + "sha256:0cbfed8ea74631fe4de00630f4bb592dad564d57f73150d6f6796a24e76c76cd", + "sha256:124af7255ffc8e964d9ff26971b3a6153e1a8a220b9a685dc407976ecb27a06a", + "sha256:384d7c681b1ab904fff3400a6909261cae1d0939cc483a68bdedab282fb89a07", + "sha256:45741f5499150593178fc98d2c1a9c6722df88b99c821ad6ae298eff0ba1ae71", + "sha256:4b9303507254ccb1181d1803a2080a798910ba89b1a3c9f53639885c90f7a756", + "sha256:4d355f2aee4a29063c10164b032d9fa8a82e2c30768737a2fd56d256146ad559", + "sha256:51e40123083d2f946794f9fe4adeeee2922b581fa3602128ce85ff813d85b81f", + "sha256:8713ddb888119b0d2a1462357d5946b8911be01ddbf31451e1d07eaa5077a261", + "sha256:8e924dbc025206e97756e8903039662aa58aa9ba357d8e1d8fc29e3092322053", + "sha256:8ecef21ac982aa78309bb6f092d1677812927e8b5ef204a10c326fc29f1367e2", + "sha256:8ecf9400d0893836ff41b6f977a33972145a855b6efeb605b49ee273c5e6469f", + "sha256:9367d00e14dee8d02134c6c9524bb4bd39d4c162456343d07191e2a0b5ec8b3b", + "sha256:a09fd9c1cca9a46b6ad4bea0a1f86ab1de3c0c932364dbcf9a6c2a5eeb44fa77", + "sha256:ab49edd5bea8d8b39a44b3db618e4783ef84c19c8b47286bf05dfdb3efb01c83", + "sha256:bea0b0468f89cdea625bb3f692cd7a4222d80a6bdafd6fb923963f2b9da0e15f", + "sha256:bec7568c6970b865f2bcebbe84d547c52bb2abadf74cefce396ba07571109c67", + "sha256:ce82cc06588e5cbc2a7df3c8a9c778f2cb722f56835a23a68b5a7264726bb00c", + "sha256:dea0ba7fe6f9461d244679efa968d215ea1f989b9c1957d7f10c21e5c7c09ad6" + ], + "index": "pypi", + "version": "==3.0" }, "cysignals": { "hashes": [ @@ -132,50 +132,50 @@ }, "cython": { "hashes": [ - "sha256:00faa77500ca2f865fd7f3126f86e77de3ec0d855dd6cf92fc85b57ebed11655", - "sha256:14e218a93d4f2e43e0063a5a0f7f26fe1783d5d20700216c5c4ff092c4553488", - "sha256:179ad5569dc101e3e0d9d04305f9a5e03fbf8acf9d93fb543340f8c1a8fb054b", - "sha256:20cdf3f918c46355128d7c7cb041872ba2863cc11313972c6e390bd3dad968ba", - "sha256:2a98c9f852b266f0b9a147da4b6699cf6da24b817375f74d51986312373689ab", - "sha256:3950ae725472ae47bfb41c6bfdb3869a8ac27b5f30405f599a51398512afa224", - "sha256:4dbb58f963f6283b31b4ddac44e4f684527b06923efdec72ecb54e70ee91c766", - "sha256:4e8d351ee840a4e491f8f0a64da19923ada0ce09d2d818bce0ae6ce1b6837aeb", - "sha256:4f35752adfd4855d39e38bf08eb6d02f7aa88b1bb420ab86e6d2e37ccd7c88c2", - "sha256:5c501742a92cbcef8f3c21d1dcba9c073b37f1218af3586957901730ac6b6665", - "sha256:6361588cb1d82875bcfbad83d7dd66c442099759f895cf547995f00601f9caf2", - "sha256:719eddf050a1c8b0abbd74b0c388523cf618c3d9fe3bf20a350f4eafa43776e6", - "sha256:785d6e88a3bb10ce6425d23f0a740a21b0bfc9e8d371fea7edba0eaa0ec57d96", - "sha256:788192badd3b1ebb1a72a5c6cc2a07b692ca4c1c1fe4431fdd3c0e439e2c0a6d", - "sha256:7c8ac5bc9726ccb1a1cce1af4ceb7589228db6c57ada3bfcd461075abe3a6a7b", - "sha256:7cec6bd82fd92f85790908fdc7a43a8a5442606e6d771d5b32a1ab8a39ad1a65", - "sha256:7d597733ad0e7fc545df39100ee3b24290ce35586466dee4fa6018d4b8815d72", - "sha256:809896928abce18e7c91a28b2705473ca4f15b9a53f433495845a882e15c09d8", - "sha256:8135cc7de72805833a118e7c8a255daddd35875d17ea21f6c356200b0fa4b732", - "sha256:86ae455b1dd7041b4b8a15499fe72f3d3f990f78a794deb799ee2ef7db389ca0", - "sha256:8ef49cafea89d99ffc2cf37af2f0f2b7d219080574f14a422f701bcaa85c7167", - "sha256:96d18413a33aa5ce51a5554615ba01e3fdb26126d8678459330d052f0bdf60ec", - "sha256:a5ebd8fe5a3d97924bd89d449914d1c5b6d084f4b124a4eb28e4412d09fb0f20", - "sha256:b19a1aa98192d44d7254613a1f9c382ef381deb79289f2ff446d1447d19085aa", - "sha256:b6f7d2cf2f6b246fd04696d6d346489628f94f72a4988682ea0591b632370a1f", - "sha256:c56f658ab6f387619a3668cd78cf2d3459324d9ea3cb39cce4d72ef5bce8f318", - "sha256:c68f3015cbb0f5bc402829bad0a6b907889413f2e28cc0873dc1443de0f1a808", - "sha256:c78fd0bdf5915f4df730298e6cc7197e4c6aa5285d7c37491366a38125b3e0ab", - "sha256:dcfee6312cf8f4f4839bae22f323a0e885c4237e2187202ab12def8a5460ca4c", - "sha256:e146b4b4ed4937a40e9e5c27b264adfce4ae4b7640d46eeffd3eef123b0170a2", - "sha256:ea75bbc076d4a5605d04c72c8c7a933f51473b0bcecd79295256b9ecd75cca49", - "sha256:f7b20838f2534ad0d231c4c6e09acbdd40fb995a9671bb05839f7879093ec5e3", - "sha256:fce2e7f500b1456f96d5b8ceefba243cae7018ad8b3f791e62c20a0f0fbba71c" - ], - "index": "pypi", - "version": "==0.29.17" + "sha256:0ac10bf476476a9f7ef61ec6e44c280ef434473124ad31d3132b720f7b0e8d2a", + "sha256:0e25c209c75df8785480dcef85db3d36c165dbc0f4c503168e8763eb735704f2", + "sha256:171b9f70ceafcec5852089d0f9c1e75b0d554f46c882cd4e2e4acaba9bd7d148", + "sha256:23f3a00b843a19de8bb4468b087db5b413a903213f67188729782488d67040e0", + "sha256:2922e3031ba9ebbe7cb9200b585cc33b71d66023d78450dcb883f824f4969371", + "sha256:31c71a615f38401b0dc1f2a5a9a6c421ffd8908c4cd5bbedc4014c1b876488e8", + "sha256:473df5d5e400444a36ed81c6596f56a5b52a3481312d0a48d68b777790f730ae", + "sha256:497841897942f734b0abc2dead2d4009795ee992267a70a23485fd0e937edc0b", + "sha256:539e59949aab4955c143a468810123bf22d3e8556421e1ce2531ed4893914ca0", + "sha256:540b3bee0711aac2e99bda4fa0a46dbcd8c74941666bfc1ef9236b1a64eeffd9", + "sha256:57ead89128dee9609119c93d3926c7a2add451453063147900408a50144598c6", + "sha256:5c4276fdcbccdf1e3c1756c7aeb8395e9a36874fa4d30860e7694f43d325ae13", + "sha256:5da187bebe38030325e1c0b5b8a804d489410be2d384c0ef3ba39493c67eb51e", + "sha256:5e545a48f919e40079b0efe7b0e081c74b96f9ef25b9c1ff4cdbd95764426b58", + "sha256:603b9f1b8e93e8b494d3e89320c410679e21018e48b6cbc77280f5db71f17dc0", + "sha256:695a6bcaf9e12b1e471dfce96bbecf22a1487adc2ac6106b15960a2b51b97f5d", + "sha256:715294cd2246b39a8edca464a8366eb635f17213e4a6b9e74e52d8b877a8cb63", + "sha256:856c7fb31d247ce713d60116375e1f8153d0291ab5e92cca7d8833a524ba9991", + "sha256:8c6e25e9cc4961bb2abb1777c6fa9d0fa2d9b014beb3276cebe69996ff162b78", + "sha256:9207fdedc7e789a3dcaca628176b80c82fbed9ae0997210738cbb12536a56699", + "sha256:93f5fed1c9445fb7afe20450cdaf94b0e0356d47cc75008105be89c6a2e417b1", + "sha256:9ce5e5209f8406ffc2b058b1293cce7a954911bb7991e623564d489197c9ba30", + "sha256:a0674f246ad5e1571ef29d4c5ec1d6ecabe9e6c424ad0d6fee46b914d5d24d69", + "sha256:b2f9172e4d6358f33ecce6a4339b5960f9f83eab67ea244baa812737793826b7", + "sha256:b8a8a31b9e8860634adbca30fea1d0c7f08e208b3d7611f3e580e5f20992e5d7", + "sha256:b8d8497091c1dc8705d1575c71e908a93b1f127a174b2d472020f3d84263ac28", + "sha256:c4b78356074fcaac04ecb4de289f11d506e438859877670992ece11f9c90f37b", + "sha256:c541b2b49c6638f2b5beb9316726db84a8d1c132bf31b942dae1f9c7f6ad3b92", + "sha256:c8435959321cf8aec867bbad54b83b7fb8343204b530d85d9ea7a1f5329d5ac2", + "sha256:ccb77faeaad99e99c6c444d04862c6cf604204fe0a07d4c8f9cbf2c9012d7d5a", + "sha256:e272ed97d20b026f4f25a012b25d7d7672a60e4f72b9ca385239d693cd91b2d5", + "sha256:e57acb89bd55943c8d8bf813763d20b9099cc7165c0f16b707631a7654be9cad", + "sha256:e93acd1f603a0c1786e0841f066ae7cef014cf4750e3cd06fd03cfdf46361419" + ], + "index": "pypi", + "version": "==0.29.21" }, "flake8": { "hashes": [ - "sha256:6c1193b0c3f853ef763969238f6c81e9e63ace9d024518edc020d5f1d6d93195", - "sha256:ea6623797bf9a52f4c9577d780da0bb17d65f870213f7b5bcc9fca82540c31d5" + "sha256:15e351d19611c887e482fb960eae4d44845013cc142d42896e9862f775d8cf5c", + "sha256:f04b9fcbac03b0a3e58c0ab3a0ecc462e023a9faf046d57794184028123aa208" ], "index": "pypi", - "version": "==3.8.1" + "version": "==3.8.3" }, "flask": { "hashes": [ @@ -202,11 +202,11 @@ }, "idna": { "hashes": [ - "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb", - "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa" + "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", + "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.9" + "version": "==2.10" }, "isort": { "hashes": [ @@ -342,76 +342,84 @@ }, "numpy": { "hashes": [ - "sha256:00d7b54c025601e28f468953d065b9b121ddca7fff30bed7be082d3656dd798d", - "sha256:02ec9582808c4e48be4e93cd629c855e644882faf704bc2bd6bbf58c08a2a897", - "sha256:0e6f72f7bb08f2f350ed4408bb7acdc0daba637e73bce9f5ea2b207039f3af88", - "sha256:1be2e96314a66f5f1ce7764274327fd4fb9da58584eaff00b5a5221edefee7d6", - "sha256:2466fbcf23711ebc5daa61d28ced319a6159b260a18839993d871096d66b93f7", - "sha256:2b573fcf6f9863ce746e4ad00ac18a948978bb3781cffa4305134d31801f3e26", - "sha256:3f0dae97e1126f529ebb66f3c63514a0f72a177b90d56e4bce8a0b5def34627a", - "sha256:50fb72bcbc2cf11e066579cb53c4ca8ac0227abb512b6cbc1faa02d1595a2a5d", - "sha256:57aea170fb23b1fd54fa537359d90d383d9bf5937ee54ae8045a723caa5e0961", - "sha256:709c2999b6bd36cdaf85cf888d8512da7433529f14a3689d6e37ab5242e7add5", - "sha256:7d59f21e43bbfd9a10953a7e26b35b6849d888fc5a331fa84a2d9c37bd9fe2a2", - "sha256:904b513ab8fbcbdb062bed1ce2f794ab20208a1b01ce9bd90776c6c7e7257032", - "sha256:96dd36f5cdde152fd6977d1bbc0f0561bccffecfde63cd397c8e6033eb66baba", - "sha256:9933b81fecbe935e6a7dc89cbd2b99fea1bf362f2790daf9422a7bb1dc3c3085", - "sha256:bbcc85aaf4cd84ba057decaead058f43191cc0e30d6bc5d44fe336dc3d3f4509", - "sha256:dccd380d8e025c867ddcb2f84b439722cf1f23f3a319381eac45fd077dee7170", - "sha256:e22cd0f72fc931d6abc69dc7764484ee20c6a60b0d0fee9ce0426029b1c1bdae", - "sha256:ed722aefb0ebffd10b32e67f48e8ac4c5c4cf5d3a785024fdf0e9eb17529cd9d", - "sha256:efb7ac5572c9a57159cf92c508aad9f856f1cb8e8302d7fdb99061dbe52d712c", - "sha256:efdba339fffb0e80fcc19524e4fdbda2e2b5772ea46720c44eaac28096d60720", - "sha256:f22273dd6a403ed870207b853a856ff6327d5cbce7a835dfa0645b3fc00273ec" - ], - "index": "pypi", - "version": "==1.18.4" + "sha256:082f8d4dd69b6b688f64f509b91d482362124986d98dc7dc5f5e9f9b9c3bb983", + "sha256:1bc0145999e8cb8aed9d4e65dd8b139adf1919e521177f198529687dbf613065", + "sha256:309cbcfaa103fc9a33ec16d2d62569d541b79f828c382556ff072442226d1968", + "sha256:3673c8b2b29077f1b7b3a848794f8e11f401ba0b71c49fbd26fb40b71788b132", + "sha256:480fdd4dbda4dd6b638d3863da3be82873bba6d32d1fc12ea1b8486ac7b8d129", + "sha256:56ef7f56470c24bb67fb43dae442e946a6ce172f97c69f8d067ff8550cf782ff", + "sha256:5a936fd51049541d86ccdeef2833cc89a18e4d3808fe58a8abeb802665c5af93", + "sha256:5b6885c12784a27e957294b60f97e8b5b4174c7504665333c5e94fbf41ae5d6a", + "sha256:667c07063940e934287993366ad5f56766bc009017b4a0fe91dbd07960d0aba7", + "sha256:7ed448ff4eaffeb01094959b19cbaf998ecdee9ef9932381420d514e446601cd", + "sha256:8343bf67c72e09cfabfab55ad4a43ce3f6bf6e6ced7acf70f45ded9ebb425055", + "sha256:92feb989b47f83ebef246adabc7ff3b9a59ac30601c3f6819f8913458610bdcc", + "sha256:935c27ae2760c21cd7354402546f6be21d3d0c806fffe967f745d5f2de5005a7", + "sha256:aaf42a04b472d12515debc621c31cf16c215e332242e7a9f56403d814c744624", + "sha256:b12e639378c741add21fbffd16ba5ad25c0a1a17cf2b6fe4288feeb65144f35b", + "sha256:b1cca51512299841bf69add3b75361779962f9cee7d9ee3bb446d5982e925b69", + "sha256:b8456987b637232602ceb4d663cb34106f7eb780e247d51a260b84760fd8f491", + "sha256:b9792b0ac0130b277536ab8944e7b754c69560dac0415dd4b2dbd16b902c8954", + "sha256:c9591886fc9cbe5532d5df85cb8e0cc3b44ba8ce4367bd4cf1b93dc19713da72", + "sha256:cf1347450c0b7644ea142712619533553f02ef23f92f781312f6a3553d031fc7", + "sha256:de8b4a9b56255797cbddb93281ed92acbc510fb7b15df3f01bd28f46ebc4edae", + "sha256:e1b1dc0372f530f26a03578ac75d5e51b3868b9b76cd2facba4c9ee0eb252ab1", + "sha256:e45f8e981a0ab47103181773cc0a54e650b2aef8c7b6cd07405d0fa8d869444a", + "sha256:e4f6d3c53911a9d103d8ec9518190e52a8b945bab021745af4939cfc7c0d4a9e", + "sha256:ed8a311493cf5480a2ebc597d1e177231984c818a86875126cfd004241a73c3e", + "sha256:ef71a1d4fd4858596ae80ad1ec76404ad29701f8ca7cdcebc50300178db14dfc" + ], + "index": "pypi", + "version": "==1.19.1" }, "pillow": { "hashes": [ - "sha256:04766c4930c174b46fd72d450674612ab44cca977ebbcc2dde722c6933290107", - "sha256:0e2a3bceb0fd4e0cb17192ae506d5f082b309ffe5fc370a5667959c9b2f85fa3", - "sha256:0f01e63c34f0e1e2580cc0b24e86a5ccbbfa8830909a52ee17624c4193224cd9", - "sha256:12e4bad6bddd8546a2f9771485c7e3d2b546b458ae8ff79621214119ac244523", - "sha256:1f694e28c169655c50bb89a3fa07f3b854d71eb47f50783621de813979ba87f3", - "sha256:3d25dd8d688f7318dca6d8cd4f962a360ee40346c15893ae3b95c061cdbc4079", - "sha256:4b02b9c27fad2054932e89f39703646d0c543f21d3cc5b8e05434215121c28cd", - "sha256:70e3e0d99a0dcda66283a185f80697a9b08806963c6149c8e6c5f452b2aa59c0", - "sha256:9744350687459234867cbebfe9df8f35ef9e1538f3e729adbd8fde0761adb705", - "sha256:a0b49960110bc6ff5fead46013bcb8825d101026d466f3a4de3476defe0fb0dd", - "sha256:ae2b270f9a0b8822b98655cb3a59cdb1bd54a34807c6c56b76dd2e786c3b7db3", - "sha256:b37bb3bd35edf53125b0ff257822afa6962649995cbdfde2791ddb62b239f891", - "sha256:b532bcc2f008e96fd9241177ec580829dee817b090532f43e54074ecffdcd97f", - "sha256:b67a6c47ed963c709ed24566daa3f95a18f07d3831334da570c71da53d97d088", - "sha256:b943e71c2065ade6fef223358e56c167fc6ce31c50bc7a02dd5c17ee4338e8ac", - "sha256:ccc9ad2460eb5bee5642eaf75a0438d7f8887d484490d5117b98edd7f33118b7", - "sha256:d23e2aa9b969cf9c26edfb4b56307792b8b374202810bd949effd1c6e11ebd6d", - "sha256:eaa83729eab9c60884f362ada982d3a06beaa6cc8b084cf9f76cae7739481dfa", - "sha256:ee94fce8d003ac9fd206496f2707efe9eadcb278d94c271f129ab36aa7181344", - "sha256:f455efb7a98557412dc6f8e463c1faf1f1911ec2432059fa3e582b6000fc90e2", - "sha256:f46e0e024346e1474083c729d50de909974237c72daca05393ee32389dabe457", - "sha256:f54be399340aa602066adb63a86a6a5d4f395adfdd9da2b9a0162ea808c7b276", - "sha256:f784aad988f12c80aacfa5b381ec21fd3f38f851720f652b9f33facc5101cf4d" - ], - "index": "pypi", - "version": "==7.1.2" + "sha256:0295442429645fa16d05bd567ef5cff178482439c9aad0411d3f0ce9b88b3a6f", + "sha256:06aba4169e78c439d528fdeb34762c3b61a70813527a2c57f0540541e9f433a8", + "sha256:09d7f9e64289cb40c2c8d7ad674b2ed6105f55dc3b09aa8e4918e20a0311e7ad", + "sha256:0a80dd307a5d8440b0a08bd7b81617e04d870e40a3e46a32d9c246e54705e86f", + "sha256:1ca594126d3c4def54babee699c055a913efb01e106c309fa6b04405d474d5ae", + "sha256:25930fadde8019f374400f7986e8404c8b781ce519da27792cbe46eabec00c4d", + "sha256:431b15cffbf949e89df2f7b48528be18b78bfa5177cb3036284a5508159492b5", + "sha256:52125833b070791fcb5710fabc640fc1df07d087fc0c0f02d3661f76c23c5b8b", + "sha256:5e51ee2b8114def244384eda1c82b10e307ad9778dac5c83fb0943775a653cd8", + "sha256:612cfda94e9c8346f239bf1a4b082fdd5c8143cf82d685ba2dba76e7adeeb233", + "sha256:6d7741e65835716ceea0fd13a7d0192961212fd59e741a46bbed7a473c634ed6", + "sha256:6edb5446f44d901e8683ffb25ebdfc26988ee813da3bf91e12252b57ac163727", + "sha256:725aa6cfc66ce2857d585f06e9519a1cc0ef6d13f186ff3447ab6dff0a09bc7f", + "sha256:8dad18b69f710bf3a001d2bf3afab7c432785d94fcf819c16b5207b1cfd17d38", + "sha256:94cf49723928eb6070a892cb39d6c156f7b5a2db4e8971cb958f7b6b104fb4c4", + "sha256:97f9e7953a77d5a70f49b9a48da7776dc51e9b738151b22dacf101641594a626", + "sha256:9ad7f865eebde135d526bb3163d0b23ffff365cf87e767c649550964ad72785d", + "sha256:a060cf8aa332052df2158e5a119303965be92c3da6f2d93b6878f0ebca80b2f6", + "sha256:c79f9c5fb846285f943aafeafda3358992d64f0ef58566e23484132ecd8d7d63", + "sha256:c92302a33138409e8f1ad16731568c55c9053eee71bb05b6b744067e1b62380f", + "sha256:d08b23fdb388c0715990cbc06866db554e1822c4bdcf6d4166cf30ac82df8c41", + "sha256:d350f0f2c2421e65fbc62690f26b59b0bcda1b614beb318c81e38647e0f673a1", + "sha256:ec29604081f10f16a7aea809ad42e27764188fc258b02259a03a8ff7ded3808d", + "sha256:edf31f1150778abd4322444c393ab9c7bd2af271dd4dafb4208fb613b1f3cdc9", + "sha256:f7e30c27477dffc3e85c2463b3e649f751789e0f6c8456099eea7ddd53be4a8a", + "sha256:ffe538682dc19cc542ae7c3e504fdf54ca7f86fb8a135e59dd6bc8627eae6cce" + ], + "index": "pypi", + "version": "==7.2.0" }, "psutil": { "hashes": [ - "sha256:1413f4158eb50e110777c4f15d7c759521703bd6beb58926f1d562da40180058", - "sha256:298af2f14b635c3c7118fd9183843f4e73e681bb6f01e12284d4d70d48a60953", - "sha256:60b86f327c198561f101a92be1995f9ae0399736b6eced8f24af41ec64fb88d4", - "sha256:685ec16ca14d079455892f25bd124df26ff9137664af445563c1bd36629b5e0e", - "sha256:73f35ab66c6c7a9ce82ba44b1e9b1050be2a80cd4dcc3352cc108656b115c74f", - "sha256:75e22717d4dbc7ca529ec5063000b2b294fc9a367f9c9ede1f65846c7955fd38", - "sha256:a02f4ac50d4a23253b68233b07e7cdb567bd025b982d5cf0ee78296990c22d9e", - "sha256:d008ddc00c6906ec80040d26dc2d3e3962109e40ad07fd8a12d0284ce5e0e4f8", - "sha256:d84029b190c8a66a946e28b4d3934d2ca1528ec94764b180f7d6ea57b0e75e26", - "sha256:e2d0c5b07c6fe5a87fa27b7855017edb0d52ee73b71e6ee368fae268605cc3f5", - "sha256:f344ca230dd8e8d5eee16827596f1c22ec0876127c28e800d7ae20ed44c4b310" + "sha256:0ee3c36428f160d2d8fce3c583a0353e848abb7de9732c50cf3356dd49ad63f8", + "sha256:10512b46c95b02842c225f58fa00385c08fa00c68bac7da2d9a58ebe2c517498", + "sha256:4080869ed93cce662905b029a1770fe89c98787e543fa7347f075ade761b19d6", + "sha256:5e9d0f26d4194479a13d5f4b3798260c20cecf9ac9a461e718eb59ea520a360c", + "sha256:66c18ca7680a31bf16ee22b1d21b6397869dda8059dbdb57d9f27efa6615f195", + "sha256:68d36986ded5dac7c2dcd42f2682af1db80d4bce3faa126a6145c1637e1b559f", + "sha256:90990af1c3c67195c44c9a889184f84f5b2320dce3ee3acbd054e3ba0b4a7beb", + "sha256:a5b120bb3c0c71dfe27551f9da2f3209a8257a178ed6c628a819037a8df487f1", + "sha256:d8a82162f23c53b8525cf5f14a355f5d1eea86fa8edde27287dd3a98399e4fdf", + "sha256:f2018461733b23f308c298653c8903d32aaad7873d25e1d228765e91ae42c3f2", + "sha256:ff1977ba1a5f71f89166d5145c3da1cea89a0fdb044075a12c720ee9123ec818" ], "index": "pypi", - "version": "==5.7.0" + "version": "==5.7.2" }, "pycapnp": { "hashes": [ @@ -438,39 +446,39 @@ }, "pycryptodome": { "hashes": [ - "sha256:07024fc364869eae8d6ac0d316e089956e6aeffe42dbdcf44fe1320d96becf7f", - "sha256:09b6d6bcc01a4eb1a2b4deeff5aa602a108ec5aed8ac75ae554f97d1d7f0a5ad", - "sha256:0e10f352ccbbcb5bb2dc4ecaf106564e65702a717d72ab260f9ac4c19753cfc2", - "sha256:1f4752186298caf2e9ff5354f2e694d607ca7342aa313a62005235d46e28cf04", - "sha256:2fbc472e0b567318fe2052281d5a8c0ae70099b446679815f655e9fbc18c3a65", - "sha256:3ec3dc2f80f71fd0c955ce48b81bfaf8914c6f63a41a738f28885a1c4892968a", - "sha256:426c188c83c10df71f053e04b4003b1437bae5cb37606440e498b00f160d71d0", - "sha256:626c0a1d4d83ec6303f970a17158114f75c3ba1736f7f2983f7b40a265861bd8", - "sha256:767ad0fb5d23efc36a4d5c2fc608ac603f3de028909bcf59abc943e0d0bc5a36", - "sha256:7ac729d9091ed5478af2b4a4f44f5335a98febbc008af619e4569a59fe503e40", - "sha256:83295a3fb5cf50c48631eb5b440cb5e9832d8c14d81d1d45f4497b67a9987de8", - "sha256:8be56bde3312e022d9d1d6afa124556460ad5c844c2fc63642f6af723c098d35", - "sha256:8f06556a8f7ea7b1e42eff39726bb0dca1c251205debae64e6eebea3cd7b438a", - "sha256:9230fcb5d948c3fb40049bace4d33c5d254f8232c2c0bba05d2570aea3ba4520", - "sha256:9378c309aec1f8cd8bad361ed0816a440151b97a2a3f6ffdaba1d1a1fb76873a", - "sha256:9977086e0f93adb326379897437373871b80501e1d176fec63c7f46fb300c862", - "sha256:9a94fca11fdc161460bd8659c15b6adef45c1b20da86402256eaf3addfaab324", - "sha256:9c739b7795ccf2ef1fdad8d44e539a39ad300ee6786e804ea7f0c6a786eb5343", - "sha256:b1e332587b3b195542e77681389c296e1837ca01240399d88803a075447d3557", - "sha256:c109a26a21f21f695d369ff9b87f5d43e0d6c768d8384e10bc74142bed2e092e", - "sha256:c818dc1f3eace93ee50c2b6b5c2becf7c418fa5dd1ba6fc0ef7db279ea21d5e4", - "sha256:cff31f5a8977534f255f729d5d2467526f2b10563a30bbdade92223e0bf264bd", - "sha256:d4f94368ce2d65873a87ad867eb3bf63f4ba81eb97a9ee66d38c2b71ce5a7439", - "sha256:d61b012baa8c2b659e9890011358455c0019a4108536b811602d2f638c40802a", - "sha256:d6e1bc5c94873bec742afe2dfadce0d20445b18e75c47afc0c115b19e5dd38dd", - "sha256:ea83bcd9d6c03248ebd46e71ac313858e0afd5aa2fa81478c0e653242f3eb476", - "sha256:ed5761b37615a1f222c5345bbf45272ae2cf8c7dff88a4f53a1e9f977cbb6d95", - "sha256:f011cd0062e54658b7086a76f8cf0f4222812acc66e219e196ea2d0a8849d0ed", - "sha256:f1add21b6d179179b3c177c33d18a2186a09cc0d3af41ff5ed3f377360b869f2", - "sha256:f655addaaaa9974108d4808f4150652589cada96074c87115c52e575bfcd87d5" - ], - "index": "pypi", - "version": "==3.9.7" + "sha256:02e51e1d5828d58f154896ddfd003e2e7584869c275e5acbe290443575370fba", + "sha256:03d5cca8618620f45fd40f827423f82b86b3a202c8d44108601b0f5f56b04299", + "sha256:0e24171cf01021bc5dc17d6a9d4f33a048f09d62cc3f62541e95ef104588bda4", + "sha256:132a56abba24e2e06a479d8e5db7a48271a73a215f605017bbd476d31f8e71c1", + "sha256:1e655746f539421d923fd48df8f6f40b3443d80b75532501c0085b64afed9df5", + "sha256:2b998dc45ef5f4e5cf5248a6edfcd8d8e9fb5e35df8e4259b13a1b10eda7b16b", + "sha256:360955eece2cd0fa694a708d10303c6abd7b39614fa2547b6bd245da76198beb", + "sha256:39ef9fb52d6ec7728fce1f1693cb99d60ce302aeebd59bcedea70ca3203fda60", + "sha256:4350a42028240c344ee855f032c7d4ad6ff4f813bfbe7121547b7dc579ecc876", + "sha256:50348edd283afdccddc0938cdc674484533912ba8a99a27c7bfebb75030aa856", + "sha256:54bdedd28476dea8a3cd86cb67c0df1f0e3d71cae8022354b0f879c41a3d27b2", + "sha256:55eb61aca2c883db770999f50d091ff7c14016f2769ad7bca3d9b75d1d7c1b68", + "sha256:6276478ada411aca97c0d5104916354b3d740d368407912722bd4d11aa9ee4c2", + "sha256:67dcad1b8b201308586a8ca2ffe89df1e4f731d5a4cdd0610cc4ea790351c739", + "sha256:709b9f144d23e290b9863121d1ace14a72e01f66ea9c903fbdc690520dfdfcf0", + "sha256:8063a712fba642f78d3c506b0896846601b6de7f5c3d534e388ad0cc07f5a149", + "sha256:80d57177a0b7c14d4594c62bbb47fe2f6309ad3b0a34348a291d570925c97a82", + "sha256:a207231a52426de3ff20f5608f0687261a3329d97a036c51f7d4c606a6f30c23", + "sha256:abc2e126c9490e58a36a0f83516479e781d83adfb134576a5cbe5c6af2a3e93c", + "sha256:b56638d58a3a4be13229c6a815cd448f9e3ce40c00880a5398471b42ee86f50e", + "sha256:bcd5b8416e73e4b0d48afba3704d8c826414764dafaed7a1a93c442188d90ccc", + "sha256:bec2bcdf7c9ce7f04d718e51887f3b05dc5c1cfaf5d2c2e9065ecddd1b2f6c9a", + "sha256:c8bf40cf6e281a4378e25846924327e728a887e8bf0ee83b2604a0f4b61692e8", + "sha256:d8074c8448cfd0705dfa71ca333277fce9786d0b9cac75d120545de6253f996a", + "sha256:dd302b6ae3965afeb5ef1b0d92486f986c0e65183cd7835973f0b593800590e6", + "sha256:de6e1cd75677423ff64712c337521e62e3a7a4fc84caabbd93207752e831a85a", + "sha256:ef39c98d9b8c0736d91937d193653e47c3b19ddf4fc3bccdc5e09aaa4b0c5d21", + "sha256:f521178e5a991ffd04182ed08f552daca1affcb826aeda0e1945cd989a9d4345", + "sha256:f78a68c2c820e4731e510a2df3eef0322f24fde1781ced970bf497b6c7d92982", + "sha256:fbe65d5cfe04ff2f7684160d50f5118bdefb01e3af4718eeb618bfed40f19d94" + ], + "index": "pypi", + "version": "==3.9.8" }, "pyflakes": { "hashes": [ @@ -490,11 +498,11 @@ }, "pylint": { "hashes": [ - "sha256:b95e31850f3af163c2283ed40432f053acbc8fc6eba6a069cb518d9dbf71848c", - "sha256:dd506acce0427e9e08fb87274bcaa953d38b50a58207170dbf5b36cf3e16957b" + "sha256:7dd78437f2d8d019717dbf287772d0b2dbdfd13fc016aa7faa08d67bccc46adc", + "sha256:d0ece7d223fe422088b0e8f13fa0a1e8eb745ebffcb8ed53d3e95394b6101a1c" ], "index": "pypi", - "version": "==2.5.2" + "version": "==2.5.3" }, "pyserial": { "hashes": [ @@ -531,37 +539,37 @@ }, "pyzmq": { "hashes": [ - "sha256:07fb8fe6826a229dada876956590135871de60dbc7de5a18c3bcce2ed1f03c98", - "sha256:13a5638ab24d628a6ade8f794195e1a1acd573496c3b85af2f1183603b7bf5e0", - "sha256:15b4cb21118f4589c4db8be4ac12b21c8b4d0d42b3ee435d47f686c32fe2e91f", - "sha256:21f7d91f3536f480cb2c10d0756bfa717927090b7fb863e6323f766e5461ee1c", - "sha256:2a88b8fabd9cc35bd59194a7723f3122166811ece8b74018147a4ed8489e6421", - "sha256:342fb8a1dddc569bc361387782e8088071593e7eaf3e3ecf7d6bd4976edff112", - "sha256:4ee0bfd82077a3ff11c985369529b12853a4064320523f8e5079b630f9551448", - "sha256:54aa24fd60c4262286fc64ca632f9e747c7cc3a3a1144827490e1dc9b8a3a960", - "sha256:58688a2dfa044fad608a8e70ba8d019d0b872ec2acd75b7b5e37da8905605891", - "sha256:5b99c2ae8089ef50223c28bac57510c163bfdff158c9e90764f812b94e69a0e6", - "sha256:5b9d21fc56c8aacd2e6d14738021a9d64f3f69b30578a99325a728e38a349f85", - "sha256:5f1f2eb22aab606f808163eb1d537ac9a0ba4283fbeb7a62eb48d9103cf015c2", - "sha256:6ca519309703e95d55965735a667809bbb65f52beda2fdb6312385d3e7a6d234", - "sha256:87c78f6936e2654397ca2979c1d323ee4a889eef536cc77a938c6b5be33351a7", - "sha256:8952f6ba6ae598e792703f3134af5a01af8f5c7cf07e9a148f05a12b02412cea", - "sha256:931339ac2000d12fe212e64f98ce291e81a7ec6c73b125f17cf08415b753c087", - "sha256:956775444d01331c7eb412c5fb9bb62130dfaac77e09f32764ea1865234e2ca9", - "sha256:97b6255ae77328d0e80593681826a0479cb7bac0ba8251b4dd882f5145a2293a", - "sha256:aaa8b40b676576fd7806839a5de8e6d5d1b74981e6376d862af6c117af2a3c10", - "sha256:af0c02cf49f4f9eedf38edb4f3b6bb621d83026e7e5d76eb5526cc5333782fd6", - "sha256:b08780e3a55215873b3b8e6e7ca8987f14c902a24b6ac081b344fd430d6ca7cd", - "sha256:ba6f24431b569aec674ede49cad197cad59571c12deed6ad8e3c596da8288217", - "sha256:bafd651b557dd81d89bd5f9c678872f3e7b7255c1c751b78d520df2caac80230", - "sha256:bfff5ffff051f5aa47ba3b379d87bd051c3196b0c8a603e8b7ed68a6b4f217ec", - "sha256:cf5d689ba9513b9753959164cf500079383bc18859f58bf8ce06d8d4bef2b054", - "sha256:dcbc3f30c11c60d709c30a213dc56e88ac016fe76ac6768e64717bd976072566", - "sha256:f9d7e742fb0196992477415bb34366c12e9bb9a0699b8b3f221ff93b213d7bec", - "sha256:faee2604f279d31312bc455f3d024f160b6168b9c1dde22bf62d8c88a4deca8e" - ], - "index": "pypi", - "version": "==19.0.1" + "sha256:00dca814469436455399660247d74045172955459c0bd49b54a540ce4d652185", + "sha256:046b92e860914e39612e84fa760fc3f16054d268c11e0e25dcb011fb1bc6a075", + "sha256:09d24a80ccb8cbda1af6ed8eb26b005b6743e58e9290566d2a6841f4e31fa8e0", + "sha256:0a422fc290d03958899743db091f8154958410fc76ce7ee0ceb66150f72c2c97", + "sha256:276ad604bffd70992a386a84bea34883e696a6b22e7378053e5d3227321d9702", + "sha256:296540a065c8c21b26d63e3cea2d1d57902373b16e4256afe46422691903a438", + "sha256:29d51279060d0a70f551663bc592418bcad7f4be4eea7b324f6dd81de05cb4c1", + "sha256:36ab114021c0cab1a423fe6689355e8f813979f2c750968833b318c1fa10a0fd", + "sha256:3fa6debf4bf9412e59353defad1f8035a1e68b66095a94ead8f7a61ae90b2675", + "sha256:5120c64646e75f6db20cc16b9a94203926ead5d633de9feba4f137004241221d", + "sha256:59f1e54627483dcf61c663941d94c4af9bf4163aec334171686cdaee67974fe5", + "sha256:5d9fc809aa8d636e757e4ced2302569d6e60e9b9c26114a83f0d9d6519c40493", + "sha256:654d3e06a4edc566b416c10293064732516cf8871a4522e0a2ba00cc2a2e600c", + "sha256:720d2b6083498a9281eaee3f2927486e9fe02cd16d13a844f2e95217f243efea", + "sha256:73483a2caaa0264ac717af33d6fb3f143d8379e60a422730ee8d010526ce1913", + "sha256:8a6ada5a3f719bf46a04ba38595073df8d6b067316c011180102ba2a1925f5b5", + "sha256:8b66b94fe6243d2d1d89bca336b2424399aac57932858b9a30309803ffc28112", + "sha256:99cc0e339a731c6a34109e5c4072aaa06d8e32c0b93dc2c2d90345dd45fa196c", + "sha256:a7e7f930039ee0c4c26e4dfee015f20bd6919cd8b97c9cd7afbde2923a5167b6", + "sha256:ab0d01148d13854de716786ca73701012e07dff4dfbbd68c4e06d8888743526e", + "sha256:c1a31cd42905b405530e92bdb70a8a56f048c8a371728b8acf9d746ecd4482c0", + "sha256:c20dd60b9428f532bc59f2ef6d3b1029a28fc790d408af82f871a7db03e722ff", + "sha256:c36ffe1e5aa35a1af6a96640d723d0d211c5f48841735c2aa8d034204e87eb87", + "sha256:c40fbb2b9933369e994b837ee72193d6a4c35dfb9a7c573257ef7ff28961272c", + "sha256:d46fb17f5693244de83e434648b3dbb4f4b0fec88415d6cbab1c1452b6f2ae17", + "sha256:e36f12f503511d72d9bdfae11cadbadca22ff632ff67c1b5459f69756a029c19", + "sha256:f1a25a61495b6f7bb986accc5b597a3541d9bd3ef0016f50be16dbb32025b302", + "sha256:fa411b1d8f371d3a49d31b0789eb6da2537dadbb2aef74a43aa99a78195c3f76" + ], + "index": "pypi", + "version": "==19.0.2" }, "raven": { "hashes": [ @@ -573,19 +581,19 @@ }, "requests": { "hashes": [ - "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee", - "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6" + "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b", + "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898" ], "index": "pypi", - "version": "==2.23.0" + "version": "==2.24.0" }, "scons": { "hashes": [ - "sha256:0f860678cd96fc943ff2294389b0f33cbe51080801591497bc652e72237f0176", - "sha256:8aaa483c303efeb678e6f7c776c8444a482f8ddc3ad891f8b6cdd35264da9a1f" + "sha256:722ed104b5c624ecdc89bd4e02b094d2b14d99d47b5d0501961e47f579a2007c", + "sha256:9b4696a806fb73f402fbf5e37ab0e8b6cd0dcef990a91210d7ed4aacbcc5231d" ], "index": "pypi", - "version": "==3.1.2" + "version": "==4.0.1" }, "setproctitle": { "hashes": [ @@ -597,11 +605,11 @@ }, "six": { "hashes": [ - "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a", - "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c" + "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", + "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" ], "index": "pypi", - "version": "==1.14.0" + "version": "==1.15.0" }, "smbus2": { "hashes": [ @@ -612,35 +620,34 @@ }, "sympy": { "hashes": [ - "sha256:4880d3a351558063bd89febda302f220dc4b88de393bba81fa6539a3966f03fa", - "sha256:d77901d748287d15281f5ffe5b0fef62dd38f357c2b827c44ff07f35695f4e7e" + "sha256:7af1e11e9fcb72362c47a481dc010e518cfcb60a594d1ee8bd268f86ea7d6cbf", + "sha256:9769e3d2952e211b1245f1d0dfdbfbdde1f7779a3953832b7dd2b88a21ca6cc6" ], "index": "pypi", - "version": "==1.5.1" + "version": "==1.6" }, "toml": { "hashes": [ - "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", - "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e", - "sha256:f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3" + "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f", + "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88" ], - "version": "==0.10.0" + "version": "==0.10.1" }, "tqdm": { "hashes": [ - "sha256:4733c4a10d0f2a4d098d801464bdaf5240c7dadd2a7fde4ee93b0a0efd9fb25e", - "sha256:acdafb20f51637ca3954150d0405ff1a7edde0ff19e38fb99a80a66210d2a28f" + "sha256:1a336d2b829be50e46b84668691e0a2719f26c97c62846298dd5ae2937e4d5cf", + "sha256:564d632ea2b9cb52979f7956e093e831c28d441c11751682f84c86fc46e4fd21" ], "index": "pypi", - "version": "==4.46.0" + "version": "==4.48.2" }, "urllib3": { "hashes": [ - "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527", - "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115" + "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a", + "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461" ], "index": "pypi", - "version": "==1.25.9" + "version": "==1.25.10" }, "utm": { "hashes": [ @@ -681,19 +688,19 @@ }, "adal": { "hashes": [ - "sha256:2ae7e02cea4552349fed6d8c9912da400f7e643fc30098defe0dcd01945e7c54", - "sha256:a74ff45b88db18d3d3d0c50d0d2d6d411866648f457bef4be714ba0b8e30d515" + "sha256:7a15d22b1ee7ce1be92441199958748982feba6b7dec35fbf60f9b607bad1bc0", + "sha256:b332316f54d947f39acd9628e7d61d90f6e54d413d6f97025a51482c96bac6bc" ], - "version": "==1.2.3" + "version": "==1.2.4" }, "aenum": { "hashes": [ - "sha256:284ddb976413d97239a932d7e5202ba58d66e5dbd81531bf3033ebb36ec30b23", - "sha256:a4334cabf47c167d44ab5a6198837b80deec5d5bad1b5cf70c966c3a330260e8", - "sha256:d2bb6ea7586aaae889d3a5c332eafa851eeffe6e7068807c79b6c86c4326b938" + "sha256:81828d1fbe20b6b188d75b21a0fa936d7d929d839ef843ef385d9c2a97082864", + "sha256:85adabd63183d283250bf7acd9fa23c7e45b1c8d1efbb84b233160f3c438dc18", + "sha256:bcb4fd350d36af336b6b5898e5d89f76344621d9c1b2de69c81acf1d3e6b1145" ], "index": "pypi", - "version": "==2.2.3" + "version": "==2.2.4" }, "aiohttp": { "hashes": [ @@ -729,18 +736,39 @@ }, "argcomplete": { "hashes": [ - "sha256:5ae7b601be17bf38a749ec06aa07fb04e7b6b5fc17906948dc1866e7facf3740", - "sha256:890bdd1fcbb973ed73db241763e78b6d958580e588c2910b508c770a59ef37d7" + "sha256:2fbe5ed09fd2c1d727d4199feca96569a5b50d44c71b16da9c742201f7cc295c", + "sha256:91dc7f9c7f6281d5a0dce5e73d2e33283aaef083495c13974a7dd197a1cdc949" ], - "version": "==1.11.1" + "version": "==1.12.0" + }, + "argon2-cffi": { + "hashes": [ + "sha256:05a8ac07c7026542377e38389638a8a1e9b78f1cd8439cd7493b39f08dd75fbf", + "sha256:0bf066bc049332489bb2d75f69216416329d9dc65deee127152caeb16e5ce7d5", + "sha256:18dee20e25e4be86680b178b35ccfc5d495ebd5792cd00781548d50880fee5c5", + "sha256:392c3c2ef91d12da510cfb6f9bae52512a4552573a9e27600bdb800e05905d2b", + "sha256:57358570592c46c420300ec94f2ff3b32cbccd10d38bdc12dc6979c4a8484fbc", + "sha256:6678bb047373f52bcff02db8afab0d2a77d83bde61cfecea7c5c62e2335cb203", + "sha256:6ea92c980586931a816d61e4faf6c192b4abce89aa767ff6581e6ddc985ed003", + "sha256:77e909cc756ef81d6abb60524d259d959bab384832f0c651ed7dcb6e5ccdbb78", + "sha256:7d455c802727710e9dfa69b74ccaab04568386ca17b0ad36350b622cd34606fe", + "sha256:9bee3212ba4f560af397b6d7146848c32a800652301843df06b9e8f68f0f7361", + "sha256:9dfd5197852530294ecb5795c97a823839258dfd5eb9420233c7cfedec2058f2", + "sha256:b160416adc0f012fb1f12588a5e6954889510f82f698e23ed4f4fa57f12a0647", + "sha256:ba7209b608945b889457f949cc04c8e762bed4fe3fec88ae9a6b7765ae82e496", + "sha256:cc0e028b209a5483b6846053d5fd7165f460a1f14774d79e632e75e7ae64b82b", + "sha256:d8029b2d3e4b4cea770e9e5a0104dd8fa185c1724a0f01528ae4826a6d25f97d", + "sha256:da7f0445b71db6d3a72462e04f36544b0de871289b0bc8a7cc87c0f5ec7079fa" + ], + "version": "==20.1.0" }, "astroid": { "hashes": [ - "sha256:4c17cea3e592c21b6e222f673868961bad77e1f985cb1694ed077475a89229c1", - "sha256:d8506842a3faf734b81599c8b98dcc423de863adcc1999248480b18bd31a0f38" + "sha256:2f4078c2a41bf377eea06d71c9d2ba4eb8f6b1af2135bec27bbbb7d8f12bb703", + "sha256:bc58d83eb610252fd8de6363e39d4f1d0619c894b0ed24603b881c02e64c7386" ], "markers": "python_version >= '3.5'", - "version": "==2.4.1" + "version": "==2.4.2" }, "astunparse": { "hashes": [ @@ -767,11 +795,11 @@ }, "azure-cli-core": { "hashes": [ - "sha256:5b2d3952f7edab1a34d7421b5a7ff1aabf32d9fca6614bdac5ec9938e64b7caa", - "sha256:668d45eef11ff155969c205b730d044d18d4729bf70d127f85cfd85ed69bff98" + "sha256:2f07ae6f4fa729398e2959f7f94424f753718f01c7301ae79156a5e72fb49a30", + "sha256:c81fc3fe245b183f7fb249f9dc46f1c3269d1621387c34a628c200d05c6593e2" ], "index": "pypi", - "version": "==2.5.1" + "version": "==2.10.1" }, "azure-cli-nspkg": { "hashes": [ @@ -799,11 +827,11 @@ }, "azure-core": { "hashes": [ - "sha256:2b7613b37ff6503312e5ec7c9ce2efab8fa0dbfe4c6c1d3bf91bab51db9bd6dc", - "sha256:afa6a6ae577859392e1ed3acb024bf5bddeb1bbb67f3191c35c587505ff431a0" + "sha256:2d1aade2795ea0ac2a903af940c3e0dfe75d25351ec4fc44edf747e97d703dfb", + "sha256:a66da240a287f447f9867f54ba09ea235895cec13ea38c5f490ce4eedefdd75c" ], "index": "pypi", - "version": "==1.5.0" + "version": "==1.7.0" }, "azure-mgmt-core": { "hashes": [ @@ -814,10 +842,10 @@ }, "azure-mgmt-resource": { "hashes": [ - "sha256:055e85a4053a987bf427653e75f537c750ecc27c0e7c74623a67cb859689b5a6", - "sha256:dc12f7998e2c1fd4088a8da5f02936c2985ceb7acbe994571c8b3778f26a7501" + "sha256:33ae072d0f60b804eda68c4396a73a7154005c88abf85d42c40a8991d0aa4eb9", + "sha256:9be7fcdf586f24acb799a799cf5e9363e9323ca0ce54cca63ab505f69fa0fddd" ], - "version": "==9.0.0" + "version": "==10.1.0" }, "azure-nspkg": { "hashes": [ @@ -854,10 +882,10 @@ }, "backcall": { "hashes": [ - "sha256:38ecd85be2c1e78f77fd91700c76e14667dc21e2713b63876c0eb901196e01e4", - "sha256:bbbf4b1e5cd2bdb08f915895b51081c041bac22394fdfcfdfbe9f14b77c08bf2" + "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e", + "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255" ], - "version": "==0.1.0" + "version": "==0.2.0" }, "backports.lzma": { "hashes": [ @@ -871,6 +899,7 @@ "sha256:0258f143f3de96b7c14f762c770f5fc56ccd72f8a1857a451c1cd9a655d9ac89", "sha256:0b0069c752ec14172c5f78208f1863d7ad6755a6fae6fe76ec2c80d13be41e42", "sha256:19a4b72a6ae5bb467fea018b825f0a7d917789bcfe893e53f15c92805d187294", + "sha256:436a487dec749bca7e6e72498a75a5fa2433bda13bac91d023e18df9089ae0b8", "sha256:5432dd7b34107ae8ed6c10a71b4397f1c853bd39a4d6ffa7e35f40584cffd161", "sha256:6305557019906466fc42dbc53b46da004e72fd7a551c044a827e572c82191752", "sha256:69361315039878c0680be456640f8705d76cb4a3a3fe1e057e0f261b74be4b31", @@ -908,67 +937,75 @@ }, "boto3": { "hashes": [ - "sha256:b81a6296134aec4d48319e5d25e47c2abcea2cd13ddd160f95b692e56c6ab9b7", - "sha256:c347350521e8138a42b7c877bb87ba32842405d7bc7fd86b29745abc60b9e83d" + "sha256:3aad418cb5a20f522f3d0267caefb5582324f5af60fe093ace12e69847cf72cd", + "sha256:d33af62c691c0078326970ec4f09bef4b8822bdfa7eca3a6c26b6b4c016c32d7" ], "index": "pypi", - "version": "==1.13.8" + "version": "==1.14.38" }, "botocore": { "hashes": [ - "sha256:68eb83d97a8ecdbf271c17989280bc9a533269d4ee983d2ef80289e2333042da", - "sha256:8263bba760c3f24aeb0651936b24798ba8a172828afdccf8bee5ca6d5d7c4b9c" + "sha256:37de221e9b9ba8a3225387d7a4d5313d55ff78e32a2986cce682cb21418b9ee3", + "sha256:e14b778d58640049d22c587c30d466bcc3432102f5715ffbe0bec2858b13a1b9" ], - "version": "==1.16.8" + "version": "==1.17.38" }, "cachetools": { "hashes": [ - "sha256:1d057645db16ca7fe1f3bd953558897603d6f0b9c51ed9d11eb4d071ec4e2aab", - "sha256:de5d88f87781602201cde465d3afe837546663b168e8b39df67411b0bf10cefc" + "sha256:513d4ff98dd27f85743a8dc0e92f55ddb1b49e060c2d5961512855cda2c01a98", + "sha256:bbaa39c3dede00175df2dc2b03d0cf18dd2d32a7de7beb68072d13043c9edb20" ], "markers": "python_version ~= '3.5'", - "version": "==4.1.0" + "version": "==4.1.1" }, "certifi": { "hashes": [ - "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304", - "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519" + "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3", + "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41" ], - "version": "==2020.4.5.1" + "version": "==2020.6.20" }, "cffi": { "hashes": [ - "sha256:001bf3242a1bb04d985d63e138230802c6c8d4db3668fb545fb5005ddf5bb5ff", - "sha256:00789914be39dffba161cfc5be31b55775de5ba2235fe49aa28c148236c4e06b", - "sha256:028a579fc9aed3af38f4892bdcc7390508adabc30c6af4a6e4f611b0c680e6ac", - "sha256:14491a910663bf9f13ddf2bc8f60562d6bc5315c1f09c704937ef17293fb85b0", - "sha256:1cae98a7054b5c9391eb3249b86e0e99ab1e02bb0cc0575da191aedadbdf4384", - "sha256:2089ed025da3919d2e75a4d963d008330c96751127dd6f73c8dc0c65041b4c26", - "sha256:2d384f4a127a15ba701207f7639d94106693b6cd64173d6c8988e2c25f3ac2b6", - "sha256:337d448e5a725bba2d8293c48d9353fc68d0e9e4088d62a9571def317797522b", - "sha256:399aed636c7d3749bbed55bc907c3288cb43c65c4389964ad5ff849b6370603e", - "sha256:3b911c2dbd4f423b4c4fcca138cadde747abdb20d196c4a48708b8a2d32b16dd", - "sha256:3d311bcc4a41408cf5854f06ef2c5cab88f9fded37a3b95936c9879c1640d4c2", - "sha256:62ae9af2d069ea2698bf536dcfe1e4eed9090211dbaafeeedf5cb6c41b352f66", - "sha256:66e41db66b47d0d8672d8ed2708ba91b2f2524ece3dee48b5dfb36be8c2f21dc", - "sha256:675686925a9fb403edba0114db74e741d8181683dcf216be697d208857e04ca8", - "sha256:7e63cbcf2429a8dbfe48dcc2322d5f2220b77b2e17b7ba023d6166d84655da55", - "sha256:8a6c688fefb4e1cd56feb6c511984a6c4f7ec7d2a1ff31a10254f3c817054ae4", - "sha256:8c0ffc886aea5df6a1762d0019e9cb05f825d0eec1f520c51be9d198701daee5", - "sha256:95cd16d3dee553f882540c1ffe331d085c9e629499ceadfbda4d4fde635f4b7d", - "sha256:99f748a7e71ff382613b4e1acc0ac83bf7ad167fb3802e35e90d9763daba4d78", - "sha256:b8c78301cefcf5fd914aad35d3c04c2b21ce8629b5e4f4e45ae6812e461910fa", - "sha256:c420917b188a5582a56d8b93bdd8e0f6eca08c84ff623a4c16e809152cd35793", - "sha256:c43866529f2f06fe0edc6246eb4faa34f03fe88b64a0a9a942561c8e22f4b71f", - "sha256:cab50b8c2250b46fe738c77dbd25ce017d5e6fb35d3407606e7a4180656a5a6a", - "sha256:cef128cb4d5e0b3493f058f10ce32365972c554572ff821e175dbc6f8ff6924f", - "sha256:cf16e3cf6c0a5fdd9bc10c21687e19d29ad1fe863372b5543deaec1039581a30", - "sha256:e56c744aa6ff427a607763346e4170629caf7e48ead6921745986db3692f987f", - "sha256:e577934fc5f8779c554639376beeaa5657d54349096ef24abe8c74c5d9c117c3", - "sha256:f2b0fa0c01d8a0c7483afd9f31d7ecf2d71760ca24499c8697aeb5ca37dc090c" - ], - "index": "pypi", - "version": "==1.14.0" + "sha256:267adcf6e68d77ba154334a3e4fc921b8e63cbb38ca00d33d40655d4228502bc", + "sha256:26f33e8f6a70c255767e3c3f957ccafc7f1f706b966e110b855bfe944511f1f9", + "sha256:3cd2c044517f38d1b577f05927fb9729d3396f1d44d0c659a445599e79519792", + "sha256:4a03416915b82b81af5502459a8a9dd62a3c299b295dcdf470877cb948d655f2", + "sha256:4ce1e995aeecf7cc32380bc11598bfdfa017d592259d5da00fc7ded11e61d022", + "sha256:4f53e4128c81ca3212ff4cf097c797ab44646a40b42ec02a891155cd7a2ba4d8", + "sha256:4fa72a52a906425416f41738728268072d5acfd48cbe7796af07a923236bcf96", + "sha256:66dd45eb9530e3dde8f7c009f84568bc7cac489b93d04ac86e3111fb46e470c2", + "sha256:6923d077d9ae9e8bacbdb1c07ae78405a9306c8fd1af13bfa06ca891095eb995", + "sha256:833401b15de1bb92791d7b6fb353d4af60dc688eaa521bd97203dcd2d124a7c1", + "sha256:8416ed88ddc057bab0526d4e4e9f3660f614ac2394b5e019a628cdfff3733849", + "sha256:892daa86384994fdf4856cb43c93f40cbe80f7f95bb5da94971b39c7f54b3a9c", + "sha256:98be759efdb5e5fa161e46d404f4e0ce388e72fbf7d9baf010aff16689e22abe", + "sha256:a6d28e7f14ecf3b2ad67c4f106841218c8ab12a0683b1528534a6c87d2307af3", + "sha256:b1d6ebc891607e71fd9da71688fcf332a6630b7f5b7f5549e6e631821c0e5d90", + "sha256:b2a2b0d276a136146e012154baefaea2758ef1f56ae9f4e01c612b0831e0bd2f", + "sha256:b87dfa9f10a470eee7f24234a37d1d5f51e5f5fa9eeffda7c282e2b8f5162eb1", + "sha256:bac0d6f7728a9cc3c1e06d4fcbac12aaa70e9379b3025b27ec1226f0e2d404cf", + "sha256:c991112622baee0ae4d55c008380c32ecfd0ad417bcd0417ba432e6ba7328caa", + "sha256:cda422d54ee7905bfc53ee6915ab68fe7b230cacf581110df4272ee10462aadc", + "sha256:d3148b6ba3923c5850ea197a91a42683f946dba7e8eb82dfa211ab7e708de939", + "sha256:d6033b4ffa34ef70f0b8086fd4c3df4bf801fee485a8a7d4519399818351aa8e", + "sha256:ddff0b2bd7edcc8c82d1adde6dbbf5e60d57ce985402541cd2985c27f7bec2a0", + "sha256:e23cb7f1d8e0f93addf0cae3c5b6f00324cccb4a7949ee558d7b6ca973ab8ae9", + "sha256:effd2ba52cee4ceff1a77f20d2a9f9bf8d50353c854a282b8760ac15b9833168", + "sha256:f90c2267101010de42f7273c94a1f026e56cbc043f9330acd8a80e64300aba33", + "sha256:f960375e9823ae6a07072ff7f8a85954e5a6434f97869f50d0e41649a1c8144f", + "sha256:fcf32bf76dc25e30ed793145a57426064520890d7c02866eb93d3e4abe516948" + ], + "index": "pypi", + "version": "==1.14.1" + }, + "cfgv": { + "hashes": [ + "sha256:32e43d604bbe7896fe7c248a9c2276447dbef840feb28fe20494f62af110211d", + "sha256:cf22deb93d4bcf92f345a5c3cd39d3d41d6340adc60c78bbbd6588c384fda6a1" + ], + "markers": "python_version >= '3.6.1'", + "version": "==3.2.0" }, "chardet": { "hashes": [ @@ -1002,65 +1039,68 @@ }, "coverage": { "hashes": [ - "sha256:00f1d23f4336efc3b311ed0d807feb45098fc86dee1ca13b3d6768cdab187c8a", - "sha256:01333e1bd22c59713ba8a79f088b3955946e293114479bbfc2e37d522be03355", - "sha256:0cb4be7e784dcdc050fc58ef05b71aa8e89b7e6636b99967fadbdba694cf2b65", - "sha256:0e61d9803d5851849c24f78227939c701ced6704f337cad0a91e0972c51c1ee7", - "sha256:1601e480b9b99697a570cea7ef749e88123c04b92d84cedaa01e117436b4a0a9", - "sha256:2742c7515b9eb368718cd091bad1a1b44135cc72468c731302b3d641895b83d1", - "sha256:2d27a3f742c98e5c6b461ee6ef7287400a1956c11421eb574d843d9ec1f772f0", - "sha256:402e1744733df483b93abbf209283898e9f0d67470707e3c7516d84f48524f55", - "sha256:5c542d1e62eece33c306d66fe0a5c4f7f7b3c08fecc46ead86d7916684b36d6c", - "sha256:5f2294dbf7875b991c381e3d5af2bcc3494d836affa52b809c91697449d0eda6", - "sha256:6402bd2fdedabbdb63a316308142597534ea8e1895f4e7d8bf7476c5e8751fef", - "sha256:66460ab1599d3cf894bb6baee8c684788819b71a5dc1e8fa2ecc152e5d752019", - "sha256:782caea581a6e9ff75eccda79287daefd1d2631cc09d642b6ee2d6da21fc0a4e", - "sha256:79a3cfd6346ce6c13145731d39db47b7a7b859c0272f02cdb89a3bdcbae233a0", - "sha256:7a5bdad4edec57b5fb8dae7d3ee58622d626fd3a0be0dfceda162a7035885ecf", - "sha256:8fa0cbc7ecad630e5b0f4f35b0f6ad419246b02bc750de7ac66db92667996d24", - "sha256:a027ef0492ede1e03a8054e3c37b8def89a1e3c471482e9f046906ba4f2aafd2", - "sha256:a3f3654d5734a3ece152636aad89f58afc9213c6520062db3978239db122f03c", - "sha256:a82b92b04a23d3c8a581fc049228bafde988abacba397d57ce95fe95e0338ab4", - "sha256:acf3763ed01af8410fc36afea23707d4ea58ba7e86a8ee915dfb9ceff9ef69d0", - "sha256:adeb4c5b608574a3d647011af36f7586811a2c1197c861aedb548dd2453b41cd", - "sha256:b83835506dfc185a319031cf853fa4bb1b3974b1f913f5bb1a0f3d98bdcded04", - "sha256:bb28a7245de68bf29f6fb199545d072d1036a1917dca17a1e75bbb919e14ee8e", - "sha256:bf9cb9a9fd8891e7efd2d44deb24b86d647394b9705b744ff6f8261e6f29a730", - "sha256:c317eaf5ff46a34305b202e73404f55f7389ef834b8dbf4da09b9b9b37f76dd2", - "sha256:dbe8c6ae7534b5b024296464f387d57c13caa942f6d8e6e0346f27e509f0f768", - "sha256:de807ae933cfb7f0c7d9d981a053772452217df2bf38e7e6267c9cbf9545a796", - "sha256:dead2ddede4c7ba6cb3a721870f5141c97dc7d85a079edb4bd8d88c3ad5b20c7", - "sha256:dec5202bfe6f672d4511086e125db035a52b00f1648d6407cc8e526912c0353a", - "sha256:e1ea316102ea1e1770724db01998d1603ed921c54a86a2efcb03428d5417e489", - "sha256:f90bfc4ad18450c80b024036eaf91e4a246ae287701aaa88eaebebf150868052" - ], - "index": "pypi", - "version": "==5.1" + "sha256:098a703d913be6fbd146a8c50cc76513d726b022d170e5e98dc56d958fd592fb", + "sha256:16042dc7f8e632e0dcd5206a5095ebd18cb1d005f4c89694f7f8aafd96dd43a3", + "sha256:1adb6be0dcef0cf9434619d3b892772fdb48e793300f9d762e480e043bd8e716", + "sha256:27ca5a2bc04d68f0776f2cdcb8bbd508bbe430a7bf9c02315cd05fb1d86d0034", + "sha256:28f42dc5172ebdc32622a2c3f7ead1b836cdbf253569ae5673f499e35db0bac3", + "sha256:2fcc8b58953d74d199a1a4d633df8146f0ac36c4e720b4a1997e9b6327af43a8", + "sha256:304fbe451698373dc6653772c72c5d5e883a4aadaf20343592a7abb2e643dae0", + "sha256:30bc103587e0d3df9e52cd9da1dd915265a22fad0b72afe54daf840c984b564f", + "sha256:40f70f81be4d34f8d491e55936904db5c527b0711b2a46513641a5729783c2e4", + "sha256:4186fc95c9febeab5681bc3248553d5ec8c2999b8424d4fc3a39c9cba5796962", + "sha256:46794c815e56f1431c66d81943fa90721bb858375fb36e5903697d5eef88627d", + "sha256:4869ab1c1ed33953bb2433ce7b894a28d724b7aa76c19b11e2878034a4e4680b", + "sha256:4f6428b55d2916a69f8d6453e48a505c07b2245653b0aa9f0dee38785939f5e4", + "sha256:52f185ffd3291196dc1aae506b42e178a592b0b60a8610b108e6ad892cfc1bb3", + "sha256:538f2fd5eb64366f37c97fdb3077d665fa946d2b6d95447622292f38407f9258", + "sha256:64c4f340338c68c463f1b56e3f2f0423f7b17ba6c3febae80b81f0e093077f59", + "sha256:675192fca634f0df69af3493a48224f211f8db4e84452b08d5fcebb9167adb01", + "sha256:700997b77cfab016533b3e7dbc03b71d33ee4df1d79f2463a318ca0263fc29dd", + "sha256:8505e614c983834239f865da2dd336dcf9d72776b951d5dfa5ac36b987726e1b", + "sha256:962c44070c281d86398aeb8f64e1bf37816a4dfc6f4c0f114756b14fc575621d", + "sha256:9e536783a5acee79a9b308be97d3952b662748c4037b6a24cbb339dc7ed8eb89", + "sha256:9ea749fd447ce7fb1ac71f7616371f04054d969d412d37611716721931e36efd", + "sha256:a34cb28e0747ea15e82d13e14de606747e9e484fb28d63c999483f5d5188e89b", + "sha256:a3ee9c793ffefe2944d3a2bd928a0e436cd0ac2d9e3723152d6fd5398838ce7d", + "sha256:aab75d99f3f2874733946a7648ce87a50019eb90baef931698f96b76b6769a46", + "sha256:b1ed2bdb27b4c9fc87058a1cb751c4df8752002143ed393899edb82b131e0546", + "sha256:b360d8fd88d2bad01cb953d81fd2edd4be539df7bfec41e8753fe9f4456a5082", + "sha256:b8f58c7db64d8f27078cbf2a4391af6aa4e4767cc08b37555c4ae064b8558d9b", + "sha256:c1bbb628ed5192124889b51204de27c575b3ffc05a5a91307e7640eff1d48da4", + "sha256:c2ff24df02a125b7b346c4c9078c8936da06964cc2d276292c357d64378158f8", + "sha256:c890728a93fffd0407d7d37c1e6083ff3f9f211c83b4316fae3778417eab9811", + "sha256:c96472b8ca5dc135fb0aa62f79b033f02aa434fb03a8b190600a5ae4102df1fd", + "sha256:ce7866f29d3025b5b34c2e944e66ebef0d92e4a4f2463f7266daa03a1332a651", + "sha256:e26c993bd4b220429d4ec8c1468eca445a4064a61c74ca08da7429af9bc53bb0" + ], + "index": "pypi", + "version": "==5.2.1" }, "cryptography": { "hashes": [ - "sha256:091d31c42f444c6f519485ed528d8b451d1a0c7bf30e8ca583a0cac44b8a0df6", - "sha256:18452582a3c85b96014b45686af264563e3e5d99d226589f057ace56196ec78b", - "sha256:1dfa985f62b137909496e7fc182dac687206d8d089dd03eaeb28ae16eec8e7d5", - "sha256:1e4014639d3d73fbc5ceff206049c5a9a849cefd106a49fa7aaaa25cc0ce35cf", - "sha256:22e91636a51170df0ae4dcbd250d318fd28c9f491c4e50b625a49964b24fe46e", - "sha256:3b3eba865ea2754738616f87292b7f29448aec342a7c720956f8083d252bf28b", - "sha256:651448cd2e3a6bc2bb76c3663785133c40d5e1a8c1a9c5429e4354201c6024ae", - "sha256:726086c17f94747cedbee6efa77e99ae170caebeb1116353c6cf0ab67ea6829b", - "sha256:844a76bc04472e5135b909da6aed84360f522ff5dfa47f93e3dd2a0b84a89fa0", - "sha256:88c881dd5a147e08d1bdcf2315c04972381d026cdb803325c03fe2b4a8ed858b", - "sha256:96c080ae7118c10fcbe6229ab43eb8b090fccd31a09ef55f83f690d1ef619a1d", - "sha256:a0c30272fb4ddda5f5ffc1089d7405b7a71b0b0f51993cb4e5dbb4590b2fc229", - "sha256:bb1f0281887d89617b4c68e8db9a2c42b9efebf2702a3c5bf70599421a8623e3", - "sha256:c447cf087cf2dbddc1add6987bbe2f767ed5317adb2d08af940db517dd704365", - "sha256:c4fd17d92e9d55b84707f4fd09992081ba872d1a0c610c109c18e062e06a2e55", - "sha256:d0d5aeaedd29be304848f1c5059074a740fa9f6f26b84c5b63e8b29e73dfc270", - "sha256:daf54a4b07d67ad437ff239c8a4080cfd1cc7213df57d33c97de7b4738048d5e", - "sha256:e993468c859d084d5579e2ebee101de8f5a27ce8e2159959b6673b418fd8c785", - "sha256:f118a95c7480f5be0df8afeb9a11bd199aa20afab7a96bcf20409b411a3a85f0" - ], - "index": "pypi", - "version": "==2.9.2" + "sha256:0c608ff4d4adad9e39b5057de43657515c7da1ccb1807c3a27d4cf31fc923b4b", + "sha256:0cbfed8ea74631fe4de00630f4bb592dad564d57f73150d6f6796a24e76c76cd", + "sha256:124af7255ffc8e964d9ff26971b3a6153e1a8a220b9a685dc407976ecb27a06a", + "sha256:384d7c681b1ab904fff3400a6909261cae1d0939cc483a68bdedab282fb89a07", + "sha256:45741f5499150593178fc98d2c1a9c6722df88b99c821ad6ae298eff0ba1ae71", + "sha256:4b9303507254ccb1181d1803a2080a798910ba89b1a3c9f53639885c90f7a756", + "sha256:4d355f2aee4a29063c10164b032d9fa8a82e2c30768737a2fd56d256146ad559", + "sha256:51e40123083d2f946794f9fe4adeeee2922b581fa3602128ce85ff813d85b81f", + "sha256:8713ddb888119b0d2a1462357d5946b8911be01ddbf31451e1d07eaa5077a261", + "sha256:8e924dbc025206e97756e8903039662aa58aa9ba357d8e1d8fc29e3092322053", + "sha256:8ecef21ac982aa78309bb6f092d1677812927e8b5ef204a10c326fc29f1367e2", + "sha256:8ecf9400d0893836ff41b6f977a33972145a855b6efeb605b49ee273c5e6469f", + "sha256:9367d00e14dee8d02134c6c9524bb4bd39d4c162456343d07191e2a0b5ec8b3b", + "sha256:a09fd9c1cca9a46b6ad4bea0a1f86ab1de3c0c932364dbcf9a6c2a5eeb44fa77", + "sha256:ab49edd5bea8d8b39a44b3db618e4783ef84c19c8b47286bf05dfdb3efb01c83", + "sha256:bea0b0468f89cdea625bb3f692cd7a4222d80a6bdafd6fb923963f2b9da0e15f", + "sha256:bec7568c6970b865f2bcebbe84d547c52bb2abadf74cefce396ba07571109c67", + "sha256:ce82cc06588e5cbc2a7df3c8a9c778f2cb722f56835a23a68b5a7264726bb00c", + "sha256:dea0ba7fe6f9461d244679efa968d215ea1f989b9c1957d7f10c21e5c7c09ad6" + ], + "index": "pypi", + "version": "==3.0" }, "cycler": { "hashes": [ @@ -1071,11 +1111,11 @@ }, "datadog": { "hashes": [ - "sha256:398c612f8fb8e1988be897fda920ffb3b8a1ec70d430730e3b71a269df31b486", - "sha256:3fe197587db49d808ba88e40f431fb2d256be3c428419ac2984609d67fd66bce" + "sha256:401cd1dcf2d5de05786016a1c790bff28d1428d12ae1dbe11485f9cb5502939b", + "sha256:b5ebf25e88cf6891ff26a4a82898ae5ff23d712ad5501e1043113bd0a1903c16" ], "index": "pypi", - "version": "==0.36.0" + "version": "==0.38.0" }, "decorator": { "hashes": [ @@ -1100,12 +1140,12 @@ "index": "pypi", "version": "==0.8.1" }, - "dlib": { + "distlib": { "hashes": [ - "sha256:d0eeaca07bc4c75973ad0f739a541d8fa4003af778f0dc1c2c595d470823819a" + "sha256:8c09de2c67b3e7deef7184574fc060ab8a793e7adbb183d942c389c8b13c52fb", + "sha256:edf6116872c863e1aa9d5bb7cb5e05a022c519a4594dc703843343a9ddd9bff1" ], - "index": "pypi", - "version": "==19.19.0" + "version": "==0.3.1" }, "docutils": { "hashes": [ @@ -1118,11 +1158,11 @@ }, "elasticsearch": { "hashes": [ - "sha256:d228b2d37ac0865f7631335268172dbdaa426adec1da3ed006dddf05134f89c8", - "sha256:f4bb05cfe55cf369bdcb4d86d0129d39d66a91fd9517b13cd4e4231fbfcf5c81" + "sha256:2ffbd746fc7d2db08e5ede29c822483705f29c4bf43b0875c238637d5d843d44", + "sha256:92b534931865a186906873f75ae0b91808ff5036b0f2b9269eb5f6dc09644b55" ], "index": "pypi", - "version": "==7.6.0" + "version": "==7.8.1" }, "entrypoints": { "hashes": [ @@ -1161,6 +1201,13 @@ "index": "pypi", "version": "==1.1.26" }, + "filelock": { + "hashes": [ + "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59", + "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836" + ], + "version": "==3.0.12" + }, "flask": { "hashes": [ "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060", @@ -1179,11 +1226,11 @@ }, "flask-socketio": { "hashes": [ - "sha256:5969e1d4ead37ec9164f82779ec86239f0f394a08b20477d2056903010920f36", - "sha256:7f9b54ac9cd92e28a657c58f51943d97e76b988840c8795784e7b2bafb13103f" + "sha256:3668675bf7763c5b5f56689d439f07356e89c0a52e0c9e9cd3cc08563c07b252", + "sha256:36c1d5765010d1f4e4f05b4cc9c20c289d9dc70698c88d1addd0afcfedc5b062" ], "index": "pypi", - "version": "==4.3.0" + "version": "==4.3.1" }, "future": { "hashes": [ @@ -1202,11 +1249,11 @@ }, "geoalchemy2": { "hashes": [ - "sha256:379b0fc4ca5f9b5ef625719f47e22c9b8abd347aa78344e85f99d32594cfccd4", - "sha256:ec2a6e9919b522631803ac5922e88b701081da7e5d56a68f10ff263f6592d552" + "sha256:3b83654db15ed807a7bdb2e7dd1c787a47cfc3e4fb92a0558685001fbb7342da", + "sha256:d9336f17df3e7a10f94d1ea2488dcfb97a8bc23fe7f5edea425ddab553534b0a" ], "index": "pypi", - "version": "==0.7.0" + "version": "==0.8.4" }, "git-pylint-commit-hook": { "hashes": [ @@ -1217,11 +1264,11 @@ }, "google-auth": { "hashes": [ - "sha256:4942ab1ff530e740866571c0416fb5a7dc9ec53233a8f8dff63e8cd7371003d1", - "sha256:82d32f6601f35309c95d5917bcdf72f3ec193c7f46c79e433b8d76ccbe68e21d" + "sha256:2f34dd810090d0d4c9d5787c4ad7b4413d1fbfb941e13682c7a2298d3b6cdcc8", + "sha256:ce1fb80b5c6d3dd038babcc43e221edeafefc72d983b3dc28b67b996f76f00b9" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.14.3" + "version": "==1.20.1" }, "google-auth-oauthlib": { "hashes": [ @@ -1240,39 +1287,47 @@ }, "grpcio": { "hashes": [ - "sha256:085bbf7fd0070b8d65e84aa32979f17cfe624d27b5ce23955ef770c19d2d9623", - "sha256:0ae207a47ec0ad66eb1f53a27d566674d13a236c62ced409891335318ea9b8c5", - "sha256:0c130204ff5de0b9f041bf3126db0d29369d69883592e4b0d3c19868ba0ced7e", - "sha256:0ef6b380a588c2c6b29c6cfa0ba7f5d367beb33d5504bcc68658fa241ad498d2", - "sha256:16e1edb367763ea08d0994d4635ec05f4f8db9db59c39304b061097e3b93df43", - "sha256:16f5523dacae5aaeda4cf900da7e980747f663298c38c18eb4e5317704aa007a", - "sha256:181b5078cf568f37915b8a118afcef5fc9f3128c59c38998ed93e7dd793e3928", - "sha256:245564713cb4ac7bccb0f11be63781beb62299a44d8ab69031c859dbd9461728", - "sha256:271abbe28eb99fa5c70b3f272c0c66b67dab7bb11e1d29d8e616b4e0e099d29a", - "sha256:2e1b01cba26988c811c7fb91a0bca19c9afb776cc3d228993f08d324bdd0510a", - "sha256:3366bd6412c1e73acb1ee27d7f0c7d7dbee118ad8d98c957c8173691b2effeec", - "sha256:3893b39a0a17d857dc3a42fdb02a26aa53a59bfce49987187bcc0261647f1f55", - "sha256:3c7864d5ae63b787001b01b376f6315aef1a015aa9c809535235ed0ead907919", - "sha256:42c6716adf3ec1f608b2b56e885f26dd86e80d2fc1617f51fc92d1b0b649e28e", - "sha256:4bef0756b9e0df78e8d67a5b1e0e89b7daf41525d575f74e1f14a993c55b680d", - "sha256:4fe081862e58b8fbef0e479aefc9a64f8f17f53074df1085d8c1fe825a6e5df4", - "sha256:505a8d1b4ac571a51f10c4c995d5d4714f03c886604dc3c097ef5fd57bcfcf0b", - "sha256:5c2e81b6ab9768c43f2ca1c9a4c925823aad79ae95efb351007df4b92ebce592", - "sha256:70ff2df0c1795c5cf585a72d95bb458838b40bad5653c314b9067ba819e918f9", - "sha256:97b5612fc5d4bbf0490a2d80bed5eab5b59112ef1640440c1a9ac824bafa6968", - "sha256:a35f8f4a0334ed8b05db90383aecef8e49923ab430689a4360a74052f3a89cf4", - "sha256:aafe85a8210dfa1da3c46831b7f00c3735240b7b028eeba339eaea6ffdb593fb", - "sha256:c2e53eb253840f05278a8410628419ba7060815f86d48c9d83b6047de21c9956", - "sha256:c3645887db3309fc87c3db740b977d403fb265ebab292f1f6a926c4661231fd5", - "sha256:c6565cc92853af13237b2233f331efdad07339d27fe1f5f74256bfde7dc2f587", - "sha256:cbc322c5d5615e67c2a15be631f64e6c2bab8c12505bc7c150948abdaa0bdbac", - "sha256:df749ee982ec35ab76d37a1e637b10a92b4573e2b4e1f86a5fa8a1273c40a850", - "sha256:e9439d7b801c86df13c6cbb4c5a7e181c058f3c119d5e119a94a5f3090a8f060", - "sha256:f493ac4754717f25ace3614a51dd408a32b8bff3c9c0c85e9356e7e0a120a8c8", - "sha256:f80d10bdf1a306f7063046321fd4efc7732a606acdd4e6259b8a37349079b704", - "sha256:f83b0c91796eb42865451a20e82246011078ba067ea0744f7301e12a94ae2e1b" - ], - "version": "==1.28.1" + "sha256:013287f99c99b201aa8a5f6bc7918f616739b9be031db132d9e3b8453e95e151", + "sha256:0397616355760cd8282ed5ea34d51830ae4cb6613b7e5f66bed3be5d041b8b9a", + "sha256:074871a184483d5cd0746fd01e7d214d3ee9d36e67e32a5786b0a21f29fb8304", + "sha256:08a9b648dbe8852ff94b73a1c96da126834c3057ba2301d13e8c4adff334c482", + "sha256:0fa86ac4452602c79774783aa68979a1a7625ebb7eaabee2b6550b975b9d61e6", + "sha256:220c46b1fc9c9a6fcca4caac398f08f0ed43cdd63c45b7458983c4a1575ef6df", + "sha256:259240aab2603891553e17ad5b2655693df79e02a9b887ff605bdeb2fcd3dcc9", + "sha256:292635f05b6ce33f87116951d0b3d8d330bdfc5cac74f739370d60981e8c256c", + "sha256:344b50865914cc8e6d023457bffee9a640abb18f75d0f2bb519041961c748da9", + "sha256:3c2aa6d7a5e5bf73fdb1715eee777efe06dd39df03383f1cc095b2fdb34883e6", + "sha256:43d44548ad6ee738b941abd9f09e3b83a5c13f3e1410321023c3c148ba50e796", + "sha256:5043440c45c0a031f387e7f48527541c65d672005fb24cf18ef6857483557d39", + "sha256:58d7121f48cb94535a4cedcce32921d0d0a78563c7372a143dedeec196d1c637", + "sha256:5d7faa89992e015d245750ca9ac916c161bbf72777b2c60abc61da3fae41339e", + "sha256:5fb0923b16590bac338e92d98c7d8effb3cfad1d2e18c71bf86bde32c49cd6dd", + "sha256:63ee8e02d04272c3d103f44b4bce5d43ea757dd288673cea212d2f7da27967d2", + "sha256:64077e3a9a7cf2f59e6c76d503c8de1f18a76428f41a5b000dc53c48a0b772ff", + "sha256:739a72abffbd36083ff7adbb862cf1afc1e311c35834bed9c0361d8e68b063e1", + "sha256:75e383053dccb610590aa53eed5278db5c09bf498d3b5105ce6c776478f59352", + "sha256:7a11b1ebb3210f34913b8be6995936bf9ebc541a65ab69e75db5ce1fe5047e8f", + "sha256:8002a89ea91c0078c15d3c0daf423fd4968946be78f08545e807ea9a5ff8054a", + "sha256:8b42f0ac76be07a5fa31117a3388d754ad35ef05e2e34be185ca9ccbcfac2069", + "sha256:8ca26b489b5dc1e3d31807d329c23d6cb06fe40fbae25b0649b718947936e26a", + "sha256:92e54ab65e782f227e751c7555918afaba8d1229601687e89b80c2b65d2f6642", + "sha256:a9a7ae74cb3108e6457cf15532d4c300324b48fbcf3ef290bcd2835745f20510", + "sha256:ba3e43cb984399064ffaa3c0997576e46a1e268f9da05f97cd9b272f0b59ee71", + "sha256:baaa036540d7ace433bdf38a3fe5e41cf9f84cdf10a88bac805f678a7ca8ddcc", + "sha256:bf00ab06ea4f89976288f4d6224d4aa120780e30c955d4f85c3214ada29b3ddf", + "sha256:bf39977282a79dc1b2765cc3402c0ada571c29a491caec6ed12c0993c1ec115e", + "sha256:c22b19abba63562a5a200e586b5bde39d26c8ec30c92e26d209d81182371693b", + "sha256:c9016ab1eaf4e054099303287195f3746bd4e69f2631d040f9dca43e910a5408", + "sha256:d2c5e05c257859febd03f5d81b5015e1946d6bcf475c7bf63ee99cea8ab0d590", + "sha256:e64bddd09842ef508d72ca354319b0eb126205d951e8ac3128fe9869bd563552", + "sha256:e8c3264b0fd728aadf3f0324471843f65bd3b38872bdab2a477e31ffb685dd5b", + "sha256:ea849210e7362559f326cbe603d5b8d8bb1e556e86a7393b5a8847057de5b084", + "sha256:ebb2ca09fa17537e35508a29dcb05575d4d9401138a68e83d1c605d65e8a1770", + "sha256:ef9fce98b6fe03874c2a6576b02aec1a0df25742cd67d1d7b75a49e30aa74225", + "sha256:f04c59d186af3157dc8811114130aaeae92e90a65283733f41de94eed484e1f7", + "sha256:f5b0870b733bcb7b6bf05a02035e7aaf20f599d3802b390282d4c2309f825f1d" + ], + "version": "==1.31.0" }, "gunicorn": { "hashes": [ @@ -1332,65 +1387,45 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==8.2" }, - "idna": { + "identify": { "hashes": [ - "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb", - "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa" + "sha256:110ed090fec6bce1aabe3c72d9258a9de82207adeaa5a05cd75c635880312f9a", + "sha256:ccd88716b890ecbe10920659450a635d2d25de499b9a638525a48b48261d989b" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.9" - }, - "imagecodecs": { - "hashes": [ - "sha256:0538f7a4def1f6745b2d83d21883dcd61e82bc8faaca810e3a35e6b551b455d1", - "sha256:22f3c39755752fe3a91a92fcf24002ca57a51efca1ab99e9919cf783f90b4026", - "sha256:286b87ee09506c35f099585e6b5ce245fb62c2a826aac4e0497cdfdfba631cc7", - "sha256:2bda6c7b13be73dfd202b3c23dc4b3003fdc02209835e348e4bd31ddca124d76", - "sha256:2c130b89fcb70bab3aa57ee0671423ab0e053c6ff7ed26646bf425592fa3116d", - "sha256:6275213bd611156fa2fd73ce81b29ca708c4344d36fe3686f567cd104ccf4d18", - "sha256:6f63ae2592086b1abbd40b699816c054dc7aad616df2b14c2e15cd2372b77653", - "sha256:91eb82b0167ff022a6a8dcf86e5871b635bfbe96801557e00d6b1e2a10ac25dd", - "sha256:9742b392640c1b2d05c6aaad956bd7e3bf461c7e0f403f7b25ee464a5c949c8c", - "sha256:9a9abc5498121f0005fb00dfbed57a062337445d32a39569e4378286b503125b", - "sha256:adc09e5f9af6927eccc35d60ae1ec422cd9791cee4d5456d39af6903dff19477", - "sha256:c019b19438dff31365fee3002b438992c16bc9955a036f466c600d80699cb5a2", - "sha256:c5667d4b8e97cf10b3754f5e8159d60620cdd35052ffc298346273d42284430f", - "sha256:c7367e01a199228b6526f05dc7fe7a85adac19f1b19e08a99edbdd2523cfcdc4", - "sha256:cf855a00bf5cb5a7cf1d608e7588ddc535d714e5422c3095dd811829b559f237", - "sha256:d1b0b2de7be918a8eada62c8d2339931381c86dbd43216a064e35ace5957e350", - "sha256:e0f3cfc2fc77c19118e173dca6af0dbed4a3cef75d3296762db687fd00fb7921", - "sha256:e8f460145258a28544d4119f58cab2daf87ac6653429ab9df7dff7d2cc30714f", - "sha256:eedf5be2c9c65a0d92970bda98dfd7e9525c137e631e1956753bb6ce369b08f9", - "sha256:f6722cd6a73501c508b361f485259f172898d3cf2530e6de71f3e89394a0a713", - "sha256:f6ac9dd40e1cdb72842fb72f147e8a51a1874c8f375629524566b388e841be20", - "sha256:fbdd0d42aa3c984377421767a892e77c40249870425aca0ba5629bdcd57d3ae4" + "version": "==1.4.25" + }, + "idna": { + "hashes": [ + "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", + "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" ], - "markers": "python_version >= '3.6'", - "version": "==2020.2.18" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.10" }, "imageio": { "hashes": [ - "sha256:1e4ab29b3775bb093c7a35854a0412857145450183344678829b30e72263b001", - "sha256:fb5fd6d3d17126bbaac9af29fe340e2c97a196eb9416d4f28c0e543744a152cf" + "sha256:3604d751f03002e8e0e7650aa71d8d9148144a87daf17cb1f3228e80747f2e6b", + "sha256:52ddbaeca2dccf53ba2d6dec5676ca7bc3b2403ef8b37f7da78b7654bb3e10f0" ], "index": "pypi", - "version": "==2.8.0" + "version": "==2.9.0" }, "ipykernel": { "hashes": [ - "sha256:003c9c1ab6ff87d11f531fee2b9ca59affab19676fc6b2c21da329aef6e73499", - "sha256:2937373c356fa5b634edb175c5ea0e4b25de8008f7c194f2d49cfbd1f9c970a8" + "sha256:9b2652af1607986a1b231c62302d070bc0534f564c393a5d9d130db9abbbe89d", + "sha256:d6fbba26dba3cebd411382bc484f7bc2caa98427ae0ddb4ab37fe8bfeb5c7dd3" ], "index": "pypi", - "version": "==5.2.1" + "version": "==5.3.4" }, "ipython": { "hashes": [ - "sha256:5b241b84bbf0eb085d43ae9d46adf38a13b45929ca7774a740990c2c242534bb", - "sha256:f0126781d0f959da852fb3089e170ed807388e986a8dd4e6ac44855845b0fb1c" + "sha256:5a8f159ca8b22b9a0a1f2a28befe5ad2b703339afb58c2ffe0d7c8d7a3af5999", + "sha256:b70974aaa2674b05eb86a910c02ed09956a33f2dd6c71afc60f0b128a77e7f28" ], "index": "pypi", - "version": "==7.14.0" + "version": "==7.17.0" }, "ipython-genutils": { "hashes": [ @@ -1431,11 +1466,11 @@ }, "jedi": { "hashes": [ - "sha256:cd60c93b71944d628ccac47df9a60fec53150de53d42dc10a7fc4b5ba6aae798", - "sha256:df40c97641cb943661d2db4c33c2e1ff75d491189423249e989bcea4464f3030" + "sha256:86ed7d9b750603e4ba582ea8edc678657fb4007894a12bcf6f4bb97892f31d20", + "sha256:98cc583fa0f2f8304968199b01b6b4b94f469a1f4a74c1560506ca2a211378b5" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.17.0" + "version": "==0.17.2" }, "jinja2": { "hashes": [ @@ -1455,11 +1490,11 @@ }, "joblib": { "hashes": [ - "sha256:0630eea4f5664c463f23fbf5dcfc54a2bc6168902719fa8e19daf033022786c8", - "sha256:bdb4fd9b72915ffb49fde2229ce482dd7ae79d842ed8c2b4c932441495af1403" + "sha256:8f52bf24c64b608bf0b2563e0e47d6fcf516abc8cfafe10cfd98ad66d94f92d6", + "sha256:d348c5d4ae31496b2aa060d6d9b787864dd204f9480baaa52d18850cb43e9f49" ], "index": "pypi", - "version": "==0.14.1" + "version": "==0.16.0" }, "json-logging-py": { "hashes": [ @@ -1486,11 +1521,11 @@ }, "jupyter-client": { "hashes": [ - "sha256:3a32fa4d0b16d1c626b30c3002a62dfd86d6863ed39eaba3f537fade197bb756", - "sha256:cde8e83aab3ec1c614f221ae54713a9a46d3bf28292609d2db1b439bef5a8c8e" + "sha256:7ad9aa91505786420d77edc5f9fb170d51050c007338ba8d196f603223fd3b3a", + "sha256:b360f8d4638bc577a4656e93f86298db755f915098dc763f6fc05da0c5d7a595" ], "markers": "python_version >= '3.5'", - "version": "==6.1.3" + "version": "==6.1.6" }, "jupyter-console": { "hashes": [ @@ -1518,22 +1553,25 @@ }, "keras-preprocessing": { "hashes": [ - "sha256:138012da7bbc5508d59681515636c01618644322db08c1f4c6d66e63de8ddb73", - "sha256:c0b1ebe444e46075a9079629fa0e0d0fb1d681b4a72340ca5406b574894276a5" + "sha256:7b82029b130ff61cc99b55f3bd27427df4838576838c5b2f65940e4fcec99a7b", + "sha256:add82567c50c8bc648c14195bf544a5ce7c1f76761536956c3d2978970179ef3" ], - "version": "==1.1.1" + "version": "==1.1.2" }, "kiwisolver": { "hashes": [ "sha256:03662cbd3e6729f341a97dd2690b271e51a67a68322affab12a5b011344b973c", "sha256:18d749f3e56c0480dccd1714230da0f328e6e4accf188dd4e6884bdd06bf02dd", "sha256:247800260cd38160c362d211dcaf4ed0f7816afb5efe56544748b21d6ad6d17f", + "sha256:38d05c9ecb24eee1246391820ed7137ac42a50209c203c908154782fced90e44", "sha256:443c2320520eda0a5b930b2725b26f6175ca4453c61f739fef7a5847bd262f74", "sha256:4eadb361baf3069f278b055e3bb53fa189cea2fd02cb2c353b7a99ebb4477ef1", "sha256:556da0a5f60f6486ec4969abbc1dd83cf9b5c2deadc8288508e55c0f5f87d29c", "sha256:603162139684ee56bcd57acc74035fceed7dd8d732f38c0959c8bd157f913fec", "sha256:60a78858580761fe611d22127868f3dc9f98871e6fdf0a15cc4203ed9ba6179b", + "sha256:63f55f490b958b6299e4e5bdac66ac988c3d11b7fafa522800359075d4fa56d1", "sha256:7cc095a4661bdd8a5742aaf7c10ea9fac142d76ff1770a0f84394038126d8fc7", + "sha256:be046da49fbc3aa9491cc7296db7e8d27bcf0c3d5d1a40259c10471b014e4e0c", "sha256:c31bc3c8e903d60a1ea31a754c72559398d91b5929fcb329b1c3a3d3f6e72113", "sha256:c955791d80e464da3b471ab41eb65cf5a40c15ce9b001fdc5bbc241170de58ec", "sha256:d069ef4b20b1e6b19f790d00097a5d5d2c50871b66d10075dab78938dc2ee2cf", @@ -1547,10 +1585,10 @@ }, "knack": { "hashes": [ - "sha256:4063e504db33d62e4fff00ccb0fb9563bdde6232a27764e07087db75f7de7830", - "sha256:66d1ff609ecfa1da48f731c9258f03d5dd1da324e2cf81732c78e993afc46683" + "sha256:d86a669f45e875fc5e49a85ac90e57c85338be89cb281cb99a9adb87f563761d", + "sha256:dfc6aef6760ea9a9620577e01540617678d78cab3111a0f03e8b9f987d0f08ca" ], - "version": "==0.7.0rc4" + "version": "==0.7.2" }, "lazy-object-proxy": { "hashes": [ @@ -1642,23 +1680,30 @@ }, "matplotlib": { "hashes": [ - "sha256:2466d4dddeb0f5666fd1e6736cc5287a4f9f7ae6c1a9e0779deff798b28e1d35", - "sha256:282b3fc8023c4365bad924d1bb442ddc565c2d1635f210b700722776da466ca3", - "sha256:4bb50ee4755271a2017b070984bcb788d483a8ce3132fab68393d1555b62d4ba", - "sha256:56d3147714da5c7ac4bc452d041e70e0e0b07c763f604110bd4e2527f320b86d", - "sha256:7a9baefad265907c6f0b037c8c35a10cf437f7708c27415a5513cf09ac6d6ddd", - "sha256:aae7d107dc37b4bb72dcc45f70394e6df2e5e92ac4079761aacd0e2ad1d3b1f7", - "sha256:af14e77829c5b5d5be11858d042d6f2459878f8e296228c7ea13ec1fd308eb68", - "sha256:c1cf735970b7cd424502719b44288b21089863aaaab099f55e0283a721aaf781", - "sha256:ce378047902b7a05546b6485b14df77b2ff207a0054e60c10b5680132090c8ee", - "sha256:d35891a86a4388b6965c2d527b9a9f9e657d9e110b0575ca8a24ba0d4e34b8fc", - "sha256:e06304686209331f99640642dee08781a9d55c6e32abb45ed54f021f46ccae47", - "sha256:e20ba7fb37d4647ac38f3c6d8672dd8b62451ee16173a0711b37ba0ce42bf37d", - "sha256:f4412241e32d0f8d3713b68d3ca6430190a5e8a7c070f1c07d7833d8c5264398", - "sha256:ffe2f9cdcea1086fc414e82f42271ecf1976700b8edd16ca9d376189c6d93aee" - ], - "index": "pypi", - "version": "==3.2.1" + "sha256:09b4096748178bcc764b81587b00ab720eac24965d2bf44ecbe09dcf4e8ed253", + "sha256:19cf4db0272da286863a50406f6430101af129f288c421b1a7f33ddfc8d0180f", + "sha256:244a9088140a4c540e0a2db9c8ada5ad12520efded592a46e5bc43ff8f0fd0aa", + "sha256:24e8db94948019d531ce0bcd637ac24b1c8f6744ac86d2aa0eb6dbaeb1386f82", + "sha256:2a9d10930406748b50f60c5fa74c399a1c1080aa6ce6e3fe5f38473b02f6f06d", + "sha256:605e4d43b421524ad955a56535391e02866d07bce27c644e2c99e25fb59d63d1", + "sha256:695b4165520bdfe381d15a6db03778babb265fee7affdc43e169a881f3f329bc", + "sha256:6aa7ea00ad7d898704ffed46e83efd7ec985beba57f507c957979f080678b9ea", + "sha256:7c9adba58a67d23cc131c4189da56cb1d0f18a237c43188d831a44e4fc5df15a", + "sha256:7ce8f5364c74aac06abad84d8744d659bd86036e86c4ebf14c75ae4292597b46", + "sha256:855bb281f3cc8e23ef66064a2beb229674fdf785638091fc82a172e3e84c2780", + "sha256:9ccc651261b7044ffc3b1e2f9af17b1ef4c6a12fc080b5a7353ef0b53a50be28", + "sha256:b0786ac32983191fcd9cc0230b4ec2f8b3c25dee9beca46ca506c5d6cc5c593d", + "sha256:bf8d527a2eb9a5db1c9e5e405d1b1c4e66be983620c9ce80af6aae430d9a0c9c", + "sha256:c06ea133b44805d42f2507cb3503f6647b0c7918f1900b5063f5a8a69c63f6d2", + "sha256:c1f850908600efa60f81ad14eedbaf7cb17185a2c6d26586ae826ae5ce21f6e0", + "sha256:cef05e9a2302f96d6f0666ee70ac7715cbc12e3802d8b8eb80bacd6ab81a0a24", + "sha256:e3868686f3023644523df486fc224b0af4349f3cdb933b0a71f261a574d7b65f", + "sha256:ebb6168c9330309b1f3360d36c481d8cd621a490cf2a69c9d6625b2a76777c12", + "sha256:f74c39621b03cec7bc08498f140192ac26ca940ef20beac6dfad3714d2298b2a", + "sha256:f9753c6292d5a1fe46828feb38d1de1820e3ea109a5fea0b6ea1dca6e9d0b220" + ], + "index": "pypi", + "version": "==3.3.0" }, "mccabe": { "hashes": [ @@ -1684,10 +1729,10 @@ }, "mpld3": { "hashes": [ - "sha256:4d455884a211bf99b37ecc760759435c7bb6a5955de47d8daf4967e301878ab7" + "sha256:1677a314125ff2984e2f291d595188d5ee8ca66ac21b0c2c8633961bc33a7bf8" ], "index": "pypi", - "version": "==0.3" + "version": "==0.5.1" }, "msal": { "hashes": [ @@ -1712,40 +1757,67 @@ }, "msrest": { "hashes": [ - "sha256:22349c718f632e37beee0dd10f7ea41984ded136db2199a9d3c6f1f3942868e9", - "sha256:9050fbbb95dd9e8f4008d7227e4dc5662e8b605c89e5621b0dd09ac7f04cf01d" + "sha256:4993023011663b4273f15432fab75cc747dfa0bca1816d8122a7d1f9fdd9288d", + "sha256:5f4ef9b8cc207d93978b1a58f055179686b9f30a5e28041872db97a4a1c49b96" ], - "version": "==0.6.13" + "version": "==0.6.18" }, "msrestazure": { "hashes": [ - "sha256:0ae7f903ff81631512beef39602c4104a8fe04cb7d166f28a1ec43c0f0985749", - "sha256:0ec9db93eeea6a6cf1240624a04f49cd8bbb26b98d84a63a8220cfda858c2a96" + "sha256:3de50f56147ef529b31e099a982496690468ecef33f0544cb0fa0cfe1e1de5b9", + "sha256:a06f0dabc9a6f5efe3b6add4bd8fb623aeadacf816b7a35b0f89107e0544d189" ], - "version": "==0.6.3" + "version": "==0.6.4" }, "multidict": { "hashes": [ - "sha256:317f96bc0950d249e96d8d29ab556d01dd38888fbe68324f46fd834b430169f1", - "sha256:42f56542166040b4474c0c608ed051732033cd821126493cf25b6c276df7dd35", - "sha256:4b7df040fb5fe826d689204f9b544af469593fb3ff3a069a6ad3409f742f5928", - "sha256:544fae9261232a97102e27a926019100a9db75bec7b37feedd74b3aa82f29969", - "sha256:620b37c3fea181dab09267cd5a84b0f23fa043beb8bc50d8474dd9694de1fa6e", - "sha256:6e6fef114741c4d7ca46da8449038ec8b1e880bbe68674c01ceeb1ac8a648e78", - "sha256:7774e9f6c9af3f12f296131453f7b81dabb7ebdb948483362f5afcaac8a826f1", - "sha256:85cb26c38c96f76b7ff38b86c9d560dea10cf3459bb5f4caf72fc1bb932c7136", - "sha256:a326f4240123a2ac66bb163eeba99578e9d63a8654a59f4688a79198f9aa10f8", - "sha256:ae402f43604e3b2bc41e8ea8b8526c7fa7139ed76b0d64fc48e28125925275b2", - "sha256:aee283c49601fa4c13adc64c09c978838a7e812f85377ae130a24d7198c0331e", - "sha256:b51249fdd2923739cd3efc95a3d6c363b67bbf779208e9f37fd5e68540d1a4d4", - "sha256:bb519becc46275c594410c6c28a8a0adc66fe24fef154a9addea54c1adb006f5", - "sha256:c2c37185fb0af79d5c117b8d2764f4321eeb12ba8c141a95d0aa8c2c1d0a11dd", - "sha256:dc561313279f9d05a3d0ffa89cd15ae477528ea37aa9795c4654588a3287a9ab", - "sha256:e439c9a10a95cb32abd708bb8be83b2134fa93790a4fb0535ca36db3dda94d20", - "sha256:fc3b4adc2ee8474cb3cd2a155305d5f8eda0a9c91320f83e55748e1fcb68f8e3" + "sha256:1ece5a3369835c20ed57adadc663400b5525904e53bae59ec854a5d36b39b21a", + "sha256:275ca32383bc5d1894b6975bb4ca6a7ff16ab76fa622967625baeebcf8079000", + "sha256:3750f2205b800aac4bb03b5ae48025a64e474d2c6cc79547988ba1d4122a09e2", + "sha256:4538273208e7294b2659b1602490f4ed3ab1c8cf9dbdd817e0e9db8e64be2507", + "sha256:5141c13374e6b25fe6bf092052ab55c0c03d21bd66c94a0e3ae371d3e4d865a5", + "sha256:51a4d210404ac61d32dada00a50ea7ba412e6ea945bbe992e4d7a595276d2ec7", + "sha256:5cf311a0f5ef80fe73e4f4c0f0998ec08f954a6ec72b746f3c179e37de1d210d", + "sha256:6513728873f4326999429a8b00fc7ceddb2509b01d5fd3f3be7881a257b8d463", + "sha256:7388d2ef3c55a8ba80da62ecfafa06a1c097c18032a501ffd4cabbc52d7f2b19", + "sha256:9456e90649005ad40558f4cf51dbb842e32807df75146c6d940b6f5abb4a78f3", + "sha256:c026fe9a05130e44157b98fea3ab12969e5b60691a276150db9eda71710cd10b", + "sha256:d14842362ed4cf63751648e7672f7174c9818459d169231d03c56e84daf90b7c", + "sha256:e0d072ae0f2a179c375f67e3da300b47e1a83293c554450b29c900e50afaae87", + "sha256:f07acae137b71af3bb548bd8da720956a3bc9f9a0b87733e0899226a2317aeb7", + "sha256:fbb77a75e529021e7c4a8d4e823d88ef4d23674a202be4f5addffc72cbb91430", + "sha256:fcfbb44c59af3f8ea984de67ec7c306f618a3ec771c2843804069917a8f2e255", + "sha256:feed85993dbdb1dbc29102f50bca65bdc68f2c0c8d352468c25b54874f23c39d" ], "markers": "python_version >= '3.5'", - "version": "==4.7.5" + "version": "==4.7.6" + }, + "mypy": { + "hashes": [ + "sha256:2c6cde8aa3426c1682d35190b59b71f661237d74b053822ea3d748e2c9578a7c", + "sha256:3fdda71c067d3ddfb21da4b80e2686b71e9e5c72cca65fa216d207a358827f86", + "sha256:5dd13ff1f2a97f94540fd37a49e5d255950ebcdf446fb597463a40d0df3fac8b", + "sha256:6731603dfe0ce4352c555c6284c6db0dc935b685e9ce2e4cf220abe1e14386fd", + "sha256:6bb93479caa6619d21d6e7160c552c1193f6952f0668cdda2f851156e85186fc", + "sha256:81c7908b94239c4010e16642c9102bfc958ab14e36048fa77d0be3289dda76ea", + "sha256:9c7a9a7ceb2871ba4bac1cf7217a7dd9ccd44c27c2950edbc6dc08530f32ad4e", + "sha256:a4a2cbcfc4cbf45cd126f531dedda8485671545b43107ded25ce952aac6fb308", + "sha256:b7fbfabdbcc78c4f6fc4712544b9b0d6bf171069c6e0e3cb82440dd10ced3406", + "sha256:c05b9e4fb1d8a41d41dec8786c94f3b95d3c5f528298d769eb8e73d293abc48d", + "sha256:d7df6eddb6054d21ca4d3c6249cae5578cb4602951fd2b6ee2f5510ffb098707", + "sha256:e0b61738ab504e656d1fe4ff0c0601387a5489ca122d55390ade31f9ca0e252d", + "sha256:eff7d4a85e9eea55afa34888dfeaccde99e7520b51f867ac28a48492c0b1130c", + "sha256:f05644db6779387ccdb468cc47a44b4356fc2ffa9287135d05b70a98dc83b89a" + ], + "index": "pypi", + "version": "==0.782" + }, + "mypy-extensions": { + "hashes": [ + "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", + "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" + ], + "version": "==0.4.3" }, "nbconvert": { "hashes": [ @@ -1757,53 +1829,65 @@ }, "nbformat": { "hashes": [ - "sha256:049af048ed76b95c3c44043620c17e56bc001329e07f83fec4f177f0e3d7b757", - "sha256:276343c78a9660ab2a63c28cc33da5f7c58c092b3f3a40b6017ae2ce6689320d" + "sha256:54d4d6354835a936bad7e8182dcd003ca3dc0cedfee5a306090e04854343b340", + "sha256:ea55c9b817855e2dfcd3f66d74857342612a60b1f09653440f4a5845e6e3523f" ], "markers": "python_version >= '3.5'", - "version": "==5.0.6" + "version": "==5.0.7" }, "networkx": { "hashes": [ - "sha256:8311ddef63cf5c5c5e7c1d0212dd141d9a1fe3f474915281b73597ed5f1d4e3d" + "sha256:cdfbf698749a5014bf2ed9db4a07a5295df1d3a53bf80bf3cbd61edf9df05fa1", + "sha256:f8f4ff0b6f96e4f9b16af6b84622597b5334bf9cae8cf9b2e42e7985d5c95c64" ], "index": "pypi", - "version": "==2.3" + "version": "==2.4" + }, + "nodeenv": { + "hashes": [ + "sha256:4b0b77afa3ba9b54f4b6396e60b0c83f59eaeb2d63dc3cc7a70f7f4af96c82bc" + ], + "version": "==1.4.0" }, "notebook": { "hashes": [ - "sha256:3edc616c684214292994a3af05eaea4cc043f6b4247d830f3a2f209fa7639a80", - "sha256:47a9092975c9e7965ada00b9a20f0cf637d001db60d241d479f53c0be117ad48" + "sha256:42391d8f3b88676e774316527599e49c11f3a7e51c41035e9e44c1b58e1398d5", + "sha256:4cc4e44a43a83a7c2f5e85bfdbbfe1c68bed91b857741df9e593d213a6fc2d27" ], "markers": "python_version >= '3.5'", - "version": "==6.0.3" + "version": "==6.1.1" }, "numpy": { "hashes": [ - "sha256:00d7b54c025601e28f468953d065b9b121ddca7fff30bed7be082d3656dd798d", - "sha256:02ec9582808c4e48be4e93cd629c855e644882faf704bc2bd6bbf58c08a2a897", - "sha256:0e6f72f7bb08f2f350ed4408bb7acdc0daba637e73bce9f5ea2b207039f3af88", - "sha256:1be2e96314a66f5f1ce7764274327fd4fb9da58584eaff00b5a5221edefee7d6", - "sha256:2466fbcf23711ebc5daa61d28ced319a6159b260a18839993d871096d66b93f7", - "sha256:2b573fcf6f9863ce746e4ad00ac18a948978bb3781cffa4305134d31801f3e26", - "sha256:3f0dae97e1126f529ebb66f3c63514a0f72a177b90d56e4bce8a0b5def34627a", - "sha256:50fb72bcbc2cf11e066579cb53c4ca8ac0227abb512b6cbc1faa02d1595a2a5d", - "sha256:57aea170fb23b1fd54fa537359d90d383d9bf5937ee54ae8045a723caa5e0961", - "sha256:709c2999b6bd36cdaf85cf888d8512da7433529f14a3689d6e37ab5242e7add5", - "sha256:7d59f21e43bbfd9a10953a7e26b35b6849d888fc5a331fa84a2d9c37bd9fe2a2", - "sha256:904b513ab8fbcbdb062bed1ce2f794ab20208a1b01ce9bd90776c6c7e7257032", - "sha256:96dd36f5cdde152fd6977d1bbc0f0561bccffecfde63cd397c8e6033eb66baba", - "sha256:9933b81fecbe935e6a7dc89cbd2b99fea1bf362f2790daf9422a7bb1dc3c3085", - "sha256:bbcc85aaf4cd84ba057decaead058f43191cc0e30d6bc5d44fe336dc3d3f4509", - "sha256:dccd380d8e025c867ddcb2f84b439722cf1f23f3a319381eac45fd077dee7170", - "sha256:e22cd0f72fc931d6abc69dc7764484ee20c6a60b0d0fee9ce0426029b1c1bdae", - "sha256:ed722aefb0ebffd10b32e67f48e8ac4c5c4cf5d3a785024fdf0e9eb17529cd9d", - "sha256:efb7ac5572c9a57159cf92c508aad9f856f1cb8e8302d7fdb99061dbe52d712c", - "sha256:efdba339fffb0e80fcc19524e4fdbda2e2b5772ea46720c44eaac28096d60720", - "sha256:f22273dd6a403ed870207b853a856ff6327d5cbce7a835dfa0645b3fc00273ec" - ], - "index": "pypi", - "version": "==1.18.4" + "sha256:082f8d4dd69b6b688f64f509b91d482362124986d98dc7dc5f5e9f9b9c3bb983", + "sha256:1bc0145999e8cb8aed9d4e65dd8b139adf1919e521177f198529687dbf613065", + "sha256:309cbcfaa103fc9a33ec16d2d62569d541b79f828c382556ff072442226d1968", + "sha256:3673c8b2b29077f1b7b3a848794f8e11f401ba0b71c49fbd26fb40b71788b132", + "sha256:480fdd4dbda4dd6b638d3863da3be82873bba6d32d1fc12ea1b8486ac7b8d129", + "sha256:56ef7f56470c24bb67fb43dae442e946a6ce172f97c69f8d067ff8550cf782ff", + "sha256:5a936fd51049541d86ccdeef2833cc89a18e4d3808fe58a8abeb802665c5af93", + "sha256:5b6885c12784a27e957294b60f97e8b5b4174c7504665333c5e94fbf41ae5d6a", + "sha256:667c07063940e934287993366ad5f56766bc009017b4a0fe91dbd07960d0aba7", + "sha256:7ed448ff4eaffeb01094959b19cbaf998ecdee9ef9932381420d514e446601cd", + "sha256:8343bf67c72e09cfabfab55ad4a43ce3f6bf6e6ced7acf70f45ded9ebb425055", + "sha256:92feb989b47f83ebef246adabc7ff3b9a59ac30601c3f6819f8913458610bdcc", + "sha256:935c27ae2760c21cd7354402546f6be21d3d0c806fffe967f745d5f2de5005a7", + "sha256:aaf42a04b472d12515debc621c31cf16c215e332242e7a9f56403d814c744624", + "sha256:b12e639378c741add21fbffd16ba5ad25c0a1a17cf2b6fe4288feeb65144f35b", + "sha256:b1cca51512299841bf69add3b75361779962f9cee7d9ee3bb446d5982e925b69", + "sha256:b8456987b637232602ceb4d663cb34106f7eb780e247d51a260b84760fd8f491", + "sha256:b9792b0ac0130b277536ab8944e7b754c69560dac0415dd4b2dbd16b902c8954", + "sha256:c9591886fc9cbe5532d5df85cb8e0cc3b44ba8ce4367bd4cf1b93dc19713da72", + "sha256:cf1347450c0b7644ea142712619533553f02ef23f92f781312f6a3553d031fc7", + "sha256:de8b4a9b56255797cbddb93281ed92acbc510fb7b15df3f01bd28f46ebc4edae", + "sha256:e1b1dc0372f530f26a03578ac75d5e51b3868b9b76cd2facba4c9ee0eb252ab1", + "sha256:e45f8e981a0ab47103181773cc0a54e650b2aef8c7b6cd07405d0fa8d869444a", + "sha256:e4f6d3c53911a9d103d8ec9518190e52a8b945bab021745af4939cfc7c0d4a9e", + "sha256:ed8a311493cf5480a2ebc597d1e177231984c818a86875126cfd004241a73c3e", + "sha256:ef71a1d4fd4858596ae80ad1ec76404ad29701f8ca7cdcebc50300178db14dfc" + ], + "index": "pypi", + "version": "==1.19.1" }, "oauthlib": { "hashes": [ @@ -1815,97 +1899,96 @@ }, "opencv-python": { "hashes": [ - "sha256:068928b9907b3d3acd53b129062557d6b0b8b324bfade77f028dbe4dfe482bf2", - "sha256:0e7c91718351449877c2d4141abd64eee1f9c8701bcfaf4e8627bd023e303368", - "sha256:1ab92d807427641ec45d28d5907426aa06b4ffd19c5b794729c74d91cd95090e", - "sha256:31d634dea1b47c231b88d384f90605c598214d0c596443c9bb808e11761829f5", - "sha256:5fdfc0bed37315f27d30ae5ae9bad47ec0a0a28c323739d39c8177b7e0929238", - "sha256:6fa8fac14dd5af4819d475f74af12d65fbbfa391d3110c3a972934a5e6507c24", - "sha256:78cc89ebc808886eb190626ee71ab65e47f374121975f86e4d5f7c0e3ce6bed9", - "sha256:7c7ba11720d01cb572b4b6945d115cb103462c0a28996b44d4e540d06e6a90fd", - "sha256:a37ee82f1b8ed4b4645619c504311e71ce845b78f40055e78d71add5fab7da82", - "sha256:aa3ca1f54054e1c6439fdf1edafa2a2b940a9eaac04a7b422a1cba9b2d7b9690", - "sha256:b9de3dd956574662712da8e285f0f54327959a4e95b96a2847d3c3f5ee7b96e2", - "sha256:c0087b428cef9a32d977390656d91b02245e0e91f909870492df7e39202645dd", - "sha256:d87e506ab205799727f0efa34b3888949bf029a3ada5eb000ff632606370ca6e", - "sha256:d8a55585631f9c9eca4b1a996e9732ae023169cf2f46f69e4518d67d96198226", - "sha256:dcb8da8c5ebaa6360c8555547a4c7beb6cd983dd95ba895bb78b86cc8cf3de2b", - "sha256:e2206bb8c17c0f212f1f356d82d72dd090ff4651994034416da9bf0c29732825", - "sha256:e3c57d6579e5bf85f564d6d48d8ee89868b92879a9232b9975d072c346625e92", - "sha256:ef89cbf332b9a735d8a82e9ff79cc743eeeb775ad1cd7100bc2aa2429b496f07", - "sha256:f45c1c3cdda1857bedd4dfe0bbd49c9419af0cc57f33490341edeae97d18f037", - "sha256:fb3c855347310788e4286b867997be354c55535597966ed5dac876d9166013a4" - ], - "index": "pypi", - "version": "==4.2.0.34" + "sha256:156e2954d5b38b676e8a24d66703cf15f252e24ec49db7e842a8b5eed46074ba", + "sha256:1bf486680a16d739f7852a62865b72eb7692df584694815774ba97b471b8bc3f", + "sha256:1ea08f22246ccd33174d59edfa3f13930bf2c28096568242090bd9d8770fb8a8", + "sha256:210ab40c8c9dadc7dc9ed7beebe2e0a2415a744f8d6857762a80c8e0fcc477c8", + "sha256:2ec6502bfac01b27ac06daf7bc9f7a4f482a6a0d8e1b30e15c411d478454a19f", + "sha256:2fe704e35808cf6b17b793e89fd00e9ef7779f85f274666a4e092671aedd09c0", + "sha256:4b93b5f8df187e4dba9fb25c46fa8cf342c257de144f7c86d75c06416566a199", + "sha256:55e1d7a2d11c40ea5b53aabe5c4122038803c7d492505c8f93af077aa7fe2ce1", + "sha256:677f61332436e22f83a1e4e6f6863a760734fbc8029ba6a8ef0af4554cde6f93", + "sha256:76ddc6daf8607eda1d866395dcf98526ef96f3e616d8c37ccc7629f9aaf6d4d4", + "sha256:c4f1e9d963c8f370284afa87fcf521cc8439a610a500bf8ede27fd64dd9050bd", + "sha256:c93b1198c85175a9fa9a9839c4da55c7ab9c5f57256f2e4211cd6c91d7d422e8", + "sha256:d765c44827778cbe6bc8f272cd61514e8509b93fd24dd3324cd4abddf2026b11", + "sha256:eb709245e56f6693d297f8818ff8e6c017fa80fdb5a923c64be623a678c7150e", + "sha256:ef4ac758a4e2caee80ef9c86b83a279d6f132c9e7ae77957cf74013928814e05", + "sha256:f67c1d92ff96c6c106f786b7ef9b9ab448fa03ef28cb7bb6f0f7b857b65bc158", + "sha256:f6fa2834d85c78865ca6e3de563916086cb8c83c3f2ef80924fcd07005f05df9", + "sha256:fa1a6d149a1a5e0bc54c737a59fe38d75384a092ae5e35f9b876fbb621f755c6", + "sha256:fd457deedcf153dd6805a2b4d891ac2a0969566d3755fbf48a3ffb53978c9ed1" + ], + "index": "pypi", + "version": "==4.3.0.36" }, "opt-einsum": { "hashes": [ - "sha256:83b76a98d18ae6a5cc7a0d88955a7f74881f0e567a0f4c949d24c942753eb998", - "sha256:96f819d46da2f937eaf326336a114aaeccbcbdb9de460d42e8b5f480a69adca7" + "sha256:2455e59e3947d3c275477df7f5205b30635e266fe6dc300e3d9f9646bfcea147", + "sha256:59f6475f77bbc37dcf7cd748519c0ec60722e91e63ca114e68821c0c54a46549" ], "markers": "python_version >= '3.5'", - "version": "==3.2.1" + "version": "==3.3.0" }, "osmium": { "hashes": [ - "sha256:0d9cfeaad95c69c5d19036f2065514cf09705ebbcf2b941c05d2a39ebed82acd", - "sha256:1229bf453a20454ac0cd64f6fd72ba05560f6e1967d0c744fad28ae1f0789457", - "sha256:1b5af19fa354c8ab3425075db87d6a022aca2d83344b07acac5ab8be1a03c8d6", - "sha256:1eec17f65688aa8c093c626102dae49c901227e1043ec4894b1e1b718c8cc78c", - "sha256:2133fff59b7c8964f4d7cce44505c994d3a72203c056b2722ddbdce1c101444b", - "sha256:2c42280676c05267a264481c9c691cfb2cbb64c1ac40b38ec834568fae205aa6", - "sha256:2dade90a89a4afc2aba89fb3a6e160f660c577bc98f5765c6a4a7f8d7451019b", - "sha256:38feb096933ad93891b7268f1b0894eac0fdfb91bec638153ce43a74c05fe150", - "sha256:4744d5c36f566a617fdb5fa4955f124926c86ee61acf18c1d870ced71fde3f2c", - "sha256:50a6395a233a17af643c48a0a92bf6173a1eb84243dcaa9ed07f373a5e3bb941", - "sha256:512c3313cfcc1ccbaff0c7a5f618ff24d6dd7de9aceaa8c21c9cada232209708", - "sha256:516c71dcf343003f7910c54d902042dba228b3c55ae5875220d94216861b4fbe", - "sha256:65da41c65b40f3a86c34a24848fe015d94d6e2f202baaabf1aca345b166b8239", - "sha256:7fbcad84cbec60359110f517650a99bc79fc966daf509ecb69e070fa7ca223e7", - "sha256:8648692409fb88f6d545890e4fda6538ed74c366d9b722f5c54d9a7f154468f8", - "sha256:9cde2311893a3727472538b3029196ceee1a2c21965c9edfb15e5fc1c1b8d18d", - "sha256:a172ea24e69266be52f06bb8dc2c8670e36e2fd4e442e4227ec3de8110ed0152", - "sha256:a533f109ed17f298d094d50fc99bd16635163fc3efda9f6fa39bb6b387100f7b", - "sha256:aa65fcdb366a01aacdb049e12f53e73326372f2fbe8832af1e350652e6b20c07", - "sha256:aad4b3887e0744a1b8457b368df6319c013ee4e707e5b6bb799771b20328faa7", - "sha256:ab250ce243fd5507c36d3f93b8e01cef5cae42cddb80e2353b3fd1ea7f3d7478", - "sha256:b792ff0b1569507afec1f4beced42d3402bd3a082dc525d9f27289f1f329c3ae", - "sha256:bafbd0d57f4376cbab9c2901490fc021df2078cb8c89b8ffe250798e43d8bc82", - "sha256:cd4b8f484b99f11cfdf9c0da970282534e0cafcc6a3107879f06ebb41b9f64f9" - ], - "index": "pypi", - "version": "==3.0.0" + "sha256:04e2f3380525c9b100d7c9350e107ae0d75c378c4c36d17cc4999c5952b33960", + "sha256:0a5e9cccd9c376ab31fe79cdb1efcd1eb8175e7ff74a1f7ac218bd084d1a819d", + "sha256:32e0b94c9a6f24c3f86787a5e23d7289c00467a19d13ff2552feb2810d8b76c3", + "sha256:396557cc44f9655419060fb56623822b64af3f835df1f35ca0bb5aad2b5f33fe", + "sha256:44cd17932ef17c1c749ff5585a76e68b4615bfbe94828b7765bdebb39dfb2d85", + "sha256:6909a93173acd4111cc179bd7317e8a4e656c3b7b1a9041c5a5a8fcd01dbc3b5", + "sha256:7638dd47f667ab2f18e0092036851e4ead4a47fb5840ff138e20c02bd47d14d7", + "sha256:7c3782400d001229302bdffd6f410c460b270aef29a4a58c45fd479c897825b6", + "sha256:8451c8ebdb39b7f3d5bc038c0230f592d4dffa50ec6baef64ee8baa72e814e8a", + "sha256:84a7259ab1c2a37b399cfd53b82c402daf8df611ce9223dc443ccf3142b97223", + "sha256:8bf205bed661aa0ab7cb39f00981ced6b1f46d923c5aec246e89616b45f64dd2", + "sha256:97de71233b4741992008ca49e77c0a92999e9077cec9d6511759ba5d55faedde", + "sha256:a4a2a7c55696ad32f809dfb48f0eca1acffc6d447063d2062aaca6d6f9a26946", + "sha256:a60445b2122e159d7775d57f4958191ea5a32395b289c91156841ef04bdc2182", + "sha256:a8f4ecebe1d536ab7cdd02fa9f82ff745dd4aa8ed478ccf588f586b4c4af38a9", + "sha256:c3526f17eeb58eda0525888542ae14586745b0faaaf00dca2ccf2d376b75899f", + "sha256:c85c2bc37b118b93dc8eb6c141bf415eff34c35084613be29ced3b969b49c7f6", + "sha256:ce18818b7260113fcedb54e3167da0e9a07723a92f23a594318086d8c09645df", + "sha256:cf78640c5cd9b8e76ee37b5c0522c5130469d3db26ffdfd54e8fb751477787f5", + "sha256:d5da39de1c00d0c0ef8771df29424abb8bdc3fe093641c1df7448f0a22266f28", + "sha256:e25a2f8f495ff7d96c1c3a4c636ea5aa5176b58d5323350f913b30a6a1b67159", + "sha256:ede6fed48da8512415a4a895c2ded2777dacddfacc1b342f7938aa4271c97bd1", + "sha256:f247a74c6a02016c7f3749f5fc6fad3abaa5c7874ae2be9516ef1649dc276792", + "sha256:fe43969f2fb021051c2c202c28bd42bd7453f3f41d5d2499126b16437bb52f63" + ], + "index": "pypi", + "version": "==3.0.1" }, "packaging": { "hashes": [ - "sha256:3c292b474fda1671ec57d46d739d072bfd495a4f51ad01a055121d81e952b7a3", - "sha256:82f77b9bee21c1bafbf35a84905d604d5d1223801d639cf3ed140bd651c08752" + "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8", + "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.3" + "version": "==20.4" }, "pandas": { "hashes": [ - "sha256:07c1b58936b80eafdfe694ce964ac21567b80a48d972879a359b3ebb2ea76835", - "sha256:0ebe327fb088df4d06145227a4aa0998e4f80a9e6aed4b61c1f303bdfdf7c722", - "sha256:11c7cb654cd3a0e9c54d81761b5920cdc86b373510d829461d8f2ed6d5905266", - "sha256:12f492dd840e9db1688126216706aa2d1fcd3f4df68a195f9479272d50054645", - "sha256:167a1315367cea6ec6a5e11e791d9604f8e03f95b57ad227409de35cf850c9c5", - "sha256:1a7c56f1df8d5ad8571fa251b864231f26b47b59cbe41aa5c0983d17dbb7a8e4", - "sha256:1fa4bae1a6784aa550a1c9e168422798104a85bf9c77a1063ea77ee6f8452e3a", - "sha256:32f42e322fb903d0e189a4c10b75ba70d90958cc4f66a1781ed027f1a1d14586", - "sha256:387dc7b3c0424327fe3218f81e05fc27832772a5dffbed385013161be58df90b", - "sha256:6597df07ea361231e60c00692d8a8099b519ed741c04e65821e632bc9ccb924c", - "sha256:743bba36e99d4440403beb45a6f4f3a667c090c00394c176092b0b910666189b", - "sha256:858a0d890d957ae62338624e4aeaf1de436dba2c2c0772570a686eaca8b4fc85", - "sha256:863c3e4b7ae550749a0bb77fa22e601a36df9d2905afef34a6965bed092ba9e5", - "sha256:a210c91a02ec5ff05617a298ad6f137b9f6f5771bf31f2d6b6367d7f71486639", - "sha256:ca84a44cf727f211752e91eab2d1c6c1ab0f0540d5636a8382a3af428542826e", - "sha256:d234bcf669e8b4d6cbcd99e3ce7a8918414520aeb113e2a81aeb02d0a533d7f7" + "sha256:0210f8fe19c2667a3817adb6de2c4fd92b1b78e1975ca60c0efa908e0985cbdb", + "sha256:0227e3a6e3a22c0e283a5041f1e3064d78fbde811217668bb966ed05386d8a7e", + "sha256:0bc440493cf9dc5b36d5d46bbd5508f6547ba68b02a28234cd8e81fdce42744d", + "sha256:16504f915f1ae424052f1e9b7cd2d01786f098fbb00fa4e0f69d42b22952d798", + "sha256:182a5aeae319df391c3df4740bb17d5300dcd78034b17732c12e62e6dd79e4a4", + "sha256:35db623487f00d9392d8af44a24516d6cb9f274afaf73cfcfe180b9c54e007d2", + "sha256:40ec0a7f611a3d00d3c666c4cceb9aa3f5bf9fbd81392948a93663064f527203", + "sha256:47a03bfef80d6812c91ed6fae43f04f2fa80a4e1b82b35aa4d9002e39529e0b8", + "sha256:4b21d46728f8a6be537716035b445e7ef3a75dbd30bd31aa1b251323219d853e", + "sha256:4d1a806252001c5db7caecbe1a26e49a6c23421d85a700960f6ba093112f54a1", + "sha256:60e20a4ab4d4fec253557d0fc9a4e4095c37b664f78c72af24860c8adcd07088", + "sha256:9f61cca5262840ff46ef857d4f5f65679b82188709d0e5e086a9123791f721c8", + "sha256:a15835c8409d5edc50b4af93be3377b5dd3eb53517e7f785060df1f06f6da0e2", + "sha256:b39508562ad0bb3f384b0db24da7d68a2608b9ddc85b1d931ccaaa92d5e45273", + "sha256:ed60848caadeacecefd0b1de81b91beff23960032cded0ac1449242b506a3b3f", + "sha256:fc714895b6de6803ac9f661abb316853d0cd657f5d23985222255ad76ccedc25" ], "markers": "python_version >= '3.6.1'", - "version": "==1.0.3" + "version": "==1.1.0" }, "pandocfilters": { "hashes": [ @@ -1913,6 +1996,14 @@ ], "version": "==1.4.2" }, + "parameterized": { + "hashes": [ + "sha256:190f8cc7230eee0b56b30d7f074fd4d165f7c45e6077582d0813c8557e738490", + "sha256:59ab908e31c01505a987a2be78854e19cb1630c047bbab7848169c371d614d56" + ], + "index": "pypi", + "version": "==0.7.4" + }, "paramiko": { "hashes": [ "sha256:920492895db8013f6cc0179293147f830b8c7b21fdfc839b6bad760c27459d9f", @@ -1923,11 +2014,11 @@ }, "parso": { "hashes": [ - "sha256:158c140fc04112dc45bca311633ae5033c2c2a7b732fa33d0955bad8152a8dd0", - "sha256:908e9fae2144a076d72ae4e25539143d40b8e3eafbaeae03c1bfe226f4cdf12c" + "sha256:97218d9159b2520ff45eb78028ba8b50d2bc61dcc062a9682666f2dc4bd331ea", + "sha256:caba44724b994a8a5e086460bb212abc5a8bc46951bf4a9a1210745953622eb9" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.7.0" + "version": "==0.7.1" }, "pexpect": { "hashes": [ @@ -1946,32 +2037,35 @@ }, "pillow": { "hashes": [ - "sha256:04766c4930c174b46fd72d450674612ab44cca977ebbcc2dde722c6933290107", - "sha256:0e2a3bceb0fd4e0cb17192ae506d5f082b309ffe5fc370a5667959c9b2f85fa3", - "sha256:0f01e63c34f0e1e2580cc0b24e86a5ccbbfa8830909a52ee17624c4193224cd9", - "sha256:12e4bad6bddd8546a2f9771485c7e3d2b546b458ae8ff79621214119ac244523", - "sha256:1f694e28c169655c50bb89a3fa07f3b854d71eb47f50783621de813979ba87f3", - "sha256:3d25dd8d688f7318dca6d8cd4f962a360ee40346c15893ae3b95c061cdbc4079", - "sha256:4b02b9c27fad2054932e89f39703646d0c543f21d3cc5b8e05434215121c28cd", - "sha256:70e3e0d99a0dcda66283a185f80697a9b08806963c6149c8e6c5f452b2aa59c0", - "sha256:9744350687459234867cbebfe9df8f35ef9e1538f3e729adbd8fde0761adb705", - "sha256:a0b49960110bc6ff5fead46013bcb8825d101026d466f3a4de3476defe0fb0dd", - "sha256:ae2b270f9a0b8822b98655cb3a59cdb1bd54a34807c6c56b76dd2e786c3b7db3", - "sha256:b37bb3bd35edf53125b0ff257822afa6962649995cbdfde2791ddb62b239f891", - "sha256:b532bcc2f008e96fd9241177ec580829dee817b090532f43e54074ecffdcd97f", - "sha256:b67a6c47ed963c709ed24566daa3f95a18f07d3831334da570c71da53d97d088", - "sha256:b943e71c2065ade6fef223358e56c167fc6ce31c50bc7a02dd5c17ee4338e8ac", - "sha256:ccc9ad2460eb5bee5642eaf75a0438d7f8887d484490d5117b98edd7f33118b7", - "sha256:d23e2aa9b969cf9c26edfb4b56307792b8b374202810bd949effd1c6e11ebd6d", - "sha256:eaa83729eab9c60884f362ada982d3a06beaa6cc8b084cf9f76cae7739481dfa", - "sha256:ee94fce8d003ac9fd206496f2707efe9eadcb278d94c271f129ab36aa7181344", - "sha256:f455efb7a98557412dc6f8e463c1faf1f1911ec2432059fa3e582b6000fc90e2", - "sha256:f46e0e024346e1474083c729d50de909974237c72daca05393ee32389dabe457", - "sha256:f54be399340aa602066adb63a86a6a5d4f395adfdd9da2b9a0162ea808c7b276", - "sha256:f784aad988f12c80aacfa5b381ec21fd3f38f851720f652b9f33facc5101cf4d" - ], - "index": "pypi", - "version": "==7.1.2" + "sha256:0295442429645fa16d05bd567ef5cff178482439c9aad0411d3f0ce9b88b3a6f", + "sha256:06aba4169e78c439d528fdeb34762c3b61a70813527a2c57f0540541e9f433a8", + "sha256:09d7f9e64289cb40c2c8d7ad674b2ed6105f55dc3b09aa8e4918e20a0311e7ad", + "sha256:0a80dd307a5d8440b0a08bd7b81617e04d870e40a3e46a32d9c246e54705e86f", + "sha256:1ca594126d3c4def54babee699c055a913efb01e106c309fa6b04405d474d5ae", + "sha256:25930fadde8019f374400f7986e8404c8b781ce519da27792cbe46eabec00c4d", + "sha256:431b15cffbf949e89df2f7b48528be18b78bfa5177cb3036284a5508159492b5", + "sha256:52125833b070791fcb5710fabc640fc1df07d087fc0c0f02d3661f76c23c5b8b", + "sha256:5e51ee2b8114def244384eda1c82b10e307ad9778dac5c83fb0943775a653cd8", + "sha256:612cfda94e9c8346f239bf1a4b082fdd5c8143cf82d685ba2dba76e7adeeb233", + "sha256:6d7741e65835716ceea0fd13a7d0192961212fd59e741a46bbed7a473c634ed6", + "sha256:6edb5446f44d901e8683ffb25ebdfc26988ee813da3bf91e12252b57ac163727", + "sha256:725aa6cfc66ce2857d585f06e9519a1cc0ef6d13f186ff3447ab6dff0a09bc7f", + "sha256:8dad18b69f710bf3a001d2bf3afab7c432785d94fcf819c16b5207b1cfd17d38", + "sha256:94cf49723928eb6070a892cb39d6c156f7b5a2db4e8971cb958f7b6b104fb4c4", + "sha256:97f9e7953a77d5a70f49b9a48da7776dc51e9b738151b22dacf101641594a626", + "sha256:9ad7f865eebde135d526bb3163d0b23ffff365cf87e767c649550964ad72785d", + "sha256:a060cf8aa332052df2158e5a119303965be92c3da6f2d93b6878f0ebca80b2f6", + "sha256:c79f9c5fb846285f943aafeafda3358992d64f0ef58566e23484132ecd8d7d63", + "sha256:c92302a33138409e8f1ad16731568c55c9053eee71bb05b6b744067e1b62380f", + "sha256:d08b23fdb388c0715990cbc06866db554e1822c4bdcf6d4166cf30ac82df8c41", + "sha256:d350f0f2c2421e65fbc62690f26b59b0bcda1b614beb318c81e38647e0f673a1", + "sha256:ec29604081f10f16a7aea809ad42e27764188fc258b02259a03a8ff7ded3808d", + "sha256:edf31f1150778abd4322444c393ab9c7bd2af271dd4dafb4208fb613b1f3cdc9", + "sha256:f7e30c27477dffc3e85c2463b3e649f751789e0f6c8456099eea7ddd53be4a8a", + "sha256:ffe538682dc19cc542ae7c3e504fdf54ca7f86fb8a135e59dd6bc8627eae6cce" + ], + "index": "pypi", + "version": "==7.2.0" }, "pkginfo": { "hashes": [ @@ -1980,33 +2074,34 @@ ], "version": "==1.5.0.1" }, - "pooch": { + "portalocker": { "hashes": [ - "sha256:453448b430ab4821178a5a5271bffece8163d4ca4e282a470f5700d55d26c697", - "sha256:b29687cd3a553d96d73c1fcbaa7551ff5b02a5503bdcd0fa1b1c96d18049d2c3" + "sha256:34cb36c618d88bcd9079beb36dcdc1848a3e3d92ac4eac59055bdeafc39f9d4a", + "sha256:6d6f5de5a3e68c4dd65a98ec1babb26d28ccc5e770e07b672d65d5a35e4b2d8a" ], - "markers": "python_version >= '3.5'", - "version": "==1.1.0" + "version": "==1.7.1" }, - "portalocker": { + "pprofile": { "hashes": [ - "sha256:091364838ed6fbb68ea291c28982d1e56125c0d9e3fad5a4ac001db54dd862dc", - "sha256:874d6063c6ceb185fe4771da41b01872d2c56d292db746698f8ad7bf1833c905" + "sha256:c2787af57c44c48e6c7e518d522fd0f93983892bfaae74ed340da02ed500ec5f" ], - "version": "==1.7.0" + "index": "pypi", + "version": "==2.0.5" }, - "pprofile": { + "pre-commit": { "hashes": [ - "sha256:2036522d201188641ab6766b3fea105ddeb72d3b752a7d6da695be7e7ba21656" + "sha256:1657663fdd63a321a4a739915d7d03baedd555b25054449090f97bb0cb30a915", + "sha256:e8b1315c585052e729ab7e99dcca5698266bedce9067d21dc909c23e3ceed626" ], "index": "pypi", - "version": "==2.0.4" + "version": "==2.6.0" }, "prometheus-client": { "hashes": [ - "sha256:71cd24a2b3eb335cb800c7159f423df1bd4dcd5171b234be15e3f31ec9f622da" + "sha256:983c7ac4b47478720db338f1491ef67a100b474e3bc7dafcbaefb7d0b8f9b01c", + "sha256:c6e6b706833a6bd1fd51711299edee907857be10ece535126a158f911ee80915" ], - "version": "==0.7.1" + "version": "==0.8.0" }, "prompt-toolkit": { "hashes": [ @@ -2018,27 +2113,26 @@ }, "protobuf": { "hashes": [ - "sha256:0bae429443cc4748be2aadfdaf9633297cfaeb24a9a02d0ab15849175ce90fab", - "sha256:24e3b6ad259544d717902777b33966a1a069208c885576254c112663e6a5bb0f", - "sha256:2affcaba328c4662f3bc3c0e9576ea107906b2c2b6422344cdad961734ff6b93", - "sha256:310a7aca6e7f257510d0c750364774034272538d51796ca31d42c3925d12a52a", - "sha256:52e586072612c1eec18e1174f8e3bb19d08f075fc2e3f91d3b16c919078469d0", - "sha256:73152776dc75f335c476d11d52ec6f0f6925774802cd48d6189f4d5d7fe753f4", - "sha256:7774bbbaac81d3ba86de646c39f154afc8156717972bf0450c9dbfa1dc8dbea2", - "sha256:82d7ac987715d8d1eb4068bf997f3053468e0ce0287e2729c30601feb6602fee", - "sha256:8eb9c93798b904f141d9de36a0ba9f9b73cc382869e67c9e642c0aba53b0fc07", - "sha256:adf0e4d57b33881d0c63bb11e7f9038f98ee0c3e334c221f0858f826e8fb0151", - "sha256:c40973a0aee65422d8cb4e7d7cbded95dfeee0199caab54d5ab25b63bce8135a", - "sha256:c77c974d1dadf246d789f6dad1c24426137c9091e930dbf50e0a29c1fcf00b1f", - "sha256:dd9aa4401c36785ea1b6fff0552c674bdd1b641319cb07ed1fe2392388e9b0d7", - "sha256:e11df1ac6905e81b815ab6fd518e79be0a58b5dc427a2cf7208980f30694b956", - "sha256:e2f8a75261c26b2f5f3442b0525d50fd79a71aeca04b5ec270fc123536188306", - "sha256:e512b7f3a4dd780f59f1bf22c302740e27b10b5c97e858a6061772668cd6f961", - "sha256:ef2c2e56aaf9ee914d3dccc3408d42661aaf7d9bb78eaa8f17b2e6282f214481", - "sha256:fac513a9dc2a74b99abd2e17109b53945e364649ca03d9f7a0b96aa8d1807d0a", - "sha256:fdfb6ad138dbbf92b5dbea3576d7c8ba7463173f7d2cb0ca1bd336ec88ddbd80" - ], - "version": "==3.11.3" + "sha256:0b00429b87821f1e6f3d641327864e6f271763ae61799f7540bc58a352825fe2", + "sha256:2636c689a6a2441da9a2ef922a21f9b8bfd5dfe676abd77d788db4b36ea86bee", + "sha256:2becd0e238ae34caf96fa7365b87f65b88aebcf7864dfe5ab461c5005f4256d9", + "sha256:2db6940c1914fa3fbfabc0e7c8193d9e18b01dbb4650acac249b113be3ba8d9e", + "sha256:32f0bcdf85e0040f36b4f548c71177027f2a618cab00ba235197fa9e230b7289", + "sha256:3d59825cba9447e8f4fcacc1f3c892cafd28b964e152629b3f420a2fb5918b5a", + "sha256:4794a7748ee645d2ae305f3f4f0abd459e789c973b5bc338008960f83e0c554b", + "sha256:50b7bb2124f6a1fb0ddc6a44428ae3a21e619ad2cdf08130ac6c00534998ef07", + "sha256:6009f3ebe761fad319b52199a49f1efa7a3729302947a78a3f5ea8e7e89e3ac2", + "sha256:a7b6cf201e67132ca99b8a6c4812fab541fdce1ceb54bb6f66bc336ab7259138", + "sha256:b6842284bb15f1b19c50c5fd496f1e2a4cfefdbdfa5d25c02620cb82793295a7", + "sha256:c0c8d7c8f07eacd9e98a907941b56e57883cf83de069cfaeaa7e02c582f72ddb", + "sha256:c99e5aea75b6f2b29c8d8da5bdc5f5ed8d9a5b4f15115c8316a3f0a850f94656", + "sha256:e2bd5c98952db3f1bb1af2e81b6a208909d3b8a2d32f7525c5cc10a6338b6593", + "sha256:e77ca4e1403b363a88bde9e31c11d093565e925e1685f40b29385a52f2320794", + "sha256:ef991cbe34d7bb935ba6349406a210d3558b9379c21621c6ed7b99112af7350e", + "sha256:f10ba89f9cd508dc00e469918552925ef7cba38d101ca47af1e78f2f9982c6b3", + "sha256:f1796e0eb911bf5b08e76b753953effbeb6bc42c95c16597177f627eaa52c375" + ], + "version": "==3.12.4" }, "ptyprocess": { "hashes": [ @@ -2050,8 +2144,19 @@ }, "pyasn1": { "hashes": [ + "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359", + "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576", + "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf", + "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7", "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d", - "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba" + "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00", + "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8", + "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86", + "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12", + "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776", + "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba", + "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2", + "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3" ], "version": "==0.4.8" }, @@ -2073,12 +2178,6 @@ ], "version": "==0.2.8" }, - "pycocotools": { - "git": "https://github.com/cocodataset/cocoapi.git", - "ref": "8c9bcc3cf640524c4c20a9c40e89cb6a2f2fa0e9", - "subdirectory": "PythonAPI", - "version": "==2.0" - }, "pycparser": { "hashes": [ "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0", @@ -2112,44 +2211,43 @@ }, "pygame": { "hashes": [ - "sha256:026e835dc69ab50db3f62e01884dceeee25283c04f5dbe992f059e24c11e29b3", - "sha256:07d9f21e2aee6679bcff760b93d336ca0981000a5bb6e665708ea9f08e9c06f6", - "sha256:134be66f54e1d588d3198f308afed3d495e5e9c1b1c36ffe71efc0afd2057eaf", - "sha256:1b153b52e1d46f1e779ef773707d23f03d23f014819ad3a822c2e357adbeed78", - "sha256:33795983f9fdce22b6e934f62d813364dbbd8846de25500fb9328f2a0ea619f9", - "sha256:33b50c90559b944b466f1cd0181a3019f80f50783fe58f43369b078c0c7172ef", - "sha256:3438463f73cc3d413b8c30daf194b5471b565cd74e4cfe0379562af534d44f22", - "sha256:34b03b5c411b60e1dca096f0237a59521b5cab0d32b388c5b3a00c1d371a5266", - "sha256:46211c0e87486c70a272246087bb8c221f546f0a5d258e7e722372de3bbfb887", - "sha256:545da86be8ed0f9af19e636ecf1c6ed2d2851d64abed7f1a64e517abb2f3058b", - "sha256:54b55f9f2fcf80aaf8c8ce2fd465e1b5cac948ccbd5a1d74561e63a9d9abd5f5", - "sha256:56fb61d0dcd8dfe9d35f402ee417bc4bc96ea41a84525efb3cda5403f9e13bda", - "sha256:587a5d52ba71ea16b299dce672d8d986364c9a4b0640fef49351839fa14a5950", - "sha256:7183302b00706ed6a886fac9775fb7f44e7a96b60aab75c73473a763a19f62b8", - "sha256:72238e9681713e68576483c8e8d7ea63c1b3bf7ee0d316f60239c5132a5b1115", - "sha256:7a01dced9d7880b4107b0b7fe65fc427c8886f26f36e4ada6eec809259742767", - "sha256:7d56c36ea9a71edb2aacdf5f628d31a9ffbf4bde025b1c9b77f707e8400dd910", - "sha256:7f6f710e7fd07adafdda139d4d43f358da666db2544608eabf0a43b1fb5dc5a4", - "sha256:8be68d1ddbb7a21ae2df8bf9621b7f6cc6bb6a15a49e76e105bd7fe9d88b84b3", - "sha256:8cf102e4b7ff37e6303b310ec38585a153a31c1eed3b5ceeae0df6f01d35ae01", - "sha256:94b3bae28d5811c400673918a0dd656f6deeb691b3530f25ee367180c822dfbe", - "sha256:9d122c30c731226efab9d1454919bb6595275345754513017b5798378f748200", - "sha256:a2062458a8b3646a13a93dbd557b46f57d6fc884486d4f14b1cb232c4014c03c", - "sha256:a39205e3e0d30a35cdab72fd22808db561599cb95e7c73ca6a113b7273f15529", - "sha256:a6c4ebb9a8c5dfa5ad8547a78b34550c2968a1ab2fe0c29a5af2e71d53a1da6b", - "sha256:a7fcfd5fadc91828bb9b0f7a8699f6c7ae900131b095e79bb1c5ca211bf9acd5", - "sha256:a9389e8b5fe55b1a1b62ccbcf8df55907bbe0250536bf39c2686f6d40d6c3e5a", - "sha256:b82470b9719dcccd1e26db132af055d5dd2fedd347ba272cc3788bf4723314de", - "sha256:bd6aca8554745760b3aade96586272fd724438b20aaa2c7335ffb8bab293e852", - "sha256:c1c5043fdc10629debabadb21854d8ff9f5642103d61f02df71104a270c2d0cc", - "sha256:d8cd6bc002b1725da0937cb5e789cb71bee6b05de90b436a2448a47ac64c9196", - "sha256:db9332d5b6040c3c0c6eed54fcd75b6fd592a219734c7bfb1cc5ecced82f0683", - "sha256:dbddf8921a3b19cfa09ad35a6a02d82f545cacd6d8e5d1dc41e26a2a468e43e9", - "sha256:e649cda58ebc5480e83db0fa217751ea5e73b3bd556ff019319acdf9a381d67c", - "sha256:feb72207824d0e77fc5c13ade0f5c9207ce0e4d0b14aa30e7e0e16f61ec36b25" - ], - "index": "pypi", - "version": "==2.0.0.dev6" + "sha256:010c2e49f15de8ca24e15ce51df6911f5d0804f2c484bd9c67ffc8ed78e452f0", + "sha256:0267b4def5c07e3b08329f80cb51c8c457d514221f6a2d5ec175569bd02280c9", + "sha256:071f0e4d50a5af008a86d43236fc3dc0a903fc6dab1872b4282e1022e8b888b6", + "sha256:0b3b26f6ad21a651301acf48c48fdc541bd3dbbdeb214d82bbad5c9403ed71e8", + "sha256:10743ba4d4d07fb2437f7399fe65b99b99202b92899b0b8f085d3f97bdd408e0", + "sha256:10ea85a1a2a06de7e9ee4b52c391f574104017bdc8a5569d92a95d4b6e4df9cc", + "sha256:1162be5304d72e84d173c1c0cfa68ba742a6d20f166095e945ee8f3952a25a25", + "sha256:1361dbc180786f17fe399f632a0809881bbaa588c094a613a5d139f0a9f5bb17", + "sha256:1f2d9df9374677a963d41e3247eea9a9da768a8556d055ffbd55fff0a48d8a1a", + "sha256:1f648ee199a7359b8bdd9534fbbb6d046910ed821ca565d23083eb4e128b38ce", + "sha256:370202bbc33b5747986eee24f44e2e84d5fb18a48398ec944018c288e9298874", + "sha256:56eefff1c9c4338533673f4cb00c975b1a807d41b429a66ecd6e0cae274b99b2", + "sha256:660ab9e8dd960d312f0bd1b0b7b62d22891fb6e188ebd980cc78d57336d067d2", + "sha256:68c3a9224bb9e878f244aad9cd842ccef10e9c074c6284b61ec2fd9931e67def", + "sha256:71d629fae5b20a88cdbf541abc4f2025b823731ee73b8b2380d9c86160640d11", + "sha256:7ae141466b6783abeaf66e10884a2824b3e47ab681f411e83b5c9884e15ba81b", + "sha256:7df846da4d24e85a38240e1bcc1d5579d72e4a8b675b4bc77aad899cb8d53feb", + "sha256:7fd14b068e784b118b51eda271a8fc3bfe2b0c54b6146ac6e34f66858ac27834", + "sha256:8068af05b2a2fc9984e55ad05f9131ec767b2fc312df0f50972e88c4485f5d8e", + "sha256:83029fa1ad72bf07aa6a6c8e05cfc5d1a07c08c648d21dfb3176d38c8f0db3b4", + "sha256:842f8991ae60c93493d548b34da4d9c9523eaa066d5dc849273cec080f9b46b8", + "sha256:8a80cff2fd8818daec3b084b4caa5c5ecbe2a2460d9c10f96682350032c3b5fe", + "sha256:921d6565b40ff3da1e505efa1f75f0438214ca0d6b413e19a481fb52bff1ca7a", + "sha256:96bc63d8e56998f079d1d92e077213935f3dea800300912e4176c2a300135e13", + "sha256:a0fe0dcdbba303cd5dd01d46231cbeabf0bbe2f9c88e6066458c8eeb584352de", + "sha256:b47875c58b507b74361cecd0083411e0b19ae15dff7da45e104da86d8a1fefcb", + "sha256:bdeb5399d90d352a393c2461ff19f2d627c602706be7ea1415021b4862ce720d", + "sha256:d4e0cd3392ebc88c321175b205ebeb0c3247ceb2468d940d90fcb849075b468f", + "sha256:d72e3a583b081058107e5157b706cc409b3afdae892f560481ef298fd4154a29", + "sha256:d76183fa2a6070006d0f8e95fb707edface752564248f63267bdd98464b55feb", + "sha256:da1d869fb24e2f852c259b79e80f47c6f38a1176f872bb79aa866ca79b052867", + "sha256:e63c0d05c384337b3354e6368769204f0b965b092d167f55eea26e13e97208d8", + "sha256:ecad810029f8058712ae649588fc0b2faaf0746be84aa225de285b2a000aba8f", + "sha256:f6d0ea74b97a487e1f491c75386d494ecd573851af4e08090eacfa707ba43428" + ], + "index": "pypi", + "version": "==2.0.0.dev8" }, "pygments": { "hashes": [ @@ -2169,11 +2267,11 @@ }, "pylint": { "hashes": [ - "sha256:b95e31850f3af163c2283ed40432f053acbc8fc6eba6a069cb518d9dbf71848c", - "sha256:dd506acce0427e9e08fb87274bcaa953d38b50a58207170dbf5b36cf3e16957b" + "sha256:7dd78437f2d8d019717dbf287772d0b2dbdfd13fc016aa7faa08d67bccc46adc", + "sha256:d0ece7d223fe422088b0e8f13fa0a1e8eb745ebffcb8ed53d3e95394b6101a1c" ], "index": "pypi", - "version": "==2.5.2" + "version": "==2.5.3" }, "pylogbeat": { "hashes": [ @@ -2184,99 +2282,93 @@ }, "pymongo": { "hashes": [ - "sha256:01b4e10027aef5bb9ecefbc26f5df3368ce34aef81df43850f701e716e3fe16d", - "sha256:0fc5aa1b1acf7f61af46fe0414e6a4d0c234b339db4c03a63da48599acf1cbfc", - "sha256:1396eb7151e0558b1f817e4b9d7697d5599e5c40d839a9f7270bd90af994ad82", - "sha256:18e84a3ec5e73adcb4187b8e5541b2ad61d716026ed9863267e650300d8bea33", - "sha256:19adf2848b80cb349b9891cc854581bbf24c338be9a3260e73159bdeb2264464", - "sha256:20ee0475aa2ba437b0a14806f125d696f90a8433d820fb558fdd6f052acde103", - "sha256:26798795097bdeb571f13942beef7e0b60125397811c75b7aa9214d89880dd1d", - "sha256:26e707a4eb851ec27bb969b5f1413b9b2eac28fe34271fa72329100317ea7c73", - "sha256:2a3c7ad01553b27ec553688a1e6445e7f40355fb37d925c11fcb50b504e367f8", - "sha256:2f07b27dbf303ea53f4147a7922ce91a26b34a0011131471d8aaf73151fdee9a", - "sha256:316f0cf543013d0c085e15a2c8abe0db70f93c9722c0f99b6f3318ff69477d70", - "sha256:31d11a600eea0c60de22c8bdcb58cda63c762891facdcb74248c36713240987f", - "sha256:334ef3ffd0df87ea83a0054454336159f8ad9c1b389e19c0032d9cb8410660e6", - "sha256:358ba4693c01022d507b96a980ded855a32dbdccc3c9331d0667be5e967f30ed", - "sha256:3a6568bc53103df260f5c7d2da36dffc5202b9a36c85540bba1836a774943794", - "sha256:444bf2f44264578c4085bb04493bfed0e5c1b4fe7c2704504d769f955cc78fe4", - "sha256:47a00b22c52ee59dffc2aad02d0bbfb20c26ec5b8de8900492bf13ad6901cf35", - "sha256:4c067db43b331fc709080d441cb2e157114fec60749667d12186cc3fc8e7a951", - "sha256:4c092310f804a5d45a1bcaa4191d6d016c457b6ed3982a622c35f729ff1c7f6b", - "sha256:53b711b33134e292ef8499835a3df10909c58df53a2a0308f598c432e9a62892", - "sha256:568d6bee70652d8a5af1cd3eec48b4ca1696fb1773b80719ebbd2925b72cb8f6", - "sha256:56fa55032782b7f8e0bf6956420d11e2d4e9860598dfe9c504edec53af0fc372", - "sha256:5a2c492680c61b440272341294172fa3b3751797b1ab983533a770e4fb0a67ac", - "sha256:61235cc39b5b2f593086d1d38f3fc130b2d125bd8fc8621d35bc5b6bdeb92bd2", - "sha256:619ac9aaf681434b4d4718d1b31aa2f0fce64f2b3f8435688fcbdc0c818b6c54", - "sha256:6238ac1f483494011abde5286282afdfacd8926659e222ba9b74c67008d3a58c", - "sha256:63752a72ca4d4e1386278bd43d14232f51718b409e7ac86bcf8810826b531113", - "sha256:6fdc5ccb43864065d40dd838437952e9e3da9821b7eac605ba46ada77f846bdf", - "sha256:7abc3a6825a346fa4621a6f63e3b662bbb9e0f6ffc32d30a459d695f20fb1a8b", - "sha256:7aef381bb9ae8a3821abd7f9d4d93978dbd99072b48522e181baeffcd95b56ae", - "sha256:80df3caf251fe61a3f0c9614adc6e2bfcffd1cd3345280896766712fb4b4d6d7", - "sha256:95f970f34b59987dee6f360d2e7d30e181d58957b85dff929eee4423739bd151", - "sha256:993257f6ca3cde55332af1f62af3e04ca89ce63c08b56a387cdd46136c72f2fa", - "sha256:9c0a57390549affc2b5dda24a38de03a5c7cbc58750cd161ff5d106c3c6eec80", - "sha256:a0794e987d55d2f719cc95fcf980fc62d12b80e287e6a761c4be14c60bd9fecc", - "sha256:a3b98121e68bf370dd8ea09df67e916f93ea95b52fc010902312168c4d1aff5d", - "sha256:a60756d55f0887023b3899e6c2923ba5f0042fb11b1d17810b4e07395404f33e", - "sha256:a676bd2fbc2309092b9bbb0083d35718b5420af3a42135ebb1e4c3633f56604d", - "sha256:a732838c78554c1257ff2492f5c8c4c7312d0aecd7f732149e255f3749edd5ee", - "sha256:ad3dc88dfe61f0f1f9b99c6bc833ea2f45203a937a18f0d2faa57c6952656012", - "sha256:ae65d65fde4135ef423a2608587c9ef585a3551fc2e4e431e7c7e527047581be", - "sha256:b070a4f064a9edb70f921bfdc270725cff7a78c22036dd37a767c51393fb956f", - "sha256:b6da85949aa91e9f8c521681344bd2e163de894a5492337fba8b05c409225a4f", - "sha256:bbf47110765b2a999803a7de457567389253f8670f7daafb98e059c899ce9764", - "sha256:bd9c1e6f92b4888ae3ef7ae23262c513b962f09f3fb3b48581dde5df7d7a860a", - "sha256:c06b3f998d2d7160db58db69adfb807d2ec307e883e2f17f6b87a1ef6c723f11", - "sha256:c318fb70542be16d3d4063cde6010b1e4d328993a793529c15a619251f517c39", - "sha256:c4aef42e5fa4c9d5a99f751fb79caa880dac7eaf8a65121549318b984676a1b7", - "sha256:c9ca545e93a9c2a3bdaa2e6e21f7a43267ff0813e8055adf2b591c13164c0c57", - "sha256:da2c3220eb55c4239dd8b982e213da0b79023cac59fe54ca09365f2bc7e4ad32", - "sha256:dd8055da300535eefd446b30995c0813cc4394873c9509323762a93e97c04c03", - "sha256:e2b46e092ea54b732d98c476720386ff2ccd126de1e52076b470b117bff7e409", - "sha256:e334c4f39a2863a239d38b5829e442a87f241a92da9941861ee6ec5d6380b7fe", - "sha256:e5c54f04ca42bbb5153aec5d4f2e3d9f81e316945220ac318abd4083308143f5", - "sha256:f4d06764a06b137e48db6d569dc95614d9d225c89842c885669ee8abc9f28c7a", - "sha256:f96333f9d2517c752c20a35ff95de5fc2763ac8cdb1653df0f6f45d281620606" - ], - "index": "pypi", - "version": "==3.10.1" + "sha256:03dc64a9aa7a5d405aea5c56db95835f6a2fa31b3502c5af1760e0e99210be30", + "sha256:05fcc6f9c60e6efe5219fbb5a30258adb3d3e5cbd317068f3d73c09727f2abb6", + "sha256:076a7f2f7c251635cf6116ac8e45eefac77758ee5a77ab7bd2f63999e957613b", + "sha256:137e6fa718c7eff270dbd2fc4b90d94b1a69c9e9eb3f3de9e850a7fd33c822dc", + "sha256:1f865b1d1c191d785106f54df9abdc7d2f45a946b45fd1ea0a641b4f982a2a77", + "sha256:213c445fe7e654621c6309e874627c35354b46ef3ee807f5a1927dc4b30e1a67", + "sha256:25e617daf47d8dfd4e152c880cd0741cbdb48e51f54b8de9ddbfe74ecd87dd16", + "sha256:3d9bb1ba935a90ec4809a8031efd988bdb13cdba05d9e9a3e9bf151bf759ecde", + "sha256:40696a9a53faa7d85aaa6fd7bef1cae08f7882640bad08c350fb59dee7ad069b", + "sha256:421aa1b92c291c429668bd8d8d8ec2bd00f183483a756928e3afbf2b6f941f00", + "sha256:4437300eb3a5e9cc1a73b07d22c77302f872f339caca97e9bf8cf45eca8fa0d2", + "sha256:455f4deb00158d5ec8b1d3092df6abb681b225774ab8a59b3510293b4c8530e3", + "sha256:475a34a0745c456ceffaec4ce86b7e0983478f1b6140890dff7b161e7bcd895b", + "sha256:4797c0080f41eba90404335e5ded3aa66731d303293a675ff097ce4ea3025bb9", + "sha256:4ae23fbbe9eadf61279a26eba866bbf161a6f7e2ffad14a42cf20e9cb8e94166", + "sha256:4b32744901ee9990aa8cd488ec85634f443526def1e5190a407dc107148249d7", + "sha256:50127b13b38e8e586d5e97d342689405edbd74ad0bd891d97ee126a8c7b6e45f", + "sha256:50531caa7b4be1c4ed5e2d5793a4e51cc9bd62a919a6fd3299ef7c902e206eab", + "sha256:63a5387e496a98170ffe638b435c0832c0f2011a6f4ff7a2880f17669fff8c03", + "sha256:68220b81850de8e966d4667d5c325a96c6ac0d6adb3d18935d6e3d325d441f48", + "sha256:689142dc0c150e9cb7c012d84cac2c346d40beb891323afb6caf18ec4caafae0", + "sha256:6a15e2bee5c4188369a87ed6f02de804651152634a46cca91966a11c8abd2550", + "sha256:7122ffe597b531fb065d3314e704a6fe152b81820ca5f38543e70ffcc95ecfd4", + "sha256:7307024b18266b302f4265da84bb1effb5d18999ef35b30d17592959568d5c0a", + "sha256:7a4a6f5b818988a3917ec4baa91d1143242bdfece8d38305020463955961266a", + "sha256:83c5a3ecd96a9f3f11cfe6dfcbcec7323265340eb24cc996acaecea129865a3a", + "sha256:890b0f1e18dbd898aeb0ab9eae1ab159c6bcbe87f0abb065b0044581d8614062", + "sha256:8deda1f7b4c03242f2a8037706d9584e703f3d8c74d6d9cac5833db36fe16c42", + "sha256:8ea13d0348b4c96b437d944d7068d59ed4a6c98aaa6c40d8537a2981313f1c66", + "sha256:91e96bf85b7c07c827d339a386e8a3cf2e90ef098c42595227f729922d0851df", + "sha256:96782ebb3c9e91e174c333208b272ea144ed2a684413afb1038e3b3342230d72", + "sha256:9755c726aa6788f076114dfdc03b92b03ff8860316cca00902cce88bcdb5fedd", + "sha256:9dbab90c348c512e03f146e93a5e2610acec76df391043ecd46b6b775d5397e6", + "sha256:9ee0eef254e340cc11c379f797af3977992a7f2c176f1a658740c94bf677e13c", + "sha256:9fc17fdac8f1973850d42e51e8ba6149d93b1993ed6768a24f352f926dd3d587", + "sha256:a2787319dc69854acdfd6452e6a8ba8f929aeb20843c7f090e04159fc18e6245", + "sha256:b7c522292407fa04d8195032493aac937e253ad9ae524aab43b9d9d242571f03", + "sha256:bd312794f51e37dcf77f013d40650fe4fbb211dd55ef2863839c37480bd44369", + "sha256:c0d660a186e36c526366edf8a64391874fe53cf8b7039224137aee0163c046df", + "sha256:c4869141e20769b65d2d72686e7a7eb141ce9f3168106bed3e7dcced54eb2422", + "sha256:cc4057f692ac35bbe82a0a908d42ce3a281c9e913290fac37d7fa3bd01307dfb", + "sha256:cccf1e7806f12300e3a3b48f219e111000c2538483e85c869c35c1ae591e6ce9", + "sha256:ce208f80f398522e49d9db789065c8ad2cd37b21bd6b23d30053474b7416af11", + "sha256:d0565481dc196986c484a7fb13214fc6402201f7fb55c65fd215b3324962fe6c", + "sha256:d1b3366329c45a474b3bbc9b9c95d4c686e03f35da7fd12bc144626d1f2a7c04", + "sha256:d226e0d4b9192d95079a9a29c04dd81816b1ce8903b8c174a39224fe978547cb", + "sha256:d38b35f6eef4237b1d0d8e845fc1546dad85c55eba447e28c211da8c7ef9697c", + "sha256:d64c98277ea80e4484f1332ab107e8dfd173a7dcf1bdbf10a9cccc97aaab145f", + "sha256:d9de8427a5601799784eb0e7fa1b031aa64086ce04de29df775a8ca37eedac41", + "sha256:e6a15cf8f887d9f578dd49c6fb3a99d53e1d922fdd67a245a67488d77bf56eb2", + "sha256:e8c446882cbb3774cd78c738c9f58220606b702b7c1655f1423357dc51674054", + "sha256:e8d188ee39bd0ffe76603da887706e4e7b471f613625899ddf1e27867dc6a0d3", + "sha256:ef76535776c0708a85258f6dc51d36a2df12633c735f6d197ed7dfcaa7449b99", + "sha256:f6efca006a81e1197b925a7d7b16b8f61980697bb6746587aad8842865233218" + ], + "index": "pypi", + "version": "==3.11.0" }, "pymysql": { "hashes": [ - "sha256:95f057328357e0e13a30e67857a8c694878b0175797a9a203ee7adbfb9b1ec5f", - "sha256:9ec760cbb251c158c19d6c88c17ca00a8632bac713890e465b2be01fdc30713f" + "sha256:adef15ceccf1ff544a23a6f46609f65187261dc8b0cf94c9644189c173b0a451", + "sha256:e14070bc84e050e0f80bf6063e31d276f03a0bb4d46b9eca2854566c4ae19837" ], "index": "pypi", - "version": "==0.9.2" + "version": "==0.10.0" }, "pynacl": { "hashes": [ - "sha256:05c26f93964373fc0abe332676cb6735f0ecad27711035b9472751faa8521255", - "sha256:0c6100edd16fefd1557da078c7a31e7b7d7a52ce39fdca2bec29d4f7b6e7600c", - "sha256:0d0a8171a68edf51add1e73d2159c4bc19fc0718e79dec51166e940856c2f28e", - "sha256:1c780712b206317a746ace34c209b8c29dbfd841dfbc02aa27f2084dd3db77ae", - "sha256:2424c8b9f41aa65bbdbd7a64e73a7450ebb4aa9ddedc6a081e7afcc4c97f7621", - "sha256:2d23c04e8d709444220557ae48ed01f3f1086439f12dbf11976e849a4926db56", - "sha256:30f36a9c70450c7878053fa1344aca0145fd47d845270b43a7ee9192a051bf39", - "sha256:37aa336a317209f1bb099ad177fef0da45be36a2aa664507c5d72015f956c310", - "sha256:4943decfc5b905748f0756fdd99d4f9498d7064815c4cf3643820c9028b711d1", - "sha256:53126cd91356342dcae7e209f840212a58dcf1177ad52c1d938d428eebc9fee5", - "sha256:57ef38a65056e7800859e5ba9e6091053cd06e1038983016effaffe0efcd594a", - "sha256:5bd61e9b44c543016ce1f6aef48606280e45f892a928ca7068fba30021e9b786", - "sha256:6482d3017a0c0327a49dddc8bd1074cc730d45db2ccb09c3bac1f8f32d1eb61b", - "sha256:7d3ce02c0784b7cbcc771a2da6ea51f87e8716004512493a2b69016326301c3b", - "sha256:a14e499c0f5955dcc3991f785f3f8e2130ed504fa3a7f44009ff458ad6bdd17f", - "sha256:a39f54ccbcd2757d1d63b0ec00a00980c0b382c62865b61a505163943624ab20", - "sha256:aabb0c5232910a20eec8563503c153a8e78bbf5459490c49ab31f6adf3f3a415", - "sha256:bd4ecb473a96ad0f90c20acba4f0bf0df91a4e03a1f4dd6a4bdc9ca75aa3a715", - "sha256:bf459128feb543cfca16a95f8da31e2e65e4c5257d2f3dfa8c0c1031139c9c92", - "sha256:e2da3c13307eac601f3de04887624939aca8ee3c9488a0bb0eca4fb9401fc6b1", - "sha256:f67814c38162f4deb31f68d590771a29d5ae3b1bd64b75cf232308e5c74777e0" + "sha256:06cbb4d9b2c4bd3c8dc0d267416aaed79906e7b33f114ddbf0911969794b1cc4", + "sha256:11335f09060af52c97137d4ac54285bcb7df0cef29014a1a4efe64ac065434c4", + "sha256:2fe0fc5a2480361dcaf4e6e7cea00e078fcda07ba45f811b167e3f99e8cff574", + "sha256:30f9b96db44e09b3304f9ea95079b1b7316b2b4f3744fe3aaecccd95d547063d", + "sha256:511d269ee845037b95c9781aa702f90ccc36036f95d0f31373a6a79bd8242e25", + "sha256:537a7ccbea22905a0ab36ea58577b39d1fa9b1884869d173b5cf111f006f689f", + "sha256:54e9a2c849c742006516ad56a88f5c74bf2ce92c9f67435187c3c5953b346505", + "sha256:757250ddb3bff1eecd7e41e65f7f833a8405fede0194319f87899690624f2122", + "sha256:7757ae33dae81c300487591c68790dfb5145c7d03324000433d9a2c141f82af7", + "sha256:7c6092102219f59ff29788860ccb021e80fffd953920c4a8653889c029b2d420", + "sha256:8122ba5f2a2169ca5da936b2e5a511740ffb73979381b4229d9188f6dcb22f1f", + "sha256:9c4a7ea4fb81536c1b1f5cc44d54a296f96ae78c1ebd2311bd0b60be45a48d96", + "sha256:cd401ccbc2a249a47a3a1724c2918fcd04be1f7b54eb2a5a71ff915db0ac51c6", + "sha256:d452a6746f0a7e11121e64625109bc4468fc3100452817001dbe018bb8b08514", + "sha256:ea6841bc3a76fa4942ce00f3bda7d436fda21e2d91602b9e21b7ca9ecab8f3ff", + "sha256:f8851ab9041756003119368c1e6cd0b9c631f46d686b3904b18c0139f4419f80" ], - "version": "==1.3.0" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.4.0" }, "pynmea2": { "hashes": [ @@ -2353,10 +2445,10 @@ }, "python-engineio": { "hashes": [ - "sha256:222926adb4bc6e03a8fc8e0ef2a3309f030c1c3f8e0fcc94c9ba214574565f02", - "sha256:2481732d93646998f7372ef0ecf003af7817b82720b881db173c3d50b4887916" + "sha256:133bdb5fb89f43a53f8612fb1ddbb3a453318713dea18a9ecf5346ed0c0f793c", + "sha256:41353c2539493e9e30e0e75e53f9cbb670f09a5ebcf82fe738081a9ba28fe55c" ], - "version": "==3.12.1" + "version": "==3.13.1" }, "python-logstash": { "hashes": [ @@ -2367,18 +2459,18 @@ }, "python-logstash-async": { "hashes": [ - "sha256:96492d7080bd197baf889d3ea927206e987161e08d3fce9cfb0557c6c6d4013e", - "sha256:c07d7f80d06b807ac8ab613562d7f246056ffb57320e60c714cd421ff053c2c2" + "sha256:56b0fd4c06ede320d7f1defa6b4f6b442227a880ce84f44c88b69c313e35cd6f", + "sha256:57aebfccd8a7e0ee5b7c4bdb7c941e84eac3c3e30c5619feabb5444d9b827d2b" ], "index": "pypi", - "version": "==1.6.4" + "version": "==1.6.6" }, "python-socketio": { "hashes": [ - "sha256:149b98c33f8c3d09273fb4ebeb83781e4dc9411b56b27d9f058bec1bd1ed74b7", - "sha256:81280cbbb7018d8ecdd006bf6025979733d347c0f2612282c1e21f6ed7d3b55b" + "sha256:358d8fbbc029c4538ea25bcaa283e47f375be0017fcba829de8a3a731c9df25a", + "sha256:d437f797c44b6efba2f201867cf02b8c96b97dff26d4e4281ac08b45817cd522" ], - "version": "==4.5.1" + "version": "==4.6.0" }, "pytz": { "hashes": [ @@ -2433,44 +2525,44 @@ }, "pyzmq": { "hashes": [ - "sha256:07fb8fe6826a229dada876956590135871de60dbc7de5a18c3bcce2ed1f03c98", - "sha256:13a5638ab24d628a6ade8f794195e1a1acd573496c3b85af2f1183603b7bf5e0", - "sha256:15b4cb21118f4589c4db8be4ac12b21c8b4d0d42b3ee435d47f686c32fe2e91f", - "sha256:21f7d91f3536f480cb2c10d0756bfa717927090b7fb863e6323f766e5461ee1c", - "sha256:2a88b8fabd9cc35bd59194a7723f3122166811ece8b74018147a4ed8489e6421", - "sha256:342fb8a1dddc569bc361387782e8088071593e7eaf3e3ecf7d6bd4976edff112", - "sha256:4ee0bfd82077a3ff11c985369529b12853a4064320523f8e5079b630f9551448", - "sha256:54aa24fd60c4262286fc64ca632f9e747c7cc3a3a1144827490e1dc9b8a3a960", - "sha256:58688a2dfa044fad608a8e70ba8d019d0b872ec2acd75b7b5e37da8905605891", - "sha256:5b99c2ae8089ef50223c28bac57510c163bfdff158c9e90764f812b94e69a0e6", - "sha256:5b9d21fc56c8aacd2e6d14738021a9d64f3f69b30578a99325a728e38a349f85", - "sha256:5f1f2eb22aab606f808163eb1d537ac9a0ba4283fbeb7a62eb48d9103cf015c2", - "sha256:6ca519309703e95d55965735a667809bbb65f52beda2fdb6312385d3e7a6d234", - "sha256:87c78f6936e2654397ca2979c1d323ee4a889eef536cc77a938c6b5be33351a7", - "sha256:8952f6ba6ae598e792703f3134af5a01af8f5c7cf07e9a148f05a12b02412cea", - "sha256:931339ac2000d12fe212e64f98ce291e81a7ec6c73b125f17cf08415b753c087", - "sha256:956775444d01331c7eb412c5fb9bb62130dfaac77e09f32764ea1865234e2ca9", - "sha256:97b6255ae77328d0e80593681826a0479cb7bac0ba8251b4dd882f5145a2293a", - "sha256:aaa8b40b676576fd7806839a5de8e6d5d1b74981e6376d862af6c117af2a3c10", - "sha256:af0c02cf49f4f9eedf38edb4f3b6bb621d83026e7e5d76eb5526cc5333782fd6", - "sha256:b08780e3a55215873b3b8e6e7ca8987f14c902a24b6ac081b344fd430d6ca7cd", - "sha256:ba6f24431b569aec674ede49cad197cad59571c12deed6ad8e3c596da8288217", - "sha256:bafd651b557dd81d89bd5f9c678872f3e7b7255c1c751b78d520df2caac80230", - "sha256:bfff5ffff051f5aa47ba3b379d87bd051c3196b0c8a603e8b7ed68a6b4f217ec", - "sha256:cf5d689ba9513b9753959164cf500079383bc18859f58bf8ce06d8d4bef2b054", - "sha256:dcbc3f30c11c60d709c30a213dc56e88ac016fe76ac6768e64717bd976072566", - "sha256:f9d7e742fb0196992477415bb34366c12e9bb9a0699b8b3f221ff93b213d7bec", - "sha256:faee2604f279d31312bc455f3d024f160b6168b9c1dde22bf62d8c88a4deca8e" - ], - "index": "pypi", - "version": "==19.0.1" + "sha256:00dca814469436455399660247d74045172955459c0bd49b54a540ce4d652185", + "sha256:046b92e860914e39612e84fa760fc3f16054d268c11e0e25dcb011fb1bc6a075", + "sha256:09d24a80ccb8cbda1af6ed8eb26b005b6743e58e9290566d2a6841f4e31fa8e0", + "sha256:0a422fc290d03958899743db091f8154958410fc76ce7ee0ceb66150f72c2c97", + "sha256:276ad604bffd70992a386a84bea34883e696a6b22e7378053e5d3227321d9702", + "sha256:296540a065c8c21b26d63e3cea2d1d57902373b16e4256afe46422691903a438", + "sha256:29d51279060d0a70f551663bc592418bcad7f4be4eea7b324f6dd81de05cb4c1", + "sha256:36ab114021c0cab1a423fe6689355e8f813979f2c750968833b318c1fa10a0fd", + "sha256:3fa6debf4bf9412e59353defad1f8035a1e68b66095a94ead8f7a61ae90b2675", + "sha256:5120c64646e75f6db20cc16b9a94203926ead5d633de9feba4f137004241221d", + "sha256:59f1e54627483dcf61c663941d94c4af9bf4163aec334171686cdaee67974fe5", + "sha256:5d9fc809aa8d636e757e4ced2302569d6e60e9b9c26114a83f0d9d6519c40493", + "sha256:654d3e06a4edc566b416c10293064732516cf8871a4522e0a2ba00cc2a2e600c", + "sha256:720d2b6083498a9281eaee3f2927486e9fe02cd16d13a844f2e95217f243efea", + "sha256:73483a2caaa0264ac717af33d6fb3f143d8379e60a422730ee8d010526ce1913", + "sha256:8a6ada5a3f719bf46a04ba38595073df8d6b067316c011180102ba2a1925f5b5", + "sha256:8b66b94fe6243d2d1d89bca336b2424399aac57932858b9a30309803ffc28112", + "sha256:99cc0e339a731c6a34109e5c4072aaa06d8e32c0b93dc2c2d90345dd45fa196c", + "sha256:a7e7f930039ee0c4c26e4dfee015f20bd6919cd8b97c9cd7afbde2923a5167b6", + "sha256:ab0d01148d13854de716786ca73701012e07dff4dfbbd68c4e06d8888743526e", + "sha256:c1a31cd42905b405530e92bdb70a8a56f048c8a371728b8acf9d746ecd4482c0", + "sha256:c20dd60b9428f532bc59f2ef6d3b1029a28fc790d408af82f871a7db03e722ff", + "sha256:c36ffe1e5aa35a1af6a96640d723d0d211c5f48841735c2aa8d034204e87eb87", + "sha256:c40fbb2b9933369e994b837ee72193d6a4c35dfb9a7c573257ef7ff28961272c", + "sha256:d46fb17f5693244de83e434648b3dbb4f4b0fec88415d6cbab1c1452b6f2ae17", + "sha256:e36f12f503511d72d9bdfae11cadbadca22ff632ff67c1b5459f69756a029c19", + "sha256:f1a25a61495b6f7bb986accc5b597a3541d9bd3ef0016f50be16dbb32025b302", + "sha256:fa411b1d8f371d3a49d31b0789eb6da2537dadbb2aef74a43aa99a78195c3f76" + ], + "index": "pypi", + "version": "==19.0.2" }, "qtconsole": { "hashes": [ - "sha256:8f5ae5571f0e921db9f2d12613ed667c350ee22c7db598d9bbbe143e8533f932", - "sha256:e7882df6e95ec710b5893ec3a7ebfd54e410e63d801e4bbf8c785d74758c2329" + "sha256:4f43d0b049eacb7d723772847f0c465feccce0ccb398871a6e146001a22bad23", + "sha256:f5cb275d30fc8085e2d1d18bc363e5ba0ce6e559bf37d7d6727b773134298754" ], - "version": "==4.7.3" + "version": "==4.7.5" }, "qtpy": { "hashes": [ @@ -2481,19 +2573,19 @@ }, "redis": { "hashes": [ - "sha256:6e9d2722a95d10ddf854596e66516d316d99c6a483e5db3b35c34e1158b2bfa1", - "sha256:a5b0e25890d216d8189636742c50ab992e42eea699bcc1b08cc2d6bf3adff52a" + "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2", + "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24" ], "index": "pypi", - "version": "==3.5.1" + "version": "==3.5.3" }, "requests": { "hashes": [ - "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee", - "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6" + "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b", + "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898" ], "index": "pypi", - "version": "==2.23.0" + "version": "==2.24.0" }, "requests-oauthlib": { "hashes": [ @@ -2512,10 +2604,11 @@ }, "rsa": { "hashes": [ - "sha256:14ba45700ff1ec9eeb206a2ce76b32814958a98e372006c8fb76ba820211be66", - "sha256:1a836406405730121ae9823e19c6e806c62bbad73f890574fff50efa4122c487" + "sha256:109ea5a66744dd859bf16fe904b8d8b627adafb9408753161e766a92e7d681fa", + "sha256:6166864e23d6b5195a5cfed6cd9fed0fe774e226d8f854fcb23b7bbef0350233" ], - "version": "==4.0" + "markers": "python_version >= '3.5'", + "version": "==4.6" }, "s2sphere": { "hashes": [ @@ -2534,22 +2627,22 @@ }, "scikit-image": { "hashes": [ - "sha256:11bcc65ca2927c1842212b37ab64fe589a3eb6de375ea09cea0d7cd99bbde418", - "sha256:1247803e7afad51b4257fc6e7187eb4da63c8d8d2d51888baaca818b3a814ca9", - "sha256:1e2e2cf2572549bdb20b88a0f0ac275eea9f04f78b2b6973afdc3f329a73c75c", - "sha256:45629ef09d96739a575136fa28a8fd0b709d132325a140cdc8c8375df180c456", - "sha256:9cb106875c11236e4b1a04725c86745e2d65b32887cd2febbd0061c88491181b", - "sha256:a5d5d38842eaeb8feaa8427fb76240208feefc8d1b0afe109999a5458fe07455", - "sha256:a5f0c923ebac6e53286c07df79141e236cc161a463ea4a9edf4042a9db495e7b", - "sha256:acd5e9176e1fbc2ed869cc781b128471ffd3e1e60b267ffc532230c4dc2808df", - "sha256:bec5ea27cd975cbdcd1688c8631852f578e63bd26a4645dd03ed6f596fe2fc24", - "sha256:d402c947b9af4e42c875e4b80bad26c8aced87b791931d6ca020dc509ec7e108", - "sha256:d42c6b87e25905e867c4038a08ef790ba1ac7764a1830a4bb89955d159e69ff4", - "sha256:f4cd4464792d744c6f4c1cf7f0aea9945ea7664eaf5124f783703a1df80560f5", - "sha256:ff9521c170b4f8081825e675879f2cbd14f4a7572111fad8fc2c6ec82ba705f3" + "sha256:113bcacdfc839854f527a166a71768708328208e7b66e491050d6a57fa6727c7", + "sha256:11eec2e65cd4cd6487fe1089aa3538dbe25525aec7a36f5a0f14145df0163ce7", + "sha256:178210582cc62a5b25c633966658f1f2598615f9c3f27f36cf45055d2a74b401", + "sha256:1fda9109a19dc9d7a4ac152d1fc226fed7282ad186a099f14c0aa9151f0c758e", + "sha256:6b65a103edbc34b22640daf3b084dc9e470c358d3298c10aa9e3b424dcc02db6", + "sha256:7bedd3881ca4fea657a894815bcd5e5bf80944c26274f6b6417bb770c3f4f8e6", + "sha256:86a834f9a4d30201c0803a48a25364fe8f93f9feb3c58f2c483d3ce0a3e5fe4a", + "sha256:87ca5168c6fc36b7a298a1db2d185a8298f549854342020f282f747a4e4ddce9", + "sha256:bd954c0588f0f7e81d9763dc95e06950e68247d540476e06cb77bcbcd8c2d8b3", + "sha256:c0876e562991b0babff989ff4d00f35067a2ddef82e5fdd895862555ffbaec25", + "sha256:c5c277704b12e702e34d1f7b7a04d5ee8418735f535d269c74c02c6c9f8abee2", + "sha256:e99fa7514320011b250a21ab855fdd61ddcc05d3c77ec9e8f13edcc15d3296b5", + "sha256:ee3db438b5b9f8716a91ab26a61377a8a63356b186706f5b979822cc7241006d" ], "index": "pypi", - "version": "==0.17.1" + "version": "==0.17.2" }, "scipy": { "hashes": [ @@ -2620,74 +2713,101 @@ }, "simplejson": { "hashes": [ - "sha256:0fe3994207485efb63d8f10a833ff31236ed27e3b23dadd0bf51c9900313f8f2", - "sha256:17163e643dbf125bb552de17c826b0161c68c970335d270e174363d19e7ea882", - "sha256:1d1e929cdd15151f3c0b2efe953b3281b2fd5ad5f234f77aca725f28486466f6", - "sha256:1d346c2c1d7dd79c118f0cc7ec5a1c4127e0c8ffc83e7b13fc5709ff78c9bb84", - "sha256:1ea59f570b9d4916ae5540a9181f9c978e16863383738b69a70363bc5e63c4cb", - "sha256:1fbba86098bbfc1f85c5b69dc9a6d009055104354e0d9880bb00b692e30e0078", - "sha256:229edb079d5dd81bf12da952d4d825bd68d1241381b37d3acf961b384c9934de", - "sha256:22a7acb81968a7c64eba7526af2cf566e7e2ded1cb5c83f0906b17ff1540f866", - "sha256:2b4b2b738b3b99819a17feaf118265d0753d5536049ea570b3c43b51c4701e81", - "sha256:4cf91aab51b02b3327c9d51897960c554f00891f9b31abd8a2f50fd4a0071ce8", - "sha256:4fd5f79590694ebff8dc980708e1c182d41ce1fda599a12189f0ca96bf41ad70", - "sha256:5cfd495527f8b85ce21db806567de52d98f5078a8e9427b18e251c68bd573a26", - "sha256:60aad424e47c5803276e332b2a861ed7a0d46560e8af53790c4c4fb3420c26c2", - "sha256:7739940d68b200877a15a5ff5149e1599737d6dd55e302625650629350466418", - "sha256:7cce4bac7e0d66f3a080b80212c2238e063211fe327f98d764c6acbc214497fc", - "sha256:8027bd5f1e633eb61b8239994e6fc3aba0346e76294beac22a892eb8faa92ba1", - "sha256:86afc5b5cbd42d706efd33f280fec7bd7e2772ef54e3f34cf6b30777cd19a614", - "sha256:87d349517b572964350cc1adc5a31b493bbcee284505e81637d0174b2758ba17", - "sha256:8de378d589eccbc75941e480b4d5b4db66f22e4232f87543b136b1f093fff342", - "sha256:926bcbef9eb60e798eabda9cd0bbcb0fca70d2779aa0aa56845749d973eb7ad5", - "sha256:9a126c3a91df5b1403e965ba63b304a50b53d8efc908a8c71545ed72535374a3", - "sha256:ad8dd3454d0c65c0f92945ac86f7b9efb67fa2040ba1b0189540e984df904378", - "sha256:d140e9376e7f73c1f9e0a8e3836caf5eec57bbafd99259d56979da05a6356388", - "sha256:da00675e5e483ead345429d4f1374ab8b949fba4429d60e71ee9d030ced64037", - "sha256:daaf4d11db982791be74b23ff4729af2c7da79316de0bebf880fa2d60bcc8c5a", - "sha256:f4b64a1031acf33e281fd9052336d6dad4d35eee3404c95431c8c6bc7a9c0588", - "sha256:fc046afda0ed8f5295212068266c92991ab1f4a50c6a7144b69364bdee4a0159", - "sha256:fc9051d249dd5512e541f20330a74592f7a65b2d62e18122ca89bf71f94db748" - ], - "index": "pypi", - "version": "==3.17.0" + "sha256:034550078a11664d77bc1a8364c90bb7eef0e44c2dbb1fd0a4d92e3997088667", + "sha256:05b43d568300c1cd43f95ff4bfcff984bc658aa001be91efb3bb21df9d6288d3", + "sha256:0dd9d9c738cb008bfc0862c9b8fa6743495c03a0ed543884bf92fb7d30f8d043", + "sha256:10fc250c3edea4abc15d930d77274ddb8df4803453dde7ad50c2f5565a18a4bb", + "sha256:2862beabfb9097a745a961426fe7daf66e1714151da8bb9a0c430dde3d59c7c0", + "sha256:292c2e3f53be314cc59853bd20a35bf1f965f3bc121e007ab6fd526ed412a85d", + "sha256:2d3eab2c3fe52007d703a26f71cf649a8c771fcdd949a3ae73041ba6797cfcf8", + "sha256:2e7b57c2c146f8e4dadf84977a83f7ee50da17c8861fd7faf694d55e3274784f", + "sha256:311f5dc2af07361725033b13cc3d0351de3da8bede3397d45650784c3f21fbcf", + "sha256:344e2d920a7f27b4023c087ab539877a1e39ce8e3e90b867e0bfa97829824748", + "sha256:3fabde09af43e0cbdee407555383063f8b45bfb52c361bc5da83fcffdb4fd278", + "sha256:42b8b8dd0799f78e067e2aaae97e60d58a8f63582939af60abce4c48631a0aa4", + "sha256:4b3442249d5e3893b90cb9f72c7d6ce4d2ea144d2c0d9f75b9ae1e5460f3121a", + "sha256:55d65f9cc1b733d85ef95ab11f559cce55c7649a2160da2ac7a078534da676c8", + "sha256:5c659a0efc80aaaba57fcd878855c8534ecb655a28ac8508885c50648e6e659d", + "sha256:72d8a3ffca19a901002d6b068cf746be85747571c6a7ba12cbcf427bfb4ed971", + "sha256:75ecc79f26d99222a084fbdd1ce5aad3ac3a8bd535cd9059528452da38b68841", + "sha256:76ac9605bf2f6d9b56abf6f9da9047a8782574ad3531c82eae774947ae99cc3f", + "sha256:7d276f69bfc8c7ba6c717ba8deaf28f9d3c8450ff0aa8713f5a3280e232be16b", + "sha256:7f10f8ba9c1b1430addc7dd385fc322e221559d3ae49b812aebf57470ce8de45", + "sha256:8042040af86a494a23c189b5aa0ea9433769cc029707833f261a79c98e3375f9", + "sha256:813846738277729d7db71b82176204abc7fdae2f566e2d9fcf874f9b6472e3e6", + "sha256:845a14f6deb124a3bcb98a62def067a67462a000e0508f256f9c18eff5847efc", + "sha256:869a183c8e44bc03be1b2bbcc9ec4338e37fa8557fc506bf6115887c1d3bb956", + "sha256:8acf76443cfb5c949b6e781c154278c059b09ac717d2757a830c869ba000cf8d", + "sha256:8f713ea65958ef40049b6c45c40c206ab363db9591ff5a49d89b448933fa5746", + "sha256:934115642c8ba9659b402c8bdbdedb48651fb94b576e3b3efd1ccb079609b04a", + "sha256:9551f23e09300a9a528f7af20e35c9f79686d46d646152a0c8fc41d2d074d9b0", + "sha256:9a2b7543559f8a1c9ed72724b549d8cc3515da7daf3e79813a15bdc4a769de25", + "sha256:a55c76254d7cf8d4494bc508e7abb993a82a192d0db4552421e5139235604625", + "sha256:ad8f41c2357b73bc9e8606d2fa226233bf4d55d85a8982ecdfd55823a6959995", + "sha256:af4868da7dd53296cd7630687161d53a7ebe2e63814234631445697bd7c29f46", + "sha256:afebfc3dd3520d37056f641969ce320b071bc7a0800639c71877b90d053e087f", + "sha256:b59aa298137ca74a744c1e6e22cfc0bf9dca3a2f41f51bc92eb05695155d905a", + "sha256:bc00d1210567a4cdd215ac6e17dc00cb9893ee521cee701adfd0fa43f7c73139", + "sha256:c1cb29b1fced01f97e6d5631c3edc2dadb424d1f4421dad079cb13fc97acb42f", + "sha256:c94dc64b1a389a416fc4218cd4799aa3756f25940cae33530a4f7f2f54f166da", + "sha256:ceaa28a5bce8a46a130cd223e895080e258a88d51bf6e8de2fc54a6ef7e38c34", + "sha256:cff6453e25204d3369c47b97dd34783ca820611bd334779d22192da23784194b", + "sha256:d0b64409df09edb4c365d95004775c988259efe9be39697d7315c42b7a5e7e94", + "sha256:d4813b30cb62d3b63ccc60dd12f2121780c7a3068db692daeb90f989877aaf04", + "sha256:da3c55cdc66cfc3fffb607db49a42448785ea2732f055ac1549b69dcb392663b", + "sha256:e058c7656c44fb494a11443191e381355388443d543f6fc1a245d5d238544396", + "sha256:fed0f22bf1313ff79c7fc318f7199d6c2f96d4de3234b2f12a1eab350e597c06", + "sha256:ffd4e4877a78c84d693e491b223385e0271278f5f4e1476a4962dca6824ecfeb" + ], + "index": "pypi", + "version": "==3.17.2" }, "six": { "hashes": [ - "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a", - "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c" + "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", + "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" ], "index": "pypi", - "version": "==1.14.0" + "version": "==1.15.0" }, "sqlalchemy": { "hashes": [ - "sha256:083e383a1dca8384d0ea6378bd182d83c600ed4ff4ec8247d3b2442cf70db1ad", - "sha256:0a690a6486658d03cc6a73536d46e796b6570ac1f8a7ec133f9e28c448b69828", - "sha256:114b6ace30001f056e944cebd46daef38fdb41ebb98f5e5940241a03ed6cad43", - "sha256:128f6179325f7597a46403dde0bf148478f868df44841348dfc8d158e00db1f9", - "sha256:13d48cd8b925b6893a4e59b2dfb3e59a5204fd8c98289aad353af78bd214db49", - "sha256:211a1ce7e825f7142121144bac76f53ac28b12172716a710f4bf3eab477e730b", - "sha256:2dc57ee80b76813759cccd1a7affedf9c4dbe5b065a91fb6092c9d8151d66078", - "sha256:3e625e283eecc15aee5b1ef77203bfb542563fa4a9aa622c7643c7b55438ff49", - "sha256:43078c7ec0457387c79b8d52fff90a7ad352ca4c7aa841c366238c3e2cf52fdf", - "sha256:5b1bf3c2c2dca738235ce08079783ef04f1a7fc5b21cf24adaae77f2da4e73c3", - "sha256:6056b671aeda3fc451382e52ab8a753c0d5f66ef2a5ccc8fa5ba7abd20988b4d", - "sha256:68d78cf4a9dfade2e6cf57c4be19f7b82ed66e67dacf93b32bb390c9bed12749", - "sha256:7025c639ce7e170db845e94006cf5f404e243e6fc00d6c86fa19e8ad8d411880", - "sha256:7224e126c00b8178dfd227bc337ba5e754b197a3867d33b9f30dc0208f773d70", - "sha256:7d98e0785c4cd7ae30b4a451416db71f5724a1839025544b4edbd92e00b91f0f", - "sha256:8d8c21e9d4efef01351bf28513648ceb988031be4159745a7ad1b3e28c8ff68a", - "sha256:bbb545da054e6297242a1bb1ba88e7a8ffb679f518258d66798ec712b82e4e07", - "sha256:d00b393f05dbd4ecd65c989b7f5a81110eae4baea7a6a4cdd94c20a908d1456e", - "sha256:e18752cecaef61031252ca72031d4d6247b3212ebb84748fc5d1a0d2029c23ea" - ], - "index": "pypi", - "version": "==1.3.16" + "sha256:0942a3a0df3f6131580eddd26d99071b48cfe5aaf3eab2783076fbc5a1c1882e", + "sha256:0ec575db1b54909750332c2e335c2bb11257883914a03bc5a3306a4488ecc772", + "sha256:109581ccc8915001e8037b73c29590e78ce74be49ca0a3630a23831f9e3ed6c7", + "sha256:16593fd748944726540cd20f7e83afec816c2ac96b082e26ae226e8f7e9688cf", + "sha256:427273b08efc16a85aa2b39892817e78e3ed074fcb89b2a51c4979bae7e7ba98", + "sha256:50c4ee32f0e1581828843267d8de35c3298e86ceecd5e9017dc45788be70a864", + "sha256:512a85c3c8c3995cc91af3e90f38f460da5d3cade8dc3a229c8e0879037547c9", + "sha256:57aa843b783179ab72e863512e14bdcba186641daf69e4e3a5761d705dcc35b1", + "sha256:621f58cd921cd71ba6215c42954ffaa8a918eecd8c535d97befa1a8acad986dd", + "sha256:6ac2558631a81b85e7fb7a44e5035347938b0a73f5fdc27a8566777d0792a6a4", + "sha256:716754d0b5490bdcf68e1e4925edc02ac07209883314ad01a137642ddb2056f1", + "sha256:736d41cfebedecc6f159fc4ac0769dc89528a989471dc1d378ba07d29a60ba1c", + "sha256:8619b86cb68b185a778635be5b3e6018623c0761dde4df2f112896424aa27bd8", + "sha256:87fad64529cde4f1914a5b9c383628e1a8f9e3930304c09cf22c2ae118a1280e", + "sha256:89494df7f93b1836cae210c42864b292f9b31eeabca4810193761990dc689cce", + "sha256:8cac7bb373a5f1423e28de3fd5fc8063b9c8ffe8957dc1b1a59cb90453db6da1", + "sha256:8fd452dc3d49b3cc54483e033de6c006c304432e6f84b74d7b2c68afa2569ae5", + "sha256:adad60eea2c4c2a1875eb6305a0b6e61a83163f8e233586a4d6a55221ef984fe", + "sha256:c26f95e7609b821b5f08a72dab929baa0d685406b953efd7c89423a511d5c413", + "sha256:cbe1324ef52ff26ccde2cb84b8593c8bf930069dfc06c1e616f1bfd4e47f48a3", + "sha256:d05c4adae06bd0c7f696ae3ec8d993ed8ffcc4e11a76b1b35a5af8a099bd2284", + "sha256:d98bc827a1293ae767c8f2f18be3bb5151fd37ddcd7da2a5f9581baeeb7a3fa1", + "sha256:da2fb75f64792c1fc64c82313a00c728a7c301efe6a60b7a9fe35b16b4368ce7", + "sha256:e4624d7edb2576cd72bb83636cd71c8ce544d8e272f308bd80885056972ca299", + "sha256:e89e0d9e106f8a9180a4ca92a6adde60c58b1b0299e1b43bd5e0312f535fbf33", + "sha256:f11c2437fb5f812d020932119ba02d9e2bc29a6eca01a055233a8b449e3e1e7d", + "sha256:f57be5673e12763dd400fea568608700a63ce1c6bd5bdbc3cc3a2c5fdb045274", + "sha256:fc728ece3d5c772c196fd338a99798e7efac7a04f9cb6416299a3638ee9a94cd" + ], + "index": "pypi", + "version": "==1.3.18" }, "subprocess32": { "hashes": [ "sha256:88e37c1aac5388df41cc8a8456bb49ebffd321a3ad4d70358e3518176de3a56b", + "sha256:e45d985aef903c5b7444d34350b05da91a9e0ea015415ab45a21212786c649d0", "sha256:eb2937c80497978d181efa1b839ec2d9622cf9600a039a79d0e108d1f9aec79d" ], "index": "pypi", @@ -2710,36 +2830,39 @@ }, "tensorboard": { "hashes": [ - "sha256:9a2a2dc9856187679e93f3c95e5dc771dd47e3257db09767b4be118d734b4dc2" + "sha256:a3feb73e1221c0a512398ad2cd08570fb082d8a2ba364aa0562543ecbd3659ef" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.2.1" + "version": "==2.2.2" }, "tensorboard-plugin-wit": { "hashes": [ - "sha256:1fdf4ac343f1665453205aef8bb227b0204893bb5ffb792d2ed4509b1daf3d4f", - "sha256:243f117d117f9e81a21dc64b602b2bcb256ca5ba038867b96022d02271b17106" + "sha256:ee775f04821185c90d9a0e9c56970ee43d7c41403beb6629385b39517129685b" ], - "version": "==1.6.0.post3" + "version": "==1.7.0" }, - "tensorflow-estimator": { + "tensorflow": { "hashes": [ - "sha256:d09dacdd127f2579cea8d5af21f4a918036b8ae246adc82f26b61f91cc247dc2" + "sha256:267017724a49c367ca5df536e5f6d3d59643eaed946c82233d6b371e62b5ddc8", + "sha256:3ee8819732d8594913b7d22ded7b22e48a49aa015050d8dd8464eaa010ba2e41", + "sha256:572f69d2d0a3d3d83ebfb2c24e6d73d88b85a09f5da796974ef4a0ad83ff7cde", + "sha256:6735486ee9c3cb0807476e2b36ef7a4cd6c597cb24abf496e66b703360e1e54e", + "sha256:68ea22aee9c269a6a0c1061c141f1ec1cd1b1be7569390519c1bf4773f434a40", + "sha256:784ab8217e4b0eb4d121c28430c6cdc2ce56c02634a9720d84fb30598b338b8c", + "sha256:7ed67b47cdf6598a79583de5b57c595493eac2b8b6b3a828f912354716cb8149", + "sha256:8f364528f70d895b96a0de36c7c6002644bf4c5df1ee3fbfa775f5cee6571ad7", + "sha256:bbcfb04738099bd46822db91584db74703fdddacf4cd0a76acfc5e086956b5ba", + "sha256:c332c7fc5cfd54cb86d5da99787c9693e3a924848097c54df1b71ee595a39c93", + "sha256:dc5548562308acde7931f040e73d46ae31b398924cf675c3486fd3504e00a4af", + "sha256:f5f27528570fc0d7b90668be10c5dfd90d6ceb8fd2ed62d7d679554acb616bfe" ], - "version": "==2.2.0" + "index": "pypi", + "version": "==2.2" }, - "tensorflow-gpu": { + "tensorflow-estimator": { "hashes": [ - "sha256:3cd3fa2b13a505902704a63d6b2f256cdc85ddfd6c70dc7093796b7e490d09c4", - "sha256:453f0e3d8e56c47f4b374fba17cb5e0b57afbe34cd17f565b5498b5a0ccf33ac", - "sha256:4c698dc157ba74aa69fc7bb41669f4f34f63f07bd722dd3b5aea33458a660066", - "sha256:5853b595cf82f803d3dddc9b9c00996a514dcfc831d2f899f0bb8073795f6301", - "sha256:845f261b0b922740bdd7f21fa3a4bed8ffd9e1712decd552fb33621da4d8ec45", - "sha256:b706f0ed98d3c216ad65272c3a08a92f6fe7e38f57b54d3f9b5800043600e215", - "sha256:ba1e16249cf9aa4057d0af443df493f8a1683be113703f6d7f184f144ac673e4", - "sha256:f0b37fc5847987c1ca4f453273667497782a8920716a804f66247e0c095fef38" + "sha256:d09dacdd127f2579cea8d5af21f4a918036b8ae246adc82f26b61f91cc247dc2" ], - "index": "pypi", "version": "==2.2.0" }, "termcolor": { @@ -2765,19 +2888,18 @@ }, "tifffile": { "hashes": [ - "sha256:2e110ea3a6381df534261a85091490a5678faa4535aa14cc11b8ea8379dcbf01", - "sha256:abfce379f2b4b97759796c1489ea0e73c349fc71bf09bea2a5d076cbe7cfd4eb" + "sha256:73cd17d8df01fed38b9000c9b209eb7c894fde5abc616c5ff7b1f476e38cf07f", + "sha256:cd8549d6f0742c3c95a856744a26064a1aad1c132fbab95dc9e5dce891a62c17" ], "markers": "python_version >= '3.6'", - "version": "==2020.5.11" + "version": "==2020.7.24" }, "toml": { "hashes": [ - "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", - "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e", - "sha256:f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3" + "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f", + "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88" ], - "version": "==0.10.0" + "version": "==0.10.1" }, "tornado": { "hashes": [ @@ -2801,20 +2923,62 @@ ], "version": "==4.3.3" }, + "typed-ast": { + "hashes": [ + "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355", + "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919", + "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa", + "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652", + "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75", + "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01", + "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d", + "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1", + "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907", + "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c", + "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3", + "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b", + "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614", + "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb", + "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b", + "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41", + "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6", + "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34", + "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe", + "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4", + "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7" + ], + "version": "==1.4.1" + }, + "typing-extensions": { + "hashes": [ + "sha256:6e95524d8a547a91e08f404ae485bbb71962de46967e1b71a0cb89af24e761c5", + "sha256:79ee589a3caca649a9bfd2a8de4709837400dfa00b6cc81962a1e6a1815969ae", + "sha256:f8d2bd89d25bc39dabe7d23df520442fa1d8969b82544370e03d88b5a591c392" + ], + "version": "==3.7.4.2" + }, "urllib3": { "hashes": [ - "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527", - "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115" + "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a", + "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461" ], "index": "pypi", - "version": "==1.25.9" + "version": "==1.25.10" + }, + "virtualenv": { + "hashes": [ + "sha256:7b54fd606a1b85f83de49ad8d80dbec08e983a2d2f96685045b262ebc7481ee5", + "sha256:8cd7b2a4850b003a11be2fc213e206419efab41115cc14bca20e69654f2ac08e" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==20.0.30" }, "wcwidth": { "hashes": [ - "sha256:cafe2186b3c009a04067022ce1dcd79cb38d8d65ee4f4791b8888d6599d1bbe1", - "sha256:ee73862862a156bf77ff92b09034fc4825dd3af9cf81bc5b360668d425f3c5f1" + "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784", + "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83" ], - "version": "==0.1.9" + "version": "==0.2.5" }, "webencodings": { "hashes": [ @@ -2854,26 +3018,26 @@ }, "yarl": { "hashes": [ - "sha256:0c2ab325d33f1b824734b3ef51d4d54a54e0e7a23d13b86974507602334c2cce", - "sha256:0ca2f395591bbd85ddd50a82eb1fde9c1066fafe888c5c7cc1d810cf03fd3cc6", - "sha256:2098a4b4b9d75ee352807a95cdf5f10180db903bc5b7270715c6bbe2551f64ce", - "sha256:25e66e5e2007c7a39541ca13b559cd8ebc2ad8fe00ea94a2aad28a9b1e44e5ae", - "sha256:26d7c90cb04dee1665282a5d1a998defc1a9e012fdca0f33396f81508f49696d", - "sha256:308b98b0c8cd1dfef1a0311dc5e38ae8f9b58349226aa0533f15a16717ad702f", - "sha256:3ce3d4f7c6b69c4e4f0704b32eca8123b9c58ae91af740481aa57d7857b5e41b", - "sha256:58cd9c469eced558cd81aa3f484b2924e8897049e06889e8ff2510435b7ef74b", - "sha256:5b10eb0e7f044cf0b035112446b26a3a2946bca9d7d7edb5e54a2ad2f6652abb", - "sha256:6faa19d3824c21bcbfdfce5171e193c8b4ddafdf0ac3f129ccf0cdfcb083e462", - "sha256:944494be42fa630134bf907714d40207e646fd5a94423c90d5b514f7b0713fea", - "sha256:a161de7e50224e8e3de6e184707476b5a989037dcb24292b391a3d66ff158e70", - "sha256:a4844ebb2be14768f7994f2017f70aca39d658a96c786211be5ddbe1c68794c1", - "sha256:c2b509ac3d4b988ae8769901c66345425e361d518aecbe4acbfc2567e416626a", - "sha256:c9959d49a77b0e07559e579f38b2f3711c2b8716b8410b320bf9713013215a1b", - "sha256:d8cdee92bc930d8b09d8bd2043cedd544d9c8bd7436a77678dd602467a993080", - "sha256:e15199cdb423316e15f108f51249e44eb156ae5dba232cb73be555324a1d49c2" + "sha256:040b237f58ff7d800e6e0fd89c8439b841f777dd99b4a9cca04d6935564b9409", + "sha256:17668ec6722b1b7a3a05cc0167659f6c95b436d25a36c2d52db0eca7d3f72593", + "sha256:3a584b28086bc93c888a6c2aa5c92ed1ae20932f078c46509a66dce9ea5533f2", + "sha256:4439be27e4eee76c7632c2427ca5e73703151b22cae23e64adb243a9c2f565d8", + "sha256:48e918b05850fffb070a496d2b5f97fc31d15d94ca33d3d08a4f86e26d4e7c5d", + "sha256:9102b59e8337f9874638fcfc9ac3734a0cfadb100e47d55c20d0dc6087fb4692", + "sha256:9b930776c0ae0c691776f4d2891ebc5362af86f152dd0da463a6614074cb1b02", + "sha256:b3b9ad80f8b68519cc3372a6ca85ae02cc5a8807723ac366b53c0f089db19e4a", + "sha256:bc2f976c0e918659f723401c4f834deb8a8e7798a71be4382e024bcc3f7e23a8", + "sha256:c22c75b5f394f3d47105045ea551e08a3e804dc7e01b37800ca35b58f856c3d6", + "sha256:c52ce2883dc193824989a9b97a76ca86ecd1fa7955b14f87bf367a61b6232511", + "sha256:ce584af5de8830d8701b8979b18fcf450cef9a382b1a3c8ef189bedc408faf1e", + "sha256:da456eeec17fa8aa4594d9a9f27c0b1060b6a75f2419fe0c00609587b2695f4a", + "sha256:db6db0f45d2c63ddb1a9d18d1b9b22f308e52c83638c26b422d520a815c4b3fb", + "sha256:df89642981b94e7db5596818499c4b2219028f2a528c9c37cc1de45bf2fd3a3f", + "sha256:f18d68f2be6bf0e89f1521af2b1bb46e66ab0018faafa81d70f358153170a317", + "sha256:f379b7f83f23fe12823085cd6b906edc49df969eb99757f58ff382349a3303c6" ], "markers": "python_version >= '3.5'", - "version": "==1.4.2" + "version": "==1.5.1" } } } diff --git a/README.md b/README.md index 1d2e08de02..f78a070883 100644 --- a/README.md +++ b/README.md @@ -66,8 +66,8 @@ Supported Cars | ----------| ------------------------------| ------------------| -----------------| -------------------| ------------------| | Acura | ILX 2016-18 | AcuraWatch Plus | openpilot | 25mph1 | 25mph | | Acura | RDX 2016-18 | AcuraWatch Plus | openpilot | 25mph1 | 12mph | -| Honda | Accord 2018-19 | All | Stock | 0mph | 3mph | -| Honda | Accord Hybrid 2018-19 | All | Stock | 0mph | 3mph | +| Honda | Accord 2018-20 | All | Stock | 0mph | 3mph | +| Honda | Accord Hybrid 2018-20 | All | Stock | 0mph | 3mph | | Honda | Civic Hatchback 2017-19 | Honda Sensing | Stock | 0mph | 12mph | | Honda | Civic Sedan/Coupe 2016-18 | Honda Sensing | openpilot | 0mph | 12mph | | Honda | Civic Sedan/Coupe 2019-20 | Honda Sensing | Stock | 0mph | 2mph2 | @@ -76,12 +76,13 @@ Supported Cars | Honda | CR-V Hybrid 2017-2019 | Honda Sensing | Stock | 0mph | 12mph | | Honda | Fit 2018-19 | Honda Sensing | openpilot | 25mph1 | 12mph | | Honda | HR-V 2019 | Honda Sensing | openpilot | 25mph1 | 12mph | -| Honda | Insight 2019 | Honda Sensing | Stock | 0mph | 3mph | +| Honda | Insight 2019-20 | Honda Sensing | Stock | 0mph | 3mph | | Honda | Odyssey 2018-20 | Honda Sensing | openpilot | 25mph1 | 0mph | | Honda | Passport 2019 | All | openpilot | 25mph1 | 12mph | | Honda | Pilot 2016-18 | Honda Sensing | openpilot | 25mph1 | 12mph | | Honda | Pilot 2019 | All | openpilot | 25mph1 | 12mph | | Honda | Ridgeline 2017-20 | Honda Sensing | openpilot | 25mph1 | 12mph | +| Hyundai | Sonata 2020 | All | Stock | 0mph | 0mph | | Lexus | CT Hybrid 2017-18 | All | Stock3| 0mph | 0mph | | Lexus | ES 2019 | All | openpilot | 0mph | 0mph | | Lexus | ES Hybrid 2019 | All | openpilot | 0mph | 0mph | @@ -91,6 +92,7 @@ Supported Cars | Lexus | RX 2016-17 | All | Stock3| 0mph | 0mph | | Lexus | RX 2020 | All | openpilot | 0mph | 0mph | | Lexus | RX Hybrid 2016-19 | All | Stock3| 0mph | 0mph | +| Lexus | RX Hybrid 2020 | All | openpilot | 0mph | 0mph | | Toyota | Avalon 2016 | TSS-P | Stock3| 20mph1 | 0mph | | Toyota | Avalon 2017-18 | All | Stock3| 20mph1 | 0mph | | Toyota | Camry 2018-20 | All | Stock | 0mph4 | 0mph | @@ -106,7 +108,7 @@ Supported Cars | Toyota | Highlander 2020 | All | openpilot | 0mph | 0mph | | Toyota | Highlander Hybrid 2020 | All | openpilot | 0mph | 0mph | | Toyota | Prius 2016 | TSS-P | Stock3| 0mph | 0mph | -| Toyota | Prius 2017-19 | All | Stock3| 0mph | 0mph | +| Toyota | Prius 2017-20 | All | Stock3| 0mph | 0mph | | Toyota | Prius Prime 2017-20 | All | Stock3| 0mph | 0mph | | Toyota | Rav4 2016 | TSS-P | Stock3| 20mph1 | 0mph | | Toyota | Rav4 2017-18 | All | Stock3| 20mph1 | 0mph | @@ -116,9 +118,9 @@ Supported Cars | Toyota | Rav4 Hybrid 2019-20 | All | openpilot | 0mph | 0mph | | Toyota | Sienna 2018-20 | All | Stock3| 0mph | 0mph | -1[Comma Pedal](https://community.comma.ai/wiki/index.php/Comma_Pedal) is used to provide stop-and-go capability to some of the openpilot-supported cars that don't currently support stop-and-go. Here is how to [build a Comma Pedal](https://medium.com/@jfrux/comma-pedal-building-with-macrofab-6328bea791e8). ***NOTE: The Comma Pedal is not officially supported by [comma](https://comma.ai).***
+1[Comma Pedal](https://github.com/commaai/openpilot/wiki/comma-pedal) is used to provide stop-and-go capability to some of the openpilot-supported cars that don't currently support stop-and-go. ***NOTE: The Comma Pedal is not officially supported by [comma](https://comma.ai).***
22019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph.
-3When disconnecting the Driver Support Unit (DSU), openpilot ACC will replace stock ACC. For DSU locations, see [Toyota Wiki page](https://community.comma.ai/wiki/index.php/Toyota). ***NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).***
+3When disconnecting the Driver Support Unit (DSU), openpilot ACC will replace stock ACC. ***NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).***
428mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.
Community Maintained Cars and Features @@ -134,35 +136,39 @@ Community Maintained Cars and Features | Chrysler | Pacifica 2020 | Adaptive Cruise | Stock | 0mph | 39mph | | Chrysler | Pacifica Hybrid 2017-18 | Adaptive Cruise | Stock | 0mph | 9mph | | Chrysler | Pacifica Hybrid 2019-20 | Adaptive Cruise | Stock | 0mph | 39mph | -| Genesis | G80 20182 | All | Stock | 0mph | 0mph | -| Genesis | G90 20182 | All | Stock | 0mph | 0mph | -| GMC | Acadia Denali 20183| Adaptive Cruise | openpilot | 0mph | 7mph | +| Genesis | G70 2018 | All | Stock | 0mph | 0mph | +| Genesis | G80 2018 | All | Stock | 0mph | 0mph | +| Genesis | G90 2018 | All | Stock | 0mph | 0mph | +| GMC | Acadia Denali 20182| Adaptive Cruise | openpilot | 0mph | 7mph | | Holden | Astra 20171 | Adaptive Cruise | openpilot | 0mph | 7mph | -| Hyundai | Elantra 2017-192 | SCC + LKAS | Stock | 19mph | 34mph | -| Hyundai | Genesis 2015-162 | SCC + LKAS | Stock | 19mph | 37mph | -| Hyundai | Ioniq 20172 | SCC + LKAS | Stock | 0mph | 32mph | -| Hyundai | Ioniq 2019 EV2 | SCC + LKAS | Stock | 0mph | 32mph | -| Hyundai | Kona 2017-192 | SCC + LKAS | Stock | 22mph | 0mph | -| Hyundai | Kona 2019 EV2 | SCC + LKAS | Stock | 0mph | 0mph | -| Hyundai | Palisade 20202 | All | Stock | 0mph | 0mph | -| Hyundai | Santa Fe 20192 | All | Stock | 0mph | 0mph | -| Hyundai | Sonata 20202 | All | Stock | 0mph | 0mph | +| Hyundai | Elantra 2017-19 | SCC + LKAS | Stock | 19mph | 34mph | +| Hyundai | Genesis 2015-16 | SCC + LKAS | Stock | 19mph | 37mph | +| Hyundai | Ioniq Electric Premium SE 2020| SCC + LKAS | Stock | 0mph | 32mph | +| Hyundai | Ioniq Electric Limited 2019 | SCC + LKAS | Stock | 0mph | 32mph | +| Hyundai | Kona 2020 | SCC + LKAS | Stock | 0mph | 0mph | +| Hyundai | Kona EV 2019 | SCC + LKAS | Stock | 0mph | 0mph | +| Hyundai | Palisade 2020 | All | Stock | 0mph | 0mph | +| Hyundai | Santa Fe 2019 | All | Stock | 0mph | 0mph | +| Hyundai | Sonata 2019 | All | Stock | 0mph | 0mph | +| Hyundai | Veloster 2019 | SCC + LKAS | Stock | 5mph | 0mph | | Jeep | Grand Cherokee 2016-18 | Adaptive Cruise | Stock | 0mph | 9mph | -| Jeep | Grand Cherokee 2019 | Adaptive Cruise | Stock | 0mph | 39mph | -| Kia | Forte 20182 | SCC + LKAS | Stock | 0mph | 0mph | -| Kia | Optima 20172 | SCC + LKAS/LDWS | Stock | 0mph | 32mph | -| Kia | Optima 20192 | SCC + LKAS | Stock | 0mph | 0mph | -| Kia | Sorento 20182 | SCC + LKAS | Stock | 0mph | 0mph | -| Kia | Stinger 20182 | SCC + LKAS | Stock | 0mph | 0mph | -| Nissan | Leaf 2019 | Propilot | Stock | 0mph | 0mph | -| Nissan | X-Trail 2018 | Propilot | Stock | 0mph | 0mph | +| Jeep | Grand Cherokee 2019-20 | Adaptive Cruise | Stock | 0mph | 39mph | +| Kia | Forte 2018-19 | SCC + LKAS | Stock | 0mph | 0mph | +| Kia | Optima 2017 | SCC + LKAS/LDWS | Stock | 0mph | 32mph | +| Kia | Optima 2019 | SCC + LKAS | Stock | 0mph | 0mph | +| Kia | Sorento 2018 | SCC + LKAS | Stock | 0mph | 0mph | +| Kia | Stinger 2018 | SCC + LKAS | Stock | 0mph | 0mph | +| Nissan | Leaf 2018-19 | Propilot | Stock | 0mph | 0mph | +| Nissan | Rogue 2019 | Propilot | Stock | 0mph | 0mph | +| Nissan | X-Trail 2017 | Propilot | Stock | 0mph | 0mph | +| Subaru | Ascent 2019 | EyeSight | Stock | 0mph | 0mph | | Subaru | Crosstrek 2018-19 | EyeSight | Stock | 0mph | 0mph | -| Subaru | Impreza 2018-20 | EyeSight | Stock | 0mph | 0mph | -| Volkswagen| Golf 2016-193 | Driver Assistance | Stock | 0mph | 0mph | +| Subaru | Forester 2019 | EyeSight | Stock | 0mph | 0mph | +| Subaru | Impreza 2017-19 | EyeSight | Stock | 0mph | 0mph | +| Volkswagen| Golf 2015-19 | Driver Assistance | Stock | 0mph | 0mph | -1Requires a [panda](https://comma.ai/shop/products/panda-obd-ii-dongle) and [community built giraffe](https://zoneos.com/volt/). ***NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).***
-2Requires a [panda](https://comma.ai/shop/products/panda-obd-ii-dongle) and open sourced [Hyundai giraffe](https://github.com/commaai/neo/tree/master/giraffe/hyundai), designed for the 2019 Sante Fe; pinout may differ for other Hyundai and Kia models.
-3Requires a [custom connector](https://community.comma.ai/wiki/index.php/Volkswagen#Integration_at_R242_Camera) for the [car harness](https://comma.ai/shop/products/car-harness)
+1Requires an [OBD-II car harness](https://comma.ai/shop/products/comma-car-harness) and [community built giraffe](https://github.com/commaai/openpilot/wiki/GM). ***NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).***
+2Requires a custom connector for the developer [car harness](https://comma.ai/shop/products/car-harness)
Although it's not upstream, there's a community of people getting openpilot to run on Tesla's [here](https://tinkla.us/) @@ -175,7 +181,7 @@ Installation Instructions Install openpilot on an EON or comma two by entering ``https://openpilot.comma.ai`` during the installer setup. -Follow these [video instructions](https://youtu.be/3nlkomHathI) to properly mount the device on the windshield. Note: openpilot features an automatic pose calibration routine and openpilot performance should not be affected by small pitch and yaw misalignments caused by imprecise device mounting. +Follow these [video instructions](https://youtu.be/lcjqxCymins) to properly mount the device on the windshield. Note: openpilot features an automatic pose calibration routine and openpilot performance should not be affected by small pitch and yaw misalignments caused by imprecise device mounting. Before placing the device on your windshield, check the state and local laws and ordinances where you drive. Some state laws prohibit or restrict the placement of objects on the windshield of a motor vehicle. @@ -278,7 +284,7 @@ openpilot is developed by [comma](https://comma.ai/) and by users like you. We w You can add support for your car by following guides we have written for [Brand](https://medium.com/@comma_ai/how-to-write-a-car-port-for-openpilot-7ce0785eda84) and [Model](https://medium.com/@comma_ai/openpilot-port-guide-for-toyota-models-e5467f4b5fe6) ports. Generally, a car with adaptive cruise control and lane keep assist is a good candidate. [Join our Discord](https://discord.comma.ai) to discuss car ports: most car makes have a dedicated channel. -Want to get paid to work on openpilot? [comma is hiring](https://comma.ai/jobs/). We also have a [bounty program](https://comma.ai/bounties.html). +Want to get paid to work on openpilot? [comma is hiring](https://comma.ai/jobs/). And [follow us on Twitter](https://twitter.com/comma_ai). @@ -328,6 +334,7 @@ NO WARRANTY EXPRESSED OR IMPLIED.** +[![openpilot tests](https://github.com/commaai/openpilot/workflows/openpilot%20tests/badge.svg?event=push)](https://github.com/commaai/openpilot/actions) [![Total alerts](https://img.shields.io/lgtm/alerts/g/commaai/openpilot.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/commaai/openpilot/alerts/) [![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/commaai/openpilot.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/commaai/openpilot/context:python) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/commaai/openpilot.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/commaai/openpilot/context:cpp) diff --git a/RELEASES.md b/RELEASES.md index 67beec7795..3709d0f222 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,40 @@ +Version 0.7.9 (2020-XX-XX) +======================== + * Improved car battery power management + +Version 0.7.8 (2020-08-19) +======================== + * New driver monitoring model: improved face detection and better compatibility with sunglasses + * Download NEOS operating system updates in the background + * Improved updater reliability and responsiveness + * Hyundai Kona 2020, Veloster 2019, and Genesis G70 2018 support thanks to xps-genesis! + +Version 0.7.7 (2020-07-20) +======================== + * White panda is no longer supported, upgrade to comma two or black panda + * Improved vehicle model estimation using high precision localizer + * Improved thermal management on comma two + * Improved autofocus for road-facing camera + * Improved noise performance for driver-facing camera + * Block lane change start using blindspot monitor on select Toyota, Hyundai, and Subaru + * Fix GM ignition detection + * Code cleanup and smaller release sizes + * Hyundai Sonata 2020 promoted to officially supported car + * Hyundai Ioniq Electric Limited 2019 and Ioniq SE 2020 support thanks to baldwalker! + * Subaru Forester 2019 and Ascent 2019 support thanks to martinl! + +Version 0.7.6.1 (2020-06-16) +======================== +* Hotfix: update kernel on some comma twos (orders #8570-#8680) + +Version 0.7.6 (2020-06-05) +======================== +* White panda is deprecated, upgrade to comma two or black panda +* 2017 Nissan X-Trail, 2018-19 Leaf and 2019 Rogue support thanks to avolmensky! +* 2017 Mazda CX-5 support in dashcam mode thanks to Jafaral! +* Huge CPU savings in modeld by using thneed! +* Lots of code cleanup and refactors + Version 0.7.5 (2020-05-13) ======================== * Right-Hand Drive support for both driving and driver monitoring! @@ -5,7 +42,6 @@ Version 0.7.5 (2020-05-13) * New driver monitoring model: overall improvement on comma two * Driver camera preview in settings to improve mounting position * Added support for many Hyundai, Kia, Genesis models thanks to xx979xx! -* 2019 Nissan X-Trail and 2018 Nissan Leaf support thanks to avolmensky! * Improved lateral tuning for 2020 Toyota Rav 4 (hybrid) Version 0.7.4 (2020-03-20) diff --git a/SAFETY.md b/SAFETY.md index 5a3c287fe9..9cf8933b93 100644 --- a/SAFETY.md +++ b/SAFETY.md @@ -1,7 +1,7 @@ openpilot Safety ====== -openpilot is an Adaptive Cruise Control (ACC) and Automated Lane Centering (ALC) system. +openpilot is an Adaptive Cruise Control (ACC) and Automated Lane Centering (ALC) system. Like other ACC and ALC systems, openpilot is a failsafe passive system and it requires the driver to be alert and to pay attention at all times. @@ -22,7 +22,7 @@ hardware-in-the-loop and in-vehicle tests before each software release. Following Hazard and Risk Analysis and FMEA, at a very high level, we have designed openpilot ensuring two main safety requirements. -1. The driver must always be capable to immediately retake manual control of the vehicle, +1. The driver must always be capable to immediately retake manual control of the vehicle, by stepping on either pedal or by pressing the cancel button. 2. The vehicle must not alter its trajectory too quickly for the driver to safely react. This means that while the system is engaged, the actuators are constrained diff --git a/SConstruct b/SConstruct index 3ba359a4fc..e3765a15c1 100644 --- a/SConstruct +++ b/SConstruct @@ -1,4 +1,7 @@ +import Cython +import distutils import os +import shutil import subprocess import sys import platform @@ -11,6 +14,10 @@ AddOption('--asan', action='store_true', help='turn on ASAN') +# Rebuild cython extensions if python, distutils, or cython change +cython_dependencies = [Value(v) for v in (sys.version, distutils.__version__, Cython.__version__)] +Export('cython_dependencies') + arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip() if platform.system() == "Darwin": arch = "Darwin" @@ -18,6 +25,7 @@ if arch == "aarch64" and not os.path.isdir("/system"): arch = "larch64" webcam = bool(ARGUMENTS.get("use_webcam", 0)) +QCOM_REPLAY = arch == "aarch64" and os.getenv("QCOM_REPLAY") is not None if arch == "aarch64" or arch == "larch64": lenv = { @@ -43,20 +51,31 @@ if arch == "aarch64" or arch == "larch64": ] if arch == "larch64": - libpath += ["#phonelibs/snpe/larch64"] - libpath += ["#phonelibs/libyuv/larch64/lib"] - libpath += ["/usr/lib/aarch64-linux-gnu"] + libpath += [ + "#phonelibs/snpe/larch64", + "#phonelibs/libyuv/larch64/lib", + "/usr/lib/aarch64-linux-gnu" + ] cflags = ["-DQCOM2", "-mcpu=cortex-a57"] cxxflags = ["-DQCOM2", "-mcpu=cortex-a57"] rpath = ["/usr/local/lib"] else: - libpath += ["#phonelibs/snpe/aarch64"] - libpath += ["#phonelibs/libyuv/lib"] + libpath += [ + "#phonelibs/snpe/aarch64", + "#phonelibs/libyuv/lib" + ] cflags = ["-DQCOM", "-mcpu=cortex-a57"] cxxflags = ["-DQCOM", "-mcpu=cortex-a57"] rpath = ["/system/vendor/lib64"] + if QCOM_REPLAY: + cflags += ["-DQCOM_REPLAY"] + cxxflags += ["-DQCOM_REPLAY"] + else: + cflags = [] + cxxflags = [] + lenv = { "PATH": "#external/bin:" + os.environ['PATH'], } @@ -72,6 +91,8 @@ else: "/usr/local/lib", "/System/Library/Frameworks/OpenGL.framework/Libraries", ] + cflags += ["-DGL_SILENCE_DEPRECATION"] + cxxflags += ["-DGL_SILENCE_DEPRECATION"] else: libpath = [ "#phonelibs/snpe/x86_64-linux-clang", @@ -84,18 +105,20 @@ else: ] rpath = [ - "external/tensorflow/lib", - "cereal", - "selfdrive/common"] + "external/tensorflow/lib", + "cereal", + "selfdrive/common" + ] # allows shared libraries to work globally rpath = [os.path.join(os.getcwd(), x) for x in rpath] - cflags = [] - cxxflags = [] - -ccflags_asan = ["-fsanitize=address", "-fno-omit-frame-pointer"] if GetOption('asan') else [] -ldflags_asan = ["-fsanitize=address"] if GetOption('asan') else [] +if GetOption('asan'): + ccflags_asan = ["-fsanitize=address", "-fno-omit-frame-pointer"] + ldflags_asan = ["-fsanitize=address"] +else: + ccflags_asan = [] + ldflags_asan = [] # change pythonpath to this lenv["PYTHONPATH"] = Dir("#").path @@ -106,11 +129,10 @@ env = Environment( "-g", "-fPIC", "-O2", - "-Werror=implicit-function-declaration", - "-Werror=incompatible-pointer-types", - "-Werror=int-conversion", - "-Werror=return-type", - "-Werror=format-extra-args", + "-Wunused", + "-Werror", + "-Wno-deprecated-register", + "-Wno-inconsistent-missing-override", ] + cflags + ccflags_asan, CPPPATH=cpppath + [ @@ -134,6 +156,7 @@ env = Environment( "#selfdrive/camerad/include", "#selfdrive/loggerd/include", "#selfdrive/modeld", + "#selfdrive/ui", "#cereal/messaging", "#cereal", "#opendbc/can", @@ -147,16 +170,73 @@ env = Environment( CFLAGS=["-std=gnu11"] + cflags, CXXFLAGS=["-std=c++14"] + cxxflags, - LIBPATH=libpath + - [ + LIBPATH=libpath + [ "#cereal", "#selfdrive/common", "#phonelibs", ] ) +qt_env = None +if arch in ["x86_64", "Darwin", "larch64"]: + qt_env = env.Clone() + + if arch == "larch64": + qt_env['QTDIR'] = "/usr/local/Qt-5.15.0" + QT_BASE = "/usr/local/Qt-5.15.0/" + qt_dirs = [ + QT_BASE + "include/", + QT_BASE + "include/QtWidgets", + QT_BASE + "include/QtGui", + QT_BASE + "include/QtCore", + QT_BASE + "include/QtDBus", + ] + qt_env["RPATH"] += [QT_BASE + "lib"] + elif arch == "Darwin": + qt_env['QTDIR'] = "/usr/local/opt/qt" + QT_BASE = "/usr/local/opt/qt/" + qt_dirs = [ + QT_BASE + "include/", + QT_BASE + "include/QtWidgets", + QT_BASE + "include/QtGui", + QT_BASE + "include/QtCore", + QT_BASE + "include/QtDBus", + ] + qt_env["LINKFLAGS"] += ["-F" + QT_BASE + "lib"] + else: + qt_dirs = [ + f"/usr/include/{arch}-linux-gnu/qt5", + f"/usr/include/{arch}-linux-gnu/qt5/QtWidgets", + f"/usr/include/{arch}-linux-gnu/qt5/QtGui", + f"/usr/include/{arch}-linux-gnu/qt5/QtCore", + f"/usr/include/{arch}-linux-gnu/qt5/QtDBus", + ] + + qt_env.Tool('qt') + qt_env['CPPPATH'] += qt_dirs + qt_flags = [ + "-D_REENTRANT", + "-DQT_NO_DEBUG", + "-DQT_WIDGETS_LIB", + "-DQT_GUI_LIB", + "-DQT_CORE_LIB" + ] + qt_env['CXXFLAGS'] += qt_flags + if os.environ.get('SCONS_CACHE'): - CacheDir('/tmp/scons_cache') + cache_dir = '/tmp/scons_cache' + + if os.getenv('CI'): + branch = os.getenv('GIT_BRANCH') + + if QCOM_REPLAY: + cache_dir = '/tmp/scons_cache_qcom_replay' + elif branch is not None and branch != 'master': + cache_dir_branch = '/tmp/scons_cache_' + branch + if not os.path.isdir(cache_dir_branch) and os.path.isdir(cache_dir): + shutil.copytree(cache_dir, cache_dir_branch) + cache_dir = cache_dir_branch + CacheDir(cache_dir) node_interval = 5 node_count = 0 @@ -181,7 +261,7 @@ def abspath(x): # still needed for apks zmq = 'zmq' -Export('env', 'arch', 'zmq', 'SHARED', 'webcam') +Export('env', 'qt_env', 'arch', 'zmq', 'SHARED', 'webcam', 'QCOM_REPLAY') # cereal and messaging are shared with the system SConscript(['cereal/SConscript']) @@ -209,11 +289,11 @@ SConscript(['opendbc/can/SConscript']) SConscript(['common/SConscript']) SConscript(['common/kalman/SConscript']) +SConscript(['common/transformations/SConscript']) SConscript(['phonelibs/SConscript']) -if arch != "Darwin": - SConscript(['selfdrive/camerad/SConscript']) - SConscript(['selfdrive/modeld/SConscript']) +SConscript(['selfdrive/camerad/SConscript']) +SConscript(['selfdrive/modeld/SConscript']) SConscript(['selfdrive/controls/lib/cluster/SConscript']) SConscript(['selfdrive/controls/lib/lateral_mpc/SConscript']) @@ -223,15 +303,18 @@ SConscript(['selfdrive/controls/lib/longitudinal_mpc_model/SConscript']) SConscript(['selfdrive/boardd/SConscript']) SConscript(['selfdrive/proclogd/SConscript']) -#SConscript(['selfdrive/ui/SConscript']) SConscript(['selfdrive/loggerd/SConscript']) SConscript(['selfdrive/locationd/SConscript']) SConscript(['selfdrive/locationd/models/SConscript']) + if arch == "aarch64": SConscript(['selfdrive/logcatd/SConscript']) SConscript(['selfdrive/sensord/SConscript']) SConscript(['selfdrive/clocksd/SConscript']) else: SConscript(['tools/lib/index_log/SConscript']) + +if arch != "larch64": + SConscript(['selfdrive/ui/SConscript']) diff --git a/apk/ai.comma.plus.offroad.apk b/apk/ai.comma.plus.offroad.apk index 8a59c2b227..75f3b219b6 100644 --- a/apk/ai.comma.plus.offroad.apk +++ b/apk/ai.comma.plus.offroad.apk @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d7b79038dccaa97d84bd38544573d3a52929770b76a259b25a27311464230e22 -size 13732809 +oid sha256:a198491887ed6029bffdf7f4dc28c4f9a6ba5f9d2235710fc11a1378893491d7 +size 13702777 diff --git a/apks b/apks deleted file mode 160000 index f5d2c1715c..0000000000 --- a/apks +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f5d2c1715c9482d898062110ce4c612093aa5d4f diff --git a/common/SConscript b/common/SConscript index 103d416f53..35abeb9ee4 100644 --- a/common/SConscript +++ b/common/SConscript @@ -1,6 +1,6 @@ -Import('env') +Import('env', 'cython_dependencies') -# parser -env.Command(['common_pyx.so'], - ['common_pyx_setup.py', 'clock.pyx'], - "cd common && python3 common_pyx_setup.py build_ext --inplace") +# Build cython clock module +env.Command(['common_pyx.so', 'clock.cpp'], + cython_dependencies + ['common_pyx_setup.py', 'clock.pyx'], + "cd common && python3 common_pyx_setup.py build_ext --inplace") diff --git a/common/android.py b/common/android.py index 4342a4259a..43bb0f3c1e 100644 --- a/common/android.py +++ b/common/android.py @@ -12,6 +12,10 @@ NetworkStrength = log.ThermalData.NetworkStrength ANDROID = os.path.isfile('/EON') +def get_sound_card_online(): + return (os.path.isfile('/proc/asound/card0/state') and + open('/proc/asound/card0/state').read().strip() == 'ONLINE') + def getprop(key): if not ANDROID: return "" @@ -22,10 +26,10 @@ def get_imei(slot): if slot not in ("0", "1"): raise ValueError("SIM slot must be 0 or 1") - ret = parse_service_call_string(service_call(["iphonesubinfo", "3" ,"i32", str(slot)])) + ret = parse_service_call_string(service_call(["iphonesubinfo", "3" , "i32", str(slot)])) if not ret: # allow non android to be identified differently - ret = "%015d" % random.randint(0, 1<<32) + ret = "%015d" % random.randint(0, 1 << 32) return ret def get_serial(): @@ -47,10 +51,10 @@ def reboot(reason=None): reason_args = ["s16", reason] subprocess.check_output([ - "service", "call", "power", "16", # IPowerManager.reboot - "i32", "0", # no confirmation, + "service", "call", "power", "16", # IPowerManager.reboot + "i32", "0", # no confirmation, *reason_args, - "i32", "1" # wait + "i32", "1" # wait ]) def service_call(call): @@ -71,7 +75,7 @@ def parse_service_call_unpack(r, fmt): def parse_service_call_string(r): try: - r = r[8:] # Cut off length field + r = r[8:] # Cut off length field r = r.decode('utf_16_be') # All pairs of two characters seem to be swapped. Not sure why @@ -132,6 +136,7 @@ def get_network_type(): def get_network_strength(network_type): network_strength = NetworkStrength.unknown + # from SignalStrength.java def get_lte_level(rsrp, rssnr): INT_MAX = 2147483647 diff --git a/common/api/__init__.py b/common/api/__init__.py index 38fe6b2477..b030c33334 100644 --- a/common/api/__init__.py +++ b/common/api/__init__.py @@ -38,5 +38,4 @@ def api_get(endpoint, method='GET', timeout=None, access_token=None, **params): headers['User-Agent'] = "openpilot-" + version - return requests.request(method, backend+endpoint, timeout=timeout, headers = headers, params=params) - + return requests.request(method, backend+endpoint, timeout=timeout, headers=headers, params=params) diff --git a/common/apk.py b/common/apk.py index 5716ed452a..c04c19aa5f 100644 --- a/common/apk.py +++ b/common/apk.py @@ -13,7 +13,7 @@ def get_installed_apks(): ret = {} for x in dat: if x.startswith("package:"): - v,k = x.split("package:")[1].split("=") + v, k = x.split("package:")[1].split("=") ret[k] = v return ret diff --git a/common/basedir.py b/common/basedir.py index e928ded4c4..4d62fdc19c 100644 --- a/common/basedir.py +++ b/common/basedir.py @@ -8,4 +8,3 @@ if ANDROID: else: PERSIST = os.path.join(BASEDIR, "persist") PARAMS = os.path.join(BASEDIR, "persist", "params") - diff --git a/common/compat.py b/common/compat.py deleted file mode 100644 index 369f5e2d84..0000000000 --- a/common/compat.py +++ /dev/null @@ -1,3 +0,0 @@ -# py2,3 compatiblity helpers - -basestring = (str, bytes) diff --git a/common/file_helpers.py b/common/file_helpers.py index 40c89fab0e..c7a70ab879 100644 --- a/common/file_helpers.py +++ b/common/file_helpers.py @@ -3,13 +3,17 @@ import shutil import tempfile from atomicwrites import AtomicWriter + def mkdirs_exists_ok(path): + if path.startswith('http://') or path.startswith('https://'): + raise ValueError('URL path') try: os.makedirs(path) except OSError: if not os.path.isdir(path): raise + def rm_not_exists_ok(path): try: os.remove(path) @@ -17,12 +21,14 @@ def rm_not_exists_ok(path): if os.path.exists(path): raise + def rm_tree_or_link(path): if os.path.islink(path): os.unlink(path) elif os.path.isdir(path): shutil.rmtree(path) + def get_tmpdir_on_same_filesystem(path): normpath = os.path.normpath(path) parts = normpath.split("/") @@ -32,6 +38,7 @@ def get_tmpdir_on_same_filesystem(path): return "/{}/runner/tmp".format(parts[1]) return "/tmp" + class AutoMoveTempdir(): def __init__(self, target_path, temp_dir=None): self._target_path = target_path @@ -44,14 +51,16 @@ class AutoMoveTempdir(): def close(self): os.rename(self._path, self._target_path) - def __enter__(self): return self + def __enter__(self): + return self - def __exit__(self, type, value, traceback): - if type is None: + def __exit__(self, exc_type, exc_value, traceback): + if exc_type is None: self.close() else: shutil.rmtree(self._path) + class NamedTemporaryDir(): def __init__(self, temp_dir=None): self._path = tempfile.mkdtemp(dir=temp_dir) @@ -63,11 +72,13 @@ class NamedTemporaryDir(): def close(self): shutil.rmtree(self._path) - def __enter__(self): return self + def __enter__(self): + return self - def __exit__(self, type, value, traceback): + def __exit__(self, exc_type, exc_value, traceback): self.close() + def _get_fileobject_func(writer, temp_dir): def _get_fileobject(): file_obj = writer.get_fileobject(dir=temp_dir) @@ -75,6 +86,7 @@ def _get_fileobject_func(writer, temp_dir): return file_obj return _get_fileobject + def atomic_write_on_fs_tmp(path, **kwargs): """Creates an atomic writer using a temporary file in a temporary directory on the same filesystem as path. @@ -92,6 +104,7 @@ def atomic_write_in_dir(path, **kwargs): writer = AtomicWriter(path, **kwargs) return writer._open(_get_fileobject_func(writer, os.path.dirname(path))) + def atomic_write_in_dir_neos(path, contents, mode=None): """ Atomically writes contents to path using a temporary file in the same directory diff --git a/common/kalman/SConscript b/common/kalman/SConscript index abd7e04375..3d7011fe29 100644 --- a/common/kalman/SConscript +++ b/common/kalman/SConscript @@ -1,6 +1,6 @@ -Import('env') +Import('env', 'cython_dependencies') env.Command(['simple_kalman_impl.so'], - ['simple_kalman_impl.pyx', 'simple_kalman_impl.pxd', 'simple_kalman_setup.py'], - "cd common/kalman && python3 simple_kalman_setup.py build_ext --inplace") + cython_dependencies + ['simple_kalman_impl.pyx', 'simple_kalman_impl.pxd', 'simple_kalman_setup.py'], + "cd common/kalman && python3 simple_kalman_setup.py build_ext --inplace") diff --git a/common/kalman/simple_kalman_old.py b/common/kalman/simple_kalman_old.py index 3f7d049cc5..d11770faf6 100644 --- a/common/kalman/simple_kalman_old.py +++ b/common/kalman/simple_kalman_old.py @@ -8,7 +8,7 @@ class KF1D: def __init__(self, x0, A, C, K): self.x = x0 self.A = A - self.C = C + self.C = np.atleast_2d(C) self.K = K self.A_K = self.A - np.dot(self.K, self.C) diff --git a/common/kalman/tests/test_simple_kalman.py b/common/kalman/tests/test_simple_kalman.py index c1f9f7b03c..6308759984 100644 --- a/common/kalman/tests/test_simple_kalman.py +++ b/common/kalman/tests/test_simple_kalman.py @@ -21,10 +21,10 @@ class TestSimpleKalman(unittest.TestCase): K0_0 = 0.12287673 K1_0 = 0.29666309 - self.kf_old = KF1D_old(x0=np.matrix([[x0_0], [x1_0]]), - A=np.matrix([[A0_0, A0_1], [A1_0, A1_1]]), - C=np.matrix([C0_0, C0_1]), - K=np.matrix([[K0_0], [K1_0]])) + self.kf_old = KF1D_old(x0=np.array([[x0_0], [x1_0]]), + A=np.array([[A0_0, A0_1], [A1_0, A1_1]]), + C=np.array([C0_0, C0_1]), + K=np.array([[K0_0], [K1_0]])) self.kf = KF1D(x0=[[x0_0], [x1_0]], A=[[A0_0, A0_1], [A1_0, A1_1]], @@ -47,9 +47,8 @@ class TestSimpleKalman(unittest.TestCase): x = self.kf.update(v_wheel) # Compare the output x, verify that the error is less than 1e-4 - self.assertAlmostEqual(x_old[0], x[0]) - self.assertAlmostEqual(x_old[1], x[1]) - + np.testing.assert_almost_equal(x_old[0], x[0]) + np.testing.assert_almost_equal(x_old[1], x[1]) def test_new_is_faster(self): setup = """ @@ -70,10 +69,10 @@ C0_1 = 0.0 K0_0 = 0.12287673 K1_0 = 0.29666309 -kf_old = KF1D_old(x0=np.matrix([[x0_0], [x1_0]]), - A=np.matrix([[A0_0, A0_1], [A1_0, A1_1]]), - C=np.matrix([C0_0, C0_1]), - K=np.matrix([[K0_0], [K1_0]])) +kf_old = KF1D_old(x0=np.array([[x0_0], [x1_0]]), + A=np.array([[A0_0, A0_1], [A1_0, A1_1]]), + C=np.array([C0_0, C0_1]), + K=np.array([[K0_0], [K1_0]])) kf = KF1D(x0=[[x0_0], [x1_0]], A=[[A0_0, A0_1], [A1_0, A1_1]], diff --git a/common/logging_extra.py b/common/logging_extra.py index b5d07f2209..ce8889b410 100644 --- a/common/logging_extra.py +++ b/common/logging_extra.py @@ -68,8 +68,11 @@ class SwagErrorFilter(logging.Filter): def filter(self, record): return record.levelno < logging.ERROR -_tmpfunc = lambda: 0 -_srcfile = os.path.normcase(_tmpfunc.__code__.co_filename) +def _tmpfunc(): + return 0 + +def _srcfile(): + return os.path.normcase(_tmpfunc.__code__.co_filename) class SwagLogger(logging.Logger): def __init__(self): @@ -112,9 +115,6 @@ class SwagLogger(logging.Logger): if args: evt['args'] = args evt.update(kwargs) - ctx = self.get_ctx() - if ctx: - evt['ctx'] = self.get_ctx() if 'error' in kwargs: self.error(evt) else: @@ -140,7 +140,9 @@ class SwagLogger(logging.Logger): while hasattr(f, "f_code"): co = f.f_code filename = os.path.normcase(co.co_filename) - if filename == _srcfile: + + # TODO: is this pylint exception correct? + if filename == _srcfile: # pylint: disable=comparison-with-callable f = f.f_back continue sinfo = None diff --git a/common/manager_helpers.py b/common/manager_helpers.py deleted file mode 100644 index a8cfb3df05..0000000000 --- a/common/manager_helpers.py +++ /dev/null @@ -1,50 +0,0 @@ -def cputime_total(ct): - return ct.cpuUser + ct.cpuSystem + ct.cpuChildrenUser + ct.cpuChildrenSystem - - -def print_cpu_usage(first_proc, last_proc): - r = 0 - procs = [ - ("selfdrive.controls.controlsd", 59.46), - ("./_modeld", 48.94), - ("./loggerd", 28.49), - ("selfdrive.controls.plannerd", 19.77), - ("selfdrive.controls.radard", 9.54), - ("./_ui", 9.54), - ("./camerad", 7.07), - ("selfdrive.locationd.locationd", 7.13), - ("./_sensord", 6.17), - ("selfdrive.controls.dmonitoringd", 5.48), - ("./boardd", 3.63), - ("./_dmonitoringmodeld", 2.67), - ("selfdrive.logmessaged", 2.71), - ("selfdrive.thermald", 2.41), - ("./paramsd", 2.18), - ("selfdrive.locationd.calibrationd", 1.76), - ("./proclogd", 1.54), - ("./_gpsd", 0.09), - ("./clocksd", 0.02), - ("./ubloxd", 0.02), - ("selfdrive.tombstoned", 0), - ("./logcatd", 0), - ("selfdrive.updated", 0), - ] - - dt = (last_proc.logMonoTime - first_proc.logMonoTime) / 1e9 - print("------------------------------------------------") - for proc_name, normal_cpu_usage in procs: - try: - first = [p for p in first_proc.procLog.procs if proc_name in p.cmdline][0] - last = [p for p in last_proc.procLog.procs if proc_name in p.cmdline][0] - cpu_time = cputime_total(last) - cputime_total(first) - cpu_usage = cpu_time / dt * 100. - if cpu_usage > max(normal_cpu_usage * 1.1, normal_cpu_usage + 5.0): - print(f"Warning {proc_name} using more CPU than normal") - r = 1 - - print(f"{proc_name.ljust(35)} {cpu_usage:.2f}%") - except IndexError: - print(f"{proc_name.ljust(35)} NO METRICS FOUND") - print("------------------------------------------------") - - return r diff --git a/common/numpy_fast.py b/common/numpy_fast.py index a5d5ad3f50..a8361214d1 100644 --- a/common/numpy_fast.py +++ b/common/numpy_fast.py @@ -6,6 +6,7 @@ def clip(x, lo, hi): def interp(x, xp, fp): N = len(xp) + def get_interp(xv): hi = 0 while hi < N and xv > xp[hi]: @@ -14,8 +15,8 @@ def interp(x, xp, fp): return fp[-1] if hi == N and xv > xp[low] else ( fp[0] if hi == 0 else (xv - xp[low]) * (fp[hi] - fp[low]) / (xp[hi] - xp[low]) + fp[low]) - return [get_interp(v) for v in x] if hasattr( - x, '__iter__') else get_interp(x) + + return [get_interp(v) for v in x] if hasattr(x, '__iter__') else get_interp(x) def mean(x): return sum(x) / len(x) diff --git a/common/params.py b/common/params.py index 787235bf13..d01b1b4ae9 100755 --- a/common/params.py +++ b/common/params.py @@ -22,10 +22,7 @@ file in place without messing with /d. """ import time import os -import string -import binascii import errno -import sys import shutil import fcntl import tempfile @@ -33,6 +30,7 @@ import threading from enum import Enum from common.basedir import PARAMS + def mkdirs_exists_ok(path): try: os.makedirs(path) @@ -55,6 +53,7 @@ keys = { "AccessToken": [TxType.CLEAR_ON_MANAGER_START], "AthenadPid": [TxType.PERSISTENT], "CalibrationParams": [TxType.PERSISTENT], + "CarBatteryCapacity": [TxType.PERSISTENT], "CarParams": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT], "CarParamsCache": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT], "CarVin": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT], @@ -62,6 +61,7 @@ keys = { "CompletedTrainingVersion": [TxType.PERSISTENT], "ControlsParams": [TxType.PERSISTENT], "DisablePowerDown": [TxType.PERSISTENT], + "DisableUpdates": [TxType.PERSISTENT], "DoUninstall": [TxType.CLEAR_ON_MANAGER_START], "DongleId": [TxType.PERSISTENT], "GitBranch": [TxType.PERSISTENT], @@ -81,6 +81,7 @@ keys = { "IsUploadRawEnabled": [TxType.PERSISTENT], "LastAthenaPingTime": [TxType.PERSISTENT], "LastUpdateTime": [TxType.PERSISTENT], + "LastUpdateException": [TxType.PERSISTENT], "LimitSetSpeed": [TxType.PERSISTENT], "LimitSetSpeedNeural": [TxType.PERSISTENT], "LiveParameters": [TxType.PERSISTENT], @@ -108,6 +109,8 @@ keys = { "Offroad_PandaFirmwareMismatch": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT], "Offroad_InvalidTime": [TxType.CLEAR_ON_MANAGER_START], "Offroad_IsTakingSnapshot": [TxType.CLEAR_ON_MANAGER_START], + "Offroad_NeosUpdate": [TxType.CLEAR_ON_MANAGER_START], + "Offroad_UpdateFailed": [TxType.CLEAR_ON_MANAGER_START], } @@ -146,6 +149,10 @@ class DBAccessor(): def get(self, key): self._check_entered() + + if self._vals is None: + return None + try: return self._vals[key] except KeyError: @@ -198,7 +205,8 @@ class DBReader(DBAccessor): finally: lock.release() - def __exit__(self, type, value, traceback): pass + def __exit__(self, exc_type, exc_value, traceback): + pass class DBWriter(DBAccessor): @@ -223,14 +231,14 @@ class DBWriter(DBAccessor): os.chmod(self._path, 0o777) self._lock = self._get_lock(True) self._vals = self._read_values_locked() - except: + except Exception: os.umask(self._prev_umask) self._prev_umask = None raise return self - def __exit__(self, type, value, traceback): + def __exit__(self, exc_type, exc_value, traceback): self._check_entered() try: @@ -304,34 +312,37 @@ def read_db(params_path, key): except IOError: return None + def write_db(params_path, key, value): if isinstance(value, str): value = value.encode('utf8') prev_umask = os.umask(0) - lock = FileLock(params_path+"/.lock", True) + lock = FileLock(params_path + "/.lock", True) lock.acquire() try: - tmp_path = tempfile.mktemp(prefix=".tmp", dir=params_path) - with open(tmp_path, "wb") as f: + tmp_path = tempfile.NamedTemporaryFile(mode="wb", prefix=".tmp", dir=params_path, delete=False) + with tmp_path as f: f.write(value) f.flush() os.fsync(f.fileno()) + os.chmod(tmp_path.name, 0o666) path = "%s/d/%s" % (params_path, key) - os.rename(tmp_path, path) + os.rename(tmp_path.name, path) fsync_dir(os.path.dirname(path)) finally: os.umask(prev_umask) lock.release() + class Params(): def __init__(self, db=PARAMS): self.db = db # create the database if it doesn't exist... - if not os.path.exists(self.db+"/d"): + if not os.path.exists(self.db + "/d"): with self.transaction(write=True): pass @@ -401,22 +412,3 @@ def put_nonblocking(key, val): t = threading.Thread(target=f, args=(key, val)) t.start() return t - - -if __name__ == "__main__": - params = Params() - if len(sys.argv) > 2: - params.put(sys.argv[1], sys.argv[2]) - else: - for k in keys: - pp = params.get(k) - if pp is None: - print("%s is None" % k) - elif all(chr(c) in string.printable for c in pp): - print("%s = %s" % (k, pp)) - else: - print("%s = %s" % (k, binascii.hexlify(pp))) - - # Test multiprocess: - # seq 0 100000 | xargs -P20 -I{} python common/params.py DongleId {} && sleep 0.05 - # while python common/params.py DongleId; do sleep 0.05; done diff --git a/common/profiler.py b/common/profiler.py index f8262dd83e..ac28bdac40 100644 --- a/common/profiler.py +++ b/common/profiler.py @@ -43,4 +43,3 @@ class Profiler(): else: print("%30s: %9.2f percent: %3.0f" % (n, ms*1000.0, ms/self.tot*100)) print("Iter clock: %2.6f TOTAL: %2.2f" % (self.tot/self.iter, self.tot)) - diff --git a/common/realtime.py b/common/realtime.py index c21222e88c..e734438646 100644 --- a/common/realtime.py +++ b/common/realtime.py @@ -6,6 +6,7 @@ import subprocess import multiprocessing from cffi import FFI +from common.android import ANDROID from common.common_pyx import sec_since_boot # pylint: disable=no-name-in-module, import-error @@ -20,11 +21,7 @@ ffi = FFI() ffi.cdef("long syscall(long number, ...);") libc = ffi.dlopen(None) - -def set_realtime_priority(level): - if os.getuid() != 0: - print("not setting priority, not root") - return +def _get_tid(): if platform.machine() == "x86_64": NR_gettid = 186 elif platform.machine() == "aarch64": @@ -32,8 +29,25 @@ def set_realtime_priority(level): else: raise NotImplementedError - tid = libc.syscall(NR_gettid) - return subprocess.call(['chrt', '-f', '-p', str(level), str(tid)]) + return libc.syscall(NR_gettid) + + +def set_realtime_priority(level): + if os.getuid() != 0: + print("not setting priority, not root") + return + + return subprocess.call(['chrt', '-f', '-p', str(level), str(_get_tid())]) + +def set_core_affinity(core): + if os.getuid() != 0: + print("not setting affinity, not root") + return + + if ANDROID: + return subprocess.call(['taskset', '-p', str(core), str(_get_tid())]) + else: + return -1 class Ratekeeper(): diff --git a/common/spinner.py b/common/spinner.py index da8084037e..53e8ee5215 100644 --- a/common/spinner.py +++ b/common/spinner.py @@ -4,14 +4,17 @@ from common.basedir import BASEDIR class Spinner(): - def __init__(self): - try: - self.spinner_proc = subprocess.Popen(["./spinner"], - stdin=subprocess.PIPE, - cwd=os.path.join(BASEDIR, "selfdrive", "ui", "spinner"), - close_fds=True) - except OSError: - self.spinner_proc = None + def __init__(self, noop=False): + # spinner is currently only implemented for android + self.spinner_proc = None + if not noop: + try: + self.spinner_proc = subprocess.Popen(["./spinner"], + stdin=subprocess.PIPE, + cwd=os.path.join(BASEDIR, "selfdrive", "ui", "spinner"), + close_fds=True) + except OSError: + self.spinner_proc = None def __enter__(self): return self @@ -36,27 +39,10 @@ class Spinner(): def __del__(self): self.close() - def __exit__(self, type, value, traceback): + def __exit__(self, exc_type, exc_value, traceback): self.close() -class FakeSpinner(): - def __init__(self): - pass - - def __enter__(self): - return self - - def update(self, _): - pass - - def close(self): - pass - - def __exit__(self, type, value, traceback): - pass - - if __name__ == "__main__": import time with Spinner() as s: diff --git a/common/stat_live.py b/common/stat_live.py index e528c3deac..a91c1819bb 100644 --- a/common/stat_live.py +++ b/common/stat_live.py @@ -32,7 +32,7 @@ class RunningStat(): self.S_last = 0. else: self.M = self.M_last + (new_data - self.M_last) / self.n - self.S = self.S_last + (new_data - self.M_last) * (new_data - self.M); + self.S = self.S_last + (new_data - self.M_last) * (new_data - self.M) self.M_last = self.M self.S_last = self.S @@ -64,7 +64,7 @@ class RunningStatFilter(): _std_last = self.raw_stat.std() self.raw_stat.push_data(new_data) _delta_std = self.raw_stat.std() - _std_last - if _delta_std<=0: + if _delta_std <= 0: self.filtered_stat.push_data(new_data) else: pass diff --git a/common/string_helpers.py b/common/string_helpers.py index 8a7624a277..3038605fbb 100644 --- a/common/string_helpers.py +++ b/common/string_helpers.py @@ -3,4 +3,4 @@ def replace_right(s, old, new, occurrence): # replace_right('1232425', '2', ' ', 2) -> '123 4 5' split = s.rsplit(old, occurrence) - return new.join(split) \ No newline at end of file + return new.join(split) diff --git a/common/testing.py b/common/testing.py deleted file mode 100644 index 7e8b16d5cf..0000000000 --- a/common/testing.py +++ /dev/null @@ -1,9 +0,0 @@ -import os -from nose.tools import nottest - -def phone_only(x): - if os.path.isfile("/init.qcom.rc"): - return x - else: - return nottest(x) - diff --git a/common/tests/test_numpy_fast.py b/common/tests/test_numpy_fast.py index bf34de2ed7..2fb8a1cef3 100644 --- a/common/tests/test_numpy_fast.py +++ b/common/tests/test_numpy_fast.py @@ -1,6 +1,5 @@ import numpy as np import unittest -import timeit from common.numpy_fast import interp diff --git a/common/tests/test_params.py b/common/tests/test_params.py index b0c7af828d..0a2ac4e12f 100644 --- a/common/tests/test_params.py +++ b/common/tests/test_params.py @@ -1,10 +1,12 @@ -from common.params import Params, UnknownKeyName +import os import threading import time import tempfile import shutil +import stat import unittest +from common.params import Params, UnknownKeyName class TestParams(unittest.TestCase): def setUp(self): @@ -58,6 +60,12 @@ class TestParams(unittest.TestCase): with self.assertRaises(UnknownKeyName): self.params.get("swag") + def test_params_permissions(self): + permissions = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH | stat.S_IWOTH + + self.params.put("DongleId", "cb38263377b873ee") + st_mode = os.stat(f"{self.tmpdir}/d/DongleId").st_mode + assert (st_mode & permissions) == permissions if __name__ == "__main__": unittest.main() diff --git a/common/text_window.py b/common/text_window.py index 0d94bc7470..b815d8022a 100755 --- a/common/text_window.py +++ b/common/text_window.py @@ -6,20 +6,22 @@ from common.basedir import BASEDIR class TextWindow(): - def __init__(self, s): - try: - self.text_proc = subprocess.Popen(["./text", s], - stdin=subprocess.PIPE, - cwd=os.path.join(BASEDIR, "selfdrive", "ui", "text"), - close_fds=True) - except OSError: - self.text_proc = None + def __init__(self, s, noop=False): + # text window is only implemented for android currently + self.text_proc = None + if not noop: + try: + self.text_proc = subprocess.Popen(["./text", s], + stdin=subprocess.PIPE, + cwd=os.path.join(BASEDIR, "selfdrive", "ui", "text"), + close_fds=True) + except OSError: + self.text_proc = None def get_status(self): if self.text_proc is not None: self.text_proc.poll() return self.text_proc.returncode - return None def __enter__(self): @@ -31,38 +33,19 @@ class TextWindow(): self.text_proc = None def wait_for_exit(self): - while True: - if self.get_status() == 1: - return - time.sleep(0.1) + if self.text_proc is not None: + while True: + if self.get_status() == 1: + return + time.sleep(0.1) def __del__(self): self.close() - def __exit__(self, type, value, traceback): + def __exit__(self, exc_type, exc_value, traceback): self.close() -class FakeTextWindow(): - def __init__(self, s): - pass - - def get_status(self): - return 1 - - def wait_for_exit(self): - return - - def __enter__(self): - return self - - def update(self, _): - pass - - def __exit__(self, type, value, traceback): - pass - - if __name__ == "__main__": text = """Traceback (most recent call last): File "./controlsd.py", line 608, in diff --git a/common/timeout.py b/common/timeout.py index c2c1f69712..4d424cdc0a 100644 --- a/common/timeout.py +++ b/common/timeout.py @@ -25,4 +25,3 @@ class Timeout: def __exit__(self, exc_type, exc_val, exc_tb): signal.alarm(0) - diff --git a/common/transformations/.gitignore b/common/transformations/.gitignore new file mode 100644 index 0000000000..a67290f09a --- /dev/null +++ b/common/transformations/.gitignore @@ -0,0 +1,2 @@ +transformations +transformations.cpp diff --git a/common/transformations/README.md b/common/transformations/README.md index 119dae630e..f10852228a 100644 --- a/common/transformations/README.md +++ b/common/transformations/README.md @@ -25,14 +25,14 @@ by generating a rotation matrix and multiplying. Orientation Conventations ------ -Quaternions, rotation matrices and euler angles are three +Quaternions, rotation matrices and euler angles are three equivalent representations of orientation and all three are used throughout the code base. For euler angles the preferred convention is [roll, pitch, yaw] which corresponds to rotations around the [x, y, z] axes. All euler angles should always be in radians or radians/s unless -for plotting or display purposes. For quaternions the hamilton +for plotting or display purposes. For quaternions the hamilton notations is preferred which is [qw, qx, qy, qz]. All quaternions should always be normalized with a strictly positive qw. **These quaternions are a unique representation of orientation whereas euler angles @@ -45,11 +45,16 @@ while rotating around the rotated axes, not the original axes. Calibration ------ -EONs are not all mounted in the exact same way. To compensate for the effects of this the vision model takes in an image that is "calibrated". This means the image is aligned so the direction of travel of the car when it is going straight and the road is flat is always in the location on the image. This calibration is defined by a pitch and yaw angle that describe the direction of travel vector in device frame. +Device frame is aligned with the road-facing camera used by openpilot. However, when controlling the vehicle it makes more sense to think in a reference frame aligned with the vehicle. These two reference frames are not necessarily aligned. Calibration is defined as the roll, pitch and yaw angles that describe the orientation of the vehicle in device frame. The vehicle orientation is the orientation of the vehicles's body, the orientation of the vehicle can change relative to the road because of suspension movements. + +The roll of the vehicle is defined to be 0 when the vehicle is on a flat road and not turning. Pitch and yaw are defined as the angles that describe the direction in which the vehicle travels when it is driving on a flat road and not turning. + +It is important for openpilot's driving model to take in images that look as if the calibration angles were all zero. To achieve this the images input into the model are transformed with the estimated calibration angles. At the moment, roll calibration is always estimated to be zero. + Example ------ -To transform global Mesh3D positions and orientations (positions_ecef, quats_ecef) into the local frame described by the +To transform global Mesh3D positions and orientations (positions_ecef, quats_ecef) into the local frame described by the first position and orientation from Mesh3D one would do: ``` ecef_from_local = rot_from_quat(quats_ecef[0]) diff --git a/common/transformations/SConscript b/common/transformations/SConscript new file mode 100644 index 0000000000..0f72952259 --- /dev/null +++ b/common/transformations/SConscript @@ -0,0 +1,8 @@ +Import('env', 'cython_dependencies') + +d = Dir('.') + +env.Command(['transformations.so'], + cython_dependencies + ['transformations.pxd', 'transformations.pyx', + 'coordinates.cc', 'orientation.cc', 'coordinates.hpp', 'orientation.hpp'], + 'cd ' + d.path + ' && python3 setup.py build_ext --inplace') diff --git a/common/transformations/camera.py b/common/transformations/camera.py index 5ca9eb57d5..b406c33fd7 100644 --- a/common/transformations/camera.py +++ b/common/transformations/camera.py @@ -52,6 +52,13 @@ def get_view_frame_from_road_frame(roll, pitch, yaw, height): return np.hstack((view_from_road, [[0], [height], [0]])) +# aka 'extrinsic_matrix' +def get_view_frame_from_calib_frame(roll, pitch, yaw, height): + device_from_calib= orient.rot_from_euler([roll, pitch, yaw]) + view_from_calib = view_frame_from_device_frame.dot(device_from_calib) + return np.hstack((view_from_calib, [[0], [height], [0]])) + + def vp_from_ke(m): """ Computes the vanishing point from the product of the intrinsic and extrinsic @@ -59,7 +66,7 @@ def vp_from_ke(m): The vanishing point is defined as lim x->infinity C (x, 0, 0, 1).T """ - return (m[0, 0]/m[2,0], m[1,0]/m[2,0]) + return (m[0, 0]/m[2, 0], m[1, 0]/m[2, 0]) def vp_from_rpy(rpy): @@ -81,10 +88,10 @@ def normalize(img_pts, intrinsics=eon_intrinsics): img_pts = np.array(img_pts) input_shape = img_pts.shape img_pts = np.atleast_2d(img_pts) - img_pts = np.hstack((img_pts, np.ones((img_pts.shape[0],1)))) + img_pts = np.hstack((img_pts, np.ones((img_pts.shape[0], 1)))) img_pts_normalized = img_pts.dot(intrinsics_inv.T) img_pts_normalized[(img_pts < 0).any(axis=1)] = np.nan - return img_pts_normalized[:,:2].reshape(input_shape) + return img_pts_normalized[:, :2].reshape(input_shape) def denormalize(img_pts, intrinsics=eon_intrinsics): @@ -93,13 +100,13 @@ def denormalize(img_pts, intrinsics=eon_intrinsics): img_pts = np.array(img_pts) input_shape = img_pts.shape img_pts = np.atleast_2d(img_pts) - img_pts = np.hstack((img_pts, np.ones((img_pts.shape[0],1)))) + img_pts = np.hstack((img_pts, np.ones((img_pts.shape[0], 1)))) img_pts_denormalized = img_pts.dot(intrinsics.T) - img_pts_denormalized[img_pts_denormalized[:,0] > W] = np.nan - img_pts_denormalized[img_pts_denormalized[:,0] < 0] = np.nan - img_pts_denormalized[img_pts_denormalized[:,1] > H] = np.nan - img_pts_denormalized[img_pts_denormalized[:,1] < 0] = np.nan - return img_pts_denormalized[:,:2].reshape(input_shape) + img_pts_denormalized[img_pts_denormalized[:, 0] > W] = np.nan + img_pts_denormalized[img_pts_denormalized[:, 0] < 0] = np.nan + img_pts_denormalized[img_pts_denormalized[:, 1] > H] = np.nan + img_pts_denormalized[img_pts_denormalized[:, 1] < 0] = np.nan + return img_pts_denormalized[:, :2].reshape(input_shape) def device_from_ecef(pos_ecef, orientation_ecef, pt_ecef): @@ -124,10 +131,10 @@ def img_from_device(pt_device): pt_view = np.einsum('jk,ik->ij', view_frame_from_device_frame, pt_device) # This function should never return negative depths - pt_view[pt_view[:,2] < 0] = np.nan + pt_view[pt_view[:, 2] < 0] = np.nan - pt_img = pt_view/pt_view[:,2:3] - return pt_img.reshape(input_shape)[:,:2] + pt_img = pt_view/pt_view[:, 2:3] + return pt_img.reshape(input_shape)[:, :2] def get_camera_frame_from_calib_frame(camera_frame_from_road_frame): @@ -145,4 +152,3 @@ def pretransform_from_calib(calib): camera_frame_from_road_frame = np.dot(eon_intrinsics, view_frame_from_road_frame) camera_frame_from_calib_frame = get_camera_frame_from_calib_frame(camera_frame_from_road_frame) return np.linalg.inv(camera_frame_from_calib_frame) - diff --git a/common/transformations/coordinates.cc b/common/transformations/coordinates.cc new file mode 100644 index 0000000000..8a1aa0ad72 --- /dev/null +++ b/common/transformations/coordinates.cc @@ -0,0 +1,104 @@ +#define _USE_MATH_DEFINES + +#include +#include +#include + +#include "coordinates.hpp" + +#define DEG2RAD(x) ((x) * M_PI / 180.0) +#define RAD2DEG(x) ((x) * 180.0 / M_PI) + + +double a = 6378137; // lgtm [cpp/short-global-name] +double b = 6356752.3142; // lgtm [cpp/short-global-name] +double esq = 6.69437999014 * 0.001; // lgtm [cpp/short-global-name] +double e1sq = 6.73949674228 * 0.001; + + +static Geodetic to_degrees(Geodetic geodetic){ + geodetic.lat = RAD2DEG(geodetic.lat); + geodetic.lon = RAD2DEG(geodetic.lon); + return geodetic; +} + +static Geodetic to_radians(Geodetic geodetic){ + geodetic.lat = DEG2RAD(geodetic.lat); + geodetic.lon = DEG2RAD(geodetic.lon); + return geodetic; +} + + +ECEF geodetic2ecef(Geodetic g){ + g = to_radians(g); + double xi = sqrt(1.0 - esq * pow(sin(g.lat), 2)); + double x = (a / xi + g.alt) * cos(g.lat) * cos(g.lon); + double y = (a / xi + g.alt) * cos(g.lat) * sin(g.lon); + double z = (a / xi * (1.0 - esq) + g.alt) * sin(g.lat); + return {x, y, z}; +} + +Geodetic ecef2geodetic(ECEF e){ + // Convert from ECEF to geodetic using Ferrari's methods + // https://en.wikipedia.org/wiki/Geographic_coordinate_conversion#Ferrari.27s_solution + double x = e.x; + double y = e.y; + double z = e.z; + + double r = sqrt(x * x + y * y); + double Esq = a * a - b * b; + double F = 54 * b * b * z * z; + double G = r * r + (1 - esq) * z * z - esq * Esq; + double C = (esq * esq * F * r * r) / (pow(G, 3)); + double S = cbrt(1 + C + sqrt(C * C + 2 * C)); + double P = F / (3 * pow((S + 1 / S + 1), 2) * G * G); + double Q = sqrt(1 + 2 * esq * esq * P); + double r_0 = -(P * esq * r) / (1 + Q) + sqrt(0.5 * a * a*(1 + 1.0 / Q) - P * (1 - esq) * z * z / (Q * (1 + Q)) - 0.5 * P * r * r); + double U = sqrt(pow((r - esq * r_0), 2) + z * z); + double V = sqrt(pow((r - esq * r_0), 2) + (1 - esq) * z * z); + double Z_0 = b * b * z / (a * V); + double h = U * (1 - b * b / (a * V)); + + double lat = atan((z + e1sq * Z_0) / r); + double lon = atan2(y, x); + + return to_degrees({lat, lon, h}); +} + +LocalCoord::LocalCoord(Geodetic g, ECEF e){ + init_ecef << e.x, e.y, e.z; + + g = to_radians(g); + + ned2ecef_matrix << + -sin(g.lat)*cos(g.lon), -sin(g.lon), -cos(g.lat)*cos(g.lon), + -sin(g.lat)*sin(g.lon), cos(g.lon), -cos(g.lat)*sin(g.lon), + cos(g.lat), 0, -sin(g.lat); + ecef2ned_matrix = ned2ecef_matrix.transpose(); +} + +NED LocalCoord::ecef2ned(ECEF e) { + Eigen::Vector3d ecef; + ecef << e.x, e.y, e.z; + + Eigen::Vector3d ned = (ecef2ned_matrix * (ecef - init_ecef)); + return {ned[0], ned[1], ned[2]}; +} + +ECEF LocalCoord::ned2ecef(NED n) { + Eigen::Vector3d ned; + ned << n.n, n.e, n.d; + + Eigen::Vector3d ecef = (ned2ecef_matrix * ned) + init_ecef; + return {ecef[0], ecef[1], ecef[2]}; +} + +NED LocalCoord::geodetic2ned(Geodetic g) { + ECEF e = ::geodetic2ecef(g); + return ecef2ned(e); +} + +Geodetic LocalCoord::ned2geodetic(NED n){ + ECEF e = ned2ecef(n); + return ::ecef2geodetic(e); +} diff --git a/common/transformations/coordinates.hpp b/common/transformations/coordinates.hpp new file mode 100644 index 0000000000..d8beb59ea9 --- /dev/null +++ b/common/transformations/coordinates.hpp @@ -0,0 +1,35 @@ +#pragma once + +struct ECEF { + double x, y, z; + Eigen::Vector3d to_vector(){ + return Eigen::Vector3d(x, y, z); + } +}; + +struct NED { + double n, e, d; +}; + +struct Geodetic { + double lat, lon, alt; + bool radians=false; +}; + +ECEF geodetic2ecef(Geodetic g); +Geodetic ecef2geodetic(ECEF e); + +class LocalCoord { +public: + Eigen::Matrix3d ned2ecef_matrix; + Eigen::Matrix3d ecef2ned_matrix; + Eigen::Vector3d init_ecef; + LocalCoord(Geodetic g, ECEF e); + LocalCoord(Geodetic g) : LocalCoord(g, ::geodetic2ecef(g)) {} + LocalCoord(ECEF e) : LocalCoord(::ecef2geodetic(e), e) {} + + NED ecef2ned(ECEF e); + ECEF ned2ecef(NED n); + NED geodetic2ned(Geodetic g); + Geodetic ned2geodetic(NED n); +}; diff --git a/common/transformations/coordinates.py b/common/transformations/coordinates.py index 864bc4d807..46cc0ded0d 100644 --- a/common/transformations/coordinates.py +++ b/common/transformations/coordinates.py @@ -1,108 +1,19 @@ -import numpy as np -""" -Coordinate transformation module. All methods accept arrays as input -with each row as a position. -""" +# pylint: skip-file +from common.transformations.orientation import numpy_wrap +from common.transformations.transformations import (ecef2geodetic_single, + geodetic2ecef_single) +from common.transformations.transformations import LocalCoord as LocalCoord_single +class LocalCoord(LocalCoord_single): + ecef2ned = numpy_wrap(LocalCoord_single.ecef2ned_single, (3,), (3,)) + ned2ecef = numpy_wrap(LocalCoord_single.ned2ecef_single, (3,), (3,)) + geodetic2ned = numpy_wrap(LocalCoord_single.geodetic2ned_single, (3,), (3,)) + ned2geodetic = numpy_wrap(LocalCoord_single.ned2geodetic_single, (3,), (3,)) -a = 6378137 -b = 6356752.3142 -esq = 6.69437999014 * 0.001 -e1sq = 6.73949674228 * 0.001 +geodetic2ecef = numpy_wrap(geodetic2ecef_single, (3,), (3,)) +ecef2geodetic = numpy_wrap(ecef2geodetic_single, (3,), (3,)) -def geodetic2ecef(geodetic, radians=False): - geodetic = np.array(geodetic) - input_shape = geodetic.shape - geodetic = np.atleast_2d(geodetic) - - ratio = 1.0 if radians else (np.pi / 180.0) - lat = ratio*geodetic[:,0] - lon = ratio*geodetic[:,1] - alt = geodetic[:,2] - - xi = np.sqrt(1 - esq * np.sin(lat)**2) - x = (a / xi + alt) * np.cos(lat) * np.cos(lon) - y = (a / xi + alt) * np.cos(lat) * np.sin(lon) - z = (a / xi * (1 - esq) + alt) * np.sin(lat) - ecef = np.array([x, y, z]).T - return ecef.reshape(input_shape) - - -def ecef2geodetic(ecef, radians=False): - """ - Convert ECEF coordinates to geodetic using ferrari's method - """ - # Save shape and export column - ecef = np.atleast_1d(ecef) - input_shape = ecef.shape - ecef = np.atleast_2d(ecef) - x, y, z = ecef[:, 0], ecef[:, 1], ecef[:, 2] - - ratio = 1.0 if radians else (180.0 / np.pi) - - # Conver from ECEF to geodetic using Ferrari's methods - # https://en.wikipedia.org/wiki/Geographic_coordinate_conversion#Ferrari.27s_solution - r = np.sqrt(x * x + y * y) - Esq = a * a - b * b - F = 54 * b * b * z * z - G = r * r + (1 - esq) * z * z - esq * Esq - C = (esq * esq * F * r * r) / (pow(G, 3)) - S = np.cbrt(1 + C + np.sqrt(C * C + 2 * C)) - P = F / (3 * pow((S + 1 / S + 1), 2) * G * G) - Q = np.sqrt(1 + 2 * esq * esq * P) - r_0 = -(P * esq * r) / (1 + Q) + np.sqrt(0.5 * a * a*(1 + 1.0 / Q) - \ - P * (1 - esq) * z * z / (Q * (1 + Q)) - 0.5 * P * r * r) - U = np.sqrt(pow((r - esq * r_0), 2) + z * z) - V = np.sqrt(pow((r - esq * r_0), 2) + (1 - esq) * z * z) - Z_0 = b * b * z / (a * V) - h = U * (1 - b * b / (a * V)) - lat = ratio*np.arctan((z + e1sq * Z_0) / r) - lon = ratio*np.arctan2(y, x) - - # stack the new columns and return to the original shape - geodetic = np.column_stack((lat, lon, h)) - return geodetic.reshape(input_shape) - -class LocalCoord(): - """ - Allows conversions to local frames. In this case NED. - That is: North East Down from the start position in - meters. - """ - def __init__(self, init_geodetic, init_ecef): - self.init_ecef = init_ecef - lat, lon, _ = (np.pi/180)*np.array(init_geodetic) - self.ned2ecef_matrix = np.array([[-np.sin(lat)*np.cos(lon), -np.sin(lon), -np.cos(lat)*np.cos(lon)], - [-np.sin(lat)*np.sin(lon), np.cos(lon), -np.cos(lat)*np.sin(lon)], - [np.cos(lat), 0, -np.sin(lat)]]) - self.ecef2ned_matrix = self.ned2ecef_matrix.T - - @classmethod - def from_geodetic(cls, init_geodetic): - init_ecef = geodetic2ecef(init_geodetic) - return LocalCoord(init_geodetic, init_ecef) - - @classmethod - def from_ecef(cls, init_ecef): - init_geodetic = ecef2geodetic(init_ecef) - return LocalCoord(init_geodetic, init_ecef) - - - def ecef2ned(self, ecef): - ecef = np.array(ecef) - return np.dot(self.ecef2ned_matrix, (ecef - self.init_ecef).T).T - - def ned2ecef(self, ned): - ned = np.array(ned) - # Transpose so that init_ecef will broadcast correctly for 1d or 2d ned. - return (np.dot(self.ned2ecef_matrix, ned.T).T + self.init_ecef) - - def geodetic2ned(self, geodetic): - ecef = geodetic2ecef(geodetic) - return self.ecef2ned(ecef) - - def ned2geodetic(self, ned): - ecef = self.ned2ecef(ned) - return ecef2geodetic(ecef) +geodetic_from_ecef = ecef2geodetic +ecef_from_geodetic = geodetic2ecef diff --git a/common/transformations/model.py b/common/transformations/model.py index c47c9e987f..a3b46858b1 100644 --- a/common/transformations/model.py +++ b/common/transformations/model.py @@ -2,6 +2,7 @@ import numpy as np from common.transformations.camera import (FULL_FRAME_SIZE, eon_focal_length, get_view_frame_from_road_frame, + get_view_frame_from_calib_frame, vp_from_ke) # segnet @@ -41,6 +42,17 @@ medmodel_intrinsics = np.array( [ 0. , eon_focal_length / medmodel_zoom, MEDMODEL_CY], [ 0. , 0. , 1.]]) +# CAL model +CALMODEL_INPUT_SIZE = (512, 256) +CALMODEL_YUV_SIZE = (CALMODEL_INPUT_SIZE[0], CALMODEL_INPUT_SIZE[1] * 3 // 2) +CALMODEL_CY = 47.6 + +calmodel_zoom = 1.5 +calmodel_intrinsics = np.array( + [[ eon_focal_length / calmodel_zoom, 0. , 0.5 * CALMODEL_INPUT_SIZE[0]], + [ 0. , eon_focal_length / calmodel_zoom, CALMODEL_CY], + [ 0. , 0. , 1.]]) + # BIG model @@ -62,6 +74,9 @@ bigmodel_frame_from_road_frame = np.dot(bigmodel_intrinsics, medmodel_frame_from_road_frame = np.dot(medmodel_intrinsics, get_view_frame_from_road_frame(0, 0, 0, model_height)) +medmodel_frame_from_calib_frame = np.dot(medmodel_intrinsics, + get_view_frame_from_calib_frame(0, 0, 0, 0)) + model_frame_from_bigmodel_frame = np.dot(model_intrinsics, np.linalg.inv(bigmodel_intrinsics)) medmodel_frame_from_bigmodel_frame = np.dot(medmodel_intrinsics, np.linalg.inv(bigmodel_intrinsics)) @@ -100,7 +115,7 @@ def get_camera_frame_from_model_frame(camera_frame_from_road_frame, height=model # This function is super slow, so skip it if height is very close to canonical # TODO: speed it up! - if abs(height - model_height) > 0.001: # + if abs(height - model_height) > 0.001: camera_from_model_camera = get_model_height_transform(camera_frame_from_road_frame, height) else: camera_from_model_camera = np.eye(3) @@ -130,9 +145,9 @@ def get_camera_frame_from_bigmodel_frame(camera_frame_from_road_frame): def get_model_frame(snu_full, camera_frame_from_model_frame, size): idxs = camera_frame_from_model_frame.dot(np.column_stack([np.tile(np.arange(size[0]), size[1]), - np.tile(np.arange(size[1]), (size[0],1)).T.flatten(), + np.tile(np.arange(size[1]), (size[0], 1)).T.flatten(), np.ones(size[0] * size[1])]).T).T.astype(int) - calib_flat = snu_full[idxs[:,1], idxs[:,0]] + calib_flat = snu_full[idxs[:, 1], idxs[:, 0]] if len(snu_full.shape) == 3: calib = calib_flat.reshape((size[1], size[0], 3)) elif len(snu_full.shape) == 2: diff --git a/common/transformations/orientation.cc b/common/transformations/orientation.cc new file mode 100644 index 0000000000..086219d234 --- /dev/null +++ b/common/transformations/orientation.cc @@ -0,0 +1,147 @@ +#define _USE_MATH_DEFINES + +#include +#include +#include + +#include "orientation.hpp" +#include "coordinates.hpp" + +Eigen::Quaterniond ensure_unique(Eigen::Quaterniond quat){ + if (quat.w() > 0){ + return quat; + } else { + return Eigen::Quaterniond(-quat.w(), -quat.x(), -quat.y(), -quat.z()); + } +} + +Eigen::Quaterniond euler2quat(Eigen::Vector3d euler){ + Eigen::Quaterniond q; + + q = Eigen::AngleAxisd(euler(2), Eigen::Vector3d::UnitZ()) + * Eigen::AngleAxisd(euler(1), Eigen::Vector3d::UnitY()) + * Eigen::AngleAxisd(euler(0), Eigen::Vector3d::UnitX()); + return ensure_unique(q); +} + + +Eigen::Vector3d quat2euler(Eigen::Quaterniond quat){ + // TODO: switch to eigen implementation if the range of the Euler angles doesn't matter anymore + // Eigen::Vector3d euler = quat.toRotationMatrix().eulerAngles(2, 1, 0); + // return {euler(2), euler(1), euler(0)}; + double gamma = atan2(2 * (quat.w() * quat.x() + quat.y() * quat.z()), 1 - 2 * (quat.x()*quat.x() + quat.y()*quat.y())); + double theta = asin(2 * (quat.w() * quat.y() - quat.z() * quat.x())); + double psi = atan2(2 * (quat.w() * quat.z() + quat.x() * quat.y()), 1 - 2 * (quat.y()*quat.y() + quat.z()*quat.z())); + return {gamma, theta, psi}; +} + +Eigen::Matrix3d quat2rot(Eigen::Quaterniond quat){ + return quat.toRotationMatrix(); +} + +Eigen::Quaterniond rot2quat(Eigen::Matrix3d rot){ + return ensure_unique(Eigen::Quaterniond(rot)); +} + +Eigen::Matrix3d euler2rot(Eigen::Vector3d euler){ + return quat2rot(euler2quat(euler)); +} + +Eigen::Vector3d rot2euler(Eigen::Matrix3d rot){ + return quat2euler(rot2quat(rot)); +} + +Eigen::Matrix3d rot_matrix(double roll, double pitch, double yaw){ + return euler2rot({roll, pitch, yaw}); +} + +Eigen::Matrix3d rot(Eigen::Vector3d axis, double angle){ + Eigen::Quaterniond q; + q = Eigen::AngleAxisd(angle, axis); + return q.toRotationMatrix(); +} + + +Eigen::Vector3d ecef_euler_from_ned(ECEF ecef_init, Eigen::Vector3d ned_pose) { + /* + Using Rotations to Build Aerospace Coordinate Systems + Don Koks + https://apps.dtic.mil/dtic/tr/fulltext/u2/a484864.pdf + */ + LocalCoord converter = LocalCoord(ecef_init); + Eigen::Vector3d zero = ecef_init.to_vector(); + + Eigen::Vector3d x0 = converter.ned2ecef({1, 0, 0}).to_vector() - zero; + Eigen::Vector3d y0 = converter.ned2ecef({0, 1, 0}).to_vector() - zero; + Eigen::Vector3d z0 = converter.ned2ecef({0, 0, 1}).to_vector() - zero; + + Eigen::Vector3d x1 = rot(z0, ned_pose(2)) * x0; + Eigen::Vector3d y1 = rot(z0, ned_pose(2)) * y0; + Eigen::Vector3d z1 = rot(z0, ned_pose(2)) * z0; + + Eigen::Vector3d x2 = rot(y1, ned_pose(1)) * x1; + Eigen::Vector3d y2 = rot(y1, ned_pose(1)) * y1; + Eigen::Vector3d z2 = rot(y1, ned_pose(1)) * z1; + + Eigen::Vector3d x3 = rot(x2, ned_pose(0)) * x2; + Eigen::Vector3d y3 = rot(x2, ned_pose(0)) * y2; + + + x0 = Eigen::Vector3d(1, 0, 0); + y0 = Eigen::Vector3d(0, 1, 0); + z0 = Eigen::Vector3d(0, 0, 1); + + double psi = atan2(x3.dot(y0), x3.dot(x0)); + double theta = atan2(-x3.dot(z0), sqrt(pow(x3.dot(x0), 2) + pow(x3.dot(y0), 2))); + + y2 = rot(z0, psi) * y0; + z2 = rot(y2, theta) * z0; + + double phi = atan2(y3.dot(z2), y3.dot(y2)); + + return {phi, theta, psi}; +} + +Eigen::Vector3d ned_euler_from_ecef(ECEF ecef_init, Eigen::Vector3d ecef_pose){ + /* + Using Rotations to Build Aerospace Coordinate Systems + Don Koks + https://apps.dtic.mil/dtic/tr/fulltext/u2/a484864.pdf + */ + LocalCoord converter = LocalCoord(ecef_init); + + Eigen::Vector3d x0 = Eigen::Vector3d(1, 0, 0); + Eigen::Vector3d y0 = Eigen::Vector3d(0, 1, 0); + Eigen::Vector3d z0 = Eigen::Vector3d(0, 0, 1); + + Eigen::Vector3d x1 = rot(z0, ecef_pose(2)) * x0; + Eigen::Vector3d y1 = rot(z0, ecef_pose(2)) * y0; + Eigen::Vector3d z1 = rot(z0, ecef_pose(2)) * z0; + + Eigen::Vector3d x2 = rot(y1, ecef_pose(1)) * x1; + Eigen::Vector3d y2 = rot(y1, ecef_pose(1)) * y1; + Eigen::Vector3d z2 = rot(y1, ecef_pose(1)) * z1; + + Eigen::Vector3d x3 = rot(x2, ecef_pose(0)) * x2; + Eigen::Vector3d y3 = rot(x2, ecef_pose(0)) * y2; + + Eigen::Vector3d zero = ecef_init.to_vector(); + x0 = converter.ned2ecef({1, 0, 0}).to_vector() - zero; + y0 = converter.ned2ecef({0, 1, 0}).to_vector() - zero; + z0 = converter.ned2ecef({0, 0, 1}).to_vector() - zero; + + double psi = atan2(x3.dot(y0), x3.dot(x0)); + double theta = atan2(-x3.dot(z0), sqrt(pow(x3.dot(x0), 2) + pow(x3.dot(y0), 2))); + + y2 = rot(z0, psi) * y0; + z2 = rot(y2, theta) * z0; + + double phi = atan2(y3.dot(z2), y3.dot(y2)); + + return {phi, theta, psi}; +} + + + +int main(void){ +} diff --git a/common/transformations/orientation.hpp b/common/transformations/orientation.hpp new file mode 100644 index 0000000000..da95f7099d --- /dev/null +++ b/common/transformations/orientation.hpp @@ -0,0 +1,17 @@ +#pragma once +#include +#include "coordinates.hpp" + + +Eigen::Quaterniond ensure_unique(Eigen::Quaterniond quat); + +Eigen::Quaterniond euler2quat(Eigen::Vector3d euler); +Eigen::Vector3d quat2euler(Eigen::Quaterniond quat); +Eigen::Matrix3d quat2rot(Eigen::Quaterniond quat); +Eigen::Quaterniond rot2quat(Eigen::Matrix3d rot); +Eigen::Matrix3d euler2rot(Eigen::Vector3d euler); +Eigen::Vector3d rot2euler(Eigen::Matrix3d rot); +Eigen::Matrix3d rot_matrix(double roll, double pitch, double yaw); +Eigen::Matrix3d rot(Eigen::Vector3d axis, double angle); +Eigen::Vector3d ecef_euler_from_ned(ECEF ecef_init, Eigen::Vector3d ned_pose); +Eigen::Vector3d ned_euler_from_ecef(ECEF ecef_init, Eigen::Vector3d ecef_pose); diff --git a/common/transformations/orientation.py b/common/transformations/orientation.py index acbd4a2bf3..415e247ab2 100644 --- a/common/transformations/orientation.py +++ b/common/transformations/orientation.py @@ -1,295 +1,52 @@ +# pylint: skip-file import numpy as np -from numpy import dot, inner, array, linalg -from common.transformations.coordinates import LocalCoord - - -''' -Vectorized functions that transform between -rotation matrices, euler angles and quaternions. -All support lists, array or array of arrays as inputs. -Supports both x2y and y_from_x format (y_from_x preferred!). -''' - -def euler2quat(eulers): - eulers = array(eulers) - if len(eulers.shape) > 1: - output_shape = (-1,4) - else: - output_shape = (4,) - eulers = np.atleast_2d(eulers) - gamma, theta, psi = eulers[:,0], eulers[:,1], eulers[:,2] - - q0 = np.cos(gamma / 2) * np.cos(theta / 2) * np.cos(psi / 2) + \ - np.sin(gamma / 2) * np.sin(theta / 2) * np.sin(psi / 2) - q1 = np.sin(gamma / 2) * np.cos(theta / 2) * np.cos(psi / 2) - \ - np.cos(gamma / 2) * np.sin(theta / 2) * np.sin(psi / 2) - q2 = np.cos(gamma / 2) * np.sin(theta / 2) * np.cos(psi / 2) + \ - np.sin(gamma / 2) * np.cos(theta / 2) * np.sin(psi / 2) - q3 = np.cos(gamma / 2) * np.cos(theta / 2) * np.sin(psi / 2) - \ - np.sin(gamma / 2) * np.sin(theta / 2) * np.cos(psi / 2) - - quats = array([q0, q1, q2, q3]).T - for i in range(len(quats)): - if quats[i,0] < 0: - quats[i] = -quats[i] - return quats.reshape(output_shape) - - -def quat2euler(quats): - quats = array(quats) - if len(quats.shape) > 1: - output_shape = (-1,3) - else: - output_shape = (3,) - quats = np.atleast_2d(quats) - q0, q1, q2, q3 = quats[:,0], quats[:,1], quats[:,2], quats[:,3] - - gamma = np.arctan2(2 * (q0 * q1 + q2 * q3), 1 - 2 * (q1**2 + q2**2)) - theta = np.arcsin(2 * (q0 * q2 - q3 * q1)) - psi = np.arctan2(2 * (q0 * q3 + q1 * q2), 1 - 2 * (q2**2 + q3**2)) - - eulers = array([gamma, theta, psi]).T - return eulers.reshape(output_shape) - - -def quat2rot(quats): - quats = array(quats) - input_shape = quats.shape - quats = np.atleast_2d(quats) - Rs = np.zeros((quats.shape[0], 3, 3)) - q0 = quats[:, 0] - q1 = quats[:, 1] - q2 = quats[:, 2] - q3 = quats[:, 3] - Rs[:, 0, 0] = q0 * q0 + q1 * q1 - q2 * q2 - q3 * q3 - Rs[:, 0, 1] = 2 * (q1 * q2 - q0 * q3) - Rs[:, 0, 2] = 2 * (q0 * q2 + q1 * q3) - Rs[:, 1, 0] = 2 * (q1 * q2 + q0 * q3) - Rs[:, 1, 1] = q0 * q0 - q1 * q1 + q2 * q2 - q3 * q3 - Rs[:, 1, 2] = 2 * (q2 * q3 - q0 * q1) - Rs[:, 2, 0] = 2 * (q1 * q3 - q0 * q2) - Rs[:, 2, 1] = 2 * (q0 * q1 + q2 * q3) - Rs[:, 2, 2] = q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3 - - if len(input_shape) < 2: - return Rs[0] - else: - return Rs - - -def rot2quat(rots): - input_shape = rots.shape - if len(input_shape) < 3: - rots = array([rots]) - K3 = np.empty((len(rots), 4, 4)) - K3[:, 0, 0] = (rots[:, 0, 0] - rots[:, 1, 1] - rots[:, 2, 2]) / 3.0 - K3[:, 0, 1] = (rots[:, 1, 0] + rots[:, 0, 1]) / 3.0 - K3[:, 0, 2] = (rots[:, 2, 0] + rots[:, 0, 2]) / 3.0 - K3[:, 0, 3] = (rots[:, 1, 2] - rots[:, 2, 1]) / 3.0 - K3[:, 1, 0] = K3[:, 0, 1] - K3[:, 1, 1] = (rots[:, 1, 1] - rots[:, 0, 0] - rots[:, 2, 2]) / 3.0 - K3[:, 1, 2] = (rots[:, 2, 1] + rots[:, 1, 2]) / 3.0 - K3[:, 1, 3] = (rots[:, 2, 0] - rots[:, 0, 2]) / 3.0 - K3[:, 2, 0] = K3[:, 0, 2] - K3[:, 2, 1] = K3[:, 1, 2] - K3[:, 2, 2] = (rots[:, 2, 2] - rots[:, 0, 0] - rots[:, 1, 1]) / 3.0 - K3[:, 2, 3] = (rots[:, 0, 1] - rots[:, 1, 0]) / 3.0 - K3[:, 3, 0] = K3[:, 0, 3] - K3[:, 3, 1] = K3[:, 1, 3] - K3[:, 3, 2] = K3[:, 2, 3] - K3[:, 3, 3] = (rots[:, 0, 0] + rots[:, 1, 1] + rots[:, 2, 2]) / 3.0 - q = np.empty((len(rots), 4)) - for i in range(len(rots)): - _, eigvecs = linalg.eigh(K3[i].T) - eigvecs = eigvecs[:,3:] - q[i, 0] = eigvecs[-1] - q[i, 1:] = -eigvecs[:-1].flatten() - if q[i, 0] < 0: - q[i] = -q[i] - - if len(input_shape) < 3: - return q[0] - else: - return q - - -def euler2rot(eulers): - return rotations_from_quats(euler2quat(eulers)) - - -def rot2euler(rots): - return quat2euler(quats_from_rotations(rots)) +from common.transformations.transformations import (ecef_euler_from_ned_single, + euler2quat_single, + euler2rot_single, + ned_euler_from_ecef_single, + quat2euler_single, + quat2rot_single, + rot2euler_single, + rot2quat_single) + + +def numpy_wrap(function, input_shape, output_shape): + """Wrap a function to take either an input or list of inputs and return the correct shape""" + def f(*inps): + *args, inp = inps + inp = np.array(inp) + shape = inp.shape + + if len(shape) == len(input_shape): + out_shape = output_shape + else: + out_shape = (shape[0],) + output_shape + + # Add empty dimension if inputs is not a list + if len(shape) == len(input_shape): + inp.shape = (1, ) + inp.shape + + result = np.asarray([function(*args, i) for i in inp]) + result.shape = out_shape + return result + return f + + +euler2quat = numpy_wrap(euler2quat_single, (3,), (4,)) +quat2euler = numpy_wrap(quat2euler_single, (4,), (3,)) +quat2rot = numpy_wrap(quat2rot_single, (4,), (3, 3)) +rot2quat = numpy_wrap(rot2quat_single, (3, 3), (4,)) +euler2rot = numpy_wrap(euler2rot_single, (3,), (3, 3)) +rot2euler = numpy_wrap(rot2euler_single, (3, 3), (3,)) +ecef_euler_from_ned = numpy_wrap(ecef_euler_from_ned_single, (3,), (3,)) +ned_euler_from_ecef = numpy_wrap(ned_euler_from_ecef_single, (3,), (3,)) quats_from_rotations = rot2quat quat_from_rot = rot2quat rotations_from_quats = quat2rot -rot_from_quat= quat2rot -rot_from_quat= quat2rot +rot_from_quat = quat2rot euler_from_rot = rot2euler euler_from_quat = quat2euler rot_from_euler = euler2rot quat_from_euler = euler2quat - - - - - - -''' -Random helpers below -''' - - -def quat_product(q, r): - t = np.zeros(4) - t[0] = r[0] * q[0] - r[1] * q[1] - r[2] * q[2] - r[3] * q[3] - t[1] = r[0] * q[1] + r[1] * q[0] - r[2] * q[3] + r[3] * q[2] - t[2] = r[0] * q[2] + r[1] * q[3] + r[2] * q[0] - r[3] * q[1] - t[3] = r[0] * q[3] - r[1] * q[2] + r[2] * q[1] + r[3] * q[0] - return t - - -def rot_matrix(roll, pitch, yaw): - cr, sr = np.cos(roll), np.sin(roll) - cp, sp = np.cos(pitch), np.sin(pitch) - cy, sy = np.cos(yaw), np.sin(yaw) - rr = array([[1,0,0],[0, cr,-sr],[0, sr, cr]]) - rp = array([[cp,0,sp],[0, 1,0],[-sp, 0, cp]]) - ry = array([[cy,-sy,0],[sy, cy,0],[0, 0, 1]]) - return ry.dot(rp.dot(rr)) - - -def rot(axis, angle): - # Rotates around an arbitrary axis - ret_1 = (1 - np.cos(angle)) * array([[axis[0]**2, axis[0] * axis[1], axis[0] * axis[2]], [ - axis[1] * axis[0], axis[1]**2, axis[1] * axis[2] - ], [axis[2] * axis[0], axis[2] * axis[1], axis[2]**2]]) - ret_2 = np.cos(angle) * np.eye(3) - ret_3 = np.sin(angle) * array([[0, -axis[2], axis[1]], [axis[2], 0, -axis[0]], - [-axis[1], axis[0], 0]]) - return ret_1 + ret_2 + ret_3 - - -def ecef_euler_from_ned(ned_ecef_init, ned_pose): - ''' - Got it from here: - Using Rotations to Build Aerospace Coordinate Systems - -Don Koks - ''' - converter = LocalCoord.from_ecef(ned_ecef_init) - x0 = converter.ned2ecef([1, 0, 0]) - converter.ned2ecef([0, 0, 0]) - y0 = converter.ned2ecef([0, 1, 0]) - converter.ned2ecef([0, 0, 0]) - z0 = converter.ned2ecef([0, 0, 1]) - converter.ned2ecef([0, 0, 0]) - - x1 = rot(z0, ned_pose[2]).dot(x0) - y1 = rot(z0, ned_pose[2]).dot(y0) - z1 = rot(z0, ned_pose[2]).dot(z0) - - x2 = rot(y1, ned_pose[1]).dot(x1) - y2 = rot(y1, ned_pose[1]).dot(y1) - z2 = rot(y1, ned_pose[1]).dot(z1) - - x3 = rot(x2, ned_pose[0]).dot(x2) - y3 = rot(x2, ned_pose[0]).dot(y2) - #z3 = rot(x2, ned_pose[0]).dot(z2) - - x0 = array([1, 0, 0]) - y0 = array([0, 1, 0]) - z0 = array([0, 0, 1]) - - psi = np.arctan2(inner(x3, y0), inner(x3, x0)) - theta = np.arctan2(-inner(x3, z0), np.sqrt(inner(x3, x0)**2 + inner(x3, y0)**2)) - y2 = rot(z0, psi).dot(y0) - z2 = rot(y2, theta).dot(z0) - phi = np.arctan2(inner(y3, z2), inner(y3, y2)) - - ret = array([phi, theta, psi]) - return ret - - -def ned_euler_from_ecef(ned_ecef_init, ecef_poses): - ''' - Got the math from here: - Using Rotations to Build Aerospace Coordinate Systems - -Don Koks - - Also accepts array of ecef_poses and array of ned_ecef_inits. - Where each row is a pose and an ecef_init. - ''' - ned_ecef_init = array(ned_ecef_init) - ecef_poses = array(ecef_poses) - output_shape = ecef_poses.shape - ned_ecef_init = np.atleast_2d(ned_ecef_init) - if ned_ecef_init.shape[0] == 1: - ned_ecef_init = np.tile(ned_ecef_init[0], (output_shape[0], 1)) - ecef_poses = np.atleast_2d(ecef_poses) - - ned_poses = np.zeros(ecef_poses.shape) - for i, ecef_pose in enumerate(ecef_poses): - converter = LocalCoord.from_ecef(ned_ecef_init[i]) - x0 = array([1, 0, 0]) - y0 = array([0, 1, 0]) - z0 = array([0, 0, 1]) - - x1 = rot(z0, ecef_pose[2]).dot(x0) - y1 = rot(z0, ecef_pose[2]).dot(y0) - z1 = rot(z0, ecef_pose[2]).dot(z0) - - x2 = rot(y1, ecef_pose[1]).dot(x1) - y2 = rot(y1, ecef_pose[1]).dot(y1) - z2 = rot(y1, ecef_pose[1]).dot(z1) - - x3 = rot(x2, ecef_pose[0]).dot(x2) - y3 = rot(x2, ecef_pose[0]).dot(y2) - #z3 = rot(x2, ecef_pose[0]).dot(z2) - - x0 = converter.ned2ecef([1, 0, 0]) - converter.ned2ecef([0, 0, 0]) - y0 = converter.ned2ecef([0, 1, 0]) - converter.ned2ecef([0, 0, 0]) - z0 = converter.ned2ecef([0, 0, 1]) - converter.ned2ecef([0, 0, 0]) - - psi = np.arctan2(inner(x3, y0), inner(x3, x0)) - theta = np.arctan2(-inner(x3, z0), np.sqrt(inner(x3, x0)**2 + inner(x3, y0)**2)) - y2 = rot(z0, psi).dot(y0) - z2 = rot(y2, theta).dot(z0) - phi = np.arctan2(inner(y3, z2), inner(y3, y2)) - ned_poses[i] = array([phi, theta, psi]) - - return ned_poses.reshape(output_shape) - - -def ecef2car(car_ecef, psi, theta, points_ecef, ned_converter): - """ - TODO: add roll rotation - Converts an array of points in ecef coordinates into - x-forward, y-left, z-up coordinates - Parameters - ---------- - psi: yaw, radian - theta: pitch, radian - Returns - ------- - [x, y, z] coordinates in car frame - """ - - # input is an array of points in ecef cocrdinates - # output is an array of points in car's coordinate (x-front, y-left, z-up) - - # convert points to NED - points_ned = [] - for p in points_ecef: - points_ned.append(ned_converter.ecef2ned_matrix.dot(array(p) - car_ecef)) - - points_ned = np.vstack(points_ned).T - - # n, e, d -> x, y, z - # Calculate relative postions and rotate wrt to heading and pitch of car - invert_R = array([[1., 0., 0.], [0., -1., 0.], [0., 0., -1.]]) - - c, s = np.cos(psi), np.sin(psi) - yaw_R = array([[c, s, 0.], [-s, c, 0.], [0., 0., 1.]]) - - c, s = np.cos(theta), np.sin(theta) - pitch_R = array([[c, 0., -s], [0., 1., 0.], [s, 0., c]]) - - return dot(pitch_R, dot(yaw_R, dot(invert_R, points_ned))) diff --git a/common/transformations/setup.py b/common/transformations/setup.py new file mode 100644 index 0000000000..c239a97450 --- /dev/null +++ b/common/transformations/setup.py @@ -0,0 +1,42 @@ +import os +import numpy +import sysconfig + +from Cython.Build import cythonize +from Cython.Distutils import build_ext +from distutils.core import Extension, setup # pylint: disable=import-error,no-name-in-module + +def get_ext_filename_without_platform_suffix(filename): + name, ext = os.path.splitext(filename) + ext_suffix = sysconfig.get_config_var('EXT_SUFFIX') + + if ext_suffix == ext: + return filename + + ext_suffix = ext_suffix.replace(ext, '') + idx = name.find(ext_suffix) + + if idx == -1: + return filename + else: + return name[:idx] + ext + + +class BuildExtWithoutPlatformSuffix(build_ext): + def get_ext_filename(self, ext_name): + filename = super().get_ext_filename(ext_name) + return get_ext_filename_without_platform_suffix(filename) + + +setup( + name='Cython transformations wrapper', + cmdclass={'build_ext': BuildExtWithoutPlatformSuffix}, + ext_modules=cythonize( + Extension( + "transformations", + sources=["transformations.pyx"], + language="c++", + extra_compile_args=["-std=c++14"], + include_dirs=[numpy.get_include()], + ) +)) diff --git a/common/transformations/tests/test_coordinates.py b/common/transformations/tests/test_coordinates.py index 82fdc35fbe..dc70faed0b 100755 --- a/common/transformations/tests/test_coordinates.py +++ b/common/transformations/tests/test_coordinates.py @@ -11,12 +11,6 @@ geodetic_positions = np.array([[37.7610403, -122.4778699, 115], [15.1392514, 103.6976037, 24], [24.2302229, 44.2835412, 1650]]) -geodetic_positions_radians = np.array([[0.65905448, -2.13764209, 115], - [0.47968789, -1.19706477, 2380], - [0.5670869, -1.98361593, -6], - [0.26422978, 1.80986461, 24], - [0.42289717, 0.7728936, 1650]]) - ecef_positions = np.array([[-2711076.55270557, -4259167.14692758, 3884579.87669935], [ 2068042.69652729, -5273435.40316622, 2927004.89190746], [-2160412.60461669, -4932588.89873832, 3406542.29652851], @@ -50,7 +44,6 @@ ned_offsets_batch = np.array([[ 53.88103168, 43.83445935, -46.27488057], [ 78.56272609, 18.53100158, -43.25290759]]) - class TestNED(unittest.TestCase): def test_small_distances(self): start_geodetic = np.array([33.8042184, -117.888593, 0.0]) @@ -72,18 +65,13 @@ class TestNED(unittest.TestCase): def test_ecef_geodetic(self): # testing single np.testing.assert_allclose(ecef_positions[0], coord.geodetic2ecef(geodetic_positions[0]), rtol=1e-9) - np.testing.assert_allclose(geodetic_positions[0,:2], coord.ecef2geodetic(ecef_positions[0])[:2], rtol=1e-9) - np.testing.assert_allclose(geodetic_positions[0,2], coord.ecef2geodetic(ecef_positions[0])[2], rtol=1e-9, atol=1e-4) + np.testing.assert_allclose(geodetic_positions[0, :2], coord.ecef2geodetic(ecef_positions[0])[:2], rtol=1e-9) + np.testing.assert_allclose(geodetic_positions[0, 2], coord.ecef2geodetic(ecef_positions[0])[2], rtol=1e-9, atol=1e-4) - np.testing.assert_allclose(geodetic_positions[:,:2], coord.ecef2geodetic(ecef_positions)[:,:2], rtol=1e-9) - np.testing.assert_allclose(geodetic_positions[:,2], coord.ecef2geodetic(ecef_positions)[:,2], rtol=1e-9, atol=1e-4) + np.testing.assert_allclose(geodetic_positions[:, :2], coord.ecef2geodetic(ecef_positions)[:, :2], rtol=1e-9) + np.testing.assert_allclose(geodetic_positions[:, 2], coord.ecef2geodetic(ecef_positions)[:, 2], rtol=1e-9, atol=1e-4) np.testing.assert_allclose(ecef_positions, coord.geodetic2ecef(geodetic_positions), rtol=1e-9) - np.testing.assert_allclose(geodetic_positions_radians[0], coord.ecef2geodetic(ecef_positions[0], radians=True), rtol=1e-5) - np.testing.assert_allclose(geodetic_positions_radians[:,:2], coord.ecef2geodetic(ecef_positions, radians=True)[:,:2], rtol=1e-7) - np.testing.assert_allclose(geodetic_positions_radians[:,2], coord.ecef2geodetic(ecef_positions, radians=True)[:,2], rtol=1e-7, atol=1e-4) - - def test_ned(self): for ecef_pos in ecef_positions: @@ -95,11 +83,10 @@ class TestNED(unittest.TestCase): for geo_pos in geodetic_positions: converter = coord.LocalCoord.from_geodetic(geo_pos) geo_pos_moved = geo_pos + np.array([0, 0, 10]) - geo_pos_double_converted_moved = converter.ned2geodetic(converter.geodetic2ned(geo_pos) + np.array([0,0,-10])) + geo_pos_double_converted_moved = converter.ned2geodetic(converter.geodetic2ned(geo_pos) + np.array([0, 0, -10])) np.testing.assert_allclose(geo_pos_moved[:2], geo_pos_double_converted_moved[:2], rtol=1e-9, atol=1e-6) np.testing.assert_allclose(geo_pos_moved[2], geo_pos_double_converted_moved[2], rtol=1e-9, atol=1e-4) - def test_ned_saved_results(self): for i, ecef_pos in enumerate(ecef_positions): converter = coord.LocalCoord.from_ecef(ecef_pos) diff --git a/common/transformations/tests/test_orientation.py b/common/transformations/tests/test_orientation.py index 1e85c81a0a..50978e1a63 100755 --- a/common/transformations/tests/test_orientation.py +++ b/common/transformations/tests/test_orientation.py @@ -61,8 +61,7 @@ class TestOrientation(unittest.TestCase): for i in range(len(eulers)): np.testing.assert_allclose(ned_eulers[i], ned_euler_from_ecef(ecef_positions[i], eulers[i]), rtol=1e-7) #np.testing.assert_allclose(eulers[i], ecef_euler_from_ned(ecef_positions[i], ned_eulers[i]), rtol=1e-7) - np.testing.assert_allclose(ned_eulers, ned_euler_from_ecef(ecef_positions, eulers), rtol=1e-7) - + # np.testing.assert_allclose(ned_eulers, ned_euler_from_ecef(ecef_positions, eulers), rtol=1e-7) if __name__ == "__main__": diff --git a/common/transformations/transformations.pxd b/common/transformations/transformations.pxd new file mode 100644 index 0000000000..cb3ee53b19 --- /dev/null +++ b/common/transformations/transformations.pxd @@ -0,0 +1,71 @@ +from libcpp cimport bool + +cdef extern from "orientation.cc": + pass + +cdef extern from "orientation.hpp": + cdef cppclass Quaternion "Eigen::Quaterniond": + Quaternion() + Quaternion(double, double, double, double) + double w() + double x() + double y() + double z() + + cdef cppclass Vector3 "Eigen::Vector3d": + Vector3() + Vector3(double, double, double) + double operator()(int) + + cdef cppclass Matrix3 "Eigen::Matrix3d": + Matrix3() + Matrix3(double*) + + double operator()(int, int) + + Quaternion euler2quat(Vector3) + Vector3 quat2euler(Quaternion) + Matrix3 quat2rot(Quaternion) + Quaternion rot2quat(Matrix3) + Vector3 rot2euler(Matrix3) + Matrix3 euler2rot(Vector3) + Matrix3 rot_matrix(double, double, double) + Vector3 ecef_euler_from_ned(ECEF, Vector3) + Vector3 ned_euler_from_ecef(ECEF, Vector3) + + +cdef extern from "coordinates.cc": + cdef struct ECEF: + double x + double y + double z + + cdef struct NED: + double n + double e + double d + + cdef struct Geodetic: + double lat + double lon + double alt + bool radians + + ECEF geodetic2ecef(Geodetic) + Geodetic ecef2geodetic(ECEF) + + cdef cppclass LocalCoord_c "LocalCoord": + Matrix3 ned2ecef_matrix + Matrix3 ecef2ned_matrix + + LocalCoord_c(Geodetic, ECEF) + LocalCoord_c(Geodetic) + LocalCoord_c(ECEF) + + NED ecef2ned(ECEF) + ECEF ned2ecef(NED) + NED geodetic2ned(Geodetic) + Geodetic ned2geodetic(NED) + +cdef extern from "coordinates.hpp": + pass diff --git a/common/transformations/transformations.pyx b/common/transformations/transformations.pyx new file mode 100644 index 0000000000..194257e037 --- /dev/null +++ b/common/transformations/transformations.pyx @@ -0,0 +1,172 @@ +from transformations cimport Matrix3, Vector3, Quaternion +from transformations cimport ECEF, NED, Geodetic + +from transformations cimport euler2quat as euler2quat_c +from transformations cimport quat2euler as quat2euler_c +from transformations cimport quat2rot as quat2rot_c +from transformations cimport rot2quat as rot2quat_c +from transformations cimport euler2rot as euler2rot_c +from transformations cimport rot2euler as rot2euler_c +from transformations cimport rot_matrix as rot_matrix_c +from transformations cimport ecef_euler_from_ned as ecef_euler_from_ned_c +from transformations cimport ned_euler_from_ecef as ned_euler_from_ecef_c +from transformations cimport geodetic2ecef as geodetic2ecef_c +from transformations cimport ecef2geodetic as ecef2geodetic_c +from transformations cimport LocalCoord_c + + +import cython +import numpy as np +cimport numpy as np + +cdef np.ndarray[double, ndim=2] matrix2numpy(Matrix3 m): + return np.array([ + [m(0, 0), m(0, 1), m(0, 2)], + [m(1, 0), m(1, 1), m(1, 2)], + [m(2, 0), m(2, 1), m(2, 2)], + ]) + +cdef Matrix3 numpy2matrix (np.ndarray[double, ndim=2, mode="fortran"] m): + assert m.shape[0] == 3 + assert m.shape[1] == 3 + return Matrix3(m.data) + +cdef ECEF list2ecef(ecef): + cdef ECEF e; + e.x = ecef[0] + e.y = ecef[1] + e.z = ecef[2] + return e + +cdef NED list2ned(ned): + cdef NED n; + n.n = ned[0] + n.e = ned[1] + n.d = ned[2] + return n + +cdef Geodetic list2geodetic(geodetic): + cdef Geodetic g + g.lat = geodetic[0] + g.lon = geodetic[1] + g.alt = geodetic[2] + return g + +def euler2quat_single(euler): + cdef Vector3 e = Vector3(euler[0], euler[1], euler[2]) + cdef Quaternion q = euler2quat_c(e) + return [q.w(), q.x(), q.y(), q.z()] + +def quat2euler_single(quat): + cdef Quaternion q = Quaternion(quat[0], quat[1], quat[2], quat[3]) + cdef Vector3 e = quat2euler_c(q); + return [e(0), e(1), e(2)] + +def quat2rot_single(quat): + cdef Quaternion q = Quaternion(quat[0], quat[1], quat[2], quat[3]) + cdef Matrix3 r = quat2rot_c(q) + return matrix2numpy(r) + +def rot2quat_single(rot): + cdef Matrix3 r = numpy2matrix(np.asfortranarray(rot, dtype=np.double)) + cdef Quaternion q = rot2quat_c(r) + return [q.w(), q.x(), q.y(), q.z()] + +def euler2rot_single(euler): + cdef Vector3 e = Vector3(euler[0], euler[1], euler[2]) + cdef Matrix3 r = euler2rot_c(e) + return matrix2numpy(r) + +def rot2euler_single(rot): + cdef Matrix3 r = numpy2matrix(np.asfortranarray(rot, dtype=np.double)) + cdef Vector3 e = rot2euler_c(r) + return [e(0), e(1), e(2)] + +def rot_matrix(roll, pitch, yaw): + return matrix2numpy(rot_matrix_c(roll, pitch, yaw)) + +def ecef_euler_from_ned_single(ecef_init, ned_pose): + cdef ECEF init = list2ecef(ecef_init) + cdef Vector3 pose = Vector3(ned_pose[0], ned_pose[1], ned_pose[2]) + + cdef Vector3 e = ecef_euler_from_ned_c(init, pose) + return [e(0), e(1), e(2)] + +def ned_euler_from_ecef_single(ecef_init, ecef_pose): + cdef ECEF init = list2ecef(ecef_init) + cdef Vector3 pose = Vector3(ecef_pose[0], ecef_pose[1], ecef_pose[2]) + + cdef Vector3 e = ned_euler_from_ecef_c(init, pose) + return [e(0), e(1), e(2)] + +def geodetic2ecef_single(geodetic): + cdef Geodetic g = list2geodetic(geodetic) + cdef ECEF e = geodetic2ecef_c(g) + return [e.x, e.y, e.z] + +def ecef2geodetic_single(ecef): + cdef ECEF e = list2ecef(ecef) + cdef Geodetic g = ecef2geodetic_c(e) + return [g.lat, g.lon, g.alt] + + +cdef class LocalCoord: + cdef LocalCoord_c * lc + + def __init__(self, geodetic=None, ecef=None): + assert (geodetic is not None) or (ecef is not None) + if geodetic is not None: + self.lc = new LocalCoord_c(list2geodetic(geodetic)) + elif ecef is not None: + self.lc = new LocalCoord_c(list2ecef(ecef)) + + @property + def ned2ecef_matrix(self): + return matrix2numpy(self.lc.ned2ecef_matrix) + + @property + def ecef2ned_matrix(self): + return matrix2numpy(self.lc.ecef2ned_matrix) + + @property + def ned_from_ecef_matrix(self): + return self.ecef2ned_matrix + + @property + def ecef_from_ned_matrix(self): + return self.ned2ecef_matrix + + @classmethod + def from_geodetic(cls, geodetic): + return cls(geodetic=geodetic) + + @classmethod + def from_ecef(cls, ecef): + return cls(ecef=ecef) + + def ecef2ned_single(self, ecef): + assert self.lc + cdef ECEF e = list2ecef(ecef) + cdef NED n = self.lc.ecef2ned(e) + return [n.n, n.e, n.d] + + def ned2ecef_single(self, ned): + assert self.lc + cdef NED n = list2ned(ned) + cdef ECEF e = self.lc.ned2ecef(n) + return [e.x, e.y, e.z] + + def geodetic2ned_single(self, geodetic): + assert self.lc + cdef Geodetic g = list2geodetic(geodetic) + cdef NED n = self.lc.geodetic2ned(g) + return [n.n, n.e, n.d] + + def ned2geodetic_single(self, ned): + assert self.lc + cdef NED n = list2ned(ned) + cdef Geodetic g = self.lc.ned2geodetic(n) + return [g.lat, g.lon, g.alt] + + def __dealloc__(self): + del self.lc diff --git a/common/window.py b/common/window.py index f93f532cb4..62f8cb9e0b 100644 --- a/common/window.py +++ b/common/window.py @@ -1,35 +1,35 @@ import sys -import pygame +import pygame # pylint: disable=import-error +import cv2 # pylint: disable=import-error class Window(): def __init__(self, w, h, caption="window", double=False): self.w = w self.h = h - pygame.init() + pygame.display.init() pygame.display.set_caption(caption) self.double = double if self.double: - self.screen = pygame.display.set_mode((w*2,h*2), pygame.DOUBLEBUF) + self.screen = pygame.display.set_mode((w*2, h*2)) else: - self.screen = pygame.display.set_mode((w,h), pygame.DOUBLEBUF) - self.camera_surface = pygame.surface.Surface((w,h), 0, 24).convert() + self.screen = pygame.display.set_mode((w, h)) def draw(self, out): - pygame.surfarray.blit_array(self.camera_surface, out.swapaxes(0,1)) + pygame.event.pump() if self.double: - camera_surface_2x = pygame.transform.scale2x(self.camera_surface) - self.screen.blit(camera_surface_2x, (0, 0)) + out2 = cv2.resize(out, (self.w*2, self.h*2)) + pygame.surfarray.blit_array(self.screen, out2.swapaxes(0, 1)) else: - self.screen.blit(self.camera_surface, (0, 0)) + pygame.surfarray.blit_array(self.screen, out.swapaxes(0, 1)) pygame.display.flip() - + def getkey(self): while 1: event = pygame.event.wait() - if event.type == QUIT: + if event.type == pygame.QUIT: pygame.quit() sys.exit() - if event.type == KEYDOWN: + if event.type == pygame.KEYDOWN: return event.key def getclick(self): @@ -40,10 +40,9 @@ class Window(): if __name__ == "__main__": import numpy as np - win = Window(200, 200) - img = np.zeros((200,200,3), np.uint8) + win = Window(200, 200, double=True) + img = np.zeros((200, 200, 3), np.uint8) while 1: print("draw") img += 1 win.draw(img) - diff --git a/external/bin/capnpc-java b/external/bin/capnpc-java new file mode 100755 index 0000000000..55af5b5763 Binary files /dev/null and b/external/bin/capnpc-java differ diff --git a/external/opencl/intel-opencl-devel_0r3.1-58621_amd64.deb b/external/opencl/intel-opencl-devel_0r3.1-58621_amd64.deb deleted file mode 100644 index 52cd5b3a72..0000000000 --- a/external/opencl/intel-opencl-devel_0r3.1-58621_amd64.deb +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e3c75edadf2e267be8a18870cafc911ea23d3b52dcff07fbe025edf815c06f5d -size 68732 diff --git a/external/opencl/intel.icd b/external/opencl/intel.icd deleted file mode 100644 index b31f24d7bc..0000000000 --- a/external/opencl/intel.icd +++ /dev/null @@ -1 +0,0 @@ -/opt/intel/opencl-1.2-6.4.0.37/lib64/libintelocl.so diff --git a/external/opencl/opencl-1.2-base-pset_6.4.0.37-2_all.deb b/external/opencl/opencl-1.2-base-pset_6.4.0.37-2_all.deb deleted file mode 100644 index a3c7fba5f4..0000000000 --- a/external/opencl/opencl-1.2-base-pset_6.4.0.37-2_all.deb +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:381814ea42344b895624597bf31c24ebc13f3449aaaaf65245f4a041d953b4c6 -size 17276236 diff --git a/external/opencl/opencl-1.2-base_6.4.0.37-2_amd64.deb b/external/opencl/opencl-1.2-base_6.4.0.37-2_amd64.deb deleted file mode 100644 index feff0b9705..0000000000 --- a/external/opencl/opencl-1.2-base_6.4.0.37-2_amd64.deb +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:25aaa33f5c338b6dcc33436fdebb5e6ad727cf85a9fae921be8d3b834166ab01 -size 11432 diff --git a/external/opencl/opencl-1.2-intel-cpu_6.4.0.37-2_amd64.deb b/external/opencl/opencl-1.2-intel-cpu_6.4.0.37-2_amd64.deb deleted file mode 100644 index dd17f9b0b6..0000000000 --- a/external/opencl/opencl-1.2-intel-cpu_6.4.0.37-2_amd64.deb +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f7300ebee63820b519c54a50c93847516dcaf37765a698826fde666990747459 -size 20290860 diff --git a/external/simpleperf/utils.py b/external/simpleperf/utils.py index 843e61212d..4077039846 100644 --- a/external/simpleperf/utils.py +++ b/external/simpleperf/utils.py @@ -101,7 +101,7 @@ def get_host_binary_path(binary_name): elif '.' not in binary_name: binary_name += '.exe' dir = os.path.join(dir, 'windows') - elif sys.platform == 'darwin': # OSX + elif sys.platform == 'darwin': # OSX if binary_name.endswith('.so'): binary_name = binary_name[0:-3] + '.dylib' dir = os.path.join(dir, 'darwin') @@ -220,11 +220,9 @@ class AdbHelper(object): self.adb_path = adb_path self.enable_switch_to_root = enable_switch_to_root - def run(self, adb_args): return self.run_and_return_output(adb_args)[0] - def run_and_return_output(self, adb_args, stdout_file=None, log_output=True): adb_args = [self.adb_path] + adb_args log_debug('run adb cmd: %s' % adb_args) @@ -247,14 +245,12 @@ class AdbHelper(object): def check_run(self, adb_args): self.check_run_and_return_output(adb_args) - def check_run_and_return_output(self, adb_args, stdout_file=None, log_output=True): result, stdoutdata = self.run_and_return_output(adb_args, stdout_file, log_output) if not result: log_exit('run "adb %s" failed' % adb_args) return stdoutdata - def _unroot(self): result, stdoutdata = self.run_and_return_output(['shell', 'whoami']) if not result: @@ -266,7 +262,6 @@ class AdbHelper(object): self.run(['wait-for-device']) time.sleep(1) - def switch_to_root(self): if not self.enable_switch_to_root: self._unroot() @@ -292,7 +287,6 @@ class AdbHelper(object): def set_property(self, name, value): return self.run(['shell', 'setprop', name, value]) - def get_device_arch(self): output = self.check_run_and_return_output(['shell', 'uname', '-m']) if 'aarch64' in output: @@ -305,7 +299,6 @@ class AdbHelper(object): return 'x86' log_fatal('unsupported architecture: %s' % output.strip()) - def get_android_version(self): build_version = self.get_property('ro.build.version.release') android_version = 0 diff --git a/flake8_openpilot.sh b/flake8_openpilot.sh deleted file mode 100755 index a2d99655cf..0000000000 --- a/flake8_openpilot.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -# only pyflakes check (--select=F) -RESULT=$(python3 -m flake8 --select=F $(eval echo $(cat <(find cereal) <(find opendbc) release/files_common release/files_common | tr '\n' ' ') | tr ' ' '\n' | 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/installer/updater/test_updater.py b/installer/updater/test_updater.py new file mode 100755 index 0000000000..6e811921de --- /dev/null +++ b/installer/updater/test_updater.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +import os +import shutil +import subprocess +import tempfile +import time +import unittest + +from common.basedir import BASEDIR + +UPDATER_PATH = os.path.join(BASEDIR, "installer/updater") +UPDATER = os.path.join(UPDATER_PATH, "updater") +UPDATE_MANIFEST = os.path.join(UPDATER_PATH, "update.json") + + +class TestUpdater(unittest.TestCase): + + @classmethod + def setUpClass(cls): + # test that the updater builds + cls.assertTrue(f"cd {UPDATER_PATH} && make clean && make", "updater failed to build") + + # restore the checked-in version, since that's what actually runs on devices + os.system(f"git reset --hard {UPDATER_PATH}") + + def setUp(self): + self._clear_dir() + + def tearDown(self): + self._clear_dir() + + def _clear_dir(self): + if os.path.isdir("/data/neoupdate"): + shutil.rmtree("/data/neoupdate") + + def _assert_ok(self, cmd, msg=None): + self.assertTrue(os.system(cmd) == 0, msg) + + def _assert_fails(self, cmd): + self.assertFalse(os.system(cmd) == 0) + + def test_background_download(self): + self._assert_ok(f"{UPDATER} bgcache 'file://{UPDATE_MANIFEST}'") + + def test_background_download_bad_manifest(self): + # update with bad manifest should fail + with tempfile.NamedTemporaryFile(mode="w", suffix=".json") as f: + f.write("{}") + self._assert_fails(f"{UPDATER} bgcache 'file://{f.name}'") + + def test_cache_resume(self): + self._assert_ok(f"{UPDATER} bgcache 'file://{UPDATE_MANIFEST}'") + # a full download takes >1m, but resuming from fully cached should only be a few seconds + start_time = time.monotonic() + self._assert_ok(f"{UPDATER} bgcache 'file://{UPDATE_MANIFEST}'") + self.assertLess(time.monotonic() - start_time, 10) + + # make sure we can recover from corrupt downloads + def test_recover_from_corrupt(self): + # download the whole update + self._assert_ok(f"{UPDATER} bgcache 'file://{UPDATE_MANIFEST}'") + + # write some random bytes + for f in os.listdir("/data/neoupdate"): + with open(os.path.join("/data/neoupdate", f), "ab") as f: + f.write(b"\xab"*20) + + # this attempt should fail, then it unlinks + self._assert_fails(f"{UPDATER} bgcache 'file://{UPDATE_MANIFEST}'") + + # now it should pass + self._assert_ok(f"{UPDATER} bgcache 'file://{UPDATE_MANIFEST}'") + + # simple test that the updater doesn't crash in UI mode + def test_ui_init(self): + with subprocess.Popen(UPDATER) as proc: + time.sleep(5) + self.assertTrue(proc.poll() is None) + proc.terminate() + +if __name__ == "__main__": + unittest.main() diff --git a/installer/updater/update_kernel.json b/installer/updater/update_kernel.json new file mode 100644 index 0000000000..41dc595b00 --- /dev/null +++ b/installer/updater/update_kernel.json @@ -0,0 +1,7 @@ +{ + "ota_url": "https://commadist.azureedge.net/neosupdate/ota-signed-3bd2b3bdd6a501569e00b8f12786d65e0fd2788c0dd238f8c986e3e2e504683a-kernel.zip", + "ota_hash": "3bd2b3bdd6a501569e00b8f12786d65e0fd2788c0dd238f8c986e3e2e504683a", + "recovery_url": "https://commadist.azureedge.net/neosupdate/recovery-97c27e6ed04ed6bb0608b845a2d4100912093f9380c3f2ba6b56bccd608e5f6e.img", + "recovery_len": 15861036, + "recovery_hash": "97c27e6ed04ed6bb0608b845a2d4100912093f9380c3f2ba6b56bccd608e5f6e" +} diff --git a/installer/updater/updater b/installer/updater/updater index 15858eabb4..66047420c1 100755 Binary files a/installer/updater/updater and b/installer/updater/updater differ diff --git a/installer/updater/updater.cc b/installer/updater/updater.cc index a76be8b8fd..ca0b9270b8 100644 --- a/installer/updater/updater.cc +++ b/installer/updater/updater.cc @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -33,10 +34,10 @@ #define USER_AGENT "NEOSUpdater-0.2" -#define MANIFEST_URL_EON_STAGING "https://github.com/commaai/eon-neos/raw/master/update.staging.json" -#define MANIFEST_URL_EON_LOCAL "http://192.168.5.1:8000/neosupdate/update.local.json" -#define MANIFEST_URL_EON "https://github.com/commaai/eon-neos/raw/master/update.json" -const char *manifest_url = MANIFEST_URL_EON; +#define MANIFEST_URL_NEOS_STAGING "https://github.com/commaai/eon-neos/raw/master/update.staging.json" +#define MANIFEST_URL_NEOS_LOCAL "http://192.168.5.1:8000/neosupdate/update.local.json" +#define MANIFEST_URL_NEOS "https://github.com/commaai/eon-neos/raw/master/update.json" +const char *manifest_url = MANIFEST_URL_NEOS; #define RECOVERY_DEV "/dev/block/bootdevice/by-name/recovery" #define RECOVERY_COMMAND "/cache/recovery/command" @@ -96,7 +97,7 @@ std::string download_string(CURL *curl, std::string url) { curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); - curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 0); curl_easy_setopt(curl, CURLOPT_USERAGENT, USER_AGENT); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); curl_easy_setopt(curl, CURLOPT_RESUME_FROM, 0); @@ -149,6 +150,32 @@ static void start_settings_activity(const char* name) { system(launch_cmd); } +bool is_settings_active() { + FILE *fp; + char sys_output[4096]; + + fp = popen("/bin/dumpsys window windows", "r"); + if (fp == NULL) { + return false; + } + + bool active = false; + while (fgets(sys_output, sizeof(sys_output), fp) != NULL) { + if (strstr(sys_output, "mCurrentFocus=null") != NULL) { + break; + } + + if (strstr(sys_output, "mCurrentFocus=Window") != NULL) { + active = true; + break; + } + } + + pclose(fp); + + return active; +} + struct Updater { bool do_exit = false; @@ -166,7 +193,6 @@ struct Updater { std::mutex lock; - // i hate state machines give me coroutines already enum UpdateState { CONFIRMATION, LOW_BATTERY, @@ -190,9 +216,15 @@ struct Updater { int b_x, b_w, b_y, b_h; int balt_x; + // download stage writes these for the installation stage + int recovery_len; + std::string recovery_hash; + std::string recovery_fn; + std::string ota_fn; + CURL *curl = NULL; - Updater() { + void ui_init() { touch_init(&touch); fb = framebuffer_init("updater", 0x00001000, false, @@ -218,7 +250,6 @@ struct Updater { b_h = 220; state = CONFIRMATION; - } int download_file_xferinfo(curl_off_t dltotal, curl_off_t dlno, @@ -251,7 +282,7 @@ struct Updater { curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); - curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 0); curl_easy_setopt(curl, CURLOPT_USERAGENT, USER_AGENT); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); curl_easy_setopt(curl, CURLOPT_RESUME_FROM, resume_from); @@ -319,92 +350,78 @@ struct Updater { state = RUNNING; } - std::string stage_download(std::string url, std::string hash, std::string name) { + std::string download(std::string url, std::string hash, std::string name) { std::string out_fn = UPDATE_DIR "/" + util::base_name(url); - set_progress("Downloading " + name + "..."); - bool r = download_file(url, out_fn); - if (!r) { - set_error("failed to download " + name); - return ""; + // start or resume downloading if hash doesn't match + std::string fn_hash = sha256_file(out_fn); + if (hash.compare(fn_hash) != 0) { + set_progress("Downloading " + name + "..."); + bool r = download_file(url, out_fn); + if (!r) { + set_error("failed to download " + name); + unlink(out_fn.c_str()); + return ""; + } + fn_hash = sha256_file(out_fn); } set_progress("Verifying " + name + "..."); - std::string fn_hash = sha256_file(out_fn); printf("got %s hash: %s\n", name.c_str(), hash.c_str()); if (fn_hash != hash) { set_error(name + " was corrupt"); unlink(out_fn.c_str()); return ""; } - return out_fn; } - void run_stages() { + bool download_stage() { curl = curl_easy_init(); assert(curl); - if (!check_battery()) { - set_battery_low(); - int battery_cap = battery_capacity(); - while(battery_cap < min_battery_cap) { - battery_cap = battery_capacity(); - battery_cap_text = std::to_string(battery_cap); - usleep(1000000); - } - set_running(); - } + // ** quick checks before download ** if (!check_space()) { set_error("2GB of free space required to update"); - return; + return false; } mkdir(UPDATE_DIR, 0777); - const int EON = (access("/EON", F_OK) != -1); - set_progress("Finding latest version..."); - std::string manifest_s; - if (EON) { - manifest_s = download_string(curl, manifest_url); - } else { - // don't update NEO - exit(0); - } - + std::string manifest_s = download_string(curl, manifest_url); printf("manifest: %s\n", manifest_s.c_str()); std::string err; auto manifest = json11::Json::parse(manifest_s, err); if (manifest.is_null() || !err.empty()) { set_error("failed to load update manifest"); - return; + return false; } std::string ota_url = manifest["ota_url"].string_value(); std::string ota_hash = manifest["ota_hash"].string_value(); std::string recovery_url = manifest["recovery_url"].string_value(); - std::string recovery_hash = manifest["recovery_hash"].string_value(); - int recovery_len = manifest["recovery_len"].int_value(); + recovery_hash = manifest["recovery_hash"].string_value(); + recovery_len = manifest["recovery_len"].int_value(); // std::string installer_url = manifest["installer_url"].string_value(); // std::string installer_hash = manifest["installer_hash"].string_value(); if (ota_url.empty() || ota_hash.empty()) { set_error("invalid update manifest"); - return; + return false; } - // std::string installer_fn = stage_download(installer_url, installer_hash, "installer"); + // std::string installer_fn = download(installer_url, installer_hash, "installer"); // if (installer_fn.empty()) { // //error'd // return; // } - std::string recovery_fn; + // ** handle recovery download ** if (recovery_url.empty() || recovery_hash.empty() || recovery_len == 0) { set_progress("Skipping recovery flash..."); } else { @@ -414,20 +431,50 @@ struct Updater { printf("existing recovery hash: %s\n", existing_recovery_hash.c_str()); if (existing_recovery_hash != recovery_hash) { - recovery_fn = stage_download(recovery_url, recovery_hash, "recovery"); + recovery_fn = download(recovery_url, recovery_hash, "recovery"); if (recovery_fn.empty()) { // error'd - return; + return false; } } } - std::string ota_fn = stage_download(ota_url, ota_hash, "update"); + // ** handle ota download ** + ota_fn = download(ota_url, ota_hash, "update"); if (ota_fn.empty()) { //error'd + return false; + } + + // download sucessful + return true; + } + + // thread that handles downloading and installing the update + void run_stages() { + printf("run_stages start\n"); + + + // ** download update ** + + if (!check_battery()) { + set_battery_low(); + int battery_cap = battery_capacity(); + while(battery_cap < min_battery_cap) { + battery_cap = battery_capacity(); + battery_cap_text = std::to_string(battery_cap); + usleep(1000000); + } + set_running(); + } + + bool sucess = download_stage(); + if (!sucess) { return; } + // ** install update ** + if (!check_battery()) { set_battery_low(); int battery_cap = battery_capacity(); @@ -601,7 +648,7 @@ struct Updater { int powerprompt_y = 312; nvgFontFace(vg, "opensans_regular"); nvgFontSize(vg, 64.0f); - nvgText(vg, fb_w/2, 740, "Ensure EON is connected to power.", NULL); + nvgText(vg, fb_w/2, 740, "Ensure your device remains connected to a power source.", NULL); NVGpaint paint = nvgBoxGradient( vg, progress_x + 1, progress_y + 1, @@ -657,9 +704,7 @@ struct Updater { void ui_update() { std::lock_guard guard(lock); - switch (state) { - case ERROR: - case CONFIRMATION: { + if (state == ERROR || state == CONFIRMATION) { int touch_x = -1, touch_y = -1; int res = touch_poll(&touch, &touch_x, &touch_y, 0); if (res == 1 && !is_settings_active()) { @@ -678,13 +723,11 @@ struct Updater { } } } - default: - break; - } } - void go() { + ui_init(); + while (!do_exit) { ui_update(); @@ -718,51 +761,37 @@ struct Updater { update_thread_handle.join(); } + // reboot system("service call power 16 i32 0 i32 0 i32 1"); } - bool is_settings_active() { - FILE *fp; - char sys_output[4096]; - - fp = popen("/bin/dumpsys window windows", "r"); - if (fp == NULL) { - return false; - } - - bool active = false; - while (fgets(sys_output, sizeof(sys_output), fp) != NULL) { - if (strstr(sys_output, "mCurrentFocus=null") != NULL) { - break; - } - - if (strstr(sys_output, "mCurrentFocus=Window") != NULL) { - active = true; - break; - } - } - - pclose(fp); - - return active; - } - }; } + int main(int argc, char *argv[]) { + bool background_cache = false; if (argc > 1) { if (strcmp(argv[1], "local") == 0) { - manifest_url = MANIFEST_URL_EON_LOCAL; + manifest_url = MANIFEST_URL_NEOS_LOCAL; } else if (strcmp(argv[1], "staging") == 0) { - manifest_url = MANIFEST_URL_EON_STAGING; + manifest_url = MANIFEST_URL_NEOS_STAGING; + } else if (strcmp(argv[1], "bgcache") == 0) { + manifest_url = argv[2]; + background_cache = true; } else { manifest_url = argv[1]; } } + printf("updating from %s\n", manifest_url); Updater updater; - updater.go(); - return 0; + int err = 0; + if (background_cache) { + err = !updater.download_stage(); + } else { + updater.go(); + } + return err; } diff --git a/laika_repo b/laika_repo index d172b27f4f..765c6584c3 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit d172b27f4f346e642802a4c7cbf14405a4161d35 +Subproject commit 765c6584c3d7f27e1af0f1180cc29766d5319f09 diff --git a/launch_chffrplus.sh b/launch_chffrplus.sh index f88f6fb7d1..af5483562d 100755 --- a/launch_chffrplus.sh +++ b/launch_chffrplus.sh @@ -1,25 +1,20 @@ #!/usr/bin/bash -export OMP_NUM_THREADS=1 -export MKL_NUM_THREADS=1 -export NUMEXPR_NUM_THREADS=1 -export OPENBLAS_NUM_THREADS=1 -export VECLIB_MAXIMUM_THREADS=1 - if [ -z "$BASEDIR" ]; then BASEDIR="/data/openpilot" fi -if [ -z "$PASSIVE" ]; then - export PASSIVE="1" -fi +source "$BASEDIR/launch_env.sh" -STAGING_ROOT="/data/safe_staging" +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" function launch { # Wifi scan wpa_cli IFNAME=wlan0 SCAN + # Remove orphaned git lock if it exists on boot + [ -f "$DIR/.git/index.lock" ] && rm -f $DIR/.git/index.lock + # Check to see if there's a valid overlay-based update available. Conditions # are as follows: # @@ -41,11 +36,15 @@ function launch { mv $BASEDIR /data/safe_staging/old_openpilot mv "${STAGING_ROOT}/finalized" $BASEDIR + cd $BASEDIR - # The mv changed our working directory to /data/safe_staging/old_openpilot - cd "${BASEDIR}" + # Partial mitigation for symlink-related filesystem corruption + # Ensure all files match the repo versions after update + git reset --hard + git submodule foreach --recursive git reset --hard echo "Restarting launch script ${LAUNCHER_LOCATION}" + unset REQUIRED_NEOS_VERSION exec "${LAUNCHER_LOCATION}" else echo "openpilot backup found, not updating" @@ -55,36 +54,57 @@ function launch { fi fi - # no cpu rationing for now - echo 0-3 > /dev/cpuset/background/cpus - echo 0-3 > /dev/cpuset/system-background/cpus - echo 0-3 > /dev/cpuset/foreground/boost/cpus - echo 0-3 > /dev/cpuset/foreground/cpus - echo 0-3 > /dev/cpuset/android/cpus - - # change interrupt affinity - echo 3 > /proc/irq/6/smp_affinity_list # MDSS - echo 1 > /proc/irq/78/smp_affinity_list # Modem, can potentially lock up - echo 2 > /proc/irq/733/smp_affinity_list # USB - echo 2 > /proc/irq/736/smp_affinity_list # USB - - DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" - - # Remove old NEOS update file - # TODO: move this code to the updater - if [ -d /data/neoupdate ]; then - rm -rf /data/neoupdate - fi + # Android and other system processes are not permitted to run on CPU 3 + # NEOS installed app processes can run anywhere + echo 0-2 > /dev/cpuset/background/cpus + echo 0-2 > /dev/cpuset/system-background/cpus + [ -d "/dev/cpuset/foreground/boost/cpus" ] && echo 0-2 > /dev/cpuset/foreground/boost/cpus # Not present in < NEOS 15 + echo 0-2 > /dev/cpuset/foreground/cpus + echo 0-2 > /dev/cpuset/android/cpus + echo 0-3 > /dev/cpuset/app/cpus + + # Collect RIL and other possibly long-running I/O interrupts onto CPU 1 + echo 1 > /proc/irq/78/smp_affinity_list # qcom,smd-modem (LTE radio) + echo 1 > /proc/irq/33/smp_affinity_list # ufshcd (flash storage) + echo 1 > /proc/irq/35/smp_affinity_list # wifi (wlan_pci) + # USB traffic needs realtime handling on cpu 3 + [ -d "/proc/irq/733" ] && echo 3 > /proc/irq/733/smp_affinity_list # USB for LeEco + [ -d "/proc/irq/736" ] && echo 3 > /proc/irq/736/smp_affinity_list # USB for OP3T + # Check for NEOS update - if [ $(< /VERSION) != "14" ]; then + if [ $(< /VERSION) != "$REQUIRED_NEOS_VERSION" ]; then if [ -f "$DIR/scripts/continue.sh" ]; then cp "$DIR/scripts/continue.sh" "/data/data/com.termux/files/continue.sh" fi + if [ ! -f "$BASEDIR/prebuilt" ]; then + # Clean old build products, but preserve the scons cache + cd $DIR + scons --clean + git clean -xdf + git submodule foreach --recursive git clean -xdf + fi + "$DIR/installer/updater/updater" "file://$DIR/installer/updater/update.json" + else + if [[ $(uname -v) == "#1 SMP PREEMPT Wed Jun 10 12:40:53 PDT 2020" ]]; then + "$DIR/installer/updater/updater" "file://$DIR/installer/updater/update_kernel.json" + fi fi + # One-time fix for a subset of OP3T with gyro orientation offsets. + # Remove and regenerate qcom sensor registry. Only done on OP3T mainboards. + # Performed exactly once. The old registry is preserved just-in-case, and + # doubles as a flag denoting we've already done the reset. + # TODO: we should really grow per-platform detect and setup routines + if ! $(grep -q "letv" /proc/cmdline) && [ ! -f "/persist/comma/op3t-sns-reg-backup" ]; then + echo "Performing OP3T sensor registry reset" + mv /persist/sensors/sns.reg /persist/comma/op3t-sns-reg-backup && + rm -f /persist/sensors/sensors_settings /persist/sensors/error_log /persist/sensors/gyro_sensitity_cal && + echo "restart" > /sys/kernel/debug/msm_subsys/slpi && + sleep 5 # Give Android sensor subsystem a moment to recover + fi # handle pythonpath ln -sfn $(pwd) /data/pythonpath diff --git a/launch_env.sh b/launch_env.sh new file mode 100755 index 0000000000..9a86d315ce --- /dev/null +++ b/launch_env.sh @@ -0,0 +1,17 @@ +#!/usr/bin/bash + +export OMP_NUM_THREADS=1 +export MKL_NUM_THREADS=1 +export NUMEXPR_NUM_THREADS=1 +export OPENBLAS_NUM_THREADS=1 +export VECLIB_MAXIMUM_THREADS=1 + +if [ -z "$REQUIRED_NEOS_VERSION" ]; then + export REQUIRED_NEOS_VERSION="14" +fi + +if [ -z "$PASSIVE" ]; then + export PASSIVE="1" +fi + +export STAGING_ROOT="/data/safe_staging" diff --git a/models/dmonitoring_model.current b/models/dmonitoring_model.current index 9c95aff333..b0026f152a 100644 --- a/models/dmonitoring_model.current +++ b/models/dmonitoring_model.current @@ -1 +1 @@ -43221d85-46fd-40b9-bff0-2b1b18a86b07 \ No newline at end of file +e96f9be6-5741-42ea-bdcd-0be6515b4230 \ No newline at end of file diff --git a/models/dmonitoring_model.keras b/models/dmonitoring_model.keras index 9a835302ec..c3d58f6fc7 100644 --- a/models/dmonitoring_model.keras +++ b/models/dmonitoring_model.keras @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5c39a2096f7058541b5339ec36bc4c468955e67285078080ed6d8802fed06c1d -size 814176 +oid sha256:09aa11a17a5a8173e231071898c499f9ea632e6e64285586122828b1bbc70d41 +size 4165968 diff --git a/models/dmonitoring_model_q.dlc b/models/dmonitoring_model_q.dlc index fc990411e9..558b359bfa 100644 --- a/models/dmonitoring_model_q.dlc +++ b/models/dmonitoring_model_q.dlc @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:29504dfd101ba2a0b48550fac2f86f9d0b8d1245af3d2d8d658247b4a73077a2 -size 230121 +oid sha256:beecf140ddc5da96cbdae3b869ebb3f5453dcd8e61e09d7d079c91e006b6df98 +size 1134208 diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 0000000000..66b82bd5df --- /dev/null +++ b/mypy.ini @@ -0,0 +1,4 @@ +[mypy] +python_version = 3.8 +ignore_missing_imports = True + diff --git a/opendbc b/opendbc index 45c0d9ecce..b7cf1a67bc 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 45c0d9ecce255e028163539e22e9a169735de69d +Subproject commit b7cf1a67bc71b674e6793ba1f2fff5d29fee1e6b diff --git a/panda b/panda index 6b19fa4961..ecef0a19d0 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 6b19fa4961d5dc6e6ea77987eb3a99ce28b0f5cd +Subproject commit ecef0a19d0f72d8fd3151593b7bd1a112d5f63e2 diff --git a/pyextra/logentries/__init__.py b/pyextra/logentries/__init__.py deleted file mode 100644 index b64e423b8b..0000000000 --- a/pyextra/logentries/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .utils import LogentriesHandler diff --git a/pyextra/logentries/helpers.py b/pyextra/logentries/helpers.py deleted file mode 100644 index bec676e22a..0000000000 --- a/pyextra/logentries/helpers.py +++ /dev/null @@ -1,49 +0,0 @@ - -""" This file contains some helpers methods in both Python2 and 3 """ -import sys -import re - -if sys.version < '3': - # Python2.x imports - import Queue - import codecs -else: - # Python 3.x imports - import queue - - -def check_token(token): - """ Checks if the given token is a valid UUID.""" - valid = re.compile(r"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-" - r"[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$") - - return valid.match(token) - -# We need to do some things different pending if its Python 2.x or 3.x -if sys.version < '3': - def to_unicode(ch): - return codecs.unicode_escape_decode(ch)[0] - - def is_unicode(ch): - return isinstance(ch, unicode) - - def create_unicode(ch): - try: - return unicode(ch, 'utf-8') - except UnicodeDecodeError as e: - return str(e) - - def create_queue(max_size): - return Queue.Queue(max_size) -else: - def to_unicode(ch): - return ch - - def is_unicode(ch): - return isinstance(ch, str) - - def create_unicode(ch): - return str(ch) - - def create_queue(max_size): - return queue.Queue(max_size) diff --git a/pyextra/logentries/metrics.py b/pyextra/logentries/metrics.py deleted file mode 100644 index 03ddb64374..0000000000 --- a/pyextra/logentries/metrics.py +++ /dev/null @@ -1,57 +0,0 @@ -from logentries import LogentriesHandler -from threading import Lock -from functools import wraps -import logging -import time -import sys -import psutil - -glob_time = 0 -glob_name = 0 - -log = logging.getLogger('logentries') -log.setLevel(logging.INFO) - -class Metric(object): - - def __init__(self, token): - self._count = 0.0 - self._sum = 0.0 - self._lock = Lock() - self.token = token - handler = LogentriesHandler(token) - log.addHandler(handler) - - def observe(self, amount): - with self._lock: - self._count += 1 - self._sum += amount - - def metric(self): - '''Mesaure function execution time in seconds - and forward it to Logentries''' - - class Timer(object): - - def __init__(self, summary): - self._summary = summary - - def __enter__(self): - self._start = time.time() - - def __exit__(self, typ, value, traceback): - global glob_time - self._summary.observe(max(time.time() - self._start, 0)) - glob_time = time.time()- self._start - log.info("function_name=" + glob_name + " " + "execution_time=" + str(glob_time) + " " + "cpu=" + str(psutil.cpu_percent(interval=None)) + " " + "cpu_count=" + str(psutil.cpu_count())+ " " + "memory=" + str(psutil.virtual_memory()) ) - - def __call__(self, f): - @wraps(f) - def wrapped(*args, **kwargs): - with self: - global glob_name - glob_name = f.__name__ - - return f(*args, **kwargs) - return wrapped - return Timer(self) diff --git a/pyextra/logentries/utils.py b/pyextra/logentries/utils.py deleted file mode 100644 index c17a1070cd..0000000000 --- a/pyextra/logentries/utils.py +++ /dev/null @@ -1,218 +0,0 @@ -# coding: utf-8 -# vim: set ts=4 sw=4 et: -""" This file contains some utils for connecting to Logentries - as well as storing logs in a queue and sending them.""" - -VERSION = '2.0.7' - -from logentries import helpers as le_helpers - -import logging -import threading -import socket -import random -import time -import sys - -import certifi - - -# Size of the internal event queue -QUEUE_SIZE = 32768 -# Logentries API server address -LE_API_DEFAULT = "data.logentries.com" -# Port number for token logging to Logentries API server -LE_PORT_DEFAULT = 80 -LE_TLS_PORT_DEFAULT = 443 -# Minimal delay between attempts to reconnect in seconds -MIN_DELAY = 0.1 -# Maximal delay between attempts to recconect in seconds -MAX_DELAY = 10 -# Unicode Line separator character \u2028 -LINE_SEP = le_helpers.to_unicode('\u2028') - - -# LE appender signature - used for debugging messages -LE = "LE: " -# Error message displayed when an incorrect Token has been detected -INVALID_TOKEN = ("\n\nIt appears the LOGENTRIES_TOKEN " - "parameter you entered is incorrect!\n\n") - - -def dbg(msg): - print(LE + msg) - - -class PlainTextSocketAppender(threading.Thread): - def __init__(self, verbose=True, le_api=LE_API_DEFAULT, le_port=LE_PORT_DEFAULT, le_tls_port=LE_TLS_PORT_DEFAULT): - threading.Thread.__init__(self) - - # Logentries API server address - self.le_api = le_api - - # Port number for token logging to Logentries API server - self.le_port = le_port - self.le_tls_port = le_tls_port - - self.daemon = True - self.verbose = verbose - self._conn = None - self._queue = le_helpers.create_queue(QUEUE_SIZE) - - def empty(self): - return self._queue.empty() - - def open_connection(self): - self._conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self._conn.connect((self.le_api, self.le_port)) - - def reopen_connection(self): - self.close_connection() - - root_delay = MIN_DELAY - while True: - try: - self.open_connection() - return - except Exception: - if self.verbose: - dbg("Unable to connect to Logentries") - - root_delay *= 2 - if(root_delay > MAX_DELAY): - root_delay = MAX_DELAY - - wait_for = root_delay + random.uniform(0, root_delay) - - try: - time.sleep(wait_for) - except KeyboardInterrupt: - raise - - def close_connection(self): - if self._conn is not None: - self._conn.close() - - def run(self): - try: - # Open connection - self.reopen_connection() - - # Send data in queue - while True: - # Take data from queue - data = self._queue.get(block=True) - - # Replace newlines with Unicode line separator - # for multi-line events - if not le_helpers.is_unicode(data): - multiline = le_helpers.create_unicode(data).replace( - '\n', LINE_SEP) - else: - multiline = data.replace('\n', LINE_SEP) - multiline += "\n" - # Send data, reconnect if needed - while True: - try: - self._conn.send(multiline.encode('utf-8')) - except socket.error: - self.reopen_connection() - continue - break - except KeyboardInterrupt: - if self.verbose: - dbg("Logentries asynchronous socket client interrupted") - - self.close_connection() - -SocketAppender = PlainTextSocketAppender - -try: - import ssl - ssl_enabled = True -except ImportError: # for systems without TLS support. - ssl_enabled = False - dbg("Unable to import ssl module. Will send over port 80.") -else: - class TLSSocketAppender(PlainTextSocketAppender): - - def open_connection(self): - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock = ssl.wrap_socket( - sock=sock, - keyfile=None, - certfile=None, - server_side=False, - cert_reqs=ssl.CERT_REQUIRED, - ssl_version=getattr( - ssl, - 'PROTOCOL_TLSv1_2', - ssl.PROTOCOL_TLSv1 - ), - ca_certs=certifi.where(), - do_handshake_on_connect=True, - suppress_ragged_eofs=True, - ) - - sock.connect((self.le_api, self.le_tls_port)) - self._conn = sock - - -class LogentriesHandler(logging.Handler): - def __init__(self, token, use_tls=True, verbose=True, format=None, le_api=LE_API_DEFAULT, le_port=LE_PORT_DEFAULT, le_tls_port=LE_TLS_PORT_DEFAULT): - logging.Handler.__init__(self) - self.token = token - self.good_config = True - self.verbose = verbose - # give the socket 10 seconds to flush, - # otherwise drop logs - self.timeout = 10 - if not le_helpers.check_token(token): - if self.verbose: - dbg(INVALID_TOKEN) - self.good_config = False - if format is None: - format = logging.Formatter('%(asctime)s : %(levelname)s, %(message)s', - '%a %b %d %H:%M:%S %Z %Y') - self.setFormatter(format) - self.setLevel(logging.DEBUG) - if use_tls and ssl_enabled: - self._thread = TLSSocketAppender(verbose=verbose, le_api=le_api, le_port=le_port, le_tls_port=le_tls_port) - else: - self._thread = SocketAppender(verbose=verbose, le_api=le_api, le_port=le_port, le_tls_port=le_tls_port) - - def flush(self): - # wait for all queued logs to be send - now = time.time() - while not self._thread.empty(): - time.sleep(0.2) - if time.time() - now > self.timeout: - break - - def emit_raw(self, msg): - if self.good_config and not self._thread.is_alive(): - try: - self._thread.start() - if self.verbose: - dbg("Starting Logentries Asynchronous Socket Appender") - except RuntimeError: # It's already started. - pass - - msg = self.token + msg - try: - self._thread._queue.put_nowait(msg) - except Exception: - # Queue is full, try to remove the oldest message and put again - try: - self._thread._queue.get_nowait() - self._thread._queue.put_nowait(msg) - except Exception: - # Race condition, no need for any action here - pass - - def emit(self, record): - msg = self.format(record).rstrip('\n') - self.emit_raw(msg) - - def close(self): - logging.Handler.close(self) diff --git a/pylint_openpilot.sh b/pylint_openpilot.sh deleted file mode 100755 index 910c5cd09a..0000000000 --- a/pylint_openpilot.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -python3 -m pylint --disable=R,C,W $(eval echo <(find cereal) <(find opendbc) $(cat release/files_common release/files_common | tr '\n' ' ') | tr ' ' '\n' | 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/rednose_repo b/rednose_repo index d3a79c6a42..2e556b8219 160000 --- a/rednose_repo +++ b/rednose_repo @@ -1 +1 @@ -Subproject commit d3a79c6a421b4eec952eeb8d1546a4c3c3ff030e +Subproject commit 2e556b8219185708ed974a4b6502796607d7ce0d diff --git a/release/build_devel.sh b/release/build_devel.sh index 26f92445a3..8e2e7ce7f6 100755 --- a/release/build_devel.sh +++ b/release/build_devel.sh @@ -1,30 +1,4 @@ -#!/usr/bin/env bash -set -e - -mkdir -p /dev/shm -chmod 777 /dev/shm - -# Write cpuset -echo $$ > /dev/cpuset/app/tasks -echo $PPID > /dev/cpuset/app/tasks - - -add_subtree() { - echo "[-] adding $2 subtree T=$SECONDS" - if [ -d "$2" ]; then - if git subtree pull --prefix "$2" https://github.com/commaai/"$1".git "$3" --squash -m "Merge $2 subtree"; then - echo "git subtree pull succeeds" - else - echo "git subtree pull failed, fixing" - git merge --abort || true - git rm -r $2 - git commit -m "Remove old $2 subtree" - git subtree add --prefix "$2" https://github.com/commaai/"$1".git "$3" --squash - fi - else - git subtree add --prefix "$2" https://github.com/commaai/"$1".git "$3" --squash - fi -} +#!/usr/bin/bash -e SOURCE_DIR=/data/openpilot_source TARGET_DIR=/data/openpilot @@ -35,17 +9,16 @@ export GIT_COMMITTER_NAME="Vehicle Researcher" export GIT_COMMITTER_EMAIL="user@comma.ai" export GIT_AUTHOR_NAME="Vehicle Researcher" export GIT_AUTHOR_EMAIL="user@comma.ai" -export GIT_SSH_COMMAND="ssh -i /tmp/deploy_key" +export GIT_SSH_COMMAND="ssh -i /data/gitkey" echo "[-] Setting up repo T=$SECONDS" if [ ! -d "$TARGET_DIR" ]; then - mkdir -p $TARGET_DIR - cd $TARGET_DIR - git init - git remote add origin git@github.com:commaai/openpilot.git + mkdir -p $TARGET_DIR + cd $TARGET_DIR + git init + git remote add origin git@github.com:commaai/openpilot.git fi - echo "[-] fetching public T=$SECONDS" cd $TARGET_DIR git prune || true @@ -55,27 +28,15 @@ echo "[-] bringing master-ci and devel in sync T=$SECONDS" git fetch origin master-ci git fetch origin devel -git checkout --track origin/master-ci || true +git checkout -f --track origin/master-ci git reset --hard master-ci git checkout master-ci git reset --hard origin/devel git clean -xdf -# subtrees to make updates more reliable. updating them needs a clean tree -add_subtree "cereal" "cereal" master -add_subtree "panda" "panda" master -add_subtree "opendbc" "opendbc" master -add_subtree "openpilot-pyextra" "pyextra" master - -# leave .git alone +# remove everything except .git echo "[-] erasing old openpilot T=$SECONDS" -rm -rf $TARGET_DIR/* $TARGET_DIR/.gitmodules - -# delete dotfiles in root -find . -maxdepth 1 -type f -delete - -# dont delete our subtrees -git checkout -- cereal panda opendbc pyextra +find . -maxdepth 1 -not -path './.git' -not -name '.' -not -name '..' -exec rm -rf '{}' \; # reset tree and get version cd $SOURCE_DIR @@ -103,15 +64,6 @@ git commit -a -m "openpilot v$VERSION release" # Run build SCONS_CACHE=1 scons -j3 -echo "[-] testing openpilot T=$SECONDS" -echo -n "0" > /data/params/d/Passive -echo -n "0.2.0" > /data/params/d/CompletedTrainingVersion -echo -n "1" > /data/params/d/HasCompletedSetup -echo -n "1" > /data/params/d/CommunityFeaturesToggle - -PYTHONPATH="$TARGET_DIR:$TARGET_DIR/pyextra" nosetests -s selfdrive/test/test_openpilot.py -PYTHONPATH="$TARGET_DIR:$TARGET_DIR/pyextra" GET_CPU_USAGE=1 selfdrive/manager.py - echo "[-] testing panda build T=$SECONDS" pushd panda/board/ make bin @@ -122,15 +74,10 @@ pushd panda/board/pedal make obj/comma.bin popd -if [ ! -z "$PUSH" ]; then - echo "[-] Pushing to $PUSH T=$SECONDS" - git push -f origin master-ci:$PUSH +if [ ! -z "$CI_PUSH" ]; then + echo "[-] Pushing to $CI_PUSH T=$SECONDS" + git remote set-url origin git@github.com:commaai/openpilot.git + git push -f origin master-ci:$CI_PUSH fi -echo "[-] done pushing T=$SECONDS" - -# reset version -cd $SOURCE_DIR -git checkout -- selfdrive/common/version.h - echo "[-] done T=$SECONDS" diff --git a/release/build_release2.sh b/release/build_release2.sh index 8e1466830b..9378bb723b 100755 --- a/release/build_release2.sh +++ b/release/build_release2.sh @@ -8,24 +8,32 @@ export GIT_AUTHOR_EMAIL="user@comma.ai" export GIT_SSH_COMMAND="ssh -i /data/gitkey" -# Create folders -rm -rf /data/openpilot -mkdir -p /data/openpilot -cd /data/openpilot - -# Create git repo -git init -git remote add origin git@github.com:commaai/openpilot.git -git fetch origin devel +# set CLEAN to build outside of CI +if [ ! -z "$CLEAN" ]; then + # Create folders + rm -rf /data/openpilot + mkdir -p /data/openpilot + cd /data/openpilot + + # Create git repo + git init + git remote add origin git@github.com:commaai/openpilot.git + git fetch origin devel-staging +else + cd /data/openpilot + git clean -xdf + git branch -D release2-staging || true +fi + git fetch origin release2-staging git fetch origin dashcam-staging -# Checkout devel -#git checkout origin/devel -#git clean -xdf - # Create release2 with no history -git checkout --orphan release2-staging origin/devel +if [ ! -z "$CLEAN" ]; then + git checkout --orphan release2-staging origin/devel-staging +else + git checkout --orphan release2-staging +fi VERSION=$(cat selfdrive/common/version.h | awk -F\" '{print $2}') git commit -m "openpilot v$VERSION" @@ -41,14 +49,24 @@ rm -rf /data/openpilot/pandaextra popd # Build stuff -ln -sf /data/openpilot /data/pythonpath +ln -sfn /data/openpilot /data/pythonpath export PYTHONPATH="/data/openpilot:/data/openpilot/pyextra" SCONS_CACHE=1 scons -j3 + +# Run tests nosetests -s selfdrive/test/test_openpilot.py +selfdrive/car/tests/test_car_interfaces.py # Cleanup +find . -name '*.a' -delete +find . -name '*.o' -delete +find . -name '*.os' -delete find . -name '*.pyc' -delete -rm .sconsign.dblite +find . -name '__pycache__' -delete +rm -rf .sconsign.dblite Jenkinsfile release/ + +# Restore phonelibs +git checkout phonelibs/ # Mark as prebuilt release touch prebuilt @@ -57,11 +75,18 @@ touch prebuilt git add -f . git commit --amend -m "openpilot v$VERSION" -# Push to release2-staging -git push -f origin release2-staging +# Print committed files that are normally gitignored +#git status --ignored + +if [ ! -z "$PUSH" ]; then + git remote set-url origin git@github.com:commaai/openpilot.git + + # Push to release2-staging + git push -f origin release2-staging -# Create dashcam release -git rm selfdrive/car/*/carcontroller.py + # Create dashcam release + git rm selfdrive/car/*/carcontroller.py -git commit -m "create dashcam release from release2" -git push -f origin release2-staging:dashcam-staging + git commit -m "create dashcam release from release2" + git push -f origin release2-staging:dashcam-staging +fi diff --git a/release/files_common b/release/files_common index 1ca68db684..3bff234eab 100644 --- a/release/files_common +++ b/release/files_common @@ -1,18 +1,17 @@ -README.md -SAFETY.md - -codecov.yml -lgtm.yml - .gitignore LICENSE +launch.sh +launch_env.sh launch_chffrplus.sh launch_openpilot.sh +Jenkinsfile +SConstruct + CONTRIBUTING.md +README.md RELEASES.md - -SConstruct +SAFETY.md apk/ai.comma*.apk @@ -29,7 +28,6 @@ common/numpy_fast.py common/params.py common/xattr.py common/profiler.py -common/testing.py common/basedir.py common/filter_simple.py common/stat_live.py @@ -39,23 +37,32 @@ common/cython_hacks.py common/apk.py common/SConscript common/common_pyx_setup.py -common/manager_helpers.py common/kalman/.gitignore common/kalman/* -common/kalman/tests/* common/transformations/__init__.py common/transformations/camera.py -common/transformations/coordinates.py common/transformations/model.py + +common/transformations/SConscript +common/transformations/setup.py +common/transformations/coordinates.py +common/transformations/coordinates.cc +common/transformations/coordinates.hpp common/transformations/orientation.py +common/transformations/orientation.cc +common/transformations/orientation.hpp +common/transformations/transformations.pxd +common/transformations/transformations.pyx common/api/__init__.py models/supercombo.dlc models/dmonitoring_model_q.dlc +release/build_release2.sh + selfdrive/version.py selfdrive/__init__.py @@ -73,8 +80,6 @@ selfdrive/updated.py selfdrive/athena/__init__.py selfdrive/athena/athenad.py selfdrive/athena/manage_athenad.py -selfdrive/athena/test.py -selfdrive/athena/test_helpers.py selfdrive/boardd/.gitignore selfdrive/boardd/SConscript @@ -84,7 +89,10 @@ selfdrive/boardd/boardd.py selfdrive/boardd/boardd_api_impl.pyx selfdrive/boardd/boardd_setup.py selfdrive/boardd/can_list_to_can_capnp.cc -selfdrive/boardd/tests/** +selfdrive/boardd/panda.cc +selfdrive/boardd/panda.h +selfdrive/boardd/pigeon.cc +selfdrive/boardd/pigeon.h selfdrive/car/__init__.py selfdrive/car/car_helpers.py @@ -93,6 +101,8 @@ selfdrive/car/interfaces.py selfdrive/car/vin.py selfdrive/car/fw_versions.py selfdrive/car/isotp_parallel_query.py +selfdrive/car/tests/__init__.py +selfdrive/car/tests/test_car_interfaces.py selfdrive/car/chrysler/__init__.py selfdrive/car/chrysler/carstate.py selfdrive/car/chrysler/interface.py @@ -100,7 +110,6 @@ selfdrive/car/chrysler/radar_interface.py selfdrive/car/chrysler/values.py selfdrive/car/chrysler/carcontroller.py selfdrive/car/chrysler/chryslercan.py -selfdrive/car/chrysler/test_chryslercan.py selfdrive/car/honda/__init__.py selfdrive/car/honda/carstate.py selfdrive/car/honda/interface.py @@ -122,6 +131,13 @@ selfdrive/car/toyota/radar_interface.py selfdrive/car/toyota/values.py selfdrive/car/toyota/carcontroller.py selfdrive/car/toyota/toyotacan.py +selfdrive/car/nissan/__init__.py +selfdrive/car/nissan/carcontroller.py +selfdrive/car/nissan/carstate.py +selfdrive/car/nissan/interface.py +selfdrive/car/nissan/nissancan.py +selfdrive/car/nissan/radar_interface.py +selfdrive/car/nissan/values.py selfdrive/car/volkswagen/__init__.py selfdrive/car/volkswagen/carstate.py selfdrive/car/volkswagen/interface.py @@ -150,13 +166,19 @@ selfdrive/car/subaru/radar_interface.py selfdrive/car/subaru/values.py selfdrive/car/subaru/carcontroller.py selfdrive/car/subaru/subarucan.py +selfdrive/car/mazda/__init__.py +selfdrive/car/mazda/carstate.py +selfdrive/car/mazda/interface.py +selfdrive/car/mazda/radar_interface.py +selfdrive/car/mazda/values.py +selfdrive/car/mazda/carcontroller.py +selfdrive/car/mazda/mazdacan.py selfdrive/car/mock/*.py selfdrive/clocksd/.gitignore selfdrive/clocksd/SConscript selfdrive/clocksd/clocksd.cc -selfdrive/debug/mpc/* selfdrive/debug/*.py selfdrive/common/SConscript @@ -176,7 +198,6 @@ selfdrive/common/util.[c,h] selfdrive/common/efd.[c,h] selfdrive/common/cqueue.[c,h] selfdrive/common/clutil.[c,h] -selfdrive/common/messaging.h selfdrive/common/params.h selfdrive/common/params.cc selfdrive/common/mutex.h @@ -192,20 +213,19 @@ selfdrive/common/visionimg.cc selfdrive/common/visionimg.h selfdrive/common/spinner.c selfdrive/common/spinner.h +selfdrive/common/gpio.cc +selfdrive/common/gpio.h selfdrive/controls/__init__.py -selfdrive/controls/tests/* selfdrive/controls/controlsd.py selfdrive/controls/plannerd.py selfdrive/controls/radard.py -selfdrive/controls/dmonitoringd.py selfdrive/controls/lib/__init__.py selfdrive/controls/lib/alertmanager.py selfdrive/controls/lib/alerts_offroad.json selfdrive/controls/lib/events.py selfdrive/controls/lib/drive_helpers.py -selfdrive/controls/lib/driver_monitor.py selfdrive/controls/lib/latcontrol_pid.py selfdrive/controls/lib/latcontrol_indi.py selfdrive/controls/lib/latcontrol_lqr.py @@ -220,7 +240,6 @@ selfdrive/controls/lib/speed_smoother.py selfdrive/controls/lib/fcw.py selfdrive/controls/lib/long_mpc.py selfdrive/controls/lib/long_mpc_model.py -selfdrive/controls/lib/driverview.py selfdrive/controls/lib/cluster/* @@ -256,7 +275,6 @@ selfdrive/locationd/ubloxd_main.cc selfdrive/locationd/ubloxd_test.cc selfdrive/locationd/ublox_msg.cc selfdrive/locationd/ublox_msg.h -selfdrive/locationd/test/*.py selfdrive/locationd/locationd.py selfdrive/locationd/paramsd.py @@ -269,12 +287,6 @@ selfdrive/locationd/models/constants.py selfdrive/locationd/calibrationd.py selfdrive/locationd/calibration_helpers.py -selfdrive/locationd/locationd_yawrate.cc -selfdrive/locationd/locationd_yawrate.h -selfdrive/locationd/params_learner.cc -selfdrive/locationd/params_learner.h -selfdrive/locationd/paramsd.cc - selfdrive/logcatd/SConscript selfdrive/logcatd/logcatd.cc @@ -295,7 +307,6 @@ selfdrive/loggerd/__init__.py selfdrive/loggerd/config.py selfdrive/loggerd/uploader.py selfdrive/loggerd/deleter.py -selfdrive/loggerd/tests/* selfdrive/sensord/SConscript selfdrive/sensord/gpsd.cc @@ -308,25 +319,14 @@ selfdrive/thermald/thermald.py selfdrive/thermald/power_monitoring.py selfdrive/test/__init__.py -selfdrive/test/longitudinal_maneuvers/*.py +selfdrive/test/helpers.py +selfdrive/test/setup_device_ci.sh selfdrive/test/test_openpilot.py selfdrive/test/test_fingerprints.py -selfdrive/test/test_car_models.py -selfdrive/test/openpilotci_upload.py - -selfdrive/test/process_replay/.gitignore -selfdrive/test/process_replay/__init__.py -selfdrive/test/process_replay/compare_logs.py -selfdrive/test/process_replay/process_replay.py -selfdrive/test/process_replay/test_processes.py -selfdrive/test/process_replay/update_refs.py -selfdrive/test/process_replay/ref_commit -selfdrive/test/process_replay/README.md +selfdrive/test/test_cpu_usage.py selfdrive/ui/SConscript -selfdrive/ui/*.c selfdrive/ui/*.cc -selfdrive/ui/*.h selfdrive/ui/*.hpp selfdrive/ui/ui selfdrive/ui/spinner/Makefile @@ -337,6 +337,9 @@ selfdrive/ui/text/Makefile selfdrive/ui/text/text selfdrive/ui/text/text.c +selfdrive/ui/qt/*.cc +selfdrive/ui/qt/*.hpp + selfdrive/camerad/SConscript selfdrive/camerad/main.cc selfdrive/camerad/bufs.h @@ -380,11 +383,17 @@ selfdrive/modeld/transforms/loadyuv.cl selfdrive/modeld/transforms/transform.[c,h] selfdrive/modeld/transforms/transform.cl +selfdrive/modeld/thneed/thneed.* +selfdrive/modeld/thneed/include/* + selfdrive/modeld/runners/snpemodel.cc selfdrive/modeld/runners/snpemodel.h selfdrive/modeld/runners/runmodel.h selfdrive/modeld/runners/run.h +selfdrive/monitoring/dmonitoringd.py +selfdrive/monitoring/driver_monitor.py + selfdrive/assets selfdrive/assets/fonts/*.ttf @@ -396,9 +405,7 @@ phonelibs/nanovg/*.h phonelibs/libgralloc/** phonelibs/linux/** phonelibs/opencl/** -phonelibs/curl/* phonelibs/zlib/* -phonelibs/boringssl/* phonelibs/bzip2/* phonelibs/openmax/** @@ -420,9 +427,132 @@ phonelibs/android_system_core/** installer/updater/updater installer/updater/updater.cc installer/updater/update.json +installer/updater/update_kernel.json installer/updater/Makefile scripts/update_now.sh scripts/stop_updater.sh +pyextra/.gitignore + rednose/** + +cereal/.gitignore +cereal/__init__.py +cereal/car.capnp +cereal/log.capnp +cereal/services.py +cereal/service_list.yaml +cereal/SConscript +cereal/include/** +cereal/messaging/.gitignore +cereal/messaging/__init__.py +cereal/messaging/bridge.cc +cereal/messaging/impl_msgq.cc +cereal/messaging/impl_msgq.hpp +cereal/messaging/impl_zmq.cc +cereal/messaging/impl_zmq.hpp +cereal/messaging/messaging.cc +cereal/messaging/messaging.hpp +cereal/messaging/messaging.pxd +cereal/messaging/messaging_pyx.pyx +cereal/messaging/messaging_pyx_setup.py +cereal/messaging/msgq.cc +cereal/messaging/msgq.hpp +cereal/messaging/socketmaster.cc + +panda/.gitignore +panda/__init__.py +panda/VERSION +panda/board/** +panda/certs/** +panda/common/** +panda/crypto/** +panda/python/** + +opendbc/.gitignore +opendbc/__init__.py +opendbc/can/__init__.py +opendbc/can/SConscript +opendbc/can/can_define.py +opendbc/can/common.cc +opendbc/can/common.h +opendbc/can/common.pxd +opendbc/can/common_dbc.h +opendbc/can/common_pyx_setup.py +opendbc/can/dbc.cc +opendbc/can/dbc.py +opendbc/can/dbc_template.cc +opendbc/can/packer.cc +opendbc/can/packer.py +opendbc/can/packer_pyx.pyx +opendbc/can/parser.cc +opendbc/can/parser.py +opendbc/can/parser_pyx.pyx +opendbc/can/process_dbc.py +opendbc/can/dbc_out/.gitkeep +opendbc/can/dbc_out/.gitignore + +opendbc/chrysler_pacifica_2017_hybrid.dbc +opendbc/chrysler_pacifica_2017_hybrid_private_fusion.dbc + +opendbc/gm_global_a_powertrain.dbc +opendbc/gm_global_a_object.dbc +opendbc/gm_global_a_chassis.dbc + +opendbc/ford_fusion_2018_pt.dbc +opendbc/ford_fusion_2018_adas.dbc + +opendbc/honda_accord_s2t_2018_can_generated.dbc +opendbc/honda_accord_lx15t_2018_can_generated.dbc +opendbc/acura_ilx_2016_can_generated.dbc +opendbc/acura_rdx_2018_can_generated.dbc +opendbc/honda_civic_touring_2016_can_generated.dbc +opendbc/honda_civic_hatchback_ex_2017_can_generated.dbc +opendbc/honda_civic_sedan_16_diesel_2019_can_generated.dbc +opendbc/honda_crv_touring_2016_can_generated.dbc +opendbc/honda_crv_ex_2017_can_generated.dbc +opendbc/honda_crv_ex_2017_body_generated.dbc +opendbc/honda_crv_executive_2016_can_generated.dbc +opendbc/honda_crv_hybrid_2019_can_generated.dbc +opendbc/honda_fit_ex_2018_can_generated.dbc +opendbc/honda_hrv_touring_2019_can_generated.dbc +opendbc/honda_odyssey_exl_2018_generated.dbc +opendbc/honda_odyssey_extreme_edition_2018_china_can_generated.dbc +opendbc/honda_pilot_touring_2017_can_generated.dbc +opendbc/honda_ridgeline_black_edition_2017_can_generated.dbc +opendbc/honda_insight_ex_2019_can_generated.dbc +opendbc/acura_ilx_2016_nidec.dbc + +opendbc/hyundai_kia_generic.dbc + +opendbc/mazda_2017.dbc + +opendbc/nissan_x_trail_2017.dbc +opendbc/nissan_leaf_2018.dbc + +opendbc/subaru_global_2017_generated.dbc +opendbc/subaru_outback_2015_generated.dbc +opendbc/subaru_outback_2019_generated.dbc +opendbc/subaru_forester_2017_generated.dbc + +opendbc/toyota_rav4_hybrid_2017_pt_generated.dbc +opendbc/toyota_rav4_2017_pt_generated.dbc +opendbc/toyota_prius_2017_pt_generated.dbc +opendbc/toyota_corolla_2017_pt_generated.dbc +opendbc/lexus_rx_350_2016_pt_generated.dbc +opendbc/lexus_rx_hybrid_2017_pt_generated.dbc +opendbc/toyota_nodsu_pt_generated.dbc +opendbc/toyota_nodsu_hybrid_pt_generated.dbc +opendbc/toyota_camry_hybrid_2018_pt_generated.dbc +opendbc/toyota_highlander_2017_pt_generated.dbc +opendbc/toyota_highlander_hybrid_2018_pt_generated.dbc +opendbc/toyota_avalon_2017_pt_generated.dbc +opendbc/toyota_sienna_xle_2018_pt_generated.dbc +opendbc/lexus_is_2018_pt_generated.dbc +opendbc/lexus_ct200h_2018_pt_generated.dbc +opendbc/lexus_nx300h_2018_pt_generated.dbc +opendbc/toyota_adas.dbc +opendbc/toyota_tss2_adas.dbc + +opendbc/vw_mqb_2010.dbc diff --git a/release/remote_build.py b/release/remote_build.py deleted file mode 100755 index f80843cef9..0000000000 --- a/release/remote_build.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python2 -import paramiko -import os -import sys -import re -import time -import socket - - -def start_build(name): - ssh = paramiko.SSHClient() - ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - - key_file = open(os.path.join(os.path.dirname(__file__), "id_rsa_public")) - key = paramiko.RSAKey.from_private_key(key_file) - - print("SSH to phone {}".format(name)) - - # Try connecting for one minute - t_start = time.time() - while True: - try: - ssh.connect(hostname=name, port=8022, pkey=key, timeout=10) - except (paramiko.ssh_exception.SSHException, socket.timeout, paramiko.ssh_exception.NoValidConnectionsError): - print("Connection failed") - if time.time() - t_start > 60: - raise - else: - break - time.sleep(1) - - conn = ssh.invoke_shell() - branch = os.environ['GIT_BRANCH'] - commit = os.environ.get('GIT_COMMIT', branch) - - conn.send('uname -a\n') - - conn.send('cd /data/openpilot_source\n') - conn.send("git reset --hard\n") - conn.send("git fetch origin\n") - conn.send("git checkout %s\n" % commit) - conn.send("git clean -xdf\n") - conn.send("git submodule update --init\n") - conn.send("git submodule foreach --recursive git reset --hard\n") - conn.send("git submodule foreach --recursive git clean -xdf\n") - conn.send("echo \"git took $SECONDS seconds\"\n") - - push = "PUSH=master-ci" if branch == "master" else "" - - conn.send("%s /data/openpilot_source/release/build_devel.sh\n" % push) - conn.send('echo "RESULT:" $?\n') - conn.send("exit\n") - return conn - - -if __name__ == "__main__": - eon_name = os.environ.get('eon_name', None) - - conn = start_build(eon_name) - - dat = b"" - - while True: - recvd = conn.recv(4096) - if len(recvd) == 0: - break - - dat += recvd - sys.stdout.buffer.write(recvd) - sys.stdout.flush() - - returns = re.findall(rb'^RESULT: (\d+)', dat[-1024:], flags=re.MULTILINE) - sys.exit(int(returns[0])) diff --git a/run_docker_tests.sh b/run_docker_tests.sh deleted file mode 100755 index 1247c24de1..0000000000 --- a/run_docker_tests.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -set -e - -SETUP="cd /tmp/openpilot && " -RUN="docker run --shm-size 1G --rm tmppilot /bin/sh -c" - -docker build -t tmppilot -f Dockerfile.openpilot . - -$RUN "$SETUP cd /tmp/openpilot/selfdrive/test/ && ./test_fingerprints.py" -$RUN "$SETUP ./flake8_openpilot.sh" -$RUN "$SETUP ./pylint_openpilot.sh" -$RUN "$SETUP python -m unittest discover common" -$RUN "$SETUP python -m unittest discover opendbc/can" -$RUN "$SETUP python -m unittest discover selfdrive/boardd" -$RUN "$SETUP python -m unittest discover selfdrive/controls" -$RUN "$SETUP python -m unittest discover selfdrive/loggerd" -$RUN "$SETUP python -m unittest discover selfdrive/car" -$RUN "$SETUP python -m unittest discover selfdrive/locationd" -$RUN "$SETUP python -m unittest discover selfdrive/athena" -$RUN "$SETUP cd /tmp/openpilot/selfdrive/test/longitudinal_maneuvers && OPTEST=1 ./test_longitudinal.py" -$RUN "$SETUP cd /tmp/openpilot/selfdrive/test/process_replay/ && ./test_processes.py" -$RUN "$SETUP mkdir -p /data/params && cd /tmp/openpilot/selfdrive/test/ && ./test_car_models.py" diff --git a/scripts/code_stats.py b/scripts/code_stats.py index ccd32c7e50..d3bc48bcec 100755 --- a/scripts/code_stats.py +++ b/scripts/code_stats.py @@ -20,6 +20,7 @@ class Analyzer(ast.NodeVisitor): for alias in node.names: imps.add(alias.name) self.generic_visit(node) + def visit_ImportFrom(self, node): imps.add(node.module) self.generic_visit(node) @@ -38,4 +39,3 @@ for f in sorted(pyf): print("%d lines of parsed openpilot python" % tlns) #print(sorted(list(imps))) - diff --git a/scripts/waste.py b/scripts/waste.py index 55aeba066a..48600253d3 100755 --- a/scripts/waste.py +++ b/scripts/waste.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 from multiprocessing import Process -from setproctitle import setproctitle +from setproctitle import setproctitle # pylint: disable=no-name-in-module import os import numpy as np from common.realtime import sec_since_boot @@ -9,8 +9,8 @@ def waste(pid): # set affinity os.system("taskset -p %d %d" % (1 << pid, os.getpid())) - m1 = np.zeros((200,200)) + 0.8 - m2 = np.zeros((200,200)) + 1.2 + m1 = np.zeros((200, 200)) + 0.8 + m2 = np.zeros((200, 200)) + 1.2 i = 1 st = sec_since_boot() @@ -32,4 +32,3 @@ def main(gctx=None): if __name__ == "__main__": main() - diff --git a/selfdrive/assets/offroad/circled-checkmark.png b/selfdrive/assets/offroad/circled-checkmark.png new file mode 100644 index 0000000000..bc6b49585d Binary files /dev/null and b/selfdrive/assets/offroad/circled-checkmark.png differ diff --git a/selfdrive/assets/offroad/icon_app_store.png b/selfdrive/assets/offroad/icon_app_store.png new file mode 100644 index 0000000000..ae0dd95cee Binary files /dev/null and b/selfdrive/assets/offroad/icon_app_store.png differ diff --git a/selfdrive/assets/offroad/icon_calibration.png b/selfdrive/assets/offroad/icon_calibration.png new file mode 100644 index 0000000000..c4ee0d63d4 Binary files /dev/null and b/selfdrive/assets/offroad/icon_calibration.png differ diff --git a/selfdrive/assets/offroad/icon_checkmark.png b/selfdrive/assets/offroad/icon_checkmark.png new file mode 100644 index 0000000000..06efdfb0cb Binary files /dev/null and b/selfdrive/assets/offroad/icon_checkmark.png differ diff --git a/selfdrive/assets/offroad/icon_chevron_right.png b/selfdrive/assets/offroad/icon_chevron_right.png new file mode 100644 index 0000000000..a3aaa76486 Binary files /dev/null and b/selfdrive/assets/offroad/icon_chevron_right.png differ diff --git a/selfdrive/assets/offroad/icon_connect_app.png b/selfdrive/assets/offroad/icon_connect_app.png new file mode 100644 index 0000000000..cd216d3e6f Binary files /dev/null and b/selfdrive/assets/offroad/icon_connect_app.png differ diff --git a/selfdrive/assets/offroad/icon_eon.png b/selfdrive/assets/offroad/icon_eon.png new file mode 100644 index 0000000000..72856c4e68 Binary files /dev/null and b/selfdrive/assets/offroad/icon_eon.png differ diff --git a/selfdrive/assets/offroad/icon_map.png b/selfdrive/assets/offroad/icon_map.png new file mode 100644 index 0000000000..21dd0bacc6 Binary files /dev/null and b/selfdrive/assets/offroad/icon_map.png differ diff --git a/selfdrive/assets/offroad/icon_map_speed.png b/selfdrive/assets/offroad/icon_map_speed.png new file mode 100644 index 0000000000..1eeab84600 Binary files /dev/null and b/selfdrive/assets/offroad/icon_map_speed.png differ diff --git a/selfdrive/assets/offroad/icon_menu.png b/selfdrive/assets/offroad/icon_menu.png new file mode 100644 index 0000000000..837cf5831c Binary files /dev/null and b/selfdrive/assets/offroad/icon_menu.png differ diff --git a/selfdrive/assets/offroad/icon_metric.png b/selfdrive/assets/offroad/icon_metric.png new file mode 100644 index 0000000000..eaa2438fa3 Binary files /dev/null and b/selfdrive/assets/offroad/icon_metric.png differ diff --git a/selfdrive/assets/offroad/icon_minus.png b/selfdrive/assets/offroad/icon_minus.png new file mode 100644 index 0000000000..e5327c0d3b Binary files /dev/null and b/selfdrive/assets/offroad/icon_minus.png differ diff --git a/selfdrive/assets/offroad/icon_monitoring.png b/selfdrive/assets/offroad/icon_monitoring.png new file mode 100644 index 0000000000..05f78811e2 Binary files /dev/null and b/selfdrive/assets/offroad/icon_monitoring.png differ diff --git a/selfdrive/assets/offroad/icon_network.png b/selfdrive/assets/offroad/icon_network.png new file mode 100644 index 0000000000..3236924f4d Binary files /dev/null and b/selfdrive/assets/offroad/icon_network.png differ diff --git a/selfdrive/assets/offroad/icon_openpilot.png b/selfdrive/assets/offroad/icon_openpilot.png new file mode 100644 index 0000000000..0a90a87910 Binary files /dev/null and b/selfdrive/assets/offroad/icon_openpilot.png differ diff --git a/selfdrive/assets/offroad/icon_openpilot_mirrored.png b/selfdrive/assets/offroad/icon_openpilot_mirrored.png new file mode 100644 index 0000000000..23a7d5a552 Binary files /dev/null and b/selfdrive/assets/offroad/icon_openpilot_mirrored.png differ diff --git a/selfdrive/assets/offroad/icon_play_store.png b/selfdrive/assets/offroad/icon_play_store.png new file mode 100644 index 0000000000..1eca9d5890 Binary files /dev/null and b/selfdrive/assets/offroad/icon_play_store.png differ diff --git a/selfdrive/assets/offroad/icon_plus.png b/selfdrive/assets/offroad/icon_plus.png new file mode 100644 index 0000000000..92b448b0bd Binary files /dev/null and b/selfdrive/assets/offroad/icon_plus.png differ diff --git a/selfdrive/assets/offroad/icon_road.png b/selfdrive/assets/offroad/icon_road.png new file mode 100644 index 0000000000..5868ed1ccc Binary files /dev/null and b/selfdrive/assets/offroad/icon_road.png differ diff --git a/selfdrive/assets/offroad/icon_settings.png b/selfdrive/assets/offroad/icon_settings.png new file mode 100644 index 0000000000..d0c90a620d Binary files /dev/null and b/selfdrive/assets/offroad/icon_settings.png differ diff --git a/selfdrive/assets/offroad/icon_shell.png b/selfdrive/assets/offroad/icon_shell.png new file mode 100644 index 0000000000..f1d655416a Binary files /dev/null and b/selfdrive/assets/offroad/icon_shell.png differ diff --git a/selfdrive/assets/offroad/icon_speed_limit.png b/selfdrive/assets/offroad/icon_speed_limit.png new file mode 100644 index 0000000000..0aa7038f90 Binary files /dev/null and b/selfdrive/assets/offroad/icon_speed_limit.png differ diff --git a/selfdrive/assets/offroad/icon_user.png b/selfdrive/assets/offroad/icon_user.png new file mode 100644 index 0000000000..9b653cc4b3 Binary files /dev/null and b/selfdrive/assets/offroad/icon_user.png differ diff --git a/selfdrive/assets/offroad/icon_warning.png b/selfdrive/assets/offroad/icon_warning.png new file mode 100644 index 0000000000..50fe821127 Binary files /dev/null and b/selfdrive/assets/offroad/icon_warning.png differ diff --git a/selfdrive/assets/offroad/illustration_arrow.png b/selfdrive/assets/offroad/illustration_arrow.png new file mode 100644 index 0000000000..2219086641 Binary files /dev/null and b/selfdrive/assets/offroad/illustration_arrow.png differ diff --git a/selfdrive/assets/offroad/illustration_sim_absent.png b/selfdrive/assets/offroad/illustration_sim_absent.png new file mode 100644 index 0000000000..554097409b Binary files /dev/null and b/selfdrive/assets/offroad/illustration_sim_absent.png differ diff --git a/selfdrive/assets/offroad/illustration_sim_present.png b/selfdrive/assets/offroad/illustration_sim_present.png new file mode 100644 index 0000000000..0856795f01 Binary files /dev/null and b/selfdrive/assets/offroad/illustration_sim_present.png differ diff --git a/selfdrive/assets/offroad/illustration_training_lane_01.png b/selfdrive/assets/offroad/illustration_training_lane_01.png new file mode 100644 index 0000000000..27d9bcee3e Binary files /dev/null and b/selfdrive/assets/offroad/illustration_training_lane_01.png differ diff --git a/selfdrive/assets/offroad/illustration_training_lane_02.png b/selfdrive/assets/offroad/illustration_training_lane_02.png new file mode 100644 index 0000000000..4f3e2ef44c Binary files /dev/null and b/selfdrive/assets/offroad/illustration_training_lane_02.png differ diff --git a/selfdrive/assets/offroad/illustration_training_lead_01.png b/selfdrive/assets/offroad/illustration_training_lead_01.png new file mode 100644 index 0000000000..12f3f6bae8 Binary files /dev/null and b/selfdrive/assets/offroad/illustration_training_lead_01.png differ diff --git a/selfdrive/assets/offroad/illustration_training_lead_02.png b/selfdrive/assets/offroad/illustration_training_lead_02.png new file mode 100644 index 0000000000..26c9ffe719 Binary files /dev/null and b/selfdrive/assets/offroad/illustration_training_lead_02.png differ diff --git a/selfdrive/assets/offroad/indicator_wifi_0.png b/selfdrive/assets/offroad/indicator_wifi_0.png new file mode 100644 index 0000000000..9cf9762ad3 Binary files /dev/null and b/selfdrive/assets/offroad/indicator_wifi_0.png differ diff --git a/selfdrive/assets/offroad/indicator_wifi_100.png b/selfdrive/assets/offroad/indicator_wifi_100.png new file mode 100644 index 0000000000..dc9f28fab3 Binary files /dev/null and b/selfdrive/assets/offroad/indicator_wifi_100.png differ diff --git a/selfdrive/assets/offroad/indicator_wifi_25.png b/selfdrive/assets/offroad/indicator_wifi_25.png new file mode 100644 index 0000000000..cbf9bc89e5 Binary files /dev/null and b/selfdrive/assets/offroad/indicator_wifi_25.png differ diff --git a/selfdrive/assets/offroad/indicator_wifi_50.png b/selfdrive/assets/offroad/indicator_wifi_50.png new file mode 100644 index 0000000000..8ee118a419 Binary files /dev/null and b/selfdrive/assets/offroad/indicator_wifi_50.png differ diff --git a/selfdrive/assets/offroad/indicator_wifi_75.png b/selfdrive/assets/offroad/indicator_wifi_75.png new file mode 100644 index 0000000000..bcbebce85d Binary files /dev/null and b/selfdrive/assets/offroad/indicator_wifi_75.png differ diff --git a/selfdrive/athena/athenad.py b/selfdrive/athena/athenad.py index b9e8d79e6f..72e81a58bb 100755 --- a/selfdrive/athena/athenad.py +++ b/selfdrive/athena/athenad.py @@ -1,42 +1,45 @@ #!/usr/bin/env python3 -import json -import os +import base64 import hashlib import io +import json +import os +import queue import random import select import socket -import time import threading -import base64 -import requests -import queue +import time from collections import namedtuple from functools import partial +from typing import Any + +import requests from jsonrpc import JSONRPCResponseManager, dispatcher -from websocket import create_connection, WebSocketTimeoutException, ABNF -from selfdrive.loggerd.config import ROOT +from websocket import ABNF, WebSocketTimeoutException, create_connection import cereal.messaging as messaging +from cereal.services import service_list from common import android -from common.basedir import PERSIST from common.api import Api +from common.basedir import PERSIST from common.params import Params from common.realtime import sec_since_boot -from cereal.services import service_list +from selfdrive.loggerd.config import ROOT from selfdrive.swaglog import cloudlog ATHENA_HOST = os.getenv('ATHENA_HOST', 'wss://athena.comma.ai') -HANDLER_THREADS = os.getenv('HANDLER_THREADS', 4) +HANDLER_THREADS = int(os.getenv('HANDLER_THREADS', "4")) LOCAL_PORT_WHITELIST = set([8022]) dispatcher["echo"] = lambda s: s -payload_queue = queue.Queue() -response_queue = queue.Queue() -upload_queue = queue.Queue() -cancelled_uploads = set() +payload_queue: Any = queue.Queue() +response_queue: Any = queue.Queue() +upload_queue: Any = queue.Queue() +cancelled_uploads: Any = set() UploadItem = namedtuple('UploadItem', ['path', 'url', 'headers', 'created_at', 'id']) + def handle_long_poll(ws): end_event = threading.Event() @@ -58,9 +61,10 @@ def handle_long_poll(ws): end_event.set() raise finally: - for i, thread in enumerate(threads): + for thread in threads: thread.join() + def jsonrpc_handler(end_event): dispatcher["startLocalProxy"] = partial(startLocalProxy, end_event) while not end_event.is_set(): @@ -74,6 +78,7 @@ def jsonrpc_handler(end_event): cloudlog.exception("athena jsonrpc handler failed") response_queue.put_nowait(json.dumps({"error": str(e)})) + def upload_handler(end_event): while not end_event.is_set(): try: @@ -87,6 +92,7 @@ def upload_handler(end_event): except Exception: cloudlog.exception("athena.upload_handler.exception") + def _do_upload(upload_item): with open(upload_item.path, "rb") as f: size = os.fstat(f.fileno()).st_size @@ -95,6 +101,7 @@ def _do_upload(upload_item): headers={**upload_item.headers, 'Content-Length': str(size)}, timeout=10) + # security: user should be able to request any message from their car @dispatcher.add_method def getMessage(service=None, timeout=1000): @@ -109,11 +116,13 @@ def getMessage(service=None, timeout=1000): return ret.to_dict() + @dispatcher.add_method def listDataDirectory(): files = [os.path.relpath(os.path.join(dp, f), ROOT) for dp, dn, fn in os.walk(ROOT) for f in fn] return files + @dispatcher.add_method def reboot(): thermal_sock = messaging.sub_sock("thermal", timeout=1000) @@ -129,6 +138,7 @@ def reboot(): return {"success": 1} + @dispatcher.add_method def uploadFileToUrl(fn, url, headers): if len(fn) == 0 or fn[0] == '/' or '..' in fn: @@ -137,7 +147,7 @@ def uploadFileToUrl(fn, url, headers): if not os.path.exists(path): return 404 - item = UploadItem(path=path, url=url, headers=headers, created_at=int(time.time()*1000), id=None) + item = UploadItem(path=path, url=url, headers=headers, created_at=int(time.time() * 1000), id=None) upload_id = hashlib.sha1(str(item).encode()).hexdigest() item = item._replace(id=upload_id) @@ -145,10 +155,12 @@ def uploadFileToUrl(fn, url, headers): return {"enqueued": 1, "item": item._asdict()} + @dispatcher.add_method def listUploadQueue(): return [item._asdict() for item in list(upload_queue.queue)] + @dispatcher.add_method def cancelUpload(upload_id): upload_ids = set(item.id for item in list(upload_queue.queue)) @@ -158,6 +170,7 @@ def cancelUpload(upload_id): cancelled_uploads.add(upload_id) return {"success": 1} + def startLocalProxy(global_end_event, remote_ws_uri, local_port): try: if local_port not in LOCAL_PORT_WHITELIST: @@ -188,18 +201,21 @@ def startLocalProxy(global_end_event, remote_ws_uri, local_port): cloudlog.exception("athenad.startLocalProxy.exception") raise e + @dispatcher.add_method def getPublicKey(): - if not os.path.isfile(PERSIST+'/comma/id_rsa.pub'): + if not os.path.isfile(PERSIST + '/comma/id_rsa.pub'): return None - with open(PERSIST+'/comma/id_rsa.pub', 'r') as f: + with open(PERSIST + '/comma/id_rsa.pub', 'r') as f: return f.read() + @dispatcher.add_method def getSshAuthorizedKeys(): return Params().get("GithubSshKeys", encoding='utf8') or '' + @dispatcher.add_method def getSimInfo(): sim_state = android.getprop("gsm.sim.state").split(",") @@ -218,6 +234,7 @@ def getSimInfo(): 'data_connected': cell_data_connected } + @dispatcher.add_method def takeSnapshot(): from selfdrive.camerad.snapshot.snapshot import snapshot, jpeg_write @@ -235,6 +252,7 @@ def takeSnapshot(): else: raise Exception("not available while camerad is started") + def ws_proxy_recv(ws, local_sock, ssock, end_event, global_end_event): while not (end_event.is_set() or global_end_event.is_set()): try: @@ -250,6 +268,7 @@ def ws_proxy_recv(ws, local_sock, ssock, end_event, global_end_event): local_sock.close() end_event.set() + def ws_proxy_send(ws, local_sock, signal_sock, end_event): while not end_event.is_set(): try: @@ -270,6 +289,7 @@ def ws_proxy_send(ws, local_sock, signal_sock, end_event): cloudlog.exception("athenad.ws_proxy_send.exception") end_event.set() + def ws_recv(ws, end_event): while not end_event.is_set(): try: @@ -279,13 +299,14 @@ def ws_recv(ws, end_event): data = data.decode("utf-8") payload_queue.put_nowait(data) elif opcode == ABNF.OPCODE_PING: - Params().put("LastAthenaPingTime", str(int(sec_since_boot()*1e9))) + Params().put("LastAthenaPingTime", str(int(sec_since_boot() * 1e9))) except WebSocketTimeoutException: pass except Exception: cloudlog.exception("athenad.ws_recv.exception") end_event.set() + def ws_send(ws, end_event): while not end_event.is_set(): try: @@ -297,9 +318,11 @@ def ws_send(ws, end_event): cloudlog.exception("athenad.ws_send.exception") end_event.set() + def backoff(retries): return random.randrange(0, min(128, int(2 ** retries))) + def main(): params = Params() dongle_id = params.get("DongleId").decode('utf-8') @@ -326,5 +349,6 @@ def main(): time.sleep(backoff(conn_retries)) + if __name__ == "__main__": main() diff --git a/selfdrive/athena/test_helpers.py b/selfdrive/athena/test_helpers.py index 2335ce89c5..77a94c0787 100644 --- a/selfdrive/athena/test_helpers.py +++ b/selfdrive/athena/test_helpers.py @@ -8,6 +8,7 @@ import time from functools import wraps from multiprocessing import Process + class EchoSocket(): def __init__(self, port): self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -15,7 +16,7 @@ class EchoSocket(): self.socket.listen(1) def run(self): - conn, client_address = self.socket.accept() + conn, _ = self.socket.accept() conn.settimeout(5.0) try: @@ -32,6 +33,7 @@ class EchoSocket(): self.socket.shutdown(0) self.socket.close() + class MockApi(): def __init__(self, dongle_id): pass @@ -39,11 +41,12 @@ class MockApi(): def get_token(self): return "fake-token" + class MockParams(): def __init__(self): self.params = { "DongleId": b"0000000000000000", - "GithubSshKeys": b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC307aE+nuHzTAgaJhzSf5v7ZZQW9gaperjhCmyPyl4PzY7T1mDGenTlVTN7yoVFZ9UfO9oMQqo0n1OwDIiqbIFxqnhrHU0cYfj88rI85m5BEKlNu5RdaVTj1tcbaPpQc5kZEolaI1nDDjzV0lwS7jo5VYDHseiJHlik3HH1SgtdtsuamGR2T80q1SyW+5rHoMOJG73IH2553NnWuikKiuikGHUYBd00K1ilVAK2xSiMWJp55tQfZ0ecr9QjEsJ+J/efL4HqGNXhffxvypCXvbUYAFSddOwXUPo5BTKevpxMtH+2YrkpSjocWA04VnTYFiPG6U4ItKmbLOTFZtPzoez private" + "GithubSshKeys": b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC307aE+nuHzTAgaJhzSf5v7ZZQW9gaperjhCmyPyl4PzY7T1mDGenTlVTN7yoVFZ9UfO9oMQqo0n1OwDIiqbIFxqnhrHU0cYfj88rI85m5BEKlNu5RdaVTj1tcbaPpQc5kZEolaI1nDDjzV0lwS7jo5VYDHseiJHlik3HH1SgtdtsuamGR2T80q1SyW+5rHoMOJG73IH2553NnWuikKiuikGHUYBd00K1ilVAK2xSiMWJp55tQfZ0ecr9QjEsJ+J/efL4HqGNXhffxvypCXvbUYAFSddOwXUPo5BTKevpxMtH+2YrkpSjocWA04VnTYFiPG6U4ItKmbLOTFZtPzoez private" # noqa: E501 } def get(self, k, encoding=None): @@ -52,6 +55,7 @@ class MockParams(): ret = ret.decode(encoding) return ret + class MockWebsocket(): def __init__(self, recv_queue, send_queue): self.recv_queue = recv_queue @@ -66,6 +70,7 @@ class MockWebsocket(): def send(self, data, opcode): self.send_queue.put_nowait((data, opcode)) + class HTTPRequestHandler(http.server.SimpleHTTPRequestHandler): def do_PUT(self): length = int(self.headers['Content-Length']) @@ -73,6 +78,7 @@ class HTTPRequestHandler(http.server.SimpleHTTPRequestHandler): self.send_response(201, "Created") self.end_headers() + def http_server(port_queue, **kwargs): while 1: try: @@ -83,6 +89,7 @@ def http_server(port_queue, **kwargs): if e.errno == 98: continue + def with_http_server(func): @wraps(func) def inner(*args, **kwargs): diff --git a/selfdrive/boardd/SConscript b/selfdrive/boardd/SConscript index 14c1ff780d..94e630a641 100644 --- a/selfdrive/boardd/SConscript +++ b/selfdrive/boardd/SConscript @@ -1,9 +1,8 @@ -Import('env', 'common', 'messaging') +Import('env', 'common', 'cereal', 'messaging', 'cython_dependencies') -env.Program('boardd.cc', LIBS=['usb-1.0', common, messaging, 'pthread', 'zmq', 'capnp', 'kj']) +env.Program('boardd', ['boardd.cc', 'panda.cc', 'pigeon.cc'], LIBS=['usb-1.0', common, cereal, messaging, 'pthread', 'zmq', 'capnp', 'kj']) env.Library('libcan_list_to_can_capnp', ['can_list_to_can_capnp.cc']) -env.Command(['boardd_api_impl.so'], - ['libcan_list_to_can_capnp.a', 'boardd_api_impl.pyx', 'boardd_setup.py'], - "cd selfdrive/boardd && python3 boardd_setup.py build_ext --inplace") - +env.Command(['boardd_api_impl.so', 'boardd_api_impl.cpp'], + cython_dependencies + ['libcan_list_to_can_capnp.a', 'boardd_api_impl.pyx', 'boardd_setup.py'], + "cd selfdrive/boardd && python3 boardd_setup.py build_ext --inplace") diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index d5990bc1d8..146e219f90 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -1,656 +1,256 @@ #include -#include #include #include -#include #include #include #include +#include #include #include -#include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include -#include -#include "cereal/gen/cpp/log.capnp.h" #include "cereal/gen/cpp/car.capnp.h" #include "common/util.h" -#include "common/messaging.h" #include "common/params.h" #include "common/swaglog.h" #include "common/timing.h" #include "messaging.hpp" -#include -#include +#include "panda.h" +#include "pigeon.h" -// double the FIFO size -#define RECV_SIZE (0x1000) -#define TIMEOUT 0 #define MAX_IR_POWER 0.5f #define MIN_IR_POWER 0.0f -#define CUTOFF_GAIN 0.015625f // iso400 -#define SATURATE_GAIN 0.0625f // iso1600 +#define CUTOFF_IL 200 +#define SATURATE_IL 1600 #define NIBBLE_TO_HEX(n) ((n) < 10 ? (n) + '0' : ((n) - 10) + 'a') -#define VOLTAGE_K 0.091 // LPF gain for 5s tau (dt/tau / (dt/tau + 1)) - -namespace { +Panda * panda = NULL; +std::atomic safety_setter_thread_running(false); volatile sig_atomic_t do_exit = 0; - -struct __attribute__((packed)) timestamp_t { - uint16_t year; - uint8_t month; - uint8_t day; - uint8_t weekday; - uint8_t hour; - uint8_t minute; - uint8_t second; -}; - -libusb_context *ctx = NULL; -libusb_device_handle *dev_handle = NULL; -pthread_mutex_t usb_lock; - bool spoofing_started = false; bool fake_send = false; -bool loopback_can = false; -cereal::HealthData::HwType hw_type = cereal::HealthData::HwType::UNKNOWN; -bool is_pigeon = false; -const uint32_t NO_IGNITION_CNT_MAX = 2 * 60 * 60 * 30; // turn off charge after 30 hrs -const float VBATT_START_CHARGING = 11.5; -const float VBATT_PAUSE_CHARGING = 11.0; -float voltage_f = 12.5; // filtered voltage -uint32_t no_ignition_cnt = 0; bool connected_once = false; -bool ignition_last = false; -bool safety_setter_thread_initialized = false; -pthread_t safety_setter_thread_handle; +struct tm get_time(){ + time_t rawtime; + time(&rawtime); -bool pigeon_thread_initialized = false; -pthread_t pigeon_thread_handle; + struct tm sys_time; + gmtime_r(&rawtime, &sys_time); -bool pigeon_needs_init; + return sys_time; +} -void pigeon_init(); -void *pigeon_thread(void *crap); +bool time_valid(struct tm sys_time){ + return 1900 + sys_time.tm_year >= 2019; +} -void *safety_setter_thread(void *s) { +void safety_setter_thread() { + LOGD("Starting safety setter thread"); // diagnostic only is the default, needed for VIN query - pthread_mutex_lock(&usb_lock); - libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel::ELM327), 0, NULL, 0, TIMEOUT); - pthread_mutex_unlock(&usb_lock); - - char *value_vin; - size_t value_vin_sz = 0; + panda->set_safety_model(cereal::CarParams::SafetyModel::ELM327); // switch to SILENT when CarVin param is read while (1) { - if (do_exit) return NULL; - const int result = read_db_value("CarVin", &value_vin, &value_vin_sz); - if (value_vin_sz > 0) { + if (do_exit || !panda->connected){ + safety_setter_thread_running = false; + return; + }; + + std::vector value_vin = read_db_bytes("CarVin"); + if (value_vin.size() > 0) { // sanity check VIN format - assert(value_vin_sz == 17); + assert(value_vin.size() == 17); + std::string str_vin(value_vin.begin(), value_vin.end()); + LOGW("got CarVin %s", str_vin.c_str()); break; } usleep(100*1000); } - LOGW("got CarVin %s", value_vin); - free(value_vin); // VIN query done, stop listening to OBDII - pthread_mutex_lock(&usb_lock); - libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel::NO_OUTPUT), 0, NULL, 0, TIMEOUT); - pthread_mutex_unlock(&usb_lock); - - char *value; - size_t value_sz = 0; + panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT); + std::vector params; LOGW("waiting for params to set safety model"); while (1) { - if (do_exit) return NULL; + if (do_exit || !panda->connected){ + safety_setter_thread_running = false; + return; + }; - const int result = read_db_value("CarParams", &value, &value_sz); - if (value_sz > 0) break; + params = read_db_bytes("CarParams"); + if (params.size() > 0) break; usleep(100*1000); } - LOGW("got %d bytes CarParams", value_sz); + LOGW("got %d bytes CarParams", params.size()); // format for board, make copy due to alignment issues, will be freed on out of scope - auto amsg = kj::heapArray((value_sz / sizeof(capnp::word)) + 1); - memcpy(amsg.begin(), value, value_sz); - free(value); + auto amsg = kj::heapArray((params.size() / sizeof(capnp::word)) + 1); + memcpy(amsg.begin(), params.data(), params.size()); capnp::FlatArrayMessageReader cmsg(amsg); cereal::CarParams::Reader car_params = cmsg.getRoot(); + cereal::CarParams::SafetyModel safety_model = car_params.getSafetyModel(); - int safety_model = int(car_params.getSafetyModel()); auto safety_param = car_params.getSafetyParam(); - LOGW("setting safety model: %d with param %d", safety_model, safety_param); - - pthread_mutex_lock(&usb_lock); + LOGW("setting safety model: %d with param %d", (int)safety_model, safety_param); - // set in the mutex to avoid race - safety_setter_thread_initialized = false; + panda->set_safety_model(safety_model, safety_param); - libusb_control_transfer(dev_handle, 0x40, 0xdc, safety_model, safety_param, NULL, 0, TIMEOUT); - - pthread_mutex_unlock(&usb_lock); - - return NULL; + safety_setter_thread_running = false; } -// must be called before threads or with mutex + bool usb_connect() { - int err, err2; - unsigned char hw_query[1] = {0}; - unsigned char fw_sig_buf[128]; - unsigned char fw_sig_hex_buf[16]; - unsigned char serial_buf[16]; - const char *serial; - int serial_sz = 0; - - ignition_last = false; - - if (dev_handle != NULL){ - libusb_close(dev_handle); - dev_handle = NULL; + try { + assert(panda == NULL); + panda = new Panda(); + } catch (std::exception &e) { + return false; } - dev_handle = libusb_open_device_with_vid_pid(ctx, 0xbbaa, 0xddcc); - if (dev_handle == NULL) { goto fail; } - - err = libusb_set_configuration(dev_handle, 1); - if (err != 0) { goto fail; } - - err = libusb_claim_interface(dev_handle, 0); - if (err != 0) { goto fail; } - - if (loopback_can) { - libusb_control_transfer(dev_handle, 0xc0, 0xe5, 1, 0, NULL, 0, TIMEOUT); + if (getenv("BOARDD_LOOPBACK")) { + panda->set_loopback(true); } - // get panda fw - err = libusb_control_transfer(dev_handle, 0xc0, 0xd3, 0, 0, fw_sig_buf, 64, TIMEOUT); - err2 = libusb_control_transfer(dev_handle, 0xc0, 0xd4, 0, 0, fw_sig_buf + 64, 64, TIMEOUT); - if ((err == 64) && (err2 == 64)) { - printf("FW signature read\n"); - write_db_value("PandaFirmware", (const char *)fw_sig_buf, 128); + const char *fw_sig_buf = panda->get_firmware_version(); + if (fw_sig_buf){ + write_db_value("PandaFirmware", fw_sig_buf, 128); + // Convert to hex for offroad + char fw_sig_hex_buf[16] = {0}; for (size_t i = 0; i < 8; i++){ - fw_sig_hex_buf[2*i] = NIBBLE_TO_HEX(fw_sig_buf[i] >> 4); - fw_sig_hex_buf[2*i+1] = NIBBLE_TO_HEX(fw_sig_buf[i] & 0xF); + fw_sig_hex_buf[2*i] = NIBBLE_TO_HEX((uint8_t)fw_sig_buf[i] >> 4); + fw_sig_hex_buf[2*i+1] = NIBBLE_TO_HEX((uint8_t)fw_sig_buf[i] & 0xF); } - write_db_value("PandaFirmwareHex", (const char *)fw_sig_hex_buf, 16); - } - else { goto fail; } + + write_db_value("PandaFirmwareHex", fw_sig_hex_buf, 16); + LOGW("fw signature: %.*s", 16, fw_sig_hex_buf); + + delete[] fw_sig_buf; + } else { return false; } // get panda serial - err = libusb_control_transfer(dev_handle, 0xc0, 0xd0, 0, 0, serial_buf, 16, TIMEOUT); + const char *serial_buf = panda->get_serial(); + if (serial_buf) { + size_t serial_sz = strnlen(serial_buf, 16); - if (err > 0) { - serial = (const char *)serial_buf; - serial_sz = strnlen(serial, err); - write_db_value("PandaDongleId", serial, serial_sz); - printf("panda serial: %.*s\n", serial_sz, serial); - } - else { goto fail; } + write_db_value("PandaDongleId", serial_buf, serial_sz); + LOGW("panda serial: %.*s", serial_sz, serial_buf); + + delete[] serial_buf; + } else { return false; } // power on charging, only the first time. Panda can also change mode and it causes a brief disconneciton #ifndef __x86_64__ if (!connected_once) { - libusb_control_transfer(dev_handle, 0xc0, 0xe6, (uint16_t)(cereal::HealthData::UsbPowerMode::CDP), 0, NULL, 0, TIMEOUT); + panda->set_usb_power_mode(cereal::HealthData::UsbPowerMode::CDP); } #endif - connected_once = true; - libusb_control_transfer(dev_handle, 0xc0, 0xc1, 0, 0, hw_query, 1, TIMEOUT); - - hw_type = (cereal::HealthData::HwType)(hw_query[0]); - is_pigeon = (hw_type == cereal::HealthData::HwType::GREY_PANDA) || - (hw_type == cereal::HealthData::HwType::BLACK_PANDA) || - (hw_type == cereal::HealthData::HwType::UNO); - if (is_pigeon) { - LOGW("panda with gps detected"); - pigeon_needs_init = true; - if (!pigeon_thread_initialized) { - err = pthread_create(&pigeon_thread_handle, NULL, pigeon_thread, NULL); - assert(err == 0); - pigeon_thread_initialized = true; - } - } - - if (hw_type == cereal::HealthData::HwType::UNO){ - // Get time from system - time_t rawtime; - time(&rawtime); - - struct tm * sys_time = gmtime(&rawtime); - - // Get time from RTC - timestamp_t rtc_time; - libusb_control_transfer(dev_handle, 0xc0, 0xa0, 0, 0, (unsigned char*)&rtc_time, sizeof(rtc_time), TIMEOUT); + if (panda->has_rtc){ + struct tm sys_time = get_time(); + struct tm rtc_time = panda->get_rtc(); - //printf("System: %d-%d-%d\t%d:%d:%d\n", 1900 + sys_time->tm_year, 1 + sys_time->tm_mon, sys_time->tm_mday, sys_time->tm_hour, sys_time->tm_min, sys_time->tm_sec); - //printf("RTC: %d-%d-%d\t%d:%d:%d\n", rtc_time.year, rtc_time.month, rtc_time.day, rtc_time.hour, rtc_time.minute, rtc_time.second); - - // Update system time from RTC if it looks off, and RTC time is good - if (1900 + sys_time->tm_year < 2019 && rtc_time.year >= 2019){ + if (!time_valid(sys_time) && time_valid(rtc_time)) { LOGE("System time wrong, setting from RTC"); - struct tm new_time = { 0 }; - new_time.tm_year = rtc_time.year - 1900; - new_time.tm_mon = rtc_time.month - 1; - new_time.tm_mday = rtc_time.day; - new_time.tm_hour = rtc_time.hour; - new_time.tm_min = rtc_time.minute; - new_time.tm_sec = rtc_time.second; - setenv("TZ","UTC",1); - const struct timeval tv = {mktime(&new_time), 0}; + const struct timeval tv = {mktime(&rtc_time), 0}; settimeofday(&tv, 0); } } + connected_once = true; return true; -fail: - return false; } // must be called before threads or with mutex void usb_retry_connect() { - LOG("attempting to connect"); + LOGW("attempting to connect"); while (!usb_connect()) { usleep(100*1000); } LOGW("connected to board"); } -void handle_usb_issue(int err, const char func[]) { - LOGE_100("usb error %d \"%s\" in %s", err, libusb_strerror((enum libusb_error)err), func); - if (err == -4) { - LOGE("lost connection"); - usb_retry_connect(); - } - // TODO: check other errors, is simply retrying okay? -} - -void can_recv(PubSocket *publisher) { - int err; - uint32_t data[RECV_SIZE/4]; - int recv; - uint32_t f1, f2; - +void can_recv(PubMaster &pm) { uint64_t start_time = nanos_since_boot(); - // do recv - pthread_mutex_lock(&usb_lock); - - do { - err = libusb_bulk_transfer(dev_handle, 0x81, (uint8_t*)data, RECV_SIZE, &recv, TIMEOUT); - if (err != 0) { handle_usb_issue(err, __func__); } - if (err == -8) { LOGE_100("overflow got 0x%x", recv); }; - - // timeout is okay to exit, recv still happened - if (err == -7) { break; } - } while(err != 0); - - pthread_mutex_unlock(&usb_lock); - - // return if length is 0 - if (recv <= 0) { - return; - } else if (recv == RECV_SIZE) { - LOGW("Receive buffer full"); - } - // create message capnp::MallocMessageBuilder msg; cereal::Event::Builder event = msg.initRoot(); event.setLogMonoTime(start_time); - size_t num_msg = recv / 0x10; - auto canData = event.initCan(num_msg); - - // populate message - for (int i = 0; i < num_msg; i++) { - if (data[i*4] & 4) { - // extended - canData[i].setAddress(data[i*4] >> 3); - //printf("got extended: %x\n", data[i*4] >> 3); - } else { - // normal - canData[i].setAddress(data[i*4] >> 21); - } - canData[i].setBusTime(data[i*4+1] >> 16); - int len = data[i*4+1]&0xF; - canData[i].setDat(kj::arrayPtr((uint8_t*)&data[i*4+2], len)); - canData[i].setSrc((data[i*4+1] >> 4) & 0xff); - } - - // send to can - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - publisher->send((char*)bytes.begin(), bytes.size()); -} - -void can_health(PubSocket *publisher) { - int cnt; - int err; - - // copied from panda/board/main.c - struct __attribute__((packed)) health { - uint32_t uptime; - uint32_t voltage; - uint32_t current; - uint32_t can_rx_errs; - uint32_t can_send_errs; - uint32_t can_fwd_errs; - uint32_t gmlan_send_errs; - uint32_t faults; - uint8_t ignition_line; - uint8_t ignition_can; - uint8_t controls_allowed; - uint8_t gas_interceptor_detected; - uint8_t car_harness_status; - uint8_t usb_power_mode; - uint8_t safety_model; - uint8_t fault_status; - uint8_t power_save_enabled; - } health; - - // create message - capnp::MallocMessageBuilder msg; - cereal::Event::Builder event = msg.initRoot(); - event.setLogMonoTime(nanos_since_boot()); - auto healthData = event.initHealth(); - - bool received = false; - - // recv from board - if (dev_handle != NULL) { - pthread_mutex_lock(&usb_lock); - cnt = libusb_control_transfer(dev_handle, 0xc0, 0xd2, 0, 0, (unsigned char*)&health, sizeof(health), TIMEOUT); - pthread_mutex_unlock(&usb_lock); - - received = (cnt == sizeof(health)); - } - - // No panda connected, send empty health packet - if (!received){ - healthData.setHwType(cereal::HealthData::HwType::UNKNOWN); - - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - publisher->send((char*)bytes.begin(), bytes.size()); - return; - } - - if (spoofing_started) { - health.ignition_line = 1; - } - - voltage_f = VOLTAGE_K * (health.voltage / 1000.0) + (1.0 - VOLTAGE_K) * voltage_f; // LPF - - // Make sure CAN buses are live: safety_setter_thread does not work if Panda CAN are silent and there is only one other CAN node - if (health.safety_model == (uint8_t)(cereal::CarParams::SafetyModel::SILENT)) { - pthread_mutex_lock(&usb_lock); - libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel::NO_OUTPUT), 0, NULL, 0, TIMEOUT); - pthread_mutex_unlock(&usb_lock); - } - - bool ignition = ((health.ignition_line != 0) || (health.ignition_can != 0)); - - if (ignition) { - no_ignition_cnt = 0; - } else { - no_ignition_cnt += 1; - } - -#ifndef __x86_64__ - bool cdp_mode = health.usb_power_mode == (uint8_t)(cereal::HealthData::UsbPowerMode::CDP); - bool no_ignition_exp = no_ignition_cnt > NO_IGNITION_CNT_MAX; - if ((no_ignition_exp || (voltage_f < VBATT_PAUSE_CHARGING)) && cdp_mode && !ignition) { - char *disable_power_down = NULL; - size_t disable_power_down_sz = 0; - const int result = read_db_value("DisablePowerDown", &disable_power_down, &disable_power_down_sz); - if (disable_power_down_sz != 1 || disable_power_down[0] != '1') { - printf("TURN OFF CHARGING!\n"); - pthread_mutex_lock(&usb_lock); - libusb_control_transfer(dev_handle, 0xc0, 0xe6, (uint16_t)(cereal::HealthData::UsbPowerMode::CLIENT), 0, NULL, 0, TIMEOUT); - pthread_mutex_unlock(&usb_lock); - printf("POWER DOWN DEVICE\n"); - system("service call power 17 i32 0 i32 1"); - } - if (disable_power_down) free(disable_power_down); - } - if (!no_ignition_exp && (voltage_f > VBATT_START_CHARGING) && !cdp_mode) { - printf("TURN ON CHARGING!\n"); - pthread_mutex_lock(&usb_lock); - libusb_control_transfer(dev_handle, 0xc0, 0xe6, (uint16_t)(cereal::HealthData::UsbPowerMode::CDP), 0, NULL, 0, TIMEOUT); - pthread_mutex_unlock(&usb_lock); - } - // set power save state enabled when car is off and viceversa when it's on - if (ignition && (health.power_save_enabled == 1)) { - pthread_mutex_lock(&usb_lock); - libusb_control_transfer(dev_handle, 0xc0, 0xe7, 0, 0, NULL, 0, TIMEOUT); - pthread_mutex_unlock(&usb_lock); - } - if (!ignition && (health.power_save_enabled == 0)) { - pthread_mutex_lock(&usb_lock); - libusb_control_transfer(dev_handle, 0xc0, 0xe7, 1, 0, NULL, 0, TIMEOUT); - pthread_mutex_unlock(&usb_lock); - } - // set safety mode to NO_OUTPUT when car is off. ELM327 is an alternative if we want to leverage athenad/connect - if (!ignition && (health.safety_model != (uint8_t)(cereal::CarParams::SafetyModel::NO_OUTPUT))) { - pthread_mutex_lock(&usb_lock); - libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel::NO_OUTPUT), 0, NULL, 0, TIMEOUT); - pthread_mutex_unlock(&usb_lock); - } -#endif - - // clear VIN, CarParams, and set new safety on car start - if (ignition && !ignition_last) { - int result = delete_db_value("CarVin"); - assert((result == 0) || (result == ERR_NO_VALUE)); - result = delete_db_value("CarParams"); - assert((result == 0) || (result == ERR_NO_VALUE)); - - if (!safety_setter_thread_initialized) { - err = pthread_create(&safety_setter_thread_handle, NULL, safety_setter_thread, NULL); - assert(err == 0); - safety_setter_thread_initialized = true; - } - } - - // Get fan RPM - uint16_t fan_speed_rpm = 0; - - pthread_mutex_lock(&usb_lock); - int sz = libusb_control_transfer(dev_handle, 0xc0, 0xb2, 0, 0, (unsigned char*)&fan_speed_rpm, sizeof(fan_speed_rpm), TIMEOUT); - pthread_mutex_unlock(&usb_lock); - - // Write to rtc once per minute when no ignition present - if ((hw_type == cereal::HealthData::HwType::UNO) && !ignition && (no_ignition_cnt % 120 == 1)){ - // Get time from system - time_t rawtime; - time(&rawtime); - - struct tm * sys_time = gmtime(&rawtime); - - // Write time to RTC if it looks reasonable - if (1900 + sys_time->tm_year >= 2019){ - pthread_mutex_lock(&usb_lock); - libusb_control_transfer(dev_handle, 0x40, 0xa1, (uint16_t)(1900 + sys_time->tm_year), 0, NULL, 0, TIMEOUT); - libusb_control_transfer(dev_handle, 0x40, 0xa2, (uint16_t)(1 + sys_time->tm_mon), 0, NULL, 0, TIMEOUT); - libusb_control_transfer(dev_handle, 0x40, 0xa3, (uint16_t)sys_time->tm_mday, 0, NULL, 0, TIMEOUT); - // libusb_control_transfer(dev_handle, 0x40, 0xa4, (uint16_t)(1 + sys_time->tm_wday), 0, NULL, 0, TIMEOUT); - libusb_control_transfer(dev_handle, 0x40, 0xa5, (uint16_t)sys_time->tm_hour, 0, NULL, 0, TIMEOUT); - libusb_control_transfer(dev_handle, 0x40, 0xa6, (uint16_t)sys_time->tm_min, 0, NULL, 0, TIMEOUT); - libusb_control_transfer(dev_handle, 0x40, 0xa7, (uint16_t)sys_time->tm_sec, 0, NULL, 0, TIMEOUT); - pthread_mutex_unlock(&usb_lock); - } - } - - ignition_last = ignition; - - // set fields - healthData.setUptime(health.uptime); - healthData.setVoltage(health.voltage); - healthData.setCurrent(health.current); - healthData.setIgnitionLine(health.ignition_line); - healthData.setIgnitionCan(health.ignition_can); - healthData.setControlsAllowed(health.controls_allowed); - healthData.setGasInterceptorDetected(health.gas_interceptor_detected); - healthData.setHasGps(is_pigeon); - healthData.setCanRxErrs(health.can_rx_errs); - healthData.setCanSendErrs(health.can_send_errs); - healthData.setCanFwdErrs(health.can_fwd_errs); - healthData.setGmlanSendErrs(health.gmlan_send_errs); - healthData.setHwType(hw_type); - healthData.setUsbPowerMode(cereal::HealthData::UsbPowerMode(health.usb_power_mode)); - healthData.setSafetyModel(cereal::CarParams::SafetyModel(health.safety_model)); - healthData.setFanSpeedRpm(fan_speed_rpm); - healthData.setFaultStatus(cereal::HealthData::FaultStatus(health.fault_status)); - healthData.setPowerSaveEnabled((bool)(health.power_save_enabled)); - - // Convert faults bitset to capnp list - std::bitset fault_bits(health.faults); - auto faults = healthData.initFaults(fault_bits.count()); - - size_t i = 0; - for (size_t f = size_t(cereal::HealthData::FaultType::RELAY_MALFUNCTION); - f <= size_t(cereal::HealthData::FaultType::REGISTER_DIVERGENT); f++){ - if (fault_bits.test(f)) { - faults.set(i, cereal::HealthData::FaultType(f)); - i++; - } - } - // send to health - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - publisher->send((char*)bytes.begin(), bytes.size()); - - // send heartbeat back to panda - pthread_mutex_lock(&usb_lock); - libusb_control_transfer(dev_handle, 0x40, 0xf3, 1, 0, NULL, 0, TIMEOUT); - pthread_mutex_unlock(&usb_lock); -} - - -void can_send(SubSocket *subscriber) { - int err; - - // recv from sendcan - Message * msg = subscriber->receive(); - - auto amsg = kj::heapArray((msg->getSize() / sizeof(capnp::word)) + 1); - memcpy(amsg.begin(), msg->getData(), msg->getSize()); - - capnp::FlatArrayMessageReader cmsg(amsg); - cereal::Event::Reader event = cmsg.getRoot(); - if (nanos_since_boot() - event.getLogMonoTime() > 1e9) { - //Older than 1 second. Dont send. - delete msg; - return; - } - int msg_count = event.getSendcan().size(); - - uint32_t *send = (uint32_t*)malloc(msg_count*0x10); - memset(send, 0, msg_count*0x10); - - for (int i = 0; i < msg_count; i++) { - auto cmsg = event.getSendcan()[i]; - if (cmsg.getAddress() >= 0x800) { - // extended - send[i*4] = (cmsg.getAddress() << 3) | 5; - } else { - // normal - send[i*4] = (cmsg.getAddress() << 21) | 1; - } - assert(cmsg.getDat().size() <= 8); - send[i*4+1] = cmsg.getDat().size() | (cmsg.getSrc() << 4); - memcpy(&send[i*4+2], cmsg.getDat().begin(), cmsg.getDat().size()); - } - // release msg - delete msg; - - // send to board - int sent; - pthread_mutex_lock(&usb_lock); - - - if (!fake_send) { - do { - // Try sending can messages. If the receive buffer on the panda is full it will NAK - // and libusb will try again. After 5ms, it will time out. We will drop the messages. - err = libusb_bulk_transfer(dev_handle, 3, (uint8_t*)send, msg_count*0x10, &sent, 5); - if (err == LIBUSB_ERROR_TIMEOUT) { - LOGW("Transmit buffer full"); - break; - } else if (err != 0 || msg_count*0x10 != sent) { - LOGW("Error"); - handle_usb_issue(err, __func__); - } - } while(err != 0); + int recv = panda->can_receive(event); + if (recv){ + pm.send("can", msg); } - - pthread_mutex_unlock(&usb_lock); - - // done - free(send); } -// **** threads **** - -void *can_send_thread(void *crap) { +void can_send_thread() { LOGD("start send thread"); - // sendcan = 8017 Context * context = Context::create(); SubSocket * subscriber = SubSocket::create(context, "sendcan"); assert(subscriber != NULL); + subscriber->setTimeout(100); + // run as fast as messages come in + while (!do_exit && panda->connected) { + Message * msg = subscriber->receive(); - // drain sendcan to delete any stale messages from previous runs - while (true){ - Message * msg = subscriber->receive(true); - if (msg == NULL){ - break; + if (!msg){ + if (errno == EINTR) { + do_exit = true; + } + continue; } + + auto amsg = kj::heapArray((msg->getSize() / sizeof(capnp::word)) + 1); + memcpy(amsg.begin(), msg->getData(), msg->getSize()); + + capnp::FlatArrayMessageReader cmsg(amsg); + cereal::Event::Reader event = cmsg.getRoot(); + + //Dont send if older than 1 second + if (nanos_since_boot() - event.getLogMonoTime() < 1e9) { + if (!fake_send){ + panda->can_send(event.getSendcan()); + } + } + delete msg; } - // run as fast as messages come in - while (!do_exit) { - can_send(subscriber); - } - delete subscriber; delete context; - return NULL; } -void *can_recv_thread(void *crap) { +void can_recv_thread() { LOGD("start recv thread"); // can = 8006 - Context * c = Context::create(); - PubSocket * publisher = PubSocket::create(c, "can"); - assert(publisher != NULL); + PubMaster pm({"can"}); // run at 100hz const uint64_t dt = 10000000ULL; uint64_t next_frame_time = nanos_since_boot() + dt; - while (!do_exit) { - can_recv(publisher); + while (!do_exit && panda->connected) { + can_recv(pm); uint64_t cur_time = nanos_since_boot(); int64_t remaining = next_frame_time - cur_time; @@ -664,92 +264,186 @@ void *can_recv_thread(void *crap) { next_frame_time += dt; } - - delete publisher; - delete c; - return NULL; } -void *can_health_thread(void *crap) { +void can_health_thread() { LOGD("start health thread"); - // health = 8011 - Context * c = Context::create(); - PubSocket * publisher = PubSocket::create(c, "health"); - assert(publisher != NULL); + PubMaster pm({"health"}); - // run at 2hz - while (!do_exit) { - can_health(publisher); + uint32_t no_ignition_cnt = 0; + bool ignition_last = false; + + // Broadcast empty health message when panda is not yet connected + while (!panda){ + capnp::MallocMessageBuilder msg; + cereal::Event::Builder event = msg.initRoot(); + event.setLogMonoTime(nanos_since_boot()); + auto healthData = event.initHealth(); + + healthData.setHwType(cereal::HealthData::HwType::UNKNOWN); + pm.send("health", msg); usleep(500*1000); } - delete publisher; - delete c; - return NULL; -} + // run at 2hz + while (!do_exit && panda->connected) { + capnp::MallocMessageBuilder msg; + cereal::Event::Builder event = msg.initRoot(); + event.setLogMonoTime(nanos_since_boot()); + auto healthData = event.initHealth(); -void *hardware_control_thread(void *crap) { - LOGD("start hardware control thread"); - Context * c = Context::create(); - SubSocket * thermal_sock = SubSocket::create(c, "thermal"); - SubSocket * front_frame_sock = SubSocket::create(c, "frontFrame"); - assert(thermal_sock != NULL); - assert(front_frame_sock != NULL); + health_t health = panda->get_health(); - Poller * poller = Poller::create({thermal_sock, front_frame_sock}); + if (spoofing_started) { + health.ignition_line = 1; + } - // Wait for hardware type to be set. - while (hw_type == cereal::HealthData::HwType::UNKNOWN){ - usleep(100*1000); + // Make sure CAN buses are live: safety_setter_thread does not work if Panda CAN are silent and there is only one other CAN node + if (health.safety_model == (uint8_t)(cereal::CarParams::SafetyModel::SILENT)) { + panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT); + } + + bool ignition = ((health.ignition_line != 0) || (health.ignition_can != 0)); + + if (ignition) { + no_ignition_cnt = 0; + } else { + no_ignition_cnt += 1; + } + +#ifndef __x86_64__ + bool power_save_desired = !ignition; + if (health.power_save_enabled != power_save_desired){ + panda->set_power_saving(power_save_desired); + } + + // set safety mode to NO_OUTPUT when car is off. ELM327 is an alternative if we want to leverage athenad/connect + if (!ignition && (health.safety_model != (uint8_t)(cereal::CarParams::SafetyModel::NO_OUTPUT))) { + panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT); + } +#endif + + // clear VIN, CarParams, and set new safety on car start + if (ignition && !ignition_last) { + int result = delete_db_value("CarVin"); + assert((result == 0) || (result == ERR_NO_VALUE)); + result = delete_db_value("CarParams"); + assert((result == 0) || (result == ERR_NO_VALUE)); + + if (!safety_setter_thread_running) { + safety_setter_thread_running = true; + std::thread(safety_setter_thread).detach(); + } else { + LOGW("Safety setter thread already running"); + } + } + + // Write to rtc once per minute when no ignition present + if ((panda->has_rtc) && !ignition && (no_ignition_cnt % 120 == 1)){ + // Write time to RTC if it looks reasonable + struct tm sys_time = get_time(); + if (time_valid(sys_time)){ + panda->set_rtc(sys_time); + } + } + + ignition_last = ignition; + uint16_t fan_speed_rpm = panda->get_fan_speed(); + + // set fields + healthData.setUptime(health.uptime); + healthData.setVoltage(health.voltage); + healthData.setCurrent(health.current); + healthData.setIgnitionLine(health.ignition_line); + healthData.setIgnitionCan(health.ignition_can); + healthData.setControlsAllowed(health.controls_allowed); + healthData.setGasInterceptorDetected(health.gas_interceptor_detected); + healthData.setHasGps(panda->is_pigeon); + healthData.setCanRxErrs(health.can_rx_errs); + healthData.setCanSendErrs(health.can_send_errs); + healthData.setCanFwdErrs(health.can_fwd_errs); + healthData.setGmlanSendErrs(health.gmlan_send_errs); + healthData.setHwType(panda->hw_type); + healthData.setUsbPowerMode(cereal::HealthData::UsbPowerMode(health.usb_power_mode)); + healthData.setSafetyModel(cereal::CarParams::SafetyModel(health.safety_model)); + healthData.setFanSpeedRpm(fan_speed_rpm); + healthData.setFaultStatus(cereal::HealthData::FaultStatus(health.fault_status)); + healthData.setPowerSaveEnabled((bool)(health.power_save_enabled)); + + // Convert faults bitset to capnp list + std::bitset fault_bits(health.faults); + auto faults = healthData.initFaults(fault_bits.count()); + + size_t i = 0; + for (size_t f = size_t(cereal::HealthData::FaultType::RELAY_MALFUNCTION); + f <= size_t(cereal::HealthData::FaultType::INTERRUPT_RATE_TIM9); f++){ + if (fault_bits.test(f)) { + faults.set(i, cereal::HealthData::FaultType(f)); + i++; + } + } + pm.send("health", msg); + panda->send_heartbeat(); + usleep(500*1000); } - // Only control fan speed on UNO - if (hw_type != cereal::HealthData::HwType::UNO) return NULL; +} + +void hardware_control_thread() { + LOGD("start hardware control thread"); + SubMaster sm({"thermal", "frontFrame"}); + // Only control fan speed on UNO + if (panda->hw_type != cereal::HealthData::HwType::UNO) return; uint64_t last_front_frame_t = 0; uint16_t prev_fan_speed = 999; uint16_t ir_pwr = 0; uint16_t prev_ir_pwr = 999; +#ifdef QCOM + bool prev_charging_disabled = false; +#endif unsigned int cnt = 0; - while (!do_exit) { + while (!do_exit && panda->connected) { cnt++; - for (auto sock : poller->poll(1000)){ - Message * msg = sock->receive(); - if (msg == NULL) continue; - - auto amsg = kj::heapArray((msg->getSize() / sizeof(capnp::word)) + 1); - memcpy(amsg.begin(), msg->getData(), msg->getSize()); - - delete msg; - - capnp::FlatArrayMessageReader cmsg(amsg); - cereal::Event::Reader event = cmsg.getRoot(); - - auto type = event.which(); - if(type == cereal::Event::THERMAL){ - uint16_t fan_speed = event.getThermal().getFanSpeed(); - if (fan_speed != prev_fan_speed || cnt % 100 == 0){ - pthread_mutex_lock(&usb_lock); - libusb_control_transfer(dev_handle, 0x40, 0xb1, fan_speed, 0, NULL, 0, TIMEOUT); - pthread_mutex_unlock(&usb_lock); + sm.update(1000); // TODO: what happens if EINTR is sent while in sm.update? + + if (sm.updated("thermal")){ + // Fan speed + uint16_t fan_speed = sm["thermal"].getThermal().getFanSpeed(); + if (fan_speed != prev_fan_speed || cnt % 100 == 0){ + panda->set_fan_speed(fan_speed); + prev_fan_speed = fan_speed; + } - prev_fan_speed = fan_speed; - } - } else if (type == cereal::Event::FRONT_FRAME){ - float cur_front_gain = event.getFrontFrame().getGainFrac(); - last_front_frame_t = event.getLogMonoTime(); - - if (cur_front_gain <= CUTOFF_GAIN) { - ir_pwr = 100.0 * MIN_IR_POWER; - } else if (cur_front_gain > SATURATE_GAIN) { - ir_pwr = 100.0 * MAX_IR_POWER; +#ifdef QCOM + // Charging mode + bool charging_disabled = sm["thermal"].getThermal().getChargingDisabled(); + if (charging_disabled != prev_charging_disabled){ + if (charging_disabled){ + panda->set_usb_power_mode(cereal::HealthData::UsbPowerMode::CLIENT); + LOGW("TURN OFF CHARGING!\n"); } else { - ir_pwr = 100.0 * (MIN_IR_POWER + ((cur_front_gain - CUTOFF_GAIN) * (MAX_IR_POWER - MIN_IR_POWER) / (SATURATE_GAIN - CUTOFF_GAIN))); + panda->set_usb_power_mode(cereal::HealthData::UsbPowerMode::CDP); + LOGW("TURN ON CHARGING!\n"); } + prev_charging_disabled = charging_disabled; + } +#endif + } + if (sm.updated("frontFrame")){ + auto event = sm["frontFrame"]; + int cur_integ_lines = event.getFrontFrame().getIntegLines(); + last_front_frame_t = event.getLogMonoTime(); + + if (cur_integ_lines <= CUTOFF_IL) { + ir_pwr = 100.0 * MIN_IR_POWER; + } else if (cur_integ_lines > SATURATE_IL) { + ir_pwr = 100.0 * MAX_IR_POWER; + } else { + ir_pwr = 100.0 * (MIN_IR_POWER + ((cur_integ_lines - CUTOFF_IL) * (MAX_IR_POWER - MIN_IR_POWER) / (SATURATE_IL - CUTOFF_IL))); } } - // Disable ir_pwr on front frame timeout uint64_t cur_t = nanos_since_boot(); if (cur_t - last_front_frame_t > 1e9){ @@ -757,182 +451,67 @@ void *hardware_control_thread(void *crap) { } if (ir_pwr != prev_ir_pwr || cnt % 100 == 0 || ir_pwr >= 50.0){ - pthread_mutex_lock(&usb_lock); - libusb_control_transfer(dev_handle, 0x40, 0xb0, ir_pwr, 0, NULL, 0, TIMEOUT); - pthread_mutex_unlock(&usb_lock); + panda->set_ir_pwr(ir_pwr); prev_ir_pwr = ir_pwr; } } - - delete poller; - delete thermal_sock; - delete c; - - return NULL; -} - -#define pigeon_send(x) _pigeon_send(x, sizeof(x)-1) - -void hexdump(unsigned char *d, int l) { - for (int i = 0; i < l; i++) { - if (i!=0 && i%0x10 == 0) printf("\n"); - printf("%2.2X ", d[i]); - } - printf("\n"); -} - -void _pigeon_send(const char *dat, int len) { - int sent; - unsigned char a[0x20]; - int err; - a[0] = 1; - for (int i=0; i(); event.setLogMonoTime(nanos_since_boot()); - auto ublox_raw = event.initUbloxRaw(alen); - memcpy(ublox_raw.begin(), dat, alen); + auto ublox_raw = event.initUbloxRaw(dat.length()); + memcpy(ublox_raw.begin(), dat.data(), dat.length()); - // send to ubloxRaw - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - publisher->send((char*)bytes.begin(), bytes.size()); + pm.send("ubloxRaw", msg); } -void *pigeon_thread(void *crap) { +void pigeon_thread() { + if (!panda->is_pigeon){ return; }; + // ubloxRaw = 8042 - Context * context = Context::create(); - PubSocket * publisher = PubSocket::create(context, "ubloxRaw"); - assert(publisher != NULL); - - // run at ~100hz - unsigned char dat[0x1000]; - uint64_t cnt = 0; - while (!do_exit) { - if (pigeon_needs_init) { - pigeon_needs_init = false; - pigeon_init(); - } - int alen = 0; - while (alen < 0xfc0) { - pthread_mutex_lock(&usb_lock); - int len = libusb_control_transfer(dev_handle, 0xc0, 0xe0, 1, 0, dat+alen, 0x40, TIMEOUT); - if (len < 0) { handle_usb_issue(len, __func__); } - pthread_mutex_unlock(&usb_lock); - if (len <= 0) break; - - //printf("got %d\n", len); - alen += len; - } - if (alen > 0) { - if (dat[0] == (char)0x00){ + PubMaster pm({"ubloxRaw"}); + +#ifdef QCOM2 + Pigeon * pigeon = Pigeon::connect("/dev/ttyHS0"); +#else + Pigeon * pigeon = Pigeon::connect(panda); +#endif + + pigeon->init(); + + while (!do_exit && panda->connected) { + std::string recv = pigeon->receive(); + if (recv.length() > 0) { + if (recv[0] == (char)0x00){ LOGW("received invalid ublox message, resetting panda GPS"); - pigeon_init(); + pigeon->init(); } else { - pigeon_publish_raw(publisher, dat, alen); + pigeon_publish_raw(pm, recv); } } - // 10ms + // 10ms - 100 Hz usleep(10*1000); - cnt++; } - delete publisher; - delete context; - return NULL; + delete pigeon; } -} int main() { int err; LOGW("starting boardd"); - // set process priority - err = set_realtime_priority(4); - LOG("setpriority returns %d", err); + // set process priority and affinity + err = set_realtime_priority(54); + LOG("set priority returns %d", err); + err = set_core_affinity(3); + LOG("set affinity returns %d", err); // check the environment if (getenv("STARTED")) { @@ -943,64 +522,23 @@ int main() { fake_send = true; } - if (getenv("BOARDD_LOOPBACK")){ - loopback_can = true; - } - - err = pthread_mutex_init(&usb_lock, NULL); - assert(err == 0); + panda_set_power(true); - // init libusb - err = libusb_init(&ctx); - assert(err == 0); + while (!do_exit){ + std::vector threads; + threads.push_back(std::thread(can_health_thread)); -#if LIBUSB_API_VERSION >= 0x01000106 - libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO); -#else - libusb_set_debug(ctx, 3); -#endif - - pthread_t can_health_thread_handle; - err = pthread_create(&can_health_thread_handle, NULL, - can_health_thread, NULL); - assert(err == 0); - - // connect to the board - pthread_mutex_lock(&usb_lock); - usb_retry_connect(); - pthread_mutex_unlock(&usb_lock); - - // create threads - pthread_t can_send_thread_handle; - err = pthread_create(&can_send_thread_handle, NULL, - can_send_thread, NULL); - assert(err == 0); - - pthread_t can_recv_thread_handle; - err = pthread_create(&can_recv_thread_handle, NULL, - can_recv_thread, NULL); - assert(err == 0); - - pthread_t hardware_control_thread_handle; - err = pthread_create(&hardware_control_thread_handle, NULL, - hardware_control_thread, NULL); - assert(err == 0); - - // join threads - - err = pthread_join(can_recv_thread_handle, NULL); - assert(err == 0); - - err = pthread_join(can_send_thread_handle, NULL); - assert(err == 0); - - err = pthread_join(can_health_thread_handle, NULL); - assert(err == 0); + // connect to the board + usb_retry_connect(); - //while (!do_exit) usleep(1000); + threads.push_back(std::thread(can_send_thread)); + threads.push_back(std::thread(can_recv_thread)); + threads.push_back(std::thread(hardware_control_thread)); + threads.push_back(std::thread(pigeon_thread)); - // destruct libusb + for (auto &t : threads) t.join(); - libusb_close(dev_handle); - libusb_exit(ctx); + delete panda; + panda = NULL; + } } diff --git a/selfdrive/boardd/boardd_setup.py b/selfdrive/boardd/boardd_setup.py index cf71901cb6..4b08590183 100644 --- a/selfdrive/boardd/boardd_setup.py +++ b/selfdrive/boardd/boardd_setup.py @@ -1,15 +1,8 @@ -import subprocess from distutils.core import Extension, setup - from Cython.Build import cythonize from common.cython_hacks import BuildExtWithoutPlatformSuffix -from common.basedir import BASEDIR -import os - -PHONELIBS = os.path.join(BASEDIR, 'phonelibs') -ARCH = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip() libraries = ['can_list_to_can_capnp', 'capnp', 'kj'] setup(name='Boardd API Implementation', diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc new file mode 100644 index 0000000000..7604bd7371 --- /dev/null +++ b/selfdrive/boardd/panda.cc @@ -0,0 +1,355 @@ +#include +#include +#include + +#include + +#include "common/swaglog.h" +#include "common/gpio.h" + +#include "panda.h" + +void panda_set_power(bool power){ +#ifdef QCOM2 + int err = 0; + err += gpio_init(GPIO_STM_RST_N, true); + err += gpio_init(GPIO_STM_BOOT0, true); + err += gpio_init(GPIO_HUB_RST_N, true); + + err += gpio_set(GPIO_STM_RST_N, false); + + // TODO: set hub somewhere else + err += gpio_set(GPIO_HUB_RST_N, true); + err += gpio_set(GPIO_STM_BOOT0, false); + + usleep(100*1000); // 100 ms + + err += gpio_set(GPIO_STM_RST_N, power); + assert(err == 0); +#endif +} + +Panda::Panda(){ + int err; + + err = pthread_mutex_init(&usb_lock, NULL); + if (err != 0) { goto fail; } + + // init libusb + err = libusb_init(&ctx); + if (err != 0) { goto fail; } + +#if LIBUSB_API_VERSION >= 0x01000106 + libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO); +#else + libusb_set_debug(ctx, 3); +#endif + + dev_handle = libusb_open_device_with_vid_pid(ctx, 0xbbaa, 0xddcc); + if (dev_handle == NULL) { goto fail; } + + if (libusb_kernel_driver_active(dev_handle, 0) == 1) { + libusb_detach_kernel_driver(dev_handle, 0); + } + + err = libusb_set_configuration(dev_handle, 1); + if (err != 0) { goto fail; } + + err = libusb_claim_interface(dev_handle, 0); + if (err != 0) { goto fail; } + + hw_type = get_hw_type(); + is_pigeon = + (hw_type == cereal::HealthData::HwType::GREY_PANDA) || + (hw_type == cereal::HealthData::HwType::BLACK_PANDA) || + (hw_type == cereal::HealthData::HwType::UNO) || + (hw_type == cereal::HealthData::HwType::DOS); + has_rtc = (hw_type == cereal::HealthData::HwType::UNO) || + (hw_type == cereal::HealthData::HwType::DOS); + + return; + +fail: + cleanup(); + throw std::runtime_error("Error connecting to panda"); +} + +Panda::~Panda(){ + pthread_mutex_lock(&usb_lock); + cleanup(); + connected = false; + pthread_mutex_unlock(&usb_lock); +} + +void Panda::cleanup(){ + if (dev_handle){ + libusb_release_interface(dev_handle, 0); + libusb_close(dev_handle); + } + + if (ctx) { + libusb_exit(ctx); + } +} + +void Panda::handle_usb_issue(int err, const char func[]) { + LOGE_100("usb error %d \"%s\" in %s", err, libusb_strerror((enum libusb_error)err), func); + if (err == LIBUSB_ERROR_NO_DEVICE) { + LOGE("lost connection"); + connected = false; + } + // TODO: check other errors, is simply retrying okay? +} + +int Panda::usb_write(uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned int timeout) { + int err; + const uint8_t bmRequestType = LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE; + + if (!connected){ + return LIBUSB_ERROR_NO_DEVICE; + } + + pthread_mutex_lock(&usb_lock); + do { + err = libusb_control_transfer(dev_handle, bmRequestType, bRequest, wValue, wIndex, NULL, 0, timeout); + if (err < 0) handle_usb_issue(err, __func__); + } while (err < 0 && connected); + + pthread_mutex_unlock(&usb_lock); + + return err; +} + +int Panda::usb_read(uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char *data, uint16_t wLength, unsigned int timeout) { + int err; + const uint8_t bmRequestType = LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE; + + pthread_mutex_lock(&usb_lock); + do { + err = libusb_control_transfer(dev_handle, bmRequestType, bRequest, wValue, wIndex, data, wLength, timeout); + if (err < 0) handle_usb_issue(err, __func__); + } while (err < 0 && connected); + pthread_mutex_unlock(&usb_lock); + + return err; +} + +int Panda::usb_bulk_write(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) { + int err; + int transferred = 0; + + if (!connected){ + return 0; + } + + pthread_mutex_lock(&usb_lock); + do { + // Try sending can messages. If the receive buffer on the panda is full it will NAK + // and libusb will try again. After 5ms, it will time out. We will drop the messages. + err = libusb_bulk_transfer(dev_handle, endpoint, data, length, &transferred, timeout); + + if (err == LIBUSB_ERROR_TIMEOUT) { + LOGW("Transmit buffer full"); + break; + } else if (err != 0 || length != transferred) { + handle_usb_issue(err, __func__); + } + } while(err != 0 && connected); + + pthread_mutex_unlock(&usb_lock); + return transferred; +} + +int Panda::usb_bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) { + int err; + int transferred = 0; + + if (!connected){ + return 0; + } + + pthread_mutex_lock(&usb_lock); + + do { + err = libusb_bulk_transfer(dev_handle, endpoint, data, length, &transferred, timeout); + + if (err == LIBUSB_ERROR_TIMEOUT) { + break; // timeout is okay to exit, recv still happened + } else if (err == LIBUSB_ERROR_OVERFLOW) { + LOGE_100("overflow got 0x%x", transferred); + } else if (err != 0) { + handle_usb_issue(err, __func__); + } + + } while(err != 0 && connected); + + pthread_mutex_unlock(&usb_lock); + + return transferred; +} + +void Panda::set_safety_model(cereal::CarParams::SafetyModel safety_model, int safety_param){ + usb_write(0xdc, (uint16_t)safety_model, safety_param); +} + +cereal::HealthData::HwType Panda::get_hw_type() { + unsigned char hw_query[1] = {0}; + + usb_read(0xc1, 0, 0, hw_query, 1); + return (cereal::HealthData::HwType)(hw_query[0]); +} + +void Panda::set_rtc(struct tm sys_time){ + // tm struct has year defined as years since 1900 + usb_write(0xa1, (uint16_t)(1900 + sys_time.tm_year), 0); + usb_write(0xa2, (uint16_t)(1 + sys_time.tm_mon), 0); + usb_write(0xa3, (uint16_t)sys_time.tm_mday, 0); + // usb_write(0xa4, (uint16_t)(1 + sys_time.tm_wday), 0); + usb_write(0xa5, (uint16_t)sys_time.tm_hour, 0); + usb_write(0xa6, (uint16_t)sys_time.tm_min, 0); + usb_write(0xa7, (uint16_t)sys_time.tm_sec, 0); +} + +struct tm Panda::get_rtc(){ + struct __attribute__((packed)) timestamp_t { + uint16_t year; // Starts at 0 + uint8_t month; + uint8_t day; + uint8_t weekday; + uint8_t hour; + uint8_t minute; + uint8_t second; + } rtc_time = {0}; + + usb_read(0xa0, 0, 0, (unsigned char*)&rtc_time, sizeof(rtc_time)); + + struct tm new_time = { 0 }; + new_time.tm_year = rtc_time.year - 1900; // tm struct has year defined as years since 1900 + new_time.tm_mon = rtc_time.month - 1; + new_time.tm_mday = rtc_time.day; + new_time.tm_hour = rtc_time.hour; + new_time.tm_min = rtc_time.minute; + new_time.tm_sec = rtc_time.second; + + return new_time; +} + +void Panda::set_fan_speed(uint16_t fan_speed){ + usb_write(0xb1, fan_speed, 0); +} + +uint16_t Panda::get_fan_speed(){ + uint16_t fan_speed_rpm = 0; + usb_read(0xb2, 0, 0, (unsigned char*)&fan_speed_rpm, sizeof(fan_speed_rpm)); + return fan_speed_rpm; +} + +void Panda::set_ir_pwr(uint16_t ir_pwr) { + usb_write(0xb0, ir_pwr, 0); +} + +health_t Panda::get_health(){ + health_t health {0}; + usb_read(0xd2, 0, 0, (unsigned char*)&health, sizeof(health)); + return health; +} + +void Panda::set_loopback(bool loopback){ + usb_write(0xe5, loopback, 0); +} + +const char* Panda::get_firmware_version(){ + const char* fw_sig_buf = new char[128](); + + int read_1 = usb_read(0xd3, 0, 0, (unsigned char*)fw_sig_buf, 64); + int read_2 = usb_read(0xd4, 0, 0, (unsigned char*)fw_sig_buf + 64, 64); + + if ((read_1 == 64) && (read_2 == 64)) { + return fw_sig_buf; + } + + delete[] fw_sig_buf; + return NULL; +} + +const char* Panda::get_serial(){ + const char* serial_buf = new char[16](); + + int err = usb_read(0xd0, 0, 0, (unsigned char*)serial_buf, 16); + + if (err >= 0) { + return serial_buf; + } + + delete[] serial_buf; + return NULL; + +} + +void Panda::set_power_saving(bool power_saving){ + usb_write(0xe7, power_saving, 0); +} + +void Panda::set_usb_power_mode(cereal::HealthData::UsbPowerMode power_mode){ + usb_write(0xe6, (uint16_t)power_mode, 0); +} + +void Panda::send_heartbeat(){ + usb_write(0xf3, 1, 0); +} + +void Panda::can_send(capnp::List::Reader can_data_list){ + int msg_count = can_data_list.size(); + + uint32_t *send = new uint32_t[msg_count*0x10](); + + for (int i = 0; i < msg_count; i++) { + auto cmsg = can_data_list[i]; + if (cmsg.getAddress() >= 0x800) { // extended + send[i*4] = (cmsg.getAddress() << 3) | 5; + } else { // normal + send[i*4] = (cmsg.getAddress() << 21) | 1; + } + auto can_data = cmsg.getDat(); + assert(can_data.size() <= 8); + send[i*4+1] = can_data.size() | (cmsg.getSrc() << 4); + memcpy(&send[i*4+2], can_data.begin(), can_data.size()); + } + + usb_bulk_write(3, (unsigned char*)send, msg_count*0x10, 5); + + delete[] send; +} + +int Panda::can_receive(cereal::Event::Builder &event){ + uint32_t data[RECV_SIZE/4]; + int recv = usb_bulk_read(0x81, (unsigned char*)data, RECV_SIZE); + + // return if length is 0 + if (recv <= 0) { + return 0; + } else if (recv == RECV_SIZE) { + LOGW("Receive buffer full"); + } + + size_t num_msg = recv / 0x10; + auto canData = event.initCan(num_msg); + + // populate message + for (int i = 0; i < num_msg; i++) { + if (data[i*4] & 4) { + // extended + canData[i].setAddress(data[i*4] >> 3); + //printf("got extended: %x\n", data[i*4] >> 3); + } else { + // normal + canData[i].setAddress(data[i*4] >> 21); + } + canData[i].setBusTime(data[i*4+1] >> 16); + int len = data[i*4+1]&0xF; + canData[i].setDat(kj::arrayPtr((uint8_t*)&data[i*4+2], len)); + canData[i].setSrc((data[i*4+1] >> 4) & 0xff); + } + + return recv; +} diff --git a/selfdrive/boardd/panda.h b/selfdrive/boardd/panda.h new file mode 100644 index 0000000000..c3e2dc981e --- /dev/null +++ b/selfdrive/boardd/panda.h @@ -0,0 +1,81 @@ +#pragma once + +#include +#include +#include + +#include + +#include "cereal/gen/cpp/car.capnp.h" +#include "cereal/gen/cpp/log.capnp.h" + +// double the FIFO size +#define RECV_SIZE (0x1000) +#define TIMEOUT 0 + +// copied from panda/board/main.c +struct __attribute__((packed)) health_t { + uint32_t uptime; + uint32_t voltage; + uint32_t current; + uint32_t can_rx_errs; + uint32_t can_send_errs; + uint32_t can_fwd_errs; + uint32_t gmlan_send_errs; + uint32_t faults; + uint8_t ignition_line; + uint8_t ignition_can; + uint8_t controls_allowed; + uint8_t gas_interceptor_detected; + uint8_t car_harness_status; + uint8_t usb_power_mode; + uint8_t safety_model; + uint8_t fault_status; + uint8_t power_save_enabled; +}; + + +void panda_set_power(bool power); + +class Panda { + private: + libusb_context *ctx = NULL; + libusb_device_handle *dev_handle = NULL; + pthread_mutex_t usb_lock; + void handle_usb_issue(int err, const char func[]); + void cleanup(); + + public: + Panda(); + ~Panda(); + + bool connected = true; + cereal::HealthData::HwType hw_type = cereal::HealthData::HwType::UNKNOWN; + bool is_pigeon = false; + bool has_rtc = false; + + // HW communication + int usb_write(uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned int timeout=TIMEOUT); + int usb_read(uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char *data, uint16_t wLength, unsigned int timeout=TIMEOUT); + int usb_bulk_write(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout=TIMEOUT); + int usb_bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout=TIMEOUT); + + // Panda functionality + cereal::HealthData::HwType get_hw_type(); + void set_safety_model(cereal::CarParams::SafetyModel safety_model, int safety_param=0); + void set_rtc(struct tm sys_time); + struct tm get_rtc(); + void set_fan_speed(uint16_t fan_speed); + uint16_t get_fan_speed(); + void set_ir_pwr(uint16_t ir_pwr); + health_t get_health(); + void set_loopback(bool loopback); + const char* get_firmware_version(); + const char* get_serial(); + void set_power_saving(bool power_saving); + void set_usb_power_mode(cereal::HealthData::UsbPowerMode power_mode); + void send_heartbeat(); + void can_send(capnp::List::Reader can_data_list); + int can_receive(cereal::Event::Builder &event); + +}; diff --git a/selfdrive/boardd/pigeon.cc b/selfdrive/boardd/pigeon.cc new file mode 100644 index 0000000000..4ec7ebf8ce --- /dev/null +++ b/selfdrive/boardd/pigeon.cc @@ -0,0 +1,226 @@ +#include +#include +#include +#include +#include + +#include "common/swaglog.h" +#include "common/gpio.h" + +#include "pigeon.h" + +// Termios on macos doesn't define all baud rate constants +#ifndef B460800 +#define B460800 0010004 +#endif + +using namespace std::string_literals; + + +Pigeon * Pigeon::connect(Panda * p){ + PandaPigeon * pigeon = new PandaPigeon(); + pigeon->connect(p); + + return pigeon; +} + +Pigeon * Pigeon::connect(const char * tty){ + TTYPigeon * pigeon = new TTYPigeon(); + pigeon->connect(tty); + + return pigeon; +} + +void Pigeon::init() { + usleep(1000*1000); + LOGW("panda GPS start"); + + // power off pigeon + set_power(0); + usleep(100*1000); + + // 9600 baud at init + set_baud(9600); + + // power on pigeon + set_power(1); + usleep(500*1000); + + // baud rate upping + send("\x24\x50\x55\x42\x58\x2C\x34\x31\x2C\x31\x2C\x30\x30\x30\x37\x2C\x30\x30\x30\x33\x2C\x34\x36\x30\x38\x30\x30\x2C\x30\x2A\x31\x35\x0D\x0A"s); + usleep(100*1000); + + // set baud rate to 460800 + set_baud(460800); + usleep(100*1000); + + // init from ubloxd + // To generate this data, run test/ubloxd.py with the print statements enabled in the write function in panda/python/serial.py + send("\xB5\x62\x06\x00\x14\x00\x03\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x1E\x7F"s); + send("\xB5\x62\x06\x3E\x00\x00\x44\xD2"s); + send("\xB5\x62\x06\x00\x14\x00\x00\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\x35"s); + send("\xB5\x62\x06\x00\x14\x00\x01\x00\x00\x00\xC0\x08\x00\x00\x00\x08\x07\x00\x01\x00\x01\x00\x00\x00\x00\x00\xF4\x80"s); + send("\xB5\x62\x06\x00\x14\x00\x04\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1D\x85"s); + send("\xB5\x62\x06\x00\x00\x00\x06\x18"s); + send("\xB5\x62\x06\x00\x01\x00\x01\x08\x22"s); + send("\xB5\x62\x06\x00\x01\x00\x02\x09\x23"s); + send("\xB5\x62\x06\x00\x01\x00\x03\x0A\x24"s); + send("\xB5\x62\x06\x08\x06\x00\x64\x00\x01\x00\x00\x00\x79\x10"s); + send("\xB5\x62\x06\x24\x24\x00\x05\x00\x04\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x5A\x63"s); + send("\xB5\x62\x06\x1E\x14\x00\x00\x00\x00\x00\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3C\x37"s); + send("\xB5\x62\x06\x24\x00\x00\x2A\x84"s); + send("\xB5\x62\x06\x23\x00\x00\x29\x81"s); + send("\xB5\x62\x06\x1E\x00\x00\x24\x72"s); + send("\xB5\x62\x06\x01\x03\x00\x01\x07\x01\x13\x51"s); + send("\xB5\x62\x06\x01\x03\x00\x02\x15\x01\x22\x70"s); + send("\xB5\x62\x06\x01\x03\x00\x02\x13\x01\x20\x6C"s); + send("\xB5\x62\x06\x01\x03\x00\x0A\x09\x01\x1E\x70"s); + + LOGW("panda GPS on"); +} + +void PandaPigeon::connect(Panda * p) { + panda = p; +} + +void PandaPigeon::set_baud(int baud) { + panda->usb_write(0xe2, 1, 0); + panda->usb_write(0xe4, 1, baud/300); +} + +void PandaPigeon::send(std::string s) { + int len = s.length(); + const char * dat = s.data(); + + unsigned char a[0x20+1]; + a[0] = 1; + for (int i=0; iusb_bulk_write(2, a, ll+1); + } +} + +std::string PandaPigeon::receive() { + std::string r; + + while (true){ + unsigned char dat[0x40]; + int len = panda->usb_read(0xe0, 1, 0, dat, sizeof(dat)); + if (len <= 0 || r.length() > 0x1000) break; + r.append((char*)dat, len); + } + + return r; +} + +void PandaPigeon::set_power(bool power) { + panda->usb_write(0xd9, power, 0); +} + +PandaPigeon::~PandaPigeon(){ +} + +void handle_tty_issue(int err, const char func[]) { + LOGE_100("tty error %d \"%s\" in %s", err, strerror(err), func); +} + +void TTYPigeon::connect(const char * tty) { + pigeon_tty_fd = open(tty, O_RDWR); + if (pigeon_tty_fd < 0){ + handle_tty_issue(errno, __func__); + assert(pigeon_tty_fd >= 0); + } + assert(tcgetattr(pigeon_tty_fd, &pigeon_tty) == 0); + + // configure tty + pigeon_tty.c_cflag &= ~PARENB; // disable parity + pigeon_tty.c_cflag &= ~CSTOPB; // single stop bit + pigeon_tty.c_cflag |= CS8; // 8 bits per byte + pigeon_tty.c_cflag &= ~CRTSCTS; // no RTS/CTS flow control + pigeon_tty.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines + pigeon_tty.c_lflag &= ~ICANON; // disable canonical mode + pigeon_tty.c_lflag &= ~ISIG; // disable interpretation of INTR, QUIT and SUSP + pigeon_tty.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off software flow ctrl + pigeon_tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // disable any special handling of received bytes + pigeon_tty.c_oflag &= ~OPOST; // prevent special interpretation of output bytes + pigeon_tty.c_oflag &= ~ONLCR; // prevent conversion of newline to carriage return/line feed + + // configure blocking behavior + pigeon_tty.c_cc[VMIN] = 0; // min amount of characters returned + pigeon_tty.c_cc[VTIME] = 0; // max blocking time in s/10 (0=inf) + + assert(tcsetattr(pigeon_tty_fd, TCSANOW, &pigeon_tty) == 0); +} + +void TTYPigeon::set_baud(int baud){ + speed_t baud_const = 0; + switch(baud){ + case 9600: + baud_const = B9600; + break; + case 460800: + baud_const = B460800; + break; + default: + assert(false); + } + + // make sure everything is tx'ed before changing baud + assert(tcdrain(pigeon_tty_fd) == 0); + + // change baud + assert(tcgetattr(pigeon_tty_fd, &pigeon_tty) == 0); + assert(cfsetspeed(&pigeon_tty, baud_const) == 0); + assert(tcsetattr(pigeon_tty_fd, TCSANOW, &pigeon_tty) == 0); + + // flush + assert(tcflush(pigeon_tty_fd, TCIOFLUSH) == 0); +} + +void TTYPigeon::send(std::string s) { + int len = s.length(); + const char * dat = s.data(); + + int err = write(pigeon_tty_fd, dat, len); + if(err < 0) { handle_tty_issue(err, __func__); } + err = tcdrain(pigeon_tty_fd); + if(err < 0) { handle_tty_issue(err, __func__); } +} + +std::string TTYPigeon::receive() { + std::string r; + + while (true){ + char dat[0x40]; + int len = read(pigeon_tty_fd, dat, sizeof(dat)); + if(len < 0) { + handle_tty_issue(len, __func__); + } else if (len == 0 || r.length() > 0x1000){ + break; + } else { + r.append(dat, len); + } + + } + return r; +} + +void TTYPigeon::set_power(bool power){ +#ifdef QCOM2 + int err = 0; + err += gpio_init(GPIO_UBLOX_RST_N, true); + err += gpio_init(GPIO_UBLOX_SAFEBOOT_N, true); + err += gpio_init(GPIO_UBLOX_PWR_EN, true); + + err += gpio_set(GPIO_UBLOX_RST_N, power); + err += gpio_set(GPIO_UBLOX_SAFEBOOT_N, power); + err += gpio_set(GPIO_UBLOX_PWR_EN, power); + assert(err == 0); +#endif +} + +TTYPigeon::~TTYPigeon(){ + close(pigeon_tty_fd); +} diff --git a/selfdrive/boardd/pigeon.h b/selfdrive/boardd/pigeon.h new file mode 100644 index 0000000000..667ac70610 --- /dev/null +++ b/selfdrive/boardd/pigeon.h @@ -0,0 +1,43 @@ +#pragma once +#include +#include + + +#include "panda.h" + +class Pigeon { + public: + static Pigeon* connect(Panda * p); + static Pigeon* connect(const char * tty); + virtual ~Pigeon(){}; + + void init(); + virtual void set_baud(int baud) = 0; + virtual void send(std::string s) = 0; + virtual std::string receive() = 0; + virtual void set_power(bool power) = 0; +}; + +class PandaPigeon : public Pigeon { + Panda * panda = NULL; +public: + ~PandaPigeon(); + void connect(Panda * p); + void set_baud(int baud); + void send(std::string s); + std::string receive(); + void set_power(bool power); +}; + + +class TTYPigeon : public Pigeon { + int pigeon_tty_fd = -1; + struct termios pigeon_tty; +public: + ~TTYPigeon(); + void connect(const char* tty); + void set_baud(int baud); + void send(std::string s); + std::string receive(); + void set_power(bool power); +}; diff --git a/selfdrive/boardd/tests/boardd_old.py b/selfdrive/boardd/tests/boardd_old.py index f6ca7eb87d..4fd2350bff 100755 --- a/selfdrive/boardd/tests/boardd_old.py +++ b/selfdrive/boardd/tests/boardd_old.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 +# pylint: skip-file -# This file is not used by OpenPilot. Only boardd.cc is used. +# This file is not used by openpilot. Only boardd.cc is used. # The python version is slower, but has more options for development. # TODO: merge the extra functionalities of this file (like MOCK) in boardd.c and @@ -21,7 +22,7 @@ SafetyModel = car.CarParams.SafetyModel # USB is optional try: import usb1 - from usb1 import USBErrorIO, USBErrorOverflow #pylint: disable=no-name-in-module + from usb1 import USBErrorIO, USBErrorOverflow # pylint: disable=no-name-in-module except Exception: pass @@ -57,7 +58,7 @@ def __parse_can_buffer(dat): for j in range(0, len(dat), 0x10): ddat = dat[j:j+0x10] f1, f2 = struct.unpack("II", ddat[0:8]) - ret.append((f1 >> 21, f2>>16, ddat[8:8+(f2&0xF)], (f2>>4)&0xFF)) + ret.append((f1 >> 21, f2 >> 16, ddat[8:8 + (f2 & 0xF)], (f2 >> 4) & 0xFF)) return ret def can_send_many(arr): @@ -138,7 +139,7 @@ def boardd_test_loop(): can_init() cnt = 0 while 1: - can_send_many([[0xbb,0,"\xaa\xaa\xaa\xaa",0], [0xaa,0,"\xaa\xaa\xaa\xaa"+struct.pack("!I", cnt),1]]) + can_send_many([[0xbb, 0, "\xaa\xaa\xaa\xaa", 0], [0xaa, 0, "\xaa\xaa\xaa\xaa"+struct.pack("!I", cnt), 1]]) #can_send_many([[0xaa,0,"\xaa\xaa\xaa\xaa",0]]) #can_send_many([[0xaa,0,"\xaa\xaa\xaa\xaa",1]]) # recv @ 100hz diff --git a/selfdrive/boardd/tests/replay_many.py b/selfdrive/boardd/tests/replay_many.py index 7596b47a14..71db229a21 100755 --- a/selfdrive/boardd/tests/replay_many.py +++ b/selfdrive/boardd/tests/replay_many.py @@ -10,7 +10,7 @@ from multiprocessing import Pool jungle = "JUNGLE" in os.environ if jungle: - from panda_jungle import PandaJungle # pylint: disable=import-error + from panda_jungle import PandaJungle # pylint: disable=import-error import cereal.messaging as messaging from selfdrive.boardd.boardd import can_capnp_to_can_list @@ -56,7 +56,6 @@ if __name__ == "__main__": serials = Panda.list() num_senders = len(serials) - if num_senders == 0: print("No senders found. Exiting") sys.exit(1) diff --git a/selfdrive/boardd/tests/test_boardd_api.py b/selfdrive/boardd/tests/test_boardd_api.py index f41e1e3571..9386c7845e 100644 --- a/selfdrive/boardd/tests/test_boardd_api.py +++ b/selfdrive/boardd/tests/test_boardd_api.py @@ -12,7 +12,7 @@ import unittest def generate_random_can_data_list(): can_list = [] cnt = random.randint(1, 64) - for j in range(cnt): + for _ in range(cnt): can_data = np.random.bytes(random.randint(1, 8)) can_list.append([random.randint(0, 128), random.randint(0, 128), can_data, random.randint(0, 128)]) return can_list, cnt @@ -54,18 +54,18 @@ class TestBoarddApiMethods(unittest.TestCase): self.assertEqual(getattr(ev.can[i], attr, 'new'), getattr(ev_old.can[i], attr, 'old')) def test_performance(self): - can_list, cnt = generate_random_can_data_list() + can_list, _ = generate_random_can_data_list() recursions = 1000 n1 = sec_since_boot() - for i in range(recursions): + for _ in range(recursions): boardd_old.can_list_to_can_capnp(can_list, 'sendcan').to_bytes() n2 = sec_since_boot() elapsed_old = n2 - n1 # print('Old API, elapsed time: {} secs'.format(elapsed_old)) n1 = sec_since_boot() - for i in range(recursions): + for _ in range(recursions): boardd.can_list_to_can_capnp(can_list) n2 = sec_since_boot() elapsed_new = n2 - n1 diff --git a/selfdrive/boardd/tests/test_boardd_loopback.py b/selfdrive/boardd/tests/test_boardd_loopback.py index cb88776a0a..d6c110bbbe 100755 --- a/selfdrive/boardd/tests/test_boardd_loopback.py +++ b/selfdrive/boardd/tests/test_boardd_loopback.py @@ -1,47 +1,87 @@ #!/usr/bin/env python3 -"""Run boardd with the BOARDD_LOOPBACK envvar before running this test.""" - import os import random import time +from collections import defaultdict +from functools import wraps +import cereal.messaging as messaging +from cereal import car +from common.basedir import PARAMS +from common.android import ANDROID +from common.params import Params +from common.spinner import Spinner +from panda import Panda from selfdrive.boardd.boardd import can_list_to_can_capnp -from cereal.messaging import drain_sock, pub_sock, sub_sock +from selfdrive.car import make_can_msg +from selfdrive.test.helpers import with_processes + + +def reset_panda(fn): + @wraps(fn) + def wrapper(): + p = Panda() + for i in [0, 1, 2, 0xFFFF]: + p.can_clear(i) + p.reset() + p.close() + fn() + return wrapper + +os.environ['STARTED'] = '1' +os.environ['BOARDD_LOOPBACK'] = '1' +os.environ['PARAMS_PATH'] = PARAMS -def get_test_string(): - return b"test"+os.urandom(10) +@reset_panda +@with_processes(['boardd']) +def test_boardd_loopback(): + # wait for boardd to init + spinner = Spinner(noop=(not ANDROID)) + time.sleep(2) -BUS = 0 + # boardd blocks on CarVin and CarParams + cp = car.CarParams.new_message() + cp.safetyModel = car.CarParams.SafetyModel.allOutput + Params().put("CarVin", b"0"*17) + Params().put("CarParams", cp.to_bytes()) -def main(): - rcv = sub_sock('can') # port 8006 - snd = pub_sock('sendcan') # port 8017 - time.sleep(0.3) # wait to bind before send/recv + sendcan = messaging.pub_sock('sendcan') + can = messaging.sub_sock('can', conflate=False, timeout=100) - for i in range(10): - print("Loop %d" % i) - at = random.randint(1024, 2000) - st = get_test_string()[0:8] - snd.send(can_list_to_can_capnp([[at, 0, st, 0]], msgtype='sendcan').to_bytes()) - time.sleep(0.1) - res = drain_sock(rcv, True) - assert len(res) == 1 + time.sleep(1) - res = res[0].can - assert len(res) == 2 + n = 1000 + for i in range(n): + spinner.update(f"boardd loopback {i}/{n}") - msg0, msg1 = res + sent_msgs = defaultdict(set) + for _ in range(random.randrange(10)): + to_send = [] + for __ in range(random.randrange(100)): + bus = random.randrange(3) + addr = random.randrange(1, 1<<29) + dat = bytes([random.getrandbits(8) for _ in range(random.randrange(1, 9))]) + sent_msgs[bus].add((addr, dat)) + to_send.append(make_can_msg(addr, dat, bus)) + sendcan.send(can_list_to_can_capnp(to_send, msgtype='sendcan')) - assert msg0.dat == st - assert msg1.dat == st + max_recv = 10 + while max_recv > 0 and any(len(sent_msgs[bus]) for bus in range(3)): + recvd = messaging.drain_sock(can, wait_for_one=True) + for msg in recvd: + for m in msg.can: + if m.src >= 128: + k = (m.address, m.dat) + assert k in sent_msgs[m.src-128] + sent_msgs[m.src-128].discard(k) + max_recv -= 1 - assert msg0.address == at - assert msg1.address == at + # if a set isn't empty, messages got dropped + for bus in range(3): + assert not len(sent_msgs[bus]), f"loop {i}: bus {bus} missing {len(sent_msgs[bus])} messages" - assert msg0.src == 0x80 | BUS - assert msg1.src == BUS + spinner.close() - print("Success") if __name__ == "__main__": - main() + test_boardd_loopback() diff --git a/selfdrive/camerad/SConscript b/selfdrive/camerad/SConscript index 0fc320fb92..3a706e2251 100644 --- a/selfdrive/camerad/SConscript +++ b/selfdrive/camerad/SConscript @@ -1,10 +1,13 @@ -Import('env', 'arch', 'messaging', 'common', 'gpucommon', 'visionipc', 'cereal', 'webcam') +Import('env', 'arch', 'cereal', 'messaging', 'common', 'gpucommon', 'visionipc', 'webcam', 'QCOM_REPLAY') -libs = ['m', 'pthread', common, 'jpeg', cereal, 'OpenCL', messaging, 'czmq', 'zmq', 'capnp', 'kj', visionipc, gpucommon] +libs = ['m', 'pthread', common, 'jpeg', 'OpenCL', cereal, messaging, 'czmq', 'zmq', 'capnp', 'kj', visionipc, gpucommon] if arch == "aarch64": libs += ['gsl', 'CB', 'adreno_utils', 'EGL', 'GLESv3', 'cutils', 'ui'] - cameras = ['cameras/camera_qcom.cc'] + if QCOM_REPLAY: + cameras = ['cameras/camera_frame_stream.cc'] + else: + cameras = ['cameras/camera_qcom.cc'] elif arch == "larch64": libs += [] cameras = ['cameras/camera_qcom2.c'] @@ -23,6 +26,10 @@ else: else: libs += [] cameras = ['cameras/camera_frame_stream.cc'] + if arch == "Darwin": + del libs[libs.index('OpenCL')] + env = env.Clone() + env['FRAMEWORKS'] = ['OpenCL'] env.SharedLibrary('snapshot/visionipc', ["#selfdrive/common/visionipc.c", "#selfdrive/common/ipc.c"]) diff --git a/selfdrive/camerad/cameras/camera_frame_stream.cc b/selfdrive/camerad/cameras/camera_frame_stream.cc index 00385ac75f..9a4263103d 100644 --- a/selfdrive/camerad/cameras/camera_frame_stream.cc +++ b/selfdrive/camerad/cameras/camera_frame_stream.cc @@ -1,15 +1,11 @@ #include "camera_frame_stream.h" -#include #include -#include #include #include #include #include -#include -#include "cereal/gen/cpp/log.capnp.h" #include "messaging.hpp" #include "common/util.h" @@ -36,9 +32,7 @@ void camera_close(CameraState *s) { tbuffer_stop(&s->camera_tb); } -void camera_release_buffer(void *cookie, int buf_idx) { - CameraState *s = static_cast(cookie); -} +void camera_release_buffer(void *cookie, int buf_idx) {} void camera_init(CameraState *s, int camera_id, unsigned int fps) { assert(camera_id < ARRAYSIZE(cameras_supported)); @@ -52,23 +46,15 @@ void camera_init(CameraState *s, int camera_id, unsigned int fps) { } void run_frame_stream(MultiCameraState *s) { - int err; - Context * context = Context::create(); - SubSocket * recorder_sock = SubSocket::create(context, "frame"); - assert(recorder_sock != NULL); + SubMaster sm({"frame"}); CameraState *const rear_camera = &s->rear; auto *tb = &rear_camera->camera_tb; while (!do_exit) { - Message * msg = recorder_sock->receive(); - - auto amsg = kj::heapArray((msg->getSize() / sizeof(capnp::word)) + 1); - memcpy(amsg.begin(), msg->getData(), msg->getSize()); + if (sm.update(1000) == 0) continue; - capnp::FlatArrayMessageReader cmsg(amsg); - cereal::Event::Reader event = cmsg.getRoot(); - auto frame = event.getFrame(); + auto frame = sm["frame"].getFrame(); const int buf_idx = tbuffer_select(tb); rear_camera->camera_bufs_metadata[buf_idx] = { @@ -81,35 +67,21 @@ void run_frame_stream(MultiCameraState *s) { cl_command_queue q = rear_camera->camera_bufs[buf_idx].copy_q; cl_mem yuv_cl = rear_camera->camera_bufs[buf_idx].buf_cl; - cl_event map_event; - void *yuv_buf = (void *)clEnqueueMapBuffer(q, yuv_cl, CL_TRUE, - CL_MAP_WRITE, 0, frame.getImage().size(), - 0, NULL, &map_event, &err); - assert(err == 0); - clWaitForEvents(1, &map_event); - clReleaseEvent(map_event); - memcpy(yuv_buf, frame.getImage().begin(), frame.getImage().size()); - - clEnqueueUnmapMemObject(q, yuv_cl, yuv_buf, 0, NULL, &map_event); - clWaitForEvents(1, &map_event); - clReleaseEvent(map_event); - tbuffer_dispatch(tb, buf_idx); - delete msg; + clEnqueueWriteBuffer(q, yuv_cl, CL_TRUE, 0, frame.getImage().size(), frame.getImage().begin(), 0, NULL, NULL); + tbuffer_dispatch(tb, buf_idx); } - delete recorder_sock; - delete context; } } // namespace CameraInfo cameras_supported[CAMERA_ID_MAX] = { [CAMERA_ID_IMX298] = { - .frame_width = FRAME_WIDTH, - .frame_height = FRAME_HEIGHT, - .frame_stride = FRAME_WIDTH*3, - .bayer = false, - .bayer_flip = false, + .frame_width = FRAME_WIDTH, + .frame_height = FRAME_HEIGHT, + .frame_stride = FRAME_WIDTH*3, + .bayer = false, + .bayer_flip = false, }, [CAMERA_ID_OV8865] = { .frame_width = 1632, @@ -122,8 +94,6 @@ CameraInfo cameras_supported[CAMERA_ID_MAX] = { }; void cameras_init(MultiCameraState *s) { - memset(s, 0, sizeof(*s)); - camera_init(&s->rear, CAMERA_ID_IMX298, 20); s->rear.transform = (mat3){{ 1.0, 0.0, 0.0, @@ -146,7 +116,6 @@ void cameras_open(MultiCameraState *s, VisionBuf *camera_bufs_rear, VisionBuf *camera_bufs_front) { assert(camera_bufs_rear); assert(camera_bufs_front); - int err; // LOG("*** open front ***"); camera_open(&s->front, camera_bufs_front, false); diff --git a/selfdrive/camerad/cameras/camera_qcom.cc b/selfdrive/camerad/cameras/camera_qcom.cc index a47fd586e6..4e8958818c 100644 --- a/selfdrive/camerad/cameras/camera_qcom.cc +++ b/selfdrive/camerad/cameras/camera_qcom.cc @@ -12,7 +12,6 @@ #include #include -#include #include #include "msmb_isp.h" #include "msmb_ispif.h" @@ -108,8 +107,6 @@ static void camera_release_buffer(void* cookie, int buf_idx) { static void camera_init(CameraState *s, int camera_id, int camera_num, uint32_t pixel_clock, uint32_t line_length_pclk, unsigned int max_gain, unsigned int fps) { - memset(s, 0, sizeof(*s)); - s->camera_num = camera_num; s->camera_id = camera_id; @@ -123,9 +120,11 @@ static void camera_init(CameraState *s, int camera_id, int camera_num, s->max_gain = max_gain; s->fps = fps; - zsock_t *ops_sock = zsock_new_push(">inproc://cameraops"); - assert(ops_sock); - s->ops_sock = zsock_resolve(ops_sock); + s->self_recover = 0; + + s->ops_sock = zsock_new_push(">inproc://cameraops"); + assert(s->ops_sock); + s->ops_sock_handle = zsock_resolve(s->ops_sock); tbuffer_init2(&s->camera_tb, FRAME_BUF_COUNT, "frame", camera_release_buffer, s); @@ -161,16 +160,6 @@ static int imx298_apply_exposure(CameraState *s, int gain, int integ_lines, int //printf("%5d/%5d %5d %f\n", s->cur_integ_lines, s->cur_frame_length, analog_gain, s->digital_gain); - int digital_gain = 0x100; - - float white_balance[] = {0.4609375, 1.0, 0.546875}; - //float white_balance[] = {1.0, 1.0, 1.0}; - - int digital_gain_gr = digital_gain / white_balance[1]; - int digital_gain_gb = digital_gain / white_balance[1]; - int digital_gain_r = digital_gain / white_balance[0]; - int digital_gain_b = digital_gain / white_balance[2]; - struct msm_camera_i2c_reg_array reg_array[] = { // REG_HOLD {0x104,0x1,0}, @@ -201,23 +190,24 @@ static int imx298_apply_exposure(CameraState *s, int gain, int integ_lines, int return err; } -static inline int ov8865_get_coarse_gain(int gain) { - static const int gains[] = {0, 256, 384, 448, 480}; - int i; +static int ov8865_apply_exposure(CameraState *s, int gain, int integ_lines, int frame_length) { + //printf("front camera: %d %d %d\n", gain, integ_lines, frame_length); + int err, coarse_gain_bitmap, fine_gain_bitmap; + // get bitmaps from iso + static const int gains[] = {0, 100, 200, 400, 800}; + int i; for (i = 1; i < ARRAYSIZE(gains); i++) { if (gain >= gains[i - 1] && gain < gains[i]) break; } + int coarse_gain = i - 1; + float fine_gain = (gain - gains[coarse_gain])/(float)(gains[coarse_gain+1]-gains[coarse_gain]); + coarse_gain_bitmap = (1 << coarse_gain) - 1; + fine_gain_bitmap = ((int)(16*fine_gain) << 3) + 128; // 7th is always 1, 0-2nd are always 0 - return i - 1; -} - -static int ov8865_apply_exposure(CameraState *s, int gain, int integ_lines, int frame_length) { - //printf("front camera: %d %d %d\n", gain, integ_lines, frame_length); - int err, gain_bitmap; - gain_bitmap = (1 << ov8865_get_coarse_gain(gain)) - 1; integ_lines *= 16; // The exposure value in reg is in 16ths of a line + struct msm_camera_i2c_reg_array reg_array[] = { //{0x104,0x1,0}, @@ -228,7 +218,7 @@ static int ov8865_apply_exposure(CameraState *s, int gain, int integ_lines, int // AEC MANUAL {0x3503, 0x4, 0}, // AEC GAIN - {0x3508, (uint16_t)(gain_bitmap), 0}, {0x3509, 0xf8, 0}, + {0x3508, (uint16_t)(coarse_gain_bitmap), 0}, {0x3509, (uint16_t)(fine_gain_bitmap), 0}, //{0x104,0x0,0}, }; @@ -269,8 +259,6 @@ static int imx179_s5k3p8sp_apply_exposure(CameraState *s, int gain, int integ_li } void cameras_init(MultiCameraState *s) { - memset(s, 0, sizeof(*s)); - char project_name[1024] = {0}; property_get("ro.boot.project_name", project_name, ""); @@ -386,7 +374,10 @@ static void set_exposure(CameraState *s, float exposure_frac, float gain_frac) { || integ_lines != s->cur_integ_lines || frame_length != s->cur_frame_length) { - if (s->apply_exposure) { + if (s->apply_exposure == ov8865_apply_exposure) { + gain = 800 * gain_frac; // ISO + err = s->apply_exposure(s, gain, integ_lines, frame_length); + } else if (s->apply_exposure) { err = s->apply_exposure(s, gain, integ_lines, frame_length); } @@ -401,7 +392,9 @@ static void set_exposure(CameraState *s, float exposure_frac, float gain_frac) { if (err == 0) { s->cur_exposure_frac = exposure_frac; + pthread_mutex_lock(&s->frame_info_lock); s->cur_gain_frac = gain_frac; + pthread_mutex_unlock(&s->frame_info_lock); } //LOGD("set exposure: %f %f - %d", exposure_frac, gain_frac, err); @@ -409,19 +402,44 @@ static void set_exposure(CameraState *s, float exposure_frac, float gain_frac) { static void do_autoexposure(CameraState *s, float grey_frac) { const float target_grey = 0.3; + if (s->apply_exposure == ov8865_apply_exposure) { + // gain limits downstream + const float gain_frac_min = 0.015625; + const float gain_frac_max = 1.0; + // exposure time limits + unsigned int frame_length = s->pixel_clock / s->line_length_pclk / s->fps; + const unsigned int exposure_time_min = 16; + const unsigned int exposure_time_max = frame_length - 11; // copied from set_exposure() + + float cur_gain_frac = s->cur_gain_frac; + float exposure_factor = pow(1.05, (target_grey - grey_frac) / 0.05); + if (cur_gain_frac > 0.125 && exposure_factor < 1) { + cur_gain_frac *= exposure_factor; + } else if (s->cur_integ_lines * exposure_factor <= exposure_time_max && s->cur_integ_lines * exposure_factor >= exposure_time_min) { // adjust exposure time first + s->cur_exposure_frac *= exposure_factor; + } else if (cur_gain_frac * exposure_factor <= gain_frac_max && cur_gain_frac * exposure_factor >= gain_frac_min) { + cur_gain_frac *= exposure_factor; + } + pthread_mutex_lock(&s->frame_info_lock); + s->cur_gain_frac = cur_gain_frac; + pthread_mutex_unlock(&s->frame_info_lock); + + set_exposure(s, s->cur_exposure_frac, cur_gain_frac); + + } else { // keep the old for others + float new_exposure = s->cur_exposure_frac; + new_exposure *= pow(1.05, (target_grey - grey_frac) / 0.05 ); + //LOGD("diff %f: %f to %f", target_grey - grey_frac, s->cur_exposure_frac, new_exposure); + + float new_gain = s->cur_gain_frac; + if (new_exposure < 0.10) { + new_gain *= 0.95; + } else if (new_exposure > 0.40) { + new_gain *= 1.05; + } - float new_exposure = s->cur_exposure_frac; - new_exposure *= pow(1.05, (target_grey - grey_frac) / 0.05 ); - //LOGD("diff %f: %f to %f", target_grey - grey_frac, s->cur_exposure_frac, new_exposure); - - float new_gain = s->cur_gain_frac; - if (new_exposure < 0.10) { - new_gain *= 0.95; - } else if (new_exposure > 0.40) { - new_gain *= 1.05; + set_exposure(s, new_exposure, new_gain); } - - set_exposure(s, new_exposure, new_gain); } void camera_autoexposure(CameraState *s, float grey_frac) { @@ -431,7 +449,7 @@ void camera_autoexposure(CameraState *s, float grey_frac) { .grey_frac = grey_frac, }; - zmq_send(s->ops_sock, &msg, sizeof(msg), ZMQ_DONTWAIT); + zmq_send(s->ops_sock_handle, &msg, sizeof(msg), ZMQ_DONTWAIT); } static uint8_t* get_eeprom(int eeprom_fd, size_t *out_len) { @@ -1745,8 +1763,13 @@ static void parse_autofocus(CameraState *s, uint8_t *d) { avg_focus += s->focus[i]; } } + // self recover override + if (s->self_recover > 1) { + s->focus_err = 200 * ((s->self_recover % 2 == 0) ? 1:-1); // far for even numbers, close for odd + s->self_recover -= 2; + return; + } - //printf("\n"); if (good_count < 4) { s->focus_err = nan(""); return; @@ -1770,18 +1793,19 @@ static void do_autofocus(CameraState *s) { float err = s->focus_err; float sag = (s->last_sag_acc_z/9.8) * 128; - const int dac_up = s->device == DEVICE_LP3? 634:456; - const int dac_down = s->device == DEVICE_LP3? 366:224; + const int dac_up = s->device == DEVICE_LP3? LP3_AF_DAC_UP:OP3T_AF_DAC_UP; + const int dac_down = s->device == DEVICE_LP3? LP3_AF_DAC_DOWN:OP3T_AF_DAC_DOWN; + float lens_true_pos = s->lens_true_pos; if (!isnan(err)) { // learn lens_true_pos - s->lens_true_pos -= err*focus_kp; + lens_true_pos -= err*focus_kp; } // stay off the walls - s->lens_true_pos = clamp(s->lens_true_pos, dac_down, dac_up); - - int target = clamp(s->lens_true_pos - sag, dac_down, dac_up); + lens_true_pos = clamp(lens_true_pos, dac_down, dac_up); + int target = clamp(lens_true_pos - sag, dac_down, dac_up); + s->lens_true_pos = lens_true_pos; /*char debug[4096]; char *pdebug = debug; @@ -1934,6 +1958,8 @@ static void camera_close(CameraState *s) { } free(s->eeprom); + + zsock_destroy(&s->ops_sock); } @@ -1980,43 +2006,6 @@ static FrameMetadata get_frame_metadata(CameraState *s, uint32_t frame_id) { }; } -static bool acceleration_from_sensor_sock(void *sock, float *vs) { - int err; - bool ret = false; - zmq_msg_t msg; - err = zmq_msg_init(&msg); - assert(err == 0); - - err = zmq_msg_recv(&msg, sock, 0); - assert(err >= 0); - - void *data = zmq_msg_data(&msg); - size_t size = zmq_msg_size(&msg); - - auto amsg = kj::heapArray(size / sizeof(capnp::word) + 1); - memcpy(amsg.begin(), data, size); - capnp::FlatArrayMessageReader cmsg(amsg); - auto event = cmsg.getRoot(); - if (event.which() == cereal::Event::SENSOR_EVENTS) { - auto sensor_events = event.getSensorEvents(); - for (auto sensor_event : sensor_events) { - if (sensor_event.which() == cereal::SensorEventData::ACCELERATION) { - auto v = sensor_event.getAcceleration().getV(); - if (v.size() < 3) { - continue; //wtf - } - for (int j = 0; j < 3; j++) { - vs[j] = v[j]; - } - ret = true; - break; - } - } - } - zmq_msg_close(&msg); - return ret; -} - static void ops_term() { zsock_t *ops_sock = zsock_new_push(">inproc://cameraops"); assert(ops_sock); @@ -2036,66 +2025,85 @@ static void* ops_thread(void* arg) { zsock_t *cameraops = zsock_new_pull("@inproc://cameraops"); assert(cameraops); - zsock_t *sensor_sock = zsock_new_sub(">tcp://127.0.0.1:8003", ""); - assert(sensor_sock); - zsock_t *terminate = zsock_new_sub(">inproc://terminate", ""); assert(terminate); - zpoller_t *poller = zpoller_new(cameraops, sensor_sock, terminate, NULL); + zpoller_t *poller = zpoller_new(cameraops, terminate, NULL); assert(poller); - while (!do_exit) { + SubMaster sm({"sensorEvents"}); // msgq submaster + while (!do_exit) { + // zmq handling zsock_t *which = (zsock_t*)zpoller_wait(poller, -1); - if (which == terminate || which == NULL) { + if (which == terminate) { break; - } - void* sockraw = zsock_resolve(which); - - if (which == cameraops) { - zmq_msg_t msg; - err = zmq_msg_init(&msg); - assert(err == 0); - - err = zmq_msg_recv(&msg, sockraw, 0); - assert(err >= 0); - - CameraMsg cmsg; - if (zmq_msg_size(&msg) == sizeof(cmsg)) { - memcpy(&cmsg, zmq_msg_data(&msg), zmq_msg_size(&msg)); - - //LOGD("cameraops %d", cmsg.type); + } else if (which != NULL) { + void* sockraw = zsock_resolve(which); + + if (which == cameraops) { + zmq_msg_t msg; + err = zmq_msg_init(&msg); + assert(err == 0); + + err = zmq_msg_recv(&msg, sockraw, 0); + if (err >= 0) { + CameraMsg cmsg; + if (zmq_msg_size(&msg) == sizeof(cmsg)) { + memcpy(&cmsg, zmq_msg_data(&msg), zmq_msg_size(&msg)); + + //LOGD("cameraops %d", cmsg.type); + + if (cmsg.type == CAMERA_MSG_AUTOEXPOSE) { + if (cmsg.camera_num == 0) { + do_autoexposure(&s->rear, cmsg.grey_frac); + do_autofocus(&s->rear); + } else { + do_autoexposure(&s->front, cmsg.grey_frac); + } + } else if (cmsg.type == -1) { + break; + } + } + } else { + // skip if zmq is interrupted by msgq + int err_no = zmq_errno(); + assert(err_no == EINTR || err_no == EAGAIN); + } - if (cmsg.type == CAMERA_MSG_AUTOEXPOSE) { - if (cmsg.camera_num == 0) { - do_autoexposure(&s->rear, cmsg.grey_frac); - do_autofocus(&s->rear); - } else { - do_autoexposure(&s->front, cmsg.grey_frac); + zmq_msg_close(&msg); + } + } + // msgq handling + if (sm.update(0) > 0) { + float vals[3] = {0.0}; + bool got_accel = false; + + auto sensor_events = sm["sensorEvents"].getSensorEvents(); + for (auto sensor_event : sensor_events) { + if (sensor_event.which() == cereal::SensorEventData::ACCELERATION) { + auto v = sensor_event.getAcceleration().getV(); + if (v.size() < 3) { + continue; //wtf } - } else if (cmsg.type == -1) { + for (int j = 0; j < 3; j++) { + vals[j] = v[j]; + } + got_accel = true; break; } } - zmq_msg_close(&msg); - - } else if (which == sensor_sock) { - float vs[3] = {0.0}; - bool got_accel = acceleration_from_sensor_sock(sockraw, vs); - uint64_t ts = nanos_since_boot(); if (got_accel && ts - s->rear.last_sag_ts > 10000000) { // 10 ms s->rear.last_sag_ts = ts; - s->rear.last_sag_acc_z = -vs[2]; + s->rear.last_sag_acc_z = -vals[2]; } } } zpoller_destroy(&poller); zsock_destroy(&cameraops); - zsock_destroy(&sensor_sock); zsock_destroy(&terminate); return NULL; diff --git a/selfdrive/camerad/cameras/camera_qcom.h b/selfdrive/camerad/cameras/camera_qcom.h index bb9e513027..e2456c253a 100644 --- a/selfdrive/camerad/cameras/camera_qcom.h +++ b/selfdrive/camerad/cameras/camera_qcom.h @@ -1,9 +1,11 @@ -#ifndef CAMERA_H -#define CAMERA_H +#pragma once #include #include #include +#include +#include +#include "messaging.hpp" #include "msmb_isp.h" #include "msmb_ispif.h" @@ -25,6 +27,18 @@ #define NUM_FOCUS 8 +#define LP3_AF_DAC_DOWN 366 +#define LP3_AF_DAC_UP 634 +#define LP3_AF_DAC_M 440 +#define LP3_AF_DAC_3SIG 52 +#define OP3T_AF_DAC_DOWN 224 +#define OP3T_AF_DAC_UP 456 +#define OP3T_AF_DAC_M 300 +#define OP3T_AF_DAC_3SIG 96 + +#define FOCUS_RECOVER_PATIENCE 50 // 2.5 seconds of complete blur +#define FOCUS_RECOVER_STEPS 240 // 6 seconds + #ifdef __cplusplus extern "C" { #endif @@ -48,7 +62,8 @@ typedef struct CameraState { int device; - void* ops_sock; + void* ops_sock_handle; + zsock_t * ops_sock; uint32_t pixel_clock; uint32_t line_length_pclk; @@ -81,7 +96,7 @@ typedef struct CameraState { int cur_frame_length; int cur_integ_lines; - float digital_gain; + std::atomic digital_gain; StreamState ss[3]; @@ -98,7 +113,9 @@ typedef struct CameraState { uint16_t cur_lens_pos; uint64_t last_sag_ts; float last_sag_acc_z; - float lens_true_pos; + std::atomic lens_true_pos; + + std::atomic self_recover; // af recovery counter, neg is patience, pos is active int fps; @@ -127,5 +144,3 @@ int sensor_write_regs(CameraState *s, struct msm_camera_i2c_reg_array* arr, size #ifdef __cplusplus } // extern "C" #endif - -#endif diff --git a/selfdrive/camerad/cameras/camera_qcom2.c b/selfdrive/camerad/cameras/camera_qcom2.c index 035a95d103..3116a062bc 100644 --- a/selfdrive/camerad/cameras/camera_qcom2.c +++ b/selfdrive/camerad/cameras/camera_qcom2.c @@ -28,6 +28,7 @@ //#define FRAME_STRIDE 1936 // for 8 bit output #define FRAME_STRIDE 2416 // for 10 bit output +/* static void hexdump(uint8_t *data, int len) { for (int i = 0; i < len; i++) { if (i!=0&&i%0x10==0) printf("\n"); @@ -35,6 +36,7 @@ static void hexdump(uint8_t *data, int len) { } printf("\n"); } +*/ extern volatile sig_atomic_t do_exit; @@ -80,8 +82,6 @@ int device_control(int fd, int op_code, int session_handle, int dev_handle) { } void *alloc_w_mmu_hdl(int video0_fd, int len, int align, int flags, uint32_t *handle, int mmu_hdl, int mmu_hdl2) { - int ret; - struct cam_mem_mgr_alloc_cmd mem_mgr_alloc_cmd = {0}; mem_mgr_alloc_cmd.len = len; mem_mgr_alloc_cmd.align = align; @@ -141,7 +141,7 @@ void sensors_poke(struct CameraState *s, int request_id) { pkt->header.size = size; pkt->header.op_code = 0x7f; pkt->header.request_id = request_id; - struct cam_cmd_buf_desc *buf_desc = (struct cam_cmd_buf_desc *)&pkt->payload; + //struct cam_cmd_buf_desc *buf_desc = (struct cam_cmd_buf_desc *)&pkt->payload; struct cam_config_dev_cmd config_dev_cmd = {}; config_dev_cmd.session_handle = s->session_handle; @@ -170,7 +170,7 @@ void sensors_i2c(struct CameraState *s, struct i2c_random_wr_payload* dat, int l buf_desc[0].size = buf_desc[0].length = sizeof(struct cam_cmd_i2c_random_wr) + (len-1)*sizeof(struct i2c_random_wr_payload); buf_desc[0].type = CAM_CMD_BUF_I2C; - struct cam_cmd_power *power = alloc(s->video0_fd, buf_desc[0].size, 8, CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE, &buf_desc[0].mem_handle); + struct cam_cmd_power *power = alloc(s->video0_fd, buf_desc[0].size, 8, CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE, (uint32_t*)&buf_desc[0].mem_handle); struct cam_cmd_i2c_random_wr *i2c_random_wr = (void*)power; i2c_random_wr->header.count = len; i2c_random_wr->header.op_code = 1; @@ -207,7 +207,7 @@ void sensors_init(int video0_fd, int sensor_fd, int camera_num) { buf_desc[0].size = buf_desc[0].length = sizeof(struct cam_cmd_i2c_info) + sizeof(struct cam_cmd_probe); buf_desc[0].type = CAM_CMD_BUF_LEGACY; - struct cam_cmd_i2c_info *i2c_info = alloc(video0_fd, buf_desc[0].size, 8, CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE, &buf_desc[0].mem_handle); + struct cam_cmd_i2c_info *i2c_info = alloc(video0_fd, buf_desc[0].size, 8, CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE, (uint32_t*)&buf_desc[0].mem_handle); struct cam_cmd_probe *probe = (struct cam_cmd_probe *)((uint8_t *)i2c_info) + sizeof(struct cam_cmd_i2c_info); switch (camera_num) { @@ -244,11 +244,11 @@ void sensors_init(int video0_fd, int sensor_fd, int camera_num) { //buf_desc[1].size = buf_desc[1].length = 148; buf_desc[1].size = buf_desc[1].length = 196; buf_desc[1].type = CAM_CMD_BUF_I2C; - struct cam_cmd_power *power = alloc(video0_fd, buf_desc[1].size, 8, CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE, &buf_desc[1].mem_handle); + struct cam_cmd_power *power = alloc(video0_fd, buf_desc[1].size, 8, CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE, (uint32_t*)&buf_desc[1].mem_handle); memset(power, 0, buf_desc[1].size); struct cam_cmd_unconditional_wait *unconditional_wait; - void *ptr = power; + //void *ptr = power; // 7750 /*power->count = 2; power->cmd_type = CAMERA_SENSOR_CMD_TYPE_PWR_UP; @@ -264,7 +264,7 @@ void sensors_init(int video0_fd, int sensor_fd, int camera_num) { power->power_settings[2].power_seq_type = 2; // digital power->power_settings[3].power_seq_type = 8; // reset low power = (void*)power + (sizeof(struct cam_cmd_power) + (power->count-1)*sizeof(struct cam_power_settings)); - + unconditional_wait = (void*)power; unconditional_wait->cmd_type = CAMERA_SENSOR_CMD_TYPE_WAIT; unconditional_wait->delay = 5; @@ -353,7 +353,7 @@ void sensors_init(int video0_fd, int sensor_fd, int camera_num) { power = (void*)power + (sizeof(struct cam_cmd_power) + (power->count-1)*sizeof(struct cam_power_settings)); LOGD("probing the sensor"); - int ret = cam_control(sensor_fd, CAM_SENSOR_PROBE_CMD, (void *)cam_packet_handle, 0); + int ret = cam_control(sensor_fd, CAM_SENSOR_PROBE_CMD, (void *)(uintptr_t)cam_packet_handle, 0); assert(ret == 0); munmap(i2c_info, buf_desc[0].size); @@ -407,8 +407,7 @@ void config_isp(struct CameraState *s, int io_mem_handle, int fence, int request } buf_desc[1].type = CAM_CMD_BUF_GENERIC; buf_desc[1].meta_data = CAM_ISP_PACKET_META_GENERIC_BLOB_COMMON; - // printf("- ispc allocing 2 for sync_obj %d, req_id %d -\n", fence, request_id); - uint32_t *buf2 = alloc(s->video0_fd, buf_desc[1].size, 0x20, CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE, &buf_desc[1].mem_handle); + uint32_t *buf2 = alloc(s->video0_fd, buf_desc[1].size, 0x20, CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE, (uint32_t*)&buf_desc[1].mem_handle); // cam_isp_packet_generic_blob_handler uint32_t tmp[] = { @@ -431,7 +430,7 @@ void config_isp(struct CameraState *s, int io_mem_handle, int fence, int request 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; memcpy(buf2, tmp, sizeof(tmp)); if (io_mem_handle != 0) { @@ -537,7 +536,6 @@ void enqueue_buffer(struct CameraState *s, int i) { // ******************* camera ******************* static void camera_release_buffer(void* cookie, int i) { - int ret; CameraState *s = cookie; enqueue_buffer(s, i); } @@ -629,7 +627,7 @@ static void camera_open(CameraState *s, VisionBuf* b) { acquire_dev_cmd.handle_type = CAM_HANDLE_USER_POINTER; acquire_dev_cmd.num_resources = 1; acquire_dev_cmd.resource_hdl = (uint64_t)&isp_resource; - + isp_resource.resource_id = CAM_ISP_RES_ID_PORT; isp_resource.length = sizeof(struct cam_isp_in_port_info) + sizeof(struct cam_isp_out_port_info)*(1-1); isp_resource.handle_type = CAM_HANDLE_USER_POINTER; @@ -662,7 +660,7 @@ static void camera_open(CameraState *s, VisionBuf* b) { in_port_info->test_pattern = 0x2; // 0x3? in_port_info->usage_type = 0x0; - + in_port_info->left_start = 0x0; in_port_info->left_stop = FRAME_WIDTH - 1; in_port_info->left_width = FRAME_WIDTH; @@ -683,10 +681,10 @@ static void camera_open(CameraState *s, VisionBuf* b) { in_port_info->num_out_res = 0x1; in_port_info->data[0] = (struct cam_isp_out_port_info){ - .res_type = CAM_ISP_IFE_OUT_RES_RDI_0, + .res_type = CAM_ISP_IFE_OUT_RES_RDI_0, //.format = CAM_FORMAT_MIPI_RAW_12, .format = CAM_FORMAT_MIPI_RAW_10, - .width = FRAME_WIDTH, + .width = FRAME_WIDTH, .height = FRAME_HEIGHT, .comp_grp_id = 0x0, .split_point = 0x0, .secure_mode = 0x0, }; @@ -712,8 +710,7 @@ static void camera_open(CameraState *s, VisionBuf* b) { // acquires done // config ISP - // 984480 = 3 * 65632 * (1+4) ? - void *buf0 = alloc_w_mmu_hdl(s->video0_fd, 984480, 0x20, CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE, &s->buf0_handle, s->device_iommu, s->cdm_iommu); + alloc_w_mmu_hdl(s->video0_fd, 984480, 0x20, CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE, (uint32_t*)&s->buf0_handle, s->device_iommu, s->cdm_iommu); config_isp(s, 0, 0, 1, s->buf0_handle, 0); LOG("-- Configuring sensor"); @@ -736,7 +733,7 @@ static void camera_open(CameraState *s, VisionBuf* b) { buf_desc[0].size = buf_desc[0].length = sizeof(struct cam_csiphy_info); buf_desc[0].type = CAM_CMD_BUF_GENERIC; - struct cam_csiphy_info *csiphy_info = alloc(s->video0_fd, buf_desc[0].size, 8, CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE, &buf_desc[0].mem_handle); + struct cam_csiphy_info *csiphy_info = alloc(s->video0_fd, buf_desc[0].size, 8, CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE, (uint32_t*)&buf_desc[0].mem_handle); csiphy_info->lane_mask = 0x1f; csiphy_info->lane_assign = 0x3210;// skip clk. How is this 16 bit for 5 channels?? @@ -840,7 +837,7 @@ void cameras_open(MultiCameraState *s, VisionBuf *camera_bufs_rear, VisionBuf *c s->rear.device_iommu = s->front.device_iommu = s->wide.device_iommu = device_iommu; s->rear.cdm_iommu = s->front.cdm_iommu = s->wide.cdm_iommu = cdm_iommu; - // subscribe + // subscribe LOG("-- Subscribing"); static struct v4l2_event_subscription sub = {0}; sub.type = 0x8000000; diff --git a/selfdrive/camerad/cameras/camera_webcam.cc b/selfdrive/camerad/cameras/camera_webcam.cc index da8ed5de3e..972d9643f4 100644 --- a/selfdrive/camerad/cameras/camera_webcam.cc +++ b/selfdrive/camerad/cameras/camera_webcam.cc @@ -222,7 +222,6 @@ CameraInfo cameras_supported[CAMERA_ID_MAX] = { }; void cameras_init(MultiCameraState *s) { - memset(s, 0, sizeof(*s)); camera_init(&s->rear, CAMERA_ID_LGC920, 20); s->rear.transform = (mat3){{ diff --git a/selfdrive/camerad/cameras/sensor2_i2c.h b/selfdrive/camerad/cameras/sensor2_i2c.h index 709d6497b8..0fbf63c09a 100644 --- a/selfdrive/camerad/cameras/sensor2_i2c.h +++ b/selfdrive/camerad/cameras/sensor2_i2c.h @@ -371,8 +371,8 @@ struct i2c_random_wr_payload init_array_ar0231[] = { }; struct i2c_random_wr_payload poke_array_ov7750[] = { - {0x3208, 0x0}, {0x380e, 0x1a}, {0x380f, 0xf0}, {0x3500, 0x0}, {0x3501, 0x0}, {0x3502, 0x10}, {0x350a, 0x0}, {0x350b, 0x10}, {0x3208, 0x10}, {0x3208, 0xa0}, - //{0x3208, 0x0}, {0x380e, 0x1a}, {0x380f, 0xf0}, {0x3500, 0x0}, {0x3501, 0x0}, {0x3502, 0x10}, {0x350a, 0x0}, {0x350b, 0x10}, {0x3208, 0x10}, {0x3208, 0xa0}, + {0x3208, 0x0}, {0x380e, 0x1a}, {0x380f, 0xf0}, {0x3500, 0x0}, {0x3501, 0x0}, {0x3502, 0x10}, {0x350a, 0x0}, {0x350b, 0x10}, {0x3208, 0x10}, {0x3208, 0xa0}, + //{0x3208, 0x0}, {0x380e, 0x1a}, {0x380f, 0xf0}, {0x3500, 0x0}, {0x3501, 0x0}, {0x3502, 0x10}, {0x350a, 0x0}, {0x350b, 0x10}, {0x3208, 0x10}, {0x3208, 0xa0}, }; struct i2c_random_wr_payload preinit_array_ov7750[] = { diff --git a/selfdrive/camerad/imgproc/conv.cl b/selfdrive/camerad/imgproc/conv.cl index f92d356705..a7115ae76c 100644 --- a/selfdrive/camerad/imgproc/conv.cl +++ b/selfdrive/camerad/imgproc/conv.cl @@ -3,7 +3,7 @@ // convert input rgb image to single channel then conv __kernel void rgb2gray_conv2d( - const __global uchar * input, + const __global uchar * input, __global short * output, __constant short * filter, __local uchar3 * cached @@ -23,8 +23,8 @@ __kernel void rgb2gray_conv2d( // pad if ( - get_global_id(0) < HALF_FILTER_SIZE || - get_global_id(0) > IMAGE_W - HALF_FILTER_SIZE - 1 || + get_global_id(0) < HALF_FILTER_SIZE || + get_global_id(0) > IMAGE_W - HALF_FILTER_SIZE - 1 || get_global_id(1) < HALF_FILTER_SIZE || get_global_id(1) > IMAGE_H - HALF_FILTER_SIZE - 1 ) @@ -32,11 +32,11 @@ __kernel void rgb2gray_conv2d( barrier(CLK_LOCAL_MEM_FENCE); return; } - else + else { int localColOffset = -1; int globalColOffset = -1; - + // cache extra if ( get_local_id(0) < HALF_FILTER_SIZE ) { @@ -51,7 +51,7 @@ __kernel void rgb2gray_conv2d( { localColOffset = get_local_id(0) + TWICE_HALF_FILTER_SIZE; globalColOffset = HALF_FILTER_SIZE; - + cached[ myLocal + HALF_FILTER_SIZE ].x = input[ my * 3 + HALF_FILTER_SIZE * 3 ]; cached[ myLocal + HALF_FILTER_SIZE ].y = input[ my * 3 + HALF_FILTER_SIZE * 3 + 1]; cached[ myLocal + HALF_FILTER_SIZE ].z = input[ my * 3 + HALF_FILTER_SIZE * 3 + 2]; diff --git a/selfdrive/camerad/imgproc/pool.cl b/selfdrive/camerad/imgproc/pool.cl index 3ba86ae24e..d674b5f363 100644 --- a/selfdrive/camerad/imgproc/pool.cl +++ b/selfdrive/camerad/imgproc/pool.cl @@ -1,6 +1,6 @@ // calculate variance in each subregion __kernel void var_pool( - const __global char * input, + const __global char * input, __global ushort * output // should not be larger than 128*128 so uint16 ) { @@ -11,7 +11,7 @@ __kernel void var_pool( float fsum = 0; char mean, max; - + for (int i = 0; i < size; i++) { int x_offset = i % X_PITCH; int y_offset = i / X_PITCH; diff --git a/selfdrive/camerad/imgproc/utils.h b/selfdrive/camerad/imgproc/utils.h index f77a456912..203ac57a66 100644 --- a/selfdrive/camerad/imgproc/utils.h +++ b/selfdrive/camerad/imgproc/utils.h @@ -11,8 +11,8 @@ #define ROI_Y_MIN 2 #define ROI_Y_MAX 3 -#define LM_THRESH 222 -#define LM_PREC_THRESH 0.9 +#define LM_THRESH 120 +#define LM_PREC_THRESH 0.9 // 90 perc is blur // only apply to QCOM #define FULL_STRIDE_X 1280 @@ -27,4 +27,4 @@ const int16_t lapl_conv_krnl[9] = {0, 1, 0, void get_lapmap_one(int16_t *lap, uint16_t *res, int x_pitch, int y_pitch); bool is_blur(uint16_t *lapmap); -#endif \ No newline at end of file +#endif diff --git a/selfdrive/camerad/main.cc b/selfdrive/camerad/main.cc index 3e9652afcf..d43578121f 100644 --- a/selfdrive/camerad/main.cc +++ b/selfdrive/camerad/main.cc @@ -2,7 +2,7 @@ #include #include -#ifdef QCOM +#if defined(QCOM) && !defined(QCOM_REPLAY) #include "cameras/camera_qcom.h" #elif QCOM2 #include "cameras/camera_qcom2.h" @@ -15,6 +15,7 @@ #include "common/util.h" #include "common/swaglog.h" +#include "common/ipc.h" #include "common/visionipc.h" #include "common/visionbuf.h" #include "common/visionimg.h" @@ -29,9 +30,7 @@ #include #include -#include #include -#include "cereal/gen/cpp/log.capnp.h" #define UI_BUF_COUNT 4 #define DEBAYER_LOCAL_WORKSIZE 16 @@ -168,11 +167,7 @@ struct VisionState { zsock_t *terminate_pub; - Context * msg_context; - PubSocket *frame_sock; - PubSocket *front_frame_sock; - PubSocket *wide_frame_sock; - PubSocket *thumbnail_sock; + PubMaster *pm; pthread_mutex_t clients_lock; VisionClientState clients[MAX_CLIENTS]; @@ -184,16 +179,9 @@ void* frontview_thread(void *arg) { VisionState *s = (VisionState*)arg; set_thread_name("frontview"); - - s->msg_context = Context::create(); - // we subscribe to this for placement of the AE metering box // TODO: the loop is bad, ideally models shouldn't affect sensors - Context *msg_context = Context::create(); - SubSocket *monitoring_sock = SubSocket::create(msg_context, "driverState", "127.0.0.1", true); - SubSocket *dmonstate_sock = SubSocket::create(msg_context, "dMonitoringState", "127.0.0.1", true); - assert(monitoring_sock != NULL); - assert(dmonstate_sock != NULL); + SubMaster sm({"driverState", "dMonitoringState"}); cl_command_queue q = clCreateCommandQueue(s->context, s->device_id, 0, &err); assert(err == 0); @@ -208,7 +196,7 @@ void* frontview_thread(void *arg) { int rgb_idx = ui_idx; FrameMetadata frame_data = s->cameras.front.camera_bufs_metadata[buf_idx]; - double t1 = millis_since_boot(); + //double t1 = millis_since_boot(); cl_event debayer_event; if (s->cameras.front.ci.bayer) { @@ -243,21 +231,12 @@ void* frontview_thread(void *arg) { tbuffer_release(&s->cameras.front.camera_tb, buf_idx); visionbuf_sync(&s->rgb_front_bufs[ui_idx], VISIONBUF_SYNC_FROM_DEVICE); + sm.update(0); // no more check after gps check - if (!s->rhd_front_checked) { - Message *msg_dmon = dmonstate_sock->receive(true); - if (msg_dmon != NULL) { - auto amsg = kj::heapArray((msg_dmon->getSize() / sizeof(capnp::word)) + 1); - memcpy(amsg.begin(), msg_dmon->getData(), msg_dmon->getSize()); - - capnp::FlatArrayMessageReader cmsg(amsg); - cereal::Event::Reader event = cmsg.getRoot(); - - s->rhd_front = event.getDMonitoringState().getIsRHD(); - s->rhd_front_checked = event.getDMonitoringState().getRhdChecked(); - - delete msg_dmon; - } + if (!s->rhd_front_checked && sm.updated("dMonitoringState")) { + auto state = sm["dMonitoringState"].getDMonitoringState(); + s->rhd_front = state.getIsRHD(); + s->rhd_front_checked = state.getRhdChecked(); } #ifdef NOSCREEN @@ -266,37 +245,26 @@ void* frontview_thread(void *arg) { } #endif - Message *msg = monitoring_sock->receive(true); - if (msg != NULL) { - auto amsg = kj::heapArray((msg->getSize() / sizeof(capnp::word)) + 1); - memcpy(amsg.begin(), msg->getData(), msg->getSize()); - - capnp::FlatArrayMessageReader cmsg(amsg); - cereal::Event::Reader event = cmsg.getRoot(); - - float face_prob = event.getDriverState().getFaceProb(); + if (sm.updated("driverState")) { + auto state = sm["driverState"].getDriverState(); + float face_prob = state.getFaceProb(); float face_position[2]; - face_position[0] = event.getDriverState().getFacePosition()[0]; - face_position[1] = event.getDriverState().getFacePosition()[1]; + face_position[0] = state.getFacePosition()[0]; + face_position[1] = state.getFacePosition()[1]; // set front camera metering target - if (face_prob > 0.4) - { + if (face_prob > 0.4) { int x_offset = s->rhd_front ? 0:s->rgb_front_width - 0.5 * s->rgb_front_height; s->front_meteringbox_xmin = x_offset + (face_position[0] + 0.5) * (0.5 * s->rgb_front_height) - 72; s->front_meteringbox_xmax = x_offset + (face_position[0] + 0.5) * (0.5 * s->rgb_front_height) + 72; s->front_meteringbox_ymin = (face_position[1] + 0.5) * (s->rgb_front_height) - 72; s->front_meteringbox_ymax = (face_position[1] + 0.5) * (s->rgb_front_height) + 72; - } - else // use default setting if no face - { + } else {// use default setting if no face s->front_meteringbox_ymin = s->rgb_front_height * 1 / 3; s->front_meteringbox_ymax = s->rgb_front_height * 1; s->front_meteringbox_xmin = s->rhd_front ? 0:s->rgb_front_width * 3 / 5; s->front_meteringbox_xmax = s->rhd_front ? s->rgb_front_width * 2 / 5:s->rgb_front_width; } - - delete msg; } // auto exposure @@ -373,7 +341,7 @@ void* frontview_thread(void *arg) { // send frame event { - if (s->front_frame_sock != NULL) { + if (s->pm != NULL) { capnp::MallocMessageBuilder msg; cereal::Event::Builder event = msg.initRoot(); event.setLogMonoTime(nanos_since_boot()); @@ -392,9 +360,7 @@ void* frontview_thread(void *arg) { framed.setGainFrac(frame_data.gain_frac); framed.setFrameType(cereal::FrameData::FrameType::FRONT); - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - s->front_frame_sock->send((char*)bytes.begin(), bytes.size()); + s->pm->send("frontFrame", msg); } } @@ -405,13 +371,10 @@ void* frontview_thread(void *arg) { tbuffer_dispatch(&s->ui_front_tb, ui_idx); - double t2 = millis_since_boot(); - + //double t2 = millis_since_boot(); //LOGD("front process: %.2fms", t2-t1); } - - delete monitoring_sock; - delete dmonstate_sock; + clReleaseCommandQueue(q); return NULL; } @@ -590,12 +553,21 @@ void* processing_thread(void *arg) { set_thread_name("processing"); - err = set_realtime_priority(1); + err = set_realtime_priority(51); LOG("setpriority returns %d", err); +#if defined(QCOM) && !defined(QCOM_REPLAY) + std::unique_ptr rgb_roi_buf = std::make_unique((s->rgb_width/NUM_SEGMENTS_X)*(s->rgb_height/NUM_SEGMENTS_Y)*3); + std::unique_ptr conv_result = std::make_unique((s->rgb_width/NUM_SEGMENTS_X)*(s->rgb_height/NUM_SEGMENTS_Y)); +#endif + // init cl stuff +#ifdef __APPLE__ + cl_command_queue q = clCreateCommandQueue(s->context, s->device_id, 0, &err); +#else const cl_queue_properties props[] = {0}; //CL_QUEUE_PRIORITY_KHR, CL_QUEUE_PRIORITY_HIGH_KHR, 0}; cl_command_queue q = clCreateCommandQueueWithProperties(s->context, s->device_id, props, &err); +#endif assert(err == 0); // init the net @@ -660,13 +632,14 @@ void* processing_thread(void *arg) { visionbuf_sync(&s->rgb_bufs[rgb_idx], VISIONBUF_SYNC_FROM_DEVICE); +<<<<<<< HEAD #ifdef NOSCREEN if (frame_data.frame_id % 4 == 1) { sendrgb(&s->cameras, (uint8_t*) s->rgb_bufs[rgb_idx].addr, s->rgb_bufs[rgb_idx].len, 0); } #endif -#ifdef QCOM +#if defined(QCOM) && !defined(QCOM_REPLAY) /*FILE *dump_rgb_file = fopen("/tmp/process_dump.rgb", "wb"); fwrite(s->rgb_bufs[rgb_idx].addr, s->rgb_bufs[rgb_idx].len, sizeof(uint8_t), dump_rgb_file); fclose(dump_rgb_file); @@ -675,13 +648,12 @@ void* processing_thread(void *arg) { /*double t10 = millis_since_boot();*/ // cache rgb roi and write to cl - uint8_t *rgb_roi_buf = new uint8_t[(s->rgb_width/NUM_SEGMENTS_X)*(s->rgb_height/NUM_SEGMENTS_Y)*3]; int roi_id = cnt % ((ROI_X_MAX-ROI_X_MIN+1)*(ROI_Y_MAX-ROI_Y_MIN+1)); // rolling roi int roi_x_offset = roi_id % (ROI_X_MAX-ROI_X_MIN+1); int roi_y_offset = roi_id / (ROI_X_MAX-ROI_X_MIN+1); for (int r=0;r<(s->rgb_height/NUM_SEGMENTS_Y);r++) { - memcpy(rgb_roi_buf + r * (s->rgb_width/NUM_SEGMENTS_X) * 3, + memcpy(rgb_roi_buf.get() + r * (s->rgb_width/NUM_SEGMENTS_X) * 3, (uint8_t *) s->rgb_bufs[rgb_idx].addr + \ (ROI_Y_MIN + roi_y_offset) * s->rgb_height/NUM_SEGMENTS_Y * FULL_STRIDE_X * 3 + \ (ROI_X_MIN + roi_x_offset) * s->rgb_width/NUM_SEGMENTS_X * 3 + r * FULL_STRIDE_X * 3, @@ -689,7 +661,7 @@ void* processing_thread(void *arg) { } err = clEnqueueWriteBuffer (q, s->rgb_conv_roi_cl, true, 0, - s->rgb_width/NUM_SEGMENTS_X * s->rgb_height/NUM_SEGMENTS_Y * 3 * sizeof(uint8_t), rgb_roi_buf, 0, 0, 0); + s->rgb_width/NUM_SEGMENTS_X * s->rgb_height/NUM_SEGMENTS_Y * 3 * sizeof(uint8_t), rgb_roi_buf.get(), 0, 0, 0); assert(err == 0); /*double t11 = millis_since_boot(); @@ -712,32 +684,57 @@ void* processing_thread(void *arg) { clWaitForEvents(1, &conv_event); clReleaseEvent(conv_event); - int16_t *conv_result = new int16_t[(s->rgb_width/NUM_SEGMENTS_X)*(s->rgb_height/NUM_SEGMENTS_Y)]; err = clEnqueueReadBuffer(q, s->rgb_conv_result_cl, true, 0, - s->rgb_width/NUM_SEGMENTS_X * s->rgb_height/NUM_SEGMENTS_Y * sizeof(int16_t), conv_result, 0, 0, 0); + s->rgb_width/NUM_SEGMENTS_X * s->rgb_height/NUM_SEGMENTS_Y * sizeof(int16_t), conv_result.get(), 0, 0, 0); assert(err == 0); /*t11 = millis_since_boot(); printf("conv time: %f ms\n", t11 - t10); t10 = millis_since_boot();*/ - get_lapmap_one(conv_result, &s->lapres[roi_id], s->rgb_width/NUM_SEGMENTS_X, s->rgb_height/NUM_SEGMENTS_Y); + get_lapmap_one(conv_result.get(), &s->lapres[roi_id], s->rgb_width/NUM_SEGMENTS_X, s->rgb_height/NUM_SEGMENTS_Y); /*t11 = millis_since_boot(); printf("pool time: %f ms\n", t11 - t10); t10 = millis_since_boot();*/ - delete [] rgb_roi_buf; - delete [] conv_result; - /*t11 = millis_since_boot(); printf("process time: %f ms\n ----- \n", t11 - t10); t10 = millis_since_boot();*/ + + // setup self recover + const float lens_true_pos = s->cameras.rear.lens_true_pos; + if (is_blur(&s->lapres[0]) && + (lens_true_pos < (s->cameras.device == DEVICE_LP3? LP3_AF_DAC_DOWN:OP3T_AF_DAC_DOWN)+1 || + lens_true_pos > (s->cameras.device == DEVICE_LP3? LP3_AF_DAC_UP:OP3T_AF_DAC_UP)-1) && + s->cameras.rear.self_recover < 2) { + // truly stuck, needs help + s->cameras.rear.self_recover -= 1; + if (s->cameras.rear.self_recover < -FOCUS_RECOVER_PATIENCE) { + LOGW("rear camera bad state detected. attempting recovery from %.1f, recover state is %d", + lens_true_pos, s->cameras.rear.self_recover.load()); + s->cameras.rear.self_recover = FOCUS_RECOVER_STEPS + ((lens_true_pos < (s->cameras.device == DEVICE_LP3? LP3_AF_DAC_M:OP3T_AF_DAC_M))?1:0); // parity determined by which end is stuck at + } + } else if ((lens_true_pos < (s->cameras.device == DEVICE_LP3? LP3_AF_DAC_M - LP3_AF_DAC_3SIG:OP3T_AF_DAC_M - OP3T_AF_DAC_3SIG) || + lens_true_pos > (s->cameras.device == DEVICE_LP3? LP3_AF_DAC_M + LP3_AF_DAC_3SIG:OP3T_AF_DAC_M + OP3T_AF_DAC_3SIG)) && + s->cameras.rear.self_recover < 2) { + // in suboptimal position with high prob, but may still recover by itself + s->cameras.rear.self_recover -= 1; + if (s->cameras.rear.self_recover < -(FOCUS_RECOVER_PATIENCE*3)) { + LOGW("rear camera bad state detected. attempting recovery from %.1f, recover state is %d", lens_true_pos, s->cameras.rear.self_recover.load()); + s->cameras.rear.self_recover = FOCUS_RECOVER_STEPS/2 + ((lens_true_pos < (s->cameras.device == DEVICE_LP3? LP3_AF_DAC_M:OP3T_AF_DAC_M))?1:0); + } + } else if (s->cameras.rear.self_recover < 0) { + s->cameras.rear.self_recover += 1; // reset if fine + } + #endif double t2 = millis_since_boot(); +#ifndef QCOM2 uint8_t *bgr_ptr = (uint8_t*)s->rgb_bufs[rgb_idx].addr; +#endif double yt1 = millis_since_boot(); @@ -746,8 +743,6 @@ void* processing_thread(void *arg) { s->yuv_metas[yuv_idx] = frame_data; uint8_t* yuv_ptr_y = s->yuv_bufs[yuv_idx].y; - uint8_t* yuv_ptr_u = s->yuv_bufs[yuv_idx].u; - uint8_t* yuv_ptr_v = s->yuv_bufs[yuv_idx].v; cl_mem yuv_cl = s->yuv_cl[yuv_idx]; rgb_to_yuv_queue(&s->rgb_to_yuv_state, q, s->rgb_bufs_cl[rgb_idx], yuv_cl); visionbuf_sync(&s->yuv_ion[yuv_idx], VISIONBUF_SYNC_FROM_DEVICE); @@ -760,7 +755,7 @@ void* processing_thread(void *arg) { // send frame event { - if (s->frame_sock != NULL) { + if (s->pm != NULL) { capnp::MallocMessageBuilder msg; cereal::Event::Builder event = msg.initRoot(); event.setLogMonoTime(nanos_since_boot()); @@ -778,13 +773,14 @@ void* processing_thread(void *arg) { framed.setLensTruePos(frame_data.lens_true_pos); framed.setGainFrac(frame_data.gain_frac); -#ifdef QCOM +#if defined(QCOM) && !defined(QCOM_REPLAY) kj::ArrayPtr focus_vals(&s->cameras.rear.focus[0], NUM_FOCUS); kj::ArrayPtr focus_confs(&s->cameras.rear.confidence[0], NUM_FOCUS); framed.setFocusVal(focus_vals); framed.setFocusConf(focus_confs); kj::ArrayPtr sharpness_score(&s->lapres[0], (ROI_X_MAX-ROI_X_MIN+1)*(ROI_Y_MAX-ROI_Y_MIN+1)); framed.setSharpnessScore(sharpness_score); + framed.setRecoverState(s->cameras.rear.self_recover); #endif // TODO: add this back @@ -796,9 +792,7 @@ void* processing_thread(void *arg) { kj::ArrayPtr transform_vs(&s->yuv_transform.v[0], 9); framed.setTransform(transform_vs); - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - s->frame_sock->send((char*)bytes.begin(), bytes.size()); + s->pm->send("frame", msg); } } @@ -807,7 +801,7 @@ void* processing_thread(void *arg) { // one thumbnail per 5 seconds (instead of %5 == 0 posenet) if (cnt % 100 == 3) { uint8_t* thumbnail_buffer = NULL; - uint64_t thumbnail_len = 0; + unsigned long thumbnail_len = 0; unsigned char *row = (unsigned char *)malloc(s->rgb_width/4*3); @@ -859,10 +853,8 @@ void* processing_thread(void *arg) { thumbnaild.setTimestampEof(frame_data.timestamp_eof); thumbnaild.setThumbnail(kj::arrayPtr((const uint8_t*)thumbnail_buffer, thumbnail_len)); - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - if (s->thumbnail_sock != NULL) { - s->thumbnail_sock->send((char*)bytes.begin(), bytes.size()); + if (s->pm != NULL) { + s->pm->send("thumbnail", msg); } free(thumbnail_buffer); @@ -906,6 +898,7 @@ void* processing_thread(void *arg) { LOGD("queued: %.2fms, yuv: %.2f, | processing: %.3fms", (t2-t1), (yt2-yt1), (t5-t1)); } + clReleaseCommandQueue(q); return NULL; } @@ -1151,21 +1144,7 @@ void* visionserver_thread(void* arg) { assert(terminate); void* terminate_raw = zsock_resolve(terminate); - unlink(VIPC_SOCKET_PATH); - - int sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); - struct sockaddr_un addr = { - .sun_family = AF_UNIX, - .sun_path = VIPC_SOCKET_PATH, - }; - err = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); - assert(err == 0); - - err = listen(sock, 3); - assert(err == 0); - - // printf("waiting\n"); - + int sock = ipc_bind(VIPC_SOCKET_PATH); while (!do_exit) { zmq_pollitem_t polls[2] = {{0}}; polls[0].socket = terminate_raw; @@ -1293,19 +1272,7 @@ cl_program build_pool_program(VisionState *s, void cl_init(VisionState *s) { int err; - cl_platform_id platform_id = NULL; - cl_uint num_devices; - cl_uint num_platforms; - - err = clGetPlatformIDs(1, &platform_id, &num_platforms); - assert(err == 0); - err = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, - &s->device_id, &num_devices); - assert(err == 0); - - cl_print_info(platform_id, s->device_id); - printf("\n"); - + s->device_id = cl_get_device_id(CL_DEVICE_TYPE_DEFAULT); s->context = clCreateContext(NULL, 1, &s->device_id, NULL, NULL, &err); assert(err == 0); } @@ -1385,6 +1352,7 @@ void init_buffers(VisionState *s) { s->rgb_wide_width = s->cameras.wide.ci.frame_width; s->rgb_wide_height = s->cameras.wide.ci.frame_height; #endif + for (int i=0; irgb_front_width, s->rgb_front_height, &s->rgb_front_bufs[i]); s->rgb_front_bufs_cl[i] = visionbuf_to_cl(&s->rgb_front_bufs[i], s->device_id, s->context); @@ -1496,13 +1464,14 @@ void init_buffers(VisionState *s) { s->debayer_cl_localWorkSize[1] = DEBAYER_LOCAL_WORKSIZE; #ifdef QCOM - s->prg_rgb_laplacian = build_conv_program(s, s->rgb_width/NUM_SEGMENTS_X, s->rgb_height/NUM_SEGMENTS_Y, + s->prg_rgb_laplacian = build_conv_program(s, s->rgb_width/NUM_SEGMENTS_X, s->rgb_height/NUM_SEGMENTS_Y, 3); s->krnl_rgb_laplacian = clCreateKernel(s->prg_rgb_laplacian, "rgb2gray_conv2d", &err); assert(err == 0); - s->rgb_conv_roi_cl = clCreateBuffer(s->context, CL_MEM_READ_WRITE | CL_MEM_SVM_FINE_GRAIN_BUFFER, + // TODO: Removed CL_MEM_SVM_FINE_GRAIN_BUFFER, confirm it doesn't matter + s->rgb_conv_roi_cl = clCreateBuffer(s->context, CL_MEM_READ_WRITE, s->rgb_width/NUM_SEGMENTS_X * s->rgb_height/NUM_SEGMENTS_Y * 3 * sizeof(uint8_t), NULL, NULL); - s->rgb_conv_result_cl = clCreateBuffer(s->context, CL_MEM_READ_WRITE | CL_MEM_SVM_FINE_GRAIN_BUFFER, + s->rgb_conv_result_cl = clCreateBuffer(s->context, CL_MEM_READ_WRITE, s->rgb_width/NUM_SEGMENTS_X * s->rgb_height/NUM_SEGMENTS_Y * sizeof(int16_t), NULL, NULL); s->rgb_conv_filter_cl = clCreateBuffer(s->context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, 9 * sizeof(int16_t), (void*)&lapl_conv_krnl, NULL); @@ -1543,9 +1512,6 @@ void free_buffers(VisionState *s) { #endif for (int i=0; irgb_bufs[i]); - } - - for (int i=0; irgb_front_bufs[i]); } #ifdef QCOM2 @@ -1555,7 +1521,21 @@ void free_buffers(VisionState *s) { #endif for (int i=0; iyuv_ion[i]); + visionbuf_free(&s->yuv_front_ion[i]); } + + clReleaseMemObject(s->rgb_conv_roi_cl); + clReleaseMemObject(s->rgb_conv_result_cl); + clReleaseMemObject(s->rgb_conv_filter_cl); + + clReleaseProgram(s->prg_debayer_rear); + clReleaseProgram(s->prg_debayer_front); + clReleaseKernel(s->krnl_debayer_rear); + clReleaseKernel(s->krnl_debayer_front); + + clReleaseProgram(s->prg_rgb_laplacian); + clReleaseKernel(s->krnl_rgb_laplacian); + } void party(VisionState *s) { @@ -1574,10 +1554,12 @@ void party(VisionState *s) { processing_thread, s); assert(err == 0); +#if !defined(__APPLE__) pthread_t frontview_thread_handle; err = pthread_create(&frontview_thread_handle, NULL, frontview_thread, s); assert(err == 0); +#endif #ifdef QCOM2 pthread_t wideview_thread_handle; err = pthread_create(&wideview_thread_handle, NULL, @@ -1586,7 +1568,7 @@ void party(VisionState *s) { #endif // priority for cameras - err = set_realtime_priority(1); + err = set_realtime_priority(51); LOG("setpriority returns %d", err); cameras_run(&s->cameras); @@ -1602,9 +1584,11 @@ void party(VisionState *s) { zsock_signal(s->terminate_pub, 0); +#if (defined(QCOM) && !defined(QCOM_REPLAY)) || defined(WEBCAM) || defined(QCOM2) LOG("joining frontview_thread"); err = pthread_join(frontview_thread_handle, NULL); assert(err == 0); +#endif #ifdef QCOM2 LOG("joining wideview_thread"); err = pthread_join(wideview_thread_handle, NULL); @@ -1622,14 +1606,13 @@ void party(VisionState *s) { } int main(int argc, char *argv[]) { - int err; - set_realtime_priority(1); + set_realtime_priority(51); zsys_handler_set(NULL); signal(SIGINT, (sighandler_t)set_do_exit); signal(SIGTERM, (sighandler_t)set_do_exit); - VisionState state = {0}; + VisionState state = {}; VisionState *s = &state; clu_init(); @@ -1644,16 +1627,8 @@ int main(int argc, char *argv[]) { init_buffers(s); -#if defined(QCOM) || defined(QCOM2) - s->msg_context = Context::create(); - s->frame_sock = PubSocket::create(s->msg_context, "frame"); - s->front_frame_sock = PubSocket::create(s->msg_context, "frontFrame"); - s->wide_frame_sock = PubSocket::create(s->msg_context, "wideFrame"); - s->thumbnail_sock = PubSocket::create(s->msg_context, "thumbnail"); - assert(s->frame_sock != NULL); - assert(s->front_frame_sock != NULL); - assert(s->wide_frame_sock != NULL); - assert(s->thumbnail_sock != NULL); +#if (defined(QCOM) && !defined(QCOM_REPLAY)) || defined(QCOM2) + s->pm = new PubMaster({"frame", "frontFrame", "wideFrame", "thumbnail"}); #endif #ifndef QCOM2 @@ -1664,13 +1639,9 @@ int main(int argc, char *argv[]) { party(s); -#if defined(QCOM) || defined(QCOM2) - delete s->frame_sock; - delete s->front_frame_sock; - delete s->wide_frame_sock; - delete s->thumbnail_sock; - delete s->msg_context; -#endif + if (s->pm != NULL) { + delete s->pm; + } free_buffers(s); cl_free(s); diff --git a/selfdrive/camerad/snapshot/snapshot.py b/selfdrive/camerad/snapshot/snapshot.py index 4ba10bf4be..317618c0b2 100755 --- a/selfdrive/camerad/snapshot/snapshot.py +++ b/selfdrive/camerad/snapshot/snapshot.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 import os -import json import signal import subprocess import time @@ -8,9 +7,7 @@ from PIL import Image from common.basedir import BASEDIR from common.params import Params from selfdrive.camerad.snapshot.visionipc import VisionIPC - -with open(BASEDIR + "/selfdrive/controls/lib/alerts_offroad.json") as json_file: - OFFROAD_ALERTS = json.load(json_file) +from selfdrive.controls.lib.alertmanager import set_offroad_alert def jpeg_write(fn, dat): @@ -26,7 +23,7 @@ def snapshot(): return None params.put("IsTakingSnapshot", "1") - params.put("Offroad_IsTakingSnapshot", json.dumps(OFFROAD_ALERTS["Offroad_IsTakingSnapshot"])) + set_offroad_alert("Offroad_IsTakingSnapshot", True) time.sleep(2.0) # Give thermald time to read the param, or if just started give camerad time to start # Check if camerad is already started @@ -64,7 +61,7 @@ def snapshot(): proc.communicate() params.put("IsTakingSnapshot", "0") - params.delete("Offroad_IsTakingSnapshot") + set_offroad_alert("Offroad_IsTakingSnapshot", False) return ret diff --git a/selfdrive/camerad/snapshot/visionipc.py b/selfdrive/camerad/snapshot/visionipc.py index 816db41208..4df79e2cc2 100644 --- a/selfdrive/camerad/snapshot/visionipc.py +++ b/selfdrive/camerad/snapshot/visionipc.py @@ -90,4 +90,4 @@ class VisionIPC(): buf = self.clib.visionstream_get(self.s, ffi.NULL) pbuf = ffi.buffer(buf.addr, buf.len) ret = np.frombuffer(pbuf, dtype=np.uint8).reshape((-1, self.buf_info.stride//3, 3)) - return ret[:self.buf_info.height, :self.buf_info.width, [2,1,0]] + return ret[:self.buf_info.height, :self.buf_info.width, [2, 1, 0]] diff --git a/selfdrive/camerad/test/camera/test.c b/selfdrive/camerad/test/camera/test.c index dc9b92ef13..4ff6a07526 100644 --- a/selfdrive/camerad/test/camera/test.c +++ b/selfdrive/camerad/test/camera/test.c @@ -35,7 +35,7 @@ void tbuffer_stop(TBuffer *tb) { } int main() { - MultiCameraState s; + MultiCameraState s={}; cameras_init(&s); VisionBuf camera_bufs_rear[0x10] = {0}; VisionBuf camera_bufs_focus[0x10] = {0}; diff --git a/selfdrive/camerad/test/frame_test.py b/selfdrive/camerad/test/frame_test.py index 2518e80344..36e6733654 100755 --- a/selfdrive/camerad/test/frame_test.py +++ b/selfdrive/camerad/test/frame_test.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -import time import numpy as np import cereal.messaging as messaging from PIL import ImageFont, ImageDraw, Image @@ -7,13 +6,13 @@ from PIL import ImageFont, ImageDraw, Image font = ImageFont.truetype("arial", size=72) def get_frame(idx): img = np.zeros((874, 1164, 3), np.uint8) - img[100:400, 100:100+(idx%10)*100] = 255 + img[100:400, 100:100+(idx % 10) * 100] = 255 # big number - im2 = Image.new("RGB", (200,200)) + im2 = Image.new("RGB", (200, 200)) draw = ImageDraw.Draw(im2) draw.text((10, 100), "%02d" % idx, font=font) - img[400:600, 400:600] = np.array(im2.getdata()).reshape((200,200,3)) + img[400:600, 400:600] = np.array(im2.getdata()).reshape((200, 200, 3)) return img.tostring() if __name__ == "__main__": @@ -29,11 +28,10 @@ if __name__ == "__main__": dat.valid = True dat.frame = { "frameId": idx, - "image": frm[idx%len(frm)], + "image": frm[idx % len(frm)], } pm.send('frame', dat) idx += 1 rk.keep_time() #time.sleep(1.0) - diff --git a/selfdrive/camerad/test/yuv_bench/cnv.py b/selfdrive/camerad/test/yuv_bench/cnv.py index 86fd0c9982..24fde0875a 100644 --- a/selfdrive/camerad/test/yuv_bench/cnv.py +++ b/selfdrive/camerad/test/yuv_bench/cnv.py @@ -1,5 +1,5 @@ import numpy as np -import cv2 +import cv2 # pylint: disable=import-error # img_bgr = np.zeros((874, 1164, 3), dtype=np.uint8) # for y in range(874): diff --git a/selfdrive/camerad/test/yuv_bench/yuv_bench.cc b/selfdrive/camerad/test/yuv_bench/yuv_bench.cc index 22e71c4128..62860ea7cc 100644 --- a/selfdrive/camerad/test/yuv_bench/yuv_bench.cc +++ b/selfdrive/camerad/test/yuv_bench/yuv_bench.cc @@ -38,27 +38,8 @@ int main() { // init cl - /* Get Platform and Device Info */ - cl_platform_id platform_id = NULL; - cl_uint num_platforms_unused; - int err = clGetPlatformIDs(1, &platform_id, &num_platforms_unused); - if (err != 0) { - fprintf(stderr, "cl error: %d\n", err); - } - assert(err == 0); - - cl_device_id device_id = NULL; - cl_uint num_devices_unused; - err = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, - &num_devices_unused); - if (err != 0) { - fprintf(stderr, "cl error: %d\n", err); - } - assert(err == 0); - - cl_print_info(platform_id, device_id); - printf("\n"); - + int err; + cl_device_id device_id = cl_get_device_id(CL_DEVICE_TYPE_DEFAULT); cl_context context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &err); assert(err == 0); diff --git a/selfdrive/camerad/transforms/rgb_to_yuv.c b/selfdrive/camerad/transforms/rgb_to_yuv.c index b9e66b36db..1a36650b9f 100644 --- a/selfdrive/camerad/transforms/rgb_to_yuv.c +++ b/selfdrive/camerad/transforms/rgb_to_yuv.c @@ -43,7 +43,7 @@ void rgb_to_yuv_queue(RGBToYUVState* s, cl_command_queue q, cl_mem rgb_cl, cl_me err = clSetKernelArg(s->rgb_to_yuv_krnl, 1, sizeof(cl_mem), &yuv_cl); assert(err == 0); const size_t work_size[2] = { - (size_t)(s->width + (s->width % 4 == 0 ? 0 : (4 - s->width % 4))) / 4, + (size_t)(s->width + (s->width % 4 == 0 ? 0 : (4 - s->width % 4))) / 4, (size_t)(s->height + (s->height % 4 == 0 ? 0 : (4 - s->height % 4))) / 4 }; cl_event event; diff --git a/selfdrive/camerad/transforms/rgb_to_yuv_test.cc b/selfdrive/camerad/transforms/rgb_to_yuv_test.cc index c8b8751058..9d68e5b9ef 100644 --- a/selfdrive/camerad/transforms/rgb_to_yuv_test.cc +++ b/selfdrive/camerad/transforms/rgb_to_yuv_test.cc @@ -42,14 +42,7 @@ static inline double millis_since_boot() { void cl_init(cl_device_id &device_id, cl_context &context) { int err; - cl_platform_id platform_id = NULL; - cl_uint num_devices; - cl_uint num_platforms; - - err = clGetPlatformIDs(1, &platform_id, &num_platforms); - err = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, - &device_id, &num_devices); - cl_print_info(platform_id, device_id); + device_id = cl_get_device_id(CL_DEVICE_TYPE_DEFAULT); context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &err); } diff --git a/selfdrive/car/__init__.py b/selfdrive/car/__init__.py index 6ad29d4b3a..7701f90a6d 100644 --- a/selfdrive/car/__init__.py +++ b/selfdrive/car/__init__.py @@ -4,9 +4,11 @@ from common.numpy_fast import clip # kg of standard extra cargo to count for drive, gas, etc... STD_CARGO_KG = 136. + def gen_empty_fingerprint(): return {i: {} for i in range(0, 4)} + # FIXME: hardcoding honda civic 2016 touring params so they can be used to # scale unknown params for other cars class CivicParams: @@ -18,11 +20,13 @@ class CivicParams: TIRE_STIFFNESS_FRONT = 192150 TIRE_STIFFNESS_REAR = 202500 + # TODO: get actual value, for now starting with reasonable value for # civic and scaling by mass and wheelbase def scale_rot_inertia(mass, wheelbase): return CivicParams.ROTATIONAL_INERTIA * mass * wheelbase ** 2 / (CivicParams.MASS * CivicParams.WHEELBASE ** 2) + # TODO: start from empirically derived lateral slip stiffness for the civic and scale by # mass and CG position, so all cars will have approximately similar dyn behaviors def scale_tire_stiffness(mass, wheelbase, center_to_front, tire_stiffness_factor=1.0): @@ -35,8 +39,9 @@ def scale_tire_stiffness(mass, wheelbase, center_to_front, tire_stiffness_factor return tire_stiffness_front, tire_stiffness_rear -def dbc_dict(pt_dbc, radar_dbc, chassis_dbc=None): - return {'pt': pt_dbc, 'radar': radar_dbc, 'chassis': chassis_dbc} + +def dbc_dict(pt_dbc, radar_dbc, chassis_dbc=None, body_dbc=None): + return {'pt': pt_dbc, 'radar': radar_dbc, 'chassis': chassis_dbc, 'body': body_dbc} def apply_std_steer_torque_limits(apply_torque, apply_torque_last, driver_torque, LIMITS): @@ -51,10 +56,10 @@ def apply_std_steer_torque_limits(apply_torque, apply_torque_last, driver_torque # slow rate if steer torque increases in magnitude if apply_torque_last > 0: apply_torque = clip(apply_torque, max(apply_torque_last - LIMITS.STEER_DELTA_DOWN, -LIMITS.STEER_DELTA_UP), - apply_torque_last + LIMITS.STEER_DELTA_UP) + apply_torque_last + LIMITS.STEER_DELTA_UP) else: apply_torque = clip(apply_torque, apply_torque_last - LIMITS.STEER_DELTA_UP, - min(apply_torque_last + LIMITS.STEER_DELTA_DOWN, LIMITS.STEER_DELTA_UP)) + min(apply_torque_last + LIMITS.STEER_DELTA_DOWN, LIMITS.STEER_DELTA_UP)) return int(round(float(apply_torque))) @@ -83,9 +88,9 @@ def crc8_pedal(data): crc = 0xFF # standard init value poly = 0xD5 # standard crc8: x8+x7+x6+x4+x2+1 size = len(data) - for i in range(size-1, -1, -1): + for i in range(size - 1, -1, -1): crc ^= data[i] - for j in range(8): + for _ in range(8): if ((crc & 0x80) != 0): crc = ((crc << 1) ^ poly) & 0xFF else: @@ -128,4 +133,3 @@ def is_ecu_disconnected(fingerprint, fingerprint_list, ecu_fingerprint, car, ecu def make_can_msg(addr, dat, bus): return [addr, 0, dat, bus] - diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py index 9052ebb26b..e79b03cc5c 100644 --- a/selfdrive/car/car_helpers.py +++ b/selfdrive/car/car_helpers.py @@ -1,6 +1,7 @@ import os from common.params import Params from common.basedir import BASEDIR +from selfdrive.version import comma_remote, tested_branch from selfdrive.car.fingerprints import eliminate_incompatible_cars, all_known_cars from selfdrive.car.vin import get_vin, VIN_UNKNOWN from selfdrive.car.fw_versions import get_fw_versions, match_fw_to_car @@ -8,14 +9,17 @@ from selfdrive.swaglog import cloudlog import cereal.messaging as messaging from selfdrive.car import gen_empty_fingerprint -from cereal import car +from cereal import car, log EventName = car.CarEvent.EventName +HwType = log.HealthData.HwType + def get_startup_event(car_recognized, controller_available): - event = EventName.startup - if Params().get("GitRemote", encoding="utf8") in ['git@github.com:commaai/openpilot.git', 'https://github.com/commaai/openpilot.git']: - if Params().get("GitBranch", encoding="utf8") not in ['devel', 'release2-staging', 'dashcam-staging', 'release2', 'dashcam']: - event = EventName.startupMaster + if comma_remote and tested_branch: + event = EventName.startup + else: + event = EventName.startupMaster + if not car_recognized: event = EventName.startupNoCar elif car_recognized and not controller_available: @@ -23,6 +27,13 @@ def get_startup_event(car_recognized, controller_available): return event +def get_one_can(logcan): + while True: + can = messaging.recv_one_retry(logcan) + if len(can.can) > 0: + return can + + def load_interfaces(brand_names): ret = {} for brand_name in brand_names: @@ -73,8 +84,9 @@ def only_toyota_left(candidate_cars): # **** for use live only **** def fingerprint(logcan, sendcan, has_relay): fixed_fingerprint = os.environ.get('FINGERPRINT', "") + skip_fw_query = os.environ.get('SKIP_FW_QUERY', False) - if has_relay and not fixed_fingerprint: + if has_relay and not fixed_fingerprint and not skip_fw_query: # Vin query only reliably works thorugh OBDII bus = 1 @@ -109,7 +121,7 @@ def fingerprint(logcan, sendcan, has_relay): done = False while not done: - a = messaging.get_one_can(logcan) + a = get_one_can(logcan) for can in a.can: # need to independently try to fingerprint both bus 0 and 1 to work diff --git a/selfdrive/car/chrysler/carcontroller.py b/selfdrive/car/chrysler/carcontroller.py index c4db730368..b81526e9c0 100644 --- a/selfdrive/car/chrysler/carcontroller.py +++ b/selfdrive/car/chrysler/carcontroller.py @@ -11,13 +11,11 @@ class CarController(): self.prev_frame = -1 self.hud_count = 0 self.car_fingerprint = CP.carFingerprint - self.alert_active = False self.gone_fast_yet = False self.steer_rate_limited = False self.packer = CANPacker(dbc_name) - def update(self, enabled, CS, actuators, pcm_cancel_cmd, hud_alert): # this seems needed to avoid steering faults and to force the sync with the EPS counter frame = CS.lkas_counter diff --git a/selfdrive/car/chrysler/carstate.py b/selfdrive/car/chrysler/carstate.py index 1a4b1e659e..b6fdb11314 100644 --- a/selfdrive/car/chrysler/carstate.py +++ b/selfdrive/car/chrysler/carstate.py @@ -24,7 +24,7 @@ class CarState(CarStateBase): cp.vl["DOORS"]['DOOR_OPEN_RR']]) ret.seatbeltUnlatched = cp.vl["SEATBELT_STATUS"]['SEATBELT_DRIVER_UNLATCHED'] == 1 - ret.brakePressed = cp.vl["BRAKE_2"]['BRAKE_PRESSED_2'] == 5 # human-only + ret.brakePressed = cp.vl["BRAKE_2"]['BRAKE_PRESSED_2'] == 5 # human-only ret.brake = 0 ret.brakeLights = ret.brakePressed ret.gas = cp.vl["ACCEL_GAS_134"]['ACCEL_134'] @@ -103,6 +103,13 @@ class CarState(CarStateBase): ("WHEEL_SPEEDS", 50), ("STEERING", 100), ("ACC_2", 50), + ("GEAR", 50), + ("ACCEL_GAS_134", 50), + ("DASHBOARD", 15), + ("STEERING_LEVERS", 10), + ("SEATBELT_STATUS", 2), + ("DOORS", 1), + ("TRACTION_BUTTON", 1), ] return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0) @@ -115,6 +122,10 @@ class CarState(CarStateBase): ("CAR_MODEL", "LKAS_HUD", -1), ("LKAS_STATUS_OK", "LKAS_HEARTBIT", -1) ] - checks = [] + checks = [ + ("LKAS_COMMAND", 100), + ("LKAS_HEARTBIT", 10), + ("LKAS_HUD", 4), + ] return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2) diff --git a/selfdrive/car/chrysler/chryslercan.py b/selfdrive/car/chrysler/chryslercan.py index bf9f3731f6..63d1fbe0b4 100644 --- a/selfdrive/car/chrysler/chryslercan.py +++ b/selfdrive/car/chrysler/chryslercan.py @@ -16,7 +16,7 @@ def create_lkas_hud(packer, gear, lkas_active, hud_alert, hud_count, lkas_car_mo lines = 1 alerts = 0 - if hud_count < (1 *4): # first 3 seconds, 4Hz + if hud_count < (1 * 4): # first 3 seconds, 4Hz alerts = 1 # CAR.PACIFICA_2018_HYBRID and CAR.PACIFICA_2019_HYBRID # had color = 1 and lines = 1 but trying 2017 hybrid style for now. diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index 66ba7159fb..fbc469ebeb 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -11,7 +11,10 @@ class CarInterface(CarInterfaceBase): return float(accel) / 3.0 @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): + def get_params(candidate, fingerprint=None, has_relay=False, car_fw=None): + if fingerprint is None: + fingerprint = gen_empty_fingerprint() + ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay) ret.carName = "chrysler" ret.safetyModel = car.CarParams.SafetyModel.chrysler @@ -21,10 +24,10 @@ class CarInterface(CarInterfaceBase): # Speed conversion: 20, 45 mph ret.wheelbase = 3.089 # in meters for Pacifica Hybrid 2017 - ret.steerRatio = 16.2 # Pacifica Hybrid 2017 + ret.steerRatio = 16.2 # Pacifica Hybrid 2017 ret.mass = 2858. + STD_CARGO_KG # kg curb weight Pacifica Hybrid 2017 ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kiBP = [[9., 20.], [9., 20.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.15,0.30], [0.03,0.05]] + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.15, 0.30], [0.03, 0.05]] ret.lateralTuning.pid.kf = 0.00006 # full torque for 10 deg at 80mph means 0.00007818594 ret.steerActuatorDelay = 0.1 ret.steerRateCost = 0.7 @@ -67,10 +70,8 @@ class CarInterface(CarInterfaceBase): # speeds ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False - ret.buttonEvents = [] - # events - events = self.create_common_events(ret, extra_gears=[car.CarState.GearShifter.low], \ + events = self.create_common_events(ret, extra_gears=[car.CarState.GearShifter.low], gas_resume_speed=2.) if ret.vEgo < self.CP.minSteerSpeed: @@ -88,7 +89,7 @@ class CarInterface(CarInterfaceBase): def apply(self, c): if (self.CS.frame == -1): - return [] # if we haven't seen a frame 220, then do not update. + return [] # if we haven't seen a frame 220, then do not update. can_sends = self.CC.update(c.enabled, self.CS, c.actuators, c.cruiseControl.cancel, c.hudControl.visualAlert) diff --git a/selfdrive/car/chrysler/radar_interface.py b/selfdrive/car/chrysler/radar_interface.py index 40a7c5a742..3139efad34 100755 --- a/selfdrive/car/chrysler/radar_interface.py +++ b/selfdrive/car/chrysler/radar_interface.py @@ -1,16 +1,15 @@ #!/usr/bin/env python3 -import os from opendbc.can.parser import CANParser from cereal import car from selfdrive.car.interfaces import RadarInterfaceBase +from selfdrive.car.chrysler.values import DBC RADAR_MSGS_C = list(range(0x2c2, 0x2d4+2, 2)) # c_ messages 706,...,724 RADAR_MSGS_D = list(range(0x2a2, 0x2b4+2, 2)) # d_ messages LAST_MSG = max(RADAR_MSGS_C + RADAR_MSGS_D) NUMBER_MSGS = len(RADAR_MSGS_C) + len(RADAR_MSGS_D) -def _create_radar_can_parser(): - dbc_f = 'chrysler_pacifica_2017_hybrid_private_fusion.dbc' +def _create_radar_can_parser(car_fingerprint): msg_n = len(RADAR_MSGS_C) # list of [(signal name, message name or number, initial values), (...)] # [('RADAR_STATE', 1024, 0), @@ -37,7 +36,7 @@ def _create_radar_can_parser(): [20]*msg_n + # 20Hz (0.05s) [20]*msg_n)) # 20Hz (0.05s) - return CANParser(os.path.splitext(dbc_f)[0], signals, checks, 1) + return CANParser(DBC[car_fingerprint]['radar'], signals, checks, 1) def _address_to_track(address): if address in RADAR_MSGS_C: @@ -49,7 +48,7 @@ def _address_to_track(address): class RadarInterface(RadarInterfaceBase): def __init__(self, CP): super().__init__(CP) - self.rcp = _create_radar_can_parser() + self.rcp = _create_radar_can_parser(CP.carFingerprint) self.updated_messages = set() self.trigger_msg = LAST_MSG diff --git a/selfdrive/car/chrysler/test_chryslercan.py b/selfdrive/car/chrysler/test_chryslercan.py deleted file mode 100644 index 5b15666c04..0000000000 --- a/selfdrive/car/chrysler/test_chryslercan.py +++ /dev/null @@ -1,57 +0,0 @@ -import unittest - -from cereal import car -from opendbc.can.packer import CANPacker -from selfdrive.car.chrysler import chryslercan - -VisualAlert = car.CarControl.HUDControl.VisualAlert -GearShifter = car.CarState.GearShifter - - - -class TestChryslerCan(unittest.TestCase): - - def test_hud(self): - packer = CANPacker('chrysler_pacifica_2017_hybrid') - self.assertEqual( - [0x2a6, 0, b'\x01\x00\x01\x01\x00\x00\x00\x00', 0], - chryslercan.create_lkas_hud( - packer, - GearShifter.park, False, False, 1, 0)) - self.assertEqual( - [0x2a6, 0, b'\x01\x00\x01\x00\x00\x00\x00\x00', 0], - chryslercan.create_lkas_hud( - packer, - GearShifter.park, False, False, 5*4, 0)) - self.assertEqual( - [0x2a6, 0, b'\x01\x00\x01\x00\x00\x00\x00\x00', 0], - chryslercan.create_lkas_hud( - packer, - GearShifter.park, False, False, 99999, 0)) - self.assertEqual( - [0x2a6, 0, b'\x02\x00\x06\x00\x00\x00\x00\x00', 0], - chryslercan.create_lkas_hud( - packer, - GearShifter.drive, True, False, 99999, 0)) - self.assertEqual( - [0x2a6, 0, b'\x02\x64\x06\x00\x00\x00\x00\x00', 0], - chryslercan.create_lkas_hud( - packer, - GearShifter.drive, True, False, 99999, 0x64)) - - def test_command(self): - packer = CANPacker('chrysler_pacifica_2017_hybrid') - self.assertEqual( - [0x292, 0, b'\x14\x00\x00\x00\x10\x86', 0], - chryslercan.create_lkas_command( - packer, - 0, True, 1)) - self.assertEqual( - [0x292, 0, b'\x04\x00\x00\x00\x80\x83', 0], - chryslercan.create_lkas_command( - packer, - 0, False, 8)) - - -if __name__ == '__main__': - unittest.main() diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index ac1ede5f9f..b7fb53f530 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -1,8 +1,9 @@ +# flake8: noqa + from selfdrive.car import dbc_dict from cereal import car Ecu = car.CarParams.Ecu - class SteerLimitParams: STEER_MAX = 261 # 262 faults STEER_DELTA_UP = 3 # 3 is stock. 100 is fine. 200 is too much it seems @@ -10,15 +11,14 @@ class SteerLimitParams: STEER_ERROR_MAX = 80 - class CAR: PACIFICA_2017_HYBRID = "CHRYSLER PACIFICA HYBRID 2017" PACIFICA_2018_HYBRID = "CHRYSLER PACIFICA HYBRID 2018" PACIFICA_2019_HYBRID = "CHRYSLER PACIFICA HYBRID 2019" - PACIFICA_2018 = "CHRYSLER PACIFICA 2018" # Also covers Pacifica 2017. + PACIFICA_2018 = "CHRYSLER PACIFICA 2018" # includes 2017 Pacifica PACIFICA_2020 = "CHRYSLER PACIFICA 2020" - JEEP_CHEROKEE = "JEEP GRAND CHEROKEE V6 2018" # Also covers Tailhawk 2017. - JEEP_CHEROKEE_2019 = "JEEP GRAND CHEROKEE 2019" + JEEP_CHEROKEE = "JEEP GRAND CHEROKEE V6 2018" # includes 2017 Trailhawk + JEEP_CHEROKEE_2019 = "JEEP GRAND CHEROKEE 2019" # includes 2020 Trailhawk # Unique can messages: # Only the hybrids have 270: 8 @@ -41,7 +41,7 @@ FINGERPRINTS = { ], CAR.PACIFICA_2020: [ { - 55: 8, 179: 8, 181: 8, 257: 5, 258: 8, 264: 8, 268: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 528: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 650: 8, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 676: 8, 678: 8, 680: 8, 683: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 746: 5, 752: 2, 754: 8, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 782: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 847: 1, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 882: 8, 897: 8, 906: 8, 924: 8, 926: 3, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 962: 8, 969: 4, 973: 8, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1223: 7, 1225: 8, 1235: 8, 1242: 8, 1246: 8, 1250: 8, 1251: 8, 1252: 8, 1284: 8, 1568: 8, 1856: 8, 1858: 8, 1860: 8, 1863: 8, 1865: 8, 1875: 8, 1882: 8, 1886: 8, 1890: 8, 1891: 8, 1892: 8, 2016: 8, 2024: 8 + 55: 8, 179: 8, 181: 8, 257: 5, 258: 8, 264: 8, 268: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 528: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 650: 8, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 676: 8, 678: 8, 680: 8, 683: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 746: 5, 752: 2, 754: 8, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 782: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 847: 1, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 882: 8, 897: 8, 906: 8, 924: 8, 926: 3, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 962: 8, 969: 4, 973: 8, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1223: 7, 1225: 8, 1235: 8, 1242: 8, 1246: 8, 1250: 8, 1251: 8, 1252: 8, 1284: 8, 1568: 8, 1570: 8, 1856: 8, 1858: 8, 1860: 8, 1863: 8, 1865: 8, 1875: 8, 1882: 8, 1886: 8, 1890: 8, 1891: 8, 1892: 8, 2016: 8, 2024: 8 } ], CAR.PACIFICA_2018_HYBRID: [ @@ -50,7 +50,7 @@ FINGERPRINTS = { {168: 8, 257: 5, 258: 8, 264: 8, 268: 8, 270: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 291: 8, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 515: 7, 516: 7, 517: 7, 518: 7, 520: 8, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 653: 8, 654: 8, 655: 8, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 701: 8, 704: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 746: 5, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 782: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 878: 8, 882: 8, 897: 8, 908: 8, 924: 8, 926: 3, 929: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 958: 8, 959: 8, 969: 4, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1082: 8, 1083: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1225: 8, 1235: 8, 1242: 8, 1246: 8, 1250: 8, 1251: 8, 1252: 8, 1258: 8, 1259: 8, 1260: 8, 1262: 8, 1284: 8, 1537: 8, 1538: 8, 1562: 8, 1568: 8, 1856: 8, 1858: 8, 1860: 8, 1865: 8, 1875: 8, 1882: 8, 1886: 8, 1890: 8, 1891: 8, 1892: 8, 1898: 8, 1899: 8, 1900: 8, 1902: 8, 2016: 8, 2018: 8, 2019: 8, 2020: 8, 2023: 8, 2024: 8, 2026: 8, 2027: 8, 2028: 8, 2031: 8}, ], CAR.PACIFICA_2019_HYBRID: [ - {168: 8, 257: 5, 258: 8, 264: 8, 268: 8, 270: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 291: 8, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 515: 7, 516: 7, 517: 7, 518: 7, 520: 8, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 653: 8, 654: 8, 655: 8, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 680: 8, 701: 8, 703: 8, 704: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 736: 8, 737: 8, 746: 5, 752: 2, 754: 8, 760: 8, 764: 8, 766: 8, 770:8, 773: 8, 779: 8, 782: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 878: 8, 882: 8, 897: 8, 906: 8, 908: 8, 924: 8, 926: 3, 929: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 958: 8, 959: 8, 962: 8, 969: 4, 973: 8, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1082: 8, 1083: 8, 1098: 8, 1100: 8, 1538: 8}, + {168: 8, 257: 5, 258: 8, 264: 8, 268: 8, 270: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 291: 8, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 515: 7, 516: 7, 517: 7, 518: 7, 520: 8, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 653: 8, 654: 8, 655: 8, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 680: 8, 701: 8, 703: 8, 704: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 736: 8, 737: 8, 746: 5, 752: 2, 754: 8, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 782: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 878: 8, 882: 8, 897: 8, 906: 8, 908: 8, 924: 8, 926: 3, 929: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 958: 8, 959: 8, 962: 8, 969: 4, 973: 8, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1082: 8, 1083: 8, 1098: 8, 1100: 8, 1538: 8}, # Based on 0607d2516fc2148f|2019-02-13--23-03-16 { 168: 8, 257: 5, 258: 8, 264: 8, 268: 8, 270: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 291: 8, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 528: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 653: 8, 654: 8, 655: 8, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 701: 8, 703: 8, 704: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 746: 5, 752: 2, 754: 8, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 782: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 878: 8, 882: 8, 897: 8, 906: 8, 908: 8, 924: 8, 926: 3, 929: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 958: 8, 959: 8, 962: 8, 969: 4, 973: 8, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1082: 8, 1083: 8, 1098: 8, 1100: 8, 1537: 8 @@ -74,40 +74,25 @@ FINGERPRINTS = { {257: 5, 258: 8, 264: 8, 268: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 352: 8, 362: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 4, 571: 3, 584: 8, 608: 8, 618: 8, 624: 8, 625: 8, 632: 8, 639: 8, 658: 6, 660: 8, 671: 8, 672: 8, 680: 8, 684: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 736: 8, 737: 8, 746: 5, 752: 2, 760: 8, 761: 8, 764: 8, 766: 8, 773: 8, 776: 8, 779: 8, 783: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 806: 2, 808: 8, 810: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 831: 6, 832: 8, 838: 2, 844: 5, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 882: 8, 897: 8, 924: 3, 937: 8, 947: 8, 948: 8, 969: 4, 974: 5, 977: 4, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1062: 8, 1098: 8, 1100: 8}, ], CAR.JEEP_CHEROKEE_2019: [ - # Jeep Grand Cherokee 2019 - # 530: 8 is so far only in this Jeep. - {55: 8, 168: 8, 181: 8, 256: 4, 257: 5, 258: 8, 264: 8, 268: 8, 272: 6, 273: 6, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 352: 8, 362: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 530: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 618: 8, 624: 8, 625: 8, 632: 8, 639: 8, 656: 4, 658: 6, 660: 8, 671: 8, 672: 8, 676: 8, 678: 8, 680: 8, 683: 8, 684: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 738: 8, 746: 5, 752: 2, 754: 8, 760: 8, 761: 8, 764: 8, 766: 8, 773: 8, 776: 8, 779: 8, 782: 8, 783: 8, 784: 8, 785: 8, 792: 8, 799: 8, 800: 8, 804: 8, 806: 2, 808: 8, 810: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 831: 6, 832: 8, 838: 2, 840: 8, 844: 5, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 882: 8, 897: 8, 906: 8, 924: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 968: 8, 969: 4, 970: 8, 973: 8, 974: 5, 976: 8, 977: 4, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1062: 8, 1098: 8, 1100: 8, 1543: 8, 2015: 8, 2016: 8, 2024: 8}, + # Jeep Grand Cherokee 2019, including most 2020 models + {55: 8, 168: 8, 179: 8, 181: 8, 256: 4, 257: 5, 258: 8, 264: 8, 268: 8, 272: 6, 273: 6, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 341: 8, 344: 8, 352: 8, 362: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 530: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 618: 8, 624: 8, 625: 8, 632: 8, 639: 8, 640: 1, 656: 4, 658: 6, 660: 8, 671: 8, 672: 8, 676: 8, 678: 8, 680: 8, 683: 8, 684: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 738: 8, 746: 5, 752: 2, 754: 8, 760: 8, 761: 8, 764: 8, 766: 8, 773: 8, 776: 8, 779: 8, 782: 8, 783: 8, 784: 8, 785: 8, 792: 8, 799: 8, 800: 8, 804: 8, 806: 2, 808: 8, 810: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 831: 6, 832: 8, 838: 2, 840: 8, 844: 5, 847: 1, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 882: 8, 897: 8, 906: 8, 924: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 960: 4, 968: 8, 969: 4, 970: 8, 973: 8, 974: 5, 976: 8, 977: 4, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1062: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1223: 8, 1225: 8, 1227: 8, 1235: 8, 1242: 8, 1250: 8, 1251: 8, 1252: 8, 1254: 8, 1264: 8, 1284: 8, 1536: 8, 1537: 8, 1543: 8, 1545: 8, 1562: 8, 1568: 8, 1570: 8, 1572: 8, 1593: 8, 1856: 8, 1858: 8, 1860: 8, 1863: 8, 1865: 8, 1867: 8, 1875: 8, 1882: 8, 1890: 8, 1891: 8, 1892: 8, 1894: 8, 1896: 8, 1904: 8, 2015: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8}, ], } DBC = { - CAR.PACIFICA_2017_HYBRID: dbc_dict( - 'chrysler_pacifica_2017_hybrid', # 'pt' - 'chrysler_pacifica_2017_hybrid_private_fusion'), # 'radar' - CAR.PACIFICA_2018: dbc_dict( # Same DBC file works. - 'chrysler_pacifica_2017_hybrid', # 'pt' - 'chrysler_pacifica_2017_hybrid_private_fusion'), # 'radar' - CAR.PACIFICA_2020: dbc_dict( # Same DBC file works. - 'chrysler_pacifica_2017_hybrid', # 'pt' - 'chrysler_pacifica_2017_hybrid_private_fusion'), # 'radar' - CAR.PACIFICA_2018_HYBRID: dbc_dict( # Same DBC file works. - 'chrysler_pacifica_2017_hybrid', # 'pt' - 'chrysler_pacifica_2017_hybrid_private_fusion'), # 'radar' - CAR.PACIFICA_2019_HYBRID: dbc_dict( # Same DBC file works. - 'chrysler_pacifica_2017_hybrid', # 'pt' - 'chrysler_pacifica_2017_hybrid_private_fusion'), # 'radar' - CAR.JEEP_CHEROKEE: dbc_dict( # Same DBC file works. - 'chrysler_pacifica_2017_hybrid', # 'pt' - 'chrysler_pacifica_2017_hybrid_private_fusion'), # 'radar' - CAR.JEEP_CHEROKEE_2019: dbc_dict( # Same DBC file works. - 'chrysler_pacifica_2017_hybrid', # 'pt' - 'chrysler_pacifica_2017_hybrid_private_fusion'), # 'radar' + CAR.PACIFICA_2017_HYBRID: dbc_dict('chrysler_pacifica_2017_hybrid', 'chrysler_pacifica_2017_hybrid_private_fusion'), + CAR.PACIFICA_2018: dbc_dict('chrysler_pacifica_2017_hybrid', 'chrysler_pacifica_2017_hybrid_private_fusion'), + CAR.PACIFICA_2020: dbc_dict('chrysler_pacifica_2017_hybrid', 'chrysler_pacifica_2017_hybrid_private_fusion'), + CAR.PACIFICA_2018_HYBRID: dbc_dict('chrysler_pacifica_2017_hybrid', 'chrysler_pacifica_2017_hybrid_private_fusion'), + CAR.PACIFICA_2019_HYBRID: dbc_dict('chrysler_pacifica_2017_hybrid', 'chrysler_pacifica_2017_hybrid_private_fusion'), + CAR.JEEP_CHEROKEE: dbc_dict('chrysler_pacifica_2017_hybrid', 'chrysler_pacifica_2017_hybrid_private_fusion'), + CAR.JEEP_CHEROKEE_2019: dbc_dict('chrysler_pacifica_2017_hybrid', 'chrysler_pacifica_2017_hybrid_private_fusion'), } STEER_THRESHOLD = 120 ECU_FINGERPRINT = { - Ecu.fwdCamera: [0x292], # lkas cmd + Ecu.fwdCamera: [0x292], # lkas cmd } diff --git a/selfdrive/car/fingerprints.py b/selfdrive/car/fingerprints.py index c2c39f687f..64dc56625c 100644 --- a/selfdrive/car/fingerprints.py +++ b/selfdrive/car/fingerprints.py @@ -2,7 +2,7 @@ import os from common.basedir import BASEDIR -def get_attr_from_cars(attr, result=dict): +def get_attr_from_cars(attr, result=dict, combine_brands=True): # read all the folders in selfdrive/car and return a dict where: # - keys are all the car models # - values are attr values from all car folders @@ -19,7 +19,12 @@ def get_attr_from_cars(attr, result=dict): if isinstance(attr_values, dict): for f, v in attr_values.items(): - result[f] = v + if combine_brands: + result[f] = v + else: + if car_name not in result: + result[car_name] = {} + result[car_name][f] = v elif isinstance(attr_values, list): result += attr_values diff --git a/selfdrive/car/ford/carcontroller.py b/selfdrive/car/ford/carcontroller.py index 4c0a37ab02..648fa07741 100644 --- a/selfdrive/car/ford/carcontroller.py +++ b/selfdrive/car/ford/carcontroller.py @@ -78,7 +78,7 @@ class CarController(): static_msgs = range(1653, 1658) for addr in static_msgs: cnt = (frame % 10) + 1 - can_sends.append(make_can_msg(addr, (cnt<<4).to_bytes(1, 'little') + b'\x00\x00\x00\x00\x00\x00\x00', 1)) + can_sends.append(make_can_msg(addr, (cnt << 4).to_bytes(1, 'little') + b'\x00\x00\x00\x00\x00\x00\x00', 1)) self.enabled_last = enabled self.main_on_last = CS.out.cruiseState.available diff --git a/selfdrive/car/ford/fordcan.py b/selfdrive/car/ford/fordcan.py index dd0c15415e..e98dec584b 100644 --- a/selfdrive/car/ford/fordcan.py +++ b/selfdrive/car/ford/fordcan.py @@ -6,7 +6,7 @@ def create_steer_command(packer, angle_cmd, enabled, lkas_state, angle_steers, c """Creates a CAN message for the Ford Steer Command.""" #if enabled and lkas available: - if enabled and lkas_state in [2,3]: #and (frame % 500) >= 3: + if enabled and lkas_state in [2, 3]: # and (frame % 500) >= 3: action = lkas_action else: action = 0xf diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 4388ae7962..6d6c82f0b8 100755 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -14,7 +14,7 @@ class CarInterface(CarInterfaceBase): return float(accel) / 3.0 @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None): ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay) ret.carName = "ford" ret.safetyModel = car.CarParams.SafetyModel.ford @@ -60,7 +60,7 @@ class CarInterface(CarInterfaceBase): # events events = self.create_common_events(ret) - if self.CS.lkas_state not in [2, 3] and ret.vEgo > 13.* CV.MPH_TO_MS and ret.cruiseState.enabled: + if self.CS.lkas_state not in [2, 3] and ret.vEgo > 13. * CV.MPH_TO_MS and ret.cruiseState.enabled: events.add(car.CarEvent.EventName.steerTempUnavailableMute) ret.events = events.to_msg() diff --git a/selfdrive/car/ford/radar_interface.py b/selfdrive/car/ford/radar_interface.py index 3733ddce7f..20a435b082 100755 --- a/selfdrive/car/ford/radar_interface.py +++ b/selfdrive/car/ford/radar_interface.py @@ -8,14 +8,13 @@ from selfdrive.car.interfaces import RadarInterfaceBase RADAR_MSGS = list(range(0x500, 0x540)) def _create_radar_can_parser(car_fingerprint): - dbc_f = DBC[car_fingerprint]['radar'] msg_n = len(RADAR_MSGS) signals = list(zip(['X_Rel'] * msg_n + ['Angle'] * msg_n + ['V_Rel'] * msg_n, RADAR_MSGS * 3, [0] * msg_n + [0] * msg_n + [0] * msg_n)) checks = list(zip(RADAR_MSGS, [20]*msg_n)) - return CANParser(dbc_f, signals, checks, 1) + return CANParser(DBC[car_fingerprint]['radar'], signals, checks, 1) class RadarInterface(RadarInterfaceBase): def __init__(self, CP): @@ -34,7 +33,6 @@ class RadarInterface(RadarInterfaceBase): if self.trigger_msg not in self.updated_messages: return None - ret = car.RadarData.new_message() errors = [] if not self.rcp.can_valid: @@ -50,7 +48,7 @@ class RadarInterface(RadarInterfaceBase): if cpt['X_Rel'] > 0.00001: self.validCnt[ii] += 1 else: - self.validCnt[ii] = max(self.validCnt[ii] -1, 0) + self.validCnt[ii] = max(self.validCnt[ii] - 1, 0) #print ii, self.validCnt[ii], cpt['VALID'], cpt['X_Rel'], cpt['Angle'] # radar point only valid if there have been enough valid measurements diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 191f06cbc8..7c4d0aed98 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -1,3 +1,5 @@ +# flake8: noqa + from selfdrive.car import dbc_dict from cereal import car Ecu = car.CarParams.Ecu diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 95b970f125..ca53460520 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -1,20 +1,24 @@ #!/usr/bin/env python3 -import traceback import struct +import traceback +from typing import Any + from tqdm import tqdm +import panda.python.uds as uds +from cereal import car +from selfdrive.car.fingerprints import FW_VERSIONS, get_attr_from_cars from selfdrive.car.isotp_parallel_query import IsoTpParallelQuery -from selfdrive.swaglog import cloudlog -from selfdrive.car.fingerprints import FW_VERSIONS from selfdrive.car.toyota.values import CAR as TOYOTA -import panda.python.uds as uds +from selfdrive.swaglog import cloudlog -from cereal import car Ecu = car.CarParams.Ecu + def p16(val): return struct.pack("!H", val) + TESTER_PRESENT_REQUEST = bytes([uds.SERVICE_TYPE.TESTER_PRESENT, 0x0]) TESTER_PRESENT_RESPONSE = bytes([uds.SERVICE_TYPE.TESTER_PRESENT + 0x40, 0x0]) @@ -36,6 +40,19 @@ UDS_VERSION_REQUEST = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \ UDS_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) + \ p16(uds.DATA_IDENTIFIER_TYPE.APPLICATION_SOFTWARE_IDENTIFICATION) + +HYUNDAI_VERSION_REQUEST_SHORT = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \ + p16(0xf1a0) # 4 Byte version number +HYUNDAI_VERSION_REQUEST_LONG = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \ + p16(0xf100) # Long description +HYUNDAI_VERSION_REQUEST_MULTI = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \ + p16(uds.DATA_IDENTIFIER_TYPE.VEHICLE_MANUFACTURER_SPARE_PART_NUMBER) + \ + p16(uds.DATA_IDENTIFIER_TYPE.APPLICATION_SOFTWARE_IDENTIFICATION) + \ + p16(0xf100) + \ + p16(0xf1a0) +HYUNDAI_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) + + TOYOTA_VERSION_REQUEST = b'\x1a\x88\x01' TOYOTA_VERSION_RESPONSE = b'\x5a\x88\x01' @@ -43,24 +60,45 @@ OBD_VERSION_REQUEST = b'\x09\x04' OBD_VERSION_RESPONSE = b'\x49\x04' +# supports subaddressing, request, response REQUESTS = [ + # Hundai + ( + "hyundai", + [HYUNDAI_VERSION_REQUEST_SHORT], + [HYUNDAI_VERSION_RESPONSE], + ), + ( + "hyundai", + [HYUNDAI_VERSION_REQUEST_LONG], + [HYUNDAI_VERSION_RESPONSE], + ), + ( + "hyundai", + [HYUNDAI_VERSION_REQUEST_MULTI], + [HYUNDAI_VERSION_RESPONSE], + ), # Honda ( + "honda", [UDS_VERSION_REQUEST], - [UDS_VERSION_RESPONSE] + [UDS_VERSION_RESPONSE], ), # Toyota ( + "toyota", [SHORT_TESTER_PRESENT_REQUEST, TOYOTA_VERSION_REQUEST], - [SHORT_TESTER_PRESENT_RESPONSE, TOYOTA_VERSION_RESPONSE] + [SHORT_TESTER_PRESENT_RESPONSE, TOYOTA_VERSION_RESPONSE], ), ( + "toyota", [SHORT_TESTER_PRESENT_REQUEST, OBD_VERSION_REQUEST], - [SHORT_TESTER_PRESENT_RESPONSE, OBD_VERSION_RESPONSE] + [SHORT_TESTER_PRESENT_RESPONSE, OBD_VERSION_RESPONSE], ), ( + "toyota", [TESTER_PRESENT_REQUEST, DEFAULT_DIAGNOSTIC_REQUEST, EXTENDED_DIAGNOSTIC_REQUEST, UDS_VERSION_REQUEST], - [TESTER_PRESENT_RESPONSE, DEFAULT_DIAGNOSTIC_RESPONSE, EXTENDED_DIAGNOSTIC_RESPONSE, UDS_VERSION_RESPONSE] + [TESTER_PRESENT_RESPONSE, DEFAULT_DIAGNOSTIC_RESPONSE, EXTENDED_DIAGNOSTIC_RESPONSE, UDS_VERSION_RESPONSE], ) ] @@ -112,33 +150,37 @@ def get_fw_versions(logcan, sendcan, bus, extra=None, timeout=0.1, debug=False, addrs = [] parallel_addrs = [] - versions = FW_VERSIONS + versions = get_attr_from_cars('FW_VERSIONS', combine_brands=False) if extra is not None: versions.update(extra) - for c in versions.values(): - for ecu_type, addr, sub_addr in c.keys(): - a = (addr, sub_addr) - if a not in ecu_types: - ecu_types[a] = ecu_type + for brand, brand_versions in versions.items(): + for c in brand_versions.values(): + for ecu_type, addr, sub_addr in c.keys(): + a = (brand, addr, sub_addr) + if a not in ecu_types: + ecu_types[(addr, sub_addr)] = ecu_type - if sub_addr is None: - if a not in parallel_addrs: - parallel_addrs.append(a) - else: - if [a] not in addrs: - addrs.append([a]) + if sub_addr is None: + if a not in parallel_addrs: + parallel_addrs.append(a) + else: + if [a] not in addrs: + addrs.append([a]) addrs.insert(0, parallel_addrs) fw_versions = {} for i, addr in enumerate(tqdm(addrs, disable=not progress)): for addr_chunk in chunks(addr): - for request, response in REQUESTS: + for brand, request, response in REQUESTS: try: - query = IsoTpParallelQuery(sendcan, logcan, bus, addr_chunk, request, response, debug=debug) - t = 2 * timeout if i == 0 else timeout - fw_versions.update(query.get_data(t)) + addrs = [(a, s) for (b, a, s) in addr_chunk if b in (brand, 'any')] + + if addrs: + query = IsoTpParallelQuery(sendcan, logcan, bus, addrs, request, response, debug=debug) + t = 2 * timeout if i == 0 else timeout + fw_versions.update(query.get_data(t)) except Exception: cloudlog.warning(f"FW query exception: {traceback.format_exc()}") @@ -173,14 +215,15 @@ if __name__ == "__main__": logcan = messaging.sub_sock('can') sendcan = messaging.pub_sock('sendcan') - extra = None + extra: Any = None if args.scan: - extra = {"DEBUG": {}} + extra = {} # Honda for i in range(256): - extra["DEBUG"][(Ecu.unknown, 0x18da00f1 + (i << 8), None)] = [] - extra["DEBUG"][(Ecu.unknown, 0x700 + i, None)] = [] - extra["DEBUG"][(Ecu.unknown, 0x750, i)] = [] + extra[(Ecu.unknown, 0x18da00f1 + (i << 8), None)] = [] + extra[(Ecu.unknown, 0x700 + i, None)] = [] + extra[(Ecu.unknown, 0x750, i)] = [] + extra = {"any": {"debug": extra}} time.sleep(1.) diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index bda8ef22cd..9b8e68fee4 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -20,7 +20,7 @@ class CarControllerParams(): self.STEER_DRIVER_ALLOWANCE = 50 # allowed driver torque before start limiting self.STEER_DRIVER_MULTIPLIER = 4 # weight driver torque heavily self.STEER_DRIVER_FACTOR = 100 # from dbc - self.NEAR_STOP_BRAKE_PHASE = 0.5 # m/s, more aggressive braking near full stop + self.NEAR_STOP_BRAKE_PHASE = 0.5 # m/s, more aggressive braking near full stop # Takes case of "Service Adaptive Cruise" and "Service Front Camera" # dashboard messages. @@ -38,24 +38,8 @@ class CarControllerParams(): self.BRAKE_LOOKUP_V = [MAX_BRAKE, 0] -def actuator_hystereses(final_pedal, pedal_steady): - # hyst params... TODO: move these to VehicleParams - pedal_hyst_gap = 0.01 # don't change pedal command for small oscillations within this value - - # for small pedal oscillations within pedal_hyst_gap, don't change the pedal command - if final_pedal == 0.: - pedal_steady = 0. - elif final_pedal > pedal_steady + pedal_hyst_gap: - pedal_steady = final_pedal - pedal_hyst_gap - elif final_pedal < pedal_steady - pedal_hyst_gap: - pedal_steady = final_pedal + pedal_hyst_gap - final_pedal = pedal_steady - - return final_pedal, pedal_steady - class CarController(): def __init__(self, dbc_name, CP, VM): - self.pedal_steady = 0. self.start_time = 0. self.apply_steer_last = 0 self.lka_icon_status_last = (False, False) @@ -64,9 +48,10 @@ class CarController(): self.params = CarControllerParams() self.packer_pt = CANPacker(DBC[CP.carFingerprint]['pt']) + self.packer_obj = CANPacker(DBC[CP.carFingerprint]['radar']) self.packer_ch = CANPacker(DBC[CP.carFingerprint]['chassis']) - def update(self, enabled, CS, frame, actuators, \ + def update(self, enabled, CS, frame, actuators, hud_v_cruise, hud_show_lanes, hud_show_car, hud_alert): P = self.params @@ -74,8 +59,7 @@ class CarController(): # Send CAN commands. can_sends = [] - ### STEER ### - + # STEER if (frame % P.STEER_STEP) == 0: lkas_enabled = enabled and not CS.out.steerWarning and CS.out.vEgo > P.MIN_STEER_SPEED if lkas_enabled: @@ -88,19 +72,13 @@ class CarController(): self.apply_steer_last = apply_steer idx = (frame // P.STEER_STEP) % 4 - can_sends.append(gmcan.create_steering_control(self.packer_pt, - CanBus.POWERTRAIN, apply_steer, idx, lkas_enabled)) - - ### GAS/BRAKE ### + can_sends.append(gmcan.create_steering_control(self.packer_pt, CanBus.POWERTRAIN, apply_steer, idx, lkas_enabled)) + # GAS/BRAKE # no output if not enabled, but keep sending keepalive messages # treat pedals as one final_pedal = actuators.gas - actuators.brake - # *** apply pedal hysteresis *** - final_brake, self.brake_steady = actuator_hystereses( - final_pedal, self.pedal_steady) - if not enabled: # Stock ECU sends max regen when not enabled. apply_gas = P.MAX_ACC_REGEN @@ -116,13 +94,12 @@ class CarController(): at_full_stop = enabled and CS.out.standstill near_stop = enabled and (CS.out.vEgo < P.NEAR_STOP_BRAKE_PHASE) can_sends.append(gmcan.create_friction_brake_command(self.packer_ch, CanBus.CHASSIS, apply_brake, idx, near_stop, at_full_stop)) - - at_full_stop = enabled and CS.out.standstill can_sends.append(gmcan.create_gas_regen_command(self.packer_pt, CanBus.POWERTRAIN, apply_gas, idx, enabled, at_full_stop)) # Send dashboard UI commands (ACC status), 25hz if (frame % 4) == 0: - can_sends.append(gmcan.create_acc_dashboard_command(self.packer_pt, CanBus.POWERTRAIN, enabled, hud_v_cruise * CV.MS_TO_KPH, hud_show_car)) + send_fcw = hud_alert == VisualAlert.fcw + can_sends.append(gmcan.create_acc_dashboard_command(self.packer_pt, CanBus.POWERTRAIN, enabled, hud_v_cruise * CV.MS_TO_KPH, hud_show_car, send_fcw)) # Radar needs to know current speed and yaw rate (50hz), # and that ADAS is alive (10hz) @@ -132,7 +109,7 @@ class CarController(): if frame % time_and_headlights_step == 0: idx = (frame // time_and_headlights_step) % 4 can_sends.append(gmcan.create_adas_time_status(CanBus.OBSTACLE, int((tt - self.start_time) * 60), idx)) - can_sends.append(gmcan.create_adas_headlights_status(CanBus.OBSTACLE)) + can_sends.append(gmcan.create_adas_headlights_status(self.packer_obj, CanBus.OBSTACLE)) speed_and_accelerometer_step = 2 if frame % speed_and_accelerometer_step == 0: @@ -150,8 +127,7 @@ class CarController(): lka_active = CS.lkas_status == 1 lka_critical = lka_active and abs(actuators.steer) > 0.9 lka_icon_status = (lka_active, lka_critical) - if frame % P.CAMERA_KEEPALIVE_STEP == 0 \ - or lka_icon_status != self.lka_icon_status_last: + if frame % P.CAMERA_KEEPALIVE_STEP == 0 or lka_icon_status != self.lka_icon_status_last: steer_alert = hud_alert == VisualAlert.steerRequired can_sends.append(gmcan.create_lka_icon_command(CanBus.SW_GMLAN, lka_active, lka_critical, steer_alert)) self.lka_icon_status_last = lka_icon_status diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index ac866ba226..7f45e7ea9e 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -5,8 +5,7 @@ from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser from selfdrive.car.interfaces import CarStateBase from selfdrive.car.gm.values import DBC, CAR, AccState, CanBus, \ - CruiseButtons, is_eps_status_ok, \ - STEER_THRESHOLD + CruiseButtons, STEER_THRESHOLD class CarState(CarStateBase): @@ -44,9 +43,9 @@ class CarState(CarStateBase): # 1 - open, 0 - closed ret.doorOpen = (pt_cp.vl["BCMDoorBeltStatus"]['FrontLeftDoor'] == 1 or - pt_cp.vl["BCMDoorBeltStatus"]['FrontRightDoor'] == 1 or - pt_cp.vl["BCMDoorBeltStatus"]['RearLeftDoor'] == 1 or - pt_cp.vl["BCMDoorBeltStatus"]['RearRightDoor'] == 1) + pt_cp.vl["BCMDoorBeltStatus"]['FrontRightDoor'] == 1 or + pt_cp.vl["BCMDoorBeltStatus"]['RearLeftDoor'] == 1 or + pt_cp.vl["BCMDoorBeltStatus"]['RearRightDoor'] == 1) # 1 - latched ret.seatbeltUnlatched = pt_cp.vl["BCMDoorBeltStatus"]['LeftSeatBelt'] == 0 @@ -58,18 +57,17 @@ class CarState(CarStateBase): ret.espDisabled = pt_cp.vl["ESPStatus"]['TractionControlOn'] != 1 self.pcm_acc_status = pt_cp.vl["AcceleratorPedal2"]['CruiseState'] - regen_pressed = False + ret.brakePressed = ret.brake > 1e-5 + # Regen braking is braking if self.car_fingerprint == CAR.VOLT: - regen_pressed = bool(pt_cp.vl["EBCMRegenPaddle"]['RegenPaddle']) + ret.brakePressed = ret.brakePressed or bool(pt_cp.vl["EBCMRegenPaddle"]['RegenPaddle']) - # Regen braking is braking - ret.brakePressed = ret.brake > 1e-5 or regen_pressed ret.cruiseState.enabled = self.pcm_acc_status != AccState.OFF ret.cruiseState.standstill = self.pcm_acc_status == AccState.STANDSTILL # 0 - inactive, 1 - active, 2 - temporary limited, 3 - failed self.lkas_status = pt_cp.vl["PSCMStatus"]['LKATorqueDeliveredStatus'] - ret.steerWarning = not is_eps_status_ok(self.lkas_status, self.car_fingerprint) + ret.steerWarning = self.lkas_status not in [0, 1] return ret diff --git a/selfdrive/car/gm/gmcan.py b/selfdrive/car/gm/gmcan.py index 23b521f55b..9dd78e4df8 100644 --- a/selfdrive/car/gm/gmcan.py +++ b/selfdrive/car/gm/gmcan.py @@ -28,7 +28,7 @@ def create_gas_regen_command(packer, bus, throttle, idx, acc_engaged, at_full_st } dat = packer.make_can_msg("ASCMGasRegenCmd", bus, values)[2] - values["GasRegenChecksum"] = (((0xff -dat[1]) & 0xff) << 16) | \ + values["GasRegenChecksum"] = (((0xff - dat[1]) & 0xff) << 16) | \ (((0xff - dat[2]) & 0xff) << 8) | \ ((0x100 - dat[3] - idx) & 0xff) @@ -60,7 +60,7 @@ def create_friction_brake_command(packer, bus, apply_brake, idx, near_stop, at_f return packer.make_can_msg("EBCMFrictionBrakeCmd", bus, values) -def create_acc_dashboard_command(packer, bus, acc_engaged, target_speed_kph, lead_car_in_sight): +def create_acc_dashboard_command(packer, bus, acc_engaged, target_speed_kph, lead_car_in_sight, fcw): # Not a bit shift, dash can round up based on low 4 bits. target_speed = int(target_speed_kph * 16) & 0xfff @@ -68,10 +68,11 @@ def create_acc_dashboard_command(packer, bus, acc_engaged, target_speed_kph, lea "ACCAlwaysOne" : 1, "ACCResumeButton" : 0, "ACCSpeedSetpoint" : target_speed, - "ACCGapLevel" : 3 * acc_engaged, # 3 "far", 0 "inactive" + "ACCGapLevel" : 3 * acc_engaged, # 3 "far", 0 "inactive" "ACCCmdActive" : acc_engaged, "ACCAlwaysOne2" : 1, - "ACCLeadCar" : lead_car_in_sight + "ACCLeadCar" : lead_car_in_sight, + "FCWAlert": 0x3 if fcw else 0 } return packer.make_can_msg("ASCMActiveCruiseControlStatus", bus, values) @@ -103,8 +104,12 @@ def create_adas_accelerometer_speed_status(bus, speed_ms, idx): dat += [(idx << 5) + (far_range_mode << 4) + (near_range_mode << 3) + (chksum >> 8), chksum & 0xff] return make_can_msg(0x308, bytes(dat), bus) -def create_adas_headlights_status(bus): - return make_can_msg(0x310, b"\x42\x04", bus) +def create_adas_headlights_status(packer, bus): + values = { + "Always42": 0x42, + "Always4": 0x4, + } + return packer.make_can_msg("ASCMHeadlight", bus, values) def create_lka_icon_command(bus, active, critical, steer): if active and steer == 1: @@ -120,4 +125,3 @@ def create_lka_icon_command(bus, active, critical, steer): else: dat = b"\x00\x00\x00" return make_can_msg(0x104c006c, dat, bus) - diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 55dffce205..0fc3d278ce 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -16,13 +16,13 @@ class CarInterface(CarInterfaceBase): return float(accel) / 4.0 @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None): ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay) ret.carName = "gm" - ret.safetyModel = car.CarParams.SafetyModel.gm # default to gm + ret.safetyModel = car.CarParams.SafetyModel.gm ret.enableCruise = False # stock cruise control is kept off - # GM port is considered a community feature, since it disables AEB; + # GM port is a community feature # TODO: make a port that uses a car harness and it only intercepts the camera ret.communityFeature = True @@ -34,6 +34,7 @@ class CarInterface(CarInterfaceBase): tire_stiffness_factor = 0.444 # not optimized yet # Start with a baseline lateral tuning for all GM vehicles. Override tuning as needed in each model section below. + ret.minSteerSpeed = 7 * CV.MPH_TO_MS ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.00]] ret.lateralTuning.pid.kf = 0.00004 # full torque for 20 deg at 80mph means 0.00007818594 @@ -47,7 +48,7 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.69 ret.steerRatio = 15.7 ret.steerRatioRear = 0. - ret.centerToFront = ret.wheelbase * 0.4 # wild guess + ret.centerToFront = ret.wheelbase * 0.4 # wild guess elif candidate == CAR.MALIBU: # supports stop and go, but initial engage must be above 18mph (which include conservatism) @@ -56,7 +57,7 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.83 ret.steerRatio = 15.8 ret.steerRatioRear = 0. - ret.centerToFront = ret.wheelbase * 0.4 # wild guess + ret.centerToFront = ret.wheelbase * 0.4 # wild guess elif candidate == CAR.HOLDEN_ASTRA: ret.mass = 1363. + STD_CARGO_KG @@ -68,20 +69,20 @@ class CarInterface(CarInterfaceBase): ret.steerRatioRear = 0. elif candidate == CAR.ACADIA: - ret.minEnableSpeed = -1. # engage speed is decided by pcm + ret.minEnableSpeed = -1. # engage speed is decided by pcm ret.mass = 4353. * CV.LB_TO_KG + STD_CARGO_KG ret.wheelbase = 2.86 - ret.steerRatio = 14.4 #end to end is 13.46 + ret.steerRatio = 14.4 # end to end is 13.46 ret.steerRatioRear = 0. ret.centerToFront = ret.wheelbase * 0.4 elif candidate == CAR.BUICK_REGAL: ret.minEnableSpeed = 18 * CV.MPH_TO_MS - ret.mass = 3779. * CV.LB_TO_KG + STD_CARGO_KG # (3849+3708)/2 - ret.wheelbase = 2.83 #111.4 inches in meters - ret.steerRatio = 14.4 # guess for tourx + ret.mass = 3779. * CV.LB_TO_KG + STD_CARGO_KG # (3849+3708)/2 + ret.wheelbase = 2.83 # 111.4 inches in meters + ret.steerRatio = 14.4 # guess for tourx ret.steerRatioRear = 0. - ret.centerToFront = ret.wheelbase * 0.4 # guess for tourx + ret.centerToFront = ret.wheelbase * 0.4 # guess for tourx elif candidate == CAR.CADILLAC_ATS: ret.minEnableSpeed = 18 * CV.MPH_TO_MS @@ -135,7 +136,7 @@ class CarInterface(CarInterfaceBase): but = self.CS.prev_cruise_buttons if but == CruiseButtons.RES_ACCEL: if not (ret.cruiseState.enabled and ret.standstill): - be.type = ButtonType.accelCruise # Suppress resume button if we're resuming from stop so we don't adjust speed. + be.type = ButtonType.accelCruise # Suppress resume button if we're resuming from stop so we don't adjust speed. elif but == CruiseButtons.DECEL_SET: be.type = ButtonType.decelCruise elif but == CruiseButtons.CANCEL: @@ -149,13 +150,15 @@ class CarInterface(CarInterfaceBase): events = self.create_common_events(ret, pcm_enable=False) if ret.vEgo < self.CP.minEnableSpeed: - events.add(EventName.speedTooLow) + events.add(EventName.belowEngageSpeed) if self.CS.park_brake: events.add(EventName.parkBrake) if ret.cruiseState.standstill: events.add(EventName.resumeRequired) if self.CS.pcm_acc_status == AccState.FAULTED: events.add(EventName.controlsFailed) + if ret.vEgo < self.CP.minSteerSpeed: + events.add(car.CarEvent.EventName.belowSteerSpeed) # handle button presses for b in ret.buttonEvents: @@ -182,9 +185,9 @@ class CarInterface(CarInterfaceBase): # In GM, PCM faults out if ACC command overlaps user gas. enabled = c.enabled and not self.CS.out.gasPressed - can_sends = self.CC.update(enabled, self.CS, self.frame, \ + can_sends = self.CC.update(enabled, self.CS, self.frame, c.actuators, - hud_v_cruise, c.hudControl.lanesVisible, \ + hud_v_cruise, c.hudControl.lanesVisible, c.hudControl.leadVisible, c.hudControl.visualAlert) self.frame += 1 diff --git a/selfdrive/car/gm/radar_interface.py b/selfdrive/car/gm/radar_interface.py index 8a2f9a2e69..dc2c2f7b7c 100755 --- a/selfdrive/car/gm/radar_interface.py +++ b/selfdrive/car/gm/radar_interface.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 from __future__ import print_function import math -import time from cereal import car from opendbc.can.parser import CANParser from selfdrive.car.gm.values import DBC, CAR, CanBus @@ -17,30 +16,28 @@ NUM_SLOTS = 20 LAST_RADAR_MSG = RADAR_HEADER_MSG + NUM_SLOTS def create_radar_can_parser(car_fingerprint): - - dbc_f = DBC[car_fingerprint]['radar'] - if car_fingerprint in (CAR.VOLT, CAR.MALIBU, CAR.HOLDEN_ASTRA, CAR.ACADIA, CAR.CADILLAC_ATS): - # C1A-ARS3-A by Continental - radar_targets = list(range(SLOT_1_MSG, SLOT_1_MSG + NUM_SLOTS)) - signals = list(zip(['FLRRNumValidTargets', - 'FLRRSnsrBlckd', 'FLRRYawRtPlsblityFlt', - 'FLRRHWFltPrsntInt', 'FLRRAntTngFltPrsnt', - 'FLRRAlgnFltPrsnt', 'FLRRSnstvFltPrsntInt'] + - ['TrkRange'] * NUM_SLOTS + ['TrkRangeRate'] * NUM_SLOTS + - ['TrkRangeAccel'] * NUM_SLOTS + ['TrkAzimuth'] * NUM_SLOTS + - ['TrkWidth'] * NUM_SLOTS + ['TrkObjectID'] * NUM_SLOTS, - [RADAR_HEADER_MSG] * 7 + radar_targets * 6, - [0] * 7 + - [0.0] * NUM_SLOTS + [0.0] * NUM_SLOTS + - [0.0] * NUM_SLOTS + [0.0] * NUM_SLOTS + - [0.0] * NUM_SLOTS + [0] * NUM_SLOTS)) - - checks = [] - - return CANParser(dbc_f, signals, checks, CanBus.OBSTACLE) - else: + if car_fingerprint not in (CAR.VOLT, CAR.MALIBU, CAR.HOLDEN_ASTRA, CAR.ACADIA, CAR.CADILLAC_ATS): return None + # C1A-ARS3-A by Continental + radar_targets = list(range(SLOT_1_MSG, SLOT_1_MSG + NUM_SLOTS)) + signals = list(zip(['FLRRNumValidTargets', + 'FLRRSnsrBlckd', 'FLRRYawRtPlsblityFlt', + 'FLRRHWFltPrsntInt', 'FLRRAntTngFltPrsnt', + 'FLRRAlgnFltPrsnt', 'FLRRSnstvFltPrsntInt'] + + ['TrkRange'] * NUM_SLOTS + ['TrkRangeRate'] * NUM_SLOTS + + ['TrkRangeAccel'] * NUM_SLOTS + ['TrkAzimuth'] * NUM_SLOTS + + ['TrkWidth'] * NUM_SLOTS + ['TrkObjectID'] * NUM_SLOTS, + [RADAR_HEADER_MSG] * 7 + radar_targets * 6, + [0] * 7 + + [0.0] * NUM_SLOTS + [0.0] * NUM_SLOTS + + [0.0] * NUM_SLOTS + [0.0] * NUM_SLOTS + + [0.0] * NUM_SLOTS + [0] * NUM_SLOTS)) + + checks = [] + + return CANParser(DBC[car_fingerprint]['radar'], signals, checks, CanBus.OBSTACLE) + class RadarInterface(RadarInterfaceBase): def __init__(self, CP): super().__init__(CP) @@ -53,8 +50,7 @@ class RadarInterface(RadarInterfaceBase): def update(self, can_strings): if self.rcp is None: - time.sleep(self.radar_ts) # nothing to do - return car.RadarData.new_message() + return super().update(None) vls = self.rcp.update_strings(can_strings) self.updated_messages.update(vls) @@ -95,7 +91,7 @@ class RadarInterface(RadarInterfaceBase): self.pts[targetId] = car.RadarData.RadarPoint.new_message() self.pts[targetId].trackId = targetId distance = cpt['TrkRange'] - self.pts[targetId].dRel = distance # from front of car + self.pts[targetId].dRel = distance # from front of car # From driver's pov, left is positive self.pts[targetId].yRel = math.sin(cpt['TrkAzimuth'] * CV.DEG_TO_RAD) * distance self.pts[targetId].vRel = cpt['TrkRangeRate'] @@ -103,7 +99,7 @@ class RadarInterface(RadarInterfaceBase): self.pts[targetId].yvRel = float('nan') for oldTarget in list(self.pts.keys()): - if not oldTarget in currentTargets: + if oldTarget not in currentTargets: del self.pts[oldTarget] ret.points = list(self.pts.values()) diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index 6a35c17c9b..efe696f8a6 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -1,3 +1,5 @@ +# flake8: noqa + from cereal import car from selfdrive.car import dbc_dict Ecu = car.CarParams.Ecu @@ -11,27 +13,24 @@ class CAR: BUICK_REGAL = "BUICK REGAL ESSENCE 2018" class CruiseButtons: - INIT = 0 - UNPRESS = 1 - RES_ACCEL = 2 - DECEL_SET = 3 - MAIN = 5 - CANCEL = 6 + INIT = 0 + UNPRESS = 1 + RES_ACCEL = 2 + DECEL_SET = 3 + MAIN = 5 + CANCEL = 6 class AccState: - OFF = 0 - ACTIVE = 1 - FAULTED = 3 + OFF = 0 + ACTIVE = 1 + FAULTED = 3 STANDSTILL = 4 class CanBus: POWERTRAIN = 0 - OBSTACLE = 1 - CHASSIS = 2 - SW_GMLAN = 3 - -def is_eps_status_ok(eps_status, car_fingerprint): - return eps_status in [0, 1] + OBSTACLE = 1 + CHASSIS = 2 + SW_GMLAN = 3 FINGERPRINTS = { # Astra BK MY17, ASCM unplugged diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index a09dffce30..0438dd76a0 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -96,8 +96,8 @@ class CarController(): self.params = CarControllerParams(CP) - def update(self, enabled, CS, frame, actuators, \ - pcm_speed, pcm_override, pcm_cancel_cmd, pcm_accel, \ + def update(self, enabled, CS, frame, actuators, + pcm_speed, pcm_override, pcm_cancel_cmd, pcm_accel, hud_v_cruise, hud_show_lanes, hud_show_car, hud_alert): P = self.params diff --git a/selfdrive/car/honda/carstate.py b/selfdrive/car/honda/carstate.py index 91124564e7..4aaa98aa66 100644 --- a/selfdrive/car/honda/carstate.py +++ b/selfdrive/car/honda/carstate.py @@ -20,7 +20,7 @@ def calc_cruise_offset(offset, speed): def get_can_signals(CP): -# this function generates lists for signal, messages and initial values + # this function generates lists for signal, messages and initial values signals = [ ("XMISSION_SPEED", "ENGINE_DATA", 0), ("WHEEL_SPEED_FL", "WHEEL_SPEEDS", 0), @@ -128,10 +128,15 @@ def get_can_signals(CP): ("MAIN_ON", "SCM_BUTTONS", 0)] elif CP.carFingerprint in (CAR.CRV, CAR.CRV_EU, CAR.ACURA_RDX, CAR.PILOT_2019, CAR.RIDGELINE): signals += [("MAIN_ON", "SCM_BUTTONS", 0)] - elif CP.carFingerprint in (CAR.FIT, CAR.HRV): + elif CP.carFingerprint == CAR.FIT: signals += [("CAR_GAS", "GAS_PEDAL_2", 0), ("MAIN_ON", "SCM_BUTTONS", 0), ("BRAKE_HOLD_ACTIVE", "VSA_STATUS", 0)] + elif CP.carFingerprint == CAR.HRV: + signals += [("CAR_GAS", "GAS_PEDAL", 0), + ("MAIN_ON", "SCM_BUTTONS", 0), + ("BRAKE_HOLD_ACTIVE", "VSA_STATUS", 0)] + elif CP.carFingerprint == CAR.ODYSSEY: signals += [("MAIN_ON", "SCM_FEEDBACK", 0), ("EPB_STATE", "EPB_STATUS", 0)] @@ -167,7 +172,7 @@ class CarState(CarStateBase): self.v_cruise_pcm_prev = 0 self.cruise_mode = 0 - def update(self, cp, cp_cam): + def update(self, cp, cp_cam, cp_body): ret = car.CarState.new_message() # car params @@ -179,7 +184,8 @@ class CarState(CarStateBase): self.prev_cruise_setting = self.cruise_setting # ******************* parse out can ******************* - if self.CP.carFingerprint in (CAR.ACCORD, CAR.ACCORD_15, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.INSIGHT): # TODO: find wheels moving bit in dbc + # TODO: find wheels moving bit in dbc + if self.CP.carFingerprint in (CAR.ACCORD, CAR.ACCORD_15, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.INSIGHT): ret.standstill = cp.vl["ENGINE_DATA"]['XMISSION_SPEED'] < 0.1 ret.doorOpen = bool(cp.vl["SCM_FEEDBACK"]['DRIVERS_DOOR_OPEN']) elif self.CP.carFingerprint == CAR.ODYSSEY_CHN: @@ -228,7 +234,8 @@ class CarState(CarStateBase): ret.rightBlinker = cp.vl["SCM_FEEDBACK"]['RIGHT_BLINKER'] != 0 self.brake_hold = cp.vl["VSA_STATUS"]['BRAKE_HOLD_ACTIVE'] - if self.CP.carFingerprint in (CAR.CIVIC, CAR.ODYSSEY, CAR.CRV_5G, CAR.ACCORD, CAR.ACCORD_15, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.INSIGHT): + if self.CP.carFingerprint in (CAR.CIVIC, CAR.ODYSSEY, CAR.CRV_5G, CAR.ACCORD, CAR.ACCORD_15, CAR.ACCORDH, CAR.CIVIC_BOSCH, + CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.INSIGHT): self.park_brake = cp.vl["EPB_STATUS"]['EPB_STATE'] != 0 main_on = cp.vl["SCM_FEEDBACK"]['MAIN_ON'] elif self.CP.carFingerprint == CAR.ODYSSEY_CHN: @@ -243,7 +250,7 @@ class CarState(CarStateBase): self.pedal_gas = cp.vl["POWERTRAIN_DATA"]['PEDAL_GAS'] # crv doesn't include cruise control - if self.CP.carFingerprint in (CAR.CRV, CAR.CRV_EU, CAR.ODYSSEY, CAR.ACURA_RDX, CAR.RIDGELINE, CAR.PILOT_2019, CAR.ODYSSEY_CHN): + if self.CP.carFingerprint in (CAR.CRV, CAR.CRV_EU, CAR.HRV, CAR.ODYSSEY, CAR.ACURA_RDX, CAR.RIDGELINE, CAR.PILOT_2019, CAR.ODYSSEY_CHN): ret.gas = self.pedal_gas / 256. else: ret.gas = cp.vl["GAS_PEDAL_2"]['CAR_GAS'] / 256. @@ -252,7 +259,7 @@ class CarState(CarStateBase): # TODO: Replace tests by toyota so this can go away if self.CP.enableGasInterceptor: self.user_gas = (cp.vl["GAS_SENSOR"]['INTERCEPTOR_GAS'] + cp.vl["GAS_SENSOR"]['INTERCEPTOR_GAS2']) / 2. - self.user_gas_pressed = self.user_gas > 1e-5 # this works because interceptor read < 0 when pedal position is 0. Once calibrated, this will change + self.user_gas_pressed = self.user_gas > 1e-5 # this works because interceptor read < 0 when pedal position is 0. Once calibrated, this will change ret.gasPressed = self.user_gas_pressed else: ret.gasPressed = self.pedal_gas > 1e-5 @@ -269,7 +276,7 @@ class CarState(CarStateBase): ret.cruiseState.speedOffset = calc_cruise_offset(0, ret.vEgo) if self.CP.carFingerprint in (CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.ACCORDH, CAR.CRV_HYBRID, CAR.INSIGHT): ret.brakePressed = cp.vl["POWERTRAIN_DATA"]['BRAKE_PRESSED'] != 0 or \ - (self.brake_switch and self.brake_switch_prev and \ + (self.brake_switch and self.brake_switch_prev and cp.ts["POWERTRAIN_DATA"]['BRAKE_SWITCH'] != self.brake_switch_ts) self.brake_switch_prev = self.brake_switch self.brake_switch_ts = cp.ts["POWERTRAIN_DATA"]['BRAKE_SWITCH'] @@ -291,7 +298,8 @@ class CarState(CarStateBase): ret.brake = cp.vl["VSA_STATUS"]['USER_BRAKE'] ret.cruiseState.enabled = cp.vl["POWERTRAIN_DATA"]['ACC_STATUS'] != 0 - ret.cruiseState.available = bool(main_on) and self.cruise_mode == 0 + ret.cruiseState.available = bool(main_on) + ret.cruiseState.nonAdaptive = self.cruise_mode != 0 # Gets rid of Pedal Grinding noise when brake is pressed at slow speeds for some models if self.CP.carFingerprint in (CAR.PILOT, CAR.PILOT_2019, CAR.RIDGELINE): @@ -314,6 +322,12 @@ class CarState(CarStateBase): self.stock_hud = cp_cam.vl["ACC_HUD"] self.stock_brake = cp_cam.vl["BRAKE_COMMAND"] + if self.CP.carFingerprint in (CAR.CRV_5G, ): + # BSM messages are on B-CAN, requires a panda forwarding B-CAN messages to CAN 0 + # more info here: https://github.com/commaai/openpilot/pull/1867 + ret.leftBlindspot = cp_body.vl["BSM_STATUS_LEFT"]['BSM_ALERT'] == 1 + ret.rightBlindspot = cp_body.vl["BSM_STATUS_RIGHT"]['BSM_ALERT'] == 1 + return ret @staticmethod @@ -339,11 +353,24 @@ class CarState(CarStateBase): ("FCM_PROBLEM", "ACC_HUD", 0), ("ICONS", "ACC_HUD", 0)] - # all hondas except CRV, RDX and 2019 Odyssey@China use 0xe4 for steering checks = [(0xe4, 100)] if CP.carFingerprint in [CAR.CRV, CAR.CRV_EU, CAR.ACURA_RDX, CAR.ODYSSEY_CHN]: checks = [(0x194, 100)] - bus_cam = 1 if CP.carFingerprint in HONDA_BOSCH and not CP.isPandaBlack else 2 + bus_cam = 1 if CP.carFingerprint in HONDA_BOSCH and not CP.isPandaBlack else 2 return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, bus_cam) + + @staticmethod + def get_body_can_parser(CP): + signals = [] + checks = [] + + if CP.carFingerprint == CAR.CRV_5G: + signals += [("BSM_ALERT", "BSM_STATUS_RIGHT", 0), + ("BSM_ALERT", "BSM_STATUS_LEFT", 0)] + + bus_body = 0 # B-CAN is forwarded to ACC-CAN radar side (CAN 0 on fake ethernet port) + return CANParser(DBC[CP.carFingerprint]['body'], signals, checks, bus_body) + + return None diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 0edae57dd9..ac8bfe3b9f 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -82,12 +82,16 @@ class CarInterface(CarInterfaceBase): else: self.compute_gb = compute_gb_honda + @staticmethod + def compute_gb(accel, speed): # pylint: disable=method-hidden + raise NotImplementedError + @staticmethod def calc_accel_override(a_ego, a_target, v_ego, v_target): # normalized max accel. Allowing max accel at low speed causes speed overshoots max_accel_bp = [10, 20] # m/s - max_accel_v = [0.714, 1.0] # unit of max accel + max_accel_v = [0.714, 1.0] # unit of max accel max_accel = interp(v_ego, max_accel_bp, max_accel_v) # limit the pcm accel cmd if: @@ -115,8 +119,7 @@ class CarInterface(CarInterfaceBase): return float(max(max_accel, a_target / A_ACC_MAX)) * min(speedLimiter, accelLimiter) @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): - + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): # pylint: disable=dangerous-default-value ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay) ret.carName = "honda" @@ -144,7 +147,7 @@ class CarInterface(CarInterfaceBase): # For modeling details, see p.198-200 in "The Science of Vehicle Dynamics (2014), M. Guiggiani" ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0], [0]] ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] - ret.lateralTuning.pid.kf = 0.00006 # conservative feed-forward + ret.lateralTuning.pid.kf = 0.00006 # conservative feed-forward eps_modified = False for fw in car_fw: @@ -182,37 +185,41 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = CivicParams.WHEELBASE ret.centerToFront = CivicParams.CENTER_TO_FRONT ret.steerRatio = 15.38 # 10.93 is end-to-end spec - ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end tire_stiffness_factor = 1. ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]] ret.longitudinalTuning.kpBP = [0., 5., 35.] - ret.longitudinalTuning.kpV = [3.6, 2.4, 1.5] + ret.longitudinalTuning.kpV = [1.2, 0.8, 0.5] ret.longitudinalTuning.kiBP = [0., 35.] - ret.longitudinalTuning.kiV = [0.54, 0.36] + ret.longitudinalTuning.kiV = [0.18, 0.12] elif candidate in (CAR.ACCORD, CAR.ACCORD_15, CAR.ACCORDH): stop_and_go = True - if not candidate == CAR.ACCORDH: # Hybrid uses same brake msg as hatch + if not candidate == CAR.ACCORDH: # Hybrid uses same brake msg as hatch ret.safetyParam = 1 # Accord and CRV 5G use an alternate user brake msg ret.mass = 3279. * CV.LB_TO_KG + STD_CARGO_KG ret.wheelbase = 2.83 ret.centerToFront = ret.wheelbase * 0.39 ret.steerRatio = 16.33 # 11.82 is spec end-to-end - ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end tire_stiffness_factor = 0.8467 - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]] ret.longitudinalTuning.kpBP = [0., 5., 35.] ret.longitudinalTuning.kpV = [1.2, 0.8, 0.5] ret.longitudinalTuning.kiBP = [0., 35.] ret.longitudinalTuning.kiV = [0.18, 0.12] + if eps_modified: + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.09]] + else: + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]] + elif candidate == CAR.ACURA_ILX: stop_and_go = False ret.mass = 3095. * CV.LB_TO_KG + STD_CARGO_KG ret.wheelbase = 2.67 ret.centerToFront = ret.wheelbase * 0.37 ret.steerRatio = 18.61 # 15.3 is spec end-to-end - ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]] # TODO: determine if there is a dead zone at the top end + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]] # TODO: determine if there is a dead zone at the top end tire_stiffness_factor = 0.72 ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]] ret.longitudinalTuning.kpBP = [0., 5., 35.] @@ -226,7 +233,7 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.62 ret.centerToFront = ret.wheelbase * 0.41 ret.steerRatio = 16.89 # as spec - ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 1000], [0, 1000]] # TODO: determine if there is a dead zone at the top end + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 1000], [0, 1000]] # TODO: determine if there is a dead zone at the top end tire_stiffness_factor = 0.444 ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]] ret.longitudinalTuning.kpBP = [0., 5., 35.] @@ -259,11 +266,11 @@ class CarInterface(CarInterfaceBase): elif candidate == CAR.CRV_HYBRID: stop_and_go = True ret.safetyParam = 1 # Accord and CRV 5G use an alternate user brake msg - ret.mass = 1667. + STD_CARGO_KG # mean of 4 models in kg + ret.mass = 1667. + STD_CARGO_KG # mean of 4 models in kg ret.wheelbase = 2.66 ret.centerToFront = ret.wheelbase * 0.41 ret.steerRatio = 16.0 # 12.3 is spec end-to-end - ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end tire_stiffness_factor = 0.677 ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]] ret.longitudinalTuning.kpBP = [0., 5., 35.] @@ -277,7 +284,7 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.53 ret.centerToFront = ret.wheelbase * 0.39 ret.steerRatio = 13.06 - ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end tire_stiffness_factor = 0.75 ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.06]] ret.longitudinalTuning.kpBP = [0., 5., 35.] @@ -305,7 +312,7 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.68 ret.centerToFront = ret.wheelbase * 0.38 ret.steerRatio = 15.0 # as spec - ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 1000], [0, 1000]] # TODO: determine if there is a dead zone at the top end + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 1000], [0, 1000]] # TODO: determine if there is a dead zone at the top end tire_stiffness_factor = 0.444 ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]] ret.longitudinalTuning.kpBP = [0., 5., 35.] @@ -319,7 +326,7 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 3.00 ret.centerToFront = ret.wheelbase * 0.41 ret.steerRatio = 14.35 # as spec - ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end tire_stiffness_factor = 0.82 ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.45], [0.135]] ret.longitudinalTuning.kpBP = [0., 5., 35.] @@ -333,7 +340,7 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.90 ret.centerToFront = ret.wheelbase * 0.41 # from CAR.ODYSSEY ret.steerRatio = 14.35 - ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 32767], [0, 32767]] # TODO: determine if there is a dead zone at the top end + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 32767], [0, 32767]] # TODO: determine if there is a dead zone at the top end tire_stiffness_factor = 0.82 ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.45], [0.135]] ret.longitudinalTuning.kpBP = [0., 5., 35.] @@ -343,11 +350,11 @@ class CarInterface(CarInterfaceBase): elif candidate in (CAR.PILOT, CAR.PILOT_2019): stop_and_go = False - ret.mass = 4204. * CV.LB_TO_KG + STD_CARGO_KG # average weight + ret.mass = 4204. * CV.LB_TO_KG + STD_CARGO_KG # average weight ret.wheelbase = 2.82 ret.centerToFront = ret.wheelbase * 0.428 ret.steerRatio = 17.25 # as spec - ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end tire_stiffness_factor = 0.444 ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.38], [0.11]] ret.longitudinalTuning.kpBP = [0., 5., 35.] @@ -361,7 +368,7 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 3.18 ret.centerToFront = ret.wheelbase * 0.41 ret.steerRatio = 15.59 # as spec - ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end tire_stiffness_factor = 0.444 ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.38], [0.11]] ret.longitudinalTuning.kpBP = [0., 5., 35.] @@ -375,7 +382,7 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.7 ret.centerToFront = ret.wheelbase * 0.39 ret.steerRatio = 15.0 # 12.58 is spec end-to-end - ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end tire_stiffness_factor = 0.82 ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]] ret.longitudinalTuning.kpBP = [0., 5., 35.] @@ -383,7 +390,6 @@ class CarInterface(CarInterfaceBase): ret.longitudinalTuning.kiBP = [0., 35.] ret.longitudinalTuning.kiV = [0.18, 0.12] - else: raise ValueError("unsupported car %s" % candidate) @@ -402,7 +408,7 @@ class CarInterface(CarInterfaceBase): tire_stiffness_factor=tire_stiffness_factor) ret.gasMaxBP = [0.] # m/s - ret.gasMaxV = [0.6] if ret.enableGasInterceptor else [0.] # max gas allowed + ret.gasMaxV = [0.6] if ret.enableGasInterceptor else [0.] # max gas allowed ret.brakeMaxBP = [5., 20.] # m/s ret.brakeMaxV = [1., 0.8] # max brake allowed @@ -420,10 +426,12 @@ class CarInterface(CarInterfaceBase): # ******************* do can recv ******************* self.cp.update_strings(can_strings) self.cp_cam.update_strings(can_strings) + if self.cp_body: + self.cp_body.update_strings(can_strings) - ret = self.CS.update(self.cp, self.cp_cam) + ret = self.CS.update(self.cp, self.cp_cam, self.cp_body) - ret.canValid = self.cp.can_valid and self.cp_cam.can_valid + ret.canValid = self.cp.can_valid and self.cp_cam.can_valid and (self.cp_body is None or self.cp_body.can_valid) ret.yawRate = self.VM.yaw_rate(ret.steeringAngle * CV.DEG_TO_RAD, ret.vEgo) # FIXME: read sendcan for brakelights brakelights_threshold = 0.02 if self.CS.CP.carFingerprint == CAR.CIVIC else 0.1 @@ -476,12 +484,13 @@ class CarInterface(CarInterfaceBase): events.add(EventName.parkBrake) if self.CP.enableCruise and ret.vEgo < self.CP.minEnableSpeed: - events.add(EventName.speedTooLow) + events.add(EventName.belowEngageSpeed) # it can happen that car cruise disables while comma system is enabled: need to # keep braking if needed or if the speed is very low - if self.CP.enableCruise and not ret.cruiseState.enabled and (c.actuators.brake <= 0. or not self.CP.openpilotLongitudinalControl): - # non loud alert if cruise disbales below 25mph as expected (+ a little margin) + if self.CP.enableCruise and not ret.cruiseState.enabled \ + and (c.actuators.brake <= 0. or not self.CP.openpilotLongitudinalControl): + # non loud alert if cruise disables below 25mph as expected (+ a little margin) if ret.vEgo < self.CP.minEnableSpeed + 2.: events.add(EventName.speedTooLow) else: diff --git a/selfdrive/car/honda/radar_interface.py b/selfdrive/car/honda/radar_interface.py index b1606e64ad..6acec73d3c 100755 --- a/selfdrive/car/honda/radar_interface.py +++ b/selfdrive/car/honda/radar_interface.py @@ -1,12 +1,10 @@ #!/usr/bin/env python3 -import os -import time from cereal import car from opendbc.can.parser import CANParser from selfdrive.car.interfaces import RadarInterfaceBase +from selfdrive.car.honda.values import DBC -def _create_nidec_can_parser(): - dbc_f = 'acura_ilx_2016_nidec.dbc' +def _create_nidec_can_parser(car_fingerprint): radar_messages = [0x400] + list(range(0x430, 0x43A)) + list(range(0x440, 0x446)) signals = list(zip(['RADAR_STATE'] + ['LONG_DIST'] * 16 + ['NEW_TRACK'] * 16 + ['LAT_DIST'] * 16 + @@ -14,8 +12,7 @@ def _create_nidec_can_parser(): [0x400] + radar_messages[1:] * 4, [0] + [255] * 16 + [1] * 16 + [0] * 16 + [0] * 16)) checks = list(zip([0x445], [20])) - fn = os.path.splitext(dbc_f)[0].encode('utf8') - return CANParser(fn, signals, checks, 1) + return CANParser(DBC[car_fingerprint]['radar'], signals, checks, 1) class RadarInterface(RadarInterfaceBase): @@ -30,7 +27,10 @@ class RadarInterface(RadarInterfaceBase): self.delay = int(round(0.1 / CP.radarTimeStep)) # 0.1s delay of radar # Nidec - self.rcp = _create_nidec_can_parser() + if self.radar_off_can: + self.rcp = None + else: + self.rcp = _create_nidec_can_parser(CP.carFingerprint) self.trigger_msg = 0x445 self.updated_messages = set() @@ -38,9 +38,7 @@ class RadarInterface(RadarInterfaceBase): # in Bosch radar and we are only steering for now, so sleep 0.05s to keep # radard at 20Hz and return no points if self.radar_off_can: - if 'NO_RADAR_SLEEP' not in os.environ: - time.sleep(self.radar_ts) - return car.RadarData.new_message() + return super().update(None) vls = self.rcp.update_strings(can_strings) self.updated_messages.update(vls) @@ -52,7 +50,6 @@ class RadarInterface(RadarInterfaceBase): self.updated_messages.clear() return rr - def _update(self, updated_messages): ret = car.RadarData.new_message() diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 05db8c023b..713c38ae1b 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -1,3 +1,5 @@ +# flake8: noqa + from cereal import car from selfdrive.car import dbc_dict @@ -6,10 +8,10 @@ VisualAlert = car.CarControl.HUDControl.VisualAlert # Car button codes class CruiseButtons: - RES_ACCEL = 4 - DECEL_SET = 3 - CANCEL = 2 - MAIN = 1 + RES_ACCEL = 4 + DECEL_SET = 3 + CANCEL = 2 + MAIN = 1 # See dbc files for info on values" VISUAL_HUD = { @@ -126,7 +128,7 @@ FINGERPRINTS = { }, # 2019 Ridgeline { - 57: 3, 145: 8, 228: 5, 229: 4, 308: 5, 316: 8, 339: 7, 342: 6, 344: 8, 380: 8, 392: 6, 399: 7, 419: 8, 420: 8, 422:8, 425: 8, 426: 8, 427: 3, 432: 7, 464: 8, 476: 4, 490: 8, 512: 6, 513: 6, 545: 5, 546: 3, 597: 8, 660: 8, 773: 7, 777: 8, 795: 8, 800: 8, 804: 8, 808: 8, 819: 7, 821: 5, 871: 8, 882: 2, 884: 7, 892: 8, 923: 2, 929: 8, 963: 8, 965: 8, 966: 8, 967: 8, 983: 8, 985: 3, 1027: 5, 1029: 8, 1036: 8, 1039: 8, 1064: 7, 1088: 8, 1089: 8, 1092: 1, 1108: 8, 1125: 8, 1296: 8, 1365: 5, 424: 5, 1613: 5, 1616: 5, 1618: 5, 1623: 5, 1668: 5 + 57: 3, 145: 8, 228: 5, 229: 4, 308: 5, 316: 8, 339: 7, 342: 6, 344: 8, 380: 8, 392: 6, 399: 7, 419: 8, 420: 8, 422: 8, 425: 8, 426: 8, 427: 3, 432: 7, 464: 8, 476: 4, 490: 8, 512: 6, 513: 6, 545: 5, 546: 3, 597: 8, 660: 8, 773: 7, 777: 8, 795: 8, 800: 8, 804: 8, 808: 8, 819: 7, 821: 5, 871: 8, 882: 2, 884: 7, 892: 8, 923: 2, 929: 8, 963: 8, 965: 8, 966: 8, 967: 8, 983: 8, 985: 3, 1027: 5, 1029: 8, 1036: 8, 1039: 8, 1064: 7, 1088: 8, 1089: 8, 1092: 1, 1108: 8, 1125: 8, 1296: 8, 1365: 5, 424: 5, 1613: 5, 1616: 5, 1618: 5, 1623: 5, 1668: 5 }], # 2019 Insight CAR.INSIGHT: [{ @@ -149,8 +151,10 @@ FW_VERSIONS = { (Ecu.programmedFuelInjection, 0x18da10f1, None): [ b'37805-6A0-A640\x00\x00', b'37805-6B2-A550\x00\x00', + b'37805-6B2-A560\x00\x00', b'37805-6B2-A650\x00\x00', b'37805-6B2-A660\x00\x00', + b'37805-6B2-A720\x00\x00', b'37805-6B2-M520\x00\x00', ], (Ecu.shiftByWire, 0x18da0bf1, None): [ @@ -158,16 +162,23 @@ FW_VERSIONS = { ], (Ecu.transmission, 0x18da1ef1, None): [ b'28102-6B8-A560\x00\x00', + b'28102-6B8-A570\x00\x00', + b'28102-6B8-A800\x00\x00', + b'28102-6B8-C570\x00\x00', b'28102-6B8-M520\x00\x00', ], (Ecu.electricBrakeBooster, 0x18da2bf1, None): [ b'46114-TVA-A060\x00\x00', b'46114-TVA-A080\x00\x00', + b'46114-TVA-A120\x00\x00', ], (Ecu.vsa, 0x18da28f1, None): [ + b'57114-TVA-C040\x00\x00', b'57114-TVA-C050\x00\x00', + b'57114-TVA-C060\x00\x00', ], (Ecu.eps, 0x18da30f1, None): [ + b'39990-TVA,A150\x00\x00', b'39990-TVA-A150\x00\x00', b'39990-TVA-A160\x00\x00', b'39990-TVA-X030\x00\x00', @@ -182,15 +193,16 @@ FW_VERSIONS = { (Ecu.combinationMeter, 0x18da60f1, None): [ b'78109-TVA-A210\x00\x00', b'78109-TVC-A010\x00\x00', + b'78109-TVC-A020\x00\x00', b'78109-TVC-A110\x00\x00', b'78109-TVC-A210\x00\x00', + b'78109-TVC-C110\x00\x00', b'78109-TVC-M510\x00\x00', ], (Ecu.hud, 0x18da61f1, None): [ b'78209-TVA-A010\x00\x00', ], (Ecu.fwdRadar, 0x18dab0f1, None): [ - b'36802-TVA-A160\x00\x00', b'36802-TVA-A160\x00\x00', b'36802-TVA-A170\x00\x00', b'36802-TWA-A070\x00\x00', @@ -206,15 +218,21 @@ FW_VERSIONS = { CAR.ACCORD_15: { (Ecu.programmedFuelInjection, 0x18da10f1, None): [ b'37805-6A0-9620\x00\x00', + b'37805-6A0-A540\x00\x00', b'37805-6A0-A640\x00\x00', + b'37805-6A0-A650\x00\x00', b'37805-6A0-A740\x00\x00', + b'37805-6A0-A750\x00\x00', b'37805-6A0-A840\x00\x00', b'37805-6A0-A850\x00\x00', + b'37805-6A0-C540\x00\x00', b'37805-6A1-H650\x00\x00', ], (Ecu.transmission, 0x18da1ef1, None): [ b'28101-6A7-A220\x00\x00', + b'28101-6A7-A230\x00\x00', b'28101-6A7-A320\x00\x00', + b'28101-6A7-A330\x00\x00', b'28101-6A7-A510\x00\x00', b'28101-6A9-H140\x00\x00', ], @@ -224,16 +242,19 @@ FW_VERSIONS = { (Ecu.electricBrakeBooster, 0x18da2bf1, None): [ b'46114-TVA-A050\x00\x00', b'46114-TVA-A060\x00\x00', + b'46114-TVA-A080\x00\x00', b'46114-TVA-A120\x00\x00', b'46114-TVE-H550\x00\x00', ], (Ecu.combinationMeter, 0x18da60f1, None): [ b'78109-TVA-A010\x00\x00', + b'78109-TVA-A110\x00\x00', b'78109-TVA-A210\x00\x00', b'78109-TVA-A220\x00\x00', b'78109-TVA-A310\x00\x00', - b'78109-TWA-A210\x00\x00', + b'78109-TVA-C010\x00\x00', b'78109-TVE-H610\x00\x00', + b'78109-TWA-A210\x00\x00', ], (Ecu.hud, 0x18da61f1, None): [ b'78209-TVA-A010\x00\x00', @@ -270,15 +291,19 @@ FW_VERSIONS = { ], (Ecu.vsa, 0x18da28f1, None): [ b'57114-TWA-A040\x00\x00', + b'57114-TWA-A050\x00\x00', ], (Ecu.srs, 0x18da53f1, None): [ b'77959-TWA-A440\x00\x00', ], (Ecu.combinationMeter, 0x18da60f1, None): [ b'78109-TWA-A010\x00\x00', + b'78109-TWA-A020\x00\x00', + b'78109-TWA-A110\x00\x00', b'78109-TWA-A120\x00\x00', b'78109-TWA-A210\x00\x00', - b'78109-TWA-A110\x00\x00', + b'78109-TWA-A220\x00\x00', + ], (Ecu.shiftByWire, 0x18da0bf1, None): [ b'54008-TWA-A910\x00\x00', @@ -305,10 +330,20 @@ FW_VERSIONS = { b'37805-5AA-A670\x00\x00', b'37805-5AA-A680\x00\x00', b'37805-5AA-A810\x00\x00', + b'37805-5AA-C680\x00\x00', b'37805-5AA-C820\x00\x00', + b'37805-5AA-L650\x00\x00', b'37805-5AA-L660\x00\x00', + b'37805-5AA-L680\x00\x00', + b'37805-5AA-L690\x00\x00', b'37805-5AJ-A610\x00\x00', + b'37805-5AJ-A620\x00\x00', + b'37805-5BA-A310\x00\x00', b'37805-5BA-A510\x00\x00', + b'37805-5BA-A740\x00\x00', + b'37805-5BA-A760\x00\x00', + b'37805-5BA-A960\x00\x00', + b'37805-5BA-L930\x00\x00', b'37805-5BA-L940\x00\x00', b'37805-5BA-L960\x00\x00', ], @@ -324,6 +359,7 @@ FW_VERSIONS = { b'28101-5DJ-A510\x00\x00', ], (Ecu.vsa, 0x18da28f1, None): [ + b'57114-TBA-A540\x00\x00', b'57114-TBA-A550\x00\x00', b'57114-TBA-A560\x00\x00', b'57114-TBA-A570\x00\x00', @@ -340,20 +376,28 @@ FW_VERSIONS = { b'77959-TBG-A030\x00\x00', ], (Ecu.combinationMeter, 0x18da60f1, None): [ + b'78109-TBA-A510\x00\x00', + b'78109-TBA-A520\x00\x00', + b'78109-TBA-A530\x00\x00', b'78109-TBC-A310\x00\x00', b'78109-TBC-A320\x00\x00', b'78109-TBC-A510\x00\x00', b'78109-TBC-A520\x00\x00', b'78109-TBC-A530\x00\x00', + b'78109-TBC-C510\x00\x00', + b'78109-TBC-C520\x00\x00', b'78109-TBC-C530\x00\x00', b'78109-TBH-A530\x00\x00', b'78109-TEG-A310\x00\x00', ], (Ecu.fwdCamera, 0x18dab0f1, None): [ + b'36161-TBA-A020\x00\x00', b'36161-TBA-A030\x00\x00', + b'36161-TBA-A040\x00\x00', b'36161-TBC-A020\x00\x00', b'36161-TBC-A030\x00\x00', b'36161-TEG-A010\x00\x00', + b'36161-TEG-A020\x00\x00', ], (Ecu.gateway, 0x18daeff1, None): [ b'38897-TBA-A010\x00\x00', @@ -362,24 +406,40 @@ FW_VERSIONS = { }, CAR.CIVIC_BOSCH: { (Ecu.programmedFuelInjection, 0x18da10f1, None): [ + b'37805-5AA-A940\x00\x00', b'37805-5AA-A950\x00\x00', + b'37805-5AA-L940\x00\x00', b'37805-5AA-L950\x00\x00', b'37805-5AN-A750\x00\x00', b'37805-5AN-A830\x00\x00', b'37805-5AN-A840\x00\x00', b'37805-5AN-A930\x00\x00', + b'37805-5AN-A940\x00\x00', b'37805-5AN-A950\x00\x00', + b'37805-5AN-AG20\x00\x00', b'37805-5AN-AH20\x00\x00', + b'37805-5AN-AJ30\x00\x00', + b'37805-5AN-AK20\x00\x00', + b'37805-5AN-AR20\x00\x00', b'37805-5AN-L940\x00\x00', b'37805-5AN-LF20\x00\x00', b'37805-5AN-LH20\x00\x00', b'37805-5AN-LJ20\x00\x00', + b'37805-5AN-LR20\x00\x00', + b'37805-5AN-LS20\x00\x00', b'37805-5AW-G720\x00\x00', b'37805-5AZ-E850\x00\x00', + b'37805-5BB-A630\x00\x00', + b'37805-5BB-A640\x00\x00', + b'37805-5BB-C540\x00\x00', + b'37805-5BB-C630\x00\x00', + b'37805-5BB-L540\x00\x00', b'37805-5BB-L640\x00\x00', ], (Ecu.transmission, 0x18da1ef1, None): [ b'28101-5CG-A920\x00\x00', + b'28101-5CG-AB10\x00\x00', + b'28101-5CG-C110\x00\x00', b'28101-5CG-C220\x00\x00', b'28101-5CG-C320\x00\x00', b'28101-5CG-G020\x00\x00', @@ -388,14 +448,19 @@ FW_VERSIONS = { b'28101-5CK-A150\x00\x00', b'28101-5CK-C130\x00\x00', b'28101-5CK-C140\x00\x00', + b'28101-5DJ-A610\x00\x00', b'28101-5DJ-A710\x00\x00', b'28101-5DV-E330\x00\x00', ], (Ecu.vsa, 0x18da28f1, None): [ b'57114-TBG-A340\x00\x00', + b'57114-TBG-A350\x00\x00', b'57114-TGG-A340\x00\x00', - b'57114-TGL-G330\x00\x00', b'57114-TGG-C320\x00\x00', + b'57114-TGG-L320\x00\x00', + b'57114-TGG-L330\x00\x00', + b'57114-TGL-G330\x00\x00', + ], (Ecu.eps, 0x18da30f1, None): [ b'39990-TBA-C020\x00\x00', @@ -404,22 +469,28 @@ FW_VERSIONS = { b'39990-TGG-A020\x00\x00', b'39990-TGG-A120\x00\x00', b'39990-TGL-E130\x00\x00', - b'39990-TGG-A020\x00\x00', ], (Ecu.srs, 0x18da53f1, None): [ b'77959-TBA-A060\x00\x00', b'77959-TEA-G020\x00\x00', b'77959-TGG-A020\x00\x00', + b'77959-TGG-A030\x00\x00', b'77959-TGG-G010\x00\x00', ], (Ecu.combinationMeter, 0x18da60f1, None): [ + b'78109-TBA-A110\x00\x00', b'78109-TBA-A910\x00\x00', + b'78109-TBA-C340\x00\x00', + b'78109-TBA-C910\x00\x00', b'78109-TBC-A740\x00\x00', b'78109-TFJ-G020\x00\x00', b'78109-TGG-A210\x00\x00', b'78109-TGG-A220\x00\x00', b'78109-TGG-A310\x00\x00', b'78109-TGG-A320\x00\x00', + b'78109-TGG-A330\x00\x00', + b'78109-TGG-A610\x00\x00', + b'78109-TGG-A620\x00\x00', b'78109-TGG-A810\x00\x00', b'78109-TGG-A820\x00\x00', b'78109-TGL-G120\x00\x00', @@ -428,19 +499,18 @@ FW_VERSIONS = { b'36802-TBA-A150\x00\x00', b'36802-TFJ-G060\x00\x00', b'36802-TGG-A050\x00\x00', - b'36802-TGL-G040\x00\x00', b'36802-TGG-A060\x00\x00', + b'36802-TGG-A130\x00\x00', + b'36802-TGL-G040\x00\x00', ], (Ecu.fwdCamera, 0x18dab5f1, None): [ b'36161-TBA-A130\x00\x00', + b'36161-TBA-A140\x00\x00', b'36161-TFJ-G070\x00\x00', b'36161-TGG-A060\x00\x00', - b'36161-TGL-G050\x00\x00', b'36161-TGG-A080\x00\x00', - ], - (Ecu.unknown, 0x18daeff1, None): [ - b'38897-TBA-A110\x00\x00', - b'38897-TBA-A020\x00\x00', + b'36161-TGG-A120\x00\x00', + b'36161-TGL-G050\x00\x00', ], (Ecu.gateway, 0x18daeff1, None): [ b'38897-TBA-A110\x00\x00', @@ -459,19 +529,29 @@ FW_VERSIONS = { (Ecu.fwdCamera, 0x18dab5f1, None): [b'36161-TFK-G130\x00\x00'], (Ecu.gateway, 0x18daeff1, None): [b'38897-TBA-A020\x00\x00'], }, + CAR.CRV: { + (Ecu.vsa, 0x18da28f1, None): [b'57114-T1W-A230\x00\x00',], + (Ecu.srs, 0x18da53f1, None): [b'77959-T0A-A230\x00\x00',], + (Ecu.combinationMeter, 0x18da60f1, None): [b'78109-T1W-A210\x00\x00',], + (Ecu.fwdRadar, 0x18dab0f1, None): [b'36161-T1W-A830\x00\x00',], + }, CAR.CRV_5G: { (Ecu.programmedFuelInjection, 0x18da10f1, None): [ + b'37805-5PA-3060\x00\x00', b'37805-5PA-3080\x00\x00', b'37805-5PA-4050\x00\x00', + b'37805-5PA-6520\x00\x00', b'37805-5PA-6530\x00\x00', b'37805-5PA-6630\x00\x00', + b'37805-5PA-9640\x00\x00', + b'37805-5PA-9830\x00\x00', + b'37805-5PA-A650\x00\x00', b'37805-5PA-A670\x00\x00', b'37805-5PA-A680\x00\x00', b'37805-5PA-A850\x00\x00', b'37805-5PA-A870\x00\x00', b'37805-5PA-A880\x00\x00', b'37805-5PA-A890\x00\x00', - b'37805-5PA-9640\x00\x00', b'37805-5PD-Q630\x00\x00', ], (Ecu.transmission, 0x18da1ef1, None): [ @@ -480,9 +560,11 @@ FW_VERSIONS = { b'28101-5RG-A040\x00\x00', b'28101-5RG-A120\x00\x00', b'28101-5RG-A220\x00\x00', + b'28101-5RH-A020\x00\x00', b'28101-5RH-A030\x00\x00', b'28101-5RH-A040\x00\x00', b'28101-5RH-A120\x00\x00', + b'28101-5RH-A220\x00\x00', b'28101-5RL-Q010\x00\x00', ], (Ecu.vsa, 0x18da28f1, None): [ @@ -495,6 +577,7 @@ FW_VERSIONS = { (Ecu.eps, 0x18da30f1, None): [ b'39990-TLA,A040\x00\x00', b'39990-TLA-A040\x00\x00', + b'39990-TLA-A110\x00\x00', b'39990-TLA-A220\x00\x00', b'39990-TMT-T010\x00\x00', ], @@ -511,6 +594,7 @@ FW_VERSIONS = { b'78109-TLA-C210\x00\x00', b'78109-TLB-A110\x00\x00', b'78109-TLB-A210\x00\x00', + b'78109-TLB-A220\x00\x00', b'78109-TMC-Q210\x00\x00', ], (Ecu.gateway, 0x18daeff1, None): [ @@ -540,41 +624,81 @@ FW_VERSIONS = { ], }, CAR.CRV_EU: { - (Ecu.programmedFuelInjection, 0x18da10f1, None): [b'37805-R5Z-G740\x00\x00'], + (Ecu.programmedFuelInjection, 0x18da10f1, None): [ + b'37805-R5Z-G740\x00\x00', + b'37805-R5Z-G780\x00\x00', + ], (Ecu.vsa, 0x18da28f1, None): [b'57114-T1V-G920\x00\x00'], (Ecu.fwdRadar, 0x18dab0f1, None): [b'36161-T1V-G520\x00\x00'], (Ecu.shiftByWire, 0x18da0bf1, None): [b'54008-T1V-G010\x00\x00'], - (Ecu.transmission, 0x18da1ef1, None): [b'28101-5LH-E120\x00\x00'], - (Ecu.combinationMeter, 0x18da60f1, None): [b'78109-T1V-G020\x00\x00'], + (Ecu.transmission, 0x18da1ef1, None): [ + b'28101-5LH-E120\x00\x00', + b'28103-5LH-E100\x00\x00', + ], + (Ecu.combinationMeter, 0x18da60f1, None): [ + b'78109-T1V-G020\x00\x00', + b'78109-T1B-3050\x00\x00', + ], (Ecu.srs, 0x18da53f1, None): [b'77959-T1G-G940\x00\x00'], }, CAR.CRV_HYBRID: { (Ecu.vsa, 0x18da28f1, None): [ b'57114-TPA-G020\x00\x00', + b'57114-TPG-A020\x00\x00', ], (Ecu.eps, 0x18da30f1, None): [ b'39990-TPA-G030\x00\x00', + b'39990-TPG-A020\x00\x00', ], (Ecu.gateway, 0x18daeff1, None): [ b'38897-TMA-H110\x00\x00', + b'38897-TPG-A110\x00\x00', ], (Ecu.shiftByWire, 0x18da0bf1, None): [ b'54008-TMB-H510\x00\x00', + b'54008-TMB-H610\x00\x00', ], (Ecu.fwdCamera, 0x18dab5f1, None): [ b'36161-TPA-E050\x00\x00', + b'36161-TPG-A030\x00\x00', ], (Ecu.combinationMeter, 0x18da60f1, None): [ b'78109-TPA-G520\x00\x00', + b'78109-TPG-A110\x00\x00', ], (Ecu.hud, 0x18da61f1, None): [ b'78209-TLA-X010\x00\x00', ], (Ecu.fwdRadar, 0x18dab0f1, None): [ b'36802-TPA-E040\x00\x00', + b'36802-TPG-A020\x00\x00', ], (Ecu.srs, 0x18da53f1, None): [ b'77959-TLA-G220\x00\x00', + b'77959-TLA-C320\x00\x00', + ], + }, + CAR.FIT: { + (Ecu.vsa, 0x18da28f1, None): [ + b'57114-T5R-L220\x00\x00', + ], + (Ecu.eps, 0x18da30f1, None): [ + b'39990-T5R-C020\x00\x00', + b'39990-T5R-C030\x00\x00', + ], + (Ecu.gateway, 0x18daeff1, None): [ + b'38897-T5A-J010\x00\x00', + ], + (Ecu.combinationMeter, 0x18da60f1, None): [ + b'78109-T5A-A420\x00\x00', + b'78109-T5A-A910\x00\x00', + ], + (Ecu.fwdRadar, 0x18dab0f1, None): [ + b'36161-T5R-A240\x00\x00', + b'36161-T5R-A520\x00\x00', + ], + (Ecu.srs, 0x18da53f1, None): [ + b'77959-T5R-A230\x00\x00', ], }, CAR.ODYSSEY: { @@ -601,13 +725,16 @@ FW_VERSIONS = { b'36161-THR-A030\x00\x00', b'36161-THR-A110\x00\x00', b'36161-THR-A720\x00\x00', + b'36161-THR-A730\x00\x00', b'36161-THR-A810\x00\x00', + b'36161-THR-A910\x00\x00', b'36161-THR-C010\x00\x00', ], (Ecu.transmission, 0x18da1ef1, None): [ b'28101-5NZ-A310\x00\x00', b'28101-5NZ-C310\x00\x00', b'28102-5MX-A001\x00\x00', + b'28102-5MX-A600\x00\x00', b'28102-5MX-A610\x00\x00', b'28102-5MX-A710\x00\x00', b'28102-5MX-A900\x00\x00', @@ -623,12 +750,15 @@ FW_VERSIONS = { b'78109-THR-A230\x00\x00', b'78109-THR-A430\x00\x00', b'78109-THR-A820\x00\x00', + b'78109-THR-A830\x00\x00', b'78109-THR-AB20\x00\x00', - b'78109-THR-AB20\x00\x00', + b'78109-THR-AB30\x00\x00', b'78109-THR-AB40\x00\x00', b'78109-THR-AC40\x00\x00', + b'78109-THR-AE20\x00\x00', b'78109-THR-AE40\x00\x00', b'78109-THR-AL10\x00\x00', + b'78109-THR-AN10\x00\x00', b'78109-THR-C330\x00\x00', b'78109-THR-CE20\x00\x00', ], @@ -636,14 +766,58 @@ FW_VERSIONS = { b'54008-THR-A020\x00\x00', ], }, + CAR.PILOT: { + (Ecu.shiftByWire, 0x18da0bf1, None): [ + b'54008-TG7-A520\x00\x00', + ], + (Ecu.transmission, 0x18da1ef1, None): [ + b'28101-5EZ-A210\x00\x00', + b'28101-5EZ-A100\x00\x00', + b'28101-5EZ-A060\x00\x00', + b'28101-5EZ-A050\x00\x00', + ], + (Ecu.programmedFuelInjection, 0x18da10f1, None): [ + b'37805-RLV-C910\x00\x00', + b'37805-RLV-C520\x00\x00', + b'37805-RLV-C510\x00\x00', + b'37805-RLV-4070\x00\x00', + b'37805-RLV-A830\x00\x00', + ], + (Ecu.eps, 0x18da30f1, None): [ + b'39990-TG7-A040\x00\x00', + b'39990-TG7-A030\x00\x00', + ], + (Ecu.fwdCamera, 0x18dab0f1, None): [ + b'36161-TG7-A520\x00\x00', + b'36161-TG7-A820\x00\x00', + b'36161-TG7-A720\x00\x00', + ], + (Ecu.srs, 0x18da53f1, None): [ + b'77959-TG7-A110\x00\x00', + b'77959-TG7-A020\x00\x00', + ], + (Ecu.combinationMeter, 0x18da60f1, None): [ + b'78109-TG7-A720\x00\x00', + b'78109-TG7-A520\x00\x00', + b'78109-TG7-A420\x00\x00', + b'78109-TG7-A040\x00\x00', + ], + (Ecu.vsa, 0x18da28f1, None): [ + b'57114-TG7-A140\x00\x00', + b'57114-TG7-A240\x00\x00', + b'57114-TG7-A230\x00\x00', + ], + + }, CAR.PILOT_2019: { (Ecu.eps, 0x18da30f1, None): [ b'39990-TG7-A060\x00\x00', b'39990-TGS-A230\x00\x00', ], (Ecu.gateway, 0x18daeff1, None): [ - b'38897-TG7-A110\x00\x00', b'38897-TG7-A030\x00\x00', + b'38897-TG7-A110\x00\x00', + b'38897-TG7-A210\x00\x00', ], (Ecu.fwdCamera, 0x18dab0f1, None): [ b'36161-TG7-A630\x00\x00', @@ -658,6 +832,8 @@ FW_VERSIONS = { ], (Ecu.combinationMeter, 0x18da60f1, None): [ b'78109-TG7-AJ20\x00\x00', + b'78109-TG7-AK10\x00\x00', + b'78109-TG7-AK20\x00\x00', b'78109-TG7-AP10\x00\x00', b'78109-TG7-AP20\x00\x00', b'78109-TG8-AJ20\x00\x00', @@ -679,6 +855,7 @@ FW_VERSIONS = { b'39990-T6Z-A030\x00\x00', ], (Ecu.fwdCamera, 0x18dab0f1, None): [ + b'36161-T6Z-A020\x00\x00', b'36161-T6Z-A310\x00\x00', b'36161-T6Z-A520\x00\x00', ], @@ -694,6 +871,7 @@ FW_VERSIONS = { b'77959-T6Z-A020\x00\x00', ], (Ecu.vsa, 0x18da28f1, None): [ + b'57114-T6Z-A120\x00\x00', b'57114-T6Z-A130\x00\x00', b'57114-T6Z-A520\x00\x00', ], @@ -707,10 +885,23 @@ FW_VERSIONS = { ], (Ecu.fwdCamera, 0x18dab5f1, None): [ b'36161-TXM-A050\x00\x00', + b'36161-TXM-A060\x00\x00', ], (Ecu.srs, 0x18da53f1, None): [ b'77959-TXM-A230\x00\x00', ], + (Ecu.vsa, 0x18da28f1, None): [ + b'57114-TXM-A040\x00\x00', + ], + (Ecu.shiftByWire, 0x18da0bf1, None): [ + b'54008-TWA-A910\x00\x00', + ], + (Ecu.gateway, 0x18daeff1, None): [ + b'38897-TXM-A020\x00\x00', + ], + (Ecu.combinationMeter, 0x18da60f1, None): [ + b'78109-TXM-A020\x00\x00', + ], }, CAR.HRV: { (Ecu.gateway, 0x18daeff1, None): [b'38897-T7A-A010\x00\x00'], @@ -731,7 +922,7 @@ DBC = { CAR.CIVIC_BOSCH: dbc_dict('honda_civic_hatchback_ex_2017_can_generated', None), CAR.CIVIC_BOSCH_DIESEL: dbc_dict('honda_civic_sedan_16_diesel_2019_can_generated', None), CAR.CRV: dbc_dict('honda_crv_touring_2016_can_generated', 'acura_ilx_2016_nidec'), - CAR.CRV_5G: dbc_dict('honda_crv_ex_2017_can_generated', None), + CAR.CRV_5G: dbc_dict('honda_crv_ex_2017_can_generated', None, body_dbc='honda_crv_ex_2017_body_generated'), CAR.CRV_EU: dbc_dict('honda_crv_executive_2016_can_generated', 'acura_ilx_2016_nidec'), CAR.CRV_HYBRID: dbc_dict('honda_crv_hybrid_2019_can_generated', None), CAR.FIT: dbc_dict('honda_fit_ex_2018_can_generated', 'acura_ilx_2016_nidec'), @@ -796,4 +987,4 @@ ECU_FINGERPRINT = { Ecu.fwdCamera: [0xE4, 0x194], # steer torque cmd } -HONDA_BOSCH = [CAR.ACCORD, CAR.ACCORD_15, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_5G, CAR.CRV_HYBRID, CAR.INSIGHT] +HONDA_BOSCH = set([CAR.ACCORD, CAR.ACCORD_15, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_5G, CAR.CRV_HYBRID, CAR.INSIGHT]) diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 59fef40d20..787cc91b00 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -1,4 +1,5 @@ from cereal import car +from common.realtime import DT_CTRL from selfdrive.car import apply_std_steer_torque_limits from selfdrive.car.hyundai.hyundaican import create_lkas11, create_clu11, create_lfa_mfa from selfdrive.car.hyundai.values import Buttons, SteerLimitParams, CAR @@ -13,7 +14,7 @@ def process_hud_alert(enabled, fingerprint, visual_alert, left_lane, # initialize to no line visible sys_state = 1 - if left_lane and right_lane or sys_warning: #HUD alert only display when LKAS status is active + if left_lane and right_lane or sys_warning: # HUD alert only display when LKAS status is active if enabled or sys_warning: sys_state = 3 else: @@ -40,9 +41,7 @@ class CarController(): self.car_fingerprint = CP.carFingerprint self.packer = CANPacker(dbc_name) self.steer_rate_limited = False - self.resume_cnt = 0 self.last_resume_frame = 0 - self.last_lead_distance = 0 def update(self, enabled, CS, frame, actuators, pcm_cancel_cmd, visual_alert, left_lane, right_lane, left_lane_depart, right_lane_depart): @@ -56,7 +55,7 @@ class CarController(): # fix for Genesis hard fault at low speed if CS.out.vEgo < 16.7 and self.car_fingerprint == CAR.HYUNDAI_GENESIS: - lkas_active = 0 + lkas_active = False if not lkas_active: apply_steer = 0 @@ -75,28 +74,15 @@ class CarController(): if pcm_cancel_cmd: can_sends.append(create_clu11(self.packer, frame, CS.clu11, Buttons.CANCEL)) - elif CS.out.cruiseState.standstill: - # run only first time when the car stopped - if self.last_lead_distance == 0: - # get the lead distance from the Radar - self.last_lead_distance = CS.lead_distance - self.resume_cnt = 0 - # when lead car starts moving, create 6 RES msgs - elif CS.lead_distance != self.last_lead_distance and (frame - self.last_resume_frame) > 5: + # SCC won't resume anyway when the lead distace is less than 3.7m + # send resume at a max freq of 5Hz + if CS.lead_distance > 3.7 and (frame - self.last_resume_frame)*DT_CTRL > 0.2: can_sends.append(create_clu11(self.packer, frame, CS.clu11, Buttons.RES_ACCEL)) - self.resume_cnt += 1 - # interval after 6 msgs - if self.resume_cnt > 5: - self.last_resume_frame = frame - self.clu11_cnt = 0 - # reset lead distnce after the car starts moving - elif self.last_lead_distance != 0: - self.last_lead_distance = 0 - + self.last_resume_frame = frame # 20 Hz LFA MFA message - if frame % 5 == 0 and self.car_fingerprint in [CAR.SONATA, CAR.PALISADE]: + if frame % 5 == 0 and self.car_fingerprint in [CAR.SONATA, CAR.PALISADE, CAR.IONIQ]: can_sends.append(create_lfa_mfa(self.packer, frame, enabled)) return can_sends diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index d6f7d30ec5..61d9de05bb 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -1,5 +1,5 @@ from cereal import car -from selfdrive.car.hyundai.values import DBC, STEER_THRESHOLD, FEATURES +from selfdrive.car.hyundai.values import DBC, STEER_THRESHOLD, FEATURES, EV_HYBRID from selfdrive.car.interfaces import CarStateBase from opendbc.can.parser import CANParser from selfdrive.config import Conversions as CV @@ -11,7 +11,7 @@ class CarState(CarStateBase): def update(self, cp, cp_cam): ret = car.CarState.new_message() - ret.doorOpen = any([cp.vl["CGW1"]['CF_Gway_DrvDrSw'],cp.vl["CGW1"]['CF_Gway_AstDrSw'], + ret.doorOpen = any([cp.vl["CGW1"]['CF_Gway_DrvDrSw'], cp.vl["CGW1"]['CF_Gway_AstDrSw'], cp.vl["CGW2"]['CF_Gway_RLDrSw'], cp.vl["CGW2"]['CF_Gway_RRDrSw']]) ret.seatbeltUnlatched = cp.vl["CGW1"]['CF_Gway_DrvSeatBeltSw'] == 0 @@ -41,8 +41,7 @@ class CarState(CarStateBase): ret.cruiseState.standstill = cp.vl["SCC11"]['SCCInfoDisplay'] == 4. if ret.cruiseState.enabled: - is_set_speed_in_mph = int(cp.vl["CLU11"]["CF_Clu_SPEED_UNIT"]) - speed_conv = CV.MPH_TO_MS if is_set_speed_in_mph else CV.KPH_TO_MS + speed_conv = CV.MPH_TO_MS if cp.vl["CLU11"]["CF_Clu_SPEED_UNIT"] else CV.KPH_TO_MS ret.cruiseState.speed = cp.vl["SCC11"]['VSetDis'] * speed_conv else: ret.cruiseState.speed = 0 @@ -54,12 +53,16 @@ class CarState(CarStateBase): # TODO: Check this ret.brakeLights = bool(cp.vl["TCS13"]['BrakeLight'] or ret.brakePressed) - #TODO: find pedal signal for EV/HYBRID Cars - ret.gas = cp.vl["EMS12"]['PV_AV_CAN'] / 100 - ret.gasPressed = bool(cp.vl["EMS16"]["CF_Ems_AclAct"]) + if self.CP.carFingerprint in EV_HYBRID: + ret.gas = cp.vl["E_EMS11"]['Accel_Pedal_Pos'] / 256. + ret.gasPressed = ret.gas > 0 + else: + ret.gas = cp.vl["EMS12"]['PV_AV_CAN'] / 100 + ret.gasPressed = bool(cp.vl["EMS16"]["CF_Ems_AclAct"]) # TODO: refactor gear parsing in function - # Gear Selection via Cluster - For those Kia/Hyundai which are not fully discovered, we can use the Cluster Indicator for Gear Selection, as this seems to be standard over all cars, but is not the preferred method. + # Gear Selection via Cluster - For those Kia/Hyundai which are not fully discovered, we can use the Cluster Indicator for Gear Selection, + # as this seems to be standard over all cars, but is not the preferred method. if self.CP.carFingerprint in FEATURES["use_cluster_gears"]: if cp.vl["CLU15"]["CF_Clu_InhibitD"] == 1: ret.gearShifter = GearShifter.drive @@ -85,7 +88,7 @@ class CarState(CarStateBase): # Gear Selecton - This is only compatible with optima hybrid 2017 elif self.CP.carFingerprint in FEATURES["use_elect_gears"]: gear = cp.vl["ELECT_GEAR"]["Elect_Gear_Shifter"] - if gear in (5, 8): # 5: D, 8: sport mode + if gear in (5, 8): # 5: D, 8: sport mode ret.gearShifter = GearShifter.drive elif gear == 6: ret.gearShifter = GearShifter.neutral @@ -98,7 +101,7 @@ class CarState(CarStateBase): # Gear Selecton - This is not compatible with all Kia/Hyundai's, But is the best way for those it is compatible with else: gear = cp.vl["LVR12"]["CF_Lvr_Gear"] - if gear in (5, 8): # 5: D, 8: sport mode + if gear in (5, 8): # 5: D, 8: sport mode ret.gearShifter = GearShifter.drive elif gear == 6: ret.gearShifter = GearShifter.neutral @@ -109,11 +112,22 @@ class CarState(CarStateBase): else: ret.gearShifter = GearShifter.unknown + if self.CP.carFingerprint in FEATURES["use_fca"]: + ret.stockAeb = cp.vl["FCA11"]['FCA_CmdAct'] != 0 + ret.stockFcw = cp.vl["FCA11"]['CF_VSM_Warn'] == 2 + else: + ret.stockAeb = cp.vl["SCC12"]['AEB_CmdAct'] != 0 + ret.stockFcw = cp.vl["SCC12"]['CF_VSM_Warn'] == 2 + + if self.CP.carFingerprint in FEATURES["use_bsm"]: + ret.leftBlindspot = cp.vl["LCA11"]["CF_Lca_IndLeft"] != 0 + ret.rightBlindspot = cp.vl["LCA11"]["CF_Lca_IndRight"] != 0 + # save the entire LKAS11 and CLU11 self.lkas11 = cp_cam.vl["LKAS11"] self.clu11 = cp.vl["CLU11"] self.park_brake = cp.vl["CGW1"]['CF_Gway_ParkBrakeSw'] - self.steer_state = cp.vl["MDPS12"]['CF_Mdps_ToiActive'] #0 NOT ACTIVE, 1 ACTIVE + self.steer_state = cp.vl["MDPS12"]['CF_Mdps_ToiActive'] # 0 NOT ACTIVE, 1 ACTIVE self.lead_distance = cp.vl["SCC11"]['ACC_ObjDist'] return ret @@ -163,7 +177,7 @@ class CarState(CarStateBase): ("ESC_Off_Step", "TCS15", 0), - ("CF_Lvr_GearInf", "LVR11", 0), #Transmission Gear (0 = N or P, 1-8 = Fwd, 14 = Rev) + ("CF_Lvr_GearInf", "LVR11", 0), # Transmission Gear (0 = N or P, 1-8 = Fwd, 14 = Rev) ("CR_Mdps_StrColTq", "MDPS12", 0), ("CF_Mdps_ToiActive", "MDPS12", 0), @@ -179,9 +193,6 @@ class CarState(CarStateBase): ("SCCInfoDisplay", "SCC11", 0), ("ACC_ObjDist", "SCC11", 0), ("ACCMode", "SCC12", 1), - - ("PV_AV_CAN", "EMS12", 0), - ("CF_Ems_AclAct", "EMS16", 0), ] checks = [ @@ -197,9 +208,32 @@ class CarState(CarStateBase): ("SAS11", 100), ("SCC11", 50), ("SCC12", 50), - ("EMS12", 100), - ("EMS16", 100), ] + + if CP.carFingerprint in FEATURES["use_bsm"]: + signals += [ + ("CF_Lca_IndLeft", "LCA11", 0), + ("CF_Lca_IndRight", "LCA11", 0), + ] + checks += [("LCA11", 50)] + + if CP.carFingerprint in EV_HYBRID: + signals += [ + ("Accel_Pedal_Pos", "E_EMS11", 0), + ] + checks += [ + ("E_EMS11", 50), + ] + else: + signals += [ + ("PV_AV_CAN", "EMS12", 0), + ("CF_Ems_AclAct", "EMS16", 0), + ] + checks += [ + ("EMS12", 100), + ("EMS16", 100), + ] + if CP.carFingerprint in FEATURES["use_cluster_gears"]: signals += [ ("CF_Clu_InhibitD", "CLU15", 0), @@ -212,7 +246,7 @@ class CarState(CarStateBase): ] elif CP.carFingerprint in FEATURES["use_tcu_gears"]: signals += [ - ("CUR_GR", "TCU12",0) + ("CUR_GR", "TCU12", 0) ] checks += [ ("TCU12", 100) @@ -222,12 +256,24 @@ class CarState(CarStateBase): checks += [("ELECT_GEAR", 20)] else: signals += [ - ("CF_Lvr_Gear","LVR12",0) + ("CF_Lvr_Gear", "LVR12", 0) ] checks += [ ("LVR12", 100) ] + if CP.carFingerprint in FEATURES["use_fca"]: + signals += [ + ("FCA_CmdAct", "FCA11", 0), + ("CF_VSM_Warn", "FCA11", 0), + ] + checks += [("FCA11", 50)] + else: + signals += [ + ("AEB_CmdAct", "SCC12", 0), + ("CF_VSM_Warn", "SCC12", 0), + ] + return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0) @staticmethod @@ -235,7 +281,7 @@ class CarState(CarStateBase): signals = [ # sig_name, sig_address, default - ("CF_Lkas_Bca_R", "LKAS11", 0), + ("CF_Lkas_LdwsActivemode", "LKAS11", 0), ("CF_Lkas_LdwsSysState", "LKAS11", 0), ("CF_Lkas_SysWarning", "LKAS11", 0), ("CF_Lkas_LdwsLHWarning", "LKAS11", 0), @@ -252,6 +298,8 @@ class CarState(CarStateBase): ("CF_Lkas_LdwsOpt_USM", "LKAS11", 0) ] - checks = [] + checks = [ + ("LKAS11", 100) + ] return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2) diff --git a/selfdrive/car/hyundai/hyundaican.py b/selfdrive/car/hyundai/hyundaican.py index b5969d018b..1e7b751018 100644 --- a/selfdrive/car/hyundai/hyundaican.py +++ b/selfdrive/car/hyundai/hyundaican.py @@ -20,7 +20,7 @@ def create_lkas11(packer, frame, car_fingerprint, apply_steer, steer_req, values["CF_Lkas_Chksum"] = 0 if car_fingerprint in [CAR.SONATA, CAR.PALISADE]: - values["CF_Lkas_Bca_R"] = int(left_lane) + (int(right_lane) << 1) + values["CF_Lkas_LdwsActivemode"] = int(left_lane) + (int(right_lane) << 1) values["CF_Lkas_LdwsOpt_USM"] = 2 # FcwOpt_USM 5 = Orange blinking car + lanes @@ -40,9 +40,9 @@ def create_lkas11(packer, frame, car_fingerprint, apply_steer, steer_req, elif car_fingerprint == CAR.HYUNDAI_GENESIS: # This field is actually LdwsActivemode # Genesis and Optima fault when forwarding while engaged - values["CF_Lkas_Bca_R"] = 2 + values["CF_Lkas_LdwsActivemode"] = 2 elif car_fingerprint == CAR.KIA_OPTIMA: - values["CF_Lkas_Bca_R"] = 0 + values["CF_Lkas_LdwsActivemode"] = 0 dat = packer.make_can_msg("LKAS11", 0, values)[2] diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 183ab7eed1..553d48a2b5 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -12,15 +12,15 @@ class CarInterface(CarInterfaceBase): return float(accel) / 3.0 @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): # pylint: disable=dangerous-default-value ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay) ret.carName = "hyundai" ret.safetyModel = car.CarParams.SafetyModel.hyundai ret.radarOffCan = True - # Hyundai port is a community feature for now - ret.communityFeature = True + # Most Hyundai car ports are community features for now + ret.communityFeature = candidate not in [CAR.SONATA] ret.steerActuatorDelay = 0.1 # Default delay ret.steerRateCost = 0.5 @@ -41,6 +41,14 @@ class CarInterface(CarInterfaceBase): ret.mass = 1513. + STD_CARGO_KG ret.wheelbase = 2.84 ret.steerRatio = 13.27 * 1.15 # 15% higher at the center seems reasonable + tire_stiffness_factor = 0.65 + ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] + elif candidate == CAR.SONATA_2019: + ret.lateralTuning.pid.kf = 0.00005 + ret.mass = 4497. * CV.LB_TO_KG + ret.wheelbase = 2.804 + ret.steerRatio = 13.27 * 1.15 # 15% higher at the center seems reasonable ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] elif candidate == CAR.PALISADE: @@ -74,6 +82,13 @@ class CarInterface(CarInterfaceBase): ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.16], [0.01]] ret.minSteerSpeed = 60 * CV.KPH_TO_MS + elif candidate == CAR.GENESIS_G70: + ret.lateralTuning.pid.kf = 0.00005 + ret.mass = 1640. + STD_CARGO_KG + ret.wheelbase = 2.84 + ret.steerRatio = 16.5 + ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.16], [0.01]] elif candidate == CAR.GENESIS_G80: ret.lateralTuning.pid.kf = 0.00005 ret.mass = 2060. + STD_CARGO_KG @@ -103,31 +118,22 @@ class CarInterface(CarInterfaceBase): ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] elif candidate == CAR.KONA: - ret.lateralTuning.pid.kf = 0.00006 - ret.mass = 1275. + STD_CARGO_KG - ret.wheelbase = 2.7 - ret.steerRatio = 13.73 #Spec - tire_stiffness_factor = 0.385 - ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] - elif candidate == CAR.IONIQ: - ret.lateralTuning.pid.kf = 0.00006 + ret.lateralTuning.pid.kf = 0.00005 ret.mass = 1275. + STD_CARGO_KG ret.wheelbase = 2.7 - ret.steerRatio = 13.73 #Spec + ret.steerRatio = 13.73 * 1.15 # Spec tire_stiffness_factor = 0.385 ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] - ret.minSteerSpeed = 32 * CV.MPH_TO_MS elif candidate == CAR.KONA_EV: ret.lateralTuning.pid.kf = 0.00006 ret.mass = 1685. + STD_CARGO_KG ret.wheelbase = 2.7 - ret.steerRatio = 13.73 #Spec + ret.steerRatio = 13.73 # Spec tire_stiffness_factor = 0.385 ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] - elif candidate == CAR.IONIQ_EV_LTD: + elif candidate in [CAR.IONIQ, CAR.IONIQ_EV_LTD]: ret.lateralTuning.pid.kf = 0.00006 ret.mass = 1490. + STD_CARGO_KG #weight per hyundai site https://www.hyundaiusa.com/ioniq-electric/specifications.aspx ret.wheelbase = 2.7 @@ -144,6 +150,19 @@ class CarInterface(CarInterfaceBase): tire_stiffness_factor = 0.5 ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] + elif candidate == CAR.VELOSTER: + ret.lateralTuning.pid.kf = 0.00005 + ret.mass = 3558. * CV.LB_TO_KG + ret.wheelbase = 2.80 + ret.steerRatio = 13.75 * 1.15 + tire_stiffness_factor = 0.5 + ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] + + # these cars require a special panda safety mode due to missing counters and checksums in the messages + if candidate in [CAR.HYUNDAI_GENESIS, CAR.IONIQ_EV_LTD, CAR.IONIQ, CAR.KONA_EV, CAR.KIA_SORENTO, CAR.SONATA_2019, + CAR.KIA_OPTIMA, CAR.VELOSTER, CAR.KIA_STINGER, CAR.GENESIS_G70]: + ret.safetyModel = car.CarParams.SafetyModel.hyundaiLegacy ret.centerToFront = ret.wheelbase * 0.4 @@ -167,9 +186,6 @@ class CarInterface(CarInterfaceBase): ret = self.CS.update(self.cp, self.cp_cam) ret.canValid = self.cp.can_valid and self.cp_cam.can_valid - # TODO: button presses - ret.buttonEvents = [] - events = self.create_common_events(ret) #TODO: addd abs(self.CS.angle_steers) > 90 to 'steerTempUnavailable' event diff --git a/selfdrive/car/hyundai/radar_interface.py b/selfdrive/car/hyundai/radar_interface.py index b5bdcd8363..fdbe837af6 100644 --- a/selfdrive/car/hyundai/radar_interface.py +++ b/selfdrive/car/hyundai/radar_interface.py @@ -1,6 +1,4 @@ #!/usr/bin/env python3 -import os -import time from cereal import car from opendbc.can.parser import CANParser from selfdrive.car.interfaces import RadarInterfaceBase @@ -33,10 +31,7 @@ class RadarInterface(RadarInterfaceBase): def update(self, can_strings): if self.radar_off_can: - if 'NO_RADAR_SLEEP' not in os.environ: - time.sleep(0.05) # radard runs on RI updates - - return car.RadarData.new_message() + return super().update(None) vls = self.rcp.update_strings(can_strings) self.updated_messages.update(vls) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 480ed6f269..9a39cb8f31 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1,3 +1,5 @@ +# flake8: noqa + from cereal import car from selfdrive.car import dbc_dict Ecu = car.CarParams.Ecu @@ -15,22 +17,24 @@ class SteerLimitParams: class CAR: ELANTRA = "HYUNDAI ELANTRA LIMITED ULTIMATE 2017" ELANTRA_GT_I30 = "HYUNDAI I30 N LINE 2019 & GT 2018 DCT" + GENESIS_G70 = "GENESIS G70 2018" GENESIS_G80 = "GENESIS G80 2017" GENESIS_G90 = "GENESIS G90 2017" HYUNDAI_GENESIS = "HYUNDAI GENESIS 2015-2016" - IONIQ = "HYUNDAI IONIQ HYBRID PREMIUM 2017" + IONIQ = "HYUNDAI IONIQ ELECTRIC PREMIUM SE 2020" IONIQ_EV_LTD = "HYUNDAI IONIQ ELECTRIC LIMITED 2019" KIA_FORTE = "KIA FORTE E 2018" KIA_OPTIMA = "KIA OPTIMA SX 2019 & 2016" KIA_OPTIMA_H = "KIA OPTIMA HYBRID 2017 & SPORTS 2019" KIA_SORENTO = "KIA SORENTO GT LINE 2018" KIA_STINGER = "KIA STINGER GT2 2018" - KONA = "HYUNDAI KONA 2019" + KONA = "HYUNDAI KONA 2020" KONA_EV = "HYUNDAI KONA ELECTRIC 2019" SANTA_FE = "HYUNDAI SANTA FE LIMITED 2019" - SANTA_FE_1 = "HYUNDAI SANTA FE has no scc" SONATA = "HYUNDAI SONATA 2020" + SONATA_2019 = "HYUNDAI SONATA 2019" PALISADE = "HYUNDAI PALISADE 2020" + VELOSTER = "HYUNDAI VELOSTER 2019" class Buttons: @@ -77,21 +81,22 @@ FINGERPRINTS = { 67: 8, 68: 8, 80: 4, 160: 8, 161: 8, 272: 8, 288: 4, 339: 8, 356: 8, 357: 8, 399: 8, 544: 8, 608: 8, 672: 8, 688: 5, 704: 1, 790: 8, 809: 8, 848: 8, 880: 8, 898: 8, 900: 8, 901: 8, 904: 8, 1056: 8, 1064: 8, 1065: 8, 1072: 8, 1075: 8, 1087: 8, 1088: 8, 1151: 8, 1200: 8, 1201: 8, 1232: 4, 1264: 8, 1265: 8, 1266: 8, 1296: 8, 1306: 8, 1312: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1348: 8, 1349: 8, 1369: 8, 1370: 8, 1371: 8, 1407: 8, 1415: 8, 1419: 8, 1440: 8, 1442: 4, 1461: 8, 1470: 8 }], CAR.SONATA: [ - {67: 8, 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 8, 545: 8, 546: 8, 547: 8, 548: 8, 549: 8, 550: 8, 576: 8, 593: 8, 608: 8, 688: 6, 809: 8, 832: 8, 854: 8, 865: 8, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 905: 8, 908: 8, 909: 8, 912: 7, 913: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1089: 5, 1107: 5, 1108: 8, 1114: 8, 1136: 8, 1145: 8, 1151: 8, 1155: 8, 1156: 8, 1157: 4, 1162: 8, 1164: 8, 1168: 8, 1170: 8, 1173: 8, 1180: 8, 1183: 8, 1184: 8, 1186: 2, 1191: 2, 1193: 8, 1210: 8, 1225: 8, 1227: 8, 1265: 4, 1268: 8, 1280: 8, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1330: 8, 1339: 8, 1342: 6, 1343: 8, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1371: 8, 1378: 8, 1384: 8, 1394: 8, 1407: 8, 1419: 8, 1427: 6, 1446: 8, 1456: 4, 1460: 8, 1470: 8, 1485: 8, 1504: 3}, + {67: 8, 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 8, 576: 8, 593: 8, 608: 8, 688: 6, 809: 8, 832: 8, 854: 8, 865: 8, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 905: 8, 908: 8, 909: 8, 912: 7, 913: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1089: 5, 1096: 8, 1107: 5, 1108: 8, 1114: 8, 1136: 8, 1145: 8, 1151: 8, 1155: 8, 1156: 8, 1157: 4, 1162: 8, 1164: 8, 1168: 8, 1170: 8, 1173: 8, 1180: 8, 1183: 8, 1184: 8, 1186: 2, 1191: 2, 1193: 8, 1210: 8, 1225: 8, 1227: 8, 1265: 4, 1268: 8, 1280: 8, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1330: 8, 1339: 8, 1342: 6, 1343: 8, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1371: 8, 1378: 8, 1379: 8, 1384: 8, 1394: 8, 1407: 8, 1419: 8, 1427: 6, 1446: 8, 1456: 4, 1460: 8, 1470: 8, 1485: 8, 1504: 3, 1988: 8, 1996: 8, 2000: 8, 2004: 8, 2008: 8, 2012: 8, 2015: 8}, ], - CAR.KIA_OPTIMA: [ - { - 64: 8, 66: 8, 67: 8, 68: 8, 127: 8, 273: 8, 274: 8, 275: 8, 339: 8, 356: 4, 399: 8, 447: 8, 512: 6, 544: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 832: 8, 884: 8, 897: 8, 899: 8, 902: 8, 903: 6, 909: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1151: 6, 1168: 7, 1170: 8, 1186: 2, 1191: 2, 1253: 8, 1254: 8, 1255: 8, 1265: 4, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1342: 6, 1345: 8, 1348: 8, 1349: 8, 1351: 8, 1353: 8, 1363: 8, 1365: 8, 1366: 8, 1367: 8, 1369: 8, 1407: 8, 1414: 3, 1415: 8, 1419: 8, 1425: 2, 1427: 6, 1440: 8, 1456: 4, 1470: 8, 1472: 8, 1486: 8, 1487: 8, 1491: 8, 1530: 8, 1532: 5, 1952: 8, 1960: 8, 1988: 8, 1996: 8, 2001: 8, 2004: 8, 2008: 8, 2009: 8, 2012: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8 - }, - { - 64: 8, 66: 8, 67: 8, 68: 8, 127: 8, 128: 8, 129: 8, 273: 8, 274: 8, 275: 8, 339: 8, 354: 3, 356: 4, 399: 8, 512: 6, 544: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 832: 8, 897: 8, 899: 8, 902: 8, 903: 6, 912: 7, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1151: 6, 1168: 7, 1170: 8, 1265: 4, 1268: 8, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1342: 6, 1345: 8, 1348: 8, 1349: 8, 1351: 8, 1353: 8, 1356: 8, 1363: 8, 1365: 8, 1366: 8, 1367: 8, 1369: 8, 1407: 8, 1419: 8, 1425: 2, 1427: 6, 1440: 8, 1456: 4, 1470: 8, 1472: 8, 1491: 8, 1492: 8 - }, + CAR.SONATA_2019: [ + {66: 8, 67: 8, 68: 8, 127: 8, 273: 8, 274: 8, 275: 8, 339: 8, 356: 4, 399: 8, 447: 8, 512: 6, 544: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 832: 8, 884: 8, 897: 8, 899: 8, 902: 8, 903: 6, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1151: 6, 1168: 7, 1170: 8, 1253: 8, 1254: 8, 1255: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1314: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1342: 6, 1345: 8, 1348: 8, 1349: 8, 1351: 8, 1353: 8, 1363: 8, 1365: 8, 1366: 8, 1367: 8, 1369: 8, 1397: 8, 1407: 8, 1415: 8, 1419: 8, 1425: 2, 1427: 6, 1440: 8, 1456: 4, 1470: 8, 1472: 8, 1486: 8, 1487: 8, 1491: 8, 1530: 8, 1532: 5, 2000: 8, 2001: 8, 2004: 8, 2005: 8, 2008: 8, 2009: 8, 2012: 8, 2013: 8, 2014: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8}, ], + CAR.KIA_OPTIMA: [{ + 64: 8, 66: 8, 67: 8, 68: 8, 127: 8, 128: 8, 129: 8, 273: 8, 274: 8, 275: 8, 339: 8, 354: 3, 356: 4, 399: 8, 447: 8, 512: 6, 544: 8, 558: 8, 593: 8, 608: 8, 640: 8, 688: 5, 790: 8, 809: 8, 832: 8, 884: 8, 897: 8, 899: 8, 902: 8, 903: 6, 909: 8, 912: 7, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1151: 6, 1168: 7, 1170: 8, 1186: 2, 1191: 2, 1253: 8, 1254: 8, 1255: 8, 1265: 4, 1268: 8, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1342: 6, 1345: 8, 1348: 8, 1349: 8, 1351: 8, 1353: 8, 1356: 8, 1363: 8, 1365: 8, 1366: 8, 1367: 8, 1369: 8, 1407: 8, 1414: 3, 1415: 8, 1419: 8, 1425: 2, 1427: 6, 1440: 8, 1456: 4, 1470: 8, 1472: 8, 1486: 8, 1487: 8, 1491: 8, 1492: 8, 1530: 8, 1532: 5, 1792: 8, 1872: 8, 1937: 8, 1953: 8, 1968: 8, 1988: 8, 1996: 8, 2000: 8, 2001: 8, 2004: 8, 2008: 8, 2009: 8, 2012: 8, 2015: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8 + }], CAR.KIA_SORENTO: [{ 67: 8, 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 8, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1168: 7, 1170: 8, 1173: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1370: 8, 1371: 8, 1384: 8, 1407: 8, 1411: 8, 1419: 8, 1425: 2, 1427: 6, 1444: 8, 1456: 4, 1470: 8, 1489: 1 }], CAR.KIA_STINGER: [{ - 67: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 358: 6, 359: 8, 544: 8, 576: 8, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1265: 4, 1280: 1, 1281: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1378: 4, 1379: 8, 1384: 8, 1407: 8, 1419: 8, 1425: 2, 1427: 6, 1456: 4, 1470: 8 + 67: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 358: 6, 359: 8, 544: 8, 576: 8, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1265: 4, 1280: 1, 1281: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1371: 8, 1378: 4, 1379: 8, 1384: 8, 1407: 8, 1419: 8, 1425: 2, 1427: 6, 1456: 4, 1470: 8 + }], + CAR.GENESIS_G70: [{ + 67: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 358: 6, 544: 8, 576: 8, 593: 8, 608: 8, 688: 5, 809: 8, 832:8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1156: 8, 1168: 7, 1170: 8, 1173:8, 1184: 8, 1186: 2, 1191: 2, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1379: 8, 1384: 8, 1407: 8, 1419:8, 1427: 6, 1456: 4, 1470: 8, 1988: 8, 1996: 8, 2000: 8, 2004: 8, 2008: 8, 2012: 8, 2015: 8 }], CAR.GENESIS_G80: [{ 67: 8, 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 358: 6, 544: 8, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 916: 8, 1024: 2, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1156: 8, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1191: 2, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1370: 8, 1371: 8, 1378: 4, 1384: 8, 1407: 8, 1419: 8, 1425: 2, 1427: 6, 1434: 2, 1456: 4, 1470: 8 @@ -105,14 +110,17 @@ FINGERPRINTS = { CAR.GENESIS_G90: [{ 67: 8, 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 358: 6, 359: 8, 544: 8, 593: 8, 608: 8, 688: 5, 809: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1162: 4, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1265: 4, 1280: 1, 1281: 3, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1370: 8, 1371: 8, 1378: 4, 1384: 8, 1407: 8, 1419: 8, 1425: 2, 1427: 6, 1434: 2, 1456: 4, 1470: 8, 1988: 8, 2000: 8, 2003: 8, 2004: 8, 2005: 8, 2008: 8, 2011: 8, 2012: 8, 2013: 8 }], - CAR.IONIQ: [{ - 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 544: 8, 576: 8, 593: 8, 688: 5, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 6, 1173: 8, 1225: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1322: 8, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1407: 8, 1419: 8, 1427: 6, 1429: 8, 1430: 8, 1448: 8, 1456: 4, 1470:8, 1476: 8, 1535: 8 - }], CAR.IONIQ_EV_LTD: [{ 127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 544: 7, 593: 8, 688: 5, 832: 8, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 8, 1151: 6, 1168: 7, 1173: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1407: 8, 1419: 8, 1425: 2, 1426: 8, 1427: 6, 1429: 8, 1430: 8, 1456: 4, 1470: 8, 1507: 8, 1535: 8 }], + CAR.IONIQ: [{ + 127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 524: 8, 544: 7, 593: 8, 688: 5, 832: 8, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 8, 1151: 6, 1155: 8, 1156: 8, 1157: 4, 1164: 8, 1168: 7, 1173: 8, 1183: 8, 1186: 2, 1191: 2, 1225: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1379: 8, 1407: 8, 1419: 8, 1426: 8, 1427: 6, 1429: 8, 1430: 8, 1456: 4, 1470: 8, 1473: 8, 1507: 8, 1535: 8, 1988: 8, 1996: 8, 2000: 8, 2004: 8, 2005: 8, 2008: 8, 2012: 8, 2013: 8 + }, + { + 68:8, 127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 524: 8, 544: 8, 576:8, 593: 8, 688: 5, 832: 8, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 6, 1151: 6, 1155: 8, 1156: 8, 1157: 4, 1164: 8, 1168: 7, 1173: 8, 1183: 8, 1186: 2, 1191: 2, 1225: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1379: 8, 1407: 8, 1419: 8, 1426: 8, 1427: 6, 1429: 8, 1430: 8, 1448: 8, 1456: 4, 1470: 8, 1473: 8, 1476: 8, 1507: 8, 1535: 8, 1988: 8, 1996: 8, 2000: 8, 2004: 8, 2005: 8, 2008: 8, 2012: 8, 2013: 8 + }], CAR.KONA: [{ - 67: 8, 127: 8, 304: 8, 320: 8, 339: 8, 354: 3, 356: 4, 544: 8, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 909: 8, 916: 8, 1040: 8, 1078: 4, 1107: 5, 1136: 8, 1156: 8, 1170: 8, 1173: 8, 1191: 2, 1265: 4, 1280: 1, 1287: 4, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1384: 8, 1394: 8,1407: 8, 1414: 3, 1419: 8, 1427: 6, 1456: 4, 1470: 8, 2004: 8, 2009: 8, 2012: 8 + 67: 8, 127: 8, 304: 8, 320: 8, 339: 8, 354: 3, 356: 4, 544: 8, 593: 8, 608: 8, 688: 5, 809: 8, 832 : 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1156: 8, 1170: 8, 1173: 8, 1186: 2, 1191: 2, 1193: 8, 1265: 4,1280: 1, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1378: 8, 1384: 8, 1394: 8, 1407: 8, 1414: 3, 1419: 8, 1427: 6, 1456: 4, 1470: 8, 1988: 8, 1996: 8, 2000: 8, 2001: 8, 2004: 8, 2008: 8, 2009: 8, 2012: 8 }], CAR.KONA_EV: [{ 127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 544: 8, 549: 8, 593: 8, 688: 5, 832: 8, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 8, 1151: 6, 1168: 7, 1173: 8, 1183: 8, 1186: 2, 1191: 2, 1225: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1307: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1378: 4, 1407: 8, 1419: 8, 1426: 8, 1427: 6, 1429: 8, 1430: 8, 1456: 4, 1470: 8, 1473: 8, 1507: 8, 1535: 8, 2000: 8, 2004: 8, 2008: 8, 2012: 8 @@ -127,33 +135,152 @@ FINGERPRINTS = { 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 544: 8, 576: 8, 593: 8, 688: 5, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 909: 8, 912: 7, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 6, 1151: 6, 1168: 7, 1173: 8, 1180: 8, 1186: 2, 1191: 2, 1265: 4, 1268: 8, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1371: 8, 1407: 8, 1419: 8, 1420: 8, 1425: 2, 1427: 6, 1429: 8, 1430: 8, 1448: 8, 1456: 4, 1470: 8, 1476: 8, 1535: 8 }], CAR.PALISADE: [{ - 67: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 8, 549: 8, 576: 8, 593: 8, 608: 8, 688: 6, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 913: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1123: 8, 1136: 8, 1151: 6, 1155: 8, 1156: 8, 1157: 4, 1162: 8, 1164: 8, 1168: 7, 1170: 8, 1173: 8, 1180: 8, 1186: 2, 1191: 2, 1193: 8, 1210: 8, 1225: 8, 1227: 8, 1265: 4, 1280: 8, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1371: 8, 1378: 8, 1384: 8, 1407: 8, 1419: 8, 1427: 6, 1456: 4, 1470: 8, 2000: 8, 2005: 8, 2008: 8 + 67: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 8, 549: 8, 576: 8, 593: 8, 608: 8, 688: 6, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 913: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1064: 8, 1078: 4, 1107: 5, 1123: 8, 1136: 8, 1151: 6, 1155: 8, 1156: 8, 1157: 4, 1162: 8, 1164: 8, 1168: 7, 1170: 8, 1173: 8, 1180: 8, 1186: 2, 1191: 2, 1193: 8, 1210: 8, 1225: 8, 1227: 8, 1265: 4, 1280: 8, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1371: 8, 1378: 8, 1384: 8, 1407: 8, 1419: 8, 1427: 6, 1456: 4, 1470: 8, 2000: 8, 2004: 8, 2005: 8, 2008: 8, 2012: 8 }], + CAR.VELOSTER: [{ + 64: 8, 66: 8, 67: 8, 68: 8, 127: 8, 128: 8, 129: 8, 273: 8, 274: 8, 275: 8, 339: 8, 354: 3, 356: 4, 399: 8, 512: 6, 544: 8, 558: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 832: 8, 884: 8, 897: 8, 899: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1170: 8, 1181: 5, 1186: 2, 1191: 2, 1265: 4, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1349: 8, 1351: 8, 1353: 8, 1356: 8, 1363: 8, 1365: 8, 1366: 8, 1367: 8, 1369: 8, 1378: 4, 1407: 8, 1414: 3, 1415: 8, 1419: 8, 1427: 6, 1440: 8, 1456: 4, 1470: 8, 1486: 8, 1487: 8, 1491: 8, 1530: 8, 1532: 5, 1872: 8, 1988: 8, 1996: 8, 2000: 8, 2001: 8, 2004: 8, 2008: 8, 2009: 8, 2012: 8, 2015: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8 + }] } ECU_FINGERPRINT = { Ecu.fwdCamera: [832, 1156, 1191, 1342] } +# Don't use these fingerprints for fingerprinting, they are still used for ECU detection +IGNORED_FINGERPRINTS = [CAR.VELOSTER, CAR.GENESIS_G70, CAR.KONA] + +FW_VERSIONS = { + CAR.SONATA: { + (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00DN8_ SCC FHCUP 1.00 1.00 99110-L0000 ', + b'\xf1\x00DN8_ SCC F-CU- 1.00 1.00 99110-L0000 ', + ], + (Ecu.esp, 0x7d1, None): [ + b'\xf1\x8758910-L0100\xf1\x00DN ESC \x06 104\x19\x08\x01 58910-L0100\xf1\xa01.04', + ], + (Ecu.engine, 0x7e0, None): [ + b'\xf1\x87391162M003\xf1\xa0000F', + ], + (Ecu.eps, 0x7d4, None): [ + b'\xf1\x8756310L0010\x00\xf1\x00DN8 MDPS C 1.00 1.01 56310L0010\x00 4DNAC101\xf1\xa01.01', + b'\xf1\x8756310-L0010\xf1\x00DN8 MDPS C 1.00 1.01 56310-L0010 4DNAC101\xf1\xa01.01', + ], + (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.00 99211-L0000 190716', + b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.01 99211-L0000 191016', + ], + (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v', + ], + }, + CAR.SANTA_FE: { + (Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00TM__ SCC F-CUP 1.00 1.02 99110-S2000 \xf1\xa01.02'], + (Ecu.esp, 0x7d1, None): [b'\xf1\x00TM ESC \x02 100\x18\x030 58910-S2600\xf1\xa01.00',], + (Ecu.engine, 0x7e0, None): [b'\xf1\x81606EA051\x00\x00\x00\x00\x00\x00\x00\x00'], + (Ecu.eps, 0x7d4, None): [b'\xf1\x00TM MDPS C 1.00 1.00 56340-S2000 8409'], + (Ecu.fwdCamera, 0x7c4, None): [b'\xf1\x00TM MFC AT USA LHD 1.00 1.00 99211-S2000 180409'], + (Ecu.transmission, 0x7e1, None): [b'\xf1\x87SBJWAA6562474GG0ffvgeTeFx\x88\x97\x88ww\x87www\x87w\x84o\xfa\xff\x87fO\xff\xc2 \xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2G24NS1\x00\x00\x00\x00'], + }, + CAR.KIA_STINGER: { + (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00CK__ SCC F_CUP 1.00 1.01 96400-J5100 \xf1\xa01.01'], + (Ecu.engine, 0x7e0, None): [ b'\xf1\x81640E0051\x00\x00\x00\x00\x00\x00\x00\x00',], + (Ecu.eps, 0x7d4, None): [b'\xf1\x00CK MDPS R 1.00 1.04 57700-J5420 4C4VL104'], + (Ecu.fwdCamera, 0x7c4, None): [b'\xf1\x00CK MFC AT USA LHD 1.00 1.03 95740-J5000 170822'], + (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x87VDHLG17118862DK2\x8awWwgu\x96wVfUVwv\x97xWvfvUTGTx\x87o\xff\xc9\xed\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0', + b'\xf1\x87VDHLG17000192DK2xdFffT\xa5VUD$DwT\x86wveVeeD&T\x99\xba\x8f\xff\xcc\x99\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0', + ], + }, + CAR.KIA_OPTIMA_H: { + (Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00DEhe SCC H-CUP 1.01 1.02 96400-G5100 ',], + (Ecu.engine, 0x7e0, None): [b'\xf1\x816H6F4051\x00\x00\x00\x00\x00\x00\x00\x00',], + (Ecu.eps, 0x7d4, None): [b'\xf1\x00DE MDPS C 1.00 1.09 56310G5301\x00 4DEHC109',], + (Ecu.fwdCamera, 0x7c4, None): [b'\xf1\x00DEP MFC AT USA LHD 1.00 1.01 95740-G5010 170424',], + (Ecu.transmission, 0x7e1, None): [b"\xf1\x816U3J2051\x00\x00\xf1\x006U3H0_C2\x00\x006U3J2051\x00\x00PDE0G16NS2\xf4'\\\x91",], + }, + CAR.PALISADE: { + (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00LX2_ SCC FHCUP 1.00 1.04 99110-S8100 \xf1\xa01.04', + b'\xf1\x00LX2 SCC FHCUP 1.00 1.04 99110-S8100 \xf1\xa01.04', + ], + (Ecu.esp, 0x7d1, None): [ + b'\xf1\x00LX ESC \x0b 102\x19\x05\x07 58910-S8330', + b'\xf1\x00LX ESC \v 102\x19\x05\a 58910-S8330\xf1\xa01.02', + b'\xf1\x00LX ESC \v 103\x19\t\x10 58910-S8360\xf1\xa01.03', + ], + (Ecu.engine, 0x7e0, None): [b'\xf1\x81640J0051\x00\x00\x00\x00\x00\x00\x00\x00',], + (Ecu.eps, 0x7d4, None): [b'\xf1\x00LX2 MDPS C 1.00 1.03 56310-S8020 4LXDC103',], + (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.03 99211-S8100 190125', + b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.05 99211-S8100 190909', + ], + (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x87LDKVBN424201KF26\xba\xaa\x9a\xa9\x99\x99\x89\x98\x89\x99\xa8\x99\x88\x99\x98\x89\x88\x99\xa8\x89v\x7f\xf7\xffwf_\xffq\xa6\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB2\xafL]\xe7', + b'\xf1\x87LDLVBN560098KF26\x86fff\x87vgfg\x88\x96xfw\x86gfw\x86g\x95\xf6\xffeU_\xff\x92c\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB2\xafL]\xe7', + ], + }, + CAR.VELOSTER: { + (Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00JS__ SCC H-CUP 1.00 1.02 95650-J3200 ', ], + (Ecu.esp, 0x7d1, None): [b'\xf1\x00\x00\x00\x00\x00\x00\x00', ], + (Ecu.engine, 0x7e0, None): [b'\x01TJS-JNU06F200H0A', ], + (Ecu.eps, 0x7d4, None): [b'\xf1\x00JSL MDPS C 1.00 1.03 56340-J3000 8308', ], + (Ecu.fwdCamera, 0x7c4, None): [b'\xf1\x00JS LKAS AT USA LHD 1.00 1.02 95740-J3000 K32', ], + (Ecu.transmission, 0x7e1, None): [b'\xf1\x816U2V8051\x00\x00\xf1\x006U2V0_C2\x00\x006U2V8051\x00\x00DJS0T16NS1\xba\x02\xb8\x80', ], + }, + CAR.GENESIS_G70: { + (Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00IK__ SCC F-CUP 1.00 1.02 96400-G9100 \xf1\xa01.02', ], + (Ecu.esp, 0x7d1, None): [b'\xf1\x00\x00\x00\x00\x00\x00\x00', ], + (Ecu.engine, 0x7e0, None): [b'\xf1\x81640F0051\x00\x00\x00\x00\x00\x00\x00\x00', ], + (Ecu.eps, 0x7d4, None): [b'\xf1\x00IK MDPS R 1.00 1.06 57700-G9420 4I4VL106', ], + (Ecu.fwdCamera, 0x7c4, None): [b'\xf1\x00IK MFC AT USA LHD 1.00 1.01 95740-G9000 170920', ], + (Ecu.transmission, 0x7e1, None): [b'\xf1\x87VDJLT17895112DN4\x88fVf\x99\x88\x88\x88\x87fVe\x88vhwwUFU\x97eFex\x99\xff\xb7\x82\xf1\x81E25\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SIK0T33NB2\x11\x1am\xda', ], + }, + CAR.KONA: { + (Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00OS__ SCC F-CUP 1.00 1.00 95655-J9200 \xf1\xa01.00', ], + (Ecu.esp, 0x7d1, None): [b'\xf1\x816V5RAK00018.ELF\xf1\x00\x00\x00\x00\x00\x00\x00\xf1\xa01.05', ], + (Ecu.engine, 0x7e0, None): [b'"\x01TOS-0NU06F301J02', ], + (Ecu.eps, 0x7d4, None): [b'\xf1\x00OS MDPS C 1.00 1.05 56310J9030\x00 4OSDC105', ], + (Ecu.fwdCamera, 0x7c4, None): [b'\xf1\x00OS9 LKAS AT USA LHD 1.00 1.00 95740-J9300 g21', ], + (Ecu.transmission, 0x7e1, None): [b'\xf1\x816U2VE051\x00\x00\xf1\x006U2V0_C2\x00\x006U2VE051\x00\x00DOS4T16NS3\x00\x00\x00\x00', ], + }, + CAR.KIA_OPTIMA: { + (Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00JF__ SCC F-CUP 1.00 1.00 96400-D4110 '], + (Ecu.esp, 0x7d1, None): [b'\xf1\x00JF ESC \v 11 \x18\x030 58920-D5180',], + (Ecu.engine, 0x7e0, None): [b'\x01TJFAJNU06F201H03'], + (Ecu.eps, 0x7d4, None): [b'\xf1\x00TM MDPS C 1.00 1.00 56340-S2000 8409'], + (Ecu.fwdCamera, 0x7c4, None): [b'\xf1\x00JFA LKAS AT USA LHD 1.00 1.02 95895-D5000 h31'], + (Ecu.transmission, 0x7e1, None): [b'\xf1\x816U2V8051\x00\x00\xf1\x006U2V0_C2\x00\x006U2V8051\x00\x00DJF0T16NL0\t\xd2GW'], + } +} + CHECKSUM = { "crc8": [CAR.SANTA_FE, CAR.SONATA, CAR.PALISADE], "6B": [CAR.KIA_SORENTO, CAR.HYUNDAI_GENESIS], } FEATURES = { - "use_cluster_gears": [CAR.ELANTRA, CAR.KONA, CAR.ELANTRA_GT_I30], # Use Cluster for Gear Selection, rather than Transmission - "use_tcu_gears": [CAR.KIA_OPTIMA], # Use TCU Message for Gear Selection - "use_elect_gears": [CAR.KIA_OPTIMA_H, CAR.IONIQ_EV_LTD, CAR.KONA_EV], # Use TCU Message for Gear Selection + # which message has the gear + "use_cluster_gears": set([CAR.ELANTRA, CAR.ELANTRA_GT_I30, CAR.KONA]), + "use_tcu_gears": set([CAR.KIA_OPTIMA, CAR.SONATA_2019, CAR.VELOSTER]), + "use_elect_gears": set([CAR.KIA_OPTIMA_H, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.IONIQ]), + + # these cars use the FCA11 message for the AEB and FCW signals, all others use SCC12 + "use_fca": set([CAR.SONATA, CAR.ELANTRA, CAR.ELANTRA_GT_I30, CAR.KIA_STINGER, CAR.IONIQ, CAR.KONA_EV, CAR.KIA_FORTE, CAR.PALISADE, CAR.GENESIS_G70, CAR.KONA]), + + "use_bsm": set([CAR.SONATA, CAR.PALISADE, CAR.HYUNDAI_GENESIS, CAR.GENESIS_G70, CAR.GENESIS_G80, CAR.GENESIS_G90, CAR.KONA]), } +EV_HYBRID = set([CAR.IONIQ_EV_LTD, CAR.IONIQ, CAR.KONA_EV]) + DBC = { CAR.ELANTRA: dbc_dict('hyundai_kia_generic', None), CAR.ELANTRA_GT_I30: dbc_dict('hyundai_kia_generic', None), + CAR.GENESIS_G70: dbc_dict('hyundai_kia_generic', None), CAR.GENESIS_G80: dbc_dict('hyundai_kia_generic', None), CAR.GENESIS_G90: dbc_dict('hyundai_kia_generic', None), CAR.HYUNDAI_GENESIS: dbc_dict('hyundai_kia_generic', None), - CAR.IONIQ: dbc_dict('hyundai_kia_generic', None), CAR.IONIQ_EV_LTD: dbc_dict('hyundai_kia_generic', None), + CAR.IONIQ: dbc_dict('hyundai_kia_generic', None), CAR.KIA_FORTE: dbc_dict('hyundai_kia_generic', None), CAR.KIA_OPTIMA: dbc_dict('hyundai_kia_generic', None), CAR.KIA_OPTIMA_H: dbc_dict('hyundai_kia_generic', None), @@ -163,7 +290,9 @@ DBC = { CAR.KONA_EV: dbc_dict('hyundai_kia_generic', None), CAR.SANTA_FE: dbc_dict('hyundai_kia_generic', None), CAR.SONATA: dbc_dict('hyundai_kia_generic', None), + CAR.SONATA_2019: dbc_dict('hyundai_kia_generic', None), CAR.PALISADE: dbc_dict('hyundai_kia_generic', None), + CAR.VELOSTER: dbc_dict('hyundai_kia_generic', None), } STEER_THRESHOLD = 150 diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 65a302000d..bd5c8eb4b7 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -7,9 +7,11 @@ from selfdrive.car import gen_empty_fingerprint from selfdrive.config import Conversions as CV from selfdrive.controls.lib.events import Events from selfdrive.controls.lib.vehicle_model import VehicleModel +from selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX GearShifter = car.CarState.GearShifter EventName = car.CarEvent.EventName +MAX_CTRL_SPEED = (V_CRUISE_MAX + 4) * CV.KPH_TO_MS # 144 + 4 = 92 mph # generic car and radar interfaces @@ -21,9 +23,11 @@ class CarInterfaceBase(): self.frame = 0 self.low_speed_alert = False - self.CS = CarState(CP) - self.cp = self.CS.get_can_parser(CP) - self.cp_cam = self.CS.get_cam_can_parser(CP) + if CarState is not None: + self.CS = CarState(CP) + self.cp = self.CS.get_can_parser(CP) + self.cp_cam = self.CS.get_cam_can_parser(CP) + self.cp_body = self.CS.get_body_can_parser(CP) self.CC = None if CarController is not None: @@ -38,7 +42,7 @@ class CarInterfaceBase(): raise NotImplementedError @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None): raise NotImplementedError # returns a set of default params to avoid repetition in car specific params @@ -81,7 +85,7 @@ class CarInterfaceBase(): def apply(self, c): raise NotImplementedError - def create_common_events(self, cs_out, extra_gears=[], gas_resume_speed=-1, pcm_enable=True): + def create_common_events(self, cs_out, extra_gears=[], gas_resume_speed=-1, pcm_enable=True): # pylint: disable=dangerous-default-value events = Events() if cs_out.doorOpen: @@ -102,8 +106,10 @@ class CarInterfaceBase(): events.add(EventName.stockFcw) if cs_out.stockAeb: events.add(EventName.stockAeb) - if cs_out.vEgo > 92 * CV.MPH_TO_MS: + if cs_out.vEgo > MAX_CTRL_SPEED: events.add(EventName.speedTooHigh) + if cs_out.cruiseState.nonAdaptive: + events.add(EventName.wrongCruiseMode) if cs_out.steerError: events.add(EventName.steerUnavailable) @@ -131,13 +137,12 @@ class RadarInterfaceBase(): self.pts = {} self.delay = 0 self.radar_ts = CP.radarTimeStep + self.no_radar_sleep = 'NO_RADAR_SLEEP' in os.environ def update(self, can_strings): ret = car.RadarData.new_message() - - if 'NO_RADAR_SLEEP' not in os.environ: + if not self.no_radar_sleep: time.sleep(self.radar_ts) # radard runs on RI updates - return ret class CarStateBase: @@ -170,3 +175,7 @@ class CarStateBase: @staticmethod def get_cam_can_parser(CP): return None + + @staticmethod + def get_body_can_parser(CP): + return None diff --git a/selfdrive/car/isotp_parallel_query.py b/selfdrive/car/isotp_parallel_query.py index cda36d50fb..c5185dec5c 100644 --- a/selfdrive/car/isotp_parallel_query.py +++ b/selfdrive/car/isotp_parallel_query.py @@ -82,7 +82,8 @@ class IsoTpParallelQuery(): id_addr = rx_addr or tx_addr[0] sub_addr = tx_addr[1] - can_client = CanClient(self._can_tx, partial(self._can_rx, id_addr, sub_addr=sub_addr), tx_addr[0], rx_addr, self.bus, sub_addr=sub_addr, debug=self.debug) + can_client = CanClient(self._can_tx, partial(self._can_rx, id_addr, sub_addr=sub_addr), tx_addr[0], rx_addr, + self.bus, sub_addr=sub_addr, debug=self.debug) max_len = 8 if sub_addr is None else 7 diff --git a/tools/lib/mkvparse/__init__.py b/selfdrive/car/mazda/__init__.py similarity index 100% rename from tools/lib/mkvparse/__init__.py rename to selfdrive/car/mazda/__init__.py diff --git a/selfdrive/car/mazda/carcontroller.py b/selfdrive/car/mazda/carcontroller.py new file mode 100644 index 0000000000..20d80e519a --- /dev/null +++ b/selfdrive/car/mazda/carcontroller.py @@ -0,0 +1,43 @@ +from selfdrive.car.mazda import mazdacan +from selfdrive.car.mazda.values import SteerLimitParams, Buttons +from opendbc.can.packer import CANPacker +from selfdrive.car import apply_std_steer_torque_limits + +class CarController(): + def __init__(self, dbc_name, CP, VM): + self.apply_steer_last = 0 + self.packer = CANPacker(dbc_name) + self.steer_rate_limited = False + + def update(self, enabled, CS, frame, actuators): + """ Controls thread """ + + can_sends = [] + + ### STEER ### + + if enabled: + # calculate steer and also set limits due to driver torque + new_steer = int(round(actuators.steer * SteerLimitParams.STEER_MAX)) + apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, + CS.out.steeringTorque, SteerLimitParams) + self.steer_rate_limited = new_steer != apply_steer + + if CS.out.standstill and frame % 20 == 0: + # Mazda Stop and Go requires a RES button (or gas) press if the car stops more than 3 seconds + # Send Resume button at 5hz if we're engaged at standstill to support full stop and go! + # TODO: improve the resume trigger logic by looking at actual radar data + can_sends.append(mazdacan.create_button_cmd(self.packer, CS.CP.carFingerprint, Buttons.RESUME)) + else: + apply_steer = 0 + self.steer_rate_limited = False + if CS.out.cruiseState.enabled and frame % 20 == 0: + # Cancel Stock ACC if it's enabled while OP is disengaged + # Send at a rate of 5hz until we sync with stock ACC state + can_sends.append(mazdacan.create_button_cmd(self.packer, CS.CP.carFingerprint, Buttons.CANCEL)) + + self.apply_steer_last = apply_steer + + can_sends.append(mazdacan.create_steering_control(self.packer, CS.CP.carFingerprint, + frame, apply_steer, CS.cam_lkas)) + return can_sends diff --git a/selfdrive/car/mazda/carstate.py b/selfdrive/car/mazda/carstate.py new file mode 100644 index 0000000000..03f3a026b5 --- /dev/null +++ b/selfdrive/car/mazda/carstate.py @@ -0,0 +1,188 @@ +from cereal import car +from selfdrive.config import Conversions as CV +from opendbc.can.can_define import CANDefine +from opendbc.can.parser import CANParser +from selfdrive.car.interfaces import CarStateBase +from selfdrive.car.mazda.values import DBC, LKAS_LIMITS, CAR + +class CarState(CarStateBase): + def __init__(self, CP): + super().__init__(CP) + + can_define = CANDefine(DBC[CP.carFingerprint]['pt']) + self.shifter_values = can_define.dv["GEAR"]['GEAR'] + + self.cruise_speed = 0 + self.acc_active_last = False + self.low_speed_lockout = True + self.low_speed_alert = False + self.lkas_allowed = False + + def update(self, cp, cp_cam): + + ret = car.CarState.new_message() + ret.wheelSpeeds.fl = cp.vl["WHEEL_SPEEDS"]['FL'] * CV.KPH_TO_MS + ret.wheelSpeeds.fr = cp.vl["WHEEL_SPEEDS"]['FR'] * CV.KPH_TO_MS + ret.wheelSpeeds.rl = cp.vl["WHEEL_SPEEDS"]['RL'] * CV.KPH_TO_MS + ret.wheelSpeeds.rr = cp.vl["WHEEL_SPEEDS"]['RR'] * CV.KPH_TO_MS + ret.vEgoRaw = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4. + ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw) + + # Match panda speed reading + speed_kph = cp.vl["ENGINE_DATA"]['SPEED'] + ret.standstill = speed_kph < .1 + + can_gear = int(cp.vl["GEAR"]['GEAR']) + ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(can_gear, None)) + + ret.leftBlinker = cp.vl["BLINK_INFO"]['LEFT_BLINK'] == 1 + ret.rightBlinker = cp.vl["BLINK_INFO"]['RIGHT_BLINK'] == 1 + + ret.steeringAngle = cp.vl["STEER"]['STEER_ANGLE'] + ret.steeringTorque = cp.vl["STEER_TORQUE"]['STEER_TORQUE_SENSOR'] + ret.steeringPressed = abs(ret.steeringTorque) > LKAS_LIMITS.STEER_THRESHOLD + + ret.steeringTorqueEps = cp.vl["STEER_TORQUE"]['STEER_TORQUE_MOTOR'] + ret.steeringRate = cp.vl["STEER_RATE"]['STEER_ANGLE_RATE'] + + ret.brakePressed = cp.vl["PEDALS"]['BRAKE_ON'] == 1 + ret.brake = cp.vl["BRAKE"]['BRAKE_PRESSURE'] + ret.brakeLights = ret.brakePressed + + ret.seatbeltUnlatched = cp.vl["SEATBELT"]['DRIVER_SEATBELT'] == 0 + ret.doorOpen = any([cp.vl["DOORS"]['FL'], cp.vl["DOORS"]['FR'], + cp.vl["DOORS"]['BL'], cp.vl["DOORS"]['BR']]) + + ret.gas = cp.vl["ENGINE_DATA"]['PEDAL_GAS'] + ret.gasPressed = ret.gas > 0 + + ret.leftBlindspot = cp.vl["BSM"]['LEFT_BS1'] == 1 + ret.rightBlindspot = cp.vl["BSM"]['RIGHT_BS1'] == 1 + + # LKAS is enabled at 52kph going up and disabled at 45kph going down + if speed_kph > LKAS_LIMITS.ENABLE_SPEED: + self.lkas_allowed = True + elif speed_kph < LKAS_LIMITS.DISABLE_SPEED: + self.lkas_allowed = False + + # if any of the cruize buttons is pressed force state update + if any([cp.vl["CRZ_BTNS"]['RES'], + cp.vl["CRZ_BTNS"]['SET_P'], + cp.vl["CRZ_BTNS"]['SET_M']]): + self.cruise_speed = ret.vEgoRaw + + ret.cruiseState.available = True + ret.cruiseState.enabled = cp.vl["CRZ_CTRL"]['CRZ_ACTIVE'] == 1 + ret.cruiseState.speed = self.cruise_speed + + if ret.cruiseState.enabled: + if not self.lkas_allowed: + if not self.acc_active_last: + self.low_speed_lockout = True + else: + self.low_speed_alert = True + else: + self.low_speed_lockout = False + self.low_speed_alert = False + + # On if no driver torque the last 5 seconds + ret.steerWarning = cp.vl["STEER_RATE"]['HANDS_OFF_5_SECONDS'] == 1 + + self.acc_active_last = ret.cruiseState.enabled + + self.cam_lkas = cp_cam.vl["CAM_LKAS"] + ret.steerError = cp_cam.vl["CAM_LKAS"]['ERR_BIT_1'] == 1 + + return ret + + @staticmethod + def get_can_parser(CP): + # this function generates lists for signal, messages and initial values + signals = [ + # sig_name, sig_address, default + ("LEFT_BLINK", "BLINK_INFO", 0), + ("RIGHT_BLINK", "BLINK_INFO", 0), + ("STEER_ANGLE", "STEER", 0), + ("STEER_ANGLE_RATE", "STEER_RATE", 0), + ("STEER_TORQUE_SENSOR", "STEER_TORQUE", 0), + ("STEER_TORQUE_MOTOR", "STEER_TORQUE", 0), + ("FL", "WHEEL_SPEEDS", 0), + ("FR", "WHEEL_SPEEDS", 0), + ("RL", "WHEEL_SPEEDS", 0), + ("RR", "WHEEL_SPEEDS", 0), + ] + + checks = [ + # sig_address, frequency + ("BLINK_INFO", 10), + ("STEER", 67), + ("STEER_RATE", 83), + ("STEER_TORQUE", 83), + ("WHEEL_SPEEDS", 100), + ] + + if CP.carFingerprint == CAR.CX5: + signals += [ + ("LKAS_BLOCK", "STEER_RATE", 0), + ("LKAS_TRACK_STATE", "STEER_RATE", 0), + ("HANDS_OFF_5_SECONDS", "STEER_RATE", 0), + ("CRZ_ACTIVE", "CRZ_CTRL", 0), + ("STANDSTILL", "PEDALS", 0), + ("BRAKE_ON", "PEDALS", 0), + ("BRAKE_PRESSURE", "BRAKE", 0), + ("GEAR", "GEAR", 0), + ("DRIVER_SEATBELT", "SEATBELT", 0), + ("FL", "DOORS", 0), + ("FR", "DOORS", 0), + ("BL", "DOORS", 0), + ("BR", "DOORS", 0), + ("PEDAL_GAS", "ENGINE_DATA", 0), + ("SPEED", "ENGINE_DATA", 0), + ("RES", "CRZ_BTNS", 0), + ("SET_P", "CRZ_BTNS", 0), + ("SET_M", "CRZ_BTNS", 0), + ("CTR", "CRZ_BTNS", 0), + ("LEFT_BS1", "BSM", 0), + ("RIGHT_BS1", "BSM", 0), + ] + + checks += [ + ("ENGINE_DATA", 100), + ("CRZ_CTRL", 50), + ("CRZ_BTNS", 10), + ("PEDALS", 50), + ("BRAKE", 50), + ("SEATBELT", 10), + ("DOORS", 10), + ("GEAR", 20), + ("BSM", 10), + ] + + return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0) + + @staticmethod + def get_cam_can_parser(CP): + signals = [] + checks = [] + + if CP.carFingerprint == CAR.CX5: + signals += [ + # sig_name, sig_address, default + ("LKAS_REQUEST", "CAM_LKAS", 0), + ("CTR", "CAM_LKAS", 0), + ("ERR_BIT_1", "CAM_LKAS", 0), + ("LINE_NOT_VISIBLE", "CAM_LKAS", 0), + ("LDW", "CAM_LKAS", 0), + ("BIT_1", "CAM_LKAS", 1), + ("ERR_BIT_2", "CAM_LKAS", 0), + ("STEERING_ANGLE", "CAM_LKAS", 0), + ("ANGLE_ENABLED", "CAM_LKAS", 0), + ("CHKSUM", "CAM_LKAS", 0), + ] + + checks += [ + # sig_address, frequency + ("CAM_LKAS", 16), + ] + + return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2) diff --git a/selfdrive/car/mazda/interface.py b/selfdrive/car/mazda/interface.py new file mode 100755 index 0000000000..dfa959da38 --- /dev/null +++ b/selfdrive/car/mazda/interface.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 +from cereal import car +from selfdrive.config import Conversions as CV +from selfdrive.car.mazda.values import CAR, LKAS_LIMITS, FINGERPRINTS, ECU_FINGERPRINT, Ecu +from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, is_ecu_disconnected +from selfdrive.car.interfaces import CarInterfaceBase + +ButtonType = car.CarState.ButtonEvent.Type +EventName = car.CarEvent.EventName + +class CarInterface(CarInterfaceBase): + + @staticmethod + def compute_gb(accel, speed): + return float(accel) / 4.0 + + @staticmethod + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None): + ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay) + + ret.carName = "mazda" + ret.safetyModel = car.CarParams.SafetyModel.mazda + + ret.dashcamOnly = True + + ret.radarOffCan = True + + # Mazda port is a community feature for now + ret.communityFeature = True + + ret.steerActuatorDelay = 0.1 + ret.steerRateCost = 1.0 + ret.steerLimitTimer = 0.8 + tire_stiffness_factor = 0.70 # not optimized yet + + if candidate in [CAR.CX5]: + ret.mass = 3655 * CV.LB_TO_KG + STD_CARGO_KG + ret.wheelbase = 2.7 + ret.steerRatio = 15.5 + + ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.2]] + + ret.lateralTuning.pid.kf = 0.00006 + + # No steer below disable speed + ret.minSteerSpeed = LKAS_LIMITS.DISABLE_SPEED * CV.KPH_TO_MS + + ret.centerToFront = ret.wheelbase * 0.41 + + # TODO: get actual value, for now starting with reasonable value for + # civic and scaling by mass and wheelbase + ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) + + # TODO: start from empirically derived lateral slip stiffness for the civic and scale by + # mass and CG position, so all cars will have approximately similar dyn behaviors + ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront, + tire_stiffness_factor=tire_stiffness_factor) + + ret.enableCamera = is_ecu_disconnected(fingerprint[0], FINGERPRINTS, ECU_FINGERPRINT, candidate, Ecu.fwdCamera) or has_relay + + return ret + + # returns a car.CarState + def update(self, c, can_strings): + + self.cp.update_strings(can_strings) + self.cp_cam.update_strings(can_strings) + + ret = self.CS.update(self.cp, self.cp_cam) + ret.canValid = self.cp.can_valid and self.cp_cam.can_valid + + # events + events = self.create_common_events(ret) + + if self.CS.low_speed_lockout: + events.add(EventName.belowEngageSpeed) + + if self.CS.low_speed_alert: + events.add(EventName.belowSteerSpeed) + + ret.events = events.to_msg() + + self.CS.out = ret.as_reader() + return self.CS.out + + def apply(self, c): + can_sends = self.CC.update(c.enabled, self.CS, self.frame, c.actuators) + self.frame += 1 + return can_sends diff --git a/selfdrive/car/mazda/mazdacan.py b/selfdrive/car/mazda/mazdacan.py new file mode 100644 index 0000000000..55b9218dbd --- /dev/null +++ b/selfdrive/car/mazda/mazdacan.py @@ -0,0 +1,104 @@ +from selfdrive.car.mazda.values import CAR, Buttons + +def create_steering_control(packer, car_fingerprint, frame, apply_steer, lkas): + + tmp = apply_steer + 2048 + + lo = tmp & 0xFF + hi = tmp >> 8 + + b1 = int(lkas["BIT_1"]) + ldw = int(lkas["LDW"]) + er1 = int(lkas["ERR_BIT_1"]) + lnv = 0 + er2 = int(lkas["ERR_BIT_2"]) + + steering_angle = int(lkas["STEERING_ANGLE"]) + b2 = int(lkas["ANGLE_ENABLED"]) + + tmp = steering_angle + 2048 + ahi = tmp >> 10 + amd = (tmp & 0x3FF) >> 2 + amd = (amd >> 4) | (( amd & 0xF) << 4) + alo = (tmp & 0x3) << 2 + + ctr = frame % 16 + # bytes: [ 1 ] [ 2 ] [ 3 ] [ 4 ] + csum = 249 - ctr - hi - lo - (lnv << 3) - er1 - (ldw << 7) - ( er2 << 4) - (b1 << 5) + + #bytes [ 5 ] [ 6 ] [ 7 ] + csum = csum - ahi - amd - alo - b2 + + if ahi == 1: + csum = csum + 15 + + if csum < 0: + if csum < -256: + csum = csum + 512 + else: + csum = csum + 256 + + csum = csum % 256 + + if car_fingerprint == CAR.CX5: + values = { + "LKAS_REQUEST" : apply_steer, + "CTR" : ctr, + "ERR_BIT_1" : er1, + "LINE_NOT_VISIBLE" : lnv, + "LDW" : ldw, + "BIT_1" : b1, + "ERR_BIT_2" : er2, + "STEERING_ANGLE" : steering_angle, + "ANGLE_ENABLED" : b2, + "CHKSUM" : csum + } + + return packer.make_can_msg("CAM_LKAS", 0, values) + + +def create_button_cmd(packer, car_fingerprint, button): + + if button == Buttons.CANCEL: + can = 1 + res = 0 + elif button == Buttons.RESUME: + can = 0 + res = 1 + else: + can = 0 + res = 0 + + if car_fingerprint == CAR.CX5: + values = { + "CAN_OFF" : can, + "CAN_OFF_INV" : (can + 1) % 2, + + "SET_P" : 0, + "SET_P_INV" : 1, + + "RES" : res, + "RES_INV" : (res + 1) % 2, + + "SET_M" : 0, + "SET_M_INV" : 1, + + "DISTANCE_LESS" : 0, + "DISTANCE_LESS_INV" : 1, + + "DISTANCE_MORE" : 0, + "DISTANCE_MORE_INV" : 1, + + "MODE_X" : 0, + "MODE_X_INV" : 1, + + "MODE_Y" : 0, + "MODE_Y_INV" : 1, + + "BIT1" : 1, + "BIT2" : 1, + "BIT3" : 1, + "CTR" : 0 + } + + return packer.make_can_msg("CRZ_BTNS", 0, values) diff --git a/selfdrive/car/mazda/radar_interface.py b/selfdrive/car/mazda/radar_interface.py new file mode 100755 index 0000000000..b2f7651136 --- /dev/null +++ b/selfdrive/car/mazda/radar_interface.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python3 +from selfdrive.car.interfaces import RadarInterfaceBase + +class RadarInterface(RadarInterfaceBase): + pass diff --git a/selfdrive/car/mazda/values.py b/selfdrive/car/mazda/values.py new file mode 100644 index 0000000000..5759d431a8 --- /dev/null +++ b/selfdrive/car/mazda/values.py @@ -0,0 +1,76 @@ +# flake8: noqa + +from selfdrive.car import dbc_dict +from cereal import car +Ecu = car.CarParams.Ecu + + +# Steer torque limits + +class SteerLimitParams: + STEER_MAX = 600 # max_steer 2048 + STEER_STEP = 1 # how often we update the steer cmd + STEER_DELTA_UP = 10 # torque increase per refresh + STEER_DELTA_DOWN = 20 # torque decrease per refresh + STEER_DRIVER_ALLOWANCE = 15 # allowed driver torque before start limiting + STEER_DRIVER_MULTIPLIER = 1 # weight driver torque + STEER_DRIVER_FACTOR = 1 # from dbc + +class CAR: + CX5 = "Mazda CX-5 2017" + +class LKAS_LIMITS: + STEER_THRESHOLD = 15 + DISABLE_SPEED = 45 # kph + ENABLE_SPEED = 52 # kph + +class Buttons: + NONE = 0 + SET_PLUS = 1 + SET_MINUS = 2 + RESUME = 3 + CANCEL = 4 + +FINGERPRINTS = { + CAR.CX5: [ + # CX-5 2017 GT + { + 64: 8, 70: 8, 80: 8, 117: 8, 118: 8, 120: 8, 121: 8, 130: 8, 134: 8, 145: 8, 154: 8, 155: 8, 157: 8, 158: 8, 159: 8, 253: 8, 304: 8, 305: 8, 357: 8, 358: 8, 359: 8, 512: 8, 514: 8, 515: 8, 529: 8, 533: 8, 535: 8, 539: 8, 540: 8, 541: 8, 542: 8, 543: 8, 552: 8, 576: 8, 577: 8, 578: 8, 579: 8, 580: 8, 581: 8, 582: 8, 605: 8, 606: 8, 607: 8, 608: 8, 628: 8, 832: 8, 836: 8, 863: 8, 865: 8, 866: 8, 867: 8, 868: 8, 869: 8, 870: 8, 976: 8, 977: 8, 978: 8, 1034: 8, 1045: 8, 1056: 8, 1061: 8, 1067: 8, 1070: 8, 1078: 8, 1080: 8, 1085: 8, 1086: 8, 1088: 8, 1093: 8, 1108: 8, 1114: 8, 1115: 8, 1116: 8, 1139: 8, 1143: 8, 1147: 8, 1154: 8, 1157: 8, 1160: 8, 1163: 8, 1166: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1183: 8, 1233: 8, 1236: 8, 1237: 8, 1238: 8, 1239: 8, 1241: 8, 1242: 8, 1243: 8, 1244: 8, 1264: 8, 1266: 8, 1267: 8, 1269: 8, 1270: 8, 1271: 8, 1272: 8, 1274: 8, 1275: 8, 1277: 8, 1278: 8, 1409: 8, 1416: 8, 1425: 8, 1430: 8, 1435: 8, 1440: 8, 1446: 8, 1456: 8, 1479: 8 + }, + + # CX-5 2019 GTR + { + 64: 8, 70: 8, 80: 8, 117: 8, 118: 8, 120: 8, 121: 8, 130: 8, 134: 8, 145: 8, 154: 8, 155: 8, 157: 8, 158: 8, 159: 8, 253: 8, 254: 8, 304: 8, 305: 8, 357: 8, 358: 8, 359: 8, 512: 8, 514: 8, 515: 8, 529: 8, 533: 8, 535: 8, 539: 8, 540: 8, 541: 8, 542: 8, 543: 8, 552: 8, 576: 8, 577: 8, 578: 8, 579: 8, 580: 8, 581: 8, 582: 8, 605: 8, 606: 8, 607: 8, 608: 8, 628: 8, 736: 8, 832: 8, 836: 8, 863: 8, 865: 8, 866: 8, 867: 8, 868: 8, 869: 8, 870: 8, 976: 8, 977: 8, 978: 8, 1034: 8, 1045: 8, 1056: 8, 1061: 8, 1067: 8, 1078: 8, 1080: 8, 1085: 8, 1086: 8, 1088: 8, 1093: 8, 1108: 8, 1114: 8, 1115: 8, 1116: 8, 1139: 8, 1143: 8, 1147: 8, 1154: 8, 1157: 8, 1160: 8, 1163: 8, 1166: 8, 1170: 8, 1171: 8, 1173: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1183: 8, 1233: 8, 1236: 8, 1237: 8, 1238: 8, 1239: 8, 1241: 8, 1242: 8, 1244: 8, 1260: 8, 1264: 8, 1266: 8, 1267: 8, 1269: 8, 1270: 8, 1271: 8, 1272: 8, 1274: 8, 1277: 8, 1278: 8, 1409: 8, 1416: 8, 1425: 8, 1430: 8, 1435: 8, 1440: 8, 1446: 8, 1456: 8, 1479: 8, 1776: 8, 1792: 8, 1872: 8, 1937: 8, 1953: 8, 1968: 8, 2015: 8, 2016: 8, 2024: 8 + }, + + # Mazda 6 2017 GT + { + 64: 8, 70: 8, 80: 8, 117: 8, 118: 8, 120: 8, 121: 8, 130: 8, 134: 8, 145: 8, 154: 8, 155: 8, 157: 8, 158: 8, 159: 8, 253: 8, 304: 8, 305: 8, 357: 8, 358: 8, 359: 8, 512: 8, 514: 8, 515: 8, 529: 8, 533: 8, 535: 8, 539: 8, 540: 8, 541: 8, 542: 8, 543: 8, 552: 8, 576: 8, 577: 8, 578: 8, 579: 8, 580: 8, 581: 8, 582: 8, 605: 8, 606: 8, 607: 8, 628: 8, 832: 8, 836: 8, 863: 8, 865: 8, 866: 8, 867: 8, 868: 8, 869: 8, 870: 8, 976: 8, 977: 8, 978: 8, 1034: 8, 1045: 8, 1056: 8, 1061: 8, 1067: 8, 1070: 8, 1078: 8, 1080: 8, 1085: 8, 1086: 8, 1088: 8, 1093: 8, 1108: 8, 1114: 8, 1115: 8, 1116: 8, 1143: 8, 1147: 8, 1154: 8, 1157: 8, 1160: 8, 1163: 8, 1166: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1182: 8, 1183: 8, 1233: 8, 1236: 8, 1237: 8, 1238: 8, 1239: 8, 1241: 8, 1242: 8, 1243: 8, 1244: 8, 1264: 8, 1266: 8, 1267: 8, 1269: 8, 1270: 8, 1271: 8, 1272: 8, 1274: 8, 1275: 8, 1277: 8, 1278: 8, 1409: 8, 1416: 8, 1425: 8, 1430: 8, 1435: 8, 1440: 8, 1456: 8, 1479: 8 + }, + + # CX-9 2017 Australia - old CAM connector + { + 64: 8, 70: 8, 80: 8, 117: 8, 118: 8, 120: 8, 121: 8, 130: 8, 134: 8, 138: 8, 145: 8, 154: 8, 155: 8, 157: 8, 158: 8, 159: 8, 253: 8, 304: 8, 305: 8, 357: 8, 358: 8, 359: 8, 512: 8, 514: 8, 515: 8, 522: 8, 529: 8, 533: 8, 535: 8, 539: 8, 540: 8, 541: 8, 542: 8, 543: 8, 552: 8, 576: 8, 577: 8, 578: 8, 579: 8, 580: 8, 581: 8, 582: 8, 583: 8, 605: 8, 606: 8, 628: 8, 832: 8, 976: 8, 977: 8, 978: 8, 1034: 8, 1045: 8, 1056: 8, 1061: 8, 1067: 8, 1078: 8, 1085: 8, 1086: 8, 1088: 8, 1093: 8, 1108: 8, 1114: 8, 1115: 8, 1116: 8, 1139: 8, 1143: 8, 1147: 8, 1154: 8, 1157: 8, 1160: 8, 1163: 8, 1166: 8, 1170: 8, 1177: 8, 1180: 8, 1183: 8, 1233: 8, 1236: 8, 1237: 8, 1238: 8, 1239: 8, 1241: 8, 1242: 8, 1243: 8, 1244: 8, 1247: 8, 1264: 8, 1266: 8, 1267: 8, 1269: 8, 1271: 8, 1272: 8, 1274: 8, 1277: 8, 1278: 8, 1409: 8, 1416: 8, 1425: 8, 1430: 8, 1435: 8, 1440: 8, 1446: 8, 1456: 8, 1479: 8 + }, + + # CX-9 2016 - old CAM connector + { + 64: 8, 70: 8, 80: 8, 117: 8, 118: 8, 120: 8, 121: 8, 130: 8, 134: 8, 145: 8, 154: 8, 155: 8, 157: 8, 158: 8, 159: 8, 253: 8, 304: 8, 305: 8, 357: 8, 358: 8, 359: 8, 512: 8, 514: 8, 515: 8, 529: 8, 533: 8, 535: 8, 539: 8, 540: 8, 541: 8, 542: 8, 543: 8, 552: 8, 576: 8, 577: 8, 578: 8, 579: 8, 580: 8, 581: 8, 582: 8, 583: 8, 605: 8, 606: 8, 608: 8, 628: 8, 832: 8, 836: 8, 976: 8, 977: 8, 978: 8, 1034: 8, 1045: 8, 1056: 8, 1061: 8, 1067: 8, 1078: 8, 1080: 8, 1085: 8, 1086: 8, 1088: 8, 1093: 8, 1108: 8, 1114: 8, 1115: 8, 1116: 8, 1139: 8, 1143: 8, 1147: 8, 1154: 8, 1157: 8, 1160: 8, 1163: 8, 1166: 8, 1170: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1183: 8, 1233: 8, 1236: 8, 1237: 8, 1238: 8, 1239: 8, 1241: 8, 1242: 8, 1244: 8, 1264: 8, 1266: 8, 1267: 8, 1269: 8, 1271: 8, 1272: 8, 1274: 8, 1277: 8, 1278: 8, 1409: 8, 1416: 8, 1425: 8, 1430: 8, 1435: 8, 1440: 8, 1446: 8, 1456: 8, 1479: 8, 1792: 8, 1872: 8, 1937: 8, 1953: 8, 1968: 8, 1988: 8, 1996: 8, 2000: 8, 2001: 8, 2004: 8, 2015: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8 + }, + + # Mazda 3 2017 + { + 19: 5, 80: 8, 117: 8, 118: 8, 120: 8, 121: 8, 130: 8, 134: 8, 145: 8, 154: 8, 155: 8, 157: 8, 158: 8, 159: 8, 253: 8, 304: 8, 305: 8, 357: 8, 358: 8, 359: 8, 512: 8, 514: 8, 515: 8, 529: 8, 533: 8, 535: 8, 539: 8, 540: 8, 541: 8, 542: 8, 543: 8, 552: 8, 576: 8, 577: 8, 578: 8, 579: 8, 580: 8, 581: 8, 582: 8, 605: 8, 606: 8, 607: 8, 628: 8, 832: 8, 863: 8, 865: 8, 866: 8, 867: 8, 868: 8, 869: 8, 870: 8, 976: 8, 977: 8, 978: 8, 1034: 8, 1045: 8, 1056: 8, 1061: 8, 1067: 8, 1070: 8, 1078: 8, 1086: 8, 1088: 8, 1093: 8, 1108: 8, 1114: 8, 1115: 8, 1116: 8, 1143: 8, 1147: 8, 1154: 8, 1157: 8, 1160: 8, 1163: 8, 1166: 8, 1169: 8, 1170: 8, 1173: 8, 1177: 8, 1180: 8, 1182: 8, 1183: 8, 1233: 8, 1236: 8, 1237: 8, 1238: 8, 1239: 8, 1241: 8, 1242: 8, 1243: 8, 1244: 8, 1264: 8, 1266: 8, 1267: 8, 1269: 8, 1270: 8, 1271: 8, 1272: 8, 1274: 8, 1275: 8, 1277: 8, 1278: 8, 1409: 8, 1416: 8, 1425: 8, 1430: 8, 1435: 8, 1440: 8, 1456: 8, 1479: 8, 2015: 8, 2024: 8, 2025: 8 + }, + ], + +} + +ECU_FINGERPRINT = { + Ecu.fwdCamera: [579], # steer torque cmd +} + + +DBC = { + CAR.CX5: dbc_dict('mazda_2017', None), +} diff --git a/selfdrive/car/mock/interface.py b/selfdrive/car/mock/interface.py index 69b3862df4..d0298ec838 100755 --- a/selfdrive/car/mock/interface.py +++ b/selfdrive/car/mock/interface.py @@ -8,7 +8,7 @@ from selfdrive.car.interfaces import CarInterfaceBase # mocked car interface to work with chffrplus TS = 0.01 # 100Hz -YAW_FR = 0.2 # ~0.8s time constant on yaw rate filter +YAW_FR = 0.2 # ~0.8s time constant on yaw rate filter # low pass gain LPG = 2 * 3.1415 * YAW_FR * TS / (1 + 2 * 3.1415 * YAW_FR * TS) @@ -33,7 +33,7 @@ class CarInterface(CarInterfaceBase): return accel @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None): ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay) ret.carName = "mock" ret.safetyModel = car.CarParams.SafetyModel.noOutput @@ -41,7 +41,7 @@ class CarInterface(CarInterfaceBase): ret.rotationalInertia = 2500. ret.wheelbase = 2.70 ret.centerToFront = ret.wheelbase * 0.5 - ret.steerRatio = 13. # reasonable + ret.steerRatio = 13. # reasonable ret.tireStiffnessFront = 1e6 # very stiff to neglect slip ret.tireStiffnessRear = 1e6 # very stiff to neglect slip diff --git a/selfdrive/car/nissan/carcontroller.py b/selfdrive/car/nissan/carcontroller.py index 56e2ae7522..5838d67ae3 100644 --- a/selfdrive/car/nissan/carcontroller.py +++ b/selfdrive/car/nissan/carcontroller.py @@ -2,7 +2,7 @@ from cereal import car from common.numpy_fast import clip, interp from selfdrive.car.nissan import nissancan from opendbc.can.packer import CANPacker -from selfdrive.car.nissan.values import CAR +from selfdrive.car.nissan.values import CAR, STEER_THRESHOLD # Steer angle limits ANGLE_DELTA_BP = [0., 5., 15.] @@ -53,7 +53,11 @@ class CarController(): else: # Scale max torque based on how much torque the driver is applying to the wheel self.lkas_max_torque = max( - 0, LKAS_MAX_TORQUE - 0.4 * abs(CS.out.steeringTorque)) + # Scale max torque down to half LKAX_MAX_TORQUE as a minimum + LKAS_MAX_TORQUE * 0.5, + # Start scaling torque at STEER_THRESHOLD + LKAS_MAX_TORQUE - 0.6 * max(0, abs(CS.out.steeringTorque) - STEER_THRESHOLD) + ) else: apply_angle = CS.out.steeringAngle @@ -65,7 +69,7 @@ class CarController(): # send acc cancel cmd if drive is disabled but pcm is still on, or if the system can't be activated cruise_cancel = 1 - if self.CP.carFingerprint == CAR.XTRAIL and cruise_cancel: + if self.CP.carFingerprint in [CAR.ROGUE, CAR.XTRAIL] and cruise_cancel: can_sends.append(nissancan.create_acc_cancel_cmd(self.packer, CS.cruise_throttle_msg, frame)) # TODO: Find better way to cancel! diff --git a/selfdrive/car/nissan/carstate.py b/selfdrive/car/nissan/carstate.py index 849e89b731..f2076183d9 100644 --- a/selfdrive/car/nissan/carstate.py +++ b/selfdrive/car/nissan/carstate.py @@ -1,4 +1,5 @@ import copy +from collections import deque from cereal import car from opendbc.can.can_define import CANDefine from selfdrive.car.interfaces import CarStateBase @@ -6,30 +7,32 @@ from selfdrive.config import Conversions as CV from opendbc.can.parser import CANParser from selfdrive.car.nissan.values import CAR, DBC, STEER_THRESHOLD +TORQUE_SAMPLES = 12 class CarState(CarStateBase): def __init__(self, CP): super().__init__(CP) can_define = CANDefine(DBC[CP.carFingerprint]['pt']) + self.steeringTorqueSamples = deque(TORQUE_SAMPLES*[0], TORQUE_SAMPLES) self.shifter_values = can_define.dv["GEARBOX"]["GEAR_SHIFTER"] def update(self, cp, cp_adas, cp_cam): ret = car.CarState.new_message() - if self.CP.carFingerprint == CAR.XTRAIL: + if self.CP.carFingerprint in [CAR.ROGUE, CAR.XTRAIL]: ret.gas = cp.vl["GAS_PEDAL"]["GAS_PEDAL"] elif self.CP.carFingerprint == CAR.LEAF: ret.gas = cp.vl["CRUISE_THROTTLE"]["GAS_PEDAL"] ret.gasPressed = bool(ret.gas > 3) - if self.CP.carFingerprint == CAR.XTRAIL: + if self.CP.carFingerprint in [CAR.ROGUE, CAR.XTRAIL]: ret.brakePressed = bool(cp.vl["DOORS_LIGHTS"]["USER_BRAKE_PRESSED"]) elif self.CP.carFingerprint == CAR.LEAF: ret.brakePressed = bool(cp.vl["BRAKE_PEDAL"]["BRAKE_PEDAL"] > 3) - if self.CP.carFingerprint == CAR.XTRAIL: + if self.CP.carFingerprint in [CAR.ROGUE, CAR.XTRAIL]: ret.brakeLights = bool(cp.vl["DOORS_LIGHTS"]["BRAKE_LIGHT"]) ret.wheelSpeeds.fl = cp.vl["WHEEL_SPEEDS_FRONT"]["WHEEL_SPEED_FL"] * CV.KPH_TO_MS @@ -43,24 +46,26 @@ class CarState(CarStateBase): ret.standstill = ret.vEgoRaw < 0.01 ret.cruiseState.enabled = bool(cp_adas.vl["CRUISE_STATE"]["CRUISE_ENABLED"]) - if self.CP.carFingerprint == CAR.XTRAIL: + if self.CP.carFingerprint in [CAR.ROGUE, CAR.XTRAIL]: + ret.seatbeltUnlatched = cp.vl["HUD"]["SEATBELT_DRIVER_LATCHED"] == 0 ret.cruiseState.available = bool(cp_cam.vl["PRO_PILOT"]["CRUISE_ON"]) elif self.CP.carFingerprint == CAR.LEAF: + ret.seatbeltUnlatched = cp.vl["SEATBELT"]["SEATBELT_DRIVER_LATCHED"] == 0 ret.cruiseState.available = bool(cp.vl["CRUISE_THROTTLE"]["CRUISE_AVAILABLE"]) - # TODO: Find mph/kph bit on XTRAIL until then, assume xtrail is kph. - # Unable to change kph to mph on the xtrail, need a rogue to test it on speed = cp_adas.vl["PROPILOT_HUD"]["SET_SPEED"] if speed != 255: - if self.CP.carFingerprint == CAR.XTRAIL: - conversion = CV.KPH_TO_MS - else: + if self.CP.carFingerprint == CAR.LEAF: conversion = CV.MPH_TO_MS if cp.vl["HUD_SETTINGS"]["SPEED_MPH"] else CV.KPH_TO_MS + else: + conversion = CV.MPH_TO_MS if cp.vl["HUD"]["SPEED_MPH"] else CV.KPH_TO_MS speed -= 1 # Speed on HUD is always 1 lower than actually sent on can bus ret.cruiseState.speed = speed * conversion ret.steeringTorque = cp.vl["STEER_TORQUE_SENSOR"]["STEER_TORQUE_DRIVER"] - ret.steeringPressed = abs(ret.steeringTorque) > STEER_THRESHOLD + self.steeringTorqueSamples.append(ret.steeringTorque) + # Filtering driver torque to prevent steeringPressed false positives + ret.steeringPressed = bool(abs(sum(self.steeringTorqueSamples) / TORQUE_SAMPLES) > STEER_THRESHOLD) ret.steeringAngle = cp.vl["STEER_ANGLE_SENSOR"]["STEER_ANGLE"] @@ -72,8 +77,6 @@ class CarState(CarStateBase): cp.vl["DOORS_LIGHTS"]["DOOR_OPEN_FR"], cp.vl["DOORS_LIGHTS"]["DOOR_OPEN_FL"]]) - ret.seatbeltUnlatched = cp.vl["SEATBELT"]["SEATBELT_DRIVER_LATCHED"] == 0 - ret.espDisabled = bool(cp.vl["ESP"]["ESP_DISABLED"]) can_gear = int(cp.vl["GEARBOX"]["GEAR_SHIFTER"]) @@ -113,8 +116,6 @@ class CarState(CarStateBase): ("RIGHT_BLINKER", "LIGHTS", 0), ("LEFT_BLINKER", "LIGHTS", 0), - ("SEATBELT_DRIVER_LATCHED", "SEATBELT", 0), - ("ESP_DISABLED", "ESP", 0), ("GEAR_SHIFTER", "GEARBOX", 0), @@ -129,12 +130,14 @@ class CarState(CarStateBase): ("DOORS_LIGHTS", 10), ] - if CP.carFingerprint == CAR.XTRAIL: + if CP.carFingerprint in [CAR.ROGUE, CAR.XTRAIL]: signals += [ ("USER_BRAKE_PRESSED", "DOORS_LIGHTS", 1), ("BRAKE_LIGHT", "DOORS_LIGHTS", 1), ("GAS_PEDAL", "GAS_PEDAL", 0), + ("SEATBELT_DRIVER_LATCHED", "HUD", 0), + ("SPEED_MPH", "HUD", 0), ("PROPILOT_BUTTON", "CRUISE_THROTTLE", 0), ("CANCEL_BUTTON", "CRUISE_THROTTLE", 0), @@ -163,6 +166,7 @@ class CarState(CarStateBase): ("GAS_PEDAL", "CRUISE_THROTTLE", 0), ("CRUISE_AVAILABLE", "CRUISE_THROTTLE", 0), ("SPEED_MPH", "HUD_SETTINGS", 0), + ("SEATBELT_DRIVER_LATCHED", "SEATBELT", 0), # Copy other values, we use this to cancel ("CANCEL_SEATBELT", "CANCEL_MSG", 0), @@ -271,7 +275,7 @@ class CarState(CarStateBase): @staticmethod def get_cam_can_parser(CP): signals = [] - if CP.carFingerprint == CAR.XTRAIL: + if CP.carFingerprint in [CAR.ROGUE, CAR.XTRAIL]: signals += [ ("CRUISE_ON", "PRO_PILOT", 0), ] diff --git a/selfdrive/car/nissan/interface.py b/selfdrive/car/nissan/interface.py index 34aeb13e65..9c419c5a8f 100644 --- a/selfdrive/car/nissan/interface.py +++ b/selfdrive/car/nissan/interface.py @@ -14,7 +14,7 @@ class CarInterface(CarInterfaceBase): return float(accel) / 4.0 @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None): ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay) ret.carName = "nissan" @@ -31,10 +31,10 @@ class CarInterface(CarInterfaceBase): ret.lateralTuning.pid.kf = 0.00006 ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.0], [0.0]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.01], [0.005]] - ret.steerMaxBP = [0.] # m/s + ret.steerMaxBP = [0.] # m/s ret.steerMaxV = [1.] - if candidate == CAR.XTRAIL: + if candidate in [CAR.ROGUE, CAR.XTRAIL]: ret.mass = 1610 + STD_CARGO_KG ret.wheelbase = 2.705 ret.centerToFront = ret.wheelbase * 0.44 @@ -86,7 +86,7 @@ class CarInterface(CarInterfaceBase): def apply(self, c): can_sends = self.CC.update(c.enabled, self.CS, self.frame, c.actuators, c.cruiseControl.cancel, c.hudControl.visualAlert, - c.hudControl.leftLaneVisible,c.hudControl.rightLaneVisible, + c.hudControl.leftLaneVisible, c.hudControl.rightLaneVisible, c.hudControl.leftLaneDepart, c.hudControl.rightLaneDepart) self.frame += 1 return can_sends diff --git a/selfdrive/car/nissan/values.py b/selfdrive/car/nissan/values.py index 96777e5a44..0630a8cb94 100644 --- a/selfdrive/car/nissan/values.py +++ b/selfdrive/car/nissan/values.py @@ -1,3 +1,5 @@ +# flake8: noqa + from selfdrive.car import dbc_dict STEER_THRESHOLD = 1.0 @@ -5,25 +7,32 @@ STEER_THRESHOLD = 1.0 class CAR: XTRAIL = "NISSAN X-TRAIL 2017" LEAF = "NISSAN LEAF 2018" + ROGUE = "NISSAN ROGUE 2019" FINGERPRINTS = { CAR.XTRAIL: [ { - 2: 5, 42: 6, 346: 6, 347: 5, 348: 8, 349: 7, 361: 8, 386: 8, 389: 8, 397: 8, 398: 8, 403: 8, 520: 2, 523: 6, 548: 8, 645: 8, 658: 8, 665: 8, 666: 8, 674: 2, 682: 8, 683: 8, 689: 8, 723: 8, 758: 3, 768: 2, 783: 3, 851: 8, 855: 8, 1041: 8, 1055: 2, 1104: 4, 1105: 6, 1107: 4, 1108: 8, 1111: 4, 1227: 8, 1228: 8, 1247: 4, 1266: 8, 1273: 7, 1342: 1, 1376: 6, 1401: 8, 1474: 2, 1497: 3, 1821: 8, 1823: 8, 1837:8, 2015: 8, 2016: 8, 2024: 8 + 2: 5, 42: 6, 346: 6, 347: 5, 348: 8, 349: 7, 361: 8, 386: 8, 389: 8, 397: 8, 398: 8, 403: 8, 520: 2, 523: 6, 548: 8, 645: 8, 658: 8, 665: 8, 666: 8, 674: 2, 682: 8, 683: 8, 689: 8, 723: 8, 758: 3, 768: 2, 783: 3, 851: 8, 855: 8, 1041: 8, 1055: 2, 1104: 4, 1105: 6, 1107: 4, 1108: 8, 1111: 4, 1227: 8, 1228: 8, 1247: 4, 1266: 8, 1273: 7, 1342: 1, 1376: 6, 1401: 8, 1474: 2, 1497: 3, 1821: 8, 1823: 8, 1837: 8, 2015: 8, 2016: 8, 2024: 8 }, { - 2: 5, 42: 6, 346: 6, 347: 5, 348: 8, 349: 7, 361: 8, 386: 8, 389: 8, 397: 8, 398: 8, 403: 8, 520: 2, 523: 6, 527: 1, 548: 8, 637: 4, 645: 8, 658: 8, 665: 8, 666: 8, 674: 2, 682: 8, 683: 8, 689: 8, 723: 8, 758: 3, 768: 6, 783: 3, 851: 8, 855: 8, 1041: 8, 1055: 2, 1104: 4, 1105: 6, 1107: 4, 1108: 8, 1111: 4, 1227: 8, 1228: 8, 1247: 4, 1266: 8, 1273: 7, 1342: 1, 1376: 6, 1401: 8, 1474: 8, 1497: 3,1534: 6, 1792: 8, 1821: 8, 1823: 8, 1837: 8, 1872: 8, 1937: 8, 1953: 8, 1968: 8, 2015: 8, 2016: 8, 2024: 8 + 2: 5, 42: 6, 346: 6, 347: 5, 348: 8, 349: 7, 361: 8, 386: 8, 389: 8, 397: 8, 398: 8, 403: 8, 520: 2, 523: 6, 527: 1, 548: 8, 637: 4, 645: 8, 658: 8, 665: 8, 666: 8, 674: 2, 682: 8, 683: 8, 689: 8, 723: 8, 758: 3, 768: 6, 783: 3, 851: 8, 855: 8, 1041: 8, 1055: 2, 1104: 4, 1105: 6, 1107: 4, 1108: 8, 1111: 4, 1227: 8, 1228: 8, 1247: 4, 1266: 8, 1273: 7, 1342: 1, 1376: 6, 1401: 8, 1474: 8, 1497: 3, 1534: 6, 1792: 8, 1821: 8, 1823: 8, 1837: 8, 1872: 8, 1937: 8, 1953: 8, 1968: 8, 2015: 8, 2016: 8, 2024: 8 }, ], CAR.LEAF: [ { - 2: 5, 42: 6, 264: 3, 361: 8, 372: 8, 384: 8, 389: 8, 403: 8, 459: 7, 460: 4, 470: 8, 520: 1, 569: 8, 581: 8, 634: 7, 640: 8, 644: 8, 645: 8, 646: 5, 658: 8, 682: 8, 683: 8, 689: 8, 724: 6, 758: 3, 761: 2, 783: 3, 852: 8, 853: 8, 856: 8, 861: 8, 944: 1, 976: 6, 1008: 7, 1011: 7, 1057: 3, 1227: 8, 1228: 8, 1261: 5, 1342: 1, 1354: 8, 1361: 8, 1459: 8, 1477: 8, 1497: 3, 1549: 8, 1573: 6, 1821: 8, 1837: 8, 1856: 8, 1859: 8, 1861: 8, 1864: 8, 1874: 8, 1888: 8, 1891: 8, 1893: 8, 1906: 8, 1947: 8, 1949: 8, 1979: 8, 1981: 8, 2016: 8, 2017: 8, 2021: 8 + 2: 5, 42: 6, 264: 3, 361: 8, 372: 8, 384: 8, 389: 8, 403: 8, 459: 7, 460: 4, 470: 8, 520: 1, 569: 8, 581: 8, 634: 7, 640: 8, 644: 8, 645: 8, 646: 5, 658: 8, 682: 8, 683: 8, 689: 8, 724: 6, 758: 3, 761: 2, 783: 3, 852: 8, 853: 8, 856: 8, 861: 8, 944: 1, 976: 6, 1008: 7, 1011: 7, 1057: 3, 1227: 8, 1228: 8, 1261: 5, 1342: 1, 1354: 8, 1361: 8, 1459: 8, 1477: 8, 1497: 3, 1549: 8, 1573: 6, 1821: 8, 1837: 8, 1856: 8, 1859: 8, 1861: 8, 1864: 8, 1874: 8, 1888: 8, 1891: 8, 1893: 8, 1906: 8, 1947: 8, 1949: 8, 1979: 8, 1981: 8, 2016: 8, 2017: 8, 2021: 8, 643: 5, 1792: 8, 1872: 8, 1937: 8, 1953: 8, 1968: 8, 1988: 8, 2000: 8, 2001: 8, 2004: 8, 2005: 8, 2015: 8 }, ], + CAR.ROGUE: [ + { + 2: 5, 42: 6, 346: 6, 347: 5, 348: 8, 361: 8, 386: 8, 389: 8, 397: 8, 398: 8, 403: 8, 520: 2, 523: 6, 548: 8, 634: 7, 643: 5, 645: 8, 658: 8, 665: 8, 666: 8, 674: 2, 682: 8, 683: 8, 689: 8, 723: 8, 758: 3, 772: 8, 773: 6, 774: 7, 775: 8, 776: 6, 777: 7, 778: 6, 783: 3, 851: 8, 855: 8, 1041: 8, 1042: 8, 1055: 2, 1104: 4, 1105: 6, 1107: 4, 1108: 8, 1110: 7, 1111: 7, 1227: 8, 1228: 8, 1247: 4, 1266: 8, 1273: 7, 1342: 1, 1376: 6, 1401: 8, 1474: 2, 1497: 3, 1534: 7, 1821: 8, 1823: 8, 1837: 8, 1839: 8 + }, + ] } DBC = { CAR.XTRAIL: dbc_dict('nissan_x_trail_2017', None), CAR.LEAF: dbc_dict('nissan_leaf_2018', None), + CAR.ROGUE: dbc_dict('nissan_x_trail_2017', None), } diff --git a/selfdrive/car/subaru/__init__.py b/selfdrive/car/subaru/__init__.py index 8b13789179..e69de29bb2 100644 --- a/selfdrive/car/subaru/__init__.py +++ b/selfdrive/car/subaru/__init__.py @@ -1 +0,0 @@ - diff --git a/selfdrive/car/subaru/carcontroller.py b/selfdrive/car/subaru/carcontroller.py index 7f3fc3d84b..744fd0bcc9 100644 --- a/selfdrive/car/subaru/carcontroller.py +++ b/selfdrive/car/subaru/carcontroller.py @@ -1,7 +1,6 @@ -#from common.numpy_fast import clip from selfdrive.car import apply_std_steer_torque_limits from selfdrive.car.subaru import subarucan -from selfdrive.car.subaru.values import DBC +from selfdrive.car.subaru.values import DBC, PREGLOBAL_CARS from opendbc.can.packer import CANPacker @@ -16,56 +15,73 @@ class CarControllerParams(): self.STEER_DRIVER_FACTOR = 1 # from dbc - class CarController(): def __init__(self, dbc_name, CP, VM): - self.lkas_active = False self.apply_steer_last = 0 self.es_distance_cnt = -1 + self.es_accel_cnt = -1 self.es_lkas_cnt = -1 + self.fake_button_prev = 0 self.steer_rate_limited = False - # Setup detection helper. Routes commands to - # an appropriate CAN bus number. self.params = CarControllerParams() self.packer = CANPacker(DBC[CP.carFingerprint]['pt']) def update(self, enabled, CS, frame, actuators, pcm_cancel_cmd, visual_alert, left_line, right_line): - """ Controls thread """ - - P = self.params - # Send CAN commands. can_sends = [] - ### STEER ### + # *** steering *** + if (frame % self.params.STEER_STEP) == 0: - if (frame % P.STEER_STEP) == 0: - - final_steer = actuators.steer if enabled else 0. - apply_steer = int(round(final_steer * P.STEER_MAX)) + apply_steer = int(round(actuators.steer * self.params.STEER_MAX)) # limits due to driver torque new_steer = int(round(apply_steer)) - apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, P) + apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params) self.steer_rate_limited = new_steer != apply_steer - lkas_enabled = enabled - - if not lkas_enabled: + if not enabled: apply_steer = 0 - can_sends.append(subarucan.create_steering_control(self.packer, apply_steer, frame, P.STEER_STEP)) + if CS.CP.carFingerprint in PREGLOBAL_CARS: + can_sends.append(subarucan.create_preglobal_steering_control(self.packer, apply_steer, frame, self.params.STEER_STEP)) + else: + can_sends.append(subarucan.create_steering_control(self.packer, apply_steer, frame, self.params.STEER_STEP)) self.apply_steer_last = apply_steer - if self.es_distance_cnt != CS.es_distance_msg["Counter"]: - can_sends.append(subarucan.create_es_distance(self.packer, CS.es_distance_msg, pcm_cancel_cmd)) - self.es_distance_cnt = CS.es_distance_msg["Counter"] - if self.es_lkas_cnt != CS.es_lkas_msg["Counter"]: - can_sends.append(subarucan.create_es_lkas(self.packer, CS.es_lkas_msg, visual_alert, left_line, right_line)) - self.es_lkas_cnt = CS.es_lkas_msg["Counter"] + # *** alerts and pcm cancel *** + + if CS.CP.carFingerprint in PREGLOBAL_CARS: + if self.es_accel_cnt != CS.es_accel_msg["Counter"]: + # 1 = main, 2 = set shallow, 3 = set deep, 4 = resume shallow, 5 = resume deep + # disengage ACC when OP is disengaged + if pcm_cancel_cmd: + fake_button = 1 + # turn main on if off and past start-up state + elif not CS.out.cruiseState.available and CS.ready: + fake_button = 1 + else: + fake_button = CS.button + + # unstick previous mocked button press + if fake_button == 1 and self.fake_button_prev == 1: + fake_button = 0 + self.fake_button_prev = fake_button + + can_sends.append(subarucan.create_es_throttle_control(self.packer, fake_button, CS.es_accel_msg)) + self.es_accel_cnt = CS.es_accel_msg["Counter"] + + else: + if self.es_distance_cnt != CS.es_distance_msg["Counter"]: + can_sends.append(subarucan.create_es_distance(self.packer, CS.es_distance_msg, pcm_cancel_cmd)) + self.es_distance_cnt = CS.es_distance_msg["Counter"] + + if self.es_lkas_cnt != CS.es_lkas_msg["Counter"]: + can_sends.append(subarucan.create_es_lkas(self.packer, CS.es_lkas_msg, visual_alert, left_line, right_line)) + self.es_lkas_cnt = CS.es_lkas_msg["Counter"] return can_sends diff --git a/selfdrive/car/subaru/carstate.py b/selfdrive/car/subaru/carstate.py index ebfbaaa39a..5b5e23599c 100644 --- a/selfdrive/car/subaru/carstate.py +++ b/selfdrive/car/subaru/carstate.py @@ -4,7 +4,7 @@ from opendbc.can.can_define import CANDefine from selfdrive.config import Conversions as CV from selfdrive.car.interfaces import CarStateBase from opendbc.can.parser import CANParser -from selfdrive.car.subaru.values import DBC, STEER_THRESHOLD +from selfdrive.car.subaru.values import DBC, STEER_THRESHOLD, CAR, PREGLOBAL_CARS class CarState(CarStateBase): @@ -20,7 +20,10 @@ class CarState(CarStateBase): ret.gas = cp.vl["Throttle"]['Throttle_Pedal'] / 255. ret.gasPressed = ret.gas > 1e-5 - ret.brakePressed = cp.vl["Brake_Pedal"]['Brake_Pedal'] > 1e-5 + if self.car_fingerprint in PREGLOBAL_CARS: + ret.brakePressed = cp.vl["Brake_Pedal"]['Brake_Pedal'] > 2 + else: + ret.brakePressed = cp.vl["Brake_Pedal"]['Brake_Pedal'] > 1e-5 ret.brakeLights = ret.brakePressed ret.wheelSpeeds.fl = cp.vl["Wheel_Speeds"]['FL'] * CV.KPH_TO_MS @@ -38,6 +41,9 @@ class CarState(CarStateBase): self.right_blinker_cnt = 50 if cp.vl["Dashlights"]['RIGHT_BLINKER'] else max(self.right_blinker_cnt - 1, 0) ret.rightBlinker = self.right_blinker_cnt > 0 + ret.leftBlindspot = (cp.vl["BSD_RCTA"]['L_ADJACENT'] == 1) or (cp.vl["BSD_RCTA"]['L_APPROACHING'] == 1) + ret.rightBlindspot = (cp.vl["BSD_RCTA"]['R_ADJACENT'] == 1) or (cp.vl["BSD_RCTA"]['R_APPROACHING'] == 1) + can_gear = int(cp.vl["Transmission"]['Gear']) ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(can_gear, None)) @@ -48,18 +54,31 @@ class CarState(CarStateBase): ret.cruiseState.enabled = cp.vl["CruiseControl"]['Cruise_Activated'] != 0 ret.cruiseState.available = cp.vl["CruiseControl"]['Cruise_On'] != 0 ret.cruiseState.speed = cp_cam.vl["ES_DashStatus"]['Cruise_Set_Speed'] * CV.KPH_TO_MS - # 1 = imperial, 6 = metric - if cp.vl["Dash_State"]['Units'] == 1: + + # UDM Forester, Legacy: mph = 0 + if self.car_fingerprint in [CAR.FORESTER_PREGLOBAL, CAR.LEGACY_PREGLOBAL] and cp.vl["Dash_State"]['Units'] == 0: + ret.cruiseState.speed *= CV.MPH_TO_KPH + # EDM Global: mph = 1, 2; All Outback: mph = 1, UDM Forester: mph = 7 + elif self.car_fingerprint not in [CAR.FORESTER_PREGLOBAL, CAR.LEGACY_PREGLOBAL] and cp.vl["Dash_State"]['Units'] in [1, 2, 7]: ret.cruiseState.speed *= CV.MPH_TO_KPH ret.seatbeltUnlatched = cp.vl["Dashlights"]['SEATBELT_FL'] == 1 ret.doorOpen = any([cp.vl["BodyInfo"]['DOOR_OPEN_RR'], - cp.vl["BodyInfo"]['DOOR_OPEN_RL'], - cp.vl["BodyInfo"]['DOOR_OPEN_FR'], - cp.vl["BodyInfo"]['DOOR_OPEN_FL']]) - - self.es_distance_msg = copy.copy(cp_cam.vl["ES_Distance"]) - self.es_lkas_msg = copy.copy(cp_cam.vl["ES_LKAS_State"]) + cp.vl["BodyInfo"]['DOOR_OPEN_RL'], + cp.vl["BodyInfo"]['DOOR_OPEN_FR'], + cp.vl["BodyInfo"]['DOOR_OPEN_FL']]) + + if self.car_fingerprint in PREGLOBAL_CARS: + ret.steerError = cp.vl["Steering_Torque"]["LKA_Lockout"] == 1 + self.button = cp_cam.vl["ES_CruiseThrottle"]["Button"] + self.ready = not cp_cam.vl["ES_DashStatus"]["Not_Ready_Startup"] + self.es_accel_msg = copy.copy(cp_cam.vl["ES_CruiseThrottle"]) + else: + ret.steerError = cp.vl["Steering_Torque"]['Steer_Error_1'] == 1 + ret.steerWarning = cp.vl["Steering_Torque"]['Steer_Warning'] == 1 + ret.cruiseState.nonAdaptive = cp_cam.vl["ES_DashStatus"]['Conventional_Cruise'] == 1 + self.es_distance_msg = copy.copy(cp_cam.vl["ES_Distance"]) + self.es_lkas_msg = copy.copy(cp_cam.vl["ES_LKAS_State"]) return ret @@ -87,56 +106,129 @@ class CarState(CarStateBase): ("DOOR_OPEN_RL", "BodyInfo", 1), ("Units", "Dash_State", 1), ("Gear", "Transmission", 0), + ("L_ADJACENT", "BSD_RCTA", 0), + ("R_ADJACENT", "BSD_RCTA", 0), + ("L_APPROACHING", "BSD_RCTA", 0), + ("R_APPROACHING", "BSD_RCTA", 0), ] checks = [ # sig_address, frequency + ("Throttle", 100), ("Dashlights", 10), - ("CruiseControl", 20), + ("Brake_Pedal", 50), ("Wheel_Speeds", 50), + ("Transmission", 100), ("Steering_Torque", 50), - ("BodyInfo", 10), ] + if CP.carFingerprint in PREGLOBAL_CARS: + signals += [ + ("LKA_Lockout", "Steering_Torque", 0), + ] + else: + signals += [ + ("Steer_Error_1", "Steering_Torque", 0), + ("Steer_Warning", "Steering_Torque", 0), + ] + + checks += [ + ("Dashlights", 10), + ("BodyInfo", 10), + ("CruiseControl", 20), + ] + + if CP.carFingerprint == CAR.FORESTER_PREGLOBAL: + checks += [ + ("Dashlights", 20), + ("BodyInfo", 1), + ("CruiseControl", 50), + ] + + if CP.carFingerprint in [CAR.LEGACY_PREGLOBAL, CAR.OUTBACK_PREGLOBAL, CAR.OUTBACK_PREGLOBAL_2018]: + checks += [ + ("Dashlights", 10), + ("CruiseControl", 50), + ] + return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0) @staticmethod def get_cam_can_parser(CP): - signals = [ - ("Cruise_Set_Speed", "ES_DashStatus", 0), - - ("Counter", "ES_Distance", 0), - ("Signal1", "ES_Distance", 0), - ("Signal2", "ES_Distance", 0), - ("Main", "ES_Distance", 0), - ("Signal3", "ES_Distance", 0), - - ("Counter", "ES_LKAS_State", 0), - ("Keep_Hands_On_Wheel", "ES_LKAS_State", 0), - ("Empty_Box", "ES_LKAS_State", 0), - ("Signal1", "ES_LKAS_State", 0), - ("LKAS_ACTIVE", "ES_LKAS_State", 0), - ("Signal2", "ES_LKAS_State", 0), - ("Backward_Speed_Limit_Menu", "ES_LKAS_State", 0), - ("LKAS_ENABLE_3", "ES_LKAS_State", 0), - ("Signal3", "ES_LKAS_State", 0), - ("LKAS_ENABLE_2", "ES_LKAS_State", 0), - ("Signal4", "ES_LKAS_State", 0), - ("LKAS_Left_Line_Visible", "ES_LKAS_State", 0), - ("Signal6", "ES_LKAS_State", 0), - ("LKAS_Right_Line_Visible", "ES_LKAS_State", 0), - ("Signal7", "ES_LKAS_State", 0), - ("FCW_Cont_Beep", "ES_LKAS_State", 0), - ("FCW_Repeated_Beep", "ES_LKAS_State", 0), - ("Throttle_Management_Activated", "ES_LKAS_State", 0), - ("Traffic_light_Ahead", "ES_LKAS_State", 0), - ("Right_Depart", "ES_LKAS_State", 0), - ("Signal5", "ES_LKAS_State", 0), - - ] - - checks = [ - ("ES_DashStatus", 10), - ] + if CP.carFingerprint in PREGLOBAL_CARS: + signals = [ + ("Cruise_Set_Speed", "ES_DashStatus", 0), + ("Not_Ready_Startup", "ES_DashStatus", 0), + + ("Throttle_Cruise", "ES_CruiseThrottle", 0), + ("Signal1", "ES_CruiseThrottle", 0), + ("Cruise_Activated", "ES_CruiseThrottle", 0), + ("Signal2", "ES_CruiseThrottle", 0), + ("Brake_On", "ES_CruiseThrottle", 0), + ("DistanceSwap", "ES_CruiseThrottle", 0), + ("Standstill", "ES_CruiseThrottle", 0), + ("Signal3", "ES_CruiseThrottle", 0), + ("CloseDistance", "ES_CruiseThrottle", 0), + ("Signal4", "ES_CruiseThrottle", 0), + ("Standstill_2", "ES_CruiseThrottle", 0), + ("ES_Error", "ES_CruiseThrottle", 0), + ("Signal5", "ES_CruiseThrottle", 0), + ("Counter", "ES_CruiseThrottle", 0), + ("Signal6", "ES_CruiseThrottle", 0), + ("Button", "ES_CruiseThrottle", 0), + ("Signal7", "ES_CruiseThrottle", 0), + ] + + checks = [ + ("ES_DashStatus", 20), + ("ES_CruiseThrottle", 20), + ] + else: + signals = [ + ("Cruise_Set_Speed", "ES_DashStatus", 0), + ("Conventional_Cruise", "ES_DashStatus", 0), + + ("Counter", "ES_Distance", 0), + ("Signal1", "ES_Distance", 0), + ("Cruise_Fault", "ES_Distance", 0), + ("Cruise_Throttle", "ES_Distance", 0), + ("Signal2", "ES_Distance", 0), + ("Car_Follow", "ES_Distance", 0), + ("Signal3", "ES_Distance", 0), + ("Cruise_Brake_Active", "ES_Distance", 0), + ("Distance_Swap", "ES_Distance", 0), + ("Cruise_EPB", "ES_Distance", 0), + ("Signal4", "ES_Distance", 0), + ("Close_Distance", "ES_Distance", 0), + ("Signal5", "ES_Distance", 0), + ("Cruise_Cancel", "ES_Distance", 0), + ("Cruise_Set", "ES_Distance", 0), + ("Cruise_Resume", "ES_Distance", 0), + ("Signal6", "ES_Distance", 0), + + ("Counter", "ES_LKAS_State", 0), + ("Keep_Hands_On_Wheel", "ES_LKAS_State", 0), + ("Empty_Box", "ES_LKAS_State", 0), + ("Signal1", "ES_LKAS_State", 0), + ("LKAS_ACTIVE", "ES_LKAS_State", 0), + ("Signal2", "ES_LKAS_State", 0), + ("Backward_Speed_Limit_Menu", "ES_LKAS_State", 0), + ("LKAS_ENABLE_3", "ES_LKAS_State", 0), + ("LKAS_Left_Line_Light_Blink", "ES_LKAS_State", 0), + ("LKAS_ENABLE_2", "ES_LKAS_State", 0), + ("LKAS_Right_Line_Light_Blink", "ES_LKAS_State", 0), + ("LKAS_Left_Line_Visible", "ES_LKAS_State", 0), + ("LKAS_Left_Line_Green", "ES_LKAS_State", 0), + ("LKAS_Right_Line_Visible", "ES_LKAS_State", 0), + ("LKAS_Right_Line_Green", "ES_LKAS_State", 0), + ("LKAS_Alert", "ES_LKAS_State", 0), + ("Signal3", "ES_LKAS_State", 0), + ] + + checks = [ + ("ES_DashStatus", 10), + ("ES_Distance", 20), + ("ES_LKAS_State", 10), + ] return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2) diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py index 328666d79c..6d65f64f3d 100644 --- a/selfdrive/car/subaru/interface.py +++ b/selfdrive/car/subaru/interface.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 from cereal import car -from selfdrive.car.subaru.values import CAR +from selfdrive.car.subaru.values import CAR, PREGLOBAL_CARS from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint from selfdrive.car.interfaces import CarInterfaceBase @@ -11,16 +11,22 @@ class CarInterface(CarInterfaceBase): return float(accel) / 4.0 @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None): ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay) ret.carName = "subaru" ret.radarOffCan = True - ret.safetyModel = car.CarParams.SafetyModel.subaru + + if candidate in PREGLOBAL_CARS: + ret.safetyModel = car.CarParams.SafetyModel.subaruLegacy + else: + ret.safetyModel = car.CarParams.SafetyModel.subaru # Subaru port is a community feature, since we don't own one to test ret.communityFeature = True + ret.dashcamOnly = candidate in PREGLOBAL_CARS + # force openpilot to fake the stock camera, since car harness is not supported yet and old style giraffe (with switches) # was never released ret.enableCamera = True @@ -28,7 +34,17 @@ class CarInterface(CarInterfaceBase): ret.steerRateCost = 0.7 ret.steerLimitTimer = 0.4 - if candidate in [CAR.IMPREZA]: + if candidate == CAR.ASCENT: + ret.mass = 2031. + STD_CARGO_KG + ret.wheelbase = 2.89 + ret.centerToFront = ret.wheelbase * 0.5 + ret.steerRatio = 13.5 + ret.steerActuatorDelay = 0.3 # end-to-end angle controller + ret.lateralTuning.pid.kf = 0.00003 + ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 20.], [0., 20.]] + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.0025, 0.1], [0.00025, 0.01]] + + if candidate == CAR.IMPREZA: ret.mass = 1568. + STD_CARGO_KG ret.wheelbase = 2.67 ret.centerToFront = ret.wheelbase * 0.5 @@ -38,6 +54,47 @@ class CarInterface(CarInterfaceBase): ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 20.], [0., 20.]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2, 0.3], [0.02, 0.03]] + if candidate == CAR.FORESTER: + ret.mass = 1568. + STD_CARGO_KG + ret.wheelbase = 2.67 + ret.centerToFront = ret.wheelbase * 0.5 + ret.steerRatio = 17 # learned, 14 stock + ret.steerActuatorDelay = 0.1 + ret.lateralTuning.pid.kf = 0.000038 + ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 14., 23.], [0., 14., 23.]] + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.01, 0.065, 0.2], [0.001, 0.015, 0.025]] + + if candidate in [CAR.FORESTER_PREGLOBAL, CAR.OUTBACK_PREGLOBAL_2018]: + ret.safetyParam = 1 # Outback 2018-2019 and Forester have reversed driver torque signal + ret.mass = 1568 + STD_CARGO_KG + ret.wheelbase = 2.67 + ret.centerToFront = ret.wheelbase * 0.5 + ret.steerRatio = 20 # learned, 14 stock + ret.steerActuatorDelay = 0.1 + ret.lateralTuning.pid.kf = 0.000039 + ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 10., 20.], [0., 10., 20.]] + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.01, 0.05, 0.2], [0.003, 0.018, 0.025]] + + if candidate == CAR.LEGACY_PREGLOBAL: + ret.mass = 1568 + STD_CARGO_KG + ret.wheelbase = 2.67 + ret.centerToFront = ret.wheelbase * 0.5 + ret.steerRatio = 12.5 # 14.5 stock + ret.steerActuatorDelay = 0.15 + ret.lateralTuning.pid.kf = 0.00005 + ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 20.], [0., 20.]] + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.1, 0.2], [0.01, 0.02]] + + if candidate == CAR.OUTBACK_PREGLOBAL: + ret.mass = 1568 + STD_CARGO_KG + ret.wheelbase = 2.67 + ret.centerToFront = ret.wheelbase * 0.5 + ret.steerRatio = 20 # learned, 14 stock + ret.steerActuatorDelay = 0.1 + ret.lateralTuning.pid.kf = 0.000039 + ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0., 10., 20.], [0., 10., 20.]] + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.01, 0.05, 0.2], [0.003, 0.018, 0.025]] + # TODO: get actual value, for now starting with reasonable value for # civic and scaling by mass and wheelbase ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) @@ -58,11 +115,6 @@ class CarInterface(CarInterfaceBase): ret.canValid = self.cp.can_valid and self.cp_cam.can_valid ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False - buttonEvents = [] - be = car.CarState.ButtonEvent.new_message() - be.type = car.CarState.ButtonEvent.Type.accelCruise - buttonEvents.append(be) - ret.events = self.create_common_events(ret).to_msg() self.CS.out = ret.as_reader() diff --git a/selfdrive/car/subaru/subarucan.py b/selfdrive/car/subaru/subarucan.py index d0850afc9e..8249d36ba9 100644 --- a/selfdrive/car/subaru/subarucan.py +++ b/selfdrive/car/subaru/subarucan.py @@ -5,8 +5,7 @@ VisualAlert = car.CarControl.HUDControl.VisualAlert def create_steering_control(packer, apply_steer, frame, steer_step): - # counts from 0 to 15 then back to 0 + 16 for enable bit - idx = ((frame // steer_step) % 16) + idx = (frame / steer_step) % 16 values = { "Counter": idx, @@ -24,7 +23,7 @@ def create_es_distance(packer, es_distance_msg, pcm_cancel_cmd): values = copy.copy(es_distance_msg) if pcm_cancel_cmd: - values["Main"] = 1 + values["Cruise_Cancel"] = 1 return packer.make_can_msg("ES_Distance", 0, values) @@ -38,3 +37,31 @@ def create_es_lkas(packer, es_lkas_msg, visual_alert, left_line, right_line): values["LKAS_Right_Line_Visible"] = int(right_line) return packer.make_can_msg("ES_LKAS_State", 0, values) + +# *** Subaru Pre-global *** + +def subaru_preglobal_checksum(packer, values, addr): + dat = packer.make_can_msg(addr, 0, values)[2] + return (sum(dat[:7])) % 256 + +def create_preglobal_steering_control(packer, apply_steer, frame, steer_step): + + idx = (frame / steer_step) % 8 + + values = { + "Counter": idx, + "LKAS_Command": apply_steer, + "LKAS_Active": 1 if apply_steer != 0 else 0 + } + values["Checksum"] = subaru_preglobal_checksum(packer, values, "ES_LKAS") + + return packer.make_can_msg("ES_LKAS", 0, values) + +def create_es_throttle_control(packer, fake_button, es_accel_msg): + + values = copy.copy(es_accel_msg) + values["Button"] = fake_button + + values["Checksum"] = subaru_preglobal_checksum(packer, values, "ES_CruiseThrottle") + + return packer.make_can_msg("ES_CruiseThrottle", 0, values) diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index b75fa9c386..8cbb6fe72d 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -1,22 +1,81 @@ +# flake8: noqa + from selfdrive.car import dbc_dict from cereal import car Ecu = car.CarParams.Ecu class CAR: + ASCENT = "SUBARU ASCENT LIMITED 2019" IMPREZA = "SUBARU IMPREZA LIMITED 2019" + FORESTER = "SUBARU FORESTER 2019" + FORESTER_PREGLOBAL = "SUBARU FORESTER 2017 - 2018" + LEGACY_PREGLOBAL = "SUBARU LEGACY 2015 - 2018" + OUTBACK_PREGLOBAL = "SUBARU OUTBACK 2015 - 2017" + OUTBACK_PREGLOBAL_2018 = "SUBARU OUTBACK 2018 - 2019" FINGERPRINTS = { + CAR.ASCENT: [{ + # SUBARU ASCENT LIMITED 2019 + 2: 8, 64: 8, 65: 8, 72: 8, 73: 8, 280: 8, 281: 8, 290: 8, 312: 8, 313: 8, 314: 8, 315: 8, 316: 8, 326: 8, 544: 8, 545: 8, 546: 8, 552: 8, 554: 8, 557: 8, 576: 8, 577: 8, 722: 8, 801: 8, 802: 8, 805: 8, 808: 8, 811: 8, 816: 8, 826: 8, 837: 8, 838: 8, 839: 8, 842: 8, 912: 8, 915: 8, 940: 8, 1614: 8, 1617: 8, 1632: 8, 1650: 8, 1657: 8, 1658: 8, 1677: 8, 1722: 8, 1743: 8, 1759: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8 + }], CAR.IMPREZA: [{ + # SUBARU IMPREZA LIMITED 2019 2: 8, 64: 8, 65: 8, 72: 8, 73: 8, 280: 8, 281: 8, 290: 8, 312: 8, 313: 8, 314: 8, 315: 8, 316: 8, 326: 8, 544: 8, 545: 8, 546: 8, 552: 8, 554: 8, 557: 8, 576: 8, 577: 8, 722: 8, 801: 8, 802: 8, 805: 8, 808: 8, 816: 8, 826: 8, 837: 8, 838: 8, 839: 8, 842: 8, 912: 8, 915: 8, 940: 8, 1614: 8, 1617: 8, 1632: 8, 1650: 8, 1657: 8, 1658: 8, 1677: 8, 1697: 8, 1722: 8, 1743: 8, 1759: 8, 1786: 5, 1787: 5, 1788: 8, 1809: 8, 1813: 8, 1817: 8, 1821: 8, 1840: 8, 1848: 8, 1924: 8, 1932: 8, 1952: 8, 1960: 8 }, - # Crosstrek 2018 (same platform as Impreza) + # SUBARU CROSSTREK 2018 + { + 2: 8, 64: 8, 65: 8, 72: 8, 73: 8, 280: 8, 281: 8, 290: 8, 312: 8, 313: 8, 314: 8, 315: 8, 316: 8, 326: 8, 372: 8, 544: 8, 545: 8, 546: 8, 554: 8, 557: 8, 576: 8, 577: 8, 722: 8, 801: 8, 802: 8, 805: 8, 808: 8, 811: 8, 826: 8, 837: 8, 838: 8, 839: 8, 842: 8, 912: 8, 915: 8, 940: 8, 1614: 8, 1617: 8, 1632: 8, 1650: 8, 1657: 8, 1658: 8, 1677: 8, 1697: 8, 1759: 8, 1786: 5, 1787: 5, 1788: 8 + }], + CAR.FORESTER: [{ + # Forester Sport 2019 + 2: 8, 64: 8, 65: 8, 72: 8, 73: 8, 280: 8, 281: 8, 282: 8, 312: 8, 313: 8, 314: 8, 315: 8, 316: 8, 326: 8, 372: 8, 552: 8, 557: 8, 576: 8, 577: 8, 722: 8, 808: 8, 811: 8, 816: 8, 826: 8, 837: 8, 838: 8, 839: 8, 842: 8, 912: 8, 915: 8, 940: 8, 1614: 8, 1617: 8, 1632: 8, 1650: 8, 1651: 8, 1657: 8, 1658: 8, 1677: 8, 1697: 8, 1698: 8, 1722: 8, 1743: 8, 1759: 8, 1787: 5, 1788: 8, 1809: 8, 1813: 8, 1817: 8, 1821: 8, 1840: 8, 1848: 8, 1924: 8, 1932: 8, 1952: 8, 1960: 8 + }, + # Forester 2019 + { + 2: 8, 64: 8, 65: 8, 72: 8, 73: 8, 280: 8, 281: 8, 282: 8, 290: 8, 312: 8, 313: 8, 314: 8, 315: 8, 316: 8, 326: 8, 372: 8, 544: 8, 545: 8, 546: 8, 554: 8, 557: 8, 576: 8, 577: 8, 722: 8, 801: 8, 802: 8, 803: 8, 805: 8, 808: 8, 811: 8, 826: 8, 837: 8, 838: 8, 839: 8, 842: 8, 912: 8, 915: 8, 940: 8, 1614: 8, 1617: 8, 1632: 8, 1650: 8, 1651: 8, 1657: 8, 1658: 8, 1677: 8, 1722: 8, 1759: 8, 1787: 5, 1788: 8 + }], + CAR.OUTBACK_PREGLOBAL: [{ + # OUTBACK PREMIUM 2.5i 2015 + 2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 346: 8, 352: 8, 353: 8, 354: 8, 356: 8, 358: 8, 359: 8, 392: 8, 640: 8, 642: 8, 644: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 977: 8, 1632: 8, 1745: 8, 1786: 5, 1882: 8, 2015: 8, 2016: 8, 2024: 8, 604: 8, 885: 8, 1788: 8, 316: 8, 1614: 8, 1640: 8, 1657: 8, 1658: 8, 1672: 8, 1743: 8, 1785: 5, 1787: 5 + }, + # OUTBACK PREMIUM 3.6i 2015 + { + 2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 392: 8, 604: 8, 640: 8, 642: 8, 644: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 977: 8, 1632: 8, 1745: 8, 1779: 8, 1786: 5 + }, + # OUTBACK LIMITED 2.5i 2018 { - 2: 8, 64: 8, 65: 8, 72: 8, 73: 8, 256: 8, 280: 8, 281: 8, 290: 8, 312: 8, 313: 8, 314: 8, 315: 8, 316: 8, 326: 8, 372: 8, 544: 8, 545: 8, 546: 8, 554: 8, 557: 8, 576: 8, 577: 8, 722: 8, 801: 8, 802: 8, 805: 8, 808: 8, 811: 8, 826: 8, 837: 8, 838: 8, 839: 8, 842: 8, 912: 8, 915: 8, 940: 8, 1614: 8, 1617: 8, 1632: 8, 1650: 8, 1657: 8, 1658: 8, 1677: 8, 1697: 8, 1759: 8, 1786: 5, 1787: 5, 1788: 8 + 2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 316: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 352: 8, 353: 8, 354: 8, 356: 8, 358: 8, 359: 8, 392: 8, 554: 8, 604: 8, 640: 8, 642: 8, 644: 8, 805: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 885: 8, 977: 8, 1614: 8, 1632: 8, 1657: 8, 1658: 8, 1672: 8, 1722: 8, 1736: 8, 1743: 8, 1745: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8 + }], + CAR.OUTBACK_PREGLOBAL_2018: [{ + # OUTBACK LIMITED 3.6R 2019 + 2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 316: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 352: 8, 353: 8, 354: 8, 356: 8, 358: 8, 359: 8, 392: 8, 554: 8, 604: 8, 640: 8, 642: 8, 644: 8, 805: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 885: 8, 886: 2, 977: 8, 1614: 8, 1632: 8, 1657: 8, 1658: 8, 1672: 8, 1736: 8, 1743: 8, 1745: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8, 1862: 8, 1870: 8, 1920: 8, 1927: 8, 1928: 8, 1935: 8, 1968: 8, 1976: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8 + }], + CAR.FORESTER_PREGLOBAL: [{ + # FORESTER PREMIUM 2.5i 2017 + 2: 8, 112: 8, 117: 8, 128: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 340: 7, 342: 8, 352: 8, 353: 8, 354: 8, 355: 8, 356: 8, 554: 8, 604: 8, 640: 8, 641: 8, 642: 8, 805: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 885: 8, 886: 1, 888: 8, 977: 8, 1398: 8, 1632: 8, 1743: 8, 1744: 8, 1745: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8, 1882: 8, 1895: 8, 1903: 8, 1986: 8, 1994: 8, 2015: 8, 2016: 8, 2024: 8, 644:8, 890:8, 1736:8 + }], + CAR.LEGACY_PREGLOBAL: [{ + # LEGACY 2.5i 2017 + 2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 392: 8, 604: 8, 640: 8, 642: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 885: 8, 977: 8, 1632: 8, 1640: 8, 1736: 8, 1745: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8, 352: 8, 353: 8, 354: 8, 356: 8, 358: 8, 359: 8, 644: 8 + }, + # LEGACY 2018 + { + 2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 316: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 392: 8, 604: 8, 640: 8, 642: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 885: 8, 977: 8, 1614: 8, 1632: 8, 1640: 8, 1657: 8, 1658: 8, 1672: 8, 1722: 8, 1743: 8, 1745: 8, 1778: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8, 2015: 8, 2016: 8, 2024: 8 + }, + # LEGACY 2018 + { + 2: 8, 208: 8, 209: 4, 210: 8, 211: 7, 212: 8, 316: 8, 320: 8, 321: 8, 324: 8, 328: 8, 329: 8, 336: 2, 338: 8, 342: 8, 352: 8, 353: 8, 354: 8, 356: 8, 358: 8, 359: 8, 392: 8, 554: 8, 604: 8, 640: 8, 642: 8, 805: 8, 864: 8, 865: 8, 866: 8, 872: 8, 880: 8, 881: 8, 882: 8, 884: 8, 885: 8, 977: 8, 1614: 8, 1632: 8, 1640: 8, 1657: 8, 1658: 8, 1672: 8, 1722: 8, 1743: 8, 1745: 8, 1785: 5, 1786: 5, 1787: 5, 1788: 8, 2015: 8, 2016: 8, 2024: 8 }], } STEER_THRESHOLD = { + CAR.ASCENT: 80, CAR.IMPREZA: 80, + CAR.FORESTER: 80, + CAR.FORESTER_PREGLOBAL: 75, + CAR.LEGACY_PREGLOBAL: 75, + CAR.OUTBACK_PREGLOBAL: 75, + CAR.OUTBACK_PREGLOBAL_2018: 75, } ECU_FINGERPRINT = { @@ -24,5 +83,13 @@ ECU_FINGERPRINT = { } DBC = { - CAR.IMPREZA: dbc_dict('subaru_global_2017', None), + CAR.ASCENT: dbc_dict('subaru_global_2017_generated', None), + CAR.IMPREZA: dbc_dict('subaru_global_2017_generated', None), + CAR.FORESTER: dbc_dict('subaru_global_2017_generated', None), + CAR.FORESTER_PREGLOBAL: dbc_dict('subaru_forester_2017_generated', None), + CAR.LEGACY_PREGLOBAL: dbc_dict('subaru_outback_2015_generated', None), + CAR.OUTBACK_PREGLOBAL: dbc_dict('subaru_outback_2015_generated', None), + CAR.OUTBACK_PREGLOBAL_2018: dbc_dict('subaru_outback_2019_generated', None), } + +PREGLOBAL_CARS = [CAR.FORESTER_PREGLOBAL, CAR.LEGACY_PREGLOBAL, CAR.OUTBACK_PREGLOBAL, CAR.OUTBACK_PREGLOBAL_2018] diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index f320e0be29..069d5af00b 100755 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -13,6 +13,7 @@ class TestCarInterfaces(unittest.TestCase): all_cars = all_known_cars() for car_name in all_cars: + print(car_name) fingerprint = FINGERPRINTS[car_name][0] CarInterface, CarController, CarState = interfaces[car_name] @@ -30,6 +31,17 @@ class TestCarInterfaces(unittest.TestCase): assert car_params assert car_interface + self.assertGreater(car_params.mass, 1) + self.assertGreater(car_params.steerRateCost, 1e-3) + + tuning = car_params.lateralTuning.which() + if tuning == 'pid': + self.assertTrue(len(car_params.lateralTuning.pid.kpV)) + elif tuning == 'lqr': + self.assertTrue(len(car_params.lateralTuning.lqr.a)) + elif tuning == 'indi': + self.assertGreater(car_params.lateralTuning.indi.outerLoopGain, 1e-3) + # Run car interface CC = car.CarControl.new_message() for _ in range(10): @@ -51,7 +63,7 @@ class TestCarInterfaces(unittest.TestCase): # Run radar interface once radar_interface.update([]) - if hasattr(radar_interface, '_update') and hasattr(radar_interface, 'trigger_msg'): + if not car_params.radarOffCan and hasattr(radar_interface, '_update') and hasattr(radar_interface, 'trigger_msg'): radar_interface._update([radar_interface.trigger_msg]) if __name__ == "__main__": diff --git a/selfdrive/car/tests/test_fw_fingerprint.py b/selfdrive/car/tests/test_fw_fingerprint.py index ff07f9fd7d..a9050e2373 100755 --- a/selfdrive/car/tests/test_fw_fingerprint.py +++ b/selfdrive/car/tests/test_fw_fingerprint.py @@ -1,18 +1,24 @@ #!/usr/bin/env python3 +import random import unittest +from itertools import product +from parameterized import parameterized + from cereal import car +from selfdrive.car.fingerprints import FW_VERSIONS from selfdrive.car.fw_versions import match_fw_to_car from selfdrive.car.toyota.values import CAR as TOYOTA CarFw = car.CarParams.CarFw Ecu = car.CarParams.Ecu +ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()} class TestFwFingerprint(unittest.TestCase): def assertFingerprints(self, candidates, expected): candidates = list(candidates) self.assertEqual(len(candidates), 1) - self.assertEqual(candidates[0], TOYOTA.RAV4_TSS2) + self.assertEqual(candidates[0], expected) def test_rav4_tss2(self): CP = car.CarParams.new_message() @@ -41,6 +47,45 @@ class TestFwFingerprint(unittest.TestCase): self.assertFingerprints(match_fw_to_car(CP.carFw), TOYOTA.RAV4_TSS2) + @parameterized.expand([(k, v) for k, v in FW_VERSIONS.items()]) + def test_fw_fingerprint_all(self, car_model, ecus): + # TODO: this is too slow, so don't run for now + return + + ecu_fw_lists = [] # pylint: disable=W0101 + for ecu, fw_versions in ecus.items(): + ecu_name, addr, sub_addr = ecu + ecu_fw_lists.append([]) + for fw in fw_versions: + ecu_fw_lists[-1].append({"ecu": ecu_name, "fwVersion": fw, "address": addr, + "subAddress": 0 if sub_addr is None else sub_addr}) + CP = car.CarParams.new_message() + for car_fw in product(*ecu_fw_lists): + CP.carFw = car_fw + self.assertFingerprints(match_fw_to_car(CP.carFw), car_model) + + @parameterized.expand([(k, v) for k, v in FW_VERSIONS.items()]) + def test_fw_fingerprint(self, car_model, ecus): + CP = car.CarParams.new_message() + for _ in range(20): + fw = [] + for ecu, fw_versions in ecus.items(): + ecu_name, addr, sub_addr = ecu + fw.append({"ecu": ecu_name, "fwVersion": random.choice(fw_versions), + "address": addr, "subAddress": 0 if sub_addr is None else sub_addr}) + CP.carFw = fw + self.assertFingerprints(match_fw_to_car(CP.carFw), car_model) + + def test_no_duplicate_fw_versions(self): + passed = True + for car_model, ecus in FW_VERSIONS.items(): + for ecu, ecu_fw in ecus.items(): + duplicates = set([fw for fw in ecu_fw if ecu_fw.count(fw) > 1]) + if len(duplicates): + print(car_model, ECU_NAME[ecu[0]], duplicates) + passed = False + + self.assertTrue(passed, "Duplicate FW versions found") if __name__ == "__main__": unittest.main() diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index 0346801c0d..96e25013ea 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -12,7 +12,7 @@ VisualAlert = car.CarControl.HUDControl.VisualAlert # Accel limits ACCEL_HYST_GAP = 0.02 # don't change accel command for small oscilalitons within this value ACCEL_MAX = 1.5 # 1.5 m/s2 -ACCEL_MIN = -3.0 # 3 m/s2 +ACCEL_MIN = -3.0 # 3 m/s2 ACCEL_SCALE = max(ACCEL_MAX, -ACCEL_MIN) def accel_hysteresis(accel, accel_steady, enabled): @@ -42,8 +42,10 @@ class CarController(): self.steer_rate_limited = False self.fake_ecus = set() - if CP.enableCamera: self.fake_ecus.add(Ecu.fwdCamera) - if CP.enableDsu: self.fake_ecus.add(Ecu.dsu) + if CP.enableCamera: + self.fake_ecus.add(Ecu.fwdCamera) + if CP.enableDsu: + self.fake_ecus.add(Ecu.dsu) self.packer = CANPacker(dbc_name) diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py index c9970beadb..4cf84904e7 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -90,6 +90,8 @@ class CarState(CarStateBase): else: ret.cruiseState.standstill = self.pcm_acc_status == 7 ret.cruiseState.enabled = bool(cp.vl["PCM_CRUISE"]['CRUISE_ACTIVE']) + # TODO: CRUISE_STATE is a 4 bit signal, find any other non-adaptive cruise states + ret.cruiseState.nonAdaptive = cp.vl["PCM_CRUISE"]['CRUISE_STATE'] in [5] if self.CP.carFingerprint == CAR.PRIUS: ret.genericToggle = cp.vl["AUTOPARK_STATUS"]['STATE'] != 0 @@ -102,8 +104,8 @@ class CarState(CarStateBase): self.steer_state = cp.vl["EPS_STATUS"]['LKA_STATE'] if self.CP.carFingerprint in TSS2_CAR: - ret.leftBlindspot = cp.vl["BSM"]['L_ADJACENT'] == 1 - ret.rightBlindspot = cp.vl["BSM"]['R_ADJACENT'] == 1 + ret.leftBlindspot = (cp.vl["BSM"]['L_ADJACENT'] == 1) or (cp.vl["BSM"]['L_APPROACHING'] == 1) + ret.rightBlindspot = (cp.vl["BSM"]['R_ADJACENT'] == 1) or (cp.vl["BSM"]['R_APPROACHING'] == 1) return ret @@ -160,7 +162,6 @@ class CarState(CarStateBase): signals.append(("LOW_SPEED_LOCKOUT", "PCM_CRUISE_2", 0)) checks.append(("PCM_CRUISE_2", 33)) - if CP.carFingerprint == CAR.PRIUS: signals += [("STATE", "AUTOPARK_STATUS", 0)] @@ -172,16 +173,23 @@ class CarState(CarStateBase): if CP.carFingerprint in TSS2_CAR: signals += [("L_ADJACENT", "BSM", 0)] + signals += [("L_APPROACHING", "BSM", 0)] signals += [("R_ADJACENT", "BSM", 0)] + signals += [("R_APPROACHING", "BSM", 0)] return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0) @staticmethod def get_cam_can_parser(CP): - signals = [("FORCE", "PRE_COLLISION", 0), ("PRECOLLISION_ACTIVE", "PRE_COLLISION", 0)] + signals = [ + ("FORCE", "PRE_COLLISION", 0), + ("PRECOLLISION_ACTIVE", "PRE_COLLISION", 0) + ] # use steering message to check if panda is connected to frc - checks = [("STEERING_LKA", 42)] + checks = [ + ("STEERING_LKA", 42) + ] return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2) diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 84fe1b8b3a..e31eaee4ff 100755 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -14,7 +14,7 @@ class CarInterface(CarInterfaceBase): return float(accel) / 3.0 @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): # pylint: disable=dangerous-default-value ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay) ret.carName = "toyota" @@ -23,7 +23,7 @@ class CarInterface(CarInterfaceBase): ret.steerActuatorDelay = 0.12 # Default delay, Prius has larger delay ret.steerLimitTimer = 0.4 - if candidate not in [CAR.PRIUS, CAR.RAV4, CAR.RAV4H]: # These cars use LQR/INDI + if candidate not in [CAR.PRIUS, CAR.RAV4, CAR.RAV4H]: # These cars use LQR/INDI ret.lateralTuning.init('pid') ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] @@ -101,6 +101,16 @@ class CarInterface(CarInterfaceBase): ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.1]] ret.lateralTuning.pid.kf = 0.00007818594 + elif candidate == CAR.LEXUS_RXH_TSS2: + stop_and_go = True + ret.safetyParam = 73 + ret.wheelbase = 2.79 + ret.steerRatio = 16.0 # 14.8 is spec end-to-end + tire_stiffness_factor = 0.444 # not optimized yet + ret.mass = 4481.0 * CV.LB_TO_KG + STD_CARGO_KG # mean between min and max + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.15]] + ret.lateralTuning.pid.kf = 0.00007818594 + elif candidate in [CAR.CHR, CAR.CHRH]: stop_and_go = True ret.safetyParam = 73 @@ -117,7 +127,7 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.82448 ret.steerRatio = 13.7 tire_stiffness_factor = 0.7933 - ret.mass = 3400. * CV.LB_TO_KG + STD_CARGO_KG #mean between normal and hybrid + ret.mass = 3400. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.1]] ret.lateralTuning.pid.kf = 0.00006 @@ -137,7 +147,7 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.78 ret.steerRatio = 16.0 tire_stiffness_factor = 0.8 - ret.mass = 4607. * CV.LB_TO_KG + STD_CARGO_KG #mean between normal and hybrid limited + ret.mass = 4607. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid limited ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.18], [0.015]] # community tuning ret.lateralTuning.pid.kf = 0.00012 # community tuning @@ -145,7 +155,7 @@ class CarInterface(CarInterfaceBase): stop_and_go = False ret.safetyParam = 73 ret.wheelbase = 2.82 - ret.steerRatio = 14.8 #Found at https://pressroom.toyota.com/releases/2016+avalon+product+specs.download + ret.steerRatio = 14.8 # Found at https://pressroom.toyota.com/releases/2016+avalon+product+specs.download tire_stiffness_factor = 0.7983 ret.mass = 3505. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.17], [0.03]] @@ -161,6 +171,12 @@ class CarInterface(CarInterfaceBase): ret.mass = 3370. * CV.LB_TO_KG + STD_CARGO_KG ret.lateralTuning.pid.kf = 0.00004 + for fw in car_fw: + if fw.ecu == "eps" and fw.fwVersion == b"8965B42170\x00\x00\x00\x00\x00\x00": + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.1]] + ret.lateralTuning.pid.kf = 0.00007818594 + break + elif candidate == CAR.RAV4H_TSS2: stop_and_go = True ret.safetyParam = 73 @@ -171,6 +187,12 @@ class CarInterface(CarInterfaceBase): ret.mass = 3800. * CV.LB_TO_KG + STD_CARGO_KG ret.lateralTuning.pid.kf = 0.00004 + for fw in car_fw: + if fw.ecu == "eps" and fw.fwVersion == b"8965B42170\x00\x00\x00\x00\x00\x00": + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.1]] + ret.lateralTuning.pid.kf = 0.00007818594 + break + elif candidate in [CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2]: stop_and_go = True ret.safetyParam = 73 @@ -185,7 +207,7 @@ class CarInterface(CarInterfaceBase): stop_and_go = True ret.safetyParam = 73 ret.wheelbase = 2.8702 - ret.steerRatio = 16.0 # not optimized + ret.steerRatio = 16.0 # not optimized tire_stiffness_factor = 0.444 # not optimized yet ret.mass = 3704. * CV.LB_TO_KG + STD_CARGO_KG ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.1]] @@ -226,7 +248,7 @@ class CarInterface(CarInterfaceBase): ret.safetyParam = 73 ret.wheelbase = 2.66 ret.steerRatio = 14.7 - tire_stiffness_factor = 0.444 # not optimized yet + tire_stiffness_factor = 0.444 # not optimized yet ret.mass = 4070 * CV.LB_TO_KG + STD_CARGO_KG ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.1]] ret.lateralTuning.pid.kf = 0.00006 @@ -291,7 +313,6 @@ class CarInterface(CarInterfaceBase): ret.canValid = self.cp.can_valid and self.cp_cam.can_valid ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False - ret.buttonEvents = [] # events events = self.create_common_events(ret) @@ -301,7 +322,7 @@ class CarInterface(CarInterfaceBase): if self.CS.low_speed_lockout and self.CP.openpilotLongitudinalControl: events.add(EventName.lowSpeedLockout) if ret.vEgo < self.CP.minEnableSpeed and self.CP.openpilotLongitudinalControl: - events.add(EventName.speedTooLow) + events.add(EventName.belowEngageSpeed) if c.actuators.gas > 0.1: # some margin on the actuator to not false trigger cancellation while stopping events.add(EventName.speedTooLow) diff --git a/selfdrive/car/toyota/radar_interface.py b/selfdrive/car/toyota/radar_interface.py index 12387d489f..a7d2ec37bb 100755 --- a/selfdrive/car/toyota/radar_interface.py +++ b/selfdrive/car/toyota/radar_interface.py @@ -1,14 +1,10 @@ #!/usr/bin/env python3 -import os -import time from opendbc.can.parser import CANParser from cereal import car from selfdrive.car.toyota.values import NO_DSU_CAR, DBC, TSS2_CAR from selfdrive.car.interfaces import RadarInterfaceBase def _create_radar_can_parser(car_fingerprint): - dbc_f = DBC[car_fingerprint]['radar'] - if car_fingerprint in TSS2_CAR: RADAR_A_MSGS = list(range(0x180, 0x190)) RADAR_B_MSGS = list(range(0x190, 0x1a0)) @@ -26,7 +22,7 @@ def _create_radar_can_parser(car_fingerprint): checks = list(zip(RADAR_A_MSGS + RADAR_B_MSGS, [20]*(msg_a_n + msg_b_n))) - return CANParser(os.path.splitext(dbc_f)[0], signals, checks, 1) + return CANParser(DBC[car_fingerprint]['radar'], signals, checks, 1) class RadarInterface(RadarInterfaceBase): def __init__(self, CP): @@ -53,8 +49,7 @@ class RadarInterface(RadarInterfaceBase): def update(self, can_strings): if self.no_radar: - time.sleep(self.radar_ts) - return car.RadarData.new_message() + return super().update(None) vls = self.rcp.update_strings(can_strings) self.updated_messages.update(vls) @@ -62,7 +57,7 @@ class RadarInterface(RadarInterfaceBase): if self.trigger_msg not in self.updated_messages: return None - rr = self._update(self.updated_messages) + rr = self._update(self.updated_messages) self.updated_messages.clear() return rr @@ -78,12 +73,12 @@ class RadarInterface(RadarInterfaceBase): if ii in self.RADAR_A_MSGS: cpt = self.rcp.vl[ii] - if cpt['LONG_DIST'] >=255 or cpt['NEW_TRACK']: + if cpt['LONG_DIST'] >= 255 or cpt['NEW_TRACK']: self.valid_cnt[ii] = 0 # reset counter if cpt['VALID'] and cpt['LONG_DIST'] < 255: self.valid_cnt[ii] += 1 else: - self.valid_cnt[ii] = max(self.valid_cnt[ii] -1, 0) + self.valid_cnt[ii] = max(self.valid_cnt[ii] - 1, 0) score = self.rcp.vl[ii+16]['SCORE'] # print ii, self.valid_cnt[ii], score, cpt['VALID'], cpt['LONG_DIST'], cpt['LAT_DIST'] diff --git a/selfdrive/car/toyota/toyotacan.py b/selfdrive/car/toyota/toyotacan.py index bdd84e7128..93176b359c 100644 --- a/selfdrive/car/toyota/toyotacan.py +++ b/selfdrive/car/toyota/toyotacan.py @@ -36,7 +36,7 @@ def create_accel_command(packer, accel, pcm_cancel, standstill_req, lead): "DISTANCE": 0, "MINI_CAR": lead, "SET_ME_X3": 3, - "SET_ME_1": 1, + "PERMIT_BRAKING": 1, "RELEASE_STANDSTILL": not standstill_req, "CANCEL_REQ": pcm_cancel, } diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index d5d759ca37..f6d0c184f2 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -1,3 +1,5 @@ +# flake8: noqa + from selfdrive.car import dbc_dict from cereal import car Ecu = car.CarParams.Ecu @@ -17,6 +19,7 @@ class CAR: LEXUS_RX = "LEXUS RX 350 2016" LEXUS_RXH = "LEXUS RX HYBRID 2017" LEXUS_RX_TSS2 = "LEXUS RX350 2020" + LEXUS_RXH_TSS2 = "LEXUS RX450 HYBRID 2020" CHR = "TOYOTA C-HR 2018" CHRH = "TOYOTA C-HR HYBRID 2018" CAMRY = "TOYOTA CAMRY 2018" @@ -68,188 +71,193 @@ ECU_FINGERPRINT = { FINGERPRINTS = { CAR.RAV4: [{ - 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 512: 6, 513: 6, 547: 8, 548: 8, 552: 4, 562: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 767:4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 918: 7, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 4, 956: 8, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1008: 2, 1014: 8, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1596: 8, 1597: 8, 1600: 8, 1656: 8, 1664: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2015: 8, 2024: 8 + 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 512: 6, 513: 6, 547: 8, 548: 8, 552: 4, 562: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 767: 4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 918: 7, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 4, 956: 8, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1008: 2, 1014: 8, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1596: 8, 1597: 8, 1600: 8, 1656: 8, 1664: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2015: 8, 2024: 8 }], CAR.RAV4H: [{ - 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 296: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 547: 8, 548: 8, 550: 8, 552: 4, 560: 7, 562: 4, 581: 5, 608: 8, 610: 5, 643: 7, 705: 8, 713: 8, 725: 2, 740: 5, 767:4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 918: 7, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 3, 955: 8, 956: 8, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1008: 2, 1014: 8, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1184: 8, 1185: 8, 1186: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1212: 8, 1227: 8, 1228: 8, 1232: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1596: 8, 1597: 8, 1600: 8, 1656: 8, 1664: 8, 1728: 8, 1745: 8, 1779: 8, 1872: 8, 1880: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 296: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 547: 8, 548: 8, 550: 8, 552: 4, 560: 7, 562: 4, 581: 5, 608: 8, 610: 5, 643: 7, 705: 8, 713: 8, 725: 2, 740: 5, 767: 4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 918: 7, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 3, 955: 8, 956: 8, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1008: 2, 1014: 8, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1184: 8, 1185: 8, 1186: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1212: 8, 1227: 8, 1228: 8, 1232: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1596: 8, 1597: 8, 1600: 8, 1656: 8, 1664: 8, 1728: 8, 1745: 8, 1779: 8, 1872: 8, 1880: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }, # Chinese RAV4 { - 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 355: 5, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 512: 6, 513: 6, 547: 8, 548: 8, 552: 4, 562: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 742: 8, 743: 8, 767:4, 800: 8, 830: 7, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 921: 8, 922: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1008: 2, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1207: 8, 1227: 8, 1235: 8, 1263: 8, 1279: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1596: 8, 1597: 8, 1600: 8, 1664: 8, 1728: 8, 1745: 8, 1779: 8 + 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 355: 5, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 512: 6, 513: 6, 547: 8, 548: 8, 552: 4, 562: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 742: 8, 743: 8, 767: 4, 800: 8, 830: 7, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 921: 8, 922: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1008: 2, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1207: 8, 1227: 8, 1235: 8, 1263: 8, 1279: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1596: 8, 1597: 8, 1600: 8, 1664: 8, 1728: 8, 1745: 8, 1779: 8 }], CAR.PRIUS: [{ - 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 512: 6, 513: 6, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 614: 8, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 767:4, 800: 8, 810: 2, 814: 8, 824: 2, 829: 2, 830: 7, 835: 8, 836: 8, 845: 5, 863: 8, 869: 7, 870: 7, 871: 2,898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 974: 8, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1083: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1175: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1595: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 512: 6, 513: 6, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 614: 8, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 767: 4, 800: 8, 810: 2, 814: 8, 824: 2, 829: 2, 830: 7, 835: 8, 836: 8, 845: 5, 863: 8, 869: 7, 870: 7, 871: 2, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 974: 8, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1083: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1175: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1595: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }, #2019 LE { - 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 614: 8, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 767:4, 800: 8, 810: 2, 814: 8, 829: 2, 830: 7, 835: 8, 836: 8, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1083: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1175: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1595: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 614: 8, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 767: 4, 800: 8, 810: 2, 814: 8, 829: 2, 830: 7, 835: 8, 836: 8, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1083: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1175: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1595: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }, # 2020 Prius Prime LE { - 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 713: 8, 740: 5, 742: 8, 743: 8, 764: 8, 767:4, 800: 8, 810: 2, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 974: 8, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1235: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1595: 8, 1649: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 713: 8, 740: 5, 742: 8, 743: 8, 764: 8, 767: 4, 800: 8, 810: 2, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 974: 8, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1235: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1595: 8, 1649: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }, #2020 Prius Prime Limited { - 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 614: 8, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 767:4, 800: 8, 810: 2, 814: 8, 824: 2, 829: 2, 830: 7, 835: 8, 836: 8, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 974: 8, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1083: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1175: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1595: 8, 1649: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2015: 8, 2024: 8, 2026: 8, 2027: 8, 2029: 8, 2030: 8, 2031: 8 + 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 614: 8, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 767: 4, 800: 8, 810: 2, 814: 8, 824: 2, 829: 2, 830: 7, 835: 8, 836: 8, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 974: 8, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1083: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1175: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1595: 8, 1649: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2015: 8, 2024: 8, 2026: 8, 2027: 8, 2029: 8, 2030: 8, 2031: 8 }, #2020 Central Europe Prime { - 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 713: 8, 740: 5, 742: 8, 743: 8, 764: 8, 767:4, 800: 8, 810: 2, 818: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 845: 5, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 889: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 8, 974: 8, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1595: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8 + 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 713: 8, 740: 5, 742: 8, 743: 8, 764: 8, 767: 4, 800: 8, 810: 2, 818: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 845: 5, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 889: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 8, 974: 8, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1595: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8 }, #2017 German Prius { - 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296:8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 614: 8, 643: 7, 658: 8, 713: 8,740: 5, 742: 8, 743: 8, 767:4, 800: 8, 810: 2, 814: 8, 829: 2, 830: 7, 835: 8, 836: 8, 845: 5, 863: 8, 869: 7, 870: 7, 871: 2, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1077: 8, 1082: 8, 1083: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1175: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1595: 8, 1777: 8, 1779: 8, 1792: 8, 1767:4, 1863:8, 1904: 8, 1912: 8, 1984: 8, 1988: 8, 1990: 8, 1992: 8, 1996:8, 1998: 8, 2002: 8, 2010: 8, 2015: 8, 2016: 8, 2018: 8, 2024: 8, 2026: 8, 2030: 8 + 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 614: 8, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 767: 4, 800: 8, 810: 2, 814: 8, 829: 2, 830: 7, 835: 8, 836: 8, 845: 5, 863: 8, 869: 7, 870: 7, 871: 2, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1077: 8, 1082: 8, 1083: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1175: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1595: 8, 1777: 8, 1779: 8, 1792: 8, 1767: 4, 1863: 8, 1904: 8, 1912: 8, 1984: 8, 1988: 8, 1990: 8, 1992: 8, 1996: 8, 1998: 8, 2002: 8, 2010: 8, 2015: 8, 2016: 8, 2018: 8, 2024: 8, 2026: 8, 2030: 8 }], #Corolla w/ added Pedal Support (512L and 513L) CAR.COROLLA: [{ - 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 512: 6, 513: 6, 547: 8, 548: 8, 552: 4, 608: 8, 610: 5, 643: 7, 705: 8, 740: 5, 767:4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 2, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 4, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1196: 8, 1227: 8, 1235: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1596: 8, 1597: 8, 1600: 8, 1664: 8, 1728: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2016: 8, 2017: 8, 2018: 8, 2019: 8, 2020: 8, 2021: 8, 2022: 8, 2023: 8, 2024: 8 + 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 512: 6, 513: 6, 547: 8, 548: 8, 552: 4, 608: 8, 610: 5, 643: 7, 705: 8, 740: 5, 767: 4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 2, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 4, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1196: 8, 1227: 8, 1235: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1596: 8, 1597: 8, 1600: 8, 1664: 8, 1728: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2016: 8, 2017: 8, 2018: 8, 2019: 8, 2020: 8, 2021: 8, 2022: 8, 2023: 8, 2024: 8 }], CAR.LEXUS_RX: [{ # 2016 Lexus RX 350 - 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 5, 643: 7, 705: 8, 740: 5, 742: 8, 743: 8, 767:4, 800: 8, 810: 2, 812: 3, 818: 8, 819: 8, 820: 8, 821: 8, 822: 8, 830: 7, 835: 8, 836: 8, 845: 5, 869: 7, 870: 7, 871: 2, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1077: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1349: 8, 1350: 8, 1351: 8, 1413: 8, 1414: 8, 1415: 8, 1416: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1595: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2015: 8, 2016: 8, 2024: 8 + 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 5, 643: 7, 705: 8, 740: 5, 742: 8, 743: 8, 767: 4, 800: 8, 810: 2, 812: 3, 818: 8, 819: 8, 820: 8, 821: 8, 822: 8, 830: 7, 835: 8, 836: 8, 845: 5, 869: 7, 870: 7, 871: 2, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1077: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1349: 8, 1350: 8, 1351: 8, 1413: 8, 1414: 8, 1415: 8, 1416: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1595: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2015: 8, 2016: 8, 2024: 8 }, # 2017 Lexus RX 350 { - 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 5, 643: 7, 658: 8, 705: 8, 740: 5, 742: 8, 743: 8, 767:4, 800: 8, 810: 2, 812: 3, 814: 8, 818: 8, 819: 8, 820: 8, 821: 8, 822: 8, 830: 7, 835: 8, 836: 8, 869: 7, 870: 7, 871: 2, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1349: 8, 1350: 8, 1351: 8, 1413: 8, 1414: 8, 1415: 8, 1416: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1595: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 5, 643: 7, 658: 8, 705: 8, 740: 5, 742: 8, 743: 8, 767: 4, 800: 8, 810: 2, 812: 3, 814: 8, 818: 8, 819: 8, 820: 8, 821: 8, 822: 8, 830: 7, 835: 8, 836: 8, 869: 7, 870: 7, 871: 2, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1349: 8, 1350: 8, 1351: 8, 1413: 8, 1414: 8, 1415: 8, 1416: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1595: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }], CAR.LEXUS_RXH: [{ - 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 512: 6, 513:6, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 5, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 767:4, 800: 8, 810: 2, 812: 3, 814: 8, 830: 7, 835: 8, 836: 8, 845: 5, 863: 8, 869: 7, 870: 7, 871: 2, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 6, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1071: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1595: 8, 1777: 8, 1779: 8, 1808: 8, 1810: 8, 1816: 8, 1818: 8, 1840: 8, 1848: 8, 1904: 8, 1912: 8, 1940: 8, 1941: 8, 1948: 8, 1949: 8, 1952: 8, 1956: 8, 1960: 8, 1964: 8, 1986: 8, 1990: 8, 1994: 8, 1998: 8, 2004: 8, 2012: 8 + 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 512: 6, 513: 6, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 5, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 767: 4, 800: 8, 810: 2, 812: 3, 814: 8, 830: 7, 835: 8, 836: 8, 845: 5, 863: 8, 869: 7, 870: 7, 871: 2, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 6, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1071: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1595: 8, 1777: 8, 1779: 8, 1808: 8, 1810: 8, 1816: 8, 1818: 8, 1840: 8, 1848: 8, 1904: 8, 1912: 8, 1940: 8, 1941: 8, 1948: 8, 1949: 8, 1952: 8, 1956: 8, 1960: 8, 1964: 8, 1986: 8, 1990: 8, 1994: 8, 1998: 8, 2004: 8, 2012: 8 }, # RX450HL # TODO: get proper fingerprint in stock mode { - 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 512: 6, 513: 6, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 5, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 767:4, 800: 8, 810: 2, 812: 3, 814: 8, 830: 7, 835: 8, 836: 8, 863: 8, 865: 8, 869: 7, 870: 7, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 6, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1056: 8, 1057: 8, 1059: 1, 1063: 8, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1228: 8, 1237: 8, 1264: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 512: 6, 513: 6, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 5, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 767: 4, 800: 8, 810: 2, 812: 3, 814: 8, 830: 7, 835: 8, 836: 8, 863: 8, 865: 8, 869: 7, 870: 7, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 6, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1056: 8, 1057: 8, 1059: 1, 1063: 8, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1228: 8, 1237: 8, 1264: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }, # RX540H 2019 with color hud { - 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 512: 6, 513: 6, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 5, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 767:4, 800: 8, 810: 2, 812: 3, 814: 8, 818: 8, 819: 8, 820: 8, 821: 8, 822: 8, 830: 7, 835: 8, 836: 8, 845: 5, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 6, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1063: 8, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1349: 8, 1350: 8, 1351: 8, 1413: 8, 1414: 8, 1415: 8, 1416: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1777: 8, 1779: 8, 1808: 8, 1810: 8, 1816: 8, 1818: 8, 1904: 8, 1912: 8, 1952: 8, 1960: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 512: 6, 513: 6, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 5, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 767: 4, 800: 8, 810: 2, 812: 3, 814: 8, 818: 8, 819: 8, 820: 8, 821: 8, 822: 8, 830: 7, 835: 8, 836: 8, 845: 5, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 6, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1063: 8, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1349: 8, 1350: 8, 1351: 8, 1413: 8, 1414: 8, 1415: 8, 1416: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1777: 8, 1779: 8, 1808: 8, 1810: 8, 1816: 8, 1818: 8, 1904: 8, 1912: 8, 1952: 8, 1960: 8, 1990: 8, 1998: 8 }, # 2017 RX 450h { - 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 5, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 744: 8, 767:4, 800: 8, 810: 2, 812: 3, 814: 8, 818: 8, 819: 8, 820: 8, 821: 8, 822: 8, 830: 7, 835: 8, 836: 8, 845: 5, 863: 8, 869: 7, 870: 7, 871: 2, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 6, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1071: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1349: 8, 1350: 8, 1351: 8, 1413: 8, 1414: 8, 1415: 8, 1416: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1595: 8, 1745: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2015: 8, 2016: 8, 2024: 8 + 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 5, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 744: 8, 767: 4, 800: 8, 810: 2, 812: 3, 814: 8, 818: 8, 819: 8, 820: 8, 821: 8, 822: 8, 830: 7, 835: 8, 836: 8, 845: 5, 863: 8, 869: 7, 870: 7, 871: 2, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 6, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1071: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1349: 8, 1350: 8, 1351: 8, 1413: 8, 1414: 8, 1415: 8, 1416: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1595: 8, 1745: 8, 1777: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2015: 8, 2016: 8, 2024: 8 }], CAR.LEXUS_RX_TSS2: [ # 2020 Lexus RX 350 { - 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 658: 8, 705: 8, 740: 5, 742: 8, 743: 8, 764: 8, 765: 8, 767:4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 824: 8, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 891: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 987: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1076: 8, 1077: 8,1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1592: 8, 1594:8, 1595: 8, 1600: 8, 1649: 8, 1775: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1808: 8, 1816: 8, 1872: 8, 1880: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2015: 8, 2016: 8, 2024: 8 + 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 658: 8, 705: 8, 740: 5, 742: 8, 743: 8, 764: 8, 765: 8, 767: 4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 824: 8, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 891: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 987: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1592: 8, 1594: 8, 1595: 8, 1600: 8, 1649: 8, 1775: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1808: 8, 1816: 8, 1872: 8, 1880: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2015: 8, 2016: 8, 2024: 8 + }], + CAR.LEXUS_RXH_TSS2: [ + # 2020 Lexus RX 450h + { + 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 401: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 744: 8, 764: 8, 765: 8, 800: 8, 810: 2, 812: 3, 814: 8, 818: 8, 822: 8, 824: 8, 830: 7, 835: 8, 836: 8, 845: 5, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 889: 8, 891: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 942: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 6, 987: 8, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1063: 8, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1592: 8, 1594: 8, 1595: 8, 1600: 8, 1649: 8, 1775: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1792: 8, 1808: 8, 1809: 8, 1810: 8, 1816: 8, 1818: 8, 1840: 8, 1848: 8, 1872: 8, 1880: 8, 1904: 8, 1912: 8, 1937: 8, 1940: 8, 1941: 8, 1945: 8, 1948: 8, 1949: 8, 1952: 8, 1953: 8, 1956: 8, 1960: 8, 1961: 8, 1968: 8, 1976: 8, 1986: 8, 1990: 8, 1994: 8, 1998: 8, 2004: 8, 2012: 8, 2015: 8, 2016: 8, 2024: 8 }], CAR.CHR: [{ - 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 614: 8, 643: 7, 658: 8, 705: 8, 740: 5, 767:4, 800: 8, 810: 2, 812: 8, 814: 8, 830: 7, 835: 8, 836: 8, 845: 5, 869: 7, 870: 7, 871: 2, 898: 8, 913: 8, 918: 8, 921: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 1014: 8, 1017: 8, 1020: 8, 1021: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1082: 8, 1083: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1175: 8, 1228: 8, 1235: 8, 1237: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1595: 8, 1745: 8, 1779: 8 + 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 614: 8, 643: 7, 658: 8, 705: 8, 740: 5, 767: 4, 800: 8, 810: 2, 812: 8, 814: 8, 830: 7, 835: 8, 836: 8, 845: 5, 869: 7, 870: 7, 871: 2, 898: 8, 913: 8, 918: 8, 921: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 1014: 8, 1017: 8, 1020: 8, 1021: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1082: 8, 1083: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1175: 8, 1228: 8, 1235: 8, 1237: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1595: 8, 1745: 8, 1779: 8 }], CAR.CHRH: [{ - 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 614: 8, 643: 7, 658: 8, 713: 8, 740: 5, 767:4, 800: 8, 810: 2, 812: 8, 814: 8, 829: 2, 830: 7, 835: 8, 836: 8, 845: 5, 869: 7, 870: 7, 871: 2, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1021: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1083: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1175: 8, 1228: 8, 1235: 8, 1237: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1595: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 614: 8, 643: 7, 658: 8, 713: 8, 740: 5, 767: 4, 800: 8, 810: 2, 812: 8, 814: 8, 829: 2, 830: 7, 835: 8, 836: 8, 845: 5, 869: 7, 870: 7, 871: 2, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1021: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1083: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1175: 8, 1228: 8, 1235: 8, 1237: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1595: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }], CAR.CAMRY: [ #XLE and LE { - 36: 8, 37: 8, 119: 6, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 658: 8, 705: 8, 728: 8, 740: 5, 761: 8, 764: 8, 767:4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 822: 8, 824: 8, 830: 7, 835: 8, 836: 8, 869: 7, 870: 7, 871: 2, 888: 8, 889: 8, 891: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 983: 8, 984: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1011: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1412: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1595: 8, 1745: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1808: 8, 1816: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 119: 6, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 658: 8, 705: 8, 728: 8, 740: 5, 761: 8, 764: 8, 767: 4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 822: 8, 824: 8, 830: 7, 835: 8, 836: 8, 869: 7, 870: 7, 871: 2, 888: 8, 889: 8, 891: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 983: 8, 984: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1011: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1412: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1595: 8, 1745: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1808: 8, 1816: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }, #XSE and SE # TODO: get proper fingerprint in stock mode { - 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 658: 8, 705: 8, 728: 8, 740: 5, 761: 8, 764: 8, 767:4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 822: 8, 824: 8, 830: 7, 835: 8, 836: 8, 869: 7, 870: 7, 888: 8, 889: 8, 891: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 983: 8, 984: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1011: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1228: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1412: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1595: 8, 1745: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1808: 8, 1816: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 658: 8, 705: 8, 728: 8, 740: 5, 761: 8, 764: 8, 767: 4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 822: 8, 824: 8, 830: 7, 835: 8, 836: 8, 869: 7, 870: 7, 888: 8, 889: 8, 891: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 983: 8, 984: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1011: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1228: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1412: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1595: 8, 1745: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1808: 8, 1816: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }, { # 2019 XSE - 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 658: 8, 705: 8, 728: 8, 740: 5, 761: 8, 764: 8, 767:4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 822: 8, 824: 8, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 888: 8, 889: 8, 891: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 942: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 983: 8, 984: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1011: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1412: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1745: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1792: 8, 1767:4, 1808: 8, 1816: 8, 1872: 8, 1880: 8, 1904: 8, 1912: 8, 1937: 8, 1945: 8, 1953: 8, 1961: 8, 1968: 8, 1976: 8, 1990: 8, 1998: 8, 2015: 8, 2016: 8, 2024: 8 + 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 658: 8, 705: 8, 728: 8, 740: 5, 761: 8, 764: 8, 767: 4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 822: 8, 824: 8, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 888: 8, 889: 8, 891: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 942: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 983: 8, 984: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1011: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1412: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1745: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1792: 8, 1767: 4, 1808: 8, 1816: 8, 1872: 8, 1880: 8, 1904: 8, 1912: 8, 1937: 8, 1945: 8, 1953: 8, 1961: 8, 1968: 8, 1976: 8, 1990: 8, 1998: 8, 2015: 8, 2016: 8, 2024: 8 }], CAR.CAMRYH: [ #SE, LE and LE with Blindspot Monitor { - 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 713: 8, 728: 8, 740: 5, 761: 8, 764: 8, 767:4, 800: 8, 810: 2, 812: 8, 818: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 889: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 983: 8, 984: 8, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1011: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1745: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1808: 8, 1810: 8, 1816: 8, 1818: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 713: 8, 728: 8, 740: 5, 761: 8, 764: 8, 767: 4, 800: 8, 810: 2, 812: 8, 818: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 889: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 983: 8, 984: 8, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1011: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1745: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1808: 8, 1810: 8, 1816: 8, 1818: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }, #SL { - 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 713: 8, 728: 8, 740: 5, 761: 8, 764: 8, 767:4, 800: 8, 810: 2, 812: 8, 818: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 869: 7, 870: 7, 871: 2, 888: 8, 889: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1595: 8, 1745: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 713: 8, 728: 8, 740: 5, 761: 8, 764: 8, 767: 4, 800: 8, 810: 2, 812: 8, 818: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 869: 7, 870: 7, 871: 2, 888: 8, 889: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1595: 8, 1745: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }, #XLE { - 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 658: 8, 713: 8, 728: 8, 740: 5, 761: 8, 764: 8, 767:4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 869: 7, 870: 7, 871: 2, 888: 8, 889: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 983: 8, 984: 8, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1011: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1595: 8, 1745: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 658: 8, 713: 8, 728: 8, 740: 5, 761: 8, 764: 8, 767: 4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 869: 7, 870: 7, 871: 2, 888: 8, 889: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 983: 8, 984: 8, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1011: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1595: 8, 1745: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }], CAR.HIGHLANDER: [{ - 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 238: 4, 355: 5, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 545: 5, 550: 8, 552: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 767:4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 921: 8, 922: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1008: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1207: 8, 1212: 8, 1227: 8, 1235: 8, 1237: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1666: 8, 1667: 8, 1728: 8, 1745: 8, 1779: 8, 1872: 8, 1880: 8, 1904: 8, 1912: 8, 1984: 8, 1988: 8, 1992: 8, 1996: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 238: 4, 355: 5, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 545: 5, 550: 8, 552: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 767: 4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 921: 8, 922: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1008: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1207: 8, 1212: 8, 1227: 8, 1235: 8, 1237: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1666: 8, 1667: 8, 1728: 8, 1745: 8, 1779: 8, 1872: 8, 1880: 8, 1904: 8, 1912: 8, 1984: 8, 1988: 8, 1992: 8, 1996: 8, 1990: 8, 1998: 8 }, # 2019 Highlander XLE { - 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 238: 4, 355: 5, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 545: 5, 550: 8, 552: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 767:4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 921: 8, 922: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1008: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1207: 8, 1212: 8, 1227: 8, 1235: 8, 1237: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 238: 4, 355: 5, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 545: 5, 550: 8, 552: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 767: 4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 921: 8, 922: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1008: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1207: 8, 1212: 8, 1227: 8, 1235: 8, 1237: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }, # 2017 Highlander Limited { - 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 238: 4, 355: 5, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 545: 5, 550: 8, 552: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 767:4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 918: 7, 921: 8, 922: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1008: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1207: 8, 1212: 8, 1227: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 238: 4, 355: 5, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 545: 5, 550: 8, 552: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 767: 4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 918: 7, 921: 8, 922: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1008: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1207: 8, 1212: 8, 1227: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }, # 2018 Highlander Limited Platinum { - 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 238: 4, 355: 5, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 545: 5, 550: 8, 552: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 767:4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 918: 7, 921: 8, 922: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1008: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1207: 8, 1212: 8, 1227: 8, 1235: 8, 1237: 8, 1263: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1585: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1728: 8, 1745: 8, 1779: 8, 1872: 8, 1880: 8, 1904: 8, 1912: 8, 1988: 8, 1990: 8, 1996: 8, 1998: 8, 2015: 8, 2016: 8, 2024: 8 + 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 238: 4, 355: 5, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 545: 5, 550: 8, 552: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 767: 4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 918: 7, 921: 8, 922: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1008: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1207: 8, 1212: 8, 1227: 8, 1235: 8, 1237: 8, 1263: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1585: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1728: 8, 1745: 8, 1779: 8, 1872: 8, 1880: 8, 1904: 8, 1912: 8, 1988: 8, 1990: 8, 1996: 8, 1998: 8, 2015: 8, 2016: 8, 2024: 8 }], CAR.HIGHLANDER_TSS2: [{ # 2020 highlander limited - 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 355: 5, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 565: 8, 608: 8, 610: 8, 643: 7, 658: 8, 705: 8, 728: 8, 740: 5, 761: 8, 764: 8, 765: 8, 767:4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 824: 8, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 885: 8, 889: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 987: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1696: 8, 1775: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1808: 8, 1816: 8, 1904: 8, 1912: 8, 1952: 8, 1960: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 355: 5, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 565: 8, 608: 8, 610: 8, 643: 7, 658: 8, 705: 8, 728: 8, 740: 5, 761: 8, 764: 8, 765: 8, 767: 4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 824: 8, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 885: 8, 889: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 987: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1696: 8, 1775: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1808: 8, 1816: 8, 1904: 8, 1912: 8, 1952: 8, 1960: 8, 1990: 8, 1998: 8 }], CAR.HIGHLANDERH: [{ - 36: 8, 37: 8, 170: 8, 180: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 581: 5, 608: 8, 610: 5, 643: 7, 713: 8, 740: 5, 767:4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 918: 7, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 3, 955: 8, 956: 8, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1112: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1184: 8, 1185: 8, 1186: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1212: 8, 1227: 8, 1232: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1552: 8, 1553: 8, 1554: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 170: 8, 180: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 581: 5, 608: 8, 610: 5, 643: 7, 713: 8, 740: 5, 767: 4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 918: 7, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 3, 955: 8, 956: 8, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1112: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1184: 8, 1185: 8, 1186: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1212: 8, 1227: 8, 1232: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1552: 8, 1553: 8, 1554: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }, { # 2019 Highlander Hybrid Limited Platinum - 36: 8, 37: 8, 170: 8, 180: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 581: 5, 608: 8, 610: 5, 643: 7, 713: 8, 740: 5, 767:4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 918: 7, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 3, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1076: 8, 1077: 8, 1112: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1184: 8, 1185: 8, 1186: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1212: 8, 1227: 8, 1232: 8, 1235: 8, 1237: 8, 1263: 8, 1279: 8, 1552: 8, 1553: 8, 1554: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1666: 8, 1667: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 170: 8, 180: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 581: 5, 608: 8, 610: 5, 643: 7, 713: 8, 740: 5, 767: 4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 918: 7, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 3, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1076: 8, 1077: 8, 1112: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1184: 8, 1185: 8, 1186: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1212: 8, 1227: 8, 1232: 8, 1235: 8, 1237: 8, 1263: 8, 1279: 8, 1552: 8, 1553: 8, 1554: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1666: 8, 1667: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }], CAR.HIGHLANDERH_TSS2: [{ 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 401: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 658: 8, 713: 8, 728: 8, 740: 5, 761: 8, 765: 8, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 822: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 881: 8, 885: 8, 891: 8, 896: 8, 898: 8, 918: 8, 942: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 971: 7, 975: 5, 987: 8, 993: 8, 1014: 8, 1017: 8, 1020: 8, 1059: 1, 1063: 8, 1071: 8, 1082: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1228: 8, 1235: 8, 1552: 8, 1553: 8, 1556: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1696: 8, 1745: 8 }], CAR.AVALON: [{ - 36: 8, 37: 8, 170: 8, 180: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 547: 8, 550: 8, 552: 4, 562: 6, 608: 8, 610: 5, 643: 7, 705: 8, 740: 5, 767:4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 905: 8, 911: 1, 916: 2, 921: 8, 933: 6, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 1005: 2, 1014: 8, 1017: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1200: 8, 1201: 8, 1202: 8, 1203: 8, 1206: 8, 1227: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1558: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1596: 8, 1597: 8, 1664: 8, 1728: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 170: 8, 180: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 547: 8, 550: 8, 552: 4, 562: 6, 608: 8, 610: 5, 643: 7, 705: 8, 740: 5, 767: 4, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 905: 8, 911: 1, 916: 2, 921: 8, 933: 6, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 1005: 2, 1014: 8, 1017: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1200: 8, 1201: 8, 1202: 8, 1203: 8, 1206: 8, 1227: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1558: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1596: 8, 1597: 8, 1664: 8, 1728: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }], CAR.RAV4_TSS2: [ # LE { - 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 355: 5, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 565: 8, 608: 8, 610: 8, 643: 7, 705: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 764: 8, 765: 8, 767:4, 800: 8, 810: 2, 812: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 882: 8, 885: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1076: 8, 1077: 8,1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1235: 8, 1279: 8, 1541: 8, 1552: 8, 1553:8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1745: 8, 1775: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 355: 5, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 565: 8, 608: 8, 610: 8, 643: 7, 705: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 764: 8, 765: 8, 767: 4, 800: 8, 810: 2, 812: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 882: 8, 885: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1076: 8, 1077: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1235: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1745: 8, 1775: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }, # XLE, Limited, and AWD { - 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 565: 8, 608: 8, 610: 8, 643: 7, 658: 8, 705: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 764: 8, 765: 8, 767:4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 822: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 882: 8, 885: 8, 889: 8, 891: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 987: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1076: 8, 1077: 8, 1082: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1696: 8, 1745: 8, 1775: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2015: 8, 2016: 8, 2024: 8 + 36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 565: 8, 608: 8, 610: 8, 643: 7, 658: 8, 705: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 764: 8, 765: 8, 767: 4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 822: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 882: 8, 885: 8, 889: 8, 891: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 987: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1076: 8, 1077: 8, 1082: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1696: 8, 1745: 8, 1775: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2015: 8, 2016: 8, 2024: 8 }], CAR.COROLLA_TSS2: [ # hatch 2019+ and sedan 2020+ { - 36: 8, 37: 8, 114: 5, 170: 8, 180: 8, 186: 4, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 705: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 764: 8, 765: 8, 767:4, 800: 8, 810: 2, 812: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1235: 8, 1237: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1595: 8, 1649: 8, 1745: 8, 1775: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1808: 8, 1809: 8, 1816: 8, 1817: 8, 1840: 8, 1848: 8, 1904: 8, 1912: 8, 1940: 8, 1941: 8, 1948: 8, 1949: 8, 1952: 8, 1960: 8, 1981: 8, 1986: 8, 1990: 8, 1994: 8, 1998: 8, 2004: 8 + 36: 8, 37: 8, 114: 5, 170: 8, 180: 8, 186: 4, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 705: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 764: 8, 765: 8, 767: 4, 800: 8, 810: 2, 812: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1235: 8, 1237: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1595: 8, 1649: 8, 1745: 8, 1775: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1808: 8, 1809: 8, 1816: 8, 1817: 8, 1840: 8, 1848: 8, 1904: 8, 1912: 8, 1940: 8, 1941: 8, 1948: 8, 1949: 8, 1952: 8, 1960: 8, 1981: 8, 1986: 8, 1990: 8, 1994: 8, 1998: 8, 2004: 8 }], CAR.COROLLAH_TSS2: [ # 2019 Taiwan Altis Hybrid { - 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 401: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 713: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 765: 8, 767:4, 800: 8, 810: 2, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 885: 8, 896: 8, 898: 8, 918: 7, 921: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 987: 8, 993: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1082: 8, 1112: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1172: 8, 1235: 8, 1237: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1745: 8, 1775: 8, 1779: 8 + 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 401: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 713: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 765: 8, 767: 4, 800: 8, 810: 2, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 885: 8, 896: 8, 898: 8, 918: 7, 921: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 987: 8, 993: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1082: 8, 1112: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1172: 8, 1235: 8, 1237: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1745: 8, 1775: 8, 1779: 8 }, # 2019 Chinese Levin Hybrid { - 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 401: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 713: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 765: 8, 767:4, 800: 8, 810: 2, 812: 8, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 885: 8, 896: 8, 898: 8, 921: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 993: 8, 1002: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1172: 8, 1235: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1600: 8, 1649: 8, 1745: 8, 1775: 8, 1779: 8 + 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 401: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 713: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 765: 8, 767: 4, 800: 8, 810: 2, 812: 8, 829: 2, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 885: 8, 896: 8, 898: 8, 921: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 993: 8, 1002: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1172: 8, 1235: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1600: 8, 1649: 8, 1745: 8, 1775: 8, 1779: 8 } ], CAR.LEXUS_ES_TSS2: [{ - 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 658: 8, 705: 8, 728: 8, 740: 5, 761: 8, 764: 8, 765: 8, 767:4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 824: 8, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 882: 8, 885: 8, 889: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 987: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1696: 8, 1775: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, + 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 401: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 550: 8, 552: 4, 562: 6, 608: 8, 610: 8, 643: 7, 658: 8, 705: 8, 728: 8, 740: 5, 761: 8, 764: 8, 765: 8, 767: 4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 824: 8, 830: 7, 835: 8, 836: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 882: 8, 885: 8, 889: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 976: 1, 987: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1696: 8, 1775: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, }], CAR.LEXUS_ESH_TSS2: [ { - 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 401: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 658: 8, 713: 8, 728: 8, 740: 5, 742: 8, 743: 8, 744: 8, 761: 8, 764: 8, 765: 8, 767:4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 882: 8, 885: 8, 889: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 987: 8, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1228: 8, 1235: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1696: 8, 1775: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 401: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 658: 8, 713: 8, 728: 8, 740: 5, 742: 8, 743: 8, 744: 8, 761: 8, 764: 8, 765: 8, 767: 4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 882: 8, 885: 8, 889: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 987: 8, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1228: 8, 1235: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1696: 8, 1775: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }], CAR.SIENNA: [ { - 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 545: 5, 548: 8, 550: 8, 552: 4, 562: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 764: 8, 767:4, 800: 8, 824: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 888: 8, 896: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 1, 918: 7, 921: 8, 933: 8, 944: 6, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1008: 2, 1014: 8, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1114: 8, 1160: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1200: 8, 1201: 8, 1202: 8, 1203: 8, 1212: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1279: 8, 1552: 8, 1553: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1656: 8, 1664: 8, 1666: 8, 1667: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 545: 5, 548: 8, 550: 8, 552: 4, 562: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 764: 8, 767: 4, 800: 8, 824: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 888: 8, 896: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 1, 918: 7, 921: 8, 933: 8, 944: 6, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1008: 2, 1014: 8, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1114: 8, 1160: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1200: 8, 1201: 8, 1202: 8, 1203: 8, 1212: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1279: 8, 1552: 8, 1553: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1656: 8, 1664: 8, 1666: 8, 1667: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }, # XLE AWD 2018 { - 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 238: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 545: 5, 548: 8, 550: 8, 552: 4, 562: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 764: 8, 767:4, 800: 8, 824: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 1, 921: 8, 933: 8, 944: 6, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1008: 2, 1014: 8, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1114: 8, 1160: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1200: 8, 1201: 8, 1202: 8, 1203: 8, 1212: 8, 1227: 8, 1235: 8, 1237: 8, 1279: 8, 1552: 8, 1553: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1656: 8, 1664: 8, 1666: 8, 1667: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 238: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 545: 5, 548: 8, 550: 8, 552: 4, 562: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 764: 8, 767: 4, 800: 8, 824: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 1, 921: 8, 933: 8, 944: 6, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1008: 2, 1014: 8, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1114: 8, 1160: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1200: 8, 1201: 8, 1202: 8, 1203: 8, 1212: 8, 1227: 8, 1235: 8, 1237: 8, 1279: 8, 1552: 8, 1553: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1656: 8, 1664: 8, 1666: 8, 1667: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }], CAR.LEXUS_IS: [ # IS300 2018 { - 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 238: 4, 400: 6, 426: 6, 452: 8, 464: 8, 466: 8, 467: 5, 544: 4, 550: 8, 552: 4, 608: 8, 610: 5, 643: 7, 705: 8, 740: 5, 767:4, 800: 8, 836: 8, 845: 5, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 913: 8, 916: 3, 918: 7, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1008: 2, 1009: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1112: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1168: 1, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1184: 8, 1185: 8, 1186: 8, 1187: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1208: 8, 1212: 8, 1227: 8, 1235: 8, 1237: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1584: 8, 1589: 8, 1590: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1648: 8, 1666: 8, 1667: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 238: 4, 400: 6, 426: 6, 452: 8, 464: 8, 466: 8, 467: 5, 544: 4, 550: 8, 552: 4, 608: 8, 610: 5, 643: 7, 705: 8, 740: 5, 767: 4, 800: 8, 836: 8, 845: 5, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 913: 8, 916: 3, 918: 7, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1008: 2, 1009: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1112: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1168: 1, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1184: 8, 1185: 8, 1186: 8, 1187: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1208: 8, 1212: 8, 1227: 8, 1235: 8, 1237: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1584: 8, 1589: 8, 1590: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1648: 8, 1666: 8, 1667: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }, # IS300H 2017 { - 36: 8, 37: 8, 170: 8, 180: 8, 295: 8, 296: 8, 400: 6, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 581: 5, 608: 8, 610: 5, 643: 7, 713: 8, 740: 5, 767:4, 800: 8, 836: 8, 845: 5, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 913: 8, 916: 3, 918: 7, 921: 7, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 3, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1009: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1112: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1168: 1, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1184: 8, 1185: 8, 1186: 8, 1187: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1208: 8, 1212: 8, 1227: 8, 1232: 8, 1235: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1728: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 170: 8, 180: 8, 295: 8, 296: 8, 400: 6, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 581: 5, 608: 8, 610: 5, 643: 7, 713: 8, 740: 5, 767: 4, 800: 8, 836: 8, 845: 5, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 913: 8, 916: 3, 918: 7, 921: 7, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 3, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1009: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1112: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1168: 1, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1184: 8, 1185: 8, 1186: 8, 1187: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1208: 8, 1212: 8, 1227: 8, 1232: 8, 1235: 8, 1279: 8, 1408: 8, 1409: 8, 1410: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1561: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1728: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }], CAR.RAV4H_TSS2: [ #Hybrid Limited { - 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 401: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 658: 8, 713: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 764: 8, 765: 8, 767:4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 822: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 882: 8, 885: 8, 889: 8, 891: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913:8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 987: 8, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1063: 8, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1696: 8, 1745: 8, 1775: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1808: 8, 1810: 8, 1816: 8, 1818: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 + 36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 401: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 658: 8, 713: 8, 728: 8, 740: 5, 742: 8, 743: 8, 761: 8, 764: 8, 765: 8, 767: 4, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 822: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 882: 8, 885: 8, 889: 8, 891: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 987: 8, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1063: 8, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1228: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1696: 8, 1745: 8, 1775: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1808: 8, 1810: 8, 1816: 8, 1818: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8 }, ], CAR.LEXUS_CTH: [{ @@ -261,32 +269,52 @@ FINGERPRINTS = { } # Don't use theses fingerprints for fingerprinting, they are still needed for ECU detection -IGNORED_FINGERPRINTS = [CAR.RAV4H_TSS2, CAR.HIGHLANDERH_TSS2] +IGNORED_FINGERPRINTS = [CAR.RAV4H_TSS2, CAR.HIGHLANDERH_TSS2, CAR.LEXUS_RXH_TSS2] FW_VERSIONS = { CAR.AVALON: { (Ecu.esp, 0x7b0, None): [b'F152607060\x00\x00\x00\x00\x00\x00'], - (Ecu.dsu, 0x791, None): [b'881510705200\x00\x00\x00\x00'], + (Ecu.dsu, 0x791, None): [ + b'881510705200\x00\x00\x00\x00', + b'881510701300\x00\x00\x00\x00', + ], (Ecu.eps, 0x7a1, None): [b'8965B41051\x00\x00\x00\x00\x00\x00'], - (Ecu.engine, 0x7e0, None): [b'\x0230721200\x00\x00\x00\x00\x00\x00\x00\x00A0C01000\x00\x00\x00\x00\x00\x00\x00\x00'], - (Ecu.fwdRadar, 0x750, 0xf): [b'8821F4702100\x00\x00\x00\x00'], - (Ecu.fwdCamera, 0x750, 0x6d): [b'8646F0703000\x00\x00\x00\x00'], + (Ecu.engine, 0x7e0, None): [ + b'\x0230721100\x00\x00\x00\x00\x00\x00\x00\x00A0C01000\x00\x00\x00\x00\x00\x00\x00\x00', + b'\x0230721200\x00\x00\x00\x00\x00\x00\x00\x00A0C01000\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 0xf): [ + b'8821F4702000\x00\x00\x00\x00', + b'8821F4702100\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x750, 0x6d): [ + b'8646F0701100\x00\x00\x00\x00', + b'8646F0703000\x00\x00\x00\x00', + ], }, CAR.CAMRY: { (Ecu.engine, 0x700, None): [ + b'\x018966306L3100\x00\x00\x00\x00', + b'\x018966306L4200\x00\x00\x00\x00', b'\x018966306L5200\x00\x00\x00\x00', + b'\x018966306Q3100\x00\x00\x00\x00', + b'\x018966306Q4000\x00\x00\x00\x00', + b'\x018966306Q4100\x00\x00\x00\x00', + b'\x018966333P3100\x00\x00\x00\x00', + b'\x018966333P3200\x00\x00\x00\x00', b'\x018966333P4200\x00\x00\x00\x00', b'\x018966333P4300\x00\x00\x00\x00', b'\x018966333P4400\x00\x00\x00\x00', b'\x018966333P4500\x00\x00\x00\x00', b'\x018966333P4700\x00\x00\x00\x00', + b'\x018966333Q6000\x00\x00\x00\x00', b'\x018966333Q6200\x00\x00\x00\x00', - b'\x018966306Q4100\x00\x00\x00\x00', ], (Ecu.dsu, 0x791, None): [ - b'8821F0607200 ', + b'8821F0601200 ', b'8821F0601300 ', b'8821F0603300 ', + b'8821F0607200 ', b'8821F0608000 ', ], (Ecu.esp, 0x7b0, None): [ @@ -301,6 +329,7 @@ FW_VERSIONS = { b'8965B33580\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ # Same as 0x791 + b'8821F0601200 ', b'8821F0601300 ', b'8821F0603300 ', b'8821F0607200 ', @@ -312,52 +341,100 @@ FW_VERSIONS = { b'8646F0603400 ', b'8646F0605000 ', b'8646F0606000 ', + b'8646F0606100 ', ], }, CAR.CAMRYH: { (Ecu.engine, 0x700, None): [ + b'\x018966333N4300\x00\x00\x00\x00', + b'\x018966333X0000\x00\x00\x00\x00', b'\x028966306B2100\x00\x00\x00\x00897CF3302002\x00\x00\x00\x00', + b'\x028966306B2300\x00\x00\x00\x00897CF3302002\x00\x00\x00\x00', + b'\x028966306N8100\x00\x00\x00\x00897CF3302002\x00\x00\x00\x00', b'\x028966306N8200\x00\x00\x00\x00897CF3302002\x00\x00\x00\x00', + b'\x028966306N8300\x00\x00\x00\x00897CF3302002\x00\x00\x00\x00', + b'\x028966306N8400\x00\x00\x00\x00897CF3302002\x00\x00\x00\x00', b'\x028966306R5000\x00\x00\x00\x00897CF3302002\x00\x00\x00\x00', + b'\x028966306R5000\x00\x00\x00\x00897CF3305001\x00\x00\x00\x00', b'\x028966306R6000\x00\x00\x00\x00897CF3302002\x00\x00\x00\x00', + b'\x028966306R6000\x00\x00\x00\x00897CF3305001\x00\x00\x00\x00', + b'\x028966306S0000\x00\x00\x00\x00897CF3305001\x00\x00\x00\x00', b'\x028966306S0100\x00\x00\x00\x00897CF3305001\x00\x00\x00\x00', + b'\x028966306S1100\x00\x00\x00\x00897CF3305001\x00\x00\x00\x00', ], (Ecu.esp, 0x7b0, None): [ + b'F152633214\x00\x00\x00\x00\x00\x00', + b'F152633660\x00\x00\x00\x00\x00\x00', b'F152633712\x00\x00\x00\x00\x00\x00', b'F152633713\x00\x00\x00\x00\x00\x00', b'F152633B51\x00\x00\x00\x00\x00\x00', + b'F152633B60\x00\x00\x00\x00\x00\x00', ], (Ecu.dsu, 0x791, None): [ b'8821F0601200 ', b'8821F0601300 ', + b'8821F0603400 ', + b'8821F0604200 ', + b'8821F0606200 ', b'8821F0607200 ', b'8821F0608000 ', + b'8821F0609000 ', + b'8821F0609100 ', ], (Ecu.eps, 0x7a1, None): [ b'8965B33540\x00\x00\x00\x00\x00\x00', + b'8965B33542\x00\x00\x00\x00\x00\x00', + b'8965B33550\x00\x00\x00\x00\x00\x00', + b'8965B33551\x00\x00\x00\x00\x00\x00', b'8965B33580\x00\x00\x00\x00\x00\x00', + b'8965B33581\x00\x00\x00\x00\x00\x00', + b'8965B33611\x00\x00\x00\x00\x00\x00', + b'8965B33621\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ # Same as 0x791 b'8821F0601200 ', b'8821F0601300 ', + b'8821F0603400 ', + b'8821F0604200 ', + b'8821F0606200 ', b'8821F0607200 ', b'8821F0608000 ', + b'8821F0609000 ', + b'8821F0609100 ', ], (Ecu.fwdCamera, 0x750, 0x6d): [ b'8646F0601200 ', b'8646F0601300 ', + b'8646F0601400 ', + b'8646F0603500 ', + b'8646F0604100 ', b'8646F0605000 ', + b'8646F0606000 ', + b'8646F0606100 ', + b'8646F0607000 ', + b'8646F0607100 ', ], }, CAR.CHR: { (Ecu.engine, 0x700, None): [ + b'\x01896631017100\x00\x00\x00\x00', + b'\x01896631017200\x00\x00\x00\x00', b'\x0189663F413100\x00\x00\x00\x00', + b'\x0189663F414100\x00\x00\x00\x00', ], (Ecu.dsu, 0x791, None): [ + b'8821F0W01000 ', b'8821FF401600 ', b'8821FF404100 ', + b'8821FF405100 ', + b'8821FF406000 ', + b'8821F0W01100 ', ], (Ecu.esp, 0x7b0, None): [ + b'F152610020\x00\x00\x00\x00\x00\x00', + b'F152610153\x00\x00\x00\x00\x00\x00', + b'F1526F4034\x00\x00\x00\x00\x00\x00', + b'F1526F4044\x00\x00\x00\x00\x00\x00', b'F1526F4073\x00\x00\x00\x00\x00\x00', b'F1526F4122\x00\x00\x00\x00\x00\x00', ], @@ -366,24 +443,50 @@ FW_VERSIONS = { b'8965B10040\x00\x00\x00\x00\x00\x00', ], (Ecu.engine, 0x7e0, None): [ + b'\x033F401100\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203102\x00\x00\x00\x00', b'\x033F424000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203202\x00\x00\x00\x00', + b'\x0331024000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203302\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ + b'8821F0W01000 ', b'8821FF401600 ', b'8821FF404100 ', + b'8821FF405100 ', + b'8821FF406000 ', + b'8821F0W01100 ', ], (Ecu.fwdCamera, 0x750, 0x6d): [ b'8646FF401800 ', b'8646FF404000 ', + b'8646FF406000 ', ], }, CAR.CHRH: { - (Ecu.engine, 0x700, None): [b'\x0289663F431000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00'], - (Ecu.esp, 0x7b0, None): [b'F152610040\x00\x00\x00\x00\x00\x00'], - (Ecu.dsu, 0x791, None): [b'8821FF407100 '], - (Ecu.eps, 0x7a1, None): [b'8965B10050\x00\x00\x00\x00\x00\x00'], - (Ecu.fwdRadar, 0x750, 0xf): [b'8821FF407100 '], - (Ecu.fwdCamera, 0x750, 0x6d): [b'8646FF407000 '], + (Ecu.engine, 0x700, None): [ + b'\x0289663F423000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', + b'\x0289663F431000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', + b'\x0189663F438000\x00\x00\x00\x00', + ], + (Ecu.esp, 0x7b0, None): [ + b'F152610040\x00\x00\x00\x00\x00\x00', + b'F152610190\x00\x00\x00\x00\x00\x00', + ], + (Ecu.dsu, 0x791, None): [ + b'8821FF404000 ', + b'8821FF407100 ', + ], + (Ecu.eps, 0x7a1, None): [ + b'8965B10040\x00\x00\x00\x00\x00\x00', + b'8965B10050\x00\x00\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 0xf): [ + b'8821FF404000 ', + b'8821FF407100 ', + ], + (Ecu.fwdCamera, 0x750, 0x6d): [ + b'8646FF404000 ', + b'8646FF407000 ', + ], }, CAR.COROLLA: { (Ecu.engine, 0x7e0, None): [ @@ -425,11 +528,13 @@ FW_VERSIONS = { b'\x01896630ZG5000\x00\x00\x00\x00', b'\x01896630ZG5100\x00\x00\x00\x00', b'\x01896630ZG5200\x00\x00\x00\x00', + b'\x01896630ZG5300\x00\x00\x00\x00', b'\x01896630ZQ5000\x00\x00\x00\x00', b'\x018966312L8000\x00\x00\x00\x00', b'\x018966312P9000\x00\x00\x00\x00', b'\x018966312P9100\x00\x00\x00\x00', b'\x018966312P9200\x00\x00\x00\x00', + b'\x018966312R0100\x00\x00\x00\x00', b'\x018966312R1000\x00\x00\x00\x00', b'\x018966312R1100\x00\x00\x00\x00', b'\x018966312R3100\x00\x00\x00\x00', @@ -438,11 +543,13 @@ FW_VERSIONS = { b'\x03312N6000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203202\x00\x00\x00\x00', b'\x03312N6000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203302\x00\x00\x00\x00', b'\x03312N6100\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203302\x00\x00\x00\x00', + b'\x03312N6100\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203402\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ b'8965B12361\x00\x00\x00\x00\x00\x00', b'\x018965B12350\x00\x00\x00\x00\x00\x00', b'\x018965B12500\x00\x00\x00\x00\x00\x00', + b'\x018965B12520\x00\x00\x00\x00\x00\x00', b'\x018965B12530\x00\x00\x00\x00\x00\x00', ], (Ecu.esp, 0x7b0, None): [ @@ -450,8 +557,10 @@ FW_VERSIONS = { b'\x01F152602280\x00\x00\x00\x00\x00\x00', b'\x01F152602560\x00\x00\x00\x00\x00\x00', b'\x01F152612641\x00\x00\x00\x00\x00\x00', + b'\x01F152612651\x00\x00\x00\x00\x00\x00', b'\x01F152612B10\x00\x00\x00\x00\x00\x00', b'\x01F152612B60\x00\x00\x00\x00\x00\x00', + b'\x01F152612B61\x00\x00\x00\x00\x00\x00', b'\x01F152612B90\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ @@ -464,24 +573,28 @@ FW_VERSIONS = { b'\x028646F12010D0\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00', b'\x028646F1201100\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00', b'\x028646F1201200\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00', + b'\x028646F1201300\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', b'\x028646F1202000\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', + b'\x028646F1202100\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', ], }, CAR.COROLLAH_TSS2: { (Ecu.engine, 0x700, None): [ + b'\x01896630ZJ1000\x00\x00\x00\x00', b'\x018966342M5000\x00\x00\x00\x00', b'\x02896630ZQ3000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896630ZR2000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x028966312Q4000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', + b'\x038966312L7000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF1205001\x00\x00\x00\x00', b'\x038966312N1000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF1203001\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ b'8965B12361\x00\x00\x00\x00\x00\x00', b'8965B12451\x00\x00\x00\x00\x00\x00', - b'8965B42170\x00\x00\x00\x00\x00\x00', b'\x018965B12350\x00\x00\x00\x00\x00\x00', b'\x018965B12470\x00\x00\x00\x00\x00\x00', b'\x018965B12500\x00\x00\x00\x00\x00\x00', + b'\x018965B12520\x00\x00\x00\x00\x00\x00', b'\x018965B12530\x00\x00\x00\x00\x00\x00', ], (Ecu.esp, 0x7b0, None): [ @@ -493,6 +606,7 @@ FW_VERSIONS = { b'F152612840\x00\x00\x00\x00\x00\x00', b'F152612A10\x00\x00\x00\x00\x00\x00', b'F152642540\x00\x00\x00\x00\x00\x00', + b'F152612A00\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ b'\x018821F3301100\x00\x00\x00\x00', @@ -502,19 +616,27 @@ FW_VERSIONS = { ], (Ecu.fwdCamera, 0x750, 0x6d): [ b'\x028646F1201100\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00', + b'\x028646F1201300\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', b'\x028646F1202000\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', + b'\x028646F1202100\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', b'\x028646F4203400\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', ], }, CAR.HIGHLANDER: { (Ecu.engine, 0x700, None): [ + b'\x01896630E09000\x00\x00\x00\x00', b'\x01896630E43100\x00\x00\x00\x00', + b'\x01896630E43200\x00\x00\x00\x00', + b'\x01896630E44200\x00\x00\x00\x00', + b'\x01896630E45000\x00\x00\x00\x00', + b'\x01896630E45100\x00\x00\x00\x00', b'\x01896630E45200\x00\x00\x00\x00', + b'\x01896630E74000\x00\x00\x00\x00', + b'\x01896630E76000\x00\x00\x00\x00', b'\x01896630E83000\x00\x00\x00\x00', b'\x01896630E84000\x00\x00\x00\x00', b'\x01896630E85000\x00\x00\x00\x00', b'\x01896630E88000\x00\x00\x00\x00', - b'\x01896630E09000\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ b'8965B48140\x00\x00\x00\x00\x00\x00', @@ -536,32 +658,90 @@ FW_VERSIONS = { ], }, CAR.HIGHLANDERH: { - (Ecu.eps, 0x7a1, None): [b'8965B48160\x00\x00\x00\x00\x00\x00'], - (Ecu.esp, 0x7b0, None): [b'F152648541\x00\x00\x00\x00\x00\x00'], - (Ecu.engine, 0x7e0, None): [b'\x0230E40000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00'], - (Ecu.fwdRadar, 0x750, 0xf): [b'8821F4702100\x00\x00\x00\x00'], - (Ecu.fwdCamera, 0x750, 0x6d): [b'8646F0E01200\x00\x00\x00\x00'], + (Ecu.eps, 0x7a1, None): [ + b'8965B48160\x00\x00\x00\x00\x00\x00' + ], + (Ecu.esp, 0x7b0, None): [ + b'F152648541\x00\x00\x00\x00\x00\x00', + b'F152648542\x00\x00\x00\x00\x00\x00', + ], + (Ecu.engine, 0x7e0, None): [ + b'\x0230E40000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', + b'\x0230EA2000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 0xf): [ + b'8821F4702100\x00\x00\x00\x00', + b'8821F4702300\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x750, 0x6d): [ + b'8646F0E01200\x00\x00\x00\x00', + b'8646F0E01300\x00\x00\x00\x00', + ], + }, + CAR.HIGHLANDER_TSS2: { + (Ecu.eps, 0x7a1, None): [ + b'8965B48241\x00\x00\x00\x00\x00\x00', + ], + (Ecu.esp, 0x7b0, None): [ + b'\x01F15260E051\x00\x00\x00\x00\x00\x00', + ], + (Ecu.engine, 0x700, None): [ + b'\x01896630E64100\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 0xf): [ + b'\x018821F3301400\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x750, 0x6d): [ + b'\x028646F0E02100\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', + ], }, CAR.HIGHLANDERH_TSS2: { - (Ecu.eps, 0x7a1, None): [b'8965B48241\x00\x00\x00\x00\x00\x00',], - (Ecu.esp, 0x7b0, None): [b'\x01F15264872300\x00\x00\x00\x00',], - (Ecu.engine, 0x700, None): [b'\x02896630E66000\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00',], - (Ecu.fwdRadar, 0x750, 0xf): [b'\x018821F3301400\x00\x00\x00\x00',], - (Ecu.fwdCamera, 0x750, 0x6d): [b'\x028646F0E02100\x00\x00\x00\x008646G2601200\x00\x00\x00\x00',], + (Ecu.eps, 0x7a1, None): [ + b'8965B48241\x00\x00\x00\x00\x00\x00', + ], + (Ecu.esp, 0x7b0, None): [ + b'\x01F15264872300\x00\x00\x00\x00', + ], + (Ecu.engine, 0x700, None): [ + b'\x02896630E66000\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 0xf): [ + b'\x018821F3301400\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x750, 0x6d): [ + b'\x028646F0E02100\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', + ], }, CAR.LEXUS_IS: { - (Ecu.engine, 0x700, None): [b'\x018966353Q2300\x00\x00\x00\x00'], - (Ecu.esp, 0x7b0, None): [b'F152653330\x00\x00\x00\x00\x00\x00'], - (Ecu.dsu, 0x791, None): [b'881515306400\x00\x00\x00\x00'], - (Ecu.eps, 0x7a1, None): [b'8965B53271\x00\x00\x00\x00\x00\x00'], - (Ecu.fwdRadar, 0x750, 0xf): [b'8821F4702300\x00\x00\x00\x00'], - (Ecu.fwdCamera, 0x750, 0x6d): [b'8646F5301400\x00\x00\x00\x00'], + (Ecu.engine, 0x700, None): [ + b'\x018966353M7100\x00\x00\x00\x00', + b'\x018966353Q2300\x00\x00\x00\x00', + b'\x018966353R8100\x00\x00\x00\x00', + ], + (Ecu.esp, 0x7b0, None): [ + b'F152653330\x00\x00\x00\x00\x00\x00', + ], + (Ecu.dsu, 0x791, None): [ + b'881515306400\x00\x00\x00\x00', + b'881515306500\x00\x00\x00\x00', + ], + (Ecu.eps, 0x7a1, None): [ + b'8965B53271\x00\x00\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 0xf): [ + b'8821F4702300\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x750, 0x6d): [ + b'8646F5301400\x00\x00\x00\x00', + ], }, CAR.PRIUS: { (Ecu.engine, 0x700, None): [ b'\x02896634761000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896634761100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', + b'\x02896634761200\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896634763000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', + b'\x02896634765000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896634769100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896634774000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896634774100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', @@ -569,20 +749,27 @@ FW_VERSIONS = { b'\x02896634782000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896634784000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x028966347A5000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', - b'\x03896634759200\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701004\x00\x00\x00\x00', + b'\x028966347A8000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', + b'\x02896634765100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', + b'\x03896634759100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701003\x00\x00\x00\x00', b'\x03896634759200\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701003\x00\x00\x00\x00', + b'\x03896634759200\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701004\x00\x00\x00\x00', b'\x03896634759300\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701004\x00\x00\x00\x00', b'\x03896634760000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701002\x00\x00\x00\x00', + b'\x03896634760000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701003\x00\x00\x00\x00', b'\x03896634760100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701003\x00\x00\x00\x00', b'\x03896634760200\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701003\x00\x00\x00\x00', b'\x03896634760200\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701004\x00\x00\x00\x00', + b'\x03896634760300\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701004\x00\x00\x00\x00', b'\x03896634768000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4703001\x00\x00\x00\x00', b'\x03896634768000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4703002\x00\x00\x00\x00', b'\x03896634768100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4703002\x00\x00\x00\x00', b'\x03896634785000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4705001\x00\x00\x00\x00', + b'\x03896634786000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4705001\x00\x00\x00\x00', b'\x03896634786000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4710001\x00\x00\x00\x00', b'\x03896634789000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4703002\x00\x00\x00\x00', b'\x038966347A3000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4707001\x00\x00\x00\x00', + b'\x038966347B6000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4710001\x00\x00\x00\x00', b'\x038966347B7000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4710001\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ @@ -594,24 +781,26 @@ FW_VERSIONS = { ], (Ecu.esp, 0x7b0, None): [ b'F152647290\x00\x00\x00\x00\x00\x00', + b'F152647300\x00\x00\x00\x00\x00\x00', b'F152647310\x00\x00\x00\x00\x00\x00', b'F152647414\x00\x00\x00\x00\x00\x00', b'F152647415\x00\x00\x00\x00\x00\x00', b'F152647416\x00\x00\x00\x00\x00\x00', b'F152647417\x00\x00\x00\x00\x00\x00', + b'F152647470\x00\x00\x00\x00\x00\x00', b'F152647490\x00\x00\x00\x00\x00\x00', b'F152647684\x00\x00\x00\x00\x00\x00', b'F152647862\x00\x00\x00\x00\x00\x00', b'F152647863\x00\x00\x00\x00\x00\x00', b'F152647864\x00\x00\x00\x00\x00\x00', b'F152647865\x00\x00\x00\x00\x00\x00', - b'F152647470\x00\x00\x00\x00\x00\x00', ], (Ecu.dsu, 0x791, None): [ b'881514702300\x00\x00\x00\x00', b'881514703100\x00\x00\x00\x00', b'881514704100\x00\x00\x00\x00', b'881514706000\x00\x00\x00\x00', + b'881514706100\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ b'8821F4702000\x00\x00\x00\x00', @@ -632,20 +821,26 @@ FW_VERSIONS = { (Ecu.engine, 0x7e0, None): [ b'\x02342Q1000\x00\x00\x00\x00\x00\x00\x00\x0054212000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02342Q1100\x00\x00\x00\x00\x00\x00\x00\x0054212000\x00\x00\x00\x00\x00\x00\x00\x00', + b'\x02342Q1200\x00\x00\x00\x00\x00\x00\x00\x0054212000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02342Q1300\x00\x00\x00\x00\x00\x00\x00\x0054212000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02342Q2000\x00\x00\x00\x00\x00\x00\x00\x0054213000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02342Q2100\x00\x00\x00\x00\x00\x00\x00\x0054213000\x00\x00\x00\x00\x00\x00\x00\x00', + b'\x02342Q2200\x00\x00\x00\x00\x00\x00\x00\x0054213000\x00\x00\x00\x00\x00\x00\x00\x00', + b'\x02342Q4000\x00\x00\x00\x00\x00\x00\x00\x0054215000\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ b'8965B42082\x00\x00\x00\x00\x00\x00', b'8965B42083\x00\x00\x00\x00\x00\x00', + b'8965B42063\x00\x00\x00\x00\x00\x00', ], (Ecu.esp, 0x7b0, None): [ b'F15260R102\x00\x00\x00\x00\x00\x00', b'F15260R103\x00\x00\x00\x00\x00\x00', b'F152642493\x00\x00\x00\x00\x00\x00', + b'F152642492\x00\x00\x00\x00\x00\x00', ], (Ecu.dsu, 0x791, None): [ + b'881514201200\x00\x00\x00\x00', b'881514201300\x00\x00\x00\x00', b'881514201400\x00\x00\x00\x00', ], @@ -679,6 +874,7 @@ FW_VERSIONS = { ], (Ecu.dsu, 0x791, None): [ b'881514202200\x00\x00\x00\x00', + b'881514202300\x00\x00\x00\x00', b'881514202400\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ @@ -696,17 +892,23 @@ FW_VERSIONS = { }, CAR.RAV4_TSS2: { (Ecu.engine, 0x700, None): [ + b'\x01896630R58000\x00\x00\x00\x00', b'\x018966342E2000\x00\x00\x00\x00', b'\x018966342M8000\x00\x00\x00\x00', b'\x018966342T1000\x00\x00\x00\x00', b'\x018966342T6000\x00\x00\x00\x00', + b'\x018966342T9000\x00\x00\x00\x00', + b'\x018966342U4000\x00\x00\x00\x00', b'\x018966342V3100\x00\x00\x00\x00', + b'\x018966342V3200\x00\x00\x00\x00', b'\x018966342X5000\x00\x00\x00\x00', b'\x01896634A05000\x00\x00\x00\x00', b'\x01896634A19000\x00\x00\x00\x00', + b'\x01896634A19100\x00\x00\x00\x00', + b'\x01896634A20000\x00\x00\x00\x00', b'\x01896634A22000\x00\x00\x00\x00', - b'\x018966342U4000\x00\x00\x00\x00', b'\x01F152642551\x00\x00\x00\x00\x00\x00', + b'\x028966342T0000\x00\x00\x00\x00897CF1201001\x00\x00\x00\x00', b'\x028966342Y8000\x00\x00\x00\x00897CF1201001\x00\x00\x00\x00', b'\x02896634A18000\x00\x00\x00\x00897CF1201001\x00\x00\x00\x00', ], @@ -714,13 +916,17 @@ FW_VERSIONS = { b'F152642520\x00\x00\x00\x00\x00\x00', b'\x01F15260R210\x00\x00\x00\x00\x00\x00', b'\x01F15260R220\x00\x00\x00\x00\x00\x00', + b'\x01F15260R300\x00\x00\x00\x00\x00\x00', b'\x01F152642551\x00\x00\x00\x00\x00\x00', b'\x01F152642561\x00\x00\x00\x00\x00\x00', + b'\x01F152642700\x00\x00\x00\x00\x00\x00', b'\x01F152642710\x00\x00\x00\x00\x00\x00', + b'\x01F152642750\x00\x00\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ b'8965B42170\x00\x00\x00\x00\x00\x00', b'8965B42171\x00\x00\x00\x00\x00\x00', + b'8965B42181\x00\x00\x00\x00\x00\x00', b'\x028965B0R01200\x00\x00\x00\x008965B0R02200\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ @@ -734,13 +940,16 @@ FW_VERSIONS = { b'\x028646F4203300\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00', b'\x028646F4203400\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', b'\x028646F4203500\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', + b'\x028646F4203700\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', ], }, CAR.RAV4H_TSS2: { (Ecu.engine, 0x700, None): [ b'\x018966342M5000\x00\x00\x00\x00', b'\x018966342X6000\x00\x00\x00\x00', + b'\x018966342W8000\x00\x00\x00\x00', b'\x028966342W4001\x00\x00\x00\x00897CF1203001\x00\x00\x00\x00', + b'\x02896634A14001\x00\x00\x00\x00897CF1203001\x00\x00\x00\x00', b'\x02896634A23001\x00\x00\x00\x00897CF1203001\x00\x00\x00\x00', ], (Ecu.esp, 0x7b0, None): [ @@ -749,22 +958,27 @@ FW_VERSIONS = { b'F152642531\x00\x00\x00\x00\x00\x00', b'F152642532\x00\x00\x00\x00\x00\x00', b'F152642521\x00\x00\x00\x00\x00\x00', + b'F152642541\x00\x00\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ b'8965B42170\x00\x00\x00\x00\x00\x00', b'8965B42171\x00\x00\x00\x00\x00\x00', b'8965B42181\x00\x00\x00\x00\x00\x00', b'\x028965B0R01200\x00\x00\x00\x008965B0R02200\x00\x00\x00\x00', + b'\x028965B0R01300\x00\x00\x00\x008965B0R02300\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ + b'\x018821F3301100\x00\x00\x00\x00', b'\x018821F3301200\x00\x00\x00\x00', b'\x018821F3301300\x00\x00\x00\x00', b'\x018821F3301400\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ + b'\x028646F4203200\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00', b'\x028646F4203300\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00', b'\x028646F4203400\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', b'\x028646F4203500\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', + b'\x028646F4203700\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', ], }, CAR.LEXUS_ES_TSS2: { @@ -786,17 +1000,33 @@ FW_VERSIONS = { CAR.SIENNA: { (Ecu.engine, 0x700, None): [ b'\x01896630832100\x00\x00\x00\x00', + b'\x01896630838000\x00\x00\x00\x00', + b'\x01896630838100\x00\x00\x00\x00', b'\x01896630842000\x00\x00\x00\x00', + b'\x01896630851000\x00\x00\x00\x00', b'\x01896630851100\x00\x00\x00\x00', - b'\x01896630860000\x00\x00\x00\x00', + b'\x01896630852100\x00\x00\x00\x00', b'\x01896630859000\x00\x00\x00\x00', + b'\x01896630860000\x00\x00\x00\x00', + ], + (Ecu.eps, 0x7a1, None): [ + b'8965B45070\x00\x00\x00\x00\x00\x00', + b'8965B45082\x00\x00\x00\x00\x00\x00', + ], + (Ecu.esp, 0x7b0, None): [ + b'F152608130\x00\x00\x00\x00\x00\x00', + ], + (Ecu.dsu, 0x791, None): [ + b'881510801100\x00\x00\x00\x00', ], - (Ecu.eps, 0x7a1, None): [b'8965B45070\x00\x00\x00\x00\x00\x00'], (Ecu.fwdRadar, 0x750, 0xf): [ b'8821F4702100\x00\x00\x00\x00', + b'8821F4702200\x00\x00\x00\x00', b'8821F4702300\x00\x00\x00\x00', ], - (Ecu.fwdCamera, 0x750, 0x6d): [b'8646F0801100\x00\x00\x00\x00'], + (Ecu.fwdCamera, 0x750, 0x6d): [ + b'8646F0801100\x00\x00\x00\x00', + ], }, CAR.LEXUS_ESH_TSS2: { (Ecu.engine, 0x700, None): [ @@ -820,27 +1050,88 @@ FW_VERSIONS = { b'\x028646F3304100\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', ], }, + CAR.LEXUS_NXH: { + (Ecu.engine, 0x7e0, None): [ + b'\x0237882000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00', + b'\x0237841000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.esp, 0x7b0, None): [ + b'F152678160\x00\x00\x00\x00\x00\x00', + b'F152678170\x00\x00\x00\x00\x00\x00', + ], + (Ecu.dsu, 0x791, None): [ + b'881517804300\x00\x00\x00\x00', + b'881517804100\x00\x00\x00\x00', + ], + (Ecu.eps, 0x7a1, None): [ + b'8965B78100\x00\x00\x00\x00\x00\x00', + b'8965B78060\x00\x00\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 0xf): [ + b'8821F4702300\x00\x00\x00\x00', + b'8821F4702100\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x750, 0x6d): [ + b'8646F7801300\x00\x00\x00\x00', + b'8646F7801100\x00\x00\x00\x00', + ], + }, CAR.LEXUS_RX: { - (Ecu.engine, 0x700, None): [b'\x01896630E41200\x00\x00\x00\x00'], - (Ecu.esp, 0x7b0, None): [b'F152648473\x00\x00\x00\x00\x00\x00'], - (Ecu.dsu, 0x791, None): [b'881514810500\x00\x00\x00\x00'], - (Ecu.eps, 0x7a1, None): [b'8965B0E012\x00\x00\x00\x00\x00\x00'], - (Ecu.fwdRadar, 0x750, 0xf): [b'8821F4701100\x00\x00\x00\x00'], - (Ecu.fwdCamera, 0x750, 0x6d): [b'8646F4802001\x00\x00\x00\x00'], + (Ecu.engine, 0x700, None): [ + b'\x01896630E37200\x00\x00\x00\x00', + b'\x01896630E41000\x00\x00\x00\x00', + b'\x01896630E41200\x00\x00\x00\x00', + b'\x01896630E37300\x00\x00\x00\x00', + b'\x018966348R8500\x00\x00\x00\x00', + ], + (Ecu.esp, 0x7b0, None): [ + b'F152648472\x00\x00\x00\x00\x00\x00', + b'F152648473\x00\x00\x00\x00\x00\x00', + b'F152648492\x00\x00\x00\x00\x00\x00', + b'F152648493\x00\x00\x00\x00\x00\x00', + b'F152648474\x00\x00\x00\x00\x00\x00', + ], + (Ecu.dsu, 0x791, None): [ + b'881514810300\x00\x00\x00\x00', + b'881514810500\x00\x00\x00\x00', + b'881514810700\x00\x00\x00\x00', + ], + (Ecu.eps, 0x7a1, None): [ + b'8965B0E011\x00\x00\x00\x00\x00\x00', + b'8965B0E012\x00\x00\x00\x00\x00\x00', + b'8965B48102\x00\x00\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 0xf): [ + b'8821F4701000\x00\x00\x00\x00', + b'8821F4701100\x00\x00\x00\x00', + b'8821F4701300\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x750, 0x6d): [ + b'8646F4801100\x00\x00\x00\x00', + b'8646F4801200\x00\x00\x00\x00', + b'8646F4802001\x00\x00\x00\x00', + b'8646F4802100\x00\x00\x00\x00', + b'8646F4809000\x00\x00\x00\x00', + ], }, CAR.LEXUS_RXH: { (Ecu.engine, 0x7e0, None): [ + b'\x02348N0000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02348Q4000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02348T1100\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', + b'\x02348V6000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02348Z3000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.esp, 0x7b0, None): [ + b'F152648361\x00\x00\x00\x00\x00\x00', b'F152648501\x00\x00\x00\x00\x00\x00', + b'F152648502\x00\x00\x00\x00\x00\x00', + b'F152648504\x00\x00\x00\x00\x00\x00', b'F152648A30\x00\x00\x00\x00\x00\x00', - b'F152648361\x00\x00\x00\x00\x00\x00', ], (Ecu.dsu, 0x791, None): [ b'881514811300\x00\x00\x00\x00', + b'881514811500\x00\x00\x00\x00', b'881514811700\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ @@ -850,14 +1141,55 @@ FW_VERSIONS = { ], (Ecu.fwdRadar, 0x750, 0xf): [ b'8821F4701000\x00\x00\x00\x00', + b'8821F4701100\x00\x00\x00\x00', + b'8821F4701200\x00\x00\x00\x00', b'8821F4701300\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ b'8646F4801200\x00\x00\x00\x00', + b'8646F4802100\x00\x00\x00\x00', b'8646F4802200\x00\x00\x00\x00', b'8646F4809000\x00\x00\x00\x00', ], }, + CAR.LEXUS_RX_TSS2: { + (Ecu.engine, 0x700, None): [ + b'\x01896630EB0000\x00\x00\x00\x00', + b'\x01896630EA9000\x00\x00\x00\x00', + ], + (Ecu.esp, 0x7b0, None): [ + b'\x01F15260E031\x00\x00\x00\x00\x00\x00', + b'\x01F15260E041\x00\x00\x00\x00\x00\x00', + ], + (Ecu.eps, 0x7a1, None): [ + b'8965B48271\x00\x00\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 0xf): [ + b'\x018821F3301100\x00\x00\x00\x00', + b'\x018821F3301300\x00\x00\x00\x00', + b'\x018821F3301400\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x750, 0x6d): [ + b'\x028646F4810100\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', + ], + }, + CAR.LEXUS_RXH_TSS2: { + (Ecu.engine, 0x7e0, None): [ + b'\x02348X8000\x00\x00\x00\x00\x00\x00\x00\x00A4802000\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.esp, 0x7b0, None): [ + b'F152648831\x00\x00\x00\x00\x00\x00', + ], + (Ecu.eps, 0x7a1, None): [ + b'8965B48271\x00\x00\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 0xf): [ + b'\x018821F3301400\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x750, 0x6d): [ + b'\x028646F4810100\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', + ], + }, } STEER_THRESHOLD = 100 @@ -870,6 +1202,7 @@ DBC = { CAR.LEXUS_RX: dbc_dict('lexus_rx_350_2016_pt_generated', 'toyota_adas'), CAR.LEXUS_RXH: dbc_dict('lexus_rx_hybrid_2017_pt_generated', 'toyota_adas'), CAR.LEXUS_RX_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), + CAR.LEXUS_RXH_TSS2: dbc_dict('toyota_nodsu_hybrid_pt_generated', 'toyota_tss2_adas'), CAR.CHR: dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'), CAR.CHRH: dbc_dict('toyota_nodsu_hybrid_pt_generated', 'toyota_adas'), CAR.CAMRY: dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'), @@ -891,6 +1224,6 @@ DBC = { CAR.LEXUS_NXH: dbc_dict('lexus_nx300h_2018_pt_generated', 'toyota_adas'), } -NO_DSU_CAR = [CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH, CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, CAR.LEXUS_RX_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2] -TSS2_CAR = [CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, CAR.LEXUS_RX_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2] -NO_STOP_TIMER_CAR = [CAR.RAV4H, CAR.HIGHLANDERH, CAR.HIGHLANDER, CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.SIENNA, CAR.RAV4H_TSS2, CAR.LEXUS_RX_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2] # no resume button press required +NO_DSU_CAR = set([CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH, CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2]) +TSS2_CAR = set([CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2]) +NO_STOP_TIMER_CAR = set([CAR.RAV4H, CAR.HIGHLANDERH, CAR.HIGHLANDER, CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.SIENNA, CAR.RAV4H_TSS2, CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2]) # no resume button press required diff --git a/selfdrive/car/volkswagen/__init__.py b/selfdrive/car/volkswagen/__init__.py index 8b13789179..e69de29bb2 100644 --- a/selfdrive/car/volkswagen/__init__.py +++ b/selfdrive/car/volkswagen/__init__.py @@ -1 +0,0 @@ - diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py index 6c90d69e78..5bb5dcc109 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -4,8 +4,6 @@ from selfdrive.car.volkswagen import volkswagencan from selfdrive.car.volkswagen.values import DBC, CANBUS, MQB_LDW_MESSAGES, BUTTON_STATES, CarControllerParams from opendbc.can.packer import CANPacker -VisualAlert = car.CarControl.HUDControl.VisualAlert - class CarController(): def __init__(self, dbc_name, CP, VM): @@ -67,7 +65,7 @@ class CarController(): self.hcaEnabledFrameCount = 0 else: self.hcaEnabledFrameCount += 1 - if self.hcaEnabledFrameCount >= 118 * (100 / P.HCA_STEP): # 118s + if self.hcaEnabledFrameCount >= 118 * (100 / P.HCA_STEP): # 118s # The Kansas I-70 Crosswind Problem: if we truly do need to steer # in one direction for > 360 seconds, we have to disable HCA for a # frame while actively steering. Testing shows we can just set the @@ -114,7 +112,7 @@ class CarController(): if frame % P.LDW_STEP == 0: hcaEnabled = True if enabled and not CS.out.standstill else False - if visual_alert == VisualAlert.steerRequired: + if visual_alert == car.CarControl.HUDControl.VisualAlert.steerRequired: hud_alert = MQB_LDW_MESSAGES["laneAssistTakeOverSilent"] else: hud_alert = MQB_LDW_MESSAGES["none"] diff --git a/selfdrive/car/volkswagen/carstate.py b/selfdrive/car/volkswagen/carstate.py index 91b24dc4ff..a994130929 100644 --- a/selfdrive/car/volkswagen/carstate.py +++ b/selfdrive/car/volkswagen/carstate.py @@ -28,16 +28,16 @@ class CarState(CarStateBase): # Update steering angle, rate, yaw rate, and driver input torque. VW send # the sign/direction in a separate signal so they must be recombined. - ret.steeringAngle = pt_cp.vl["LWI_01"]['LWI_Lenkradwinkel'] * (1,-1)[int(pt_cp.vl["LWI_01"]['LWI_VZ_Lenkradwinkel'])] - ret.steeringRate = pt_cp.vl["LWI_01"]['LWI_Lenkradw_Geschw'] * (1,-1)[int(pt_cp.vl["LWI_01"]['LWI_VZ_Lenkradwinkel'])] - ret.steeringTorque = pt_cp.vl["EPS_01"]['Driver_Strain'] * (1,-1)[int(pt_cp.vl["EPS_01"]['Driver_Strain_VZ'])] + ret.steeringAngle = pt_cp.vl["LWI_01"]['LWI_Lenkradwinkel'] * (1, -1)[int(pt_cp.vl["LWI_01"]['LWI_VZ_Lenkradwinkel'])] + ret.steeringRate = pt_cp.vl["LWI_01"]['LWI_Lenkradw_Geschw'] * (1, -1)[int(pt_cp.vl["LWI_01"]['LWI_VZ_Lenkradwinkel'])] + ret.steeringTorque = pt_cp.vl["EPS_01"]['Driver_Strain'] * (1, -1)[int(pt_cp.vl["EPS_01"]['Driver_Strain_VZ'])] ret.steeringPressed = abs(ret.steeringTorque) > CarControllerParams.STEER_DRIVER_ALLOWANCE - ret.yawRate = pt_cp.vl["ESP_02"]['ESP_Gierrate'] * (1,-1)[int(pt_cp.vl["ESP_02"]['ESP_VZ_Gierrate'])] * CV.DEG_TO_RAD + ret.yawRate = pt_cp.vl["ESP_02"]['ESP_Gierrate'] * (1, -1)[int(pt_cp.vl["ESP_02"]['ESP_VZ_Gierrate'])] * CV.DEG_TO_RAD # Update gas, brakes, and gearshift. ret.gas = pt_cp.vl["Motor_20"]['MO_Fahrpedalrohwert_01'] / 100.0 ret.gasPressed = ret.gas > 0 - ret.brake = pt_cp.vl["ESP_05"]['ESP_Bremsdruck'] / 250.0 # FIXME: this is pressure in Bar, not sure what OP expects + ret.brake = pt_cp.vl["ESP_05"]['ESP_Bremsdruck'] / 250.0 # FIXME: this is pressure in Bar, not sure what OP expects ret.brakePressed = bool(pt_cp.vl["ESP_05"]['ESP_Fahrer_bremst']) ret.brakeLights = bool(pt_cp.vl["ESP_05"]['ESP_Status_Bremsdruck']) @@ -53,7 +53,7 @@ class CarState(CarStateBase): pt_cp.vl["Gateway_72"]['ZV_HD_offen']]) # Update seatbelt fastened status. - ret.seatbeltUnlatched = False if pt_cp.vl["Airbag_02"]["AB_Gurtschloss_FA"] == 3 else True + ret.seatbeltUnlatched = pt_cp.vl["Airbag_02"]["AB_Gurtschloss_FA"] != 3 # Update driver preference for metric. VW stores many different unit # preferences, including separate units for for distance vs. speed. @@ -107,7 +107,7 @@ class CarState(CarStateBase): self.steeringFault = not pt_cp.vl["EPS_01"]["HCA_Ready"] # Additional safety checks performed in CarInterface. - self.parkingBrakeSet = bool(pt_cp.vl["Kombi_01"]['KBI_Handbremse']) # FIXME: need to include an EPB check as well + self.parkingBrakeSet = bool(pt_cp.vl["Kombi_01"]['KBI_Handbremse']) # FIXME: need to include an EPB check as well ret.espDisabled = pt_cp.vl["ESP_21"]['ESP_Tastung_passiv'] != 0 return ret @@ -159,7 +159,7 @@ class CarState(CarStateBase): ("GRA_Tip_Hoch", "GRA_ACC_01", 0), # ACC button, increase or accel ("GRA_Tip_Runter", "GRA_ACC_01", 0), # ACC button, decrease or decel ("GRA_Tip_Wiederaufnahme", "GRA_ACC_01", 0), # ACC button, resume - ("GRA_Verstellung_Zeitluecke", "GRA_ACC_01", 0), # ACC button, time gap adj + ("GRA_Verstellung_Zeitluecke", "GRA_ACC_01", 0), # ACC button, time gap adj ("GRA_Typ_Hauptschalter", "GRA_ACC_01", 0), # ACC main button type ("GRA_Tip_Stufe_2", "GRA_ACC_01", 0), # unknown related to stalk type ("GRA_ButtonTypeInfo", "GRA_ACC_01", 0), # unknown related to stalk type diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index 8e2797de9c..c041c6c44c 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -1,7 +1,5 @@ from cereal import car -from selfdrive.config import Conversions as CV from selfdrive.car.volkswagen.values import CAR, BUTTON_STATES -from common.params import put_nonblocking from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint from selfdrive.car.interfaces import CarInterfaceBase @@ -20,7 +18,7 @@ class CarInterface(CarInterfaceBase): return float(accel) / 4.0 @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=None): ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay) # VW port is a community feature, since we don't own one to test @@ -33,35 +31,23 @@ class CarInterface(CarInterfaceBase): ret.safetyModel = car.CarParams.SafetyModel.volkswagen # Additional common MQB parameters that may be overridden per-vehicle - ret.steerRateCost = 0.5 - ret.steerActuatorDelay = 0.05 # Hopefully all MQB racks are similar here + ret.steerRateCost = 1.0 + ret.steerActuatorDelay = 0.05 # Hopefully all MQB racks are similar here ret.steerLimitTimer = 0.4 - # As a starting point for speed-adjusted lateral tuning, use the example - # map speed breakpoints from a VW Tiguan (SSP 399 page 9). It's unclear - # whether the driver assist map breakpoints have any direct bearing on - # HCA assist torque, but if they're good breakpoints for the driver, - # they're probably good breakpoints for HCA as well. OP won't be driving - # 250kph/155mph but it provides interpolation scaling above 100kmh/62mph. - ret.lateralTuning.pid.kpBP = [0., 15 * CV.KPH_TO_MS, 50 * CV.KPH_TO_MS] - ret.lateralTuning.pid.kiBP = [0., 15 * CV.KPH_TO_MS, 50 * CV.KPH_TO_MS] - - # FIXME: Per-vehicle parameters need to be reintegrated. - # For the time being, per-vehicle stuff is being archived since we - # can't auto-detect very well yet. Now that tuning is figured out, - # averaged params should work reasonably on a range of cars. Owners - # can tweak here, as needed, until we have car type auto-detection. - - ret.mass = 1700 + STD_CARGO_KG - ret.wheelbase = 2.75 + ret.lateralTuning.pid.kpBP = [0.] + ret.lateralTuning.pid.kiBP = [0.] + + ret.mass = 1500 + STD_CARGO_KG + ret.wheelbase = 2.64 ret.centerToFront = ret.wheelbase * 0.45 ret.steerRatio = 15.6 ret.lateralTuning.pid.kf = 0.00006 - ret.lateralTuning.pid.kpV = [0.15, 0.25, 0.60] - ret.lateralTuning.pid.kiV = [0.05, 0.05, 0.05] - tire_stiffness_factor = 0.6 + ret.lateralTuning.pid.kpV = [0.6] + ret.lateralTuning.pid.kiV = [0.2] + tire_stiffness_factor = 1.0 - ret.enableCamera = True # Stock camera detection doesn't apply to VW + ret.enableCamera = True # Stock camera detection doesn't apply to VW ret.transmissionType = car.CarParams.TransmissionType.automatic # TODO: get actual value, for now starting with reasonable value for @@ -77,7 +63,6 @@ class CarInterface(CarInterfaceBase): # returns a car.CarState def update(self, c, can_strings): - canMonoTimes = [] buttonEvents = [] # Process the most recent CAN message traffic, and check for validity @@ -90,10 +75,11 @@ class CarInterface(CarInterfaceBase): ret.canValid = self.cp.can_valid and self.cp_cam.can_valid ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False - # Update the EON metric configuration to match the car at first startup, + # TODO: add a field for this to carState, car interface code shouldn't write params + # Update the device metric configuration to match the car at first startup, # or if there's been a change. - if self.CS.displayMetricUnits != self.displayMetricUnitsPrev: - put_nonblocking("IsMetric", "1" if self.CS.displayMetricUnits else "0") + #if self.CS.displayMetricUnits != self.displayMetricUnitsPrev: + # put_nonblocking("IsMetric", "1" if self.CS.displayMetricUnits else "0") # Check for and process state-change events (button press or release) from # the turn stalk switch or ACC steering wheel/control stalk buttons. @@ -114,7 +100,6 @@ class CarInterface(CarInterfaceBase): ret.events = events.to_msg() ret.buttonEvents = buttonEvents - ret.canMonoTimes = canMonoTimes # update previous car states self.displayMetricUnitsPrev = self.CS.displayMetricUnits diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 30c32b6080..d99d781026 100644 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -1,3 +1,5 @@ +# flake8: noqa + from selfdrive.car import dbc_dict class CarControllerParams: @@ -44,7 +46,7 @@ MQB_LDW_MESSAGES = { } class CAR: - GOLF = "Volkswagen Golf" + GOLF = "VOLKSWAGEN GOLF" FINGERPRINTS = { CAR.GOLF: [ diff --git a/selfdrive/car/volkswagen/volkswagencan.py b/selfdrive/car/volkswagen/volkswagencan.py index 34f19003d8..3cd47a0957 100644 --- a/selfdrive/car/volkswagen/volkswagencan.py +++ b/selfdrive/car/volkswagen/volkswagencan.py @@ -25,7 +25,7 @@ def create_mqb_hud_control(packer, bus, hca_enabled, steering_pressed, hud_alert rightlanehud = 2 if rightLaneVisible else 1 values = { - "LDW_Unknown": 2, # FIXME: possible speed or attention relationship + "LDW_Unknown": 2, # FIXME: possible speed or attention relationship "Kombi_Lamp_Orange": 1 if hca_enabled and steering_pressed else 0, "Kombi_Lamp_Green": 1 if hca_enabled and not steering_pressed else 0, "Left_Lane_Status": leftlanehud, @@ -48,5 +48,4 @@ def create_mqb_acc_buttons_control(packer, bus, buttonStatesToSend, CS, idx): "GRA_Tip_Stufe_2": CS.graTipStufe2, "GRA_ButtonTypeInfo": CS.graButtonTypeInfo } - return packer.make_can_msg("GRA_ACC_01", bus, values, idx) diff --git a/selfdrive/clocksd/SConscript b/selfdrive/clocksd/SConscript index 63c508c4fe..601e64bf16 100644 --- a/selfdrive/clocksd/SConscript +++ b/selfdrive/clocksd/SConscript @@ -1,2 +1,2 @@ -Import('env', 'common', 'messaging') -env.Program('clocksd.cc', LIBS=['diag', 'time_genoff', common, messaging, 'capnp', 'zmq', 'kj']) \ No newline at end of file +Import('env', 'common', 'cereal', 'messaging') +env.Program('clocksd.cc', LIBS=['diag', 'time_genoff', common, cereal, messaging, 'capnp', 'zmq', 'kj']) \ No newline at end of file diff --git a/selfdrive/clocksd/clocksd.cc b/selfdrive/clocksd/clocksd.cc index d289387a8b..2e17058e0e 100644 --- a/selfdrive/clocksd/clocksd.cc +++ b/selfdrive/clocksd/clocksd.cc @@ -4,10 +4,8 @@ #include #include #include -#include #include "messaging.hpp" #include "common/timing.h" -#include "cereal/gen/cpp/log.capnp.h" namespace { int64_t arm_cntpct() { @@ -21,10 +19,7 @@ int main() { setpriority(PRIO_PROCESS, 0, -13); int err = 0; - Context *context = Context::create(); - - PubSocket* clock_publisher = PubSocket::create(context, "clocks"); - assert(clock_publisher != NULL); + PubMaster pm({"clocks"}); int timerfd = timerfd_create(CLOCK_BOOTTIME, 0); assert(timerfd >= 0); @@ -60,13 +55,9 @@ int main() { clocks.setWallTimeNanos(wall_time); clocks.setModemUptimeMillis(modem_uptime_v); - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - clock_publisher->send((char*)bytes.begin(), bytes.size()); + pm.send("clocks", msg); } close(timerfd); - delete clock_publisher; - delete context; return 0; } \ No newline at end of file diff --git a/selfdrive/common/SConscript b/selfdrive/common/SConscript index 18f9fdf4a8..0ba5b1abcc 100644 --- a/selfdrive/common/SConscript +++ b/selfdrive/common/SConscript @@ -1,11 +1,11 @@ -Import('env', 'arch', 'SHARED') +Import('env', 'arch', 'SHARED', 'QCOM_REPLAY') if SHARED: fxn = env.SharedLibrary else: fxn = env.Library -_common = fxn('common', ['params.cc', 'swaglog.cc', 'util.c', 'cqueue.c'], LIBS="json11") +_common = fxn('common', ['params.cc', 'swaglog.cc', 'util.c', 'cqueue.c', 'gpio.cc'], LIBS="json11") _visionipc = fxn('visionipc', ['visionipc.c', 'ipc.c']) files = [ @@ -21,8 +21,11 @@ if arch == "aarch64": files += [ 'framebuffer.cc', 'touch.c', - 'visionbuf_ion.c', ] + if QCOM_REPLAY: + files += ['visionbuf_cl.c'] + else: + files += ['visionbuf_ion.c'] _gpu_libs = ['gui', 'adreno_utils'] elif arch == "larch64": defines = {"CLU_NO_CACHE": None} @@ -39,4 +42,3 @@ else: _gpucommon = fxn('gpucommon', files, CPPDEFINES=defines, LIBS=_gpu_libs) Export('_common', '_visionipc', '_gpucommon', '_gpu_libs') - diff --git a/selfdrive/common/buffering.c b/selfdrive/common/buffering.c index 9cbb1b86e0..bba2e82ab9 100644 --- a/selfdrive/common/buffering.c +++ b/selfdrive/common/buffering.c @@ -70,7 +70,7 @@ void tbuffer_dispatch(TBuffer *tb, int idx) { efd_write(tb->efd); pthread_cond_signal(&tb->cv); - pthread_mutex_unlock(&tb->lock); + pthread_mutex_unlock(&tb->lock); } int tbuffer_acquire(TBuffer *tb) { @@ -344,7 +344,7 @@ void pool_push(Pool *s, int idx) { for (int i=0; iqueues[i]; if (!c->inited) continue; - + pthread_mutex_lock(&c->lock); if (((c->head+1) % c->num) == c->tail) { // queue is full. skip for now diff --git a/selfdrive/common/clutil.c b/selfdrive/common/clutil.c index 22c9b45de1..00d63cdcac 100644 --- a/selfdrive/common/clutil.c +++ b/selfdrive/common/clutil.c @@ -36,6 +36,44 @@ void clu_init(void) { #endif } +cl_device_id cl_get_device_id(cl_device_type device_type) { + bool opencl_platform_found = false; + cl_device_id device_id = NULL; + + cl_uint num_platforms = 0; + int err = clGetPlatformIDs(0, NULL, &num_platforms); + assert(err == 0); + cl_platform_id* platform_ids = malloc(sizeof(cl_platform_id) * num_platforms); + err = clGetPlatformIDs(num_platforms, platform_ids, NULL); + assert(err == 0); + + char cBuffer[1024]; + for (size_t i = 0; i < num_platforms; i++) { + err = clGetPlatformInfo(platform_ids[i], CL_PLATFORM_NAME, sizeof(cBuffer), &cBuffer, NULL); + assert(err == 0); + printf("platform[%zu] CL_PLATFORM_NAME: %s\n", i, cBuffer); + + cl_uint num_devices; + err = clGetDeviceIDs(platform_ids[i], device_type, 0, NULL, &num_devices); + if (err != 0 || !num_devices) { + continue; + } + // Get first device + err = clGetDeviceIDs(platform_ids[i], device_type, 1, &device_id, NULL); + assert(err == 0); + cl_print_info(platform_ids[i], device_id); + opencl_platform_found = true; + break; + } + free(platform_ids); + + if (!opencl_platform_found) { + printf("No valid openCL platform found\n"); + assert(opencl_platform_found); + } + return device_id; +} + cl_program cl_create_program_from_file(cl_context ctx, const char* path) { char* src_buf = read_file(path, NULL); assert(src_buf); @@ -175,6 +213,7 @@ cl_program cl_cached_program_from_hash(cl_context ctx, cl_device_id device_id, u return prg; } +#ifndef CLU_NO_CACHE static uint8_t* get_program_binary(cl_program prg, size_t *out_size) { int err; @@ -199,6 +238,7 @@ static uint8_t* get_program_binary(cl_program prg, size_t *out_size) { *out_size = binary_size; return binary_buf; } +#endif cl_program cl_cached_program_from_string(cl_context ctx, cl_device_id device_id, const char* src, const char* args, @@ -265,13 +305,14 @@ cl_program cl_cached_program_from_file(cl_context ctx, cl_device_id device_id, c return ret; } +#ifndef CLU_NO_CACHE static void add_index(uint64_t index_hash, uint64_t src_hash) { FILE *f = fopen("/tmp/clcache/index.cli", "a"); assert(f); fprintf(f, "%016" PRIx64 " %016" PRIx64 "\n", index_hash, src_hash); fclose(f); } - +#endif cl_program cl_program_from_index(cl_context ctx, cl_device_id device_id, uint64_t index_hash) { int err; diff --git a/selfdrive/common/clutil.h b/selfdrive/common/clutil.h index b87961eacd..abbda8c806 100644 --- a/selfdrive/common/clutil.h +++ b/selfdrive/common/clutil.h @@ -17,6 +17,7 @@ extern "C" { void clu_init(void); +cl_device_id cl_get_device_id(cl_device_type device_type); cl_program cl_create_program_from_file(cl_context ctx, const char* path); void cl_print_info(cl_platform_id platform, cl_device_id device); void cl_print_build_errors(cl_program program, cl_device_id device); diff --git a/selfdrive/common/framebuffer.cc b/selfdrive/common/framebuffer.cc index 7bea565d59..30604deb2e 100644 --- a/selfdrive/common/framebuffer.cc +++ b/selfdrive/common/framebuffer.cc @@ -12,8 +12,7 @@ #include #include -#define BACKLIGHT_CONTROL "/sys/class/leds/lcd-backlight/brightness" -#define BACKLIGHT_LEVEL "205" +#define BACKLIGHT_LEVEL 205 using namespace android; @@ -32,6 +31,21 @@ struct FramebufferState { EGLContext context; }; +extern "C" void framebuffer_swap(FramebufferState *s) { + eglSwapBuffers(s->display, s->surface); + assert(glGetError() == GL_NO_ERROR); +} + +extern "C" bool set_brightness(int brightness) { + FILE *f = fopen("/sys/class/leds/lcd-backlight/brightness", "wb"); + if (f != NULL) { + fprintf(f, "%d", brightness); + fclose(f); + return true; + } + return false; +} + extern "C" void framebuffer_set_power(FramebufferState *s, int mode) { SurfaceComposerClient::setDisplayPowerMode(s->dtoken, mode); } @@ -88,6 +102,9 @@ extern "C" FramebufferState* framebuffer_init( EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 8, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR, + // enable MSAA + EGL_SAMPLE_BUFFERS, 1, + EGL_SAMPLES, 4, EGL_NONE, }; @@ -98,7 +115,7 @@ extern "C" FramebufferState* framebuffer_init( assert(success); printf("egl version %d.%d\n", s->egl_major, s->egl_minor); - + EGLint num_configs; success = eglChooseConfig(s->display, attribs, &s->config, 1, &num_configs); assert(success); @@ -123,23 +140,10 @@ extern "C" FramebufferState* framebuffer_init( printf("gl version %s\n", glGetString(GL_VERSION)); - - // set brightness - int brightness_fd = open(BACKLIGHT_CONTROL, O_RDWR); - if (brightness_fd != -1){ - const char brightness_level[] = BACKLIGHT_LEVEL; - write(brightness_fd, brightness_level, strlen(brightness_level)); - close(brightness_fd); - } + set_brightness(BACKLIGHT_LEVEL); if (out_w) *out_w = w; if (out_h) *out_h = h; return s; } - -extern "C" void framebuffer_swap(FramebufferState *s) { - eglSwapBuffers(s->display, s->surface); - assert(glGetError() == GL_NO_ERROR); -} - diff --git a/selfdrive/common/framebuffer.h b/selfdrive/common/framebuffer.h index 45920b8e42..45053bbb14 100644 --- a/selfdrive/common/framebuffer.h +++ b/selfdrive/common/framebuffer.h @@ -1,5 +1,4 @@ -#ifndef FRAMEBUFFER_H -#define FRAMEBUFFER_H +#pragma once #ifdef __cplusplus extern "C" { @@ -13,6 +12,7 @@ FramebufferState* framebuffer_init( void framebuffer_set_power(FramebufferState *s, int mode); void framebuffer_swap(FramebufferState *s); +bool set_brightness(int brightness); /* Display power modes */ enum { @@ -40,9 +40,6 @@ enum { HWC_POWER_MODE_DOZE_SUSPEND = 3, }; - #ifdef __cplusplus } #endif - -#endif diff --git a/selfdrive/common/gpio.cc b/selfdrive/common/gpio.cc new file mode 100644 index 0000000000..fd68bcd523 --- /dev/null +++ b/selfdrive/common/gpio.cc @@ -0,0 +1,75 @@ +#include "gpio.h" +#include +#include +#include + +// We assume that all pins have already been exported on boot, +// and that we have permission to write to them. + +int gpio_init(int pin_nr, bool output){ + int ret = 0; + int fd = -1, tmp; + + char pin_dir_path[50]; + int pin_dir_path_len = snprintf(pin_dir_path, sizeof(pin_dir_path), + "/sys/class/gpio/gpio%d/direction", pin_nr); + if(pin_dir_path_len <= 0){ + ret = -1; + goto cleanup; + } + + fd = open(pin_dir_path, O_WRONLY); + if(fd == -1){ + ret = -1; + goto cleanup; + } + if(output){ + tmp = write(fd, "out", 3); + if(tmp != 3){ + ret = -1; + goto cleanup; + } + } else { + tmp = write(fd, "in", 2); + if(tmp != 2){ + ret = -1; + goto cleanup; + } + } + +cleanup: + if(fd >= 0){ + close(fd); + } + return ret; +} + +int gpio_set(int pin_nr, bool high){ + int ret = 0; + int fd = -1, tmp; + + char pin_val_path[50]; + int pin_val_path_len = snprintf(pin_val_path, sizeof(pin_val_path), + "/sys/class/gpio/gpio%d/value", pin_nr); + if(pin_val_path_len <= 0){ + ret = -1; + goto cleanup; + } + + fd = open(pin_val_path, O_WRONLY); + if(fd == -1){ + ret = -1; + goto cleanup; + } + tmp = write(fd, high ? "1" : "0", 1); + if(tmp != 1){ + ret = -1; + goto cleanup; + } + +cleanup: + if(fd >= 0){ + close(fd); + } + return ret; +} diff --git a/selfdrive/common/gpio.h b/selfdrive/common/gpio.h new file mode 100644 index 0000000000..479b4f7e06 --- /dev/null +++ b/selfdrive/common/gpio.h @@ -0,0 +1,35 @@ +#ifndef GPIO_H +#define GPIO_H + +#include + +// Pin definitions +#ifdef QCOM2 + #define GPIO_HUB_RST_N 30 + #define GPIO_UBLOX_RST_N 32 + #define GPIO_UBLOX_SAFEBOOT_N 33 + #define GPIO_UBLOX_PWR_EN 34 + #define GPIO_STM_RST_N 124 + #define GPIO_STM_BOOT0 134 +#else + #define GPIO_HUB_RST_N 0 + #define GPIO_UBLOX_RST_N 0 + #define GPIO_UBLOX_SAFEBOOT_N 0 + #define GPIO_UBLOX_PWR_EN 0 + #define GPIO_STM_RST_N 0 + #define GPIO_STM_BOOT0 0 +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +int gpio_init(int pin_nr, bool output); +int gpio_set(int pin_nr, bool high); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/selfdrive/common/ipc.c b/selfdrive/common/ipc.c index 41b0cc0eaa..a5993598d2 100644 --- a/selfdrive/common/ipc.c +++ b/selfdrive/common/ipc.c @@ -15,7 +15,11 @@ int ipc_connect(const char* socket_path) { int err; +#ifdef __APPLE__ + int sock = socket(AF_UNIX, SOCK_STREAM, 0); +#else int sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); +#endif if (sock < 0) return -1; struct sockaddr_un addr = { .sun_family = AF_UNIX, @@ -35,7 +39,11 @@ int ipc_bind(const char* socket_path) { unlink(socket_path); +#ifdef __APPLE__ + int sock = socket(AF_UNIX, SOCK_STREAM, 0); +#else int sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); +#endif struct sockaddr_un addr = { .sun_family = AF_UNIX, }; @@ -52,8 +60,6 @@ int ipc_bind(const char* socket_path) { int ipc_sendrecv_with_fds(bool send, int fd, void *buf, size_t buf_size, int* fds, int num_fds, int *out_num_fds) { - int err; - char control_buf[CMSG_SPACE(sizeof(int) * num_fds)]; memset(control_buf, 0, CMSG_SPACE(sizeof(int) * num_fds)); diff --git a/selfdrive/common/messaging.h b/selfdrive/common/messaging.h deleted file mode 100644 index dd1198e826..0000000000 --- a/selfdrive/common/messaging.h +++ /dev/null @@ -1,15 +0,0 @@ -// the c version of cereal/messaging.py - -#include - -// TODO: refactor to take in service instead of endpoint? -void *sub_sock(void *ctx, const char *endpoint) { - void* sock = zmq_socket(ctx, ZMQ_SUB); - assert(sock); - zmq_setsockopt(sock, ZMQ_SUBSCRIBE, "", 0); - int reconnect_ivl = 500; - zmq_setsockopt(sock, ZMQ_RECONNECT_IVL_MAX, &reconnect_ivl, sizeof(reconnect_ivl)); - zmq_connect(sock, endpoint); - return sock; -} - diff --git a/selfdrive/common/modeldata.h b/selfdrive/common/modeldata.h index 555a75614c..77f4a1b7a1 100644 --- a/selfdrive/common/modeldata.h +++ b/selfdrive/common/modeldata.h @@ -1,40 +1,7 @@ -#ifndef MODELDATA_H -#define MODELDATA_H +#pragma once #define MODEL_PATH_DISTANCE 192 #define POLYFIT_DEGREE 4 #define SPEED_PERCENTILES 10 #define DESIRE_PRED_SIZE 32 #define OTHER_META_SIZE 4 - -typedef struct PathData { - float points[MODEL_PATH_DISTANCE]; - float prob; - float std; - float stds[MODEL_PATH_DISTANCE]; - float poly[POLYFIT_DEGREE]; -} PathData; - -typedef struct LeadData { - float dist; - float prob; - float std; - float rel_y; - float rel_y_std; - float rel_v; - float rel_v_std; - float rel_a; - float rel_a_std; -} LeadData; - -typedef struct ModelData { - PathData path; - PathData left_lane; - PathData right_lane; - LeadData lead; - LeadData lead_future; - float meta[OTHER_META_SIZE + DESIRE_PRED_SIZE]; - float speed[SPEED_PERCENTILES]; -} ModelData; - -#endif diff --git a/selfdrive/common/params.cc b/selfdrive/common/params.cc index 5ab2eae349..4d9c214d37 100644 --- a/selfdrive/common/params.cc +++ b/selfdrive/common/params.cc @@ -13,6 +13,7 @@ #include #include +#include #include "common/util.h" #include "common/utilpp.h" @@ -353,3 +354,15 @@ int read_db_all(std::map *params, bool persistent_para close(lock_fd); return 0; } + +std::vector read_db_bytes(const char* param_name, bool persistent_param) { + std::vector bytes; + char* value; + size_t sz; + int result = read_db_value(param_name, &value, &sz, persistent_param); + if (result == 0) { + bytes.assign(value, value+sz); + free(value); + } + return bytes; +} diff --git a/selfdrive/common/params.h b/selfdrive/common/params.h index ea002eb0de..49af04b4fd 100644 --- a/selfdrive/common/params.h +++ b/selfdrive/common/params.h @@ -1,6 +1,4 @@ -#ifndef _SELFDRIVE_COMMON_PARAMS_H_ -#define _SELFDRIVE_COMMON_PARAMS_H_ - +#pragma once #include #ifdef __cplusplus @@ -39,7 +37,7 @@ void read_db_value_blocking(const char* key, char** value, size_t* value_sz, boo #ifdef __cplusplus #include #include +#include int read_db_all(std::map *params, bool persistent_param = false); +std::vector read_db_bytes(const char* param_name, bool persistent_param = false); #endif - -#endif // _SELFDRIVE_COMMON_PARAMS_H_ diff --git a/selfdrive/common/util.c b/selfdrive/common/util.c index 9bdb23f999..3728dabcd0 100644 --- a/selfdrive/common/util.c +++ b/selfdrive/common/util.c @@ -7,6 +7,7 @@ #ifdef __linux__ #include #include +#define __USE_GNU #include #endif @@ -19,7 +20,9 @@ void* read_file(const char* path, size_t* out_len) { long f_len = ftell(f); rewind(f); - char* buf = (char*)calloc(f_len, 1); + // malloc one extra byte so the file will always be NULL terminated + // cl_cached_program_from_file relies on this + char* buf = (char*)malloc(f_len+1); assert(buf); size_t num_read = fread(buf, f_len, 1, f); @@ -30,6 +33,7 @@ void* read_file(const char* path, size_t* out_len) { return NULL; } + buf[f_len] = '\0'; if (out_len) { *out_len = f_len; } @@ -59,3 +63,16 @@ int set_realtime_priority(int level) { #endif } +int set_core_affinity(int core) { +#ifdef QCOM + + long tid = syscall(SYS_gettid); + cpu_set_t rt_cpu; + + CPU_ZERO(&rt_cpu); + CPU_SET(core, &rt_cpu); + return sched_setaffinity(tid, sizeof(rt_cpu), &rt_cpu); +#else + return -1; +#endif +} diff --git a/selfdrive/common/util.h b/selfdrive/common/util.h index ed0c88f2c8..a9052146c7 100644 --- a/selfdrive/common/util.h +++ b/selfdrive/common/util.h @@ -29,6 +29,7 @@ typedef void (*sighandler_t)(int sig); #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) +#undef ALIGN #define ALIGN(x, align) (((x) + (align)-1) & ~((align)-1)) #ifdef __cplusplus @@ -44,6 +45,7 @@ void* read_file(const char* path, size_t* out_len); void set_thread_name(const char* name); int set_realtime_priority(int level); +int set_core_affinity(int core); #ifdef __cplusplus } diff --git a/selfdrive/common/version.h b/selfdrive/common/version.h index d6131d2de7..718297f674 100644 --- a/selfdrive/common/version.h +++ b/selfdrive/common/version.h @@ -1 +1 @@ -#define COMMA_VERSION "0.7.6" +#define COMMA_VERSION "0.7.9" diff --git a/selfdrive/common/visionbuf.h b/selfdrive/common/visionbuf.h index 8958bdd1d0..95f4826a96 100644 --- a/selfdrive/common/visionbuf.h +++ b/selfdrive/common/visionbuf.h @@ -14,6 +14,7 @@ extern "C" { typedef struct VisionBuf { size_t len; + size_t mmap_len; void* addr; int handle; int fd; diff --git a/selfdrive/common/visionbuf_cl.c b/selfdrive/common/visionbuf_cl.c index 5e94649811..c68950baa8 100644 --- a/selfdrive/common/visionbuf_cl.c +++ b/selfdrive/common/visionbuf_cl.c @@ -18,11 +18,17 @@ int offset = 0; void *malloc_with_fd(size_t len, int *fd) { char full_path[0x100]; +#ifdef __APPLE__ + snprintf(full_path, sizeof(full_path)-1, "/tmp/visionbuf_%d_%d", getpid(), offset++); +#else snprintf(full_path, sizeof(full_path)-1, "/dev/shm/visionbuf_%d_%d", getpid(), offset++); +#endif *fd = open(full_path, O_RDWR | O_CREAT, 0777); + assert(*fd >= 0); unlink(full_path); ftruncate(*fd, len); void *addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0); + assert(addr != MAP_FAILED); return addr; } diff --git a/selfdrive/common/visionbuf_ion.c b/selfdrive/common/visionbuf_ion.c index e5dddfad22..3068994d28 100644 --- a/selfdrive/common/visionbuf_ion.c +++ b/selfdrive/common/visionbuf_ion.c @@ -7,7 +7,7 @@ #include #include #include - +#include #include #include @@ -64,6 +64,7 @@ VisionBuf visionbuf_allocate(size_t len) { return (VisionBuf){ .len = len, + .mmap_len = ion_alloc.len, .addr = addr, .handle = ion_alloc.handle, .fd = ion_fd_data.fd, @@ -73,6 +74,7 @@ VisionBuf visionbuf_allocate(size_t len) { VisionBuf visionbuf_allocate_cl(size_t len, cl_device_id device_id, cl_context ctx, cl_mem *out_mem) { VisionBuf r = visionbuf_allocate(len); *out_mem = visionbuf_to_cl(&r, device_id, ctx); + r.buf_cl = *out_mem; return r; } @@ -137,6 +139,9 @@ void visionbuf_sync(const VisionBuf* buf, int dir) { } void visionbuf_free(const VisionBuf* buf) { + clReleaseMemObject(buf->buf_cl); + munmap(buf->addr, buf->mmap_len); + close(buf->fd); struct ion_handle_data handle_data = { .handle = buf->handle, }; diff --git a/selfdrive/common/visionimg.cc b/selfdrive/common/visionimg.cc index a533acb597..e0220c18f2 100644 --- a/selfdrive/common/visionimg.cc +++ b/selfdrive/common/visionimg.cc @@ -37,7 +37,7 @@ extern "C" void compute_aligned_width_and_height(int width, #endif void visionimg_compute_aligned_width_and_height(int width, int height, int *aligned_w, int *aligned_h) { -#ifdef QCOM +#if defined(QCOM) && !defined(QCOM_REPLAY) compute_aligned_width_and_height(ALIGN(width, 32), ALIGN(height, 32), 3, 0, 0, 512, aligned_w, aligned_h); #else *aligned_w = width; *aligned_h = height; @@ -49,7 +49,7 @@ VisionImg visionimg_alloc_rgb24(int width, int height, VisionBuf *out_buf) { visionimg_compute_aligned_width_and_height(width, height, &aligned_w, &aligned_h); int stride = aligned_w * 3; - size_t size = aligned_w * aligned_h * 3; + size_t size = (size_t) aligned_w * aligned_h * 3; VisionBuf buf = visionbuf_allocate(size); diff --git a/selfdrive/common/visionipc.c b/selfdrive/common/visionipc.c index a9c4e8a133..bae05ccc77 100644 --- a/selfdrive/common/visionipc.c +++ b/selfdrive/common/visionipc.c @@ -35,7 +35,7 @@ int vipc_recv(int fd, VisionPacket *out_p) { p2.d = p.d; *out_p = p2; } - //printf("%d = vipc_recv(%d, %d): %d %d %d %u\n", ret, fd, p2.num_fds, out_p->d.stream_bufs.type, out_p->d.stream_bufs.width, out_p->d.stream_bufs.height, out_p->d.stream_bufs.buf_len); + //printf("%d = vipc_recv(%d, %d): %d %d %d %zu\n", ret, fd, p2.num_fds, out_p->d.stream_bufs.type, out_p->d.stream_bufs.width, out_p->d.stream_bufs.height, out_p->d.stream_bufs.buf_len); return ret; } @@ -47,7 +47,7 @@ int vipc_send(int fd, const VisionPacket *p2) { .d = p2->d, }; int ret = ipc_sendrecv_with_fds(true, fd, (void*)&p, sizeof(p), (int*)p2->fds, p2->num_fds, NULL); - //printf("%d = vipc_send(%d, %d): %d %d %d %u\n", ret, fd, p2->num_fds, p2->d.stream_bufs.type, p2->d.stream_bufs.width, p2->d.stream_bufs.height, p2->d.stream_bufs.buf_len); + //printf("%d = vipc_send(%d, %d): %d %d %d %zu\n", ret, fd, p2->num_fds, p2->d.stream_bufs.type, p2->d.stream_bufs.width, p2->d.stream_bufs.height, p2->d.stream_bufs.buf_len); return ret; } diff --git a/selfdrive/common/visionstream.c b/selfdrive/common/visionstream.c deleted file mode 100644 index 63cf4122c1..0000000000 --- a/selfdrive/common/visionstream.c +++ /dev/null @@ -1,124 +0,0 @@ - - -int visionstream_init(VisionStream *s, VisionStreamType type, bool tbuffer, VisionStreamBufs *out_bufs_info) { - int err; - - memset(s, 0, sizeof(*s)); - - s->last_idx = -1; - - s->ipc_fd = vipc_connect(); - if (s->ipc_fd < 0) return -1; - - VisionPacket p = { - .type = VIPC_STREAM_SUBSCRIBE, - .d = { .stream_sub = { - .type = type, - .tbuffer = tbuffer, - }, }, - }; - err = vipc_send(s->ipc_fd, &p); - if (err < 0) { - close(s->ipc_fd); - return -1; - } - - VisionPacket rp; - err = vipc_recv(s->ipc_fd, &rp); - if (err <= 0) { - close(s->ipc_fd); - return -1; - } - assert(rp.type = VIPC_STREAM_BUFS); - assert(rp.d.stream_bufs.type == type); - - s->bufs_info = rp.d.stream_bufs; - - s->num_bufs = rp.num_fds; - s->bufs = calloc(s->num_bufs, sizeof(VIPCBuf)); - assert(s->bufs); - - vipc_bufs_load(s->bufs, &rp.d.stream_bufs, s->num_bufs, rp.fds); - - if (out_bufs_info) { - *out_bufs_info = s->bufs_info; - } - - return 0; -} - -void visionstream_release(VisionStream *s) { - int err; - if (s->last_idx >= 0) { - VisionPacket rep = { - .type = VIPC_STREAM_RELEASE, - .d = { .stream_rel = { - .type = s->last_type, - .idx = s->last_idx, - }} - }; - err = vipc_send(s->ipc_fd, &rep); - s->last_idx = -1; - } -} - -VIPCBuf* visionstream_get(VisionStream *s, VIPCBufExtra *out_extra) { - int err; - - VisionPacket rp; - err = vipc_recv(s->ipc_fd, &rp); - if (err <= 0) { - return NULL; - } - assert(rp.type == VIPC_STREAM_ACQUIRE); - - if (s->last_idx >= 0) { - VisionPacket rep = { - .type = VIPC_STREAM_RELEASE, - .d = { .stream_rel = { - .type = s->last_type, - .idx = s->last_idx, - }} - }; - err = vipc_send(s->ipc_fd, &rep); - if (err <= 0) { - return NULL; - } - } - - s->last_type = rp.d.stream_acq.type; - s->last_idx = rp.d.stream_acq.idx; - assert(s->last_idx < s->num_bufs); - - if (out_extra) { - *out_extra = rp.d.stream_acq.extra; - } - - return &s->bufs[s->last_idx]; -} - -void visionstream_destroy(VisionStream *s) { - int err; - - if (s->last_idx >= 0) { - VisionPacket rep = { - .type = VIPC_STREAM_RELEASE, - .d = { .stream_rel = { - .type = s->last_type, - .idx = s->last_idx, - }} - }; - err = vipc_send(s->ipc_fd, &rep); - s->last_idx = -1; - } - - for (int i=0; inum_bufs; i++) { - if (s->bufs[i].addr) { - munmap(s->bufs[i].addr, s->bufs[i].len); - s->bufs[i].addr = NULL; - close(s->bufs[i].fd); - } - } - if (s->bufs) free(s->bufs); - close(s->ipc_fd); -} \ No newline at end of file diff --git a/selfdrive/config.py b/selfdrive/config.py index 6c2296273a..2a89580889 100644 --- a/selfdrive/config.py +++ b/selfdrive/config.py @@ -25,6 +25,5 @@ class UIParams: lidar_car_x, lidar_car_y = lidar_x/2., lidar_y/1.1 car_hwidth = 1.7272/2 * lidar_zoom car_front = 2.6924 * lidar_zoom - car_back = 1.8796 * lidar_zoom + car_back = 1.8796 * lidar_zoom car_color = 110 - diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index c85db56713..2546a598af 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -2,14 +2,15 @@ import os import gc from cereal import car, log +from common.android import ANDROID, get_sound_card_online from common.numpy_fast import clip -from common.realtime import sec_since_boot, set_realtime_priority, Ratekeeper, DT_CTRL +from common.realtime import sec_since_boot, set_realtime_priority, set_core_affinity, Ratekeeper, DT_CTRL from common.profiler import Profiler from common.params import Params, put_nonblocking import cereal.messaging as messaging from selfdrive.config import Conversions as CV from selfdrive.boardd.boardd import can_list_to_can_capnp -from selfdrive.car.car_helpers import get_car, get_startup_event +from selfdrive.car.car_helpers import get_car, get_startup_event, get_one_can from selfdrive.controls.lib.lane_planner import CAMERA_OFFSET from selfdrive.controls.lib.drive_helpers import update_v_cruise, initialize_v_cruise from selfdrive.controls.lib.longcontrol import LongControl, STARTING_TARGET_SPEED @@ -36,21 +37,23 @@ LaneChangeState = log.PathPlan.LaneChangeState LaneChangeDirection = log.PathPlan.LaneChangeDirection EventName = car.CarEvent.EventName + class Controls: def __init__(self, sm=None, pm=None, can_sock=None): gc.disable() - set_realtime_priority(3) + set_realtime_priority(53) + set_core_affinity(3) # Setup sockets self.pm = pm if self.pm is None: - self.pm = messaging.PubMaster(['sendcan', 'controlsState', 'carState', \ + self.pm = messaging.PubMaster(['sendcan', 'controlsState', 'carState', 'carControl', 'carEvents', 'carParams']) self.sm = sm if self.sm is None: - self.sm = messaging.SubMaster(['thermal', 'health', 'model', 'liveCalibration', \ - 'dMonitoringState', 'plan', 'pathPlan']) + self.sm = messaging.SubMaster(['thermal', 'health', 'frame', 'model', 'liveCalibration', + 'dMonitoringState', 'plan', 'pathPlan', 'liveLocationKalman']) self.can_sock = can_sock if can_sock is None: @@ -59,9 +62,9 @@ class Controls: # wait for one health and one CAN packet hw_type = messaging.recv_one(self.sm.sock['health']).health.hwType - has_relay = hw_type in [HwType.blackPanda, HwType.uno] + has_relay = hw_type in [HwType.blackPanda, HwType.uno, HwType.dos] print("Waiting for CAN messages...") - messaging.get_one_can(self.can_sock) + get_one_can(self.can_sock) self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan'], has_relay) @@ -69,15 +72,14 @@ class Controls: params = Params() self.is_metric = params.get("IsMetric", encoding='utf8') == "1" self.is_ldw_enabled = params.get("IsLdwEnabled", encoding='utf8') == "1" - internet_needed = params.get("Offroad_ConnectivityNeeded", encoding='utf8') is not None + internet_needed = (params.get("Offroad_ConnectivityNeeded", encoding='utf8') is not None) and (params.get("DisableUpdates") != b"1") community_feature_toggle = params.get("CommunityFeaturesToggle", encoding='utf8') == "1" openpilot_enabled_toggle = params.get("OpenpilotEnabledToggle", encoding='utf8') == "1" passive = params.get("Passive", encoding='utf8') == "1" or \ internet_needed or not openpilot_enabled_toggle # detect sound card presence and ensure successful init - sounds_available = not os.path.isfile('/EON') or (os.path.isdir('/proc/asound/card0') \ - and open('/proc/asound/card0/state').read().strip() == 'ONLINE') + sounds_available = not ANDROID or get_sound_card_online() car_recognized = self.CP.carName != 'mock' # If stock camera is disconnected, we loaded car controls and it's not dashcam mode @@ -119,12 +121,11 @@ class Controls: self.can_error_counter = 0 self.last_blinker_frame = 0 self.saturated_count = 0 + self.distance_traveled = 0 self.events_prev = [] - self.current_alert_types = [] + self.current_alert_types = [ET.PERMANENT] self.sm['liveCalibration'].calStatus = Calibration.INVALID - self.sm['pathPlan'].sensorValid = True - self.sm['pathPlan'].posenetValid = True self.sm['thermal'].freeSpace = 1. self.sm['dMonitoringState'].events = [] self.sm['dMonitoringState'].awarenessStatus = 1. @@ -140,12 +141,13 @@ class Controls: self.events.add(EventName.communityFeatureDisallowed, static=True) if self.read_only and not passive: self.events.add(EventName.carUnrecognized, static=True) + if hw_type == HwType.whitePanda: + self.events.add(EventName.whitePandaUnsupported, static=True) # controlsd is driven by can recv, expected at 100Hz self.rk = Ratekeeper(100, print_delay_threshold=None) self.prof = Profiler(False) # off by default - def update_events(self, CS): """Compute carEvents from carState""" @@ -180,15 +182,20 @@ class Controls: # Handle lane change if self.sm['pathPlan'].laneChangeState == LaneChangeState.preLaneChange: - if self.sm['pathPlan'].laneChangeDirection == LaneChangeDirection.left: - self.events.add(EventName.preLaneChangeLeft) + direction = self.sm['pathPlan'].laneChangeDirection + if (CS.leftBlindspot and direction == LaneChangeDirection.left) or \ + (CS.rightBlindspot and direction == LaneChangeDirection.right): + self.events.add(EventName.laneChangeBlocked) else: - self.events.add(EventName.preLaneChangeRight) - elif self.sm['pathPlan'].laneChangeState in [LaneChangeState.laneChangeStarting, \ + if direction == LaneChangeDirection.left: + self.events.add(EventName.preLaneChangeLeft) + else: + self.events.add(EventName.preLaneChangeRight) + elif self.sm['pathPlan'].laneChangeState in [LaneChangeState.laneChangeStarting, LaneChangeState.laneChangeFinishing]: self.events.add(EventName.laneChange) - if self.can_rcv_error: + if self.can_rcv_error or (not CS.canValid and self.sm.frame > 5 / DT_CTRL): self.events.add(EventName.canError) if self.mismatch_counter >= 200: self.events.add(EventName.controlsMismatch) @@ -199,29 +206,37 @@ class Controls: self.events.add(EventName.commIssue) if not self.sm['pathPlan'].mpcSolutionValid: self.events.add(EventName.plannerError) - if not self.sm['pathPlan'].sensorValid and os.getenv("NOSENSOR") is None: - self.events.add(EventName.sensorDataInvalid) + if not self.sm['liveLocationKalman'].sensorsOK and os.getenv("NOSENSOR") is None: + if self.sm.frame > 5 / DT_CTRL: # Give locationd some time to receive all the inputs + self.events.add(EventName.sensorDataInvalid) + if not self.sm['liveLocationKalman'].gpsOK and (self.distance_traveled > 1000) and os.getenv("NOSENSOR") is None: + # Not show in first 1 km to allow for driving out of garage. This event shows after 5 minutes + self.events.add(EventName.noGps) if not self.sm['pathPlan'].paramsValid: self.events.add(EventName.vehicleModelInvalid) - if not self.sm['pathPlan'].posenetValid: + if not self.sm['liveLocationKalman'].posenetOK: self.events.add(EventName.posenetInvalid) + if not self.sm['liveLocationKalman'].deviceStable: + self.events.add(EventName.deviceFalling) + if not self.sm['frame'].recoverState < 2: + # counter>=2 is active + self.events.add(EventName.focusRecoverActive) if not self.sm['plan'].radarValid: self.events.add(EventName.radarFault) if self.sm['plan'].radarCanError: self.events.add(EventName.radarCanError) - if not CS.canValid: - self.events.add(EventName.canError) if log.HealthData.FaultType.relayMalfunction in self.sm['health'].faults: self.events.add(EventName.relayMalfunction) if self.sm['plan'].fcw: self.events.add(EventName.fcw) + if self.sm['model'].frameDropPerc > 1: + self.events.add(EventName.modeldLagging) # Only allow engagement with brake pressed when stopped behind another stopped car if CS.brakePressed and self.sm['plan'].vTargetFuture >= STARTING_TARGET_SPEED \ - and not self.CP.radarOffCan and CS.vEgo < 0.3: + and not self.CP.radarOffCan and CS.vEgo < 0.3: self.events.add(EventName.noTarget) - def data_sample(self): """Receive data from sockets and update carState""" @@ -248,8 +263,9 @@ class Controls: if not self.sm['health'].controlsAllowed and self.enabled: self.mismatch_counter += 1 - return CS + self.distance_traveled += CS.vEgo * DT_CTRL + return CS def state_transition(self, CS): """Compute conditional state transitions and execute actions on state transitions""" @@ -303,6 +319,8 @@ class Controls: elif self.state == State.preEnabled: if not self.events.any(ET.PRE_ENABLE): self.state = State.enabled + else: + self.current_alert_types.append(ET.PRE_ENABLE) # DISABLED elif self.state == State.disabled: @@ -326,7 +344,6 @@ class Controls: # Check if openpilot is engaged self.enabled = self.active or self.state == State.preEnabled - def state_control(self, CS): """Given the state, this function returns an actuators packet""" @@ -362,10 +379,12 @@ class Controls: if angle_control_saturated and not CS.steeringPressed and self.active: self.saturated_count += 1 + else: + self.saturated_count = 0 # Send a "steering required alert" if saturation count has reached the limit if (lac_log.saturated and not CS.steeringPressed) or \ - (self.saturated_count > STEER_ANGLE_SATURATION_TIMEOUT): + (self.saturated_count > STEER_ANGLE_SATURATION_TIMEOUT): # Check if we deviated from the path left_deviation = actuators.steer > 0 and path_plan.dPoly[3] > 0.1 right_deviation = actuators.steer < 0 and path_plan.dPoly[3] < -0.1 @@ -375,7 +394,6 @@ class Controls: return actuators, v_acc_sol, a_acc_sol, lac_log - def publish_logs(self, CS, start_time, actuators, v_acc, a_acc, lac_log): """Send actuators and hud commands to the car, send controlsstate and MPC logging""" diff --git a/selfdrive/controls/lib/alertmanager.py b/selfdrive/controls/lib/alertmanager.py index 42daff420f..870d8d4b7e 100644 --- a/selfdrive/controls/lib/alertmanager.py +++ b/selfdrive/controls/lib/alertmanager.py @@ -1,14 +1,34 @@ +import os +import copy +import json + from cereal import car, log +from common.basedir import BASEDIR +from common.params import Params from common.realtime import DT_CTRL from selfdrive.swaglog import cloudlog -import copy - AlertSize = log.ControlsState.AlertSize AlertStatus = log.ControlsState.AlertStatus VisualAlert = car.CarControl.HUDControl.VisualAlert AudibleAlert = car.CarControl.HUDControl.AudibleAlert + +with open(os.path.join(BASEDIR, "selfdrive/controls/lib/alerts_offroad.json")) as f: + OFFROAD_ALERTS = json.load(f) + + +def set_offroad_alert(alert, show_alert, extra_text=None): + if show_alert: + a = OFFROAD_ALERTS[alert] + if extra_text is not None: + a = copy.copy(OFFROAD_ALERTS[alert]) + a['text'] += extra_text + Params().put(alert, json.dumps(a)) + else: + Params().delete(alert) + + class AlertManager(): def __init__(self): diff --git a/selfdrive/controls/lib/alerts_offroad.json b/selfdrive/controls/lib/alerts_offroad.json index cebb1a2c26..f343f4cd5e 100644 --- a/selfdrive/controls/lib/alerts_offroad.json +++ b/selfdrive/controls/lib/alerts_offroad.json @@ -16,6 +16,11 @@ "text": "Connect to internet to check for updates. openpilot won't engage until it connects to internet to check for updates.", "severity": 1 }, + "Offroad_UpdateFailed": { + "text": "Unable to download updates\n", + "severity": 1, + "_comment": "Append the command and error to the text." + }, "Offroad_PandaFirmwareMismatch": { "text": "Unexpected panda firmware version. System won't start. Reboot your device to reflash panda.", "severity": 1 @@ -27,5 +32,9 @@ "Offroad_IsTakingSnapshot": { "text": "Taking camera snapshots. System won't start until finished.", "severity": 0 + }, + "Offroad_NeosUpdate": { + "text": "An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install.", + "severity": 0 } } diff --git a/selfdrive/controls/lib/cluster/fastcluster_dm.cpp b/selfdrive/controls/lib/cluster/fastcluster_dm.cpp index 8834bc24a0..ee6670c204 100644 --- a/selfdrive/controls/lib/cluster/fastcluster_dm.cpp +++ b/selfdrive/controls/lib/cluster/fastcluster_dm.cpp @@ -49,8 +49,8 @@ #ifdef NO_INCLUDE_FENV #pragma message("Do not use fenv header.") #else -#pragma message("Use fenv header. If there is a warning about unknown #pragma STDC FENV_ACCESS, this can be ignored.") -#pragma STDC FENV_ACCESS on +//#pragma message("Use fenv header. If there is a warning about unknown #pragma STDC FENV_ACCESS, this can be ignored.") +//#pragma STDC FENV_ACCESS on #include #endif diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index 629d072e82..ea7002475f 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -1,5 +1,6 @@ from common.numpy_fast import clip, interp from selfdrive.config import Conversions as CV +from cereal import car # kph V_CRUISE_MAX = 144 @@ -35,9 +36,9 @@ def update_v_cruise(v_cruise_kph, buttonEvents, enabled): # would have the effect of both enabling and changing speed is checked after the state transition for b in buttonEvents: if enabled and not b.pressed: - if b.type == "accelCruise": + if b.type == car.CarState.ButtonEvent.Type.accelCruise: v_cruise_kph += V_CRUISE_DELTA - (v_cruise_kph % V_CRUISE_DELTA) - elif b.type == "decelCruise": + elif b.type == car.CarState.ButtonEvent.Type.decelCruise: v_cruise_kph -= V_CRUISE_DELTA - ((V_CRUISE_DELTA - v_cruise_kph) % V_CRUISE_DELTA) v_cruise_kph = clip(v_cruise_kph, V_CRUISE_MIN, V_CRUISE_MAX) @@ -47,7 +48,7 @@ def update_v_cruise(v_cruise_kph, buttonEvents, enabled): def initialize_v_cruise(v_ego, buttonEvents, v_cruise_last): for b in buttonEvents: # 250kph or above probably means we never had a set speed - if b.type == "accelCruise" and v_cruise_last < 250: + if b.type == car.CarState.ButtonEvent.Type.accelCruise and v_cruise_last < 250: return v_cruise_last return int(round(clip(v_ego * CV.MS_TO_KPH, V_CRUISE_ENABLE_MIN, V_CRUISE_MAX))) diff --git a/selfdrive/controls/lib/driverview.py b/selfdrive/controls/lib/driverview.py deleted file mode 100755 index 298858bd4d..0000000000 --- a/selfdrive/controls/lib/driverview.py +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env python3 -import os -import subprocess -import multiprocessing -import signal -import time - -import cereal.messaging as messaging -from common.params import Params - -from common.basedir import BASEDIR - -KILL_TIMEOUT = 15 - -def send_controls_packet(pm): - while True: - dat = messaging.new_message('controlsState') - dat.controlsState = { - "rearViewCam": True, - } - pm.send('controlsState', dat) - -def send_dmon_packet(pm, d): - dat = messaging.new_message('dMonitoringState') - dat.dMonitoringState = { - "isRHD": d[0], - "rhdChecked": d[1], - "isPreview": d[2], - } - pm.send('dMonitoringState', dat) - -def main(): - pm = messaging.PubMaster(['controlsState', 'dMonitoringState']) - controls_sender = multiprocessing.Process(target=send_controls_packet, args=[pm]) - controls_sender.start() - - # TODO: refactor with manager start/kill - proc_cam = subprocess.Popen(os.path.join(BASEDIR, "selfdrive/camerad/camerad"), cwd=os.path.join(BASEDIR, "selfdrive/camerad")) - proc_mon = subprocess.Popen(os.path.join(BASEDIR, "selfdrive/modeld/dmonitoringmodeld"), cwd=os.path.join(BASEDIR, "selfdrive/modeld")) - - params = Params() - is_rhd = False - is_rhd_checked = False - should_exit = False - - def terminate(signalNumber, frame): - print('got SIGTERM, exiting..') - should_exit = True - send_dmon_packet(pm, [is_rhd, is_rhd_checked, not should_exit]) - proc_cam.send_signal(signal.SIGINT) - proc_mon.send_signal(signal.SIGINT) - kill_start = time.time() - while proc_cam.poll() is None: - if time.time() - kill_start > KILL_TIMEOUT: - from selfdrive.swaglog import cloudlog - cloudlog.critical("FORCE REBOOTING PHONE!") - os.system("date >> /sdcard/unkillable_reboot") - os.system("reboot") - raise RuntimeError - continue - controls_sender.terminate() - exit() - - signal.signal(signal.SIGTERM, terminate) - - while True: - send_dmon_packet(pm, [is_rhd, is_rhd_checked, not should_exit]) - - if not is_rhd_checked: - is_rhd = params.get("IsRHD") == b"1" - is_rhd_checked = True - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index 081ef0db81..193efc8c63 100644 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -1,7 +1,8 @@ -from cereal import log, car +from functools import total_ordering +from cereal import log, car +from common.realtime import DT_CTRL from selfdrive.config import Conversions as CV - from selfdrive.locationd.calibration_helpers import Filter AlertSize = log.ControlsState.AlertSize @@ -37,6 +38,7 @@ class Events: def __init__(self): self.events = [] self.static_events = [] + self.events_prev = dict.fromkeys(EVENTS.keys(), 0) @property def names(self): @@ -51,6 +53,7 @@ class Events: self.events.append(event_name) def clear(self): + self.events_prev = {k: (v+1 if k in self.events else 0) for k, v in self.events_prev.items()} self.events = self.static_events.copy() def any(self, event_type): @@ -59,7 +62,10 @@ class Events: return True return False - def create_alerts(self, event_types, callback_args=[]): + def create_alerts(self, event_types, callback_args=None): + if callback_args is None: + callback_args = [] + ret = [] for e in self.events: types = EVENTS[e].keys() @@ -68,8 +74,10 @@ class Events: alert = EVENTS[e][et] if not isinstance(alert, Alert): alert = alert(*callback_args) - alert.alert_type = EVENT_NAME[e] - ret.append(alert) + + if DT_CTRL * (self.events_prev[e] + 1) >= alert.creation_delay: + alert.alert_type = f"{EVENT_NAME[e]}/{et}" + ret.append(alert) return ret def add_from_msg(self, events): @@ -86,6 +94,7 @@ class Events: ret.append(event) return ret +@total_ordering class Alert: def __init__(self, alert_text_1, @@ -98,7 +107,8 @@ class Alert: duration_sound, duration_hud_alert, duration_text, - alert_rate=0.): + alert_rate=0., + creation_delay=0.): self.alert_type = "" self.alert_text_1 = alert_text_1 @@ -115,6 +125,7 @@ class Alert: self.start_time = 0. self.alert_rate = alert_rate + self.creation_delay = creation_delay # typecheck that enums are valid on startup tst = car.CarControl.new_message() @@ -127,6 +138,9 @@ class Alert: def __gt__(self, alert2): return self.alert_priority > alert2.alert_priority + def __eq__(self, alert2): + return self.alert_priority == alert2.alert_priority + class NoEntryAlert(Alert): def __init__(self, alert_text_2, audible_alert=AudibleAlert.chimeError, visual_alert=VisualAlert.none, duration_hud_alert=2.): @@ -157,29 +171,44 @@ class EngagementAlert(Alert): Priority.MID, VisualAlert.none, audible_alert, .2, 0., 0.), + +# ********** alert callback functions ********** + def below_steer_speed_alert(CP, sm, metric): - speed = CP.minSteerSpeed * (CV.MS_TO_KPH if metric else CV.MS_TO_MPH) - unit = "kph" if metric else "mph" + speed = int(round(CP.minSteerSpeed * (CV.MS_TO_KPH if metric else CV.MS_TO_MPH))) + unit = "km/h" if metric else "mph" return Alert( "TAKE CONTROL", "Steer Unavailable Below %d %s" % (speed, unit), AlertStatus.userPrompt, AlertSize.mid, - Priority.MID, VisualAlert.steerRequired, AudibleAlert.none, 0., 0.4, .3), + Priority.MID, VisualAlert.steerRequired, AudibleAlert.none, 0., 0.4, .3) def calibration_incomplete_alert(CP, sm, metric): speed = int(Filter.MIN_SPEED * (CV.MS_TO_KPH if metric else CV.MS_TO_MPH)) - unit = "kph" if metric else "mph" + unit = "km/h" if metric else "mph" return Alert( - "Calibration in Progress: %d" % sm['liveCalibration'].calPerc, + "Calibration in Progress: %d%%" % sm['liveCalibration'].calPerc, "Drive Above %d %s" % (speed, unit), AlertStatus.normal, AlertSize.mid, - Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0., 0., .2), + Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0., 0., .2) + +def no_gps_alert(CP, sm, metric): + gps_integrated = sm['health'].hwType in [log.HealthData.HwType.uno, log.HealthData.HwType.dos] + return Alert( + "Poor GPS reception", + "If sky is visible, contact support" if gps_integrated else "Check GPS antenna placement", + AlertStatus.normal, AlertSize.mid, + Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2, creation_delay=300.) + +def wrong_car_mode_alert(CP, sm, metric): + text = "Cruise Mode Disabled" + if CP.carName == "honda": + text = "Main Switch Off" + return NoEntryAlert(text, duration_hud_alert=0.) EVENTS = { # ********** events with no alerts ********** - EventName.gasPressed: {ET.PRE_ENABLE: None}, - # ********** events only containing alerts displayed in all states ********** EventName.debugAlert: { @@ -198,6 +227,14 @@ EVENTS = { Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.), }, + EventName.startupWhitePanda: { + ET.PERMANENT: Alert( + "WARNING: White panda is deprecated", + "Upgrade to comma two or black panda", + AlertStatus.userPrompt, AlertSize.mid, + Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.), + }, + EventName.startupMaster: { ET.PERMANENT: Alert( "WARNING: This branch is not tested", @@ -230,6 +267,15 @@ EVENTS = { Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), }, + EventName.whitePandaUnsupported: { + ET.PERMANENT: Alert( + "White Panda Is No Longer Supported", + "Upgrade to comma two or black panda", + AlertStatus.normal, AlertSize.mid, + Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), + ET.NO_ENTRY: NoEntryAlert("White panda is no longer supported"), + }, + EventName.invalidLkasSetting: { ET.PERMANENT: Alert( "Stock LKAS is turned on", @@ -253,7 +299,7 @@ EVENTS = { "Dashcam Mode", "Car Unrecognized", AlertStatus.normal, AlertSize.mid, - Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), + Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0., 0., .2), }, EventName.stockAeb: { @@ -290,6 +336,14 @@ EVENTS = { # ********** events only containing alerts that display while engaged ********** + EventName.gasPressed: { + ET.PRE_ENABLE: Alert( + "openpilot will not brake while gas pressed", + "", + AlertStatus.normal, AlertSize.small, + Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .0, .0, .1), + }, + EventName.vehicleModelInvalid: { ET.WARNING: Alert( "Vehicle Parameter Identification Failed", @@ -324,7 +378,7 @@ EVENTS = { EventName.driverDistracted: { ET.WARNING: Alert( - "DISEventName.AGE IMMEDIATELY", + "DISENGAGE IMMEDIATELY", "Driver Was Distracted", AlertStatus.critical, AlertSize.full, Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, .1, .1), @@ -348,7 +402,7 @@ EVENTS = { EventName.driverUnresponsive: { ET.WARNING: Alert( - "DISEventName.AGE IMMEDIATELY", + "DISENGAGE IMMEDIATELY", "Driver Was Unresponsive", AlertStatus.critical, AlertSize.full, Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, .1, .1), @@ -379,11 +433,7 @@ EVENTS = { }, EventName.belowSteerSpeed: { - ET.WARNING: Alert( - "TAKE CONTROL", - "Steer Unavailable Below ", - AlertStatus.userPrompt, AlertSize.mid, - Priority.MID, VisualAlert.steerRequired, AudibleAlert.none, 0., 0.4, .3), + ET.WARNING: below_steer_speed_alert, }, EventName.preLaneChangeLeft: { @@ -402,6 +452,14 @@ EVENTS = { Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .0, .1, .1, alert_rate=0.75), }, + EventName.laneChangeBlocked: { + ET.WARNING: Alert( + "Car Detected in Blindspot", + "Monitor Other Vehicles", + AlertStatus.normal, AlertSize.mid, + Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .0, .1, .1), + }, + EventName.laneChange: { ET.WARNING: Alert( "Changing Lane", @@ -454,8 +512,12 @@ EVENTS = { EventName.wrongCarMode: { ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage), - ET.NO_ENTRY: NoEntryAlert("Main Switch Off", - duration_hud_alert=0.), + ET.NO_ENTRY: wrong_car_mode_alert, + }, + + EventName.wrongCruiseMode: { + ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage), + ET.NO_ENTRY: NoEntryAlert("Enable Adaptive Cruise"), }, EventName.steerTempUnavailable: { @@ -468,13 +530,12 @@ EVENTS = { duration_hud_alert=0.), }, - EventName.posenetInvalid: { + EventName.focusRecoverActive: { ET.WARNING: Alert( "TAKE CONTROL", - "Vision Model Output Uncertain", + "Attempting Refocus: Camera Focus Invalid", AlertStatus.userPrompt, AlertSize.mid, Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimeWarning1, .4, 2., 3.), - ET.NO_ENTRY: NoEntryAlert("Vision Model Output Uncertain"), }, EventName.outOfSpace: { @@ -482,15 +543,32 @@ EVENTS = { duration_hud_alert=0.), }, + EventName.belowEngageSpeed: { + ET.NO_ENTRY: NoEntryAlert("Speed Too Low"), + }, + + EventName.neosUpdateRequired: { + ET.PERMANENT: Alert( + "NEOS Update Required", + "Please Wait for Update", + AlertStatus.normal, AlertSize.mid, + Priority.HIGHEST, VisualAlert.none, AudibleAlert.none, 0., 0., .2), + ET.NO_ENTRY: NoEntryAlert("NEOS Update Required"), + }, + EventName.sensorDataInvalid: { ET.PERMANENT: Alert( "No Data from Device Sensors", "Reboot your Device", AlertStatus.normal, AlertSize.mid, - Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), + Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2, creation_delay=1.), ET.NO_ENTRY: NoEntryAlert("No Data from Device Sensors"), }, + EventName.noGps: { + ET.PERMANENT: no_gps_alert, + }, + EventName.soundsUnavailable: { ET.PERMANENT: Alert( "Speaker not found", @@ -567,6 +645,21 @@ EVENTS = { ET.NO_ENTRY : NoEntryAlert("Radar Error: Restart the Car"), }, + EventName.modeldLagging: { + ET.SOFT_DISABLE: SoftDisableAlert("Driving model lagging"), + ET.NO_ENTRY : NoEntryAlert("Driving model lagging"), + }, + + EventName.posenetInvalid: { + ET.SOFT_DISABLE: SoftDisableAlert("Vision Model Output Uncertain"), + ET.NO_ENTRY: NoEntryAlert("Vision Model Output Uncertain"), + }, + + EventName.deviceFalling: { + ET.SOFT_DISABLE: SoftDisableAlert("Device Fell Off Mount"), + ET.NO_ENTRY: NoEntryAlert("Device Fell Off Mount"), + }, + EventName.lowMemory: { ET.SOFT_DISABLE: SoftDisableAlert("Low Memory: Reboot Your Device"), ET.PERMANENT: Alert( @@ -589,6 +682,11 @@ EVENTS = { EventName.canError: { ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("CAN Error: Check Connections"), + ET.PERMANENT: Alert( + "CAN Error: Check Connections", + "", + AlertStatus.normal, AlertSize.small, + Priority.LOW, VisualAlert.none, AudibleAlert.none, 0., 0., .2, creation_delay=1.), ET.NO_ENTRY: NoEntryAlert("CAN Error: Check Connections"), }, @@ -656,11 +754,10 @@ EVENTS = { "Speed too low", AlertStatus.normal, AlertSize.mid, Priority.HIGH, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.), - ET.NO_ENTRY: NoEntryAlert("Speed Too Low"), }, EventName.speedTooHigh: { - ET.IMMEDIATE_DISABLE: Alert( + ET.WARNING: Alert( "Speed Too High", "Slow down to resume operation", AlertStatus.normal, AlertSize.mid, diff --git a/selfdrive/controls/lib/latcontrol_indi.py b/selfdrive/controls/lib/latcontrol_indi.py index 91a5e2d6ae..8371d5ad3c 100644 --- a/selfdrive/controls/lib/latcontrol_indi.py +++ b/selfdrive/controls/lib/latcontrol_indi.py @@ -116,7 +116,7 @@ class LatControlINDI(): indi_log.delta = float(delta_u) indi_log.output = float(self.output_steer) - check_saturation = (CS.vEgo> 10.) and not CS.steeringRateLimited and not CS.steeringPressed + check_saturation = (CS.vEgo > 10.) and not CS.steeringRateLimited and not CS.steeringPressed indi_log.saturated = self._check_saturation(self.output_steer, check_saturation, steers_max) return float(self.output_steer), float(self.angle_steers_des), indi_log diff --git a/selfdrive/controls/lib/latcontrol_lqr.py b/selfdrive/controls/lib/latcontrol_lqr.py index a12aee2e93..cb54e52ebd 100644 --- a/selfdrive/controls/lib/latcontrol_lqr.py +++ b/selfdrive/controls/lib/latcontrol_lqr.py @@ -10,11 +10,11 @@ class LatControlLQR(): self.scale = CP.lateralTuning.lqr.scale self.ki = CP.lateralTuning.lqr.ki - self.A = np.array(CP.lateralTuning.lqr.a).reshape((2,2)) - self.B = np.array(CP.lateralTuning.lqr.b).reshape((2,1)) - self.C = np.array(CP.lateralTuning.lqr.c).reshape((1,2)) - self.K = np.array(CP.lateralTuning.lqr.k).reshape((1,2)) - self.L = np.array(CP.lateralTuning.lqr.l).reshape((2,1)) + self.A = np.array(CP.lateralTuning.lqr.a).reshape((2, 2)) + self.B = np.array(CP.lateralTuning.lqr.b).reshape((2, 1)) + self.C = np.array(CP.lateralTuning.lqr.c).reshape((1, 2)) + self.K = np.array(CP.lateralTuning.lqr.k).reshape((1, 2)) + self.L = np.array(CP.lateralTuning.lqr.l).reshape((2, 1)) self.dc_gain = CP.lateralTuning.lqr.dcGain self.x_hat = np.array([[0], [0]]) @@ -79,8 +79,8 @@ class LatControlLQR(): i = self.i_lqr + self.ki * self.i_rate * error control = lqr_output + i - if ((error >= 0 and (control <= steers_max or i < 0.0)) or \ - (error <= 0 and (control >= -steers_max or i > 0.0))): + if (error >= 0 and (control <= steers_max or i < 0.0)) or \ + (error <= 0 and (control >= -steers_max or i > 0.0)): self.i_lqr = i self.output_steer = lqr_output + self.i_lqr diff --git a/selfdrive/controls/lib/latcontrol_pid.py b/selfdrive/controls/lib/latcontrol_pid.py index 5662942b8f..aa069e81fc 100644 --- a/selfdrive/controls/lib/latcontrol_pid.py +++ b/selfdrive/controls/lib/latcontrol_pid.py @@ -8,7 +8,8 @@ class LatControlPID(): def __init__(self, CP): self.pid = PIController((CP.lateralTuning.pid.kpBP, CP.lateralTuning.pid.kpV), (CP.lateralTuning.pid.kiBP, CP.lateralTuning.pid.kiV), - k_f=CP.lateralTuning.pid.kf, pos_limit=1.0, sat_limit=CP.steerLimitTimer) + k_f=CP.lateralTuning.pid.kf, pos_limit=1.0, neg_limit=-1.0, + sat_limit=CP.steerLimitTimer) self.angle_steers_des = 0. def reset(self): diff --git a/selfdrive/controls/lib/longcontrol.py b/selfdrive/controls/lib/longcontrol.py index 2b4db2e7af..5262f480a7 100644 --- a/selfdrive/controls/lib/longcontrol.py +++ b/selfdrive/controls/lib/longcontrol.py @@ -24,7 +24,7 @@ def long_control_state_trans(active, long_control_state, v_ego, v_target, v_pid, output_gb, brake_pressed, cruise_standstill): """Update longitudinal control state machine""" stopping_condition = (v_ego < 2.0 and cruise_standstill) or \ - (v_ego < STOPPING_EGO_SPEED and \ + (v_ego < STOPPING_EGO_SPEED and ((v_pid < STOPPING_TARGET_SPEED and v_target < STOPPING_TARGET_SPEED) or brake_pressed)) @@ -85,7 +85,7 @@ class LongControl(): v_ego_pid = max(CS.vEgo, MIN_CAN_SPEED) # Without this we get jumps, CAN bus reports 0 when speed < 0.3 - if self.long_control_state == LongCtrlState.off: + if self.long_control_state == LongCtrlState.off or CS.gasPressed: self.v_pid = v_ego_pid self.pid.reset() output_gb = 0. diff --git a/selfdrive/controls/lib/pathplanner.py b/selfdrive/controls/lib/pathplanner.py index 413d71d3a2..375dea4735 100644 --- a/selfdrive/controls/lib/pathplanner.py +++ b/selfdrive/controls/lib/pathplanner.py @@ -87,7 +87,12 @@ class PathPlanner(): # Run MPC self.angle_steers_des_prev = self.angle_steers_des_mpc - VM.update_params(sm['liveParameters'].stiffnessFactor, sm['liveParameters'].steerRatio) + + # Update vehicle model + x = max(sm['liveParameters'].stiffnessFactor, 0.1) + sr = max(sm['liveParameters'].steerRatio, 0.1) + VM.update_params(x, sr) + curvature_factor = VM.curvature_factor(v_ego) self.LP.parse_model(sm['model']) @@ -106,9 +111,12 @@ class PathPlanner(): self.lane_change_direction = LaneChangeDirection.none else: torque_applied = sm['carState'].steeringPressed and \ - ((sm['carState'].steeringTorque > 0 and self.lane_change_direction == LaneChangeDirection.left) or \ + ((sm['carState'].steeringTorque > 0 and self.lane_change_direction == LaneChangeDirection.left) or (sm['carState'].steeringTorque < 0 and self.lane_change_direction == LaneChangeDirection.right)) + blindspot_detected = ((sm['carState'].leftBlindspot and self.lane_change_direction == LaneChangeDirection.left) or + (sm['carState'].rightBlindspot and self.lane_change_direction == LaneChangeDirection.right)) + lane_change_prob = self.LP.l_lane_change_prob + self.LP.r_lane_change_prob # State transitions @@ -121,13 +129,13 @@ class PathPlanner(): elif self.lane_change_state == LaneChangeState.preLaneChange: if not one_blinker or below_lane_change_speed: self.lane_change_state = LaneChangeState.off - elif torque_applied: + elif torque_applied and not blindspot_detected: self.lane_change_state = LaneChangeState.laneChangeStarting # starting elif self.lane_change_state == LaneChangeState.laneChangeStarting: - # fade out over .2s - self.lane_change_ll_prob = max(self.lane_change_ll_prob - DT_MDL/5, 0.0) + # fade out over .5s + self.lane_change_ll_prob = max(self.lane_change_ll_prob - 2*DT_MDL, 0.0) # 98% certainty if lane_change_prob < 0.02 and self.lane_change_ll_prob < 0.01: self.lane_change_state = LaneChangeState.laneChangeFinishing @@ -207,8 +215,6 @@ class PathPlanner(): plan_send.pathPlan.angleOffset = float(sm['liveParameters'].angleOffsetAverage) plan_send.pathPlan.mpcSolutionValid = bool(plan_solution_valid) plan_send.pathPlan.paramsValid = bool(sm['liveParameters'].valid) - plan_send.pathPlan.sensorValid = bool(sm['liveParameters'].sensorValid) - plan_send.pathPlan.posenetValid = bool(sm['liveParameters'].posenetValid) plan_send.pathPlan.desire = desire plan_send.pathPlan.laneChangeState = self.lane_change_state diff --git a/selfdrive/controls/lib/pid.py b/selfdrive/controls/lib/pid.py index fbd3885304..916b95c9ea 100644 --- a/selfdrive/controls/lib/pid.py +++ b/selfdrive/controls/lib/pid.py @@ -12,8 +12,8 @@ def apply_deadzone(error, deadzone): class PIController(): def __init__(self, k_p, k_i, k_f=1., pos_limit=None, neg_limit=None, rate=100, sat_limit=0.8, convert=None): - self._k_p = k_p # proportional gain - self._k_i = k_i # integral gain + self._k_p = k_p # proportional gain + self._k_i = k_i # integral gain self.k_f = k_f # feedforward gain self.pos_limit = pos_limit @@ -73,7 +73,7 @@ class PIController(): # Update when changing i will move the control away from the limits # or when i will move towards the sign of the error - if ((error >= 0 and (control <= self.pos_limit or i < 0.0)) or \ + if ((error >= 0 and (control <= self.pos_limit or i < 0.0)) or (error <= 0 and (control >= self.neg_limit or i > 0.0))) and \ not freeze_integrator: self.i = i diff --git a/selfdrive/controls/lib/planner.py b/selfdrive/controls/lib/planner.py index e88a8fe11b..553e5bb6fa 100755 --- a/selfdrive/controls/lib/planner.py +++ b/selfdrive/controls/lib/planner.py @@ -23,7 +23,7 @@ AWARENESS_DECEL = -0.2 # car smoothly decel at .2m/s^2 when user is distract # lookup tables VS speed to determine min and max accels in cruise # make sure these accelerations are smaller than mpc limits -_A_CRUISE_MIN_V = [-1.0, -.8, -.67, -.5, -.30] +_A_CRUISE_MIN_V = [-1.0, -.8, -.67, -.5, -.30] _A_CRUISE_MIN_BP = [ 0., 5., 10., 20., 40.] # need fast accel at very low speed for stop and go @@ -78,8 +78,6 @@ class Planner(): self.a_acc = 0.0 self.v_cruise = 0.0 self.a_cruise = 0.0 - self.v_model = 0.0 - self.a_model = 0.0 self.longitudinalPlanSource = 'cruise' self.fcw_checker = FCWChecker() @@ -90,7 +88,7 @@ class Planner(): def choose_solution(self, v_cruise_setpoint, enabled): if enabled: - solutions = {'model': self.v_model, 'cruise': self.v_cruise} + solutions = {'cruise': self.v_cruise} if self.mpc1.prev_lead_status: solutions['mpc1'] = self.mpc1.v_mpc if self.mpc2.prev_lead_status: @@ -109,9 +107,6 @@ class Planner(): elif slowest == 'cruise': self.v_acc = self.v_cruise self.a_acc = self.a_cruise - elif slowest == 'model': - self.v_acc = self.v_model - self.a_acc = self.a_model self.v_acc_future = min([self.mpc1.v_mpc_future, self.mpc2.v_mpc_future, v_cruise_setpoint]) @@ -133,26 +128,8 @@ class Planner(): enabled = (long_control_state == LongCtrlState.pid) or (long_control_state == LongCtrlState.stopping) following = lead_1.status and lead_1.dRel < 45.0 and lead_1.vLeadK > v_ego and lead_1.aLeadK > 0.0 - if len(sm['model'].path.poly): - path = list(sm['model'].path.poly) - - # Curvature of polynomial https://en.wikipedia.org/wiki/Curvature#Curvature_of_the_graph_of_a_function - # y = a x^3 + b x^2 + c x + d, y' = 3 a x^2 + 2 b x + c, y'' = 6 a x + 2 b - # k = y'' / (1 + y'^2)^1.5 - # TODO: compute max speed without using a list of points and without numpy - y_p = 3 * path[0] * self.path_x**2 + 2 * path[1] * self.path_x + path[2] - y_pp = 6 * path[0] * self.path_x + 2 * path[1] - curv = y_pp / (1. + y_p**2)**1.5 - - a_y_max = 2.975 - v_ego * 0.0375 # ~1.85 @ 75mph, ~2.6 @ 25mph - v_curvature = np.sqrt(a_y_max / np.clip(np.abs(curv), 1e-4, None)) - model_speed = np.min(v_curvature) - model_speed = max(20.0 * CV.MPH_TO_MS, model_speed) # Don't slow down below 20mph - else: - model_speed = MAX_SPEED - # Calculate speed for normal cruise control - if enabled and not self.first_loop: + if enabled and not self.first_loop and not sm['carState'].gasPressed: accel_limits = [float(x) for x in calc_cruise_accel_limits(v_ego, following)] jerk_limits = [min(-0.1, accel_limits[0]), max(0.1, accel_limits[1])] # TODO: make a separate lookup for jerk tuning accel_limits_turns = limit_accel_in_turns(v_ego, sm['carState'].steeringAngle, accel_limits, self.CP) @@ -168,12 +145,6 @@ class Planner(): jerk_limits[1], jerk_limits[0], LON_MPC_STEP) - self.v_model, self.a_model = speed_smoother(self.v_acc_start, self.a_acc_start, - model_speed, - 2*accel_limits[1], accel_limits[0], - 2*jerk_limits[1], jerk_limits[0], - LON_MPC_STEP) - # cruise speed can't be negative even is user is distracted self.v_cruise = max(self.v_cruise, 0.) else: diff --git a/selfdrive/controls/lib/speed_smoother.py b/selfdrive/controls/lib/speed_smoother.py index 1ee7ec6b18..431822dd9f 100644 --- a/selfdrive/controls/lib/speed_smoother.py +++ b/selfdrive/controls/lib/speed_smoother.py @@ -67,7 +67,7 @@ def speed_smoother(vEgo, aEgo, vT, aMax, aMin, jMax, jMin, ts): if aPeak > aMax: aPeak = aMax t1 = (aPeak - aEgo) / jMax - if aPeak <= 0: # there is no solution, so stop after t1 + if aPeak <= 0: # there is no solution, so stop after t1 t2 = t1 + ts + 1e-9 t3 = t2 else: diff --git a/selfdrive/controls/lib/vehicle_model.py b/selfdrive/controls/lib/vehicle_model.py index 6ac5f856f4..dc3d1f4b25 100755 --- a/selfdrive/controls/lib/vehicle_model.py +++ b/selfdrive/controls/lib/vehicle_model.py @@ -1,7 +1,4 @@ #!/usr/bin/env python3 -import numpy as np -from numpy.linalg import solve - """ Dynamic bycicle model from "The Science of Vehicle Dynamics (2014), M. Guiggiani" @@ -15,83 +12,14 @@ x_dot = A*x + B*u A depends on longitudinal speed, u [m/s], and vehicle parameters CP """ +import numpy as np +from numpy.linalg import solve +from typing import Tuple +from cereal import car -def create_dyn_state_matrices(u, VM): - """Returns the A and B matrix for the dynamics system - - Args: - u: Vehicle speed [m/s] - VM: Vehicle model - - Returns: - A tuple with the 2x2 A matrix, and 2x1 B matrix - - Parameters in the vehicle model: - cF: Tire stiffnes Front [N/rad] - cR: Tire stiffnes Front [N/rad] - aF: Distance from CG to front wheels [m] - aR: Distance from CG to rear wheels [m] - m: Mass [kg] - j: Rotational inertia [kg m^2] - sR: Steering ratio [-] - chi: Steer ratio rear [-] - """ - A = np.zeros((2, 2)) - B = np.zeros((2, 1)) - A[0, 0] = - (VM.cF + VM.cR) / (VM.m * u) - A[0, 1] = - (VM.cF * VM.aF - VM.cR * VM.aR) / (VM.m * u) - u - A[1, 0] = - (VM.cF * VM.aF - VM.cR * VM.aR) / (VM.j * u) - A[1, 1] = - (VM.cF * VM.aF**2 + VM.cR * VM.aR**2) / (VM.j * u) - B[0, 0] = (VM.cF + VM.chi * VM.cR) / VM.m / VM.sR - B[1, 0] = (VM.cF * VM.aF - VM.chi * VM.cR * VM.aR) / VM.j / VM.sR - return A, B - - -def kin_ss_sol(sa, u, VM): - """Calculate the steady state solution at low speeds - At low speeds the tire slip is undefined, so a kinematic - model is used. - - Args: - sa: Steering angle [rad] - u: Speed [m/s] - VM: Vehicle model - - Returns: - 2x1 matrix with steady state solution - """ - K = np.zeros((2, 1)) - K[0, 0] = VM.aR / VM.sR / VM.l * u - K[1, 0] = 1. / VM.sR / VM.l * u - return K * sa - - -def dyn_ss_sol(sa, u, VM): - """Calculate the steady state solution when x_dot = 0, - Ax + Bu = 0 => x = A^{-1} B u - - Args: - sa: Steering angle [rad] - u: Speed [m/s] - VM: Vehicle model - - Returns: - 2x1 matrix with steady state solution - """ - A, B = create_dyn_state_matrices(u, VM) - return -solve(A, B) * sa - - -def calc_slip_factor(VM): - """The slip factor is a measure of how the curvature changes with speed - it's positive for Oversteering vehicle, negative (usual case) otherwise. - """ - return VM.m * (VM.cF * VM.aF - VM.cR * VM.aR) / (VM.l**2 * VM.cF * VM.cR) - - -class VehicleModel(): - def __init__(self, CP): +class VehicleModel: + def __init__(self, CP: car.CarParams): """ Args: CP: Car Parameters @@ -108,13 +36,13 @@ class VehicleModel(): self.cR_orig = CP.tireStiffnessRear self.update_params(1.0, CP.steerRatio) - def update_params(self, stiffness_factor, steer_ratio): + def update_params(self, stiffness_factor: float, steer_ratio: float) -> None: """Update the vehicle model with a new stiffness factor and steer ratio""" self.cF = stiffness_factor * self.cF_orig self.cR = stiffness_factor * self.cR_orig self.sR = steer_ratio - def steady_state_sol(self, sa, u): + def steady_state_sol(self, sa: float, u: float) -> np.ndarray: """Returns the steady state solution. If the speed is too small we can't use the dynamic model (tire slip is undefined), @@ -132,7 +60,7 @@ class VehicleModel(): else: return kin_ss_sol(sa, u, self) - def calc_curvature(self, sa, u): + def calc_curvature(self, sa: float, u: float) -> float: """Returns the curvature. Multiplied by the speed this will give the yaw rate. Args: @@ -144,7 +72,7 @@ class VehicleModel(): """ return self.curvature_factor(u) * sa / self.sR - def curvature_factor(self, u): + def curvature_factor(self, u: float) -> float: """Returns the curvature factor. Multiplied by wheel angle (not steering wheel angle) this will give the curvature. @@ -157,7 +85,7 @@ class VehicleModel(): sf = calc_slip_factor(self) return (1. - self.chi) / (1. - sf * u**2) / self.l - def get_steer_from_curvature(self, curv, u): + def get_steer_from_curvature(self, curv: float, u: float) -> float: """Calculates the required steering wheel angle for a given curvature Args: @@ -170,7 +98,7 @@ class VehicleModel(): return curv * self.sR * 1.0 / self.curvature_factor(u) - def get_steer_from_yaw_rate(self, yaw_rate, u): + def get_steer_from_yaw_rate(self, yaw_rate: float, u: float) -> float: """Calculates the required steering wheel angle for a given yaw_rate Args: @@ -183,7 +111,7 @@ class VehicleModel(): curv = yaw_rate / u return self.get_steer_from_curvature(curv, u) - def yaw_rate(self, sa, u): + def yaw_rate(self, sa: float, u: float) -> float: """Calculate yaw rate Args: @@ -195,3 +123,75 @@ class VehicleModel(): """ return self.calc_curvature(sa, u) * u + +def kin_ss_sol(sa: float, u: float, VM: VehicleModel) -> np.ndarray: + """Calculate the steady state solution at low speeds + At low speeds the tire slip is undefined, so a kinematic + model is used. + + Args: + sa: Steering angle [rad] + u: Speed [m/s] + VM: Vehicle model + + Returns: + 2x1 matrix with steady state solution + """ + K = np.zeros((2, 1)) + K[0, 0] = VM.aR / VM.sR / VM.l * u + K[1, 0] = 1. / VM.sR / VM.l * u + return K * sa + + +def create_dyn_state_matrices(u: float, VM: VehicleModel) -> Tuple[np.ndarray, np.ndarray]: + """Returns the A and B matrix for the dynamics system + + Args: + u: Vehicle speed [m/s] + VM: Vehicle model + + Returns: + A tuple with the 2x2 A matrix, and 2x1 B matrix + + Parameters in the vehicle model: + cF: Tire stiffnes Front [N/rad] + cR: Tire stiffnes Front [N/rad] + aF: Distance from CG to front wheels [m] + aR: Distance from CG to rear wheels [m] + m: Mass [kg] + j: Rotational inertia [kg m^2] + sR: Steering ratio [-] + chi: Steer ratio rear [-] + """ + A = np.zeros((2, 2)) + B = np.zeros((2, 1)) + A[0, 0] = - (VM.cF + VM.cR) / (VM.m * u) + A[0, 1] = - (VM.cF * VM.aF - VM.cR * VM.aR) / (VM.m * u) - u + A[1, 0] = - (VM.cF * VM.aF - VM.cR * VM.aR) / (VM.j * u) + A[1, 1] = - (VM.cF * VM.aF**2 + VM.cR * VM.aR**2) / (VM.j * u) + B[0, 0] = (VM.cF + VM.chi * VM.cR) / VM.m / VM.sR + B[1, 0] = (VM.cF * VM.aF - VM.chi * VM.cR * VM.aR) / VM.j / VM.sR + return A, B + + +def dyn_ss_sol(sa: float, u: float, VM: VehicleModel) -> np.ndarray: + """Calculate the steady state solution when x_dot = 0, + Ax + Bu = 0 => x = A^{-1} B u + + Args: + sa: Steering angle [rad] + u: Speed [m/s] + VM: Vehicle model + + Returns: + 2x1 matrix with steady state solution + """ + A, B = create_dyn_state_matrices(u, VM) + return -solve(A, B) * sa + + +def calc_slip_factor(VM): + """The slip factor is a measure of how the curvature changes with speed + it's positive for Oversteering vehicle, negative (usual case) otherwise. + """ + return VM.m * (VM.cF * VM.aF - VM.cR * VM.aR) / (VM.l**2 * VM.cF * VM.cR) diff --git a/selfdrive/controls/plannerd.py b/selfdrive/controls/plannerd.py index 21ea32a51a..b439681a3a 100755 --- a/selfdrive/controls/plannerd.py +++ b/selfdrive/controls/plannerd.py @@ -15,7 +15,7 @@ def plannerd_thread(sm=None, pm=None): gc.disable() # start the loop - set_realtime_priority(2) + set_realtime_priority(52) cloudlog.info("plannerd is waiting for CarParams") CP = car.CarParams.from_bytes(Params().get("CarParams", block=True)) diff --git a/selfdrive/controls/radard.py b/selfdrive/controls/radard.py index 0b8523313f..0ba14dcf26 100755 --- a/selfdrive/controls/radard.py +++ b/selfdrive/controls/radard.py @@ -52,7 +52,7 @@ def match_vision_to_cluster(v_ego, lead, clusters): # if no 'sane' match is found return -1 # stationary radar points can be false positives dist_sane = abs(cluster.dRel - offset_vision_dist) < max([(offset_vision_dist)*.25, 5.0]) - vel_sane = (abs(cluster.vRel - lead.relVel) < 10) or (v_ego + cluster.vRel > 2) + vel_sane = (abs(cluster.vRel - lead.relVel) < 10) or (v_ego + cluster.vRel > 3) if dist_sane and vel_sane: return cluster else: @@ -91,9 +91,6 @@ class RadarD(): self.tracks = defaultdict(dict) self.kalman_params = KalmanParams(radar_ts) - self.last_md_ts = 0 - self.last_controls_state_ts = 0 - self.active = 0 # v_ego @@ -136,7 +133,6 @@ class RadarD(): idens = list(sorted(self.tracks.keys())) track_pts = list([self.tracks[iden].get_key_for_cluster() for iden in idens]) - # If we have multiple points, cluster them if len(track_pts) > 1: cluster_idxs = cluster_points_centroid(track_pts, 2.5) @@ -165,10 +161,10 @@ class RadarD(): # *** publish radarState *** dat = messaging.new_message('radarState') dat.valid = sm.all_alive_and_valid(service_list=['controlsState', 'model']) - dat.radarState.mdMonoTime = self.last_md_ts + dat.radarState.mdMonoTime = sm.logMonoTime['model'] dat.radarState.canMonoTimes = list(rr.canMonoTimes) dat.radarState.radarErrors = list(rr.errors) - dat.radarState.controlsStateMonoTime = self.last_controls_state_ts + dat.radarState.controlsStateMonoTime = sm.logMonoTime['controlsState'] if has_radar: dat.radarState.leadOne = get_lead(self.v_ego, self.ready, clusters, sm['model'].lead, low_speed_override=True) @@ -178,7 +174,7 @@ class RadarD(): # fuses camera and radar data for best lead detection def radard_thread(sm=None, pm=None, can_sock=None): - set_realtime_priority(2) + set_realtime_priority(52) # wait for stats about the car to come in from controls cloudlog.info("radard is waiting for CarParams") diff --git a/selfdrive/controls/tests/test_events.py b/selfdrive/controls/tests/test_alerts.py similarity index 56% rename from selfdrive/controls/tests/test_events.py rename to selfdrive/controls/tests/test_alerts.py index 79662b719e..5f3a962cfa 100755 --- a/selfdrive/controls/tests/test_events.py +++ b/selfdrive/controls/tests/test_alerts.py @@ -1,16 +1,27 @@ #!/usr/bin/env python3 +import json import os import unittest +import random from PIL import Image, ImageDraw, ImageFont from cereal import log, car from common.basedir import BASEDIR +from common.params import Params from selfdrive.controls.lib.events import Alert, EVENTS +from selfdrive.controls.lib.alertmanager import set_offroad_alert AlertSize = log.ControlsState.AlertSize +OFFROAD_ALERTS_PATH = os.path.join(BASEDIR, "selfdrive/controls/lib/alerts_offroad.json") + class TestAlerts(unittest.TestCase): + @classmethod + def setUpClass(cls): + with open(OFFROAD_ALERTS_PATH) as f: + cls.offroad_alerts = json.loads(f.read()) + def test_events_defined(self): # Ensure all events in capnp schema are defined in events.py events = car.CarEvent.EventName.schema.enumerants @@ -27,16 +38,16 @@ class TestAlerts(unittest.TestCase): bold_font_path = os.path.join(font_path, "opensans_semibold.ttf") semibold_font_path = os.path.join(font_path, "opensans_semibold.ttf") - max_text_width = 1920 - 300 # full screen width is useable, minus sidebar + max_text_width = 1920 - 300 # full screen width is useable, minus sidebar # TODO: get exact scale factor. found this empirically, works well enough - font_scale_factor = 1.85 # factor to scale from nanovg units to PIL + font_scale_factor = 1.85 # factor to scale from nanovg units to PIL draw = ImageDraw.Draw(Image.new('RGB', (0, 0))) fonts = { - AlertSize.small: [ImageFont.truetype(semibold_font_path, int(40*font_scale_factor))], - AlertSize.mid: [ImageFont.truetype(bold_font_path, int(48*font_scale_factor)), - ImageFont.truetype(regular_font_path, int(36*font_scale_factor))], + AlertSize.small: [ImageFont.truetype(semibold_font_path, int(40 * font_scale_factor))], + AlertSize.mid: [ImageFont.truetype(bold_font_path, int(48 * font_scale_factor)), + ImageFont.truetype(regular_font_path, int(36 * font_scale_factor))], } alerts = [] @@ -52,12 +63,37 @@ class TestAlerts(unittest.TestCase): continue for i, txt in enumerate([alert.alert_text_1, alert.alert_text_2]): - if i >= len(fonts[alert.alert_size]): break + if i >= len(fonts[alert.alert_size]): + break font = fonts[alert.alert_size][i] - w, h = draw.textsize(txt, font) + w, _ = draw.textsize(txt, font) msg = "type: %s msg: %s" % (alert.alert_type, txt) self.assertLessEqual(w, max_text_width, msg=msg) + def test_offroad_alerts(self): + params = Params() + for a in self.offroad_alerts: + # set the alert + alert = self.offroad_alerts[a] + set_offroad_alert(a, True) + self.assertTrue(json.dumps(alert) == params.get(a, encoding='utf8')) + + # then delete it + set_offroad_alert(a, False) + self.assertTrue(params.get(a) is None) + + def test_offroad_alerts_extra_text(self): + params = Params() + for i in range(50): + # set the alert + a = random.choice(list(self.offroad_alerts)) + alert = self.offroad_alerts[a] + set_offroad_alert(a, True, extra_text="a"*i) + + expected_txt = alert['text'] + "a"*i + written_txt = json.loads(params.get(a, encoding='utf8'))['text'] + self.assertTrue(expected_txt == written_txt) + if __name__ == "__main__": unittest.main() diff --git a/selfdrive/controls/tests/test_clustering.py b/selfdrive/controls/tests/test_clustering.py index e899ff7d57..290b267029 100644 --- a/selfdrive/controls/tests/test_clustering.py +++ b/selfdrive/controls/tests/test_clustering.py @@ -1,3 +1,5 @@ +# pylint: skip-file + import time import unittest import numpy as np diff --git a/selfdrive/crash.py b/selfdrive/crash.py index a8cb758a7e..7459f71668 100644 --- a/selfdrive/crash.py +++ b/selfdrive/crash.py @@ -9,12 +9,15 @@ from selfdrive.swaglog import cloudlog from common.android import ANDROID if os.getenv("NOLOG") or os.getenv("NOCRASH") or not ANDROID: - def capture_exception(*exc_info): + def capture_exception(*args, **kwargs): pass + def bind_user(**kwargs): pass + def bind_extra(**kwargs): pass + def install(): pass else: @@ -36,20 +39,21 @@ else: client.extra_context(kwargs) def install(): + """ + Workaround for `sys.excepthook` thread bug from: + http://bugs.python.org/issue1230540 + Call once from the main thread before creating any threads. + Source: https://stackoverflow.com/a/31622038 + """ # installs a sys.excepthook __excepthook__ = sys.excepthook + def handle_exception(*exc_info): if exc_info[0] not in (KeyboardInterrupt, SystemExit): capture_exception() __excepthook__(*exc_info) sys.excepthook = handle_exception - """ - Workaround for `sys.excepthook` thread bug from: - http://bugs.python.org/issue1230540 - Call once from the main thread before creating any threads. - Source: https://stackoverflow.com/a/31622038 - """ init_original = threading.Thread.__init__ def init(self, *args, **kwargs): diff --git a/selfdrive/debug/can_printer.py b/selfdrive/debug/can_printer.py index f06db79545..7ea26d62fc 100755 --- a/selfdrive/debug/can_printer.py +++ b/selfdrive/debug/can_printer.py @@ -25,9 +25,9 @@ def can_printer(bus=0, max_msg=None, addr="127.0.0.1"): if sec_since_boot() - lp > 0.1: dd = chr(27) + "[2J" dd += "%5.2f\n" % (sec_since_boot() - start) - for k,v in sorted(zip(msgs.keys(), map(lambda x: binascii.hexlify(x[-1]), msgs.values()))): + for k, v in sorted(zip(msgs.keys(), map(lambda x: binascii.hexlify(x[-1]), msgs.values()))): if max_msg is None or k < max_msg: - dd += "%s(%6d) %s\n" % ("%04X(%4d)" % (k,k),len(msgs[k]), v.decode('ascii')) + dd += "%s(%6d) %s\n" % ("%04X(%4d)" % (k, k), len(msgs[k]), v.decode('ascii')) print(dd) lp = sec_since_boot() diff --git a/selfdrive/debug/check_freq.py b/selfdrive/debug/check_freq.py index 75c0b8f89a..fd4f510c2b 100755 --- a/selfdrive/debug/check_freq.py +++ b/selfdrive/debug/check_freq.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +# type: ignore + import argparse import numpy as np from collections import defaultdict, deque diff --git a/selfdrive/debug/check_lag.py b/selfdrive/debug/check_lag.py index 418f1f872b..c922642982 100755 --- a/selfdrive/debug/check_lag.py +++ b/selfdrive/debug/check_lag.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +# type: ignore + import cereal.messaging as messaging from cereal.services import service_list diff --git a/selfdrive/debug/compare_fingerprints.py b/selfdrive/debug/compare_fingerprints.py index a0c80a740e..5b7ba58b1e 100755 --- a/selfdrive/debug/compare_fingerprints.py +++ b/selfdrive/debug/compare_fingerprints.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +# flake8: noqa # put 2 fingeprints and print the diffs f1 = { diff --git a/selfdrive/debug/cpu_usage_stat.py b/selfdrive/debug/cpu_usage_stat.py index d59a148558..28cabe6c8c 100755 --- a/selfdrive/debug/cpu_usage_stat.py +++ b/selfdrive/debug/cpu_usage_stat.py @@ -1,17 +1,9 @@ #!/usr/bin/env python3 -import psutil -import time -import os -import sys -import numpy as np -import argparse -import re -from collections import defaultdict - +# type: ignore ''' System tools like top/htop can only show current cpu usage values, so I write this script to do statistics jobs. Features: - Use psutil library to sample cpu usage(avergage for all cores) of OpenPilot processes, at a rate of 5 samples/sec. + Use psutil library to sample cpu usage(avergage for all cores) of openpilot processes, at a rate of 5 samples/sec. Do cpu usage statistics periodically, 5 seconds as a cycle. Caculate the average cpu usage within this cycle. Caculate minumium/maximium/accumulated_average cpu usage as long term inspections. @@ -23,18 +15,28 @@ System tools like top/htop can only show current cpu usage values, so I write th boardd: 1.96%, min: 1.96%, max: 1.96%, acc: 1.96% ubloxd.py: 0.39%, min: 0.39%, max: 0.39%, acc: 0.39% ''' +import psutil +import time +import os +import sys +import numpy as np +import argparse +import re +from collections import defaultdict + # Do statistics every 5 seconds PRINT_INTERVAL = 5 SLEEP_INTERVAL = 0.2 monitored_proc_names = [ - 'ubloxd', 'thermald', 'uploader', 'deleter', 'controlsd', 'plannerd', 'radard', 'mapd', 'loggerd' , 'logmessaged', 'tombstoned', - 'logcatd', 'proclogd', 'boardd', 'pandad', './ui', 'ui', 'calibrationd', 'params_learner', 'modeld', 'dmonitoringmodeld', 'camerad', 'sensord', 'updated', 'gpsd', 'athena'] + 'ubloxd', 'thermald', 'uploader', 'deleter', 'controlsd', 'plannerd', 'radard', 'mapd', 'loggerd', 'logmessaged', 'tombstoned', + 'logcatd', 'proclogd', 'boardd', 'pandad', './ui', 'ui', 'calibrationd', 'params_learner', 'modeld', 'dmonitoringd', 'dmonitoringmodeld', 'camerad', 'sensord', 'updated', 'gpsd', 'athena', 'locationd', 'paramsd'] cpu_time_names = ['user', 'system', 'children_user', 'children_system'] timer = getattr(time, 'monotonic', time.time) + def get_arg_parser(): parser = argparse.ArgumentParser( description="Unlogger and UI", @@ -68,7 +70,7 @@ if __name__ == "__main__": k = ' '.join(p.cmdline()) print('Add monitored proc:', k) stats[k] = {'cpu_samples': defaultdict(list), 'min': defaultdict(lambda: None), 'max': defaultdict(lambda: None), - 'avg': defaultdict(lambda: 0.0), 'last_cpu_times': None, 'last_sys_time':None} + 'avg': defaultdict(lambda: 0.0), 'last_cpu_times': None, 'last_sys_time': None} stats[k]['last_sys_time'] = timer() stats[k]['last_cpu_times'] = p.cpu_times() monitored_procs.append(p) @@ -112,7 +114,7 @@ if __name__ == "__main__": for stat_type in ['avg', 'min', 'max']: msg += '\n {}: {}'.format(stat_type, [name + ':' + str(round(stat[stat_type][name]*100, 2)) for name in cpu_time_names]) l.append((os.path.basename(k), stat['avg']['total'], msg)) - l.sort(key= lambda x: -x[1]) + l.sort(key=lambda x: -x[1]) for x in l: print(x[2]) print('avg sum: {0:.2%} over {1} samples {2} seconds\n'.format( diff --git a/selfdrive/debug/cycle_alerts.py b/selfdrive/debug/cycle_alerts.py new file mode 100755 index 0000000000..63b7d758c5 --- /dev/null +++ b/selfdrive/debug/cycle_alerts.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +# flake8: noqa +# pylint: skip-file +# type: ignore + +import argparse +import time + +import cereal.messaging as messaging +from selfdrive.controls.lib.events import EVENTS, Alert + +def now_millis(): return time.time() * 1000 + +ALERTS = [a for _, et in EVENTS.items() for _, a in et.items() if isinstance(a, Alert)] + +#from cereal import car +#ALERTS = [a for a in ALERTS if a.audible_alert == car.CarControl.HUDControl.AudibleAlert.chimeWarningRepeat] + +default_alerts = sorted(ALERTS, key=lambda alert: (alert.alert_size, len(alert.alert_text_2))) + +def cycle_alerts(duration_millis, alerts=None): + if alerts is None: + alerts = default_alerts + + controls_state = messaging.pub_sock('controlsState') + + idx, last_alert_millis = 0, 0 + alert = alerts[0] + while 1: + if (now_millis() - last_alert_millis) > duration_millis: + alert = alerts[idx] + idx = (idx + 1) % len(alerts) + last_alert_millis = now_millis() + print('sending {}'.format(str(alert))) + + dat = messaging.new_message() + dat.init('controlsState') + + dat.controlsState.alertType = alert.alert_type + dat.controlsState.alertText1 = alert.alert_text_1 + dat.controlsState.alertText2 = alert.alert_text_2 + dat.controlsState.alertSize = alert.alert_size + #dat.controlsState.alertStatus = alert.alert_status + dat.controlsState.alertSound = alert.audible_alert + controls_state.send(dat.to_bytes()) + + time.sleep(0.01) + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--duration', type=int, default=1000) + parser.add_argument('--alert-types', nargs='+') + args = parser.parse_args() + alerts = None + if args.alert_types: + alerts = [next(a for a in ALERTS if a.alert_type==alert_type) for alert_type in args.alert_types] + + cycle_alerts(args.duration, alerts=alerts) diff --git a/selfdrive/debug/dump.py b/selfdrive/debug/dump.py index 26ce350530..112ca96a93 100755 --- a/selfdrive/debug/dump.py +++ b/selfdrive/debug/dump.py @@ -29,7 +29,7 @@ if __name__ == "__main__": poller = messaging.Poller() for m in args.socket if len(args.socket) > 0 else service_list: - sock = messaging.sub_sock(m, poller, addr=args.addr) + messaging.sub_sock(m, poller, addr=args.addr) values = None if args.values: @@ -61,4 +61,11 @@ if __name__ == "__main__": print("{} = {}".format(".".join(value), item)) print("") else: - print(evt) + try: + print(evt) + except UnicodeDecodeError: + w = evt.which() + s = f"( logMonoTime {evt.logMonoTime} \n {w} = " + s += str(evt.__getattr__(w)) + s += f"\n valid = {evt.valid} )" + print(s) diff --git a/selfdrive/debug/internal/check_alive_valid.py b/selfdrive/debug/internal/check_alive_valid.py index cee03d6a37..cd8a2463eb 100755 --- a/selfdrive/debug/internal/check_alive_valid.py +++ b/selfdrive/debug/internal/check_alive_valid.py @@ -6,12 +6,10 @@ import cereal.messaging as messaging if __name__ == "__main__": sm = messaging.SubMaster(['thermal', 'health', 'model', 'liveCalibration', 'dMonitoringState', 'plan', 'pathPlan']) - i = 0 while True: sm.update(0) - i += 1 if i % 100 == 0: print() diff --git a/selfdrive/debug/internal/cycle_alerts.py b/selfdrive/debug/internal/cycle_alerts.py deleted file mode 100644 index cc073aaa29..0000000000 --- a/selfdrive/debug/internal/cycle_alerts.py +++ /dev/null @@ -1,50 +0,0 @@ -# USAGE: python cycle_alerts.py [duration_millis=1000] -# Then start manager - -import argparse -import time - -import cereal.messaging as messaging -from selfdrive.controls.lib.alerts import ALERTS - -def now_millis(): return time.time() * 1000 - -default_alerts = sorted(ALERTS, key=lambda alert: (alert.alert_size, len(alert.alert_text_2))) - -def cycle_alerts(duration_millis, alerts=None): - if alerts is None: - alerts = default_alerts - - controls_state = messaging.pub_sock('controlsState') - - last_pop_millis = now_millis() - alert = alerts.pop() - while 1: - if (now_millis() - last_pop_millis) > duration_millis: - alerts.insert(0, alert) - alert = alerts.pop() - last_pop_millis = now_millis() - print('sending {}'.format(str(alert))) - - dat = messaging.new_message('controlsState') - - dat.controlsState.alertType = alert.alert_type - dat.controlsState.alertText1 = alert.alert_text_1 - dat.controlsState.alertText2 = alert.alert_text_2 - dat.controlsState.alertSize = alert.alert_size - dat.controlsState.alertStatus = alert.alert_status - dat.controlsState.alertSound = alert.audible_alert - controls_state.send(dat.to_bytes()) - - time.sleep(0.01) - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--duration', type=int, default=1000) - parser.add_argument('--alert-types', nargs='+') - args = parser.parse_args() - alerts = None - if args.alert_types: - alerts = [next(a for a in ALERTS if a.alert_type==alert_type) for alert_type in args.alert_types] - - cycle_alerts(args.duration, alerts=alerts) diff --git a/selfdrive/debug/internal/design_lqr.py b/selfdrive/debug/internal/design_lqr.py index 0304df5aa1..e86926f607 100755 --- a/selfdrive/debug/internal/design_lqr.py +++ b/selfdrive/debug/internal/design_lqr.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 import numpy as np -import control +import control # pylint: disable=import-error dt = 0.01 A = np.array([[ 0. , 1. ], [-0.78823806, 1.78060701]]) diff --git a/selfdrive/debug/internal/get_fingerprint_from_route.py b/selfdrive/debug/internal/get_fingerprint_from_route.py index 42df3029c9..2a0f99fab2 100755 --- a/selfdrive/debug/internal/get_fingerprint_from_route.py +++ b/selfdrive/debug/internal/get_fingerprint_from_route.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 +# type: ignore import sys from tools.lib.logreader import MultiLogIterator -from xx.chffr.lib.route import Route +from xx.chffr.lib.route import Route # pylint: disable=import-error def get_fingerprint(lr): diff --git a/selfdrive/debug/internal/measure_modeld_packet_drop.py b/selfdrive/debug/internal/measure_modeld_packet_drop.py new file mode 100755 index 0000000000..457771df0e --- /dev/null +++ b/selfdrive/debug/internal/measure_modeld_packet_drop.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +import cereal.messaging as messaging + +if __name__ == "__main__": + modeld_sock = messaging.sub_sock("model") + + last_frame_id = None + start_t = None + frame_cnt = 0 + dropped = 0 + + while True: + m = messaging.recv_one(modeld_sock) + frame_id = m.model.frameId + t = m.logMonoTime / 1e9 + frame_cnt += 1 + + if start_t is None: + start_t = t + last_frame_id = frame_id + continue + + d_frame = frame_id - last_frame_id + dropped += d_frame - 1 + + expected_num_frames = int((t - start_t) * 20) + frame_drop = 100 * (1 - (expected_num_frames / frame_cnt)) + print(f"Num dropped {dropped}, Drop compared to 20Hz: {frame_drop:.2f}%") + + last_frame_id = frame_id diff --git a/selfdrive/debug/internal/measure_steering_accuracy.py b/selfdrive/debug/internal/measure_steering_accuracy.py index fabf8030d1..706af73989 100755 --- a/selfdrive/debug/internal/measure_steering_accuracy.py +++ b/selfdrive/debug/internal/measure_steering_accuracy.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +# type: ignore + import os import argparse import signal @@ -28,7 +30,7 @@ if __name__ == "__main__": stats = defaultdict(lambda: {'err': 0, "cnt": 0, "=": 0, "+": 0, "-": 0}) cnt = 0 total_error = 0 - + while messaging.recv_one(carControl): sm.update() msg_cnt += 1 diff --git a/selfdrive/debug/internal/measure_torque_time_to_max.py b/selfdrive/debug/internal/measure_torque_time_to_max.py index d1beeae44d..58a29532cd 100755 --- a/selfdrive/debug/internal/measure_torque_time_to_max.py +++ b/selfdrive/debug/internal/measure_torque_time_to_max.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +# type: ignore + import os import argparse import struct diff --git a/selfdrive/debug/internal/power_monitor.py b/selfdrive/debug/internal/power_monitor.py index 74a7e2ba0d..3377088f8b 100755 --- a/selfdrive/debug/internal/power_monitor.py +++ b/selfdrive/debug/internal/power_monitor.py @@ -17,7 +17,7 @@ if __name__ == '__main__': print("disabling charging") os.system('echo "0" > /sys/class/power_supply/battery/charging_enabled') - voltage_average = (0., 0) # average, count + voltage_average = (0., 0) # average, count current_average = (0., 0) power_average = (0., 0) capacity_average = (0., 0) diff --git a/selfdrive/debug/internal/replay_drive_can.py b/selfdrive/debug/internal/replay_drive_can.py index 7fc5dceeb0..05b7137977 100755 --- a/selfdrive/debug/internal/replay_drive_can.py +++ b/selfdrive/debug/internal/replay_drive_can.py @@ -6,12 +6,12 @@ from tools.lib.logreader import LogReader import cereal.messaging as messaging ROUTE = "77611a1fac303767/2020-03-24--09-50-38" -NUM_SEGS = 82 +NUM_SEGS = 10 # route has 82 segments available # Get can messages from logs print("Loading...") can_msgs = [] -for i in tqdm(list(range(NUM_SEGS))): +for i in tqdm(list(range(1, NUM_SEGS))): log_url = f"https://commadataci.blob.core.windows.net/openpilotci/{ROUTE}/{i}/rlog.bz2" lr = LogReader(log_url) can_msgs += [m for m in lr if m.which() == 'can'] diff --git a/selfdrive/debug/internal/sensor_test_bootloop.py b/selfdrive/debug/internal/sensor_test_bootloop.py index 041905544e..9e89add6bb 100755 --- a/selfdrive/debug/internal/sensor_test_bootloop.py +++ b/selfdrive/debug/internal/sensor_test_bootloop.py @@ -32,7 +32,7 @@ except Exception: sys.exit(-1) sensord_env = {**os.environ, 'SENSOR_TEST': '1'} -process = subprocess.run("./sensord", cwd="/data/openpilot/selfdrive/sensord", env=sensord_env) +process = subprocess.run("./sensord", cwd="/data/openpilot/selfdrive/sensord", env=sensord_env) # pylint: disable=subprocess-run-check if process.returncode == 40: text = "Current run: SUCCESS\n" @@ -45,7 +45,7 @@ else: with open('/tmp/dmesg-' + timestr + '.log', 'w') as dmesg_out: subprocess.call('dmesg', stdout=dmesg_out, shell=False) with open("/tmp/logcat-" + timestr + '.log', 'w') as logcat_out: - subprocess.call(['logcat','-d'], stdout=logcat_out, shell=False) + subprocess.call(['logcat', '-d'], stdout=logcat_out, shell=False) text += "Sensor pass history: " + str(data['sensor-pass']) + "\n" text += "Sensor fail history: " + str(data['sensor-fail']) + "\n" diff --git a/selfdrive/debug/internal/sounds/set_volume.sh b/selfdrive/debug/internal/sounds/set_volume.sh new file mode 100755 index 0000000000..b25a421822 --- /dev/null +++ b/selfdrive/debug/internal/sounds/set_volume.sh @@ -0,0 +1,6 @@ +#!/usr/bin/bash +while true +do + service call audio 3 i32 3 i32 $1 i32 1 + sleep 1 +done diff --git a/selfdrive/debug/internal/sounds/test_sound_stability.py b/selfdrive/debug/internal/sounds/test_sound_stability.py index 18b87abb2e..2b86622081 100755 --- a/selfdrive/debug/internal/sounds/test_sound_stability.py +++ b/selfdrive/debug/internal/sounds/test_sound_stability.py @@ -6,7 +6,7 @@ import datetime import random from common.basedir import BASEDIR -from selfdrive import messaging +import cereal.messaging as messaging if __name__ == "__main__": diff --git a/selfdrive/debug/internal/test_paramsd.py b/selfdrive/debug/internal/test_paramsd.py index 356edfaef6..fa8c31ef1e 100755 --- a/selfdrive/debug/internal/test_paramsd.py +++ b/selfdrive/debug/internal/test_paramsd.py @@ -1,7 +1,10 @@ #!/usr/bin/env python3 +# pylint: skip-file + import numpy as np import math from tqdm import tqdm +from typing import cast import seaborn as sns import matplotlib.pyplot as plt @@ -32,7 +35,7 @@ speeds = 10 * np.sin(2 * np.pi * ts / 200.) + 25 angle_offsets = math.radians(1.0) * np.ones_like(ts) angle_offsets[ts > 60] = 0 -steering_angles = np.radians(5 * np.cos(2 * np.pi * ts / 100.)) +steering_angles = cast(np.ndarray, np.radians(5 * np.cos(2 * np.pi * ts / 100.))) xs = [] ys = [] diff --git a/selfdrive/debug/mpc/live_lateral_mpc.py b/selfdrive/debug/mpc/live_lateral_mpc.py index 48be5be9c6..7cd5c677a2 100755 --- a/selfdrive/debug/mpc/live_lateral_mpc.py +++ b/selfdrive/debug/mpc/live_lateral_mpc.py @@ -55,7 +55,6 @@ def mpc_vwr_thread(addr="127.0.0.1"): aa.invert_xaxis() plt.show() - # *** log *** livempc = messaging.sub_sock('liveMpc', addr=addr) model = messaging.sub_sock('model', addr=addr) @@ -81,10 +80,10 @@ def mpc_vwr_thread(addr="127.0.0.1"): lineP.set_ydata(path_x) if lMpc is not None: - mpc_path_x = list(lMpc.liveMpc.x)[1:] - mpc_path_y = list(lMpc.liveMpc.y)[1:] - mpc_steer_angle = list(lMpc.liveMpc.delta)[1:] - mpc_psi = list(lMpc.liveMpc.psi)[1:] + mpc_path_x = list(lMpc.liveMpc.x)[1:] + mpc_path_y = list(lMpc.liveMpc.y)[1:] + mpc_steer_angle = list(lMpc.liveMpc.delta)[1:] + mpc_psi = list(lMpc.liveMpc.psi)[1:] line1.set_xdata(mpc_path_y) line1.set_ydata(mpc_path_x) diff --git a/selfdrive/debug/mpc/live_longitudinal_mpc.py b/selfdrive/debug/mpc/live_longitudinal_mpc.py index b5b4361e13..4861a03ede 100755 --- a/selfdrive/debug/mpc/live_longitudinal_mpc.py +++ b/selfdrive/debug/mpc/live_longitudinal_mpc.py @@ -97,8 +97,6 @@ def plot_longitudinal_mpc(addr="127.0.0.1"): fig.canvas.flush_events() - - if __name__ == "__main__": if len(sys.argv) > 1: plot_longitudinal_mpc(sys.argv[1]) diff --git a/selfdrive/debug/mpc/test_mpc_wobble.py b/selfdrive/debug/mpc/test_mpc_wobble.py index 5f9f1b3355..6117779d8b 100755 --- a/selfdrive/debug/mpc/test_mpc_wobble.py +++ b/selfdrive/debug/mpc/test_mpc_wobble.py @@ -1,4 +1,5 @@ #! /usr/bin/env python +# type: ignore import matplotlib.pyplot as plt from selfdrive.controls.lib.lateral_mpc import libmpc_py from selfdrive.controls.lib.drive_helpers import MPC_COST_LAT diff --git a/selfdrive/debug/mpc/tune_lateral.py b/selfdrive/debug/mpc/tune_lateral.py index 4a8ec2ce0b..f01865574b 100755 --- a/selfdrive/debug/mpc/tune_lateral.py +++ b/selfdrive/debug/mpc/tune_lateral.py @@ -1,4 +1,6 @@ #! /usr/bin/env python +# type: ignore + import numpy as np from collections import OrderedDict import matplotlib.pyplot as plt @@ -149,7 +151,6 @@ ys.append(sol_y) deltas.append(delta) - plt.figure() for i in range(len(xs)): diff --git a/selfdrive/debug/mpc/tune_longitudinal.py b/selfdrive/debug/mpc/tune_longitudinal.py index ed3eb6378a..f7fd43c48d 100755 --- a/selfdrive/debug/mpc/tune_longitudinal.py +++ b/selfdrive/debug/mpc/tune_longitudinal.py @@ -1,4 +1,5 @@ #! /usr/bin/env python +# type: ignore import numpy as np import matplotlib.pyplot as plt from selfdrive.controls.lib.longitudinal_mpc import libmpc_py diff --git a/selfdrive/debug/test_fw_query_on_routes.py b/selfdrive/debug/test_fw_query_on_routes.py index 2e668046e9..6ca5436e9c 100755 --- a/selfdrive/debug/test_fw_query_on_routes.py +++ b/selfdrive/debug/test_fw_query_on_routes.py @@ -1,4 +1,7 @@ #!/usr/bin/env python3 +# type: ignore + +from collections import defaultdict import argparse import os import traceback @@ -7,9 +10,11 @@ from tools.lib.logreader import LogReader from selfdrive.car.fw_versions import match_fw_to_car from selfdrive.car.toyota.values import FW_VERSIONS as TOYOTA_FW_VERSIONS from selfdrive.car.honda.values import FW_VERSIONS as HONDA_FW_VERSIONS +from selfdrive.car.hyundai.values import FW_VERSIONS as HYUNDAI_FW_VERSIONS from selfdrive.car.toyota.values import FINGERPRINTS as TOYOTA_FINGERPRINTS from selfdrive.car.honda.values import FINGERPRINTS as HONDA_FINGERPRINTS +from selfdrive.car.hyundai.values import FINGERPRINTS as HYUNDAI_FINGERPRINTS if __name__ == "__main__": @@ -23,6 +28,8 @@ if __name__ == "__main__": else: routes = [args.route] + mismatches = defaultdict(list) + wrong = 0 good = 0 @@ -45,6 +52,8 @@ if __name__ == "__main__": break elif msg.which() == "carParams": + bts = msg.carParams.as_builder().to_bytes() + car_fw = msg.carParams.carFw if len(car_fw) == 0: break @@ -55,7 +64,7 @@ if __name__ == "__main__": if args.car is not None: live_fingerprint = args.car - if live_fingerprint not in list(TOYOTA_FINGERPRINTS.keys()) + list(HONDA_FINGERPRINTS.keys()): + if live_fingerprint not in list(TOYOTA_FINGERPRINTS.keys()) + list(HONDA_FINGERPRINTS.keys()) + list(HYUNDAI_FINGERPRINTS.keys()): continue candidates = match_fw_to_car(car_fw) @@ -73,9 +82,10 @@ if __name__ == "__main__": print(f" (Ecu.{version.ecu}, {hex(version.address)}, {subaddr}): [{version.fwVersion}],") print("Mismatches") - for car_fws in [TOYOTA_FW_VERSIONS, HONDA_FW_VERSIONS]: + found = False + for car_fws in [TOYOTA_FW_VERSIONS, HONDA_FW_VERSIONS, HYUNDAI_FW_VERSIONS]: if live_fingerprint in car_fws: - + found = True expected = car_fws[live_fingerprint] for (_, expected_addr, expected_sub_addr), v in expected.items(): for version in car_fw: @@ -86,11 +96,42 @@ if __name__ == "__main__": if version.fwVersion not in v: print(f"({hex(addr)}, {'None' if sub_addr is None else hex(sub_addr)}) - {version.fwVersion}") + # Add to global list of mismatches + mismatch = (addr, sub_addr, version.fwVersion) + if mismatch not in mismatches[live_fingerprint]: + mismatches[live_fingerprint].append(mismatch) + + # No FW versions for this car yet, add them all to mismatch list + if not found: + for version in car_fw: + sub_addr = None if version.subAddress == 0 else version.subAddress + addr = version.address + mismatch = (addr, sub_addr, version.fwVersion) + if mismatch not in mismatches[live_fingerprint]: + mismatches[live_fingerprint].append(mismatch) + print() wrong += 1 break except Exception: traceback.print_exc() + except KeyboardInterrupt: + break print(f"Fingerprinted: {good} - Not fingerprinted: {wrong}") print(f"Number of dongle ids checked: {len(dongles)}") + print() + + # Print FW versions that need to be added seperated out by car and address + for car, m in mismatches.items(): + print(car) + addrs = defaultdict(list) + for (addr, sub_addr, version) in m: + addrs[(addr, sub_addr)].append(version) + + for (addr, sub_addr), versions in addrs.items(): + print(f" ({hex(addr)}, {'None' if sub_addr is None else hex(sub_addr)}): [") + for v in versions: + print(f" {v},") + print(" ]") + print() diff --git a/selfdrive/debug/uiview.py b/selfdrive/debug/uiview.py new file mode 100644 index 0000000000..899f932ad6 --- /dev/null +++ b/selfdrive/debug/uiview.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +import time +import cereal.messaging as messaging +from selfdrive.manager import start_managed_process, kill_managed_process + +services = ['controlsState', 'thermal'] # the services needed to be spoofed to start ui offroad +procs = ['camerad', 'ui'] +[start_managed_process(p) for p in procs] # start needed processes +pm = messaging.PubMaster(services) + +dat_cs, dat_thermal = [messaging.new_message(s) for s in services] +dat_cs.controlsState.rearViewCam = False # ui checks for these two messages +dat_thermal.thermal.started = True + +try: + while True: + pm.send('controlsState', dat_cs) + pm.send('thermal', dat_thermal) + time.sleep(1 / 100) # continually send, rate doesn't matter for thermal +except KeyboardInterrupt: + [kill_managed_process(p) for p in procs] diff --git a/selfdrive/launcher.py b/selfdrive/launcher.py index 8253347d6b..dcedf07167 100644 --- a/selfdrive/launcher.py +++ b/selfdrive/launcher.py @@ -1,5 +1,5 @@ import importlib -from setproctitle import setproctitle #pylint: disable=no-name-in-module +from setproctitle import setproctitle # pylint: disable=no-name-in-module import cereal.messaging as messaging import selfdrive.crash as crash diff --git a/selfdrive/locationd/SConscript b/selfdrive/locationd/SConscript index 29b5d00d01..59516574d8 100644 --- a/selfdrive/locationd/SConscript +++ b/selfdrive/locationd/SConscript @@ -1,12 +1,6 @@ -Import('env', 'common', 'messaging') -loc_objs = [ - "locationd_yawrate.cc", - "params_learner.cc", - "paramsd.cc"] -loc_libs = [messaging, 'zmq', common, 'capnp', 'kj', 'json11', 'pthread'] +Import('env', 'common', 'cereal', 'messaging') -env.Program("paramsd", loc_objs, LIBS=loc_libs) -env.SharedLibrary("locationd", loc_objs, LIBS=loc_libs) +loc_libs = [cereal, messaging, 'zmq', common, 'capnp', 'kj', 'pthread'] env.Program("ubloxd", [ "ubloxd.cc", diff --git a/selfdrive/locationd/calibration_helpers.py b/selfdrive/locationd/calibration_helpers.py index f290900759..c7886d3019 100644 --- a/selfdrive/locationd/calibration_helpers.py +++ b/selfdrive/locationd/calibration_helpers.py @@ -1,11 +1,10 @@ import math class Filter: - MIN_SPEED = 7 # m/s (~15.5mph) - MAX_YAW_RATE = math.radians(3) # per second + MIN_SPEED = 7 # m/s (~15.5mph) + MAX_YAW_RATE = math.radians(3) # per second class Calibration: UNCALIBRATED = 0 CALIBRATED = 1 INVALID = 2 - diff --git a/selfdrive/locationd/calibrationd.py b/selfdrive/locationd/calibrationd.py index e7836c05ca..a27e284a9c 100755 --- a/selfdrive/locationd/calibrationd.py +++ b/selfdrive/locationd/calibrationd.py @@ -24,22 +24,21 @@ INPUTS_WANTED = 50 # We want a little bit more than we need for stability WRITE_CYCLES = 10 # write every 1000 cycles VP_INIT = np.array([W/2., H/2.]) -# These validity corners were chosen by looking at 1000 -# and taking most extreme cases with some margin. -VP_VALIDITY_CORNERS = np.array([[W//2 - 120, 300], [W//2 + 120, 520]]) +# These values are needed to accomodate biggest modelframe +VP_VALIDITY_CORNERS = np.array([[W//2 - 63, 300], [W//2 + 63, 520]]) DEBUG = os.getenv("DEBUG") is not None def is_calibration_valid(vp): - return vp[0] > VP_VALIDITY_CORNERS[0,0] and vp[0] < VP_VALIDITY_CORNERS[1,0] and \ - vp[1] > VP_VALIDITY_CORNERS[0,1] and vp[1] < VP_VALIDITY_CORNERS[1,1] + return vp[0] > VP_VALIDITY_CORNERS[0, 0] and vp[0] < VP_VALIDITY_CORNERS[1, 0] and \ + vp[1] > VP_VALIDITY_CORNERS[0, 1] and vp[1] < VP_VALIDITY_CORNERS[1, 1] def sanity_clip(vp): if np.isnan(vp).any(): vp = VP_INIT - return np.array([np.clip(vp[0], VP_VALIDITY_CORNERS[0,0] - 20, VP_VALIDITY_CORNERS[1,0] + 20), - np.clip(vp[1], VP_VALIDITY_CORNERS[0,1] - 20, VP_VALIDITY_CORNERS[1,1] + 20)]) + return np.array([np.clip(vp[0], VP_VALIDITY_CORNERS[0, 0] - 5, VP_VALIDITY_CORNERS[1, 0] + 5), + np.clip(vp[1], VP_VALIDITY_CORNERS[0, 1] - 5, VP_VALIDITY_CORNERS[1, 1] + 5)]) def intrinsics_from_vp(vp): @@ -69,10 +68,7 @@ class Calibrator(): if calibration_params: try: calibration_params = json.loads(calibration_params) - if 'calib_radians' in calibration_params: - self.vp = vp_from_rpy(calibration_params["calib_radians"]) - else: - self.vp = np.array(calibration_params["vanishing_point"]) + self.vp = vp_from_rpy(calibration_params["calib_radians"]) if not np.isfinite(self.vp).all(): self.vp = copy.copy(VP_INIT) self.vps = np.tile(self.vp, (INPUTS_WANTED, 1)) @@ -92,7 +88,7 @@ class Calibrator(): end_status = self.cal_status self.just_calibrated = False - if start_status == Calibration.UNCALIBRATED and end_status == Calibration.CALIBRATED: + if start_status == Calibration.UNCALIBRATED and end_status != Calibration.UNCALIBRATED: self.just_calibrated = True def handle_v_ego(self, v_ego): @@ -130,13 +126,21 @@ class Calibrator(): def send_data(self, pm): calib = get_calib_from_vp(self.vp) + if self.valid_blocks > 0: + max_vp_calib = np.array(get_calib_from_vp(np.max(self.vps[:self.valid_blocks], axis=0))) + min_vp_calib = np.array(get_calib_from_vp(np.min(self.vps[:self.valid_blocks], axis=0))) + calib_spread = np.abs(max_vp_calib - min_vp_calib) + else: + calib_spread = np.zeros(3) extrinsic_matrix = get_view_frame_from_road_frame(0, calib[1], calib[2], model_height) cal_send = messaging.new_message('liveCalibration') + cal_send.liveCalibration.validBlocks = self.valid_blocks cal_send.liveCalibration.calStatus = self.cal_status cal_send.liveCalibration.calPerc = min(100 * (self.valid_blocks * BLOCK_SIZE + self.idx) // (INPUTS_NEEDED * BLOCK_SIZE), 100) cal_send.liveCalibration.extrinsicMatrix = [float(x) for x in extrinsic_matrix.flatten()] cal_send.liveCalibration.rpyCalib = [float(x) for x in calib] + cal_send.liveCalibration.rpyCalibSpread = [float(x) for x in calib_spread] pm.send('liveCalibration', cal_send) @@ -171,12 +175,9 @@ def calibrationd_thread(sm=None, pm=None): sm['cameraOdometry'].transStd, sm['cameraOdometry'].rotStd) - if DEBUG and new_vp is not None: print('got new vp', new_vp) - # decimate outputs for efficiency - def main(sm=None, pm=None): calibrationd_thread(sm, pm) diff --git a/selfdrive/locationd/liblocationd_py.py b/selfdrive/locationd/liblocationd_py.py deleted file mode 100644 index d9f71b8c30..0000000000 --- a/selfdrive/locationd/liblocationd_py.py +++ /dev/null @@ -1,29 +0,0 @@ -import os -from common.basedir import BASEDIR - -from cffi import FFI - -locationd_dir = os.path.dirname(os.path.abspath(__file__)) -liblocationd_fn = os.path.join(locationd_dir, "liblocationd.so") - - -ffi = FFI() -ffi.cdef(""" -void *localizer_init(void); -void localizer_handle_log(void * localizer, const unsigned char * data, size_t len); -double localizer_get_yaw(void * localizer); -double localizer_get_bias(void * localizer); -double localizer_get_t(void * localizer); -void *params_learner_init(size_t len, char * params, double angle_offset, double stiffness_factor, double steer_ratio, double learning_rate); -bool params_learner_update(void * params_learner, double psi, double u, double sa); -double params_learner_get_ao(void * params_learner); -double params_learner_get_slow_ao(void * params_learner); -double params_learner_get_x(void * params_learner); -double params_learner_get_sR(void * params_learner); -double * localizer_get_P(void * localizer); -void localizer_set_P(void * localizer, double * P); -double * localizer_get_state(void * localizer); -void localizer_set_state(void * localizer, double * state); -""") - -liblocationd = ffi.dlopen(liblocationd_fn) diff --git a/selfdrive/locationd/locationd.py b/selfdrive/locationd/locationd.py index 7075fdf3f0..be78176844 100755 --- a/selfdrive/locationd/locationd.py +++ b/selfdrive/locationd/locationd.py @@ -1,16 +1,13 @@ #!/usr/bin/env python3 -import math - import numpy as np import sympy as sp - import cereal.messaging as messaging import common.transformations.coordinates as coord -from common.transformations.orientation import (ecef_euler_from_ned, - euler_from_quat, - ned_euler_from_ecef, - quat_from_euler, - rot_from_quat, rot_from_euler) +from common.transformations.orientation import ecef_euler_from_ned, \ + euler_from_quat, \ + ned_euler_from_ecef, \ + quat_from_euler, euler_from_rot, \ + rot_from_quat, rot_from_euler from rednose.helpers import KalmanError from selfdrive.locationd.models.live_kf import LiveKalman, States, ObservationKind from selfdrive.locationd.models.constants import GENERATED_DIR @@ -25,6 +22,7 @@ from rednose.helpers.sympy_helpers import euler_rotate VISION_DECIMATION = 2 SENSOR_DECIMATION = 10 +POSENET_STD_HIST = 40 def to_float(arr): @@ -48,10 +46,13 @@ def get_H(): class Localizer(): - def __init__(self, disabled_logs=[], dog=None): + def __init__(self, disabled_logs=None, dog=None): + if disabled_logs is None: + disabled_logs = [] + self.kf = LiveKalman(GENERATED_DIR) self.reset_kalman() - self.max_age = .2 # seconds + self.max_age = .1 # seconds self.disabled_logs = disabled_logs self.calib = np.zeros(3) self.device_from_calib = np.eye(3) @@ -59,6 +60,17 @@ class Localizer(): self.calibrated = 0 self.H = get_H() + self.posenet_invalid_count = 0 + self.posenet_speed = 0 + self.car_speed = 0 + self.posenet_stds = 10*np.ones((POSENET_STD_HIST)) + + self.converter = coord.LocalCoord.from_ecef(self.kf.x[States.ECEF_POS]) + + self.unix_timestamp_millis = 0 + self.last_gps_fix = 0 + self.device_fell = False + @staticmethod def msg_from_state(converter, calib_from_device, H, predicted_state, predicted_cov): predicted_std = np.sqrt(np.diagonal(predicted_cov)) @@ -71,6 +83,8 @@ class Localizer(): #fix_pos_geo_std = np.abs(coord.ecef2geodetic(fix_ecef + fix_ecef_std) - fix_pos_geo) orientation_ecef = euler_from_quat(predicted_state[States.ECEF_ORIENTATION]) orientation_ecef_std = predicted_std[States.ECEF_ORIENTATION_ERR] + device_from_ecef = rot_from_quat(predicted_state[States.ECEF_ORIENTATION]).T + calibrated_orientation_ecef = euler_from_rot(calib_from_device.dot(device_from_ecef)) acc_calib = calib_from_device.dot(predicted_state[States.ACCELERATION]) acc_calib_std = np.sqrt(np.diagonal(calib_from_device.dot( @@ -81,11 +95,11 @@ class Localizer(): predicted_cov[States.ANGULAR_VELOCITY_ERR, States.ANGULAR_VELOCITY_ERR]).dot( calib_from_device.T))) - device_from_ecef = rot_from_quat(predicted_state[States.ECEF_ORIENTATION]).T vel_device = device_from_ecef.dot(vel_ecef) device_from_ecef_eul = euler_from_quat(predicted_state[States.ECEF_ORIENTATION]).T - idxs = list(range(States.ECEF_ORIENTATION_ERR.start, States.ECEF_ORIENTATION_ERR.stop)) + list(range(States.ECEF_VELOCITY_ERR.start, States.ECEF_VELOCITY_ERR.stop)) - condensed_cov = predicted_cov[idxs][:,idxs] + idxs = list(range(States.ECEF_ORIENTATION_ERR.start, States.ECEF_ORIENTATION_ERR.stop)) + \ + list(range(States.ECEF_VELOCITY_ERR.start, States.ECEF_VELOCITY_ERR.stop)) + condensed_cov = predicted_cov[idxs][:, idxs] HH = H(*list(np.concatenate([device_from_ecef_eul, vel_ecef]))) vel_device_cov = HH.dot(condensed_cov).dot(HH.T) vel_device_std = np.sqrt(np.diagonal(vel_device_cov)) @@ -100,117 +114,103 @@ class Localizer(): #ned_vel_std = self.converter.ecef2ned(fix_ecef + vel_ecef + vel_ecef_std) - self.converter.ecef2ned(fix_ecef + vel_ecef) fix = messaging.log.LiveLocationKalman.new_message() - fix.positionGeodetic.value = to_float(fix_pos_geo) - #fix.positionGeodetic.std = to_float(fix_pos_geo_std) - #fix.positionGeodetic.valid = True - fix.positionECEF.value = to_float(fix_ecef) - fix.positionECEF.std = to_float(fix_ecef_std) - fix.positionECEF.valid = True - fix.velocityECEF.value = to_float(vel_ecef) - fix.velocityECEF.std = to_float(vel_ecef_std) - fix.velocityECEF.valid = True - fix.velocityNED.value = to_float(ned_vel) - #fix.velocityNED.std = to_float(ned_vel_std) - #fix.velocityNED.valid = True - fix.velocityDevice.value = to_float(vel_device) - fix.velocityDevice.std = to_float(vel_device_std) - fix.velocityDevice.valid = True - fix.accelerationDevice.value = to_float(predicted_state[States.ACCELERATION]) - fix.accelerationDevice.std = to_float(predicted_std[States.ACCELERATION_ERR]) - fix.accelerationDevice.valid = True - - fix.orientationECEF.value = to_float(orientation_ecef) - fix.orientationECEF.std = to_float(orientation_ecef_std) - fix.orientationECEF.valid = True - fix.orientationNED.value = to_float(orientation_ned) - #fix.orientationNED.std = to_float(orientation_ned_std) - #fix.orientationNED.valid = True - fix.angularVelocityDevice.value = to_float(predicted_state[States.ANGULAR_VELOCITY]) - fix.angularVelocityDevice.std = to_float(predicted_std[States.ANGULAR_VELOCITY_ERR]) - fix.angularVelocityDevice.valid = True - - fix.velocityCalibrated.value = to_float(vel_calib) - fix.velocityCalibrated.std = to_float(vel_calib_std) - fix.velocityCalibrated.valid = True - fix.angularVelocityCalibrated.value = to_float(ang_vel_calib) - fix.angularVelocityCalibrated.std = to_float(ang_vel_calib_std) - fix.angularVelocityCalibrated.valid = True - fix.accelerationCalibrated.value = to_float(acc_calib) - fix.accelerationCalibrated.std = to_float(acc_calib_std) - fix.accelerationCalibrated.valid = True + + # write measurements to msg + measurements = [ + # measurement field, value, std, valid + (fix.positionGeodetic, fix_pos_geo, np.nan*np.zeros(3), True), + (fix.positionECEF, fix_ecef, fix_ecef_std, True), + (fix.velocityECEF, vel_ecef, vel_ecef_std, True), + (fix.velocityNED, ned_vel, np.nan*np.zeros(3), True), + (fix.velocityDevice, vel_device, vel_device_std, True), + (fix.accelerationDevice, predicted_state[States.ACCELERATION], predicted_std[States.ACCELERATION_ERR], True), + (fix.orientationECEF, orientation_ecef, orientation_ecef_std, True), + (fix.calibratedOrientationECEF, calibrated_orientation_ecef, np.nan*np.zeros(3), True), + (fix.orientationNED, orientation_ned, np.nan*np.zeros(3), True), + (fix.angularVelocityDevice, predicted_state[States.ANGULAR_VELOCITY], predicted_std[States.ANGULAR_VELOCITY_ERR], True), + (fix.velocityCalibrated, vel_calib, vel_calib_std, True), + (fix.angularVelocityCalibrated, ang_vel_calib, ang_vel_calib_std, True), + (fix.accelerationCalibrated, acc_calib, acc_calib_std, True), + ] + + for field, value, std, valid in measurements: + # TODO: can we write the lists faster? + field.value = to_float(value) + field.std = to_float(std) + field.valid = valid + return fix - def liveLocationMsg(self, time): + def liveLocationMsg(self): fix = self.msg_from_state(self.converter, self.calib_from_device, self.H, self.kf.x, self.kf.P) + # experimentally found these values, no false positives in 20k minutes of driving + old_mean, new_mean = np.mean(self.posenet_stds[:POSENET_STD_HIST//2]), np.mean(self.posenet_stds[POSENET_STD_HIST//2:]) + std_spike = new_mean/old_mean > 4 and new_mean > 7 + + fix.posenetOK = not (std_spike and self.car_speed > 5) + fix.deviceStable = not self.device_fell + self.device_fell = False #fix.gpsWeek = self.time.week #fix.gpsTimeOfWeek = self.time.tow fix.unixTimestampMillis = self.unix_timestamp_millis - if self.filter_ready and self.calibrated: + if np.linalg.norm(fix.positionECEF.std) < 50 and self.calibrated: fix.status = 'valid' - elif self.filter_ready: + elif np.linalg.norm(fix.positionECEF.std) < 50: fix.status = 'uncalibrated' else: fix.status = 'uninitialized' return fix - def update_kalman(self, time, kind, meas): - if self.filter_ready: - try: - self.kf.predict_and_observe(time, kind, meas) - except KalmanError: - cloudlog.error("Error in predict and observe, kalman reset") - self.reset_kalman() - #idx = bisect_right([x[0] for x in self.observation_buffer], time) - #self.observation_buffer.insert(idx, (time, kind, meas)) - #while len(self.observation_buffer) > 0 and self.observation_buffer[-1][0] - self.observation_buffer[0][0] > self.max_age: - # else: - # self.observation_buffer.pop(0) + def update_kalman(self, time, kind, meas, R=None): + try: + self.kf.predict_and_observe(time, kind, meas, R) + except KalmanError: + cloudlog.error("Error in predict and observe, kalman reset") + self.reset_kalman() def handle_gps(self, current_time, log): + # ignore the message if the fix is invalid + if log.flags % 2 == 0: + return + + self.last_gps_fix = current_time + self.converter = coord.LocalCoord.from_geodetic([log.latitude, log.longitude, log.altitude]) - fix_ecef = self.converter.ned2ecef([0, 0, 0]) + ecef_pos = self.converter.ned2ecef([0, 0, 0]) + ecef_vel = self.converter.ned2ecef(np.array(log.vNED)) - ecef_pos + ecef_pos_R = np.diag([(3*log.verticalAccuracy)**2]*3) + ecef_vel_R = np.diag([(log.speedAccuracy)**2]*3) #self.time = GPSTime.from_datetime(datetime.utcfromtimestamp(log.timestamp*1e-3)) self.unix_timestamp_millis = log.timestamp - - # TODO initing with bad bearing not allowed, maybe not bad? - if not self.filter_ready and log.speed > 5: - self.filter_ready = True - initial_ecef = fix_ecef - gps_bearing = math.radians(log.bearing) - initial_pose_ecef = ecef_euler_from_ned(initial_ecef, [0, 0, gps_bearing]) - initial_pose_ecef_quat = quat_from_euler(initial_pose_ecef) - gps_speed = log.speed - quat_uncertainty = 0.2**2 - - initial_state = LiveKalman.initial_x - initial_covs_diag = LiveKalman.initial_P_diag - - initial_state[States.ECEF_POS] = initial_ecef - initial_state[States.ECEF_ORIENTATION] = initial_pose_ecef_quat - initial_state[States.ECEF_VELOCITY] = rot_from_quat(initial_pose_ecef_quat).dot(np.array([gps_speed, 0, 0])) - - initial_covs_diag[States.ECEF_POS_ERR] = 10**2 - initial_covs_diag[States.ECEF_ORIENTATION_ERR] = quat_uncertainty - initial_covs_diag[States.ECEF_VELOCITY_ERR] = 1**2 - self.kf.init_state(initial_state, covs=np.diag(initial_covs_diag), filter_time=current_time) - cloudlog.info("Filter initialized") - elif self.filter_ready: - self.update_kalman(current_time, ObservationKind.ECEF_POS, fix_ecef) - gps_est_error = np.sqrt((self.kf.x[0] - fix_ecef[0])**2 + - (self.kf.x[1] - fix_ecef[1])**2 + - (self.kf.x[2] - fix_ecef[2])**2) - if gps_est_error > 50: - cloudlog.error("Locationd vs ubloxLocation difference too large, kalman reset") - self.reset_kalman() + gps_est_error = np.sqrt((self.kf.x[0] - ecef_pos[0])**2 + + (self.kf.x[1] - ecef_pos[1])**2 + + (self.kf.x[2] - ecef_pos[2])**2) + + orientation_ecef = euler_from_quat(self.kf.x[States.ECEF_ORIENTATION]) + orientation_ned = ned_euler_from_ecef(ecef_pos, orientation_ecef) + orientation_ned_gps = np.array([0, 0, np.radians(log.bearing)]) + orientation_error = np.mod(orientation_ned - orientation_ned_gps - np.pi, 2*np.pi) - np.pi + if np.linalg.norm(ecef_vel) > 5 and np.linalg.norm(orientation_error) > 1: + cloudlog.error("Locationd vs ubloxLocation orientation difference too large, kalman reset") + initial_pose_ecef_quat = quat_from_euler(ecef_euler_from_ned(ecef_pos, orientation_ned_gps)) + self.reset_kalman(init_orient=initial_pose_ecef_quat) + self.update_kalman(current_time, ObservationKind.ECEF_ORIENTATION_FROM_GPS, initial_pose_ecef_quat) + elif gps_est_error > 50: + cloudlog.error("Locationd vs ubloxLocation position difference too large, kalman reset") + self.reset_kalman() + + self.update_kalman(current_time, ObservationKind.ECEF_POS, ecef_pos, R=ecef_pos_R) + self.update_kalman(current_time, ObservationKind.ECEF_VEL, ecef_vel, R=ecef_vel_R) def handle_car_state(self, current_time, log): self.speed_counter += 1 if self.speed_counter % SENSOR_DECIMATION == 0: self.update_kalman(current_time, ObservationKind.ODOMETRIC_SPEED, [log.vEgo]) + self.car_speed = abs(log.vEgo) if log.vEgo == 0: self.update_kalman(current_time, ObservationKind.NO_ROT, [0, 0, 0]) @@ -222,12 +222,15 @@ class Localizer(): rot_device_std = self.device_from_calib.dot(log.rotStd) self.update_kalman(current_time, ObservationKind.CAMERA_ODO_ROTATION, - np.concatenate([rot_device, rot_device_std])) + np.concatenate([rot_device, 10*rot_device_std])) trans_device = self.device_from_calib.dot(log.trans) trans_device_std = self.device_from_calib.dot(log.transStd) + self.posenet_speed = np.linalg.norm(trans_device) + self.posenet_stds[:-1] = self.posenet_stds[1:] + self.posenet_stds[-1] = trans_device_std[0] self.update_kalman(current_time, ObservationKind.CAMERA_ODO_TRANSLATION, - np.concatenate([trans_device, trans_device_std])) + np.concatenate([trans_device, 10*trans_device_std])) def handle_sensors(self, current_time, log): # TODO does not yet account for double sensor readings in the log @@ -236,29 +239,35 @@ class Localizer(): if sensor_reading.sensor == 5 and sensor_reading.type == 16: self.gyro_counter += 1 if self.gyro_counter % SENSOR_DECIMATION == 0: - if max(abs(self.kf.x[States.IMU_OFFSET])) > 0.07: - cloudlog.info('imu frame angles exceeded, correcting') - self.update_kalman(current_time, ObservationKind.IMU_FRAME, [0, 0, 0]) - v = sensor_reading.gyroUncalibrated.v self.update_kalman(current_time, ObservationKind.PHONE_GYRO, [-v[2], -v[1], -v[0]]) # Accelerometer if sensor_reading.sensor == 1 and sensor_reading.type == 1: + # check if device fell, estimate 10 for g + # 40m/s**2 is a good filter for falling detection, no false positives in 20k minutes of driving + self.device_fell = self.device_fell or (np.linalg.norm(np.array(sensor_reading.acceleration.v) - np.array([10, 0, 0])) > 40) + self.acc_counter += 1 if self.acc_counter % SENSOR_DECIMATION == 0: v = sensor_reading.acceleration.v self.update_kalman(current_time, ObservationKind.PHONE_ACCEL, [-v[2], -v[1], -v[0]]) def handle_live_calib(self, current_time, log): - self.calib = log.rpyCalib - self.device_from_calib = rot_from_euler(self.calib) - self.calib_from_device = self.device_from_calib.T - self.calibrated = log.calStatus == 1 - - def reset_kalman(self): - self.filter_time = None - self.filter_ready = False + if len(log.rpyCalib): + self.calib = log.rpyCalib + self.device_from_calib = rot_from_euler(self.calib) + self.calib_from_device = self.device_from_calib.T + self.calibrated = log.calStatus == 1 + + def reset_kalman(self, current_time=None, init_orient=None): + self.filter_time = current_time + init_x = LiveKalman.initial_x.copy() + # too nonlinear to init on completely wrong + if init_orient is not None: + init_x[3:7] = init_orient + self.kf.init_state(init_x, covs=np.diag(LiveKalman.initial_P_diag), filter_time=current_time) + self.observation_buffer = [] self.gyro_counter = 0 @@ -267,9 +276,13 @@ class Localizer(): self.cam_counter = 0 -def locationd_thread(sm, pm, disabled_logs=[]): +def locationd_thread(sm, pm, disabled_logs=None): + if disabled_logs is None: + disabled_logs = [] + if sm is None: - sm = messaging.SubMaster(['gpsLocationExternal', 'sensorEvents', 'cameraOdometry', 'liveCalibration']) + socks = ['gpsLocationExternal', 'sensorEvents', 'cameraOdometry', 'liveCalibration', 'carState'] + sm = messaging.SubMaster(socks, ignore_alive=['gpsLocationExternal']) if pm is None: pm = messaging.PubMaster(['liveLocationKalman']) @@ -279,7 +292,7 @@ def locationd_thread(sm, pm, disabled_logs=[]): sm.update() for sock, updated in sm.updated.items(): - if updated: + if updated and sm.valid[sock]: t = sm.logMonoTime[sock] * 1e-9 if sock == "sensorEvents": localizer.handle_sensors(t, sm[sock]) @@ -292,12 +305,17 @@ def locationd_thread(sm, pm, disabled_logs=[]): elif sock == "liveCalibration": localizer.handle_live_calib(t, sm[sock]) - if localizer.filter_ready and sm.updated['gpsLocationExternal']: - t = sm.logMonoTime['gpsLocationExternal'] + if sm.updated['cameraOdometry']: + t = sm.logMonoTime['cameraOdometry'] msg = messaging.new_message('liveLocationKalman') msg.logMonoTime = t - msg.liveLocationKalman = localizer.liveLocationMsg(t * 1e-9) + msg.liveLocationKalman = localizer.liveLocationMsg() + msg.liveLocationKalman.inputsOK = sm.all_alive_and_valid() + msg.liveLocationKalman.sensorsOK = sm.alive['sensorEvents'] and sm.valid['sensorEvents'] + + gps_age = (t / 1e9) - localizer.last_gps_fix + msg.liveLocationKalman.gpsOK = gps_age < 1.0 pm.send('liveLocationKalman', msg) diff --git a/selfdrive/locationd/locationd_yawrate.cc b/selfdrive/locationd/locationd_yawrate.cc deleted file mode 100644 index 4b93b68014..0000000000 --- a/selfdrive/locationd/locationd_yawrate.cc +++ /dev/null @@ -1,156 +0,0 @@ -#include -#include - -#include -#include -#include - -#include "cereal/gen/cpp/log.capnp.h" - -#include "locationd_yawrate.h" - - -void Localizer::update_state(const Eigen::Matrix &C, const double R, double current_time, double meas) { - double dt = current_time - prev_update_time; - - if (dt < 0) { - dt = 0; - } else { - prev_update_time = current_time; - } - - x = A * x; - P = A * P * A.transpose() + dt * Q; - - double y = meas - C * x; - double S = R + C * P * C.transpose(); - Eigen::Vector2d K = P * C.transpose() * (1.0 / S); - x = x + K * y; - P = (I - K * C) * P; -} - -void Localizer::handle_sensor_events(capnp::List::Reader sensor_events, double current_time) { - for (cereal::SensorEventData::Reader sensor_event : sensor_events){ - if (sensor_event.getSensor() == 5 && sensor_event.getType() == 16) { - sensor_data_time = current_time; - double meas = -sensor_event.getGyroUncalibrated().getV()[0]; - update_state(C_gyro, R_gyro, current_time, meas); - } - } -} - -void Localizer::handle_camera_odometry(cereal::CameraOdometry::Reader camera_odometry, double current_time) { - double R = pow(5 * camera_odometry.getRotStd()[2], 2); - double meas = camera_odometry.getRot()[2]; - update_state(C_posenet, R, current_time, meas); - - auto trans = camera_odometry.getTrans(); - posenet_speed = sqrt(trans[0]*trans[0] + trans[1]*trans[1] + trans[2]*trans[2]); - camera_odometry_time = current_time; -} - -void Localizer::handle_controls_state(cereal::ControlsState::Reader controls_state, double current_time) { - steering_angle = controls_state.getAngleSteers() * DEGREES_TO_RADIANS; - car_speed = controls_state.getVEgo(); - controls_state_time = current_time; -} - - -Localizer::Localizer() { - // States: [yaw rate, gyro bias] - A << - 1, 0, - 0, 1; - - Q << - pow(.1, 2.0), 0, - 0, pow(0.05/ 100.0, 2.0), - P << - pow(10000.0, 2.0), 0, - 0, pow(10000.0, 2.0); - - I << - 1, 0, - 0, 1; - - C_posenet << 1, 0; - C_gyro << 1, 1; - x << 0, 0; - - R_gyro = pow(0.025, 2.0); -} - -void Localizer::handle_log(cereal::Event::Reader event) { - double current_time = event.getLogMonoTime() / 1.0e9; - - // Initialize update_time on first update - if (prev_update_time < 0) { - prev_update_time = current_time; - } - - auto type = event.which(); - switch(type) { - case cereal::Event::CONTROLS_STATE: - handle_controls_state(event.getControlsState(), current_time); - break; - case cereal::Event::CAMERA_ODOMETRY: - handle_camera_odometry(event.getCameraOdometry(), current_time); - break; - case cereal::Event::SENSOR_EVENTS: - handle_sensor_events(event.getSensorEvents(), current_time); - break; - default: - break; - } -} - - -extern "C" { - void *localizer_init(void) { - Localizer * localizer = new Localizer; - return (void*)localizer; - } - - void localizer_handle_log(void * localizer, const unsigned char * data, size_t len) { - const kj::ArrayPtr view((const capnp::word*)data, len); - capnp::FlatArrayMessageReader msg(view); - cereal::Event::Reader event = msg.getRoot(); - - Localizer * loc = (Localizer*) localizer; - loc->handle_log(event); - } - - double localizer_get_yaw(void * localizer) { - Localizer * loc = (Localizer*) localizer; - return loc->x[0]; - } - double localizer_get_bias(void * localizer) { - Localizer * loc = (Localizer*) localizer; - return loc->x[1]; - } - - double * localizer_get_state(void * localizer) { - Localizer * loc = (Localizer*) localizer; - return loc->x.data(); - } - - void localizer_set_state(void * localizer, double * state) { - Localizer * loc = (Localizer*) localizer; - memcpy(loc->x.data(), state, 4 * sizeof(double)); - } - - double localizer_get_t(void * localizer) { - Localizer * loc = (Localizer*) localizer; - return loc->prev_update_time; - } - - double * localizer_get_P(void * localizer) { - Localizer * loc = (Localizer*) localizer; - return loc->P.data(); - } - - void localizer_set_P(void * localizer, double * P) { - Localizer * loc = (Localizer*) localizer; - memcpy(loc->P.data(), P, 16 * sizeof(double)); - } -} diff --git a/selfdrive/locationd/locationd_yawrate.h b/selfdrive/locationd/locationd_yawrate.h deleted file mode 100644 index c59734aa68..0000000000 --- a/selfdrive/locationd/locationd_yawrate.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include -#include "cereal/gen/cpp/log.capnp.h" - -#define DEGREES_TO_RADIANS 0.017453292519943295 - -class Localizer -{ - Eigen::Matrix2d A; - Eigen::Matrix2d I; - Eigen::Matrix2d Q; - Eigen::Matrix C_posenet; - Eigen::Matrix C_gyro; - - double R_gyro; - - void update_state(const Eigen::Matrix &C, const double R, double current_time, double meas); - void handle_sensor_events(capnp::List::Reader sensor_events, double current_time); - void handle_camera_odometry(cereal::CameraOdometry::Reader camera_odometry, double current_time); - void handle_controls_state(cereal::ControlsState::Reader controls_state, double current_time); - -public: - Eigen::Vector2d x; - Eigen::Matrix2d P; - double steering_angle = 0; - double car_speed = 0; - double posenet_speed = 0; - double prev_update_time = -1; - double controls_state_time = -1; - double sensor_data_time = -1; - double camera_odometry_time = -1; - - Localizer(); - void handle_log(cereal::Event::Reader event); - -}; diff --git a/selfdrive/locationd/models/SConscript b/selfdrive/locationd/models/SConscript index c8b5c93f7a..0a197ffda8 100644 --- a/selfdrive/locationd/models/SConscript +++ b/selfdrive/locationd/models/SConscript @@ -17,6 +17,7 @@ if arch != "aarch64": 'pos_computer_4': ('#rednose/helpers/lst_sq_computer.py', 'generated'), 'pos_computer_5': ('#rednose/helpers/lst_sq_computer.py', 'generated'), 'feature_handler_5': ('#rednose/helpers/feature_handler.py', 'generated'), + 'lane': ('#xx/pipeline/lib/ekf/lane_kf.py', 'generated'), }) found = {} diff --git a/selfdrive/locationd/models/car_kf.py b/selfdrive/locationd/models/car_kf.py index 7907670383..ee409ecebc 100755 --- a/selfdrive/locationd/models/car_kf.py +++ b/selfdrive/locationd/models/car_kf.py @@ -1,12 +1,14 @@ #!/usr/bin/env python3 +import math import sys +from typing import Any, Dict -import math import numpy as np import sympy as sp -from selfdrive.locationd.models.constants import ObservationKind +from rednose import KalmanFilter from rednose.helpers.ekf_sym import EKF_sym, gen_code +from selfdrive.locationd.models.constants import ObservationKind i = 0 @@ -31,10 +33,10 @@ class States(): STEER_ANGLE = _slice(1) # [rad] -class CarKalman(): +class CarKalman(KalmanFilter): name = 'car' - x_initial = np.array([ + initial_x = np.array([ 1.0, 15.0, 0.0, @@ -47,10 +49,10 @@ class CarKalman(): # process noise Q = np.diag([ - (.05/100)**2, + (.05 / 100)**2, .01**2, - math.radians(0.002)**2, - math.radians(0.1)**2, + math.radians(0.02)**2, + math.radians(0.25)**2, .1**2, .01**2, math.radians(0.1)**2, @@ -58,15 +60,14 @@ class CarKalman(): ]) P_initial = Q.copy() - obs_noise = { + obs_noise: Dict[int, Any] = { ObservationKind.STEER_ANGLE: np.atleast_2d(math.radians(0.01)**2), - ObservationKind.ANGLE_OFFSET_FAST: np.atleast_2d(math.radians(5.0)**2), + ObservationKind.ANGLE_OFFSET_FAST: np.atleast_2d(math.radians(10.0)**2), ObservationKind.STEER_RATIO: np.atleast_2d(5.0**2), ObservationKind.STIFFNESS: np.atleast_2d(5.0**2), ObservationKind.ROAD_FRAME_X_SPEED: np.atleast_2d(0.1**2), } - maha_test_kinds = [] # [ObservationKind.ROAD_FRAME_YAW_RATE, ObservationKind.ROAD_FRAME_XY_SPEED] global_vars = [ sp.Symbol('mass'), sp.Symbol('rotational_inertia'), @@ -78,9 +79,8 @@ class CarKalman(): @staticmethod def generate_code(generated_dir): - dim_state = CarKalman.x_initial.shape[0] + dim_state = CarKalman.initial_x.shape[0] name = CarKalman.name - maha_test_kinds = CarKalman.maha_test_kinds # globals m, j, aF, aR, cF_orig, cR_orig = CarKalman.global_vars @@ -137,57 +137,18 @@ class CarKalman(): [sp.Matrix([x]), ObservationKind.STIFFNESS, None], ] - gen_code(generated_dir, name, f_sym, dt, state_sym, obs_eqs, dim_state, dim_state, maha_test_kinds=maha_test_kinds, global_vars=CarKalman.global_vars) + gen_code(generated_dir, name, f_sym, dt, state_sym, obs_eqs, dim_state, dim_state, global_vars=CarKalman.global_vars) - def __init__(self, generated_dir, steer_ratio=15, stiffness_factor=1, angle_offset=0): - self.dim_state = self.x_initial.shape[0] - x_init = self.x_initial + def __init__(self, generated_dir, steer_ratio=15, stiffness_factor=1, angle_offset=0): # pylint: disable=super-init-not-called + dim_state = self.initial_x.shape[0] + dim_state_err = self.P_initial.shape[0] + x_init = self.initial_x x_init[States.STEER_RATIO] = steer_ratio x_init[States.STIFFNESS] = stiffness_factor x_init[States.ANGLE_OFFSET] = angle_offset # init filter - self.filter = EKF_sym(generated_dir, self.name, self.Q, self.x_initial, self.P_initial, self.dim_state, self.dim_state, maha_test_kinds=self.maha_test_kinds, global_vars=self.global_vars) - - @property - def x(self): - return self.filter.state() - - @property - def P(self): - return self.filter.covs() - - def predict(self, t): - return self.filter.predict(t) - - def rts_smooth(self, estimates): - return self.filter.rts_smooth(estimates, norm_quats=False) - - def get_R(self, kind, n): - obs_noise = self.obs_noise[kind] - dim = obs_noise.shape[0] - R = np.zeros((n, dim, dim)) - for i in range(n): - R[i, :, :] = obs_noise - return R - - def init_state(self, state, covs_diag=None, covs=None, filter_time=None): - if covs_diag is not None: - P = np.diag(covs_diag) - elif covs is not None: - P = covs - else: - P = self.filter.covs() - self.filter.init_state(state, P, filter_time) - - def predict_and_observe(self, t, kind, data, R=None): - if len(data) > 0: - data = np.atleast_2d(data) - - if R is None: - R = self.get_R(kind, len(data)) - - self.filter.predict_and_update_batch(t, kind, data, R) + self.filter = EKF_sym(generated_dir, self.name, self.Q, self.initial_x, self.P_initial, dim_state, dim_state_err, global_vars=self.global_vars) if __name__ == "__main__": diff --git a/selfdrive/locationd/models/constants.py b/selfdrive/locationd/models/constants.py index 8b99fce649..ebe83186e4 100644 --- a/selfdrive/locationd/models/constants.py +++ b/selfdrive/locationd/models/constants.py @@ -27,6 +27,8 @@ class ObservationKind: PSEUDORANGE_RATE_GLONASS = 21 PSEUDORANGE = 22 PSEUDORANGE_RATE = 23 + ECEF_VEL = 31 + ECEF_ORIENTATION_FROM_GPS = 32 ROAD_FRAME_XY_SPEED = 24 # (x, y) [m/s] ROAD_FRAME_YAW_RATE = 25 # [rad/s] diff --git a/selfdrive/locationd/models/gnss_kf.py b/selfdrive/locationd/models/gnss_kf.py index a672e67ed6..3f4baab7b5 100755 --- a/selfdrive/locationd/models/gnss_kf.py +++ b/selfdrive/locationd/models/gnss_kf.py @@ -1,11 +1,12 @@ #!/usr/bin/env python3 import sys +from typing import List import numpy as np import sympy as sp -from selfdrive.locationd.models.constants import ObservationKind from rednose.helpers.ekf_sym import EKF_sym, gen_code +from selfdrive.locationd.models.constants import ObservationKind from selfdrive.locationd.models.loc_kf import parse_pr, parse_prr @@ -28,18 +29,18 @@ class GNSSKalman(): 0, 0]) # state covariance - P_initial = np.diag([10000**2, 10000**2, 10000**2, + P_initial = np.diag([1e16, 1e16, 1e16, 10**2, 10**2, 10**2, - (2000000)**2, (100)**2, (0.5)**2, + 1e14, (100)**2, (0.2)**2, (10)**2, (1)**2]) # process noise - Q = np.diag([0.3**2, 0.3**2, 0.3**2, + Q = np.diag([0.03**2, 0.03**2, 0.03**2, 3**2, 3**2, 3**2, - (.1)**2, (0)**2, (0.01)**2, + (.1)**2, (0)**2, (0.005)**2, .1**2, (.01)**2]) - maha_test_kinds = [] # ObservationKind.PSEUDORANGE_RATE, ObservationKind.PSEUDORANGE, ObservationKind.PSEUDORANGE_GLONASS] + maha_test_kinds: List[int] = [] # ObservationKind.PSEUDORANGE_RATE, ObservationKind.PSEUDORANGE, ObservationKind.PSEUDORANGE_GLONASS] @staticmethod def generate_code(generated_dir): @@ -75,14 +76,14 @@ class GNSSKalman(): # extra args sat_pos_freq_sym = sp.MatrixSymbol('sat_pos', 4, 1) sat_pos_vel_sym = sp.MatrixSymbol('sat_pos_vel', 6, 1) - sat_los_sym = sp.MatrixSymbol('sat_los', 3, 1) - orb_epos_sym = sp.MatrixSymbol('orb_epos_sym', 3, 1) + # sat_los_sym = sp.MatrixSymbol('sat_los', 3, 1) + # orb_epos_sym = sp.MatrixSymbol('orb_epos_sym', 3, 1) # expand extra args sat_x, sat_y, sat_z, glonass_freq = sat_pos_freq_sym sat_vx, sat_vy, sat_vz = sat_pos_vel_sym[3:] - los_x, los_y, los_z = sat_los_sym - orb_x, orb_y, orb_z = orb_epos_sym + # los_x, los_y, los_z = sat_los_sym + # orb_x, orb_y, orb_z = orb_epos_sym h_pseudorange_sym = sp.Matrix([ sp.sqrt( @@ -118,7 +119,9 @@ class GNSSKalman(): self.dim_state = self.x_initial.shape[0] # init filter - self.filter = EKF_sym(generated_dir, self.name, self.Q, self.x_initial, self.P_initial, self.dim_state, self.dim_state, maha_test_kinds=self.maha_test_kinds) + self.filter = EKF_sym(generated_dir, self.name, self.Q, self.x_initial, self.P_initial, self.dim_state, + self.dim_state, maha_test_kinds=self.maha_test_kinds) + self.init_state(GNSSKalman.x_initial, covs=GNSSKalman.P_initial) @property def x(self): diff --git a/selfdrive/locationd/models/live_kf.py b/selfdrive/locationd/models/live_kf.py index 299d6b25c4..d2153487b2 100755 --- a/selfdrive/locationd/models/live_kf.py +++ b/selfdrive/locationd/models/live_kf.py @@ -1,11 +1,11 @@ #!/usr/bin/env python3 + import sys import numpy as np import sympy as sp from selfdrive.locationd.models.constants import ObservationKind -from rednose.helpers import KalmanError from rednose.helpers.ekf_sym import EKF_sym, gen_code from rednose.helpers.sympy_helpers import euler_rotate, quat_matrix_r, quat_rotate @@ -46,9 +46,9 @@ class LiveKalman(): 0, 0, 0]) # state covariance - initial_P_diag = np.array([10000**2, 10000**2, 10000**2, - 10**2, 10**2, 10**2, - 10**2, 10**2, 10**2, + initial_P_diag = np.array([1e16, 1e16, 1e16, + 1e6, 1e6, 1e6, + 1e4, 1e4, 1e4, 1**2, 1**2, 1**2, 0.05**2, 0.05**2, 0.05**2, 0.02**2, @@ -57,8 +57,8 @@ class LiveKalman(): # process noise Q = np.diag([0.03**2, 0.03**2, 0.03**2, - 0.0**2, 0.0**2, 0.0**2, - 0.0**2, 0.0**2, 0.0**2, + 0.001**2, 0.001*2, 0.001**2, + 0.01**2, 0.01**2, 0.01**2, 0.1**2, 0.1**2, 0.1**2, (0.005 / 100)**2, (0.005 / 100)**2, (0.005 / 100)**2, (0.02 / 100)**2, @@ -80,7 +80,7 @@ class LiveKalman(): omega = state[States.ANGULAR_VELOCITY, :] vroll, vpitch, vyaw = omega roll_bias, pitch_bias, yaw_bias = state[States.GYRO_BIAS, :] - odo_scale = state[States.ODO_SCALE, :][0,:] + odo_scale = state[States.ODO_SCALE, :][0, :] acceleration = state[States.ACCELERATION, :] imu_angles = state[States.IMU_OFFSET, :] @@ -168,10 +168,12 @@ class LiveKalman(): h_acc_sym = (gravity + acceleration) h_phone_rot_sym = sp.Matrix([vroll, vpitch, vyaw]) - speed = sp.sqrt(vx**2 + vy**2 + vz**2) + speed = sp.sqrt(vx**2 + vy**2 + vz**2 + 1e-6) h_speed_sym = sp.Matrix([speed * odo_scale]) h_pos_sym = sp.Matrix([x, y, z]) + h_vel_sym = sp.Matrix([vx, vy, vz]) + h_orientation_sym = q h_imu_frame_sym = sp.Matrix(imu_angles) h_relative_motion = sp.Matrix(quat_rot.T * v) @@ -181,6 +183,8 @@ class LiveKalman(): [h_phone_rot_sym, ObservationKind.NO_ROT, None], [h_acc_sym, ObservationKind.PHONE_ACCEL, None], [h_pos_sym, ObservationKind.ECEF_POS, None], + [h_vel_sym, ObservationKind.ECEF_VEL, None], + [h_orientation_sym, ObservationKind.ECEF_ORIENTATION_FROM_GPS, None], [h_relative_motion, ObservationKind.CAMERA_ODO_TRANSLATION, None], [h_phone_rot_sym, ObservationKind.CAMERA_ODO_ROTATION, None], [h_imu_frame_sym, ObservationKind.IMU_FRAME, None]] @@ -197,10 +201,12 @@ class LiveKalman(): ObservationKind.CAMERA_ODO_ROTATION: np.diag([0.05**2, 0.05**2, 0.05**2]), ObservationKind.IMU_FRAME: np.diag([0.05**2, 0.05**2, 0.05**2]), ObservationKind.NO_ROT: np.diag([0.00025**2, 0.00025**2, 0.00025**2]), - ObservationKind.ECEF_POS: np.diag([5**2, 5**2, 5**2])} + ObservationKind.ECEF_POS: np.diag([5**2, 5**2, 5**2]), + ObservationKind.ECEF_VEL: np.diag([.5**2, .5**2, .5**2]), + ObservationKind.ECEF_ORIENTATION_FROM_GPS: np.diag([.2**2, .2**2, .2**2, .2**2])} # init filter - self.filter = EKF_sym(generated_dir, self.name, self.Q, self.initial_x, np.diag(self.initial_P_diag), self.dim_state, self.dim_state_err) + self.filter = EKF_sym(generated_dir, self.name, self.Q, self.initial_x, np.diag(self.initial_P_diag), self.dim_state, self.dim_state_err, max_rewind_age=0.2) @property def x(self): @@ -226,25 +232,24 @@ class LiveKalman(): P = self.filter.covs() self.filter.init_state(state, P, filter_time) - def predict_and_observe(self, t, kind, data): - if len(data) > 0: - data = np.atleast_2d(data) + def predict_and_observe(self, t, kind, meas, R=None): + if len(meas) > 0: + meas = np.atleast_2d(meas) if kind == ObservationKind.CAMERA_ODO_TRANSLATION: - r = self.predict_and_update_odo_trans(data, t, kind) + r = self.predict_and_update_odo_trans(meas, t, kind) elif kind == ObservationKind.CAMERA_ODO_ROTATION: - r = self.predict_and_update_odo_rot(data, t, kind) + r = self.predict_and_update_odo_rot(meas, t, kind) elif kind == ObservationKind.ODOMETRIC_SPEED: - r = self.predict_and_update_odo_speed(data, t, kind) + r = self.predict_and_update_odo_speed(meas, t, kind) else: - r = self.filter.predict_and_update_batch(t, kind, data, self.get_R(kind, len(data))) + if R is None: + R = self.get_R(kind, len(meas)) + elif len(R.shape) == 2: + R = R[None] + r = self.filter.predict_and_update_batch(t, kind, meas, R) # Normalize quats quat_norm = np.linalg.norm(self.filter.x[3:7, 0]) - - # Should not continue if the quats behave this weirdly - if not (0.1 < quat_norm < 10): - raise KalmanError("Kalman filter quaternions unstable") - self.filter.x[States.ECEF_ORIENTATION, 0] = self.filter.x[States.ECEF_ORIENTATION, 0] / quat_norm return r diff --git a/selfdrive/locationd/models/loc_kf.py b/selfdrive/locationd/models/loc_kf.py index 7401fa8b8e..013fbc7303 100755 --- a/selfdrive/locationd/models/loc_kf.py +++ b/selfdrive/locationd/models/loc_kf.py @@ -48,6 +48,7 @@ class States(): GLONASS_BIAS = slice(26, 27) # GLONASS bias in m expressed as bias + freq_num*freq_slope GLONASS_FREQ_SLOPE = slice(27, 28) # GLONASS bias in m expressed as bias + freq_num*freq_slope CLOCK_ACCELERATION = slice(28, 29) # clock acceleration in light-meters/s**2, + ACCELEROMETER_SCALE = slice(29, 30) # scale of mems accelerometer # Error-state has different slices because it is an ESKF ECEF_POS_ERR = slice(0, 3) @@ -64,11 +65,12 @@ class States(): GLONASS_BIAS_ERR = slice(25, 26) GLONASS_FREQ_SLOPE_ERR = slice(26, 27) CLOCK_ACCELERATION_ERR = slice(27, 28) + ACCELEROMETER_SCALE_ERR = slice(28, 29) class LocKalman(): name = "loc" - x_initial = np.array([-2.7e6, 4.2e6, 3.8e6, + x_initial = np.array([0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -79,20 +81,22 @@ class LocKalman(): 1, 0, 0, 0, 0, 0, - 0]) + 0, + 1], dtype=np.float64) # state covariance - P_initial = np.diag([10000**2, 10000**2, 10000**2, + P_initial = np.diag([1e16, 1e16, 1e16, 10**2, 10**2, 10**2, 10**2, 10**2, 10**2, 1**2, 1**2, 1**2, - (200000)**2, (100)**2, + 1e14, (100)**2, 0.05**2, 0.05**2, 0.05**2, 0.02**2, - 1**2, 1**2, 1**2, + 2**2, 2**2, 2**2, 0.01**2, (0.01)**2, (0.01)**2, (0.01)**2, 10**2, 1**2, + 0.2**2, 0.05**2]) # process noise @@ -107,7 +111,8 @@ class LocKalman(): 0.001**2, (0.05 / 60)**2, (0.05 / 60)**2, (0.05 / 60)**2, (.1)**2, (.01)**2, - 0.005**2]) + 0.005**2, + (0.02 / 100)**2]) # measurements that need to pass mahalanobis distance outlier rejector maha_test_kinds = [ObservationKind.ORB_FEATURES] # , ObservationKind.PSEUDORANGE, ObservationKind.PSEUDORANGE_RATE] @@ -137,21 +142,19 @@ class LocKalman(): vx, vy, vz = v omega = state[States.ANGULAR_VELOCITY, :] vroll, vpitch, vyaw = omega - #cb = state[States.CLOCK_BIAS, :][0, 0] - #cd = state[States.CLOCK_DRIFT, :][0, 0] - cb, cd = state[13:15, :] + cb = state[States.CLOCK_BIAS, :] + cd = state[States.CLOCK_DRIFT, :] roll_bias, pitch_bias, yaw_bias = state[States.GYRO_BIAS, :] - #odo_scale = state[States.ODO_SCALE, :][0,0] - odo_scale = state[18, :] + odo_scale = state[States.ODO_SCALE, :] acceleration = state[States.ACCELERATION, :] - #focal_scale = state[States.FOCAL_SCALE, :][0,0] - focal_scale = state[22, :] + focal_scale = state[States.FOCAL_SCALE, :] imu_angles = state[States.IMU_OFFSET, :] - glonass_bias, glonass_freq_slope = state[26:28, :] - ca = state[28, 0] - #glonass_bias = state[States.GLONASS_BIAS, :][0,0] - #glonass_freq_slope = state[States.GLONASS_FREQ_SLOPE, :][0,0] - #ca = state[States.CLOCK_ACCELERATION, :][0,0] + imu_angles[0, 0] = 0 + imu_angles[2, 0] = 0 + glonass_bias = state[States.GLONASS_BIAS, :] + glonass_freq_slope = state[States.GLONASS_FREQ_SLOPE, :] + ca = state[States.CLOCK_ACCELERATION, :] + accel_scale = state[States.ACCELEROMETER_SCALE, :] dt = sp.Symbol('dt') @@ -173,10 +176,8 @@ class LocKalman(): state_dot[States.ECEF_POS, :] = v state_dot[States.ECEF_ORIENTATION, :] = q_dot state_dot[States.ECEF_VELOCITY, 0] = quat_rot * acceleration - state_dot[13, 0] = cd - state_dot[14, 0] = ca - #state_dot[States.CLOCK_BIAS, 0][0,0] = cd - state_dot[States.CLOCK_DRIFT, 0][0,0] = ca + state_dot[States.CLOCK_BIAS, :] = cd + state_dot[States.CLOCK_DRIFT, :] = ca # Basic descretization, 1st order intergrator # Can be pretty bad if dt is big @@ -187,10 +188,9 @@ class LocKalman(): quat_err = state_err[States.ECEF_ORIENTATION_ERR, :] v_err = state_err[States.ECEF_VELOCITY_ERR, :] omega_err = state_err[States.ANGULAR_VELOCITY_ERR, :] - #cd_err = state_err[States.CLOCK_DRIFT_ERR, :][0,:] - cd_err = state_err[13, :] + cd_err = state_err[States.CLOCK_DRIFT_ERR, :] acceleration_err = state_err[States.ACCELERATION_ERR, :] - ca_err = state_err[27, :] + ca_err = state_err[States.CLOCK_ACCELERATION_ERR, :] # Time derivative of the state error as a function of state error and state quat_err_matrix = euler_rotate(quat_err[0], quat_err[1], quat_err[2]) @@ -199,10 +199,8 @@ class LocKalman(): state_err_dot[States.ECEF_POS_ERR, :] = v_err state_err_dot[States.ECEF_ORIENTATION_ERR, :] = q_err_dot state_err_dot[States.ECEF_VELOCITY_ERR, :] = quat_err_matrix * quat_rot * (acceleration + acceleration_err) - #state_err_dot[States.CLOCK_BIAS_ERR, :][0,:] = cd_err - #state_err_dot[States.CLOCK_DRIFT_ERR, :][0,:] = ca_err - state_err_dot[12, :][0,:] = cd_err - state_err_dot[13, :][0,:] = ca_err + state_err_dot[States.CLOCK_BIAS_ERR, :] = cd_err + state_err_dot[States.CLOCK_DRIFT_ERR, :] = ca_err f_err_sym = state_err + dt * state_err_dot # convenient indexing @@ -252,13 +250,13 @@ class LocKalman(): # extra args sat_pos_freq_sym = sp.MatrixSymbol('sat_pos', 4, 1) sat_pos_vel_sym = sp.MatrixSymbol('sat_pos_vel', 6, 1) - sat_los_sym = sp.MatrixSymbol('sat_los', 3, 1) + # sat_los_sym = sp.MatrixSymbol('sat_los', 3, 1) orb_epos_sym = sp.MatrixSymbol('orb_epos_sym', 3, 1) # expand extra args sat_x, sat_y, sat_z, glonass_freq = sat_pos_freq_sym sat_vx, sat_vy, sat_vz = sat_pos_vel_sym[3:] - los_x, los_y, los_z = sat_los_sym + # los_x, los_y, los_z = sat_los_sym orb_x, orb_y, orb_z = orb_epos_sym h_pseudorange_sym = sp.Matrix([ @@ -266,7 +264,7 @@ class LocKalman(): (x - sat_x)**2 + (y - sat_y)**2 + (z - sat_z)**2 - ) + cb + ) + cb[0] ]) h_pseudorange_glonass_sym = sp.Matrix([ @@ -274,7 +272,7 @@ class LocKalman(): (x - sat_x)**2 + (y - sat_y)**2 + (z - sat_z)**2 - ) + cb + glonass_bias + glonass_freq_slope * glonass_freq + ) + cb[0] + glonass_bias[0] + glonass_freq_slope[0] * glonass_freq ]) los_vector = (sp.Matrix(sat_pos_vel_sym[0:3]) - sp.Matrix([x, y, z])) @@ -282,7 +280,7 @@ class LocKalman(): h_pseudorange_rate_sym = sp.Matrix([los_vector[0] * (sat_vx - vx) + los_vector[1] * (sat_vy - vy) + los_vector[2] * (sat_vz - vz) + - cd]) + cd[0]]) imu_rot = euler_rotate(*imu_angles) h_gyro_sym = imu_rot * sp.Matrix([vroll + roll_bias, @@ -290,8 +288,9 @@ class LocKalman(): vyaw + yaw_bias]) pos = sp.Matrix([x, y, z]) - gravity = quat_rot.T * ((EARTH_GM / ((x**2 + y**2 + z**2)**(3.0 / 2.0))) * pos) - h_acc_sym = imu_rot * (gravity + acceleration) + # add 1 for stability, prevent division by 0 + gravity = quat_rot.T * ((EARTH_GM / ((x**2 + y**2 + z**2 + 1)**(3.0 / 2.0))) * pos) + h_acc_sym = imu_rot * (accel_scale[0] * (gravity + acceleration)) h_phone_rot_sym = sp.Matrix([vroll, vpitch, vyaw]) speed = sp.sqrt(vx**2 + vy**2 + vz**2) @@ -325,7 +324,9 @@ class LocKalman(): # MSCKF configuration if N > 0: - focal_scale = 1 + # experimentally found this is correct value for imx298 with 910 focal length + # this is a variable so it can change with focus, but we disregard that for now + focal_scale = 1.01 # Add observation functions for orb feature tracks track_epos_sym = sp.MatrixSymbol('track_epos_sym', 3, 1) track_x, track_y, track_z = track_epos_sym @@ -340,7 +341,7 @@ class LocKalman(): for n in range(N): idx = dim_main + n * dim_augment - err_idx = dim_main_err + n * dim_augment_err # FIXME: Why is this not used? + # err_idx = dim_main_err + n * dim_augment_err # FIXME: Why is this not used? x, y, z = state[idx:idx + 3] q = state[idx + 3:idx + 7] quat_rot = quat_rotate(*q) @@ -366,7 +367,7 @@ class LocKalman(): ObservationKind.PHONE_ACCEL: np.diag([.5**2, .5**2, .5**2]), ObservationKind.CAMERA_ODO_ROTATION: np.diag([0.05**2, 0.05**2, 0.05**2]), ObservationKind.IMU_FRAME: np.diag([0.05**2, 0.05**2, 0.05**2]), - ObservationKind.NO_ROT: np.diag([0.00025**2, 0.00025**2, 0.00025**2]), + ObservationKind.NO_ROT: np.diag([0.0025**2, 0.0025**2, 0.0025**2]), ObservationKind.ECEF_POS: np.diag([5**2, 5**2, 5**2])} # MSCKF stuff @@ -377,7 +378,7 @@ class LocKalman(): self.dim_state_err = self.dim_main_err + self.dim_augment_err * self.N if self.N > 0: - x_initial, P_initial, Q = self.pad_augmented(self.x_initial, self.P_initial, self.Q) + x_initial, P_initial, Q = self.pad_augmented(self.x_initial, self.P_initial, self.Q) # pylint: disable=unbalanced-tuple-unpacking self.computer = LstSqComputer(generated_dir, N) self.max_tracks = max_tracks @@ -443,8 +444,6 @@ class LocKalman(): r = self.predict_and_update_orb_features(data, t, kind) elif kind == ObservationKind.MSCKF_TEST: r = self.predict_and_update_msckf_test(data, t, kind) - elif kind == ObservationKind.FEATURE_TRACK_TEST: - r = self.predict_and_update_feature_track_test(data, t, kind) elif kind == ObservationKind.ODOMETRIC_SPEED: r = self.predict_and_update_odo_speed(data, t, kind) else: @@ -571,14 +570,14 @@ class LocKalman(): def maha_test_pseudorange(self, x, P, meas, kind, maha_thresh=.3): bools = [] - for i, m in enumerate(meas): + for m in meas: z, R, sat_pos_freq = parse_pr(m) bools.append(self.filter.maha_test(x, P, kind, z, R, extra_args=sat_pos_freq, maha_thresh=maha_thresh)) return np.array(bools) def maha_test_pseudorange_rate(self, x, P, meas, kind, maha_thresh=.999): bools = [] - for i, m in enumerate(meas): + for m in meas: z, R, sat_pos_vel = parse_prr(m) bools.append(self.filter.maha_test(x, P, kind, z, R, extra_args=sat_pos_vel, maha_thresh=maha_thresh)) return np.array(bools) diff --git a/selfdrive/locationd/params_learner.cc b/selfdrive/locationd/params_learner.cc deleted file mode 100644 index 66f378a1da..0000000000 --- a/selfdrive/locationd/params_learner.cc +++ /dev/null @@ -1,118 +0,0 @@ -#include -#include -#include - -#include -#include -#include "cereal/gen/cpp/log.capnp.h" -#include "cereal/gen/cpp/car.capnp.h" -#include "params_learner.h" - -// #define DEBUG - -template -T clip(const T& n, const T& lower, const T& upper) { - return std::max(lower, std::min(n, upper)); -} - -ParamsLearner::ParamsLearner(cereal::CarParams::Reader car_params, - double angle_offset, - double stiffness_factor, - double steer_ratio, - double learning_rate) : - ao(angle_offset * DEGREES_TO_RADIANS), - slow_ao(angle_offset * DEGREES_TO_RADIANS), - x(stiffness_factor), - sR(steer_ratio) { - - cF0 = car_params.getTireStiffnessFront(); - cR0 = car_params.getTireStiffnessRear(); - - l = car_params.getWheelbase(); - m = car_params.getMass(); - - aF = car_params.getCenterToFront(); - aR = l - aF; - - min_sr = MIN_SR * car_params.getSteerRatio(); - max_sr = MAX_SR * car_params.getSteerRatio(); - min_sr_th = MIN_SR_TH * car_params.getSteerRatio(); - max_sr_th = MAX_SR_TH * car_params.getSteerRatio(); - alpha1 = 0.01 * learning_rate; - alpha2 = 0.0005 * learning_rate; - alpha3 = 0.1 * learning_rate; - alpha4 = 1.0 * learning_rate; -} - -bool ParamsLearner::update(double psi, double u, double sa) { - if (u > 10.0 && fabs(sa) < (DEGREES_TO_RADIANS * 90.)) { - double ao_diff = 2.0*cF0*cR0*l*u*x*(1.0*cF0*cR0*l*u*x*(ao - sa) + psi*sR*(cF0*cR0*pow(l, 2)*x - m*pow(u, 2)*(aF*cF0 - aR*cR0)))/(pow(sR, 2)*pow(cF0*cR0*pow(l, 2)*x - m*pow(u, 2)*(aF*cF0 - aR*cR0), 2)); - double new_ao = ao - alpha1 * ao_diff; - - double slow_ao_diff = 2.0*cF0*cR0*l*u*x*(1.0*cF0*cR0*l*u*x*(slow_ao - sa) + psi*sR*(cF0*cR0*pow(l, 2)*x - m*pow(u, 2)*(aF*cF0 - aR*cR0)))/(pow(sR, 2)*pow(cF0*cR0*pow(l, 2)*x - m*pow(u, 2)*(aF*cF0 - aR*cR0), 2)); - double new_slow_ao = slow_ao - alpha2 * slow_ao_diff; - - double new_x = x - alpha3 * (-2.0*cF0*cR0*l*m*pow(u, 3)*(slow_ao - sa)*(aF*cF0 - aR*cR0)*(1.0*cF0*cR0*l*u*x*(slow_ao - sa) + psi*sR*(cF0*cR0*pow(l, 2)*x - m*pow(u, 2)*(aF*cF0 - aR*cR0)))/(pow(sR, 2)*pow(cF0*cR0*pow(l, 2)*x - m*pow(u, 2)*(aF*cF0 - aR*cR0), 3))); - double new_sR = sR - alpha4 * (-2.0*cF0*cR0*l*u*x*(slow_ao - sa)*(1.0*cF0*cR0*l*u*x*(slow_ao - sa) + psi*sR*(cF0*cR0*pow(l, 2)*x - m*pow(u, 2)*(aF*cF0 - aR*cR0)))/(pow(sR, 3)*pow(cF0*cR0*pow(l, 2)*x - m*pow(u, 2)*(aF*cF0 - aR*cR0), 2))); - - ao = new_ao; - slow_ao = new_slow_ao; - x = new_x; - sR = new_sR; - } - -#ifdef DEBUG - std::cout << "Instant AO: " << (RADIANS_TO_DEGREES * ao) << "\tAverage AO: " << (RADIANS_TO_DEGREES * slow_ao); - std::cout << "\tStiffness: " << x << "\t sR: " << sR << std::endl; -#endif - - ao = clip(ao, -MAX_ANGLE_OFFSET, MAX_ANGLE_OFFSET); - slow_ao = clip(slow_ao, -MAX_ANGLE_OFFSET, MAX_ANGLE_OFFSET); - x = clip(x, MIN_STIFFNESS, MAX_STIFFNESS); - sR = clip(sR, min_sr, max_sr); - - bool valid = fabs(slow_ao) < MAX_ANGLE_OFFSET_TH; - valid = valid && sR > min_sr_th; - valid = valid && sR < max_sr_th; - return valid; -} - - -extern "C" { - void *params_learner_init(size_t len, char * params, double angle_offset, double stiffness_factor, double steer_ratio, double learning_rate) { - - auto amsg = kj::heapArray((len / sizeof(capnp::word)) + 1); - memcpy(amsg.begin(), params, len); - - capnp::FlatArrayMessageReader cmsg(amsg); - cereal::CarParams::Reader car_params = cmsg.getRoot(); - - ParamsLearner * p = new ParamsLearner(car_params, angle_offset, stiffness_factor, steer_ratio, learning_rate); - return (void*)p; - } - - bool params_learner_update(void * params_learner, double psi, double u, double sa) { - ParamsLearner * p = (ParamsLearner*) params_learner; - return p->update(psi, u, sa); - } - - double params_learner_get_ao(void * params_learner){ - ParamsLearner * p = (ParamsLearner*) params_learner; - return p->ao; - } - - double params_learner_get_x(void * params_learner){ - ParamsLearner * p = (ParamsLearner*) params_learner; - return p->x; - } - - double params_learner_get_slow_ao(void * params_learner){ - ParamsLearner * p = (ParamsLearner*) params_learner; - return p->slow_ao; - } - - double params_learner_get_sR(void * params_learner){ - ParamsLearner * p = (ParamsLearner*) params_learner; - return p->sR; - } -} diff --git a/selfdrive/locationd/params_learner.h b/selfdrive/locationd/params_learner.h deleted file mode 100644 index 4d97551b3b..0000000000 --- a/selfdrive/locationd/params_learner.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#define DEGREES_TO_RADIANS 0.017453292519943295 -#define RADIANS_TO_DEGREES (1.0 / DEGREES_TO_RADIANS) - -#define MAX_ANGLE_OFFSET (10.0 * DEGREES_TO_RADIANS) -#define MAX_ANGLE_OFFSET_TH (9.0 * DEGREES_TO_RADIANS) -#define MIN_STIFFNESS 0.5 -#define MAX_STIFFNESS 2.0 -#define MIN_SR 0.5 -#define MAX_SR 2.0 -#define MIN_SR_TH 0.55 -#define MAX_SR_TH 1.9 - -class ParamsLearner { - double cF0, cR0; - double aR, aF; - double l, m; - - double min_sr, max_sr, min_sr_th, max_sr_th; - double alpha1, alpha2, alpha3, alpha4; - -public: - double ao; - double slow_ao; - double x, sR; - - ParamsLearner(cereal::CarParams::Reader car_params, - double angle_offset, - double stiffness_factor, - double steer_ratio, - double learning_rate); - - bool update(double psi, double u, double sa); -}; diff --git a/selfdrive/locationd/paramsd.cc b/selfdrive/locationd/paramsd.cc deleted file mode 100644 index 8c60bc12e4..0000000000 --- a/selfdrive/locationd/paramsd.cc +++ /dev/null @@ -1,187 +0,0 @@ -#include -#include -#include -#include -#include - - -#include -#include - -#include "json11.hpp" -#include "cereal/gen/cpp/log.capnp.h" - -#include "common/swaglog.h" -#include "common/messaging.h" -#include "common/params.h" -#include "common/timing.h" - -#include "messaging.hpp" -#include "locationd_yawrate.h" -#include "params_learner.h" - -#include "common/util.h" - -void sigpipe_handler(int sig) { - LOGE("SIGPIPE received"); -} - - -int main(int argc, char *argv[]) { - signal(SIGPIPE, (sighandler_t)sigpipe_handler); - - Context * c = Context::create(); - SubSocket * controls_state_sock = SubSocket::create(c, "controlsState"); - SubSocket * sensor_events_sock = SubSocket::create(c, "sensorEvents"); - SubSocket * camera_odometry_sock = SubSocket::create(c, "cameraOdometry"); - PubSocket * live_parameters_sock = PubSocket::create(c, "liveParameters"); - - assert(controls_state_sock != NULL); - assert(sensor_events_sock != NULL); - assert(camera_odometry_sock != NULL); - assert(live_parameters_sock != NULL); - - Poller * poller = Poller::create({controls_state_sock, sensor_events_sock, camera_odometry_sock}); - - Localizer localizer; - - // Read car params - char *value; - size_t value_sz = 0; - - LOGW("waiting for params to set vehicle model"); - while (true) { - read_db_value("CarParams", &value, &value_sz); - if (value_sz > 0) break; - usleep(100*1000); - } - LOGW("got %d bytes CarParams", value_sz); - - // make copy due to alignment issues - auto amsg = kj::heapArray((value_sz / sizeof(capnp::word)) + 1); - memcpy(amsg.begin(), value, value_sz); - free(value); - - capnp::FlatArrayMessageReader cmsg(amsg); - cereal::CarParams::Reader car_params = cmsg.getRoot(); - - // Read params from previous run - const int result = read_db_value("LiveParameters", &value, &value_sz); - - std::string fingerprint = car_params.getCarFingerprint(); - std::string vin = car_params.getCarVin(); - double sR = car_params.getSteerRatio(); - double x = 1.0; - double ao = 0.0; - double posenet_invalid_count = 0; - - if (result == 0){ - auto str = std::string(value, value_sz); - free(value); - - std::string err; - auto json = json11::Json::parse(str, err); - if (json.is_null() || !err.empty()) { - std::string log = "Error parsing json: " + err; - LOGW(log.c_str()); - } else { - std::string new_fingerprint = json["carFingerprint"].string_value(); - std::string new_vin = json["carVin"].string_value(); - - if (fingerprint == new_fingerprint && vin == new_vin) { - std::string log = "Parameter starting with: " + str; - LOGW(log.c_str()); - - sR = json["steerRatio"].number_value(); - x = json["stiffnessFactor"].number_value(); - ao = json["angleOffsetAverage"].number_value(); - } - } - } - - ParamsLearner learner(car_params, ao, x, sR, 1.0); - - // Main loop - int save_counter = 0; - while (true){ - for (auto s : poller->poll(100)){ - Message * msg = s->receive(); - - auto amsg = kj::heapArray((msg->getSize() / sizeof(capnp::word)) + 1); - memcpy(amsg.begin(), msg->getData(), msg->getSize()); - - capnp::FlatArrayMessageReader capnp_msg(amsg); - cereal::Event::Reader event = capnp_msg.getRoot(); - - localizer.handle_log(event); - - auto which = event.which(); - // Throw vision failure if posenet and odometric speed too different - if (which == cereal::Event::CAMERA_ODOMETRY){ - if (std::abs(localizer.posenet_speed - localizer.car_speed) > std::max(0.4 * localizer.car_speed, 5.0)) { - posenet_invalid_count++; - } else { - posenet_invalid_count = 0; - } - } else if (which == cereal::Event::CONTROLS_STATE){ - save_counter++; - - double yaw_rate = -localizer.x[0]; - bool valid = learner.update(yaw_rate, localizer.car_speed, localizer.steering_angle); - - // TODO: Fix in replay - double sensor_data_age = localizer.controls_state_time - localizer.sensor_data_time; - double camera_odometry_age = localizer.controls_state_time - localizer.camera_odometry_time; - - double angle_offset_degrees = RADIANS_TO_DEGREES * learner.ao; - double angle_offset_average_degrees = RADIANS_TO_DEGREES * learner.slow_ao; - - capnp::MallocMessageBuilder msg; - cereal::Event::Builder event = msg.initRoot(); - event.setLogMonoTime(nanos_since_boot()); - auto live_params = event.initLiveParameters(); - live_params.setValid(valid); - live_params.setYawRate(localizer.x[0]); - live_params.setGyroBias(localizer.x[1]); - live_params.setSensorValid(sensor_data_age < 5.0); - live_params.setAngleOffset(angle_offset_degrees); - live_params.setAngleOffsetAverage(angle_offset_average_degrees); - live_params.setStiffnessFactor(learner.x); - live_params.setSteerRatio(learner.sR); - live_params.setPosenetSpeed(localizer.posenet_speed); - live_params.setPosenetValid((posenet_invalid_count < 4) && (camera_odometry_age < 5.0)); - - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - live_parameters_sock->send((char*)bytes.begin(), bytes.size()); - - // Save parameters every minute - if (save_counter % 6000 == 0) { - json11::Json json = json11::Json::object { - {"carVin", vin}, - {"carFingerprint", fingerprint}, - {"steerRatio", learner.sR}, - {"stiffnessFactor", learner.x}, - {"angleOffsetAverage", angle_offset_average_degrees}, - }; - - std::string out = json.dump(); - std::async(std::launch::async, - [out]{ - write_db_value("LiveParameters", out.c_str(), out.length()); - }); - } - } - delete msg; - } - } - - delete live_parameters_sock; - delete controls_state_sock; - delete camera_odometry_sock; - delete sensor_events_sock; - delete poller; - delete c; - - return 0; -} diff --git a/selfdrive/locationd/paramsd.py b/selfdrive/locationd/paramsd.py index e359870ba8..ad820b4ea2 100755 --- a/selfdrive/locationd/paramsd.py +++ b/selfdrive/locationd/paramsd.py @@ -5,12 +5,14 @@ import json import numpy as np import cereal.messaging as messaging -from cereal import car +from cereal import car, log from common.params import Params, put_nonblocking from selfdrive.locationd.models.car_kf import CarKalman, ObservationKind, States from selfdrive.locationd.models.constants import GENERATED_DIR from selfdrive.swaglog import cloudlog +KalmanStatus = log.LiveLocationKalman.Status + CARSTATE_DECIMATION = 5 @@ -32,6 +34,8 @@ class ParamsLearner: self.steering_angle = 0 self.carstate_counter = 0 + self.valid = True + def handle_log(self, t, which, msg): if which == 'liveLocationKalman': @@ -39,21 +43,13 @@ class ParamsLearner: yaw_rate_std = msg.angularVelocityCalibrated.std[2] if self.active: - self.kf.predict_and_observe(t, - ObservationKind.ROAD_FRAME_YAW_RATE, - np.array([[[-yaw_rate]]]), - np.array([np.atleast_2d(yaw_rate_std**2)])) - + if msg.inputsOK and msg.posenetOK and msg.status == KalmanStatus.valid: + self.kf.predict_and_observe(t, + ObservationKind.ROAD_FRAME_YAW_RATE, + np.array([[[-yaw_rate]]]), + np.array([np.atleast_2d(yaw_rate_std**2)])) self.kf.predict_and_observe(t, ObservationKind.ANGLE_OFFSET_FAST, np.array([[[0]]])) - # Clamp values - # x = self.kf.x - # if not (10 < x[States.STEER_RATIO] < 25): - # self.kf.predict_and_observe(t, ObservationKind.STEER_RATIO, np.array([[[15.0]]])) - - # if not (0.5 < x[States.STIFFNESS] < 3.0): - # self.kf.predict_and_observe(t, ObservationKind.STIFFNESS, np.array([[[1.0]]])) - elif which == 'carState': self.carstate_counter += 1 if self.carstate_counter % CARSTATE_DECIMATION == 0: @@ -104,9 +100,13 @@ def main(sm=None, pm=None): } cloudlog.info("Parameter learner resetting to default values") + # When driving in wet conditions the stiffness can go down, and then be too low on the next drive + # Without a way to detect this we have to reset the stiffness every drive + params['stiffnessFactor'] = 1.0 + learner = ParamsLearner(CP, params['steerRatio'], params['stiffnessFactor'], math.radians(params['angleOffsetAverage'])) + min_sr, max_sr = 0.5 * CP.steerRatio, 2.0 * CP.steerRatio - i = 0 while True: sm.update() @@ -116,14 +116,10 @@ def main(sm=None, pm=None): t = sm.logMonoTime[which] * 1e-9 learner.handle_log(t, which, sm[which]) - # TODO: set valid to false when locationd stops sending - # TODO: make sure controlsd knows when there is no gyro - - if sm.updated['carState']: + if sm.updated['carState'] and (learner.carstate_counter % CARSTATE_DECIMATION == 0): msg = messaging.new_message('liveParameters') msg.logMonoTime = sm.logMonoTime['carState'] - msg.liveParameters.valid = True # TODO: Check if learned values are sane msg.liveParameters.posenetValid = True msg.liveParameters.sensorValid = True @@ -132,9 +128,14 @@ def main(sm=None, pm=None): msg.liveParameters.stiffnessFactor = float(x[States.STIFFNESS]) msg.liveParameters.angleOffsetAverage = math.degrees(x[States.ANGLE_OFFSET]) msg.liveParameters.angleOffset = msg.liveParameters.angleOffsetAverage + math.degrees(x[States.ANGLE_OFFSET_FAST]) - - i += 1 - if i % 6000 == 0: # once a minute + msg.liveParameters.valid = all(( + abs(msg.liveParameters.angleOffsetAverage) < 10.0, + abs(msg.liveParameters.angleOffset) < 10.0, + 0.2 <= msg.liveParameters.stiffnessFactor <= 5.0, + min_sr <= msg.liveParameters.steerRatio <= max_sr, + )) + + if learner.carstate_counter % 6000 == 0: # once a minute params = { 'carFingerprint': CP.carFingerprint, 'steerRatio': msg.liveParameters.steerRatio, @@ -143,13 +144,6 @@ def main(sm=None, pm=None): } put_nonblocking("LiveParameters", json.dumps(params)) - # P = learner.kf.P - # print() - # print("sR", float(x[States.STEER_RATIO]), float(P[States.STEER_RATIO, States.STEER_RATIO])**0.5) - # print("x ", float(x[States.STIFFNESS]), float(P[States.STIFFNESS, States.STIFFNESS])**0.5) - # print("ao avg ", math.degrees(x[States.ANGLE_OFFSET]), math.degrees(P[States.ANGLE_OFFSET, States.ANGLE_OFFSET])**0.5) - # print("ao ", math.degrees(x[States.ANGLE_OFFSET_FAST]), math.degrees(P[States.ANGLE_OFFSET_FAST, States.ANGLE_OFFSET_FAST])**0.5) - pm.send('liveParameters', msg) diff --git a/selfdrive/locationd/test/ci_test.py b/selfdrive/locationd/test/ci_test.py index 5b23e8326a..b715a499af 100755 --- a/selfdrive/locationd/test/ci_test.py +++ b/selfdrive/locationd/test/ci_test.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +# type: ignore import subprocess import os import sys diff --git a/selfdrive/locationd/test/ephemeris.py b/selfdrive/locationd/test/ephemeris.py index dd8155e19a..2793e3c62a 100644 --- a/selfdrive/locationd/test/ephemeris.py +++ b/selfdrive/locationd/test/ephemeris.py @@ -1,3 +1,5 @@ +import math + def GET_FIELD_U(w, nb, pos): return (((w) >> (pos)) & ((1 << (nb)) - 1)) @@ -35,7 +37,6 @@ on of this parser ''' def __init__(self, svId, subframes): - from math import pow self.svId = svId week_no = GET_FIELD_U(subframes[1][2+0], 10, 20) # code_on_l2 = GET_FIELD_U(subframes[1][0], 2, 12) @@ -84,30 +85,30 @@ on of this parser gpsPi = 3.1415926535898 # now form variables in radians, meters and seconds etc - self.Tgd = t_gd * pow(2, -31) - self.A = pow(a_powhalf * pow(2, -19), 2.0) - self.cic = c_ic * pow(2, -29) - self.cis = c_is * pow(2, -29) - self.crc = c_rc * pow(2, -5) - self.crs = c_rs * pow(2, -5) - self.cuc = c_uc * pow(2, -29) - self.cus = c_us * pow(2, -29) - self.deltaN = delta_n * pow(2, -43) * gpsPi - self.ecc = e * pow(2, -33) - self.i0 = i_0 * pow(2, -31) * gpsPi - self.idot = idot * pow(2, -43) * gpsPi - self.M0 = m_0 * pow(2, -31) * gpsPi - self.omega = w * pow(2, -31) * gpsPi - self.omega_dot = omega_dot * pow(2, -43) * gpsPi - self.omega0 = omega_0 * pow(2, -31) * gpsPi - self.toe = t_oe * pow(2, 4) + self.Tgd = t_gd * math.pow(2, -31) + self.A = math.pow(a_powhalf * math.pow(2, -19), 2.0) + self.cic = c_ic * math.pow(2, -29) + self.cis = c_is * math.pow(2, -29) + self.crc = c_rc * math.pow(2, -5) + self.crs = c_rs * math.pow(2, -5) + self.cuc = c_uc * math.pow(2, -29) + self.cus = c_us * math.pow(2, -29) + self.deltaN = delta_n * math.pow(2, -43) * gpsPi + self.ecc = e * math.pow(2, -33) + self.i0 = i_0 * math.pow(2, -31) * gpsPi + self.idot = idot * math.pow(2, -43) * gpsPi + self.M0 = m_0 * math.pow(2, -31) * gpsPi + self.omega = w * math.pow(2, -31) * gpsPi + self.omega_dot = omega_dot * math.pow(2, -43) * gpsPi + self.omega0 = omega_0 * math.pow(2, -31) * gpsPi + self.toe = t_oe * math.pow(2, 4) # clock correction information - self.toc = t_oc * pow(2, 4) + self.toc = t_oc * math.pow(2, 4) self.gpsWeek = week_no - self.af0 = a_f0 * pow(2, -31) - self.af1 = a_f1 * pow(2, -43) - self.af2 = a_f2 * pow(2, -55) + self.af0 = a_f0 * math.pow(2, -31) + self.af1 = a_f1 * math.pow(2, -43) + self.af2 = a_f2 * math.pow(2, -55) iode1 = GET_FIELD_U(subframes[2][2+0], 8, 22) iode2 = GET_FIELD_U(subframes[3][2+7], 8, 22) @@ -117,14 +118,14 @@ on of this parser if GET_FIELD_U(subframes[4][2+0], 6, 22) == 56 and \ GET_FIELD_U(subframes[4][2+0], 2, 28) == 1 and \ GET_FIELD_U(subframes[5][2+0], 2, 28) == 1: - a0 = GET_FIELD_S(subframes[4][2], 8, 14) * pow(2, -30) - a1 = GET_FIELD_S(subframes[4][2], 8, 6) * pow(2, -27) - a2 = GET_FIELD_S(subframes[4][3], 8, 22) * pow(2, -24) - a3 = GET_FIELD_S(subframes[4][3], 8, 14) * pow(2, -24) - b0 = GET_FIELD_S(subframes[4][3], 8, 6) * pow(2, 11) - b1 = GET_FIELD_S(subframes[4][4], 8, 22) * pow(2, 14) - b2 = GET_FIELD_S(subframes[4][4], 8, 14) * pow(2, 16) - b3 = GET_FIELD_S(subframes[4][4], 8, 6) * pow(2, 16) + a0 = GET_FIELD_S(subframes[4][2], 8, 14) * math.pow(2, -30) + a1 = GET_FIELD_S(subframes[4][2], 8, 6) * math.pow(2, -27) + a2 = GET_FIELD_S(subframes[4][3], 8, 22) * math.pow(2, -24) + a3 = GET_FIELD_S(subframes[4][3], 8, 14) * math.pow(2, -24) + b0 = GET_FIELD_S(subframes[4][3], 8, 6) * math.pow(2, 11) + b1 = GET_FIELD_S(subframes[4][4], 8, 22) * math.pow(2, 14) + b2 = GET_FIELD_S(subframes[4][4], 8, 14) * math.pow(2, 16) + b3 = GET_FIELD_S(subframes[4][4], 8, 6) * math.pow(2, 16) self.ionoAlpha = [a0, a1, a2, a3] self.ionoBeta = [b0, b1, b2, b3] @@ -133,5 +134,3 @@ on of this parser self.ionoAlpha = [] self.ionoBeta = [] self.ionoCoeffsValid = False - - diff --git a/selfdrive/locationd/test/test_params_learner.py b/selfdrive/locationd/test/test_params_learner.py deleted file mode 100755 index a3c8487858..0000000000 --- a/selfdrive/locationd/test/test_params_learner.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python3 - -import numpy as np -import unittest - -from selfdrive.car.honda.interface import CarInterface -from selfdrive.car.honda.values import CAR -from selfdrive.controls.lib.vehicle_model import VehicleModel -from selfdrive.locationd.liblocationd_py import liblocationd # pylint: disable=no-name-in-module, import-error - - -class TestParamsLearner(unittest.TestCase): - def setUp(self): - - self.CP = CarInterface.get_params(CAR.CIVIC) - bts = self.CP.to_bytes() - - self.params_learner = liblocationd.params_learner_init(len(bts), bts, 0.0, 1.0, self.CP.steerRatio, 1.0) - - def test_convergence(self): - # Setup vehicle model with wrong parameters - VM_sim = VehicleModel(self.CP) - x_target = 0.75 - sr_target = self.CP.steerRatio - 0.5 - ao_target = -1.0 - VM_sim.update_params(x_target, sr_target) - - # Run simulation - times = np.arange(0, 15*3600, 0.01) - angle_offset = np.radians(ao_target) - steering_angles = np.radians(10 * np.sin(2 * np.pi * times / 100.)) + angle_offset - speeds = 10 * np.sin(2 * np.pi * times / 1000.) + 25 - - for i, t in enumerate(times): - u = speeds[i] - sa = steering_angles[i] - psi = VM_sim.yaw_rate(sa - angle_offset, u) - liblocationd.params_learner_update(self.params_learner, psi, u, sa) - - # Verify learned parameters - sr = liblocationd.params_learner_get_sR(self.params_learner) - ao_slow = np.degrees(liblocationd.params_learner_get_slow_ao(self.params_learner)) - x = liblocationd.params_learner_get_x(self.params_learner) - self.assertAlmostEqual(x_target, x, places=1) - self.assertAlmostEqual(ao_target, ao_slow, places=1) - self.assertAlmostEqual(sr_target, sr, places=1) - - - - - -if __name__ == "__main__": - unittest.main() diff --git a/selfdrive/locationd/test/ublox.py b/selfdrive/locationd/test/ublox.py index d99e714696..6a28edb1aa 100644 --- a/selfdrive/locationd/test/ublox.py +++ b/selfdrive/locationd/test/ublox.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +# pylint: skip-file ''' UBlox binary protocol handling @@ -12,7 +13,8 @@ for ublox version 8, not all functions may work. import struct -import time, os +import os +import time # protocol constants PREAMBLE1 = 0xb5 @@ -291,7 +293,7 @@ class UBloxDescriptor: fields = self.fields[:] for f in fields: (fieldname, alen) = ArrayParse(f) - if not fieldname in msg._fields: + if fieldname not in msg._fields: break if alen == -1: f1.append(msg._fields[fieldname]) @@ -327,7 +329,7 @@ class UBloxDescriptor: ret = self.name + ': ' for f in self.fields: (fieldname, alen) = ArrayParse(f) - if not fieldname in msg._fields: + if fieldname not in msg._fields: continue v = msg._fields[fieldname] if isinstance(v, list): @@ -591,7 +593,7 @@ class UBloxMessage: if not self.valid(): raise UBloxError('INVALID MESSAGE') type = self.msg_type() - if not type in msg_types: + if type not in msg_types: raise UBloxError('Unknown message %s length=%u' % (str(type), len(self._buf))) msg_types[type].unpack(self) return self._fields, self._recs @@ -601,7 +603,7 @@ class UBloxMessage: if not self.valid(): raise UBloxError('INVALID MESSAGE') type = self.msg_type() - if not type in msg_types: + if type not in msg_types: raise UBloxError('Unknown message %s' % str(type)) msg_types[type].pack(self) @@ -610,7 +612,7 @@ class UBloxMessage: if not self.valid(): raise UBloxError('INVALID MESSAGE') type = self.msg_type() - if not type in msg_types: + if type not in msg_types: raise UBloxError('Unknown message %s length=%u' % (str(type), len(self._buf))) return msg_types[type].name @@ -716,7 +718,7 @@ class UBlox: self.dev = PandaSerial(self.panda, 1, self.baudrate) self.baudrate = 460800 - print("upping baud:",self.baudrate) + print("upping baud:", self.baudrate) self.send_nmea("$PUBX,41,1,0007,0003,%u,0" % self.baudrate) time.sleep(0.1) @@ -736,7 +738,6 @@ class UBlox: self.buf = self.buf[n:] return ret - def write(self, dat): pass diff --git a/selfdrive/locationd/test/ubloxd.py b/selfdrive/locationd/test/ubloxd.py index 65fdfce9b5..314c80237f 100755 --- a/selfdrive/locationd/test/ubloxd.py +++ b/selfdrive/locationd/test/ubloxd.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +# type: ignore +# pylint: skip-file import os import serial @@ -18,10 +20,10 @@ debug = os.getenv("DEBUG") is not None # debug prints print_dB = os.getenv("PRINT_DB") is not None # print antenna dB timeout = 1 -dyn_model = 4 # auto model +dyn_model = 4 # auto model baudrate = 460800 -ports = ["/dev/ttyACM0","/dev/ttyACM1"] -rate = 100 # send new data every 100ms +ports = ["/dev/ttyACM0", "/dev/ttyACM1"] +rate = 100 # send new data every 100ms # which SV IDs we have seen and when we got iono svid_seen = {} @@ -31,17 +33,17 @@ iono_seen = 0 def configure_ublox(dev): # configure ports and solution parameters and rate # TODO: configure constellations and channels to allow for 10Hz and high precision - dev.configure_port(port=ublox.PORT_USB, inMask=1, outMask=1) # enable only UBX on USB - dev.configure_port(port=0, inMask=0, outMask=0) # disable DDC + dev.configure_port(port=ublox.PORT_USB, inMask=1, outMask=1) # enable only UBX on USB + dev.configure_port(port=0, inMask=0, outMask=0) # disable DDC if panda: payload = struct.pack(' #include -#include #include #include #include #include #include #include -#include #include #include #include #include -#include -#include #include -#include -#include "cereal/gen/cpp/log.capnp.h" - #include "common/params.h" #include "common/swaglog.h" #include "common/timing.h" @@ -45,7 +38,7 @@ inline int GET_FIELD_S(uint32_t w, uint32_t nb, uint32_t pos) { class EphemerisData { public: - EphemerisData(uint8_t svId, subframes_map subframes) { + EphemerisData(uint8_t svId, subframes_map &subframes) { this->svId = svId; int week_no = GET_FIELD_U(subframes[1][2+0], 10, 20); int t_gd = GET_FIELD_S(subframes[1][2+4], 8, 6); diff --git a/selfdrive/locationd/ubloxd.cc b/selfdrive/locationd/ubloxd.cc index 2c28f14228..4ffc010f3e 100644 --- a/selfdrive/locationd/ubloxd.cc +++ b/selfdrive/locationd/ubloxd.cc @@ -7,17 +7,12 @@ #include #include #include -#include #include #include #include #include -#include -#include #include "messaging.hpp" -#include -#include "cereal/gen/cpp/log.capnp.h" #include "common/params.h" #include "common/swaglog.h" diff --git a/selfdrive/locationd/ubloxd_main.cc b/selfdrive/locationd/ubloxd_main.cc index 4e07932fff..ad895f8d3e 100644 --- a/selfdrive/locationd/ubloxd_main.cc +++ b/selfdrive/locationd/ubloxd_main.cc @@ -4,21 +4,16 @@ #include #include #include +#include #include #include #include -#include #include #include #include #include -#include -#include #include "messaging.hpp" -#include -#include "cereal/gen/cpp/log.capnp.h" - #include "common/util.h" #include "common/params.h" #include "common/swaglog.h" @@ -33,7 +28,6 @@ void set_do_exit(int sig) { } using namespace ublox; - int ubloxd_main(poll_ubloxraw_msg_func poll_func, send_gps_event_func send_func) { LOGW("starting ubloxd"); signal(SIGINT, (sighandler_t) set_do_exit); @@ -41,30 +35,31 @@ int ubloxd_main(poll_ubloxraw_msg_func poll_func, send_gps_event_func send_func) UbloxMsgParser parser; - Context * c = Context::create(); - PubSocket * gpsLocationExternal = PubSocket::create(c, "gpsLocationExternal"); - PubSocket * ubloxGnss = PubSocket::create(c, "ubloxGnss"); - SubSocket * ubloxRaw = SubSocket::create(c, "ubloxRaw"); - - assert(gpsLocationExternal != NULL); - assert(ubloxGnss != NULL); - assert(ubloxRaw != NULL); - - Poller * poller = Poller::create({ubloxRaw}); + Context * context = Context::create(); + SubSocket * subscriber = SubSocket::create(context, "ubloxRaw"); + assert(subscriber != NULL); + subscriber->setTimeout(100); + PubMaster pm({"ubloxGnss", "gpsLocationExternal"}); while (!do_exit) { - Message * msg = poll_func(poller); - if (msg == NULL) continue; + Message * msg = subscriber->receive(); + if (!msg){ + if (errno == EINTR) { + do_exit = true; + } + continue; + } auto amsg = kj::heapArray((msg->getSize() / sizeof(capnp::word)) + 1); memcpy(amsg.begin(), msg->getData(), msg->getSize()); capnp::FlatArrayMessageReader cmsg(amsg); cereal::Event::Reader event = cmsg.getRoot(); + auto ubloxRaw = event.getUbloxRaw(); - const uint8_t *data = event.getUbloxRaw().begin(); - size_t len = event.getUbloxRaw().size(); + const uint8_t *data = ubloxRaw.begin(); + size_t len = ubloxRaw.size(); size_t bytes_consumed = 0; while(bytes_consumed < len && !do_exit) { size_t bytes_consumed_this_time = 0U; @@ -76,7 +71,7 @@ int ubloxd_main(poll_ubloxraw_msg_func poll_func, send_gps_event_func send_func) auto words = parser.gen_solution(); if(words.size() > 0) { auto bytes = words.asBytes(); - send_func(gpsLocationExternal, bytes.begin(), bytes.size()); + pm.send("gpsLocationExternal", bytes.begin(), bytes.size()); } } else LOGW("Unknown nav msg id: 0x%02X", parser.msg_id()); @@ -86,14 +81,14 @@ int ubloxd_main(poll_ubloxraw_msg_func poll_func, send_gps_event_func send_func) auto words = parser.gen_raw(); if(words.size() > 0) { auto bytes = words.asBytes(); - send_func(ubloxGnss, bytes.begin(), bytes.size()); + pm.send("ubloxGnss", bytes.begin(), bytes.size()); } } else if(parser.msg_id() == MSG_RXM_SFRBX) { //LOGD("MSG_RXM_SFRBX"); auto words = parser.gen_nav_data(); if(words.size() > 0) { auto bytes = words.asBytes(); - send_func(ubloxGnss, bytes.begin(), bytes.size()); + pm.send("ubloxGnss", bytes.begin(), bytes.size()); } } else LOGW("Unknown rxm msg id: 0x%02X", parser.msg_id()); @@ -103,7 +98,7 @@ int ubloxd_main(poll_ubloxraw_msg_func poll_func, send_gps_event_func send_func) auto words = parser.gen_mon_hw(); if(words.size() > 0) { auto bytes = words.asBytes(); - send_func(ubloxGnss, bytes.begin(), bytes.size()); + pm.send("ubloxGnss", bytes.begin(), bytes.size()); } } else { LOGW("Unknown mon msg id: 0x%02X", parser.msg_id()); @@ -117,11 +112,8 @@ int ubloxd_main(poll_ubloxraw_msg_func poll_func, send_gps_event_func send_func) delete msg; } - delete poller; - delete ubloxRaw; - delete ubloxGnss; - delete gpsLocationExternal; - delete c; + delete subscriber; + delete context; return 0; } diff --git a/selfdrive/locationd/ubloxd_test.cc b/selfdrive/locationd/ubloxd_test.cc index ec65577f2a..8653cedeab 100644 --- a/selfdrive/locationd/ubloxd_test.cc +++ b/selfdrive/locationd/ubloxd_test.cc @@ -7,19 +7,14 @@ #include #include #include -#include #include #include #include #include -#include -#include #include #include "messaging.hpp" #include "impl_zmq.hpp" -#include -#include "cereal/gen/cpp/log.capnp.h" #include "common/params.h" #include "common/swaglog.h" @@ -30,13 +25,13 @@ using namespace ublox; extern volatile sig_atomic_t do_exit; -void write_file(std::string fpath, uint8_t *to_write, int len) { +void write_file(std::string fpath, uint8_t *to_write, int length) { FILE* f = fopen(fpath.c_str(), "wb"); if (!f) { std::cout << "Open " << fpath << " failed" << std::endl; return; } - fwrite(to_write, len, 1, f); + fwrite(to_write, length, 1, f); fclose(f); } diff --git a/selfdrive/logcatd/SConscript b/selfdrive/logcatd/SConscript index 1040c3af70..67ad673002 100644 --- a/selfdrive/logcatd/SConscript +++ b/selfdrive/logcatd/SConscript @@ -1,2 +1,2 @@ -Import('env', 'messaging') -env.Program('logcatd.cc', LIBS=[messaging, 'cutils', 'zmq', 'czmq', 'capnp', 'kj']) +Import('env', 'cereal', 'messaging') +env.Program('logcatd.cc', LIBS=[cereal, messaging, 'cutils', 'zmq', 'czmq', 'capnp', 'kj']) diff --git a/selfdrive/logcatd/logcatd.cc b/selfdrive/logcatd/logcatd.cc index 9a7f1ba520..181e29df11 100644 --- a/selfdrive/logcatd/logcatd.cc +++ b/selfdrive/logcatd/logcatd.cc @@ -7,9 +7,7 @@ #include #include -#include #include "common/timing.h" -#include "cereal/gen/cpp/log.capnp.h" #include "messaging.hpp" int main() { @@ -27,10 +25,7 @@ int main() { assert(crash_logger); struct logger *kernel_logger = android_logger_open(logger_list, (log_id_t)5); // LOG_ID_KERNEL assert(kernel_logger); - - Context * c = Context::create(); - PubSocket * androidLog = PubSocket::create(c, "androidLog"); - assert(androidLog != NULL); + PubMaster pm({"androidLog"}); while (1) { log_msg log_msg; @@ -57,15 +52,9 @@ int main() { androidEntry.setTag(entry.tag); androidEntry.setMessage(entry.message); - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - androidLog->send((char*)bytes.begin(), bytes.size()); + pm.send("androidLog", msg); } android_logger_list_close(logger_list); - - delete androidLog; - delete c; - return 0; } diff --git a/selfdrive/loggerd/SConscript b/selfdrive/loggerd/SConscript index cb5dfa6ee9..2e5dae5553 100644 --- a/selfdrive/loggerd/SConscript +++ b/selfdrive/loggerd/SConscript @@ -1,9 +1,9 @@ -Import('env', 'arch', 'messaging', 'common', 'visionipc') +Import('env', 'arch', 'cereal', 'messaging', 'common', 'visionipc') src = ['loggerd.cc', 'logger.cc'] libs = ['zmq', 'czmq', 'capnp', 'kj', 'z', 'avformat', 'avcodec', 'swscale', 'avutil', - 'yuv', 'bz2', common, messaging, visionipc] + 'yuv', 'bz2', common, cereal, messaging, visionipc] if arch == "aarch64": src += ['encoder.c', 'raw_logger.cc'] diff --git a/selfdrive/loggerd/encoder.c b/selfdrive/loggerd/encoder.c index c66fc38700..ebbc5737b1 100644 --- a/selfdrive/loggerd/encoder.c +++ b/selfdrive/loggerd/encoder.c @@ -1,3 +1,5 @@ +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + #include #include #include @@ -24,6 +26,7 @@ #include "encoder.h" + //#define ALOG(...) __android_log_print(ANDROID_LOG_VERBOSE, "omxapp", ##__VA_ARGS__) // encoder: lossey codec using hardware hevc @@ -93,6 +96,7 @@ static OMX_CALLBACKTYPE omx_callbacks = { #define PORT_INDEX_IN 0 #define PORT_INDEX_OUT 1 +static const char* omx_color_fomat_name(uint32_t format) __attribute__((unused)); static const char* omx_color_fomat_name(uint32_t format) { switch (format) { case OMX_COLOR_FormatUnused: return "OMX_COLOR_FormatUnused"; @@ -226,7 +230,7 @@ void encoder_init(EncoderState *s, const char* filename, int width, int height, in_port.format.video.xFramerate = (s->fps * 65536); in_port.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; // in_port.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar; - in_port.format.video.eColorFormat = QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; + in_port.format.video.eColorFormat = (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; err = OMX_SetParameter(s->handle, OMX_IndexParamPortDefinition, (OMX_PTR) &in_port); @@ -394,9 +398,9 @@ static void handle_out_buf(EncoderState *s, OMX_BUFFERHEADERTYPE *out_buf) { } if (s->stream_sock_raw) { - uint64_t current_time = nanos_since_boot(); - uint64_t diff = current_time - out_buf->nTimeStamp*1000LL; - double msdiff = (double) diff / 1000000.0; + //uint64_t current_time = nanos_since_boot(); + //uint64_t diff = current_time - out_buf->nTimeStamp*1000LL; + //double msdiff = (double) diff / 1000000.0; // printf("encoded latency to tsEof: %f\n", msdiff); zmq_send(s->stream_sock_raw, &out_buf->nTimeStamp, sizeof(out_buf->nTimeStamp), ZMQ_SNDMORE); zmq_send(s->stream_sock_raw, buf_data, out_buf->nFilledLen, 0); diff --git a/selfdrive/loggerd/ethernetsniffer.py b/selfdrive/loggerd/ethernetsniffer.py index 023dacc90b..3c3ffb338c 100755 --- a/selfdrive/loggerd/ethernetsniffer.py +++ b/selfdrive/loggerd/ethernetsniffer.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +# pylint: skip-file + import cereal.messaging as messaging import pcap @@ -13,4 +15,3 @@ def main(): if __name__ == "__main__": main() - diff --git a/selfdrive/loggerd/frame_logger.h b/selfdrive/loggerd/frame_logger.h index bfc0681b75..85ddabafdc 100644 --- a/selfdrive/loggerd/frame_logger.h +++ b/selfdrive/loggerd/frame_logger.h @@ -15,7 +15,7 @@ public: int LogFrame(uint64_t ts, const uint8_t *y_ptr, const uint8_t *u_ptr, const uint8_t *v_ptr, int *frame_segment) { std::lock_guard guard(lock); - + if (opening) { Open(next_path); opening = false; diff --git a/selfdrive/loggerd/loggerd.cc b/selfdrive/loggerd/loggerd.cc index 6bd26e59ba..274f2481b5 100644 --- a/selfdrive/loggerd/loggerd.cc +++ b/selfdrive/loggerd/loggerd.cc @@ -22,10 +22,7 @@ #include #include - #include -#include - #ifdef QCOM #include #endif @@ -82,6 +79,7 @@ namespace { +double randrange(double a, double b) __attribute__((unused)); double randrange(double a, double b) { static std::mt19937 gen(millis_since_boot()); @@ -121,11 +119,8 @@ void encoder_thread(bool is_streaming, bool raw_clips, int cam_idx) { if (cam_idx == CAM_IDX_DCAM) { // TODO: add this back #ifndef QCOM2 - char *value; - const int result = read_db_value("RecordFront", &value, NULL); - if (result != 0) return; - if (value[0] != '1') { free(value); return; } - free(value); + std::vector value = read_db_bytes("RecordFront"); + if (value.size() == 0 || value[0] != '1') return; LOGW("recording front camera"); #endif set_thread_name("FrontCameraEncoder"); @@ -202,13 +197,12 @@ void encoder_thread(bool is_streaming, bool raw_clips, int cam_idx) { VIPCBuf* buf = visionstream_get(&stream, &extra); if (buf == NULL) { LOG("visionstream get failed"); - visionstream_destroy(&stream); break; } - uint64_t current_time = nanos_since_boot(); - uint64_t diff = current_time - extra.timestamp_eof; - double msdiff = (double) diff / 1000000.0; + //uint64_t current_time = nanos_since_boot(); + //uint64_t diff = current_time - extra.timestamp_eof; + //double msdiff = (double) diff / 1000000.0; // printf("logger latency to tsEof: %f\n", msdiff); uint8_t *y = (uint8_t*)buf->addr; @@ -527,30 +521,23 @@ kj::Array gen_init_data() { init.setDirty(true); } - char* git_commit = NULL; - size_t size; - read_db_value("GitCommit", &git_commit, &size); - if (git_commit) { - init.setGitCommit(capnp::Text::Reader(git_commit, size)); + std::vector git_commit = read_db_bytes("GitCommit"); + if (git_commit.size() > 0) { + init.setGitCommit(capnp::Text::Reader(git_commit.data(), git_commit.size())); } - char* git_branch = NULL; - read_db_value("GitBranch", &git_branch, &size); - if (git_branch) { - init.setGitBranch(capnp::Text::Reader(git_branch, size)); + std::vector git_branch = read_db_bytes("GitBranch"); + if (git_branch.size() > 0) { + init.setGitBranch(capnp::Text::Reader(git_branch.data(), git_branch.size())); } - char* git_remote = NULL; - read_db_value("GitRemote", &git_remote, &size); - if (git_remote) { - init.setGitRemote(capnp::Text::Reader(git_remote, size)); + std::vector git_remote = read_db_bytes("GitRemote"); + if (git_remote.size() > 0) { + init.setGitRemote(capnp::Text::Reader(git_remote.data(), git_remote.size())); } - char* passive = NULL; - read_db_value("Passive", &passive, NULL); - init.setPassive(passive && strlen(passive) && passive[0] == '1'); - - + std::vector passive = read_db_bytes("Passive"); + init.setPassive(passive.size() > 0 && passive[0] == '1'); { // log params std::map params; @@ -564,27 +551,7 @@ kj::Array gen_init_data() { i++; } } - - - auto words = capnp::messageToFlatArray(msg); - - if (git_commit) { - free((void*)git_commit); - } - - if (git_branch) { - free((void*)git_branch); - } - - if (git_remote) { - free((void*)git_remote); - } - - if (passive) { - free((void*)passive); - } - - return words; + return capnp::messageToFlatArray(msg); } static int clear_locks_fn(const char* fpath, const struct stat *sb, int tyupeflag) { @@ -817,7 +784,7 @@ int main(int argc, char** argv) { for (auto s : socks){ delete s; } - + delete poller; delete s.ctx; return 0; diff --git a/selfdrive/loggerd/raw_logger.cc b/selfdrive/loggerd/raw_logger.cc index 37b3f28428..d9fc289ded 100644 --- a/selfdrive/loggerd/raw_logger.cc +++ b/selfdrive/loggerd/raw_logger.cc @@ -1,3 +1,5 @@ +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + #include #include #include diff --git a/selfdrive/loggerd/tests/loggerd_tests_common.py b/selfdrive/loggerd/tests/loggerd_tests_common.py index 72bd5e3b35..d3dc92a52a 100644 --- a/selfdrive/loggerd/tests/loggerd_tests_common.py +++ b/selfdrive/loggerd/tests/loggerd_tests_common.py @@ -57,6 +57,7 @@ class MockParams(): self.params = { "DongleId": b"0000000000000000", "IsUploadRawEnabled": b"1", + "IsOffroad": b"1", } def get(self, k): diff --git a/selfdrive/loggerd/tests/test_deleter.py b/selfdrive/loggerd/tests/test_deleter.py index f06946b2fe..89904e694a 100644 --- a/selfdrive/loggerd/tests/test_deleter.py +++ b/selfdrive/loggerd/tests/test_deleter.py @@ -23,9 +23,6 @@ class TestDeleter(UploaderTestCase): deleter.os.statvfs = self.fake_statvfs deleter.ROOT = self.root - def tearDown(self): - super(TestDeleter, self).tearDown() - def start_thread(self): self.end_event = threading.Event() self.del_thread = threading.Thread(target=deleter.deleter_thread, args=[self.end_event]) diff --git a/selfdrive/loggerd/tests/test_uploader.py b/selfdrive/loggerd/tests/test_uploader.py index 96f449b03b..4a44f80b5c 100644 --- a/selfdrive/loggerd/tests/test_uploader.py +++ b/selfdrive/loggerd/tests/test_uploader.py @@ -38,9 +38,6 @@ class TestUploader(UploaderTestCase): super(TestUploader, self).setUp() log_handler.reset() - def tearDown(self): - super(TestUploader, self).tearDown() - def start_thread(self): self.end_event = threading.Event() self.up_thread = threading.Thread(target=uploader.uploader_fn, args=[self.end_event]) @@ -61,9 +58,9 @@ class TestUploader(UploaderTestCase): keys = [f"{self.seg_format.format(i)}/qlog.bz2" for i in seg1] keys += [f"{self.seg_format2.format(i)}/qlog.bz2" for i in seg2] for i in seg1: - keys += [f"{self.seg_format.format(i)}/{f}" for f in ['rlog.bz2','fcamera.hevc','dcamera.hevc']] + keys += [f"{self.seg_format.format(i)}/{f}" for f in ['rlog.bz2', 'fcamera.hevc', 'dcamera.hevc']] for i in seg2: - keys += [f"{self.seg_format2.format(i)}/{f}" for f in ['rlog.bz2','fcamera.hevc','dcamera.hevc']] + keys += [f"{self.seg_format2.format(i)}/{f}" for f in ['rlog.bz2', 'fcamera.hevc', 'dcamera.hevc']] keys += [f"{self.seg_format.format(i)}/bootlog.bz2" for i in seg1] keys += [f"{self.seg_format2.format(i)}/bootlog.bz2" for i in seg2] return keys @@ -103,11 +100,11 @@ class TestUploader(UploaderTestCase): def test_upload_files_in_create_order(self): f_paths = list() - seg1_nums = [0,1,2,10,20] + seg1_nums = [0, 1, 2, 10, 20] for i in seg1_nums: self.seg_dir = self.seg_format.format(i) f_paths += self.gen_files() - seg2_nums = [5,50,51] + seg2_nums = [5, 50, 51] for i in seg2_nums: self.seg_dir = self.seg_format2.format(i) f_paths += self.gen_files() diff --git a/selfdrive/loggerd/tools/mark_unuploaded.py b/selfdrive/loggerd/tools/mark_unuploaded.py index 266c6261be..e219c3a53a 100755 --- a/selfdrive/loggerd/tools/mark_unuploaded.py +++ b/selfdrive/loggerd/tools/mark_unuploaded.py @@ -6,4 +6,3 @@ from selfdrive.loggerd.uploader import UPLOAD_ATTR_NAME for fn in sys.argv[1:]: print("unmarking %s" % fn) removexattr(fn, UPLOAD_ATTR_NAME) - diff --git a/selfdrive/loggerd/uploader.py b/selfdrive/loggerd/uploader.py index 6f10093a6c..e4ec377637 100644 --- a/selfdrive/loggerd/uploader.py +++ b/selfdrive/loggerd/uploader.py @@ -25,6 +25,7 @@ UPLOAD_ATTR_VALUE = b'1' fake_upload = os.getenv("FAKEUPLOAD") is not None def raise_on_thread(t, exctype): + '''Raises an exception in the threads with id tid''' for ctid, tobj in threading._active.items(): if tobj is t: tid = ctid @@ -32,7 +33,6 @@ def raise_on_thread(t, exctype): else: raise Exception("Could not find thread") - '''Raises an exception in the threads with id tid''' if not inspect.isclass(exctype): raise TypeError("Only types can be raised (not instances)") @@ -134,7 +134,7 @@ class Uploader(): is_uploaded = getxattr(fn, UPLOAD_ATTR_NAME) except OSError: cloudlog.event("uploader_getxattr_failed", exc=self.last_exc, key=key, fn=fn) - is_uploaded = True # deleter could have deleted + is_uploaded = True # deleter could have deleted if is_uploaded: continue @@ -166,7 +166,7 @@ class Uploader(): if url_resp.status_code == 412: self.last_resp = url_resp return - + url_resp_json = json.loads(url_resp.text) url = url_resp_json['url'] headers = url_resp_json['headers'] @@ -174,9 +174,11 @@ class Uploader(): if fake_upload: cloudlog.info("*** WARNING, THIS IS A FAKE UPLOAD TO %s ***" % url) + class FakeResponse(): def __init__(self): self.status_code = 200 + self.last_resp = FakeResponse() else: with open(fn, "rb") as f: @@ -245,7 +247,8 @@ def uploader_fn(exit_event): backoff = 0.1 while True: - allow_raw_upload = (params.get("IsUploadRawEnabled") != b"0") + offroad = params.get("IsOffroad") == b'1' + allow_raw_upload = (params.get("IsUploadRawEnabled") != b"0") and offroad on_hotspot = is_on_hotspot() on_wifi = is_on_wifi() should_upload = on_wifi and not on_hotspot @@ -254,8 +257,8 @@ def uploader_fn(exit_event): return d = uploader.next_file_to_upload(with_raw=allow_raw_upload and should_upload) - if d is None: - time.sleep(5) + if d is None: # Nothing to upload + time.sleep(60 if offroad else 5) continue key, fn = d diff --git a/selfdrive/manager.py b/selfdrive/manager.py index c2db758233..e9ef36a2fc 100755 --- a/selfdrive/manager.py +++ b/selfdrive/manager.py @@ -9,15 +9,17 @@ import shutil import subprocess import datetime import textwrap +from typing import Dict, List from selfdrive.swaglog import cloudlog, add_logentries_handler + from common.basedir import BASEDIR, PARAMS from common.android import ANDROID WEBCAM = os.getenv("WEBCAM") is not None sys.path.append(os.path.join(BASEDIR, "pyextra")) os.environ['BASEDIR'] = BASEDIR -TOTAL_SCONS_NODES = 1140 +TOTAL_SCONS_NODES = 1005 prebuilt = os.path.exists(os.path.join(BASEDIR, 'prebuilt')) # Create folders needed for msgq @@ -34,7 +36,7 @@ if ANDROID: def unblock_stdout(): # get a non-blocking stdout child_pid, child_pty = os.forkpty() - if child_pid != 0: # parent + if child_pid != 0: # parent # child is in its own process group, manually pass kill signals signal.signal(signal.SIGINT, lambda signum, frame: os.kill(child_pid, signal.SIGINT)) @@ -68,19 +70,15 @@ def unblock_stdout(): if __name__ == "__main__": unblock_stdout() -if __name__ == "__main__" and ANDROID: - from common.spinner import Spinner - from common.text_window import TextWindow -else: - from common.spinner import FakeSpinner as Spinner - from common.text_window import FakeTextWindow as TextWindow +from common.spinner import Spinner +from common.text_window import TextWindow import importlib import traceback from multiprocessing import Process # Run scons -spinner = Spinner() +spinner = Spinner(noop=(__name__ != "__main__" or not ANDROID)) spinner.update("0") if not prebuilt: @@ -99,7 +97,7 @@ if not prebuilt: # Read progress from stderr and update spinner while scons.poll() is None: try: - line = scons.stderr.readline() + line = scons.stderr.readline() # type: ignore if line is None: continue line = line.rstrip() @@ -117,16 +115,20 @@ if not prebuilt: if scons.returncode != 0: # Read remaining output - r = scons.stderr.read().split(b'\n') + r = scons.stderr.read().split(b'\n') # type: ignore compile_output += r if retry: - print("scons build failed, cleaning in") - for i in range(3,-1,-1): - print("....%d" % i) - time.sleep(1) - subprocess.check_call(["scons", "-c"], cwd=BASEDIR, env=env) - shutil.rmtree("/tmp/scons_cache") + if not os.getenv("CI"): + print("scons build failed, cleaning in") + for i in range(3, -1, -1): + print("....%d" % i) + time.sleep(1) + subprocess.check_call(["scons", "-c"], cwd=BASEDIR, env=env) + shutil.rmtree("/tmp/scons_cache") + else: + print("scons build failed after retry") + sys.exit(1) else: # Build failed log errors errors = [line.decode('utf8', 'replace') for line in compile_output @@ -136,8 +138,9 @@ if not prebuilt: cloudlog.error("scons build failed\n" + error_s) # Show TextWindow + no_ui = __name__ != "__main__" or not ANDROID error_s = "\n \n".join(["\n".join(textwrap.wrap(e, 65)) for e in errors]) - with TextWindow("Openpilot failed to build\n \n" + error_s) as t: + with TextWindow("openpilot failed to build\n \n" + error_s, noop=no_ui) as t: t.wait_for_exit() exit(1) @@ -155,7 +158,6 @@ from selfdrive.loggerd.config import ROOT from selfdrive.launcher import launcher from common import android from common.apk import update_apks, pm_apply_packages, start_offroad -from common.manager_helpers import print_cpu_usage ThermalStatus = cereal.log.ThermalData.ThermalStatus @@ -167,7 +169,7 @@ managed_processes = { "controlsd": "selfdrive.controls.controlsd", "plannerd": "selfdrive.controls.plannerd", "radard": "selfdrive.controls.radard", - "dmonitoringd": "selfdrive.controls.dmonitoringd", + "dmonitoringd": "selfdrive.monitoring.dmonitoringd", "ubloxd": ("selfdrive/locationd", ["./ubloxd"]), "loggerd": ("selfdrive/loggerd", ["./loggerd"]), "logmessaged": "selfdrive.logmessaged", @@ -179,7 +181,7 @@ managed_processes = { "pandad": "selfdrive.pandad", "ui": ("selfdrive/ui", ["./ui"]), "calibrationd": "selfdrive.locationd.calibrationd", - "paramsd": ("selfdrive/locationd", ["./paramsd"]), + "paramsd": "selfdrive.locationd.paramsd", "camerad": ("selfdrive/camerad", ["./camerad"]), "sensord": ("selfdrive/sensord", ["./sensord"]), "clocksd": ("selfdrive/clocksd", ["./clocksd"]), @@ -187,14 +189,13 @@ managed_processes = { "updated": "selfdrive.updated", "dmonitoringmodeld": ("selfdrive/modeld", ["./dmonitoringmodeld"]), "modeld": ("selfdrive/modeld", ["./modeld"]), - "driverview": "selfdrive.controls.lib.driverview", } daemon_processes = { "manage_athenad": ("selfdrive.athena.manage_athenad", "AthenadPid"), } -running = {} +running: Dict[str, Process] = {} def get_running(): return running @@ -202,10 +203,10 @@ def get_running(): unkillable_processes = ['camerad'] # processes to end with SIGINT instead of SIGTERM -interrupt_processes = [] +interrupt_processes: List[str] = [] # processes to end with SIGKILL instead of SIGTERM -kill_processes = ['sensord', 'paramsd'] +kill_processes = ['sensord'] # processes to end if thermal conditions exceed Green parameters green_temp_processes = ['uploader'] @@ -222,6 +223,7 @@ if ANDROID: 'logcatd', 'tombstoned', 'updated', + 'deleter', ] car_started_processes = [ @@ -236,7 +238,13 @@ car_started_processes = [ 'modeld', 'proclogd', 'ubloxd', - #'locationd', + 'locationd', +] + +driver_view_processes = [ + 'camerad', + 'dmonitoringd', + 'dmonitoringmodeld' ] if WEBCAM: @@ -250,7 +258,6 @@ if ANDROID: 'clocksd', 'gpsd', 'dmonitoringmodeld', - 'deleter', ] def register_managed_process(name, desc, car_started=False): @@ -303,11 +310,11 @@ def start_daemon_process(name): pass cloudlog.info("starting daemon %s" % name) - proc = subprocess.Popen(['python', '-m', proc], - stdin=open('/dev/null', 'r'), - stdout=open('/dev/null', 'w'), - stderr=open('/dev/null', 'w'), - preexec_fn=os.setpgrp) + proc = subprocess.Popen(['python', '-m', proc], # pylint: disable=subprocess-popen-preexec-fn + stdin=open('/dev/null', 'r'), + stdout=open('/dev/null', 'w'), + stderr=open('/dev/null', 'w'), + preexec_fn=os.setpgrp) params.put(pid_param, str(proc.pid)) @@ -357,9 +364,11 @@ def kill_managed_process(name): cloudlog.critical("unkillable process %s failed to exit! rebooting in 15 if it doesn't die" % name) join_process(running[name], 15) if running[name].exitcode is None: - cloudlog.critical("FORCE REBOOTING PHONE!") - os.system("date >> /sdcard/unkillable_reboot") - os.system("reboot") + cloudlog.critical("unkillable process %s failed to die!" % name) + if ANDROID: + cloudlog.critical("FORCE REBOOTING PHONE!") + os.system("date >> /sdcard/unkillable_reboot") + os.system("reboot") raise RuntimeError else: cloudlog.info("killing %s with SIGKILL" % name) @@ -380,6 +389,14 @@ def cleanup_all_processes(signal, frame): kill_managed_process(name) cloudlog.info("everything is dead") + +def send_managed_process_signal(name, sig): + if name not in running or name not in managed_processes: + return + cloudlog.info(f"sending signal {sig} to {name}") + os.kill(running[name].pid, sig) + + # ****************** run loop ****************** def manager_init(should_register=True): @@ -420,9 +437,6 @@ def manager_thread(): # now loop thermal_sock = messaging.sub_sock('thermal') - if os.getenv("GET_CPU_USAGE"): - proc_sock = messaging.sub_sock('procLog', conflate=True) - cloudlog.info("manager start") cloudlog.info({"environ": os.environ}) @@ -451,11 +465,9 @@ def manager_thread(): for k in os.getenv("BLOCK").split(","): del managed_processes[k] + started_prev = False logger_dead = False - start_t = time.time() - first_proc = None - while 1: msg = messaging.recv_sock(thermal_sock, wait=True) @@ -472,7 +484,7 @@ def manager_thread(): if msg.thermal.freeSpace < 0.05: logger_dead = True - if msg.thermal.started and "driverview" not in running: + if msg.thermal.started: for p in car_started_processes: if p == "loggerd" and logger_dead: kill_managed_process(p) @@ -480,13 +492,24 @@ def manager_thread(): start_managed_process(p) else: logger_dead = False + driver_view = params.get("IsDriverViewEnabled") == b"1" + + # TODO: refactor how manager manages processes for p in reversed(car_started_processes): - kill_managed_process(p) - # this is ugly - if "driverview" not in running and params.get("IsDriverViewEnabled") == b"1": - start_managed_process("driverview") - elif "driverview" in running and params.get("IsDriverViewEnabled") == b"0": - kill_managed_process("driverview") + if p not in driver_view_processes or not driver_view: + kill_managed_process(p) + + for p in driver_view_processes: + if driver_view: + start_managed_process(p) + else: + kill_managed_process(p) + + # trigger an update after going offroad + if started_prev: + send_managed_process_signal("updated", signal.SIGHUP) + + started_prev = msg.thermal.started # check the status of all processes, did any of them die? running_list = ["%s%s\u001b[0m" % ("\u001b[32m" if running[p].is_alive() else "\u001b[31m", p) for p in running] @@ -496,20 +519,6 @@ def manager_thread(): if params.get("DoUninstall", encoding='utf8') == "1": break - if os.getenv("GET_CPU_USAGE"): - dt = time.time() - start_t - - # Get first sample - if dt > 30 and first_proc is None: - first_proc = messaging.recv_sock(proc_sock) - - # Get last sample and exit - if dt > 90: - last_proc = messaging.recv_sock(proc_sock, wait=True) - - cleanup_all_processes(None, None) - sys.exit(print_cpu_usage(first_proc, last_proc)) - def manager_prepare(spinner=None): # build all processes os.chdir(os.path.dirname(os.path.abspath(__file__))) @@ -532,11 +541,12 @@ def uninstall(): def main(): os.environ['PARAMS_PATH'] = PARAMS - # the flippening! - os.system('LD_LIBRARY_PATH="" content insert --uri content://settings/system --bind name:s:user_rotation --bind value:i:1') + if ANDROID: + # the flippening! + os.system('LD_LIBRARY_PATH="" content insert --uri content://settings/system --bind name:s:user_rotation --bind value:i:1') - # disable bluetooth - os.system('service call bluetooth_manager 8') + # disable bluetooth + os.system('service call bluetooth_manager 8') params = Params() params.manager_start() @@ -588,8 +598,6 @@ def main(): try: manager_thread() - except SystemExit: - raise except Exception: traceback.print_exc() crash.capture_exception() diff --git a/selfdrive/modeld/SConscript b/selfdrive/modeld/SConscript index a36d23da9c..cebbccd83a 100644 --- a/selfdrive/modeld/SConscript +++ b/selfdrive/modeld/SConscript @@ -1,16 +1,23 @@ -Import('env', 'arch', 'messaging', 'common', 'gpucommon', 'visionipc') +Import('env', 'arch', 'cereal', 'messaging', 'common', 'gpucommon', 'visionipc') lenv = env.Clone() -libs = [messaging, common, 'OpenCL', 'SNPE', 'capnp', 'zmq', 'czmq', 'kj', 'yuv', gpucommon, visionipc] +libs = [cereal, messaging, common, 'OpenCL', 'SNPE', 'capnp', 'zmq', 'czmq', 'kj', 'yuv', gpucommon, visionipc] + +TEST_THNEED = False common_src = [ "models/commonmodel.c", "runners/snpemodel.cc", "transforms/loadyuv.c", - "transforms/transform.c"] + "transforms/transform.c" +] if arch == "aarch64": libs += ['gsl', 'CB', 'gnustl_shared'] + if not TEST_THNEED: + common_src += ["thneed/thneed.cc"] + lenv['CFLAGS'].append("-DUSE_THNEED") + lenv['CXXFLAGS'].append("-DUSE_THNEED") elif arch == "larch64": libs += ['gsl', 'CB', 'symphony-cpu', 'pthread'] # no screen @@ -21,10 +28,21 @@ else: # for tensorflow support common_src += ['runners/tfmodel.cc'] - # tell runners to use it + + # tell runners to use tensorflow lenv['CFLAGS'].append("-DUSE_TF_MODEL") lenv['CXXFLAGS'].append("-DUSE_TF_MODEL") + if arch == "Darwin": + # fix OpenCL + del libs[libs.index('OpenCL')] + lenv['FRAMEWORKS'] = ['OpenCL'] + + # no SNPE on Mac + del libs[libs.index('SNPE')] + del libs[libs.index('symphony-cpu')] + del common_src[common_src.index('runners/snpemodel.cc')] + common = lenv.Object(common_src) lenv.Program('_dmonitoringmodeld', [ @@ -37,3 +55,8 @@ lenv.Program('_modeld', [ "models/driving.cc", ]+common, LIBS=libs) +if TEST_THNEED: + lenv.Program('thneed/debug/_thneed', [ + "thneed/thneed.cc", "thneed/debug/test.cc" + ]+common, LIBS=libs) + diff --git a/selfdrive/modeld/dmonitoringmodeld.cc b/selfdrive/modeld/dmonitoringmodeld.cc index d17247f9e5..28776f94ee 100644 --- a/selfdrive/modeld/dmonitoringmodeld.cc +++ b/selfdrive/modeld/dmonitoringmodeld.cc @@ -23,13 +23,14 @@ static void set_do_exit(int sig) { int main(int argc, char **argv) { int err; - set_realtime_priority(1); + set_realtime_priority(51); + + signal(SIGINT, (sighandler_t)set_do_exit); + signal(SIGTERM, (sighandler_t)set_do_exit); // messaging - Context *msg_context = Context::create(); - PubSocket *dmonitoring_sock = PubSocket::create(msg_context, "driverState"); - SubSocket *dmonstate_sock = SubSocket::create(msg_context, "dMonitoringState", "127.0.0.1", true); - assert(dmonstate_sock != NULL); + SubMaster sm({"dMonitoringState"}); + PubMaster pm({"driverState"}); // init the models DMonitoringModelState dmonitoringmodel; @@ -55,23 +56,15 @@ int main(int argc, char **argv) { buf = visionstream_get(&stream, &extra); if (buf == NULL) { printf("visionstream get failed\n"); - visionstream_destroy(&stream); break; } //printf("frame_id: %d %dx%d\n", extra.frame_id, buf_info.width, buf_info.height); if (!dmonitoringmodel.is_rhd_checked) { if (chk_counter >= RHD_CHECK_INTERVAL) { - Message *msg = dmonstate_sock->receive(true); - if (msg != NULL) { - auto amsg = kj::heapArray((msg->getSize() / sizeof(capnp::word)) + 1); - memcpy(amsg.begin(), msg->getData(), msg->getSize()); - - capnp::FlatArrayMessageReader cmsg(amsg); - cereal::Event::Reader event = cmsg.getRoot(); - - dmonitoringmodel.is_rhd = event.getDMonitoringState().getIsRHD(); - dmonitoringmodel.is_rhd_checked = event.getDMonitoringState().getRhdChecked(); - delete msg; + if (sm.update(0) > 0) { + auto state = sm["dMonitoringState"].getDMonitoringState(); + dmonitoringmodel.is_rhd = state.getIsRHD(); + dmonitoringmodel.is_rhd_checked = state.getRhdChecked(); } chk_counter = 0; } @@ -85,18 +78,14 @@ int main(int argc, char **argv) { double t2 = millis_since_boot(); // send dm packet - dmonitoring_publish(dmonitoring_sock, extra.frame_id, res); + dmonitoring_publish(pm, extra.frame_id, res); LOGD("dmonitoring process: %.2fms, from last %.2fms", t2-t1, t1-last); last = t1; } - + visionstream_destroy(&stream); } - visionstream_destroy(&stream); - - delete dmonitoring_sock; - delete msg_context; dmonitoring_free(&dmonitoringmodel); return 0; diff --git a/selfdrive/modeld/modeld.cc b/selfdrive/modeld/modeld.cc index 3b360bccc3..3df4e2252a 100644 --- a/selfdrive/modeld/modeld.cc +++ b/selfdrive/modeld/modeld.cc @@ -1,14 +1,16 @@ #include #include #include +#include #include #include "common/visionbuf.h" #include "common/visionipc.h" #include "common/swaglog.h" +#include "common/clutil.h" #include "models/driving.h" - +#include "messaging.hpp" volatile sig_atomic_t do_exit = 0; static void set_do_exit(int sig) { @@ -21,15 +23,9 @@ mat3 cur_transform; pthread_mutex_t transform_lock; void* live_thread(void *arg) { - int err; set_thread_name("live"); - Context * c = Context::create(); - SubSocket * live_calibration_sock = SubSocket::create(c, "liveCalibration"); - assert(live_calibration_sock != NULL); - - Poller * poller = Poller::create({live_calibration_sock}); - + SubMaster sm({"liveCalibration"}); /* import numpy as np from common.transformations.model import medmodel_frame_from_road_frame @@ -57,55 +53,42 @@ void* live_thread(void *arg) { #endif while (!do_exit) { - for (auto sock : poller->poll(10)){ - Message * msg = sock->receive(); - - auto amsg = kj::heapArray((msg->getSize() / sizeof(capnp::word)) + 1); - memcpy(amsg.begin(), msg->getData(), msg->getSize()); - - capnp::FlatArrayMessageReader cmsg(amsg); - cereal::Event::Reader event = cmsg.getRoot(); - - if (event.isLiveCalibration()) { - pthread_mutex_lock(&transform_lock); - - auto extrinsic_matrix = event.getLiveCalibration().getExtrinsicMatrix(); - Eigen::Matrix extrinsic_matrix_eigen; - for (int i = 0; i < 4*3; i++){ - extrinsic_matrix_eigen(i / 4, i % 4) = extrinsic_matrix[i]; - } + if (sm.update(10) > 0){ - auto camera_frame_from_road_frame = eon_intrinsics * extrinsic_matrix_eigen; - Eigen::Matrix camera_frame_from_ground; - camera_frame_from_ground.col(0) = camera_frame_from_road_frame.col(0); - camera_frame_from_ground.col(1) = camera_frame_from_road_frame.col(1); - camera_frame_from_ground.col(2) = camera_frame_from_road_frame.col(3); + auto extrinsic_matrix = sm["liveCalibration"].getLiveCalibration().getExtrinsicMatrix(); + Eigen::Matrix extrinsic_matrix_eigen; + for (int i = 0; i < 4*3; i++){ + extrinsic_matrix_eigen(i / 4, i % 4) = extrinsic_matrix[i]; + } - auto warp_matrix = camera_frame_from_ground * ground_from_medmodel_frame; + auto camera_frame_from_road_frame = eon_intrinsics * extrinsic_matrix_eigen; + Eigen::Matrix camera_frame_from_ground; + camera_frame_from_ground.col(0) = camera_frame_from_road_frame.col(0); + camera_frame_from_ground.col(1) = camera_frame_from_road_frame.col(1); + camera_frame_from_ground.col(2) = camera_frame_from_road_frame.col(3); - for (int i=0; i<3*3; i++) { - cur_transform.v[i] = warp_matrix(i / 3, i % 3); - } + auto warp_matrix = camera_frame_from_ground * ground_from_medmodel_frame; - run_model = true; - pthread_mutex_unlock(&transform_lock); + pthread_mutex_lock(&transform_lock); + for (int i=0; i<3*3; i++) { + cur_transform.v[i] = warp_matrix(i / 3, i % 3); } - delete msg; + run_model = true; + pthread_mutex_unlock(&transform_lock); } - } - - delete live_calibration_sock; - delete poller; - delete c; - return NULL; } int main(int argc, char **argv) { int err; - set_realtime_priority(1); + set_realtime_priority(51); + + signal(SIGINT, (sighandler_t)set_do_exit); + signal(SIGTERM, (sighandler_t)set_do_exit); + + pthread_mutex_init(&transform_lock, NULL); // start calibration thread pthread_t live_thread_handle; @@ -113,50 +96,22 @@ int main(int argc, char **argv) { assert(err == 0); // messaging - Context *msg_context = Context::create(); - PubSocket *model_sock = PubSocket::create(msg_context, "model"); - PubSocket *posenet_sock = PubSocket::create(msg_context, "cameraOdometry"); - SubSocket *pathplan_sock = SubSocket::create(msg_context, "pathPlan", "127.0.0.1", true); + PubMaster pm({"model", "cameraOdometry"}); + SubMaster sm({"pathPlan", "frame"}); - assert(model_sock != NULL); - assert(posenet_sock != NULL); - assert(pathplan_sock != NULL); +#ifdef QCOM + cl_device_type device_type = CL_DEVICE_TYPE_DEFAULT; +#else + cl_device_type device_type = CL_DEVICE_TYPE_CPU; +#endif // cl init - cl_device_id device_id; - cl_context context; - cl_command_queue q; - { - // TODO: refactor this - cl_platform_id platform_id[2]; - cl_uint num_devices; - cl_uint num_platforms; - - err = clGetPlatformIDs(sizeof(platform_id)/sizeof(cl_platform_id), platform_id, &num_platforms); - assert(err == 0); - - #ifdef QCOM - int clPlatform = 0; - #else - // don't use nvidia on pc, it's broken - // TODO: write this nicely - int clPlatform = num_platforms-1; - #endif - - char cBuffer[1024]; - clGetPlatformInfo(platform_id[clPlatform], CL_PLATFORM_NAME, sizeof(cBuffer), &cBuffer, NULL); - LOGD("got %d opencl platform(s), using %s", num_platforms, cBuffer); - - err = clGetDeviceIDs(platform_id[clPlatform], CL_DEVICE_TYPE_DEFAULT, 1, - &device_id, &num_devices); - assert(err == 0); - - context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &err); - assert(err == 0); - - q = clCreateCommandQueue(context, device_id, 0, &err); - assert(err == 0); - } + cl_device_id device_id = cl_get_device_id(device_type); + cl_context context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &err); + assert(err == 0); + + cl_command_queue q = clCreateCommandQueue(context, device_id, 0, &err); + assert(err == 0); // init the models ModelState model; @@ -182,10 +137,17 @@ int main(int argc, char **argv) { } LOGW("connected with buffer size: %d", buf_info.buf_len); + // setup filter to track dropped frames + const float dt = 1. / MODEL_FREQ; + const float ts = 5.0; // 5 s filter time constant + const float frame_filter_k = (dt / ts) / (1. + dt / ts); + float frames_dropped = 0; + // one frame in memory cl_mem yuv_cl; VisionBuf yuv_ion = visionbuf_allocate_cl(buf_info.buf_len, device_id, context, &yuv_cl); + uint32_t frame_id = 0, last_vipc_frame_id = 0; double last = 0; int desire = -1; while (!do_exit) { @@ -194,7 +156,6 @@ int main(int argc, char **argv) { buf = visionstream_get(&stream, &extra); if (buf == NULL) { LOGW("visionstream get failed"); - visionstream_destroy(&stream); break; } @@ -203,18 +164,10 @@ int main(int argc, char **argv) { const bool run_model_this_iter = run_model; pthread_mutex_unlock(&transform_lock); - Message *msg = pathplan_sock->receive(true); - if (msg != NULL) { - // TODO: copy and pasted from camerad/main.cc - auto amsg = kj::heapArray((msg->getSize() / sizeof(capnp::word)) + 1); - memcpy(amsg.begin(), msg->getData(), msg->getSize()); - - capnp::FlatArrayMessageReader cmsg(amsg); - cereal::Event::Reader event = cmsg.getRoot(); - + if (sm.update(0) > 0){ // TODO: path planner timeout? - desire = ((int)event.getPathPlan().getDesire()) - 1; - delete msg; + desire = ((int)sm["pathPlan"].getPathPlan().getDesire()) - 1; + frame_id = sm["frame"].getFrame().getFrameId(); } double mt1 = 0, mt2 = 0; @@ -225,7 +178,7 @@ int main(int argc, char **argv) { } mat3 model_transform = matmul3(yuv_transform, transform); - + mt1 = millis_since_boot(); // TODO: don't make copies! @@ -236,24 +189,24 @@ int main(int argc, char **argv) { model_transform, NULL, vec_desire); mt2 = millis_since_boot(); - model_publish(model_sock, extra.frame_id, model_buf, extra.timestamp_eof); - posenet_publish(posenet_sock, extra.frame_id, model_buf, extra.timestamp_eof); + // tracked dropped frames + uint32_t vipc_dropped_frames = extra.frame_id - last_vipc_frame_id - 1; + frames_dropped = (1. - frame_filter_k) * frames_dropped + frame_filter_k * (float)std::min(vipc_dropped_frames, 10U); + float frame_drop_perc = frames_dropped / MODEL_FREQ; - LOGD("model process: %.2fms, from last %.2fms", mt2-mt1, mt1-last); + model_publish(pm, extra.frame_id, frame_id, vipc_dropped_frames, frame_drop_perc, model_buf, extra.timestamp_eof); + posenet_publish(pm, extra.frame_id, frame_id, vipc_dropped_frames, frame_drop_perc, model_buf, extra.timestamp_eof); + + LOGD("model process: %.2fms, from last %.2fms, vipc_frame_id %zu, frame_id, %zu, frame_drop %.3f", mt2-mt1, mt1-last, extra.frame_id, frame_id, frame_drop_perc); last = mt1; + last_vipc_frame_id = extra.frame_id; } } visionbuf_free(&yuv_ion); + visionstream_destroy(&stream); } - visionstream_destroy(&stream); - - delete model_sock; - delete posenet_sock; - delete pathplan_sock; - delete msg_context; - #ifdef NOSCREEN zsock_destroy(&model.yuv_sock); #endif @@ -263,6 +216,9 @@ int main(int argc, char **argv) { LOG("joining live_thread"); err = pthread_join(live_thread_handle, NULL); assert(err == 0); + clReleaseCommandQueue(q); + clReleaseContext(context); + pthread_mutex_destroy(&transform_lock); return 0; } diff --git a/selfdrive/modeld/models/commonmodel.c b/selfdrive/modeld/models/commonmodel.c index db990af0cb..eebf4761af 100644 --- a/selfdrive/modeld/models/commonmodel.c +++ b/selfdrive/modeld/models/commonmodel.c @@ -15,13 +15,13 @@ void frame_init(ModelFrame* frame, int width, int height, frame->transformed_height = height; frame->transformed_y_cl = clCreateBuffer(frame->context, CL_MEM_READ_WRITE, - frame->transformed_width*frame->transformed_height, NULL, &err); + (size_t)frame->transformed_width*frame->transformed_height, NULL, &err); assert(err == 0); frame->transformed_u_cl = clCreateBuffer(frame->context, CL_MEM_READ_WRITE, - (frame->transformed_width/2)*(frame->transformed_height/2), NULL, &err); + (size_t)(frame->transformed_width/2)*(frame->transformed_height/2), NULL, &err); assert(err == 0); frame->transformed_v_cl = clCreateBuffer(frame->context, CL_MEM_READ_WRITE, - (frame->transformed_width/2)*(frame->transformed_height/2), NULL, &err); + (size_t)(frame->transformed_width/2)*(frame->transformed_height/2), NULL, &err); assert(err == 0); frame->net_input_size = ((width*height*3)/2)*sizeof(float); @@ -36,7 +36,6 @@ float *frame_prepare(ModelFrame* frame, cl_command_queue q, cl_mem yuv_cl, int width, int height, mat3 transform) { int err; - int i = 0; transform_queue(&frame->transform, q, yuv_cl, width, height, frame->transformed_y_cl, frame->transformed_u_cl, frame->transformed_v_cl, @@ -55,6 +54,10 @@ float *frame_prepare(ModelFrame* frame, cl_command_queue q, void frame_free(ModelFrame* frame) { transform_destroy(&frame->transform); loadyuv_destroy(&frame->loadyuv); + clReleaseMemObject(frame->net_input); + clReleaseMemObject(frame->transformed_v_cl); + clReleaseMemObject(frame->transformed_u_cl); + clReleaseMemObject(frame->transformed_y_cl); } diff --git a/selfdrive/modeld/models/commonmodel.h b/selfdrive/modeld/models/commonmodel.h index 0a03d281ad..bb52366481 100644 --- a/selfdrive/modeld/models/commonmodel.h +++ b/selfdrive/modeld/models/commonmodel.h @@ -2,7 +2,11 @@ #define COMMONMODEL_H #define CL_USE_DEPRECATED_OPENCL_1_2_APIS +#ifdef __APPLE__ +#include +#else #include +#endif #include "common/mat.h" #include "transforms/transform.h" diff --git a/selfdrive/modeld/models/dmonitoring.cc b/selfdrive/modeld/models/dmonitoring.cc index 41de617ad6..4f4203a38a 100644 --- a/selfdrive/modeld/models/dmonitoring.cc +++ b/selfdrive/modeld/models/dmonitoring.cc @@ -5,9 +5,9 @@ #include -#define MODEL_WIDTH 160 -#define MODEL_HEIGHT 320 -#define FULL_W 426 +#define MODEL_WIDTH 320 +#define MODEL_HEIGHT 640 +#define FULL_W 852 #if defined(QCOM) || defined(QCOM2) #define input_lambda(x) (x - 128.f) * 0.0078125f @@ -26,6 +26,14 @@ void dmonitoring_init(DMonitoringModelState* s) { s->is_rhd_checked = false; } +template +static inline T *get_buffer(std::vector &buf, const size_t size) { + if (buf.size() < size) { + buf.resize(size); + } + return buf.data(); +} + DMonitoringResult dmonitoring_eval_frame(DMonitoringModelState* s, void* stream_buf, int width, int height) { uint8_t *raw_buf = (uint8_t*) stream_buf; @@ -39,8 +47,7 @@ DMonitoringResult dmonitoring_eval_frame(DMonitoringModelState* s, void* stream_ int resized_width = MODEL_WIDTH; int resized_height = MODEL_HEIGHT; - uint8_t *cropped_buf = new uint8_t[cropped_width*cropped_height*3/2]; - uint8_t *cropped_y_buf = cropped_buf; + uint8_t *cropped_y_buf = get_buffer(s->cropped_buf, cropped_width*cropped_height*3/2); uint8_t *cropped_u_buf = cropped_y_buf + (cropped_width * cropped_height); uint8_t *cropped_v_buf = cropped_u_buf + ((cropped_width/2) * (cropped_height/2)); @@ -53,8 +60,7 @@ DMonitoringResult dmonitoring_eval_frame(DMonitoringModelState* s, void* stream_ } } else { // not tested - uint8_t *premirror_cropped_buf = new uint8_t[cropped_width*cropped_height*3/2]; - uint8_t *premirror_cropped_y_buf = premirror_cropped_buf; + uint8_t *premirror_cropped_y_buf = get_buffer(s->premirror_cropped_buf, cropped_width*cropped_height*3/2); uint8_t *premirror_cropped_u_buf = premirror_cropped_y_buf + (cropped_width * cropped_height); uint8_t *premirror_cropped_v_buf = premirror_cropped_u_buf + ((cropped_width/2) * (cropped_height/2)); for (int r = 0; r < height/2; r++) { @@ -70,10 +76,9 @@ DMonitoringResult dmonitoring_eval_frame(DMonitoringModelState* s, void* stream_ cropped_u_buf, cropped_width/2, cropped_v_buf, cropped_width/2, cropped_width, cropped_height); - delete[] premirror_cropped_buf; } - uint8_t *resized_buf = new uint8_t[resized_width*resized_height*3/2]; + uint8_t *resized_buf = get_buffer(s->resized_buf, resized_width*resized_height*3/2); uint8_t *resized_y_buf = resized_buf; uint8_t *resized_u_buf = resized_y_buf + (resized_width * resized_height); uint8_t *resized_v_buf = resized_u_buf + ((resized_width/2) * (resized_height/2)); @@ -90,8 +95,7 @@ DMonitoringResult dmonitoring_eval_frame(DMonitoringModelState* s, void* stream_ mode); int yuv_buf_len = (MODEL_WIDTH/2) * (MODEL_HEIGHT/2) * 6; // Y|u|v -> y|y|y|y|u|v - - float *net_input_buf = new float[yuv_buf_len]; + float *net_input_buf = get_buffer(s->net_input_buf, yuv_buf_len); // one shot conversion, O(n) anyway // yuvframe2tensor, normalize for (int r = 0; r < MODEL_HEIGHT/2; r++) { @@ -120,10 +124,7 @@ DMonitoringResult dmonitoring_eval_frame(DMonitoringModelState* s, void* stream_ //fwrite(net_input_buf, MODEL_HEIGHT*MODEL_WIDTH*3/2, sizeof(float), dump_yuv_file2); //fclose(dump_yuv_file2); - delete[] cropped_buf; - delete[] resized_buf; s->m->execute(net_input_buf, yuv_buf_len); - delete[] net_input_buf; DMonitoringResult ret = {0}; memcpy(&ret.face_orientation, &s->output[0], sizeof ret.face_orientation); @@ -135,6 +136,7 @@ DMonitoringResult dmonitoring_eval_frame(DMonitoringModelState* s, void* stream_ memcpy(&ret.right_eye_prob, &s->output[30], sizeof ret.right_eye_prob); memcpy(&ret.left_blink_prob, &s->output[31], sizeof ret.right_eye_prob); memcpy(&ret.right_blink_prob, &s->output[32], sizeof ret.right_eye_prob); + memcpy(&ret.sg_prob, &s->output[33], sizeof ret.sg_prob); ret.face_orientation_meta[0] = softplus(ret.face_orientation_meta[0]); ret.face_orientation_meta[1] = softplus(ret.face_orientation_meta[1]); ret.face_orientation_meta[2] = softplus(ret.face_orientation_meta[2]); @@ -143,7 +145,7 @@ DMonitoringResult dmonitoring_eval_frame(DMonitoringModelState* s, void* stream_ return ret; } -void dmonitoring_publish(PubSocket* sock, uint32_t frame_id, const DMonitoringResult res) { +void dmonitoring_publish(PubMaster &pm, uint32_t frame_id, const DMonitoringResult &res){ // make msg capnp::MallocMessageBuilder msg; cereal::Event::Builder event = msg.initRoot(); @@ -165,11 +167,9 @@ void dmonitoring_publish(PubSocket* sock, uint32_t frame_id, const DMonitoringRe framed.setRightEyeProb(res.right_eye_prob); framed.setLeftBlinkProb(res.left_blink_prob); framed.setRightBlinkProb(res.right_blink_prob); + framed.setSgProb(res.sg_prob); - // send message - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - sock->send((char*)bytes.begin(), bytes.size()); + pm.send("driverState", msg); } void dmonitoring_free(DMonitoringModelState* s) { diff --git a/selfdrive/modeld/models/dmonitoring.h b/selfdrive/modeld/models/dmonitoring.h index dc5d116e98..439b9c0051 100644 --- a/selfdrive/modeld/models/dmonitoring.h +++ b/selfdrive/modeld/models/dmonitoring.h @@ -1,19 +1,15 @@ -#ifndef DMONITORING_H -#define DMONITORING_H - +#pragma once +#include #include "common/util.h" #include "commonmodel.h" #include "runners/run.h" - -#include "cereal/gen/cpp/log.capnp.h" -#include #include "messaging.hpp" #ifdef __cplusplus extern "C" { #endif -#define OUTPUT_SIZE 33 +#define OUTPUT_SIZE 34 #define RHD_CHECK_INTERVAL 10 typedef struct DMonitoringResult { @@ -26,6 +22,7 @@ typedef struct DMonitoringResult { float right_eye_prob; float left_blink_prob; float right_blink_prob; + float sg_prob; } DMonitoringResult; typedef struct DMonitoringModelState { @@ -33,15 +30,18 @@ typedef struct DMonitoringModelState { bool is_rhd; bool is_rhd_checked; float output[OUTPUT_SIZE]; + std::vector resized_buf; + std::vector cropped_buf; + std::vector premirror_cropped_buf; + std::vector net_input_buf; } DMonitoringModelState; void dmonitoring_init(DMonitoringModelState* s); DMonitoringResult dmonitoring_eval_frame(DMonitoringModelState* s, void* stream_buf, int width, int height); -void dmonitoring_publish(PubSocket *sock, uint32_t frame_id, const DMonitoringResult res); +void dmonitoring_publish(PubMaster &pm, uint32_t frame_id, const DMonitoringResult &res); void dmonitoring_free(DMonitoringModelState* s); #ifdef __cplusplus } #endif -#endif diff --git a/selfdrive/modeld/models/driving.cc b/selfdrive/modeld/models/driving.cc index 2e3615c45e..45d000eba1 100644 --- a/selfdrive/modeld/models/driving.cc +++ b/selfdrive/modeld/models/driving.cc @@ -9,9 +9,6 @@ #include "common/params.h" #include "driving.h" - - - #define PATH_IDX 0 #define LL_IDX PATH_IDX + MODEL_PATH_DISTANCE*2 + 1 #define RL_IDX LL_IDX + MODEL_PATH_DISTANCE*2 + 2 @@ -54,23 +51,18 @@ void model_init(ModelState* s, cl_device_id device_id, cl_context context, int t #endif #ifdef DESIRE - s->prev_desire = (float*)malloc(DESIRE_LEN * sizeof(float)); - for (int i = 0; i < DESIRE_LEN; i++) s->prev_desire[i] = 0.0; - s->pulse_desire = (float*)malloc(DESIRE_LEN * sizeof(float)); - for (int i = 0; i < DESIRE_LEN; i++) s->pulse_desire[i] = 0.0; - s->m->addDesire(s->pulse_desire, DESIRE_LEN); + s->prev_desire = std::make_unique(DESIRE_LEN); + s->pulse_desire = std::make_unique(DESIRE_LEN); + s->m->addDesire(s->pulse_desire.get(), DESIRE_LEN); #endif #ifdef TRAFFIC_CONVENTION - s->traffic_convention = (float*)malloc(TRAFFIC_CONVENTION_LEN * sizeof(float)); - for (int i = 0; i < TRAFFIC_CONVENTION_LEN; i++) s->traffic_convention[i] = 0.0; - s->m->addTrafficConvention(s->traffic_convention, TRAFFIC_CONVENTION_LEN); - - char *string; - const int result = read_db_value("IsRHD", &string, NULL); - if (result == 0) { - bool is_rhd = string[0] == '1'; - free(string); + s->traffic_convention = std::make_unique(TRAFFIC_CONVENTION_LEN); + s->m->addTrafficConvention(s->traffic_convention.get(), TRAFFIC_CONVENTION_LEN); + + std::vector result = read_db_bytes("IsRHD"); + if (result.size() > 0) { + bool is_rhd = result[0] == '1'; if (is_rhd) { s->traffic_convention[1] = 1.0; } else { @@ -87,8 +79,6 @@ void model_init(ModelState* s, cl_device_id device_id, cl_context context, int t } } - - ModelDataRaw model_eval_frame(ModelState* s, cl_command_queue q, cl_mem yuv_cl, int width, int height, mat3 transform, void* sock, @@ -108,7 +98,6 @@ ModelDataRaw model_eval_frame(ModelState* s, cl_command_queue q, } #endif - //for (int i = 0; i < OUTPUT_SIZE + TEMPORAL_SIZE; i++) { printf("%f ", s->output[i]); } printf("\n"); float *new_frame_buf = frame_prepare(&s->frame, q, yuv_cl, width, height, transform); @@ -178,7 +167,6 @@ void poly_fit(float *in_pts, float *in_stds, float *out, int valid_len) { out[3] = y0; } - void fill_path(cereal::ModelData::PathData::Builder path, const float * data, bool has_prob, const float offset) { float points_arr[MODEL_PATH_DISTANCE]; float stds_arr[MODEL_PATH_DISTANCE]; @@ -187,8 +175,8 @@ void fill_path(cereal::ModelData::PathData::Builder path, const float * data, bo float prob; float valid_len; - // clamp to 5 and 192 - valid_len = fmin(192, fmax(5, data[MODEL_PATH_DISTANCE*2])); + // clamp to 5 and MODEL_PATH_DISTANCE + valid_len = fmin(MODEL_PATH_DISTANCE, fmax(5, data[MODEL_PATH_DISTANCE*2])); for (int i=0; i(); - event.setLogMonoTime(nanos_since_boot()); - - auto framed = event.initModel(); - framed.setFrameId(frame_id); - framed.setTimestampEof(timestamp_eof); - - auto lpath = framed.initPath(); - fill_path(lpath, net_outputs.path, false, 0); - auto left_lane = framed.initLeftLane(); - fill_path(left_lane, net_outputs.left_lane, true, 1.8); - auto right_lane = framed.initRightLane(); - fill_path(right_lane, net_outputs.right_lane, true, -1.8); - auto longi = framed.initLongitudinal(); - fill_longi(longi, net_outputs.long_x, net_outputs.long_v, net_outputs.long_a); - - - // Find the distribution that corresponds to the current lead - int mdn_max_idx = 0; - int t_offset = 0; - for (int i=1; i net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + 8 + t_offset]) { - mdn_max_idx = i; - } +void model_publish(PubMaster &pm, uint32_t vipc_frame_id, uint32_t frame_id, + uint32_t vipc_dropped_frames, float frame_drop, const ModelDataRaw &net_outputs, uint64_t timestamp_eof) { + // make msg + capnp::MallocMessageBuilder msg; + cereal::Event::Builder event = msg.initRoot(); + event.setLogMonoTime(nanos_since_boot()); + + uint32_t frame_age = (frame_id > vipc_frame_id) ? (frame_id - vipc_frame_id) : 0; + + auto framed = event.initModel(); + framed.setFrameId(vipc_frame_id); + framed.setFrameAge(frame_age); + framed.setFrameDropPerc(frame_drop * 100); + framed.setTimestampEof(timestamp_eof); + + auto lpath = framed.initPath(); + fill_path(lpath, net_outputs.path, false, 0); + auto left_lane = framed.initLeftLane(); + fill_path(left_lane, net_outputs.left_lane, true, 1.8); + auto right_lane = framed.initRightLane(); + fill_path(right_lane, net_outputs.right_lane, true, -1.8); + auto longi = framed.initLongitudinal(); + fill_longi(longi, net_outputs.long_x, net_outputs.long_v, net_outputs.long_a); + + + // Find the distribution that corresponds to the current lead + int mdn_max_idx = 0; + int t_offset = 0; + for (int i=1; i net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + 8 + t_offset]) { + mdn_max_idx = i; } - auto lead = framed.initLead(); - fill_lead(lead, net_outputs.lead, mdn_max_idx, t_offset); - // Find the distribution that corresponds to the lead in 2s - mdn_max_idx = 0; - t_offset = 1; - for (int i=1; i net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + 8 + t_offset]) { - mdn_max_idx = i; - } + } + auto lead = framed.initLead(); + fill_lead(lead, net_outputs.lead, mdn_max_idx, t_offset); + // Find the distribution that corresponds to the lead in 2s + mdn_max_idx = 0; + t_offset = 1; + for (int i=1; i net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + 8 + t_offset]) { + mdn_max_idx = i; } - auto lead_future = framed.initLeadFuture(); - fill_lead(lead_future, net_outputs.lead, mdn_max_idx, t_offset); - + } + auto lead_future = framed.initLeadFuture(); + fill_lead(lead_future, net_outputs.lead, mdn_max_idx, t_offset); - auto meta = framed.initMeta(); - fill_meta(meta, net_outputs.meta); + auto meta = framed.initMeta(); + fill_meta(meta, net_outputs.meta); + event.setValid(frame_drop < MAX_FRAME_DROP); - // send message - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - sock->send((char*)bytes.begin(), bytes.size()); - } + pm.send("model", msg); +} -void posenet_publish(PubSocket *sock, uint32_t frame_id, - const ModelDataRaw net_outputs, uint64_t timestamp_eof) { +void posenet_publish(PubMaster &pm, uint32_t vipc_frame_id, uint32_t frame_id, + uint32_t vipc_dropped_frames, float frame_drop, const ModelDataRaw &net_outputs, uint64_t timestamp_eof) { capnp::MallocMessageBuilder msg; cereal::Event::Builder event = msg.initRoot(); event.setLogMonoTime(nanos_since_boot()); @@ -341,10 +331,11 @@ void posenet_publish(PubSocket *sock, uint32_t frame_id, kj::ArrayPtr rot_std_vs(&rot_std_arr[0], 3); posenetd.setRotStd(rot_std_vs); + posenetd.setTimestampEof(timestamp_eof); - posenetd.setFrameId(frame_id); + posenetd.setFrameId(vipc_frame_id); - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - sock->send((char*)bytes.begin(), bytes.size()); - } + event.setValid(vipc_dropped_frames < 1); + + pm.send("cameraOdometry", msg); +} diff --git a/selfdrive/modeld/models/driving.h b/selfdrive/modeld/models/driving.h index d48a067607..3b2235ddd4 100644 --- a/selfdrive/modeld/models/driving.h +++ b/selfdrive/modeld/models/driving.h @@ -9,13 +9,13 @@ #include "common/mat.h" #include "common/util.h" +#include "common/modeldata.h" #include "commonmodel.h" #include "runners/run.h" -#include "cereal/gen/cpp/log.capnp.h" #include -#include +#include #include "messaging.hpp" #define MODEL_WIDTH 512 @@ -23,13 +23,8 @@ #define MODEL_FRAME_SIZE MODEL_WIDTH * MODEL_HEIGHT * 3 / 2 #define MODEL_NAME "supercombo_dlc" -#define MODEL_PATH_DISTANCE 192 -#define POLYFIT_DEGREE 4 -#define SPEED_PERCENTILES 10 #define DESIRE_LEN 8 #define TRAFFIC_CONVENTION_LEN 2 -#define DESIRE_PRED_SIZE 32 -#define OTHER_META_SIZE 4 #define LEAD_MDN_N 5 // probs for 5 groups #define MDN_VALS 4 // output xyva for each lead group #define SELECTION 3 //output 3 group (lead now, in 2s and 6s) @@ -37,6 +32,9 @@ #define TIME_DISTANCE 100 #define POSE_SIZE 12 +#define MODEL_FREQ 20 +#define MAX_FRAME_DROP 0.05 + struct ModelDataRaw { float *path; float *left_lane; @@ -57,11 +55,11 @@ typedef struct ModelState { float *input_frames; RunModel *m; #ifdef DESIRE - float *prev_desire; - float *pulse_desire; + std::unique_ptr prev_desire; + std::unique_ptr pulse_desire; #endif #ifdef TRAFFIC_CONVENTION - float *traffic_convention; + std::unique_ptr traffic_convention; #endif #ifdef NOSCREEN zsock_t *yuv_sock; @@ -76,8 +74,8 @@ ModelDataRaw model_eval_frame(ModelState* s, cl_command_queue q, void model_free(ModelState* s); void poly_fit(float *in_pts, float *in_stds, float *out); -void model_publish(PubSocket* sock, uint32_t frame_id, - const ModelDataRaw data, uint64_t timestamp_eof); -void posenet_publish(PubSocket* sock, uint32_t frame_id, - const ModelDataRaw data, uint64_t timestamp_eof); +void model_publish(PubMaster &pm, uint32_t vipc_frame_id, uint32_t frame_id, + uint32_t vipc_dropped_frames, float frame_drop, const ModelDataRaw &data, uint64_t timestamp_eof); +void posenet_publish(PubMaster &pm, uint32_t vipc_frame_id, uint32_t frame_id, + uint32_t vipc_dropped_frames, float frame_drop, const ModelDataRaw &data, uint64_t timestamp_eof); #endif diff --git a/selfdrive/modeld/runners/keras_runner.py b/selfdrive/modeld/runners/keras_runner.py index 4dfd197673..0a9eddeac7 100755 --- a/selfdrive/modeld/runners/keras_runner.py +++ b/selfdrive/modeld/runners/keras_runner.py @@ -2,35 +2,39 @@ # TODO: why are the keras models saved with python 2? from __future__ import print_function -import tensorflow as tf +import tensorflow as tf # pylint: disable=import-error import os import sys -import tensorflow.keras as keras import numpy as np -from tensorflow.keras.models import Model -from tensorflow.keras.models import load_model +from tensorflow.keras.models import load_model # pylint: disable=import-error def read(sz): dd = [] gt = 0 - while gt < sz*4: - st = os.read(0, sz*4 - gt) + while gt < sz * 4: + st = os.read(0, sz * 4 - gt) assert(len(st) > 0) dd.append(st) gt += len(st) - return np.fromstring(b''.join(dd), dtype=np.float32) + return np.frombuffer(b''.join(dd), dtype=np.float32) def write(d): os.write(1, d.tobytes()) def run_loop(m): - isize = m.inputs[0].shape[1] - osize = m.outputs[0].shape[1] - print("ready to run keras model %d -> %d" % (isize, osize), file=sys.stderr) + ishapes = [[1]+ii.shape[1:] for ii in m.inputs] + print("ready to run keras model", ishapes, file=sys.stderr) while 1: - idata = read(isize).reshape((1, isize)) - ret = m.predict_on_batch(idata) - write(ret) + inputs = [] + for shp in ishapes: + ts = np.product(shp) + #print("reshaping %s with offset %d" % (str(shp), offset), file=sys.stderr) + inputs.append(read(ts).reshape(shp)) + ret = m.predict_on_batch(inputs) + #print(ret, file=sys.stderr) + for r in ret: + write(r) + if __name__ == "__main__": print(tf.__version__, file=sys.stderr) @@ -41,18 +45,6 @@ if __name__ == "__main__": m = load_model(sys.argv[1]) print(m, file=sys.stderr) - bs = [int(np.product(ii.shape[1:])) for ii in m.inputs] - ri = keras.layers.Input((sum(bs),)) - - tii = [] - acc = 0 - for i, ii in enumerate(m.inputs): - print(ii, file=sys.stderr) - ti = keras.layers.Lambda(lambda x: x[:,acc:acc+bs[i]], output_shape=(1, bs[i]))(ri) - acc += bs[i] - tr = keras.layers.Reshape(ii.shape[1:])(ti) - tii.append(tr) - no = keras.layers.Concatenate()(m(tii)) - m = Model(inputs=ri, outputs=[no]) + run_loop(m) diff --git a/selfdrive/modeld/runners/snpemodel.cc b/selfdrive/modeld/runners/snpemodel.cc index 1785eaf962..38da13453a 100644 --- a/selfdrive/modeld/runners/snpemodel.cc +++ b/selfdrive/modeld/runners/snpemodel.cc @@ -1,17 +1,19 @@ +#pragma clang diagnostic ignored "-Wexceptions" + #include #include #include "common/util.h" #include "snpemodel.h" void PrintErrorStringAndExit() { - const char* const errStr = zdl::DlSystem::getLastErrorString(); std::cerr << zdl::DlSystem::getLastErrorString() << std::endl; std::exit(EXIT_FAILURE); } -SNPEModel::SNPEModel(const char *path, float *output, size_t output_size, int runtime) { +SNPEModel::SNPEModel(const char *path, float *loutput, size_t loutput_size, int runtime) { + output = loutput; + output_size = loutput_size; #if defined(QCOM) || defined(QCOM2) - zdl::DlSystem::Runtime_t Runtime; if (runtime==USE_GPU_RUNTIME) { Runtime = zdl::DlSystem::Runtime_t::GPU; } else if (runtime==USE_DSP_RUNTIME) { @@ -87,6 +89,13 @@ SNPEModel::SNPEModel(const char *path, float *output, size_t output_size, int ru // create output buffer { + const zdl::DlSystem::TensorShape& bufferShape = snpe->getInputOutputBufferAttributes(output_tensor_name)->getDims(); + if (output_size != 0) { + assert(output_size == bufferShape[1]); + } else { + output_size = bufferShape[1]; + } + std::vector outputStrides = {output_size * sizeof(float), sizeof(float)}; outputBuffer = ubFactory.createUserBuffer(output, output_size * sizeof(float), outputStrides, &userBufferEncodingFloat); outputMap.add(output_tensor_name, outputBuffer.get()); @@ -94,14 +103,18 @@ SNPEModel::SNPEModel(const char *path, float *output, size_t output_size, int ru } void SNPEModel::addRecurrent(float *state, int state_size) { + recurrent = state; + recurrent_size = state_size; recurrentBuffer = this->addExtra(state, state_size, 3); } void SNPEModel::addTrafficConvention(float *state, int state_size) { + trafficConvention = state; trafficConventionBuffer = this->addExtra(state, state_size, 2); } void SNPEModel::addDesire(float *state, int state_size) { + desire = state; desireBuffer = this->addExtra(state, state_size, 1); } @@ -122,9 +135,49 @@ std::unique_ptr SNPEModel::addExtra(float *state, in } void SNPEModel::execute(float *net_input_buf, int buf_size) { - assert(inputBuffer->setBufferAddress(net_input_buf)); - if (!snpe->execute(inputMap, outputMap)) { - PrintErrorStringAndExit(); +#ifdef USE_THNEED + if (Runtime == zdl::DlSystem::Runtime_t::GPU) { + float *inputs[4] = {recurrent, trafficConvention, desire, net_input_buf}; + if (thneed == NULL) { + assert(inputBuffer->setBufferAddress(net_input_buf)); + if (!snpe->execute(inputMap, outputMap)) { + PrintErrorStringAndExit(); + } + memset(recurrent, 0, recurrent_size*sizeof(float)); + thneed = new Thneed(); + if (!snpe->execute(inputMap, outputMap)) { + PrintErrorStringAndExit(); + } + thneed->stop(); + printf("thneed cached\n"); + + // doing self test + float *outputs_golden = (float *)malloc(output_size*sizeof(float)); + memcpy(outputs_golden, output, output_size*sizeof(float)); + memset(output, 0, output_size*sizeof(float)); + memset(recurrent, 0, recurrent_size*sizeof(float)); + thneed->execute(inputs, output); + + if (memcmp(output, outputs_golden, output_size*sizeof(float)) == 0) { + printf("thneed selftest passed\n"); + } else { + for (int i = 0; i < output_size; i++) { + printf("mismatch %3d: %f %f\n", i, output[i], outputs_golden[i]); + } + assert(false); + } + free(outputs_golden); + } else { + thneed->execute(inputs, output); + } + } else { +#endif + assert(inputBuffer->setBufferAddress(net_input_buf)); + if (!snpe->execute(inputMap, outputMap)) { + PrintErrorStringAndExit(); + } +#ifdef USE_THNEED } +#endif } diff --git a/selfdrive/modeld/runners/snpemodel.h b/selfdrive/modeld/runners/snpemodel.h index 9289444b09..90c26664f6 100644 --- a/selfdrive/modeld/runners/snpemodel.h +++ b/selfdrive/modeld/runners/snpemodel.h @@ -17,9 +17,13 @@ #define USE_GPU_RUNTIME 1 #define USE_DSP_RUNTIME 2 +#ifdef USE_THNEED +#include "thneed/thneed.h" +#endif + class SNPEModel : public RunModel { public: - SNPEModel(const char *path, float *output, size_t output_size, int runtime); + SNPEModel(const char *path, float *loutput, size_t loutput_size, int runtime); ~SNPEModel() { if (model_data) free(model_data); } @@ -30,6 +34,14 @@ public: private: uint8_t *model_data = NULL; +#ifdef USE_THNEED + Thneed *thneed = NULL; +#endif + +#if defined(QCOM) || defined(QCOM2) + zdl::DlSystem::Runtime_t Runtime; +#endif + // snpe model stuff std::unique_ptr snpe; @@ -41,11 +53,16 @@ private: zdl::DlSystem::UserBufferMap outputMap; std::unique_ptr outputBuffer; float *output; + size_t output_size; // recurrent and desire std::unique_ptr addExtra(float *state, int state_size, int idx); + float *recurrent; + size_t recurrent_size; std::unique_ptr recurrentBuffer; + float *trafficConvention; std::unique_ptr trafficConventionBuffer; + float *desire; std::unique_ptr desireBuffer; }; diff --git a/selfdrive/modeld/runners/tfmodel.cc b/selfdrive/modeld/runners/tfmodel.cc index c955e54a77..c96fedfbf0 100644 --- a/selfdrive/modeld/runners/tfmodel.cc +++ b/selfdrive/modeld/runners/tfmodel.cc @@ -62,20 +62,20 @@ void TFModel::pwrite(float *buf, int size) { cbuf += err; tw -= err; } - //printf("host write done\n"); + LOGD("host write of size %d done", size); } void TFModel::pread(float *buf, int size) { char *cbuf = (char *)buf; int tr = size*sizeof(float); while (tr > 0) { + LOGD("host read remaining %d/%d", tr, size*sizeof(float)); int err = read(pipeout[0], cbuf, tr); - //printf("host read %d/%d\n", err, tr); assert(err >= 0); cbuf += err; tr -= err; } - //printf("host read done\n"); + LOGD("host read done"); } void TFModel::addRecurrent(float *state, int state_size) { @@ -99,12 +99,12 @@ void TFModel::execute(float *net_input_buf, int buf_size) { if (desire_input_buf != NULL) { pwrite(desire_input_buf, desire_state_size); } - if (rnn_input_buf != NULL) { - pwrite(rnn_input_buf, rnn_state_size); - } if (traffic_convention_input_buf != NULL) { pwrite(traffic_convention_input_buf, traffic_convention_size); } + if (rnn_input_buf != NULL) { + pwrite(rnn_input_buf, rnn_state_size); + } pread(output, output_size); } diff --git a/selfdrive/modeld/test/opencl_hooks/build.sh b/selfdrive/modeld/test/opencl_hooks/build.sh deleted file mode 100755 index 03f8115354..0000000000 --- a/selfdrive/modeld/test/opencl_hooks/build.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -gcc -fPIC -I /data/openpilot/phonelibs/opencl/include -shared hook.c - diff --git a/selfdrive/modeld/test/opencl_hooks/hook.c b/selfdrive/modeld/test/opencl_hooks/hook.c deleted file mode 100644 index f2ee2c0d51..0000000000 --- a/selfdrive/modeld/test/opencl_hooks/hook.c +++ /dev/null @@ -1,155 +0,0 @@ -#include -#include -#include -#include -#include -#include - -static inline uint64_t nanos_since_boot() { - struct timespec t; - clock_gettime(CLOCK_BOOTTIME, &t); - return t.tv_sec * 1000000000ULL + t.tv_nsec; -} - -struct kernel { - cl_kernel k; - const char *name; - cl_program p; -}; - - -int k_index = 0; -struct kernel kk[0x1000] = {0}; - -FILE *f = NULL; - -cl_program clCreateProgramWithSource(cl_context context, - cl_uint count, - const char **strings, - const size_t *lengths, - cl_int *errcode_ret) { - printf("clCreateProgramWithSource: %d\n", count); - - if (f == NULL) { - f = fopen("/tmp/kernels.cl", "w"); - } - - fprintf(f, "/* ************************ PROGRAM BREAK ****************************/\n"); - for (int i = 0; i < count; i++) { - fprintf(f, "%s\n", strings[i]); - if (i != 0) fprintf(f, "/* ************************ SECTION BREAK ****************************/\n"); - } - fflush(f); - - cl_program (*my_clCreateProgramWithSource)(cl_context context, - cl_uint count, - const char **strings, - const size_t *lengths, - cl_int *errcode_ret) = dlsym(RTLD_NEXT, "REAL_clCreateProgramWithSource"); - - return my_clCreateProgramWithSource(context, count, strings, lengths, errcode_ret); -} - -cl_program clCreateProgramWithBinary(cl_context context, - cl_uint num_devices, - const cl_device_id *device_list, - const size_t *lengths, - const unsigned char **binaries, - cl_int *binary_status, - cl_int *errcode_ret) { - printf("clCreateProgramWithBinary\n"); - - cl_program (*my_clCreateProgramWithBinary)(cl_context context, - cl_uint num_devices, - const cl_device_id *device_list, - const size_t *lengths, - const unsigned char **binaries, - cl_int *binary_status, - cl_int *errcode_ret) = dlsym(RTLD_NEXT, "REAL_clCreateProgramWithBinary"); - - return my_clCreateProgramWithBinary(context, num_devices, device_list, lengths, binaries, binary_status, errcode_ret); -} - -cl_kernel clCreateKernel(cl_program program, const char *kernel_name, cl_int *errcode_ret) { - cl_kernel (*my_clCreateKernel)(cl_program program, const char *kernel_name, cl_int *errcode_ret); - my_clCreateKernel = dlsym(RTLD_NEXT, "REAL_clCreateKernel"); - cl_kernel ret = my_clCreateKernel(program, kernel_name, errcode_ret); - //printf("clCreateKernel: %s -> %p\n", kernel_name, ret); - - char *tmp = (char*)malloc(strlen(kernel_name)+1); - strcpy(tmp, kernel_name); - - kk[k_index].k = ret; - kk[k_index].name = tmp; - kk[k_index].p = program; - k_index++; - return ret; -} - - -uint64_t start_time = 0; -int cnt = 0; - -cl_int clEnqueueNDRangeKernel(cl_command_queue command_queue, - cl_kernel kernel, - cl_uint work_dim, - const size_t *global_work_offset, - const size_t *global_work_size, - const size_t *local_work_size, - cl_uint num_events_in_wait_list, - const cl_event *event_wait_list, - cl_event *event) { - - cl_int (*my_clEnqueueNDRangeKernel)(cl_command_queue, cl_kernel, cl_uint, - const size_t *, const size_t *, const size_t *, - cl_uint, const cl_event *, cl_event *) = NULL; - my_clEnqueueNDRangeKernel = dlsym(RTLD_NEXT, "REAL_clEnqueueNDRangeKernel"); - - if (start_time == 0) { - start_time = nanos_since_boot(); - } - - // get kernel name - const char *name = NULL; - cl_program p; - for (int i = 0; i < k_index; i++) { - if (kk[i].k == kernel) { - name = kk[i].name; - p = kk[i].p; - break; - } - } - - uint64_t tb = nanos_since_boot(); - cl_int ret = my_clEnqueueNDRangeKernel(command_queue, kernel, work_dim, - global_work_offset, global_work_size, local_work_size, - num_events_in_wait_list, event_wait_list, event); - uint64_t te = nanos_since_boot(); - - printf("%10lu run%8d in %5ld us command_queue:%p work_dim:%d event:%p ", (tb-start_time)/1000, cnt++, (te-tb)/1000, - command_queue, work_dim, event); - for (int i = 0; i < work_dim; i++) { - printf("%4zu ", global_work_size[i]); - } - printf("%p %s\n", p, name); - return ret; -} - -void *dlsym(void *handle, const char *symbol) { - void *(*my_dlsym)(void *handle, const char *symbol) = (void*)dlopen-0x2d4; - if (memcmp("REAL_", symbol, 5) == 0) { - return my_dlsym(handle, symbol+5); - } else if (strcmp("clEnqueueNDRangeKernel", symbol) == 0) { - return clEnqueueNDRangeKernel; - } else if (strcmp("clCreateKernel", symbol) == 0) { - return clCreateKernel; - } else if (strcmp("clCreateProgramWithSource", symbol) == 0) { - return clCreateProgramWithSource; - } else if (strcmp("clCreateProgramWithBinary", symbol) == 0) { - return clCreateProgramWithBinary; - } else { - printf("dlsym %s\n", symbol); - return my_dlsym(handle, symbol); - } -} - diff --git a/selfdrive/modeld/test/polyfit/test.py b/selfdrive/modeld/test/polyfit/test.py index 0caadf352a..82776e81ef 100644 --- a/selfdrive/modeld/test/polyfit/test.py +++ b/selfdrive/modeld/test/polyfit/test.py @@ -1,3 +1,5 @@ +# flake8: noqa + import numpy as np pts = np.array([3.1261718, 3.1642578, 3.0548828, 3.1125, 3.190625, 3.01875, 2.9816406, 3.1222656, 2.9728515, 2.9826171, 3.034375, 3.0392578, 3.1642578, 3.0792968, 3.0011718, 3.0705078, 2.9904296, 3.0089843, 3.0597656, 3.0978515, 2.9210937, 2.9992187, 2.9474609, 2.9621093, 2.9289062, 2.89375, 2.7975585, 2.9015625, 2.8175781, 2.9132812, 2.8175781, 2.7501953, 2.8332031, 2.8166015, 2.7638671, 2.8878906, 2.7599609, 2.6999023, 2.6720703, 2.6398437, 2.7243164, 2.6120117, 2.6588867, 2.5558593, 2.5978515, 2.5485351, 2.4269531, 2.5001953, 2.4855468, 2.4367187, 2.2973144, 2.2812011, 2.2890136, 2.39375, 2.2836425, 2.3815429, 2.2138183, 2.1964843, 2.1840332, 2.1759765, 2.0421875, 2.1034667, 2.0281494, 2.0880859, 1.9706542, 1.9276855, 1.8522155, 1.8991821, 1.7780273, 1.8180053, 1.8326843, 1.8270385, 1.7182128, 1.6439941, 1.5360839, 1.68385, 1.4584472, 1.5955322, 1.6002929, 1.4157226, 1.4704101, 1.2936523, 1.2990234, 1.4281738, 1.4357421, 1.409375, 1.2511718, 1.2194335, 1.1554687, 1.043164, 1.0954101, 1.0392578, 1.0895507, 1.0880859, 0.897168, 0.83369142, 0.86494142, 0.87763673, 0.85322267, 0.72968751, 0.57832032, 0.73066407, 0.78828126, 0.69160157, 0.64375, 0.5919922, 0.5529297, 0.52070314, 0.60957032, 0.51093751, 0.3576172, 0.49921876, 0.284375, 0.21992187, 0.25214845, 0.30683595, 0.30976564, 0.2716797, 0.22089843, 0.25507814, 0.084179685, 0.071484372, 0.1828125, 0.15644531, 0.13789062, 0.054882813, 0.021679688, -0.091601565, -0.0203125, -0.13359375, -0.037890624, -0.29765624, -0.15605469, -0.30351561, -0.055468749, -0.22148438, -0.246875, -0.31718749, -0.25468749, -0.35234374, -0.16484375, -0.56523436, -0.56523436, -0.39921874, -0.58671874, -0.45585936, -0.50859374, -0.44023436, -0.42656249, -0.56328124, -0.70195311, -0.403125, -0.76445311, -0.98710936, -0.7625, -0.75273436, -0.825, -0.996875, -0.86210936, -0.99492186, -0.85625, -0.88359374, -0.97148436, -1.0320313, -1.1609375, -1.1296875, -1.0203125, -1.0691407, -1.2371094, -1.1277344, -1.2214844, -1.1921875, -1.2996094, -1.2917969, -1.3699219, -1.434375, -1.3699219, -1.3601563, -1.5730469, -1.3152344, -1.4851563, -1.48125, -1.5925782, -1.746875, -1.5847657, -1.6003907, -1.5984375, -1.7703125, -1.8328125, -1.8152344, -1.9714844, -1.9421875]) diff --git a/selfdrive/modeld/test/tf_test/pb_loader.py b/selfdrive/modeld/test/tf_test/pb_loader.py index d4db20eb66..78fd33aef2 100755 --- a/selfdrive/modeld/test/tf_test/pb_loader.py +++ b/selfdrive/modeld/test/tf_test/pb_loader.py @@ -1,9 +1,8 @@ #!/usr/bin/env python3 import sys -import tensorflow as tf +import tensorflow as tf # pylint: disable=import-error with open(sys.argv[1], "rb") as f: graph_def = tf.compat.v1.GraphDef() graph_def.ParseFromString(f.read()) #tf.io.write_graph(graph_def, '', sys.argv[1]+".try") - diff --git a/selfdrive/modeld/thneed/README b/selfdrive/modeld/thneed/README new file mode 100644 index 0000000000..f3bc66d8fc --- /dev/null +++ b/selfdrive/modeld/thneed/README @@ -0,0 +1,8 @@ +thneed is an SNPE accelerator. I know SNPE is already an accelerator, but sometimes things need to go even faster.. + +It runs on the local device, and caches a single model run. Then it replays it, but fast. + +thneed slices through abstraction layers like a fish. + +You need a thneed. + diff --git a/selfdrive/modeld/thneed/debug/.gitignore b/selfdrive/modeld/thneed/debug/.gitignore new file mode 100644 index 0000000000..b7ed9fb0a7 --- /dev/null +++ b/selfdrive/modeld/thneed/debug/.gitignore @@ -0,0 +1 @@ +_thneed diff --git a/selfdrive/modeld/thneed/debug/decompiler/disasm-a3xx.c b/selfdrive/modeld/thneed/debug/decompiler/disasm-a3xx.c new file mode 100644 index 0000000000..1b40fb7fc0 --- /dev/null +++ b/selfdrive/modeld/thneed/debug/decompiler/disasm-a3xx.c @@ -0,0 +1,1426 @@ +/* + * Copyright (c) 2013 Rob Clark + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +//#include + +#include "util/macros.h" +#include "instr-a3xx.h" + +/* bitmask of debug flags */ +enum debug_t { + PRINT_RAW = 0x1, /* dump raw hexdump */ + PRINT_VERBOSE = 0x2, + EXPAND_REPEAT = 0x4, +}; + +static enum debug_t debug = PRINT_RAW | PRINT_VERBOSE | EXPAND_REPEAT; + +static const char *levels[] = { + "", + "\t", + "\t\t", + "\t\t\t", + "\t\t\t\t", + "\t\t\t\t\t", + "\t\t\t\t\t\t", + "\t\t\t\t\t\t\t", + "\t\t\t\t\t\t\t\t", + "\t\t\t\t\t\t\t\t\t", + "x", + "x", + "x", + "x", + "x", + "x", +}; + +static const char *component = "xyzw"; + +static const char *type[] = { + [TYPE_F16] = "f16", + [TYPE_F32] = "f32", + [TYPE_U16] = "u16", + [TYPE_U32] = "u32", + [TYPE_S16] = "s16", + [TYPE_S32] = "s32", + [TYPE_U8] = "u8", + [TYPE_S8] = "s8", +}; + +struct disasm_ctx { + FILE *out; + int level; + unsigned gpu_id; + + /* current instruction repeat flag: */ + unsigned repeat; + /* current instruction repeat indx/offset (for --expand): */ + unsigned repeatidx; + + unsigned instructions; +}; + +static const char *float_imms[] = { + "0.0", + "0.5", + "1.0", + "2.0", + "e", + "pi", + "1/pi", + "1/log2(e)", + "log2(e)", + "1/log2(10)", + "log2(10)", + "4.0", +}; + +static void print_reg(struct disasm_ctx *ctx, reg_t reg, bool full, + bool is_float, bool r, + bool c, bool im, bool neg, bool abs, bool addr_rel) +{ + const char type = c ? 'c' : 'r'; + + // XXX I prefer - and || for neg/abs, but preserving format used + // by libllvm-a3xx for easy diffing.. + + if (abs && neg) + fprintf(ctx->out, "(absneg)"); + else if (neg) + fprintf(ctx->out, "(neg)"); + else if (abs) + fprintf(ctx->out, "(abs)"); + + if (r) + fprintf(ctx->out, "(r)"); + + if (im) { + if (is_float && full && reg.iim_val < ARRAY_SIZE(float_imms)) { + fprintf(ctx->out, "(%s)", float_imms[reg.iim_val]); + } else { + fprintf(ctx->out, "%d", reg.iim_val); + } + } else if (addr_rel) { + /* I would just use %+d but trying to make it diff'able with + * libllvm-a3xx... + */ + if (reg.iim_val < 0) + fprintf(ctx->out, "%s%c", full ? "" : "h", type, -reg.iim_val); + else if (reg.iim_val > 0) + fprintf(ctx->out, "%s%c", full ? "" : "h", type, reg.iim_val); + else + fprintf(ctx->out, "%s%c", full ? "" : "h", type); + } else if ((reg.num == REG_A0) && !c) { + /* This matches libllvm output, the second (scalar) address register + * seems to be called a1.x instead of a0.y. + */ + fprintf(ctx->out, "a%d.x", reg.comp); + } else if ((reg.num == REG_P0) && !c) { + fprintf(ctx->out, "p0.%c", component[reg.comp]); + } else { + fprintf(ctx->out, "%s%c%d.%c", full ? "" : "h", type, reg.num, component[reg.comp]); + } +} + +static unsigned regidx(reg_t reg) +{ + return (4 * reg.num) + reg.comp; +} + +static reg_t idxreg(unsigned idx) +{ + return (reg_t){ + .comp = idx & 0x3, + .num = idx >> 2, + }; +} + +static void print_reg_dst(struct disasm_ctx *ctx, reg_t reg, bool full, bool addr_rel) +{ + reg = idxreg(regidx(reg) + ctx->repeatidx); + print_reg(ctx, reg, full, false, false, false, false, false, false, addr_rel); +} + +/* TODO switch to using reginfo struct everywhere, since more readable + * than passing a bunch of bools to print_reg_src + */ + +struct reginfo { + reg_t reg; + bool full; + bool r; + bool c; + bool f; /* src reg is interpreted as float, used for printing immediates */ + bool im; + bool neg; + bool abs; + bool addr_rel; +}; + +static void print_src(struct disasm_ctx *ctx, struct reginfo *info) +{ + reg_t reg = info->reg; + + if (info->r) + reg = idxreg(regidx(info->reg) + ctx->repeatidx); + + print_reg(ctx, reg, info->full, info->f, info->r, info->c, info->im, + info->neg, info->abs, info->addr_rel); +} + +//static void print_dst(struct disasm_ctx *ctx, struct reginfo *info) +//{ +// print_reg_dst(ctx, info->reg, info->full, info->addr_rel); +//} + +static void print_instr_cat0(struct disasm_ctx *ctx, instr_t *instr) +{ + static const struct { + const char *suffix; + int nsrc; + bool idx; + } brinfo[7] = { + [BRANCH_PLAIN] = { "r", 1, false }, + [BRANCH_OR] = { "rao", 2, false }, + [BRANCH_AND] = { "raa", 2, false }, + [BRANCH_CONST] = { "rac", 0, true }, + [BRANCH_ANY] = { "any", 1, false }, + [BRANCH_ALL] = { "all", 1, false }, + [BRANCH_X] = { "rax", 0, false }, + }; + instr_cat0_t *cat0 = &instr->cat0; + + switch (instr_opc(instr, ctx->gpu_id)) { + case OPC_KILL: + case OPC_PREDT: + case OPC_PREDF: + fprintf(ctx->out, " %sp0.%c", cat0->inv0 ? "!" : "", + component[cat0->comp0]); + break; + case OPC_B: + fprintf(ctx->out, "%s", brinfo[cat0->brtype].suffix); + if (brinfo[cat0->brtype].idx) { + fprintf(ctx->out, ".%u", cat0->idx); + } + if (brinfo[cat0->brtype].nsrc >= 1) { + fprintf(ctx->out, " %sp0.%c,", cat0->inv0 ? "!" : "", + component[cat0->comp0]); + } + if (brinfo[cat0->brtype].nsrc >= 2) { + fprintf(ctx->out, " %sp0.%c,", cat0->inv1 ? "!" : "", + component[cat0->comp1]); + } + fprintf(ctx->out, " #%d", cat0->a3xx.immed); + break; + case OPC_JUMP: + case OPC_CALL: + case OPC_BKT: + case OPC_GETONE: + case OPC_SHPS: + fprintf(ctx->out, " #%d", cat0->a3xx.immed); + break; + } + + if ((debug & PRINT_VERBOSE) && (cat0->dummy3|cat0->dummy4)) + fprintf(ctx->out, "\t{0: %x,%x}", cat0->dummy3, cat0->dummy4); +} + +static void print_instr_cat1(struct disasm_ctx *ctx, instr_t *instr) +{ + instr_cat1_t *cat1 = &instr->cat1; + + if (cat1->ul) + fprintf(ctx->out, "(ul)"); + + if (cat1->src_type == cat1->dst_type) { + if ((cat1->src_type == TYPE_S16) && (((reg_t)cat1->dst).num == REG_A0)) { + /* special case (nmemonic?): */ + fprintf(ctx->out, "mova"); + } else { + fprintf(ctx->out, "mov.%s%s", type[cat1->src_type], type[cat1->dst_type]); + } + } else { + fprintf(ctx->out, "cov.%s%s", type[cat1->src_type], type[cat1->dst_type]); + } + + fprintf(ctx->out, " "); + + if (cat1->even) + fprintf(ctx->out, "(even)"); + + if (cat1->pos_inf) + fprintf(ctx->out, "(pos_infinity)"); + + print_reg_dst(ctx, (reg_t)(cat1->dst), type_size(cat1->dst_type) == 32, + cat1->dst_rel); + + fprintf(ctx->out, ", "); + + /* ugg, have to special case this.. vs print_reg().. */ + if (cat1->src_im) { + if (type_float(cat1->src_type)) + fprintf(ctx->out, "(%f)", cat1->fim_val); + else if (type_uint(cat1->src_type)) + fprintf(ctx->out, "0x%08x", cat1->uim_val); + else + fprintf(ctx->out, "%d", cat1->iim_val); + } else if (cat1->src_rel && !cat1->src_c) { + /* I would just use %+d but trying to make it diff'able with + * libllvm-a3xx... + */ + char type = cat1->src_rel_c ? 'c' : 'r'; + const char *full = (type_size(cat1->src_type) == 32) ? "" : "h"; + if (cat1->off < 0) + fprintf(ctx->out, "%s%c", full, type, -cat1->off); + else if (cat1->off > 0) + fprintf(ctx->out, "%s%c", full, type, cat1->off); + else + fprintf(ctx->out, "%s%c", full, type); + } else { + struct reginfo src = { + .reg = (reg_t)cat1->src, + .full = type_size(cat1->src_type) == 32, + .r = cat1->src_r, + .c = cat1->src_c, + .im = cat1->src_im, + }; + print_src(ctx, &src); + } + + if ((debug & PRINT_VERBOSE) && (cat1->must_be_0)) + fprintf(ctx->out, "\t{1: %x}", cat1->must_be_0); +} + +static void print_instr_cat2(struct disasm_ctx *ctx, instr_t *instr) +{ + instr_cat2_t *cat2 = &instr->cat2; + int opc = _OPC(2, cat2->opc); + static const char *cond[] = { + "lt", + "le", + "gt", + "ge", + "eq", + "ne", + "?6?", + }; + + switch (opc) { + case OPC_CMPS_F: + case OPC_CMPS_U: + case OPC_CMPS_S: + case OPC_CMPV_F: + case OPC_CMPV_U: + case OPC_CMPV_S: + fprintf(ctx->out, ".%s", cond[cat2->cond]); + break; + } + + fprintf(ctx->out, " "); + if (cat2->ei) + fprintf(ctx->out, "(ei)"); + print_reg_dst(ctx, (reg_t)(cat2->dst), cat2->full ^ cat2->dst_half, false); + fprintf(ctx->out, ", "); + + struct reginfo src1 = { + .full = cat2->full, + .r = cat2->repeat ? cat2->src1_r : 0, + .f = is_cat2_float(opc), + .im = cat2->src1_im, + .abs = cat2->src1_abs, + .neg = cat2->src1_neg, + }; + + if (cat2->c1.src1_c) { + src1.reg = (reg_t)(cat2->c1.src1); + src1.c = true; + } else if (cat2->rel1.src1_rel) { + src1.reg = (reg_t)(cat2->rel1.src1); + src1.c = cat2->rel1.src1_c; + src1.addr_rel = true; + } else { + src1.reg = (reg_t)(cat2->src1); + } + print_src(ctx, &src1); + + struct reginfo src2 = { + .r = cat2->repeat ? cat2->src2_r : 0, + .full = cat2->full, + .f = is_cat2_float(opc), + .abs = cat2->src2_abs, + .neg = cat2->src2_neg, + .im = cat2->src2_im, + }; + switch (opc) { + case OPC_ABSNEG_F: + case OPC_ABSNEG_S: + case OPC_CLZ_B: + case OPC_CLZ_S: + case OPC_SIGN_F: + case OPC_FLOOR_F: + case OPC_CEIL_F: + case OPC_RNDNE_F: + case OPC_RNDAZ_F: + case OPC_TRUNC_F: + case OPC_NOT_B: + case OPC_BFREV_B: + case OPC_SETRM: + case OPC_CBITS_B: + /* these only have one src reg */ + break; + default: + fprintf(ctx->out, ", "); + if (cat2->c2.src2_c) { + src2.reg = (reg_t)(cat2->c2.src2); + src2.c = true; + } else if (cat2->rel2.src2_rel) { + src2.reg = (reg_t)(cat2->rel2.src2); + src2.c = cat2->rel2.src2_c; + src2.addr_rel = true; + } else { + src2.reg = (reg_t)(cat2->src2); + } + print_src(ctx, &src2); + break; + } +} + +static void print_instr_cat3(struct disasm_ctx *ctx, instr_t *instr) +{ + instr_cat3_t *cat3 = &instr->cat3; + bool full = instr_cat3_full(cat3); + + fprintf(ctx->out, " "); + print_reg_dst(ctx, (reg_t)(cat3->dst), full ^ cat3->dst_half, false); + fprintf(ctx->out, ", "); + + struct reginfo src1 = { + .r = cat3->repeat ? cat3->src1_r : 0, + .full = full, + .neg = cat3->src1_neg, + }; + if (cat3->c1.src1_c) { + src1.reg = (reg_t)(cat3->c1.src1); + src1.c = true; + } else if (cat3->rel1.src1_rel) { + src1.reg = (reg_t)(cat3->rel1.src1); + src1.c = cat3->rel1.src1_c; + src1.addr_rel = true; + } else { + src1.reg = (reg_t)(cat3->src1); + } + print_src(ctx, &src1); + + fprintf(ctx->out, ", "); + struct reginfo src2 = { + .reg = (reg_t)cat3->src2, + .full = full, + .r = cat3->repeat ? cat3->src2_r : 0, + .c = cat3->src2_c, + .neg = cat3->src2_neg, + }; + print_src(ctx, &src2); + + fprintf(ctx->out, ", "); + struct reginfo src3 = { + .r = cat3->src3_r, + .full = full, + .neg = cat3->src3_neg, + }; + if (cat3->c2.src3_c) { + src3.reg = (reg_t)(cat3->c2.src3); + src3.c = true; + } else if (cat3->rel2.src3_rel) { + src3.reg = (reg_t)(cat3->rel2.src3); + src3.c = cat3->rel2.src3_c; + src3.addr_rel = true; + } else { + src3.reg = (reg_t)(cat3->src3); + } + print_src(ctx, &src3); +} + +static void print_instr_cat4(struct disasm_ctx *ctx, instr_t *instr) +{ + instr_cat4_t *cat4 = &instr->cat4; + + fprintf(ctx->out, " "); + print_reg_dst(ctx, (reg_t)(cat4->dst), cat4->full ^ cat4->dst_half, false); + fprintf(ctx->out, ", "); + + struct reginfo src = { + .r = cat4->src_r, + .im = cat4->src_im, + .full = cat4->full, + .neg = cat4->src_neg, + .abs = cat4->src_abs, + }; + if (cat4->c.src_c) { + src.reg = (reg_t)(cat4->c.src); + src.c = true; + } else if (cat4->rel.src_rel) { + src.reg = (reg_t)(cat4->rel.src); + src.c = cat4->rel.src_c; + src.addr_rel = true; + } else { + src.reg = (reg_t)(cat4->src); + } + print_src(ctx, &src); + + if ((debug & PRINT_VERBOSE) && (cat4->dummy1|cat4->dummy2)) + fprintf(ctx->out, "\t{4: %x,%x}", cat4->dummy1, cat4->dummy2); +} + +static void print_instr_cat5(struct disasm_ctx *ctx, instr_t *instr) +{ + static const struct { + bool src1, src2, samp, tex; + } info[0x1f] = { + [opc_op(OPC_ISAM)] = { true, false, true, true, }, + [opc_op(OPC_ISAML)] = { true, true, true, true, }, + [opc_op(OPC_ISAMM)] = { true, false, true, true, }, + [opc_op(OPC_SAM)] = { true, false, true, true, }, + [opc_op(OPC_SAMB)] = { true, true, true, true, }, + [opc_op(OPC_SAML)] = { true, true, true, true, }, + [opc_op(OPC_SAMGQ)] = { true, false, true, true, }, + [opc_op(OPC_GETLOD)] = { true, false, true, true, }, + [opc_op(OPC_CONV)] = { true, true, true, true, }, + [opc_op(OPC_CONVM)] = { true, true, true, true, }, + [opc_op(OPC_GETSIZE)] = { true, false, false, true, }, + [opc_op(OPC_GETBUF)] = { false, false, false, true, }, + [opc_op(OPC_GETPOS)] = { true, false, false, true, }, + [opc_op(OPC_GETINFO)] = { false, false, false, true, }, + [opc_op(OPC_DSX)] = { true, false, false, false, }, + [opc_op(OPC_DSY)] = { true, false, false, false, }, + [opc_op(OPC_GATHER4R)] = { true, false, true, true, }, + [opc_op(OPC_GATHER4G)] = { true, false, true, true, }, + [opc_op(OPC_GATHER4B)] = { true, false, true, true, }, + [opc_op(OPC_GATHER4A)] = { true, false, true, true, }, + [opc_op(OPC_SAMGP0)] = { true, false, true, true, }, + [opc_op(OPC_SAMGP1)] = { true, false, true, true, }, + [opc_op(OPC_SAMGP2)] = { true, false, true, true, }, + [opc_op(OPC_SAMGP3)] = { true, false, true, true, }, + [opc_op(OPC_DSXPP_1)] = { true, false, false, false, }, + [opc_op(OPC_DSYPP_1)] = { true, false, false, false, }, + [opc_op(OPC_RGETPOS)] = { true, false, false, false, }, + [opc_op(OPC_RGETINFO)] = { false, false, false, false, }, + }; + + static const struct { + bool indirect; + bool bindless; + bool use_a1; + bool uniform; + } desc_features[8] = { + [CAT5_NONUNIFORM] = { .indirect = true, }, + [CAT5_UNIFORM] = { .indirect = true, .uniform = true, }, + [CAT5_BINDLESS_IMM] = { .bindless = true, }, + [CAT5_BINDLESS_UNIFORM] = { + .bindless = true, + .indirect = true, + .uniform = true, + }, + [CAT5_BINDLESS_NONUNIFORM] = { + .bindless = true, + .indirect = true, + }, + [CAT5_BINDLESS_A1_IMM] = { + .bindless = true, + .use_a1 = true, + }, + [CAT5_BINDLESS_A1_UNIFORM] = { + .bindless = true, + .indirect = true, + .uniform = true, + .use_a1 = true, + }, + [CAT5_BINDLESS_A1_NONUNIFORM] = { + .bindless = true, + .indirect = true, + .use_a1 = true, + }, + }; + + instr_cat5_t *cat5 = &instr->cat5; + int i; + + bool desc_indirect = + cat5->is_s2en_bindless && + desc_features[cat5->s2en_bindless.desc_mode].indirect; + bool bindless = + cat5->is_s2en_bindless && + desc_features[cat5->s2en_bindless.desc_mode].bindless; + bool use_a1 = + cat5->is_s2en_bindless && + desc_features[cat5->s2en_bindless.desc_mode].use_a1; + bool uniform = + cat5->is_s2en_bindless && + desc_features[cat5->s2en_bindless.desc_mode].uniform; + + if (cat5->is_3d) fprintf(ctx->out, ".3d"); + if (cat5->is_a) fprintf(ctx->out, ".a"); + if (cat5->is_o) fprintf(ctx->out, ".o"); + if (cat5->is_p) fprintf(ctx->out, ".p"); + if (cat5->is_s) fprintf(ctx->out, ".s"); + if (desc_indirect) fprintf(ctx->out, ".s2en"); + if (uniform) fprintf(ctx->out, ".uniform"); + + if (bindless) { + unsigned base = (cat5->s2en_bindless.base_hi << 1) | cat5->base_lo; + fprintf(ctx->out, ".base%d", base); + } + + fprintf(ctx->out, " "); + + switch (_OPC(5, cat5->opc)) { + case OPC_DSXPP_1: + case OPC_DSYPP_1: + break; + default: + fprintf(ctx->out, "(%s)", type[cat5->type]); + break; + } + + fprintf(ctx->out, "("); + for (i = 0; i < 4; i++) + if (cat5->wrmask & (1 << i)) + fprintf(ctx->out, "%c", "xyzw"[i]); + fprintf(ctx->out, ")"); + + print_reg_dst(ctx, (reg_t)(cat5->dst), type_size(cat5->type) == 32, false); + + if (info[cat5->opc].src1) { + fprintf(ctx->out, ", "); + struct reginfo src = { .reg = (reg_t)(cat5->src1), .full = cat5->full }; + print_src(ctx, &src); + } + + if (cat5->is_o || info[cat5->opc].src2) { + fprintf(ctx->out, ", "); + struct reginfo src = { .reg = (reg_t)(cat5->src2), .full = cat5->full }; + print_src(ctx, &src); + } + if (cat5->is_s2en_bindless) { + if (!desc_indirect) { + if (info[cat5->opc].samp) { + if (use_a1) + fprintf(ctx->out, ", s#%d", cat5->s2en_bindless.src3); + else + fprintf(ctx->out, ", s#%d", cat5->s2en_bindless.src3 & 0xf); + } + + if (info[cat5->opc].tex && !use_a1) { + fprintf(ctx->out, ", t#%d", cat5->s2en_bindless.src3 >> 4); + } + } + } else { + if (info[cat5->opc].samp) + fprintf(ctx->out, ", s#%d", cat5->norm.samp); + if (info[cat5->opc].tex) + fprintf(ctx->out, ", t#%d", cat5->norm.tex); + } + + if (desc_indirect) { + fprintf(ctx->out, ", "); + struct reginfo src = { .reg = (reg_t)(cat5->s2en_bindless.src3), .full = bindless }; + print_src(ctx, &src); + } + + if (use_a1) + fprintf(ctx->out, ", a1.x"); + + if (debug & PRINT_VERBOSE) { + if (cat5->is_s2en_bindless) { + if ((debug & PRINT_VERBOSE) && cat5->s2en_bindless.dummy1) + fprintf(ctx->out, "\t{5: %x}", cat5->s2en_bindless.dummy1); + } else { + if ((debug & PRINT_VERBOSE) && cat5->norm.dummy1) + fprintf(ctx->out, "\t{5: %x}", cat5->norm.dummy1); + } + } +} + +static void print_instr_cat6_a3xx(struct disasm_ctx *ctx, instr_t *instr) +{ + instr_cat6_t *cat6 = &instr->cat6; + char sd = 0, ss = 0; /* dst/src address space */ + bool nodst = false; + struct reginfo dst, src1, src2; + int src1off = 0, dstoff = 0; + + memset(&dst, 0, sizeof(dst)); + memset(&src1, 0, sizeof(src1)); + memset(&src2, 0, sizeof(src2)); + + switch (_OPC(6, cat6->opc)) { + case OPC_RESINFO: + case OPC_RESFMT: + dst.full = type_size(cat6->type) == 32; + src1.full = type_size(cat6->type) == 32; + src2.full = type_size(cat6->type) == 32; + break; + case OPC_L2G: + case OPC_G2L: + dst.full = true; + src1.full = true; + src2.full = true; + break; + case OPC_STG: + case OPC_STL: + case OPC_STP: + case OPC_STLW: + case OPC_STIB: + dst.full = type_size(cat6->type) == 32; + src1.full = type_size(cat6->type) == 32; + src2.full = type_size(cat6->type) == 32; + break; + default: + dst.full = type_size(cat6->type) == 32; + src1.full = true; + src2.full = true; + break; + } + + switch (_OPC(6, cat6->opc)) { + case OPC_PREFETCH: + break; + case OPC_RESINFO: + fprintf(ctx->out, ".%dd", cat6->ldgb.d + 1); + break; + case OPC_LDGB: + fprintf(ctx->out, ".%s", cat6->ldgb.typed ? "typed" : "untyped"); + fprintf(ctx->out, ".%dd", cat6->ldgb.d + 1); + fprintf(ctx->out, ".%s", type[cat6->type]); + fprintf(ctx->out, ".%d", cat6->ldgb.type_size + 1); + break; + case OPC_STGB: + case OPC_STIB: + fprintf(ctx->out, ".%s", cat6->stgb.typed ? "typed" : "untyped"); + fprintf(ctx->out, ".%dd", cat6->stgb.d + 1); + fprintf(ctx->out, ".%s", type[cat6->type]); + fprintf(ctx->out, ".%d", cat6->stgb.type_size + 1); + break; + case OPC_ATOMIC_ADD: + case OPC_ATOMIC_SUB: + case OPC_ATOMIC_XCHG: + case OPC_ATOMIC_INC: + case OPC_ATOMIC_DEC: + case OPC_ATOMIC_CMPXCHG: + case OPC_ATOMIC_MIN: + case OPC_ATOMIC_MAX: + case OPC_ATOMIC_AND: + case OPC_ATOMIC_OR: + case OPC_ATOMIC_XOR: + ss = cat6->g ? 'g' : 'l'; + fprintf(ctx->out, ".%s", cat6->ldgb.typed ? "typed" : "untyped"); + fprintf(ctx->out, ".%dd", cat6->ldgb.d + 1); + fprintf(ctx->out, ".%s", type[cat6->type]); + fprintf(ctx->out, ".%d", cat6->ldgb.type_size + 1); + fprintf(ctx->out, ".%c", ss); + break; + default: + dst.im = cat6->g && !cat6->dst_off; + fprintf(ctx->out, ".%s", type[cat6->type]); + break; + } + fprintf(ctx->out, " "); + + switch (_OPC(6, cat6->opc)) { + case OPC_STG: + sd = 'g'; + break; + case OPC_STP: + sd = 'p'; + break; + case OPC_STL: + case OPC_STLW: + sd = 'l'; + break; + + case OPC_LDG: + case OPC_LDC: + ss = 'g'; + break; + case OPC_LDP: + ss = 'p'; + break; + case OPC_LDL: + case OPC_LDLW: + case OPC_LDLV: + ss = 'l'; + break; + + case OPC_L2G: + ss = 'l'; + sd = 'g'; + break; + + case OPC_G2L: + ss = 'g'; + sd = 'l'; + break; + + case OPC_PREFETCH: + ss = 'g'; + nodst = true; + break; + } + + if ((_OPC(6, cat6->opc) == OPC_STGB) || (_OPC(6, cat6->opc) == OPC_STIB)) { + struct reginfo src3; + + memset(&src3, 0, sizeof(src3)); + + src1.reg = (reg_t)(cat6->stgb.src1); + src2.reg = (reg_t)(cat6->stgb.src2); + src2.im = cat6->stgb.src2_im; + src3.reg = (reg_t)(cat6->stgb.src3); + src3.im = cat6->stgb.src3_im; + src3.full = true; + + fprintf(ctx->out, "g[%u], ", cat6->stgb.dst_ssbo); + print_src(ctx, &src1); + fprintf(ctx->out, ", "); + print_src(ctx, &src2); + fprintf(ctx->out, ", "); + print_src(ctx, &src3); + + if (debug & PRINT_VERBOSE) + fprintf(ctx->out, " (pad0=%x, pad3=%x)", cat6->stgb.pad0, cat6->stgb.pad3); + + return; + } + + if (is_atomic(_OPC(6, cat6->opc))) { + + src1.reg = (reg_t)(cat6->ldgb.src1); + src1.im = cat6->ldgb.src1_im; + src2.reg = (reg_t)(cat6->ldgb.src2); + src2.im = cat6->ldgb.src2_im; + dst.reg = (reg_t)(cat6->ldgb.dst); + + print_src(ctx, &dst); + fprintf(ctx->out, ", "); + if (ss == 'g') { + struct reginfo src3; + memset(&src3, 0, sizeof(src3)); + + src3.reg = (reg_t)(cat6->ldgb.src3); + src3.full = true; + + /* For images, the ".typed" variant is used and src2 is + * the ivecN coordinates, ie ivec2 for 2d. + * + * For SSBOs, the ".untyped" variant is used and src2 is + * a simple dword offset.. src3 appears to be + * uvec2(offset * 4, 0). Not sure the point of that. + */ + + fprintf(ctx->out, "g[%u], ", cat6->ldgb.src_ssbo); + print_src(ctx, &src1); /* value */ + fprintf(ctx->out, ", "); + print_src(ctx, &src2); /* offset/coords */ + fprintf(ctx->out, ", "); + print_src(ctx, &src3); /* 64b byte offset.. */ + + if (debug & PRINT_VERBOSE) { + fprintf(ctx->out, " (pad0=%x, pad3=%x, mustbe0=%x)", cat6->ldgb.pad0, + cat6->ldgb.pad3, cat6->ldgb.mustbe0); + } + } else { /* ss == 'l' */ + fprintf(ctx->out, "l["); + print_src(ctx, &src1); /* simple byte offset */ + fprintf(ctx->out, "], "); + print_src(ctx, &src2); /* value */ + + if (debug & PRINT_VERBOSE) { + fprintf(ctx->out, " (src3=%x, pad0=%x, pad3=%x, mustbe0=%x)", + cat6->ldgb.src3, cat6->ldgb.pad0, + cat6->ldgb.pad3, cat6->ldgb.mustbe0); + } + } + + return; + } else if (_OPC(6, cat6->opc) == OPC_RESINFO) { + dst.reg = (reg_t)(cat6->ldgb.dst); + + print_src(ctx, &dst); + fprintf(ctx->out, ", "); + fprintf(ctx->out, "g[%u]", cat6->ldgb.src_ssbo); + + return; + } else if (_OPC(6, cat6->opc) == OPC_LDGB) { + + src1.reg = (reg_t)(cat6->ldgb.src1); + src1.im = cat6->ldgb.src1_im; + src2.reg = (reg_t)(cat6->ldgb.src2); + src2.im = cat6->ldgb.src2_im; + dst.reg = (reg_t)(cat6->ldgb.dst); + + print_src(ctx, &dst); + fprintf(ctx->out, ", "); + fprintf(ctx->out, "g[%u], ", cat6->ldgb.src_ssbo); + print_src(ctx, &src1); + fprintf(ctx->out, ", "); + print_src(ctx, &src2); + + if (debug & PRINT_VERBOSE) + fprintf(ctx->out, " (pad0=%x, pad3=%x, mustbe0=%x)", cat6->ldgb.pad0, cat6->ldgb.pad3, cat6->ldgb.mustbe0); + + return; + } else if (_OPC(6, cat6->opc) == OPC_LDG && cat6->a.src1_im && cat6->a.src2_im) { + struct reginfo src3; + + memset(&src3, 0, sizeof(src3)); + src1.reg = (reg_t)(cat6->a.src1); + src2.reg = (reg_t)(cat6->a.src2); + src2.im = cat6->a.src2_im; + src3.reg = (reg_t)(cat6->a.off); + src3.full = true; + dst.reg = (reg_t)(cat6->d.dst); + + print_src(ctx, &dst); + fprintf(ctx->out, ", g["); + print_src(ctx, &src1); + fprintf(ctx->out, "+"); + print_src(ctx, &src3); + fprintf(ctx->out, "], "); + print_src(ctx, &src2); + + return; + } + if (cat6->dst_off) { + dst.reg = (reg_t)(cat6->c.dst); + dstoff = cat6->c.off; + } else { + dst.reg = (reg_t)(cat6->d.dst); + } + + if (cat6->src_off) { + src1.reg = (reg_t)(cat6->a.src1); + src1.im = cat6->a.src1_im; + src2.reg = (reg_t)(cat6->a.src2); + src2.im = cat6->a.src2_im; + src1off = cat6->a.off; + } else { + src1.reg = (reg_t)(cat6->b.src1); + src1.im = cat6->b.src1_im; + src2.reg = (reg_t)(cat6->b.src2); + src2.im = cat6->b.src2_im; + } + + if (!nodst) { + if (sd) + fprintf(ctx->out, "%c[", sd); + /* note: dst might actually be a src (ie. address to store to) */ + print_src(ctx, &dst); + if (cat6->dst_off && cat6->g) { + struct reginfo dstoff_reg = {0}; + dstoff_reg.reg = (reg_t) cat6->c.off; + dstoff_reg.full = true; + fprintf(ctx->out, "+"); + print_src(ctx, &dstoff_reg); + } else if (dstoff) + fprintf(ctx->out, "%+d", dstoff); + if (sd) + fprintf(ctx->out, "]"); + fprintf(ctx->out, ", "); + } + + if (ss) + fprintf(ctx->out, "%c[", ss); + + /* can have a larger than normal immed, so hack: */ + if (src1.im) { + fprintf(ctx->out, "%u", src1.reg.dummy13); + } else { + print_src(ctx, &src1); + } + + if (cat6->src_off && cat6->g) + print_src(ctx, &src2); + else if (src1off) + fprintf(ctx->out, "%+d", src1off); + if (ss) + fprintf(ctx->out, "]"); + + switch (_OPC(6, cat6->opc)) { + case OPC_RESINFO: + case OPC_RESFMT: + break; + default: + fprintf(ctx->out, ", "); + print_src(ctx, &src2); + break; + } +} + +static void print_instr_cat6_a6xx(struct disasm_ctx *ctx, instr_t *instr) +{ + instr_cat6_a6xx_t *cat6 = &instr->cat6_a6xx; + struct reginfo src1, src2, ssbo; + bool uses_type = _OPC(6, cat6->opc) != OPC_LDC; + + static const struct { + bool indirect; + bool bindless; + const char *name; + } desc_features[8] = { + [CAT6_IMM] = { + .name = "imm" + }, + [CAT6_UNIFORM] = { + .indirect = true, + .name = "uniform" + }, + [CAT6_NONUNIFORM] = { + .indirect = true, + .name = "nonuniform" + }, + [CAT6_BINDLESS_IMM] = { + .bindless = true, + .name = "imm" + }, + [CAT6_BINDLESS_UNIFORM] = { + .bindless = true, + .indirect = true, + .name = "uniform" + }, + [CAT6_BINDLESS_NONUNIFORM] = { + .bindless = true, + .indirect = true, + .name = "nonuniform" + }, + }; + + bool indirect_ssbo = desc_features[cat6->desc_mode].indirect; + bool bindless = desc_features[cat6->desc_mode].bindless; + bool type_full = cat6->type != TYPE_U16; + + + memset(&src1, 0, sizeof(src1)); + memset(&src2, 0, sizeof(src2)); + memset(&ssbo, 0, sizeof(ssbo)); + + if (uses_type) { + fprintf(ctx->out, ".%s", cat6->typed ? "typed" : "untyped"); + fprintf(ctx->out, ".%dd", cat6->d + 1); + fprintf(ctx->out, ".%s", type[cat6->type]); + } else { + fprintf(ctx->out, ".offset%d", cat6->d); + } + fprintf(ctx->out, ".%u", cat6->type_size + 1); + + fprintf(ctx->out, ".%s", desc_features[cat6->desc_mode].name); + if (bindless) + fprintf(ctx->out, ".base%d", cat6->base); + fprintf(ctx->out, " "); + + src2.reg = (reg_t)(cat6->src2); + src2.full = type_full; + print_src(ctx, &src2); + fprintf(ctx->out, ", "); + + src1.reg = (reg_t)(cat6->src1); + src1.full = true; // XXX + print_src(ctx, &src1); + fprintf(ctx->out, ", "); + ssbo.reg = (reg_t)(cat6->ssbo); + ssbo.im = !indirect_ssbo; + ssbo.full = true; + print_src(ctx, &ssbo); + + if (debug & PRINT_VERBOSE) { + fprintf(ctx->out, " (pad1=%x, pad2=%x, pad3=%x, pad4=%x, pad5=%x)", + cat6->pad1, cat6->pad2, cat6->pad3, cat6->pad4, cat6->pad5); + } +} + +static void print_instr_cat6(struct disasm_ctx *ctx, instr_t *instr) +{ + if (!is_cat6_legacy(instr, ctx->gpu_id)) { + print_instr_cat6_a6xx(ctx, instr); + if (debug & PRINT_VERBOSE) + fprintf(ctx->out, " NEW"); + } else { + print_instr_cat6_a3xx(ctx, instr); + if (debug & PRINT_VERBOSE) + fprintf(ctx->out, " LEGACY"); + } +} +static void print_instr_cat7(struct disasm_ctx *ctx, instr_t *instr) +{ + instr_cat7_t *cat7 = &instr->cat7; + + if (cat7->g) + fprintf(ctx->out, ".g"); + if (cat7->l) + fprintf(ctx->out, ".l"); + + if (_OPC(7, cat7->opc) == OPC_FENCE) { + if (cat7->r) + fprintf(ctx->out, ".r"); + if (cat7->w) + fprintf(ctx->out, ".w"); + } +} + +/* size of largest OPC field of all the instruction categories: */ +#define NOPC_BITS 6 + +static const struct opc_info { + uint16_t cat; + uint16_t opc; + const char *name; + void (*print)(struct disasm_ctx *ctx, instr_t *instr); +} opcs[1 << (3+NOPC_BITS)] = { +#define OPC(cat, opc, name) [(opc)] = { (cat), (opc), #name, print_instr_cat##cat } + /* category 0: */ + OPC(0, OPC_NOP, nop), + OPC(0, OPC_B, b), + OPC(0, OPC_JUMP, jump), + OPC(0, OPC_CALL, call), + OPC(0, OPC_RET, ret), + OPC(0, OPC_KILL, kill), + OPC(0, OPC_END, end), + OPC(0, OPC_EMIT, emit), + OPC(0, OPC_CUT, cut), + OPC(0, OPC_CHMASK, chmask), + OPC(0, OPC_CHSH, chsh), + OPC(0, OPC_FLOW_REV, flow_rev), + OPC(0, OPC_PREDT, predt), + OPC(0, OPC_PREDF, predf), + OPC(0, OPC_PREDE, prede), + OPC(0, OPC_BKT, bkt), + OPC(0, OPC_STKS, stks), + OPC(0, OPC_STKR, stkr), + OPC(0, OPC_XSET, xset), + OPC(0, OPC_XCLR, xclr), + OPC(0, OPC_GETONE, getone), + OPC(0, OPC_DBG, dbg), + OPC(0, OPC_SHPS, shps), + OPC(0, OPC_SHPE, shpe), + + /* category 1: */ + OPC(1, OPC_MOV, ), + + /* category 2: */ + OPC(2, OPC_ADD_F, add.f), + OPC(2, OPC_MIN_F, min.f), + OPC(2, OPC_MAX_F, max.f), + OPC(2, OPC_MUL_F, mul.f), + OPC(2, OPC_SIGN_F, sign.f), + OPC(2, OPC_CMPS_F, cmps.f), + OPC(2, OPC_ABSNEG_F, absneg.f), + OPC(2, OPC_CMPV_F, cmpv.f), + OPC(2, OPC_FLOOR_F, floor.f), + OPC(2, OPC_CEIL_F, ceil.f), + OPC(2, OPC_RNDNE_F, rndne.f), + OPC(2, OPC_RNDAZ_F, rndaz.f), + OPC(2, OPC_TRUNC_F, trunc.f), + OPC(2, OPC_ADD_U, add.u), + OPC(2, OPC_ADD_S, add.s), + OPC(2, OPC_SUB_U, sub.u), + OPC(2, OPC_SUB_S, sub.s), + OPC(2, OPC_CMPS_U, cmps.u), + OPC(2, OPC_CMPS_S, cmps.s), + OPC(2, OPC_MIN_U, min.u), + OPC(2, OPC_MIN_S, min.s), + OPC(2, OPC_MAX_U, max.u), + OPC(2, OPC_MAX_S, max.s), + OPC(2, OPC_ABSNEG_S, absneg.s), + OPC(2, OPC_AND_B, and.b), + OPC(2, OPC_OR_B, or.b), + OPC(2, OPC_NOT_B, not.b), + OPC(2, OPC_XOR_B, xor.b), + OPC(2, OPC_CMPV_U, cmpv.u), + OPC(2, OPC_CMPV_S, cmpv.s), + OPC(2, OPC_MUL_U24, mul.u24), + OPC(2, OPC_MUL_S24, mul.s24), + OPC(2, OPC_MULL_U, mull.u), + OPC(2, OPC_BFREV_B, bfrev.b), + OPC(2, OPC_CLZ_S, clz.s), + OPC(2, OPC_CLZ_B, clz.b), + OPC(2, OPC_SHL_B, shl.b), + OPC(2, OPC_SHR_B, shr.b), + OPC(2, OPC_ASHR_B, ashr.b), + OPC(2, OPC_BARY_F, bary.f), + OPC(2, OPC_MGEN_B, mgen.b), + OPC(2, OPC_GETBIT_B, getbit.b), + OPC(2, OPC_SETRM, setrm), + OPC(2, OPC_CBITS_B, cbits.b), + OPC(2, OPC_SHB, shb), + OPC(2, OPC_MSAD, msad), + + /* category 3: */ + OPC(3, OPC_MAD_U16, mad.u16), + OPC(3, OPC_MADSH_U16, madsh.u16), + OPC(3, OPC_MAD_S16, mad.s16), + OPC(3, OPC_MADSH_M16, madsh.m16), + OPC(3, OPC_MAD_U24, mad.u24), + OPC(3, OPC_MAD_S24, mad.s24), + OPC(3, OPC_MAD_F16, mad.f16), + OPC(3, OPC_MAD_F32, mad.f32), + OPC(3, OPC_SEL_B16, sel.b16), + OPC(3, OPC_SEL_B32, sel.b32), + OPC(3, OPC_SEL_S16, sel.s16), + OPC(3, OPC_SEL_S32, sel.s32), + OPC(3, OPC_SEL_F16, sel.f16), + OPC(3, OPC_SEL_F32, sel.f32), + OPC(3, OPC_SAD_S16, sad.s16), + OPC(3, OPC_SAD_S32, sad.s32), + + /* category 4: */ + OPC(4, OPC_RCP, rcp), + OPC(4, OPC_RSQ, rsq), + OPC(4, OPC_LOG2, log2), + OPC(4, OPC_EXP2, exp2), + OPC(4, OPC_SIN, sin), + OPC(4, OPC_COS, cos), + OPC(4, OPC_SQRT, sqrt), + OPC(4, OPC_HRSQ, hrsq), + OPC(4, OPC_HLOG2, hlog2), + OPC(4, OPC_HEXP2, hexp2), + + /* category 5: */ + OPC(5, OPC_ISAM, isam), + OPC(5, OPC_ISAML, isaml), + OPC(5, OPC_ISAMM, isamm), + OPC(5, OPC_SAM, sam), + OPC(5, OPC_SAMB, samb), + OPC(5, OPC_SAML, saml), + OPC(5, OPC_SAMGQ, samgq), + OPC(5, OPC_GETLOD, getlod), + OPC(5, OPC_CONV, conv), + OPC(5, OPC_CONVM, convm), + OPC(5, OPC_GETSIZE, getsize), + OPC(5, OPC_GETBUF, getbuf), + OPC(5, OPC_GETPOS, getpos), + OPC(5, OPC_GETINFO, getinfo), + OPC(5, OPC_DSX, dsx), + OPC(5, OPC_DSY, dsy), + OPC(5, OPC_GATHER4R, gather4r), + OPC(5, OPC_GATHER4G, gather4g), + OPC(5, OPC_GATHER4B, gather4b), + OPC(5, OPC_GATHER4A, gather4a), + OPC(5, OPC_SAMGP0, samgp0), + OPC(5, OPC_SAMGP1, samgp1), + OPC(5, OPC_SAMGP2, samgp2), + OPC(5, OPC_SAMGP3, samgp3), + OPC(5, OPC_DSXPP_1, dsxpp.1), + OPC(5, OPC_DSYPP_1, dsypp.1), + OPC(5, OPC_RGETPOS, rgetpos), + OPC(5, OPC_RGETINFO, rgetinfo), + + + /* category 6: */ + OPC(6, OPC_LDG, ldg), + OPC(6, OPC_LDL, ldl), + OPC(6, OPC_LDP, ldp), + OPC(6, OPC_STG, stg), + OPC(6, OPC_STL, stl), + OPC(6, OPC_STP, stp), + OPC(6, OPC_LDIB, ldib), + OPC(6, OPC_G2L, g2l), + OPC(6, OPC_L2G, l2g), + OPC(6, OPC_PREFETCH, prefetch), + OPC(6, OPC_LDLW, ldlw), + OPC(6, OPC_STLW, stlw), + OPC(6, OPC_RESFMT, resfmt), + OPC(6, OPC_RESINFO, resinfo), + OPC(6, OPC_ATOMIC_ADD, atomic.add), + OPC(6, OPC_ATOMIC_SUB, atomic.sub), + OPC(6, OPC_ATOMIC_XCHG, atomic.xchg), + OPC(6, OPC_ATOMIC_INC, atomic.inc), + OPC(6, OPC_ATOMIC_DEC, atomic.dec), + OPC(6, OPC_ATOMIC_CMPXCHG, atomic.cmpxchg), + OPC(6, OPC_ATOMIC_MIN, atomic.min), + OPC(6, OPC_ATOMIC_MAX, atomic.max), + OPC(6, OPC_ATOMIC_AND, atomic.and), + OPC(6, OPC_ATOMIC_OR, atomic.or), + OPC(6, OPC_ATOMIC_XOR, atomic.xor), + OPC(6, OPC_LDGB, ldgb), + OPC(6, OPC_STGB, stgb), + OPC(6, OPC_STIB, stib), + OPC(6, OPC_LDC, ldc), + OPC(6, OPC_LDLV, ldlv), + + OPC(7, OPC_BAR, bar), + OPC(7, OPC_FENCE, fence), + +#undef OPC +}; + +#define GETINFO(instr) (&(opcs[((instr)->opc_cat << NOPC_BITS) | instr_opc(instr, ctx->gpu_id)])) + +// XXX hack.. probably should move this table somewhere common: +#include "ir3.h" +const char *ir3_instr_name(struct ir3_instruction *instr) +{ + if (opc_cat(instr->opc) == -1) return "??meta??"; + return opcs[instr->opc].name; +} + +static void print_single_instr(struct disasm_ctx *ctx, instr_t *instr) +{ + const char *name = GETINFO(instr)->name; + uint32_t opc = instr_opc(instr, ctx->gpu_id); + + if (name) { + fprintf(ctx->out, "%s", name); + GETINFO(instr)->print(ctx, instr); + } else { + fprintf(ctx->out, "unknown(%d,%d)", instr->opc_cat, opc); + + switch (instr->opc_cat) { + case 0: print_instr_cat0(ctx, instr); break; + case 1: print_instr_cat1(ctx, instr); break; + case 2: print_instr_cat2(ctx, instr); break; + case 3: print_instr_cat3(ctx, instr); break; + case 4: print_instr_cat4(ctx, instr); break; + case 5: print_instr_cat5(ctx, instr); break; + case 6: print_instr_cat6(ctx, instr); break; + case 7: print_instr_cat7(ctx, instr); break; + } + } +} + +static bool print_instr(struct disasm_ctx *ctx, uint32_t *dwords, int n) +{ + instr_t *instr = (instr_t *)dwords; + uint32_t opc = instr_opc(instr, ctx->gpu_id); + unsigned nop = 0; + unsigned cycles = ctx->instructions; + + if (debug & PRINT_VERBOSE) { + fprintf(ctx->out, "%s%04d:%04d[%08xx_%08xx] ", levels[ctx->level], + n, cycles++, dwords[1], dwords[0]); + } + + /* NOTE: order flags are printed is a bit fugly.. but for now I + * try to match the order in llvm-a3xx disassembler for easy + * diff'ing.. + */ + + ctx->repeat = instr_repeat(instr); + ctx->instructions += 1 + ctx->repeat; + + if (instr->sync) { + fprintf(ctx->out, "(sy)"); + } + if (instr->ss && ((instr->opc_cat <= 4) || (instr->opc_cat == 7))) { + fprintf(ctx->out, "(ss)"); + } + if (instr->jmp_tgt) + fprintf(ctx->out, "(jp)"); + if ((instr->opc_cat == 0) && instr->cat0.eq) + fprintf(ctx->out, "(eq)"); + if (instr_sat(instr)) + fprintf(ctx->out, "(sat)"); + if (ctx->repeat) + fprintf(ctx->out, "(rpt%d)", ctx->repeat); + else if ((instr->opc_cat == 2) && (instr->cat2.src1_r || instr->cat2.src2_r)) + nop = (instr->cat2.src2_r * 2) + instr->cat2.src1_r; + else if ((instr->opc_cat == 3) && (instr->cat3.src1_r || instr->cat3.src2_r)) + nop = (instr->cat3.src2_r * 2) + instr->cat3.src1_r; + ctx->instructions += nop; + if (nop) + fprintf(ctx->out, "(nop%d) ", nop); + + if (instr->ul && ((2 <= instr->opc_cat) && (instr->opc_cat <= 4))) + fprintf(ctx->out, "(ul)"); + + print_single_instr(ctx, instr); + fprintf(ctx->out, "\n"); + + if ((instr->opc_cat <= 4) && (debug & EXPAND_REPEAT)) { + int i; + for (i = 0; i < nop; i++) { + if (debug & PRINT_VERBOSE) { + fprintf(ctx->out, "%s%04d:%04d[ ] ", + levels[ctx->level], n, cycles++); + } + fprintf(ctx->out, "nop\n"); + } + for (i = 0; i < ctx->repeat; i++) { + ctx->repeatidx = i + 1; + if (debug & PRINT_VERBOSE) { + fprintf(ctx->out, "%s%04d:%04d[ ] ", + levels[ctx->level], n, cycles++); + } + print_single_instr(ctx, instr); + fprintf(ctx->out, "\n"); + } + ctx->repeatidx = 0; + } + + return (instr->opc_cat == 0) && (opc == OPC_END); +} + +int disasm_a3xx(uint32_t *dwords, int sizedwords, int level, FILE *out, unsigned gpu_id) +{ + struct disasm_ctx ctx; + int i; + int nop_count = 0; + + //assert((sizedwords % 2) == 0); + + memset(&ctx, 0, sizeof(ctx)); + ctx.out = out; + ctx.level = level; + ctx.gpu_id = gpu_id; + + for (i = 0; i < sizedwords; i += 2) { + print_instr(&ctx, &dwords[i], i/2); + if (dwords[i] == 0 && dwords[i + 1] == 0) + nop_count++; + else + nop_count = 0; + if (nop_count > 3) + break; + } + + return 0; +} + +int main(int argc, char *argv[]) { + uint32_t buf[0x10000]; + FILE *f = fopen(argv[1], "rb"); + if (argc > 2) { + int seek = atoi(argv[2]); + printf("skip %d\n", seek); + fread(buf, 1, seek , f); + } + int len = fread(buf, 1, sizeof(buf), f); + fclose(f); + + disasm_a3xx(buf, len/4, 0, stdout, 0); +} + diff --git a/selfdrive/modeld/thneed/debug/decompiler/instr-a3xx.h b/selfdrive/modeld/thneed/debug/decompiler/instr-a3xx.h new file mode 100644 index 0000000000..e4f548d639 --- /dev/null +++ b/selfdrive/modeld/thneed/debug/decompiler/instr-a3xx.h @@ -0,0 +1,1119 @@ +/* + * Copyright (c) 2013 Rob Clark + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef INSTR_A3XX_H_ +#define INSTR_A3XX_H_ + +#define PACKED __attribute__((__packed__)) + +#include +#include +#include +#include + +/* size of largest OPC field of all the instruction categories: */ +#define NOPC_BITS 6 + +#define _OPC(cat, opc) (((cat) << NOPC_BITS) | opc) + +typedef enum { + /* category 0: */ + OPC_NOP = _OPC(0, 0), + OPC_B = _OPC(0, 1), + OPC_JUMP = _OPC(0, 2), + OPC_CALL = _OPC(0, 3), + OPC_RET = _OPC(0, 4), + OPC_KILL = _OPC(0, 5), + OPC_END = _OPC(0, 6), + OPC_EMIT = _OPC(0, 7), + OPC_CUT = _OPC(0, 8), + OPC_CHMASK = _OPC(0, 9), + OPC_CHSH = _OPC(0, 10), + OPC_FLOW_REV = _OPC(0, 11), + + OPC_BKT = _OPC(0, 16), + OPC_STKS = _OPC(0, 17), + OPC_STKR = _OPC(0, 18), + OPC_XSET = _OPC(0, 19), + OPC_XCLR = _OPC(0, 20), + OPC_GETONE = _OPC(0, 21), + OPC_DBG = _OPC(0, 22), + OPC_SHPS = _OPC(0, 23), /* shader prologue start */ + OPC_SHPE = _OPC(0, 24), /* shader prologue end */ + + OPC_PREDT = _OPC(0, 29), /* predicated true */ + OPC_PREDF = _OPC(0, 30), /* predicated false */ + OPC_PREDE = _OPC(0, 31), /* predicated end */ + + /* category 1: */ + OPC_MOV = _OPC(1, 0), + + /* category 2: */ + OPC_ADD_F = _OPC(2, 0), + OPC_MIN_F = _OPC(2, 1), + OPC_MAX_F = _OPC(2, 2), + OPC_MUL_F = _OPC(2, 3), + OPC_SIGN_F = _OPC(2, 4), + OPC_CMPS_F = _OPC(2, 5), + OPC_ABSNEG_F = _OPC(2, 6), + OPC_CMPV_F = _OPC(2, 7), + /* 8 - invalid */ + OPC_FLOOR_F = _OPC(2, 9), + OPC_CEIL_F = _OPC(2, 10), + OPC_RNDNE_F = _OPC(2, 11), + OPC_RNDAZ_F = _OPC(2, 12), + OPC_TRUNC_F = _OPC(2, 13), + /* 14-15 - invalid */ + OPC_ADD_U = _OPC(2, 16), + OPC_ADD_S = _OPC(2, 17), + OPC_SUB_U = _OPC(2, 18), + OPC_SUB_S = _OPC(2, 19), + OPC_CMPS_U = _OPC(2, 20), + OPC_CMPS_S = _OPC(2, 21), + OPC_MIN_U = _OPC(2, 22), + OPC_MIN_S = _OPC(2, 23), + OPC_MAX_U = _OPC(2, 24), + OPC_MAX_S = _OPC(2, 25), + OPC_ABSNEG_S = _OPC(2, 26), + /* 27 - invalid */ + OPC_AND_B = _OPC(2, 28), + OPC_OR_B = _OPC(2, 29), + OPC_NOT_B = _OPC(2, 30), + OPC_XOR_B = _OPC(2, 31), + /* 32 - invalid */ + OPC_CMPV_U = _OPC(2, 33), + OPC_CMPV_S = _OPC(2, 34), + /* 35-47 - invalid */ + OPC_MUL_U24 = _OPC(2, 48), /* 24b mul into 32b result */ + OPC_MUL_S24 = _OPC(2, 49), /* 24b mul into 32b result with sign extension */ + OPC_MULL_U = _OPC(2, 50), + OPC_BFREV_B = _OPC(2, 51), + OPC_CLZ_S = _OPC(2, 52), + OPC_CLZ_B = _OPC(2, 53), + OPC_SHL_B = _OPC(2, 54), + OPC_SHR_B = _OPC(2, 55), + OPC_ASHR_B = _OPC(2, 56), + OPC_BARY_F = _OPC(2, 57), + OPC_MGEN_B = _OPC(2, 58), + OPC_GETBIT_B = _OPC(2, 59), + OPC_SETRM = _OPC(2, 60), + OPC_CBITS_B = _OPC(2, 61), + OPC_SHB = _OPC(2, 62), + OPC_MSAD = _OPC(2, 63), + + /* category 3: */ + OPC_MAD_U16 = _OPC(3, 0), + OPC_MADSH_U16 = _OPC(3, 1), + OPC_MAD_S16 = _OPC(3, 2), + OPC_MADSH_M16 = _OPC(3, 3), /* should this be .s16? */ + OPC_MAD_U24 = _OPC(3, 4), + OPC_MAD_S24 = _OPC(3, 5), + OPC_MAD_F16 = _OPC(3, 6), + OPC_MAD_F32 = _OPC(3, 7), + OPC_SEL_B16 = _OPC(3, 8), + OPC_SEL_B32 = _OPC(3, 9), + OPC_SEL_S16 = _OPC(3, 10), + OPC_SEL_S32 = _OPC(3, 11), + OPC_SEL_F16 = _OPC(3, 12), + OPC_SEL_F32 = _OPC(3, 13), + OPC_SAD_S16 = _OPC(3, 14), + OPC_SAD_S32 = _OPC(3, 15), + + /* category 4: */ + OPC_RCP = _OPC(4, 0), + OPC_RSQ = _OPC(4, 1), + OPC_LOG2 = _OPC(4, 2), + OPC_EXP2 = _OPC(4, 3), + OPC_SIN = _OPC(4, 4), + OPC_COS = _OPC(4, 5), + OPC_SQRT = _OPC(4, 6), + /* NOTE that these are 8+opc from their highp equivs, so it's possible + * that the high order bit in the opc field has been repurposed for + * half-precision use? But note that other ops (rcp/lsin/cos/sqrt) + * still use the same opc as highp + */ + OPC_HRSQ = _OPC(4, 9), + OPC_HLOG2 = _OPC(4, 10), + OPC_HEXP2 = _OPC(4, 11), + + /* category 5: */ + OPC_ISAM = _OPC(5, 0), + OPC_ISAML = _OPC(5, 1), + OPC_ISAMM = _OPC(5, 2), + OPC_SAM = _OPC(5, 3), + OPC_SAMB = _OPC(5, 4), + OPC_SAML = _OPC(5, 5), + OPC_SAMGQ = _OPC(5, 6), + OPC_GETLOD = _OPC(5, 7), + OPC_CONV = _OPC(5, 8), + OPC_CONVM = _OPC(5, 9), + OPC_GETSIZE = _OPC(5, 10), + OPC_GETBUF = _OPC(5, 11), + OPC_GETPOS = _OPC(5, 12), + OPC_GETINFO = _OPC(5, 13), + OPC_DSX = _OPC(5, 14), + OPC_DSY = _OPC(5, 15), + OPC_GATHER4R = _OPC(5, 16), + OPC_GATHER4G = _OPC(5, 17), + OPC_GATHER4B = _OPC(5, 18), + OPC_GATHER4A = _OPC(5, 19), + OPC_SAMGP0 = _OPC(5, 20), + OPC_SAMGP1 = _OPC(5, 21), + OPC_SAMGP2 = _OPC(5, 22), + OPC_SAMGP3 = _OPC(5, 23), + OPC_DSXPP_1 = _OPC(5, 24), + OPC_DSYPP_1 = _OPC(5, 25), + OPC_RGETPOS = _OPC(5, 26), + OPC_RGETINFO = _OPC(5, 27), + + /* category 6: */ + OPC_LDG = _OPC(6, 0), /* load-global */ + OPC_LDL = _OPC(6, 1), + OPC_LDP = _OPC(6, 2), + OPC_STG = _OPC(6, 3), /* store-global */ + OPC_STL = _OPC(6, 4), + OPC_STP = _OPC(6, 5), + OPC_LDIB = _OPC(6, 6), + OPC_G2L = _OPC(6, 7), + OPC_L2G = _OPC(6, 8), + OPC_PREFETCH = _OPC(6, 9), + OPC_LDLW = _OPC(6, 10), + OPC_STLW = _OPC(6, 11), + OPC_RESFMT = _OPC(6, 14), + OPC_RESINFO = _OPC(6, 15), + OPC_ATOMIC_ADD = _OPC(6, 16), + OPC_ATOMIC_SUB = _OPC(6, 17), + OPC_ATOMIC_XCHG = _OPC(6, 18), + OPC_ATOMIC_INC = _OPC(6, 19), + OPC_ATOMIC_DEC = _OPC(6, 20), + OPC_ATOMIC_CMPXCHG = _OPC(6, 21), + OPC_ATOMIC_MIN = _OPC(6, 22), + OPC_ATOMIC_MAX = _OPC(6, 23), + OPC_ATOMIC_AND = _OPC(6, 24), + OPC_ATOMIC_OR = _OPC(6, 25), + OPC_ATOMIC_XOR = _OPC(6, 26), + OPC_LDGB = _OPC(6, 27), + OPC_STGB = _OPC(6, 28), + OPC_STIB = _OPC(6, 29), + OPC_LDC = _OPC(6, 30), + OPC_LDLV = _OPC(6, 31), + + /* category 7: */ + OPC_BAR = _OPC(7, 0), + OPC_FENCE = _OPC(7, 1), + + /* meta instructions (category -1): */ + /* placeholder instr to mark shader inputs: */ + OPC_META_INPUT = _OPC(-1, 0), + /* The "collect" and "split" instructions are used for keeping + * track of instructions that write to multiple dst registers + * (split) like texture sample instructions, or read multiple + * consecutive scalar registers (collect) (bary.f, texture samp) + * + * A "split" extracts a scalar component from a vecN, and a + * "collect" gathers multiple scalar components into a vecN + */ + OPC_META_SPLIT = _OPC(-1, 2), + OPC_META_COLLECT = _OPC(-1, 3), + + /* placeholder for texture fetches that run before FS invocation + * starts: + */ + OPC_META_TEX_PREFETCH = _OPC(-1, 4), + +} opc_t; + +#define opc_cat(opc) ((int)((opc) >> NOPC_BITS)) +#define opc_op(opc) ((unsigned)((opc) & ((1 << NOPC_BITS) - 1))) + +typedef enum { + TYPE_F16 = 0, + TYPE_F32 = 1, + TYPE_U16 = 2, + TYPE_U32 = 3, + TYPE_S16 = 4, + TYPE_S32 = 5, + TYPE_U8 = 6, + TYPE_S8 = 7, // XXX I assume? +} type_t; + +static inline uint32_t type_size(type_t type) +{ + switch (type) { + case TYPE_F32: + case TYPE_U32: + case TYPE_S32: + return 32; + case TYPE_F16: + case TYPE_U16: + case TYPE_S16: + return 16; + case TYPE_U8: + case TYPE_S8: + return 8; + default: + assert(0); /* invalid type */ + return 0; + } +} + +static inline int type_float(type_t type) +{ + return (type == TYPE_F32) || (type == TYPE_F16); +} + +static inline int type_uint(type_t type) +{ + return (type == TYPE_U32) || (type == TYPE_U16) || (type == TYPE_U8); +} + +static inline int type_sint(type_t type) +{ + return (type == TYPE_S32) || (type == TYPE_S16) || (type == TYPE_S8); +} + +typedef union PACKED { + /* normal gpr or const src register: */ + struct PACKED { + uint32_t comp : 2; + uint32_t num : 10; + }; + /* for immediate val: */ + int32_t iim_val : 11; + /* to make compiler happy: */ + uint32_t dummy32; + uint32_t dummy10 : 10; + int32_t idummy10 : 10; + uint32_t dummy11 : 11; + uint32_t dummy12 : 12; + uint32_t dummy13 : 13; + uint32_t dummy8 : 8; + int32_t idummy13 : 13; + int32_t idummy8 : 8; +} reg_t; + +/* special registers: */ +#define REG_A0 61 /* address register */ +#define REG_P0 62 /* predicate register */ + +static inline int reg_special(reg_t reg) +{ + return (reg.num == REG_A0) || (reg.num == REG_P0); +} + +typedef enum { + BRANCH_PLAIN = 0, /* br */ + BRANCH_OR = 1, /* brao */ + BRANCH_AND = 2, /* braa */ + BRANCH_CONST = 3, /* brac */ + BRANCH_ANY = 4, /* bany */ + BRANCH_ALL = 5, /* ball */ + BRANCH_X = 6, /* brax ??? */ +} brtype_t; + +typedef struct PACKED { + /* dword0: */ + union PACKED { + struct PACKED { + int16_t immed : 16; + uint32_t dummy1 : 16; + } a3xx; + struct PACKED { + int32_t immed : 20; + uint32_t dummy1 : 12; + } a4xx; + struct PACKED { + int32_t immed : 32; + } a5xx; + }; + + /* dword1: */ + uint32_t idx : 5; /* brac.N index */ + uint32_t brtype : 3; /* branch type, see brtype_t */ + uint32_t repeat : 3; + uint32_t dummy3 : 1; + uint32_t ss : 1; + uint32_t inv1 : 1; + uint32_t comp1 : 2; + uint32_t eq : 1; + uint32_t opc_hi : 1; /* at least one bit */ + uint32_t dummy4 : 2; + uint32_t inv0 : 1; + uint32_t comp0 : 2; /* component for first src */ + uint32_t opc : 4; + uint32_t jmp_tgt : 1; + uint32_t sync : 1; + uint32_t opc_cat : 3; +} instr_cat0_t; + +typedef struct PACKED { + /* dword0: */ + union PACKED { + /* for normal src register: */ + struct PACKED { + uint32_t src : 11; + /* at least low bit of pad must be zero or it will + * look like a address relative src + */ + uint32_t pad : 21; + }; + /* for address relative: */ + struct PACKED { + int32_t off : 10; + uint32_t src_rel_c : 1; + uint32_t src_rel : 1; + uint32_t unknown : 20; + }; + /* for immediate: */ + int32_t iim_val; + uint32_t uim_val; + float fim_val; + }; + + /* dword1: */ + uint32_t dst : 8; + uint32_t repeat : 3; + uint32_t src_r : 1; + uint32_t ss : 1; + uint32_t ul : 1; + uint32_t dst_type : 3; + uint32_t dst_rel : 1; + uint32_t src_type : 3; + uint32_t src_c : 1; + uint32_t src_im : 1; + uint32_t even : 1; + uint32_t pos_inf : 1; + uint32_t must_be_0 : 2; + uint32_t jmp_tgt : 1; + uint32_t sync : 1; + uint32_t opc_cat : 3; +} instr_cat1_t; + +typedef struct PACKED { + /* dword0: */ + union PACKED { + struct PACKED { + uint32_t src1 : 11; + uint32_t must_be_zero1: 2; + uint32_t src1_im : 1; /* immediate */ + uint32_t src1_neg : 1; /* negate */ + uint32_t src1_abs : 1; /* absolute value */ + }; + struct PACKED { + uint32_t src1 : 10; + uint32_t src1_c : 1; /* relative-const */ + uint32_t src1_rel : 1; /* relative address */ + uint32_t must_be_zero : 1; + uint32_t dummy : 3; + } rel1; + struct PACKED { + uint32_t src1 : 12; + uint32_t src1_c : 1; /* const */ + uint32_t dummy : 3; + } c1; + }; + + union PACKED { + struct PACKED { + uint32_t src2 : 11; + uint32_t must_be_zero2: 2; + uint32_t src2_im : 1; /* immediate */ + uint32_t src2_neg : 1; /* negate */ + uint32_t src2_abs : 1; /* absolute value */ + }; + struct PACKED { + uint32_t src2 : 10; + uint32_t src2_c : 1; /* relative-const */ + uint32_t src2_rel : 1; /* relative address */ + uint32_t must_be_zero : 1; + uint32_t dummy : 3; + } rel2; + struct PACKED { + uint32_t src2 : 12; + uint32_t src2_c : 1; /* const */ + uint32_t dummy : 3; + } c2; + }; + + /* dword1: */ + uint32_t dst : 8; + uint32_t repeat : 2; + uint32_t sat : 1; + uint32_t src1_r : 1; /* doubles as nop0 if repeat==0 */ + uint32_t ss : 1; + uint32_t ul : 1; /* dunno */ + uint32_t dst_half : 1; /* or widen/narrow.. ie. dst hrN <-> rN */ + uint32_t ei : 1; + uint32_t cond : 3; + uint32_t src2_r : 1; /* doubles as nop1 if repeat==0 */ + uint32_t full : 1; /* not half */ + uint32_t opc : 6; + uint32_t jmp_tgt : 1; + uint32_t sync : 1; + uint32_t opc_cat : 3; +} instr_cat2_t; + +typedef struct PACKED { + /* dword0: */ + union PACKED { + struct PACKED { + uint32_t src1 : 11; + uint32_t must_be_zero1: 2; + uint32_t src2_c : 1; + uint32_t src1_neg : 1; + uint32_t src2_r : 1; /* doubles as nop1 if repeat==0 */ + }; + struct PACKED { + uint32_t src1 : 10; + uint32_t src1_c : 1; + uint32_t src1_rel : 1; + uint32_t must_be_zero : 1; + uint32_t dummy : 3; + } rel1; + struct PACKED { + uint32_t src1 : 12; + uint32_t src1_c : 1; + uint32_t dummy : 3; + } c1; + }; + + union PACKED { + struct PACKED { + uint32_t src3 : 11; + uint32_t must_be_zero2: 2; + uint32_t src3_r : 1; + uint32_t src2_neg : 1; + uint32_t src3_neg : 1; + }; + struct PACKED { + uint32_t src3 : 10; + uint32_t src3_c : 1; + uint32_t src3_rel : 1; + uint32_t must_be_zero : 1; + uint32_t dummy : 3; + } rel2; + struct PACKED { + uint32_t src3 : 12; + uint32_t src3_c : 1; + uint32_t dummy : 3; + } c2; + }; + + /* dword1: */ + uint32_t dst : 8; + uint32_t repeat : 2; + uint32_t sat : 1; + uint32_t src1_r : 1; /* doubles as nop0 if repeat==0 */ + uint32_t ss : 1; + uint32_t ul : 1; + uint32_t dst_half : 1; /* or widen/narrow.. ie. dst hrN <-> rN */ + uint32_t src2 : 8; + uint32_t opc : 4; + uint32_t jmp_tgt : 1; + uint32_t sync : 1; + uint32_t opc_cat : 3; +} instr_cat3_t; + +static inline bool instr_cat3_full(instr_cat3_t *cat3) +{ + switch (_OPC(3, cat3->opc)) { + case OPC_MAD_F16: + case OPC_MAD_U16: + case OPC_MAD_S16: + case OPC_SEL_B16: + case OPC_SEL_S16: + case OPC_SEL_F16: + case OPC_SAD_S16: + case OPC_SAD_S32: // really?? + return false; + default: + return true; + } +} + +typedef struct PACKED { + /* dword0: */ + union PACKED { + struct PACKED { + uint32_t src : 11; + uint32_t must_be_zero1: 2; + uint32_t src_im : 1; /* immediate */ + uint32_t src_neg : 1; /* negate */ + uint32_t src_abs : 1; /* absolute value */ + }; + struct PACKED { + uint32_t src : 10; + uint32_t src_c : 1; /* relative-const */ + uint32_t src_rel : 1; /* relative address */ + uint32_t must_be_zero : 1; + uint32_t dummy : 3; + } rel; + struct PACKED { + uint32_t src : 12; + uint32_t src_c : 1; /* const */ + uint32_t dummy : 3; + } c; + }; + uint32_t dummy1 : 16; /* seem to be ignored */ + + /* dword1: */ + uint32_t dst : 8; + uint32_t repeat : 2; + uint32_t sat : 1; + uint32_t src_r : 1; + uint32_t ss : 1; + uint32_t ul : 1; + uint32_t dst_half : 1; /* or widen/narrow.. ie. dst hrN <-> rN */ + uint32_t dummy2 : 5; /* seem to be ignored */ + uint32_t full : 1; /* not half */ + uint32_t opc : 6; + uint32_t jmp_tgt : 1; + uint32_t sync : 1; + uint32_t opc_cat : 3; +} instr_cat4_t; + +/* With is_bindless_s2en = 1, this determines whether bindless is enabled and + * if so, how to get the (base, index) pair for both sampler and texture. + * There is a single base embedded in the instruction, which is always used + * for the texture. + */ +typedef enum { + /* Use traditional GL binding model, get texture and sampler index + * from src3 which is not presumed to be uniform. This is + * backwards-compatible with earlier generations, where this field was + * always 0 and nonuniform-indexed sampling always worked. + */ + CAT5_NONUNIFORM = 0, + + /* The sampler base comes from the low 3 bits of a1.x, and the sampler + * and texture index come from src3 which is presumed to be uniform. + */ + CAT5_BINDLESS_A1_UNIFORM = 1, + + /* The texture and sampler share the same base, and the sampler and + * texture index come from src3 which is *not* presumed to be uniform. + */ + CAT5_BINDLESS_NONUNIFORM = 2, + + /* The sampler base comes from the low 3 bits of a1.x, and the sampler + * and texture index come from src3 which is *not* presumed to be + * uniform. + */ + CAT5_BINDLESS_A1_NONUNIFORM = 3, + + /* Use traditional GL binding model, get texture and sampler index + * from src3 which is presumed to be uniform. + */ + CAT5_UNIFORM = 4, + + /* The texture and sampler share the same base, and the sampler and + * texture index come from src3 which is presumed to be uniform. + */ + CAT5_BINDLESS_UNIFORM = 5, + + /* The texture and sampler share the same base, get sampler index from low + * 4 bits of src3 and texture index from high 4 bits. + */ + CAT5_BINDLESS_IMM = 6, + + /* The sampler base comes from the low 3 bits of a1.x, and the texture + * index comes from the next 8 bits of a1.x. The sampler index is an + * immediate in src3. + */ + CAT5_BINDLESS_A1_IMM = 7, +} cat5_desc_mode_t; + +typedef struct PACKED { + /* dword0: */ + union PACKED { + /* normal case: */ + struct PACKED { + uint32_t full : 1; /* not half */ + uint32_t src1 : 8; + uint32_t src2 : 8; + uint32_t dummy1 : 4; /* seem to be ignored */ + uint32_t samp : 4; + uint32_t tex : 7; + } norm; + /* s2en case: */ + struct PACKED { + uint32_t full : 1; /* not half */ + uint32_t src1 : 8; + uint32_t src2 : 8; + uint32_t dummy1 : 2; + uint32_t base_hi : 2; + uint32_t src3 : 8; + uint32_t desc_mode : 3; + } s2en_bindless; + /* same in either case: */ + // XXX I think, confirm this + struct PACKED { + uint32_t full : 1; /* not half */ + uint32_t src1 : 8; + uint32_t src2 : 8; + uint32_t pad : 15; + }; + }; + + /* dword1: */ + uint32_t dst : 8; + uint32_t wrmask : 4; /* write-mask */ + uint32_t type : 3; + uint32_t base_lo : 1; /* used with bindless */ + uint32_t is_3d : 1; + + uint32_t is_a : 1; + uint32_t is_s : 1; + uint32_t is_s2en_bindless : 1; + uint32_t is_o : 1; + uint32_t is_p : 1; + + uint32_t opc : 5; + uint32_t jmp_tgt : 1; + uint32_t sync : 1; + uint32_t opc_cat : 3; +} instr_cat5_t; + +/* dword0 encoding for src_off: [src1 + off], src2: */ +typedef struct PACKED { + /* dword0: */ + uint32_t mustbe1 : 1; + int32_t off : 13; + uint32_t src1 : 8; + uint32_t src1_im : 1; + uint32_t src2_im : 1; + uint32_t src2 : 8; + + /* dword1: */ + uint32_t dword1; +} instr_cat6a_t; + +/* dword0 encoding for !src_off: [src1], src2 */ +typedef struct PACKED { + /* dword0: */ + uint32_t mustbe0 : 1; + uint32_t src1 : 13; + uint32_t ignore0 : 8; + uint32_t src1_im : 1; + uint32_t src2_im : 1; + uint32_t src2 : 8; + + /* dword1: */ + uint32_t dword1; +} instr_cat6b_t; + +/* dword1 encoding for dst_off: */ +typedef struct PACKED { + /* dword0: */ + uint32_t dword0; + + /* note: there is some weird stuff going on where sometimes + * cat6->a.off is involved.. but that seems like a bug in + * the blob, since it is used even if !cat6->src_off + * It would make sense for there to be some more bits to + * bring us to 11 bits worth of offset, but not sure.. + */ + int32_t off : 8; + uint32_t mustbe1 : 1; + uint32_t dst : 8; + uint32_t pad1 : 15; +} instr_cat6c_t; + +/* dword1 encoding for !dst_off: */ +typedef struct PACKED { + /* dword0: */ + uint32_t dword0; + + uint32_t dst : 8; + uint32_t mustbe0 : 1; + uint32_t idx : 8; + uint32_t pad0 : 15; +} instr_cat6d_t; + +/* ldgb and atomics.. + * + * ldgb: pad0=0, pad3=1 + * atomic .g: pad0=1, pad3=1 + * .l: pad0=1, pad3=0 + */ +typedef struct PACKED { + /* dword0: */ + uint32_t pad0 : 1; + uint32_t src3 : 8; + uint32_t d : 2; + uint32_t typed : 1; + uint32_t type_size : 2; + uint32_t src1 : 8; + uint32_t src1_im : 1; + uint32_t src2_im : 1; + uint32_t src2 : 8; + + /* dword1: */ + uint32_t dst : 8; + uint32_t mustbe0 : 1; + uint32_t src_ssbo : 8; + uint32_t pad2 : 3; // type + uint32_t g : 1; + uint32_t pad3 : 1; + uint32_t pad4 : 10; // opc/jmp_tgt/sync/opc_cat +} instr_cat6ldgb_t; + +/* stgb, pad0=0, pad3=2 + */ +typedef struct PACKED { + /* dword0: */ + uint32_t mustbe1 : 1; // ??? + uint32_t src1 : 8; + uint32_t d : 2; + uint32_t typed : 1; + uint32_t type_size : 2; + uint32_t pad0 : 9; + uint32_t src2_im : 1; + uint32_t src2 : 8; + + /* dword1: */ + uint32_t src3 : 8; + uint32_t src3_im : 1; + uint32_t dst_ssbo : 8; + uint32_t pad2 : 3; // type + uint32_t pad3 : 2; + uint32_t pad4 : 10; // opc/jmp_tgt/sync/opc_cat +} instr_cat6stgb_t; + +typedef union PACKED { + instr_cat6a_t a; + instr_cat6b_t b; + instr_cat6c_t c; + instr_cat6d_t d; + instr_cat6ldgb_t ldgb; + instr_cat6stgb_t stgb; + struct PACKED { + /* dword0: */ + uint32_t src_off : 1; + uint32_t pad1 : 31; + + /* dword1: */ + uint32_t pad2 : 8; + uint32_t dst_off : 1; + uint32_t pad3 : 8; + uint32_t type : 3; + uint32_t g : 1; /* or in some cases it means dst immed */ + uint32_t pad4 : 1; + uint32_t opc : 5; + uint32_t jmp_tgt : 1; + uint32_t sync : 1; + uint32_t opc_cat : 3; + }; +} instr_cat6_t; + +/* Similar to cat5_desc_mode_t, describes how the descriptor is loaded. + */ +typedef enum { + /* Use old GL binding model with an immediate index. */ + CAT6_IMM = 0, + + CAT6_UNIFORM = 1, + + CAT6_NONUNIFORM = 2, + + /* Use the bindless model, with an immediate index. + */ + CAT6_BINDLESS_IMM = 4, + + /* Use the bindless model, with a uniform register index. + */ + CAT6_BINDLESS_UNIFORM = 5, + + /* Use the bindless model, with a register index that isn't guaranteed + * to be uniform. This presumably checks if the indices are equal and + * splits up the load/store, because it works the way you would + * expect. + */ + CAT6_BINDLESS_NONUNIFORM = 6, +} cat6_desc_mode_t; + +/** + * For atomic ops (which return a value): + * + * pad1=1, pad3=c, pad5=3 + * src1 - vecN offset/coords + * src2.x - is actually dest register + * src2.y - is 'data' except for cmpxchg where src2.y is 'compare' + * and src2.z is 'data' + * + * For stib (which does not return a value): + * pad1=0, pad3=c, pad5=2 + * src1 - vecN offset/coords + * src2 - value to store + * + * For ldib: + * pad1=1, pad3=c, pad5=2 + * src1 - vecN offset/coords + * + * for ldc (load from UBO using descriptor): + * pad1=0, pad3=8, pad5=2 + * + * pad2 and pad5 are only observed to be 0. + */ +typedef struct PACKED { + /* dword0: */ + uint32_t pad1 : 1; + uint32_t base : 3; + uint32_t pad2 : 2; + uint32_t desc_mode : 3; + uint32_t d : 2; + uint32_t typed : 1; + uint32_t type_size : 2; + uint32_t opc : 5; + uint32_t pad3 : 5; + uint32_t src1 : 8; /* coordinate/offset */ + + /* dword1: */ + uint32_t src2 : 8; /* or the dst for load instructions */ + uint32_t pad4 : 1; //mustbe0 ?? + uint32_t ssbo : 8; /* ssbo/image binding point */ + uint32_t type : 3; + uint32_t pad5 : 7; + uint32_t jmp_tgt : 1; + uint32_t sync : 1; + uint32_t opc_cat : 3; +} instr_cat6_a6xx_t; + +typedef struct PACKED { + /* dword0: */ + uint32_t pad1 : 32; + + /* dword1: */ + uint32_t pad2 : 12; + uint32_t ss : 1; /* maybe in the encoding, but blob only uses (sy) */ + uint32_t pad3 : 6; + uint32_t w : 1; /* write */ + uint32_t r : 1; /* read */ + uint32_t l : 1; /* local */ + uint32_t g : 1; /* global */ + uint32_t opc : 4; /* presumed, but only a couple known OPCs */ + uint32_t jmp_tgt : 1; /* (jp) */ + uint32_t sync : 1; /* (sy) */ + uint32_t opc_cat : 3; +} instr_cat7_t; + +typedef union PACKED { + instr_cat0_t cat0; + instr_cat1_t cat1; + instr_cat2_t cat2; + instr_cat3_t cat3; + instr_cat4_t cat4; + instr_cat5_t cat5; + instr_cat6_t cat6; + instr_cat6_a6xx_t cat6_a6xx; + instr_cat7_t cat7; + struct PACKED { + /* dword0: */ + uint32_t pad1 : 32; + + /* dword1: */ + uint32_t pad2 : 12; + uint32_t ss : 1; /* cat1-cat4 (cat0??) and cat7 (?) */ + uint32_t ul : 1; /* cat2-cat4 (and cat1 in blob.. which may be bug??) */ + uint32_t pad3 : 13; + uint32_t jmp_tgt : 1; + uint32_t sync : 1; + uint32_t opc_cat : 3; + + }; +} instr_t; + +static inline uint32_t instr_repeat(instr_t *instr) +{ + switch (instr->opc_cat) { + case 0: return instr->cat0.repeat; + case 1: return instr->cat1.repeat; + case 2: return instr->cat2.repeat; + case 3: return instr->cat3.repeat; + case 4: return instr->cat4.repeat; + default: return 0; + } +} + +static inline bool instr_sat(instr_t *instr) +{ + switch (instr->opc_cat) { + case 2: return instr->cat2.sat; + case 3: return instr->cat3.sat; + case 4: return instr->cat4.sat; + default: return false; + } +} + +/* We can probably drop the gpu_id arg, but keeping it for now so we can + * assert if we see something we think should be new encoding on an older + * gpu. + */ +static inline bool is_cat6_legacy(instr_t *instr, unsigned gpu_id) +{ + instr_cat6_a6xx_t *cat6 = &instr->cat6_a6xx; + + /* At least one of these two bits is pad in all the possible + * "legacy" cat6 encodings, and a analysis of all the pre-a6xx + * cmdstream traces I have indicates that the pad bit is zero + * in all cases. So we can use this to detect new encoding: + */ + if ((cat6->pad3 & 0x8) && (cat6->pad5 & 0x2)) { + assert(gpu_id >= 600); + assert(instr->cat6.opc == 0); + return false; + } + + return true; +} + +static inline uint32_t instr_opc(instr_t *instr, unsigned gpu_id) +{ + switch (instr->opc_cat) { + case 0: return instr->cat0.opc | instr->cat0.opc_hi << 4; + case 1: return 0; + case 2: return instr->cat2.opc; + case 3: return instr->cat3.opc; + case 4: return instr->cat4.opc; + case 5: return instr->cat5.opc; + case 6: + if (!is_cat6_legacy(instr, gpu_id)) + return instr->cat6_a6xx.opc; + return instr->cat6.opc; + case 7: return instr->cat7.opc; + default: return 0; + } +} + +static inline bool is_mad(opc_t opc) +{ + switch (opc) { + case OPC_MAD_U16: + case OPC_MAD_S16: + case OPC_MAD_U24: + case OPC_MAD_S24: + case OPC_MAD_F16: + case OPC_MAD_F32: + return true; + default: + return false; + } +} + +static inline bool is_madsh(opc_t opc) +{ + switch (opc) { + case OPC_MADSH_U16: + case OPC_MADSH_M16: + return true; + default: + return false; + } +} + +static inline bool is_atomic(opc_t opc) +{ + switch (opc) { + case OPC_ATOMIC_ADD: + case OPC_ATOMIC_SUB: + case OPC_ATOMIC_XCHG: + case OPC_ATOMIC_INC: + case OPC_ATOMIC_DEC: + case OPC_ATOMIC_CMPXCHG: + case OPC_ATOMIC_MIN: + case OPC_ATOMIC_MAX: + case OPC_ATOMIC_AND: + case OPC_ATOMIC_OR: + case OPC_ATOMIC_XOR: + return true; + default: + return false; + } +} + +static inline bool is_ssbo(opc_t opc) +{ + switch (opc) { + case OPC_RESFMT: + case OPC_RESINFO: + case OPC_LDGB: + case OPC_STGB: + case OPC_STIB: + return true; + default: + return false; + } +} + +static inline bool is_isam(opc_t opc) +{ + switch (opc) { + case OPC_ISAM: + case OPC_ISAML: + case OPC_ISAMM: + return true; + default: + return false; + } +} + + +static inline bool is_cat2_float(opc_t opc) +{ + switch (opc) { + case OPC_ADD_F: + case OPC_MIN_F: + case OPC_MAX_F: + case OPC_MUL_F: + case OPC_SIGN_F: + case OPC_CMPS_F: + case OPC_ABSNEG_F: + case OPC_CMPV_F: + case OPC_FLOOR_F: + case OPC_CEIL_F: + case OPC_RNDNE_F: + case OPC_RNDAZ_F: + case OPC_TRUNC_F: + return true; + + default: + return false; + } +} + +static inline bool is_cat3_float(opc_t opc) +{ + switch (opc) { + case OPC_MAD_F16: + case OPC_MAD_F32: + case OPC_SEL_F16: + case OPC_SEL_F32: + return true; + default: + return false; + } +} + +int disasm_a3xx(uint32_t *dwords, int sizedwords, int level, FILE *out, unsigned gpu_id); + +#endif /* INSTR_A3XX_H_ */ diff --git a/selfdrive/modeld/thneed/debug/decompiler/ir3.h b/selfdrive/modeld/thneed/debug/decompiler/ir3.h new file mode 100644 index 0000000000..278dc96362 --- /dev/null +++ b/selfdrive/modeld/thneed/debug/decompiler/ir3.h @@ -0,0 +1,1755 @@ +/* + * Copyright (c) 2013 Rob Clark + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef IR3_H_ +#define IR3_H_ + +#include +#include + +#include "shader_enums.h" +#include "util/list.h" + +/*#include "util/bitscan.h" +#include "util/list.h" +#include "util/set.h" +#include "util/u_debug.h"*/ + +#include "instr-a3xx.h" + +/* low level intermediate representation of an adreno shader program */ + +struct ir3_compiler; +struct ir3; +struct ir3_instruction; +struct ir3_block; + +struct ir3_info { + uint32_t gpu_id; + uint16_t sizedwords; + uint16_t instrs_count; /* expanded to account for rpt's */ + uint16_t nops_count; /* # of nop instructions, including nopN */ + uint16_t mov_count; + uint16_t cov_count; + /* NOTE: max_reg, etc, does not include registers not touched + * by the shader (ie. vertex fetched via VFD_DECODE but not + * touched by shader) + */ + int8_t max_reg; /* highest GPR # used by shader */ + int8_t max_half_reg; + int16_t max_const; + + /* number of sync bits: */ + uint16_t ss, sy; + + /* estimate of number of cycles stalled on (ss) */ + uint16_t sstall; + + uint16_t last_baryf; /* instruction # of last varying fetch */ +}; + +struct ir3_register { + enum { + IR3_REG_CONST = 0x001, + IR3_REG_IMMED = 0x002, + IR3_REG_HALF = 0x004, + /* high registers are used for some things in compute shaders, + * for example. Seems to be for things that are global to all + * threads in a wave, so possibly these are global/shared by + * all the threads in the wave? + */ + IR3_REG_HIGH = 0x008, + IR3_REG_RELATIV= 0x010, + IR3_REG_R = 0x020, + /* Most instructions, it seems, can do float abs/neg but not + * integer. The CP pass needs to know what is intended (int or + * float) in order to do the right thing. For this reason the + * abs/neg flags are split out into float and int variants. In + * addition, .b (bitwise) operations, the negate is actually a + * bitwise not, so split that out into a new flag to make it + * more clear. + */ + IR3_REG_FNEG = 0x040, + IR3_REG_FABS = 0x080, + IR3_REG_SNEG = 0x100, + IR3_REG_SABS = 0x200, + IR3_REG_BNOT = 0x400, + IR3_REG_EVEN = 0x800, + IR3_REG_POS_INF= 0x1000, + /* (ei) flag, end-input? Set on last bary, presumably to signal + * that the shader needs no more input: + */ + IR3_REG_EI = 0x2000, + /* meta-flags, for intermediate stages of IR, ie. + * before register assignment is done: + */ + IR3_REG_SSA = 0x4000, /* 'instr' is ptr to assigning instr */ + IR3_REG_ARRAY = 0x8000, + + } flags; + + /* used for cat5 instructions, but also for internal/IR level + * tracking of what registers are read/written by an instruction. + * wrmask may be a bad name since it is used to represent both + * src and dst that touch multiple adjacent registers. + */ + unsigned wrmask : 16; /* up to vec16 */ + + /* for relative addressing, 32bits for array size is too small, + * but otoh we don't need to deal with disjoint sets, so instead + * use a simple size field (number of scalar components). + * + * Note the size field isn't important for relative const (since + * we don't have to do register allocation for constants). + */ + unsigned size : 15; + + bool merged : 1; /* half-regs conflict with full regs (ie >= a6xx) */ + + /* normal registers: + * the component is in the low two bits of the reg #, so + * rN.x becomes: (N << 2) | x + */ + uint16_t num; + union { + /* immediate: */ + int32_t iim_val; + uint32_t uim_val; + float fim_val; + /* relative: */ + struct { + uint16_t id; + int16_t offset; + } array; + }; + + /* For IR3_REG_SSA, src registers contain ptr back to assigning + * instruction. + * + * For IR3_REG_ARRAY, the pointer is back to the last dependent + * array access (although the net effect is the same, it points + * back to a previous instruction that we depend on). + */ + struct ir3_instruction *instr; +}; + +/* + * Stupid/simple growable array implementation: + */ +#define DECLARE_ARRAY(type, name) \ + unsigned name ## _count, name ## _sz; \ + type * name; + +#define array_insert(ctx, arr, val) do { \ + if (arr ## _count == arr ## _sz) { \ + arr ## _sz = MAX2(2 * arr ## _sz, 16); \ + arr = reralloc_size(ctx, arr, arr ## _sz * sizeof(arr[0])); \ + } \ + arr[arr ##_count++] = val; \ + } while (0) + +struct ir3_instruction { + struct ir3_block *block; + opc_t opc; + enum { + /* (sy) flag is set on first instruction, and after sample + * instructions (probably just on RAW hazard). + */ + IR3_INSTR_SY = 0x001, + /* (ss) flag is set on first instruction, and first instruction + * to depend on the result of "long" instructions (RAW hazard): + * + * rcp, rsq, log2, exp2, sin, cos, sqrt + * + * It seems to synchronize until all in-flight instructions are + * completed, for example: + * + * rsq hr1.w, hr1.w + * add.f hr2.z, (neg)hr2.z, hc0.y + * mul.f hr2.w, (neg)hr2.y, (neg)hr2.y + * rsq hr2.x, hr2.x + * (rpt1)nop + * mad.f16 hr2.w, hr2.z, hr2.z, hr2.w + * nop + * mad.f16 hr2.w, (neg)hr0.w, (neg)hr0.w, hr2.w + * (ss)(rpt2)mul.f hr1.x, (r)hr1.x, hr1.w + * (rpt2)mul.f hr0.x, (neg)(r)hr0.x, hr2.x + * + * The last mul.f does not have (ss) set, presumably because the + * (ss) on the previous instruction does the job. + * + * The blob driver also seems to set it on WAR hazards, although + * not really clear if this is needed or just blob compiler being + * sloppy. So far I haven't found a case where removing the (ss) + * causes problems for WAR hazard, but I could just be getting + * lucky: + * + * rcp r1.y, r3.y + * (ss)(rpt2)mad.f32 r3.y, (r)c9.x, r1.x, (r)r3.z + * + */ + IR3_INSTR_SS = 0x002, + /* (jp) flag is set on jump targets: + */ + IR3_INSTR_JP = 0x004, + IR3_INSTR_UL = 0x008, + IR3_INSTR_3D = 0x010, + IR3_INSTR_A = 0x020, + IR3_INSTR_O = 0x040, + IR3_INSTR_P = 0x080, + IR3_INSTR_S = 0x100, + IR3_INSTR_S2EN = 0x200, + IR3_INSTR_G = 0x400, + IR3_INSTR_SAT = 0x800, + /* (cat5/cat6) Bindless */ + IR3_INSTR_B = 0x1000, + /* (cat5-only) Get some parts of the encoding from a1.x */ + IR3_INSTR_A1EN = 0x2000, + /* meta-flags, for intermediate stages of IR, ie. + * before register assignment is done: + */ + IR3_INSTR_MARK = 0x4000, + IR3_INSTR_UNUSED= 0x8000, + } flags; + uint8_t repeat; + uint8_t nop; +#ifdef DEBUG + unsigned regs_max; +#endif + unsigned regs_count; + struct ir3_register **regs; + union { + struct { + char inv; + char comp; + int immed; + struct ir3_block *target; + } cat0; + struct { + type_t src_type, dst_type; + } cat1; + struct { + enum { + IR3_COND_LT = 0, + IR3_COND_LE = 1, + IR3_COND_GT = 2, + IR3_COND_GE = 3, + IR3_COND_EQ = 4, + IR3_COND_NE = 5, + } condition; + } cat2; + struct { + unsigned samp, tex; + unsigned tex_base : 3; + type_t type; + } cat5; + struct { + type_t type; + int src_offset; + int dst_offset; + int iim_val : 3; /* for ldgb/stgb, # of components */ + unsigned d : 3; /* for ldc, component offset */ + bool typed : 1; + unsigned base : 3; + } cat6; + struct { + unsigned w : 1; /* write */ + unsigned r : 1; /* read */ + unsigned l : 1; /* local */ + unsigned g : 1; /* global */ + } cat7; + /* for meta-instructions, just used to hold extra data + * before instruction scheduling, etc + */ + struct { + int off; /* component/offset */ + } split; + struct { + /* for output collects, this maps back to the entry in the + * ir3_shader_variant::outputs table. + */ + int outidx; + } collect; + struct { + unsigned samp, tex; + unsigned input_offset; + unsigned samp_base : 3; + unsigned tex_base : 3; + } prefetch; + struct { + /* maps back to entry in ir3_shader_variant::inputs table: */ + int inidx; + /* for sysvals, identifies the sysval type. Mostly so we can + * identify the special cases where a sysval should not be DCE'd + * (currently, just pre-fs texture fetch) + */ + gl_system_value sysval; + } input; + }; + + /* When we get to the RA stage, we need instruction's position/name: */ + uint16_t ip; + uint16_t name; + + /* used for per-pass extra instruction data. + * + * TODO we should remove the per-pass data like this and 'use_count' + * and do something similar to what RA does w/ ir3_ra_instr_data.. + * ie. use the ir3_count_instructions pass, and then use instr->ip + * to index into a table of pass-private data. + */ + void *data; + + /** + * Valid if pass calls ir3_find_ssa_uses().. see foreach_ssa_use() + */ + struct set *uses; + + int sun; /* Sethi–Ullman number, used by sched */ + int use_count; /* currently just updated/used by cp */ + + /* Used during CP and RA stages. For collect and shader inputs/ + * outputs where we need a sequence of consecutive registers, + * keep track of each src instructions left (ie 'n-1') and right + * (ie 'n+1') neighbor. The front-end must insert enough mov's + * to ensure that each instruction has at most one left and at + * most one right neighbor. During the copy-propagation pass, + * we only remove mov's when we can preserve this constraint. + * And during the RA stage, we use the neighbor information to + * allocate a block of registers in one shot. + * + * TODO: maybe just add something like: + * struct ir3_instruction_ref { + * struct ir3_instruction *instr; + * unsigned cnt; + * } + * + * Or can we get away without the refcnt stuff? It seems like + * it should be overkill.. the problem is if, potentially after + * already eliminating some mov's, if you have a single mov that + * needs to be grouped with it's neighbors in two different + * places (ex. shader output and a collect). + */ + struct { + struct ir3_instruction *left, *right; + uint16_t left_cnt, right_cnt; + } cp; + + /* an instruction can reference at most one address register amongst + * it's src/dst registers. Beyond that, you need to insert mov's. + * + * NOTE: do not write this directly, use ir3_instr_set_address() + */ + struct ir3_instruction *address; + + /* Tracking for additional dependent instructions. Used to handle + * barriers, WAR hazards for arrays/SSBOs/etc. + */ + DECLARE_ARRAY(struct ir3_instruction *, deps); + + /* + * From PoV of instruction scheduling, not execution (ie. ignores global/ + * local distinction): + * shared image atomic SSBO everything + * barrier()/ - R/W R/W R/W R/W X + * groupMemoryBarrier() + * memoryBarrier() - R/W R/W + * (but only images declared coherent?) + * memoryBarrierAtomic() - R/W + * memoryBarrierBuffer() - R/W + * memoryBarrierImage() - R/W + * memoryBarrierShared() - R/W + * + * TODO I think for SSBO/image/shared, in cases where we can determine + * which variable is accessed, we don't need to care about accesses to + * different variables (unless declared coherent??) + */ + enum { + IR3_BARRIER_EVERYTHING = 1 << 0, + IR3_BARRIER_SHARED_R = 1 << 1, + IR3_BARRIER_SHARED_W = 1 << 2, + IR3_BARRIER_IMAGE_R = 1 << 3, + IR3_BARRIER_IMAGE_W = 1 << 4, + IR3_BARRIER_BUFFER_R = 1 << 5, + IR3_BARRIER_BUFFER_W = 1 << 6, + IR3_BARRIER_ARRAY_R = 1 << 7, + IR3_BARRIER_ARRAY_W = 1 << 8, + } barrier_class, barrier_conflict; + + /* Entry in ir3_block's instruction list: */ + struct list_head node; + +#ifdef DEBUG + uint32_t serialno; +#endif + + // TODO only computerator/assembler: + int line; +}; + +static inline struct ir3_instruction * +ir3_neighbor_first(struct ir3_instruction *instr) +{ + int cnt = 0; + while (instr->cp.left) { + instr = instr->cp.left; + if (++cnt > 0xffff) { + debug_assert(0); + break; + } + } + return instr; +} + +static inline int ir3_neighbor_count(struct ir3_instruction *instr) +{ + int num = 1; + + debug_assert(!instr->cp.left); + + while (instr->cp.right) { + num++; + instr = instr->cp.right; + if (num > 0xffff) { + debug_assert(0); + break; + } + } + + return num; +} + +struct ir3 { + struct ir3_compiler *compiler; + gl_shader_stage type; + + DECLARE_ARRAY(struct ir3_instruction *, inputs); + DECLARE_ARRAY(struct ir3_instruction *, outputs); + + /* Track bary.f (and ldlv) instructions.. this is needed in + * scheduling to ensure that all varying fetches happen before + * any potential kill instructions. The hw gets grumpy if all + * threads in a group are killed before the last bary.f gets + * a chance to signal end of input (ei). + */ + DECLARE_ARRAY(struct ir3_instruction *, baryfs); + + /* Track all indirect instructions (read and write). To avoid + * deadlock scenario where an address register gets scheduled, + * but other dependent src instructions cannot be scheduled due + * to dependency on a *different* address register value, the + * scheduler needs to ensure that all dependencies other than + * the instruction other than the address register are scheduled + * before the one that writes the address register. Having a + * convenient list of instructions that reference some address + * register simplifies this. + */ + DECLARE_ARRAY(struct ir3_instruction *, a0_users); + + /* same for a1.x: */ + DECLARE_ARRAY(struct ir3_instruction *, a1_users); + + /* and same for instructions that consume predicate register: */ + DECLARE_ARRAY(struct ir3_instruction *, predicates); + + /* Track texture sample instructions which need texture state + * patched in (for astc-srgb workaround): + */ + DECLARE_ARRAY(struct ir3_instruction *, astc_srgb); + + /* List of blocks: */ + struct list_head block_list; + + /* List of ir3_array's: */ + struct list_head array_list; + + unsigned max_sun; /* max Sethi–Ullman number */ + +#ifdef DEBUG + unsigned block_count, instr_count; +#endif +}; + +struct ir3_array { + struct list_head node; + unsigned length; + unsigned id; + + struct nir_register *r; + + /* To avoid array write's from getting DCE'd, keep track of the + * most recent write. Any array access depends on the most + * recent write. This way, nothing depends on writes after the + * last read. But all the writes that happen before that have + * something depending on them + */ + struct ir3_instruction *last_write; + + /* extra stuff used in RA pass: */ + unsigned base; /* base vreg name */ + unsigned reg; /* base physical reg */ + uint16_t start_ip, end_ip; + + /* Indicates if half-precision */ + bool half; +}; + +struct ir3_array * ir3_lookup_array(struct ir3 *ir, unsigned id); + +struct ir3_block { + struct list_head node; + struct ir3 *shader; + + const struct nir_block *nblock; + + struct list_head instr_list; /* list of ir3_instruction */ + + /* each block has either one or two successors.. in case of + * two successors, 'condition' decides which one to follow. + * A block preceding an if/else has two successors. + */ + struct ir3_instruction *condition; + struct ir3_block *successors[2]; + + struct set *predecessors; /* set of ir3_block */ + + uint16_t start_ip, end_ip; + + /* Track instructions which do not write a register but other- + * wise must not be discarded (such as kill, stg, etc) + */ + DECLARE_ARRAY(struct ir3_instruction *, keeps); + + /* used for per-pass extra block data. Mainly used right + * now in RA step to track livein/liveout. + */ + void *data; + +#ifdef DEBUG + uint32_t serialno; +#endif +}; + +static inline uint32_t +block_id(struct ir3_block *block) +{ +#ifdef DEBUG + return block->serialno; +#else + return (uint32_t)(unsigned long)block; +#endif +} + +struct ir3 * ir3_create(struct ir3_compiler *compiler, gl_shader_stage type); +void ir3_destroy(struct ir3 *shader); +void * ir3_assemble(struct ir3 *shader, + struct ir3_info *info, uint32_t gpu_id); +void * ir3_alloc(struct ir3 *shader, int sz); + +struct ir3_block * ir3_block_create(struct ir3 *shader); + +struct ir3_instruction * ir3_instr_create(struct ir3_block *block, opc_t opc); +struct ir3_instruction * ir3_instr_create2(struct ir3_block *block, + opc_t opc, int nreg); +struct ir3_instruction * ir3_instr_clone(struct ir3_instruction *instr); +void ir3_instr_add_dep(struct ir3_instruction *instr, struct ir3_instruction *dep); +const char *ir3_instr_name(struct ir3_instruction *instr); + +struct ir3_register * ir3_reg_create(struct ir3_instruction *instr, + int num, int flags); +struct ir3_register * ir3_reg_clone(struct ir3 *shader, + struct ir3_register *reg); + +void ir3_instr_set_address(struct ir3_instruction *instr, + struct ir3_instruction *addr); + +static inline bool ir3_instr_check_mark(struct ir3_instruction *instr) +{ + if (instr->flags & IR3_INSTR_MARK) + return true; /* already visited */ + instr->flags |= IR3_INSTR_MARK; + return false; +} + +void ir3_block_clear_mark(struct ir3_block *block); +void ir3_clear_mark(struct ir3 *shader); + +unsigned ir3_count_instructions(struct ir3 *ir); +unsigned ir3_count_instructions_ra(struct ir3 *ir); + +void ir3_find_ssa_uses(struct ir3 *ir, void *mem_ctx, bool falsedeps); + +//#include "util/set.h" +#define foreach_ssa_use(__use, __instr) \ + for (struct ir3_instruction *__use = (void *)~0; \ + __use && (__instr)->uses; __use = NULL) \ + set_foreach ((__instr)->uses, __entry) \ + if ((__use = (void *)__entry->key)) + +#define MAX_ARRAYS 16 + +/* comp: + * 0 - x + * 1 - y + * 2 - z + * 3 - w + */ +static inline uint32_t regid(int num, int comp) +{ + return (num << 2) | (comp & 0x3); +} + +static inline uint32_t reg_num(struct ir3_register *reg) +{ + return reg->num >> 2; +} + +static inline uint32_t reg_comp(struct ir3_register *reg) +{ + return reg->num & 0x3; +} + +#define INVALID_REG regid(63, 0) +#define VALIDREG(r) ((r) != INVALID_REG) +#define CONDREG(r, val) COND(VALIDREG(r), (val)) + +static inline bool is_flow(struct ir3_instruction *instr) +{ + return (opc_cat(instr->opc) == 0); +} + +static inline bool is_kill(struct ir3_instruction *instr) +{ + return instr->opc == OPC_KILL; +} + +static inline bool is_nop(struct ir3_instruction *instr) +{ + return instr->opc == OPC_NOP; +} + +static inline bool is_same_type_reg(struct ir3_register *reg1, + struct ir3_register *reg2) +{ + unsigned type_reg1 = (reg1->flags & (IR3_REG_HIGH | IR3_REG_HALF)); + unsigned type_reg2 = (reg2->flags & (IR3_REG_HIGH | IR3_REG_HALF)); + + if (type_reg1 ^ type_reg2) + return false; + else + return true; +} + +/* Is it a non-transformative (ie. not type changing) mov? This can + * also include absneg.s/absneg.f, which for the most part can be + * treated as a mov (single src argument). + */ +static inline bool is_same_type_mov(struct ir3_instruction *instr) +{ + struct ir3_register *dst; + + switch (instr->opc) { + case OPC_MOV: + if (instr->cat1.src_type != instr->cat1.dst_type) + return false; + /* If the type of dest reg and src reg are different, + * it shouldn't be considered as same type mov + */ + if (!is_same_type_reg(instr->regs[0], instr->regs[1])) + return false; + break; + case OPC_ABSNEG_F: + case OPC_ABSNEG_S: + if (instr->flags & IR3_INSTR_SAT) + return false; + /* If the type of dest reg and src reg are different, + * it shouldn't be considered as same type mov + */ + if (!is_same_type_reg(instr->regs[0], instr->regs[1])) + return false; + break; + default: + return false; + } + + dst = instr->regs[0]; + + /* mov's that write to a0 or p0.x are special: */ + if (dst->num == regid(REG_P0, 0)) + return false; + if (reg_num(dst) == REG_A0) + return false; + + if (dst->flags & (IR3_REG_RELATIV | IR3_REG_ARRAY)) + return false; + + return true; +} + +/* A move from const, which changes size but not type, can also be + * folded into dest instruction in some cases. + */ +static inline bool is_const_mov(struct ir3_instruction *instr) +{ + if (instr->opc != OPC_MOV) + return false; + + if (!(instr->regs[1]->flags & IR3_REG_CONST)) + return false; + + type_t src_type = instr->cat1.src_type; + type_t dst_type = instr->cat1.dst_type; + + return (type_float(src_type) && type_float(dst_type)) || + (type_uint(src_type) && type_uint(dst_type)) || + (type_sint(src_type) && type_sint(dst_type)); +} + +static inline bool is_alu(struct ir3_instruction *instr) +{ + return (1 <= opc_cat(instr->opc)) && (opc_cat(instr->opc) <= 3); +} + +static inline bool is_sfu(struct ir3_instruction *instr) +{ + return (opc_cat(instr->opc) == 4); +} + +static inline bool is_tex(struct ir3_instruction *instr) +{ + return (opc_cat(instr->opc) == 5); +} + +static inline bool is_tex_or_prefetch(struct ir3_instruction *instr) +{ + return is_tex(instr) || (instr->opc == OPC_META_TEX_PREFETCH); +} + +static inline bool is_mem(struct ir3_instruction *instr) +{ + return (opc_cat(instr->opc) == 6); +} + +static inline bool is_barrier(struct ir3_instruction *instr) +{ + return (opc_cat(instr->opc) == 7); +} + +static inline bool +is_half(struct ir3_instruction *instr) +{ + return !!(instr->regs[0]->flags & IR3_REG_HALF); +} + +static inline bool +is_high(struct ir3_instruction *instr) +{ + return !!(instr->regs[0]->flags & IR3_REG_HIGH); +} + +static inline bool +is_store(struct ir3_instruction *instr) +{ + /* these instructions, the "destination" register is + * actually a source, the address to store to. + */ + switch (instr->opc) { + case OPC_STG: + case OPC_STGB: + case OPC_STIB: + case OPC_STP: + case OPC_STL: + case OPC_STLW: + case OPC_L2G: + case OPC_G2L: + return true; + default: + return false; + } +} + +static inline bool is_load(struct ir3_instruction *instr) +{ + switch (instr->opc) { + case OPC_LDG: + case OPC_LDGB: + case OPC_LDIB: + case OPC_LDL: + case OPC_LDP: + case OPC_L2G: + case OPC_LDLW: + case OPC_LDC: + case OPC_LDLV: + /* probably some others too.. */ + return true; + default: + return false; + } +} + +static inline bool is_input(struct ir3_instruction *instr) +{ + /* in some cases, ldlv is used to fetch varying without + * interpolation.. fortunately inloc is the first src + * register in either case + */ + switch (instr->opc) { + case OPC_LDLV: + case OPC_BARY_F: + return true; + default: + return false; + } +} + +static inline bool is_bool(struct ir3_instruction *instr) +{ + switch (instr->opc) { + case OPC_CMPS_F: + case OPC_CMPS_S: + case OPC_CMPS_U: + return true; + default: + return false; + } +} + +static inline bool is_meta(struct ir3_instruction *instr) +{ + return (opc_cat(instr->opc) == -1); +} + +static inline unsigned dest_regs(struct ir3_instruction *instr) +{ + if ((instr->regs_count == 0) || is_store(instr) || is_flow(instr)) + return 0; + + return util_last_bit(instr->regs[0]->wrmask); +} + +static inline bool +writes_gpr(struct ir3_instruction *instr) +{ + if (dest_regs(instr) == 0) + return false; + /* is dest a normal temp register: */ + struct ir3_register *reg = instr->regs[0]; + debug_assert(!(reg->flags & (IR3_REG_CONST | IR3_REG_IMMED))); + if ((reg_num(reg) == REG_A0) || + (reg->num == regid(REG_P0, 0))) + return false; + return true; +} + +static inline bool writes_addr0(struct ir3_instruction *instr) +{ + if (instr->regs_count > 0) { + struct ir3_register *dst = instr->regs[0]; + return dst->num == regid(REG_A0, 0); + } + return false; +} + +static inline bool writes_addr1(struct ir3_instruction *instr) +{ + if (instr->regs_count > 0) { + struct ir3_register *dst = instr->regs[0]; + return dst->num == regid(REG_A0, 1); + } + return false; +} + +static inline bool writes_pred(struct ir3_instruction *instr) +{ + if (instr->regs_count > 0) { + struct ir3_register *dst = instr->regs[0]; + return reg_num(dst) == REG_P0; + } + return false; +} + +/* returns defining instruction for reg */ +/* TODO better name */ +static inline struct ir3_instruction *ssa(struct ir3_register *reg) +{ + if (reg->flags & (IR3_REG_SSA | IR3_REG_ARRAY)) { + return reg->instr; + } + return NULL; +} + +static inline bool conflicts(struct ir3_instruction *a, + struct ir3_instruction *b) +{ + return (a && b) && (a != b); +} + +static inline bool reg_gpr(struct ir3_register *r) +{ + if (r->flags & (IR3_REG_CONST | IR3_REG_IMMED)) + return false; + if ((reg_num(r) == REG_A0) || (reg_num(r) == REG_P0)) + return false; + return true; +} + +static inline type_t half_type(type_t type) +{ + switch (type) { + case TYPE_F32: return TYPE_F16; + case TYPE_U32: return TYPE_U16; + case TYPE_S32: return TYPE_S16; + case TYPE_F16: + case TYPE_U16: + case TYPE_S16: + return type; + default: + assert(0); + return ~0; + } +} + +/* some cat2 instructions (ie. those which are not float) can embed an + * immediate: + */ +static inline bool ir3_cat2_int(opc_t opc) +{ + switch (opc) { + case OPC_ADD_U: + case OPC_ADD_S: + case OPC_SUB_U: + case OPC_SUB_S: + case OPC_CMPS_U: + case OPC_CMPS_S: + case OPC_MIN_U: + case OPC_MIN_S: + case OPC_MAX_U: + case OPC_MAX_S: + case OPC_CMPV_U: + case OPC_CMPV_S: + case OPC_MUL_U24: + case OPC_MUL_S24: + case OPC_MULL_U: + case OPC_CLZ_S: + case OPC_ABSNEG_S: + case OPC_AND_B: + case OPC_OR_B: + case OPC_NOT_B: + case OPC_XOR_B: + case OPC_BFREV_B: + case OPC_CLZ_B: + case OPC_SHL_B: + case OPC_SHR_B: + case OPC_ASHR_B: + case OPC_MGEN_B: + case OPC_GETBIT_B: + case OPC_CBITS_B: + case OPC_BARY_F: + return true; + + default: + return false; + } +} + +/* map cat2 instruction to valid abs/neg flags: */ +static inline unsigned ir3_cat2_absneg(opc_t opc) +{ + switch (opc) { + case OPC_ADD_F: + case OPC_MIN_F: + case OPC_MAX_F: + case OPC_MUL_F: + case OPC_SIGN_F: + case OPC_CMPS_F: + case OPC_ABSNEG_F: + case OPC_CMPV_F: + case OPC_FLOOR_F: + case OPC_CEIL_F: + case OPC_RNDNE_F: + case OPC_RNDAZ_F: + case OPC_TRUNC_F: + case OPC_BARY_F: + return IR3_REG_FABS | IR3_REG_FNEG; + + case OPC_ADD_U: + case OPC_ADD_S: + case OPC_SUB_U: + case OPC_SUB_S: + case OPC_CMPS_U: + case OPC_CMPS_S: + case OPC_MIN_U: + case OPC_MIN_S: + case OPC_MAX_U: + case OPC_MAX_S: + case OPC_CMPV_U: + case OPC_CMPV_S: + case OPC_MUL_U24: + case OPC_MUL_S24: + case OPC_MULL_U: + case OPC_CLZ_S: + return 0; + + case OPC_ABSNEG_S: + return IR3_REG_SABS | IR3_REG_SNEG; + + case OPC_AND_B: + case OPC_OR_B: + case OPC_NOT_B: + case OPC_XOR_B: + case OPC_BFREV_B: + case OPC_CLZ_B: + case OPC_SHL_B: + case OPC_SHR_B: + case OPC_ASHR_B: + case OPC_MGEN_B: + case OPC_GETBIT_B: + case OPC_CBITS_B: + return IR3_REG_BNOT; + + default: + return 0; + } +} + +/* map cat3 instructions to valid abs/neg flags: */ +static inline unsigned ir3_cat3_absneg(opc_t opc) +{ + switch (opc) { + case OPC_MAD_F16: + case OPC_MAD_F32: + case OPC_SEL_F16: + case OPC_SEL_F32: + return IR3_REG_FNEG; + + case OPC_MAD_U16: + case OPC_MADSH_U16: + case OPC_MAD_S16: + case OPC_MADSH_M16: + case OPC_MAD_U24: + case OPC_MAD_S24: + case OPC_SEL_S16: + case OPC_SEL_S32: + case OPC_SAD_S16: + case OPC_SAD_S32: + /* neg *may* work on 3rd src.. */ + + case OPC_SEL_B16: + case OPC_SEL_B32: + + default: + return 0; + } +} + +#define MASK(n) ((1 << (n)) - 1) + +/* iterator for an instructions's sources (reg), also returns src #: */ +#define foreach_src_n(__srcreg, __n, __instr) \ + if ((__instr)->regs_count) \ + for (unsigned __cnt = (__instr)->regs_count - 1, __n = 0; __n < __cnt; __n++) \ + if ((__srcreg = (__instr)->regs[__n + 1])) + +/* iterator for an instructions's sources (reg): */ +#define foreach_src(__srcreg, __instr) \ + foreach_src_n(__srcreg, __i, __instr) + +static inline unsigned __ssa_src_cnt(struct ir3_instruction *instr) +{ + unsigned cnt = instr->regs_count + instr->deps_count; + if (instr->address) + cnt++; + return cnt; +} + +static inline struct ir3_instruction ** +__ssa_srcp_n(struct ir3_instruction *instr, unsigned n) +{ + if (n == (instr->regs_count + instr->deps_count)) + return &instr->address; + if (n >= instr->regs_count) + return &instr->deps[n - instr->regs_count]; + if (ssa(instr->regs[n])) + return &instr->regs[n]->instr; + return NULL; +} + +static inline bool __is_false_dep(struct ir3_instruction *instr, unsigned n) +{ + if (n == (instr->regs_count + instr->deps_count)) + return false; + if (n >= instr->regs_count) + return true; + return false; +} + +#define foreach_ssa_srcp_n(__srcp, __n, __instr) \ + for (struct ir3_instruction **__srcp = (void *)~0; __srcp; __srcp = NULL) \ + for (unsigned __cnt = __ssa_src_cnt(__instr), __n = 0; __n < __cnt; __n++) \ + if ((__srcp = __ssa_srcp_n(__instr, __n))) + +#define foreach_ssa_srcp(__srcp, __instr) \ + foreach_ssa_srcp_n(__srcp, __i, __instr) + +/* iterator for an instruction's SSA sources (instr), also returns src #: */ +#define foreach_ssa_src_n(__srcinst, __n, __instr) \ + foreach_ssa_srcp_n(__srcp, __n, __instr) \ + if ((__srcinst = *__srcp)) + +/* iterator for an instruction's SSA sources (instr): */ +#define foreach_ssa_src(__srcinst, __instr) \ + foreach_ssa_src_n(__srcinst, __i, __instr) + +/* iterators for shader inputs: */ +#define foreach_input_n(__ininstr, __cnt, __ir) \ + for (unsigned __cnt = 0; __cnt < (__ir)->inputs_count; __cnt++) \ + if ((__ininstr = (__ir)->inputs[__cnt])) +#define foreach_input(__ininstr, __ir) \ + foreach_input_n(__ininstr, __i, __ir) + +/* iterators for shader outputs: */ +#define foreach_output_n(__outinstr, __cnt, __ir) \ + for (unsigned __cnt = 0; __cnt < (__ir)->outputs_count; __cnt++) \ + if ((__outinstr = (__ir)->outputs[__cnt])) +#define foreach_output(__outinstr, __ir) \ + foreach_output_n(__outinstr, __i, __ir) + +/* iterators for instructions: */ +#define foreach_instr(__instr, __list) \ + list_for_each_entry(struct ir3_instruction, __instr, __list, node) +#define foreach_instr_rev(__instr, __list) \ + list_for_each_entry_rev(struct ir3_instruction, __instr, __list, node) +#define foreach_instr_safe(__instr, __list) \ + list_for_each_entry_safe(struct ir3_instruction, __instr, __list, node) + +/* iterators for blocks: */ +#define foreach_block(__block, __list) \ + list_for_each_entry(struct ir3_block, __block, __list, node) +#define foreach_block_safe(__block, __list) \ + list_for_each_entry_safe(struct ir3_block, __block, __list, node) +#define foreach_block_rev(__block, __list) \ + list_for_each_entry_rev(struct ir3_block, __block, __list, node) + +/* iterators for arrays: */ +#define foreach_array(__array, __list) \ + list_for_each_entry(struct ir3_array, __array, __list, node) + +/* Check if condition is true for any src instruction. + */ +static inline bool +check_src_cond(struct ir3_instruction *instr, bool (*cond)(struct ir3_instruction *)) +{ + struct ir3_register *reg; + + /* Note that this is also used post-RA so skip the ssa iterator: */ + foreach_src (reg, instr) { + struct ir3_instruction *src = reg->instr; + + if (!src) + continue; + + /* meta:split/collect aren't real instructions, the thing that + * we actually care about is *their* srcs + */ + if ((src->opc == OPC_META_SPLIT) || (src->opc == OPC_META_COLLECT)) { + if (check_src_cond(src, cond)) + return true; + } else { + if (cond(src)) + return true; + } + } + + return false; +} + +/* dump: */ +void ir3_print(struct ir3 *ir); +void ir3_print_instr(struct ir3_instruction *instr); + +/* delay calculation: */ +int ir3_delayslots(struct ir3_instruction *assigner, + struct ir3_instruction *consumer, unsigned n, bool soft); +unsigned ir3_delay_calc(struct ir3_block *block, struct ir3_instruction *instr, + bool soft, bool pred); +void ir3_remove_nops(struct ir3 *ir); + +/* dead code elimination: */ +struct ir3_shader_variant; +void ir3_dce(struct ir3 *ir, struct ir3_shader_variant *so); + +/* fp16 conversion folding */ +void ir3_cf(struct ir3 *ir); + +/* copy-propagate: */ +void ir3_cp(struct ir3 *ir, struct ir3_shader_variant *so); + +/* group neighbors and insert mov's to resolve conflicts: */ +void ir3_group(struct ir3 *ir); + +/* Sethi–Ullman numbering: */ +void ir3_sun(struct ir3 *ir); + +/* scheduling: */ +void ir3_sched_add_deps(struct ir3 *ir); +int ir3_sched(struct ir3 *ir); + +struct ir3_context; +int ir3_postsched(struct ir3_context *ctx); + +bool ir3_a6xx_fixup_atomic_dests(struct ir3 *ir, struct ir3_shader_variant *so); + +/* register assignment: */ +struct ir3_ra_reg_set * ir3_ra_alloc_reg_set(struct ir3_compiler *compiler); +int ir3_ra(struct ir3_shader_variant *v, struct ir3_instruction **precolor, unsigned nprecolor); + +/* legalize: */ +void ir3_legalize(struct ir3 *ir, struct ir3_shader_variant *so, int *max_bary); + +static inline bool +ir3_has_latency_to_hide(struct ir3 *ir) +{ + /* VS/GS/TCS/TESS co-exist with frag shader invocations, but we don't + * know the nature of the fragment shader. Just assume it will have + * latency to hide: + */ + if (ir->type != MESA_SHADER_FRAGMENT) + return true; + + foreach_block (block, &ir->block_list) { + foreach_instr (instr, &block->instr_list) { + if (is_tex_or_prefetch(instr)) + return true; + + if (is_load(instr)) { + switch (instr->opc) { + case OPC_LDLV: + case OPC_LDL: + case OPC_LDLW: + break; + default: + return true; + } + } + } + } + + return false; +} + +/* ************************************************************************* */ +/* instruction helpers */ + +/* creates SSA src of correct type (ie. half vs full precision) */ +static inline struct ir3_register * __ssa_src(struct ir3_instruction *instr, + struct ir3_instruction *src, unsigned flags) +{ + struct ir3_register *reg; + if (src->regs[0]->flags & IR3_REG_HALF) + flags |= IR3_REG_HALF; + reg = ir3_reg_create(instr, 0, IR3_REG_SSA | flags); + reg->instr = src; + reg->wrmask = src->regs[0]->wrmask; + return reg; +} + +static inline struct ir3_register * __ssa_dst(struct ir3_instruction *instr) +{ + struct ir3_register *reg = ir3_reg_create(instr, 0, 0); + reg->flags |= IR3_REG_SSA; + return reg; +} + +static inline struct ir3_instruction * +create_immed_typed(struct ir3_block *block, uint32_t val, type_t type) +{ + struct ir3_instruction *mov; + unsigned flags = (type_size(type) < 32) ? IR3_REG_HALF : 0; + + mov = ir3_instr_create(block, OPC_MOV); + mov->cat1.src_type = type; + mov->cat1.dst_type = type; + __ssa_dst(mov)->flags |= flags; + ir3_reg_create(mov, 0, IR3_REG_IMMED | flags)->uim_val = val; + + return mov; +} + +static inline struct ir3_instruction * +create_immed(struct ir3_block *block, uint32_t val) +{ + return create_immed_typed(block, val, TYPE_U32); +} + +static inline struct ir3_instruction * +create_uniform_typed(struct ir3_block *block, unsigned n, type_t type) +{ + struct ir3_instruction *mov; + unsigned flags = (type_size(type) < 32) ? IR3_REG_HALF : 0; + + mov = ir3_instr_create(block, OPC_MOV); + mov->cat1.src_type = type; + mov->cat1.dst_type = type; + __ssa_dst(mov)->flags |= flags; + ir3_reg_create(mov, n, IR3_REG_CONST | flags); + + return mov; +} + +static inline struct ir3_instruction * +create_uniform(struct ir3_block *block, unsigned n) +{ + return create_uniform_typed(block, n, TYPE_F32); +} + +static inline struct ir3_instruction * +create_uniform_indirect(struct ir3_block *block, int n, + struct ir3_instruction *address) +{ + struct ir3_instruction *mov; + + mov = ir3_instr_create(block, OPC_MOV); + mov->cat1.src_type = TYPE_U32; + mov->cat1.dst_type = TYPE_U32; + __ssa_dst(mov); + ir3_reg_create(mov, 0, IR3_REG_CONST | IR3_REG_RELATIV)->array.offset = n; + + ir3_instr_set_address(mov, address); + + return mov; +} + +static inline struct ir3_instruction * +ir3_MOV(struct ir3_block *block, struct ir3_instruction *src, type_t type) +{ + struct ir3_instruction *instr = ir3_instr_create(block, OPC_MOV); + __ssa_dst(instr); + if (src->regs[0]->flags & IR3_REG_ARRAY) { + struct ir3_register *src_reg = __ssa_src(instr, src, IR3_REG_ARRAY); + src_reg->array = src->regs[0]->array; + } else { + __ssa_src(instr, src, src->regs[0]->flags & IR3_REG_HIGH); + } + debug_assert(!(src->regs[0]->flags & IR3_REG_RELATIV)); + instr->cat1.src_type = type; + instr->cat1.dst_type = type; + return instr; +} + +static inline struct ir3_instruction * +ir3_COV(struct ir3_block *block, struct ir3_instruction *src, + type_t src_type, type_t dst_type) +{ + struct ir3_instruction *instr = ir3_instr_create(block, OPC_MOV); + unsigned dst_flags = (type_size(dst_type) < 32) ? IR3_REG_HALF : 0; + unsigned src_flags = (type_size(src_type) < 32) ? IR3_REG_HALF : 0; + + debug_assert((src->regs[0]->flags & IR3_REG_HALF) == src_flags); + + __ssa_dst(instr)->flags |= dst_flags; + __ssa_src(instr, src, 0); + instr->cat1.src_type = src_type; + instr->cat1.dst_type = dst_type; + debug_assert(!(src->regs[0]->flags & IR3_REG_ARRAY)); + return instr; +} + +static inline struct ir3_instruction * +ir3_NOP(struct ir3_block *block) +{ + return ir3_instr_create(block, OPC_NOP); +} + +#define IR3_INSTR_0 0 + +#define __INSTR0(flag, name, opc) \ +static inline struct ir3_instruction * \ +ir3_##name(struct ir3_block *block) \ +{ \ + struct ir3_instruction *instr = \ + ir3_instr_create(block, opc); \ + instr->flags |= flag; \ + return instr; \ +} +#define INSTR0F(f, name) __INSTR0(IR3_INSTR_##f, name##_##f, OPC_##name) +#define INSTR0(name) __INSTR0(0, name, OPC_##name) + +#define __INSTR1(flag, name, opc) \ +static inline struct ir3_instruction * \ +ir3_##name(struct ir3_block *block, \ + struct ir3_instruction *a, unsigned aflags) \ +{ \ + struct ir3_instruction *instr = \ + ir3_instr_create(block, opc); \ + __ssa_dst(instr); \ + __ssa_src(instr, a, aflags); \ + instr->flags |= flag; \ + return instr; \ +} +#define INSTR1F(f, name) __INSTR1(IR3_INSTR_##f, name##_##f, OPC_##name) +#define INSTR1(name) __INSTR1(0, name, OPC_##name) + +#define __INSTR2(flag, name, opc) \ +static inline struct ir3_instruction * \ +ir3_##name(struct ir3_block *block, \ + struct ir3_instruction *a, unsigned aflags, \ + struct ir3_instruction *b, unsigned bflags) \ +{ \ + struct ir3_instruction *instr = \ + ir3_instr_create(block, opc); \ + __ssa_dst(instr); \ + __ssa_src(instr, a, aflags); \ + __ssa_src(instr, b, bflags); \ + instr->flags |= flag; \ + return instr; \ +} +#define INSTR2F(f, name) __INSTR2(IR3_INSTR_##f, name##_##f, OPC_##name) +#define INSTR2(name) __INSTR2(0, name, OPC_##name) + +#define __INSTR3(flag, name, opc) \ +static inline struct ir3_instruction * \ +ir3_##name(struct ir3_block *block, \ + struct ir3_instruction *a, unsigned aflags, \ + struct ir3_instruction *b, unsigned bflags, \ + struct ir3_instruction *c, unsigned cflags) \ +{ \ + struct ir3_instruction *instr = \ + ir3_instr_create2(block, opc, 4); \ + __ssa_dst(instr); \ + __ssa_src(instr, a, aflags); \ + __ssa_src(instr, b, bflags); \ + __ssa_src(instr, c, cflags); \ + instr->flags |= flag; \ + return instr; \ +} +#define INSTR3F(f, name) __INSTR3(IR3_INSTR_##f, name##_##f, OPC_##name) +#define INSTR3(name) __INSTR3(0, name, OPC_##name) + +#define __INSTR4(flag, name, opc) \ +static inline struct ir3_instruction * \ +ir3_##name(struct ir3_block *block, \ + struct ir3_instruction *a, unsigned aflags, \ + struct ir3_instruction *b, unsigned bflags, \ + struct ir3_instruction *c, unsigned cflags, \ + struct ir3_instruction *d, unsigned dflags) \ +{ \ + struct ir3_instruction *instr = \ + ir3_instr_create2(block, opc, 5); \ + __ssa_dst(instr); \ + __ssa_src(instr, a, aflags); \ + __ssa_src(instr, b, bflags); \ + __ssa_src(instr, c, cflags); \ + __ssa_src(instr, d, dflags); \ + instr->flags |= flag; \ + return instr; \ +} +#define INSTR4F(f, name) __INSTR4(IR3_INSTR_##f, name##_##f, OPC_##name) +#define INSTR4(name) __INSTR4(0, name, OPC_##name) + +/* cat0 instructions: */ +INSTR1(B) +INSTR0(JUMP) +INSTR1(KILL) +INSTR0(END) +INSTR0(CHSH) +INSTR0(CHMASK) +INSTR1(PREDT) +INSTR0(PREDF) +INSTR0(PREDE) + +/* cat2 instructions, most 2 src but some 1 src: */ +INSTR2(ADD_F) +INSTR2(MIN_F) +INSTR2(MAX_F) +INSTR2(MUL_F) +INSTR1(SIGN_F) +INSTR2(CMPS_F) +INSTR1(ABSNEG_F) +INSTR2(CMPV_F) +INSTR1(FLOOR_F) +INSTR1(CEIL_F) +INSTR1(RNDNE_F) +INSTR1(RNDAZ_F) +INSTR1(TRUNC_F) +INSTR2(ADD_U) +INSTR2(ADD_S) +INSTR2(SUB_U) +INSTR2(SUB_S) +INSTR2(CMPS_U) +INSTR2(CMPS_S) +INSTR2(MIN_U) +INSTR2(MIN_S) +INSTR2(MAX_U) +INSTR2(MAX_S) +INSTR1(ABSNEG_S) +INSTR2(AND_B) +INSTR2(OR_B) +INSTR1(NOT_B) +INSTR2(XOR_B) +INSTR2(CMPV_U) +INSTR2(CMPV_S) +INSTR2(MUL_U24) +INSTR2(MUL_S24) +INSTR2(MULL_U) +INSTR1(BFREV_B) +INSTR1(CLZ_S) +INSTR1(CLZ_B) +INSTR2(SHL_B) +INSTR2(SHR_B) +INSTR2(ASHR_B) +INSTR2(BARY_F) +INSTR2(MGEN_B) +INSTR2(GETBIT_B) +INSTR1(SETRM) +INSTR1(CBITS_B) +INSTR2(SHB) +INSTR2(MSAD) + +/* cat3 instructions: */ +INSTR3(MAD_U16) +INSTR3(MADSH_U16) +INSTR3(MAD_S16) +INSTR3(MADSH_M16) +INSTR3(MAD_U24) +INSTR3(MAD_S24) +INSTR3(MAD_F16) +INSTR3(MAD_F32) +/* NOTE: SEL_B32 checks for zero vs nonzero */ +INSTR3(SEL_B16) +INSTR3(SEL_B32) +INSTR3(SEL_S16) +INSTR3(SEL_S32) +INSTR3(SEL_F16) +INSTR3(SEL_F32) +INSTR3(SAD_S16) +INSTR3(SAD_S32) + +/* cat4 instructions: */ +INSTR1(RCP) +INSTR1(RSQ) +INSTR1(HRSQ) +INSTR1(LOG2) +INSTR1(HLOG2) +INSTR1(EXP2) +INSTR1(HEXP2) +INSTR1(SIN) +INSTR1(COS) +INSTR1(SQRT) + +/* cat5 instructions: */ +INSTR1(DSX) +INSTR1(DSXPP_1) +INSTR1(DSY) +INSTR1(DSYPP_1) +INSTR1F(3D, DSX) +INSTR1F(3D, DSY) +INSTR1(RGETPOS) + +static inline struct ir3_instruction * +ir3_SAM(struct ir3_block *block, opc_t opc, type_t type, + unsigned wrmask, unsigned flags, struct ir3_instruction *samp_tex, + struct ir3_instruction *src0, struct ir3_instruction *src1) +{ + struct ir3_instruction *sam; + + sam = ir3_instr_create(block, opc); + sam->flags |= flags; + __ssa_dst(sam)->wrmask = wrmask; + if (flags & IR3_INSTR_S2EN) { + __ssa_src(sam, samp_tex, IR3_REG_HALF); + } + if (src0) { + __ssa_src(sam, src0, 0); + } + if (src1) { + __ssa_src(sam, src1, 0); + } + sam->cat5.type = type; + + return sam; +} + +/* cat6 instructions: */ +INSTR2(LDLV) +INSTR3(LDG) +INSTR3(LDL) +INSTR3(LDLW) +INSTR3(STG) +INSTR3(STL) +INSTR3(STLW) +INSTR1(RESINFO) +INSTR1(RESFMT) +INSTR2(ATOMIC_ADD) +INSTR2(ATOMIC_SUB) +INSTR2(ATOMIC_XCHG) +INSTR2(ATOMIC_INC) +INSTR2(ATOMIC_DEC) +INSTR2(ATOMIC_CMPXCHG) +INSTR2(ATOMIC_MIN) +INSTR2(ATOMIC_MAX) +INSTR2(ATOMIC_AND) +INSTR2(ATOMIC_OR) +INSTR2(ATOMIC_XOR) +INSTR2(LDC) +#if GPU >= 600 +INSTR3(STIB); +INSTR2(LDIB); +INSTR3F(G, ATOMIC_ADD) +INSTR3F(G, ATOMIC_SUB) +INSTR3F(G, ATOMIC_XCHG) +INSTR3F(G, ATOMIC_INC) +INSTR3F(G, ATOMIC_DEC) +INSTR3F(G, ATOMIC_CMPXCHG) +INSTR3F(G, ATOMIC_MIN) +INSTR3F(G, ATOMIC_MAX) +INSTR3F(G, ATOMIC_AND) +INSTR3F(G, ATOMIC_OR) +INSTR3F(G, ATOMIC_XOR) +#elif GPU >= 400 +INSTR3(LDGB) +INSTR4(STGB) +INSTR4(STIB) +INSTR4F(G, ATOMIC_ADD) +INSTR4F(G, ATOMIC_SUB) +INSTR4F(G, ATOMIC_XCHG) +INSTR4F(G, ATOMIC_INC) +INSTR4F(G, ATOMIC_DEC) +INSTR4F(G, ATOMIC_CMPXCHG) +INSTR4F(G, ATOMIC_MIN) +INSTR4F(G, ATOMIC_MAX) +INSTR4F(G, ATOMIC_AND) +INSTR4F(G, ATOMIC_OR) +INSTR4F(G, ATOMIC_XOR) +#endif + +INSTR4F(G, STG) + +/* cat7 instructions: */ +INSTR0(BAR) +INSTR0(FENCE) + +/* meta instructions: */ +INSTR0(META_TEX_PREFETCH); + +/* ************************************************************************* */ +/* split this out or find some helper to use.. like main/bitset.h.. */ + +#include +#include "util/bitset.h" + +#define MAX_REG 256 + +typedef BITSET_DECLARE(regmask_t, 2 * MAX_REG); + +static inline bool +__regmask_get(regmask_t *regmask, struct ir3_register *reg, unsigned n) +{ + if (reg->merged) { + /* a6xx+ case, with merged register file, we track things in terms + * of half-precision registers, with a full precisions register + * using two half-precision slots: + */ + if (reg->flags & IR3_REG_HALF) { + return BITSET_TEST(*regmask, n); + } else { + n *= 2; + return BITSET_TEST(*regmask, n) || BITSET_TEST(*regmask, n+1); + } + } else { + /* pre a6xx case, with separate register file for half and full + * precision: + */ + if (reg->flags & IR3_REG_HALF) + n += MAX_REG; + return BITSET_TEST(*regmask, n); + } +} + +static inline void +__regmask_set(regmask_t *regmask, struct ir3_register *reg, unsigned n) +{ + if (reg->merged) { + /* a6xx+ case, with merged register file, we track things in terms + * of half-precision registers, with a full precisions register + * using two half-precision slots: + */ + if (reg->flags & IR3_REG_HALF) { + BITSET_SET(*regmask, n); + } else { + n *= 2; + BITSET_SET(*regmask, n); + BITSET_SET(*regmask, n+1); + } + } else { + /* pre a6xx case, with separate register file for half and full + * precision: + */ + if (reg->flags & IR3_REG_HALF) + n += MAX_REG; + BITSET_SET(*regmask, n); + } +} + +static inline void regmask_init(regmask_t *regmask) +{ + memset(regmask, 0, sizeof(*regmask)); +} + +static inline void regmask_set(regmask_t *regmask, struct ir3_register *reg) +{ + if (reg->flags & IR3_REG_RELATIV) { + for (unsigned i = 0; i < reg->size; i++) + __regmask_set(regmask, reg, reg->array.offset + i); + } else { + for (unsigned mask = reg->wrmask, n = reg->num; mask; mask >>= 1, n++) + if (mask & 1) + __regmask_set(regmask, reg, n); + } +} + +static inline void regmask_or(regmask_t *dst, regmask_t *a, regmask_t *b) +{ + unsigned i; + for (i = 0; i < ARRAY_SIZE(*dst); i++) + (*dst)[i] = (*a)[i] | (*b)[i]; +} + +static inline bool regmask_get(regmask_t *regmask, + struct ir3_register *reg) +{ + if (reg->flags & IR3_REG_RELATIV) { + for (unsigned i = 0; i < reg->size; i++) + if (__regmask_get(regmask, reg, reg->array.offset + i)) + return true; + } else { + for (unsigned mask = reg->wrmask, n = reg->num; mask; mask >>= 1, n++) + if (mask & 1) + if (__regmask_get(regmask, reg, n)) + return true; + } + return false; +} + +/* ************************************************************************* */ + +#endif /* IR3_H_ */ diff --git a/selfdrive/modeld/thneed/debug/decompiler/shader_enums.h b/selfdrive/modeld/thneed/debug/decompiler/shader_enums.h new file mode 100644 index 0000000000..b33a91727a --- /dev/null +++ b/selfdrive/modeld/thneed/debug/decompiler/shader_enums.h @@ -0,0 +1,906 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SHADER_ENUMS_H +#define SHADER_ENUMS_H + +#include + +/* Project-wide (GL and Vulkan) maximum. */ +#define MAX_DRAW_BUFFERS 8 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Shader stages. + * + * The order must match how shaders are ordered in the pipeline. + * The GLSL linker assumes that if i is the maximum number of + * invocations in a sub-group. The maximum + * supported in this extension is 64." + * + * The spec defines this as a uniform. However, it's highly unlikely that + * implementations actually treat it as a uniform (which is loaded from a + * constant buffer). Most likely, this is an implementation-wide constant, + * or perhaps something that depends on the shader stage. + */ + SYSTEM_VALUE_SUBGROUP_SIZE, + + /** + * From the GL_ARB_shader_ballot spec: + * + * "The variable holds the index of the + * invocation within sub-group. This variable is in the range 0 to + * -1, where is the total + * number of invocations in a sub-group." + */ + SYSTEM_VALUE_SUBGROUP_INVOCATION, + + /** + * From the GL_ARB_shader_ballot spec: + * + * "The variables provide a bitmask for all + * invocations, with one bit per invocation starting with the least + * significant bit, according to the following table, + * + * variable equation for bit values + * -------------------- ------------------------------------ + * gl_SubGroupEqMaskARB bit index == gl_SubGroupInvocationARB + * gl_SubGroupGeMaskARB bit index >= gl_SubGroupInvocationARB + * gl_SubGroupGtMaskARB bit index > gl_SubGroupInvocationARB + * gl_SubGroupLeMaskARB bit index <= gl_SubGroupInvocationARB + * gl_SubGroupLtMaskARB bit index < gl_SubGroupInvocationARB + */ + SYSTEM_VALUE_SUBGROUP_EQ_MASK, + SYSTEM_VALUE_SUBGROUP_GE_MASK, + SYSTEM_VALUE_SUBGROUP_GT_MASK, + SYSTEM_VALUE_SUBGROUP_LE_MASK, + SYSTEM_VALUE_SUBGROUP_LT_MASK, + /*@}*/ + + /** + * Builtin variables added by VK_KHR_subgroups + */ + /*@{*/ + SYSTEM_VALUE_NUM_SUBGROUPS, + SYSTEM_VALUE_SUBGROUP_ID, + /*@}*/ + + /*@}*/ + + /** + * \name Vertex shader system values + */ + /*@{*/ + /** + * OpenGL-style vertex ID. + * + * Section 2.11.7 (Shader Execution), subsection Shader Inputs, of the + * OpenGL 3.3 core profile spec says: + * + * "gl_VertexID holds the integer index i implicitly passed by + * DrawArrays or one of the other drawing commands defined in section + * 2.8.3." + * + * Section 2.8.3 (Drawing Commands) of the same spec says: + * + * "The commands....are equivalent to the commands with the same base + * name (without the BaseVertex suffix), except that the ith element + * transferred by the corresponding draw call will be taken from + * element indices[i] + basevertex of each enabled array." + * + * Additionally, the overview in the GL_ARB_shader_draw_parameters spec + * says: + * + * "In unextended GL, vertex shaders have inputs named gl_VertexID and + * gl_InstanceID, which contain, respectively the index of the vertex + * and instance. The value of gl_VertexID is the implicitly passed + * index of the vertex being processed, which includes the value of + * baseVertex, for those commands that accept it." + * + * gl_VertexID gets basevertex added in. This differs from DirectX where + * SV_VertexID does \b not get basevertex added in. + * + * \note + * If all system values are available, \c SYSTEM_VALUE_VERTEX_ID will be + * equal to \c SYSTEM_VALUE_VERTEX_ID_ZERO_BASE plus + * \c SYSTEM_VALUE_BASE_VERTEX. + * + * \sa SYSTEM_VALUE_VERTEX_ID_ZERO_BASE, SYSTEM_VALUE_BASE_VERTEX + */ + SYSTEM_VALUE_VERTEX_ID, + + /** + * Instanced ID as supplied to gl_InstanceID + * + * Values assigned to gl_InstanceID always begin with zero, regardless of + * the value of baseinstance. + * + * Section 11.1.3.9 (Shader Inputs) of the OpenGL 4.4 core profile spec + * says: + * + * "gl_InstanceID holds the integer instance number of the current + * primitive in an instanced draw call (see section 10.5)." + * + * Through a big chain of pseudocode, section 10.5 describes that + * baseinstance is not counted by gl_InstanceID. In that section, notice + * + * "If an enabled vertex attribute array is instanced (it has a + * non-zero divisor as specified by VertexAttribDivisor), the element + * index that is transferred to the GL, for all vertices, is given by + * + * floor(instance/divisor) + baseinstance + * + * If an array corresponding to an attribute required by a vertex + * shader is not enabled, then the corresponding element is taken from + * the current attribute state (see section 10.2)." + * + * Note that baseinstance is \b not included in the value of instance. + */ + SYSTEM_VALUE_INSTANCE_ID, + + /** + * Vulkan InstanceIndex. + * + * InstanceIndex = gl_InstanceID + gl_BaseInstance + */ + SYSTEM_VALUE_INSTANCE_INDEX, + + /** + * DirectX-style vertex ID. + * + * Unlike \c SYSTEM_VALUE_VERTEX_ID, this system value does \b not include + * the value of basevertex. + * + * \sa SYSTEM_VALUE_VERTEX_ID, SYSTEM_VALUE_BASE_VERTEX + */ + SYSTEM_VALUE_VERTEX_ID_ZERO_BASE, + + /** + * Value of \c basevertex passed to \c glDrawElementsBaseVertex and similar + * functions. + * + * \sa SYSTEM_VALUE_VERTEX_ID, SYSTEM_VALUE_VERTEX_ID_ZERO_BASE + */ + SYSTEM_VALUE_BASE_VERTEX, + + /** + * Depending on the type of the draw call (indexed or non-indexed), + * is the value of \c basevertex passed to \c glDrawElementsBaseVertex and + * similar, or is the value of \c first passed to \c glDrawArrays and + * similar. + * + * \note + * It can be used to calculate the \c SYSTEM_VALUE_VERTEX_ID as + * \c SYSTEM_VALUE_VERTEX_ID_ZERO_BASE plus \c SYSTEM_VALUE_FIRST_VERTEX. + * + * \sa SYSTEM_VALUE_VERTEX_ID_ZERO_BASE, SYSTEM_VALUE_VERTEX_ID + */ + SYSTEM_VALUE_FIRST_VERTEX, + + /** + * If the Draw command used to start the rendering was an indexed draw + * or not (~0/0). Useful to calculate \c SYSTEM_VALUE_BASE_VERTEX as + * \c SYSTEM_VALUE_IS_INDEXED_DRAW & \c SYSTEM_VALUE_FIRST_VERTEX. + */ + SYSTEM_VALUE_IS_INDEXED_DRAW, + + /** + * Value of \c baseinstance passed to instanced draw entry points + * + * \sa SYSTEM_VALUE_INSTANCE_ID + */ + SYSTEM_VALUE_BASE_INSTANCE, + + /** + * From _ARB_shader_draw_parameters: + * + * "Additionally, this extension adds a further built-in variable, + * gl_DrawID to the shading language. This variable contains the index + * of the draw currently being processed by a Multi* variant of a + * drawing command (such as MultiDrawElements or + * MultiDrawArraysIndirect)." + * + * If GL_ARB_multi_draw_indirect is not supported, this is always 0. + */ + SYSTEM_VALUE_DRAW_ID, + /*@}*/ + + /** + * \name Geometry shader system values + */ + /*@{*/ + SYSTEM_VALUE_INVOCATION_ID, /**< (Also in Tessellation Control shader) */ + /*@}*/ + + /** + * \name Fragment shader system values + */ + /*@{*/ + SYSTEM_VALUE_FRAG_COORD, + SYSTEM_VALUE_POINT_COORD, + SYSTEM_VALUE_FRONT_FACE, + SYSTEM_VALUE_SAMPLE_ID, + SYSTEM_VALUE_SAMPLE_POS, + SYSTEM_VALUE_SAMPLE_MASK_IN, + SYSTEM_VALUE_HELPER_INVOCATION, + SYSTEM_VALUE_COLOR0, + SYSTEM_VALUE_COLOR1, + /*@}*/ + + /** + * \name Tessellation Evaluation shader system values + */ + /*@{*/ + SYSTEM_VALUE_TESS_COORD, + SYSTEM_VALUE_VERTICES_IN, /**< Tessellation vertices in input patch */ + SYSTEM_VALUE_PRIMITIVE_ID, + SYSTEM_VALUE_TESS_LEVEL_OUTER, /**< TES input */ + SYSTEM_VALUE_TESS_LEVEL_INNER, /**< TES input */ + SYSTEM_VALUE_TESS_LEVEL_OUTER_DEFAULT, /**< TCS input for passthru TCS */ + SYSTEM_VALUE_TESS_LEVEL_INNER_DEFAULT, /**< TCS input for passthru TCS */ + /*@}*/ + + /** + * \name Compute shader system values + */ + /*@{*/ + SYSTEM_VALUE_LOCAL_INVOCATION_ID, + SYSTEM_VALUE_LOCAL_INVOCATION_INDEX, + SYSTEM_VALUE_GLOBAL_INVOCATION_ID, + SYSTEM_VALUE_GLOBAL_INVOCATION_INDEX, + SYSTEM_VALUE_WORK_GROUP_ID, + SYSTEM_VALUE_NUM_WORK_GROUPS, + SYSTEM_VALUE_LOCAL_GROUP_SIZE, + SYSTEM_VALUE_GLOBAL_GROUP_SIZE, + SYSTEM_VALUE_WORK_DIM, + SYSTEM_VALUE_USER_DATA_AMD, + /*@}*/ + + /** Required for VK_KHR_device_group */ + SYSTEM_VALUE_DEVICE_INDEX, + + /** Required for VK_KHX_multiview */ + SYSTEM_VALUE_VIEW_INDEX, + + /** + * Driver internal vertex-count, used (for example) for drivers to + * calculate stride for stream-out outputs. Not externally visible. + */ + SYSTEM_VALUE_VERTEX_CNT, + + /** + * Required for AMD_shader_explicit_vertex_parameter and also used for + * varying-fetch instructions. + * + * The _SIZE value is "primitive size", used to scale i/j in primitive + * space to pixel space. + */ + SYSTEM_VALUE_BARYCENTRIC_PERSP_PIXEL, + SYSTEM_VALUE_BARYCENTRIC_PERSP_SAMPLE, + SYSTEM_VALUE_BARYCENTRIC_PERSP_CENTROID, + SYSTEM_VALUE_BARYCENTRIC_PERSP_SIZE, + SYSTEM_VALUE_BARYCENTRIC_LINEAR_PIXEL, + SYSTEM_VALUE_BARYCENTRIC_LINEAR_CENTROID, + SYSTEM_VALUE_BARYCENTRIC_LINEAR_SAMPLE, + SYSTEM_VALUE_BARYCENTRIC_PULL_MODEL, + + /** + * IR3 specific geometry shader and tesselation control shader system + * values that packs invocation id, thread id and vertex id. Having this + * as a nir level system value lets us do the unpacking in nir. + */ + SYSTEM_VALUE_GS_HEADER_IR3, + SYSTEM_VALUE_TCS_HEADER_IR3, + + SYSTEM_VALUE_MAX /**< Number of values */ +} gl_system_value; + +const char *gl_system_value_name(gl_system_value sysval); + +/** + * The possible interpolation qualifiers that can be applied to a fragment + * shader input in GLSL. + * + * Note: INTERP_MODE_NONE must be 0 so that memsetting the + * ir_variable data structure to 0 causes the default behavior. + */ +enum glsl_interp_mode +{ + INTERP_MODE_NONE = 0, + INTERP_MODE_SMOOTH, + INTERP_MODE_FLAT, + INTERP_MODE_NOPERSPECTIVE, + INTERP_MODE_EXPLICIT, + INTERP_MODE_COUNT /**< Number of interpolation qualifiers */ +}; + +enum glsl_interface_packing { + GLSL_INTERFACE_PACKING_STD140, + GLSL_INTERFACE_PACKING_SHARED, + GLSL_INTERFACE_PACKING_PACKED, + GLSL_INTERFACE_PACKING_STD430 +}; + +const char *glsl_interp_mode_name(enum glsl_interp_mode qual); + +/** + * Fragment program results + */ +typedef enum +{ + FRAG_RESULT_DEPTH = 0, + FRAG_RESULT_STENCIL = 1, + /* If a single color should be written to all render targets, this + * register is written. No FRAG_RESULT_DATAn will be written. + */ + FRAG_RESULT_COLOR = 2, + FRAG_RESULT_SAMPLE_MASK = 3, + + /* FRAG_RESULT_DATAn are the per-render-target (GLSL gl_FragData[n] + * or ARB_fragment_program fragment.color[n]) color results. If + * any are written, FRAG_RESULT_COLOR will not be written. + * FRAG_RESULT_DATA1 and up are simply for the benefit of + * gl_frag_result_name() and not to be construed as an upper bound + */ + FRAG_RESULT_DATA0 = 4, + FRAG_RESULT_DATA1, + FRAG_RESULT_DATA2, + FRAG_RESULT_DATA3, + FRAG_RESULT_DATA4, + FRAG_RESULT_DATA5, + FRAG_RESULT_DATA6, + FRAG_RESULT_DATA7, +} gl_frag_result; + +const char *gl_frag_result_name(gl_frag_result result); + +#define FRAG_RESULT_MAX (FRAG_RESULT_DATA0 + MAX_DRAW_BUFFERS) + +/** + * \brief Layout qualifiers for gl_FragDepth. + * + * Extension AMD_conservative_depth allows gl_FragDepth to be redeclared with + * a layout qualifier. + * + * \see enum ir_depth_layout + */ +enum gl_frag_depth_layout +{ + FRAG_DEPTH_LAYOUT_NONE, /**< No layout is specified. */ + FRAG_DEPTH_LAYOUT_ANY, + FRAG_DEPTH_LAYOUT_GREATER, + FRAG_DEPTH_LAYOUT_LESS, + FRAG_DEPTH_LAYOUT_UNCHANGED +}; + +/** + * \brief Buffer access qualifiers + */ +enum gl_access_qualifier +{ + ACCESS_COHERENT = (1 << 0), + ACCESS_RESTRICT = (1 << 1), + ACCESS_VOLATILE = (1 << 2), + ACCESS_NON_READABLE = (1 << 3), + ACCESS_NON_WRITEABLE = (1 << 4), + + /** The access may use a non-uniform buffer or image index */ + ACCESS_NON_UNIFORM = (1 << 5), + + /* This has the same semantics as NIR_INTRINSIC_CAN_REORDER, only to be + * used with loads. In other words, it means that the load can be + * arbitrarily reordered, or combined with other loads to the same address. + * It is implied by ACCESS_NON_WRITEABLE together with ACCESS_RESTRICT, and + * a lack of ACCESS_COHERENT and ACCESS_VOLATILE. + */ + ACCESS_CAN_REORDER = (1 << 6), + + /** Use as little cache space as possible. */ + ACCESS_STREAM_CACHE_POLICY = (1 << 7), +}; + +/** + * \brief Blend support qualifiers + */ +enum gl_advanced_blend_mode +{ + BLEND_NONE = 0x0000, + + BLEND_MULTIPLY = 0x0001, + BLEND_SCREEN = 0x0002, + BLEND_OVERLAY = 0x0004, + BLEND_DARKEN = 0x0008, + BLEND_LIGHTEN = 0x0010, + BLEND_COLORDODGE = 0x0020, + BLEND_COLORBURN = 0x0040, + BLEND_HARDLIGHT = 0x0080, + BLEND_SOFTLIGHT = 0x0100, + BLEND_DIFFERENCE = 0x0200, + BLEND_EXCLUSION = 0x0400, + BLEND_HSL_HUE = 0x0800, + BLEND_HSL_SATURATION = 0x1000, + BLEND_HSL_COLOR = 0x2000, + BLEND_HSL_LUMINOSITY = 0x4000, + + BLEND_ALL = 0x7fff, +}; + +enum blend_func +{ + BLEND_FUNC_ADD, + BLEND_FUNC_SUBTRACT, + BLEND_FUNC_REVERSE_SUBTRACT, + BLEND_FUNC_MIN, + BLEND_FUNC_MAX, +}; + +enum blend_factor +{ + BLEND_FACTOR_ZERO, + BLEND_FACTOR_SRC_COLOR, + BLEND_FACTOR_DST_COLOR, + BLEND_FACTOR_SRC_ALPHA, + BLEND_FACTOR_DST_ALPHA, + BLEND_FACTOR_CONSTANT_COLOR, + BLEND_FACTOR_CONSTANT_ALPHA, + BLEND_FACTOR_SRC_ALPHA_SATURATE, +}; + +enum gl_tess_spacing +{ + TESS_SPACING_UNSPECIFIED, + TESS_SPACING_EQUAL, + TESS_SPACING_FRACTIONAL_ODD, + TESS_SPACING_FRACTIONAL_EVEN, +}; + +/** + * A compare function enum for use in compiler lowering passes. This is in + * the same order as GL's compare functions (shifted down by GL_NEVER), and is + * exactly the same as gallium's PIPE_FUNC_*. + */ +enum compare_func +{ + COMPARE_FUNC_NEVER, + COMPARE_FUNC_LESS, + COMPARE_FUNC_EQUAL, + COMPARE_FUNC_LEQUAL, + COMPARE_FUNC_GREATER, + COMPARE_FUNC_NOTEQUAL, + COMPARE_FUNC_GEQUAL, + COMPARE_FUNC_ALWAYS, +}; + +/** + * Arrangements for grouping invocations from NV_compute_shader_derivatives. + * + * The extension provides new layout qualifiers that support two different + * arrangements of compute shader invocations for the purpose of derivative + * computation. When specifying + * + * layout(derivative_group_quadsNV) in; + * + * compute shader invocations are grouped into 2x2x1 arrays whose four local + * invocation ID values follow the pattern: + * + * +-----------------+------------------+ + * | (2x+0, 2y+0, z) | (2x+1, 2y+0, z) | + * +-----------------+------------------+ + * | (2x+0, 2y+1, z) | (2x+1, 2y+1, z) | + * +-----------------+------------------+ + * + * where Y increases from bottom to top. When specifying + * + * layout(derivative_group_linearNV) in; + * + * compute shader invocations are grouped into 2x2x1 arrays whose four local + * invocation index values follow the pattern: + * + * +------+------+ + * | 4n+0 | 4n+1 | + * +------+------+ + * | 4n+2 | 4n+3 | + * +------+------+ + * + * If neither layout qualifier is specified, derivatives in compute shaders + * return zero, which is consistent with the handling of built-in texture + * functions like texture() in GLSL 4.50 compute shaders. + */ +enum gl_derivative_group { + DERIVATIVE_GROUP_NONE = 0, + DERIVATIVE_GROUP_QUADS, + DERIVATIVE_GROUP_LINEAR, +}; + +enum float_controls +{ + FLOAT_CONTROLS_DEFAULT_FLOAT_CONTROL_MODE = 0x0000, + FLOAT_CONTROLS_DENORM_PRESERVE_FP16 = 0x0001, + FLOAT_CONTROLS_DENORM_PRESERVE_FP32 = 0x0002, + FLOAT_CONTROLS_DENORM_PRESERVE_FP64 = 0x0004, + FLOAT_CONTROLS_DENORM_FLUSH_TO_ZERO_FP16 = 0x0008, + FLOAT_CONTROLS_DENORM_FLUSH_TO_ZERO_FP32 = 0x0010, + FLOAT_CONTROLS_DENORM_FLUSH_TO_ZERO_FP64 = 0x0020, + FLOAT_CONTROLS_SIGNED_ZERO_INF_NAN_PRESERVE_FP16 = 0x0040, + FLOAT_CONTROLS_SIGNED_ZERO_INF_NAN_PRESERVE_FP32 = 0x0080, + FLOAT_CONTROLS_SIGNED_ZERO_INF_NAN_PRESERVE_FP64 = 0x0100, + FLOAT_CONTROLS_ROUNDING_MODE_RTE_FP16 = 0x0200, + FLOAT_CONTROLS_ROUNDING_MODE_RTE_FP32 = 0x0400, + FLOAT_CONTROLS_ROUNDING_MODE_RTE_FP64 = 0x0800, + FLOAT_CONTROLS_ROUNDING_MODE_RTZ_FP16 = 0x1000, + FLOAT_CONTROLS_ROUNDING_MODE_RTZ_FP32 = 0x2000, + FLOAT_CONTROLS_ROUNDING_MODE_RTZ_FP64 = 0x4000, +}; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SHADER_ENUMS_H */ diff --git a/selfdrive/modeld/thneed/debug/decompiler/util/bitset.h b/selfdrive/modeld/thneed/debug/decompiler/util/bitset.h new file mode 100644 index 0000000000..264144c39b --- /dev/null +++ b/selfdrive/modeld/thneed/debug/decompiler/util/bitset.h @@ -0,0 +1,261 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file bitset.h + * \brief Bitset of arbitrary size definitions. + * \author Michal Krol + */ + +#ifndef BITSET_H +#define BITSET_H + +//#include "util/bitscan.h" +//#include "util/macros.h" + +/**************************************************************************** + * generic bitset implementation + */ + +#define BITSET_WORD unsigned int +#define BITSET_WORDBITS (sizeof (BITSET_WORD) * 8) + +/* bitset declarations + */ +#define BITSET_WORDS(bits) (((bits) + BITSET_WORDBITS - 1) / BITSET_WORDBITS) +#define BITSET_DECLARE(name, bits) BITSET_WORD name[BITSET_WORDS(bits)] + +/* bitset operations + */ +#define BITSET_COPY(x, y) memcpy( (x), (y), sizeof (x) ) +#define BITSET_EQUAL(x, y) (memcmp( (x), (y), sizeof (x) ) == 0) +#define BITSET_ZERO(x) memset( (x), 0, sizeof (x) ) +#define BITSET_ONES(x) memset( (x), 0xff, sizeof (x) ) + +#define BITSET_BITWORD(b) ((b) / BITSET_WORDBITS) +#define BITSET_BIT(b) (1u << ((b) % BITSET_WORDBITS)) + +/* single bit operations + */ +#define BITSET_TEST(x, b) (((x)[BITSET_BITWORD(b)] & BITSET_BIT(b)) != 0) +#define BITSET_SET(x, b) ((x)[BITSET_BITWORD(b)] |= BITSET_BIT(b)) +#define BITSET_CLEAR(x, b) ((x)[BITSET_BITWORD(b)] &= ~BITSET_BIT(b)) + +#define BITSET_MASK(b) (((b) % BITSET_WORDBITS == 0) ? ~0 : BITSET_BIT(b) - 1) +#define BITSET_RANGE(b, e) ((BITSET_MASK((e) + 1)) & ~(BITSET_BIT(b) - 1)) + +/* bit range operations + */ +#define BITSET_TEST_RANGE(x, b, e) \ + (BITSET_BITWORD(b) == BITSET_BITWORD(e) ? \ + (((x)[BITSET_BITWORD(b)] & BITSET_RANGE(b, e)) != 0) : \ + (assert (!"BITSET_TEST_RANGE: bit range crosses word boundary"), 0)) +#define BITSET_SET_RANGE(x, b, e) \ + (BITSET_BITWORD(b) == BITSET_BITWORD(e) ? \ + ((x)[BITSET_BITWORD(b)] |= BITSET_RANGE(b, e)) : \ + (assert (!"BITSET_SET_RANGE: bit range crosses word boundary"), 0)) +#define BITSET_CLEAR_RANGE(x, b, e) \ + (BITSET_BITWORD(b) == BITSET_BITWORD(e) ? \ + ((x)[BITSET_BITWORD(b)] &= ~BITSET_RANGE(b, e)) : \ + (assert (!"BITSET_CLEAR_RANGE: bit range crosses word boundary"), 0)) + +/* Get first bit set in a bitset. + */ +static inline int +__bitset_ffs(const BITSET_WORD *x, int n) +{ + int i; + + for (i = 0; i < n; i++) { + if (x[i]) + return ffs(x[i]) + BITSET_WORDBITS * i; + } + + return 0; +} + +#define BITSET_FFS(x) __bitset_ffs(x, ARRAY_SIZE(x)) + +static inline unsigned +__bitset_next_set(unsigned i, BITSET_WORD *tmp, + const BITSET_WORD *set, unsigned size) +{ + unsigned bit, word; + + /* NOTE: The initial conditions for this function are very specific. At + * the start of the loop, the tmp variable must be set to *set and the + * initial i value set to 0. This way, if there is a bit set in the first + * word, we ignore the i-value and just grab that bit (so 0 is ok, even + * though 0 may be returned). If the first word is 0, then the value of + * `word` will be 0 and we will go on to look at the second word. + */ + word = BITSET_BITWORD(i); + while (*tmp == 0) { + word++; + + if (word >= BITSET_WORDS(size)) + return size; + + *tmp = set[word]; + } + + /* Find the next set bit in the non-zero word */ + bit = ffs(*tmp) - 1; + + /* Unset the bit */ + *tmp &= ~(1ull << bit); + + return word * BITSET_WORDBITS + bit; +} + +/** + * Iterates over each set bit in a set + * + * @param __i iteration variable, bit number + * @param __set the bitset to iterate (will not be modified) + * @param __size number of bits in the set to consider + */ +#define BITSET_FOREACH_SET(__i, __set, __size) \ + for (BITSET_WORD __tmp = *(__set), *__foo = &__tmp; __foo != NULL; __foo = NULL) \ + for (__i = 0; \ + (__i = __bitset_next_set(__i, &__tmp, __set, __size)) < __size;) + +#ifdef __cplusplus + +/** + * Simple C++ wrapper of a bitset type of static size, with value semantics + * and basic bitwise arithmetic operators. The operators defined below are + * expected to have the same semantics as the same operator applied to other + * fundamental integer types. T is the name of the struct to instantiate + * it as, and N is the number of bits in the bitset. + */ +#define DECLARE_BITSET_T(T, N) struct T { \ + EXPLICIT_CONVERSION \ + operator bool() const \ + { \ + for (unsigned i = 0; i < BITSET_WORDS(N); i++) \ + if (words[i]) \ + return true; \ + return false; \ + } \ + \ + T & \ + operator=(int x) \ + { \ + const T c = {{ (BITSET_WORD)x }}; \ + return *this = c; \ + } \ + \ + friend bool \ + operator==(const T &b, const T &c) \ + { \ + return BITSET_EQUAL(b.words, c.words); \ + } \ + \ + friend bool \ + operator!=(const T &b, const T &c) \ + { \ + return !(b == c); \ + } \ + \ + friend bool \ + operator==(const T &b, int x) \ + { \ + const T c = {{ (BITSET_WORD)x }}; \ + return b == c; \ + } \ + \ + friend bool \ + operator!=(const T &b, int x) \ + { \ + return !(b == x); \ + } \ + \ + friend T \ + operator~(const T &b) \ + { \ + T c; \ + for (unsigned i = 0; i < BITSET_WORDS(N); i++) \ + c.words[i] = ~b.words[i]; \ + return c; \ + } \ + \ + T & \ + operator|=(const T &b) \ + { \ + for (unsigned i = 0; i < BITSET_WORDS(N); i++) \ + words[i] |= b.words[i]; \ + return *this; \ + } \ + \ + friend T \ + operator|(const T &b, const T &c) \ + { \ + T d = b; \ + d |= c; \ + return d; \ + } \ + \ + T & \ + operator&=(const T &b) \ + { \ + for (unsigned i = 0; i < BITSET_WORDS(N); i++) \ + words[i] &= b.words[i]; \ + return *this; \ + } \ + \ + friend T \ + operator&(const T &b, const T &c) \ + { \ + T d = b; \ + d &= c; \ + return d; \ + } \ + \ + bool \ + test(unsigned i) const \ + { \ + return BITSET_TEST(words, i); \ + } \ + \ + T & \ + set(unsigned i) \ + { \ + BITSET_SET(words, i); \ + return *this; \ + } \ + \ + T & \ + clear(unsigned i) \ + { \ + BITSET_CLEAR(words, i); \ + return *this; \ + } \ + \ + BITSET_WORD words[BITSET_WORDS(N)]; \ + } + +#endif + +#endif diff --git a/selfdrive/modeld/thneed/debug/decompiler/util/list.h b/selfdrive/modeld/thneed/debug/decompiler/util/list.h new file mode 100644 index 0000000000..7f36e8c39d --- /dev/null +++ b/selfdrive/modeld/thneed/debug/decompiler/util/list.h @@ -0,0 +1,262 @@ +/************************************************************************** + * + * Copyright 2006 VMware, Inc., Bismarck, ND. USA. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + **************************************************************************/ + +/** + * \file + * List macros heavily inspired by the Linux kernel + * list handling. No list looping yet. + * + * Is not threadsafe, so common operations need to + * be protected using an external mutex. + */ + +#ifndef _UTIL_LIST_H_ +#define _UTIL_LIST_H_ + + +#include +#include +#include + +#ifdef DEBUG +# define list_assert(cond, msg) assert(cond && msg) +#else +# define list_assert(cond, msg) (void)(0 && (cond)) +#endif + +struct list_head +{ + struct list_head *prev; + struct list_head *next; +}; + +static inline void list_inithead(struct list_head *item) +{ + item->prev = item; + item->next = item; +} + +static inline void list_add(struct list_head *item, struct list_head *list) +{ + item->prev = list; + item->next = list->next; + list->next->prev = item; + list->next = item; +} + +static inline void list_addtail(struct list_head *item, struct list_head *list) +{ + item->next = list; + item->prev = list->prev; + list->prev->next = item; + list->prev = item; +} + +static inline bool list_is_empty(const struct list_head *list); + +static inline void list_replace(struct list_head *from, struct list_head *to) +{ + if (list_is_empty(from)) { + list_inithead(to); + } else { + to->prev = from->prev; + to->next = from->next; + from->next->prev = to; + from->prev->next = to; + } +} + +static inline void list_del(struct list_head *item) +{ + item->prev->next = item->next; + item->next->prev = item->prev; + item->prev = item->next = NULL; +} + +static inline void list_delinit(struct list_head *item) +{ + item->prev->next = item->next; + item->next->prev = item->prev; + item->next = item; + item->prev = item; +} + +static inline bool list_is_empty(const struct list_head *list) +{ + return list->next == list; +} + +/** + * Returns whether the list has exactly one element. + */ +static inline bool list_is_singular(const struct list_head *list) +{ + return list->next != NULL && list->next != list && list->next->next == list; +} + +static inline unsigned list_length(const struct list_head *list) +{ + struct list_head *node; + unsigned length = 0; + for (node = list->next; node != list; node = node->next) + length++; + return length; +} + +static inline void list_splice(struct list_head *src, struct list_head *dst) +{ + if (list_is_empty(src)) + return; + + src->next->prev = dst; + src->prev->next = dst->next; + dst->next->prev = src->prev; + dst->next = src->next; +} + +static inline void list_splicetail(struct list_head *src, struct list_head *dst) +{ + if (list_is_empty(src)) + return; + + src->prev->next = dst; + src->next->prev = dst->prev; + dst->prev->next = src->next; + dst->prev = src->prev; +} + +static inline void list_validate(const struct list_head *list) +{ + struct list_head *node; + assert(list->next->prev == list && list->prev->next == list); + for (node = list->next; node != list; node = node->next) + assert(node->next->prev == node && node->prev->next == node); +} + +#define LIST_ENTRY(__type, __item, __field) \ + ((__type *)(((char *)(__item)) - offsetof(__type, __field))) + +/** + * Cast from a pointer to a member of a struct back to the containing struct. + * + * 'sample' MUST be initialized, or else the result is undefined! + */ +#ifndef container_of +#define container_of(ptr, sample, member) \ + (void *)((char *)(ptr) \ + - ((char *)&(sample)->member - (char *)(sample))) +#endif + +#define list_first_entry(ptr, type, member) \ + LIST_ENTRY(type, (ptr)->next, member) + +#define list_last_entry(ptr, type, member) \ + LIST_ENTRY(type, (ptr)->prev, member) + + +#define LIST_FOR_EACH_ENTRY(pos, head, member) \ + for (pos = NULL, pos = container_of((head)->next, pos, member); \ + &pos->member != (head); \ + pos = container_of(pos->member.next, pos, member)) + +#define LIST_FOR_EACH_ENTRY_SAFE(pos, storage, head, member) \ + for (pos = NULL, pos = container_of((head)->next, pos, member), \ + storage = container_of(pos->member.next, pos, member); \ + &pos->member != (head); \ + pos = storage, storage = container_of(storage->member.next, storage, member)) + +#define LIST_FOR_EACH_ENTRY_SAFE_REV(pos, storage, head, member) \ + for (pos = NULL, pos = container_of((head)->prev, pos, member), \ + storage = container_of(pos->member.prev, pos, member); \ + &pos->member != (head); \ + pos = storage, storage = container_of(storage->member.prev, storage, member)) + +#define LIST_FOR_EACH_ENTRY_FROM(pos, start, head, member) \ + for (pos = NULL, pos = container_of((start), pos, member); \ + &pos->member != (head); \ + pos = container_of(pos->member.next, pos, member)) + +#define LIST_FOR_EACH_ENTRY_FROM_REV(pos, start, head, member) \ + for (pos = NULL, pos = container_of((start), pos, member); \ + &pos->member != (head); \ + pos = container_of(pos->member.prev, pos, member)) + +#define list_for_each_entry(type, pos, head, member) \ + for (type *pos = LIST_ENTRY(type, (head)->next, member), \ + *__next = LIST_ENTRY(type, pos->member.next, member); \ + &pos->member != (head); \ + pos = LIST_ENTRY(type, pos->member.next, member), \ + list_assert(pos == __next, "use _safe iterator"), \ + __next = LIST_ENTRY(type, __next->member.next, member)) + +#define list_for_each_entry_safe(type, pos, head, member) \ + for (type *pos = LIST_ENTRY(type, (head)->next, member), \ + *__next = LIST_ENTRY(type, pos->member.next, member); \ + &pos->member != (head); \ + pos = __next, \ + __next = LIST_ENTRY(type, __next->member.next, member)) + +#define list_for_each_entry_rev(type, pos, head, member) \ + for (type *pos = LIST_ENTRY(type, (head)->prev, member), \ + *__prev = LIST_ENTRY(type, pos->member.prev, member); \ + &pos->member != (head); \ + pos = LIST_ENTRY(type, pos->member.prev, member), \ + list_assert(pos == __prev, "use _safe iterator"), \ + __prev = LIST_ENTRY(type, __prev->member.prev, member)) + +#define list_for_each_entry_safe_rev(type, pos, head, member) \ + for (type *pos = LIST_ENTRY(type, (head)->prev, member), \ + *__prev = LIST_ENTRY(type, pos->member.prev, member); \ + &pos->member != (head); \ + pos = __prev, \ + __prev = LIST_ENTRY(type, __prev->member.prev, member)) + +#define list_for_each_entry_from(type, pos, start, head, member) \ + for (type *pos = LIST_ENTRY(type, (start), member); \ + &pos->member != (head); \ + pos = LIST_ENTRY(type, pos->member.next, member)) + +#define list_for_each_entry_from_safe(type, pos, start, head, member) \ + for (type *pos = LIST_ENTRY(type, (start), member), \ + *__next = LIST_ENTRY(type, pos->member.next, member); \ + &pos->member != (head); \ + pos = __next, \ + __next = LIST_ENTRY(type, __next->member.next, member)) + +#define list_for_each_entry_from_rev(type, pos, start, head, member) \ + for (type *pos = LIST_ENTRY(type, (start), member); \ + &pos->member != (head); \ + pos = LIST_ENTRY(type, pos->member.prev, member)) + +#define list_pair_for_each_entry(type, pos1, pos2, head1, head2, member) \ + for (type *pos1 = LIST_ENTRY(type, (head1)->next, member), \ + *pos2 = LIST_ENTRY(type, (head2)->next, member); \ + &pos1->member != (head1) && &pos2->member != (head2); \ + pos1 = LIST_ENTRY(type, pos1->member.next, member), \ + pos2 = LIST_ENTRY(type, pos2->member.next, member)) + +#endif /*_UTIL_LIST_H_*/ diff --git a/selfdrive/modeld/thneed/debug/decompiler/util/macros.h b/selfdrive/modeld/thneed/debug/decompiler/util/macros.h new file mode 100644 index 0000000000..a36bdd411e --- /dev/null +++ b/selfdrive/modeld/thneed/debug/decompiler/util/macros.h @@ -0,0 +1,346 @@ +/* + * Copyright © 2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UTIL_MACROS_H +#define UTIL_MACROS_H + +#include + +/* Compute the size of an array */ +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +/* For compatibility with Clang's __has_builtin() */ +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +/** + * __builtin_expect macros + */ +#if !defined(HAVE___BUILTIN_EXPECT) +# define __builtin_expect(x, y) (x) +#endif + +#ifndef likely +# ifdef HAVE___BUILTIN_EXPECT +# define likely(x) __builtin_expect(!!(x), 1) +# define unlikely(x) __builtin_expect(!!(x), 0) +# else +# define likely(x) (x) +# define unlikely(x) (x) +# endif +#endif + + +/** + * Static (compile-time) assertion. + * Basically, use COND to dimension an array. If COND is false/zero the + * array size will be -1 and we'll get a compilation error. + */ +#define STATIC_ASSERT(COND) \ + do { \ + (void) sizeof(char [1 - 2*!(COND)]); \ + } while (0) + + +/** + * Unreachable macro. Useful for suppressing "control reaches end of non-void + * function" warnings. + */ +#if defined(HAVE___BUILTIN_UNREACHABLE) || __has_builtin(__builtin_unreachable) +#define unreachable(str) \ +do { \ + assert(!str); \ + __builtin_unreachable(); \ +} while (0) +#elif defined (_MSC_VER) +#define unreachable(str) \ +do { \ + assert(!str); \ + __assume(0); \ +} while (0) +#else +#define unreachable(str) assert(!str) +#endif + +/** + * Assume macro. Useful for expressing our assumptions to the compiler, + * typically for purposes of silencing warnings. + */ +#if __has_builtin(__builtin_assume) +#define assume(expr) \ +do { \ + assert(expr); \ + __builtin_assume(expr); \ +} while (0) +#elif defined HAVE___BUILTIN_UNREACHABLE +#define assume(expr) ((expr) ? ((void) 0) \ + : (assert(!"assumption failed"), \ + __builtin_unreachable())) +#elif defined (_MSC_VER) +#define assume(expr) __assume(expr) +#else +#define assume(expr) assert(expr) +#endif + +/* Attribute const is used for functions that have no effects other than their + * return value, and only rely on the argument values to compute the return + * value. As a result, calls to it can be CSEed. Note that using memory + * pointed to by the arguments is not allowed for const functions. + */ +#ifdef HAVE_FUNC_ATTRIBUTE_CONST +#define ATTRIBUTE_CONST __attribute__((__const__)) +#else +#define ATTRIBUTE_CONST +#endif + +#ifdef HAVE_FUNC_ATTRIBUTE_FLATTEN +#define FLATTEN __attribute__((__flatten__)) +#else +#define FLATTEN +#endif + +#ifdef HAVE_FUNC_ATTRIBUTE_FORMAT +#define PRINTFLIKE(f, a) __attribute__ ((format(__printf__, f, a))) +#else +#define PRINTFLIKE(f, a) +#endif + +#ifdef HAVE_FUNC_ATTRIBUTE_MALLOC +#define MALLOCLIKE __attribute__((__malloc__)) +#else +#define MALLOCLIKE +#endif + +/* Forced function inlining */ +/* Note: Clang also sets __GNUC__ (see other cases below) */ +#ifndef ALWAYS_INLINE +# if defined(__GNUC__) +# define ALWAYS_INLINE inline __attribute__((always_inline)) +# elif defined(_MSC_VER) +# define ALWAYS_INLINE __forceinline +# else +# define ALWAYS_INLINE inline +# endif +#endif + +/* Used to optionally mark structures with misaligned elements or size as + * packed, to trade off performance for space. + */ +#ifdef HAVE_FUNC_ATTRIBUTE_PACKED +#define PACKED __attribute__((__packed__)) +#else +#define PACKED +#endif + +/* Attribute pure is used for functions that have no effects other than their + * return value. As a result, calls to it can be dead code eliminated. + */ +#ifdef HAVE_FUNC_ATTRIBUTE_PURE +#define ATTRIBUTE_PURE __attribute__((__pure__)) +#else +#define ATTRIBUTE_PURE +#endif + +#ifdef HAVE_FUNC_ATTRIBUTE_RETURNS_NONNULL +#define ATTRIBUTE_RETURNS_NONNULL __attribute__((__returns_nonnull__)) +#else +#define ATTRIBUTE_RETURNS_NONNULL +#endif + +#ifndef NORETURN +# ifdef _MSC_VER +# define NORETURN __declspec(noreturn) +# elif defined HAVE_FUNC_ATTRIBUTE_NORETURN +# define NORETURN __attribute__((__noreturn__)) +# else +# define NORETURN +# endif +#endif + +#ifdef __cplusplus +/** + * Macro function that evaluates to true if T is a trivially + * destructible type -- that is, if its (non-virtual) destructor + * performs no action and all member variables and base classes are + * trivially destructible themselves. + */ +# if (defined(__clang__) && defined(__has_feature)) +# if __has_feature(has_trivial_destructor) +# define HAS_TRIVIAL_DESTRUCTOR(T) __has_trivial_destructor(T) +# endif +# elif defined(__GNUC__) +# if ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3))) +# define HAS_TRIVIAL_DESTRUCTOR(T) __has_trivial_destructor(T) +# endif +# elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) +# define HAS_TRIVIAL_DESTRUCTOR(T) __has_trivial_destructor(T) +# endif +# ifndef HAS_TRIVIAL_DESTRUCTOR + /* It's always safe (if inefficient) to assume that a + * destructor is non-trivial. + */ +# define HAS_TRIVIAL_DESTRUCTOR(T) (false) +# endif +#endif + +/** + * PUBLIC/USED macros + * + * If we build the library with gcc's -fvisibility=hidden flag, we'll + * use the PUBLIC macro to mark functions that are to be exported. + * + * We also need to define a USED attribute, so the optimizer doesn't + * inline a static function that we later use in an alias. - ajax + */ +#ifndef PUBLIC +# if defined(__GNUC__) +# define PUBLIC __attribute__((visibility("default"))) +# define USED __attribute__((used)) +# elif defined(_MSC_VER) +# define PUBLIC __declspec(dllexport) +# define USED +# else +# define PUBLIC +# define USED +# endif +#endif + +/** + * UNUSED marks variables (or sometimes functions) that have to be defined, + * but are sometimes (or always) unused beyond that. A common case is for + * a function parameter to be used in some build configurations but not others. + * Another case is fallback vfuncs that don't do anything with their params. + * + * Note that this should not be used for identifiers used in `assert()`; + * see ASSERTED below. + */ +#ifdef HAVE_FUNC_ATTRIBUTE_UNUSED +#define UNUSED __attribute__((unused)) +#else +#define UNUSED +#endif + +/** + * Use ASSERTED to indicate that an identifier is unused outside of an `assert()`, + * so that assert-free builds don't get "unused variable" warnings. + */ +#ifdef NDEBUG +#define ASSERTED UNUSED +#else +#define ASSERTED +#endif + +#ifdef HAVE_FUNC_ATTRIBUTE_WARN_UNUSED_RESULT +#define MUST_CHECK __attribute__((warn_unused_result)) +#else +#define MUST_CHECK +#endif + +#if defined(__GNUC__) +#define ATTRIBUTE_NOINLINE __attribute__((noinline)) +#else +#define ATTRIBUTE_NOINLINE +#endif + + +/** + * Check that STRUCT::FIELD can hold MAXVAL. We use a lot of bitfields + * in Mesa/gallium. We have to be sure they're of sufficient size to + * hold the largest expected value. + * Note that with MSVC, enums are signed and enum bitfields need one extra + * high bit (always zero) to ensure the max value is handled correctly. + * This macro will detect that with MSVC, but not GCC. + */ +#define ASSERT_BITFIELD_SIZE(STRUCT, FIELD, MAXVAL) \ + do { \ + ASSERTED STRUCT s; \ + s.FIELD = (MAXVAL); \ + assert((int) s.FIELD == (MAXVAL) && "Insufficient bitfield size!"); \ + } while (0) + + +/** Compute ceiling of integer quotient of A divided by B. */ +#define DIV_ROUND_UP( A, B ) ( ((A) + (B) - 1) / (B) ) + +/** Clamp X to [MIN,MAX]. Turn NaN into MIN, arbitrarily. */ +#define CLAMP( X, MIN, MAX ) ( (X)>(MIN) ? ((X)>(MAX) ? (MAX) : (X)) : (MIN) ) + +/** Minimum of two values: */ +#define MIN2( A, B ) ( (A)<(B) ? (A) : (B) ) + +/** Maximum of two values: */ +#define MAX2( A, B ) ( (A)>(B) ? (A) : (B) ) + +/** Minimum and maximum of three values: */ +#define MIN3( A, B, C ) ((A) < (B) ? MIN2(A, C) : MIN2(B, C)) +#define MAX3( A, B, C ) ((A) > (B) ? MAX2(A, C) : MAX2(B, C)) + +/** Align a value to a power of two */ +#define ALIGN_POT(x, pot_align) (((x) + (pot_align) - 1) & ~((pot_align) - 1)) + +/** + * Macro for declaring an explicit conversion operator. Defaults to an + * implicit conversion if C++11 is not supported. + */ +#if __cplusplus >= 201103L +#define EXPLICIT_CONVERSION explicit +#elif defined(__cplusplus) +#define EXPLICIT_CONVERSION +#endif + +/** Set a single bit */ +#define BITFIELD_BIT(b) (1u << (b)) +/** Set all bits up to excluding bit b */ +#define BITFIELD_MASK(b) \ + ((b) == 32 ? (~0u) : BITFIELD_BIT((b) % 32) - 1) +/** Set count bits starting from bit b */ +#define BITFIELD_RANGE(b, count) \ + (BITFIELD_MASK((b) + (count)) & ~BITFIELD_MASK(b)) + +/** Set a single bit */ +#define BITFIELD64_BIT(b) (1ull << (b)) +/** Set all bits up to excluding bit b */ +#define BITFIELD64_MASK(b) \ + ((b) == 64 ? (~0ull) : BITFIELD64_BIT(b) - 1) +/** Set count bits starting from bit b */ +#define BITFIELD64_RANGE(b, count) \ + (BITFIELD64_MASK((b) + (count)) & ~BITFIELD64_MASK(b)) + +/* TODO: In future we should try to move this to u_debug.h once header + * dependencies are reorganised to allow this. + */ +enum pipe_debug_type +{ + PIPE_DEBUG_TYPE_OUT_OF_MEMORY = 1, + PIPE_DEBUG_TYPE_ERROR, + PIPE_DEBUG_TYPE_SHADER_INFO, + PIPE_DEBUG_TYPE_PERF_INFO, + PIPE_DEBUG_TYPE_INFO, + PIPE_DEBUG_TYPE_FALLBACK, + PIPE_DEBUG_TYPE_CONFORMANCE, +}; + +#endif /* UTIL_MACROS_H */ diff --git a/selfdrive/modeld/thneed/debug/disassembler.cc b/selfdrive/modeld/thneed/debug/disassembler.cc new file mode 100644 index 0000000000..c1f7e6332c --- /dev/null +++ b/selfdrive/modeld/thneed/debug/disassembler.cc @@ -0,0 +1,132 @@ +#include "debug/include/adreno_pm4types.h" +#define REG_A5XX_TPL1_CS_TEX_CONST_LO 0x0000e760 +#define REG_A5XX_TPL1_CS_TEX_SAMP_LO 0x0000e75c +#define REG_A5XX_SP_CS_CTRL_REG0 0x0000e5f0 + +std::map regs = { + {0x0000e760, "REG_A5XX_TPL1_CS_TEX_CONST_LO"}, + {0x0000e75c, "REG_A5XX_TPL1_CS_TEX_SAMP_LO"}, + {0x00000e06, "REG_A5XX_HLSQ_MODE_CNTL"}, + {0x00000e91, "REG_A5XX_UCHE_CACHE_INVALIDATE_MIN_LO"}, + {0x00000ec2, "REG_A5XX_SP_MODE_CNTL"}, + {0x0000e580, "REG_A5XX_SP_SP_CNTL"}, + {0x0000e5f0, "REG_A5XX_SP_CS_CTRL_REG0"}, + {0x0000e796, "REG_A5XX_HLSQ_CS_CNTL"}, + {0x0000e784, "REG_A5XX_HLSQ_CONTROL_0_REG"}, + {0x0000e7b0, "REG_A5XX_HLSQ_CS_NDRANGE_0"}, + {0x0000e7b9, "REG_A5XX_HLSQ_CS_KERNEL_GROUP_X"}, + {0x00000cdd, "REG_A5XX_VSC_RESOLVE_CNTL"}, +}; + +std::map ops = { + {33, "CP_REG_RMW"}, + {62, "CP_REG_TO_MEM"}, + {49, "CP_RUN_OPENCL"}, + {16, "CP_NOP"}, + {38, "CP_WAIT_FOR_IDLE"}, + {110, "CP_COMPUTE_CHECKPOINT"}, + {48, "CP_LOAD_STATE"}, +}; + +void CachedCommand::disassemble() { + uint32_t *src = (uint32_t *)cmds[1].gpuaddr; + int len = cmds[1].size/4; + printf("disassemble %p %d\n", src, len); + + int i = 0; + while (i < len) { + int pktsize; + int pkttype = -1; + + if (pkt_is_type0(src[i])) { + pkttype = 0; + pktsize = type0_pkt_size(src[i]); + } else if (pkt_is_type3(src[i])) { + pkttype = 3; + pktsize = type3_pkt_size(src[i]); + } else if (pkt_is_type4(src[i])) { + pkttype = 4; + pktsize = type4_pkt_size(src[i]); + } else if (pkt_is_type7(src[i])) { + pkttype = 7; + pktsize = type7_pkt_size(src[i]); + } + printf("%3d: type:%d size:%d ", i, pkttype, pktsize); + + if (pkttype == 7) { + int op = cp_type7_opcode(src[i]); + if (ops.find(op) != ops.end()) { + printf("%-40s ", ops[op].c_str()); + } else { + printf("op: %4d ", op); + } + } + + if (pkttype == 4) { + int reg = cp_type4_base_index_one_reg_wr(src[i]); + if (regs.find(reg) != regs.end()) { + printf("%-40s ", regs[reg].c_str()); + } else { + printf("reg: %4x ", reg); + } + } + + for (int j = 0; j < pktsize+1; j++) { + printf("%8.8X ", src[i+j]); + } + printf("\n"); + + uint64_t addr; + if (pkttype == 7) { + switch (cp_type7_opcode(src[i])) { + case CP_LOAD_STATE: + int dst_off = src[i+1] & 0x1FFF; + int state_src = (src[i+1] >> 16) & 3; + int state_block = (src[i+1] >> 18) & 7; + int state_type = src[i+2] & 3; + int num_unit = (src[i+1] & 0xffc00000) >> 22; + printf(" dst_off: %x state_src: %d state_block: %d state_type: %d num_unit: %d\n", + dst_off, state_src, state_block, state_type, num_unit); + addr = (uint64_t)(src[i+2] & 0xfffffffc) | ((uint64_t)(src[i+3]) << 32); + if (state_block == 5 && state_type == 0) { + if (!(addr&0xFFF)) { + int len = 0x1000; + if (num_unit >= 32) len += 0x1000; + //hexdump((uint32_t *)addr, len); + char fn[0x100]; + snprintf(fn, sizeof(fn), "/tmp/0x%lx.shader", addr); + printf("dumping %s\n", fn); + FILE *f = fopen(fn, "wb"); + // groups of 16 instructions + fwrite((void*)addr, 1, len, f); + fclose(f); + } + } + break; + } + } + + /*if (pkttype == 4) { + switch (cp_type4_base_index_one_reg_wr(src[i])) { + case REG_A5XX_SP_CS_CTRL_REG0: + addr = (uint64_t)(src[i+4] & 0xfffffffc) | ((uint64_t)(src[i+5]) << 32); + hexdump((uint32_t *)addr, 0x1000); + break; + } + }*/ + + /*if (pkttype == 4 && cp_type4_base_index_one_reg_wr(src[i]) == REG_A5XX_TPL1_CS_TEX_CONST_LO) { + uint64_t addr = (uint64_t)(src[i+1] & 0xffffffff) | ((uint64_t)(src[i+2]) << 32); + hexdump((uint32_t *)addr, 0x40); + } + + if (pkttype == 4 && cp_type4_base_index_one_reg_wr(src[i]) == REG_A5XX_TPL1_CS_TEX_SAMP_LO) { + uint64_t addr = (uint64_t)(src[i+1] & 0xffffffff) | ((uint64_t)(src[i+2]) << 32); + hexdump((uint32_t *)addr, 0x40); + }*/ + + if (pkttype == -1) break; + i += (1+pktsize); + } + assert(i == len); +} diff --git a/selfdrive/modeld/thneed/debug/include/a5xx.xml.h b/selfdrive/modeld/thneed/debug/include/a5xx.xml.h new file mode 100644 index 0000000000..4a61d4e72c --- /dev/null +++ b/selfdrive/modeld/thneed/debug/include/a5xx.xml.h @@ -0,0 +1,5201 @@ +#ifndef A5XX_XML +#define A5XX_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://github.com/freedreno/envytools/ +git clone https://github.com/freedreno/envytools.git + +The rules-ng-ng source files this header was generated from are: +- /home/ubuntu/envytools/envytools/rnndb/./adreno.xml ( 501 bytes, from 2019-05-29 01:28:15) +- /home/ubuntu/envytools/envytools/rnndb/freedreno_copyright.xml ( 1572 bytes, from 2019-05-29 01:28:15) +- /home/ubuntu/envytools/envytools/rnndb/adreno/a2xx.xml ( 79608 bytes, from 2019-05-29 01:28:15) +- /home/ubuntu/envytools/envytools/rnndb/adreno/adreno_common.xml ( 14239 bytes, from 2019-05-29 01:28:15) +- /home/ubuntu/envytools/envytools/rnndb/adreno/adreno_pm4.xml ( 43155 bytes, from 2019-05-29 01:28:15) +- /home/ubuntu/envytools/envytools/rnndb/adreno/a3xx.xml ( 83840 bytes, from 2019-05-29 01:28:15) +- /home/ubuntu/envytools/envytools/rnndb/adreno/a4xx.xml ( 112086 bytes, from 2019-05-29 01:28:15) +- /home/ubuntu/envytools/envytools/rnndb/adreno/a5xx.xml ( 147291 bytes, from 2019-05-29 14:51:41) +- /home/ubuntu/envytools/envytools/rnndb/adreno/a6xx.xml ( 148461 bytes, from 2019-05-29 01:28:15) +- /home/ubuntu/envytools/envytools/rnndb/adreno/a6xx_gmu.xml ( 10431 bytes, from 2019-05-29 01:28:15) +- /home/ubuntu/envytools/envytools/rnndb/adreno/ocmem.xml ( 1773 bytes, from 2019-05-29 01:28:15) + +Copyright (C) 2013-2019 by the following authors: +- Rob Clark (robclark) +- Ilia Mirkin (imirkin) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + + +enum a5xx_color_fmt { + RB5_A8_UNORM = 2, + RB5_R8_UNORM = 3, + RB5_R8_SNORM = 4, + RB5_R8_UINT = 5, + RB5_R8_SINT = 6, + RB5_R4G4B4A4_UNORM = 8, + RB5_R5G5B5A1_UNORM = 10, + RB5_R5G6B5_UNORM = 14, + RB5_R8G8_UNORM = 15, + RB5_R8G8_SNORM = 16, + RB5_R8G8_UINT = 17, + RB5_R8G8_SINT = 18, + RB5_R16_UNORM = 21, + RB5_R16_SNORM = 22, + RB5_R16_FLOAT = 23, + RB5_R16_UINT = 24, + RB5_R16_SINT = 25, + RB5_R8G8B8A8_UNORM = 48, + RB5_R8G8B8_UNORM = 49, + RB5_R8G8B8A8_SNORM = 50, + RB5_R8G8B8A8_UINT = 51, + RB5_R8G8B8A8_SINT = 52, + RB5_R10G10B10A2_UNORM = 55, + RB5_R10G10B10A2_UINT = 58, + RB5_R11G11B10_FLOAT = 66, + RB5_R16G16_UNORM = 67, + RB5_R16G16_SNORM = 68, + RB5_R16G16_FLOAT = 69, + RB5_R16G16_UINT = 70, + RB5_R16G16_SINT = 71, + RB5_R32_FLOAT = 74, + RB5_R32_UINT = 75, + RB5_R32_SINT = 76, + RB5_R16G16B16A16_UNORM = 96, + RB5_R16G16B16A16_SNORM = 97, + RB5_R16G16B16A16_FLOAT = 98, + RB5_R16G16B16A16_UINT = 99, + RB5_R16G16B16A16_SINT = 100, + RB5_R32G32_FLOAT = 103, + RB5_R32G32_UINT = 104, + RB5_R32G32_SINT = 105, + RB5_R32G32B32A32_FLOAT = 130, + RB5_R32G32B32A32_UINT = 131, + RB5_R32G32B32A32_SINT = 132, +}; + +enum a5xx_tile_mode { + TILE5_LINEAR = 0, + TILE5_2 = 2, + TILE5_3 = 3, +}; + +enum a5xx_vtx_fmt { + VFMT5_8_UNORM = 3, + VFMT5_8_SNORM = 4, + VFMT5_8_UINT = 5, + VFMT5_8_SINT = 6, + VFMT5_8_8_UNORM = 15, + VFMT5_8_8_SNORM = 16, + VFMT5_8_8_UINT = 17, + VFMT5_8_8_SINT = 18, + VFMT5_16_UNORM = 21, + VFMT5_16_SNORM = 22, + VFMT5_16_FLOAT = 23, + VFMT5_16_UINT = 24, + VFMT5_16_SINT = 25, + VFMT5_8_8_8_UNORM = 33, + VFMT5_8_8_8_SNORM = 34, + VFMT5_8_8_8_UINT = 35, + VFMT5_8_8_8_SINT = 36, + VFMT5_8_8_8_8_UNORM = 48, + VFMT5_8_8_8_8_SNORM = 50, + VFMT5_8_8_8_8_UINT = 51, + VFMT5_8_8_8_8_SINT = 52, + VFMT5_10_10_10_2_UNORM = 54, + VFMT5_10_10_10_2_SNORM = 57, + VFMT5_10_10_10_2_UINT = 58, + VFMT5_10_10_10_2_SINT = 59, + VFMT5_11_11_10_FLOAT = 66, + VFMT5_16_16_UNORM = 67, + VFMT5_16_16_SNORM = 68, + VFMT5_16_16_FLOAT = 69, + VFMT5_16_16_UINT = 70, + VFMT5_16_16_SINT = 71, + VFMT5_32_UNORM = 72, + VFMT5_32_SNORM = 73, + VFMT5_32_FLOAT = 74, + VFMT5_32_UINT = 75, + VFMT5_32_SINT = 76, + VFMT5_32_FIXED = 77, + VFMT5_16_16_16_UNORM = 88, + VFMT5_16_16_16_SNORM = 89, + VFMT5_16_16_16_FLOAT = 90, + VFMT5_16_16_16_UINT = 91, + VFMT5_16_16_16_SINT = 92, + VFMT5_16_16_16_16_UNORM = 96, + VFMT5_16_16_16_16_SNORM = 97, + VFMT5_16_16_16_16_FLOAT = 98, + VFMT5_16_16_16_16_UINT = 99, + VFMT5_16_16_16_16_SINT = 100, + VFMT5_32_32_UNORM = 101, + VFMT5_32_32_SNORM = 102, + VFMT5_32_32_FLOAT = 103, + VFMT5_32_32_UINT = 104, + VFMT5_32_32_SINT = 105, + VFMT5_32_32_FIXED = 106, + VFMT5_32_32_32_UNORM = 112, + VFMT5_32_32_32_SNORM = 113, + VFMT5_32_32_32_UINT = 114, + VFMT5_32_32_32_SINT = 115, + VFMT5_32_32_32_FLOAT = 116, + VFMT5_32_32_32_FIXED = 117, + VFMT5_32_32_32_32_UNORM = 128, + VFMT5_32_32_32_32_SNORM = 129, + VFMT5_32_32_32_32_FLOAT = 130, + VFMT5_32_32_32_32_UINT = 131, + VFMT5_32_32_32_32_SINT = 132, + VFMT5_32_32_32_32_FIXED = 133, +}; + +enum a5xx_tex_fmt { + TFMT5_A8_UNORM = 2, + TFMT5_8_UNORM = 3, + TFMT5_8_SNORM = 4, + TFMT5_8_UINT = 5, + TFMT5_8_SINT = 6, + TFMT5_4_4_4_4_UNORM = 8, + TFMT5_5_5_5_1_UNORM = 10, + TFMT5_5_6_5_UNORM = 14, + TFMT5_8_8_UNORM = 15, + TFMT5_8_8_SNORM = 16, + TFMT5_8_8_UINT = 17, + TFMT5_8_8_SINT = 18, + TFMT5_L8_A8_UNORM = 19, + TFMT5_16_UNORM = 21, + TFMT5_16_SNORM = 22, + TFMT5_16_FLOAT = 23, + TFMT5_16_UINT = 24, + TFMT5_16_SINT = 25, + TFMT5_8_8_8_8_UNORM = 48, + TFMT5_8_8_8_UNORM = 49, + TFMT5_8_8_8_8_SNORM = 50, + TFMT5_8_8_8_8_UINT = 51, + TFMT5_8_8_8_8_SINT = 52, + TFMT5_9_9_9_E5_FLOAT = 53, + TFMT5_10_10_10_2_UNORM = 54, + TFMT5_10_10_10_2_UINT = 58, + TFMT5_11_11_10_FLOAT = 66, + TFMT5_16_16_UNORM = 67, + TFMT5_16_16_SNORM = 68, + TFMT5_16_16_FLOAT = 69, + TFMT5_16_16_UINT = 70, + TFMT5_16_16_SINT = 71, + TFMT5_32_FLOAT = 74, + TFMT5_32_UINT = 75, + TFMT5_32_SINT = 76, + TFMT5_16_16_16_16_UNORM = 96, + TFMT5_16_16_16_16_SNORM = 97, + TFMT5_16_16_16_16_FLOAT = 98, + TFMT5_16_16_16_16_UINT = 99, + TFMT5_16_16_16_16_SINT = 100, + TFMT5_32_32_FLOAT = 103, + TFMT5_32_32_UINT = 104, + TFMT5_32_32_SINT = 105, + TFMT5_32_32_32_UINT = 114, + TFMT5_32_32_32_SINT = 115, + TFMT5_32_32_32_FLOAT = 116, + TFMT5_32_32_32_32_FLOAT = 130, + TFMT5_32_32_32_32_UINT = 131, + TFMT5_32_32_32_32_SINT = 132, + TFMT5_X8Z24_UNORM = 160, + TFMT5_ETC2_RG11_UNORM = 171, + TFMT5_ETC2_RG11_SNORM = 172, + TFMT5_ETC2_R11_UNORM = 173, + TFMT5_ETC2_R11_SNORM = 174, + TFMT5_ETC1 = 175, + TFMT5_ETC2_RGB8 = 176, + TFMT5_ETC2_RGBA8 = 177, + TFMT5_ETC2_RGB8A1 = 178, + TFMT5_DXT1 = 179, + TFMT5_DXT3 = 180, + TFMT5_DXT5 = 181, + TFMT5_RGTC1_UNORM = 183, + TFMT5_RGTC1_SNORM = 184, + TFMT5_RGTC2_UNORM = 187, + TFMT5_RGTC2_SNORM = 188, + TFMT5_BPTC_UFLOAT = 190, + TFMT5_BPTC_FLOAT = 191, + TFMT5_BPTC = 192, + TFMT5_ASTC_4x4 = 193, + TFMT5_ASTC_5x4 = 194, + TFMT5_ASTC_5x5 = 195, + TFMT5_ASTC_6x5 = 196, + TFMT5_ASTC_6x6 = 197, + TFMT5_ASTC_8x5 = 198, + TFMT5_ASTC_8x6 = 199, + TFMT5_ASTC_8x8 = 200, + TFMT5_ASTC_10x5 = 201, + TFMT5_ASTC_10x6 = 202, + TFMT5_ASTC_10x8 = 203, + TFMT5_ASTC_10x10 = 204, + TFMT5_ASTC_12x10 = 205, + TFMT5_ASTC_12x12 = 206, +}; + +enum a5xx_tex_fetchsize { + TFETCH5_1_BYTE = 0, + TFETCH5_2_BYTE = 1, + TFETCH5_4_BYTE = 2, + TFETCH5_8_BYTE = 3, + TFETCH5_16_BYTE = 4, +}; + +enum a5xx_depth_format { + DEPTH5_NONE = 0, + DEPTH5_16 = 1, + DEPTH5_24_8 = 2, + DEPTH5_32 = 4, +}; + +enum a5xx_blit_buf { + BLIT_MRT0 = 0, + BLIT_MRT1 = 1, + BLIT_MRT2 = 2, + BLIT_MRT3 = 3, + BLIT_MRT4 = 4, + BLIT_MRT5 = 5, + BLIT_MRT6 = 6, + BLIT_MRT7 = 7, + BLIT_ZS = 8, + BLIT_S = 9, +}; + +enum a5xx_cp_perfcounter_select { + PERF_CP_ALWAYS_COUNT = 0, + PERF_CP_BUSY_GFX_CORE_IDLE = 1, + PERF_CP_BUSY_CYCLES = 2, + PERF_CP_PFP_IDLE = 3, + PERF_CP_PFP_BUSY_WORKING = 4, + PERF_CP_PFP_STALL_CYCLES_ANY = 5, + PERF_CP_PFP_STARVE_CYCLES_ANY = 6, + PERF_CP_PFP_ICACHE_MISS = 7, + PERF_CP_PFP_ICACHE_HIT = 8, + PERF_CP_PFP_MATCH_PM4_PKT_PROFILE = 9, + PERF_CP_ME_BUSY_WORKING = 10, + PERF_CP_ME_IDLE = 11, + PERF_CP_ME_STARVE_CYCLES_ANY = 12, + PERF_CP_ME_FIFO_EMPTY_PFP_IDLE = 13, + PERF_CP_ME_FIFO_EMPTY_PFP_BUSY = 14, + PERF_CP_ME_FIFO_FULL_ME_BUSY = 15, + PERF_CP_ME_FIFO_FULL_ME_NON_WORKING = 16, + PERF_CP_ME_STALL_CYCLES_ANY = 17, + PERF_CP_ME_ICACHE_MISS = 18, + PERF_CP_ME_ICACHE_HIT = 19, + PERF_CP_NUM_PREEMPTIONS = 20, + PERF_CP_PREEMPTION_REACTION_DELAY = 21, + PERF_CP_PREEMPTION_SWITCH_OUT_TIME = 22, + PERF_CP_PREEMPTION_SWITCH_IN_TIME = 23, + PERF_CP_DEAD_DRAWS_IN_BIN_RENDER = 24, + PERF_CP_PREDICATED_DRAWS_KILLED = 25, + PERF_CP_MODE_SWITCH = 26, + PERF_CP_ZPASS_DONE = 27, + PERF_CP_CONTEXT_DONE = 28, + PERF_CP_CACHE_FLUSH = 29, + PERF_CP_LONG_PREEMPTIONS = 30, +}; + +enum a5xx_rbbm_perfcounter_select { + PERF_RBBM_ALWAYS_COUNT = 0, + PERF_RBBM_ALWAYS_ON = 1, + PERF_RBBM_TSE_BUSY = 2, + PERF_RBBM_RAS_BUSY = 3, + PERF_RBBM_PC_DCALL_BUSY = 4, + PERF_RBBM_PC_VSD_BUSY = 5, + PERF_RBBM_STATUS_MASKED = 6, + PERF_RBBM_COM_BUSY = 7, + PERF_RBBM_DCOM_BUSY = 8, + PERF_RBBM_VBIF_BUSY = 9, + PERF_RBBM_VSC_BUSY = 10, + PERF_RBBM_TESS_BUSY = 11, + PERF_RBBM_UCHE_BUSY = 12, + PERF_RBBM_HLSQ_BUSY = 13, +}; + +enum a5xx_pc_perfcounter_select { + PERF_PC_BUSY_CYCLES = 0, + PERF_PC_WORKING_CYCLES = 1, + PERF_PC_STALL_CYCLES_VFD = 2, + PERF_PC_STALL_CYCLES_TSE = 3, + PERF_PC_STALL_CYCLES_VPC = 4, + PERF_PC_STALL_CYCLES_UCHE = 5, + PERF_PC_STALL_CYCLES_TESS = 6, + PERF_PC_STALL_CYCLES_TSE_ONLY = 7, + PERF_PC_STALL_CYCLES_VPC_ONLY = 8, + PERF_PC_PASS1_TF_STALL_CYCLES = 9, + PERF_PC_STARVE_CYCLES_FOR_INDEX = 10, + PERF_PC_STARVE_CYCLES_FOR_TESS_FACTOR = 11, + PERF_PC_STARVE_CYCLES_FOR_VIZ_STREAM = 12, + PERF_PC_STARVE_CYCLES_FOR_POSITION = 13, + PERF_PC_STARVE_CYCLES_DI = 14, + PERF_PC_VIS_STREAMS_LOADED = 15, + PERF_PC_INSTANCES = 16, + PERF_PC_VPC_PRIMITIVES = 17, + PERF_PC_DEAD_PRIM = 18, + PERF_PC_LIVE_PRIM = 19, + PERF_PC_VERTEX_HITS = 20, + PERF_PC_IA_VERTICES = 21, + PERF_PC_IA_PRIMITIVES = 22, + PERF_PC_GS_PRIMITIVES = 23, + PERF_PC_HS_INVOCATIONS = 24, + PERF_PC_DS_INVOCATIONS = 25, + PERF_PC_VS_INVOCATIONS = 26, + PERF_PC_GS_INVOCATIONS = 27, + PERF_PC_DS_PRIMITIVES = 28, + PERF_PC_VPC_POS_DATA_TRANSACTION = 29, + PERF_PC_3D_DRAWCALLS = 30, + PERF_PC_2D_DRAWCALLS = 31, + PERF_PC_NON_DRAWCALL_GLOBAL_EVENTS = 32, + PERF_TESS_BUSY_CYCLES = 33, + PERF_TESS_WORKING_CYCLES = 34, + PERF_TESS_STALL_CYCLES_PC = 35, + PERF_TESS_STARVE_CYCLES_PC = 36, +}; + +enum a5xx_vfd_perfcounter_select { + PERF_VFD_BUSY_CYCLES = 0, + PERF_VFD_STALL_CYCLES_UCHE = 1, + PERF_VFD_STALL_CYCLES_VPC_ALLOC = 2, + PERF_VFD_STALL_CYCLES_MISS_VB = 3, + PERF_VFD_STALL_CYCLES_MISS_Q = 4, + PERF_VFD_STALL_CYCLES_SP_INFO = 5, + PERF_VFD_STALL_CYCLES_SP_ATTR = 6, + PERF_VFD_STALL_CYCLES_VFDP_VB = 7, + PERF_VFD_STALL_CYCLES_VFDP_Q = 8, + PERF_VFD_DECODER_PACKER_STALL = 9, + PERF_VFD_STARVE_CYCLES_UCHE = 10, + PERF_VFD_RBUFFER_FULL = 11, + PERF_VFD_ATTR_INFO_FIFO_FULL = 12, + PERF_VFD_DECODED_ATTRIBUTE_BYTES = 13, + PERF_VFD_NUM_ATTRIBUTES = 14, + PERF_VFD_INSTRUCTIONS = 15, + PERF_VFD_UPPER_SHADER_FIBERS = 16, + PERF_VFD_LOWER_SHADER_FIBERS = 17, + PERF_VFD_MODE_0_FIBERS = 18, + PERF_VFD_MODE_1_FIBERS = 19, + PERF_VFD_MODE_2_FIBERS = 20, + PERF_VFD_MODE_3_FIBERS = 21, + PERF_VFD_MODE_4_FIBERS = 22, + PERF_VFD_TOTAL_VERTICES = 23, + PERF_VFD_NUM_ATTR_MISS = 24, + PERF_VFD_1_BURST_REQ = 25, + PERF_VFDP_STALL_CYCLES_VFD = 26, + PERF_VFDP_STALL_CYCLES_VFD_INDEX = 27, + PERF_VFDP_STALL_CYCLES_VFD_PROG = 28, + PERF_VFDP_STARVE_CYCLES_PC = 29, + PERF_VFDP_VS_STAGE_32_WAVES = 30, +}; + +enum a5xx_hlsq_perfcounter_select { + PERF_HLSQ_BUSY_CYCLES = 0, + PERF_HLSQ_STALL_CYCLES_UCHE = 1, + PERF_HLSQ_STALL_CYCLES_SP_STATE = 2, + PERF_HLSQ_STALL_CYCLES_SP_FS_STAGE = 3, + PERF_HLSQ_UCHE_LATENCY_CYCLES = 4, + PERF_HLSQ_UCHE_LATENCY_COUNT = 5, + PERF_HLSQ_FS_STAGE_32_WAVES = 6, + PERF_HLSQ_FS_STAGE_64_WAVES = 7, + PERF_HLSQ_QUADS = 8, + PERF_HLSQ_SP_STATE_COPY_TRANS_FS_STAGE = 9, + PERF_HLSQ_SP_STATE_COPY_TRANS_VS_STAGE = 10, + PERF_HLSQ_TP_STATE_COPY_TRANS_FS_STAGE = 11, + PERF_HLSQ_TP_STATE_COPY_TRANS_VS_STAGE = 12, + PERF_HLSQ_CS_INVOCATIONS = 13, + PERF_HLSQ_COMPUTE_DRAWCALLS = 14, +}; + +enum a5xx_vpc_perfcounter_select { + PERF_VPC_BUSY_CYCLES = 0, + PERF_VPC_WORKING_CYCLES = 1, + PERF_VPC_STALL_CYCLES_UCHE = 2, + PERF_VPC_STALL_CYCLES_VFD_WACK = 3, + PERF_VPC_STALL_CYCLES_HLSQ_PRIM_ALLOC = 4, + PERF_VPC_STALL_CYCLES_PC = 5, + PERF_VPC_STALL_CYCLES_SP_LM = 6, + PERF_VPC_POS_EXPORT_STALL_CYCLES = 7, + PERF_VPC_STARVE_CYCLES_SP = 8, + PERF_VPC_STARVE_CYCLES_LRZ = 9, + PERF_VPC_PC_PRIMITIVES = 10, + PERF_VPC_SP_COMPONENTS = 11, + PERF_VPC_SP_LM_PRIMITIVES = 12, + PERF_VPC_SP_LM_COMPONENTS = 13, + PERF_VPC_SP_LM_DWORDS = 14, + PERF_VPC_STREAMOUT_COMPONENTS = 15, + PERF_VPC_GRANT_PHASES = 16, +}; + +enum a5xx_tse_perfcounter_select { + PERF_TSE_BUSY_CYCLES = 0, + PERF_TSE_CLIPPING_CYCLES = 1, + PERF_TSE_STALL_CYCLES_RAS = 2, + PERF_TSE_STALL_CYCLES_LRZ_BARYPLANE = 3, + PERF_TSE_STALL_CYCLES_LRZ_ZPLANE = 4, + PERF_TSE_STARVE_CYCLES_PC = 5, + PERF_TSE_INPUT_PRIM = 6, + PERF_TSE_INPUT_NULL_PRIM = 7, + PERF_TSE_TRIVAL_REJ_PRIM = 8, + PERF_TSE_CLIPPED_PRIM = 9, + PERF_TSE_ZERO_AREA_PRIM = 10, + PERF_TSE_FACENESS_CULLED_PRIM = 11, + PERF_TSE_ZERO_PIXEL_PRIM = 12, + PERF_TSE_OUTPUT_NULL_PRIM = 13, + PERF_TSE_OUTPUT_VISIBLE_PRIM = 14, + PERF_TSE_CINVOCATION = 15, + PERF_TSE_CPRIMITIVES = 16, + PERF_TSE_2D_INPUT_PRIM = 17, + PERF_TSE_2D_ALIVE_CLCLES = 18, +}; + +enum a5xx_ras_perfcounter_select { + PERF_RAS_BUSY_CYCLES = 0, + PERF_RAS_SUPERTILE_ACTIVE_CYCLES = 1, + PERF_RAS_STALL_CYCLES_LRZ = 2, + PERF_RAS_STARVE_CYCLES_TSE = 3, + PERF_RAS_SUPER_TILES = 4, + PERF_RAS_8X4_TILES = 5, + PERF_RAS_MASKGEN_ACTIVE = 6, + PERF_RAS_FULLY_COVERED_SUPER_TILES = 7, + PERF_RAS_FULLY_COVERED_8X4_TILES = 8, + PERF_RAS_PRIM_KILLED_INVISILBE = 9, +}; + +enum a5xx_lrz_perfcounter_select { + PERF_LRZ_BUSY_CYCLES = 0, + PERF_LRZ_STARVE_CYCLES_RAS = 1, + PERF_LRZ_STALL_CYCLES_RB = 2, + PERF_LRZ_STALL_CYCLES_VSC = 3, + PERF_LRZ_STALL_CYCLES_VPC = 4, + PERF_LRZ_STALL_CYCLES_FLAG_PREFETCH = 5, + PERF_LRZ_STALL_CYCLES_UCHE = 6, + PERF_LRZ_LRZ_READ = 7, + PERF_LRZ_LRZ_WRITE = 8, + PERF_LRZ_READ_LATENCY = 9, + PERF_LRZ_MERGE_CACHE_UPDATING = 10, + PERF_LRZ_PRIM_KILLED_BY_MASKGEN = 11, + PERF_LRZ_PRIM_KILLED_BY_LRZ = 12, + PERF_LRZ_VISIBLE_PRIM_AFTER_LRZ = 13, + PERF_LRZ_FULL_8X8_TILES = 14, + PERF_LRZ_PARTIAL_8X8_TILES = 15, + PERF_LRZ_TILE_KILLED = 16, + PERF_LRZ_TOTAL_PIXEL = 17, + PERF_LRZ_VISIBLE_PIXEL_AFTER_LRZ = 18, +}; + +enum a5xx_uche_perfcounter_select { + PERF_UCHE_BUSY_CYCLES = 0, + PERF_UCHE_STALL_CYCLES_VBIF = 1, + PERF_UCHE_VBIF_LATENCY_CYCLES = 2, + PERF_UCHE_VBIF_LATENCY_SAMPLES = 3, + PERF_UCHE_VBIF_READ_BEATS_TP = 4, + PERF_UCHE_VBIF_READ_BEATS_VFD = 5, + PERF_UCHE_VBIF_READ_BEATS_HLSQ = 6, + PERF_UCHE_VBIF_READ_BEATS_LRZ = 7, + PERF_UCHE_VBIF_READ_BEATS_SP = 8, + PERF_UCHE_READ_REQUESTS_TP = 9, + PERF_UCHE_READ_REQUESTS_VFD = 10, + PERF_UCHE_READ_REQUESTS_HLSQ = 11, + PERF_UCHE_READ_REQUESTS_LRZ = 12, + PERF_UCHE_READ_REQUESTS_SP = 13, + PERF_UCHE_WRITE_REQUESTS_LRZ = 14, + PERF_UCHE_WRITE_REQUESTS_SP = 15, + PERF_UCHE_WRITE_REQUESTS_VPC = 16, + PERF_UCHE_WRITE_REQUESTS_VSC = 17, + PERF_UCHE_EVICTS = 18, + PERF_UCHE_BANK_REQ0 = 19, + PERF_UCHE_BANK_REQ1 = 20, + PERF_UCHE_BANK_REQ2 = 21, + PERF_UCHE_BANK_REQ3 = 22, + PERF_UCHE_BANK_REQ4 = 23, + PERF_UCHE_BANK_REQ5 = 24, + PERF_UCHE_BANK_REQ6 = 25, + PERF_UCHE_BANK_REQ7 = 26, + PERF_UCHE_VBIF_READ_BEATS_CH0 = 27, + PERF_UCHE_VBIF_READ_BEATS_CH1 = 28, + PERF_UCHE_GMEM_READ_BEATS = 29, + PERF_UCHE_FLAG_COUNT = 30, +}; + +enum a5xx_tp_perfcounter_select { + PERF_TP_BUSY_CYCLES = 0, + PERF_TP_STALL_CYCLES_UCHE = 1, + PERF_TP_LATENCY_CYCLES = 2, + PERF_TP_LATENCY_TRANS = 3, + PERF_TP_FLAG_CACHE_REQUEST_SAMPLES = 4, + PERF_TP_FLAG_CACHE_REQUEST_LATENCY = 5, + PERF_TP_L1_CACHELINE_REQUESTS = 6, + PERF_TP_L1_CACHELINE_MISSES = 7, + PERF_TP_SP_TP_TRANS = 8, + PERF_TP_TP_SP_TRANS = 9, + PERF_TP_OUTPUT_PIXELS = 10, + PERF_TP_FILTER_WORKLOAD_16BIT = 11, + PERF_TP_FILTER_WORKLOAD_32BIT = 12, + PERF_TP_QUADS_RECEIVED = 13, + PERF_TP_QUADS_OFFSET = 14, + PERF_TP_QUADS_SHADOW = 15, + PERF_TP_QUADS_ARRAY = 16, + PERF_TP_QUADS_GRADIENT = 17, + PERF_TP_QUADS_1D = 18, + PERF_TP_QUADS_2D = 19, + PERF_TP_QUADS_BUFFER = 20, + PERF_TP_QUADS_3D = 21, + PERF_TP_QUADS_CUBE = 22, + PERF_TP_STATE_CACHE_REQUESTS = 23, + PERF_TP_STATE_CACHE_MISSES = 24, + PERF_TP_DIVERGENT_QUADS_RECEIVED = 25, + PERF_TP_BINDLESS_STATE_CACHE_REQUESTS = 26, + PERF_TP_BINDLESS_STATE_CACHE_MISSES = 27, + PERF_TP_PRT_NON_RESIDENT_EVENTS = 28, + PERF_TP_OUTPUT_PIXELS_POINT = 29, + PERF_TP_OUTPUT_PIXELS_BILINEAR = 30, + PERF_TP_OUTPUT_PIXELS_MIP = 31, + PERF_TP_OUTPUT_PIXELS_ANISO = 32, + PERF_TP_OUTPUT_PIXELS_ZERO_LOD = 33, + PERF_TP_FLAG_CACHE_REQUESTS = 34, + PERF_TP_FLAG_CACHE_MISSES = 35, + PERF_TP_L1_5_L2_REQUESTS = 36, + PERF_TP_2D_OUTPUT_PIXELS = 37, + PERF_TP_2D_OUTPUT_PIXELS_POINT = 38, + PERF_TP_2D_OUTPUT_PIXELS_BILINEAR = 39, + PERF_TP_2D_FILTER_WORKLOAD_16BIT = 40, + PERF_TP_2D_FILTER_WORKLOAD_32BIT = 41, +}; + +enum a5xx_sp_perfcounter_select { + PERF_SP_BUSY_CYCLES = 0, + PERF_SP_ALU_WORKING_CYCLES = 1, + PERF_SP_EFU_WORKING_CYCLES = 2, + PERF_SP_STALL_CYCLES_VPC = 3, + PERF_SP_STALL_CYCLES_TP = 4, + PERF_SP_STALL_CYCLES_UCHE = 5, + PERF_SP_STALL_CYCLES_RB = 6, + PERF_SP_SCHEDULER_NON_WORKING = 7, + PERF_SP_WAVE_CONTEXTS = 8, + PERF_SP_WAVE_CONTEXT_CYCLES = 9, + PERF_SP_FS_STAGE_WAVE_CYCLES = 10, + PERF_SP_FS_STAGE_WAVE_SAMPLES = 11, + PERF_SP_VS_STAGE_WAVE_CYCLES = 12, + PERF_SP_VS_STAGE_WAVE_SAMPLES = 13, + PERF_SP_FS_STAGE_DURATION_CYCLES = 14, + PERF_SP_VS_STAGE_DURATION_CYCLES = 15, + PERF_SP_WAVE_CTRL_CYCLES = 16, + PERF_SP_WAVE_LOAD_CYCLES = 17, + PERF_SP_WAVE_EMIT_CYCLES = 18, + PERF_SP_WAVE_NOP_CYCLES = 19, + PERF_SP_WAVE_WAIT_CYCLES = 20, + PERF_SP_WAVE_FETCH_CYCLES = 21, + PERF_SP_WAVE_IDLE_CYCLES = 22, + PERF_SP_WAVE_END_CYCLES = 23, + PERF_SP_WAVE_LONG_SYNC_CYCLES = 24, + PERF_SP_WAVE_SHORT_SYNC_CYCLES = 25, + PERF_SP_WAVE_JOIN_CYCLES = 26, + PERF_SP_LM_LOAD_INSTRUCTIONS = 27, + PERF_SP_LM_STORE_INSTRUCTIONS = 28, + PERF_SP_LM_ATOMICS = 29, + PERF_SP_GM_LOAD_INSTRUCTIONS = 30, + PERF_SP_GM_STORE_INSTRUCTIONS = 31, + PERF_SP_GM_ATOMICS = 32, + PERF_SP_VS_STAGE_TEX_INSTRUCTIONS = 33, + PERF_SP_VS_STAGE_CFLOW_INSTRUCTIONS = 34, + PERF_SP_VS_STAGE_EFU_INSTRUCTIONS = 35, + PERF_SP_VS_STAGE_FULL_ALU_INSTRUCTIONS = 36, + PERF_SP_VS_STAGE_HALF_ALU_INSTRUCTIONS = 37, + PERF_SP_FS_STAGE_TEX_INSTRUCTIONS = 38, + PERF_SP_FS_STAGE_CFLOW_INSTRUCTIONS = 39, + PERF_SP_FS_STAGE_EFU_INSTRUCTIONS = 40, + PERF_SP_FS_STAGE_FULL_ALU_INSTRUCTIONS = 41, + PERF_SP_FS_STAGE_HALF_ALU_INSTRUCTIONS = 42, + PERF_SP_FS_STAGE_BARY_INSTRUCTIONS = 43, + PERF_SP_VS_INSTRUCTIONS = 44, + PERF_SP_FS_INSTRUCTIONS = 45, + PERF_SP_ADDR_LOCK_COUNT = 46, + PERF_SP_UCHE_READ_TRANS = 47, + PERF_SP_UCHE_WRITE_TRANS = 48, + PERF_SP_EXPORT_VPC_TRANS = 49, + PERF_SP_EXPORT_RB_TRANS = 50, + PERF_SP_PIXELS_KILLED = 51, + PERF_SP_ICL1_REQUESTS = 52, + PERF_SP_ICL1_MISSES = 53, + PERF_SP_ICL0_REQUESTS = 54, + PERF_SP_ICL0_MISSES = 55, + PERF_SP_HS_INSTRUCTIONS = 56, + PERF_SP_DS_INSTRUCTIONS = 57, + PERF_SP_GS_INSTRUCTIONS = 58, + PERF_SP_CS_INSTRUCTIONS = 59, + PERF_SP_GPR_READ = 60, + PERF_SP_GPR_WRITE = 61, + PERF_SP_LM_CH0_REQUESTS = 62, + PERF_SP_LM_CH1_REQUESTS = 63, + PERF_SP_LM_BANK_CONFLICTS = 64, +}; + +enum a5xx_rb_perfcounter_select { + PERF_RB_BUSY_CYCLES = 0, + PERF_RB_STALL_CYCLES_CCU = 1, + PERF_RB_STALL_CYCLES_HLSQ = 2, + PERF_RB_STALL_CYCLES_FIFO0_FULL = 3, + PERF_RB_STALL_CYCLES_FIFO1_FULL = 4, + PERF_RB_STALL_CYCLES_FIFO2_FULL = 5, + PERF_RB_STARVE_CYCLES_SP = 6, + PERF_RB_STARVE_CYCLES_LRZ_TILE = 7, + PERF_RB_STARVE_CYCLES_CCU = 8, + PERF_RB_STARVE_CYCLES_Z_PLANE = 9, + PERF_RB_STARVE_CYCLES_BARY_PLANE = 10, + PERF_RB_Z_WORKLOAD = 11, + PERF_RB_HLSQ_ACTIVE = 12, + PERF_RB_Z_READ = 13, + PERF_RB_Z_WRITE = 14, + PERF_RB_C_READ = 15, + PERF_RB_C_WRITE = 16, + PERF_RB_TOTAL_PASS = 17, + PERF_RB_Z_PASS = 18, + PERF_RB_Z_FAIL = 19, + PERF_RB_S_FAIL = 20, + PERF_RB_BLENDED_FXP_COMPONENTS = 21, + PERF_RB_BLENDED_FP16_COMPONENTS = 22, + RB_RESERVED = 23, + PERF_RB_2D_ALIVE_CYCLES = 24, + PERF_RB_2D_STALL_CYCLES_A2D = 25, + PERF_RB_2D_STARVE_CYCLES_SRC = 26, + PERF_RB_2D_STARVE_CYCLES_SP = 27, + PERF_RB_2D_STARVE_CYCLES_DST = 28, + PERF_RB_2D_VALID_PIXELS = 29, +}; + +enum a5xx_rb_samples_perfcounter_select { + TOTAL_SAMPLES = 0, + ZPASS_SAMPLES = 1, + ZFAIL_SAMPLES = 2, + SFAIL_SAMPLES = 3, +}; + +enum a5xx_vsc_perfcounter_select { + PERF_VSC_BUSY_CYCLES = 0, + PERF_VSC_WORKING_CYCLES = 1, + PERF_VSC_STALL_CYCLES_UCHE = 2, + PERF_VSC_EOT_NUM = 3, +}; + +enum a5xx_ccu_perfcounter_select { + PERF_CCU_BUSY_CYCLES = 0, + PERF_CCU_STALL_CYCLES_RB_DEPTH_RETURN = 1, + PERF_CCU_STALL_CYCLES_RB_COLOR_RETURN = 2, + PERF_CCU_STARVE_CYCLES_FLAG_RETURN = 3, + PERF_CCU_DEPTH_BLOCKS = 4, + PERF_CCU_COLOR_BLOCKS = 5, + PERF_CCU_DEPTH_BLOCK_HIT = 6, + PERF_CCU_COLOR_BLOCK_HIT = 7, + PERF_CCU_PARTIAL_BLOCK_READ = 8, + PERF_CCU_GMEM_READ = 9, + PERF_CCU_GMEM_WRITE = 10, + PERF_CCU_DEPTH_READ_FLAG0_COUNT = 11, + PERF_CCU_DEPTH_READ_FLAG1_COUNT = 12, + PERF_CCU_DEPTH_READ_FLAG2_COUNT = 13, + PERF_CCU_DEPTH_READ_FLAG3_COUNT = 14, + PERF_CCU_DEPTH_READ_FLAG4_COUNT = 15, + PERF_CCU_COLOR_READ_FLAG0_COUNT = 16, + PERF_CCU_COLOR_READ_FLAG1_COUNT = 17, + PERF_CCU_COLOR_READ_FLAG2_COUNT = 18, + PERF_CCU_COLOR_READ_FLAG3_COUNT = 19, + PERF_CCU_COLOR_READ_FLAG4_COUNT = 20, + PERF_CCU_2D_BUSY_CYCLES = 21, + PERF_CCU_2D_RD_REQ = 22, + PERF_CCU_2D_WR_REQ = 23, + PERF_CCU_2D_REORDER_STARVE_CYCLES = 24, + PERF_CCU_2D_PIXELS = 25, +}; + +enum a5xx_cmp_perfcounter_select { + PERF_CMPDECMP_STALL_CYCLES_VBIF = 0, + PERF_CMPDECMP_VBIF_LATENCY_CYCLES = 1, + PERF_CMPDECMP_VBIF_LATENCY_SAMPLES = 2, + PERF_CMPDECMP_VBIF_READ_DATA_CCU = 3, + PERF_CMPDECMP_VBIF_WRITE_DATA_CCU = 4, + PERF_CMPDECMP_VBIF_READ_REQUEST = 5, + PERF_CMPDECMP_VBIF_WRITE_REQUEST = 6, + PERF_CMPDECMP_VBIF_READ_DATA = 7, + PERF_CMPDECMP_VBIF_WRITE_DATA = 8, + PERF_CMPDECMP_FLAG_FETCH_CYCLES = 9, + PERF_CMPDECMP_FLAG_FETCH_SAMPLES = 10, + PERF_CMPDECMP_DEPTH_WRITE_FLAG1_COUNT = 11, + PERF_CMPDECMP_DEPTH_WRITE_FLAG2_COUNT = 12, + PERF_CMPDECMP_DEPTH_WRITE_FLAG3_COUNT = 13, + PERF_CMPDECMP_DEPTH_WRITE_FLAG4_COUNT = 14, + PERF_CMPDECMP_COLOR_WRITE_FLAG1_COUNT = 15, + PERF_CMPDECMP_COLOR_WRITE_FLAG2_COUNT = 16, + PERF_CMPDECMP_COLOR_WRITE_FLAG3_COUNT = 17, + PERF_CMPDECMP_COLOR_WRITE_FLAG4_COUNT = 18, + PERF_CMPDECMP_2D_STALL_CYCLES_VBIF_REQ = 19, + PERF_CMPDECMP_2D_STALL_CYCLES_VBIF_WR = 20, + PERF_CMPDECMP_2D_STALL_CYCLES_VBIF_RETURN = 21, + PERF_CMPDECMP_2D_RD_DATA = 22, + PERF_CMPDECMP_2D_WR_DATA = 23, +}; + +enum a5xx_vbif_perfcounter_select { + AXI_READ_REQUESTS_ID_0 = 0, + AXI_READ_REQUESTS_ID_1 = 1, + AXI_READ_REQUESTS_ID_2 = 2, + AXI_READ_REQUESTS_ID_3 = 3, + AXI_READ_REQUESTS_ID_4 = 4, + AXI_READ_REQUESTS_ID_5 = 5, + AXI_READ_REQUESTS_ID_6 = 6, + AXI_READ_REQUESTS_ID_7 = 7, + AXI_READ_REQUESTS_ID_8 = 8, + AXI_READ_REQUESTS_ID_9 = 9, + AXI_READ_REQUESTS_ID_10 = 10, + AXI_READ_REQUESTS_ID_11 = 11, + AXI_READ_REQUESTS_ID_12 = 12, + AXI_READ_REQUESTS_ID_13 = 13, + AXI_READ_REQUESTS_ID_14 = 14, + AXI_READ_REQUESTS_ID_15 = 15, + AXI0_READ_REQUESTS_TOTAL = 16, + AXI1_READ_REQUESTS_TOTAL = 17, + AXI2_READ_REQUESTS_TOTAL = 18, + AXI3_READ_REQUESTS_TOTAL = 19, + AXI_READ_REQUESTS_TOTAL = 20, + AXI_WRITE_REQUESTS_ID_0 = 21, + AXI_WRITE_REQUESTS_ID_1 = 22, + AXI_WRITE_REQUESTS_ID_2 = 23, + AXI_WRITE_REQUESTS_ID_3 = 24, + AXI_WRITE_REQUESTS_ID_4 = 25, + AXI_WRITE_REQUESTS_ID_5 = 26, + AXI_WRITE_REQUESTS_ID_6 = 27, + AXI_WRITE_REQUESTS_ID_7 = 28, + AXI_WRITE_REQUESTS_ID_8 = 29, + AXI_WRITE_REQUESTS_ID_9 = 30, + AXI_WRITE_REQUESTS_ID_10 = 31, + AXI_WRITE_REQUESTS_ID_11 = 32, + AXI_WRITE_REQUESTS_ID_12 = 33, + AXI_WRITE_REQUESTS_ID_13 = 34, + AXI_WRITE_REQUESTS_ID_14 = 35, + AXI_WRITE_REQUESTS_ID_15 = 36, + AXI0_WRITE_REQUESTS_TOTAL = 37, + AXI1_WRITE_REQUESTS_TOTAL = 38, + AXI2_WRITE_REQUESTS_TOTAL = 39, + AXI3_WRITE_REQUESTS_TOTAL = 40, + AXI_WRITE_REQUESTS_TOTAL = 41, + AXI_TOTAL_REQUESTS = 42, + AXI_READ_DATA_BEATS_ID_0 = 43, + AXI_READ_DATA_BEATS_ID_1 = 44, + AXI_READ_DATA_BEATS_ID_2 = 45, + AXI_READ_DATA_BEATS_ID_3 = 46, + AXI_READ_DATA_BEATS_ID_4 = 47, + AXI_READ_DATA_BEATS_ID_5 = 48, + AXI_READ_DATA_BEATS_ID_6 = 49, + AXI_READ_DATA_BEATS_ID_7 = 50, + AXI_READ_DATA_BEATS_ID_8 = 51, + AXI_READ_DATA_BEATS_ID_9 = 52, + AXI_READ_DATA_BEATS_ID_10 = 53, + AXI_READ_DATA_BEATS_ID_11 = 54, + AXI_READ_DATA_BEATS_ID_12 = 55, + AXI_READ_DATA_BEATS_ID_13 = 56, + AXI_READ_DATA_BEATS_ID_14 = 57, + AXI_READ_DATA_BEATS_ID_15 = 58, + AXI0_READ_DATA_BEATS_TOTAL = 59, + AXI1_READ_DATA_BEATS_TOTAL = 60, + AXI2_READ_DATA_BEATS_TOTAL = 61, + AXI3_READ_DATA_BEATS_TOTAL = 62, + AXI_READ_DATA_BEATS_TOTAL = 63, + AXI_WRITE_DATA_BEATS_ID_0 = 64, + AXI_WRITE_DATA_BEATS_ID_1 = 65, + AXI_WRITE_DATA_BEATS_ID_2 = 66, + AXI_WRITE_DATA_BEATS_ID_3 = 67, + AXI_WRITE_DATA_BEATS_ID_4 = 68, + AXI_WRITE_DATA_BEATS_ID_5 = 69, + AXI_WRITE_DATA_BEATS_ID_6 = 70, + AXI_WRITE_DATA_BEATS_ID_7 = 71, + AXI_WRITE_DATA_BEATS_ID_8 = 72, + AXI_WRITE_DATA_BEATS_ID_9 = 73, + AXI_WRITE_DATA_BEATS_ID_10 = 74, + AXI_WRITE_DATA_BEATS_ID_11 = 75, + AXI_WRITE_DATA_BEATS_ID_12 = 76, + AXI_WRITE_DATA_BEATS_ID_13 = 77, + AXI_WRITE_DATA_BEATS_ID_14 = 78, + AXI_WRITE_DATA_BEATS_ID_15 = 79, + AXI0_WRITE_DATA_BEATS_TOTAL = 80, + AXI1_WRITE_DATA_BEATS_TOTAL = 81, + AXI2_WRITE_DATA_BEATS_TOTAL = 82, + AXI3_WRITE_DATA_BEATS_TOTAL = 83, + AXI_WRITE_DATA_BEATS_TOTAL = 84, + AXI_DATA_BEATS_TOTAL = 85, +}; + +enum a5xx_tex_filter { + A5XX_TEX_NEAREST = 0, + A5XX_TEX_LINEAR = 1, + A5XX_TEX_ANISO = 2, +}; + +enum a5xx_tex_clamp { + A5XX_TEX_REPEAT = 0, + A5XX_TEX_CLAMP_TO_EDGE = 1, + A5XX_TEX_MIRROR_REPEAT = 2, + A5XX_TEX_CLAMP_TO_BORDER = 3, + A5XX_TEX_MIRROR_CLAMP = 4, +}; + +enum a5xx_tex_aniso { + A5XX_TEX_ANISO_1 = 0, + A5XX_TEX_ANISO_2 = 1, + A5XX_TEX_ANISO_4 = 2, + A5XX_TEX_ANISO_8 = 3, + A5XX_TEX_ANISO_16 = 4, +}; + +enum a5xx_tex_swiz { + A5XX_TEX_X = 0, + A5XX_TEX_Y = 1, + A5XX_TEX_Z = 2, + A5XX_TEX_W = 3, + A5XX_TEX_ZERO = 4, + A5XX_TEX_ONE = 5, +}; + +enum a5xx_tex_type { + A5XX_TEX_1D = 0, + A5XX_TEX_2D = 1, + A5XX_TEX_CUBE = 2, + A5XX_TEX_3D = 3, +}; + +#define A5XX_INT0_RBBM_GPU_IDLE 0x00000001 +#define A5XX_INT0_RBBM_AHB_ERROR 0x00000002 +#define A5XX_INT0_RBBM_TRANSFER_TIMEOUT 0x00000004 +#define A5XX_INT0_RBBM_ME_MS_TIMEOUT 0x00000008 +#define A5XX_INT0_RBBM_PFP_MS_TIMEOUT 0x00000010 +#define A5XX_INT0_RBBM_ETS_MS_TIMEOUT 0x00000020 +#define A5XX_INT0_RBBM_ATB_ASYNC_OVERFLOW 0x00000040 +#define A5XX_INT0_RBBM_GPC_ERROR 0x00000080 +#define A5XX_INT0_CP_SW 0x00000100 +#define A5XX_INT0_CP_HW_ERROR 0x00000200 +#define A5XX_INT0_CP_CCU_FLUSH_DEPTH_TS 0x00000400 +#define A5XX_INT0_CP_CCU_FLUSH_COLOR_TS 0x00000800 +#define A5XX_INT0_CP_CCU_RESOLVE_TS 0x00001000 +#define A5XX_INT0_CP_IB2 0x00002000 +#define A5XX_INT0_CP_IB1 0x00004000 +#define A5XX_INT0_CP_RB 0x00008000 +#define A5XX_INT0_CP_UNUSED_1 0x00010000 +#define A5XX_INT0_CP_RB_DONE_TS 0x00020000 +#define A5XX_INT0_CP_WT_DONE_TS 0x00040000 +#define A5XX_INT0_UNKNOWN_1 0x00080000 +#define A5XX_INT0_CP_CACHE_FLUSH_TS 0x00100000 +#define A5XX_INT0_UNUSED_2 0x00200000 +#define A5XX_INT0_RBBM_ATB_BUS_OVERFLOW 0x00400000 +#define A5XX_INT0_MISC_HANG_DETECT 0x00800000 +#define A5XX_INT0_UCHE_OOB_ACCESS 0x01000000 +#define A5XX_INT0_UCHE_TRAP_INTR 0x02000000 +#define A5XX_INT0_DEBBUS_INTR_0 0x04000000 +#define A5XX_INT0_DEBBUS_INTR_1 0x08000000 +#define A5XX_INT0_GPMU_VOLTAGE_DROOP 0x10000000 +#define A5XX_INT0_GPMU_FIRMWARE 0x20000000 +#define A5XX_INT0_ISDB_CPU_IRQ 0x40000000 +#define A5XX_INT0_ISDB_UNDER_DEBUG 0x80000000 +#define A5XX_CP_INT_CP_OPCODE_ERROR 0x00000001 +#define A5XX_CP_INT_CP_RESERVED_BIT_ERROR 0x00000002 +#define A5XX_CP_INT_CP_HW_FAULT_ERROR 0x00000004 +#define A5XX_CP_INT_CP_DMA_ERROR 0x00000008 +#define A5XX_CP_INT_CP_REGISTER_PROTECTION_ERROR 0x00000010 +#define A5XX_CP_INT_CP_AHB_ERROR 0x00000020 +#define REG_A5XX_CP_RB_BASE 0x00000800 + +#define REG_A5XX_CP_RB_BASE_HI 0x00000801 + +#define REG_A5XX_CP_RB_CNTL 0x00000802 + +#define REG_A5XX_CP_RB_RPTR_ADDR 0x00000804 + +#define REG_A5XX_CP_RB_RPTR_ADDR_HI 0x00000805 + +#define REG_A5XX_CP_RB_RPTR 0x00000806 + +#define REG_A5XX_CP_RB_WPTR 0x00000807 + +#define REG_A5XX_CP_PFP_STAT_ADDR 0x00000808 + +#define REG_A5XX_CP_PFP_STAT_DATA 0x00000809 + +#define REG_A5XX_CP_DRAW_STATE_ADDR 0x0000080b + +#define REG_A5XX_CP_DRAW_STATE_DATA 0x0000080c + +#define REG_A5XX_CP_ME_NRT_ADDR_LO 0x0000080d + +#define REG_A5XX_CP_ME_NRT_ADDR_HI 0x0000080e + +#define REG_A5XX_CP_ME_NRT_DATA 0x00000810 + +#define REG_A5XX_CP_CRASH_SCRIPT_BASE_LO 0x00000817 + +#define REG_A5XX_CP_CRASH_SCRIPT_BASE_HI 0x00000818 + +#define REG_A5XX_CP_CRASH_DUMP_CNTL 0x00000819 + +#define REG_A5XX_CP_ME_STAT_ADDR 0x0000081a + +#define REG_A5XX_CP_ROQ_THRESHOLDS_1 0x0000081f + +#define REG_A5XX_CP_ROQ_THRESHOLDS_2 0x00000820 + +#define REG_A5XX_CP_ROQ_DBG_ADDR 0x00000821 + +#define REG_A5XX_CP_ROQ_DBG_DATA 0x00000822 + +#define REG_A5XX_CP_MEQ_DBG_ADDR 0x00000823 + +#define REG_A5XX_CP_MEQ_DBG_DATA 0x00000824 + +#define REG_A5XX_CP_MEQ_THRESHOLDS 0x00000825 + +#define REG_A5XX_CP_MERCIU_SIZE 0x00000826 + +#define REG_A5XX_CP_MERCIU_DBG_ADDR 0x00000827 + +#define REG_A5XX_CP_MERCIU_DBG_DATA_1 0x00000828 + +#define REG_A5XX_CP_MERCIU_DBG_DATA_2 0x00000829 + +#define REG_A5XX_CP_PFP_UCODE_DBG_ADDR 0x0000082a + +#define REG_A5XX_CP_PFP_UCODE_DBG_DATA 0x0000082b + +#define REG_A5XX_CP_ME_UCODE_DBG_ADDR 0x0000082f + +#define REG_A5XX_CP_ME_UCODE_DBG_DATA 0x00000830 + +#define REG_A5XX_CP_CNTL 0x00000831 + +#define REG_A5XX_CP_PFP_ME_CNTL 0x00000832 + +#define REG_A5XX_CP_CHICKEN_DBG 0x00000833 + +#define REG_A5XX_CP_PFP_INSTR_BASE_LO 0x00000835 + +#define REG_A5XX_CP_PFP_INSTR_BASE_HI 0x00000836 + +#define REG_A5XX_CP_ME_INSTR_BASE_LO 0x00000838 + +#define REG_A5XX_CP_ME_INSTR_BASE_HI 0x00000839 + +#define REG_A5XX_CP_CONTEXT_SWITCH_CNTL 0x0000083b + +#define REG_A5XX_CP_CONTEXT_SWITCH_RESTORE_ADDR_LO 0x0000083c + +#define REG_A5XX_CP_CONTEXT_SWITCH_RESTORE_ADDR_HI 0x0000083d + +#define REG_A5XX_CP_CONTEXT_SWITCH_SAVE_ADDR_LO 0x0000083e + +#define REG_A5XX_CP_CONTEXT_SWITCH_SAVE_ADDR_HI 0x0000083f + +#define REG_A5XX_CP_CONTEXT_SWITCH_SMMU_INFO_LO 0x00000840 + +#define REG_A5XX_CP_CONTEXT_SWITCH_SMMU_INFO_HI 0x00000841 + +#define REG_A5XX_CP_ADDR_MODE_CNTL 0x00000860 + +#define REG_A5XX_CP_ME_STAT_DATA 0x00000b14 + +#define REG_A5XX_CP_WFI_PEND_CTR 0x00000b15 + +#define REG_A5XX_CP_INTERRUPT_STATUS 0x00000b18 + +#define REG_A5XX_CP_HW_FAULT 0x00000b1a + +#define REG_A5XX_CP_PROTECT_STATUS 0x00000b1c + +#define REG_A5XX_CP_IB1_BASE 0x00000b1f + +#define REG_A5XX_CP_IB1_BASE_HI 0x00000b20 + +#define REG_A5XX_CP_IB1_BUFSZ 0x00000b21 + +#define REG_A5XX_CP_IB2_BASE 0x00000b22 + +#define REG_A5XX_CP_IB2_BASE_HI 0x00000b23 + +#define REG_A5XX_CP_IB2_BUFSZ 0x00000b24 + +static inline uint32_t REG_A5XX_CP_SCRATCH(uint32_t i0) { return 0x00000b78 + 0x1*i0; } + +static inline uint32_t REG_A5XX_CP_SCRATCH_REG(uint32_t i0) { return 0x00000b78 + 0x1*i0; } + +static inline uint32_t REG_A5XX_CP_PROTECT(uint32_t i0) { return 0x00000880 + 0x1*i0; } + +static inline uint32_t REG_A5XX_CP_PROTECT_REG(uint32_t i0) { return 0x00000880 + 0x1*i0; } +#define A5XX_CP_PROTECT_REG_BASE_ADDR__MASK 0x0001ffff +#define A5XX_CP_PROTECT_REG_BASE_ADDR__SHIFT 0 +static inline uint32_t A5XX_CP_PROTECT_REG_BASE_ADDR(uint32_t val) +{ + return ((val) << A5XX_CP_PROTECT_REG_BASE_ADDR__SHIFT) & A5XX_CP_PROTECT_REG_BASE_ADDR__MASK; +} +#define A5XX_CP_PROTECT_REG_MASK_LEN__MASK 0x1f000000 +#define A5XX_CP_PROTECT_REG_MASK_LEN__SHIFT 24 +static inline uint32_t A5XX_CP_PROTECT_REG_MASK_LEN(uint32_t val) +{ + return ((val) << A5XX_CP_PROTECT_REG_MASK_LEN__SHIFT) & A5XX_CP_PROTECT_REG_MASK_LEN__MASK; +} +#define A5XX_CP_PROTECT_REG_TRAP_WRITE 0x20000000 +#define A5XX_CP_PROTECT_REG_TRAP_READ 0x40000000 + +#define REG_A5XX_CP_PROTECT_CNTL 0x000008a0 + +#define REG_A5XX_CP_AHB_FAULT 0x00000b1b + +#define REG_A5XX_CP_PERFCTR_CP_SEL_0 0x00000bb0 + +#define REG_A5XX_CP_PERFCTR_CP_SEL_1 0x00000bb1 + +#define REG_A5XX_CP_PERFCTR_CP_SEL_2 0x00000bb2 + +#define REG_A5XX_CP_PERFCTR_CP_SEL_3 0x00000bb3 + +#define REG_A5XX_CP_PERFCTR_CP_SEL_4 0x00000bb4 + +#define REG_A5XX_CP_PERFCTR_CP_SEL_5 0x00000bb5 + +#define REG_A5XX_CP_PERFCTR_CP_SEL_6 0x00000bb6 + +#define REG_A5XX_CP_PERFCTR_CP_SEL_7 0x00000bb7 + +#define REG_A5XX_VSC_ADDR_MODE_CNTL 0x00000bc1 + +#define REG_A5XX_CP_POWERCTR_CP_SEL_0 0x00000bba + +#define REG_A5XX_CP_POWERCTR_CP_SEL_1 0x00000bbb + +#define REG_A5XX_CP_POWERCTR_CP_SEL_2 0x00000bbc + +#define REG_A5XX_CP_POWERCTR_CP_SEL_3 0x00000bbd + +#define REG_A5XX_RBBM_CFG_DBGBUS_SEL_A 0x00000004 + +#define REG_A5XX_RBBM_CFG_DBGBUS_SEL_B 0x00000005 + +#define REG_A5XX_RBBM_CFG_DBGBUS_SEL_C 0x00000006 + +#define REG_A5XX_RBBM_CFG_DBGBUS_SEL_D 0x00000007 + +#define REG_A5XX_RBBM_CFG_DBGBUS_CNTLT 0x00000008 + +#define REG_A5XX_RBBM_CFG_DBGBUS_CNTLM 0x00000009 + +#define REG_A5XX_RBBM_CFG_DEBBUS_CTLTM_ENABLE_SHIFT 0x00000018 + +#define REG_A5XX_RBBM_CFG_DBGBUS_OPL 0x0000000a + +#define REG_A5XX_RBBM_CFG_DBGBUS_OPE 0x0000000b + +#define REG_A5XX_RBBM_CFG_DBGBUS_IVTL_0 0x0000000c + +#define REG_A5XX_RBBM_CFG_DBGBUS_IVTL_1 0x0000000d + +#define REG_A5XX_RBBM_CFG_DBGBUS_IVTL_2 0x0000000e + +#define REG_A5XX_RBBM_CFG_DBGBUS_IVTL_3 0x0000000f + +#define REG_A5XX_RBBM_CFG_DBGBUS_MASKL_0 0x00000010 + +#define REG_A5XX_RBBM_CFG_DBGBUS_MASKL_1 0x00000011 + +#define REG_A5XX_RBBM_CFG_DBGBUS_MASKL_2 0x00000012 + +#define REG_A5XX_RBBM_CFG_DBGBUS_MASKL_3 0x00000013 + +#define REG_A5XX_RBBM_CFG_DBGBUS_BYTEL_0 0x00000014 + +#define REG_A5XX_RBBM_CFG_DBGBUS_BYTEL_1 0x00000015 + +#define REG_A5XX_RBBM_CFG_DBGBUS_IVTE_0 0x00000016 + +#define REG_A5XX_RBBM_CFG_DBGBUS_IVTE_1 0x00000017 + +#define REG_A5XX_RBBM_CFG_DBGBUS_IVTE_2 0x00000018 + +#define REG_A5XX_RBBM_CFG_DBGBUS_IVTE_3 0x00000019 + +#define REG_A5XX_RBBM_CFG_DBGBUS_MASKE_0 0x0000001a + +#define REG_A5XX_RBBM_CFG_DBGBUS_MASKE_1 0x0000001b + +#define REG_A5XX_RBBM_CFG_DBGBUS_MASKE_2 0x0000001c + +#define REG_A5XX_RBBM_CFG_DBGBUS_MASKE_3 0x0000001d + +#define REG_A5XX_RBBM_CFG_DBGBUS_NIBBLEE 0x0000001e + +#define REG_A5XX_RBBM_CFG_DBGBUS_PTRC0 0x0000001f + +#define REG_A5XX_RBBM_CFG_DBGBUS_PTRC1 0x00000020 + +#define REG_A5XX_RBBM_CFG_DBGBUS_LOADREG 0x00000021 + +#define REG_A5XX_RBBM_CFG_DBGBUS_IDX 0x00000022 + +#define REG_A5XX_RBBM_CFG_DBGBUS_CLRC 0x00000023 + +#define REG_A5XX_RBBM_CFG_DBGBUS_LOADIVT 0x00000024 + +#define REG_A5XX_RBBM_INTERFACE_HANG_INT_CNTL 0x0000002f + +#define REG_A5XX_RBBM_INT_CLEAR_CMD 0x00000037 + +#define REG_A5XX_RBBM_INT_0_MASK 0x00000038 +#define A5XX_RBBM_INT_0_MASK_RBBM_GPU_IDLE 0x00000001 +#define A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR 0x00000002 +#define A5XX_RBBM_INT_0_MASK_RBBM_TRANSFER_TIMEOUT 0x00000004 +#define A5XX_RBBM_INT_0_MASK_RBBM_ME_MS_TIMEOUT 0x00000008 +#define A5XX_RBBM_INT_0_MASK_RBBM_PFP_MS_TIMEOUT 0x00000010 +#define A5XX_RBBM_INT_0_MASK_RBBM_ETS_MS_TIMEOUT 0x00000020 +#define A5XX_RBBM_INT_0_MASK_RBBM_ATB_ASYNC_OVERFLOW 0x00000040 +#define A5XX_RBBM_INT_0_MASK_RBBM_GPC_ERROR 0x00000080 +#define A5XX_RBBM_INT_0_MASK_CP_SW 0x00000100 +#define A5XX_RBBM_INT_0_MASK_CP_HW_ERROR 0x00000200 +#define A5XX_RBBM_INT_0_MASK_CP_CCU_FLUSH_DEPTH_TS 0x00000400 +#define A5XX_RBBM_INT_0_MASK_CP_CCU_FLUSH_COLOR_TS 0x00000800 +#define A5XX_RBBM_INT_0_MASK_CP_CCU_RESOLVE_TS 0x00001000 +#define A5XX_RBBM_INT_0_MASK_CP_IB2 0x00002000 +#define A5XX_RBBM_INT_0_MASK_CP_IB1 0x00004000 +#define A5XX_RBBM_INT_0_MASK_CP_RB 0x00008000 +#define A5XX_RBBM_INT_0_MASK_CP_RB_DONE_TS 0x00020000 +#define A5XX_RBBM_INT_0_MASK_CP_WT_DONE_TS 0x00040000 +#define A5XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS 0x00100000 +#define A5XX_RBBM_INT_0_MASK_RBBM_ATB_BUS_OVERFLOW 0x00400000 +#define A5XX_RBBM_INT_0_MASK_MISC_HANG_DETECT 0x00800000 +#define A5XX_RBBM_INT_0_MASK_UCHE_OOB_ACCESS 0x01000000 +#define A5XX_RBBM_INT_0_MASK_UCHE_TRAP_INTR 0x02000000 +#define A5XX_RBBM_INT_0_MASK_DEBBUS_INTR_0 0x04000000 +#define A5XX_RBBM_INT_0_MASK_DEBBUS_INTR_1 0x08000000 +#define A5XX_RBBM_INT_0_MASK_GPMU_VOLTAGE_DROOP 0x10000000 +#define A5XX_RBBM_INT_0_MASK_GPMU_FIRMWARE 0x20000000 +#define A5XX_RBBM_INT_0_MASK_ISDB_CPU_IRQ 0x40000000 +#define A5XX_RBBM_INT_0_MASK_ISDB_UNDER_DEBUG 0x80000000 + +#define REG_A5XX_RBBM_AHB_DBG_CNTL 0x0000003f + +#define REG_A5XX_RBBM_EXT_VBIF_DBG_CNTL 0x00000041 + +#define REG_A5XX_RBBM_SW_RESET_CMD 0x00000043 + +#define REG_A5XX_RBBM_BLOCK_SW_RESET_CMD 0x00000045 + +#define REG_A5XX_RBBM_BLOCK_SW_RESET_CMD2 0x00000046 + +#define REG_A5XX_RBBM_DBG_LO_HI_GPIO 0x00000048 + +#define REG_A5XX_RBBM_EXT_TRACE_BUS_CNTL 0x00000049 + +#define REG_A5XX_RBBM_CLOCK_CNTL_TP0 0x0000004a + +#define REG_A5XX_RBBM_CLOCK_CNTL_TP1 0x0000004b + +#define REG_A5XX_RBBM_CLOCK_CNTL_TP2 0x0000004c + +#define REG_A5XX_RBBM_CLOCK_CNTL_TP3 0x0000004d + +#define REG_A5XX_RBBM_CLOCK_CNTL2_TP0 0x0000004e + +#define REG_A5XX_RBBM_CLOCK_CNTL2_TP1 0x0000004f + +#define REG_A5XX_RBBM_CLOCK_CNTL2_TP2 0x00000050 + +#define REG_A5XX_RBBM_CLOCK_CNTL2_TP3 0x00000051 + +#define REG_A5XX_RBBM_CLOCK_CNTL3_TP0 0x00000052 + +#define REG_A5XX_RBBM_CLOCK_CNTL3_TP1 0x00000053 + +#define REG_A5XX_RBBM_CLOCK_CNTL3_TP2 0x00000054 + +#define REG_A5XX_RBBM_CLOCK_CNTL3_TP3 0x00000055 + +#define REG_A5XX_RBBM_READ_AHB_THROUGH_DBG 0x00000059 + +#define REG_A5XX_RBBM_CLOCK_CNTL_UCHE 0x0000005a + +#define REG_A5XX_RBBM_CLOCK_CNTL2_UCHE 0x0000005b + +#define REG_A5XX_RBBM_CLOCK_CNTL3_UCHE 0x0000005c + +#define REG_A5XX_RBBM_CLOCK_CNTL4_UCHE 0x0000005d + +#define REG_A5XX_RBBM_CLOCK_HYST_UCHE 0x0000005e + +#define REG_A5XX_RBBM_CLOCK_DELAY_UCHE 0x0000005f + +#define REG_A5XX_RBBM_CLOCK_MODE_GPC 0x00000060 + +#define REG_A5XX_RBBM_CLOCK_DELAY_GPC 0x00000061 + +#define REG_A5XX_RBBM_CLOCK_HYST_GPC 0x00000062 + +#define REG_A5XX_RBBM_CLOCK_CNTL_TSE_RAS_RBBM 0x00000063 + +#define REG_A5XX_RBBM_CLOCK_HYST_TSE_RAS_RBBM 0x00000064 + +#define REG_A5XX_RBBM_CLOCK_DELAY_TSE_RAS_RBBM 0x00000065 + +#define REG_A5XX_RBBM_CLOCK_DELAY_HLSQ 0x00000066 + +#define REG_A5XX_RBBM_CLOCK_CNTL 0x00000067 + +#define REG_A5XX_RBBM_CLOCK_CNTL_SP0 0x00000068 + +#define REG_A5XX_RBBM_CLOCK_CNTL_SP1 0x00000069 + +#define REG_A5XX_RBBM_CLOCK_CNTL_SP2 0x0000006a + +#define REG_A5XX_RBBM_CLOCK_CNTL_SP3 0x0000006b + +#define REG_A5XX_RBBM_CLOCK_CNTL2_SP0 0x0000006c + +#define REG_A5XX_RBBM_CLOCK_CNTL2_SP1 0x0000006d + +#define REG_A5XX_RBBM_CLOCK_CNTL2_SP2 0x0000006e + +#define REG_A5XX_RBBM_CLOCK_CNTL2_SP3 0x0000006f + +#define REG_A5XX_RBBM_CLOCK_HYST_SP0 0x00000070 + +#define REG_A5XX_RBBM_CLOCK_HYST_SP1 0x00000071 + +#define REG_A5XX_RBBM_CLOCK_HYST_SP2 0x00000072 + +#define REG_A5XX_RBBM_CLOCK_HYST_SP3 0x00000073 + +#define REG_A5XX_RBBM_CLOCK_DELAY_SP0 0x00000074 + +#define REG_A5XX_RBBM_CLOCK_DELAY_SP1 0x00000075 + +#define REG_A5XX_RBBM_CLOCK_DELAY_SP2 0x00000076 + +#define REG_A5XX_RBBM_CLOCK_DELAY_SP3 0x00000077 + +#define REG_A5XX_RBBM_CLOCK_CNTL_RB0 0x00000078 + +#define REG_A5XX_RBBM_CLOCK_CNTL_RB1 0x00000079 + +#define REG_A5XX_RBBM_CLOCK_CNTL_RB2 0x0000007a + +#define REG_A5XX_RBBM_CLOCK_CNTL_RB3 0x0000007b + +#define REG_A5XX_RBBM_CLOCK_CNTL2_RB0 0x0000007c + +#define REG_A5XX_RBBM_CLOCK_CNTL2_RB1 0x0000007d + +#define REG_A5XX_RBBM_CLOCK_CNTL2_RB2 0x0000007e + +#define REG_A5XX_RBBM_CLOCK_CNTL2_RB3 0x0000007f + +#define REG_A5XX_RBBM_CLOCK_HYST_RAC 0x00000080 + +#define REG_A5XX_RBBM_CLOCK_DELAY_RAC 0x00000081 + +#define REG_A5XX_RBBM_CLOCK_CNTL_CCU0 0x00000082 + +#define REG_A5XX_RBBM_CLOCK_CNTL_CCU1 0x00000083 + +#define REG_A5XX_RBBM_CLOCK_CNTL_CCU2 0x00000084 + +#define REG_A5XX_RBBM_CLOCK_CNTL_CCU3 0x00000085 + +#define REG_A5XX_RBBM_CLOCK_HYST_RB_CCU0 0x00000086 + +#define REG_A5XX_RBBM_CLOCK_HYST_RB_CCU1 0x00000087 + +#define REG_A5XX_RBBM_CLOCK_HYST_RB_CCU2 0x00000088 + +#define REG_A5XX_RBBM_CLOCK_HYST_RB_CCU3 0x00000089 + +#define REG_A5XX_RBBM_CLOCK_CNTL_RAC 0x0000008a + +#define REG_A5XX_RBBM_CLOCK_CNTL2_RAC 0x0000008b + +#define REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_0 0x0000008c + +#define REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_1 0x0000008d + +#define REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_2 0x0000008e + +#define REG_A5XX_RBBM_CLOCK_DELAY_RB_CCU_L1_3 0x0000008f + +#define REG_A5XX_RBBM_CLOCK_HYST_VFD 0x00000090 + +#define REG_A5XX_RBBM_CLOCK_MODE_VFD 0x00000091 + +#define REG_A5XX_RBBM_CLOCK_DELAY_VFD 0x00000092 + +#define REG_A5XX_RBBM_AHB_CNTL0 0x00000093 + +#define REG_A5XX_RBBM_AHB_CNTL1 0x00000094 + +#define REG_A5XX_RBBM_AHB_CNTL2 0x00000095 + +#define REG_A5XX_RBBM_AHB_CMD 0x00000096 + +#define REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL11 0x0000009c + +#define REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL12 0x0000009d + +#define REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL13 0x0000009e + +#define REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL14 0x0000009f + +#define REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL15 0x000000a0 + +#define REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL16 0x000000a1 + +#define REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL17 0x000000a2 + +#define REG_A5XX_RBBM_INTERFACE_HANG_MASK_CNTL18 0x000000a3 + +#define REG_A5XX_RBBM_CLOCK_DELAY_TP0 0x000000a4 + +#define REG_A5XX_RBBM_CLOCK_DELAY_TP1 0x000000a5 + +#define REG_A5XX_RBBM_CLOCK_DELAY_TP2 0x000000a6 + +#define REG_A5XX_RBBM_CLOCK_DELAY_TP3 0x000000a7 + +#define REG_A5XX_RBBM_CLOCK_DELAY2_TP0 0x000000a8 + +#define REG_A5XX_RBBM_CLOCK_DELAY2_TP1 0x000000a9 + +#define REG_A5XX_RBBM_CLOCK_DELAY2_TP2 0x000000aa + +#define REG_A5XX_RBBM_CLOCK_DELAY2_TP3 0x000000ab + +#define REG_A5XX_RBBM_CLOCK_DELAY3_TP0 0x000000ac + +#define REG_A5XX_RBBM_CLOCK_DELAY3_TP1 0x000000ad + +#define REG_A5XX_RBBM_CLOCK_DELAY3_TP2 0x000000ae + +#define REG_A5XX_RBBM_CLOCK_DELAY3_TP3 0x000000af + +#define REG_A5XX_RBBM_CLOCK_HYST_TP0 0x000000b0 + +#define REG_A5XX_RBBM_CLOCK_HYST_TP1 0x000000b1 + +#define REG_A5XX_RBBM_CLOCK_HYST_TP2 0x000000b2 + +#define REG_A5XX_RBBM_CLOCK_HYST_TP3 0x000000b3 + +#define REG_A5XX_RBBM_CLOCK_HYST2_TP0 0x000000b4 + +#define REG_A5XX_RBBM_CLOCK_HYST2_TP1 0x000000b5 + +#define REG_A5XX_RBBM_CLOCK_HYST2_TP2 0x000000b6 + +#define REG_A5XX_RBBM_CLOCK_HYST2_TP3 0x000000b7 + +#define REG_A5XX_RBBM_CLOCK_HYST3_TP0 0x000000b8 + +#define REG_A5XX_RBBM_CLOCK_HYST3_TP1 0x000000b9 + +#define REG_A5XX_RBBM_CLOCK_HYST3_TP2 0x000000ba + +#define REG_A5XX_RBBM_CLOCK_HYST3_TP3 0x000000bb + +#define REG_A5XX_RBBM_CLOCK_CNTL_GPMU 0x000000c8 + +#define REG_A5XX_RBBM_CLOCK_DELAY_GPMU 0x000000c9 + +#define REG_A5XX_RBBM_CLOCK_HYST_GPMU 0x000000ca + +#define REG_A5XX_RBBM_PERFCTR_CP_0_LO 0x000003a0 + +#define REG_A5XX_RBBM_PERFCTR_CP_0_HI 0x000003a1 + +#define REG_A5XX_RBBM_PERFCTR_CP_1_LO 0x000003a2 + +#define REG_A5XX_RBBM_PERFCTR_CP_1_HI 0x000003a3 + +#define REG_A5XX_RBBM_PERFCTR_CP_2_LO 0x000003a4 + +#define REG_A5XX_RBBM_PERFCTR_CP_2_HI 0x000003a5 + +#define REG_A5XX_RBBM_PERFCTR_CP_3_LO 0x000003a6 + +#define REG_A5XX_RBBM_PERFCTR_CP_3_HI 0x000003a7 + +#define REG_A5XX_RBBM_PERFCTR_CP_4_LO 0x000003a8 + +#define REG_A5XX_RBBM_PERFCTR_CP_4_HI 0x000003a9 + +#define REG_A5XX_RBBM_PERFCTR_CP_5_LO 0x000003aa + +#define REG_A5XX_RBBM_PERFCTR_CP_5_HI 0x000003ab + +#define REG_A5XX_RBBM_PERFCTR_CP_6_LO 0x000003ac + +#define REG_A5XX_RBBM_PERFCTR_CP_6_HI 0x000003ad + +#define REG_A5XX_RBBM_PERFCTR_CP_7_LO 0x000003ae + +#define REG_A5XX_RBBM_PERFCTR_CP_7_HI 0x000003af + +#define REG_A5XX_RBBM_PERFCTR_RBBM_0_LO 0x000003b0 + +#define REG_A5XX_RBBM_PERFCTR_RBBM_0_HI 0x000003b1 + +#define REG_A5XX_RBBM_PERFCTR_RBBM_1_LO 0x000003b2 + +#define REG_A5XX_RBBM_PERFCTR_RBBM_1_HI 0x000003b3 + +#define REG_A5XX_RBBM_PERFCTR_RBBM_2_LO 0x000003b4 + +#define REG_A5XX_RBBM_PERFCTR_RBBM_2_HI 0x000003b5 + +#define REG_A5XX_RBBM_PERFCTR_RBBM_3_LO 0x000003b6 + +#define REG_A5XX_RBBM_PERFCTR_RBBM_3_HI 0x000003b7 + +#define REG_A5XX_RBBM_PERFCTR_PC_0_LO 0x000003b8 + +#define REG_A5XX_RBBM_PERFCTR_PC_0_HI 0x000003b9 + +#define REG_A5XX_RBBM_PERFCTR_PC_1_LO 0x000003ba + +#define REG_A5XX_RBBM_PERFCTR_PC_1_HI 0x000003bb + +#define REG_A5XX_RBBM_PERFCTR_PC_2_LO 0x000003bc + +#define REG_A5XX_RBBM_PERFCTR_PC_2_HI 0x000003bd + +#define REG_A5XX_RBBM_PERFCTR_PC_3_LO 0x000003be + +#define REG_A5XX_RBBM_PERFCTR_PC_3_HI 0x000003bf + +#define REG_A5XX_RBBM_PERFCTR_PC_4_LO 0x000003c0 + +#define REG_A5XX_RBBM_PERFCTR_PC_4_HI 0x000003c1 + +#define REG_A5XX_RBBM_PERFCTR_PC_5_LO 0x000003c2 + +#define REG_A5XX_RBBM_PERFCTR_PC_5_HI 0x000003c3 + +#define REG_A5XX_RBBM_PERFCTR_PC_6_LO 0x000003c4 + +#define REG_A5XX_RBBM_PERFCTR_PC_6_HI 0x000003c5 + +#define REG_A5XX_RBBM_PERFCTR_PC_7_LO 0x000003c6 + +#define REG_A5XX_RBBM_PERFCTR_PC_7_HI 0x000003c7 + +#define REG_A5XX_RBBM_PERFCTR_VFD_0_LO 0x000003c8 + +#define REG_A5XX_RBBM_PERFCTR_VFD_0_HI 0x000003c9 + +#define REG_A5XX_RBBM_PERFCTR_VFD_1_LO 0x000003ca + +#define REG_A5XX_RBBM_PERFCTR_VFD_1_HI 0x000003cb + +#define REG_A5XX_RBBM_PERFCTR_VFD_2_LO 0x000003cc + +#define REG_A5XX_RBBM_PERFCTR_VFD_2_HI 0x000003cd + +#define REG_A5XX_RBBM_PERFCTR_VFD_3_LO 0x000003ce + +#define REG_A5XX_RBBM_PERFCTR_VFD_3_HI 0x000003cf + +#define REG_A5XX_RBBM_PERFCTR_VFD_4_LO 0x000003d0 + +#define REG_A5XX_RBBM_PERFCTR_VFD_4_HI 0x000003d1 + +#define REG_A5XX_RBBM_PERFCTR_VFD_5_LO 0x000003d2 + +#define REG_A5XX_RBBM_PERFCTR_VFD_5_HI 0x000003d3 + +#define REG_A5XX_RBBM_PERFCTR_VFD_6_LO 0x000003d4 + +#define REG_A5XX_RBBM_PERFCTR_VFD_6_HI 0x000003d5 + +#define REG_A5XX_RBBM_PERFCTR_VFD_7_LO 0x000003d6 + +#define REG_A5XX_RBBM_PERFCTR_VFD_7_HI 0x000003d7 + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_0_LO 0x000003d8 + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_0_HI 0x000003d9 + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_1_LO 0x000003da + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_1_HI 0x000003db + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_2_LO 0x000003dc + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_2_HI 0x000003dd + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_3_LO 0x000003de + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_3_HI 0x000003df + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_4_LO 0x000003e0 + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_4_HI 0x000003e1 + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_5_LO 0x000003e2 + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_5_HI 0x000003e3 + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_6_LO 0x000003e4 + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_6_HI 0x000003e5 + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_7_LO 0x000003e6 + +#define REG_A5XX_RBBM_PERFCTR_HLSQ_7_HI 0x000003e7 + +#define REG_A5XX_RBBM_PERFCTR_VPC_0_LO 0x000003e8 + +#define REG_A5XX_RBBM_PERFCTR_VPC_0_HI 0x000003e9 + +#define REG_A5XX_RBBM_PERFCTR_VPC_1_LO 0x000003ea + +#define REG_A5XX_RBBM_PERFCTR_VPC_1_HI 0x000003eb + +#define REG_A5XX_RBBM_PERFCTR_VPC_2_LO 0x000003ec + +#define REG_A5XX_RBBM_PERFCTR_VPC_2_HI 0x000003ed + +#define REG_A5XX_RBBM_PERFCTR_VPC_3_LO 0x000003ee + +#define REG_A5XX_RBBM_PERFCTR_VPC_3_HI 0x000003ef + +#define REG_A5XX_RBBM_PERFCTR_CCU_0_LO 0x000003f0 + +#define REG_A5XX_RBBM_PERFCTR_CCU_0_HI 0x000003f1 + +#define REG_A5XX_RBBM_PERFCTR_CCU_1_LO 0x000003f2 + +#define REG_A5XX_RBBM_PERFCTR_CCU_1_HI 0x000003f3 + +#define REG_A5XX_RBBM_PERFCTR_CCU_2_LO 0x000003f4 + +#define REG_A5XX_RBBM_PERFCTR_CCU_2_HI 0x000003f5 + +#define REG_A5XX_RBBM_PERFCTR_CCU_3_LO 0x000003f6 + +#define REG_A5XX_RBBM_PERFCTR_CCU_3_HI 0x000003f7 + +#define REG_A5XX_RBBM_PERFCTR_TSE_0_LO 0x000003f8 + +#define REG_A5XX_RBBM_PERFCTR_TSE_0_HI 0x000003f9 + +#define REG_A5XX_RBBM_PERFCTR_TSE_1_LO 0x000003fa + +#define REG_A5XX_RBBM_PERFCTR_TSE_1_HI 0x000003fb + +#define REG_A5XX_RBBM_PERFCTR_TSE_2_LO 0x000003fc + +#define REG_A5XX_RBBM_PERFCTR_TSE_2_HI 0x000003fd + +#define REG_A5XX_RBBM_PERFCTR_TSE_3_LO 0x000003fe + +#define REG_A5XX_RBBM_PERFCTR_TSE_3_HI 0x000003ff + +#define REG_A5XX_RBBM_PERFCTR_RAS_0_LO 0x00000400 + +#define REG_A5XX_RBBM_PERFCTR_RAS_0_HI 0x00000401 + +#define REG_A5XX_RBBM_PERFCTR_RAS_1_LO 0x00000402 + +#define REG_A5XX_RBBM_PERFCTR_RAS_1_HI 0x00000403 + +#define REG_A5XX_RBBM_PERFCTR_RAS_2_LO 0x00000404 + +#define REG_A5XX_RBBM_PERFCTR_RAS_2_HI 0x00000405 + +#define REG_A5XX_RBBM_PERFCTR_RAS_3_LO 0x00000406 + +#define REG_A5XX_RBBM_PERFCTR_RAS_3_HI 0x00000407 + +#define REG_A5XX_RBBM_PERFCTR_UCHE_0_LO 0x00000408 + +#define REG_A5XX_RBBM_PERFCTR_UCHE_0_HI 0x00000409 + +#define REG_A5XX_RBBM_PERFCTR_UCHE_1_LO 0x0000040a + +#define REG_A5XX_RBBM_PERFCTR_UCHE_1_HI 0x0000040b + +#define REG_A5XX_RBBM_PERFCTR_UCHE_2_LO 0x0000040c + +#define REG_A5XX_RBBM_PERFCTR_UCHE_2_HI 0x0000040d + +#define REG_A5XX_RBBM_PERFCTR_UCHE_3_LO 0x0000040e + +#define REG_A5XX_RBBM_PERFCTR_UCHE_3_HI 0x0000040f + +#define REG_A5XX_RBBM_PERFCTR_UCHE_4_LO 0x00000410 + +#define REG_A5XX_RBBM_PERFCTR_UCHE_4_HI 0x00000411 + +#define REG_A5XX_RBBM_PERFCTR_UCHE_5_LO 0x00000412 + +#define REG_A5XX_RBBM_PERFCTR_UCHE_5_HI 0x00000413 + +#define REG_A5XX_RBBM_PERFCTR_UCHE_6_LO 0x00000414 + +#define REG_A5XX_RBBM_PERFCTR_UCHE_6_HI 0x00000415 + +#define REG_A5XX_RBBM_PERFCTR_UCHE_7_LO 0x00000416 + +#define REG_A5XX_RBBM_PERFCTR_UCHE_7_HI 0x00000417 + +#define REG_A5XX_RBBM_PERFCTR_TP_0_LO 0x00000418 + +#define REG_A5XX_RBBM_PERFCTR_TP_0_HI 0x00000419 + +#define REG_A5XX_RBBM_PERFCTR_TP_1_LO 0x0000041a + +#define REG_A5XX_RBBM_PERFCTR_TP_1_HI 0x0000041b + +#define REG_A5XX_RBBM_PERFCTR_TP_2_LO 0x0000041c + +#define REG_A5XX_RBBM_PERFCTR_TP_2_HI 0x0000041d + +#define REG_A5XX_RBBM_PERFCTR_TP_3_LO 0x0000041e + +#define REG_A5XX_RBBM_PERFCTR_TP_3_HI 0x0000041f + +#define REG_A5XX_RBBM_PERFCTR_TP_4_LO 0x00000420 + +#define REG_A5XX_RBBM_PERFCTR_TP_4_HI 0x00000421 + +#define REG_A5XX_RBBM_PERFCTR_TP_5_LO 0x00000422 + +#define REG_A5XX_RBBM_PERFCTR_TP_5_HI 0x00000423 + +#define REG_A5XX_RBBM_PERFCTR_TP_6_LO 0x00000424 + +#define REG_A5XX_RBBM_PERFCTR_TP_6_HI 0x00000425 + +#define REG_A5XX_RBBM_PERFCTR_TP_7_LO 0x00000426 + +#define REG_A5XX_RBBM_PERFCTR_TP_7_HI 0x00000427 + +#define REG_A5XX_RBBM_PERFCTR_SP_0_LO 0x00000428 + +#define REG_A5XX_RBBM_PERFCTR_SP_0_HI 0x00000429 + +#define REG_A5XX_RBBM_PERFCTR_SP_1_LO 0x0000042a + +#define REG_A5XX_RBBM_PERFCTR_SP_1_HI 0x0000042b + +#define REG_A5XX_RBBM_PERFCTR_SP_2_LO 0x0000042c + +#define REG_A5XX_RBBM_PERFCTR_SP_2_HI 0x0000042d + +#define REG_A5XX_RBBM_PERFCTR_SP_3_LO 0x0000042e + +#define REG_A5XX_RBBM_PERFCTR_SP_3_HI 0x0000042f + +#define REG_A5XX_RBBM_PERFCTR_SP_4_LO 0x00000430 + +#define REG_A5XX_RBBM_PERFCTR_SP_4_HI 0x00000431 + +#define REG_A5XX_RBBM_PERFCTR_SP_5_LO 0x00000432 + +#define REG_A5XX_RBBM_PERFCTR_SP_5_HI 0x00000433 + +#define REG_A5XX_RBBM_PERFCTR_SP_6_LO 0x00000434 + +#define REG_A5XX_RBBM_PERFCTR_SP_6_HI 0x00000435 + +#define REG_A5XX_RBBM_PERFCTR_SP_7_LO 0x00000436 + +#define REG_A5XX_RBBM_PERFCTR_SP_7_HI 0x00000437 + +#define REG_A5XX_RBBM_PERFCTR_SP_8_LO 0x00000438 + +#define REG_A5XX_RBBM_PERFCTR_SP_8_HI 0x00000439 + +#define REG_A5XX_RBBM_PERFCTR_SP_9_LO 0x0000043a + +#define REG_A5XX_RBBM_PERFCTR_SP_9_HI 0x0000043b + +#define REG_A5XX_RBBM_PERFCTR_SP_10_LO 0x0000043c + +#define REG_A5XX_RBBM_PERFCTR_SP_10_HI 0x0000043d + +#define REG_A5XX_RBBM_PERFCTR_SP_11_LO 0x0000043e + +#define REG_A5XX_RBBM_PERFCTR_SP_11_HI 0x0000043f + +#define REG_A5XX_RBBM_PERFCTR_RB_0_LO 0x00000440 + +#define REG_A5XX_RBBM_PERFCTR_RB_0_HI 0x00000441 + +#define REG_A5XX_RBBM_PERFCTR_RB_1_LO 0x00000442 + +#define REG_A5XX_RBBM_PERFCTR_RB_1_HI 0x00000443 + +#define REG_A5XX_RBBM_PERFCTR_RB_2_LO 0x00000444 + +#define REG_A5XX_RBBM_PERFCTR_RB_2_HI 0x00000445 + +#define REG_A5XX_RBBM_PERFCTR_RB_3_LO 0x00000446 + +#define REG_A5XX_RBBM_PERFCTR_RB_3_HI 0x00000447 + +#define REG_A5XX_RBBM_PERFCTR_RB_4_LO 0x00000448 + +#define REG_A5XX_RBBM_PERFCTR_RB_4_HI 0x00000449 + +#define REG_A5XX_RBBM_PERFCTR_RB_5_LO 0x0000044a + +#define REG_A5XX_RBBM_PERFCTR_RB_5_HI 0x0000044b + +#define REG_A5XX_RBBM_PERFCTR_RB_6_LO 0x0000044c + +#define REG_A5XX_RBBM_PERFCTR_RB_6_HI 0x0000044d + +#define REG_A5XX_RBBM_PERFCTR_RB_7_LO 0x0000044e + +#define REG_A5XX_RBBM_PERFCTR_RB_7_HI 0x0000044f + +#define REG_A5XX_RBBM_PERFCTR_VSC_0_LO 0x00000450 + +#define REG_A5XX_RBBM_PERFCTR_VSC_0_HI 0x00000451 + +#define REG_A5XX_RBBM_PERFCTR_VSC_1_LO 0x00000452 + +#define REG_A5XX_RBBM_PERFCTR_VSC_1_HI 0x00000453 + +#define REG_A5XX_RBBM_PERFCTR_LRZ_0_LO 0x00000454 + +#define REG_A5XX_RBBM_PERFCTR_LRZ_0_HI 0x00000455 + +#define REG_A5XX_RBBM_PERFCTR_LRZ_1_LO 0x00000456 + +#define REG_A5XX_RBBM_PERFCTR_LRZ_1_HI 0x00000457 + +#define REG_A5XX_RBBM_PERFCTR_LRZ_2_LO 0x00000458 + +#define REG_A5XX_RBBM_PERFCTR_LRZ_2_HI 0x00000459 + +#define REG_A5XX_RBBM_PERFCTR_LRZ_3_LO 0x0000045a + +#define REG_A5XX_RBBM_PERFCTR_LRZ_3_HI 0x0000045b + +#define REG_A5XX_RBBM_PERFCTR_CMP_0_LO 0x0000045c + +#define REG_A5XX_RBBM_PERFCTR_CMP_0_HI 0x0000045d + +#define REG_A5XX_RBBM_PERFCTR_CMP_1_LO 0x0000045e + +#define REG_A5XX_RBBM_PERFCTR_CMP_1_HI 0x0000045f + +#define REG_A5XX_RBBM_PERFCTR_CMP_2_LO 0x00000460 + +#define REG_A5XX_RBBM_PERFCTR_CMP_2_HI 0x00000461 + +#define REG_A5XX_RBBM_PERFCTR_CMP_3_LO 0x00000462 + +#define REG_A5XX_RBBM_PERFCTR_CMP_3_HI 0x00000463 + +#define REG_A5XX_RBBM_PERFCTR_RBBM_SEL_0 0x0000046b + +#define REG_A5XX_RBBM_PERFCTR_RBBM_SEL_1 0x0000046c + +#define REG_A5XX_RBBM_PERFCTR_RBBM_SEL_2 0x0000046d + +#define REG_A5XX_RBBM_PERFCTR_RBBM_SEL_3 0x0000046e + +#define REG_A5XX_RBBM_ALWAYSON_COUNTER_LO 0x000004d2 + +#define REG_A5XX_RBBM_ALWAYSON_COUNTER_HI 0x000004d3 + +#define REG_A5XX_RBBM_STATUS 0x000004f5 +#define A5XX_RBBM_STATUS_GPU_BUSY_IGN_AHB 0x80000000 +#define A5XX_RBBM_STATUS_GPU_BUSY_IGN_AHB_CP 0x40000000 +#define A5XX_RBBM_STATUS_HLSQ_BUSY 0x20000000 +#define A5XX_RBBM_STATUS_VSC_BUSY 0x10000000 +#define A5XX_RBBM_STATUS_TPL1_BUSY 0x08000000 +#define A5XX_RBBM_STATUS_SP_BUSY 0x04000000 +#define A5XX_RBBM_STATUS_UCHE_BUSY 0x02000000 +#define A5XX_RBBM_STATUS_VPC_BUSY 0x01000000 +#define A5XX_RBBM_STATUS_VFDP_BUSY 0x00800000 +#define A5XX_RBBM_STATUS_VFD_BUSY 0x00400000 +#define A5XX_RBBM_STATUS_TESS_BUSY 0x00200000 +#define A5XX_RBBM_STATUS_PC_VSD_BUSY 0x00100000 +#define A5XX_RBBM_STATUS_PC_DCALL_BUSY 0x00080000 +#define A5XX_RBBM_STATUS_GPMU_SLAVE_BUSY 0x00040000 +#define A5XX_RBBM_STATUS_DCOM_BUSY 0x00020000 +#define A5XX_RBBM_STATUS_COM_BUSY 0x00010000 +#define A5XX_RBBM_STATUS_LRZ_BUZY 0x00008000 +#define A5XX_RBBM_STATUS_A2D_DSP_BUSY 0x00004000 +#define A5XX_RBBM_STATUS_CCUFCHE_BUSY 0x00002000 +#define A5XX_RBBM_STATUS_RB_BUSY 0x00001000 +#define A5XX_RBBM_STATUS_RAS_BUSY 0x00000800 +#define A5XX_RBBM_STATUS_TSE_BUSY 0x00000400 +#define A5XX_RBBM_STATUS_VBIF_BUSY 0x00000200 +#define A5XX_RBBM_STATUS_GPU_BUSY_IGN_AHB_HYST 0x00000100 +#define A5XX_RBBM_STATUS_CP_BUSY_IGN_HYST 0x00000080 +#define A5XX_RBBM_STATUS_CP_BUSY 0x00000040 +#define A5XX_RBBM_STATUS_GPMU_MASTER_BUSY 0x00000020 +#define A5XX_RBBM_STATUS_CP_CRASH_BUSY 0x00000010 +#define A5XX_RBBM_STATUS_CP_ETS_BUSY 0x00000008 +#define A5XX_RBBM_STATUS_CP_PFP_BUSY 0x00000004 +#define A5XX_RBBM_STATUS_CP_ME_BUSY 0x00000002 +#define A5XX_RBBM_STATUS_HI_BUSY 0x00000001 + +#define REG_A5XX_RBBM_STATUS3 0x00000530 + +#define REG_A5XX_RBBM_INT_0_STATUS 0x000004e1 + +#define REG_A5XX_RBBM_AHB_ME_SPLIT_STATUS 0x000004f0 + +#define REG_A5XX_RBBM_AHB_PFP_SPLIT_STATUS 0x000004f1 + +#define REG_A5XX_RBBM_AHB_ETS_SPLIT_STATUS 0x000004f3 + +#define REG_A5XX_RBBM_AHB_ERROR_STATUS 0x000004f4 + +#define REG_A5XX_RBBM_PERFCTR_CNTL 0x00000464 + +#define REG_A5XX_RBBM_PERFCTR_LOAD_CMD0 0x00000465 + +#define REG_A5XX_RBBM_PERFCTR_LOAD_CMD1 0x00000466 + +#define REG_A5XX_RBBM_PERFCTR_LOAD_CMD2 0x00000467 + +#define REG_A5XX_RBBM_PERFCTR_LOAD_CMD3 0x00000468 + +#define REG_A5XX_RBBM_PERFCTR_LOAD_VALUE_LO 0x00000469 + +#define REG_A5XX_RBBM_PERFCTR_LOAD_VALUE_HI 0x0000046a + +#define REG_A5XX_RBBM_PERFCTR_RBBM_SEL_0 0x0000046b + +#define REG_A5XX_RBBM_PERFCTR_RBBM_SEL_1 0x0000046c + +#define REG_A5XX_RBBM_PERFCTR_RBBM_SEL_2 0x0000046d + +#define REG_A5XX_RBBM_PERFCTR_RBBM_SEL_3 0x0000046e + +#define REG_A5XX_RBBM_PERFCTR_GPU_BUSY_MASKED 0x0000046f + +#define REG_A5XX_RBBM_AHB_ERROR 0x000004ed + +#define REG_A5XX_RBBM_CFG_DBGBUS_EVENT_LOGIC 0x00000504 + +#define REG_A5XX_RBBM_CFG_DBGBUS_OVER 0x00000505 + +#define REG_A5XX_RBBM_CFG_DBGBUS_COUNT0 0x00000506 + +#define REG_A5XX_RBBM_CFG_DBGBUS_COUNT1 0x00000507 + +#define REG_A5XX_RBBM_CFG_DBGBUS_COUNT2 0x00000508 + +#define REG_A5XX_RBBM_CFG_DBGBUS_COUNT3 0x00000509 + +#define REG_A5XX_RBBM_CFG_DBGBUS_COUNT4 0x0000050a + +#define REG_A5XX_RBBM_CFG_DBGBUS_COUNT5 0x0000050b + +#define REG_A5XX_RBBM_CFG_DBGBUS_TRACE_ADDR 0x0000050c + +#define REG_A5XX_RBBM_CFG_DBGBUS_TRACE_BUF0 0x0000050d + +#define REG_A5XX_RBBM_CFG_DBGBUS_TRACE_BUF1 0x0000050e + +#define REG_A5XX_RBBM_CFG_DBGBUS_TRACE_BUF2 0x0000050f + +#define REG_A5XX_RBBM_CFG_DBGBUS_TRACE_BUF3 0x00000510 + +#define REG_A5XX_RBBM_CFG_DBGBUS_TRACE_BUF4 0x00000511 + +#define REG_A5XX_RBBM_CFG_DBGBUS_MISR0 0x00000512 + +#define REG_A5XX_RBBM_CFG_DBGBUS_MISR1 0x00000513 + +#define REG_A5XX_RBBM_ISDB_CNT 0x00000533 + +#define REG_A5XX_RBBM_SECVID_TRUST_CONFIG 0x0000f000 + +#define REG_A5XX_RBBM_SECVID_TRUST_CNTL 0x0000f400 + +#define REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_LO 0x0000f800 + +#define REG_A5XX_RBBM_SECVID_TSB_TRUSTED_BASE_HI 0x0000f801 + +#define REG_A5XX_RBBM_SECVID_TSB_TRUSTED_SIZE 0x0000f802 + +#define REG_A5XX_RBBM_SECVID_TSB_CNTL 0x0000f803 + +#define REG_A5XX_RBBM_SECVID_TSB_COMP_STATUS_LO 0x0000f804 + +#define REG_A5XX_RBBM_SECVID_TSB_COMP_STATUS_HI 0x0000f805 + +#define REG_A5XX_RBBM_SECVID_TSB_UCHE_STATUS_LO 0x0000f806 + +#define REG_A5XX_RBBM_SECVID_TSB_UCHE_STATUS_HI 0x0000f807 + +#define REG_A5XX_RBBM_SECVID_TSB_ADDR_MODE_CNTL 0x0000f810 + +#define REG_A5XX_VSC_BIN_SIZE 0x00000bc2 +#define A5XX_VSC_BIN_SIZE_WIDTH__MASK 0x000000ff +#define A5XX_VSC_BIN_SIZE_WIDTH__SHIFT 0 +static inline uint32_t A5XX_VSC_BIN_SIZE_WIDTH(uint32_t val) +{ + return ((val >> 5) << A5XX_VSC_BIN_SIZE_WIDTH__SHIFT) & A5XX_VSC_BIN_SIZE_WIDTH__MASK; +} +#define A5XX_VSC_BIN_SIZE_HEIGHT__MASK 0x0001fe00 +#define A5XX_VSC_BIN_SIZE_HEIGHT__SHIFT 9 +static inline uint32_t A5XX_VSC_BIN_SIZE_HEIGHT(uint32_t val) +{ + return ((val >> 5) << A5XX_VSC_BIN_SIZE_HEIGHT__SHIFT) & A5XX_VSC_BIN_SIZE_HEIGHT__MASK; +} + +#define REG_A5XX_VSC_SIZE_ADDRESS_LO 0x00000bc3 + +#define REG_A5XX_VSC_SIZE_ADDRESS_HI 0x00000bc4 + +#define REG_A5XX_UNKNOWN_0BC5 0x00000bc5 + +#define REG_A5XX_UNKNOWN_0BC6 0x00000bc6 + +static inline uint32_t REG_A5XX_VSC_PIPE_CONFIG(uint32_t i0) { return 0x00000bd0 + 0x1*i0; } + +static inline uint32_t REG_A5XX_VSC_PIPE_CONFIG_REG(uint32_t i0) { return 0x00000bd0 + 0x1*i0; } +#define A5XX_VSC_PIPE_CONFIG_REG_X__MASK 0x000003ff +#define A5XX_VSC_PIPE_CONFIG_REG_X__SHIFT 0 +static inline uint32_t A5XX_VSC_PIPE_CONFIG_REG_X(uint32_t val) +{ + return ((val) << A5XX_VSC_PIPE_CONFIG_REG_X__SHIFT) & A5XX_VSC_PIPE_CONFIG_REG_X__MASK; +} +#define A5XX_VSC_PIPE_CONFIG_REG_Y__MASK 0x000ffc00 +#define A5XX_VSC_PIPE_CONFIG_REG_Y__SHIFT 10 +static inline uint32_t A5XX_VSC_PIPE_CONFIG_REG_Y(uint32_t val) +{ + return ((val) << A5XX_VSC_PIPE_CONFIG_REG_Y__SHIFT) & A5XX_VSC_PIPE_CONFIG_REG_Y__MASK; +} +#define A5XX_VSC_PIPE_CONFIG_REG_W__MASK 0x00f00000 +#define A5XX_VSC_PIPE_CONFIG_REG_W__SHIFT 20 +static inline uint32_t A5XX_VSC_PIPE_CONFIG_REG_W(uint32_t val) +{ + return ((val) << A5XX_VSC_PIPE_CONFIG_REG_W__SHIFT) & A5XX_VSC_PIPE_CONFIG_REG_W__MASK; +} +#define A5XX_VSC_PIPE_CONFIG_REG_H__MASK 0x0f000000 +#define A5XX_VSC_PIPE_CONFIG_REG_H__SHIFT 24 +static inline uint32_t A5XX_VSC_PIPE_CONFIG_REG_H(uint32_t val) +{ + return ((val) << A5XX_VSC_PIPE_CONFIG_REG_H__SHIFT) & A5XX_VSC_PIPE_CONFIG_REG_H__MASK; +} + +static inline uint32_t REG_A5XX_VSC_PIPE_DATA_ADDRESS(uint32_t i0) { return 0x00000be0 + 0x2*i0; } + +static inline uint32_t REG_A5XX_VSC_PIPE_DATA_ADDRESS_LO(uint32_t i0) { return 0x00000be0 + 0x2*i0; } + +static inline uint32_t REG_A5XX_VSC_PIPE_DATA_ADDRESS_HI(uint32_t i0) { return 0x00000be1 + 0x2*i0; } + +static inline uint32_t REG_A5XX_VSC_PIPE_DATA_LENGTH(uint32_t i0) { return 0x00000c00 + 0x1*i0; } + +static inline uint32_t REG_A5XX_VSC_PIPE_DATA_LENGTH_REG(uint32_t i0) { return 0x00000c00 + 0x1*i0; } + +#define REG_A5XX_VSC_PERFCTR_VSC_SEL_0 0x00000c60 + +#define REG_A5XX_VSC_PERFCTR_VSC_SEL_1 0x00000c61 + +#define REG_A5XX_VSC_RESOLVE_CNTL 0x00000cdd +#define A5XX_VSC_RESOLVE_CNTL_WINDOW_OFFSET_DISABLE 0x80000000 +#define A5XX_VSC_RESOLVE_CNTL_X__MASK 0x00007fff +#define A5XX_VSC_RESOLVE_CNTL_X__SHIFT 0 +static inline uint32_t A5XX_VSC_RESOLVE_CNTL_X(uint32_t val) +{ + return ((val) << A5XX_VSC_RESOLVE_CNTL_X__SHIFT) & A5XX_VSC_RESOLVE_CNTL_X__MASK; +} +#define A5XX_VSC_RESOLVE_CNTL_Y__MASK 0x7fff0000 +#define A5XX_VSC_RESOLVE_CNTL_Y__SHIFT 16 +static inline uint32_t A5XX_VSC_RESOLVE_CNTL_Y(uint32_t val) +{ + return ((val) << A5XX_VSC_RESOLVE_CNTL_Y__SHIFT) & A5XX_VSC_RESOLVE_CNTL_Y__MASK; +} + +#define REG_A5XX_GRAS_ADDR_MODE_CNTL 0x00000c81 + +#define REG_A5XX_GRAS_PERFCTR_TSE_SEL_0 0x00000c90 + +#define REG_A5XX_GRAS_PERFCTR_TSE_SEL_1 0x00000c91 + +#define REG_A5XX_GRAS_PERFCTR_TSE_SEL_2 0x00000c92 + +#define REG_A5XX_GRAS_PERFCTR_TSE_SEL_3 0x00000c93 + +#define REG_A5XX_GRAS_PERFCTR_RAS_SEL_0 0x00000c94 + +#define REG_A5XX_GRAS_PERFCTR_RAS_SEL_1 0x00000c95 + +#define REG_A5XX_GRAS_PERFCTR_RAS_SEL_2 0x00000c96 + +#define REG_A5XX_GRAS_PERFCTR_RAS_SEL_3 0x00000c97 + +#define REG_A5XX_GRAS_PERFCTR_LRZ_SEL_0 0x00000c98 + +#define REG_A5XX_GRAS_PERFCTR_LRZ_SEL_1 0x00000c99 + +#define REG_A5XX_GRAS_PERFCTR_LRZ_SEL_2 0x00000c9a + +#define REG_A5XX_GRAS_PERFCTR_LRZ_SEL_3 0x00000c9b + +#define REG_A5XX_RB_DBG_ECO_CNTL 0x00000cc4 + +#define REG_A5XX_RB_ADDR_MODE_CNTL 0x00000cc5 + +#define REG_A5XX_RB_MODE_CNTL 0x00000cc6 + +#define REG_A5XX_RB_CCU_CNTL 0x00000cc7 + +#define REG_A5XX_RB_PERFCTR_RB_SEL_0 0x00000cd0 + +#define REG_A5XX_RB_PERFCTR_RB_SEL_1 0x00000cd1 + +#define REG_A5XX_RB_PERFCTR_RB_SEL_2 0x00000cd2 + +#define REG_A5XX_RB_PERFCTR_RB_SEL_3 0x00000cd3 + +#define REG_A5XX_RB_PERFCTR_RB_SEL_4 0x00000cd4 + +#define REG_A5XX_RB_PERFCTR_RB_SEL_5 0x00000cd5 + +#define REG_A5XX_RB_PERFCTR_RB_SEL_6 0x00000cd6 + +#define REG_A5XX_RB_PERFCTR_RB_SEL_7 0x00000cd7 + +#define REG_A5XX_RB_PERFCTR_CCU_SEL_0 0x00000cd8 + +#define REG_A5XX_RB_PERFCTR_CCU_SEL_1 0x00000cd9 + +#define REG_A5XX_RB_PERFCTR_CCU_SEL_2 0x00000cda + +#define REG_A5XX_RB_PERFCTR_CCU_SEL_3 0x00000cdb + +#define REG_A5XX_RB_POWERCTR_RB_SEL_0 0x00000ce0 + +#define REG_A5XX_RB_POWERCTR_RB_SEL_1 0x00000ce1 + +#define REG_A5XX_RB_POWERCTR_RB_SEL_2 0x00000ce2 + +#define REG_A5XX_RB_POWERCTR_RB_SEL_3 0x00000ce3 + +#define REG_A5XX_RB_POWERCTR_CCU_SEL_0 0x00000ce4 + +#define REG_A5XX_RB_POWERCTR_CCU_SEL_1 0x00000ce5 + +#define REG_A5XX_RB_PERFCTR_CMP_SEL_0 0x00000cec + +#define REG_A5XX_RB_PERFCTR_CMP_SEL_1 0x00000ced + +#define REG_A5XX_RB_PERFCTR_CMP_SEL_2 0x00000cee + +#define REG_A5XX_RB_PERFCTR_CMP_SEL_3 0x00000cef + +#define REG_A5XX_PC_DBG_ECO_CNTL 0x00000d00 +#define A5XX_PC_DBG_ECO_CNTL_TWOPASSUSEWFI 0x00000100 + +#define REG_A5XX_PC_ADDR_MODE_CNTL 0x00000d01 + +#define REG_A5XX_PC_MODE_CNTL 0x00000d02 + +#define REG_A5XX_PC_INDEX_BUF_LO 0x00000d04 + +#define REG_A5XX_PC_INDEX_BUF_HI 0x00000d05 + +#define REG_A5XX_PC_START_INDEX 0x00000d06 + +#define REG_A5XX_PC_MAX_INDEX 0x00000d07 + +#define REG_A5XX_PC_TESSFACTOR_ADDR_LO 0x00000d08 + +#define REG_A5XX_PC_TESSFACTOR_ADDR_HI 0x00000d09 + +#define REG_A5XX_PC_PERFCTR_PC_SEL_0 0x00000d10 + +#define REG_A5XX_PC_PERFCTR_PC_SEL_1 0x00000d11 + +#define REG_A5XX_PC_PERFCTR_PC_SEL_2 0x00000d12 + +#define REG_A5XX_PC_PERFCTR_PC_SEL_3 0x00000d13 + +#define REG_A5XX_PC_PERFCTR_PC_SEL_4 0x00000d14 + +#define REG_A5XX_PC_PERFCTR_PC_SEL_5 0x00000d15 + +#define REG_A5XX_PC_PERFCTR_PC_SEL_6 0x00000d16 + +#define REG_A5XX_PC_PERFCTR_PC_SEL_7 0x00000d17 + +#define REG_A5XX_HLSQ_TIMEOUT_THRESHOLD_0 0x00000e00 + +#define REG_A5XX_HLSQ_TIMEOUT_THRESHOLD_1 0x00000e01 + +#define REG_A5XX_HLSQ_DBG_ECO_CNTL 0x00000e04 + +#define REG_A5XX_HLSQ_ADDR_MODE_CNTL 0x00000e05 + +#define REG_A5XX_HLSQ_MODE_CNTL 0x00000e06 + +#define REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_0 0x00000e10 + +#define REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_1 0x00000e11 + +#define REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_2 0x00000e12 + +#define REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_3 0x00000e13 + +#define REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_4 0x00000e14 + +#define REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_5 0x00000e15 + +#define REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_6 0x00000e16 + +#define REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_7 0x00000e17 + +#define REG_A5XX_HLSQ_SPTP_RDSEL 0x00000f08 + +#define REG_A5XX_HLSQ_DBG_READ_SEL 0x0000bc00 + +#define REG_A5XX_HLSQ_DBG_AHB_READ_APERTURE 0x0000a000 + +#define REG_A5XX_VFD_ADDR_MODE_CNTL 0x00000e41 + +#define REG_A5XX_VFD_MODE_CNTL 0x00000e42 + +#define REG_A5XX_VFD_PERFCTR_VFD_SEL_0 0x00000e50 + +#define REG_A5XX_VFD_PERFCTR_VFD_SEL_1 0x00000e51 + +#define REG_A5XX_VFD_PERFCTR_VFD_SEL_2 0x00000e52 + +#define REG_A5XX_VFD_PERFCTR_VFD_SEL_3 0x00000e53 + +#define REG_A5XX_VFD_PERFCTR_VFD_SEL_4 0x00000e54 + +#define REG_A5XX_VFD_PERFCTR_VFD_SEL_5 0x00000e55 + +#define REG_A5XX_VFD_PERFCTR_VFD_SEL_6 0x00000e56 + +#define REG_A5XX_VFD_PERFCTR_VFD_SEL_7 0x00000e57 + +#define REG_A5XX_VPC_DBG_ECO_CNTL 0x00000e60 + +#define REG_A5XX_VPC_ADDR_MODE_CNTL 0x00000e61 + +#define REG_A5XX_VPC_MODE_CNTL 0x00000e62 +#define A5XX_VPC_MODE_CNTL_BINNING_PASS 0x00000001 + +#define REG_A5XX_VPC_PERFCTR_VPC_SEL_0 0x00000e64 + +#define REG_A5XX_VPC_PERFCTR_VPC_SEL_1 0x00000e65 + +#define REG_A5XX_VPC_PERFCTR_VPC_SEL_2 0x00000e66 + +#define REG_A5XX_VPC_PERFCTR_VPC_SEL_3 0x00000e67 + +#define REG_A5XX_UCHE_ADDR_MODE_CNTL 0x00000e80 + +#define REG_A5XX_UCHE_SVM_CNTL 0x00000e82 + +#define REG_A5XX_UCHE_WRITE_THRU_BASE_LO 0x00000e87 + +#define REG_A5XX_UCHE_WRITE_THRU_BASE_HI 0x00000e88 + +#define REG_A5XX_UCHE_TRAP_BASE_LO 0x00000e89 + +#define REG_A5XX_UCHE_TRAP_BASE_HI 0x00000e8a + +#define REG_A5XX_UCHE_GMEM_RANGE_MIN_LO 0x00000e8b + +#define REG_A5XX_UCHE_GMEM_RANGE_MIN_HI 0x00000e8c + +#define REG_A5XX_UCHE_GMEM_RANGE_MAX_LO 0x00000e8d + +#define REG_A5XX_UCHE_GMEM_RANGE_MAX_HI 0x00000e8e + +#define REG_A5XX_UCHE_DBG_ECO_CNTL_2 0x00000e8f + +#define REG_A5XX_UCHE_DBG_ECO_CNTL 0x00000e90 + +#define REG_A5XX_UCHE_CACHE_INVALIDATE_MIN_LO 0x00000e91 + +#define REG_A5XX_UCHE_CACHE_INVALIDATE_MIN_HI 0x00000e92 + +#define REG_A5XX_UCHE_CACHE_INVALIDATE_MAX_LO 0x00000e93 + +#define REG_A5XX_UCHE_CACHE_INVALIDATE_MAX_HI 0x00000e94 + +#define REG_A5XX_UCHE_CACHE_INVALIDATE 0x00000e95 + +#define REG_A5XX_UCHE_CACHE_WAYS 0x00000e96 + +#define REG_A5XX_UCHE_PERFCTR_UCHE_SEL_0 0x00000ea0 + +#define REG_A5XX_UCHE_PERFCTR_UCHE_SEL_1 0x00000ea1 + +#define REG_A5XX_UCHE_PERFCTR_UCHE_SEL_2 0x00000ea2 + +#define REG_A5XX_UCHE_PERFCTR_UCHE_SEL_3 0x00000ea3 + +#define REG_A5XX_UCHE_PERFCTR_UCHE_SEL_4 0x00000ea4 + +#define REG_A5XX_UCHE_PERFCTR_UCHE_SEL_5 0x00000ea5 + +#define REG_A5XX_UCHE_PERFCTR_UCHE_SEL_6 0x00000ea6 + +#define REG_A5XX_UCHE_PERFCTR_UCHE_SEL_7 0x00000ea7 + +#define REG_A5XX_UCHE_POWERCTR_UCHE_SEL_0 0x00000ea8 + +#define REG_A5XX_UCHE_POWERCTR_UCHE_SEL_1 0x00000ea9 + +#define REG_A5XX_UCHE_POWERCTR_UCHE_SEL_2 0x00000eaa + +#define REG_A5XX_UCHE_POWERCTR_UCHE_SEL_3 0x00000eab + +#define REG_A5XX_UCHE_TRAP_LOG_LO 0x00000eb1 + +#define REG_A5XX_UCHE_TRAP_LOG_HI 0x00000eb2 + +#define REG_A5XX_SP_DBG_ECO_CNTL 0x00000ec0 + +#define REG_A5XX_SP_ADDR_MODE_CNTL 0x00000ec1 + +#define REG_A5XX_SP_MODE_CNTL 0x00000ec2 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_0 0x00000ed0 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_1 0x00000ed1 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_2 0x00000ed2 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_3 0x00000ed3 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_4 0x00000ed4 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_5 0x00000ed5 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_6 0x00000ed6 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_7 0x00000ed7 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_8 0x00000ed8 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_9 0x00000ed9 + +#define REG_A5XX_SP_PERFCTR_SP_SEL_10 0x00000eda + +#define REG_A5XX_SP_PERFCTR_SP_SEL_11 0x00000edb + +#define REG_A5XX_SP_POWERCTR_SP_SEL_0 0x00000edc + +#define REG_A5XX_SP_POWERCTR_SP_SEL_1 0x00000edd + +#define REG_A5XX_SP_POWERCTR_SP_SEL_2 0x00000ede + +#define REG_A5XX_SP_POWERCTR_SP_SEL_3 0x00000edf + +#define REG_A5XX_TPL1_ADDR_MODE_CNTL 0x00000f01 + +#define REG_A5XX_TPL1_MODE_CNTL 0x00000f02 + +#define REG_A5XX_TPL1_PERFCTR_TP_SEL_0 0x00000f10 + +#define REG_A5XX_TPL1_PERFCTR_TP_SEL_1 0x00000f11 + +#define REG_A5XX_TPL1_PERFCTR_TP_SEL_2 0x00000f12 + +#define REG_A5XX_TPL1_PERFCTR_TP_SEL_3 0x00000f13 + +#define REG_A5XX_TPL1_PERFCTR_TP_SEL_4 0x00000f14 + +#define REG_A5XX_TPL1_PERFCTR_TP_SEL_5 0x00000f15 + +#define REG_A5XX_TPL1_PERFCTR_TP_SEL_6 0x00000f16 + +#define REG_A5XX_TPL1_PERFCTR_TP_SEL_7 0x00000f17 + +#define REG_A5XX_TPL1_POWERCTR_TP_SEL_0 0x00000f18 + +#define REG_A5XX_TPL1_POWERCTR_TP_SEL_1 0x00000f19 + +#define REG_A5XX_TPL1_POWERCTR_TP_SEL_2 0x00000f1a + +#define REG_A5XX_TPL1_POWERCTR_TP_SEL_3 0x00000f1b + +#define REG_A5XX_VBIF_VERSION 0x00003000 + +#define REG_A5XX_VBIF_CLKON 0x00003001 + +#define REG_A5XX_VBIF_ABIT_SORT 0x00003028 + +#define REG_A5XX_VBIF_ABIT_SORT_CONF 0x00003029 + +#define REG_A5XX_VBIF_ROUND_ROBIN_QOS_ARB 0x00003049 + +#define REG_A5XX_VBIF_GATE_OFF_WRREQ_EN 0x0000302a + +#define REG_A5XX_VBIF_IN_RD_LIM_CONF0 0x0000302c + +#define REG_A5XX_VBIF_IN_RD_LIM_CONF1 0x0000302d + +#define REG_A5XX_VBIF_XIN_HALT_CTRL0 0x00003080 + +#define REG_A5XX_VBIF_XIN_HALT_CTRL1 0x00003081 + +#define REG_A5XX_VBIF_TEST_BUS_OUT_CTRL 0x00003084 + +#define REG_A5XX_VBIF_TEST_BUS1_CTRL0 0x00003085 + +#define REG_A5XX_VBIF_TEST_BUS1_CTRL1 0x00003086 + +#define REG_A5XX_VBIF_TEST_BUS2_CTRL0 0x00003087 + +#define REG_A5XX_VBIF_TEST_BUS2_CTRL1 0x00003088 + +#define REG_A5XX_VBIF_TEST_BUS_OUT 0x0000308c + +#define REG_A5XX_VBIF_PERF_CNT_EN0 0x000030c0 + +#define REG_A5XX_VBIF_PERF_CNT_EN1 0x000030c1 + +#define REG_A5XX_VBIF_PERF_CNT_EN2 0x000030c2 + +#define REG_A5XX_VBIF_PERF_CNT_EN3 0x000030c3 + +#define REG_A5XX_VBIF_PERF_CNT_CLR0 0x000030c8 + +#define REG_A5XX_VBIF_PERF_CNT_CLR1 0x000030c9 + +#define REG_A5XX_VBIF_PERF_CNT_CLR2 0x000030ca + +#define REG_A5XX_VBIF_PERF_CNT_CLR3 0x000030cb + +#define REG_A5XX_VBIF_PERF_CNT_SEL0 0x000030d0 + +#define REG_A5XX_VBIF_PERF_CNT_SEL1 0x000030d1 + +#define REG_A5XX_VBIF_PERF_CNT_SEL2 0x000030d2 + +#define REG_A5XX_VBIF_PERF_CNT_SEL3 0x000030d3 + +#define REG_A5XX_VBIF_PERF_CNT_LOW0 0x000030d8 + +#define REG_A5XX_VBIF_PERF_CNT_LOW1 0x000030d9 + +#define REG_A5XX_VBIF_PERF_CNT_LOW2 0x000030da + +#define REG_A5XX_VBIF_PERF_CNT_LOW3 0x000030db + +#define REG_A5XX_VBIF_PERF_CNT_HIGH0 0x000030e0 + +#define REG_A5XX_VBIF_PERF_CNT_HIGH1 0x000030e1 + +#define REG_A5XX_VBIF_PERF_CNT_HIGH2 0x000030e2 + +#define REG_A5XX_VBIF_PERF_CNT_HIGH3 0x000030e3 + +#define REG_A5XX_VBIF_PERF_PWR_CNT_EN0 0x00003100 + +#define REG_A5XX_VBIF_PERF_PWR_CNT_EN1 0x00003101 + +#define REG_A5XX_VBIF_PERF_PWR_CNT_EN2 0x00003102 + +#define REG_A5XX_VBIF_PERF_PWR_CNT_LOW0 0x00003110 + +#define REG_A5XX_VBIF_PERF_PWR_CNT_LOW1 0x00003111 + +#define REG_A5XX_VBIF_PERF_PWR_CNT_LOW2 0x00003112 + +#define REG_A5XX_VBIF_PERF_PWR_CNT_HIGH0 0x00003118 + +#define REG_A5XX_VBIF_PERF_PWR_CNT_HIGH1 0x00003119 + +#define REG_A5XX_VBIF_PERF_PWR_CNT_HIGH2 0x0000311a + +#define REG_A5XX_GPMU_INST_RAM_BASE 0x00008800 + +#define REG_A5XX_GPMU_DATA_RAM_BASE 0x00009800 + +#define REG_A5XX_GPMU_SP_POWER_CNTL 0x0000a881 + +#define REG_A5XX_GPMU_RBCCU_CLOCK_CNTL 0x0000a886 + +#define REG_A5XX_GPMU_RBCCU_POWER_CNTL 0x0000a887 + +#define REG_A5XX_GPMU_SP_PWR_CLK_STATUS 0x0000a88b +#define A5XX_GPMU_SP_PWR_CLK_STATUS_PWR_ON 0x00100000 + +#define REG_A5XX_GPMU_RBCCU_PWR_CLK_STATUS 0x0000a88d +#define A5XX_GPMU_RBCCU_PWR_CLK_STATUS_PWR_ON 0x00100000 + +#define REG_A5XX_GPMU_PWR_COL_STAGGER_DELAY 0x0000a891 + +#define REG_A5XX_GPMU_PWR_COL_INTER_FRAME_CTRL 0x0000a892 + +#define REG_A5XX_GPMU_PWR_COL_INTER_FRAME_HYST 0x0000a893 + +#define REG_A5XX_GPMU_PWR_COL_BINNING_CTRL 0x0000a894 + +#define REG_A5XX_GPMU_CLOCK_THROTTLE_CTRL 0x0000a8a3 + +#define REG_A5XX_GPMU_WFI_CONFIG 0x0000a8c1 + +#define REG_A5XX_GPMU_RBBM_INTR_INFO 0x0000a8d6 + +#define REG_A5XX_GPMU_CM3_SYSRESET 0x0000a8d8 + +#define REG_A5XX_GPMU_GENERAL_0 0x0000a8e0 + +#define REG_A5XX_GPMU_GENERAL_1 0x0000a8e1 + +#define REG_A5XX_SP_POWER_COUNTER_0_LO 0x0000a840 + +#define REG_A5XX_SP_POWER_COUNTER_0_HI 0x0000a841 + +#define REG_A5XX_SP_POWER_COUNTER_1_LO 0x0000a842 + +#define REG_A5XX_SP_POWER_COUNTER_1_HI 0x0000a843 + +#define REG_A5XX_SP_POWER_COUNTER_2_LO 0x0000a844 + +#define REG_A5XX_SP_POWER_COUNTER_2_HI 0x0000a845 + +#define REG_A5XX_SP_POWER_COUNTER_3_LO 0x0000a846 + +#define REG_A5XX_SP_POWER_COUNTER_3_HI 0x0000a847 + +#define REG_A5XX_TP_POWER_COUNTER_0_LO 0x0000a848 + +#define REG_A5XX_TP_POWER_COUNTER_0_HI 0x0000a849 + +#define REG_A5XX_TP_POWER_COUNTER_1_LO 0x0000a84a + +#define REG_A5XX_TP_POWER_COUNTER_1_HI 0x0000a84b + +#define REG_A5XX_TP_POWER_COUNTER_2_LO 0x0000a84c + +#define REG_A5XX_TP_POWER_COUNTER_2_HI 0x0000a84d + +#define REG_A5XX_TP_POWER_COUNTER_3_LO 0x0000a84e + +#define REG_A5XX_TP_POWER_COUNTER_3_HI 0x0000a84f + +#define REG_A5XX_RB_POWER_COUNTER_0_LO 0x0000a850 + +#define REG_A5XX_RB_POWER_COUNTER_0_HI 0x0000a851 + +#define REG_A5XX_RB_POWER_COUNTER_1_LO 0x0000a852 + +#define REG_A5XX_RB_POWER_COUNTER_1_HI 0x0000a853 + +#define REG_A5XX_RB_POWER_COUNTER_2_LO 0x0000a854 + +#define REG_A5XX_RB_POWER_COUNTER_2_HI 0x0000a855 + +#define REG_A5XX_RB_POWER_COUNTER_3_LO 0x0000a856 + +#define REG_A5XX_RB_POWER_COUNTER_3_HI 0x0000a857 + +#define REG_A5XX_CCU_POWER_COUNTER_0_LO 0x0000a858 + +#define REG_A5XX_CCU_POWER_COUNTER_0_HI 0x0000a859 + +#define REG_A5XX_CCU_POWER_COUNTER_1_LO 0x0000a85a + +#define REG_A5XX_CCU_POWER_COUNTER_1_HI 0x0000a85b + +#define REG_A5XX_UCHE_POWER_COUNTER_0_LO 0x0000a85c + +#define REG_A5XX_UCHE_POWER_COUNTER_0_HI 0x0000a85d + +#define REG_A5XX_UCHE_POWER_COUNTER_1_LO 0x0000a85e + +#define REG_A5XX_UCHE_POWER_COUNTER_1_HI 0x0000a85f + +#define REG_A5XX_UCHE_POWER_COUNTER_2_LO 0x0000a860 + +#define REG_A5XX_UCHE_POWER_COUNTER_2_HI 0x0000a861 + +#define REG_A5XX_UCHE_POWER_COUNTER_3_LO 0x0000a862 + +#define REG_A5XX_UCHE_POWER_COUNTER_3_HI 0x0000a863 + +#define REG_A5XX_CP_POWER_COUNTER_0_LO 0x0000a864 + +#define REG_A5XX_CP_POWER_COUNTER_0_HI 0x0000a865 + +#define REG_A5XX_CP_POWER_COUNTER_1_LO 0x0000a866 + +#define REG_A5XX_CP_POWER_COUNTER_1_HI 0x0000a867 + +#define REG_A5XX_CP_POWER_COUNTER_2_LO 0x0000a868 + +#define REG_A5XX_CP_POWER_COUNTER_2_HI 0x0000a869 + +#define REG_A5XX_CP_POWER_COUNTER_3_LO 0x0000a86a + +#define REG_A5XX_CP_POWER_COUNTER_3_HI 0x0000a86b + +#define REG_A5XX_GPMU_POWER_COUNTER_0_LO 0x0000a86c + +#define REG_A5XX_GPMU_POWER_COUNTER_0_HI 0x0000a86d + +#define REG_A5XX_GPMU_POWER_COUNTER_1_LO 0x0000a86e + +#define REG_A5XX_GPMU_POWER_COUNTER_1_HI 0x0000a86f + +#define REG_A5XX_GPMU_POWER_COUNTER_2_LO 0x0000a870 + +#define REG_A5XX_GPMU_POWER_COUNTER_2_HI 0x0000a871 + +#define REG_A5XX_GPMU_POWER_COUNTER_3_LO 0x0000a872 + +#define REG_A5XX_GPMU_POWER_COUNTER_3_HI 0x0000a873 + +#define REG_A5XX_GPMU_POWER_COUNTER_4_LO 0x0000a874 + +#define REG_A5XX_GPMU_POWER_COUNTER_4_HI 0x0000a875 + +#define REG_A5XX_GPMU_POWER_COUNTER_5_LO 0x0000a876 + +#define REG_A5XX_GPMU_POWER_COUNTER_5_HI 0x0000a877 + +#define REG_A5XX_GPMU_POWER_COUNTER_ENABLE 0x0000a878 + +#define REG_A5XX_GPMU_ALWAYS_ON_COUNTER_LO 0x0000a879 + +#define REG_A5XX_GPMU_ALWAYS_ON_COUNTER_HI 0x0000a87a + +#define REG_A5XX_GPMU_ALWAYS_ON_COUNTER_RESET 0x0000a87b + +#define REG_A5XX_GPMU_POWER_COUNTER_SELECT_0 0x0000a87c + +#define REG_A5XX_GPMU_POWER_COUNTER_SELECT_1 0x0000a87d + +#define REG_A5XX_GPMU_CLOCK_THROTTLE_CTRL 0x0000a8a3 + +#define REG_A5XX_GPMU_THROTTLE_UNMASK_FORCE_CTRL 0x0000a8a8 + +#define REG_A5XX_GPMU_TEMP_SENSOR_ID 0x0000ac00 + +#define REG_A5XX_GPMU_TEMP_SENSOR_CONFIG 0x0000ac01 + +#define REG_A5XX_GPMU_TEMP_VAL 0x0000ac02 + +#define REG_A5XX_GPMU_DELTA_TEMP_THRESHOLD 0x0000ac03 + +#define REG_A5XX_GPMU_TEMP_THRESHOLD_INTR_STATUS 0x0000ac05 + +#define REG_A5XX_GPMU_TEMP_THRESHOLD_INTR_EN_MASK 0x0000ac06 + +#define REG_A5XX_GPMU_LEAKAGE_TEMP_COEFF_0_1 0x0000ac40 + +#define REG_A5XX_GPMU_LEAKAGE_TEMP_COEFF_2_3 0x0000ac41 + +#define REG_A5XX_GPMU_LEAKAGE_VTG_COEFF_0_1 0x0000ac42 + +#define REG_A5XX_GPMU_LEAKAGE_VTG_COEFF_2_3 0x0000ac43 + +#define REG_A5XX_GPMU_BASE_LEAKAGE 0x0000ac46 + +#define REG_A5XX_GPMU_GPMU_VOLTAGE 0x0000ac60 + +#define REG_A5XX_GPMU_GPMU_VOLTAGE_INTR_STATUS 0x0000ac61 + +#define REG_A5XX_GPMU_GPMU_VOLTAGE_INTR_EN_MASK 0x0000ac62 + +#define REG_A5XX_GPMU_GPMU_PWR_THRESHOLD 0x0000ac80 + +#define REG_A5XX_GPMU_GPMU_LLM_GLM_SLEEP_CTRL 0x0000acc4 + +#define REG_A5XX_GPMU_GPMU_LLM_GLM_SLEEP_STATUS 0x0000acc5 + +#define REG_A5XX_GDPM_CONFIG1 0x0000b80c + +#define REG_A5XX_GDPM_CONFIG2 0x0000b80d + +#define REG_A5XX_GDPM_INT_EN 0x0000b80f + +#define REG_A5XX_GDPM_INT_MASK 0x0000b811 + +#define REG_A5XX_GPMU_BEC_ENABLE 0x0000b9a0 + +#define REG_A5XX_GPU_CS_SENSOR_GENERAL_STATUS 0x0000c41a + +#define REG_A5XX_GPU_CS_AMP_CALIBRATION_STATUS1_0 0x0000c41d + +#define REG_A5XX_GPU_CS_AMP_CALIBRATION_STATUS1_2 0x0000c41f + +#define REG_A5XX_GPU_CS_AMP_CALIBRATION_STATUS1_4 0x0000c421 + +#define REG_A5XX_GPU_CS_ENABLE_REG 0x0000c520 + +#define REG_A5XX_GPU_CS_AMP_CALIBRATION_CONTROL1 0x0000c557 + +#define REG_A5XX_GRAS_CL_CNTL 0x0000e000 +#define A5XX_GRAS_CL_CNTL_ZERO_GB_SCALE_Z 0x00000040 + +#define REG_A5XX_UNKNOWN_E001 0x0000e001 + +#define REG_A5XX_UNKNOWN_E004 0x0000e004 + +#define REG_A5XX_GRAS_CNTL 0x0000e005 +#define A5XX_GRAS_CNTL_VARYING 0x00000001 +#define A5XX_GRAS_CNTL_UNK3 0x00000008 +#define A5XX_GRAS_CNTL_XCOORD 0x00000040 +#define A5XX_GRAS_CNTL_YCOORD 0x00000080 +#define A5XX_GRAS_CNTL_ZCOORD 0x00000100 +#define A5XX_GRAS_CNTL_WCOORD 0x00000200 + +#define REG_A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ 0x0000e006 +#define A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ_HORZ__MASK 0x000003ff +#define A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ_HORZ__SHIFT 0 +static inline uint32_t A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ_HORZ(uint32_t val) +{ + return ((val) << A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ_HORZ__SHIFT) & A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ_HORZ__MASK; +} +#define A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ_VERT__MASK 0x000ffc00 +#define A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ_VERT__SHIFT 10 +static inline uint32_t A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ_VERT(uint32_t val) +{ + return ((val) << A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ_VERT__SHIFT) & A5XX_GRAS_CL_GUARDBAND_CLIP_ADJ_VERT__MASK; +} + +#define REG_A5XX_GRAS_CL_VPORT_XOFFSET_0 0x0000e010 +#define A5XX_GRAS_CL_VPORT_XOFFSET_0__MASK 0xffffffff +#define A5XX_GRAS_CL_VPORT_XOFFSET_0__SHIFT 0 +static inline uint32_t A5XX_GRAS_CL_VPORT_XOFFSET_0(float val) +{ + return ((fui(val)) << A5XX_GRAS_CL_VPORT_XOFFSET_0__SHIFT) & A5XX_GRAS_CL_VPORT_XOFFSET_0__MASK; +} + +#define REG_A5XX_GRAS_CL_VPORT_XSCALE_0 0x0000e011 +#define A5XX_GRAS_CL_VPORT_XSCALE_0__MASK 0xffffffff +#define A5XX_GRAS_CL_VPORT_XSCALE_0__SHIFT 0 +static inline uint32_t A5XX_GRAS_CL_VPORT_XSCALE_0(float val) +{ + return ((fui(val)) << A5XX_GRAS_CL_VPORT_XSCALE_0__SHIFT) & A5XX_GRAS_CL_VPORT_XSCALE_0__MASK; +} + +#define REG_A5XX_GRAS_CL_VPORT_YOFFSET_0 0x0000e012 +#define A5XX_GRAS_CL_VPORT_YOFFSET_0__MASK 0xffffffff +#define A5XX_GRAS_CL_VPORT_YOFFSET_0__SHIFT 0 +static inline uint32_t A5XX_GRAS_CL_VPORT_YOFFSET_0(float val) +{ + return ((fui(val)) << A5XX_GRAS_CL_VPORT_YOFFSET_0__SHIFT) & A5XX_GRAS_CL_VPORT_YOFFSET_0__MASK; +} + +#define REG_A5XX_GRAS_CL_VPORT_YSCALE_0 0x0000e013 +#define A5XX_GRAS_CL_VPORT_YSCALE_0__MASK 0xffffffff +#define A5XX_GRAS_CL_VPORT_YSCALE_0__SHIFT 0 +static inline uint32_t A5XX_GRAS_CL_VPORT_YSCALE_0(float val) +{ + return ((fui(val)) << A5XX_GRAS_CL_VPORT_YSCALE_0__SHIFT) & A5XX_GRAS_CL_VPORT_YSCALE_0__MASK; +} + +#define REG_A5XX_GRAS_CL_VPORT_ZOFFSET_0 0x0000e014 +#define A5XX_GRAS_CL_VPORT_ZOFFSET_0__MASK 0xffffffff +#define A5XX_GRAS_CL_VPORT_ZOFFSET_0__SHIFT 0 +static inline uint32_t A5XX_GRAS_CL_VPORT_ZOFFSET_0(float val) +{ + return ((fui(val)) << A5XX_GRAS_CL_VPORT_ZOFFSET_0__SHIFT) & A5XX_GRAS_CL_VPORT_ZOFFSET_0__MASK; +} + +#define REG_A5XX_GRAS_CL_VPORT_ZSCALE_0 0x0000e015 +#define A5XX_GRAS_CL_VPORT_ZSCALE_0__MASK 0xffffffff +#define A5XX_GRAS_CL_VPORT_ZSCALE_0__SHIFT 0 +static inline uint32_t A5XX_GRAS_CL_VPORT_ZSCALE_0(float val) +{ + return ((fui(val)) << A5XX_GRAS_CL_VPORT_ZSCALE_0__SHIFT) & A5XX_GRAS_CL_VPORT_ZSCALE_0__MASK; +} + +#define REG_A5XX_GRAS_SU_CNTL 0x0000e090 +#define A5XX_GRAS_SU_CNTL_CULL_FRONT 0x00000001 +#define A5XX_GRAS_SU_CNTL_CULL_BACK 0x00000002 +#define A5XX_GRAS_SU_CNTL_FRONT_CW 0x00000004 +#define A5XX_GRAS_SU_CNTL_LINEHALFWIDTH__MASK 0x000007f8 +#define A5XX_GRAS_SU_CNTL_LINEHALFWIDTH__SHIFT 3 +static inline uint32_t A5XX_GRAS_SU_CNTL_LINEHALFWIDTH(float val) +{ + return ((((int32_t)(val * 4.0))) << A5XX_GRAS_SU_CNTL_LINEHALFWIDTH__SHIFT) & A5XX_GRAS_SU_CNTL_LINEHALFWIDTH__MASK; +} +#define A5XX_GRAS_SU_CNTL_POLY_OFFSET 0x00000800 +#define A5XX_GRAS_SU_CNTL_MSAA_ENABLE 0x00002000 + +#define REG_A5XX_GRAS_SU_POINT_MINMAX 0x0000e091 +#define A5XX_GRAS_SU_POINT_MINMAX_MIN__MASK 0x0000ffff +#define A5XX_GRAS_SU_POINT_MINMAX_MIN__SHIFT 0 +static inline uint32_t A5XX_GRAS_SU_POINT_MINMAX_MIN(float val) +{ + return ((((uint32_t)(val * 16.0))) << A5XX_GRAS_SU_POINT_MINMAX_MIN__SHIFT) & A5XX_GRAS_SU_POINT_MINMAX_MIN__MASK; +} +#define A5XX_GRAS_SU_POINT_MINMAX_MAX__MASK 0xffff0000 +#define A5XX_GRAS_SU_POINT_MINMAX_MAX__SHIFT 16 +static inline uint32_t A5XX_GRAS_SU_POINT_MINMAX_MAX(float val) +{ + return ((((uint32_t)(val * 16.0))) << A5XX_GRAS_SU_POINT_MINMAX_MAX__SHIFT) & A5XX_GRAS_SU_POINT_MINMAX_MAX__MASK; +} + +#define REG_A5XX_GRAS_SU_POINT_SIZE 0x0000e092 +#define A5XX_GRAS_SU_POINT_SIZE__MASK 0xffffffff +#define A5XX_GRAS_SU_POINT_SIZE__SHIFT 0 +static inline uint32_t A5XX_GRAS_SU_POINT_SIZE(float val) +{ + return ((((int32_t)(val * 16.0))) << A5XX_GRAS_SU_POINT_SIZE__SHIFT) & A5XX_GRAS_SU_POINT_SIZE__MASK; +} + +#define REG_A5XX_GRAS_SU_LAYERED 0x0000e093 + +#define REG_A5XX_GRAS_SU_DEPTH_PLANE_CNTL 0x0000e094 +#define A5XX_GRAS_SU_DEPTH_PLANE_CNTL_FRAG_WRITES_Z 0x00000001 +#define A5XX_GRAS_SU_DEPTH_PLANE_CNTL_UNK1 0x00000002 + +#define REG_A5XX_GRAS_SU_POLY_OFFSET_SCALE 0x0000e095 +#define A5XX_GRAS_SU_POLY_OFFSET_SCALE__MASK 0xffffffff +#define A5XX_GRAS_SU_POLY_OFFSET_SCALE__SHIFT 0 +static inline uint32_t A5XX_GRAS_SU_POLY_OFFSET_SCALE(float val) +{ + return ((fui(val)) << A5XX_GRAS_SU_POLY_OFFSET_SCALE__SHIFT) & A5XX_GRAS_SU_POLY_OFFSET_SCALE__MASK; +} + +#define REG_A5XX_GRAS_SU_POLY_OFFSET_OFFSET 0x0000e096 +#define A5XX_GRAS_SU_POLY_OFFSET_OFFSET__MASK 0xffffffff +#define A5XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT 0 +static inline uint32_t A5XX_GRAS_SU_POLY_OFFSET_OFFSET(float val) +{ + return ((fui(val)) << A5XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT) & A5XX_GRAS_SU_POLY_OFFSET_OFFSET__MASK; +} + +#define REG_A5XX_GRAS_SU_POLY_OFFSET_OFFSET_CLAMP 0x0000e097 +#define A5XX_GRAS_SU_POLY_OFFSET_OFFSET_CLAMP__MASK 0xffffffff +#define A5XX_GRAS_SU_POLY_OFFSET_OFFSET_CLAMP__SHIFT 0 +static inline uint32_t A5XX_GRAS_SU_POLY_OFFSET_OFFSET_CLAMP(float val) +{ + return ((fui(val)) << A5XX_GRAS_SU_POLY_OFFSET_OFFSET_CLAMP__SHIFT) & A5XX_GRAS_SU_POLY_OFFSET_OFFSET_CLAMP__MASK; +} + +#define REG_A5XX_GRAS_SU_DEPTH_BUFFER_INFO 0x0000e098 +#define A5XX_GRAS_SU_DEPTH_BUFFER_INFO_DEPTH_FORMAT__MASK 0x00000007 +#define A5XX_GRAS_SU_DEPTH_BUFFER_INFO_DEPTH_FORMAT__SHIFT 0 +static inline uint32_t A5XX_GRAS_SU_DEPTH_BUFFER_INFO_DEPTH_FORMAT(enum a5xx_depth_format val) +{ + return ((val) << A5XX_GRAS_SU_DEPTH_BUFFER_INFO_DEPTH_FORMAT__SHIFT) & A5XX_GRAS_SU_DEPTH_BUFFER_INFO_DEPTH_FORMAT__MASK; +} + +#define REG_A5XX_GRAS_SU_CONSERVATIVE_RAS_CNTL 0x0000e099 + +#define REG_A5XX_GRAS_SC_CNTL 0x0000e0a0 +#define A5XX_GRAS_SC_CNTL_BINNING_PASS 0x00000001 +#define A5XX_GRAS_SC_CNTL_SAMPLES_PASSED 0x00008000 + +#define REG_A5XX_GRAS_SC_BIN_CNTL 0x0000e0a1 + +#define REG_A5XX_GRAS_SC_RAS_MSAA_CNTL 0x0000e0a2 +#define A5XX_GRAS_SC_RAS_MSAA_CNTL_SAMPLES__MASK 0x00000003 +#define A5XX_GRAS_SC_RAS_MSAA_CNTL_SAMPLES__SHIFT 0 +static inline uint32_t A5XX_GRAS_SC_RAS_MSAA_CNTL_SAMPLES(enum a3xx_msaa_samples val) +{ + return ((val) << A5XX_GRAS_SC_RAS_MSAA_CNTL_SAMPLES__SHIFT) & A5XX_GRAS_SC_RAS_MSAA_CNTL_SAMPLES__MASK; +} + +#define REG_A5XX_GRAS_SC_DEST_MSAA_CNTL 0x0000e0a3 +#define A5XX_GRAS_SC_DEST_MSAA_CNTL_SAMPLES__MASK 0x00000003 +#define A5XX_GRAS_SC_DEST_MSAA_CNTL_SAMPLES__SHIFT 0 +static inline uint32_t A5XX_GRAS_SC_DEST_MSAA_CNTL_SAMPLES(enum a3xx_msaa_samples val) +{ + return ((val) << A5XX_GRAS_SC_DEST_MSAA_CNTL_SAMPLES__SHIFT) & A5XX_GRAS_SC_DEST_MSAA_CNTL_SAMPLES__MASK; +} +#define A5XX_GRAS_SC_DEST_MSAA_CNTL_MSAA_DISABLE 0x00000004 + +#define REG_A5XX_GRAS_SC_SCREEN_SCISSOR_CNTL 0x0000e0a4 + +#define REG_A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0 0x0000e0aa +#define A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_WINDOW_OFFSET_DISABLE 0x80000000 +#define A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_X__MASK 0x00007fff +#define A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_X__SHIFT 0 +static inline uint32_t A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_X(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_X__SHIFT) & A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_X__MASK; +} +#define A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_Y__MASK 0x7fff0000 +#define A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_Y__SHIFT 16 +static inline uint32_t A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_Y(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_Y__SHIFT) & A5XX_GRAS_SC_SCREEN_SCISSOR_TL_0_Y__MASK; +} + +#define REG_A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0 0x0000e0ab +#define A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_WINDOW_OFFSET_DISABLE 0x80000000 +#define A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_X__MASK 0x00007fff +#define A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_X__SHIFT 0 +static inline uint32_t A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_X(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_X__SHIFT) & A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_X__MASK; +} +#define A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_Y__MASK 0x7fff0000 +#define A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_Y__SHIFT 16 +static inline uint32_t A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_Y(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_Y__SHIFT) & A5XX_GRAS_SC_SCREEN_SCISSOR_BR_0_Y__MASK; +} + +#define REG_A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0 0x0000e0ca +#define A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_WINDOW_OFFSET_DISABLE 0x80000000 +#define A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_X__MASK 0x00007fff +#define A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_X__SHIFT 0 +static inline uint32_t A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_X(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_X__SHIFT) & A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_X__MASK; +} +#define A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_Y__MASK 0x7fff0000 +#define A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_Y__SHIFT 16 +static inline uint32_t A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_Y(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_Y__SHIFT) & A5XX_GRAS_SC_VIEWPORT_SCISSOR_TL_0_Y__MASK; +} + +#define REG_A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0 0x0000e0cb +#define A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_WINDOW_OFFSET_DISABLE 0x80000000 +#define A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_X__MASK 0x00007fff +#define A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_X__SHIFT 0 +static inline uint32_t A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_X(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_X__SHIFT) & A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_X__MASK; +} +#define A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_Y__MASK 0x7fff0000 +#define A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_Y__SHIFT 16 +static inline uint32_t A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_Y(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_Y__SHIFT) & A5XX_GRAS_SC_VIEWPORT_SCISSOR_BR_0_Y__MASK; +} + +#define REG_A5XX_GRAS_SC_WINDOW_SCISSOR_TL 0x0000e0ea +#define A5XX_GRAS_SC_WINDOW_SCISSOR_TL_WINDOW_OFFSET_DISABLE 0x80000000 +#define A5XX_GRAS_SC_WINDOW_SCISSOR_TL_X__MASK 0x00007fff +#define A5XX_GRAS_SC_WINDOW_SCISSOR_TL_X__SHIFT 0 +static inline uint32_t A5XX_GRAS_SC_WINDOW_SCISSOR_TL_X(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_WINDOW_SCISSOR_TL_X__SHIFT) & A5XX_GRAS_SC_WINDOW_SCISSOR_TL_X__MASK; +} +#define A5XX_GRAS_SC_WINDOW_SCISSOR_TL_Y__MASK 0x7fff0000 +#define A5XX_GRAS_SC_WINDOW_SCISSOR_TL_Y__SHIFT 16 +static inline uint32_t A5XX_GRAS_SC_WINDOW_SCISSOR_TL_Y(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_WINDOW_SCISSOR_TL_Y__SHIFT) & A5XX_GRAS_SC_WINDOW_SCISSOR_TL_Y__MASK; +} + +#define REG_A5XX_GRAS_SC_WINDOW_SCISSOR_BR 0x0000e0eb +#define A5XX_GRAS_SC_WINDOW_SCISSOR_BR_WINDOW_OFFSET_DISABLE 0x80000000 +#define A5XX_GRAS_SC_WINDOW_SCISSOR_BR_X__MASK 0x00007fff +#define A5XX_GRAS_SC_WINDOW_SCISSOR_BR_X__SHIFT 0 +static inline uint32_t A5XX_GRAS_SC_WINDOW_SCISSOR_BR_X(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_WINDOW_SCISSOR_BR_X__SHIFT) & A5XX_GRAS_SC_WINDOW_SCISSOR_BR_X__MASK; +} +#define A5XX_GRAS_SC_WINDOW_SCISSOR_BR_Y__MASK 0x7fff0000 +#define A5XX_GRAS_SC_WINDOW_SCISSOR_BR_Y__SHIFT 16 +static inline uint32_t A5XX_GRAS_SC_WINDOW_SCISSOR_BR_Y(uint32_t val) +{ + return ((val) << A5XX_GRAS_SC_WINDOW_SCISSOR_BR_Y__SHIFT) & A5XX_GRAS_SC_WINDOW_SCISSOR_BR_Y__MASK; +} + +#define REG_A5XX_GRAS_LRZ_CNTL 0x0000e100 +#define A5XX_GRAS_LRZ_CNTL_ENABLE 0x00000001 +#define A5XX_GRAS_LRZ_CNTL_LRZ_WRITE 0x00000002 +#define A5XX_GRAS_LRZ_CNTL_GREATER 0x00000004 + +#define REG_A5XX_GRAS_LRZ_BUFFER_BASE_LO 0x0000e101 + +#define REG_A5XX_GRAS_LRZ_BUFFER_BASE_HI 0x0000e102 + +#define REG_A5XX_GRAS_LRZ_BUFFER_PITCH 0x0000e103 +#define A5XX_GRAS_LRZ_BUFFER_PITCH__MASK 0xffffffff +#define A5XX_GRAS_LRZ_BUFFER_PITCH__SHIFT 0 +static inline uint32_t A5XX_GRAS_LRZ_BUFFER_PITCH(uint32_t val) +{ + return ((val >> 5) << A5XX_GRAS_LRZ_BUFFER_PITCH__SHIFT) & A5XX_GRAS_LRZ_BUFFER_PITCH__MASK; +} + +#define REG_A5XX_GRAS_LRZ_FAST_CLEAR_BUFFER_BASE_LO 0x0000e104 + +#define REG_A5XX_GRAS_LRZ_FAST_CLEAR_BUFFER_BASE_HI 0x0000e105 + +#define REG_A5XX_RB_CNTL 0x0000e140 +#define A5XX_RB_CNTL_WIDTH__MASK 0x000000ff +#define A5XX_RB_CNTL_WIDTH__SHIFT 0 +static inline uint32_t A5XX_RB_CNTL_WIDTH(uint32_t val) +{ + return ((val >> 5) << A5XX_RB_CNTL_WIDTH__SHIFT) & A5XX_RB_CNTL_WIDTH__MASK; +} +#define A5XX_RB_CNTL_HEIGHT__MASK 0x0001fe00 +#define A5XX_RB_CNTL_HEIGHT__SHIFT 9 +static inline uint32_t A5XX_RB_CNTL_HEIGHT(uint32_t val) +{ + return ((val >> 5) << A5XX_RB_CNTL_HEIGHT__SHIFT) & A5XX_RB_CNTL_HEIGHT__MASK; +} +#define A5XX_RB_CNTL_BYPASS 0x00020000 + +#define REG_A5XX_RB_RENDER_CNTL 0x0000e141 +#define A5XX_RB_RENDER_CNTL_BINNING_PASS 0x00000001 +#define A5XX_RB_RENDER_CNTL_SAMPLES_PASSED 0x00000040 +#define A5XX_RB_RENDER_CNTL_DISABLE_COLOR_PIPE 0x00000080 +#define A5XX_RB_RENDER_CNTL_FLAG_DEPTH 0x00004000 +#define A5XX_RB_RENDER_CNTL_FLAG_DEPTH2 0x00008000 +#define A5XX_RB_RENDER_CNTL_FLAG_MRTS__MASK 0x00ff0000 +#define A5XX_RB_RENDER_CNTL_FLAG_MRTS__SHIFT 16 +static inline uint32_t A5XX_RB_RENDER_CNTL_FLAG_MRTS(uint32_t val) +{ + return ((val) << A5XX_RB_RENDER_CNTL_FLAG_MRTS__SHIFT) & A5XX_RB_RENDER_CNTL_FLAG_MRTS__MASK; +} +#define A5XX_RB_RENDER_CNTL_FLAG_MRTS2__MASK 0xff000000 +#define A5XX_RB_RENDER_CNTL_FLAG_MRTS2__SHIFT 24 +static inline uint32_t A5XX_RB_RENDER_CNTL_FLAG_MRTS2(uint32_t val) +{ + return ((val) << A5XX_RB_RENDER_CNTL_FLAG_MRTS2__SHIFT) & A5XX_RB_RENDER_CNTL_FLAG_MRTS2__MASK; +} + +#define REG_A5XX_RB_RAS_MSAA_CNTL 0x0000e142 +#define A5XX_RB_RAS_MSAA_CNTL_SAMPLES__MASK 0x00000003 +#define A5XX_RB_RAS_MSAA_CNTL_SAMPLES__SHIFT 0 +static inline uint32_t A5XX_RB_RAS_MSAA_CNTL_SAMPLES(enum a3xx_msaa_samples val) +{ + return ((val) << A5XX_RB_RAS_MSAA_CNTL_SAMPLES__SHIFT) & A5XX_RB_RAS_MSAA_CNTL_SAMPLES__MASK; +} + +#define REG_A5XX_RB_DEST_MSAA_CNTL 0x0000e143 +#define A5XX_RB_DEST_MSAA_CNTL_SAMPLES__MASK 0x00000003 +#define A5XX_RB_DEST_MSAA_CNTL_SAMPLES__SHIFT 0 +static inline uint32_t A5XX_RB_DEST_MSAA_CNTL_SAMPLES(enum a3xx_msaa_samples val) +{ + return ((val) << A5XX_RB_DEST_MSAA_CNTL_SAMPLES__SHIFT) & A5XX_RB_DEST_MSAA_CNTL_SAMPLES__MASK; +} +#define A5XX_RB_DEST_MSAA_CNTL_MSAA_DISABLE 0x00000004 + +#define REG_A5XX_RB_RENDER_CONTROL0 0x0000e144 +#define A5XX_RB_RENDER_CONTROL0_VARYING 0x00000001 +#define A5XX_RB_RENDER_CONTROL0_UNK3 0x00000008 +#define A5XX_RB_RENDER_CONTROL0_XCOORD 0x00000040 +#define A5XX_RB_RENDER_CONTROL0_YCOORD 0x00000080 +#define A5XX_RB_RENDER_CONTROL0_ZCOORD 0x00000100 +#define A5XX_RB_RENDER_CONTROL0_WCOORD 0x00000200 + +#define REG_A5XX_RB_RENDER_CONTROL1 0x0000e145 +#define A5XX_RB_RENDER_CONTROL1_SAMPLEMASK 0x00000001 +#define A5XX_RB_RENDER_CONTROL1_FACENESS 0x00000002 +#define A5XX_RB_RENDER_CONTROL1_SAMPLEID 0x00000004 + +#define REG_A5XX_RB_FS_OUTPUT_CNTL 0x0000e146 +#define A5XX_RB_FS_OUTPUT_CNTL_MRT__MASK 0x0000000f +#define A5XX_RB_FS_OUTPUT_CNTL_MRT__SHIFT 0 +static inline uint32_t A5XX_RB_FS_OUTPUT_CNTL_MRT(uint32_t val) +{ + return ((val) << A5XX_RB_FS_OUTPUT_CNTL_MRT__SHIFT) & A5XX_RB_FS_OUTPUT_CNTL_MRT__MASK; +} +#define A5XX_RB_FS_OUTPUT_CNTL_FRAG_WRITES_Z 0x00000020 + +#define REG_A5XX_RB_RENDER_COMPONENTS 0x0000e147 +#define A5XX_RB_RENDER_COMPONENTS_RT0__MASK 0x0000000f +#define A5XX_RB_RENDER_COMPONENTS_RT0__SHIFT 0 +static inline uint32_t A5XX_RB_RENDER_COMPONENTS_RT0(uint32_t val) +{ + return ((val) << A5XX_RB_RENDER_COMPONENTS_RT0__SHIFT) & A5XX_RB_RENDER_COMPONENTS_RT0__MASK; +} +#define A5XX_RB_RENDER_COMPONENTS_RT1__MASK 0x000000f0 +#define A5XX_RB_RENDER_COMPONENTS_RT1__SHIFT 4 +static inline uint32_t A5XX_RB_RENDER_COMPONENTS_RT1(uint32_t val) +{ + return ((val) << A5XX_RB_RENDER_COMPONENTS_RT1__SHIFT) & A5XX_RB_RENDER_COMPONENTS_RT1__MASK; +} +#define A5XX_RB_RENDER_COMPONENTS_RT2__MASK 0x00000f00 +#define A5XX_RB_RENDER_COMPONENTS_RT2__SHIFT 8 +static inline uint32_t A5XX_RB_RENDER_COMPONENTS_RT2(uint32_t val) +{ + return ((val) << A5XX_RB_RENDER_COMPONENTS_RT2__SHIFT) & A5XX_RB_RENDER_COMPONENTS_RT2__MASK; +} +#define A5XX_RB_RENDER_COMPONENTS_RT3__MASK 0x0000f000 +#define A5XX_RB_RENDER_COMPONENTS_RT3__SHIFT 12 +static inline uint32_t A5XX_RB_RENDER_COMPONENTS_RT3(uint32_t val) +{ + return ((val) << A5XX_RB_RENDER_COMPONENTS_RT3__SHIFT) & A5XX_RB_RENDER_COMPONENTS_RT3__MASK; +} +#define A5XX_RB_RENDER_COMPONENTS_RT4__MASK 0x000f0000 +#define A5XX_RB_RENDER_COMPONENTS_RT4__SHIFT 16 +static inline uint32_t A5XX_RB_RENDER_COMPONENTS_RT4(uint32_t val) +{ + return ((val) << A5XX_RB_RENDER_COMPONENTS_RT4__SHIFT) & A5XX_RB_RENDER_COMPONENTS_RT4__MASK; +} +#define A5XX_RB_RENDER_COMPONENTS_RT5__MASK 0x00f00000 +#define A5XX_RB_RENDER_COMPONENTS_RT5__SHIFT 20 +static inline uint32_t A5XX_RB_RENDER_COMPONENTS_RT5(uint32_t val) +{ + return ((val) << A5XX_RB_RENDER_COMPONENTS_RT5__SHIFT) & A5XX_RB_RENDER_COMPONENTS_RT5__MASK; +} +#define A5XX_RB_RENDER_COMPONENTS_RT6__MASK 0x0f000000 +#define A5XX_RB_RENDER_COMPONENTS_RT6__SHIFT 24 +static inline uint32_t A5XX_RB_RENDER_COMPONENTS_RT6(uint32_t val) +{ + return ((val) << A5XX_RB_RENDER_COMPONENTS_RT6__SHIFT) & A5XX_RB_RENDER_COMPONENTS_RT6__MASK; +} +#define A5XX_RB_RENDER_COMPONENTS_RT7__MASK 0xf0000000 +#define A5XX_RB_RENDER_COMPONENTS_RT7__SHIFT 28 +static inline uint32_t A5XX_RB_RENDER_COMPONENTS_RT7(uint32_t val) +{ + return ((val) << A5XX_RB_RENDER_COMPONENTS_RT7__SHIFT) & A5XX_RB_RENDER_COMPONENTS_RT7__MASK; +} + +static inline uint32_t REG_A5XX_RB_MRT(uint32_t i0) { return 0x0000e150 + 0x7*i0; } + +static inline uint32_t REG_A5XX_RB_MRT_CONTROL(uint32_t i0) { return 0x0000e150 + 0x7*i0; } +#define A5XX_RB_MRT_CONTROL_BLEND 0x00000001 +#define A5XX_RB_MRT_CONTROL_BLEND2 0x00000002 +#define A5XX_RB_MRT_CONTROL_ROP_ENABLE 0x00000004 +#define A5XX_RB_MRT_CONTROL_ROP_CODE__MASK 0x00000078 +#define A5XX_RB_MRT_CONTROL_ROP_CODE__SHIFT 3 +static inline uint32_t A5XX_RB_MRT_CONTROL_ROP_CODE(enum a3xx_rop_code val) +{ + return ((val) << A5XX_RB_MRT_CONTROL_ROP_CODE__SHIFT) & A5XX_RB_MRT_CONTROL_ROP_CODE__MASK; +} +#define A5XX_RB_MRT_CONTROL_COMPONENT_ENABLE__MASK 0x00000780 +#define A5XX_RB_MRT_CONTROL_COMPONENT_ENABLE__SHIFT 7 +static inline uint32_t A5XX_RB_MRT_CONTROL_COMPONENT_ENABLE(uint32_t val) +{ + return ((val) << A5XX_RB_MRT_CONTROL_COMPONENT_ENABLE__SHIFT) & A5XX_RB_MRT_CONTROL_COMPONENT_ENABLE__MASK; +} + +static inline uint32_t REG_A5XX_RB_MRT_BLEND_CONTROL(uint32_t i0) { return 0x0000e151 + 0x7*i0; } +#define A5XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR__MASK 0x0000001f +#define A5XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR__SHIFT 0 +static inline uint32_t A5XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR(enum adreno_rb_blend_factor val) +{ + return ((val) << A5XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR__SHIFT) & A5XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR__MASK; +} +#define A5XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE__MASK 0x000000e0 +#define A5XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE__SHIFT 5 +static inline uint32_t A5XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE(enum a3xx_rb_blend_opcode val) +{ + return ((val) << A5XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE__SHIFT) & A5XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE__MASK; +} +#define A5XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR__MASK 0x00001f00 +#define A5XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR__SHIFT 8 +static inline uint32_t A5XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR(enum adreno_rb_blend_factor val) +{ + return ((val) << A5XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR__SHIFT) & A5XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR__MASK; +} +#define A5XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR__MASK 0x001f0000 +#define A5XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR__SHIFT 16 +static inline uint32_t A5XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR(enum adreno_rb_blend_factor val) +{ + return ((val) << A5XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR__SHIFT) & A5XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR__MASK; +} +#define A5XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE__MASK 0x00e00000 +#define A5XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE__SHIFT 21 +static inline uint32_t A5XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE(enum a3xx_rb_blend_opcode val) +{ + return ((val) << A5XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE__SHIFT) & A5XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE__MASK; +} +#define A5XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR__MASK 0x1f000000 +#define A5XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR__SHIFT 24 +static inline uint32_t A5XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR(enum adreno_rb_blend_factor val) +{ + return ((val) << A5XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR__SHIFT) & A5XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR__MASK; +} + +static inline uint32_t REG_A5XX_RB_MRT_BUF_INFO(uint32_t i0) { return 0x0000e152 + 0x7*i0; } +#define A5XX_RB_MRT_BUF_INFO_COLOR_FORMAT__MASK 0x000000ff +#define A5XX_RB_MRT_BUF_INFO_COLOR_FORMAT__SHIFT 0 +static inline uint32_t A5XX_RB_MRT_BUF_INFO_COLOR_FORMAT(enum a5xx_color_fmt val) +{ + return ((val) << A5XX_RB_MRT_BUF_INFO_COLOR_FORMAT__SHIFT) & A5XX_RB_MRT_BUF_INFO_COLOR_FORMAT__MASK; +} +#define A5XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE__MASK 0x00000300 +#define A5XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE__SHIFT 8 +static inline uint32_t A5XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE(enum a5xx_tile_mode val) +{ + return ((val) << A5XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE__SHIFT) & A5XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE__MASK; +} +#define A5XX_RB_MRT_BUF_INFO_DITHER_MODE__MASK 0x00001800 +#define A5XX_RB_MRT_BUF_INFO_DITHER_MODE__SHIFT 11 +static inline uint32_t A5XX_RB_MRT_BUF_INFO_DITHER_MODE(enum adreno_rb_dither_mode val) +{ + return ((val) << A5XX_RB_MRT_BUF_INFO_DITHER_MODE__SHIFT) & A5XX_RB_MRT_BUF_INFO_DITHER_MODE__MASK; +} +#define A5XX_RB_MRT_BUF_INFO_COLOR_SWAP__MASK 0x00006000 +#define A5XX_RB_MRT_BUF_INFO_COLOR_SWAP__SHIFT 13 +static inline uint32_t A5XX_RB_MRT_BUF_INFO_COLOR_SWAP(enum a3xx_color_swap val) +{ + return ((val) << A5XX_RB_MRT_BUF_INFO_COLOR_SWAP__SHIFT) & A5XX_RB_MRT_BUF_INFO_COLOR_SWAP__MASK; +} +#define A5XX_RB_MRT_BUF_INFO_COLOR_SRGB 0x00008000 + +static inline uint32_t REG_A5XX_RB_MRT_PITCH(uint32_t i0) { return 0x0000e153 + 0x7*i0; } +#define A5XX_RB_MRT_PITCH__MASK 0xffffffff +#define A5XX_RB_MRT_PITCH__SHIFT 0 +static inline uint32_t A5XX_RB_MRT_PITCH(uint32_t val) +{ + return ((val >> 6) << A5XX_RB_MRT_PITCH__SHIFT) & A5XX_RB_MRT_PITCH__MASK; +} + +static inline uint32_t REG_A5XX_RB_MRT_ARRAY_PITCH(uint32_t i0) { return 0x0000e154 + 0x7*i0; } +#define A5XX_RB_MRT_ARRAY_PITCH__MASK 0xffffffff +#define A5XX_RB_MRT_ARRAY_PITCH__SHIFT 0 +static inline uint32_t A5XX_RB_MRT_ARRAY_PITCH(uint32_t val) +{ + return ((val >> 6) << A5XX_RB_MRT_ARRAY_PITCH__SHIFT) & A5XX_RB_MRT_ARRAY_PITCH__MASK; +} + +static inline uint32_t REG_A5XX_RB_MRT_BASE_LO(uint32_t i0) { return 0x0000e155 + 0x7*i0; } + +static inline uint32_t REG_A5XX_RB_MRT_BASE_HI(uint32_t i0) { return 0x0000e156 + 0x7*i0; } + +#define REG_A5XX_RB_BLEND_RED 0x0000e1a0 +#define A5XX_RB_BLEND_RED_UINT__MASK 0x000000ff +#define A5XX_RB_BLEND_RED_UINT__SHIFT 0 +static inline uint32_t A5XX_RB_BLEND_RED_UINT(uint32_t val) +{ + return ((val) << A5XX_RB_BLEND_RED_UINT__SHIFT) & A5XX_RB_BLEND_RED_UINT__MASK; +} +#define A5XX_RB_BLEND_RED_SINT__MASK 0x0000ff00 +#define A5XX_RB_BLEND_RED_SINT__SHIFT 8 +static inline uint32_t A5XX_RB_BLEND_RED_SINT(uint32_t val) +{ + return ((val) << A5XX_RB_BLEND_RED_SINT__SHIFT) & A5XX_RB_BLEND_RED_SINT__MASK; +} +#define A5XX_RB_BLEND_RED_FLOAT__MASK 0xffff0000 +#define A5XX_RB_BLEND_RED_FLOAT__SHIFT 16 +static inline uint32_t A5XX_RB_BLEND_RED_FLOAT(float val) +{ + return ((util_float_to_half(val)) << A5XX_RB_BLEND_RED_FLOAT__SHIFT) & A5XX_RB_BLEND_RED_FLOAT__MASK; +} + +#define REG_A5XX_RB_BLEND_RED_F32 0x0000e1a1 +#define A5XX_RB_BLEND_RED_F32__MASK 0xffffffff +#define A5XX_RB_BLEND_RED_F32__SHIFT 0 +static inline uint32_t A5XX_RB_BLEND_RED_F32(float val) +{ + return ((fui(val)) << A5XX_RB_BLEND_RED_F32__SHIFT) & A5XX_RB_BLEND_RED_F32__MASK; +} + +#define REG_A5XX_RB_BLEND_GREEN 0x0000e1a2 +#define A5XX_RB_BLEND_GREEN_UINT__MASK 0x000000ff +#define A5XX_RB_BLEND_GREEN_UINT__SHIFT 0 +static inline uint32_t A5XX_RB_BLEND_GREEN_UINT(uint32_t val) +{ + return ((val) << A5XX_RB_BLEND_GREEN_UINT__SHIFT) & A5XX_RB_BLEND_GREEN_UINT__MASK; +} +#define A5XX_RB_BLEND_GREEN_SINT__MASK 0x0000ff00 +#define A5XX_RB_BLEND_GREEN_SINT__SHIFT 8 +static inline uint32_t A5XX_RB_BLEND_GREEN_SINT(uint32_t val) +{ + return ((val) << A5XX_RB_BLEND_GREEN_SINT__SHIFT) & A5XX_RB_BLEND_GREEN_SINT__MASK; +} +#define A5XX_RB_BLEND_GREEN_FLOAT__MASK 0xffff0000 +#define A5XX_RB_BLEND_GREEN_FLOAT__SHIFT 16 +static inline uint32_t A5XX_RB_BLEND_GREEN_FLOAT(float val) +{ + return ((util_float_to_half(val)) << A5XX_RB_BLEND_GREEN_FLOAT__SHIFT) & A5XX_RB_BLEND_GREEN_FLOAT__MASK; +} + +#define REG_A5XX_RB_BLEND_GREEN_F32 0x0000e1a3 +#define A5XX_RB_BLEND_GREEN_F32__MASK 0xffffffff +#define A5XX_RB_BLEND_GREEN_F32__SHIFT 0 +static inline uint32_t A5XX_RB_BLEND_GREEN_F32(float val) +{ + return ((fui(val)) << A5XX_RB_BLEND_GREEN_F32__SHIFT) & A5XX_RB_BLEND_GREEN_F32__MASK; +} + +#define REG_A5XX_RB_BLEND_BLUE 0x0000e1a4 +#define A5XX_RB_BLEND_BLUE_UINT__MASK 0x000000ff +#define A5XX_RB_BLEND_BLUE_UINT__SHIFT 0 +static inline uint32_t A5XX_RB_BLEND_BLUE_UINT(uint32_t val) +{ + return ((val) << A5XX_RB_BLEND_BLUE_UINT__SHIFT) & A5XX_RB_BLEND_BLUE_UINT__MASK; +} +#define A5XX_RB_BLEND_BLUE_SINT__MASK 0x0000ff00 +#define A5XX_RB_BLEND_BLUE_SINT__SHIFT 8 +static inline uint32_t A5XX_RB_BLEND_BLUE_SINT(uint32_t val) +{ + return ((val) << A5XX_RB_BLEND_BLUE_SINT__SHIFT) & A5XX_RB_BLEND_BLUE_SINT__MASK; +} +#define A5XX_RB_BLEND_BLUE_FLOAT__MASK 0xffff0000 +#define A5XX_RB_BLEND_BLUE_FLOAT__SHIFT 16 +static inline uint32_t A5XX_RB_BLEND_BLUE_FLOAT(float val) +{ + return ((util_float_to_half(val)) << A5XX_RB_BLEND_BLUE_FLOAT__SHIFT) & A5XX_RB_BLEND_BLUE_FLOAT__MASK; +} + +#define REG_A5XX_RB_BLEND_BLUE_F32 0x0000e1a5 +#define A5XX_RB_BLEND_BLUE_F32__MASK 0xffffffff +#define A5XX_RB_BLEND_BLUE_F32__SHIFT 0 +static inline uint32_t A5XX_RB_BLEND_BLUE_F32(float val) +{ + return ((fui(val)) << A5XX_RB_BLEND_BLUE_F32__SHIFT) & A5XX_RB_BLEND_BLUE_F32__MASK; +} + +#define REG_A5XX_RB_BLEND_ALPHA 0x0000e1a6 +#define A5XX_RB_BLEND_ALPHA_UINT__MASK 0x000000ff +#define A5XX_RB_BLEND_ALPHA_UINT__SHIFT 0 +static inline uint32_t A5XX_RB_BLEND_ALPHA_UINT(uint32_t val) +{ + return ((val) << A5XX_RB_BLEND_ALPHA_UINT__SHIFT) & A5XX_RB_BLEND_ALPHA_UINT__MASK; +} +#define A5XX_RB_BLEND_ALPHA_SINT__MASK 0x0000ff00 +#define A5XX_RB_BLEND_ALPHA_SINT__SHIFT 8 +static inline uint32_t A5XX_RB_BLEND_ALPHA_SINT(uint32_t val) +{ + return ((val) << A5XX_RB_BLEND_ALPHA_SINT__SHIFT) & A5XX_RB_BLEND_ALPHA_SINT__MASK; +} +#define A5XX_RB_BLEND_ALPHA_FLOAT__MASK 0xffff0000 +#define A5XX_RB_BLEND_ALPHA_FLOAT__SHIFT 16 +static inline uint32_t A5XX_RB_BLEND_ALPHA_FLOAT(float val) +{ + return ((util_float_to_half(val)) << A5XX_RB_BLEND_ALPHA_FLOAT__SHIFT) & A5XX_RB_BLEND_ALPHA_FLOAT__MASK; +} + +#define REG_A5XX_RB_BLEND_ALPHA_F32 0x0000e1a7 +#define A5XX_RB_BLEND_ALPHA_F32__MASK 0xffffffff +#define A5XX_RB_BLEND_ALPHA_F32__SHIFT 0 +static inline uint32_t A5XX_RB_BLEND_ALPHA_F32(float val) +{ + return ((fui(val)) << A5XX_RB_BLEND_ALPHA_F32__SHIFT) & A5XX_RB_BLEND_ALPHA_F32__MASK; +} + +#define REG_A5XX_RB_ALPHA_CONTROL 0x0000e1a8 +#define A5XX_RB_ALPHA_CONTROL_ALPHA_REF__MASK 0x000000ff +#define A5XX_RB_ALPHA_CONTROL_ALPHA_REF__SHIFT 0 +static inline uint32_t A5XX_RB_ALPHA_CONTROL_ALPHA_REF(uint32_t val) +{ + return ((val) << A5XX_RB_ALPHA_CONTROL_ALPHA_REF__SHIFT) & A5XX_RB_ALPHA_CONTROL_ALPHA_REF__MASK; +} +#define A5XX_RB_ALPHA_CONTROL_ALPHA_TEST 0x00000100 +#define A5XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC__MASK 0x00000e00 +#define A5XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC__SHIFT 9 +static inline uint32_t A5XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC(enum adreno_compare_func val) +{ + return ((val) << A5XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC__SHIFT) & A5XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC__MASK; +} + +#define REG_A5XX_RB_BLEND_CNTL 0x0000e1a9 +#define A5XX_RB_BLEND_CNTL_ENABLE_BLEND__MASK 0x000000ff +#define A5XX_RB_BLEND_CNTL_ENABLE_BLEND__SHIFT 0 +static inline uint32_t A5XX_RB_BLEND_CNTL_ENABLE_BLEND(uint32_t val) +{ + return ((val) << A5XX_RB_BLEND_CNTL_ENABLE_BLEND__SHIFT) & A5XX_RB_BLEND_CNTL_ENABLE_BLEND__MASK; +} +#define A5XX_RB_BLEND_CNTL_INDEPENDENT_BLEND 0x00000100 +#define A5XX_RB_BLEND_CNTL_ALPHA_TO_COVERAGE 0x00000400 +#define A5XX_RB_BLEND_CNTL_SAMPLE_MASK__MASK 0xffff0000 +#define A5XX_RB_BLEND_CNTL_SAMPLE_MASK__SHIFT 16 +static inline uint32_t A5XX_RB_BLEND_CNTL_SAMPLE_MASK(uint32_t val) +{ + return ((val) << A5XX_RB_BLEND_CNTL_SAMPLE_MASK__SHIFT) & A5XX_RB_BLEND_CNTL_SAMPLE_MASK__MASK; +} + +#define REG_A5XX_RB_DEPTH_PLANE_CNTL 0x0000e1b0 +#define A5XX_RB_DEPTH_PLANE_CNTL_FRAG_WRITES_Z 0x00000001 +#define A5XX_RB_DEPTH_PLANE_CNTL_UNK1 0x00000002 + +#define REG_A5XX_RB_DEPTH_CNTL 0x0000e1b1 +#define A5XX_RB_DEPTH_CNTL_Z_ENABLE 0x00000001 +#define A5XX_RB_DEPTH_CNTL_Z_WRITE_ENABLE 0x00000002 +#define A5XX_RB_DEPTH_CNTL_ZFUNC__MASK 0x0000001c +#define A5XX_RB_DEPTH_CNTL_ZFUNC__SHIFT 2 +static inline uint32_t A5XX_RB_DEPTH_CNTL_ZFUNC(enum adreno_compare_func val) +{ + return ((val) << A5XX_RB_DEPTH_CNTL_ZFUNC__SHIFT) & A5XX_RB_DEPTH_CNTL_ZFUNC__MASK; +} +#define A5XX_RB_DEPTH_CNTL_Z_TEST_ENABLE 0x00000040 + +#define REG_A5XX_RB_DEPTH_BUFFER_INFO 0x0000e1b2 +#define A5XX_RB_DEPTH_BUFFER_INFO_DEPTH_FORMAT__MASK 0x00000007 +#define A5XX_RB_DEPTH_BUFFER_INFO_DEPTH_FORMAT__SHIFT 0 +static inline uint32_t A5XX_RB_DEPTH_BUFFER_INFO_DEPTH_FORMAT(enum a5xx_depth_format val) +{ + return ((val) << A5XX_RB_DEPTH_BUFFER_INFO_DEPTH_FORMAT__SHIFT) & A5XX_RB_DEPTH_BUFFER_INFO_DEPTH_FORMAT__MASK; +} + +#define REG_A5XX_RB_DEPTH_BUFFER_BASE_LO 0x0000e1b3 + +#define REG_A5XX_RB_DEPTH_BUFFER_BASE_HI 0x0000e1b4 + +#define REG_A5XX_RB_DEPTH_BUFFER_PITCH 0x0000e1b5 +#define A5XX_RB_DEPTH_BUFFER_PITCH__MASK 0xffffffff +#define A5XX_RB_DEPTH_BUFFER_PITCH__SHIFT 0 +static inline uint32_t A5XX_RB_DEPTH_BUFFER_PITCH(uint32_t val) +{ + return ((val >> 6) << A5XX_RB_DEPTH_BUFFER_PITCH__SHIFT) & A5XX_RB_DEPTH_BUFFER_PITCH__MASK; +} + +#define REG_A5XX_RB_DEPTH_BUFFER_ARRAY_PITCH 0x0000e1b6 +#define A5XX_RB_DEPTH_BUFFER_ARRAY_PITCH__MASK 0xffffffff +#define A5XX_RB_DEPTH_BUFFER_ARRAY_PITCH__SHIFT 0 +static inline uint32_t A5XX_RB_DEPTH_BUFFER_ARRAY_PITCH(uint32_t val) +{ + return ((val >> 6) << A5XX_RB_DEPTH_BUFFER_ARRAY_PITCH__SHIFT) & A5XX_RB_DEPTH_BUFFER_ARRAY_PITCH__MASK; +} + +#define REG_A5XX_RB_STENCIL_CONTROL 0x0000e1c0 +#define A5XX_RB_STENCIL_CONTROL_STENCIL_ENABLE 0x00000001 +#define A5XX_RB_STENCIL_CONTROL_STENCIL_ENABLE_BF 0x00000002 +#define A5XX_RB_STENCIL_CONTROL_STENCIL_READ 0x00000004 +#define A5XX_RB_STENCIL_CONTROL_FUNC__MASK 0x00000700 +#define A5XX_RB_STENCIL_CONTROL_FUNC__SHIFT 8 +static inline uint32_t A5XX_RB_STENCIL_CONTROL_FUNC(enum adreno_compare_func val) +{ + return ((val) << A5XX_RB_STENCIL_CONTROL_FUNC__SHIFT) & A5XX_RB_STENCIL_CONTROL_FUNC__MASK; +} +#define A5XX_RB_STENCIL_CONTROL_FAIL__MASK 0x00003800 +#define A5XX_RB_STENCIL_CONTROL_FAIL__SHIFT 11 +static inline uint32_t A5XX_RB_STENCIL_CONTROL_FAIL(enum adreno_stencil_op val) +{ + return ((val) << A5XX_RB_STENCIL_CONTROL_FAIL__SHIFT) & A5XX_RB_STENCIL_CONTROL_FAIL__MASK; +} +#define A5XX_RB_STENCIL_CONTROL_ZPASS__MASK 0x0001c000 +#define A5XX_RB_STENCIL_CONTROL_ZPASS__SHIFT 14 +static inline uint32_t A5XX_RB_STENCIL_CONTROL_ZPASS(enum adreno_stencil_op val) +{ + return ((val) << A5XX_RB_STENCIL_CONTROL_ZPASS__SHIFT) & A5XX_RB_STENCIL_CONTROL_ZPASS__MASK; +} +#define A5XX_RB_STENCIL_CONTROL_ZFAIL__MASK 0x000e0000 +#define A5XX_RB_STENCIL_CONTROL_ZFAIL__SHIFT 17 +static inline uint32_t A5XX_RB_STENCIL_CONTROL_ZFAIL(enum adreno_stencil_op val) +{ + return ((val) << A5XX_RB_STENCIL_CONTROL_ZFAIL__SHIFT) & A5XX_RB_STENCIL_CONTROL_ZFAIL__MASK; +} +#define A5XX_RB_STENCIL_CONTROL_FUNC_BF__MASK 0x00700000 +#define A5XX_RB_STENCIL_CONTROL_FUNC_BF__SHIFT 20 +static inline uint32_t A5XX_RB_STENCIL_CONTROL_FUNC_BF(enum adreno_compare_func val) +{ + return ((val) << A5XX_RB_STENCIL_CONTROL_FUNC_BF__SHIFT) & A5XX_RB_STENCIL_CONTROL_FUNC_BF__MASK; +} +#define A5XX_RB_STENCIL_CONTROL_FAIL_BF__MASK 0x03800000 +#define A5XX_RB_STENCIL_CONTROL_FAIL_BF__SHIFT 23 +static inline uint32_t A5XX_RB_STENCIL_CONTROL_FAIL_BF(enum adreno_stencil_op val) +{ + return ((val) << A5XX_RB_STENCIL_CONTROL_FAIL_BF__SHIFT) & A5XX_RB_STENCIL_CONTROL_FAIL_BF__MASK; +} +#define A5XX_RB_STENCIL_CONTROL_ZPASS_BF__MASK 0x1c000000 +#define A5XX_RB_STENCIL_CONTROL_ZPASS_BF__SHIFT 26 +static inline uint32_t A5XX_RB_STENCIL_CONTROL_ZPASS_BF(enum adreno_stencil_op val) +{ + return ((val) << A5XX_RB_STENCIL_CONTROL_ZPASS_BF__SHIFT) & A5XX_RB_STENCIL_CONTROL_ZPASS_BF__MASK; +} +#define A5XX_RB_STENCIL_CONTROL_ZFAIL_BF__MASK 0xe0000000 +#define A5XX_RB_STENCIL_CONTROL_ZFAIL_BF__SHIFT 29 +static inline uint32_t A5XX_RB_STENCIL_CONTROL_ZFAIL_BF(enum adreno_stencil_op val) +{ + return ((val) << A5XX_RB_STENCIL_CONTROL_ZFAIL_BF__SHIFT) & A5XX_RB_STENCIL_CONTROL_ZFAIL_BF__MASK; +} + +#define REG_A5XX_RB_STENCIL_INFO 0x0000e1c1 +#define A5XX_RB_STENCIL_INFO_SEPARATE_STENCIL 0x00000001 + +#define REG_A5XX_RB_STENCIL_BASE_LO 0x0000e1c2 + +#define REG_A5XX_RB_STENCIL_BASE_HI 0x0000e1c3 + +#define REG_A5XX_RB_STENCIL_PITCH 0x0000e1c4 +#define A5XX_RB_STENCIL_PITCH__MASK 0xffffffff +#define A5XX_RB_STENCIL_PITCH__SHIFT 0 +static inline uint32_t A5XX_RB_STENCIL_PITCH(uint32_t val) +{ + return ((val >> 6) << A5XX_RB_STENCIL_PITCH__SHIFT) & A5XX_RB_STENCIL_PITCH__MASK; +} + +#define REG_A5XX_RB_STENCIL_ARRAY_PITCH 0x0000e1c5 +#define A5XX_RB_STENCIL_ARRAY_PITCH__MASK 0xffffffff +#define A5XX_RB_STENCIL_ARRAY_PITCH__SHIFT 0 +static inline uint32_t A5XX_RB_STENCIL_ARRAY_PITCH(uint32_t val) +{ + return ((val >> 6) << A5XX_RB_STENCIL_ARRAY_PITCH__SHIFT) & A5XX_RB_STENCIL_ARRAY_PITCH__MASK; +} + +#define REG_A5XX_RB_STENCILREFMASK 0x0000e1c6 +#define A5XX_RB_STENCILREFMASK_STENCILREF__MASK 0x000000ff +#define A5XX_RB_STENCILREFMASK_STENCILREF__SHIFT 0 +static inline uint32_t A5XX_RB_STENCILREFMASK_STENCILREF(uint32_t val) +{ + return ((val) << A5XX_RB_STENCILREFMASK_STENCILREF__SHIFT) & A5XX_RB_STENCILREFMASK_STENCILREF__MASK; +} +#define A5XX_RB_STENCILREFMASK_STENCILMASK__MASK 0x0000ff00 +#define A5XX_RB_STENCILREFMASK_STENCILMASK__SHIFT 8 +static inline uint32_t A5XX_RB_STENCILREFMASK_STENCILMASK(uint32_t val) +{ + return ((val) << A5XX_RB_STENCILREFMASK_STENCILMASK__SHIFT) & A5XX_RB_STENCILREFMASK_STENCILMASK__MASK; +} +#define A5XX_RB_STENCILREFMASK_STENCILWRITEMASK__MASK 0x00ff0000 +#define A5XX_RB_STENCILREFMASK_STENCILWRITEMASK__SHIFT 16 +static inline uint32_t A5XX_RB_STENCILREFMASK_STENCILWRITEMASK(uint32_t val) +{ + return ((val) << A5XX_RB_STENCILREFMASK_STENCILWRITEMASK__SHIFT) & A5XX_RB_STENCILREFMASK_STENCILWRITEMASK__MASK; +} + +#define REG_A5XX_RB_STENCILREFMASK_BF 0x0000e1c7 +#define A5XX_RB_STENCILREFMASK_BF_STENCILREF__MASK 0x000000ff +#define A5XX_RB_STENCILREFMASK_BF_STENCILREF__SHIFT 0 +static inline uint32_t A5XX_RB_STENCILREFMASK_BF_STENCILREF(uint32_t val) +{ + return ((val) << A5XX_RB_STENCILREFMASK_BF_STENCILREF__SHIFT) & A5XX_RB_STENCILREFMASK_BF_STENCILREF__MASK; +} +#define A5XX_RB_STENCILREFMASK_BF_STENCILMASK__MASK 0x0000ff00 +#define A5XX_RB_STENCILREFMASK_BF_STENCILMASK__SHIFT 8 +static inline uint32_t A5XX_RB_STENCILREFMASK_BF_STENCILMASK(uint32_t val) +{ + return ((val) << A5XX_RB_STENCILREFMASK_BF_STENCILMASK__SHIFT) & A5XX_RB_STENCILREFMASK_BF_STENCILMASK__MASK; +} +#define A5XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK__MASK 0x00ff0000 +#define A5XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK__SHIFT 16 +static inline uint32_t A5XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK(uint32_t val) +{ + return ((val) << A5XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK__SHIFT) & A5XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK__MASK; +} + +#define REG_A5XX_RB_WINDOW_OFFSET 0x0000e1d0 +#define A5XX_RB_WINDOW_OFFSET_WINDOW_OFFSET_DISABLE 0x80000000 +#define A5XX_RB_WINDOW_OFFSET_X__MASK 0x00007fff +#define A5XX_RB_WINDOW_OFFSET_X__SHIFT 0 +static inline uint32_t A5XX_RB_WINDOW_OFFSET_X(uint32_t val) +{ + return ((val) << A5XX_RB_WINDOW_OFFSET_X__SHIFT) & A5XX_RB_WINDOW_OFFSET_X__MASK; +} +#define A5XX_RB_WINDOW_OFFSET_Y__MASK 0x7fff0000 +#define A5XX_RB_WINDOW_OFFSET_Y__SHIFT 16 +static inline uint32_t A5XX_RB_WINDOW_OFFSET_Y(uint32_t val) +{ + return ((val) << A5XX_RB_WINDOW_OFFSET_Y__SHIFT) & A5XX_RB_WINDOW_OFFSET_Y__MASK; +} + +#define REG_A5XX_RB_SAMPLE_COUNT_CONTROL 0x0000e1d1 +#define A5XX_RB_SAMPLE_COUNT_CONTROL_COPY 0x00000002 + +#define REG_A5XX_RB_BLIT_CNTL 0x0000e210 +#define A5XX_RB_BLIT_CNTL_BUF__MASK 0x0000000f +#define A5XX_RB_BLIT_CNTL_BUF__SHIFT 0 +static inline uint32_t A5XX_RB_BLIT_CNTL_BUF(enum a5xx_blit_buf val) +{ + return ((val) << A5XX_RB_BLIT_CNTL_BUF__SHIFT) & A5XX_RB_BLIT_CNTL_BUF__MASK; +} + +#define REG_A5XX_RB_RESOLVE_CNTL_1 0x0000e211 +#define A5XX_RB_RESOLVE_CNTL_1_WINDOW_OFFSET_DISABLE 0x80000000 +#define A5XX_RB_RESOLVE_CNTL_1_X__MASK 0x00007fff +#define A5XX_RB_RESOLVE_CNTL_1_X__SHIFT 0 +static inline uint32_t A5XX_RB_RESOLVE_CNTL_1_X(uint32_t val) +{ + return ((val) << A5XX_RB_RESOLVE_CNTL_1_X__SHIFT) & A5XX_RB_RESOLVE_CNTL_1_X__MASK; +} +#define A5XX_RB_RESOLVE_CNTL_1_Y__MASK 0x7fff0000 +#define A5XX_RB_RESOLVE_CNTL_1_Y__SHIFT 16 +static inline uint32_t A5XX_RB_RESOLVE_CNTL_1_Y(uint32_t val) +{ + return ((val) << A5XX_RB_RESOLVE_CNTL_1_Y__SHIFT) & A5XX_RB_RESOLVE_CNTL_1_Y__MASK; +} + +#define REG_A5XX_RB_RESOLVE_CNTL_2 0x0000e212 +#define A5XX_RB_RESOLVE_CNTL_2_WINDOW_OFFSET_DISABLE 0x80000000 +#define A5XX_RB_RESOLVE_CNTL_2_X__MASK 0x00007fff +#define A5XX_RB_RESOLVE_CNTL_2_X__SHIFT 0 +static inline uint32_t A5XX_RB_RESOLVE_CNTL_2_X(uint32_t val) +{ + return ((val) << A5XX_RB_RESOLVE_CNTL_2_X__SHIFT) & A5XX_RB_RESOLVE_CNTL_2_X__MASK; +} +#define A5XX_RB_RESOLVE_CNTL_2_Y__MASK 0x7fff0000 +#define A5XX_RB_RESOLVE_CNTL_2_Y__SHIFT 16 +static inline uint32_t A5XX_RB_RESOLVE_CNTL_2_Y(uint32_t val) +{ + return ((val) << A5XX_RB_RESOLVE_CNTL_2_Y__SHIFT) & A5XX_RB_RESOLVE_CNTL_2_Y__MASK; +} + +#define REG_A5XX_RB_RESOLVE_CNTL_3 0x0000e213 +#define A5XX_RB_RESOLVE_CNTL_3_TILED 0x00000001 + +#define REG_A5XX_RB_BLIT_DST_LO 0x0000e214 + +#define REG_A5XX_RB_BLIT_DST_HI 0x0000e215 + +#define REG_A5XX_RB_BLIT_DST_PITCH 0x0000e216 +#define A5XX_RB_BLIT_DST_PITCH__MASK 0xffffffff +#define A5XX_RB_BLIT_DST_PITCH__SHIFT 0 +static inline uint32_t A5XX_RB_BLIT_DST_PITCH(uint32_t val) +{ + return ((val >> 6) << A5XX_RB_BLIT_DST_PITCH__SHIFT) & A5XX_RB_BLIT_DST_PITCH__MASK; +} + +#define REG_A5XX_RB_BLIT_DST_ARRAY_PITCH 0x0000e217 +#define A5XX_RB_BLIT_DST_ARRAY_PITCH__MASK 0xffffffff +#define A5XX_RB_BLIT_DST_ARRAY_PITCH__SHIFT 0 +static inline uint32_t A5XX_RB_BLIT_DST_ARRAY_PITCH(uint32_t val) +{ + return ((val >> 6) << A5XX_RB_BLIT_DST_ARRAY_PITCH__SHIFT) & A5XX_RB_BLIT_DST_ARRAY_PITCH__MASK; +} + +#define REG_A5XX_RB_CLEAR_COLOR_DW0 0x0000e218 + +#define REG_A5XX_RB_CLEAR_COLOR_DW1 0x0000e219 + +#define REG_A5XX_RB_CLEAR_COLOR_DW2 0x0000e21a + +#define REG_A5XX_RB_CLEAR_COLOR_DW3 0x0000e21b + +#define REG_A5XX_RB_CLEAR_CNTL 0x0000e21c +#define A5XX_RB_CLEAR_CNTL_FAST_CLEAR 0x00000002 +#define A5XX_RB_CLEAR_CNTL_MSAA_RESOLVE 0x00000004 +#define A5XX_RB_CLEAR_CNTL_MASK__MASK 0x000000f0 +#define A5XX_RB_CLEAR_CNTL_MASK__SHIFT 4 +static inline uint32_t A5XX_RB_CLEAR_CNTL_MASK(uint32_t val) +{ + return ((val) << A5XX_RB_CLEAR_CNTL_MASK__SHIFT) & A5XX_RB_CLEAR_CNTL_MASK__MASK; +} + +#define REG_A5XX_RB_DEPTH_FLAG_BUFFER_BASE_LO 0x0000e240 + +#define REG_A5XX_RB_DEPTH_FLAG_BUFFER_BASE_HI 0x0000e241 + +#define REG_A5XX_RB_DEPTH_FLAG_BUFFER_PITCH 0x0000e242 + +static inline uint32_t REG_A5XX_RB_MRT_FLAG_BUFFER(uint32_t i0) { return 0x0000e243 + 0x4*i0; } + +static inline uint32_t REG_A5XX_RB_MRT_FLAG_BUFFER_ADDR_LO(uint32_t i0) { return 0x0000e243 + 0x4*i0; } + +static inline uint32_t REG_A5XX_RB_MRT_FLAG_BUFFER_ADDR_HI(uint32_t i0) { return 0x0000e244 + 0x4*i0; } + +static inline uint32_t REG_A5XX_RB_MRT_FLAG_BUFFER_PITCH(uint32_t i0) { return 0x0000e245 + 0x4*i0; } +#define A5XX_RB_MRT_FLAG_BUFFER_PITCH__MASK 0xffffffff +#define A5XX_RB_MRT_FLAG_BUFFER_PITCH__SHIFT 0 +static inline uint32_t A5XX_RB_MRT_FLAG_BUFFER_PITCH(uint32_t val) +{ + return ((val >> 6) << A5XX_RB_MRT_FLAG_BUFFER_PITCH__SHIFT) & A5XX_RB_MRT_FLAG_BUFFER_PITCH__MASK; +} + +static inline uint32_t REG_A5XX_RB_MRT_FLAG_BUFFER_ARRAY_PITCH(uint32_t i0) { return 0x0000e246 + 0x4*i0; } +#define A5XX_RB_MRT_FLAG_BUFFER_ARRAY_PITCH__MASK 0xffffffff +#define A5XX_RB_MRT_FLAG_BUFFER_ARRAY_PITCH__SHIFT 0 +static inline uint32_t A5XX_RB_MRT_FLAG_BUFFER_ARRAY_PITCH(uint32_t val) +{ + return ((val >> 6) << A5XX_RB_MRT_FLAG_BUFFER_ARRAY_PITCH__SHIFT) & A5XX_RB_MRT_FLAG_BUFFER_ARRAY_PITCH__MASK; +} + +#define REG_A5XX_RB_BLIT_FLAG_DST_LO 0x0000e263 + +#define REG_A5XX_RB_BLIT_FLAG_DST_HI 0x0000e264 + +#define REG_A5XX_RB_BLIT_FLAG_DST_PITCH 0x0000e265 +#define A5XX_RB_BLIT_FLAG_DST_PITCH__MASK 0xffffffff +#define A5XX_RB_BLIT_FLAG_DST_PITCH__SHIFT 0 +static inline uint32_t A5XX_RB_BLIT_FLAG_DST_PITCH(uint32_t val) +{ + return ((val >> 6) << A5XX_RB_BLIT_FLAG_DST_PITCH__SHIFT) & A5XX_RB_BLIT_FLAG_DST_PITCH__MASK; +} + +#define REG_A5XX_RB_BLIT_FLAG_DST_ARRAY_PITCH 0x0000e266 +#define A5XX_RB_BLIT_FLAG_DST_ARRAY_PITCH__MASK 0xffffffff +#define A5XX_RB_BLIT_FLAG_DST_ARRAY_PITCH__SHIFT 0 +static inline uint32_t A5XX_RB_BLIT_FLAG_DST_ARRAY_PITCH(uint32_t val) +{ + return ((val >> 6) << A5XX_RB_BLIT_FLAG_DST_ARRAY_PITCH__SHIFT) & A5XX_RB_BLIT_FLAG_DST_ARRAY_PITCH__MASK; +} + +#define REG_A5XX_RB_SAMPLE_COUNT_ADDR_LO 0x0000e267 + +#define REG_A5XX_RB_SAMPLE_COUNT_ADDR_HI 0x0000e268 + +#define REG_A5XX_VPC_CNTL_0 0x0000e280 +#define A5XX_VPC_CNTL_0_STRIDE_IN_VPC__MASK 0x0000007f +#define A5XX_VPC_CNTL_0_STRIDE_IN_VPC__SHIFT 0 +static inline uint32_t A5XX_VPC_CNTL_0_STRIDE_IN_VPC(uint32_t val) +{ + return ((val) << A5XX_VPC_CNTL_0_STRIDE_IN_VPC__SHIFT) & A5XX_VPC_CNTL_0_STRIDE_IN_VPC__MASK; +} +#define A5XX_VPC_CNTL_0_VARYING 0x00000800 + +static inline uint32_t REG_A5XX_VPC_VARYING_INTERP(uint32_t i0) { return 0x0000e282 + 0x1*i0; } + +static inline uint32_t REG_A5XX_VPC_VARYING_INTERP_MODE(uint32_t i0) { return 0x0000e282 + 0x1*i0; } + +static inline uint32_t REG_A5XX_VPC_VARYING_PS_REPL(uint32_t i0) { return 0x0000e28a + 0x1*i0; } + +static inline uint32_t REG_A5XX_VPC_VARYING_PS_REPL_MODE(uint32_t i0) { return 0x0000e28a + 0x1*i0; } + +#define REG_A5XX_UNKNOWN_E292 0x0000e292 + +#define REG_A5XX_UNKNOWN_E293 0x0000e293 + +static inline uint32_t REG_A5XX_VPC_VAR(uint32_t i0) { return 0x0000e294 + 0x1*i0; } + +static inline uint32_t REG_A5XX_VPC_VAR_DISABLE(uint32_t i0) { return 0x0000e294 + 0x1*i0; } + +#define REG_A5XX_VPC_GS_SIV_CNTL 0x0000e298 + +#define REG_A5XX_UNKNOWN_E29A 0x0000e29a + +#define REG_A5XX_VPC_PACK 0x0000e29d +#define A5XX_VPC_PACK_NUMNONPOSVAR__MASK 0x000000ff +#define A5XX_VPC_PACK_NUMNONPOSVAR__SHIFT 0 +static inline uint32_t A5XX_VPC_PACK_NUMNONPOSVAR(uint32_t val) +{ + return ((val) << A5XX_VPC_PACK_NUMNONPOSVAR__SHIFT) & A5XX_VPC_PACK_NUMNONPOSVAR__MASK; +} +#define A5XX_VPC_PACK_PSIZELOC__MASK 0x0000ff00 +#define A5XX_VPC_PACK_PSIZELOC__SHIFT 8 +static inline uint32_t A5XX_VPC_PACK_PSIZELOC(uint32_t val) +{ + return ((val) << A5XX_VPC_PACK_PSIZELOC__SHIFT) & A5XX_VPC_PACK_PSIZELOC__MASK; +} + +#define REG_A5XX_VPC_FS_PRIMITIVEID_CNTL 0x0000e2a0 + +#define REG_A5XX_VPC_SO_BUF_CNTL 0x0000e2a1 +#define A5XX_VPC_SO_BUF_CNTL_BUF0 0x00000001 +#define A5XX_VPC_SO_BUF_CNTL_BUF1 0x00000008 +#define A5XX_VPC_SO_BUF_CNTL_BUF2 0x00000040 +#define A5XX_VPC_SO_BUF_CNTL_BUF3 0x00000200 +#define A5XX_VPC_SO_BUF_CNTL_ENABLE 0x00008000 + +#define REG_A5XX_VPC_SO_OVERRIDE 0x0000e2a2 +#define A5XX_VPC_SO_OVERRIDE_SO_DISABLE 0x00000001 + +#define REG_A5XX_VPC_SO_CNTL 0x0000e2a3 +#define A5XX_VPC_SO_CNTL_ENABLE 0x00010000 + +#define REG_A5XX_VPC_SO_PROG 0x0000e2a4 +#define A5XX_VPC_SO_PROG_A_BUF__MASK 0x00000003 +#define A5XX_VPC_SO_PROG_A_BUF__SHIFT 0 +static inline uint32_t A5XX_VPC_SO_PROG_A_BUF(uint32_t val) +{ + return ((val) << A5XX_VPC_SO_PROG_A_BUF__SHIFT) & A5XX_VPC_SO_PROG_A_BUF__MASK; +} +#define A5XX_VPC_SO_PROG_A_OFF__MASK 0x000007fc +#define A5XX_VPC_SO_PROG_A_OFF__SHIFT 2 +static inline uint32_t A5XX_VPC_SO_PROG_A_OFF(uint32_t val) +{ + return ((val >> 2) << A5XX_VPC_SO_PROG_A_OFF__SHIFT) & A5XX_VPC_SO_PROG_A_OFF__MASK; +} +#define A5XX_VPC_SO_PROG_A_EN 0x00000800 +#define A5XX_VPC_SO_PROG_B_BUF__MASK 0x00003000 +#define A5XX_VPC_SO_PROG_B_BUF__SHIFT 12 +static inline uint32_t A5XX_VPC_SO_PROG_B_BUF(uint32_t val) +{ + return ((val) << A5XX_VPC_SO_PROG_B_BUF__SHIFT) & A5XX_VPC_SO_PROG_B_BUF__MASK; +} +#define A5XX_VPC_SO_PROG_B_OFF__MASK 0x007fc000 +#define A5XX_VPC_SO_PROG_B_OFF__SHIFT 14 +static inline uint32_t A5XX_VPC_SO_PROG_B_OFF(uint32_t val) +{ + return ((val >> 2) << A5XX_VPC_SO_PROG_B_OFF__SHIFT) & A5XX_VPC_SO_PROG_B_OFF__MASK; +} +#define A5XX_VPC_SO_PROG_B_EN 0x00800000 + +static inline uint32_t REG_A5XX_VPC_SO(uint32_t i0) { return 0x0000e2a7 + 0x7*i0; } + +static inline uint32_t REG_A5XX_VPC_SO_BUFFER_BASE_LO(uint32_t i0) { return 0x0000e2a7 + 0x7*i0; } + +static inline uint32_t REG_A5XX_VPC_SO_BUFFER_BASE_HI(uint32_t i0) { return 0x0000e2a8 + 0x7*i0; } + +static inline uint32_t REG_A5XX_VPC_SO_BUFFER_SIZE(uint32_t i0) { return 0x0000e2a9 + 0x7*i0; } + +static inline uint32_t REG_A5XX_VPC_SO_NCOMP(uint32_t i0) { return 0x0000e2aa + 0x7*i0; } + +static inline uint32_t REG_A5XX_VPC_SO_BUFFER_OFFSET(uint32_t i0) { return 0x0000e2ab + 0x7*i0; } + +static inline uint32_t REG_A5XX_VPC_SO_FLUSH_BASE_LO(uint32_t i0) { return 0x0000e2ac + 0x7*i0; } + +static inline uint32_t REG_A5XX_VPC_SO_FLUSH_BASE_HI(uint32_t i0) { return 0x0000e2ad + 0x7*i0; } + +#define REG_A5XX_PC_PRIMITIVE_CNTL 0x0000e384 +#define A5XX_PC_PRIMITIVE_CNTL_STRIDE_IN_VPC__MASK 0x0000007f +#define A5XX_PC_PRIMITIVE_CNTL_STRIDE_IN_VPC__SHIFT 0 +static inline uint32_t A5XX_PC_PRIMITIVE_CNTL_STRIDE_IN_VPC(uint32_t val) +{ + return ((val) << A5XX_PC_PRIMITIVE_CNTL_STRIDE_IN_VPC__SHIFT) & A5XX_PC_PRIMITIVE_CNTL_STRIDE_IN_VPC__MASK; +} +#define A5XX_PC_PRIMITIVE_CNTL_PRIMITIVE_RESTART 0x00000100 +#define A5XX_PC_PRIMITIVE_CNTL_COUNT_PRIMITIVES 0x00000200 +#define A5XX_PC_PRIMITIVE_CNTL_PROVOKING_VTX_LAST 0x00000400 + +#define REG_A5XX_PC_PRIM_VTX_CNTL 0x0000e385 +#define A5XX_PC_PRIM_VTX_CNTL_PSIZE 0x00000800 + +#define REG_A5XX_PC_RASTER_CNTL 0x0000e388 +#define A5XX_PC_RASTER_CNTL_POLYMODE_FRONT_PTYPE__MASK 0x00000007 +#define A5XX_PC_RASTER_CNTL_POLYMODE_FRONT_PTYPE__SHIFT 0 +static inline uint32_t A5XX_PC_RASTER_CNTL_POLYMODE_FRONT_PTYPE(enum adreno_pa_su_sc_draw val) +{ + return ((val) << A5XX_PC_RASTER_CNTL_POLYMODE_FRONT_PTYPE__SHIFT) & A5XX_PC_RASTER_CNTL_POLYMODE_FRONT_PTYPE__MASK; +} +#define A5XX_PC_RASTER_CNTL_POLYMODE_BACK_PTYPE__MASK 0x00000038 +#define A5XX_PC_RASTER_CNTL_POLYMODE_BACK_PTYPE__SHIFT 3 +static inline uint32_t A5XX_PC_RASTER_CNTL_POLYMODE_BACK_PTYPE(enum adreno_pa_su_sc_draw val) +{ + return ((val) << A5XX_PC_RASTER_CNTL_POLYMODE_BACK_PTYPE__SHIFT) & A5XX_PC_RASTER_CNTL_POLYMODE_BACK_PTYPE__MASK; +} +#define A5XX_PC_RASTER_CNTL_POLYMODE_ENABLE 0x00000040 + +#define REG_A5XX_UNKNOWN_E389 0x0000e389 + +#define REG_A5XX_PC_RESTART_INDEX 0x0000e38c + +#define REG_A5XX_PC_GS_LAYERED 0x0000e38d + +#define REG_A5XX_PC_GS_PARAM 0x0000e38e +#define A5XX_PC_GS_PARAM_MAX_VERTICES__MASK 0x000003ff +#define A5XX_PC_GS_PARAM_MAX_VERTICES__SHIFT 0 +static inline uint32_t A5XX_PC_GS_PARAM_MAX_VERTICES(uint32_t val) +{ + return ((val) << A5XX_PC_GS_PARAM_MAX_VERTICES__SHIFT) & A5XX_PC_GS_PARAM_MAX_VERTICES__MASK; +} +#define A5XX_PC_GS_PARAM_INVOCATIONS__MASK 0x0000f800 +#define A5XX_PC_GS_PARAM_INVOCATIONS__SHIFT 11 +static inline uint32_t A5XX_PC_GS_PARAM_INVOCATIONS(uint32_t val) +{ + return ((val) << A5XX_PC_GS_PARAM_INVOCATIONS__SHIFT) & A5XX_PC_GS_PARAM_INVOCATIONS__MASK; +} +#define A5XX_PC_GS_PARAM_PRIMTYPE__MASK 0x01800000 +#define A5XX_PC_GS_PARAM_PRIMTYPE__SHIFT 23 +static inline uint32_t A5XX_PC_GS_PARAM_PRIMTYPE(enum adreno_pa_su_sc_draw val) +{ + return ((val) << A5XX_PC_GS_PARAM_PRIMTYPE__SHIFT) & A5XX_PC_GS_PARAM_PRIMTYPE__MASK; +} + +#define REG_A5XX_PC_HS_PARAM 0x0000e38f +#define A5XX_PC_HS_PARAM_VERTICES_OUT__MASK 0x0000003f +#define A5XX_PC_HS_PARAM_VERTICES_OUT__SHIFT 0 +static inline uint32_t A5XX_PC_HS_PARAM_VERTICES_OUT(uint32_t val) +{ + return ((val) << A5XX_PC_HS_PARAM_VERTICES_OUT__SHIFT) & A5XX_PC_HS_PARAM_VERTICES_OUT__MASK; +} +#define A5XX_PC_HS_PARAM_SPACING__MASK 0x00600000 +#define A5XX_PC_HS_PARAM_SPACING__SHIFT 21 +static inline uint32_t A5XX_PC_HS_PARAM_SPACING(enum a4xx_tess_spacing val) +{ + return ((val) << A5XX_PC_HS_PARAM_SPACING__SHIFT) & A5XX_PC_HS_PARAM_SPACING__MASK; +} +#define A5XX_PC_HS_PARAM_CW 0x00800000 +#define A5XX_PC_HS_PARAM_CONNECTED 0x01000000 + +#define REG_A5XX_PC_POWER_CNTL 0x0000e3b0 + +#define REG_A5XX_VFD_CONTROL_0 0x0000e400 +#define A5XX_VFD_CONTROL_0_VTXCNT__MASK 0x0000003f +#define A5XX_VFD_CONTROL_0_VTXCNT__SHIFT 0 +static inline uint32_t A5XX_VFD_CONTROL_0_VTXCNT(uint32_t val) +{ + return ((val) << A5XX_VFD_CONTROL_0_VTXCNT__SHIFT) & A5XX_VFD_CONTROL_0_VTXCNT__MASK; +} + +#define REG_A5XX_VFD_CONTROL_1 0x0000e401 +#define A5XX_VFD_CONTROL_1_REGID4VTX__MASK 0x000000ff +#define A5XX_VFD_CONTROL_1_REGID4VTX__SHIFT 0 +static inline uint32_t A5XX_VFD_CONTROL_1_REGID4VTX(uint32_t val) +{ + return ((val) << A5XX_VFD_CONTROL_1_REGID4VTX__SHIFT) & A5XX_VFD_CONTROL_1_REGID4VTX__MASK; +} +#define A5XX_VFD_CONTROL_1_REGID4INST__MASK 0x0000ff00 +#define A5XX_VFD_CONTROL_1_REGID4INST__SHIFT 8 +static inline uint32_t A5XX_VFD_CONTROL_1_REGID4INST(uint32_t val) +{ + return ((val) << A5XX_VFD_CONTROL_1_REGID4INST__SHIFT) & A5XX_VFD_CONTROL_1_REGID4INST__MASK; +} +#define A5XX_VFD_CONTROL_1_REGID4PRIMID__MASK 0x00ff0000 +#define A5XX_VFD_CONTROL_1_REGID4PRIMID__SHIFT 16 +static inline uint32_t A5XX_VFD_CONTROL_1_REGID4PRIMID(uint32_t val) +{ + return ((val) << A5XX_VFD_CONTROL_1_REGID4PRIMID__SHIFT) & A5XX_VFD_CONTROL_1_REGID4PRIMID__MASK; +} + +#define REG_A5XX_VFD_CONTROL_2 0x0000e402 +#define A5XX_VFD_CONTROL_2_REGID_PATCHID__MASK 0x000000ff +#define A5XX_VFD_CONTROL_2_REGID_PATCHID__SHIFT 0 +static inline uint32_t A5XX_VFD_CONTROL_2_REGID_PATCHID(uint32_t val) +{ + return ((val) << A5XX_VFD_CONTROL_2_REGID_PATCHID__SHIFT) & A5XX_VFD_CONTROL_2_REGID_PATCHID__MASK; +} + +#define REG_A5XX_VFD_CONTROL_3 0x0000e403 +#define A5XX_VFD_CONTROL_3_REGID_PATCHID__MASK 0x0000ff00 +#define A5XX_VFD_CONTROL_3_REGID_PATCHID__SHIFT 8 +static inline uint32_t A5XX_VFD_CONTROL_3_REGID_PATCHID(uint32_t val) +{ + return ((val) << A5XX_VFD_CONTROL_3_REGID_PATCHID__SHIFT) & A5XX_VFD_CONTROL_3_REGID_PATCHID__MASK; +} +#define A5XX_VFD_CONTROL_3_REGID_TESSX__MASK 0x00ff0000 +#define A5XX_VFD_CONTROL_3_REGID_TESSX__SHIFT 16 +static inline uint32_t A5XX_VFD_CONTROL_3_REGID_TESSX(uint32_t val) +{ + return ((val) << A5XX_VFD_CONTROL_3_REGID_TESSX__SHIFT) & A5XX_VFD_CONTROL_3_REGID_TESSX__MASK; +} +#define A5XX_VFD_CONTROL_3_REGID_TESSY__MASK 0xff000000 +#define A5XX_VFD_CONTROL_3_REGID_TESSY__SHIFT 24 +static inline uint32_t A5XX_VFD_CONTROL_3_REGID_TESSY(uint32_t val) +{ + return ((val) << A5XX_VFD_CONTROL_3_REGID_TESSY__SHIFT) & A5XX_VFD_CONTROL_3_REGID_TESSY__MASK; +} + +#define REG_A5XX_VFD_CONTROL_4 0x0000e404 + +#define REG_A5XX_VFD_CONTROL_5 0x0000e405 + +#define REG_A5XX_VFD_INDEX_OFFSET 0x0000e408 + +#define REG_A5XX_VFD_INSTANCE_START_OFFSET 0x0000e409 + +static inline uint32_t REG_A5XX_VFD_FETCH(uint32_t i0) { return 0x0000e40a + 0x4*i0; } + +static inline uint32_t REG_A5XX_VFD_FETCH_BASE_LO(uint32_t i0) { return 0x0000e40a + 0x4*i0; } + +static inline uint32_t REG_A5XX_VFD_FETCH_BASE_HI(uint32_t i0) { return 0x0000e40b + 0x4*i0; } + +static inline uint32_t REG_A5XX_VFD_FETCH_SIZE(uint32_t i0) { return 0x0000e40c + 0x4*i0; } + +static inline uint32_t REG_A5XX_VFD_FETCH_STRIDE(uint32_t i0) { return 0x0000e40d + 0x4*i0; } + +static inline uint32_t REG_A5XX_VFD_DECODE(uint32_t i0) { return 0x0000e48a + 0x2*i0; } + +static inline uint32_t REG_A5XX_VFD_DECODE_INSTR(uint32_t i0) { return 0x0000e48a + 0x2*i0; } +#define A5XX_VFD_DECODE_INSTR_IDX__MASK 0x0000001f +#define A5XX_VFD_DECODE_INSTR_IDX__SHIFT 0 +static inline uint32_t A5XX_VFD_DECODE_INSTR_IDX(uint32_t val) +{ + return ((val) << A5XX_VFD_DECODE_INSTR_IDX__SHIFT) & A5XX_VFD_DECODE_INSTR_IDX__MASK; +} +#define A5XX_VFD_DECODE_INSTR_INSTANCED 0x00020000 +#define A5XX_VFD_DECODE_INSTR_FORMAT__MASK 0x0ff00000 +#define A5XX_VFD_DECODE_INSTR_FORMAT__SHIFT 20 +static inline uint32_t A5XX_VFD_DECODE_INSTR_FORMAT(enum a5xx_vtx_fmt val) +{ + return ((val) << A5XX_VFD_DECODE_INSTR_FORMAT__SHIFT) & A5XX_VFD_DECODE_INSTR_FORMAT__MASK; +} +#define A5XX_VFD_DECODE_INSTR_SWAP__MASK 0x30000000 +#define A5XX_VFD_DECODE_INSTR_SWAP__SHIFT 28 +static inline uint32_t A5XX_VFD_DECODE_INSTR_SWAP(enum a3xx_color_swap val) +{ + return ((val) << A5XX_VFD_DECODE_INSTR_SWAP__SHIFT) & A5XX_VFD_DECODE_INSTR_SWAP__MASK; +} +#define A5XX_VFD_DECODE_INSTR_UNK30 0x40000000 +#define A5XX_VFD_DECODE_INSTR_FLOAT 0x80000000 + +static inline uint32_t REG_A5XX_VFD_DECODE_STEP_RATE(uint32_t i0) { return 0x0000e48b + 0x2*i0; } + +static inline uint32_t REG_A5XX_VFD_DEST_CNTL(uint32_t i0) { return 0x0000e4ca + 0x1*i0; } + +static inline uint32_t REG_A5XX_VFD_DEST_CNTL_INSTR(uint32_t i0) { return 0x0000e4ca + 0x1*i0; } +#define A5XX_VFD_DEST_CNTL_INSTR_WRITEMASK__MASK 0x0000000f +#define A5XX_VFD_DEST_CNTL_INSTR_WRITEMASK__SHIFT 0 +static inline uint32_t A5XX_VFD_DEST_CNTL_INSTR_WRITEMASK(uint32_t val) +{ + return ((val) << A5XX_VFD_DEST_CNTL_INSTR_WRITEMASK__SHIFT) & A5XX_VFD_DEST_CNTL_INSTR_WRITEMASK__MASK; +} +#define A5XX_VFD_DEST_CNTL_INSTR_REGID__MASK 0x00000ff0 +#define A5XX_VFD_DEST_CNTL_INSTR_REGID__SHIFT 4 +static inline uint32_t A5XX_VFD_DEST_CNTL_INSTR_REGID(uint32_t val) +{ + return ((val) << A5XX_VFD_DEST_CNTL_INSTR_REGID__SHIFT) & A5XX_VFD_DEST_CNTL_INSTR_REGID__MASK; +} + +#define REG_A5XX_VFD_POWER_CNTL 0x0000e4f0 + +#define REG_A5XX_SP_SP_CNTL 0x0000e580 + +#define REG_A5XX_SP_VS_CONFIG 0x0000e584 +#define A5XX_SP_VS_CONFIG_ENABLED 0x00000001 +#define A5XX_SP_VS_CONFIG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_SP_VS_CONFIG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_SP_VS_CONFIG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_VS_CONFIG_CONSTOBJECTOFFSET__SHIFT) & A5XX_SP_VS_CONFIG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_SP_VS_CONFIG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_SP_VS_CONFIG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_SP_VS_CONFIG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_VS_CONFIG_SHADEROBJOFFSET__SHIFT) & A5XX_SP_VS_CONFIG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_SP_FS_CONFIG 0x0000e585 +#define A5XX_SP_FS_CONFIG_ENABLED 0x00000001 +#define A5XX_SP_FS_CONFIG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_SP_FS_CONFIG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_SP_FS_CONFIG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_FS_CONFIG_CONSTOBJECTOFFSET__SHIFT) & A5XX_SP_FS_CONFIG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_SP_FS_CONFIG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_SP_FS_CONFIG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_SP_FS_CONFIG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_FS_CONFIG_SHADEROBJOFFSET__SHIFT) & A5XX_SP_FS_CONFIG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_SP_HS_CONFIG 0x0000e586 +#define A5XX_SP_HS_CONFIG_ENABLED 0x00000001 +#define A5XX_SP_HS_CONFIG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_SP_HS_CONFIG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_SP_HS_CONFIG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_HS_CONFIG_CONSTOBJECTOFFSET__SHIFT) & A5XX_SP_HS_CONFIG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_SP_HS_CONFIG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_SP_HS_CONFIG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_SP_HS_CONFIG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_HS_CONFIG_SHADEROBJOFFSET__SHIFT) & A5XX_SP_HS_CONFIG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_SP_DS_CONFIG 0x0000e587 +#define A5XX_SP_DS_CONFIG_ENABLED 0x00000001 +#define A5XX_SP_DS_CONFIG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_SP_DS_CONFIG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_SP_DS_CONFIG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_DS_CONFIG_CONSTOBJECTOFFSET__SHIFT) & A5XX_SP_DS_CONFIG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_SP_DS_CONFIG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_SP_DS_CONFIG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_SP_DS_CONFIG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_DS_CONFIG_SHADEROBJOFFSET__SHIFT) & A5XX_SP_DS_CONFIG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_SP_GS_CONFIG 0x0000e588 +#define A5XX_SP_GS_CONFIG_ENABLED 0x00000001 +#define A5XX_SP_GS_CONFIG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_SP_GS_CONFIG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_SP_GS_CONFIG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_GS_CONFIG_CONSTOBJECTOFFSET__SHIFT) & A5XX_SP_GS_CONFIG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_SP_GS_CONFIG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_SP_GS_CONFIG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_SP_GS_CONFIG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_GS_CONFIG_SHADEROBJOFFSET__SHIFT) & A5XX_SP_GS_CONFIG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_SP_CS_CONFIG 0x0000e589 +#define A5XX_SP_CS_CONFIG_ENABLED 0x00000001 +#define A5XX_SP_CS_CONFIG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_SP_CS_CONFIG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_SP_CS_CONFIG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_CS_CONFIG_CONSTOBJECTOFFSET__SHIFT) & A5XX_SP_CS_CONFIG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_SP_CS_CONFIG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_SP_CS_CONFIG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_SP_CS_CONFIG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_SP_CS_CONFIG_SHADEROBJOFFSET__SHIFT) & A5XX_SP_CS_CONFIG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_SP_VS_CONFIG_MAX_CONST 0x0000e58a + +#define REG_A5XX_SP_FS_CONFIG_MAX_CONST 0x0000e58b + +#define REG_A5XX_SP_VS_CTRL_REG0 0x0000e590 +#define A5XX_SP_VS_CTRL_REG0_THREADSIZE__MASK 0x00000008 +#define A5XX_SP_VS_CTRL_REG0_THREADSIZE__SHIFT 3 +static inline uint32_t A5XX_SP_VS_CTRL_REG0_THREADSIZE(enum a3xx_threadsize val) +{ + return ((val) << A5XX_SP_VS_CTRL_REG0_THREADSIZE__SHIFT) & A5XX_SP_VS_CTRL_REG0_THREADSIZE__MASK; +} +#define A5XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT__MASK 0x000003f0 +#define A5XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT 4 +static inline uint32_t A5XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT(uint32_t val) +{ + return ((val) << A5XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT) & A5XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT__MASK; +} +#define A5XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT__MASK 0x0000fc00 +#define A5XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT 10 +static inline uint32_t A5XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT(uint32_t val) +{ + return ((val) << A5XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT) & A5XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT__MASK; +} +#define A5XX_SP_VS_CTRL_REG0_VARYING 0x00010000 +#define A5XX_SP_VS_CTRL_REG0_PIXLODENABLE 0x00100000 +#define A5XX_SP_VS_CTRL_REG0_BRANCHSTACK__MASK 0xfe000000 +#define A5XX_SP_VS_CTRL_REG0_BRANCHSTACK__SHIFT 25 +static inline uint32_t A5XX_SP_VS_CTRL_REG0_BRANCHSTACK(uint32_t val) +{ + return ((val) << A5XX_SP_VS_CTRL_REG0_BRANCHSTACK__SHIFT) & A5XX_SP_VS_CTRL_REG0_BRANCHSTACK__MASK; +} + +#define REG_A5XX_SP_PRIMITIVE_CNTL 0x0000e592 +#define A5XX_SP_PRIMITIVE_CNTL_VSOUT__MASK 0x0000001f +#define A5XX_SP_PRIMITIVE_CNTL_VSOUT__SHIFT 0 +static inline uint32_t A5XX_SP_PRIMITIVE_CNTL_VSOUT(uint32_t val) +{ + return ((val) << A5XX_SP_PRIMITIVE_CNTL_VSOUT__SHIFT) & A5XX_SP_PRIMITIVE_CNTL_VSOUT__MASK; +} + +static inline uint32_t REG_A5XX_SP_VS_OUT(uint32_t i0) { return 0x0000e593 + 0x1*i0; } + +static inline uint32_t REG_A5XX_SP_VS_OUT_REG(uint32_t i0) { return 0x0000e593 + 0x1*i0; } +#define A5XX_SP_VS_OUT_REG_A_REGID__MASK 0x000000ff +#define A5XX_SP_VS_OUT_REG_A_REGID__SHIFT 0 +static inline uint32_t A5XX_SP_VS_OUT_REG_A_REGID(uint32_t val) +{ + return ((val) << A5XX_SP_VS_OUT_REG_A_REGID__SHIFT) & A5XX_SP_VS_OUT_REG_A_REGID__MASK; +} +#define A5XX_SP_VS_OUT_REG_A_COMPMASK__MASK 0x00000f00 +#define A5XX_SP_VS_OUT_REG_A_COMPMASK__SHIFT 8 +static inline uint32_t A5XX_SP_VS_OUT_REG_A_COMPMASK(uint32_t val) +{ + return ((val) << A5XX_SP_VS_OUT_REG_A_COMPMASK__SHIFT) & A5XX_SP_VS_OUT_REG_A_COMPMASK__MASK; +} +#define A5XX_SP_VS_OUT_REG_B_REGID__MASK 0x00ff0000 +#define A5XX_SP_VS_OUT_REG_B_REGID__SHIFT 16 +static inline uint32_t A5XX_SP_VS_OUT_REG_B_REGID(uint32_t val) +{ + return ((val) << A5XX_SP_VS_OUT_REG_B_REGID__SHIFT) & A5XX_SP_VS_OUT_REG_B_REGID__MASK; +} +#define A5XX_SP_VS_OUT_REG_B_COMPMASK__MASK 0x0f000000 +#define A5XX_SP_VS_OUT_REG_B_COMPMASK__SHIFT 24 +static inline uint32_t A5XX_SP_VS_OUT_REG_B_COMPMASK(uint32_t val) +{ + return ((val) << A5XX_SP_VS_OUT_REG_B_COMPMASK__SHIFT) & A5XX_SP_VS_OUT_REG_B_COMPMASK__MASK; +} + +static inline uint32_t REG_A5XX_SP_VS_VPC_DST(uint32_t i0) { return 0x0000e5a3 + 0x1*i0; } + +static inline uint32_t REG_A5XX_SP_VS_VPC_DST_REG(uint32_t i0) { return 0x0000e5a3 + 0x1*i0; } +#define A5XX_SP_VS_VPC_DST_REG_OUTLOC0__MASK 0x000000ff +#define A5XX_SP_VS_VPC_DST_REG_OUTLOC0__SHIFT 0 +static inline uint32_t A5XX_SP_VS_VPC_DST_REG_OUTLOC0(uint32_t val) +{ + return ((val) << A5XX_SP_VS_VPC_DST_REG_OUTLOC0__SHIFT) & A5XX_SP_VS_VPC_DST_REG_OUTLOC0__MASK; +} +#define A5XX_SP_VS_VPC_DST_REG_OUTLOC1__MASK 0x0000ff00 +#define A5XX_SP_VS_VPC_DST_REG_OUTLOC1__SHIFT 8 +static inline uint32_t A5XX_SP_VS_VPC_DST_REG_OUTLOC1(uint32_t val) +{ + return ((val) << A5XX_SP_VS_VPC_DST_REG_OUTLOC1__SHIFT) & A5XX_SP_VS_VPC_DST_REG_OUTLOC1__MASK; +} +#define A5XX_SP_VS_VPC_DST_REG_OUTLOC2__MASK 0x00ff0000 +#define A5XX_SP_VS_VPC_DST_REG_OUTLOC2__SHIFT 16 +static inline uint32_t A5XX_SP_VS_VPC_DST_REG_OUTLOC2(uint32_t val) +{ + return ((val) << A5XX_SP_VS_VPC_DST_REG_OUTLOC2__SHIFT) & A5XX_SP_VS_VPC_DST_REG_OUTLOC2__MASK; +} +#define A5XX_SP_VS_VPC_DST_REG_OUTLOC3__MASK 0xff000000 +#define A5XX_SP_VS_VPC_DST_REG_OUTLOC3__SHIFT 24 +static inline uint32_t A5XX_SP_VS_VPC_DST_REG_OUTLOC3(uint32_t val) +{ + return ((val) << A5XX_SP_VS_VPC_DST_REG_OUTLOC3__SHIFT) & A5XX_SP_VS_VPC_DST_REG_OUTLOC3__MASK; +} + +#define REG_A5XX_UNKNOWN_E5AB 0x0000e5ab + +#define REG_A5XX_SP_VS_OBJ_START_LO 0x0000e5ac + +#define REG_A5XX_SP_VS_OBJ_START_HI 0x0000e5ad + +#define REG_A5XX_SP_FS_CTRL_REG0 0x0000e5c0 +#define A5XX_SP_FS_CTRL_REG0_THREADSIZE__MASK 0x00000008 +#define A5XX_SP_FS_CTRL_REG0_THREADSIZE__SHIFT 3 +static inline uint32_t A5XX_SP_FS_CTRL_REG0_THREADSIZE(enum a3xx_threadsize val) +{ + return ((val) << A5XX_SP_FS_CTRL_REG0_THREADSIZE__SHIFT) & A5XX_SP_FS_CTRL_REG0_THREADSIZE__MASK; +} +#define A5XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT__MASK 0x000003f0 +#define A5XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT 4 +static inline uint32_t A5XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT(uint32_t val) +{ + return ((val) << A5XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT) & A5XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT__MASK; +} +#define A5XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT__MASK 0x0000fc00 +#define A5XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT 10 +static inline uint32_t A5XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT(uint32_t val) +{ + return ((val) << A5XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT) & A5XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT__MASK; +} +#define A5XX_SP_FS_CTRL_REG0_VARYING 0x00010000 +#define A5XX_SP_FS_CTRL_REG0_PIXLODENABLE 0x00100000 +#define A5XX_SP_FS_CTRL_REG0_BRANCHSTACK__MASK 0xfe000000 +#define A5XX_SP_FS_CTRL_REG0_BRANCHSTACK__SHIFT 25 +static inline uint32_t A5XX_SP_FS_CTRL_REG0_BRANCHSTACK(uint32_t val) +{ + return ((val) << A5XX_SP_FS_CTRL_REG0_BRANCHSTACK__SHIFT) & A5XX_SP_FS_CTRL_REG0_BRANCHSTACK__MASK; +} + +#define REG_A5XX_UNKNOWN_E5C2 0x0000e5c2 + +#define REG_A5XX_SP_FS_OBJ_START_LO 0x0000e5c3 + +#define REG_A5XX_SP_FS_OBJ_START_HI 0x0000e5c4 + +#define REG_A5XX_SP_BLEND_CNTL 0x0000e5c9 +#define A5XX_SP_BLEND_CNTL_ENABLED 0x00000001 +#define A5XX_SP_BLEND_CNTL_UNK8 0x00000100 +#define A5XX_SP_BLEND_CNTL_ALPHA_TO_COVERAGE 0x00000400 + +#define REG_A5XX_SP_FS_OUTPUT_CNTL 0x0000e5ca +#define A5XX_SP_FS_OUTPUT_CNTL_MRT__MASK 0x0000000f +#define A5XX_SP_FS_OUTPUT_CNTL_MRT__SHIFT 0 +static inline uint32_t A5XX_SP_FS_OUTPUT_CNTL_MRT(uint32_t val) +{ + return ((val) << A5XX_SP_FS_OUTPUT_CNTL_MRT__SHIFT) & A5XX_SP_FS_OUTPUT_CNTL_MRT__MASK; +} +#define A5XX_SP_FS_OUTPUT_CNTL_DEPTH_REGID__MASK 0x00001fe0 +#define A5XX_SP_FS_OUTPUT_CNTL_DEPTH_REGID__SHIFT 5 +static inline uint32_t A5XX_SP_FS_OUTPUT_CNTL_DEPTH_REGID(uint32_t val) +{ + return ((val) << A5XX_SP_FS_OUTPUT_CNTL_DEPTH_REGID__SHIFT) & A5XX_SP_FS_OUTPUT_CNTL_DEPTH_REGID__MASK; +} +#define A5XX_SP_FS_OUTPUT_CNTL_SAMPLEMASK_REGID__MASK 0x001fe000 +#define A5XX_SP_FS_OUTPUT_CNTL_SAMPLEMASK_REGID__SHIFT 13 +static inline uint32_t A5XX_SP_FS_OUTPUT_CNTL_SAMPLEMASK_REGID(uint32_t val) +{ + return ((val) << A5XX_SP_FS_OUTPUT_CNTL_SAMPLEMASK_REGID__SHIFT) & A5XX_SP_FS_OUTPUT_CNTL_SAMPLEMASK_REGID__MASK; +} + +static inline uint32_t REG_A5XX_SP_FS_OUTPUT(uint32_t i0) { return 0x0000e5cb + 0x1*i0; } + +static inline uint32_t REG_A5XX_SP_FS_OUTPUT_REG(uint32_t i0) { return 0x0000e5cb + 0x1*i0; } +#define A5XX_SP_FS_OUTPUT_REG_REGID__MASK 0x000000ff +#define A5XX_SP_FS_OUTPUT_REG_REGID__SHIFT 0 +static inline uint32_t A5XX_SP_FS_OUTPUT_REG_REGID(uint32_t val) +{ + return ((val) << A5XX_SP_FS_OUTPUT_REG_REGID__SHIFT) & A5XX_SP_FS_OUTPUT_REG_REGID__MASK; +} +#define A5XX_SP_FS_OUTPUT_REG_HALF_PRECISION 0x00000100 + +static inline uint32_t REG_A5XX_SP_FS_MRT(uint32_t i0) { return 0x0000e5d3 + 0x1*i0; } + +static inline uint32_t REG_A5XX_SP_FS_MRT_REG(uint32_t i0) { return 0x0000e5d3 + 0x1*i0; } +#define A5XX_SP_FS_MRT_REG_COLOR_FORMAT__MASK 0x000000ff +#define A5XX_SP_FS_MRT_REG_COLOR_FORMAT__SHIFT 0 +static inline uint32_t A5XX_SP_FS_MRT_REG_COLOR_FORMAT(enum a5xx_color_fmt val) +{ + return ((val) << A5XX_SP_FS_MRT_REG_COLOR_FORMAT__SHIFT) & A5XX_SP_FS_MRT_REG_COLOR_FORMAT__MASK; +} +#define A5XX_SP_FS_MRT_REG_COLOR_SINT 0x00000100 +#define A5XX_SP_FS_MRT_REG_COLOR_UINT 0x00000200 +#define A5XX_SP_FS_MRT_REG_COLOR_SRGB 0x00000400 + +#define REG_A5XX_UNKNOWN_E5DB 0x0000e5db + +#define REG_A5XX_SP_CS_CTRL_REG0 0x0000e5f0 +#define A5XX_SP_CS_CTRL_REG0_THREADSIZE__MASK 0x00000008 +#define A5XX_SP_CS_CTRL_REG0_THREADSIZE__SHIFT 3 +static inline uint32_t A5XX_SP_CS_CTRL_REG0_THREADSIZE(enum a3xx_threadsize val) +{ + return ((val) << A5XX_SP_CS_CTRL_REG0_THREADSIZE__SHIFT) & A5XX_SP_CS_CTRL_REG0_THREADSIZE__MASK; +} +#define A5XX_SP_CS_CTRL_REG0_HALFREGFOOTPRINT__MASK 0x000003f0 +#define A5XX_SP_CS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT 4 +static inline uint32_t A5XX_SP_CS_CTRL_REG0_HALFREGFOOTPRINT(uint32_t val) +{ + return ((val) << A5XX_SP_CS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT) & A5XX_SP_CS_CTRL_REG0_HALFREGFOOTPRINT__MASK; +} +#define A5XX_SP_CS_CTRL_REG0_FULLREGFOOTPRINT__MASK 0x0000fc00 +#define A5XX_SP_CS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT 10 +static inline uint32_t A5XX_SP_CS_CTRL_REG0_FULLREGFOOTPRINT(uint32_t val) +{ + return ((val) << A5XX_SP_CS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT) & A5XX_SP_CS_CTRL_REG0_FULLREGFOOTPRINT__MASK; +} +#define A5XX_SP_CS_CTRL_REG0_VARYING 0x00010000 +#define A5XX_SP_CS_CTRL_REG0_PIXLODENABLE 0x00100000 +#define A5XX_SP_CS_CTRL_REG0_BRANCHSTACK__MASK 0xfe000000 +#define A5XX_SP_CS_CTRL_REG0_BRANCHSTACK__SHIFT 25 +static inline uint32_t A5XX_SP_CS_CTRL_REG0_BRANCHSTACK(uint32_t val) +{ + return ((val) << A5XX_SP_CS_CTRL_REG0_BRANCHSTACK__SHIFT) & A5XX_SP_CS_CTRL_REG0_BRANCHSTACK__MASK; +} + +#define REG_A5XX_UNKNOWN_E5F2 0x0000e5f2 + +#define REG_A5XX_SP_CS_OBJ_START_LO 0x0000e5f3 + +#define REG_A5XX_SP_CS_OBJ_START_HI 0x0000e5f4 + +#define REG_A5XX_SP_HS_CTRL_REG0 0x0000e600 +#define A5XX_SP_HS_CTRL_REG0_THREADSIZE__MASK 0x00000008 +#define A5XX_SP_HS_CTRL_REG0_THREADSIZE__SHIFT 3 +static inline uint32_t A5XX_SP_HS_CTRL_REG0_THREADSIZE(enum a3xx_threadsize val) +{ + return ((val) << A5XX_SP_HS_CTRL_REG0_THREADSIZE__SHIFT) & A5XX_SP_HS_CTRL_REG0_THREADSIZE__MASK; +} +#define A5XX_SP_HS_CTRL_REG0_HALFREGFOOTPRINT__MASK 0x000003f0 +#define A5XX_SP_HS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT 4 +static inline uint32_t A5XX_SP_HS_CTRL_REG0_HALFREGFOOTPRINT(uint32_t val) +{ + return ((val) << A5XX_SP_HS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT) & A5XX_SP_HS_CTRL_REG0_HALFREGFOOTPRINT__MASK; +} +#define A5XX_SP_HS_CTRL_REG0_FULLREGFOOTPRINT__MASK 0x0000fc00 +#define A5XX_SP_HS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT 10 +static inline uint32_t A5XX_SP_HS_CTRL_REG0_FULLREGFOOTPRINT(uint32_t val) +{ + return ((val) << A5XX_SP_HS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT) & A5XX_SP_HS_CTRL_REG0_FULLREGFOOTPRINT__MASK; +} +#define A5XX_SP_HS_CTRL_REG0_VARYING 0x00010000 +#define A5XX_SP_HS_CTRL_REG0_PIXLODENABLE 0x00100000 +#define A5XX_SP_HS_CTRL_REG0_BRANCHSTACK__MASK 0xfe000000 +#define A5XX_SP_HS_CTRL_REG0_BRANCHSTACK__SHIFT 25 +static inline uint32_t A5XX_SP_HS_CTRL_REG0_BRANCHSTACK(uint32_t val) +{ + return ((val) << A5XX_SP_HS_CTRL_REG0_BRANCHSTACK__SHIFT) & A5XX_SP_HS_CTRL_REG0_BRANCHSTACK__MASK; +} + +#define REG_A5XX_UNKNOWN_E602 0x0000e602 + +#define REG_A5XX_SP_HS_OBJ_START_LO 0x0000e603 + +#define REG_A5XX_SP_HS_OBJ_START_HI 0x0000e604 + +#define REG_A5XX_SP_DS_CTRL_REG0 0x0000e610 +#define A5XX_SP_DS_CTRL_REG0_THREADSIZE__MASK 0x00000008 +#define A5XX_SP_DS_CTRL_REG0_THREADSIZE__SHIFT 3 +static inline uint32_t A5XX_SP_DS_CTRL_REG0_THREADSIZE(enum a3xx_threadsize val) +{ + return ((val) << A5XX_SP_DS_CTRL_REG0_THREADSIZE__SHIFT) & A5XX_SP_DS_CTRL_REG0_THREADSIZE__MASK; +} +#define A5XX_SP_DS_CTRL_REG0_HALFREGFOOTPRINT__MASK 0x000003f0 +#define A5XX_SP_DS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT 4 +static inline uint32_t A5XX_SP_DS_CTRL_REG0_HALFREGFOOTPRINT(uint32_t val) +{ + return ((val) << A5XX_SP_DS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT) & A5XX_SP_DS_CTRL_REG0_HALFREGFOOTPRINT__MASK; +} +#define A5XX_SP_DS_CTRL_REG0_FULLREGFOOTPRINT__MASK 0x0000fc00 +#define A5XX_SP_DS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT 10 +static inline uint32_t A5XX_SP_DS_CTRL_REG0_FULLREGFOOTPRINT(uint32_t val) +{ + return ((val) << A5XX_SP_DS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT) & A5XX_SP_DS_CTRL_REG0_FULLREGFOOTPRINT__MASK; +} +#define A5XX_SP_DS_CTRL_REG0_VARYING 0x00010000 +#define A5XX_SP_DS_CTRL_REG0_PIXLODENABLE 0x00100000 +#define A5XX_SP_DS_CTRL_REG0_BRANCHSTACK__MASK 0xfe000000 +#define A5XX_SP_DS_CTRL_REG0_BRANCHSTACK__SHIFT 25 +static inline uint32_t A5XX_SP_DS_CTRL_REG0_BRANCHSTACK(uint32_t val) +{ + return ((val) << A5XX_SP_DS_CTRL_REG0_BRANCHSTACK__SHIFT) & A5XX_SP_DS_CTRL_REG0_BRANCHSTACK__MASK; +} + +#define REG_A5XX_UNKNOWN_E62B 0x0000e62b + +#define REG_A5XX_SP_DS_OBJ_START_LO 0x0000e62c + +#define REG_A5XX_SP_DS_OBJ_START_HI 0x0000e62d + +#define REG_A5XX_SP_GS_CTRL_REG0 0x0000e640 +#define A5XX_SP_GS_CTRL_REG0_THREADSIZE__MASK 0x00000008 +#define A5XX_SP_GS_CTRL_REG0_THREADSIZE__SHIFT 3 +static inline uint32_t A5XX_SP_GS_CTRL_REG0_THREADSIZE(enum a3xx_threadsize val) +{ + return ((val) << A5XX_SP_GS_CTRL_REG0_THREADSIZE__SHIFT) & A5XX_SP_GS_CTRL_REG0_THREADSIZE__MASK; +} +#define A5XX_SP_GS_CTRL_REG0_HALFREGFOOTPRINT__MASK 0x000003f0 +#define A5XX_SP_GS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT 4 +static inline uint32_t A5XX_SP_GS_CTRL_REG0_HALFREGFOOTPRINT(uint32_t val) +{ + return ((val) << A5XX_SP_GS_CTRL_REG0_HALFREGFOOTPRINT__SHIFT) & A5XX_SP_GS_CTRL_REG0_HALFREGFOOTPRINT__MASK; +} +#define A5XX_SP_GS_CTRL_REG0_FULLREGFOOTPRINT__MASK 0x0000fc00 +#define A5XX_SP_GS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT 10 +static inline uint32_t A5XX_SP_GS_CTRL_REG0_FULLREGFOOTPRINT(uint32_t val) +{ + return ((val) << A5XX_SP_GS_CTRL_REG0_FULLREGFOOTPRINT__SHIFT) & A5XX_SP_GS_CTRL_REG0_FULLREGFOOTPRINT__MASK; +} +#define A5XX_SP_GS_CTRL_REG0_VARYING 0x00010000 +#define A5XX_SP_GS_CTRL_REG0_PIXLODENABLE 0x00100000 +#define A5XX_SP_GS_CTRL_REG0_BRANCHSTACK__MASK 0xfe000000 +#define A5XX_SP_GS_CTRL_REG0_BRANCHSTACK__SHIFT 25 +static inline uint32_t A5XX_SP_GS_CTRL_REG0_BRANCHSTACK(uint32_t val) +{ + return ((val) << A5XX_SP_GS_CTRL_REG0_BRANCHSTACK__SHIFT) & A5XX_SP_GS_CTRL_REG0_BRANCHSTACK__MASK; +} + +#define REG_A5XX_UNKNOWN_E65B 0x0000e65b + +#define REG_A5XX_SP_GS_OBJ_START_LO 0x0000e65c + +#define REG_A5XX_SP_GS_OBJ_START_HI 0x0000e65d + +#define REG_A5XX_TPL1_TP_RAS_MSAA_CNTL 0x0000e704 +#define A5XX_TPL1_TP_RAS_MSAA_CNTL_SAMPLES__MASK 0x00000003 +#define A5XX_TPL1_TP_RAS_MSAA_CNTL_SAMPLES__SHIFT 0 +static inline uint32_t A5XX_TPL1_TP_RAS_MSAA_CNTL_SAMPLES(enum a3xx_msaa_samples val) +{ + return ((val) << A5XX_TPL1_TP_RAS_MSAA_CNTL_SAMPLES__SHIFT) & A5XX_TPL1_TP_RAS_MSAA_CNTL_SAMPLES__MASK; +} + +#define REG_A5XX_TPL1_TP_DEST_MSAA_CNTL 0x0000e705 +#define A5XX_TPL1_TP_DEST_MSAA_CNTL_SAMPLES__MASK 0x00000003 +#define A5XX_TPL1_TP_DEST_MSAA_CNTL_SAMPLES__SHIFT 0 +static inline uint32_t A5XX_TPL1_TP_DEST_MSAA_CNTL_SAMPLES(enum a3xx_msaa_samples val) +{ + return ((val) << A5XX_TPL1_TP_DEST_MSAA_CNTL_SAMPLES__SHIFT) & A5XX_TPL1_TP_DEST_MSAA_CNTL_SAMPLES__MASK; +} +#define A5XX_TPL1_TP_DEST_MSAA_CNTL_MSAA_DISABLE 0x00000004 + +#define REG_A5XX_TPL1_TP_BORDER_COLOR_BASE_ADDR_LO 0x0000e706 + +#define REG_A5XX_TPL1_TP_BORDER_COLOR_BASE_ADDR_HI 0x0000e707 + +#define REG_A5XX_TPL1_VS_TEX_COUNT 0x0000e700 + +#define REG_A5XX_TPL1_HS_TEX_COUNT 0x0000e701 + +#define REG_A5XX_TPL1_DS_TEX_COUNT 0x0000e702 + +#define REG_A5XX_TPL1_GS_TEX_COUNT 0x0000e703 + +#define REG_A5XX_TPL1_VS_TEX_SAMP_LO 0x0000e722 + +#define REG_A5XX_TPL1_VS_TEX_SAMP_HI 0x0000e723 + +#define REG_A5XX_TPL1_HS_TEX_SAMP_LO 0x0000e724 + +#define REG_A5XX_TPL1_HS_TEX_SAMP_HI 0x0000e725 + +#define REG_A5XX_TPL1_DS_TEX_SAMP_LO 0x0000e726 + +#define REG_A5XX_TPL1_DS_TEX_SAMP_HI 0x0000e727 + +#define REG_A5XX_TPL1_GS_TEX_SAMP_LO 0x0000e728 + +#define REG_A5XX_TPL1_GS_TEX_SAMP_HI 0x0000e729 + +#define REG_A5XX_TPL1_VS_TEX_CONST_LO 0x0000e72a + +#define REG_A5XX_TPL1_VS_TEX_CONST_HI 0x0000e72b + +#define REG_A5XX_TPL1_HS_TEX_CONST_LO 0x0000e72c + +#define REG_A5XX_TPL1_HS_TEX_CONST_HI 0x0000e72d + +#define REG_A5XX_TPL1_DS_TEX_CONST_LO 0x0000e72e + +#define REG_A5XX_TPL1_DS_TEX_CONST_HI 0x0000e72f + +#define REG_A5XX_TPL1_GS_TEX_CONST_LO 0x0000e730 + +#define REG_A5XX_TPL1_GS_TEX_CONST_HI 0x0000e731 + +#define REG_A5XX_TPL1_FS_TEX_COUNT 0x0000e750 + +#define REG_A5XX_TPL1_CS_TEX_COUNT 0x0000e751 + +#define REG_A5XX_TPL1_FS_TEX_SAMP_LO 0x0000e75a + +#define REG_A5XX_TPL1_FS_TEX_SAMP_HI 0x0000e75b + +#define REG_A5XX_TPL1_CS_TEX_SAMP_LO 0x0000e75c + +#define REG_A5XX_TPL1_CS_TEX_SAMP_HI 0x0000e75d + +#define REG_A5XX_TPL1_FS_TEX_CONST_LO 0x0000e75e + +#define REG_A5XX_TPL1_FS_TEX_CONST_HI 0x0000e75f + +#define REG_A5XX_TPL1_CS_TEX_CONST_LO 0x0000e760 + +#define REG_A5XX_TPL1_CS_TEX_CONST_HI 0x0000e761 + +#define REG_A5XX_TPL1_TP_FS_ROTATION_CNTL 0x0000e764 + +#define REG_A5XX_HLSQ_CONTROL_0_REG 0x0000e784 +#define A5XX_HLSQ_CONTROL_0_REG_FSTHREADSIZE__MASK 0x00000001 +#define A5XX_HLSQ_CONTROL_0_REG_FSTHREADSIZE__SHIFT 0 +static inline uint32_t A5XX_HLSQ_CONTROL_0_REG_FSTHREADSIZE(enum a3xx_threadsize val) +{ + return ((val) << A5XX_HLSQ_CONTROL_0_REG_FSTHREADSIZE__SHIFT) & A5XX_HLSQ_CONTROL_0_REG_FSTHREADSIZE__MASK; +} +#define A5XX_HLSQ_CONTROL_0_REG_CSTHREADSIZE__MASK 0x00000004 +#define A5XX_HLSQ_CONTROL_0_REG_CSTHREADSIZE__SHIFT 2 +static inline uint32_t A5XX_HLSQ_CONTROL_0_REG_CSTHREADSIZE(enum a3xx_threadsize val) +{ + return ((val) << A5XX_HLSQ_CONTROL_0_REG_CSTHREADSIZE__SHIFT) & A5XX_HLSQ_CONTROL_0_REG_CSTHREADSIZE__MASK; +} + +#define REG_A5XX_HLSQ_CONTROL_1_REG 0x0000e785 +#define A5XX_HLSQ_CONTROL_1_REG_PRIMALLOCTHRESHOLD__MASK 0x0000003f +#define A5XX_HLSQ_CONTROL_1_REG_PRIMALLOCTHRESHOLD__SHIFT 0 +static inline uint32_t A5XX_HLSQ_CONTROL_1_REG_PRIMALLOCTHRESHOLD(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CONTROL_1_REG_PRIMALLOCTHRESHOLD__SHIFT) & A5XX_HLSQ_CONTROL_1_REG_PRIMALLOCTHRESHOLD__MASK; +} + +#define REG_A5XX_HLSQ_CONTROL_2_REG 0x0000e786 +#define A5XX_HLSQ_CONTROL_2_REG_FACEREGID__MASK 0x000000ff +#define A5XX_HLSQ_CONTROL_2_REG_FACEREGID__SHIFT 0 +static inline uint32_t A5XX_HLSQ_CONTROL_2_REG_FACEREGID(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CONTROL_2_REG_FACEREGID__SHIFT) & A5XX_HLSQ_CONTROL_2_REG_FACEREGID__MASK; +} +#define A5XX_HLSQ_CONTROL_2_REG_SAMPLEID__MASK 0x0000ff00 +#define A5XX_HLSQ_CONTROL_2_REG_SAMPLEID__SHIFT 8 +static inline uint32_t A5XX_HLSQ_CONTROL_2_REG_SAMPLEID(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CONTROL_2_REG_SAMPLEID__SHIFT) & A5XX_HLSQ_CONTROL_2_REG_SAMPLEID__MASK; +} +#define A5XX_HLSQ_CONTROL_2_REG_SAMPLEMASK__MASK 0x00ff0000 +#define A5XX_HLSQ_CONTROL_2_REG_SAMPLEMASK__SHIFT 16 +static inline uint32_t A5XX_HLSQ_CONTROL_2_REG_SAMPLEMASK(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CONTROL_2_REG_SAMPLEMASK__SHIFT) & A5XX_HLSQ_CONTROL_2_REG_SAMPLEMASK__MASK; +} + +#define REG_A5XX_HLSQ_CONTROL_3_REG 0x0000e787 +#define A5XX_HLSQ_CONTROL_3_REG_FRAGCOORDXYREGID__MASK 0x000000ff +#define A5XX_HLSQ_CONTROL_3_REG_FRAGCOORDXYREGID__SHIFT 0 +static inline uint32_t A5XX_HLSQ_CONTROL_3_REG_FRAGCOORDXYREGID(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CONTROL_3_REG_FRAGCOORDXYREGID__SHIFT) & A5XX_HLSQ_CONTROL_3_REG_FRAGCOORDXYREGID__MASK; +} + +#define REG_A5XX_HLSQ_CONTROL_4_REG 0x0000e788 +#define A5XX_HLSQ_CONTROL_4_REG_XYCOORDREGID__MASK 0x00ff0000 +#define A5XX_HLSQ_CONTROL_4_REG_XYCOORDREGID__SHIFT 16 +static inline uint32_t A5XX_HLSQ_CONTROL_4_REG_XYCOORDREGID(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CONTROL_4_REG_XYCOORDREGID__SHIFT) & A5XX_HLSQ_CONTROL_4_REG_XYCOORDREGID__MASK; +} +#define A5XX_HLSQ_CONTROL_4_REG_ZWCOORDREGID__MASK 0xff000000 +#define A5XX_HLSQ_CONTROL_4_REG_ZWCOORDREGID__SHIFT 24 +static inline uint32_t A5XX_HLSQ_CONTROL_4_REG_ZWCOORDREGID(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CONTROL_4_REG_ZWCOORDREGID__SHIFT) & A5XX_HLSQ_CONTROL_4_REG_ZWCOORDREGID__MASK; +} + +#define REG_A5XX_HLSQ_UPDATE_CNTL 0x0000e78a + +#define REG_A5XX_HLSQ_VS_CONFIG 0x0000e78b +#define A5XX_HLSQ_VS_CONFIG_ENABLED 0x00000001 +#define A5XX_HLSQ_VS_CONFIG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_HLSQ_VS_CONFIG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_HLSQ_VS_CONFIG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_VS_CONFIG_CONSTOBJECTOFFSET__SHIFT) & A5XX_HLSQ_VS_CONFIG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_HLSQ_VS_CONFIG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_HLSQ_VS_CONFIG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_HLSQ_VS_CONFIG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_VS_CONFIG_SHADEROBJOFFSET__SHIFT) & A5XX_HLSQ_VS_CONFIG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_HLSQ_FS_CONFIG 0x0000e78c +#define A5XX_HLSQ_FS_CONFIG_ENABLED 0x00000001 +#define A5XX_HLSQ_FS_CONFIG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_HLSQ_FS_CONFIG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_HLSQ_FS_CONFIG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_FS_CONFIG_CONSTOBJECTOFFSET__SHIFT) & A5XX_HLSQ_FS_CONFIG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_HLSQ_FS_CONFIG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_HLSQ_FS_CONFIG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_HLSQ_FS_CONFIG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_FS_CONFIG_SHADEROBJOFFSET__SHIFT) & A5XX_HLSQ_FS_CONFIG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_HLSQ_HS_CONFIG 0x0000e78d +#define A5XX_HLSQ_HS_CONFIG_ENABLED 0x00000001 +#define A5XX_HLSQ_HS_CONFIG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_HLSQ_HS_CONFIG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_HLSQ_HS_CONFIG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_HS_CONFIG_CONSTOBJECTOFFSET__SHIFT) & A5XX_HLSQ_HS_CONFIG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_HLSQ_HS_CONFIG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_HLSQ_HS_CONFIG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_HLSQ_HS_CONFIG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_HS_CONFIG_SHADEROBJOFFSET__SHIFT) & A5XX_HLSQ_HS_CONFIG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_HLSQ_DS_CONFIG 0x0000e78e +#define A5XX_HLSQ_DS_CONFIG_ENABLED 0x00000001 +#define A5XX_HLSQ_DS_CONFIG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_HLSQ_DS_CONFIG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_HLSQ_DS_CONFIG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_DS_CONFIG_CONSTOBJECTOFFSET__SHIFT) & A5XX_HLSQ_DS_CONFIG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_HLSQ_DS_CONFIG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_HLSQ_DS_CONFIG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_HLSQ_DS_CONFIG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_DS_CONFIG_SHADEROBJOFFSET__SHIFT) & A5XX_HLSQ_DS_CONFIG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_HLSQ_GS_CONFIG 0x0000e78f +#define A5XX_HLSQ_GS_CONFIG_ENABLED 0x00000001 +#define A5XX_HLSQ_GS_CONFIG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_HLSQ_GS_CONFIG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_HLSQ_GS_CONFIG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_GS_CONFIG_CONSTOBJECTOFFSET__SHIFT) & A5XX_HLSQ_GS_CONFIG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_HLSQ_GS_CONFIG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_HLSQ_GS_CONFIG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_HLSQ_GS_CONFIG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_GS_CONFIG_SHADEROBJOFFSET__SHIFT) & A5XX_HLSQ_GS_CONFIG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_HLSQ_CS_CONFIG 0x0000e790 +#define A5XX_HLSQ_CS_CONFIG_ENABLED 0x00000001 +#define A5XX_HLSQ_CS_CONFIG_CONSTOBJECTOFFSET__MASK 0x000000fe +#define A5XX_HLSQ_CS_CONFIG_CONSTOBJECTOFFSET__SHIFT 1 +static inline uint32_t A5XX_HLSQ_CS_CONFIG_CONSTOBJECTOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CS_CONFIG_CONSTOBJECTOFFSET__SHIFT) & A5XX_HLSQ_CS_CONFIG_CONSTOBJECTOFFSET__MASK; +} +#define A5XX_HLSQ_CS_CONFIG_SHADEROBJOFFSET__MASK 0x00007f00 +#define A5XX_HLSQ_CS_CONFIG_SHADEROBJOFFSET__SHIFT 8 +static inline uint32_t A5XX_HLSQ_CS_CONFIG_SHADEROBJOFFSET(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CS_CONFIG_SHADEROBJOFFSET__SHIFT) & A5XX_HLSQ_CS_CONFIG_SHADEROBJOFFSET__MASK; +} + +#define REG_A5XX_HLSQ_VS_CNTL 0x0000e791 +#define A5XX_HLSQ_VS_CNTL_SSBO_ENABLE 0x00000001 +#define A5XX_HLSQ_VS_CNTL_INSTRLEN__MASK 0xfffffffe +#define A5XX_HLSQ_VS_CNTL_INSTRLEN__SHIFT 1 +static inline uint32_t A5XX_HLSQ_VS_CNTL_INSTRLEN(uint32_t val) +{ + return ((val) << A5XX_HLSQ_VS_CNTL_INSTRLEN__SHIFT) & A5XX_HLSQ_VS_CNTL_INSTRLEN__MASK; +} + +#define REG_A5XX_HLSQ_FS_CNTL 0x0000e792 +#define A5XX_HLSQ_FS_CNTL_SSBO_ENABLE 0x00000001 +#define A5XX_HLSQ_FS_CNTL_INSTRLEN__MASK 0xfffffffe +#define A5XX_HLSQ_FS_CNTL_INSTRLEN__SHIFT 1 +static inline uint32_t A5XX_HLSQ_FS_CNTL_INSTRLEN(uint32_t val) +{ + return ((val) << A5XX_HLSQ_FS_CNTL_INSTRLEN__SHIFT) & A5XX_HLSQ_FS_CNTL_INSTRLEN__MASK; +} + +#define REG_A5XX_HLSQ_HS_CNTL 0x0000e793 +#define A5XX_HLSQ_HS_CNTL_SSBO_ENABLE 0x00000001 +#define A5XX_HLSQ_HS_CNTL_INSTRLEN__MASK 0xfffffffe +#define A5XX_HLSQ_HS_CNTL_INSTRLEN__SHIFT 1 +static inline uint32_t A5XX_HLSQ_HS_CNTL_INSTRLEN(uint32_t val) +{ + return ((val) << A5XX_HLSQ_HS_CNTL_INSTRLEN__SHIFT) & A5XX_HLSQ_HS_CNTL_INSTRLEN__MASK; +} + +#define REG_A5XX_HLSQ_DS_CNTL 0x0000e794 +#define A5XX_HLSQ_DS_CNTL_SSBO_ENABLE 0x00000001 +#define A5XX_HLSQ_DS_CNTL_INSTRLEN__MASK 0xfffffffe +#define A5XX_HLSQ_DS_CNTL_INSTRLEN__SHIFT 1 +static inline uint32_t A5XX_HLSQ_DS_CNTL_INSTRLEN(uint32_t val) +{ + return ((val) << A5XX_HLSQ_DS_CNTL_INSTRLEN__SHIFT) & A5XX_HLSQ_DS_CNTL_INSTRLEN__MASK; +} + +#define REG_A5XX_HLSQ_GS_CNTL 0x0000e795 +#define A5XX_HLSQ_GS_CNTL_SSBO_ENABLE 0x00000001 +#define A5XX_HLSQ_GS_CNTL_INSTRLEN__MASK 0xfffffffe +#define A5XX_HLSQ_GS_CNTL_INSTRLEN__SHIFT 1 +static inline uint32_t A5XX_HLSQ_GS_CNTL_INSTRLEN(uint32_t val) +{ + return ((val) << A5XX_HLSQ_GS_CNTL_INSTRLEN__SHIFT) & A5XX_HLSQ_GS_CNTL_INSTRLEN__MASK; +} + +#define REG_A5XX_HLSQ_CS_CNTL 0x0000e796 +#define A5XX_HLSQ_CS_CNTL_SSBO_ENABLE 0x00000001 +#define A5XX_HLSQ_CS_CNTL_INSTRLEN__MASK 0xfffffffe +#define A5XX_HLSQ_CS_CNTL_INSTRLEN__SHIFT 1 +static inline uint32_t A5XX_HLSQ_CS_CNTL_INSTRLEN(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CS_CNTL_INSTRLEN__SHIFT) & A5XX_HLSQ_CS_CNTL_INSTRLEN__MASK; +} + +#define REG_A5XX_HLSQ_CS_KERNEL_GROUP_X 0x0000e7b9 + +#define REG_A5XX_HLSQ_CS_KERNEL_GROUP_Y 0x0000e7ba + +#define REG_A5XX_HLSQ_CS_KERNEL_GROUP_Z 0x0000e7bb + +#define REG_A5XX_HLSQ_CS_NDRANGE_0 0x0000e7b0 +#define A5XX_HLSQ_CS_NDRANGE_0_KERNELDIM__MASK 0x00000003 +#define A5XX_HLSQ_CS_NDRANGE_0_KERNELDIM__SHIFT 0 +static inline uint32_t A5XX_HLSQ_CS_NDRANGE_0_KERNELDIM(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CS_NDRANGE_0_KERNELDIM__SHIFT) & A5XX_HLSQ_CS_NDRANGE_0_KERNELDIM__MASK; +} +#define A5XX_HLSQ_CS_NDRANGE_0_LOCALSIZEX__MASK 0x00000ffc +#define A5XX_HLSQ_CS_NDRANGE_0_LOCALSIZEX__SHIFT 2 +static inline uint32_t A5XX_HLSQ_CS_NDRANGE_0_LOCALSIZEX(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CS_NDRANGE_0_LOCALSIZEX__SHIFT) & A5XX_HLSQ_CS_NDRANGE_0_LOCALSIZEX__MASK; +} +#define A5XX_HLSQ_CS_NDRANGE_0_LOCALSIZEY__MASK 0x003ff000 +#define A5XX_HLSQ_CS_NDRANGE_0_LOCALSIZEY__SHIFT 12 +static inline uint32_t A5XX_HLSQ_CS_NDRANGE_0_LOCALSIZEY(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CS_NDRANGE_0_LOCALSIZEY__SHIFT) & A5XX_HLSQ_CS_NDRANGE_0_LOCALSIZEY__MASK; +} +#define A5XX_HLSQ_CS_NDRANGE_0_LOCALSIZEZ__MASK 0xffc00000 +#define A5XX_HLSQ_CS_NDRANGE_0_LOCALSIZEZ__SHIFT 22 +static inline uint32_t A5XX_HLSQ_CS_NDRANGE_0_LOCALSIZEZ(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CS_NDRANGE_0_LOCALSIZEZ__SHIFT) & A5XX_HLSQ_CS_NDRANGE_0_LOCALSIZEZ__MASK; +} + +#define REG_A5XX_HLSQ_CS_NDRANGE_1 0x0000e7b1 +#define A5XX_HLSQ_CS_NDRANGE_1_GLOBALSIZE_X__MASK 0xffffffff +#define A5XX_HLSQ_CS_NDRANGE_1_GLOBALSIZE_X__SHIFT 0 +static inline uint32_t A5XX_HLSQ_CS_NDRANGE_1_GLOBALSIZE_X(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CS_NDRANGE_1_GLOBALSIZE_X__SHIFT) & A5XX_HLSQ_CS_NDRANGE_1_GLOBALSIZE_X__MASK; +} + +#define REG_A5XX_HLSQ_CS_NDRANGE_2 0x0000e7b2 +#define A5XX_HLSQ_CS_NDRANGE_2_GLOBALOFF_X__MASK 0xffffffff +#define A5XX_HLSQ_CS_NDRANGE_2_GLOBALOFF_X__SHIFT 0 +static inline uint32_t A5XX_HLSQ_CS_NDRANGE_2_GLOBALOFF_X(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CS_NDRANGE_2_GLOBALOFF_X__SHIFT) & A5XX_HLSQ_CS_NDRANGE_2_GLOBALOFF_X__MASK; +} + +#define REG_A5XX_HLSQ_CS_NDRANGE_3 0x0000e7b3 +#define A5XX_HLSQ_CS_NDRANGE_3_GLOBALSIZE_Y__MASK 0xffffffff +#define A5XX_HLSQ_CS_NDRANGE_3_GLOBALSIZE_Y__SHIFT 0 +static inline uint32_t A5XX_HLSQ_CS_NDRANGE_3_GLOBALSIZE_Y(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CS_NDRANGE_3_GLOBALSIZE_Y__SHIFT) & A5XX_HLSQ_CS_NDRANGE_3_GLOBALSIZE_Y__MASK; +} + +#define REG_A5XX_HLSQ_CS_NDRANGE_4 0x0000e7b4 +#define A5XX_HLSQ_CS_NDRANGE_4_GLOBALOFF_Y__MASK 0xffffffff +#define A5XX_HLSQ_CS_NDRANGE_4_GLOBALOFF_Y__SHIFT 0 +static inline uint32_t A5XX_HLSQ_CS_NDRANGE_4_GLOBALOFF_Y(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CS_NDRANGE_4_GLOBALOFF_Y__SHIFT) & A5XX_HLSQ_CS_NDRANGE_4_GLOBALOFF_Y__MASK; +} + +#define REG_A5XX_HLSQ_CS_NDRANGE_5 0x0000e7b5 +#define A5XX_HLSQ_CS_NDRANGE_5_GLOBALSIZE_Z__MASK 0xffffffff +#define A5XX_HLSQ_CS_NDRANGE_5_GLOBALSIZE_Z__SHIFT 0 +static inline uint32_t A5XX_HLSQ_CS_NDRANGE_5_GLOBALSIZE_Z(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CS_NDRANGE_5_GLOBALSIZE_Z__SHIFT) & A5XX_HLSQ_CS_NDRANGE_5_GLOBALSIZE_Z__MASK; +} + +#define REG_A5XX_HLSQ_CS_NDRANGE_6 0x0000e7b6 +#define A5XX_HLSQ_CS_NDRANGE_6_GLOBALOFF_Z__MASK 0xffffffff +#define A5XX_HLSQ_CS_NDRANGE_6_GLOBALOFF_Z__SHIFT 0 +static inline uint32_t A5XX_HLSQ_CS_NDRANGE_6_GLOBALOFF_Z(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CS_NDRANGE_6_GLOBALOFF_Z__SHIFT) & A5XX_HLSQ_CS_NDRANGE_6_GLOBALOFF_Z__MASK; +} + +#define REG_A5XX_HLSQ_CS_CNTL_0 0x0000e7b7 +#define A5XX_HLSQ_CS_CNTL_0_WGIDCONSTID__MASK 0x000000ff +#define A5XX_HLSQ_CS_CNTL_0_WGIDCONSTID__SHIFT 0 +static inline uint32_t A5XX_HLSQ_CS_CNTL_0_WGIDCONSTID(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CS_CNTL_0_WGIDCONSTID__SHIFT) & A5XX_HLSQ_CS_CNTL_0_WGIDCONSTID__MASK; +} +#define A5XX_HLSQ_CS_CNTL_0_UNK0__MASK 0x0000ff00 +#define A5XX_HLSQ_CS_CNTL_0_UNK0__SHIFT 8 +static inline uint32_t A5XX_HLSQ_CS_CNTL_0_UNK0(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CS_CNTL_0_UNK0__SHIFT) & A5XX_HLSQ_CS_CNTL_0_UNK0__MASK; +} +#define A5XX_HLSQ_CS_CNTL_0_UNK1__MASK 0x00ff0000 +#define A5XX_HLSQ_CS_CNTL_0_UNK1__SHIFT 16 +static inline uint32_t A5XX_HLSQ_CS_CNTL_0_UNK1(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CS_CNTL_0_UNK1__SHIFT) & A5XX_HLSQ_CS_CNTL_0_UNK1__MASK; +} +#define A5XX_HLSQ_CS_CNTL_0_LOCALIDREGID__MASK 0xff000000 +#define A5XX_HLSQ_CS_CNTL_0_LOCALIDREGID__SHIFT 24 +static inline uint32_t A5XX_HLSQ_CS_CNTL_0_LOCALIDREGID(uint32_t val) +{ + return ((val) << A5XX_HLSQ_CS_CNTL_0_LOCALIDREGID__SHIFT) & A5XX_HLSQ_CS_CNTL_0_LOCALIDREGID__MASK; +} + +#define REG_A5XX_HLSQ_CS_CNTL_1 0x0000e7b8 + +#define REG_A5XX_UNKNOWN_E7C0 0x0000e7c0 + +#define REG_A5XX_HLSQ_VS_CONSTLEN 0x0000e7c3 + +#define REG_A5XX_HLSQ_VS_INSTRLEN 0x0000e7c4 + +#define REG_A5XX_UNKNOWN_E7C5 0x0000e7c5 + +#define REG_A5XX_HLSQ_HS_CONSTLEN 0x0000e7c8 + +#define REG_A5XX_HLSQ_HS_INSTRLEN 0x0000e7c9 + +#define REG_A5XX_UNKNOWN_E7CA 0x0000e7ca + +#define REG_A5XX_HLSQ_DS_CONSTLEN 0x0000e7cd + +#define REG_A5XX_HLSQ_DS_INSTRLEN 0x0000e7ce + +#define REG_A5XX_UNKNOWN_E7CF 0x0000e7cf + +#define REG_A5XX_HLSQ_GS_CONSTLEN 0x0000e7d2 + +#define REG_A5XX_HLSQ_GS_INSTRLEN 0x0000e7d3 + +#define REG_A5XX_UNKNOWN_E7D4 0x0000e7d4 + +#define REG_A5XX_HLSQ_FS_CONSTLEN 0x0000e7d7 + +#define REG_A5XX_HLSQ_FS_INSTRLEN 0x0000e7d8 + +#define REG_A5XX_UNKNOWN_E7D9 0x0000e7d9 + +#define REG_A5XX_HLSQ_CS_CONSTLEN 0x0000e7dc + +#define REG_A5XX_HLSQ_CS_INSTRLEN 0x0000e7dd + +#define REG_A5XX_RB_2D_BLIT_CNTL 0x00002100 + +#define REG_A5XX_RB_2D_SRC_SOLID_DW0 0x00002101 + +#define REG_A5XX_RB_2D_SRC_SOLID_DW1 0x00002102 + +#define REG_A5XX_RB_2D_SRC_SOLID_DW2 0x00002103 + +#define REG_A5XX_RB_2D_SRC_SOLID_DW3 0x00002104 + +#define REG_A5XX_RB_2D_SRC_INFO 0x00002107 +#define A5XX_RB_2D_SRC_INFO_COLOR_FORMAT__MASK 0x000000ff +#define A5XX_RB_2D_SRC_INFO_COLOR_FORMAT__SHIFT 0 +static inline uint32_t A5XX_RB_2D_SRC_INFO_COLOR_FORMAT(enum a5xx_color_fmt val) +{ + return ((val) << A5XX_RB_2D_SRC_INFO_COLOR_FORMAT__SHIFT) & A5XX_RB_2D_SRC_INFO_COLOR_FORMAT__MASK; +} +#define A5XX_RB_2D_SRC_INFO_TILE_MODE__MASK 0x00000300 +#define A5XX_RB_2D_SRC_INFO_TILE_MODE__SHIFT 8 +static inline uint32_t A5XX_RB_2D_SRC_INFO_TILE_MODE(enum a5xx_tile_mode val) +{ + return ((val) << A5XX_RB_2D_SRC_INFO_TILE_MODE__SHIFT) & A5XX_RB_2D_SRC_INFO_TILE_MODE__MASK; +} +#define A5XX_RB_2D_SRC_INFO_COLOR_SWAP__MASK 0x00000c00 +#define A5XX_RB_2D_SRC_INFO_COLOR_SWAP__SHIFT 10 +static inline uint32_t A5XX_RB_2D_SRC_INFO_COLOR_SWAP(enum a3xx_color_swap val) +{ + return ((val) << A5XX_RB_2D_SRC_INFO_COLOR_SWAP__SHIFT) & A5XX_RB_2D_SRC_INFO_COLOR_SWAP__MASK; +} +#define A5XX_RB_2D_SRC_INFO_FLAGS 0x00001000 + +#define REG_A5XX_RB_2D_SRC_LO 0x00002108 + +#define REG_A5XX_RB_2D_SRC_HI 0x00002109 + +#define REG_A5XX_RB_2D_SRC_SIZE 0x0000210a +#define A5XX_RB_2D_SRC_SIZE_PITCH__MASK 0x0000ffff +#define A5XX_RB_2D_SRC_SIZE_PITCH__SHIFT 0 +static inline uint32_t A5XX_RB_2D_SRC_SIZE_PITCH(uint32_t val) +{ + return ((val >> 6) << A5XX_RB_2D_SRC_SIZE_PITCH__SHIFT) & A5XX_RB_2D_SRC_SIZE_PITCH__MASK; +} +#define A5XX_RB_2D_SRC_SIZE_ARRAY_PITCH__MASK 0xffff0000 +#define A5XX_RB_2D_SRC_SIZE_ARRAY_PITCH__SHIFT 16 +static inline uint32_t A5XX_RB_2D_SRC_SIZE_ARRAY_PITCH(uint32_t val) +{ + return ((val >> 6) << A5XX_RB_2D_SRC_SIZE_ARRAY_PITCH__SHIFT) & A5XX_RB_2D_SRC_SIZE_ARRAY_PITCH__MASK; +} + +#define REG_A5XX_RB_2D_DST_INFO 0x00002110 +#define A5XX_RB_2D_DST_INFO_COLOR_FORMAT__MASK 0x000000ff +#define A5XX_RB_2D_DST_INFO_COLOR_FORMAT__SHIFT 0 +static inline uint32_t A5XX_RB_2D_DST_INFO_COLOR_FORMAT(enum a5xx_color_fmt val) +{ + return ((val) << A5XX_RB_2D_DST_INFO_COLOR_FORMAT__SHIFT) & A5XX_RB_2D_DST_INFO_COLOR_FORMAT__MASK; +} +#define A5XX_RB_2D_DST_INFO_TILE_MODE__MASK 0x00000300 +#define A5XX_RB_2D_DST_INFO_TILE_MODE__SHIFT 8 +static inline uint32_t A5XX_RB_2D_DST_INFO_TILE_MODE(enum a5xx_tile_mode val) +{ + return ((val) << A5XX_RB_2D_DST_INFO_TILE_MODE__SHIFT) & A5XX_RB_2D_DST_INFO_TILE_MODE__MASK; +} +#define A5XX_RB_2D_DST_INFO_COLOR_SWAP__MASK 0x00000c00 +#define A5XX_RB_2D_DST_INFO_COLOR_SWAP__SHIFT 10 +static inline uint32_t A5XX_RB_2D_DST_INFO_COLOR_SWAP(enum a3xx_color_swap val) +{ + return ((val) << A5XX_RB_2D_DST_INFO_COLOR_SWAP__SHIFT) & A5XX_RB_2D_DST_INFO_COLOR_SWAP__MASK; +} +#define A5XX_RB_2D_DST_INFO_FLAGS 0x00001000 + +#define REG_A5XX_RB_2D_DST_LO 0x00002111 + +#define REG_A5XX_RB_2D_DST_HI 0x00002112 + +#define REG_A5XX_RB_2D_DST_SIZE 0x00002113 +#define A5XX_RB_2D_DST_SIZE_PITCH__MASK 0x0000ffff +#define A5XX_RB_2D_DST_SIZE_PITCH__SHIFT 0 +static inline uint32_t A5XX_RB_2D_DST_SIZE_PITCH(uint32_t val) +{ + return ((val >> 6) << A5XX_RB_2D_DST_SIZE_PITCH__SHIFT) & A5XX_RB_2D_DST_SIZE_PITCH__MASK; +} +#define A5XX_RB_2D_DST_SIZE_ARRAY_PITCH__MASK 0xffff0000 +#define A5XX_RB_2D_DST_SIZE_ARRAY_PITCH__SHIFT 16 +static inline uint32_t A5XX_RB_2D_DST_SIZE_ARRAY_PITCH(uint32_t val) +{ + return ((val >> 6) << A5XX_RB_2D_DST_SIZE_ARRAY_PITCH__SHIFT) & A5XX_RB_2D_DST_SIZE_ARRAY_PITCH__MASK; +} + +#define REG_A5XX_RB_2D_SRC_FLAGS_LO 0x00002140 + +#define REG_A5XX_RB_2D_SRC_FLAGS_HI 0x00002141 + +#define REG_A5XX_RB_2D_DST_FLAGS_LO 0x00002143 + +#define REG_A5XX_RB_2D_DST_FLAGS_HI 0x00002144 + +#define REG_A5XX_GRAS_2D_BLIT_CNTL 0x00002180 + +#define REG_A5XX_GRAS_2D_SRC_INFO 0x00002181 +#define A5XX_GRAS_2D_SRC_INFO_COLOR_FORMAT__MASK 0x000000ff +#define A5XX_GRAS_2D_SRC_INFO_COLOR_FORMAT__SHIFT 0 +static inline uint32_t A5XX_GRAS_2D_SRC_INFO_COLOR_FORMAT(enum a5xx_color_fmt val) +{ + return ((val) << A5XX_GRAS_2D_SRC_INFO_COLOR_FORMAT__SHIFT) & A5XX_GRAS_2D_SRC_INFO_COLOR_FORMAT__MASK; +} +#define A5XX_GRAS_2D_SRC_INFO_TILE_MODE__MASK 0x00000300 +#define A5XX_GRAS_2D_SRC_INFO_TILE_MODE__SHIFT 8 +static inline uint32_t A5XX_GRAS_2D_SRC_INFO_TILE_MODE(enum a5xx_tile_mode val) +{ + return ((val) << A5XX_GRAS_2D_SRC_INFO_TILE_MODE__SHIFT) & A5XX_GRAS_2D_SRC_INFO_TILE_MODE__MASK; +} +#define A5XX_GRAS_2D_SRC_INFO_COLOR_SWAP__MASK 0x00000c00 +#define A5XX_GRAS_2D_SRC_INFO_COLOR_SWAP__SHIFT 10 +static inline uint32_t A5XX_GRAS_2D_SRC_INFO_COLOR_SWAP(enum a3xx_color_swap val) +{ + return ((val) << A5XX_GRAS_2D_SRC_INFO_COLOR_SWAP__SHIFT) & A5XX_GRAS_2D_SRC_INFO_COLOR_SWAP__MASK; +} +#define A5XX_GRAS_2D_SRC_INFO_FLAGS 0x00001000 + +#define REG_A5XX_GRAS_2D_DST_INFO 0x00002182 +#define A5XX_GRAS_2D_DST_INFO_COLOR_FORMAT__MASK 0x000000ff +#define A5XX_GRAS_2D_DST_INFO_COLOR_FORMAT__SHIFT 0 +static inline uint32_t A5XX_GRAS_2D_DST_INFO_COLOR_FORMAT(enum a5xx_color_fmt val) +{ + return ((val) << A5XX_GRAS_2D_DST_INFO_COLOR_FORMAT__SHIFT) & A5XX_GRAS_2D_DST_INFO_COLOR_FORMAT__MASK; +} +#define A5XX_GRAS_2D_DST_INFO_TILE_MODE__MASK 0x00000300 +#define A5XX_GRAS_2D_DST_INFO_TILE_MODE__SHIFT 8 +static inline uint32_t A5XX_GRAS_2D_DST_INFO_TILE_MODE(enum a5xx_tile_mode val) +{ + return ((val) << A5XX_GRAS_2D_DST_INFO_TILE_MODE__SHIFT) & A5XX_GRAS_2D_DST_INFO_TILE_MODE__MASK; +} +#define A5XX_GRAS_2D_DST_INFO_COLOR_SWAP__MASK 0x00000c00 +#define A5XX_GRAS_2D_DST_INFO_COLOR_SWAP__SHIFT 10 +static inline uint32_t A5XX_GRAS_2D_DST_INFO_COLOR_SWAP(enum a3xx_color_swap val) +{ + return ((val) << A5XX_GRAS_2D_DST_INFO_COLOR_SWAP__SHIFT) & A5XX_GRAS_2D_DST_INFO_COLOR_SWAP__MASK; +} +#define A5XX_GRAS_2D_DST_INFO_FLAGS 0x00001000 + +#define REG_A5XX_UNKNOWN_2100 0x00002100 + +#define REG_A5XX_UNKNOWN_2180 0x00002180 + +#define REG_A5XX_UNKNOWN_2184 0x00002184 + +#define REG_A5XX_TEX_SAMP_0 0x00000000 +#define A5XX_TEX_SAMP_0_MIPFILTER_LINEAR_NEAR 0x00000001 +#define A5XX_TEX_SAMP_0_XY_MAG__MASK 0x00000006 +#define A5XX_TEX_SAMP_0_XY_MAG__SHIFT 1 +static inline uint32_t A5XX_TEX_SAMP_0_XY_MAG(enum a5xx_tex_filter val) +{ + return ((val) << A5XX_TEX_SAMP_0_XY_MAG__SHIFT) & A5XX_TEX_SAMP_0_XY_MAG__MASK; +} +#define A5XX_TEX_SAMP_0_XY_MIN__MASK 0x00000018 +#define A5XX_TEX_SAMP_0_XY_MIN__SHIFT 3 +static inline uint32_t A5XX_TEX_SAMP_0_XY_MIN(enum a5xx_tex_filter val) +{ + return ((val) << A5XX_TEX_SAMP_0_XY_MIN__SHIFT) & A5XX_TEX_SAMP_0_XY_MIN__MASK; +} +#define A5XX_TEX_SAMP_0_WRAP_S__MASK 0x000000e0 +#define A5XX_TEX_SAMP_0_WRAP_S__SHIFT 5 +static inline uint32_t A5XX_TEX_SAMP_0_WRAP_S(enum a5xx_tex_clamp val) +{ + return ((val) << A5XX_TEX_SAMP_0_WRAP_S__SHIFT) & A5XX_TEX_SAMP_0_WRAP_S__MASK; +} +#define A5XX_TEX_SAMP_0_WRAP_T__MASK 0x00000700 +#define A5XX_TEX_SAMP_0_WRAP_T__SHIFT 8 +static inline uint32_t A5XX_TEX_SAMP_0_WRAP_T(enum a5xx_tex_clamp val) +{ + return ((val) << A5XX_TEX_SAMP_0_WRAP_T__SHIFT) & A5XX_TEX_SAMP_0_WRAP_T__MASK; +} +#define A5XX_TEX_SAMP_0_WRAP_R__MASK 0x00003800 +#define A5XX_TEX_SAMP_0_WRAP_R__SHIFT 11 +static inline uint32_t A5XX_TEX_SAMP_0_WRAP_R(enum a5xx_tex_clamp val) +{ + return ((val) << A5XX_TEX_SAMP_0_WRAP_R__SHIFT) & A5XX_TEX_SAMP_0_WRAP_R__MASK; +} +#define A5XX_TEX_SAMP_0_ANISO__MASK 0x0001c000 +#define A5XX_TEX_SAMP_0_ANISO__SHIFT 14 +static inline uint32_t A5XX_TEX_SAMP_0_ANISO(enum a5xx_tex_aniso val) +{ + return ((val) << A5XX_TEX_SAMP_0_ANISO__SHIFT) & A5XX_TEX_SAMP_0_ANISO__MASK; +} +#define A5XX_TEX_SAMP_0_LOD_BIAS__MASK 0xfff80000 +#define A5XX_TEX_SAMP_0_LOD_BIAS__SHIFT 19 +static inline uint32_t A5XX_TEX_SAMP_0_LOD_BIAS(float val) +{ + return ((((int32_t)(val * 256.0))) << A5XX_TEX_SAMP_0_LOD_BIAS__SHIFT) & A5XX_TEX_SAMP_0_LOD_BIAS__MASK; +} + +#define REG_A5XX_TEX_SAMP_1 0x00000001 +#define A5XX_TEX_SAMP_1_COMPARE_FUNC__MASK 0x0000000e +#define A5XX_TEX_SAMP_1_COMPARE_FUNC__SHIFT 1 +static inline uint32_t A5XX_TEX_SAMP_1_COMPARE_FUNC(enum adreno_compare_func val) +{ + return ((val) << A5XX_TEX_SAMP_1_COMPARE_FUNC__SHIFT) & A5XX_TEX_SAMP_1_COMPARE_FUNC__MASK; +} +#define A5XX_TEX_SAMP_1_CUBEMAPSEAMLESSFILTOFF 0x00000010 +#define A5XX_TEX_SAMP_1_UNNORM_COORDS 0x00000020 +#define A5XX_TEX_SAMP_1_MIPFILTER_LINEAR_FAR 0x00000040 +#define A5XX_TEX_SAMP_1_MAX_LOD__MASK 0x000fff00 +#define A5XX_TEX_SAMP_1_MAX_LOD__SHIFT 8 +static inline uint32_t A5XX_TEX_SAMP_1_MAX_LOD(float val) +{ + return ((((uint32_t)(val * 256.0))) << A5XX_TEX_SAMP_1_MAX_LOD__SHIFT) & A5XX_TEX_SAMP_1_MAX_LOD__MASK; +} +#define A5XX_TEX_SAMP_1_MIN_LOD__MASK 0xfff00000 +#define A5XX_TEX_SAMP_1_MIN_LOD__SHIFT 20 +static inline uint32_t A5XX_TEX_SAMP_1_MIN_LOD(float val) +{ + return ((((uint32_t)(val * 256.0))) << A5XX_TEX_SAMP_1_MIN_LOD__SHIFT) & A5XX_TEX_SAMP_1_MIN_LOD__MASK; +} + +#define REG_A5XX_TEX_SAMP_2 0x00000002 +#define A5XX_TEX_SAMP_2_BCOLOR_OFFSET__MASK 0xfffffff0 +#define A5XX_TEX_SAMP_2_BCOLOR_OFFSET__SHIFT 4 +static inline uint32_t A5XX_TEX_SAMP_2_BCOLOR_OFFSET(uint32_t val) +{ + return ((val) << A5XX_TEX_SAMP_2_BCOLOR_OFFSET__SHIFT) & A5XX_TEX_SAMP_2_BCOLOR_OFFSET__MASK; +} + +#define REG_A5XX_TEX_SAMP_3 0x00000003 + +#define REG_A5XX_TEX_CONST_0 0x00000000 +#define A5XX_TEX_CONST_0_TILE_MODE__MASK 0x00000003 +#define A5XX_TEX_CONST_0_TILE_MODE__SHIFT 0 +static inline uint32_t A5XX_TEX_CONST_0_TILE_MODE(enum a5xx_tile_mode val) +{ + return ((val) << A5XX_TEX_CONST_0_TILE_MODE__SHIFT) & A5XX_TEX_CONST_0_TILE_MODE__MASK; +} +#define A5XX_TEX_CONST_0_SRGB 0x00000004 +#define A5XX_TEX_CONST_0_SWIZ_X__MASK 0x00000070 +#define A5XX_TEX_CONST_0_SWIZ_X__SHIFT 4 +static inline uint32_t A5XX_TEX_CONST_0_SWIZ_X(enum a5xx_tex_swiz val) +{ + return ((val) << A5XX_TEX_CONST_0_SWIZ_X__SHIFT) & A5XX_TEX_CONST_0_SWIZ_X__MASK; +} +#define A5XX_TEX_CONST_0_SWIZ_Y__MASK 0x00000380 +#define A5XX_TEX_CONST_0_SWIZ_Y__SHIFT 7 +static inline uint32_t A5XX_TEX_CONST_0_SWIZ_Y(enum a5xx_tex_swiz val) +{ + return ((val) << A5XX_TEX_CONST_0_SWIZ_Y__SHIFT) & A5XX_TEX_CONST_0_SWIZ_Y__MASK; +} +#define A5XX_TEX_CONST_0_SWIZ_Z__MASK 0x00001c00 +#define A5XX_TEX_CONST_0_SWIZ_Z__SHIFT 10 +static inline uint32_t A5XX_TEX_CONST_0_SWIZ_Z(enum a5xx_tex_swiz val) +{ + return ((val) << A5XX_TEX_CONST_0_SWIZ_Z__SHIFT) & A5XX_TEX_CONST_0_SWIZ_Z__MASK; +} +#define A5XX_TEX_CONST_0_SWIZ_W__MASK 0x0000e000 +#define A5XX_TEX_CONST_0_SWIZ_W__SHIFT 13 +static inline uint32_t A5XX_TEX_CONST_0_SWIZ_W(enum a5xx_tex_swiz val) +{ + return ((val) << A5XX_TEX_CONST_0_SWIZ_W__SHIFT) & A5XX_TEX_CONST_0_SWIZ_W__MASK; +} +#define A5XX_TEX_CONST_0_MIPLVLS__MASK 0x000f0000 +#define A5XX_TEX_CONST_0_MIPLVLS__SHIFT 16 +static inline uint32_t A5XX_TEX_CONST_0_MIPLVLS(uint32_t val) +{ + return ((val) << A5XX_TEX_CONST_0_MIPLVLS__SHIFT) & A5XX_TEX_CONST_0_MIPLVLS__MASK; +} +#define A5XX_TEX_CONST_0_SAMPLES__MASK 0x00300000 +#define A5XX_TEX_CONST_0_SAMPLES__SHIFT 20 +static inline uint32_t A5XX_TEX_CONST_0_SAMPLES(enum a3xx_msaa_samples val) +{ + return ((val) << A5XX_TEX_CONST_0_SAMPLES__SHIFT) & A5XX_TEX_CONST_0_SAMPLES__MASK; +} +#define A5XX_TEX_CONST_0_FMT__MASK 0x3fc00000 +#define A5XX_TEX_CONST_0_FMT__SHIFT 22 +static inline uint32_t A5XX_TEX_CONST_0_FMT(enum a5xx_tex_fmt val) +{ + return ((val) << A5XX_TEX_CONST_0_FMT__SHIFT) & A5XX_TEX_CONST_0_FMT__MASK; +} +#define A5XX_TEX_CONST_0_SWAP__MASK 0xc0000000 +#define A5XX_TEX_CONST_0_SWAP__SHIFT 30 +static inline uint32_t A5XX_TEX_CONST_0_SWAP(enum a3xx_color_swap val) +{ + return ((val) << A5XX_TEX_CONST_0_SWAP__SHIFT) & A5XX_TEX_CONST_0_SWAP__MASK; +} + +#define REG_A5XX_TEX_CONST_1 0x00000001 +#define A5XX_TEX_CONST_1_WIDTH__MASK 0x00007fff +#define A5XX_TEX_CONST_1_WIDTH__SHIFT 0 +static inline uint32_t A5XX_TEX_CONST_1_WIDTH(uint32_t val) +{ + return ((val) << A5XX_TEX_CONST_1_WIDTH__SHIFT) & A5XX_TEX_CONST_1_WIDTH__MASK; +} +#define A5XX_TEX_CONST_1_HEIGHT__MASK 0x3fff8000 +#define A5XX_TEX_CONST_1_HEIGHT__SHIFT 15 +static inline uint32_t A5XX_TEX_CONST_1_HEIGHT(uint32_t val) +{ + return ((val) << A5XX_TEX_CONST_1_HEIGHT__SHIFT) & A5XX_TEX_CONST_1_HEIGHT__MASK; +} + +#define REG_A5XX_TEX_CONST_2 0x00000002 +#define A5XX_TEX_CONST_2_FETCHSIZE__MASK 0x0000000f +#define A5XX_TEX_CONST_2_FETCHSIZE__SHIFT 0 +static inline uint32_t A5XX_TEX_CONST_2_FETCHSIZE(enum a5xx_tex_fetchsize val) +{ + return ((val) << A5XX_TEX_CONST_2_FETCHSIZE__SHIFT) & A5XX_TEX_CONST_2_FETCHSIZE__MASK; +} +#define A5XX_TEX_CONST_2_PITCH__MASK 0x1fffff80 +#define A5XX_TEX_CONST_2_PITCH__SHIFT 7 +static inline uint32_t A5XX_TEX_CONST_2_PITCH(uint32_t val) +{ + return ((val) << A5XX_TEX_CONST_2_PITCH__SHIFT) & A5XX_TEX_CONST_2_PITCH__MASK; +} +#define A5XX_TEX_CONST_2_TYPE__MASK 0x60000000 +#define A5XX_TEX_CONST_2_TYPE__SHIFT 29 +static inline uint32_t A5XX_TEX_CONST_2_TYPE(enum a5xx_tex_type val) +{ + return ((val) << A5XX_TEX_CONST_2_TYPE__SHIFT) & A5XX_TEX_CONST_2_TYPE__MASK; +} + +#define REG_A5XX_TEX_CONST_3 0x00000003 +#define A5XX_TEX_CONST_3_ARRAY_PITCH__MASK 0x00003fff +#define A5XX_TEX_CONST_3_ARRAY_PITCH__SHIFT 0 +static inline uint32_t A5XX_TEX_CONST_3_ARRAY_PITCH(uint32_t val) +{ + return ((val >> 12) << A5XX_TEX_CONST_3_ARRAY_PITCH__SHIFT) & A5XX_TEX_CONST_3_ARRAY_PITCH__MASK; +} +#define A5XX_TEX_CONST_3_FLAG 0x10000000 + +#define REG_A5XX_TEX_CONST_4 0x00000004 +#define A5XX_TEX_CONST_4_BASE_LO__MASK 0xffffffe0 +#define A5XX_TEX_CONST_4_BASE_LO__SHIFT 5 +static inline uint32_t A5XX_TEX_CONST_4_BASE_LO(uint32_t val) +{ + return ((val >> 5) << A5XX_TEX_CONST_4_BASE_LO__SHIFT) & A5XX_TEX_CONST_4_BASE_LO__MASK; +} + +#define REG_A5XX_TEX_CONST_5 0x00000005 +#define A5XX_TEX_CONST_5_BASE_HI__MASK 0x0001ffff +#define A5XX_TEX_CONST_5_BASE_HI__SHIFT 0 +static inline uint32_t A5XX_TEX_CONST_5_BASE_HI(uint32_t val) +{ + return ((val) << A5XX_TEX_CONST_5_BASE_HI__SHIFT) & A5XX_TEX_CONST_5_BASE_HI__MASK; +} +#define A5XX_TEX_CONST_5_DEPTH__MASK 0x3ffe0000 +#define A5XX_TEX_CONST_5_DEPTH__SHIFT 17 +static inline uint32_t A5XX_TEX_CONST_5_DEPTH(uint32_t val) +{ + return ((val) << A5XX_TEX_CONST_5_DEPTH__SHIFT) & A5XX_TEX_CONST_5_DEPTH__MASK; +} + +#define REG_A5XX_TEX_CONST_6 0x00000006 + +#define REG_A5XX_TEX_CONST_7 0x00000007 + +#define REG_A5XX_TEX_CONST_8 0x00000008 + +#define REG_A5XX_TEX_CONST_9 0x00000009 + +#define REG_A5XX_TEX_CONST_10 0x0000000a + +#define REG_A5XX_TEX_CONST_11 0x0000000b + +#define REG_A5XX_SSBO_0_0 0x00000000 +#define A5XX_SSBO_0_0_BASE_LO__MASK 0xffffffe0 +#define A5XX_SSBO_0_0_BASE_LO__SHIFT 5 +static inline uint32_t A5XX_SSBO_0_0_BASE_LO(uint32_t val) +{ + return ((val >> 5) << A5XX_SSBO_0_0_BASE_LO__SHIFT) & A5XX_SSBO_0_0_BASE_LO__MASK; +} + +#define REG_A5XX_SSBO_0_1 0x00000001 +#define A5XX_SSBO_0_1_PITCH__MASK 0x003fffff +#define A5XX_SSBO_0_1_PITCH__SHIFT 0 +static inline uint32_t A5XX_SSBO_0_1_PITCH(uint32_t val) +{ + return ((val) << A5XX_SSBO_0_1_PITCH__SHIFT) & A5XX_SSBO_0_1_PITCH__MASK; +} + +#define REG_A5XX_SSBO_0_2 0x00000002 +#define A5XX_SSBO_0_2_ARRAY_PITCH__MASK 0x03fff000 +#define A5XX_SSBO_0_2_ARRAY_PITCH__SHIFT 12 +static inline uint32_t A5XX_SSBO_0_2_ARRAY_PITCH(uint32_t val) +{ + return ((val >> 12) << A5XX_SSBO_0_2_ARRAY_PITCH__SHIFT) & A5XX_SSBO_0_2_ARRAY_PITCH__MASK; +} + +#define REG_A5XX_SSBO_0_3 0x00000003 +#define A5XX_SSBO_0_3_CPP__MASK 0x0000003f +#define A5XX_SSBO_0_3_CPP__SHIFT 0 +static inline uint32_t A5XX_SSBO_0_3_CPP(uint32_t val) +{ + return ((val) << A5XX_SSBO_0_3_CPP__SHIFT) & A5XX_SSBO_0_3_CPP__MASK; +} + +#define REG_A5XX_SSBO_1_0 0x00000000 +#define A5XX_SSBO_1_0_FMT__MASK 0x0000ff00 +#define A5XX_SSBO_1_0_FMT__SHIFT 8 +static inline uint32_t A5XX_SSBO_1_0_FMT(enum a5xx_tex_fmt val) +{ + return ((val) << A5XX_SSBO_1_0_FMT__SHIFT) & A5XX_SSBO_1_0_FMT__MASK; +} +#define A5XX_SSBO_1_0_WIDTH__MASK 0xffff0000 +#define A5XX_SSBO_1_0_WIDTH__SHIFT 16 +static inline uint32_t A5XX_SSBO_1_0_WIDTH(uint32_t val) +{ + return ((val) << A5XX_SSBO_1_0_WIDTH__SHIFT) & A5XX_SSBO_1_0_WIDTH__MASK; +} + +#define REG_A5XX_SSBO_1_1 0x00000001 +#define A5XX_SSBO_1_1_HEIGHT__MASK 0x0000ffff +#define A5XX_SSBO_1_1_HEIGHT__SHIFT 0 +static inline uint32_t A5XX_SSBO_1_1_HEIGHT(uint32_t val) +{ + return ((val) << A5XX_SSBO_1_1_HEIGHT__SHIFT) & A5XX_SSBO_1_1_HEIGHT__MASK; +} +#define A5XX_SSBO_1_1_DEPTH__MASK 0xffff0000 +#define A5XX_SSBO_1_1_DEPTH__SHIFT 16 +static inline uint32_t A5XX_SSBO_1_1_DEPTH(uint32_t val) +{ + return ((val) << A5XX_SSBO_1_1_DEPTH__SHIFT) & A5XX_SSBO_1_1_DEPTH__MASK; +} + +#define REG_A5XX_SSBO_2_0 0x00000000 +#define A5XX_SSBO_2_0_BASE_LO__MASK 0xffffffff +#define A5XX_SSBO_2_0_BASE_LO__SHIFT 0 +static inline uint32_t A5XX_SSBO_2_0_BASE_LO(uint32_t val) +{ + return ((val) << A5XX_SSBO_2_0_BASE_LO__SHIFT) & A5XX_SSBO_2_0_BASE_LO__MASK; +} + +#define REG_A5XX_SSBO_2_1 0x00000001 +#define A5XX_SSBO_2_1_BASE_HI__MASK 0xffffffff +#define A5XX_SSBO_2_1_BASE_HI__SHIFT 0 +static inline uint32_t A5XX_SSBO_2_1_BASE_HI(uint32_t val) +{ + return ((val) << A5XX_SSBO_2_1_BASE_HI__SHIFT) & A5XX_SSBO_2_1_BASE_HI__MASK; +} + + +#endif /* A5XX_XML */ diff --git a/selfdrive/modeld/thneed/debug/include/adreno_pm4.xml.h b/selfdrive/modeld/thneed/debug/include/adreno_pm4.xml.h new file mode 100644 index 0000000000..08f8ff2682 --- /dev/null +++ b/selfdrive/modeld/thneed/debug/include/adreno_pm4.xml.h @@ -0,0 +1,1344 @@ +#ifndef ADRENO_PM4_XML +#define ADRENO_PM4_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://github.com/freedreno/envytools/ +git clone https://github.com/freedreno/envytools.git + +The rules-ng-ng source files this header was generated from are: +- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 501 bytes, from 2018-01-31 18:26:32) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1572 bytes, from 2018-01-08 14:56:24) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 36805 bytes, from 2018-05-20 19:03:35) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 13634 bytes, from 2018-06-10 17:35:36) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 41584 bytes, from 2018-06-18 14:25:44) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 83840 bytes, from 2018-01-10 16:21:40) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 112086 bytes, from 2018-01-08 14:56:24) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a5xx.xml ( 147158 bytes, from 2018-06-18 14:25:44) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a6xx.xml ( 88437 bytes, from 2018-06-18 14:25:44) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a6xx_gmu.xml ( 10431 bytes, from 2018-06-10 17:37:04) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/ocmem.xml ( 1773 bytes, from 2018-01-08 14:56:24) + +Copyright (C) 2013-2018 by the following authors: +- Rob Clark (robclark) +- Ilia Mirkin (imirkin) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + + +enum vgt_event_type { + VS_DEALLOC = 0, + PS_DEALLOC = 1, + VS_DONE_TS = 2, + PS_DONE_TS = 3, + CACHE_FLUSH_TS = 4, + CONTEXT_DONE = 5, + CACHE_FLUSH = 6, + HLSQ_FLUSH = 7, + VIZQUERY_START = 7, + VIZQUERY_END = 8, + SC_WAIT_WC = 9, + RST_PIX_CNT = 13, + RST_VTX_CNT = 14, + TILE_FLUSH = 15, + STAT_EVENT = 16, + CACHE_FLUSH_AND_INV_TS_EVENT = 20, + ZPASS_DONE = 21, + CACHE_FLUSH_AND_INV_EVENT = 22, + PERFCOUNTER_START = 23, + PERFCOUNTER_STOP = 24, + VS_FETCH_DONE = 27, + FACENESS_FLUSH = 28, + FLUSH_SO_0 = 17, + FLUSH_SO_1 = 18, + FLUSH_SO_2 = 19, + FLUSH_SO_3 = 20, + PC_CCU_INVALIDATE_DEPTH = 24, + PC_CCU_INVALIDATE_COLOR = 25, + UNK_1C = 28, + UNK_1D = 29, + BLIT = 30, + UNK_25 = 37, + LRZ_FLUSH = 38, + UNK_2C = 44, + UNK_2D = 45, +}; + +enum pc_di_primtype { + DI_PT_NONE = 0, + DI_PT_POINTLIST_PSIZE = 1, + DI_PT_LINELIST = 2, + DI_PT_LINESTRIP = 3, + DI_PT_TRILIST = 4, + DI_PT_TRIFAN = 5, + DI_PT_TRISTRIP = 6, + DI_PT_LINELOOP = 7, + DI_PT_RECTLIST = 8, + DI_PT_POINTLIST = 9, + DI_PT_LINE_ADJ = 10, + DI_PT_LINESTRIP_ADJ = 11, + DI_PT_TRI_ADJ = 12, + DI_PT_TRISTRIP_ADJ = 13, +}; + +enum pc_di_src_sel { + DI_SRC_SEL_DMA = 0, + DI_SRC_SEL_IMMEDIATE = 1, + DI_SRC_SEL_AUTO_INDEX = 2, + DI_SRC_SEL_RESERVED = 3, +}; + +enum pc_di_index_size { + INDEX_SIZE_IGN = 0, + INDEX_SIZE_16_BIT = 0, + INDEX_SIZE_32_BIT = 1, + INDEX_SIZE_8_BIT = 2, + INDEX_SIZE_INVALID = 0, +}; + +enum pc_di_vis_cull_mode { + IGNORE_VISIBILITY = 0, + USE_VISIBILITY = 1, +}; + +enum adreno_pm4_packet_type { + CP_TYPE0_PKT = 0, + CP_TYPE1_PKT = 0x40000000, + CP_TYPE2_PKT = 0x80000000, + CP_TYPE3_PKT = 0xc0000000, + CP_TYPE4_PKT = 0x40000000, + CP_TYPE7_PKT = 0x70000000, +}; + +enum adreno_pm4_type3_packets { + CP_ME_INIT = 72, + CP_NOP = 16, + CP_PREEMPT_ENABLE = 28, + CP_PREEMPT_TOKEN = 30, + CP_INDIRECT_BUFFER = 63, + CP_INDIRECT_BUFFER_PFD = 55, + CP_WAIT_FOR_IDLE = 38, + CP_WAIT_REG_MEM = 60, + CP_WAIT_REG_EQ = 82, + CP_WAIT_REG_GTE = 83, + CP_WAIT_UNTIL_READ = 92, + CP_WAIT_IB_PFD_COMPLETE = 93, + CP_REG_RMW = 33, + CP_SET_BIN_DATA = 47, + CP_SET_BIN_DATA5 = 47, + CP_REG_TO_MEM = 62, + CP_MEM_WRITE = 61, + CP_MEM_WRITE_CNTR = 79, + CP_COND_EXEC = 68, + CP_COND_WRITE = 69, + CP_COND_WRITE5 = 69, + CP_EVENT_WRITE = 70, + CP_EVENT_WRITE_SHD = 88, + CP_EVENT_WRITE_CFL = 89, + CP_EVENT_WRITE_ZPD = 91, + CP_RUN_OPENCL = 49, + CP_DRAW_INDX = 34, + CP_DRAW_INDX_2 = 54, + CP_DRAW_INDX_BIN = 52, + CP_DRAW_INDX_2_BIN = 53, + CP_VIZ_QUERY = 35, + CP_SET_STATE = 37, + CP_SET_CONSTANT = 45, + CP_IM_LOAD = 39, + CP_IM_LOAD_IMMEDIATE = 43, + CP_LOAD_CONSTANT_CONTEXT = 46, + CP_INVALIDATE_STATE = 59, + CP_SET_SHADER_BASES = 74, + CP_SET_BIN_MASK = 80, + CP_SET_BIN_SELECT = 81, + CP_CONTEXT_UPDATE = 94, + CP_INTERRUPT = 64, + CP_IM_STORE = 44, + CP_SET_DRAW_INIT_FLAGS = 75, + CP_SET_PROTECTED_MODE = 95, + CP_BOOTSTRAP_UCODE = 111, + CP_LOAD_STATE = 48, + CP_LOAD_STATE4 = 48, + CP_COND_INDIRECT_BUFFER_PFE = 58, + CP_COND_INDIRECT_BUFFER_PFD = 50, + CP_INDIRECT_BUFFER_PFE = 63, + CP_SET_BIN = 76, + CP_TEST_TWO_MEMS = 113, + CP_REG_WR_NO_CTXT = 120, + CP_RECORD_PFP_TIMESTAMP = 17, + CP_SET_SECURE_MODE = 102, + CP_WAIT_FOR_ME = 19, + CP_SET_DRAW_STATE = 67, + CP_DRAW_INDX_OFFSET = 56, + CP_DRAW_INDIRECT = 40, + CP_DRAW_INDX_INDIRECT = 41, + CP_DRAW_AUTO = 36, + CP_UNKNOWN_19 = 25, + CP_UNKNOWN_1A = 26, + CP_UNKNOWN_4E = 78, + CP_WIDE_REG_WRITE = 116, + CP_SCRATCH_TO_REG = 77, + CP_REG_TO_SCRATCH = 74, + CP_WAIT_MEM_WRITES = 18, + CP_COND_REG_EXEC = 71, + CP_MEM_TO_REG = 66, + CP_EXEC_CS_INDIRECT = 65, + CP_EXEC_CS = 51, + CP_PERFCOUNTER_ACTION = 80, + CP_SMMU_TABLE_UPDATE = 83, + CP_SET_MARKER = 101, + CP_SET_PSEUDO_REG = 86, + CP_CONTEXT_REG_BUNCH = 92, + CP_YIELD_ENABLE = 28, + CP_SKIP_IB2_ENABLE_GLOBAL = 29, + CP_SKIP_IB2_ENABLE_LOCAL = 35, + CP_SET_SUBDRAW_SIZE = 53, + CP_SET_VISIBILITY_OVERRIDE = 100, + CP_PREEMPT_ENABLE_GLOBAL = 105, + CP_PREEMPT_ENABLE_LOCAL = 106, + CP_CONTEXT_SWITCH_YIELD = 107, + CP_SET_RENDER_MODE = 108, + CP_COMPUTE_CHECKPOINT = 110, + CP_MEM_TO_MEM = 115, + CP_BLIT = 44, + CP_REG_TEST = 57, + IN_IB_PREFETCH_END = 23, + IN_SUBBLK_PREFETCH = 31, + IN_INSTR_PREFETCH = 32, + IN_INSTR_MATCH = 71, + IN_CONST_PREFETCH = 73, + IN_INCR_UPDT_STATE = 85, + IN_INCR_UPDT_CONST = 86, + IN_INCR_UPDT_INSTR = 87, + PKT4 = 4, +}; + +enum adreno_state_block { + SB_VERT_TEX = 0, + SB_VERT_MIPADDR = 1, + SB_FRAG_TEX = 2, + SB_FRAG_MIPADDR = 3, + SB_VERT_SHADER = 4, + SB_GEOM_SHADER = 5, + SB_FRAG_SHADER = 6, + SB_COMPUTE_SHADER = 7, +}; + +enum adreno_state_type { + ST_SHADER = 0, + ST_CONSTANTS = 1, +}; + +enum adreno_state_src { + SS_DIRECT = 0, + SS_INVALID_ALL_IC = 2, + SS_INVALID_PART_IC = 3, + SS_INDIRECT = 4, + SS_INDIRECT_TCM = 5, + SS_INDIRECT_STM = 6, +}; + +enum a4xx_state_block { + SB4_VS_TEX = 0, + SB4_HS_TEX = 1, + SB4_DS_TEX = 2, + SB4_GS_TEX = 3, + SB4_FS_TEX = 4, + SB4_CS_TEX = 5, + SB4_VS_SHADER = 8, + SB4_HS_SHADER = 9, + SB4_DS_SHADER = 10, + SB4_GS_SHADER = 11, + SB4_FS_SHADER = 12, + SB4_CS_SHADER = 13, + SB4_SSBO = 14, + SB4_CS_SSBO = 15, +}; + +enum a4xx_state_type { + ST4_SHADER = 0, + ST4_CONSTANTS = 1, +}; + +enum a4xx_state_src { + SS4_DIRECT = 0, + SS4_INDIRECT = 2, +}; + +enum a4xx_index_size { + INDEX4_SIZE_8_BIT = 0, + INDEX4_SIZE_16_BIT = 1, + INDEX4_SIZE_32_BIT = 2, +}; + +enum cp_cond_function { + WRITE_ALWAYS = 0, + WRITE_LT = 1, + WRITE_LE = 2, + WRITE_EQ = 3, + WRITE_NE = 4, + WRITE_GE = 5, + WRITE_GT = 6, +}; + +enum render_mode_cmd { + BYPASS = 1, + BINNING = 2, + GMEM = 3, + BLIT2D = 5, + BLIT2DSCALE = 7, + END2D = 8, +}; + +enum cp_blit_cmd { + BLIT_OP_FILL = 0, + BLIT_OP_COPY = 1, + BLIT_OP_SCALE = 3, +}; + +#define REG_CP_LOAD_STATE_0 0x00000000 +#define CP_LOAD_STATE_0_DST_OFF__MASK 0x0000ffff +#define CP_LOAD_STATE_0_DST_OFF__SHIFT 0 +static inline uint32_t CP_LOAD_STATE_0_DST_OFF(uint32_t val) +{ + return ((val) << CP_LOAD_STATE_0_DST_OFF__SHIFT) & CP_LOAD_STATE_0_DST_OFF__MASK; +} +#define CP_LOAD_STATE_0_STATE_SRC__MASK 0x00070000 +#define CP_LOAD_STATE_0_STATE_SRC__SHIFT 16 +static inline uint32_t CP_LOAD_STATE_0_STATE_SRC(enum adreno_state_src val) +{ + return ((val) << CP_LOAD_STATE_0_STATE_SRC__SHIFT) & CP_LOAD_STATE_0_STATE_SRC__MASK; +} +#define CP_LOAD_STATE_0_STATE_BLOCK__MASK 0x00380000 +#define CP_LOAD_STATE_0_STATE_BLOCK__SHIFT 19 +static inline uint32_t CP_LOAD_STATE_0_STATE_BLOCK(enum adreno_state_block val) +{ + return ((val) << CP_LOAD_STATE_0_STATE_BLOCK__SHIFT) & CP_LOAD_STATE_0_STATE_BLOCK__MASK; +} +#define CP_LOAD_STATE_0_NUM_UNIT__MASK 0xffc00000 +#define CP_LOAD_STATE_0_NUM_UNIT__SHIFT 22 +static inline uint32_t CP_LOAD_STATE_0_NUM_UNIT(uint32_t val) +{ + return ((val) << CP_LOAD_STATE_0_NUM_UNIT__SHIFT) & CP_LOAD_STATE_0_NUM_UNIT__MASK; +} + +#define REG_CP_LOAD_STATE_1 0x00000001 +#define CP_LOAD_STATE_1_STATE_TYPE__MASK 0x00000003 +#define CP_LOAD_STATE_1_STATE_TYPE__SHIFT 0 +static inline uint32_t CP_LOAD_STATE_1_STATE_TYPE(enum adreno_state_type val) +{ + return ((val) << CP_LOAD_STATE_1_STATE_TYPE__SHIFT) & CP_LOAD_STATE_1_STATE_TYPE__MASK; +} +#define CP_LOAD_STATE_1_EXT_SRC_ADDR__MASK 0xfffffffc +#define CP_LOAD_STATE_1_EXT_SRC_ADDR__SHIFT 2 +static inline uint32_t CP_LOAD_STATE_1_EXT_SRC_ADDR(uint32_t val) +{ + assert(!(val & 0x3)); + return ((val >> 2) << CP_LOAD_STATE_1_EXT_SRC_ADDR__SHIFT) & CP_LOAD_STATE_1_EXT_SRC_ADDR__MASK; +} + +#define REG_CP_LOAD_STATE4_0 0x00000000 +#define CP_LOAD_STATE4_0_DST_OFF__MASK 0x00003fff +#define CP_LOAD_STATE4_0_DST_OFF__SHIFT 0 +static inline uint32_t CP_LOAD_STATE4_0_DST_OFF(uint32_t val) +{ + return ((val) << CP_LOAD_STATE4_0_DST_OFF__SHIFT) & CP_LOAD_STATE4_0_DST_OFF__MASK; +} +#define CP_LOAD_STATE4_0_STATE_SRC__MASK 0x00030000 +#define CP_LOAD_STATE4_0_STATE_SRC__SHIFT 16 +static inline uint32_t CP_LOAD_STATE4_0_STATE_SRC(enum a4xx_state_src val) +{ + return ((val) << CP_LOAD_STATE4_0_STATE_SRC__SHIFT) & CP_LOAD_STATE4_0_STATE_SRC__MASK; +} +#define CP_LOAD_STATE4_0_STATE_BLOCK__MASK 0x003c0000 +#define CP_LOAD_STATE4_0_STATE_BLOCK__SHIFT 18 +static inline uint32_t CP_LOAD_STATE4_0_STATE_BLOCK(enum a4xx_state_block val) +{ + return ((val) << CP_LOAD_STATE4_0_STATE_BLOCK__SHIFT) & CP_LOAD_STATE4_0_STATE_BLOCK__MASK; +} +#define CP_LOAD_STATE4_0_NUM_UNIT__MASK 0xffc00000 +#define CP_LOAD_STATE4_0_NUM_UNIT__SHIFT 22 +static inline uint32_t CP_LOAD_STATE4_0_NUM_UNIT(uint32_t val) +{ + return ((val) << CP_LOAD_STATE4_0_NUM_UNIT__SHIFT) & CP_LOAD_STATE4_0_NUM_UNIT__MASK; +} + +#define REG_CP_LOAD_STATE4_1 0x00000001 +#define CP_LOAD_STATE4_1_STATE_TYPE__MASK 0x00000003 +#define CP_LOAD_STATE4_1_STATE_TYPE__SHIFT 0 +static inline uint32_t CP_LOAD_STATE4_1_STATE_TYPE(enum a4xx_state_type val) +{ + return ((val) << CP_LOAD_STATE4_1_STATE_TYPE__SHIFT) & CP_LOAD_STATE4_1_STATE_TYPE__MASK; +} +#define CP_LOAD_STATE4_1_EXT_SRC_ADDR__MASK 0xfffffffc +#define CP_LOAD_STATE4_1_EXT_SRC_ADDR__SHIFT 2 +static inline uint32_t CP_LOAD_STATE4_1_EXT_SRC_ADDR(uint32_t val) +{ + assert(!(val & 0x3)); + return ((val >> 2) << CP_LOAD_STATE4_1_EXT_SRC_ADDR__SHIFT) & CP_LOAD_STATE4_1_EXT_SRC_ADDR__MASK; +} + +#define REG_CP_LOAD_STATE4_2 0x00000002 +#define CP_LOAD_STATE4_2_EXT_SRC_ADDR_HI__MASK 0xffffffff +#define CP_LOAD_STATE4_2_EXT_SRC_ADDR_HI__SHIFT 0 +static inline uint32_t CP_LOAD_STATE4_2_EXT_SRC_ADDR_HI(uint32_t val) +{ + return ((val) << CP_LOAD_STATE4_2_EXT_SRC_ADDR_HI__SHIFT) & CP_LOAD_STATE4_2_EXT_SRC_ADDR_HI__MASK; +} + +#define REG_CP_DRAW_INDX_0 0x00000000 +#define CP_DRAW_INDX_0_VIZ_QUERY__MASK 0xffffffff +#define CP_DRAW_INDX_0_VIZ_QUERY__SHIFT 0 +static inline uint32_t CP_DRAW_INDX_0_VIZ_QUERY(uint32_t val) +{ + return ((val) << CP_DRAW_INDX_0_VIZ_QUERY__SHIFT) & CP_DRAW_INDX_0_VIZ_QUERY__MASK; +} + +#define REG_CP_DRAW_INDX_1 0x00000001 +#define CP_DRAW_INDX_1_PRIM_TYPE__MASK 0x0000003f +#define CP_DRAW_INDX_1_PRIM_TYPE__SHIFT 0 +static inline uint32_t CP_DRAW_INDX_1_PRIM_TYPE(enum pc_di_primtype val) +{ + return ((val) << CP_DRAW_INDX_1_PRIM_TYPE__SHIFT) & CP_DRAW_INDX_1_PRIM_TYPE__MASK; +} +#define CP_DRAW_INDX_1_SOURCE_SELECT__MASK 0x000000c0 +#define CP_DRAW_INDX_1_SOURCE_SELECT__SHIFT 6 +static inline uint32_t CP_DRAW_INDX_1_SOURCE_SELECT(enum pc_di_src_sel val) +{ + return ((val) << CP_DRAW_INDX_1_SOURCE_SELECT__SHIFT) & CP_DRAW_INDX_1_SOURCE_SELECT__MASK; +} +#define CP_DRAW_INDX_1_VIS_CULL__MASK 0x00000600 +#define CP_DRAW_INDX_1_VIS_CULL__SHIFT 9 +static inline uint32_t CP_DRAW_INDX_1_VIS_CULL(enum pc_di_vis_cull_mode val) +{ + return ((val) << CP_DRAW_INDX_1_VIS_CULL__SHIFT) & CP_DRAW_INDX_1_VIS_CULL__MASK; +} +#define CP_DRAW_INDX_1_INDEX_SIZE__MASK 0x00000800 +#define CP_DRAW_INDX_1_INDEX_SIZE__SHIFT 11 +static inline uint32_t CP_DRAW_INDX_1_INDEX_SIZE(enum pc_di_index_size val) +{ + return ((val) << CP_DRAW_INDX_1_INDEX_SIZE__SHIFT) & CP_DRAW_INDX_1_INDEX_SIZE__MASK; +} +#define CP_DRAW_INDX_1_NOT_EOP 0x00001000 +#define CP_DRAW_INDX_1_SMALL_INDEX 0x00002000 +#define CP_DRAW_INDX_1_PRE_DRAW_INITIATOR_ENABLE 0x00004000 +#define CP_DRAW_INDX_1_NUM_INSTANCES__MASK 0xff000000 +#define CP_DRAW_INDX_1_NUM_INSTANCES__SHIFT 24 +static inline uint32_t CP_DRAW_INDX_1_NUM_INSTANCES(uint32_t val) +{ + return ((val) << CP_DRAW_INDX_1_NUM_INSTANCES__SHIFT) & CP_DRAW_INDX_1_NUM_INSTANCES__MASK; +} + +#define REG_CP_DRAW_INDX_2 0x00000002 +#define CP_DRAW_INDX_2_NUM_INDICES__MASK 0xffffffff +#define CP_DRAW_INDX_2_NUM_INDICES__SHIFT 0 +static inline uint32_t CP_DRAW_INDX_2_NUM_INDICES(uint32_t val) +{ + return ((val) << CP_DRAW_INDX_2_NUM_INDICES__SHIFT) & CP_DRAW_INDX_2_NUM_INDICES__MASK; +} + +#define REG_CP_DRAW_INDX_3 0x00000003 +#define CP_DRAW_INDX_3_INDX_BASE__MASK 0xffffffff +#define CP_DRAW_INDX_3_INDX_BASE__SHIFT 0 +static inline uint32_t CP_DRAW_INDX_3_INDX_BASE(uint32_t val) +{ + return ((val) << CP_DRAW_INDX_3_INDX_BASE__SHIFT) & CP_DRAW_INDX_3_INDX_BASE__MASK; +} + +#define REG_CP_DRAW_INDX_4 0x00000004 +#define CP_DRAW_INDX_4_INDX_SIZE__MASK 0xffffffff +#define CP_DRAW_INDX_4_INDX_SIZE__SHIFT 0 +static inline uint32_t CP_DRAW_INDX_4_INDX_SIZE(uint32_t val) +{ + return ((val) << CP_DRAW_INDX_4_INDX_SIZE__SHIFT) & CP_DRAW_INDX_4_INDX_SIZE__MASK; +} + +#define REG_CP_DRAW_INDX_2_0 0x00000000 +#define CP_DRAW_INDX_2_0_VIZ_QUERY__MASK 0xffffffff +#define CP_DRAW_INDX_2_0_VIZ_QUERY__SHIFT 0 +static inline uint32_t CP_DRAW_INDX_2_0_VIZ_QUERY(uint32_t val) +{ + return ((val) << CP_DRAW_INDX_2_0_VIZ_QUERY__SHIFT) & CP_DRAW_INDX_2_0_VIZ_QUERY__MASK; +} + +#define REG_CP_DRAW_INDX_2_1 0x00000001 +#define CP_DRAW_INDX_2_1_PRIM_TYPE__MASK 0x0000003f +#define CP_DRAW_INDX_2_1_PRIM_TYPE__SHIFT 0 +static inline uint32_t CP_DRAW_INDX_2_1_PRIM_TYPE(enum pc_di_primtype val) +{ + return ((val) << CP_DRAW_INDX_2_1_PRIM_TYPE__SHIFT) & CP_DRAW_INDX_2_1_PRIM_TYPE__MASK; +} +#define CP_DRAW_INDX_2_1_SOURCE_SELECT__MASK 0x000000c0 +#define CP_DRAW_INDX_2_1_SOURCE_SELECT__SHIFT 6 +static inline uint32_t CP_DRAW_INDX_2_1_SOURCE_SELECT(enum pc_di_src_sel val) +{ + return ((val) << CP_DRAW_INDX_2_1_SOURCE_SELECT__SHIFT) & CP_DRAW_INDX_2_1_SOURCE_SELECT__MASK; +} +#define CP_DRAW_INDX_2_1_VIS_CULL__MASK 0x00000600 +#define CP_DRAW_INDX_2_1_VIS_CULL__SHIFT 9 +static inline uint32_t CP_DRAW_INDX_2_1_VIS_CULL(enum pc_di_vis_cull_mode val) +{ + return ((val) << CP_DRAW_INDX_2_1_VIS_CULL__SHIFT) & CP_DRAW_INDX_2_1_VIS_CULL__MASK; +} +#define CP_DRAW_INDX_2_1_INDEX_SIZE__MASK 0x00000800 +#define CP_DRAW_INDX_2_1_INDEX_SIZE__SHIFT 11 +static inline uint32_t CP_DRAW_INDX_2_1_INDEX_SIZE(enum pc_di_index_size val) +{ + return ((val) << CP_DRAW_INDX_2_1_INDEX_SIZE__SHIFT) & CP_DRAW_INDX_2_1_INDEX_SIZE__MASK; +} +#define CP_DRAW_INDX_2_1_NOT_EOP 0x00001000 +#define CP_DRAW_INDX_2_1_SMALL_INDEX 0x00002000 +#define CP_DRAW_INDX_2_1_PRE_DRAW_INITIATOR_ENABLE 0x00004000 +#define CP_DRAW_INDX_2_1_NUM_INSTANCES__MASK 0xff000000 +#define CP_DRAW_INDX_2_1_NUM_INSTANCES__SHIFT 24 +static inline uint32_t CP_DRAW_INDX_2_1_NUM_INSTANCES(uint32_t val) +{ + return ((val) << CP_DRAW_INDX_2_1_NUM_INSTANCES__SHIFT) & CP_DRAW_INDX_2_1_NUM_INSTANCES__MASK; +} + +#define REG_CP_DRAW_INDX_2_2 0x00000002 +#define CP_DRAW_INDX_2_2_NUM_INDICES__MASK 0xffffffff +#define CP_DRAW_INDX_2_2_NUM_INDICES__SHIFT 0 +static inline uint32_t CP_DRAW_INDX_2_2_NUM_INDICES(uint32_t val) +{ + return ((val) << CP_DRAW_INDX_2_2_NUM_INDICES__SHIFT) & CP_DRAW_INDX_2_2_NUM_INDICES__MASK; +} + +#define REG_CP_DRAW_INDX_OFFSET_0 0x00000000 +#define CP_DRAW_INDX_OFFSET_0_PRIM_TYPE__MASK 0x0000003f +#define CP_DRAW_INDX_OFFSET_0_PRIM_TYPE__SHIFT 0 +static inline uint32_t CP_DRAW_INDX_OFFSET_0_PRIM_TYPE(enum pc_di_primtype val) +{ + return ((val) << CP_DRAW_INDX_OFFSET_0_PRIM_TYPE__SHIFT) & CP_DRAW_INDX_OFFSET_0_PRIM_TYPE__MASK; +} +#define CP_DRAW_INDX_OFFSET_0_SOURCE_SELECT__MASK 0x000000c0 +#define CP_DRAW_INDX_OFFSET_0_SOURCE_SELECT__SHIFT 6 +static inline uint32_t CP_DRAW_INDX_OFFSET_0_SOURCE_SELECT(enum pc_di_src_sel val) +{ + return ((val) << CP_DRAW_INDX_OFFSET_0_SOURCE_SELECT__SHIFT) & CP_DRAW_INDX_OFFSET_0_SOURCE_SELECT__MASK; +} +#define CP_DRAW_INDX_OFFSET_0_VIS_CULL__MASK 0x00000300 +#define CP_DRAW_INDX_OFFSET_0_VIS_CULL__SHIFT 8 +static inline uint32_t CP_DRAW_INDX_OFFSET_0_VIS_CULL(enum pc_di_vis_cull_mode val) +{ + return ((val) << CP_DRAW_INDX_OFFSET_0_VIS_CULL__SHIFT) & CP_DRAW_INDX_OFFSET_0_VIS_CULL__MASK; +} +#define CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__MASK 0x00000c00 +#define CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__SHIFT 10 +static inline uint32_t CP_DRAW_INDX_OFFSET_0_INDEX_SIZE(enum a4xx_index_size val) +{ + return ((val) << CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__SHIFT) & CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__MASK; +} +#define CP_DRAW_INDX_OFFSET_0_TESS_MODE__MASK 0x01f00000 +#define CP_DRAW_INDX_OFFSET_0_TESS_MODE__SHIFT 20 +static inline uint32_t CP_DRAW_INDX_OFFSET_0_TESS_MODE(uint32_t val) +{ + return ((val) << CP_DRAW_INDX_OFFSET_0_TESS_MODE__SHIFT) & CP_DRAW_INDX_OFFSET_0_TESS_MODE__MASK; +} + +#define REG_CP_DRAW_INDX_OFFSET_1 0x00000001 +#define CP_DRAW_INDX_OFFSET_1_NUM_INSTANCES__MASK 0xffffffff +#define CP_DRAW_INDX_OFFSET_1_NUM_INSTANCES__SHIFT 0 +static inline uint32_t CP_DRAW_INDX_OFFSET_1_NUM_INSTANCES(uint32_t val) +{ + return ((val) << CP_DRAW_INDX_OFFSET_1_NUM_INSTANCES__SHIFT) & CP_DRAW_INDX_OFFSET_1_NUM_INSTANCES__MASK; +} + +#define REG_CP_DRAW_INDX_OFFSET_2 0x00000002 +#define CP_DRAW_INDX_OFFSET_2_NUM_INDICES__MASK 0xffffffff +#define CP_DRAW_INDX_OFFSET_2_NUM_INDICES__SHIFT 0 +static inline uint32_t CP_DRAW_INDX_OFFSET_2_NUM_INDICES(uint32_t val) +{ + return ((val) << CP_DRAW_INDX_OFFSET_2_NUM_INDICES__SHIFT) & CP_DRAW_INDX_OFFSET_2_NUM_INDICES__MASK; +} + +#define REG_CP_DRAW_INDX_OFFSET_3 0x00000003 + +#define REG_CP_DRAW_INDX_OFFSET_4 0x00000004 +#define CP_DRAW_INDX_OFFSET_4_INDX_BASE__MASK 0xffffffff +#define CP_DRAW_INDX_OFFSET_4_INDX_BASE__SHIFT 0 +static inline uint32_t CP_DRAW_INDX_OFFSET_4_INDX_BASE(uint32_t val) +{ + return ((val) << CP_DRAW_INDX_OFFSET_4_INDX_BASE__SHIFT) & CP_DRAW_INDX_OFFSET_4_INDX_BASE__MASK; +} + +#define REG_CP_DRAW_INDX_OFFSET_5 0x00000005 +#define CP_DRAW_INDX_OFFSET_5_INDX_SIZE__MASK 0xffffffff +#define CP_DRAW_INDX_OFFSET_5_INDX_SIZE__SHIFT 0 +static inline uint32_t CP_DRAW_INDX_OFFSET_5_INDX_SIZE(uint32_t val) +{ + return ((val) << CP_DRAW_INDX_OFFSET_5_INDX_SIZE__SHIFT) & CP_DRAW_INDX_OFFSET_5_INDX_SIZE__MASK; +} + +#define REG_A4XX_CP_DRAW_INDIRECT_0 0x00000000 +#define A4XX_CP_DRAW_INDIRECT_0_PRIM_TYPE__MASK 0x0000003f +#define A4XX_CP_DRAW_INDIRECT_0_PRIM_TYPE__SHIFT 0 +static inline uint32_t A4XX_CP_DRAW_INDIRECT_0_PRIM_TYPE(enum pc_di_primtype val) +{ + return ((val) << A4XX_CP_DRAW_INDIRECT_0_PRIM_TYPE__SHIFT) & A4XX_CP_DRAW_INDIRECT_0_PRIM_TYPE__MASK; +} +#define A4XX_CP_DRAW_INDIRECT_0_SOURCE_SELECT__MASK 0x000000c0 +#define A4XX_CP_DRAW_INDIRECT_0_SOURCE_SELECT__SHIFT 6 +static inline uint32_t A4XX_CP_DRAW_INDIRECT_0_SOURCE_SELECT(enum pc_di_src_sel val) +{ + return ((val) << A4XX_CP_DRAW_INDIRECT_0_SOURCE_SELECT__SHIFT) & A4XX_CP_DRAW_INDIRECT_0_SOURCE_SELECT__MASK; +} +#define A4XX_CP_DRAW_INDIRECT_0_VIS_CULL__MASK 0x00000300 +#define A4XX_CP_DRAW_INDIRECT_0_VIS_CULL__SHIFT 8 +static inline uint32_t A4XX_CP_DRAW_INDIRECT_0_VIS_CULL(enum pc_di_vis_cull_mode val) +{ + return ((val) << A4XX_CP_DRAW_INDIRECT_0_VIS_CULL__SHIFT) & A4XX_CP_DRAW_INDIRECT_0_VIS_CULL__MASK; +} +#define A4XX_CP_DRAW_INDIRECT_0_INDEX_SIZE__MASK 0x00000c00 +#define A4XX_CP_DRAW_INDIRECT_0_INDEX_SIZE__SHIFT 10 +static inline uint32_t A4XX_CP_DRAW_INDIRECT_0_INDEX_SIZE(enum a4xx_index_size val) +{ + return ((val) << A4XX_CP_DRAW_INDIRECT_0_INDEX_SIZE__SHIFT) & A4XX_CP_DRAW_INDIRECT_0_INDEX_SIZE__MASK; +} +#define A4XX_CP_DRAW_INDIRECT_0_TESS_MODE__MASK 0x01f00000 +#define A4XX_CP_DRAW_INDIRECT_0_TESS_MODE__SHIFT 20 +static inline uint32_t A4XX_CP_DRAW_INDIRECT_0_TESS_MODE(uint32_t val) +{ + return ((val) << A4XX_CP_DRAW_INDIRECT_0_TESS_MODE__SHIFT) & A4XX_CP_DRAW_INDIRECT_0_TESS_MODE__MASK; +} + +#define REG_A4XX_CP_DRAW_INDIRECT_1 0x00000001 +#define A4XX_CP_DRAW_INDIRECT_1_INDIRECT__MASK 0xffffffff +#define A4XX_CP_DRAW_INDIRECT_1_INDIRECT__SHIFT 0 +static inline uint32_t A4XX_CP_DRAW_INDIRECT_1_INDIRECT(uint32_t val) +{ + return ((val) << A4XX_CP_DRAW_INDIRECT_1_INDIRECT__SHIFT) & A4XX_CP_DRAW_INDIRECT_1_INDIRECT__MASK; +} + + +#define REG_A5XX_CP_DRAW_INDIRECT_2 0x00000002 +#define A5XX_CP_DRAW_INDIRECT_2_INDIRECT_HI__MASK 0xffffffff +#define A5XX_CP_DRAW_INDIRECT_2_INDIRECT_HI__SHIFT 0 +static inline uint32_t A5XX_CP_DRAW_INDIRECT_2_INDIRECT_HI(uint32_t val) +{ + return ((val) << A5XX_CP_DRAW_INDIRECT_2_INDIRECT_HI__SHIFT) & A5XX_CP_DRAW_INDIRECT_2_INDIRECT_HI__MASK; +} + +#define REG_A4XX_CP_DRAW_INDX_INDIRECT_0 0x00000000 +#define A4XX_CP_DRAW_INDX_INDIRECT_0_PRIM_TYPE__MASK 0x0000003f +#define A4XX_CP_DRAW_INDX_INDIRECT_0_PRIM_TYPE__SHIFT 0 +static inline uint32_t A4XX_CP_DRAW_INDX_INDIRECT_0_PRIM_TYPE(enum pc_di_primtype val) +{ + return ((val) << A4XX_CP_DRAW_INDX_INDIRECT_0_PRIM_TYPE__SHIFT) & A4XX_CP_DRAW_INDX_INDIRECT_0_PRIM_TYPE__MASK; +} +#define A4XX_CP_DRAW_INDX_INDIRECT_0_SOURCE_SELECT__MASK 0x000000c0 +#define A4XX_CP_DRAW_INDX_INDIRECT_0_SOURCE_SELECT__SHIFT 6 +static inline uint32_t A4XX_CP_DRAW_INDX_INDIRECT_0_SOURCE_SELECT(enum pc_di_src_sel val) +{ + return ((val) << A4XX_CP_DRAW_INDX_INDIRECT_0_SOURCE_SELECT__SHIFT) & A4XX_CP_DRAW_INDX_INDIRECT_0_SOURCE_SELECT__MASK; +} +#define A4XX_CP_DRAW_INDX_INDIRECT_0_VIS_CULL__MASK 0x00000300 +#define A4XX_CP_DRAW_INDX_INDIRECT_0_VIS_CULL__SHIFT 8 +static inline uint32_t A4XX_CP_DRAW_INDX_INDIRECT_0_VIS_CULL(enum pc_di_vis_cull_mode val) +{ + return ((val) << A4XX_CP_DRAW_INDX_INDIRECT_0_VIS_CULL__SHIFT) & A4XX_CP_DRAW_INDX_INDIRECT_0_VIS_CULL__MASK; +} +#define A4XX_CP_DRAW_INDX_INDIRECT_0_INDEX_SIZE__MASK 0x00000c00 +#define A4XX_CP_DRAW_INDX_INDIRECT_0_INDEX_SIZE__SHIFT 10 +static inline uint32_t A4XX_CP_DRAW_INDX_INDIRECT_0_INDEX_SIZE(enum a4xx_index_size val) +{ + return ((val) << A4XX_CP_DRAW_INDX_INDIRECT_0_INDEX_SIZE__SHIFT) & A4XX_CP_DRAW_INDX_INDIRECT_0_INDEX_SIZE__MASK; +} +#define A4XX_CP_DRAW_INDX_INDIRECT_0_TESS_MODE__MASK 0x01f00000 +#define A4XX_CP_DRAW_INDX_INDIRECT_0_TESS_MODE__SHIFT 20 +static inline uint32_t A4XX_CP_DRAW_INDX_INDIRECT_0_TESS_MODE(uint32_t val) +{ + return ((val) << A4XX_CP_DRAW_INDX_INDIRECT_0_TESS_MODE__SHIFT) & A4XX_CP_DRAW_INDX_INDIRECT_0_TESS_MODE__MASK; +} + + +#define REG_A4XX_CP_DRAW_INDX_INDIRECT_1 0x00000001 +#define A4XX_CP_DRAW_INDX_INDIRECT_1_INDX_BASE__MASK 0xffffffff +#define A4XX_CP_DRAW_INDX_INDIRECT_1_INDX_BASE__SHIFT 0 +static inline uint32_t A4XX_CP_DRAW_INDX_INDIRECT_1_INDX_BASE(uint32_t val) +{ + return ((val) << A4XX_CP_DRAW_INDX_INDIRECT_1_INDX_BASE__SHIFT) & A4XX_CP_DRAW_INDX_INDIRECT_1_INDX_BASE__MASK; +} + +#define REG_A4XX_CP_DRAW_INDX_INDIRECT_2 0x00000002 +#define A4XX_CP_DRAW_INDX_INDIRECT_2_INDX_SIZE__MASK 0xffffffff +#define A4XX_CP_DRAW_INDX_INDIRECT_2_INDX_SIZE__SHIFT 0 +static inline uint32_t A4XX_CP_DRAW_INDX_INDIRECT_2_INDX_SIZE(uint32_t val) +{ + return ((val) << A4XX_CP_DRAW_INDX_INDIRECT_2_INDX_SIZE__SHIFT) & A4XX_CP_DRAW_INDX_INDIRECT_2_INDX_SIZE__MASK; +} + +#define REG_A4XX_CP_DRAW_INDX_INDIRECT_3 0x00000003 +#define A4XX_CP_DRAW_INDX_INDIRECT_3_INDIRECT__MASK 0xffffffff +#define A4XX_CP_DRAW_INDX_INDIRECT_3_INDIRECT__SHIFT 0 +static inline uint32_t A4XX_CP_DRAW_INDX_INDIRECT_3_INDIRECT(uint32_t val) +{ + return ((val) << A4XX_CP_DRAW_INDX_INDIRECT_3_INDIRECT__SHIFT) & A4XX_CP_DRAW_INDX_INDIRECT_3_INDIRECT__MASK; +} + + +#define REG_A5XX_CP_DRAW_INDX_INDIRECT_1 0x00000001 +#define A5XX_CP_DRAW_INDX_INDIRECT_1_INDX_BASE_LO__MASK 0xffffffff +#define A5XX_CP_DRAW_INDX_INDIRECT_1_INDX_BASE_LO__SHIFT 0 +static inline uint32_t A5XX_CP_DRAW_INDX_INDIRECT_1_INDX_BASE_LO(uint32_t val) +{ + return ((val) << A5XX_CP_DRAW_INDX_INDIRECT_1_INDX_BASE_LO__SHIFT) & A5XX_CP_DRAW_INDX_INDIRECT_1_INDX_BASE_LO__MASK; +} + +#define REG_A5XX_CP_DRAW_INDX_INDIRECT_2 0x00000002 +#define A5XX_CP_DRAW_INDX_INDIRECT_2_INDX_BASE_HI__MASK 0xffffffff +#define A5XX_CP_DRAW_INDX_INDIRECT_2_INDX_BASE_HI__SHIFT 0 +static inline uint32_t A5XX_CP_DRAW_INDX_INDIRECT_2_INDX_BASE_HI(uint32_t val) +{ + return ((val) << A5XX_CP_DRAW_INDX_INDIRECT_2_INDX_BASE_HI__SHIFT) & A5XX_CP_DRAW_INDX_INDIRECT_2_INDX_BASE_HI__MASK; +} + +#define REG_A5XX_CP_DRAW_INDX_INDIRECT_3 0x00000003 +#define A5XX_CP_DRAW_INDX_INDIRECT_3_MAX_INDICES__MASK 0xffffffff +#define A5XX_CP_DRAW_INDX_INDIRECT_3_MAX_INDICES__SHIFT 0 +static inline uint32_t A5XX_CP_DRAW_INDX_INDIRECT_3_MAX_INDICES(uint32_t val) +{ + return ((val) << A5XX_CP_DRAW_INDX_INDIRECT_3_MAX_INDICES__SHIFT) & A5XX_CP_DRAW_INDX_INDIRECT_3_MAX_INDICES__MASK; +} + +#define REG_A5XX_CP_DRAW_INDX_INDIRECT_4 0x00000004 +#define A5XX_CP_DRAW_INDX_INDIRECT_4_INDIRECT_LO__MASK 0xffffffff +#define A5XX_CP_DRAW_INDX_INDIRECT_4_INDIRECT_LO__SHIFT 0 +static inline uint32_t A5XX_CP_DRAW_INDX_INDIRECT_4_INDIRECT_LO(uint32_t val) +{ + return ((val) << A5XX_CP_DRAW_INDX_INDIRECT_4_INDIRECT_LO__SHIFT) & A5XX_CP_DRAW_INDX_INDIRECT_4_INDIRECT_LO__MASK; +} + +#define REG_A5XX_CP_DRAW_INDX_INDIRECT_5 0x00000005 +#define A5XX_CP_DRAW_INDX_INDIRECT_5_INDIRECT_HI__MASK 0xffffffff +#define A5XX_CP_DRAW_INDX_INDIRECT_5_INDIRECT_HI__SHIFT 0 +static inline uint32_t A5XX_CP_DRAW_INDX_INDIRECT_5_INDIRECT_HI(uint32_t val) +{ + return ((val) << A5XX_CP_DRAW_INDX_INDIRECT_5_INDIRECT_HI__SHIFT) & A5XX_CP_DRAW_INDX_INDIRECT_5_INDIRECT_HI__MASK; +} + +static inline uint32_t REG_CP_SET_DRAW_STATE_(uint32_t i0) { return 0x00000000 + 0x3*i0; } + +static inline uint32_t REG_CP_SET_DRAW_STATE__0(uint32_t i0) { return 0x00000000 + 0x3*i0; } +#define CP_SET_DRAW_STATE__0_COUNT__MASK 0x0000ffff +#define CP_SET_DRAW_STATE__0_COUNT__SHIFT 0 +static inline uint32_t CP_SET_DRAW_STATE__0_COUNT(uint32_t val) +{ + return ((val) << CP_SET_DRAW_STATE__0_COUNT__SHIFT) & CP_SET_DRAW_STATE__0_COUNT__MASK; +} +#define CP_SET_DRAW_STATE__0_DIRTY 0x00010000 +#define CP_SET_DRAW_STATE__0_DISABLE 0x00020000 +#define CP_SET_DRAW_STATE__0_DISABLE_ALL_GROUPS 0x00040000 +#define CP_SET_DRAW_STATE__0_LOAD_IMMED 0x00080000 +#define CP_SET_DRAW_STATE__0_GROUP_ID__MASK 0x1f000000 +#define CP_SET_DRAW_STATE__0_GROUP_ID__SHIFT 24 +static inline uint32_t CP_SET_DRAW_STATE__0_GROUP_ID(uint32_t val) +{ + return ((val) << CP_SET_DRAW_STATE__0_GROUP_ID__SHIFT) & CP_SET_DRAW_STATE__0_GROUP_ID__MASK; +} + +static inline uint32_t REG_CP_SET_DRAW_STATE__1(uint32_t i0) { return 0x00000001 + 0x3*i0; } +#define CP_SET_DRAW_STATE__1_ADDR_LO__MASK 0xffffffff +#define CP_SET_DRAW_STATE__1_ADDR_LO__SHIFT 0 +static inline uint32_t CP_SET_DRAW_STATE__1_ADDR_LO(uint32_t val) +{ + return ((val) << CP_SET_DRAW_STATE__1_ADDR_LO__SHIFT) & CP_SET_DRAW_STATE__1_ADDR_LO__MASK; +} + +static inline uint32_t REG_CP_SET_DRAW_STATE__2(uint32_t i0) { return 0x00000002 + 0x3*i0; } +#define CP_SET_DRAW_STATE__2_ADDR_HI__MASK 0xffffffff +#define CP_SET_DRAW_STATE__2_ADDR_HI__SHIFT 0 +static inline uint32_t CP_SET_DRAW_STATE__2_ADDR_HI(uint32_t val) +{ + return ((val) << CP_SET_DRAW_STATE__2_ADDR_HI__SHIFT) & CP_SET_DRAW_STATE__2_ADDR_HI__MASK; +} + +#define REG_CP_SET_BIN_0 0x00000000 + +#define REG_CP_SET_BIN_1 0x00000001 +#define CP_SET_BIN_1_X1__MASK 0x0000ffff +#define CP_SET_BIN_1_X1__SHIFT 0 +static inline uint32_t CP_SET_BIN_1_X1(uint32_t val) +{ + return ((val) << CP_SET_BIN_1_X1__SHIFT) & CP_SET_BIN_1_X1__MASK; +} +#define CP_SET_BIN_1_Y1__MASK 0xffff0000 +#define CP_SET_BIN_1_Y1__SHIFT 16 +static inline uint32_t CP_SET_BIN_1_Y1(uint32_t val) +{ + return ((val) << CP_SET_BIN_1_Y1__SHIFT) & CP_SET_BIN_1_Y1__MASK; +} + +#define REG_CP_SET_BIN_2 0x00000002 +#define CP_SET_BIN_2_X2__MASK 0x0000ffff +#define CP_SET_BIN_2_X2__SHIFT 0 +static inline uint32_t CP_SET_BIN_2_X2(uint32_t val) +{ + return ((val) << CP_SET_BIN_2_X2__SHIFT) & CP_SET_BIN_2_X2__MASK; +} +#define CP_SET_BIN_2_Y2__MASK 0xffff0000 +#define CP_SET_BIN_2_Y2__SHIFT 16 +static inline uint32_t CP_SET_BIN_2_Y2(uint32_t val) +{ + return ((val) << CP_SET_BIN_2_Y2__SHIFT) & CP_SET_BIN_2_Y2__MASK; +} + +#define REG_CP_SET_BIN_DATA_0 0x00000000 +#define CP_SET_BIN_DATA_0_BIN_DATA_ADDR__MASK 0xffffffff +#define CP_SET_BIN_DATA_0_BIN_DATA_ADDR__SHIFT 0 +static inline uint32_t CP_SET_BIN_DATA_0_BIN_DATA_ADDR(uint32_t val) +{ + return ((val) << CP_SET_BIN_DATA_0_BIN_DATA_ADDR__SHIFT) & CP_SET_BIN_DATA_0_BIN_DATA_ADDR__MASK; +} + +#define REG_CP_SET_BIN_DATA_1 0x00000001 +#define CP_SET_BIN_DATA_1_BIN_SIZE_ADDRESS__MASK 0xffffffff +#define CP_SET_BIN_DATA_1_BIN_SIZE_ADDRESS__SHIFT 0 +static inline uint32_t CP_SET_BIN_DATA_1_BIN_SIZE_ADDRESS(uint32_t val) +{ + return ((val) << CP_SET_BIN_DATA_1_BIN_SIZE_ADDRESS__SHIFT) & CP_SET_BIN_DATA_1_BIN_SIZE_ADDRESS__MASK; +} + +#define REG_CP_SET_BIN_DATA5_0 0x00000000 +#define CP_SET_BIN_DATA5_0_VSC_SIZE__MASK 0x003f0000 +#define CP_SET_BIN_DATA5_0_VSC_SIZE__SHIFT 16 +static inline uint32_t CP_SET_BIN_DATA5_0_VSC_SIZE(uint32_t val) +{ + return ((val) << CP_SET_BIN_DATA5_0_VSC_SIZE__SHIFT) & CP_SET_BIN_DATA5_0_VSC_SIZE__MASK; +} +#define CP_SET_BIN_DATA5_0_VSC_N__MASK 0x07c00000 +#define CP_SET_BIN_DATA5_0_VSC_N__SHIFT 22 +static inline uint32_t CP_SET_BIN_DATA5_0_VSC_N(uint32_t val) +{ + return ((val) << CP_SET_BIN_DATA5_0_VSC_N__SHIFT) & CP_SET_BIN_DATA5_0_VSC_N__MASK; +} + +#define REG_CP_SET_BIN_DATA5_1 0x00000001 +#define CP_SET_BIN_DATA5_1_BIN_DATA_ADDR_LO__MASK 0xffffffff +#define CP_SET_BIN_DATA5_1_BIN_DATA_ADDR_LO__SHIFT 0 +static inline uint32_t CP_SET_BIN_DATA5_1_BIN_DATA_ADDR_LO(uint32_t val) +{ + return ((val) << CP_SET_BIN_DATA5_1_BIN_DATA_ADDR_LO__SHIFT) & CP_SET_BIN_DATA5_1_BIN_DATA_ADDR_LO__MASK; +} + +#define REG_CP_SET_BIN_DATA5_2 0x00000002 +#define CP_SET_BIN_DATA5_2_BIN_DATA_ADDR_HI__MASK 0xffffffff +#define CP_SET_BIN_DATA5_2_BIN_DATA_ADDR_HI__SHIFT 0 +static inline uint32_t CP_SET_BIN_DATA5_2_BIN_DATA_ADDR_HI(uint32_t val) +{ + return ((val) << CP_SET_BIN_DATA5_2_BIN_DATA_ADDR_HI__SHIFT) & CP_SET_BIN_DATA5_2_BIN_DATA_ADDR_HI__MASK; +} + +#define REG_CP_SET_BIN_DATA5_3 0x00000003 +#define CP_SET_BIN_DATA5_3_BIN_SIZE_ADDRESS_LO__MASK 0xffffffff +#define CP_SET_BIN_DATA5_3_BIN_SIZE_ADDRESS_LO__SHIFT 0 +static inline uint32_t CP_SET_BIN_DATA5_3_BIN_SIZE_ADDRESS_LO(uint32_t val) +{ + return ((val) << CP_SET_BIN_DATA5_3_BIN_SIZE_ADDRESS_LO__SHIFT) & CP_SET_BIN_DATA5_3_BIN_SIZE_ADDRESS_LO__MASK; +} + +#define REG_CP_SET_BIN_DATA5_4 0x00000004 +#define CP_SET_BIN_DATA5_4_BIN_SIZE_ADDRESS_HI__MASK 0xffffffff +#define CP_SET_BIN_DATA5_4_BIN_SIZE_ADDRESS_HI__SHIFT 0 +static inline uint32_t CP_SET_BIN_DATA5_4_BIN_SIZE_ADDRESS_HI(uint32_t val) +{ + return ((val) << CP_SET_BIN_DATA5_4_BIN_SIZE_ADDRESS_HI__SHIFT) & CP_SET_BIN_DATA5_4_BIN_SIZE_ADDRESS_HI__MASK; +} + +#define REG_CP_REG_TO_MEM_0 0x00000000 +#define CP_REG_TO_MEM_0_REG__MASK 0x0000ffff +#define CP_REG_TO_MEM_0_REG__SHIFT 0 +static inline uint32_t CP_REG_TO_MEM_0_REG(uint32_t val) +{ + return ((val) << CP_REG_TO_MEM_0_REG__SHIFT) & CP_REG_TO_MEM_0_REG__MASK; +} +#define CP_REG_TO_MEM_0_CNT__MASK 0x3ff80000 +#define CP_REG_TO_MEM_0_CNT__SHIFT 19 +static inline uint32_t CP_REG_TO_MEM_0_CNT(uint32_t val) +{ + return ((val) << CP_REG_TO_MEM_0_CNT__SHIFT) & CP_REG_TO_MEM_0_CNT__MASK; +} +#define CP_REG_TO_MEM_0_64B 0x40000000 +#define CP_REG_TO_MEM_0_ACCUMULATE 0x80000000 + +#define REG_CP_REG_TO_MEM_1 0x00000001 +#define CP_REG_TO_MEM_1_DEST__MASK 0xffffffff +#define CP_REG_TO_MEM_1_DEST__SHIFT 0 +static inline uint32_t CP_REG_TO_MEM_1_DEST(uint32_t val) +{ + return ((val) << CP_REG_TO_MEM_1_DEST__SHIFT) & CP_REG_TO_MEM_1_DEST__MASK; +} + +#define REG_CP_MEM_TO_MEM_0 0x00000000 +#define CP_MEM_TO_MEM_0_NEG_A 0x00000001 +#define CP_MEM_TO_MEM_0_NEG_B 0x00000002 +#define CP_MEM_TO_MEM_0_NEG_C 0x00000004 +#define CP_MEM_TO_MEM_0_DOUBLE 0x20000000 + +#define REG_CP_COND_WRITE_0 0x00000000 +#define CP_COND_WRITE_0_FUNCTION__MASK 0x00000007 +#define CP_COND_WRITE_0_FUNCTION__SHIFT 0 +static inline uint32_t CP_COND_WRITE_0_FUNCTION(enum cp_cond_function val) +{ + return ((val) << CP_COND_WRITE_0_FUNCTION__SHIFT) & CP_COND_WRITE_0_FUNCTION__MASK; +} +#define CP_COND_WRITE_0_POLL_MEMORY 0x00000010 +#define CP_COND_WRITE_0_WRITE_MEMORY 0x00000100 + +#define REG_CP_COND_WRITE_1 0x00000001 +#define CP_COND_WRITE_1_POLL_ADDR__MASK 0xffffffff +#define CP_COND_WRITE_1_POLL_ADDR__SHIFT 0 +static inline uint32_t CP_COND_WRITE_1_POLL_ADDR(uint32_t val) +{ + return ((val) << CP_COND_WRITE_1_POLL_ADDR__SHIFT) & CP_COND_WRITE_1_POLL_ADDR__MASK; +} + +#define REG_CP_COND_WRITE_2 0x00000002 +#define CP_COND_WRITE_2_REF__MASK 0xffffffff +#define CP_COND_WRITE_2_REF__SHIFT 0 +static inline uint32_t CP_COND_WRITE_2_REF(uint32_t val) +{ + return ((val) << CP_COND_WRITE_2_REF__SHIFT) & CP_COND_WRITE_2_REF__MASK; +} + +#define REG_CP_COND_WRITE_3 0x00000003 +#define CP_COND_WRITE_3_MASK__MASK 0xffffffff +#define CP_COND_WRITE_3_MASK__SHIFT 0 +static inline uint32_t CP_COND_WRITE_3_MASK(uint32_t val) +{ + return ((val) << CP_COND_WRITE_3_MASK__SHIFT) & CP_COND_WRITE_3_MASK__MASK; +} + +#define REG_CP_COND_WRITE_4 0x00000004 +#define CP_COND_WRITE_4_WRITE_ADDR__MASK 0xffffffff +#define CP_COND_WRITE_4_WRITE_ADDR__SHIFT 0 +static inline uint32_t CP_COND_WRITE_4_WRITE_ADDR(uint32_t val) +{ + return ((val) << CP_COND_WRITE_4_WRITE_ADDR__SHIFT) & CP_COND_WRITE_4_WRITE_ADDR__MASK; +} + +#define REG_CP_COND_WRITE_5 0x00000005 +#define CP_COND_WRITE_5_WRITE_DATA__MASK 0xffffffff +#define CP_COND_WRITE_5_WRITE_DATA__SHIFT 0 +static inline uint32_t CP_COND_WRITE_5_WRITE_DATA(uint32_t val) +{ + return ((val) << CP_COND_WRITE_5_WRITE_DATA__SHIFT) & CP_COND_WRITE_5_WRITE_DATA__MASK; +} + +#define REG_CP_COND_WRITE5_0 0x00000000 +#define CP_COND_WRITE5_0_FUNCTION__MASK 0x00000007 +#define CP_COND_WRITE5_0_FUNCTION__SHIFT 0 +static inline uint32_t CP_COND_WRITE5_0_FUNCTION(enum cp_cond_function val) +{ + return ((val) << CP_COND_WRITE5_0_FUNCTION__SHIFT) & CP_COND_WRITE5_0_FUNCTION__MASK; +} +#define CP_COND_WRITE5_0_POLL_MEMORY 0x00000010 +#define CP_COND_WRITE5_0_WRITE_MEMORY 0x00000100 + +#define REG_CP_COND_WRITE5_1 0x00000001 +#define CP_COND_WRITE5_1_POLL_ADDR_LO__MASK 0xffffffff +#define CP_COND_WRITE5_1_POLL_ADDR_LO__SHIFT 0 +static inline uint32_t CP_COND_WRITE5_1_POLL_ADDR_LO(uint32_t val) +{ + return ((val) << CP_COND_WRITE5_1_POLL_ADDR_LO__SHIFT) & CP_COND_WRITE5_1_POLL_ADDR_LO__MASK; +} + +#define REG_CP_COND_WRITE5_2 0x00000002 +#define CP_COND_WRITE5_2_POLL_ADDR_HI__MASK 0xffffffff +#define CP_COND_WRITE5_2_POLL_ADDR_HI__SHIFT 0 +static inline uint32_t CP_COND_WRITE5_2_POLL_ADDR_HI(uint32_t val) +{ + return ((val) << CP_COND_WRITE5_2_POLL_ADDR_HI__SHIFT) & CP_COND_WRITE5_2_POLL_ADDR_HI__MASK; +} + +#define REG_CP_COND_WRITE5_3 0x00000003 +#define CP_COND_WRITE5_3_REF__MASK 0xffffffff +#define CP_COND_WRITE5_3_REF__SHIFT 0 +static inline uint32_t CP_COND_WRITE5_3_REF(uint32_t val) +{ + return ((val) << CP_COND_WRITE5_3_REF__SHIFT) & CP_COND_WRITE5_3_REF__MASK; +} + +#define REG_CP_COND_WRITE5_4 0x00000004 +#define CP_COND_WRITE5_4_MASK__MASK 0xffffffff +#define CP_COND_WRITE5_4_MASK__SHIFT 0 +static inline uint32_t CP_COND_WRITE5_4_MASK(uint32_t val) +{ + return ((val) << CP_COND_WRITE5_4_MASK__SHIFT) & CP_COND_WRITE5_4_MASK__MASK; +} + +#define REG_CP_COND_WRITE5_5 0x00000005 +#define CP_COND_WRITE5_5_WRITE_ADDR_LO__MASK 0xffffffff +#define CP_COND_WRITE5_5_WRITE_ADDR_LO__SHIFT 0 +static inline uint32_t CP_COND_WRITE5_5_WRITE_ADDR_LO(uint32_t val) +{ + return ((val) << CP_COND_WRITE5_5_WRITE_ADDR_LO__SHIFT) & CP_COND_WRITE5_5_WRITE_ADDR_LO__MASK; +} + +#define REG_CP_COND_WRITE5_6 0x00000006 +#define CP_COND_WRITE5_6_WRITE_ADDR_HI__MASK 0xffffffff +#define CP_COND_WRITE5_6_WRITE_ADDR_HI__SHIFT 0 +static inline uint32_t CP_COND_WRITE5_6_WRITE_ADDR_HI(uint32_t val) +{ + return ((val) << CP_COND_WRITE5_6_WRITE_ADDR_HI__SHIFT) & CP_COND_WRITE5_6_WRITE_ADDR_HI__MASK; +} + +#define REG_CP_COND_WRITE5_7 0x00000007 +#define CP_COND_WRITE5_7_WRITE_DATA__MASK 0xffffffff +#define CP_COND_WRITE5_7_WRITE_DATA__SHIFT 0 +static inline uint32_t CP_COND_WRITE5_7_WRITE_DATA(uint32_t val) +{ + return ((val) << CP_COND_WRITE5_7_WRITE_DATA__SHIFT) & CP_COND_WRITE5_7_WRITE_DATA__MASK; +} + +#define REG_CP_DISPATCH_COMPUTE_0 0x00000000 + +#define REG_CP_DISPATCH_COMPUTE_1 0x00000001 +#define CP_DISPATCH_COMPUTE_1_X__MASK 0xffffffff +#define CP_DISPATCH_COMPUTE_1_X__SHIFT 0 +static inline uint32_t CP_DISPATCH_COMPUTE_1_X(uint32_t val) +{ + return ((val) << CP_DISPATCH_COMPUTE_1_X__SHIFT) & CP_DISPATCH_COMPUTE_1_X__MASK; +} + +#define REG_CP_DISPATCH_COMPUTE_2 0x00000002 +#define CP_DISPATCH_COMPUTE_2_Y__MASK 0xffffffff +#define CP_DISPATCH_COMPUTE_2_Y__SHIFT 0 +static inline uint32_t CP_DISPATCH_COMPUTE_2_Y(uint32_t val) +{ + return ((val) << CP_DISPATCH_COMPUTE_2_Y__SHIFT) & CP_DISPATCH_COMPUTE_2_Y__MASK; +} + +#define REG_CP_DISPATCH_COMPUTE_3 0x00000003 +#define CP_DISPATCH_COMPUTE_3_Z__MASK 0xffffffff +#define CP_DISPATCH_COMPUTE_3_Z__SHIFT 0 +static inline uint32_t CP_DISPATCH_COMPUTE_3_Z(uint32_t val) +{ + return ((val) << CP_DISPATCH_COMPUTE_3_Z__SHIFT) & CP_DISPATCH_COMPUTE_3_Z__MASK; +} + +#define REG_CP_SET_RENDER_MODE_0 0x00000000 +#define CP_SET_RENDER_MODE_0_MODE__MASK 0x000001ff +#define CP_SET_RENDER_MODE_0_MODE__SHIFT 0 +static inline uint32_t CP_SET_RENDER_MODE_0_MODE(enum render_mode_cmd val) +{ + return ((val) << CP_SET_RENDER_MODE_0_MODE__SHIFT) & CP_SET_RENDER_MODE_0_MODE__MASK; +} + +#define REG_CP_SET_RENDER_MODE_1 0x00000001 +#define CP_SET_RENDER_MODE_1_ADDR_0_LO__MASK 0xffffffff +#define CP_SET_RENDER_MODE_1_ADDR_0_LO__SHIFT 0 +static inline uint32_t CP_SET_RENDER_MODE_1_ADDR_0_LO(uint32_t val) +{ + return ((val) << CP_SET_RENDER_MODE_1_ADDR_0_LO__SHIFT) & CP_SET_RENDER_MODE_1_ADDR_0_LO__MASK; +} + +#define REG_CP_SET_RENDER_MODE_2 0x00000002 +#define CP_SET_RENDER_MODE_2_ADDR_0_HI__MASK 0xffffffff +#define CP_SET_RENDER_MODE_2_ADDR_0_HI__SHIFT 0 +static inline uint32_t CP_SET_RENDER_MODE_2_ADDR_0_HI(uint32_t val) +{ + return ((val) << CP_SET_RENDER_MODE_2_ADDR_0_HI__SHIFT) & CP_SET_RENDER_MODE_2_ADDR_0_HI__MASK; +} + +#define REG_CP_SET_RENDER_MODE_3 0x00000003 +#define CP_SET_RENDER_MODE_3_VSC_ENABLE 0x00000008 +#define CP_SET_RENDER_MODE_3_GMEM_ENABLE 0x00000010 + +#define REG_CP_SET_RENDER_MODE_4 0x00000004 + +#define REG_CP_SET_RENDER_MODE_5 0x00000005 +#define CP_SET_RENDER_MODE_5_ADDR_1_LEN__MASK 0xffffffff +#define CP_SET_RENDER_MODE_5_ADDR_1_LEN__SHIFT 0 +static inline uint32_t CP_SET_RENDER_MODE_5_ADDR_1_LEN(uint32_t val) +{ + return ((val) << CP_SET_RENDER_MODE_5_ADDR_1_LEN__SHIFT) & CP_SET_RENDER_MODE_5_ADDR_1_LEN__MASK; +} + +#define REG_CP_SET_RENDER_MODE_6 0x00000006 +#define CP_SET_RENDER_MODE_6_ADDR_1_LO__MASK 0xffffffff +#define CP_SET_RENDER_MODE_6_ADDR_1_LO__SHIFT 0 +static inline uint32_t CP_SET_RENDER_MODE_6_ADDR_1_LO(uint32_t val) +{ + return ((val) << CP_SET_RENDER_MODE_6_ADDR_1_LO__SHIFT) & CP_SET_RENDER_MODE_6_ADDR_1_LO__MASK; +} + +#define REG_CP_SET_RENDER_MODE_7 0x00000007 +#define CP_SET_RENDER_MODE_7_ADDR_1_HI__MASK 0xffffffff +#define CP_SET_RENDER_MODE_7_ADDR_1_HI__SHIFT 0 +static inline uint32_t CP_SET_RENDER_MODE_7_ADDR_1_HI(uint32_t val) +{ + return ((val) << CP_SET_RENDER_MODE_7_ADDR_1_HI__SHIFT) & CP_SET_RENDER_MODE_7_ADDR_1_HI__MASK; +} + +#define REG_CP_COMPUTE_CHECKPOINT_0 0x00000000 +#define CP_COMPUTE_CHECKPOINT_0_ADDR_0_LO__MASK 0xffffffff +#define CP_COMPUTE_CHECKPOINT_0_ADDR_0_LO__SHIFT 0 +static inline uint32_t CP_COMPUTE_CHECKPOINT_0_ADDR_0_LO(uint32_t val) +{ + return ((val) << CP_COMPUTE_CHECKPOINT_0_ADDR_0_LO__SHIFT) & CP_COMPUTE_CHECKPOINT_0_ADDR_0_LO__MASK; +} + +#define REG_CP_COMPUTE_CHECKPOINT_1 0x00000001 +#define CP_COMPUTE_CHECKPOINT_1_ADDR_0_HI__MASK 0xffffffff +#define CP_COMPUTE_CHECKPOINT_1_ADDR_0_HI__SHIFT 0 +static inline uint32_t CP_COMPUTE_CHECKPOINT_1_ADDR_0_HI(uint32_t val) +{ + return ((val) << CP_COMPUTE_CHECKPOINT_1_ADDR_0_HI__SHIFT) & CP_COMPUTE_CHECKPOINT_1_ADDR_0_HI__MASK; +} + +#define REG_CP_COMPUTE_CHECKPOINT_2 0x00000002 + +#define REG_CP_COMPUTE_CHECKPOINT_3 0x00000003 +#define CP_COMPUTE_CHECKPOINT_3_ADDR_1_LEN__MASK 0xffffffff +#define CP_COMPUTE_CHECKPOINT_3_ADDR_1_LEN__SHIFT 0 +static inline uint32_t CP_COMPUTE_CHECKPOINT_3_ADDR_1_LEN(uint32_t val) +{ + return ((val) << CP_COMPUTE_CHECKPOINT_3_ADDR_1_LEN__SHIFT) & CP_COMPUTE_CHECKPOINT_3_ADDR_1_LEN__MASK; +} + +#define REG_CP_COMPUTE_CHECKPOINT_4 0x00000004 + +#define REG_CP_COMPUTE_CHECKPOINT_5 0x00000005 +#define CP_COMPUTE_CHECKPOINT_5_ADDR_1_LO__MASK 0xffffffff +#define CP_COMPUTE_CHECKPOINT_5_ADDR_1_LO__SHIFT 0 +static inline uint32_t CP_COMPUTE_CHECKPOINT_5_ADDR_1_LO(uint32_t val) +{ + return ((val) << CP_COMPUTE_CHECKPOINT_5_ADDR_1_LO__SHIFT) & CP_COMPUTE_CHECKPOINT_5_ADDR_1_LO__MASK; +} + +#define REG_CP_COMPUTE_CHECKPOINT_6 0x00000006 +#define CP_COMPUTE_CHECKPOINT_6_ADDR_1_HI__MASK 0xffffffff +#define CP_COMPUTE_CHECKPOINT_6_ADDR_1_HI__SHIFT 0 +static inline uint32_t CP_COMPUTE_CHECKPOINT_6_ADDR_1_HI(uint32_t val) +{ + return ((val) << CP_COMPUTE_CHECKPOINT_6_ADDR_1_HI__SHIFT) & CP_COMPUTE_CHECKPOINT_6_ADDR_1_HI__MASK; +} + +#define REG_CP_COMPUTE_CHECKPOINT_7 0x00000007 + +#define REG_CP_PERFCOUNTER_ACTION_0 0x00000000 + +#define REG_CP_PERFCOUNTER_ACTION_1 0x00000001 +#define CP_PERFCOUNTER_ACTION_1_ADDR_0_LO__MASK 0xffffffff +#define CP_PERFCOUNTER_ACTION_1_ADDR_0_LO__SHIFT 0 +static inline uint32_t CP_PERFCOUNTER_ACTION_1_ADDR_0_LO(uint32_t val) +{ + return ((val) << CP_PERFCOUNTER_ACTION_1_ADDR_0_LO__SHIFT) & CP_PERFCOUNTER_ACTION_1_ADDR_0_LO__MASK; +} + +#define REG_CP_PERFCOUNTER_ACTION_2 0x00000002 +#define CP_PERFCOUNTER_ACTION_2_ADDR_0_HI__MASK 0xffffffff +#define CP_PERFCOUNTER_ACTION_2_ADDR_0_HI__SHIFT 0 +static inline uint32_t CP_PERFCOUNTER_ACTION_2_ADDR_0_HI(uint32_t val) +{ + return ((val) << CP_PERFCOUNTER_ACTION_2_ADDR_0_HI__SHIFT) & CP_PERFCOUNTER_ACTION_2_ADDR_0_HI__MASK; +} + +#define REG_CP_EVENT_WRITE_0 0x00000000 +#define CP_EVENT_WRITE_0_EVENT__MASK 0x000000ff +#define CP_EVENT_WRITE_0_EVENT__SHIFT 0 +static inline uint32_t CP_EVENT_WRITE_0_EVENT(enum vgt_event_type val) +{ + return ((val) << CP_EVENT_WRITE_0_EVENT__SHIFT) & CP_EVENT_WRITE_0_EVENT__MASK; +} +#define CP_EVENT_WRITE_0_TIMESTAMP 0x40000000 + +#define REG_CP_EVENT_WRITE_1 0x00000001 +#define CP_EVENT_WRITE_1_ADDR_0_LO__MASK 0xffffffff +#define CP_EVENT_WRITE_1_ADDR_0_LO__SHIFT 0 +static inline uint32_t CP_EVENT_WRITE_1_ADDR_0_LO(uint32_t val) +{ + return ((val) << CP_EVENT_WRITE_1_ADDR_0_LO__SHIFT) & CP_EVENT_WRITE_1_ADDR_0_LO__MASK; +} + +#define REG_CP_EVENT_WRITE_2 0x00000002 +#define CP_EVENT_WRITE_2_ADDR_0_HI__MASK 0xffffffff +#define CP_EVENT_WRITE_2_ADDR_0_HI__SHIFT 0 +static inline uint32_t CP_EVENT_WRITE_2_ADDR_0_HI(uint32_t val) +{ + return ((val) << CP_EVENT_WRITE_2_ADDR_0_HI__SHIFT) & CP_EVENT_WRITE_2_ADDR_0_HI__MASK; +} + +#define REG_CP_EVENT_WRITE_3 0x00000003 + +#define REG_CP_BLIT_0 0x00000000 +#define CP_BLIT_0_OP__MASK 0x0000000f +#define CP_BLIT_0_OP__SHIFT 0 +static inline uint32_t CP_BLIT_0_OP(enum cp_blit_cmd val) +{ + return ((val) << CP_BLIT_0_OP__SHIFT) & CP_BLIT_0_OP__MASK; +} + +#define REG_CP_BLIT_1 0x00000001 +#define CP_BLIT_1_SRC_X1__MASK 0x00003fff +#define CP_BLIT_1_SRC_X1__SHIFT 0 +static inline uint32_t CP_BLIT_1_SRC_X1(uint32_t val) +{ + return ((val) << CP_BLIT_1_SRC_X1__SHIFT) & CP_BLIT_1_SRC_X1__MASK; +} +#define CP_BLIT_1_SRC_Y1__MASK 0x3fff0000 +#define CP_BLIT_1_SRC_Y1__SHIFT 16 +static inline uint32_t CP_BLIT_1_SRC_Y1(uint32_t val) +{ + return ((val) << CP_BLIT_1_SRC_Y1__SHIFT) & CP_BLIT_1_SRC_Y1__MASK; +} + +#define REG_CP_BLIT_2 0x00000002 +#define CP_BLIT_2_SRC_X2__MASK 0x00003fff +#define CP_BLIT_2_SRC_X2__SHIFT 0 +static inline uint32_t CP_BLIT_2_SRC_X2(uint32_t val) +{ + return ((val) << CP_BLIT_2_SRC_X2__SHIFT) & CP_BLIT_2_SRC_X2__MASK; +} +#define CP_BLIT_2_SRC_Y2__MASK 0x3fff0000 +#define CP_BLIT_2_SRC_Y2__SHIFT 16 +static inline uint32_t CP_BLIT_2_SRC_Y2(uint32_t val) +{ + return ((val) << CP_BLIT_2_SRC_Y2__SHIFT) & CP_BLIT_2_SRC_Y2__MASK; +} + +#define REG_CP_BLIT_3 0x00000003 +#define CP_BLIT_3_DST_X1__MASK 0x00003fff +#define CP_BLIT_3_DST_X1__SHIFT 0 +static inline uint32_t CP_BLIT_3_DST_X1(uint32_t val) +{ + return ((val) << CP_BLIT_3_DST_X1__SHIFT) & CP_BLIT_3_DST_X1__MASK; +} +#define CP_BLIT_3_DST_Y1__MASK 0x3fff0000 +#define CP_BLIT_3_DST_Y1__SHIFT 16 +static inline uint32_t CP_BLIT_3_DST_Y1(uint32_t val) +{ + return ((val) << CP_BLIT_3_DST_Y1__SHIFT) & CP_BLIT_3_DST_Y1__MASK; +} + +#define REG_CP_BLIT_4 0x00000004 +#define CP_BLIT_4_DST_X2__MASK 0x00003fff +#define CP_BLIT_4_DST_X2__SHIFT 0 +static inline uint32_t CP_BLIT_4_DST_X2(uint32_t val) +{ + return ((val) << CP_BLIT_4_DST_X2__SHIFT) & CP_BLIT_4_DST_X2__MASK; +} +#define CP_BLIT_4_DST_Y2__MASK 0x3fff0000 +#define CP_BLIT_4_DST_Y2__SHIFT 16 +static inline uint32_t CP_BLIT_4_DST_Y2(uint32_t val) +{ + return ((val) << CP_BLIT_4_DST_Y2__SHIFT) & CP_BLIT_4_DST_Y2__MASK; +} + +#define REG_CP_EXEC_CS_0 0x00000000 + +#define REG_CP_EXEC_CS_1 0x00000001 +#define CP_EXEC_CS_1_NGROUPS_X__MASK 0xffffffff +#define CP_EXEC_CS_1_NGROUPS_X__SHIFT 0 +static inline uint32_t CP_EXEC_CS_1_NGROUPS_X(uint32_t val) +{ + return ((val) << CP_EXEC_CS_1_NGROUPS_X__SHIFT) & CP_EXEC_CS_1_NGROUPS_X__MASK; +} + +#define REG_CP_EXEC_CS_2 0x00000002 +#define CP_EXEC_CS_2_NGROUPS_Y__MASK 0xffffffff +#define CP_EXEC_CS_2_NGROUPS_Y__SHIFT 0 +static inline uint32_t CP_EXEC_CS_2_NGROUPS_Y(uint32_t val) +{ + return ((val) << CP_EXEC_CS_2_NGROUPS_Y__SHIFT) & CP_EXEC_CS_2_NGROUPS_Y__MASK; +} + +#define REG_CP_EXEC_CS_3 0x00000003 +#define CP_EXEC_CS_3_NGROUPS_Z__MASK 0xffffffff +#define CP_EXEC_CS_3_NGROUPS_Z__SHIFT 0 +static inline uint32_t CP_EXEC_CS_3_NGROUPS_Z(uint32_t val) +{ + return ((val) << CP_EXEC_CS_3_NGROUPS_Z__SHIFT) & CP_EXEC_CS_3_NGROUPS_Z__MASK; +} + +#define REG_A4XX_CP_EXEC_CS_INDIRECT_0 0x00000000 + + +#define REG_A4XX_CP_EXEC_CS_INDIRECT_1 0x00000001 +#define A4XX_CP_EXEC_CS_INDIRECT_1_ADDR__MASK 0xffffffff +#define A4XX_CP_EXEC_CS_INDIRECT_1_ADDR__SHIFT 0 +static inline uint32_t A4XX_CP_EXEC_CS_INDIRECT_1_ADDR(uint32_t val) +{ + return ((val) << A4XX_CP_EXEC_CS_INDIRECT_1_ADDR__SHIFT) & A4XX_CP_EXEC_CS_INDIRECT_1_ADDR__MASK; +} + +#define REG_A4XX_CP_EXEC_CS_INDIRECT_2 0x00000002 +#define A4XX_CP_EXEC_CS_INDIRECT_2_LOCALSIZEX__MASK 0x00000ffc +#define A4XX_CP_EXEC_CS_INDIRECT_2_LOCALSIZEX__SHIFT 2 +static inline uint32_t A4XX_CP_EXEC_CS_INDIRECT_2_LOCALSIZEX(uint32_t val) +{ + return ((val) << A4XX_CP_EXEC_CS_INDIRECT_2_LOCALSIZEX__SHIFT) & A4XX_CP_EXEC_CS_INDIRECT_2_LOCALSIZEX__MASK; +} +#define A4XX_CP_EXEC_CS_INDIRECT_2_LOCALSIZEY__MASK 0x003ff000 +#define A4XX_CP_EXEC_CS_INDIRECT_2_LOCALSIZEY__SHIFT 12 +static inline uint32_t A4XX_CP_EXEC_CS_INDIRECT_2_LOCALSIZEY(uint32_t val) +{ + return ((val) << A4XX_CP_EXEC_CS_INDIRECT_2_LOCALSIZEY__SHIFT) & A4XX_CP_EXEC_CS_INDIRECT_2_LOCALSIZEY__MASK; +} +#define A4XX_CP_EXEC_CS_INDIRECT_2_LOCALSIZEZ__MASK 0xffc00000 +#define A4XX_CP_EXEC_CS_INDIRECT_2_LOCALSIZEZ__SHIFT 22 +static inline uint32_t A4XX_CP_EXEC_CS_INDIRECT_2_LOCALSIZEZ(uint32_t val) +{ + return ((val) << A4XX_CP_EXEC_CS_INDIRECT_2_LOCALSIZEZ__SHIFT) & A4XX_CP_EXEC_CS_INDIRECT_2_LOCALSIZEZ__MASK; +} + + +#define REG_A5XX_CP_EXEC_CS_INDIRECT_1 0x00000001 +#define A5XX_CP_EXEC_CS_INDIRECT_1_ADDR_LO__MASK 0xffffffff +#define A5XX_CP_EXEC_CS_INDIRECT_1_ADDR_LO__SHIFT 0 +static inline uint32_t A5XX_CP_EXEC_CS_INDIRECT_1_ADDR_LO(uint32_t val) +{ + return ((val) << A5XX_CP_EXEC_CS_INDIRECT_1_ADDR_LO__SHIFT) & A5XX_CP_EXEC_CS_INDIRECT_1_ADDR_LO__MASK; +} + +#define REG_A5XX_CP_EXEC_CS_INDIRECT_2 0x00000002 +#define A5XX_CP_EXEC_CS_INDIRECT_2_ADDR_HI__MASK 0xffffffff +#define A5XX_CP_EXEC_CS_INDIRECT_2_ADDR_HI__SHIFT 0 +static inline uint32_t A5XX_CP_EXEC_CS_INDIRECT_2_ADDR_HI(uint32_t val) +{ + return ((val) << A5XX_CP_EXEC_CS_INDIRECT_2_ADDR_HI__SHIFT) & A5XX_CP_EXEC_CS_INDIRECT_2_ADDR_HI__MASK; +} + +#define REG_A5XX_CP_EXEC_CS_INDIRECT_3 0x00000003 +#define A5XX_CP_EXEC_CS_INDIRECT_3_LOCALSIZEX__MASK 0x00000ffc +#define A5XX_CP_EXEC_CS_INDIRECT_3_LOCALSIZEX__SHIFT 2 +static inline uint32_t A5XX_CP_EXEC_CS_INDIRECT_3_LOCALSIZEX(uint32_t val) +{ + return ((val) << A5XX_CP_EXEC_CS_INDIRECT_3_LOCALSIZEX__SHIFT) & A5XX_CP_EXEC_CS_INDIRECT_3_LOCALSIZEX__MASK; +} +#define A5XX_CP_EXEC_CS_INDIRECT_3_LOCALSIZEY__MASK 0x003ff000 +#define A5XX_CP_EXEC_CS_INDIRECT_3_LOCALSIZEY__SHIFT 12 +static inline uint32_t A5XX_CP_EXEC_CS_INDIRECT_3_LOCALSIZEY(uint32_t val) +{ + return ((val) << A5XX_CP_EXEC_CS_INDIRECT_3_LOCALSIZEY__SHIFT) & A5XX_CP_EXEC_CS_INDIRECT_3_LOCALSIZEY__MASK; +} +#define A5XX_CP_EXEC_CS_INDIRECT_3_LOCALSIZEZ__MASK 0xffc00000 +#define A5XX_CP_EXEC_CS_INDIRECT_3_LOCALSIZEZ__SHIFT 22 +static inline uint32_t A5XX_CP_EXEC_CS_INDIRECT_3_LOCALSIZEZ(uint32_t val) +{ + return ((val) << A5XX_CP_EXEC_CS_INDIRECT_3_LOCALSIZEZ__SHIFT) & A5XX_CP_EXEC_CS_INDIRECT_3_LOCALSIZEZ__MASK; +} + + +#endif /* ADRENO_PM4_XML */ diff --git a/selfdrive/modeld/thneed/debug/include/adreno_pm4types.h b/selfdrive/modeld/thneed/debug/include/adreno_pm4types.h new file mode 100644 index 0000000000..aefffdd577 --- /dev/null +++ b/selfdrive/modeld/thneed/debug/include/adreno_pm4types.h @@ -0,0 +1,473 @@ +/* Copyright (c) 2002,2007-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef __ADRENO_PM4TYPES_H +#define __ADRENO_PM4TYPES_H + +//#include "adreno.h" + +#define CP_PKT_MASK 0xc0000000 + +#define CP_TYPE0_PKT ((unsigned int)0 << 30) +#define CP_TYPE3_PKT ((unsigned int)3 << 30) +#define CP_TYPE4_PKT ((unsigned int)4 << 28) +#define CP_TYPE7_PKT ((unsigned int)7 << 28) + +#define PM4_TYPE4_PKT_SIZE_MAX 128 + +/* type3 packets */ + +/* Enable preemption flag */ +#define CP_PREEMPT_ENABLE 0x1C +/* Preemption token command on which preemption occurs */ +#define CP_PREEMPT_TOKEN 0x1E +/* Bit to set in CP_PREEMPT_TOKEN ordinal for interrupt on preemption */ +#define CP_PREEMPT_ORDINAL_INTERRUPT 24 +/* copy from ME scratch RAM to a register */ +#define CP_SCRATCH_TO_REG 0x4d + +/* Copy from REG to ME scratch RAM */ +#define CP_REG_TO_SCRATCH 0x4a + +/* Wait for memory writes to complete */ +#define CP_WAIT_MEM_WRITES 0x12 + +/* Conditional execution based on register comparison */ +#define CP_COND_REG_EXEC 0x47 + +/* Memory to REG copy */ +#define CP_MEM_TO_REG 0x42 + +/* initialize CP's micro-engine */ +#define CP_ME_INIT 0x48 + +/* skip N 32-bit words to get to the next packet */ +#define CP_NOP 0x10 + +/* indirect buffer dispatch. same as IB, but init is pipelined */ +#define CP_INDIRECT_BUFFER_PFD 0x37 + +/* wait for the IDLE state of the engine */ +#define CP_WAIT_FOR_IDLE 0x26 + +/* wait until a register or memory location is a specific value */ +#define CP_WAIT_REG_MEM 0x3c + +/* wait until a register location is equal to a specific value */ +#define CP_WAIT_REG_EQ 0x52 + +/* switches SMMU pagetable, used on a5xx only */ +#define CP_SMMU_TABLE_UPDATE 0x53 + +/* wait until a read completes */ +#define CP_WAIT_UNTIL_READ 0x5c + +/* wait until all base/size writes from an IB_PFD packet have completed */ +#define CP_WAIT_IB_PFD_COMPLETE 0x5d + +/* register read/modify/write */ +#define CP_REG_RMW 0x21 + +/* Set binning configuration registers */ +#define CP_SET_BIN_DATA 0x2f + +/* reads register in chip and writes to memory */ +#define CP_REG_TO_MEM 0x3e + +/* write N 32-bit words to memory */ +#define CP_MEM_WRITE 0x3d + +/* write CP_PROG_COUNTER value to memory */ +#define CP_MEM_WRITE_CNTR 0x4f + +/* conditional execution of a sequence of packets */ +#define CP_COND_EXEC 0x44 + +/* conditional write to memory or register */ +#define CP_COND_WRITE 0x45 + +/* generate an event that creates a write to memory when completed */ +#define CP_EVENT_WRITE 0x46 + +/* generate a VS|PS_done event */ +#define CP_EVENT_WRITE_SHD 0x58 + +/* generate a cache flush done event */ +#define CP_EVENT_WRITE_CFL 0x59 + +/* generate a z_pass done event */ +#define CP_EVENT_WRITE_ZPD 0x5b + + +/* initiate fetch of index buffer and draw */ +#define CP_DRAW_INDX 0x22 + +/* draw using supplied indices in packet */ +#define CP_DRAW_INDX_2 0x36 + +/* initiate fetch of index buffer and binIDs and draw */ +#define CP_DRAW_INDX_BIN 0x34 + +/* initiate fetch of bin IDs and draw using supplied indices */ +#define CP_DRAW_INDX_2_BIN 0x35 + +/* New draw packets defined for A4XX */ +#define CP_DRAW_INDX_OFFSET 0x38 +#define CP_DRAW_INDIRECT 0x28 +#define CP_DRAW_INDX_INDIRECT 0x29 +#define CP_DRAW_AUTO 0x24 + +/* begin/end initiator for viz query extent processing */ +#define CP_VIZ_QUERY 0x23 + +/* fetch state sub-blocks and initiate shader code DMAs */ +#define CP_SET_STATE 0x25 + +/* load constant into chip and to memory */ +#define CP_SET_CONSTANT 0x2d + +/* load sequencer instruction memory (pointer-based) */ +#define CP_IM_LOAD 0x27 + +/* load sequencer instruction memory (code embedded in packet) */ +#define CP_IM_LOAD_IMMEDIATE 0x2b + +/* load constants from a location in memory */ +#define CP_LOAD_CONSTANT_CONTEXT 0x2e + +/* selective invalidation of state pointers */ +#define CP_INVALIDATE_STATE 0x3b + + +/* dynamically changes shader instruction memory partition */ +#define CP_SET_SHADER_BASES 0x4A + +/* sets the 64-bit BIN_MASK register in the PFP */ +#define CP_SET_BIN_MASK 0x50 + +/* sets the 64-bit BIN_SELECT register in the PFP */ +#define CP_SET_BIN_SELECT 0x51 + + +/* updates the current context, if needed */ +#define CP_CONTEXT_UPDATE 0x5e + +/* generate interrupt from the command stream */ +#define CP_INTERRUPT 0x40 + +/* A5XX Enable yield in RB only */ +#define CP_YIELD_ENABLE 0x1C + +/* Enable/Disable/Defer A5x global preemption model */ +#define CP_PREEMPT_ENABLE_GLOBAL 0x69 + +/* Enable/Disable A5x local preemption model */ +#define CP_PREEMPT_ENABLE_LOCAL 0x6A + +/* Yeild token on a5xx similar to CP_PREEMPT on a4xx */ +#define CP_CONTEXT_SWITCH_YIELD 0x6B + +/* Inform CP about current render mode (needed for a5xx preemption) */ +#define CP_SET_RENDER_MODE 0x6C + +/* copy sequencer instruction memory to system memory */ +#define CP_IM_STORE 0x2c + +/* test 2 memory locations to dword values specified */ +#define CP_TEST_TWO_MEMS 0x71 + +/* Write register, ignoring context state for context sensitive registers */ +#define CP_REG_WR_NO_CTXT 0x78 + +/* + * for A4xx + * Write to register with address that does not fit into type-0 pkt + */ +#define CP_WIDE_REG_WRITE 0x74 + + +/* PFP waits until the FIFO between the PFP and the ME is empty */ +#define CP_WAIT_FOR_ME 0x13 + +/* Record the real-time when this packet is processed by PFP */ +#define CP_RECORD_PFP_TIMESTAMP 0x11 + +#define CP_SET_PROTECTED_MODE 0x5f /* sets the register protection mode */ + +/* Used to switch GPU between secure and non-secure modes */ +#define CP_SET_SECURE_MODE 0x66 + +#define CP_BOOTSTRAP_UCODE 0x6f /* bootstraps microcode */ + +/* + * for a3xx + */ + +#define CP_LOAD_STATE 0x30 /* load high level sequencer command */ + +/* Conditionally load a IB based on a flag */ +#define CP_COND_INDIRECT_BUFFER_PFE 0x3A /* prefetch enabled */ +#define CP_COND_INDIRECT_BUFFER_PFD 0x32 /* prefetch disabled */ + +/* Load a buffer with pre-fetch enabled */ +#define CP_INDIRECT_BUFFER_PFE 0x3F + +#define CP_EXEC_CL 0x31 + +/* (A4x) save PM4 stream pointers to execute upon a visible draw */ +#define CP_SET_DRAW_STATE 0x43 + +#define CP_LOADSTATE_DSTOFFSET_SHIFT 0x00000000 +#define CP_LOADSTATE_STATESRC_SHIFT 0x00000010 +#define CP_LOADSTATE_STATEBLOCKID_SHIFT 0x00000013 +#define CP_LOADSTATE_NUMOFUNITS_SHIFT 0x00000016 +#define CP_LOADSTATE_STATETYPE_SHIFT 0x00000000 +#define CP_LOADSTATE_EXTSRCADDR_SHIFT 0x00000002 + +static inline uint pm4_calc_odd_parity_bit(uint val) +{ + return (0x9669 >> (0xf & ((val) ^ + ((val) >> 4) ^ ((val) >> 8) ^ ((val) >> 12) ^ + ((val) >> 16) ^ ((val) >> 20) ^ ((val) >> 24) ^ + ((val) >> 28)))) & 1; +} + +/* + * PM4 packet header functions + * For all the packet functions the passed in count should be the size of the + * payload excluding the header + */ +static inline uint cp_type0_packet(uint regindx, uint cnt) +{ + return CP_TYPE0_PKT | ((cnt-1) << 16) | ((regindx) & 0x7FFF); +} + +static inline uint cp_type3_packet(uint opcode, uint cnt) +{ + return CP_TYPE3_PKT | ((cnt-1) << 16) | (((opcode) & 0xFF) << 8); +} + +static inline uint cp_type4_packet(uint opcode, uint cnt) +{ + return CP_TYPE4_PKT | ((cnt) << 0) | + (pm4_calc_odd_parity_bit(cnt) << 7) | + (((opcode) & 0x3FFFF) << 8) | + ((pm4_calc_odd_parity_bit(opcode) << 27)); +} + +static inline uint cp_type7_packet(uint opcode, uint cnt) +{ + return CP_TYPE7_PKT | ((cnt) << 0) | + (pm4_calc_odd_parity_bit(cnt) << 15) | + (((opcode) & 0x7F) << 16) | + ((pm4_calc_odd_parity_bit(opcode) << 23)); + +} + +#define pkt_is_type0(pkt) (((pkt) & 0XC0000000) == CP_TYPE0_PKT) + +#define type0_pkt_size(pkt) ((((pkt) >> 16) & 0x3FFF) + 1) +#define type0_pkt_offset(pkt) ((pkt) & 0x7FFF) + +/* + * Check both for the type3 opcode and make sure that the reserved bits [1:7] + * and 15 are 0 + */ + +#define pkt_is_type3(pkt) \ + ((((pkt) & 0xC0000000) == CP_TYPE3_PKT) && \ + (((pkt) & 0x80FE) == 0)) + +#define cp_type3_opcode(pkt) (((pkt) >> 8) & 0xFF) +#define type3_pkt_size(pkt) ((((pkt) >> 16) & 0x3FFF) + 1) + +#define pkt_is_type4(pkt) \ + ((((pkt) & 0xF0000000) == CP_TYPE4_PKT) && \ + ((((pkt) >> 27) & 0x1) == \ + pm4_calc_odd_parity_bit(cp_type4_base_index_one_reg_wr(pkt))) \ + && ((((pkt) >> 7) & 0x1) == \ + pm4_calc_odd_parity_bit(type4_pkt_size(pkt)))) + +#define cp_type4_base_index_one_reg_wr(pkt) (((pkt) >> 8) & 0x7FFFF) +#define type4_pkt_size(pkt) ((pkt) & 0x7F) + +#define pkt_is_type7(pkt) \ + ((((pkt) & 0xF0000000) == CP_TYPE7_PKT) && \ + (((pkt) & 0x0F000000) == 0) && \ + ((((pkt) >> 23) & 0x1) == \ + pm4_calc_odd_parity_bit(cp_type7_opcode(pkt))) \ + && ((((pkt) >> 15) & 0x1) == \ + pm4_calc_odd_parity_bit(type7_pkt_size(pkt)))) + +#define cp_type7_opcode(pkt) (((pkt) >> 16) & 0x7F) +#define type7_pkt_size(pkt) ((pkt) & 0x3FFF) + +/* dword base address of the GFX decode space */ +#define SUBBLOCK_OFFSET(reg) ((unsigned int)((reg) - (0x2000))) + +/* gmem command buffer length */ +#define CP_REG(reg) ((0x4 << 16) | (SUBBLOCK_OFFSET(reg))) + +// add these +#define ADRENO_GPUREV(x) 530 +#define lower_32_bits(n) ((uint32_t)(n)) +#define upper_32_bits(n) ((uint32_t)(((n) >> 16) >> 16)) + +/* Return true if the hardware uses the legacy (A4XX and older) PM4 format */ +#define ADRENO_LEGACY_PM4(_d) (ADRENO_GPUREV(_d) < 500) + +/** + * cp_packet - Generic CP packet to support different opcodes on + * different GPU cores. + * @adreno_dev: The adreno device + * @opcode: Operation for cp packet + * @size: size for cp packet + */ +static inline uint cp_packet(struct adreno_device *adreno_dev, + int opcode, uint size) +{ + if (ADRENO_LEGACY_PM4(adreno_dev)) + return cp_type3_packet(opcode, size); + + return cp_type7_packet(opcode, size); +} + +/** + * cp_mem_packet - Generic CP memory packet to support different + * opcodes on different GPU cores. + * @adreno_dev: The adreno device + * @opcode: mem operation for cp packet + * @size: size for cp packet + * @num_mem: num of mem access + */ +static inline uint cp_mem_packet(struct adreno_device *adreno_dev, + int opcode, uint size, uint num_mem) +{ + if (ADRENO_LEGACY_PM4(adreno_dev)) + return cp_type3_packet(opcode, size); + + return cp_type7_packet(opcode, size + num_mem); +} + +/* Return 1 if the command is an indirect buffer of any kind */ +static inline int adreno_cmd_is_ib(struct adreno_device *adreno_dev, + unsigned int cmd) +{ + return cmd == cp_mem_packet(adreno_dev, + CP_INDIRECT_BUFFER_PFE, 2, 1) || + cmd == cp_mem_packet(adreno_dev, + CP_INDIRECT_BUFFER_PFD, 2, 1) || + cmd == cp_mem_packet(adreno_dev, + CP_COND_INDIRECT_BUFFER_PFE, 2, 1) || + cmd == cp_mem_packet(adreno_dev, + CP_COND_INDIRECT_BUFFER_PFD, 2, 1); +} + +/** + * cp_gpuaddr - Generic function to add 64bit and 32bit gpuaddr + * to pm4 commands + * @adreno_dev: The adreno device + * @cmds: command pointer to add gpuaddr + * @gpuaddr: gpuaddr to add + */ +static inline uint cp_gpuaddr(struct adreno_device *adreno_dev, + uint *cmds, uint64_t gpuaddr) +{ + uint *start = cmds; + + if (ADRENO_LEGACY_PM4(adreno_dev)) + *cmds++ = (uint)gpuaddr; + else { + *cmds++ = lower_32_bits(gpuaddr); + *cmds++ = upper_32_bits(gpuaddr); + } + return cmds - start; +} + +/** + * cp_register - Generic function for gpu register operation + * @adreno_dev: The adreno device + * @reg: GPU register + * @size: count for PM4 operation + */ +static inline uint cp_register(struct adreno_device *adreno_dev, + unsigned int reg, unsigned int size) +{ + if (ADRENO_LEGACY_PM4(adreno_dev)) + return cp_type0_packet(reg, size); + + return cp_type4_packet(reg, size); +} + +/** + * cp_wait_for_me - common function for WAIT_FOR_ME + * @adreno_dev: The adreno device + * @cmds: command pointer to add gpuaddr + */ +static inline uint cp_wait_for_me(struct adreno_device *adreno_dev, + uint *cmds) +{ + uint *start = cmds; + + if (ADRENO_LEGACY_PM4(adreno_dev)) { + *cmds++ = cp_type3_packet(CP_WAIT_FOR_ME, 1); + *cmds++ = 0; + } else + *cmds++ = cp_type7_packet(CP_WAIT_FOR_ME, 0); + + return cmds - start; +} + +/** + * cp_wait_for_idle - common function for WAIT_FOR_IDLE + * @adreno_dev: The adreno device + * @cmds: command pointer to add gpuaddr + */ +static inline uint cp_wait_for_idle(struct adreno_device *adreno_dev, + uint *cmds) +{ + uint *start = cmds; + + if (ADRENO_LEGACY_PM4(adreno_dev)) { + *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1); + *cmds++ = 0; + } else + *cmds++ = cp_type7_packet(CP_WAIT_FOR_IDLE, 0); + + return cmds - start; +} + +/** + * cp_invalidate_state - common function for invalidating cp + * state + * @adreno_dev: The adreno device + * @cmds: command pointer to add gpuaddr + */ +static inline uint cp_invalidate_state(struct adreno_device *adreno_dev, + uint *cmds) +{ + uint *start = cmds; + + if (ADRENO_GPUREV(adreno_dev) < 500) { + *cmds++ = cp_type3_packet(CP_INVALIDATE_STATE, 1); + *cmds++ = 0x7fff; + } else { + *cmds++ = cp_type7_packet(CP_SET_DRAW_STATE, 3); + *cmds++ = 0x40000; + *cmds++ = 0; + *cmds++ = 0; + } + + return cmds - start; +} + +#endif /* __ADRENO_PM4TYPES_H */ diff --git a/selfdrive/modeld/thneed/debug/main.cc b/selfdrive/modeld/thneed/debug/main.cc new file mode 100644 index 0000000000..cf96c61e39 --- /dev/null +++ b/selfdrive/modeld/thneed/debug/main.cc @@ -0,0 +1,724 @@ +#include +#include "include/msm_kgsl.h" +#include "common/clutil.h" +#include +#include +#include +#include +#include + +int run_num = 0; +int ioctl_num = 0; + +void hexdump(uint32_t *d, int len) { + assert((len%4) == 0); + printf(" dumping %p len 0x%x\n", d, len); + for (int i = 0; i < len/4; i++) { + if (i != 0 && (i%0x10) == 0) printf("\n"); + printf("%8x ", d[i]); + } + printf("\n"); +} + +void hexdump8(uint8_t *d, int len) { + printf(" dumping %p len 0x%x\n", d, len); + for (int i = 0; i < len; i++) { + if (i != 0 && (i%0x10) == 0) printf("\n"); + printf("%02x ", d[i]); + } + printf("\n"); +} + + +#include +#include +#include +using namespace std; + +#include "disasm/include/adreno_pm4types.h" + +#define REG_A5XX_TPL1_CS_TEX_CONST_LO 0x0000e760 +#define REG_A5XX_TPL1_CS_TEX_SAMP_LO 0x0000e75c + +class CachedCommand { + public: + CachedCommand(struct kgsl_gpu_command *cmd, int lfd); + void exec(bool wait); + private: + string cmd_0, cmd_1; + int obj_len; + int fd; + + struct kgsl_gpu_command cache; + struct kgsl_command_object cmds[2]; + struct kgsl_command_object objs[1]; +}; + +vector queue_cmds; + +void disassemble(uint32_t *src, int len) { + int i = 0; + while (i < len) { + int pktsize; + int pkttype = -1; + + if (pkt_is_type0(src[i])) { + pkttype = 0; + pktsize = type0_pkt_size(src[i]); + } else if (pkt_is_type3(src[i])) { + pkttype = 3; + pktsize = type3_pkt_size(src[i]); + } else if (pkt_is_type4(src[i])) { + pkttype = 4; + pktsize = type4_pkt_size(src[i]); + } else if (pkt_is_type7(src[i])) { + pkttype = 7; + pktsize = type7_pkt_size(src[i]); + } + printf("%3d: type:%d size:%d ", i, pkttype, pktsize); + + if (pkttype == 7) { + printf("op: %4x ", cp_type7_opcode(src[i])); + } + + if (pkttype == 4) { + printf("reg: %4x ", cp_type4_base_index_one_reg_wr(src[i])); + } + + for (int j = 0; j < pktsize+1; j++) { + printf("%8.8X ", src[i+j]); + } + printf("\n"); + + if (pkttype == 7 && cp_type7_opcode(src[i]) == CP_LOAD_STATE) { + // CP_LOAD_STATE4 + int sz = (src[i+1] & 0xffc00000) >> 22; + uint64_t addr = (uint64_t)(src[i+2] & 0xfffffffc) | ((uint64_t)(src[i+3]) << 32); + hexdump((uint32_t *)addr, sz*4); + } + + if (pkttype == 4 && cp_type4_base_index_one_reg_wr(src[i]) == REG_A5XX_TPL1_CS_TEX_CONST_LO) { + uint64_t addr = (uint64_t)(src[i+1] & 0xffffffff) | ((uint64_t)(src[i+2]) << 32); + hexdump((uint32_t *)addr, 0x40); + } + + if (pkttype == 4 && cp_type4_base_index_one_reg_wr(src[i]) == REG_A5XX_TPL1_CS_TEX_SAMP_LO) { + uint64_t addr = (uint64_t)(src[i+1] & 0xffffffff) | ((uint64_t)(src[i+2]) << 32); + hexdump((uint32_t *)addr, 0x40); + } + + if (pkttype == -1) break; + i += (1+pktsize); + } + assert(i == len); + +} + +int intercept = 1; +int prop_num = 0; + +extern "C" { + +/*void *gsl_memory_alloc_pure(long param_1, long param_2, long *param_3) { + void *(*my_gsl_memory_alloc_pure)(long param_1, long param_2, long *param_3); + my_gsl_memory_alloc_pure = reinterpret_cast(dlsym(RTLD_NEXT, "gsl_memory_alloc_pure")); + + void *ret = my_gsl_memory_alloc_pure(param_1, param_2, param_3); + printf("gsl_memory_alloc_pure: 0x%lx 0x%lx %p = %p\n", param_1, param_2, param_3, ret); + return ret; +}*/ + +void *mmap64(void *addr, size_t len, int prot, int flags, int fildes, off64_t off) { + void *(*my_mmap64)(void *addr, size_t len, int prot, int flags, int fildes, off64_t off); + my_mmap64 = reinterpret_cast(dlsym(RTLD_NEXT, "mmap64")); + + void *ret = my_mmap64(addr, len, prot, flags, fildes, off); + + if (fildes == 3) { + printf("mmap64(addr=%p, len=0x%zx, prot=0x%x, flags=0x%x, fildes=%d, off=0x%lx) = %p\n", addr, len, prot, flags, fildes, off, ret); + } + + return ret; +} + + +pid_t gettid(void); + +#undef ioctl +int ioctl(int filedes, unsigned long request, void *argp) { + int (*my_ioctl)(int filedes, unsigned long request, void *argp); + my_ioctl = reinterpret_cast(dlsym(RTLD_NEXT, "ioctl")); + int skip = 0; + +if (intercept) { + + int tid = gettid(); + + if (request == IOCTL_KGSL_GPU_COMMAND) { + struct kgsl_gpu_command *cmd = (struct kgsl_gpu_command *)argp; + printf("IOCTL_KGSL_GPU_COMMAND(%d): flags: 0x%lx numcmds: %u numobjs: %u numsyncs: %u context_id: %u timestamp: %u\n", + tid, + cmd->flags, + cmd->numcmds, cmd->numobjs, cmd->numsyncs, + cmd->context_id, cmd->timestamp); + + assert(cmd->numcmds == 2); + assert(cmd->numobjs == 1); + assert(cmd->numsyncs == 0); + + //struct kgsl_command_object *obj = (struct kgsl_command_object *)cmd->cmdlist; + //assert(obj[0].size == sizeof(queue_init)); + //memcpy(queue_init, (void*)obj[0].gpuaddr, sizeof(queue_init)); + //string qcmd((char*)obj[1].gpuaddr, obj[1].size); + if (run_num == 3) { + CachedCommand *ccmd = new CachedCommand(cmd, filedes); + queue_cmds.push_back(ccmd); + + //ccmd->exec(); + + //skip = 0; + //printf("command 0x%lx\n", obj[1].gpuaddr); + //disassemble((uint32_t *)qcmd.data(), qcmd.size()/4); + //queue_cmds.push_back(qcmd); + } + + #ifdef DUMP + char tmp[0x100]; + snprintf(tmp, sizeof(tmp), "/tmp/thneed/run_%d_%d", run_num, ioctl_num++); + FILE *f = fopen(tmp, "wb"); + #endif + + // kgsl_cmdbatch_add_cmdlist + for (int i = 0; i < cmd->numcmds; i++) { + struct kgsl_command_object *obj = (struct kgsl_command_object *)cmd->cmdlist; + printf(" cmd: %lx %5lx %5lx flags:%3x %d\n", + obj[i].offset, obj[i].gpuaddr, obj[i].size, obj[i].flags, obj[i].id); + //hexdump((uint32_t *)obj[i].gpuaddr, obj[i].size); + #ifdef DUMP + fwrite(&obj[i].size, sizeof(obj[i].size), 1, f); + fwrite((void*)obj[i].gpuaddr, obj[i].size, 1, f); + #endif + } + + // kgsl_cmdbatch_add_memlist + for (int i = 0; i < cmd->numobjs; i++) { + struct kgsl_command_object *obj = (struct kgsl_command_object *)cmd->objlist; + printf(" obj: %lx %5lx %5lx flags:%3x %d\n", + obj[i].offset, obj[i].gpuaddr, obj[i].size, obj[i].flags, obj[i].id); + //hexdump((uint32_t *)obj[i].gpuaddr, obj[i].size); + + #ifdef DUMP + fwrite(&obj[i].size, sizeof(obj[i].size), 1, f); + fwrite((void*)obj[i].gpuaddr, obj[i].size, 1, f); + #endif + } + + #ifdef DUMP + fclose(f); + #endif + + } else if (request == IOCTL_KGSL_SETPROPERTY) { + struct kgsl_device_getproperty *prop = (struct kgsl_device_getproperty *)argp; + printf("IOCTL_KGSL_SETPROPERTY(%d): 0x%x\n", tid, prop->type); + hexdump8((uint8_t*)prop->value, prop->sizebytes); + if (prop_num == 1) { printf("SKIPPING\n"); skip = 1; } + if (run_num == 3) prop_num++; + //hexdump((unsigned char*)prop->value, prop->sizebytes); + } else if (request == IOCTL_KGSL_GPUOBJ_SYNC) { + struct kgsl_gpuobj_sync *cmd = (struct kgsl_gpuobj_sync *)argp; + struct kgsl_gpuobj_sync_obj *objs = (struct kgsl_gpuobj_sync_obj *)(cmd->objs); + + printf("IOCTL_KGSL_GPUOBJ_SYNC(%d) count:%d ", tid, cmd->count); + for (int i = 0; i < cmd->count; i++) { + printf(" -- offset:0x%lx len:0x%lx id:%d op:%d ", objs[i].offset, objs[i].length, objs[i].id, objs[i].op); + } + printf("\n"); + } else if (request == IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID) { + struct kgsl_device_waittimestamp_ctxtid *cmd = (struct kgsl_device_waittimestamp_ctxtid *)argp; + printf("IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID(%d): context_id: %d timestamp: %d timeout: %d\n", + tid, cmd->context_id, cmd->timestamp, cmd->timeout); + } else if (request == IOCTL_KGSL_GPUOBJ_ALLOC) { + struct kgsl_gpuobj_alloc *cmd = (struct kgsl_gpuobj_alloc *)argp; + printf("IOCTL_KGSL_GPUOBJ_ALLOC: size:0x%lx flags:0x%lx va_len:0x%lx ", cmd->size, cmd->flags, cmd->va_len); + } else if (request == IOCTL_KGSL_GPUOBJ_FREE) { + //printf("IOCTL_KGSL_GPUOBJ_FREE\n"); + } else if (filedes == 3) { + printf("ioctl(%d) %lx\n", tid, request); + } + +} + + int ret; + if (skip) { + ret = 0; + } else { + ret = my_ioctl(filedes, request, argp); + } + + if (request == IOCTL_KGSL_GPUOBJ_ALLOC) { + struct kgsl_gpuobj_alloc *cmd = (struct kgsl_gpuobj_alloc *)argp; + printf("mmapsize:0x%lx id:%d metadata_len:%x metadata:0x%lx = %d\n", cmd->mmapsize, cmd->id, cmd->metadata_len, cmd->metadata, ret); + } + + return ret; +} + +} + +#include +#include "../runners/snpemodel.h" +#include +#include + +static inline uint64_t nanos_since_boot() { + struct timespec t; + clock_gettime(CLOCK_BOOTTIME, &t); + return t.tv_sec * 1000000000ULL + t.tv_nsec; +} + +int global_timestamp = -1; +CachedCommand::CachedCommand(struct kgsl_gpu_command *cmd, int lfd) { + fd = lfd; + assert(cmd->numcmds == 2); + assert(cmd->numobjs == 1); + assert(cmd->numsyncs == 0); + + global_timestamp = cmd->timestamp; + + printf("%p %p %p\n", cmd, (void*)cmd->cmdlist, (void*)cmd->objlist); + + memcpy(cmds, (void *)cmd->cmdlist, sizeof(struct kgsl_command_object)*2); + memcpy(objs, (void *)cmd->objlist, sizeof(struct kgsl_command_object)*1); + cmd_0.assign((char*)cmds[0].gpuaddr, cmds[0].size); + cmd_1.assign((char*)cmds[1].gpuaddr, cmds[1].size); + + + memcpy(&cache, cmd, sizeof(cache)); +} + +// i think you get these with cl_a5x_ringbuffer_alloc +uint64_t base = 0; + +void CachedCommand::exec(bool wait) { + printf("old addr 0x%lx ", cmds[1].gpuaddr); + cmds[1].gpuaddr = base; + printf("using addr 0x%lx with size 0x%4lx ", cmds[1].gpuaddr, cmd_1.size()); + base += (cmd_1.size()+0xff) & (~0xFF); + memcpy((void*)cmds[1].gpuaddr, cmd_1.data(), cmd_1.size()); + + // set up other buffers + memcpy((void*)cmds[0].gpuaddr, cmd_0.data(), cmd_0.size()); + memset((void*)objs[0].gpuaddr, 0, objs[0].size); + + cache.timestamp = ++global_timestamp; + cache.cmdlist = (uint64_t)cmds; + cache.objlist = (uint64_t)objs; + + // run + int ret = ioctl(fd, IOCTL_KGSL_GPU_COMMAND, &cache); + + if (wait) { + struct kgsl_device_waittimestamp_ctxtid wait; + wait.context_id = cache.context_id; + wait.timestamp = cache.timestamp; + wait.timeout = -1; + + uint64_t tb = nanos_since_boot(); + int wret = ioctl(fd, IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID, &wait); + uint64_t te = nanos_since_boot(); + + printf("exec %d wait %d after %lu us\n", ret, wret, (te-tb)/1000); + } else { + printf("CachedCommand::exec got %d\n", ret); + } +} + + +int do_print = 0; + +#define TEMPORAL_SIZE 512 +#define DESIRE_LEN 8 +#define TRAFFIC_CONVENTION_LEN 2 + +FILE *f = NULL; + +cl_program clCreateProgramWithSource(cl_context context, cl_uint count, const char **strings, const size_t *lengths, cl_int *errcode_ret) { + cl_program (*my_clCreateProgramWithSource)(cl_context context, cl_uint count, const char **strings, const size_t *lengths, cl_int *errcode_ret) = NULL; + my_clCreateProgramWithSource = reinterpret_cast(dlsym(RTLD_NEXT, "REAL_clCreateProgramWithSource")); + //printf("clCreateProgramWithSource: %d\n", count); + + if (f == NULL) { + f = fopen("/tmp/kernels.cl", "w"); + } + + fprintf(f, "/* ************************ PROGRAM BREAK ****************************/\n"); + for (int i = 0; i < count; i++) { + fprintf(f, "%s\n", strings[i]); + if (i != 0) fprintf(f, "/* ************************ SECTION BREAK ****************************/\n"); + } + fflush(f); + + return my_clCreateProgramWithSource(context, count, strings, lengths, errcode_ret); +} + +map kernels; +map kernel_inputs; +map kernel_outputs; + +cl_kernel clCreateKernel(cl_program program, const char *kernel_name, cl_int *errcode_ret) { + cl_kernel (*my_clCreateKernel)(cl_program program, const char *kernel_name, cl_int *errcode_ret) = NULL; + my_clCreateKernel = reinterpret_cast(dlsym(RTLD_NEXT, "REAL_clCreateKernel")); + cl_kernel ret = my_clCreateKernel(program, kernel_name, errcode_ret); + + printf("clCreateKernel: %s -> %p\n", kernel_name, ret); + kernels.insert(make_pair(ret, kernel_name)); + return ret; +} + +typedef struct image { + size_t image_width; + size_t image_height; + size_t image_row_pitch; + cl_mem buffer; +} image; + +map buffers; +map images; + +cl_int clSetKernelArg(cl_kernel kernel, cl_uint arg_index, size_t arg_size, const void *arg_value) { + cl_int (*my_clSetKernelArg)(cl_kernel kernel, cl_uint arg_index, size_t arg_size, const void *arg_value) = NULL; + my_clSetKernelArg = reinterpret_cast(dlsym(RTLD_NEXT, "REAL_clSetKernelArg")); + + char arg_type[0x100]; + char arg_name[0x100]; + clGetKernelArgInfo(kernel, arg_index, CL_KERNEL_ARG_TYPE_NAME, sizeof(arg_type), arg_type, NULL); + clGetKernelArgInfo(kernel, arg_index, CL_KERNEL_ARG_NAME, sizeof(arg_name), arg_name, NULL); + printf(" %s %s", arg_type, arg_name); + + if (arg_size == 1) { + printf(" = %d", *((char*)arg_value)); + } else if (arg_size == 2) { + printf(" = %d", *((short*)arg_value)); + } else if (arg_size == 4) { + if (strcmp(arg_type, "float") == 0) { + printf(" = %f", *((float*)arg_value)); + } else { + printf(" = %d", *((int*)arg_value)); + } + } else if (arg_size == 8) { + cl_mem val = (cl_mem)(*((uintptr_t*)arg_value)); + printf(" = %p", val); + if (strcmp(arg_name, "input") == 0) kernel_inputs[kernel] = val; + if (strcmp(arg_name, "output") == 0) kernel_outputs[kernel] = val; + if (strcmp(arg_name, "accumulator") == 0) assert(kernel_inputs[kernel] = val); + + if (buffers.find(val) != buffers.end()) { + printf(" buffer %zu", buffers[val]); + } + + if (images.find(val) != images.end()) { + printf(" image %zu x %zu rp %zu @ %p", images[val].image_width, images[val].image_height, images[val].image_row_pitch, images[val].buffer); + } + + } else { + printf(" %zu", arg_size); + } + printf("\n"); + cl_int ret = my_clSetKernelArg(kernel, arg_index, arg_size, arg_value); + return ret; +} + +uint64_t start_time = 0; +uint64_t tns = 0; + +int cnt = 0; + +cl_int clEnqueueNDRangeKernel(cl_command_queue command_queue, + cl_kernel kernel, + cl_uint work_dim, + const size_t *global_work_offset, + const size_t *global_work_size, + const size_t *local_work_size, + cl_uint num_events_in_wait_list, + const cl_event *event_wait_list, + cl_event *event) { + + // SNPE doesn't use these + assert(num_events_in_wait_list == 0); + assert(global_work_offset == NULL); + + cl_int (*my_clEnqueueNDRangeKernel)(cl_command_queue, cl_kernel, cl_uint, const size_t *, const size_t *, const size_t *, cl_uint, const cl_event *, cl_event *) = NULL; + my_clEnqueueNDRangeKernel = reinterpret_cast(dlsym(RTLD_NEXT, "REAL_clEnqueueNDRangeKernel")); + + + uint64_t tb = nanos_since_boot(); + cl_int ret = my_clEnqueueNDRangeKernel(command_queue, kernel, work_dim, + global_work_offset, global_work_size, local_work_size, + num_events_in_wait_list, event_wait_list, event); + uint64_t te = nanos_since_boot(); + + /*ret = clWaitForEvents(1, event); + assert(ret == CL_SUCCESS); + uint64_t tq = nanos_since_boot();*/ + + if (do_print) { + tns += te-tb; + } + + printf("%10lu %10lu running(%3d) -- %p -- %56s -- %p -> %p %s ", (tb-start_time)/1000, (tns/1000), cnt++, kernel, kernels[kernel].c_str(), kernel_inputs[kernel], kernel_outputs[kernel], + (buffers[kernel_outputs[kernel]] != 0) ? "B" : "I"); + + printf("global -- "); + for (int i = 0; i < work_dim; i++) { + printf("%4zu ", global_work_size[i]); + } + printf("local -- "); + for (int i = 0; i < work_dim; i++) { + printf("%4zu ", local_work_size[i]); + } + printf("\n"); + + return ret; +} + + +cl_mem clCreateBuffer(cl_context context, cl_mem_flags flags, size_t size, void *host_ptr, cl_int *errcode_ret) { + cl_mem (*my_clCreateBuffer)(cl_context context, cl_mem_flags flags, size_t size, void *host_ptr, cl_int *errcode_ret) = NULL; + my_clCreateBuffer = reinterpret_cast(dlsym(RTLD_NEXT, "REAL_clCreateBuffer")); + + cl_mem ret = my_clCreateBuffer(context, flags, size, host_ptr, errcode_ret); + buffers[ret] = size; + printf("%p = clCreateBuffer %zu\n", ret, size); + return ret; +} + +cl_mem clCreateImage(cl_context context, cl_mem_flags flags, const cl_image_format *image_format, const cl_image_desc *image_desc, void *host_ptr, cl_int *errcode_ret) { + cl_mem (*my_clCreateImage)(cl_context context, cl_mem_flags flags, const cl_image_format *image_format, const cl_image_desc *image_desc, void *host_ptr, cl_int *errcode_ret) = NULL; + my_clCreateImage = reinterpret_cast(dlsym(RTLD_NEXT, "REAL_clCreateImage")); + + // SNPE only uses this + assert(CL_MEM_OBJECT_IMAGE2D == image_desc->image_type); + + // RGBA, HALF FLOAT + assert(CL_RGBA == image_format->image_channel_order); + assert(CL_HALF_FLOAT == image_format->image_channel_data_type); + + map lc = { + {CL_MEM_OBJECT_BUFFER, "CL_MEM_OBJECT_BUFFER"}, + {CL_MEM_OBJECT_IMAGE2D, "CL_MEM_OBJECT_IMAGE2D"}, // all this one + {CL_MEM_OBJECT_IMAGE3D, "CL_MEM_OBJECT_IMAGE3D"}, + {CL_MEM_OBJECT_IMAGE2D_ARRAY, "CL_MEM_OBJECT_IMAGE2D_ARRAY"}, + {CL_MEM_OBJECT_IMAGE1D, "CL_MEM_OBJECT_IMAGE1D"}, + {CL_MEM_OBJECT_IMAGE1D_ARRAY, "CL_MEM_OBJECT_IMAGE1D_ARRAY"}, + {CL_MEM_OBJECT_IMAGE1D_BUFFER, "CL_MEM_OBJECT_IMAGE1D_BUFFER"}}; + + assert(image_desc->image_depth == 0); + assert(image_desc->image_array_size == 0); + assert(image_desc->image_slice_pitch == 0); + //assert(image_desc->image_width * image_desc->image_height * 2 == image_desc->image_row_pitch); + + image img; + img.image_width = image_desc->image_width; + img.image_height = image_desc->image_height; + img.image_row_pitch = image_desc->image_row_pitch; + img.buffer = image_desc->buffer; + + cl_mem ret = my_clCreateImage(context, flags, image_format, image_desc, host_ptr, errcode_ret); + printf("%p = clCreateImage %s -- %p -- %d %d -- %4zu x %4zu x %4zu -- %4zu %4zu %4zu\n", ret, lc[image_desc->image_type].c_str(), + image_desc->buffer, + image_format->image_channel_order, image_format->image_channel_data_type, + image_desc->image_width, image_desc->image_height, image_desc->image_depth, + image_desc->image_array_size, image_desc->image_row_pitch, image_desc->image_slice_pitch + ); + images[ret] = img; + return ret; +} + +cl_int clWaitForEvents(cl_uint num_events, const cl_event *event_list) { + cl_int (*my_clWaitForEvents)(cl_uint num_events, const cl_event *event_list); + my_clWaitForEvents = reinterpret_cast(dlsym(RTLD_NEXT, "REAL_clWaitForEvents")); + printf("clWaitForEvents\n"); + return my_clWaitForEvents(num_events, event_list); +} + +cl_int clReleaseEvent(cl_event event) { + cl_int (*my_clReleaseEvent)(cl_event event); + my_clReleaseEvent = reinterpret_cast(dlsym(RTLD_NEXT, "REAL_clReleaseEvent")); + printf("clReleaseEvent: %p\n", event); + return my_clReleaseEvent(event); +} + +/*size_t total = 0; + +void *calloc(size_t num, size_t size) { + void *(*my_calloc)(size_t num, size_t size); + my_calloc = reinterpret_cast(dlsym(RTLD_NEXT, "REAL_calloc")); + + void *ret = my_calloc(num, size); + + if (do_print) { + total += num*size; + printf("calloc %p -- total:0x%zx -- num:0x%zx size:0x%zx\n", ret, total, num, size); + } + return ret; +} + +void free(void *ptr) { + void (*my_free)(void *ptr); + my_free = reinterpret_cast(dlsym(RTLD_NEXT, "REAL_free")); + + if (do_print) { + //printf("free: %p\n", ptr); + } else { + my_free(ptr); + } +}*/ + +void *dlsym(void *handle, const char *symbol) { + void *(*my_dlsym)(void *handle, const char *symbol) = (void *(*)(void *handle, const char *symbol))((uintptr_t)dlopen-0x2d4); + if (memcmp("REAL_", symbol, 5) == 0) { + return my_dlsym(handle, symbol+5); + } else if (strcmp("clCreateProgramWithSource", symbol) == 0) { + return (void*)clCreateProgramWithSource; + } else if (strcmp("clCreateKernel", symbol) == 0) { + return (void*)clCreateKernel; + } else if (strcmp("clEnqueueNDRangeKernel", symbol) == 0) { + return (void*)clEnqueueNDRangeKernel; + } else if (strcmp("clSetKernelArg", symbol) == 0) { + return (void*)clSetKernelArg; + } else if (strcmp("clCreateBuffer", symbol) == 0) { + return (void*)clCreateBuffer; + } else if (strcmp("clCreateImage", symbol) == 0) { + return (void*)clCreateImage; + /*} else if (strcmp("clReleaseEvent", symbol) == 0) { + return (void*)clReleaseEvent; + } else if (strcmp("clWaitForEvents", symbol) == 0) { + return (void*)clWaitForEvents;*/ + } else { + //printf("dlsym %s\n", symbol); + return my_dlsym(handle, symbol); + } +} + +int main(int argc, char* argv[]) { + int err; + start_time = nanos_since_boot(); + cl_device_id device_id = cl_get_device_id(CL_DEVICE_TYPE_DEFAULT); + cl_uint tmp; + + // sweet this is 64! + err = clGetDeviceInfo(device_id, CL_DEVICE_MAX_WRITE_IMAGE_ARGS, sizeof(tmp), &tmp, NULL); + assert(err == 0); + printf("CL_DEVICE_MAX_WRITE_IMAGE_ARGS: %u\n", tmp); + + err = clGetDeviceInfo(device_id, CL_DEVICE_MAX_READ_IMAGE_ARGS, sizeof(tmp), &tmp, NULL); + assert(err == 0); + printf("CL_DEVICE_MAX_READ_IMAGE_ARGS: %u\n", tmp); + + float *output = (float*)calloc(0x10000, sizeof(float)); + SNPEModel mdl(argv[1], output, 0, USE_GPU_RUNTIME); + + float state[TEMPORAL_SIZE]; + mdl.addRecurrent(state, TEMPORAL_SIZE); + + float desire[DESIRE_LEN]; + mdl.addDesire(desire, DESIRE_LEN); + + float traffic_convention[TRAFFIC_CONVENTION_LEN]; + mdl.addTrafficConvention(traffic_convention, TRAFFIC_CONVENTION_LEN); + + float *input = (float*)calloc(0x1000000, sizeof(float));; + printf("************** execute 1 **************\n"); + printf("%p %p %p %p -> %p\n", input, state, desire, traffic_convention, output); + run_num = 1; ioctl_num = 0; + do_print = 0; + start_time = nanos_since_boot(); + mdl.execute(input, 0); + printf("************** execute 2 **************\n"); + run_num = 2; ioctl_num = 0; + do_print = 0; + mdl.execute(input, 0); + printf("************** execute 3 **************\n"); + run_num = 3; ioctl_num = 0; + + do_print = 1; + start_time = nanos_since_boot(); + mdl.execute(input, 0); + do_print = 0; + + struct kgsl_gpuobj_alloc alloc; + memset(&alloc, 0, sizeof(alloc)); + alloc.size = 0x40000; + alloc.flags = 0x10000a00; + int fd = 3; + int ret = ioctl(fd, IOCTL_KGSL_GPUOBJ_ALLOC, &alloc); + void *addr = mmap64(NULL, alloc.mmapsize, 0x3, 0x1, fd, alloc.id*0x1000); + assert(addr != MAP_FAILED); + + intercept = 0; + while (1) { + printf("************** execute 4 **************\n"); + run_num = 4; + base = (uint64_t)addr; + + uint64_t tb = nanos_since_boot(); + int i = 0; + for (auto it = queue_cmds.begin(); it != queue_cmds.end(); ++it) { + printf("run %2d: ", i++); + //(*it)->exec(i == queue_cmds.size()); + (*it)->exec(true); + } + uint64_t te = nanos_since_boot(); + printf("model exec in %lu us\n", (te-tb)/1000); + + break; + } + + /*FILE *f = fopen("/proc/self/maps", "rb"); + char maps[0x100000]; + int len = fread(maps, 1, sizeof(maps), f); + maps[len] = '\0'; + fclose(f); + printf("%s\n", maps);*/ + + printf("buffers: %lu images: %lu\n", buffers.size(), images.size()); + printf("queues: %lu\n", queue_cmds.size()); + + // IOCTL_KGSL_GPU_COMMAND: flags: 0x11 numcmds: 2 numobjs: 1 numsyncs: 0 context_id: 7 timestamp: 77 + /*int ts = 100; + for (auto it = queue_cmds.begin(); it != queue_cmds.end(); ++it) { + auto qcmd = *it; + //disassemble((uint32_t *)qcmd.data(), qcmd.size()/4); + + struct kgsl_command_object cmdlists[2]; + struct kgsl_command_object objlists; + struct kgsl_gpu_command cmd; + uint8_t objs[0xc0]; + memset(objs, 0, 0xc0); + + memset(&cmd, 0, sizeof(cmd)); + memset(&cmdlists, 0, sizeof(struct kgsl_command_object)*2); + memset(&objlists, 0, sizeof(objlists)); + + cmd.flags = 0x11; + cmd.cmdlist = (uint64_t)cmdlists; + cmd.numcmds = 2; + cmd.objlist = (uint64_t)objlists; + cmd.numobjs = 1; + cmd.numsyncs = 0; + cmd.context_id = 7; + cmd.timestamp = ts++; + + cmdlists[0].gpuaddr = (uint64_t)queue_init; + cmdlists[0].size = 0xbc; + cmdlists[0].flags = 1; + cmdlists[1].gpuaddr = (uint64_t)qcmd.data(); + cmdlists[1].size = qcmd.size(); + cmdlists[1].flags = 1; + + objlists.gpuaddr = (uint64_t)objs; + objlists.size = 0xc0; + objlists.flags = 0x18; + }*/ +} + diff --git a/selfdrive/modeld/thneed/debug/microbenchmark/gemm.cl b/selfdrive/modeld/thneed/debug/microbenchmark/gemm.cl new file mode 100644 index 0000000000..6a55406aee --- /dev/null +++ b/selfdrive/modeld/thneed/debug/microbenchmark/gemm.cl @@ -0,0 +1,51 @@ +// https://github.com/moskewcz/boda/issues/13 + +#define USE_FP16 + +#ifdef USE_FP16 + #define up(x) x + #define down(x) x + #define xtype half8 + #define skip 128 +#else + #define up(x) convert_float8(x) + #define down(x) convert_half8(x) + #define xtype float8 + #define skip 128 +#endif + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable +__kernel void gemm(const int M, const int N, const int K, + global const half8* a, global const half8* b, global half8* c ) +{ + xtype c_r[8] = {0,0,0,0,0,0,0,0}; + + int const a_off_thr = get_global_id(0); + int const b_off_thr = get_global_id(1); + + int a_off = a_off_thr; + int b_off = b_off_thr; + for( int k = 0; k < 1024; k += 1 ) { + xtype a_r = up(a[a_off]); + xtype b_r = up(b[b_off]); + + c_r[0] += a_r.s0*b_r; + c_r[1] += a_r.s1*b_r; + c_r[2] += a_r.s2*b_r; + c_r[3] += a_r.s3*b_r; + c_r[4] += a_r.s4*b_r; + c_r[5] += a_r.s5*b_r; + c_r[6] += a_r.s6*b_r; + c_r[7] += a_r.s7*b_r; + + a_off += skip; + b_off += skip; + } + + int c_off = a_off_thr*1024 + b_off_thr; + for (int i = 0; i < 8; i++) { + c[c_off] = down(c_r[i]); + c_off += skip; + } +} + diff --git a/selfdrive/modeld/thneed/debug/microbenchmark/gemm_image.cl b/selfdrive/modeld/thneed/debug/microbenchmark/gemm_image.cl new file mode 100644 index 0000000000..f466a8ca49 --- /dev/null +++ b/selfdrive/modeld/thneed/debug/microbenchmark/gemm_image.cl @@ -0,0 +1,75 @@ +// https://github.com/moskewcz/boda/issues/13 + +//#define USE_FP16 + +#ifdef USE_FP16 + #define xtype half4 + #define read_imagep read_imageh + #define write_imagep write_imageh +#else + #define xtype float4 + #define read_imagep read_imagef + #define write_imagep write_imagef +#endif + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable +__kernel void gemm(const int M, const int N, const int K, + read_only image2d_t A, + read_only image2d_t B, + write_only image2d_t C) +{ + const sampler_t smp = CLK_NORMALIZED_COORDS_FALSE | + CLK_ADDRESS_CLAMP | + CLK_FILTER_NEAREST; + + xtype c_r[4] = {0,0,0,0}; + xtype a_r[4], b_r[4]; + + int const a_off_thr = get_global_id(0); + int const b_off_thr = get_global_id(1); + + int2 a_samp = {0, a_off_thr}; + int2 b_samp = {0, b_off_thr}; + + for (short k = 0; k < K/4; k++) { + for (short i = 0; i < 4; ++i) { + a_r[i] = read_imagep(A, smp, a_samp); + b_r[i] = read_imagep(B, smp, b_samp); + ++a_samp.x; + ++b_samp.x; + } + + for (short i = 0; i < 4; ++i) { + float4 ov = c_r[i]; + + ov.x += a_r[i].x * b_r[0].x; + ov.x += a_r[i].y * b_r[0].y; + ov.x += a_r[i].z * b_r[0].z; + ov.x += a_r[i].w * b_r[0].w; + + ov.y += a_r[i].x * b_r[1].x; + ov.y += a_r[i].y * b_r[1].y; + ov.y += a_r[i].z * b_r[1].z; + ov.y += a_r[i].w * b_r[1].w; + + ov.z += a_r[i].x * b_r[2].x; + ov.z += a_r[i].y * b_r[2].y; + ov.z += a_r[i].z * b_r[2].z; + ov.z += a_r[i].w * b_r[2].w; + + ov.w += a_r[i].x * b_r[3].x; + ov.w += a_r[i].y * b_r[3].y; + ov.w += a_r[i].z * b_r[3].z; + ov.w += a_r[i].w * b_r[3].w; + + c_r[i] = ov; + } + } + + int2 c_samp = {a_off_thr, b_off_thr*4}; + for (short i = 0; i < 4; i++) { + write_imagep(C, c_samp, c_r[i]); + ++c_samp.y; + } +} + diff --git a/selfdrive/modeld/thneed/debug/microbenchmark/go.c b/selfdrive/modeld/thneed/debug/microbenchmark/go.c new file mode 100644 index 0000000000..18b91a6cb2 --- /dev/null +++ b/selfdrive/modeld/thneed/debug/microbenchmark/go.c @@ -0,0 +1,314 @@ +#include +#include +#include +#include +#include + +/* +block7b_project_conv (Conv2D) (None, 8, 16, 352) 743424 block7b_activation[0][0] +8448*8*4 = 8*16*2112 = 270336 = input = 128*2112 +2112*88*4 = 743424 = weights = 2112*352 +1408*8*4 = 8*16*352 = 45056 = output = 128*352 + +FLOPS = 128*2112*352 = 95158272 = 95 MFLOPS +RAM = 128*2112 + 2112*352 + 128*352 = 1058816 = 1 M accesses + +# 22 groups +128*2112 + 2112*16 + 128*16 = 306176 +306176*22 = 6735872 real accesses + +This is a 128x2112 by 2112x352 matrix multiply + +work_size = {88, 4, 8} +Each kernel run computes 16 outputs + +0x7f7e8a6380 convolution_horizontal_reduced_reads_1x1 -- 88 4 8 -- 4 4 8 + image2d_t input = 0x7f7f490b00 image 8448 x 8 rp 67840 + short startPackedInputChannel = 0 + short numPackedInputChannelsForGroup = 528 + short totalNumPackedInputChannels = 528 + short packedOuputChannelOffset = 0 + short totalNumPackedOutputChannels = 88 + image2d_t weights = 0x7f7f52fb80 image 2112 x 88 rp 16896 + float* biases = 0x7f7f564d80 buffer 1408 + short filterSizeX = 1 + short filterSizeY = 1 + image2d_t output = 0x7f7f490e80 image 1408 x 8 rp 11264 + short paddingX = 0 + short paddingY = 0 + short strideX = 1 + short strideY = 1 + short neuron = 0 + float a = 1.000000 + float b = 1.000000 + float min_clamp = 0.000000 + float max_clamp = 0.000000 + float* parameters = 0x0 + float* batchNormBiases = 0x0 + short numOutputColumns = 16 +*/ + +#define GEMM +#define IMAGE + +void dump_maps() { + FILE *f = fopen("/proc/self/maps", "rb"); + char maps[0x100000]; + int len = fread(maps, 1, sizeof(maps), f); + maps[len] = '\0'; + maps[0x800] = '\0'; + fclose(f); + printf("%s\n", maps); +} + +static inline uint64_t nanos_since_boot() { + struct timespec t; + clock_gettime(CLOCK_BOOTTIME, &t); + return t.tv_sec * 1000000000ULL + t.tv_nsec; +} + +int main(int argc, char *argv[]) { + cl_int err; + + // cl init + cl_device_id device_id; + cl_context context; + cl_command_queue q; + { + cl_platform_id platform_id[2]; + cl_uint num_devices; + cl_uint num_platforms; + + err = clGetPlatformIDs(sizeof(platform_id)/sizeof(cl_platform_id), platform_id, &num_platforms); + assert(err == 0); + + err = clGetDeviceIDs(platform_id[0], CL_DEVICE_TYPE_DEFAULT, 1, &device_id, &num_devices); + assert(err == 0); + + context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &err); + assert(err == 0); + + q = clCreateCommandQueue(context, device_id, 0, &err); + assert(err == 0); + } + printf("cl ready\n"); + + char tmp[0x10000]; + memset(tmp, 0, sizeof(tmp)); + FILE *f = fopen(argv[1], "rb"); + fread(tmp, 1, sizeof(tmp), f); + fclose(f); + + const char *strings[1]; + size_t lengths[1]; + strings[0] = tmp; + lengths[0] = strlen(tmp); + + cl_program prog = clCreateProgramWithSource(context, 1, strings, lengths, &err); + assert(err == 0); + printf("creating program\n"); + + err = clBuildProgram(prog, 1, &device_id, "-D AVANTE_IS_GPU_A530_64", NULL, NULL); + + if (err != 0) { + printf("got err %d\n", err); + size_t length; + char buffer[2048]; + clGetProgramBuildInfo(prog, device_id, CL_PROGRAM_BUILD_LOG, sizeof(buffer), buffer, &length); + buffer[length] = '\0'; + printf("%s\n", buffer); + } + assert(err == 0); + printf("built program\n"); + + +#ifdef GEMM + // 128x2112 by 2112x352 + int M,N,K; + + M = N = K = 1024; + //M = 128; K = 2112; N = 352; + + cl_kernel kern = clCreateKernel(prog, "gemm", &err); + assert(err == 0); + printf("creating kernel %p\n", kern); + + cl_mem A,B,C; + A = clCreateBuffer(context, CL_MEM_READ_WRITE, M*K*2, NULL, &err); + assert(err == 0); + B = clCreateBuffer(context, CL_MEM_READ_WRITE, K*N*2, NULL, &err); + assert(err == 0); + C = clCreateBuffer(context, CL_MEM_READ_WRITE, M*N*2, NULL, &err); + assert(err == 0); + printf("created buffers\n"); + +#ifdef IMAGE + cl_image_format fmt; + fmt.image_channel_order = CL_RGBA; + fmt.image_channel_data_type = CL_HALF_FLOAT; + + cl_image_desc desc; + desc.image_type = CL_MEM_OBJECT_IMAGE2D; + desc.image_depth = 0; desc.image_slice_pitch = 0; desc.num_mip_levels = 0; desc.num_samples = 0; + + desc.image_width = K; desc.image_height = M/4; + desc.buffer = A; + desc.image_row_pitch = desc.image_width*8; + A = clCreateImage(context, CL_MEM_READ_WRITE, &fmt, &desc, NULL, &err); + assert(err == 0); + + desc.image_width = K; desc.image_height = N/4; + desc.buffer = B; desc.image_row_pitch = desc.image_width*8; + B = clCreateImage(context, CL_MEM_READ_WRITE, &fmt, &desc, NULL, &err); + assert(err == 0); + + desc.image_width = M/4; desc.image_height = N; + desc.buffer = C; desc.image_row_pitch = desc.image_width*8; + C = clCreateImage(context, CL_MEM_READ_WRITE, &fmt, &desc, NULL, &err); + assert(err == 0); + printf("created images\n"); +#endif + + clSetKernelArg(kern, 0, sizeof(int), &M); + clSetKernelArg(kern, 1, sizeof(int), &N); + clSetKernelArg(kern, 2, sizeof(int), &K); + + clSetKernelArg(kern, 3, sizeof(cl_mem), &A); + clSetKernelArg(kern, 4, sizeof(cl_mem), &B); + clSetKernelArg(kern, 5, sizeof(cl_mem), &C); + printf("set args\n"); + +#ifdef IMAGE + size_t global_work_size[3] = {M/4, N/4, 1}; + size_t local_work_size[3] = {4, 64, 1}; +#else + size_t global_work_size[3] = {128, 128, 1}; + size_t local_work_size[3] = {2, 128, 1}; +#endif + +#else + cl_kernel kern = clCreateKernel(prog, "convolution_horizontal_reduced_reads_1x1", &err); + assert(err == 0); + printf("creating kernel\n"); + + cl_mem input; + cl_mem weights; + cl_mem weights_buffer; + cl_mem biases; + cl_mem outputs; + + cl_image_format fmt; + fmt.image_channel_order = CL_RGBA; + fmt.image_channel_data_type = CL_HALF_FLOAT; + + cl_image_desc desc; + desc.image_type = CL_MEM_OBJECT_IMAGE2D; + desc.image_depth = 0; desc.image_slice_pitch = 0; desc.num_mip_levels = 0; desc.num_samples = 0; + desc.buffer = NULL; + + biases = clCreateBuffer(context, CL_MEM_READ_WRITE, 1408, NULL, &err); + assert(err == 0); + + desc.image_width = 8448; desc.image_height = 8; desc.image_row_pitch = 67840; + desc.buffer = clCreateBuffer(context, CL_MEM_READ_WRITE, desc.image_height * desc.image_row_pitch, NULL, &err); + assert(err == 0); + input = clCreateImage(context, CL_MEM_READ_WRITE, &fmt, &desc, NULL, &err); + assert(err == 0); + + desc.image_width = 2112; desc.image_height = 88; desc.image_row_pitch = 16896; + weights_buffer = desc.buffer = clCreateBuffer(context, CL_MEM_READ_WRITE, desc.image_height * desc.image_row_pitch, NULL, &err); + assert(err == 0); + weights = clCreateImage(context, CL_MEM_READ_WRITE, &fmt, &desc, NULL, &err); + assert(err == 0); + + desc.image_width = 1408; desc.image_height = 8; desc.image_row_pitch = 11264; + desc.buffer = clCreateBuffer(context, CL_MEM_READ_WRITE, desc.image_height * desc.image_row_pitch, NULL, &err); + assert(err == 0); + outputs = clCreateImage(context, CL_MEM_READ_WRITE, &fmt, &desc, NULL, &err); + assert(err == 0); + + void *n = NULL; + uint16_t v; + float fl; + + clSetKernelArg(kern, 0, sizeof(cl_mem), &input); + v = 0; clSetKernelArg(kern, 1, sizeof(v), &v); + v = 528; clSetKernelArg(kern, 2, sizeof(v), &v); + v = 528; clSetKernelArg(kern, 3, sizeof(v), &v); + v = 0; clSetKernelArg(kern, 4, sizeof(v), &v); + v = 88; clSetKernelArg(kern, 5, sizeof(v), &v); + clSetKernelArg(kern, 6, sizeof(cl_mem), &weights); + //clSetKernelArg(kern, 6, sizeof(cl_mem), &weights_buffer); + clSetKernelArg(kern, 7, sizeof(cl_mem), &biases); + v = 1; clSetKernelArg(kern, 8, sizeof(v), &v); + v = 1; clSetKernelArg(kern, 9, sizeof(v), &v); + clSetKernelArg(kern, 10, sizeof(cl_mem), &outputs); + v = 0; clSetKernelArg(kern, 11, sizeof(v), &v); + v = 0; clSetKernelArg(kern, 12, sizeof(v), &v); + v = 1; clSetKernelArg(kern, 13, sizeof(v), &v); + v = 1; clSetKernelArg(kern, 14, sizeof(v), &v); + v = 0; clSetKernelArg(kern, 15, sizeof(v), &v); + fl = 1.0; clSetKernelArg(kern, 16, sizeof(fl), &fl); + fl = 0.0; clSetKernelArg(kern, 17, sizeof(fl), &fl); + fl = 0.0; clSetKernelArg(kern, 18, sizeof(fl), &fl); + fl = 0.0; clSetKernelArg(kern, 19, sizeof(fl), &fl); + clSetKernelArg(kern, 20, sizeof(n), &n); + clSetKernelArg(kern, 21, sizeof(n), &n); + v = 16; clSetKernelArg(kern, 22, sizeof(v), &v); + + size_t global_work_size[3] = {88, 4, 8}; + size_t local_work_size[3] = {4, 4, 8}; +#endif + + printf("ready to enqueue\n"); + for (int i = 0; i < 20; i++) { + cl_event event; + err = clEnqueueNDRangeKernel(q, kern, 3, NULL, global_work_size, local_work_size, 0, NULL, &event); + assert(err == 0); + + uint64_t tb = nanos_since_boot(); + err = clWaitForEvents(1, &event); + assert(err == 0); + uint64_t te = nanos_since_boot(); + uint64_t us = (te-tb)/1000; + + float s = 1000000.0/us; + +#ifdef GEMM + float flops = M*N*K*s; + float rams = (M*N + N*K + M*K)*s; +#else + float flops = 95158272.0*s; + float rams = 1058816.0*s; + //float rams = 6735872.0*s; +#endif + + printf("%2d: wait %lu us -- %.2f GFLOPS -- %.2f GB/s\n", i, us, flops/1e9, rams*2/1e9); + } + + size_t binary_size = 0; + err = clGetProgramInfo(prog, CL_PROGRAM_BINARY_SIZES, sizeof(binary_size), &binary_size, NULL); + assert(err == 0); + assert(binary_size > 0); + + uint8_t *binary_buf = (uint8_t *)malloc(binary_size); + assert(binary_buf); + + uint8_t* bufs[1] = { binary_buf, }; + err = clGetProgramInfo(prog, CL_PROGRAM_BINARIES, sizeof(bufs), &bufs, NULL); + assert(err == 0); + + FILE *g = fopen("/tmp/bin.bin", "wb"); + fwrite(binary_buf, 1, binary_size, g); + fclose(g); + + /*dump_maps(); + for (uint64_t i = 0x7ffbd2000; i < 0x800000000; i += 0x1000) { + uint64_t cmd = *((uint64_t*)i); + printf("%llx: %llx\n", i, cmd); + }*/ + + + return 0; +} + diff --git a/selfdrive/modeld/thneed/debug/microbenchmark/run.sh b/selfdrive/modeld/thneed/debug/microbenchmark/run.sh new file mode 100755 index 0000000000..f77d27d817 --- /dev/null +++ b/selfdrive/modeld/thneed/debug/microbenchmark/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +gcc -I/data/openpilot/phonelibs/opencl/include -L/system/vendor/lib64 -lOpenCL -lCB -lgsl go.c diff --git a/selfdrive/modeld/thneed/debug/test.cc b/selfdrive/modeld/thneed/debug/test.cc new file mode 100644 index 0000000000..6f185b9f00 --- /dev/null +++ b/selfdrive/modeld/thneed/debug/test.cc @@ -0,0 +1,99 @@ +#include "../thneed.h" +#include "../../runners/snpemodel.h" + +#define TEMPORAL_SIZE 512 +#define DESIRE_LEN 8 +#define TRAFFIC_CONVENTION_LEN 2 + +void hexdump(uint32_t *d, int len); + +int main(int argc, char* argv[]) { + #define OUTPUT_SIZE 0x10000 + float *output = (float*)calloc(OUTPUT_SIZE, sizeof(float)); + float *golden = (float*)calloc(OUTPUT_SIZE, sizeof(float)); + SNPEModel mdl(argv[1], output, 0, USE_GPU_RUNTIME); + + // cmd line test + if (argc > 2) { + for (int i = 2; i < argc; i++) { + float *buf[5]; + FILE *f = fopen(argv[i], "rb"); + + size_t sz; + for (int j = 0; j < 5; j++) { + fread(&sz, 1, sizeof(sz), f); + printf("reading %zu\n", sz); + buf[j] = (float*)malloc(sz); + fread(buf[j], 1, sz, f); + } + + if (sz != 9532) continue; + + mdl.addRecurrent(buf[0], TEMPORAL_SIZE); + mdl.addTrafficConvention(buf[1], TRAFFIC_CONVENTION_LEN); + mdl.addDesire(buf[2], DESIRE_LEN); + mdl.execute(buf[3], 0); + + hexdump((uint32_t*)buf[4], 0x100); + hexdump((uint32_t*)output, 0x100); + + for (int j = 0; j < sz/4; j++) { + if (buf[4][j] != output[j]) { + printf("MISMATCH %d real:%f comp:%f\n", j, buf[4][j], output[j]); + } + } + } + + return 0; + } + + float state[TEMPORAL_SIZE]; + mdl.addRecurrent(state, TEMPORAL_SIZE); + + float desire[DESIRE_LEN]; + mdl.addDesire(desire, DESIRE_LEN); + + float traffic_convention[TRAFFIC_CONVENTION_LEN]; + mdl.addTrafficConvention(traffic_convention, TRAFFIC_CONVENTION_LEN); + + float *input = (float*)calloc(0x1000000, sizeof(float));; + + // first run + printf("************** execute 1 **************\n"); + memset(output, 0, OUTPUT_SIZE * sizeof(float)); + mdl.execute(input, 0); + hexdump((uint32_t *)output, 0x100); + memcpy(golden, output, OUTPUT_SIZE * sizeof(float)); + + // second run + printf("************** execute 2 **************\n"); + memset(output, 0, OUTPUT_SIZE * sizeof(float)); + Thneed *t = new Thneed(); + t->record = 7; // debug print with record + mdl.execute(input, 0); + t->stop(); + hexdump((uint32_t *)output, 0x100); + if (memcmp(golden, output, OUTPUT_SIZE * sizeof(float)) != 0) { printf("FAILURE\n"); return -1; } + + // third run + printf("************** execute 3 **************\n"); + memset(output, 0, OUTPUT_SIZE * sizeof(float)); + t->record = 2; // debug print w/o record + float *inputs[4] = {state, traffic_convention, desire, input}; + t->execute(inputs, output, true); + hexdump((uint32_t *)output, 0x100); + if (memcmp(golden, output, OUTPUT_SIZE * sizeof(float)) != 0) { printf("FAILURE\n"); return -1; } + + printf("************** execute 4 **************\n"); + while (1) { + memset(output, 0, OUTPUT_SIZE * sizeof(float)); + //t->record = 2; // debug print w/o record + t->execute(inputs, output); + hexdump((uint32_t *)output, 0x100); + if (memcmp(golden, output, OUTPUT_SIZE * sizeof(float)) != 0) { printf("FAILURE\n"); return -1; } + break; + } + + printf("************** execute done **************\n"); +} + diff --git a/selfdrive/modeld/thneed/debug/thneed b/selfdrive/modeld/thneed/debug/thneed new file mode 100755 index 0000000000..ab2d721bb2 --- /dev/null +++ b/selfdrive/modeld/thneed/debug/thneed @@ -0,0 +1,4 @@ +#!/bin/sh +export LD_LIBRARY_PATH="/data/openpilot/phonelibs/snpe/aarch64/:$HOME/openpilot/phonelibs/snpe/larch64:$HOME/openpilot/phonelibs/snpe/x86_64-linux-clang:$LD_LIBRARY_PATH" +exec ./_thneed $@ + diff --git a/selfdrive/modeld/thneed/include/msm_kgsl.h b/selfdrive/modeld/thneed/include/msm_kgsl.h new file mode 100644 index 0000000000..93582eb066 --- /dev/null +++ b/selfdrive/modeld/thneed/include/msm_kgsl.h @@ -0,0 +1,1449 @@ +#ifndef _UAPI_MSM_KGSL_H +#define _UAPI_MSM_KGSL_H + +#include +#include + +/* + * The KGSL version has proven not to be very useful in userspace if features + * are cherry picked into other trees out of order so it is frozen as of 3.14. + * It is left here for backwards compatabilty and as a reminder that + * software releases are never linear. Also, I like pie. + */ + +#define KGSL_VERSION_MAJOR 3 +#define KGSL_VERSION_MINOR 14 + +/* + * We have traditionally mixed context and issueibcmds / command batch flags + * together into a big flag stew. This worked fine until we started adding a + * lot more command batch flags and we started running out of bits. Turns out + * we have a bit of room in the context type / priority mask that we could use + * for command batches, but that means we need to split out the flags into two + * coherent sets. + * + * If any future definitions are for both context and cmdbatch add both defines + * and link the cmdbatch to the context define as we do below. Otherwise feel + * free to add exclusive bits to either set. + */ + +/* --- context flags --- */ +#define KGSL_CONTEXT_SAVE_GMEM 0x00000001 +#define KGSL_CONTEXT_NO_GMEM_ALLOC 0x00000002 +/* This is a cmdbatch exclusive flag - use the CMDBATCH equivalent instead */ +#define KGSL_CONTEXT_SUBMIT_IB_LIST 0x00000004 +#define KGSL_CONTEXT_CTX_SWITCH 0x00000008 +#define KGSL_CONTEXT_PREAMBLE 0x00000010 +#define KGSL_CONTEXT_TRASH_STATE 0x00000020 +#define KGSL_CONTEXT_PER_CONTEXT_TS 0x00000040 +#define KGSL_CONTEXT_USER_GENERATED_TS 0x00000080 +/* This is a cmdbatch exclusive flag - use the CMDBATCH equivalent instead */ +#define KGSL_CONTEXT_END_OF_FRAME 0x00000100 +#define KGSL_CONTEXT_NO_FAULT_TOLERANCE 0x00000200 +/* This is a cmdbatch exclusive flag - use the CMDBATCH equivalent instead */ +#define KGSL_CONTEXT_SYNC 0x00000400 +#define KGSL_CONTEXT_PWR_CONSTRAINT 0x00000800 + +#define KGSL_CONTEXT_PRIORITY_MASK 0x0000F000 +#define KGSL_CONTEXT_PRIORITY_SHIFT 12 +#define KGSL_CONTEXT_PRIORITY_UNDEF 0 + +#define KGSL_CONTEXT_IFH_NOP 0x00010000 +#define KGSL_CONTEXT_SECURE 0x00020000 + +#define KGSL_CONTEXT_PREEMPT_STYLE_MASK 0x0E000000 +#define KGSL_CONTEXT_PREEMPT_STYLE_SHIFT 25 +#define KGSL_CONTEXT_PREEMPT_STYLE_DEFAULT 0x0 +#define KGSL_CONTEXT_PREEMPT_STYLE_RINGBUFFER 0x1 +#define KGSL_CONTEXT_PREEMPT_STYLE_FINEGRAIN 0x2 + +#define KGSL_CONTEXT_TYPE_MASK 0x01F00000 +#define KGSL_CONTEXT_TYPE_SHIFT 20 +#define KGSL_CONTEXT_TYPE_ANY 0 +#define KGSL_CONTEXT_TYPE_GL 1 +#define KGSL_CONTEXT_TYPE_CL 2 +#define KGSL_CONTEXT_TYPE_C2D 3 +#define KGSL_CONTEXT_TYPE_RS 4 +#define KGSL_CONTEXT_TYPE_UNKNOWN 0x1E + +#define KGSL_CONTEXT_INVALID 0xffffffff + +/* + * --- command batch flags --- + * The bits that are linked to a KGSL_CONTEXT equivalent are either legacy + * definitions or bits that are valid for both contexts and cmdbatches. To be + * safe the other 8 bits that are still available in the context field should be + * omitted here in case we need to share - the other bits are available for + * cmdbatch only flags as needed + */ +#define KGSL_CMDBATCH_MEMLIST 0x00000001 +#define KGSL_CMDBATCH_MARKER 0x00000002 +#define KGSL_CMDBATCH_SUBMIT_IB_LIST KGSL_CONTEXT_SUBMIT_IB_LIST /* 0x004 */ +#define KGSL_CMDBATCH_CTX_SWITCH KGSL_CONTEXT_CTX_SWITCH /* 0x008 */ +#define KGSL_CMDBATCH_PROFILING 0x00000010 +#define KGSL_CMDBATCH_PROFILING_KTIME 0x00000020 +#define KGSL_CMDBATCH_END_OF_FRAME KGSL_CONTEXT_END_OF_FRAME /* 0x100 */ +#define KGSL_CMDBATCH_SYNC KGSL_CONTEXT_SYNC /* 0x400 */ +#define KGSL_CMDBATCH_PWR_CONSTRAINT KGSL_CONTEXT_PWR_CONSTRAINT /* 0x800 */ + +/* + * Reserve bits [16:19] and bits [28:31] for possible bits shared between + * contexts and command batches. Update this comment as new flags are added. + */ + +/* + * gpu_command_object flags - these flags communicate the type of command or + * memory object being submitted for a GPU command + */ + +/* Flags for GPU command objects */ +#define KGSL_CMDLIST_IB 0x00000001U +#define KGSL_CMDLIST_CTXTSWITCH_PREAMBLE 0x00000002U +#define KGSL_CMDLIST_IB_PREAMBLE 0x00000004U + +/* Flags for GPU command memory objects */ +#define KGSL_OBJLIST_MEMOBJ 0x00000008U +#define KGSL_OBJLIST_PROFILE 0x00000010U + +/* Flags for GPU command sync points */ +#define KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP 0 +#define KGSL_CMD_SYNCPOINT_TYPE_FENCE 1 + +/* --- Memory allocation flags --- */ + +/* General allocation hints */ +#define KGSL_MEMFLAGS_SECURE 0x00000008ULL +#define KGSL_MEMFLAGS_GPUREADONLY 0x01000000U +#define KGSL_MEMFLAGS_GPUWRITEONLY 0x02000000U +#define KGSL_MEMFLAGS_FORCE_32BIT 0x100000000ULL + +/* Memory caching hints */ +#define KGSL_CACHEMODE_MASK 0x0C000000U +#define KGSL_CACHEMODE_SHIFT 26 + +#define KGSL_CACHEMODE_WRITECOMBINE 0 +#define KGSL_CACHEMODE_UNCACHED 1 +#define KGSL_CACHEMODE_WRITETHROUGH 2 +#define KGSL_CACHEMODE_WRITEBACK 3 + +#define KGSL_MEMFLAGS_USE_CPU_MAP 0x10000000ULL + +/* Memory types for which allocations are made */ +#define KGSL_MEMTYPE_MASK 0x0000FF00 +#define KGSL_MEMTYPE_SHIFT 8 + +#define KGSL_MEMTYPE_OBJECTANY 0 +#define KGSL_MEMTYPE_FRAMEBUFFER 1 +#define KGSL_MEMTYPE_RENDERBUFFER 2 +#define KGSL_MEMTYPE_ARRAYBUFFER 3 +#define KGSL_MEMTYPE_ELEMENTARRAYBUFFER 4 +#define KGSL_MEMTYPE_VERTEXARRAYBUFFER 5 +#define KGSL_MEMTYPE_TEXTURE 6 +#define KGSL_MEMTYPE_SURFACE 7 +#define KGSL_MEMTYPE_EGL_SURFACE 8 +#define KGSL_MEMTYPE_GL 9 +#define KGSL_MEMTYPE_CL 10 +#define KGSL_MEMTYPE_CL_BUFFER_MAP 11 +#define KGSL_MEMTYPE_CL_BUFFER_NOMAP 12 +#define KGSL_MEMTYPE_CL_IMAGE_MAP 13 +#define KGSL_MEMTYPE_CL_IMAGE_NOMAP 14 +#define KGSL_MEMTYPE_CL_KERNEL_STACK 15 +#define KGSL_MEMTYPE_COMMAND 16 +#define KGSL_MEMTYPE_2D 17 +#define KGSL_MEMTYPE_EGL_IMAGE 18 +#define KGSL_MEMTYPE_EGL_SHADOW 19 +#define KGSL_MEMTYPE_MULTISAMPLE 20 +#define KGSL_MEMTYPE_KERNEL 255 + +/* + * Alignment hint, passed as the power of 2 exponent. + * i.e 4k (2^12) would be 12, 64k (2^16)would be 16. + */ +#define KGSL_MEMALIGN_MASK 0x00FF0000 +#define KGSL_MEMALIGN_SHIFT 16 + +enum kgsl_user_mem_type { + KGSL_USER_MEM_TYPE_PMEM = 0x00000000, + KGSL_USER_MEM_TYPE_ASHMEM = 0x00000001, + KGSL_USER_MEM_TYPE_ADDR = 0x00000002, + KGSL_USER_MEM_TYPE_ION = 0x00000003, + /* + * ION type is retained for backwards compatibilty but Ion buffers are + * dma-bufs so try to use that naming if we can + */ + KGSL_USER_MEM_TYPE_DMABUF = 0x00000003, + KGSL_USER_MEM_TYPE_MAX = 0x00000007, +}; +#define KGSL_MEMFLAGS_USERMEM_MASK 0x000000e0 +#define KGSL_MEMFLAGS_USERMEM_SHIFT 5 + +/* + * Unfortunately, enum kgsl_user_mem_type starts at 0 which does not + * leave a good value for allocated memory. In the flags we use + * 0 to indicate allocated memory and thus need to add 1 to the enum + * values. + */ +#define KGSL_USERMEM_FLAG(x) (((x) + 1) << KGSL_MEMFLAGS_USERMEM_SHIFT) + +#define KGSL_MEMFLAGS_NOT_USERMEM 0 +#define KGSL_MEMFLAGS_USERMEM_PMEM KGSL_USERMEM_FLAG(KGSL_USER_MEM_TYPE_PMEM) +#define KGSL_MEMFLAGS_USERMEM_ASHMEM \ + KGSL_USERMEM_FLAG(KGSL_USER_MEM_TYPE_ASHMEM) +#define KGSL_MEMFLAGS_USERMEM_ADDR KGSL_USERMEM_FLAG(KGSL_USER_MEM_TYPE_ADDR) +#define KGSL_MEMFLAGS_USERMEM_ION KGSL_USERMEM_FLAG(KGSL_USER_MEM_TYPE_ION) + +/* --- generic KGSL flag values --- */ + +#define KGSL_FLAGS_NORMALMODE 0x00000000 +#define KGSL_FLAGS_SAFEMODE 0x00000001 +#define KGSL_FLAGS_INITIALIZED0 0x00000002 +#define KGSL_FLAGS_INITIALIZED 0x00000004 +#define KGSL_FLAGS_STARTED 0x00000008 +#define KGSL_FLAGS_ACTIVE 0x00000010 +#define KGSL_FLAGS_RESERVED0 0x00000020 +#define KGSL_FLAGS_RESERVED1 0x00000040 +#define KGSL_FLAGS_RESERVED2 0x00000080 +#define KGSL_FLAGS_SOFT_RESET 0x00000100 +#define KGSL_FLAGS_PER_CONTEXT_TIMESTAMPS 0x00000200 + +/* Server Side Sync Timeout in milliseconds */ +#define KGSL_SYNCOBJ_SERVER_TIMEOUT 2000 + +/* + * Reset status values for context + */ +enum kgsl_ctx_reset_stat { + KGSL_CTX_STAT_NO_ERROR = 0x00000000, + KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT = 0x00000001, + KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT = 0x00000002, + KGSL_CTX_STAT_UNKNOWN_CONTEXT_RESET_EXT = 0x00000003 +}; + +#define KGSL_CONVERT_TO_MBPS(val) \ + (val*1000*1000U) + +/* device id */ +enum kgsl_deviceid { + KGSL_DEVICE_3D0 = 0x00000000, + KGSL_DEVICE_MAX +}; + +struct kgsl_devinfo { + + unsigned int device_id; + /* chip revision id + * coreid:8 majorrev:8 minorrev:8 patch:8 + */ + unsigned int chip_id; + unsigned int mmu_enabled; + unsigned long gmem_gpubaseaddr; + /* + * This field contains the adreno revision + * number 200, 205, 220, etc... + */ + unsigned int gpu_id; + size_t gmem_sizebytes; +}; + +/* + * struct kgsl_devmemstore - this structure defines the region of memory + * that can be mmap()ed from this driver. The timestamp fields are volatile + * because they are written by the GPU + * @soptimestamp: Start of pipeline timestamp written by GPU before the + * commands in concern are processed + * @sbz: Unused, kept for 8 byte alignment + * @eoptimestamp: End of pipeline timestamp written by GPU after the + * commands in concern are processed + * @sbz2: Unused, kept for 8 byte alignment + * @preempted: Indicates if the context was preempted + * @sbz3: Unused, kept for 8 byte alignment + * @ref_wait_ts: Timestamp on which to generate interrupt, unused now. + * @sbz4: Unused, kept for 8 byte alignment + * @current_context: The current context the GPU is working on + * @sbz5: Unused, kept for 8 byte alignment + */ +struct kgsl_devmemstore { + volatile unsigned int soptimestamp; + unsigned int sbz; + volatile unsigned int eoptimestamp; + unsigned int sbz2; + volatile unsigned int preempted; + unsigned int sbz3; + volatile unsigned int ref_wait_ts; + unsigned int sbz4; + unsigned int current_context; + unsigned int sbz5; +}; + +#define KGSL_MEMSTORE_OFFSET(ctxt_id, field) \ + ((ctxt_id)*sizeof(struct kgsl_devmemstore) + \ + offsetof(struct kgsl_devmemstore, field)) + +/* timestamp id*/ +enum kgsl_timestamp_type { + KGSL_TIMESTAMP_CONSUMED = 0x00000001, /* start-of-pipeline timestamp */ + KGSL_TIMESTAMP_RETIRED = 0x00000002, /* end-of-pipeline timestamp*/ + KGSL_TIMESTAMP_QUEUED = 0x00000003, +}; + +/* property types - used with kgsl_device_getproperty */ +#define KGSL_PROP_DEVICE_INFO 0x1 +#define KGSL_PROP_DEVICE_SHADOW 0x2 +#define KGSL_PROP_DEVICE_POWER 0x3 +#define KGSL_PROP_SHMEM 0x4 +#define KGSL_PROP_SHMEM_APERTURES 0x5 +#define KGSL_PROP_MMU_ENABLE 0x6 +#define KGSL_PROP_INTERRUPT_WAITS 0x7 +#define KGSL_PROP_VERSION 0x8 +#define KGSL_PROP_GPU_RESET_STAT 0x9 +#define KGSL_PROP_PWRCTRL 0xE +#define KGSL_PROP_PWR_CONSTRAINT 0x12 +#define KGSL_PROP_UCHE_GMEM_VADDR 0x13 +#define KGSL_PROP_SP_GENERIC_MEM 0x14 +#define KGSL_PROP_UCODE_VERSION 0x15 +#define KGSL_PROP_GPMU_VERSION 0x16 +#define KGSL_PROP_DEVICE_BITNESS 0x18 + +struct kgsl_shadowprop { + unsigned long gpuaddr; + size_t size; + unsigned int flags; /* contains KGSL_FLAGS_ values */ +}; + +struct kgsl_version { + unsigned int drv_major; + unsigned int drv_minor; + unsigned int dev_major; + unsigned int dev_minor; +}; + +struct kgsl_sp_generic_mem { + uint64_t local; + uint64_t pvt; +}; + +struct kgsl_ucode_version { + unsigned int pfp; + unsigned int pm4; +}; + +struct kgsl_gpmu_version { + unsigned int major; + unsigned int minor; + unsigned int features; +}; + +/* Performance counter groups */ + +#define KGSL_PERFCOUNTER_GROUP_CP 0x0 +#define KGSL_PERFCOUNTER_GROUP_RBBM 0x1 +#define KGSL_PERFCOUNTER_GROUP_PC 0x2 +#define KGSL_PERFCOUNTER_GROUP_VFD 0x3 +#define KGSL_PERFCOUNTER_GROUP_HLSQ 0x4 +#define KGSL_PERFCOUNTER_GROUP_VPC 0x5 +#define KGSL_PERFCOUNTER_GROUP_TSE 0x6 +#define KGSL_PERFCOUNTER_GROUP_RAS 0x7 +#define KGSL_PERFCOUNTER_GROUP_UCHE 0x8 +#define KGSL_PERFCOUNTER_GROUP_TP 0x9 +#define KGSL_PERFCOUNTER_GROUP_SP 0xA +#define KGSL_PERFCOUNTER_GROUP_RB 0xB +#define KGSL_PERFCOUNTER_GROUP_PWR 0xC +#define KGSL_PERFCOUNTER_GROUP_VBIF 0xD +#define KGSL_PERFCOUNTER_GROUP_VBIF_PWR 0xE +#define KGSL_PERFCOUNTER_GROUP_MH 0xF +#define KGSL_PERFCOUNTER_GROUP_PA_SU 0x10 +#define KGSL_PERFCOUNTER_GROUP_SQ 0x11 +#define KGSL_PERFCOUNTER_GROUP_SX 0x12 +#define KGSL_PERFCOUNTER_GROUP_TCF 0x13 +#define KGSL_PERFCOUNTER_GROUP_TCM 0x14 +#define KGSL_PERFCOUNTER_GROUP_TCR 0x15 +#define KGSL_PERFCOUNTER_GROUP_L2 0x16 +#define KGSL_PERFCOUNTER_GROUP_VSC 0x17 +#define KGSL_PERFCOUNTER_GROUP_CCU 0x18 +#define KGSL_PERFCOUNTER_GROUP_LRZ 0x19 +#define KGSL_PERFCOUNTER_GROUP_CMP 0x1A +#define KGSL_PERFCOUNTER_GROUP_ALWAYSON 0x1B +#define KGSL_PERFCOUNTER_GROUP_SP_PWR 0x1C +#define KGSL_PERFCOUNTER_GROUP_TP_PWR 0x1D +#define KGSL_PERFCOUNTER_GROUP_RB_PWR 0x1E +#define KGSL_PERFCOUNTER_GROUP_CCU_PWR 0x1F +#define KGSL_PERFCOUNTER_GROUP_UCHE_PWR 0x20 +#define KGSL_PERFCOUNTER_GROUP_CP_PWR 0x21 +#define KGSL_PERFCOUNTER_GROUP_GPMU_PWR 0x22 +#define KGSL_PERFCOUNTER_GROUP_ALWAYSON_PWR 0x23 +#define KGSL_PERFCOUNTER_GROUP_MAX 0x24 + +#define KGSL_PERFCOUNTER_NOT_USED 0xFFFFFFFF +#define KGSL_PERFCOUNTER_BROKEN 0xFFFFFFFE + +/* structure holds list of ibs */ +struct kgsl_ibdesc { + unsigned long gpuaddr; + unsigned long __pad; + size_t sizedwords; + unsigned int ctrl; +}; + +/** + * struct kgsl_cmdbatch_profiling_buffer + * @wall_clock_s: Ringbuffer submission time (seconds). + * If KGSL_CMDBATCH_PROFILING_KTIME is set, time is provided + * in kernel clocks, otherwise wall clock time is used. + * @wall_clock_ns: Ringbuffer submission time (nanoseconds). + * If KGSL_CMDBATCH_PROFILING_KTIME is set time is provided + * in kernel clocks, otherwise wall clock time is used. + * @gpu_ticks_queued: GPU ticks at ringbuffer submission + * @gpu_ticks_submitted: GPU ticks when starting cmdbatch execution + * @gpu_ticks_retired: GPU ticks when finishing cmdbatch execution + * + * This structure defines the profiling buffer used to measure cmdbatch + * execution time + */ +struct kgsl_cmdbatch_profiling_buffer { + uint64_t wall_clock_s; + uint64_t wall_clock_ns; + uint64_t gpu_ticks_queued; + uint64_t gpu_ticks_submitted; + uint64_t gpu_ticks_retired; +}; + +/* ioctls */ +#define KGSL_IOC_TYPE 0x09 + +/* get misc info about the GPU + type should be a value from enum kgsl_property_type + value points to a structure that varies based on type + sizebytes is sizeof() that structure + for KGSL_PROP_DEVICE_INFO, use struct kgsl_devinfo + this structure contaings hardware versioning info. + for KGSL_PROP_DEVICE_SHADOW, use struct kgsl_shadowprop + this is used to find mmap() offset and sizes for mapping + struct kgsl_memstore into userspace. +*/ +struct kgsl_device_getproperty { + unsigned int type; + void __user *value; + size_t sizebytes; +}; + +#define IOCTL_KGSL_DEVICE_GETPROPERTY \ + _IOWR(KGSL_IOC_TYPE, 0x2, struct kgsl_device_getproperty) + +/* IOCTL_KGSL_DEVICE_READ (0x3) - removed 03/2012 + */ + +/* block until the GPU has executed past a given timestamp + * timeout is in milliseconds. + */ +struct kgsl_device_waittimestamp { + unsigned int timestamp; + unsigned int timeout; +}; + +#define IOCTL_KGSL_DEVICE_WAITTIMESTAMP \ + _IOW(KGSL_IOC_TYPE, 0x6, struct kgsl_device_waittimestamp) + +struct kgsl_device_waittimestamp_ctxtid { + unsigned int context_id; + unsigned int timestamp; + unsigned int timeout; +}; + +#define IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID \ + _IOW(KGSL_IOC_TYPE, 0x7, struct kgsl_device_waittimestamp_ctxtid) + +/* DEPRECATED: issue indirect commands to the GPU. + * drawctxt_id must have been created with IOCTL_KGSL_DRAWCTXT_CREATE + * ibaddr and sizedwords must specify a subset of a buffer created + * with IOCTL_KGSL_SHAREDMEM_FROM_PMEM + * flags may be a mask of KGSL_CONTEXT_ values + * timestamp is a returned counter value which can be passed to + * other ioctls to determine when the commands have been executed by + * the GPU. + * + * This fucntion is deprecated - consider using IOCTL_KGSL_SUBMIT_COMMANDS + * instead + */ +struct kgsl_ringbuffer_issueibcmds { + unsigned int drawctxt_id; + unsigned long ibdesc_addr; + unsigned int numibs; + unsigned int timestamp; /*output param */ + unsigned int flags; +}; + +#define IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS \ + _IOWR(KGSL_IOC_TYPE, 0x10, struct kgsl_ringbuffer_issueibcmds) + +/* read the most recently executed timestamp value + * type should be a value from enum kgsl_timestamp_type + */ +struct kgsl_cmdstream_readtimestamp { + unsigned int type; + unsigned int timestamp; /*output param */ +}; + +#define IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_OLD \ + _IOR(KGSL_IOC_TYPE, 0x11, struct kgsl_cmdstream_readtimestamp) + +#define IOCTL_KGSL_CMDSTREAM_READTIMESTAMP \ + _IOWR(KGSL_IOC_TYPE, 0x11, struct kgsl_cmdstream_readtimestamp) + +/* free memory when the GPU reaches a given timestamp. + * gpuaddr specify a memory region created by a + * IOCTL_KGSL_SHAREDMEM_FROM_PMEM call + * type should be a value from enum kgsl_timestamp_type + */ +struct kgsl_cmdstream_freememontimestamp { + unsigned long gpuaddr; + unsigned int type; + unsigned int timestamp; +}; + +#define IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP \ + _IOW(KGSL_IOC_TYPE, 0x12, struct kgsl_cmdstream_freememontimestamp) + +/* Previous versions of this header had incorrectly defined + IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP as a read-only ioctl instead + of a write only ioctl. To ensure binary compatability, the following + #define will be used to intercept the incorrect ioctl +*/ + +#define IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_OLD \ + _IOR(KGSL_IOC_TYPE, 0x12, struct kgsl_cmdstream_freememontimestamp) + +/* create a draw context, which is used to preserve GPU state. + * The flags field may contain a mask KGSL_CONTEXT_* values + */ +struct kgsl_drawctxt_create { + unsigned int flags; + unsigned int drawctxt_id; /*output param */ +}; + +#define IOCTL_KGSL_DRAWCTXT_CREATE \ + _IOWR(KGSL_IOC_TYPE, 0x13, struct kgsl_drawctxt_create) + +/* destroy a draw context */ +struct kgsl_drawctxt_destroy { + unsigned int drawctxt_id; +}; + +#define IOCTL_KGSL_DRAWCTXT_DESTROY \ + _IOW(KGSL_IOC_TYPE, 0x14, struct kgsl_drawctxt_destroy) + +/* add a block of pmem, fb, ashmem or user allocated address + * into the GPU address space */ +struct kgsl_map_user_mem { + int fd; + unsigned long gpuaddr; /*output param */ + size_t len; + size_t offset; + unsigned long hostptr; /*input param */ + enum kgsl_user_mem_type memtype; + unsigned int flags; +}; + +#define IOCTL_KGSL_MAP_USER_MEM \ + _IOWR(KGSL_IOC_TYPE, 0x15, struct kgsl_map_user_mem) + +struct kgsl_cmdstream_readtimestamp_ctxtid { + unsigned int context_id; + unsigned int type; + unsigned int timestamp; /*output param */ +}; + +#define IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_CTXTID \ + _IOWR(KGSL_IOC_TYPE, 0x16, struct kgsl_cmdstream_readtimestamp_ctxtid) + +struct kgsl_cmdstream_freememontimestamp_ctxtid { + unsigned int context_id; + unsigned long gpuaddr; + unsigned int type; + unsigned int timestamp; +}; + +#define IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_CTXTID \ + _IOW(KGSL_IOC_TYPE, 0x17, \ + struct kgsl_cmdstream_freememontimestamp_ctxtid) + +/* add a block of pmem or fb into the GPU address space */ +struct kgsl_sharedmem_from_pmem { + int pmem_fd; + unsigned long gpuaddr; /*output param */ + unsigned int len; + unsigned int offset; +}; + +#define IOCTL_KGSL_SHAREDMEM_FROM_PMEM \ + _IOWR(KGSL_IOC_TYPE, 0x20, struct kgsl_sharedmem_from_pmem) + +/* remove memory from the GPU's address space */ +struct kgsl_sharedmem_free { + unsigned long gpuaddr; +}; + +#define IOCTL_KGSL_SHAREDMEM_FREE \ + _IOW(KGSL_IOC_TYPE, 0x21, struct kgsl_sharedmem_free) + +struct kgsl_cff_user_event { + unsigned char cff_opcode; + unsigned int op1; + unsigned int op2; + unsigned int op3; + unsigned int op4; + unsigned int op5; + unsigned int __pad[2]; +}; + +#define IOCTL_KGSL_CFF_USER_EVENT \ + _IOW(KGSL_IOC_TYPE, 0x31, struct kgsl_cff_user_event) + +struct kgsl_gmem_desc { + unsigned int x; + unsigned int y; + unsigned int width; + unsigned int height; + unsigned int pitch; +}; + +struct kgsl_buffer_desc { + void *hostptr; + unsigned long gpuaddr; + int size; + unsigned int format; + unsigned int pitch; + unsigned int enabled; +}; + +struct kgsl_bind_gmem_shadow { + unsigned int drawctxt_id; + struct kgsl_gmem_desc gmem_desc; + unsigned int shadow_x; + unsigned int shadow_y; + struct kgsl_buffer_desc shadow_buffer; + unsigned int buffer_id; +}; + +#define IOCTL_KGSL_DRAWCTXT_BIND_GMEM_SHADOW \ + _IOW(KGSL_IOC_TYPE, 0x22, struct kgsl_bind_gmem_shadow) + +/* add a block of memory into the GPU address space */ + +/* + * IOCTL_KGSL_SHAREDMEM_FROM_VMALLOC deprecated 09/2012 + * use IOCTL_KGSL_GPUMEM_ALLOC instead + */ + +struct kgsl_sharedmem_from_vmalloc { + unsigned long gpuaddr; /*output param */ + unsigned int hostptr; + unsigned int flags; +}; + +#define IOCTL_KGSL_SHAREDMEM_FROM_VMALLOC \ + _IOWR(KGSL_IOC_TYPE, 0x23, struct kgsl_sharedmem_from_vmalloc) + +/* + * This is being deprecated in favor of IOCTL_KGSL_GPUMEM_CACHE_SYNC which + * supports both directions (flush and invalidate). This code will still + * work, but by definition it will do a flush of the cache which might not be + * what you want to have happen on a buffer following a GPU operation. It is + * safer to go with IOCTL_KGSL_GPUMEM_CACHE_SYNC + */ + +#define IOCTL_KGSL_SHAREDMEM_FLUSH_CACHE \ + _IOW(KGSL_IOC_TYPE, 0x24, struct kgsl_sharedmem_free) + +struct kgsl_drawctxt_set_bin_base_offset { + unsigned int drawctxt_id; + unsigned int offset; +}; + +#define IOCTL_KGSL_DRAWCTXT_SET_BIN_BASE_OFFSET \ + _IOW(KGSL_IOC_TYPE, 0x25, struct kgsl_drawctxt_set_bin_base_offset) + +enum kgsl_cmdwindow_type { + KGSL_CMDWINDOW_MIN = 0x00000000, + KGSL_CMDWINDOW_2D = 0x00000000, + KGSL_CMDWINDOW_3D = 0x00000001, /* legacy */ + KGSL_CMDWINDOW_MMU = 0x00000002, + KGSL_CMDWINDOW_ARBITER = 0x000000FF, + KGSL_CMDWINDOW_MAX = 0x000000FF, +}; + +/* write to the command window */ +struct kgsl_cmdwindow_write { + enum kgsl_cmdwindow_type target; + unsigned int addr; + unsigned int data; +}; + +#define IOCTL_KGSL_CMDWINDOW_WRITE \ + _IOW(KGSL_IOC_TYPE, 0x2e, struct kgsl_cmdwindow_write) + +struct kgsl_gpumem_alloc { + unsigned long gpuaddr; /* output param */ + size_t size; + unsigned int flags; +}; + +#define IOCTL_KGSL_GPUMEM_ALLOC \ + _IOWR(KGSL_IOC_TYPE, 0x2f, struct kgsl_gpumem_alloc) + +struct kgsl_cff_syncmem { + unsigned long gpuaddr; + size_t len; + unsigned int __pad[2]; /* For future binary compatibility */ +}; + +#define IOCTL_KGSL_CFF_SYNCMEM \ + _IOW(KGSL_IOC_TYPE, 0x30, struct kgsl_cff_syncmem) + +/* + * A timestamp event allows the user space to register an action following an + * expired timestamp. Note IOCTL_KGSL_TIMESTAMP_EVENT has been redefined to + * _IOWR to support fences which need to return a fd for the priv parameter. + */ + +struct kgsl_timestamp_event { + int type; /* Type of event (see list below) */ + unsigned int timestamp; /* Timestamp to trigger event on */ + unsigned int context_id; /* Context for the timestamp */ + void __user *priv; /* Pointer to the event specific blob */ + size_t len; /* Size of the event specific blob */ +}; + +#define IOCTL_KGSL_TIMESTAMP_EVENT_OLD \ + _IOW(KGSL_IOC_TYPE, 0x31, struct kgsl_timestamp_event) + +/* A genlock timestamp event releases an existing lock on timestamp expire */ + +#define KGSL_TIMESTAMP_EVENT_GENLOCK 1 + +struct kgsl_timestamp_event_genlock { + int handle; /* Handle of the genlock lock to release */ +}; + +/* A fence timestamp event releases an existing lock on timestamp expire */ + +#define KGSL_TIMESTAMP_EVENT_FENCE 2 + +struct kgsl_timestamp_event_fence { + int fence_fd; /* Fence to signal */ +}; + +/* + * Set a property within the kernel. Uses the same structure as + * IOCTL_KGSL_GETPROPERTY + */ + +#define IOCTL_KGSL_SETPROPERTY \ + _IOW(KGSL_IOC_TYPE, 0x32, struct kgsl_device_getproperty) + +#define IOCTL_KGSL_TIMESTAMP_EVENT \ + _IOWR(KGSL_IOC_TYPE, 0x33, struct kgsl_timestamp_event) + +/** + * struct kgsl_gpumem_alloc_id - argument to IOCTL_KGSL_GPUMEM_ALLOC_ID + * @id: returned id value for this allocation. + * @flags: mask of KGSL_MEM* values requested and actual flags on return. + * @size: requested size of the allocation and actual size on return. + * @mmapsize: returned size to pass to mmap() which may be larger than 'size' + * @gpuaddr: returned GPU address for the allocation + * + * Allocate memory for access by the GPU. The flags and size fields are echoed + * back by the kernel, so that the caller can know if the request was + * adjusted. + * + * Supported flags: + * KGSL_MEMFLAGS_GPUREADONLY: the GPU will be unable to write to the buffer + * KGSL_MEMTYPE*: usage hint for debugging aid + * KGSL_MEMALIGN*: alignment hint, may be ignored or adjusted by the kernel. + * KGSL_MEMFLAGS_USE_CPU_MAP: If set on call and return, the returned GPU + * address will be 0. Calling mmap() will set the GPU address. + */ +struct kgsl_gpumem_alloc_id { + unsigned int id; + unsigned int flags; + size_t size; + size_t mmapsize; + unsigned long gpuaddr; +/* private: reserved for future use*/ + unsigned long __pad[2]; +}; + +#define IOCTL_KGSL_GPUMEM_ALLOC_ID \ + _IOWR(KGSL_IOC_TYPE, 0x34, struct kgsl_gpumem_alloc_id) + +/** + * struct kgsl_gpumem_free_id - argument to IOCTL_KGSL_GPUMEM_FREE_ID + * @id: GPU allocation id to free + * + * Free an allocation by id, in case a GPU address has not been assigned or + * is unknown. Freeing an allocation by id with this ioctl or by GPU address + * with IOCTL_KGSL_SHAREDMEM_FREE are equivalent. + */ +struct kgsl_gpumem_free_id { + unsigned int id; +/* private: reserved for future use*/ + unsigned int __pad; +}; + +#define IOCTL_KGSL_GPUMEM_FREE_ID \ + _IOWR(KGSL_IOC_TYPE, 0x35, struct kgsl_gpumem_free_id) + +/** + * struct kgsl_gpumem_get_info - argument to IOCTL_KGSL_GPUMEM_GET_INFO + * @gpuaddr: GPU address to query. Also set on return. + * @id: GPU allocation id to query. Also set on return. + * @flags: returned mask of KGSL_MEM* values. + * @size: returned size of the allocation. + * @mmapsize: returned size to pass mmap(), which may be larger than 'size' + * @useraddr: returned address of the userspace mapping for this buffer + * + * This ioctl allows querying of all user visible attributes of an existing + * allocation, by either the GPU address or the id returned by a previous + * call to IOCTL_KGSL_GPUMEM_ALLOC_ID. Legacy allocation ioctls may not + * return all attributes so this ioctl can be used to look them up if needed. + * + */ +struct kgsl_gpumem_get_info { + unsigned long gpuaddr; + unsigned int id; + unsigned int flags; + size_t size; + size_t mmapsize; + unsigned long useraddr; +/* private: reserved for future use*/ + unsigned long __pad[4]; +}; + +#define IOCTL_KGSL_GPUMEM_GET_INFO\ + _IOWR(KGSL_IOC_TYPE, 0x36, struct kgsl_gpumem_get_info) + +/** + * struct kgsl_gpumem_sync_cache - argument to IOCTL_KGSL_GPUMEM_SYNC_CACHE + * @gpuaddr: GPU address of the buffer to sync. + * @id: id of the buffer to sync. Either gpuaddr or id is sufficient. + * @op: a mask of KGSL_GPUMEM_CACHE_* values + * @offset: offset into the buffer + * @length: number of bytes starting from offset to perform + * the cache operation on + * + * Sync the L2 cache for memory headed to and from the GPU - this replaces + * KGSL_SHAREDMEM_FLUSH_CACHE since it can handle cache management for both + * directions + * + */ +struct kgsl_gpumem_sync_cache { + unsigned long gpuaddr; + unsigned int id; + unsigned int op; + size_t offset; + size_t length; +}; + +#define KGSL_GPUMEM_CACHE_CLEAN (1 << 0) +#define KGSL_GPUMEM_CACHE_TO_GPU KGSL_GPUMEM_CACHE_CLEAN + +#define KGSL_GPUMEM_CACHE_INV (1 << 1) +#define KGSL_GPUMEM_CACHE_FROM_GPU KGSL_GPUMEM_CACHE_INV + +#define KGSL_GPUMEM_CACHE_FLUSH \ + (KGSL_GPUMEM_CACHE_CLEAN | KGSL_GPUMEM_CACHE_INV) + +/* Flag to ensure backwards compatibility of kgsl_gpumem_sync_cache struct */ +#define KGSL_GPUMEM_CACHE_RANGE (1 << 31U) + +#define IOCTL_KGSL_GPUMEM_SYNC_CACHE \ + _IOW(KGSL_IOC_TYPE, 0x37, struct kgsl_gpumem_sync_cache) + +/** + * struct kgsl_perfcounter_get - argument to IOCTL_KGSL_PERFCOUNTER_GET + * @groupid: Performance counter group ID + * @countable: Countable to select within the group + * @offset: Return offset of the reserved LO counter + * @offset_hi: Return offset of the reserved HI counter + * + * Get an available performance counter from a specified groupid. The offset + * of the performance counter will be returned after successfully assigning + * the countable to the counter for the specified group. An error will be + * returned and an offset of 0 if the groupid is invalid or there are no + * more counters left. After successfully getting a perfcounter, the user + * must call kgsl_perfcounter_put(groupid, contable) when finished with + * the perfcounter to clear up perfcounter resources. + * + */ +struct kgsl_perfcounter_get { + unsigned int groupid; + unsigned int countable; + unsigned int offset; + unsigned int offset_hi; +/* private: reserved for future use */ + unsigned int __pad; /* For future binary compatibility */ +}; + +#define IOCTL_KGSL_PERFCOUNTER_GET \ + _IOWR(KGSL_IOC_TYPE, 0x38, struct kgsl_perfcounter_get) + +/** + * struct kgsl_perfcounter_put - argument to IOCTL_KGSL_PERFCOUNTER_PUT + * @groupid: Performance counter group ID + * @countable: Countable to release within the group + * + * Put an allocated performance counter to allow others to have access to the + * resource that was previously taken. This is only to be called after + * successfully getting a performance counter from kgsl_perfcounter_get(). + * + */ +struct kgsl_perfcounter_put { + unsigned int groupid; + unsigned int countable; +/* private: reserved for future use */ + unsigned int __pad[2]; /* For future binary compatibility */ +}; + +#define IOCTL_KGSL_PERFCOUNTER_PUT \ + _IOW(KGSL_IOC_TYPE, 0x39, struct kgsl_perfcounter_put) + +/** + * struct kgsl_perfcounter_query - argument to IOCTL_KGSL_PERFCOUNTER_QUERY + * @groupid: Performance counter group ID + * @countable: Return active countables array + * @size: Size of active countables array + * @max_counters: Return total number counters for the group ID + * + * Query the available performance counters given a groupid. The array + * *countables is used to return the current active countables in counters. + * The size of the array is passed in so the kernel will only write at most + * size or counter->size for the group id. The total number of available + * counters for the group ID is returned in max_counters. + * If the array or size passed in are invalid, then only the maximum number + * of counters will be returned, no data will be written to *countables. + * If the groupid is invalid an error code will be returned. + * + */ +struct kgsl_perfcounter_query { + unsigned int groupid; + /* Array to return the current countable for up to size counters */ + unsigned int __user *countables; + unsigned int count; + unsigned int max_counters; +/* private: reserved for future use */ + unsigned int __pad[2]; /* For future binary compatibility */ +}; + +#define IOCTL_KGSL_PERFCOUNTER_QUERY \ + _IOWR(KGSL_IOC_TYPE, 0x3A, struct kgsl_perfcounter_query) + +/** + * struct kgsl_perfcounter_query - argument to IOCTL_KGSL_PERFCOUNTER_QUERY + * @groupid: Performance counter group IDs + * @countable: Performance counter countable IDs + * @value: Return performance counter reads + * @size: Size of all arrays (groupid/countable pair and return value) + * + * Read in the current value of a performance counter given by the groupid + * and countable. + * + */ + +struct kgsl_perfcounter_read_group { + unsigned int groupid; + unsigned int countable; + unsigned long long value; +}; + +struct kgsl_perfcounter_read { + struct kgsl_perfcounter_read_group __user *reads; + unsigned int count; +/* private: reserved for future use */ + unsigned int __pad[2]; /* For future binary compatibility */ +}; + +#define IOCTL_KGSL_PERFCOUNTER_READ \ + _IOWR(KGSL_IOC_TYPE, 0x3B, struct kgsl_perfcounter_read) +/* + * struct kgsl_gpumem_sync_cache_bulk - argument to + * IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK + * @id_list: list of GPU buffer ids of the buffers to sync + * @count: number of GPU buffer ids in id_list + * @op: a mask of KGSL_GPUMEM_CACHE_* values + * + * Sync the cache for memory headed to and from the GPU. Certain + * optimizations can be made on the cache operation based on the total + * size of the working set of memory to be managed. + */ +struct kgsl_gpumem_sync_cache_bulk { + unsigned int __user *id_list; + unsigned int count; + unsigned int op; +/* private: reserved for future use */ + unsigned int __pad[2]; /* For future binary compatibility */ +}; + +#define IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK \ + _IOWR(KGSL_IOC_TYPE, 0x3C, struct kgsl_gpumem_sync_cache_bulk) + +/* + * struct kgsl_cmd_syncpoint_timestamp + * @context_id: ID of a KGSL context + * @timestamp: GPU timestamp + * + * This structure defines a syncpoint comprising a context/timestamp pair. A + * list of these may be passed by IOCTL_KGSL_SUBMIT_COMMANDS to define + * dependencies that must be met before the command can be submitted to the + * hardware + */ +struct kgsl_cmd_syncpoint_timestamp { + unsigned int context_id; + unsigned int timestamp; +}; + +struct kgsl_cmd_syncpoint_fence { + int fd; +}; + +/** + * struct kgsl_cmd_syncpoint - Define a sync point for a command batch + * @type: type of sync point defined here + * @priv: Pointer to the type specific buffer + * @size: Size of the type specific buffer + * + * This structure contains pointers defining a specific command sync point. + * The pointer and size should point to a type appropriate structure. + */ +struct kgsl_cmd_syncpoint { + int type; + void __user *priv; + size_t size; +}; + +/* Flag to indicate that the cmdlist may contain memlists */ +#define KGSL_IBDESC_MEMLIST 0x1 + +/* Flag to point out the cmdbatch profiling buffer in the memlist */ +#define KGSL_IBDESC_PROFILING_BUFFER 0x2 + +/** + * struct kgsl_submit_commands - Argument to IOCTL_KGSL_SUBMIT_COMMANDS + * @context_id: KGSL context ID that owns the commands + * @flags: + * @cmdlist: User pointer to a list of kgsl_ibdesc structures + * @numcmds: Number of commands listed in cmdlist + * @synclist: User pointer to a list of kgsl_cmd_syncpoint structures + * @numsyncs: Number of sync points listed in synclist + * @timestamp: On entry the a user defined timestamp, on exist the timestamp + * assigned to the command batch + * + * This structure specifies a command to send to the GPU hardware. This is + * similar to kgsl_issueibcmds expect that it doesn't support the legacy way to + * submit IB lists and it adds sync points to block the IB until the + * dependencies are satisified. This entry point is the new and preferred way + * to submit commands to the GPU. The memory list can be used to specify all + * memory that is referrenced in the current set of commands. + */ + +struct kgsl_submit_commands { + unsigned int context_id; + unsigned int flags; + struct kgsl_ibdesc __user *cmdlist; + unsigned int numcmds; + struct kgsl_cmd_syncpoint __user *synclist; + unsigned int numsyncs; + unsigned int timestamp; +/* private: reserved for future use */ + unsigned int __pad[4]; +}; + +#define IOCTL_KGSL_SUBMIT_COMMANDS \ + _IOWR(KGSL_IOC_TYPE, 0x3D, struct kgsl_submit_commands) + +/** + * struct kgsl_device_constraint - device constraint argument + * @context_id: KGSL context ID + * @type: type of constraint i.e pwrlevel/none + * @data: constraint data + * @size: size of the constraint data + */ +struct kgsl_device_constraint { + unsigned int type; + unsigned int context_id; + void __user *data; + size_t size; +}; + +/* Constraint Type*/ +#define KGSL_CONSTRAINT_NONE 0 +#define KGSL_CONSTRAINT_PWRLEVEL 1 + +/* PWRLEVEL constraint level*/ +/* set to min frequency */ +#define KGSL_CONSTRAINT_PWR_MIN 0 +/* set to max frequency */ +#define KGSL_CONSTRAINT_PWR_MAX 1 + +struct kgsl_device_constraint_pwrlevel { + unsigned int level; +}; + +/** + * struct kgsl_syncsource_create - Argument to IOCTL_KGSL_SYNCSOURCE_CREATE + * @id: returned id for the syncsource that was created. + * + * This ioctl creates a userspace sync timeline. + */ + +struct kgsl_syncsource_create { + unsigned int id; +/* private: reserved for future use */ + unsigned int __pad[3]; +}; + +#define IOCTL_KGSL_SYNCSOURCE_CREATE \ + _IOWR(KGSL_IOC_TYPE, 0x40, struct kgsl_syncsource_create) + +/** + * struct kgsl_syncsource_destroy - Argument to IOCTL_KGSL_SYNCSOURCE_DESTROY + * @id: syncsource id to destroy + * + * This ioctl creates a userspace sync timeline. + */ + +struct kgsl_syncsource_destroy { + unsigned int id; +/* private: reserved for future use */ + unsigned int __pad[3]; +}; + +#define IOCTL_KGSL_SYNCSOURCE_DESTROY \ + _IOWR(KGSL_IOC_TYPE, 0x41, struct kgsl_syncsource_destroy) + +/** + * struct kgsl_syncsource_create_fence - Argument to + * IOCTL_KGSL_SYNCSOURCE_CREATE_FENCE + * @id: syncsource id + * @fence_fd: returned sync_fence fd + * + * Create a fence that may be signaled by userspace by calling + * IOCTL_KGSL_SYNCSOURCE_SIGNAL_FENCE. There are no order dependencies between + * these fences. + */ +struct kgsl_syncsource_create_fence { + unsigned int id; + int fence_fd; +/* private: reserved for future use */ + unsigned int __pad[4]; +}; + +/** + * struct kgsl_syncsource_signal_fence - Argument to + * IOCTL_KGSL_SYNCSOURCE_SIGNAL_FENCE + * @id: syncsource id + * @fence_fd: sync_fence fd to signal + * + * Signal a fence that was created by a IOCTL_KGSL_SYNCSOURCE_CREATE_FENCE + * call using the same syncsource id. This allows a fence to be shared + * to other processes but only signaled by the process owning the fd + * used to create the fence. + */ +#define IOCTL_KGSL_SYNCSOURCE_CREATE_FENCE \ + _IOWR(KGSL_IOC_TYPE, 0x42, struct kgsl_syncsource_create_fence) + +struct kgsl_syncsource_signal_fence { + unsigned int id; + int fence_fd; +/* private: reserved for future use */ + unsigned int __pad[4]; +}; + +#define IOCTL_KGSL_SYNCSOURCE_SIGNAL_FENCE \ + _IOWR(KGSL_IOC_TYPE, 0x43, struct kgsl_syncsource_signal_fence) + +/** + * struct kgsl_cff_sync_gpuobj - Argument to IOCTL_KGSL_CFF_SYNC_GPUOBJ + * @offset: Offset into the GPU object to sync + * @length: Number of bytes to sync + * @id: ID of the GPU object to sync + */ +struct kgsl_cff_sync_gpuobj { + uint64_t offset; + uint64_t length; + unsigned int id; +}; + +#define IOCTL_KGSL_CFF_SYNC_GPUOBJ \ + _IOW(KGSL_IOC_TYPE, 0x44, struct kgsl_cff_sync_gpuobj) + +/** + * struct kgsl_gpuobj_alloc - Argument to IOCTL_KGSL_GPUOBJ_ALLOC + * @size: Size in bytes of the object to allocate + * @flags: mask of KGSL_MEMFLAG_* bits + * @va_len: Size in bytes of the virtual region to allocate + * @mmapsize: Returns the mmap() size of the object + * @id: Returns the GPU object ID of the new object + * @metadata_len: Length of the metdata to copy from the user + * @metadata: Pointer to the user specified metadata to store for the object + */ +struct kgsl_gpuobj_alloc { + uint64_t size; + uint64_t flags; + uint64_t va_len; + uint64_t mmapsize; + unsigned int id; + unsigned int metadata_len; + uint64_t metadata; +}; + +/* Let the user know that this header supports the gpuobj metadata */ +#define KGSL_GPUOBJ_ALLOC_METADATA_MAX 64 + +#define IOCTL_KGSL_GPUOBJ_ALLOC \ + _IOWR(KGSL_IOC_TYPE, 0x45, struct kgsl_gpuobj_alloc) + +/** + * struct kgsl_gpuobj_free - Argument to IOCTL_KGLS_GPUOBJ_FREE + * @flags: Mask of: KGSL_GUPOBJ_FREE_ON_EVENT + * @priv: Pointer to the private object if KGSL_GPUOBJ_FREE_ON_EVENT is + * specified + * @id: ID of the GPU object to free + * @type: If KGSL_GPUOBJ_FREE_ON_EVENT is specified, the type of asynchronous + * event to free on + * @len: Length of the data passed in priv + */ +struct kgsl_gpuobj_free { + uint64_t flags; + uint64_t __user priv; + unsigned int id; + unsigned int type; + unsigned int len; +}; + +#define KGSL_GPUOBJ_FREE_ON_EVENT 1 + +#define KGSL_GPU_EVENT_TIMESTAMP 1 +#define KGSL_GPU_EVENT_FENCE 2 + +/** + * struct kgsl_gpu_event_timestamp - Specifies a timestamp event to free a GPU + * object on + * @context_id: ID of the timestamp event to wait for + * @timestamp: Timestamp of the timestamp event to wait for + */ +struct kgsl_gpu_event_timestamp { + unsigned int context_id; + unsigned int timestamp; +}; + +/** + * struct kgsl_gpu_event_fence - Specifies a fence ID to to free a GPU object on + * @fd: File descriptor for the fence + */ +struct kgsl_gpu_event_fence { + int fd; +}; + +#define IOCTL_KGSL_GPUOBJ_FREE \ + _IOW(KGSL_IOC_TYPE, 0x46, struct kgsl_gpuobj_free) + +/** + * struct kgsl_gpuobj_info - argument to IOCTL_KGSL_GPUOBJ_INFO + * @gpuaddr: GPU address of the object + * @flags: Current flags for the object + * @size: Size of the object + * @va_len: VA size of the object + * @va_addr: Virtual address of the object (if it is mapped) + * id - GPU object ID of the object to query + */ +struct kgsl_gpuobj_info { + uint64_t gpuaddr; + uint64_t flags; + uint64_t size; + uint64_t va_len; + uint64_t va_addr; + unsigned int id; +}; + +#define IOCTL_KGSL_GPUOBJ_INFO \ + _IOWR(KGSL_IOC_TYPE, 0x47, struct kgsl_gpuobj_info) + +/** + * struct kgsl_gpuobj_import - argument to IOCTL_KGSL_GPUOBJ_IMPORT + * @priv: Pointer to the private data for the import type + * @priv_len: Length of the private data + * @flags: Mask of KGSL_MEMFLAG_ flags + * @type: Type of the import (KGSL_USER_MEM_TYPE_*) + * @id: Returns the ID of the new GPU object + */ +struct kgsl_gpuobj_import { + uint64_t __user priv; + uint64_t priv_len; + uint64_t flags; + unsigned int type; + unsigned int id; +}; + +/** + * struct kgsl_gpuobj_import_dma_buf - import a dmabuf object + * @fd: File descriptor for the dma-buf object + */ +struct kgsl_gpuobj_import_dma_buf { + int fd; +}; + +/** + * struct kgsl_gpuobj_import_useraddr - import an object based on a useraddr + * @virtaddr: Virtual address of the object to import + */ +struct kgsl_gpuobj_import_useraddr { + uint64_t virtaddr; +}; + +#define IOCTL_KGSL_GPUOBJ_IMPORT \ + _IOWR(KGSL_IOC_TYPE, 0x48, struct kgsl_gpuobj_import) + +/** + * struct kgsl_gpuobj_sync_obj - Individual GPU object to sync + * @offset: Offset within the GPU object to sync + * @length: Number of bytes to sync + * @id: ID of the GPU object to sync + * @op: Cache operation to execute + */ + +struct kgsl_gpuobj_sync_obj { + uint64_t offset; + uint64_t length; + unsigned int id; + unsigned int op; +}; + +/** + * struct kgsl_gpuobj_sync - Argument for IOCTL_KGSL_GPUOBJ_SYNC + * @objs: Pointer to an array of kgsl_gpuobj_sync_obj structs + * @obj_len: Size of each item in the array + * @count: Number of items in the array + */ + +struct kgsl_gpuobj_sync { + uint64_t __user objs; + unsigned int obj_len; + unsigned int count; +}; + +#define IOCTL_KGSL_GPUOBJ_SYNC \ + _IOW(KGSL_IOC_TYPE, 0x49, struct kgsl_gpuobj_sync) + +/** + * struct kgsl_command_object - GPU command object + * @offset: GPU address offset of the object + * @gpuaddr: GPU address of the object + * @size: Size of the object + * @flags: Current flags for the object + * @id - GPU command object ID + */ +struct kgsl_command_object { + uint64_t offset; + uint64_t gpuaddr; + uint64_t size; + unsigned int flags; + unsigned int id; +}; + +/** + * struct kgsl_command_syncpoint - GPU syncpoint object + * @priv: Pointer to the type specific buffer + * @size: Size of the type specific buffer + * @type: type of sync point defined here + */ +struct kgsl_command_syncpoint { + uint64_t __user priv; + uint64_t size; + unsigned int type; +}; + +/** + * struct kgsl_command_object - Argument for IOCTL_KGSL_GPU_COMMAND + * @flags: Current flags for the object + * @cmdlist: List of kgsl_command_objects for submission + * @cmd_size: Size of kgsl_command_objects structure + * @numcmds: Number of kgsl_command_objects in command list + * @objlist: List of kgsl_command_objects for tracking + * @obj_size: Size of kgsl_command_objects structure + * @numobjs: Number of kgsl_command_objects in object list + * @synclist: List of kgsl_command_syncpoints + * @sync_size: Size of kgsl_command_syncpoint structure + * @numsyncs: Number of kgsl_command_syncpoints in syncpoint list + * @context_id: Context ID submittin ghte kgsl_gpu_command + * @timestamp: Timestamp for the submitted commands + */ +struct kgsl_gpu_command { + uint64_t flags; + uint64_t __user cmdlist; + unsigned int cmdsize; + unsigned int numcmds; + uint64_t __user objlist; + unsigned int objsize; + unsigned int numobjs; + uint64_t __user synclist; + unsigned int syncsize; + unsigned int numsyncs; + unsigned int context_id; + unsigned int timestamp; +}; + +#define IOCTL_KGSL_GPU_COMMAND \ + _IOWR(KGSL_IOC_TYPE, 0x4A, struct kgsl_gpu_command) + +/** + * struct kgsl_preemption_counters_query - argument to + * IOCTL_KGSL_PREEMPTIONCOUNTER_QUERY + * @counters: Return preemption counters array + * @size_user: Size allocated by userspace + * @size_priority_level: Size of preemption counters for each + * priority level + * @max_priority_level: Return max number of priority levels + * + * Query the available preemption counters. The array counters + * is used to return preemption counters. The size of the array + * is passed in so the kernel will only write at most size_user + * or max available preemption counters. The total number of + * preemption counters is returned in max_priority_level. If the + * array or size passed in are invalid, then an error is + * returned back. + */ +struct kgsl_preemption_counters_query { + uint64_t __user counters; + unsigned int size_user; + unsigned int size_priority_level; + unsigned int max_priority_level; +}; + +#define IOCTL_KGSL_PREEMPTIONCOUNTER_QUERY \ + _IOWR(KGSL_IOC_TYPE, 0x4B, struct kgsl_preemption_counters_query) + +/** + * struct kgsl_gpuobj_set_info - argument for IOCTL_KGSL_GPUOBJ_SET_INFO + * @flags: Flags to indicate which paramaters to change + * @metadata: If KGSL_GPUOBJ_SET_INFO_METADATA is set, a pointer to the new + * metadata + * @id: GPU memory object ID to change + * @metadata_len: If KGSL_GPUOBJ_SET_INFO_METADATA is set, the length of the + * new metadata string + * @type: If KGSL_GPUOBJ_SET_INFO_TYPE is set, the new type of the memory object + */ + +#define KGSL_GPUOBJ_SET_INFO_METADATA (1 << 0) +#define KGSL_GPUOBJ_SET_INFO_TYPE (1 << 1) + +struct kgsl_gpuobj_set_info { + uint64_t flags; + uint64_t metadata; + unsigned int id; + unsigned int metadata_len; + unsigned int type; +}; + +#define IOCTL_KGSL_GPUOBJ_SET_INFO \ + _IOW(KGSL_IOC_TYPE, 0x4C, struct kgsl_gpuobj_set_info) + +#endif /* _UAPI_MSM_KGSL_H */ diff --git a/selfdrive/modeld/thneed/thneed.cc b/selfdrive/modeld/thneed/thneed.cc new file mode 100644 index 0000000000..11f10cfeb5 --- /dev/null +++ b/selfdrive/modeld/thneed/thneed.cc @@ -0,0 +1,458 @@ +#include "thneed.h" +#include +#include +#include +#include +#include +#include + +Thneed *g_thneed = NULL; +int g_fd = -1; +map, string> g_args; + +static inline uint64_t nanos_since_boot() { + struct timespec t; + clock_gettime(CLOCK_BOOTTIME, &t); + return t.tv_sec * 1000000000ULL + t.tv_nsec; +} + +void hexdump(uint32_t *d, int len) { + assert((len%4) == 0); + printf(" dumping %p len 0x%x\n", d, len); + for (int i = 0; i < len/4; i++) { + if (i != 0 && (i%0x10) == 0) printf("\n"); + printf("%8x ", d[i]); + } + printf("\n"); +} + +extern "C" { + +int (*my_ioctl)(int filedes, unsigned long request, void *argp) = NULL; +#undef ioctl +int ioctl(int filedes, unsigned long request, void *argp) { + if (my_ioctl == NULL) my_ioctl = reinterpret_cast(dlsym(RTLD_NEXT, "ioctl")); + Thneed *thneed = g_thneed; + + // save the fd + if (request == IOCTL_KGSL_GPUOBJ_ALLOC) g_fd = filedes; + + if (thneed != NULL) { + if (request == IOCTL_KGSL_GPU_COMMAND) { + struct kgsl_gpu_command *cmd = (struct kgsl_gpu_command *)argp; + if (thneed->record & 1) { + thneed->timestamp = cmd->timestamp; + thneed->context_id = cmd->context_id; + thneed->cmds.push_back(unique_ptr(new CachedCommand(thneed, cmd))); + } + if (thneed->record & 2) { + printf("IOCTL_KGSL_GPU_COMMAND(%2zu): flags: 0x%lx context_id: %u timestamp: %u\n", + thneed->cmds.size(), + cmd->flags, + cmd->context_id, cmd->timestamp); + } + } else if (request == IOCTL_KGSL_GPUOBJ_SYNC) { + struct kgsl_gpuobj_sync *cmd = (struct kgsl_gpuobj_sync *)argp; + struct kgsl_gpuobj_sync_obj *objs = (struct kgsl_gpuobj_sync_obj *)(cmd->objs); + + if (thneed->record & 2) { + printf("IOCTL_KGSL_GPUOBJ_SYNC count:%d ", cmd->count); + for (int i = 0; i < cmd->count; i++) { + printf(" -- offset:0x%lx len:0x%lx id:%d op:%d ", objs[i].offset, objs[i].length, objs[i].id, objs[i].op); + } + printf("\n"); + } + + if (thneed->record & 1) { + thneed->syncobjs.push_back(string((char *)objs, sizeof(struct kgsl_gpuobj_sync_obj)*cmd->count)); + } + } else if (request == IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID) { + struct kgsl_device_waittimestamp_ctxtid *cmd = (struct kgsl_device_waittimestamp_ctxtid *)argp; + if (thneed->record & 2) { + printf("IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID: context_id: %d timestamp: %d timeout: %d\n", + cmd->context_id, cmd->timestamp, cmd->timeout); + } + } else if (request == IOCTL_KGSL_SETPROPERTY) { + if (thneed->record & 2) { + struct kgsl_device_getproperty *prop = (struct kgsl_device_getproperty *)argp; + printf("IOCTL_KGSL_SETPROPERTY: 0x%x sizebytes:%zu\n", prop->type, prop->sizebytes); + if (thneed->record & 4) { + hexdump((uint32_t *)prop->value, prop->sizebytes); + if (prop->type == KGSL_PROP_PWR_CONSTRAINT) { + struct kgsl_device_constraint *constraint = (struct kgsl_device_constraint *)prop->value; + hexdump((uint32_t *)constraint->data, constraint->size); + } + } + } + } + } + + int ret = my_ioctl(filedes, request, argp); + if (ret != 0) printf("ioctl returned %d with errno %d\n", ret, errno); + return ret; +} + +} + +GPUMalloc::GPUMalloc(int size, int fd) { + struct kgsl_gpuobj_alloc alloc; + memset(&alloc, 0, sizeof(alloc)); + alloc.size = size; + alloc.flags = 0x10000a00; + ioctl(fd, IOCTL_KGSL_GPUOBJ_ALLOC, &alloc); + void *addr = mmap64(NULL, alloc.mmapsize, 0x3, 0x1, fd, alloc.id*0x1000); + assert(addr != MAP_FAILED); + + base = (uint64_t)addr; + remaining = size; +} + +GPUMalloc::~GPUMalloc() { + // TODO: free the GPU malloced area +} + +void *GPUMalloc::alloc(int size) { + if (size > remaining) return NULL; + remaining -= size; + void *ret = (void*)base; + base += (size+0xff) & (~0xFF); + return ret; +} + +CachedCommand::CachedCommand(Thneed *lthneed, struct kgsl_gpu_command *cmd) { + thneed = lthneed; + assert(cmd->numcmds == 2); + assert(cmd->numobjs == 1); + assert(cmd->numsyncs == 0); + + memcpy(cmds, (void *)cmd->cmdlist, sizeof(struct kgsl_command_object)*2); + memcpy(objs, (void *)cmd->objlist, sizeof(struct kgsl_command_object)*1); + + memcpy(&cache, cmd, sizeof(cache)); + cache.cmdlist = (uint64_t)cmds; + cache.objlist = (uint64_t)objs; + + for (int i = 0; i < cmd->numcmds; i++) { + void *nn = thneed->ram->alloc(cmds[i].size); + memcpy(nn, (void*)cmds[i].gpuaddr, cmds[i].size); + cmds[i].gpuaddr = (uint64_t)nn; + } + + for (int i = 0; i < cmd->numobjs; i++) { + void *nn = thneed->ram->alloc(objs[i].size); + memset(nn, 0, objs[i].size); + objs[i].gpuaddr = (uint64_t)nn; + } +} + +void CachedCommand::exec(bool wait) { + cache.timestamp = ++thneed->timestamp; + int ret = ioctl(thneed->fd, IOCTL_KGSL_GPU_COMMAND, &cache); + + if (wait) { + struct kgsl_device_waittimestamp_ctxtid wait; + wait.context_id = cache.context_id; + wait.timestamp = cache.timestamp; + wait.timeout = -1; + + uint64_t tb = nanos_since_boot(); + int wret = ioctl(thneed->fd, IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID, &wait); + uint64_t te = nanos_since_boot(); + + if (thneed->record & 2) printf("exec %d wait %d after %lu us\n", ret, wret, (te-tb)/1000); + } else { + if (thneed->record & 2) printf("CachedCommand::exec got %d\n", ret); + } + + assert(ret == 0); +} + +Thneed::Thneed() { + assert(g_fd != -1); + fd = g_fd; + ram = make_unique(0x40000, fd); + record = 1; + timestamp = -1; + g_thneed = this; +} + +void Thneed::stop() { + record = 0; +} + +//#define SAVE_LOG + +void Thneed::execute(float **finputs, float *foutput, bool slow) { + uint64_t tb, te; + if (record & 2) tb = nanos_since_boot(); + + #ifdef SAVE_LOG + char fn[0x100]; + snprintf(fn, sizeof(fn), "/tmp/thneed_log_%d", timestamp); + FILE *f = fopen(fn, "wb"); + #endif + + // ****** copy inputs + for (int idx = 0; idx < inputs.size(); ++idx) { + size_t sz; + clGetMemObjectInfo(inputs[idx], CL_MEM_SIZE, sizeof(sz), &sz, NULL); + + #ifdef SAVE_LOG + fwrite(&sz, 1, sizeof(sz), f); + fwrite(finputs[idx], 1, sz, f); + #endif + + if (record & 2) printf("copying %lu -- %p -> %p\n", sz, finputs[idx], inputs[idx]); + clEnqueueWriteBuffer(command_queue, inputs[idx], CL_TRUE, 0, sz, finputs[idx], 0, NULL, NULL); + } + + // ****** set power constraint + struct kgsl_device_constraint_pwrlevel pwrlevel; + pwrlevel.level = KGSL_CONSTRAINT_PWR_MAX; + + struct kgsl_device_constraint constraint; + constraint.type = KGSL_CONSTRAINT_PWRLEVEL; + constraint.context_id = context_id; + constraint.data = (void*)&pwrlevel; + constraint.size = sizeof(pwrlevel); + + struct kgsl_device_getproperty prop; + prop.type = KGSL_PROP_PWR_CONSTRAINT; + prop.value = (void*)&constraint; + prop.sizebytes = sizeof(constraint); + int ret = ioctl(fd, IOCTL_KGSL_SETPROPERTY, &prop); + assert(ret == 0); + + // ****** run commands + int i = 0; + for (auto it = cmds.begin(); it != cmds.end(); ++it) { + ++i; + if (record & 2) printf("run %2d: ", i); + (*it)->exec((i == cmds.size()) || slow); + } + + // ****** sync objects + for (auto it = syncobjs.begin(); it != syncobjs.end(); ++it) { + struct kgsl_gpuobj_sync cmd; + + cmd.objs = (uint64_t)it->data(); + cmd.obj_len = it->length(); + cmd.count = it->length() / sizeof(struct kgsl_gpuobj_sync_obj); + + ret = ioctl(fd, IOCTL_KGSL_GPUOBJ_SYNC, &cmd); + assert(ret == 0); + } + + // ****** copy outputs + size_t sz; + clGetMemObjectInfo(output, CL_MEM_SIZE, sizeof(sz), &sz, NULL); + if (record & 2) printf("copying %lu for output %p -> %p\n", sz, output, foutput); + clEnqueueReadBuffer(command_queue, output, CL_TRUE, 0, sz, foutput, 0, NULL, NULL); + + #ifdef SAVE_LOG + fwrite(&sz, 1, sizeof(sz), f); + fwrite(foutput, 1, sz, f); + fclose(f); + #endif + + // ****** unset power constraint + constraint.type = KGSL_CONSTRAINT_NONE; + constraint.data = NULL; + constraint.size = 0; + + ret = ioctl(fd, IOCTL_KGSL_SETPROPERTY, &prop); + assert(ret == 0); + + if (record & 2) { + te = nanos_since_boot(); + printf("model exec in %lu us\n", (te-tb)/1000); + } +} + +// TODO: with a different way of getting the input and output buffers, we don't have to intercept CL at all + +cl_int (*my_clSetKernelArg)(cl_kernel kernel, cl_uint arg_index, size_t arg_size, const void *arg_value) = NULL; +cl_int thneed_clSetKernelArg(cl_kernel kernel, cl_uint arg_index, size_t arg_size, const void *arg_value) { + if (my_clSetKernelArg == NULL) my_clSetKernelArg = reinterpret_cast(dlsym(RTLD_NEXT, "REAL_clSetKernelArg")); + if (arg_value != NULL) { + g_args[make_pair(kernel, arg_index)] = string((char*)arg_value, arg_size); + } + cl_int ret = my_clSetKernelArg(kernel, arg_index, arg_size, arg_value); + return ret; +} + +cl_int (*my_clEnqueueNDRangeKernel)(cl_command_queue, cl_kernel, cl_uint, const size_t *, const size_t *, const size_t *, cl_uint, const cl_event *, cl_event *) = NULL; +cl_int thneed_clEnqueueNDRangeKernel(cl_command_queue command_queue, + cl_kernel kernel, + cl_uint work_dim, + const size_t *global_work_offset, + const size_t *global_work_size, + const size_t *local_work_size, + cl_uint num_events_in_wait_list, + const cl_event *event_wait_list, + cl_event *event) { + + if (my_clEnqueueNDRangeKernel == NULL) my_clEnqueueNDRangeKernel = reinterpret_cast(dlsym(RTLD_NEXT, "REAL_clEnqueueNDRangeKernel")); + Thneed *thneed = g_thneed; + + // SNPE doesn't use these + assert(num_events_in_wait_list == 0); + assert(global_work_offset == NULL); + + char name[0x100]; + clGetKernelInfo(kernel, CL_KERNEL_FUNCTION_NAME, sizeof(name), name, NULL); + + cl_uint num_args; + clGetKernelInfo(kernel, CL_KERNEL_NUM_ARGS, sizeof(num_args), &num_args, NULL); + + if (thneed != NULL && thneed->record & 1) { + thneed->command_queue = command_queue; + for (int i = 0; i < num_args; i++) { + char arg_name[0x100]; + clGetKernelArgInfo(kernel, i, CL_KERNEL_ARG_NAME, sizeof(arg_name), arg_name, NULL); + string arg = g_args[make_pair(kernel, i)]; + + if (strcmp(arg_name, "input") == 0 && strcmp(name, "zero_pad_image_float") == 0) { + cl_mem mem; + memcpy(&mem, (void*)arg.data(), sizeof(mem)); + thneed->inputs.push_back(mem); + } + + if (strcmp(arg_name, "output") == 0 && strcmp(name, "image2d_to_buffer_float") == 0) { + cl_mem mem; + memcpy(&mem, (void*)arg.data(), sizeof(mem)); + thneed->output = mem; + } + } + } + if (thneed != NULL && thneed->record & 2) { + printf("%p %56s -- ", kernel, name); + for (int i = 0; i < work_dim; i++) { + printf("%4zu ", global_work_size[i]); + } + printf(" -- "); + for (int i = 0; i < work_dim; i++) { + printf("%4zu ", local_work_size[i]); + } + printf("\n"); + } + if (thneed != NULL && thneed->record & 4) { + // extreme debug + for (int i = 0; i < num_args; i++) { + char arg_type[0x100]; + char arg_name[0x100]; + clGetKernelArgInfo(kernel, i, CL_KERNEL_ARG_TYPE_NAME, sizeof(arg_type), arg_type, NULL); + clGetKernelArgInfo(kernel, i, CL_KERNEL_ARG_NAME, sizeof(arg_name), arg_name, NULL); + string arg = g_args[make_pair(kernel, i)]; + printf(" %s %s", arg_type, arg_name); + void *arg_value = (void*)arg.data(); + int arg_size = arg.size(); + if (arg_size == 1) { + printf(" = %d", *((char*)arg_value)); + } else if (arg_size == 2) { + printf(" = %d", *((short*)arg_value)); + } else if (arg_size == 4) { + if (strcmp(arg_type, "float") == 0) { + printf(" = %f", *((float*)arg_value)); + } else { + printf(" = %d", *((int*)arg_value)); + } + } else if (arg_size == 8) { + cl_mem val = (cl_mem)(*((uintptr_t*)arg_value)); + printf(" = %p", val); + if (val != NULL) { + if (strcmp("image2d_t", arg_type) == 0 || strcmp("image1d_t", arg_type) == 0) { + cl_image_format format; + size_t width, height, depth, array_size, row_pitch, slice_pitch; + clGetImageInfo(val, CL_IMAGE_FORMAT, sizeof(format), &format, NULL); + assert(format.image_channel_data_type == CL_HALF_FLOAT); + clGetImageInfo(val, CL_IMAGE_WIDTH, sizeof(width), &width, NULL); + clGetImageInfo(val, CL_IMAGE_HEIGHT, sizeof(height), &height, NULL); + clGetImageInfo(val, CL_IMAGE_DEPTH, sizeof(depth), &depth, NULL); + clGetImageInfo(val, CL_IMAGE_ARRAY_SIZE, sizeof(array_size), &array_size, NULL); + clGetImageInfo(val, CL_IMAGE_ROW_PITCH, sizeof(row_pitch), &row_pitch, NULL); + clGetImageInfo(val, CL_IMAGE_SLICE_PITCH, sizeof(slice_pitch), &slice_pitch, NULL); + assert(depth == 0); + assert(array_size == 0); + assert(slice_pitch == 0); + + printf(" image %zu x %zu rp %zu", width, height, row_pitch); + } else { + size_t sz; + clGetMemObjectInfo(val, CL_MEM_SIZE, sizeof(sz), &sz, NULL); + printf(" buffer %zu", sz); + } + } + } + printf("\n"); + } + } + + cl_int ret = my_clEnqueueNDRangeKernel(command_queue, kernel, work_dim, + global_work_offset, global_work_size, local_work_size, + num_events_in_wait_list, event_wait_list, event); + + /*uint64_t tb = nanos_since_boot(); + clWaitForEvents(1, event); + uint64_t te = nanos_since_boot(); + if (thneed != NULL && thneed->record & 2) { + printf(" wait %lu us\n", (te-tb)/1000); + }*/ + + return ret; +} + +//#define SAVE_KERNELS + +#ifdef SAVE_KERNELS +map program_source; + +cl_program (*my_clCreateProgramWithSource)(cl_context context, cl_uint count, const char **strings, const size_t *lengths, cl_int *errcode_ret) = NULL; +cl_program thneed_clCreateProgramWithSource(cl_context context, cl_uint count, const char **strings, const size_t *lengths, cl_int *errcode_ret) { + if (my_clCreateProgramWithSource == NULL) my_clCreateProgramWithSource = reinterpret_cast(dlsym(RTLD_NEXT, "REAL_clCreateProgramWithSource")); + assert(count == 1); + size_t my_lengths[1]; + my_lengths[0] = lengths[0]; + + char fn[0x100]; + snprintf(fn, sizeof(fn), "/tmp/program_%zu.cl", strlen(strings[0])); + FILE *f = fopen(fn, "wb"); + fprintf(f, "%s", strings[0]); + fclose(f); + + char tmp[0x10000]; + memset(tmp, 0, sizeof(tmp)); + snprintf(fn, sizeof(fn), "/tmp/patched_%zu.cl", strlen(strings[0])); + FILE *g = fopen(fn, "rb"); + if (g != NULL) { + printf("LOADING PATCHED PROGRAM %s\n", fn); + fread(tmp, 1, sizeof(tmp), g); + fclose(g); + strings[0] = tmp; + my_lengths[0] = strlen(tmp); + } + + program_source[ret] = strings[0]; + + cl_program ret = my_clCreateProgramWithSource(context, count, strings, my_lengths, errcode_ret); + return ret; +} +#endif + +void *dlsym(void *handle, const char *symbol) { + void *(*my_dlsym)(void *handle, const char *symbol) = (void *(*)(void *handle, const char *symbol))((uintptr_t)dlopen-0x2d4); + if (memcmp("REAL_", symbol, 5) == 0) { + return my_dlsym(handle, symbol+5); + } else if (strcmp("clEnqueueNDRangeKernel", symbol) == 0) { + return (void*)thneed_clEnqueueNDRangeKernel; + } else if (strcmp("clSetKernelArg", symbol) == 0) { + return (void*)thneed_clSetKernelArg; +#ifdef SAVE_KERNELS + } else if (strcmp("clCreateProgramWithSource", symbol) == 0) { + return (void*)thneed_clCreateProgramWithSource; +#endif + } else { + return my_dlsym(handle, symbol); + } +} + diff --git a/selfdrive/modeld/thneed/thneed.h b/selfdrive/modeld/thneed/thneed.h new file mode 100644 index 0000000000..36f0bfed7f --- /dev/null +++ b/selfdrive/modeld/thneed/thneed.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include "include/msm_kgsl.h" +#include +#include + +using namespace std; + +class Thneed; + +class GPUMalloc { + public: + GPUMalloc(int size, int fd); + ~GPUMalloc(); + void *alloc(int size); + private: + uint64_t base; + int remaining; +}; + +class CachedCommand { + public: + CachedCommand(Thneed *lthneed, struct kgsl_gpu_command *cmd); + void exec(bool wait); + void disassemble(); + private: + struct kgsl_gpu_command cache; + struct kgsl_command_object cmds[2]; + struct kgsl_command_object objs[1]; + Thneed *thneed; +}; + +class Thneed { + public: + Thneed(); + void stop(); + void execute(float **finputs, float *foutput, bool slow=false); + + vector inputs; + cl_mem output; + + cl_command_queue command_queue; + int context_id; + + // protected? + int record; + int timestamp; + unique_ptr ram; + vector > cmds; + vector syncobjs; + int fd; +}; + diff --git a/selfdrive/modeld/visiontest.c b/selfdrive/modeld/visiontest.c index 325e257e86..2ce68ad9c1 100644 --- a/selfdrive/modeld/visiontest.c +++ b/selfdrive/modeld/visiontest.c @@ -33,28 +33,8 @@ typedef struct { void initialize_opencl(VisionTest* visiontest) { // init cl - /* Get Platform and Device Info */ - cl_platform_id platform_ids[16] = {0}; - cl_uint num_platforms; - int err = clGetPlatformIDs(16, platform_ids, &num_platforms); - if (err != 0) { - fprintf(stderr, "cl error: %d\n", err); - } - assert(err == 0); - - // try to find a CPU device - cl_device_id device_id = NULL; - for (int i=0; icontext = clCreateContext(NULL, 1, &device_id, NULL, NULL, &err); assert(err == 0); diff --git a/selfdrive/modeld/visiontest.py b/selfdrive/modeld/visiontest.py index f3c10c5986..6f97684244 100644 --- a/selfdrive/modeld/visiontest.py +++ b/selfdrive/modeld/visiontest.py @@ -8,11 +8,12 @@ _visiond_dir = os.path.dirname(os.path.abspath(__file__)) _libvisiontest = "libvisiontest.so" try: # bacause this crashes somtimes when running pipeline subprocess.check_output(["make", "-C", _visiond_dir, "-f", - os.path.join(_visiond_dir, "visiontest.mk"), - _libvisiontest]) + os.path.join(_visiond_dir, "visiontest.mk"), + _libvisiontest]) except Exception: pass + class VisionTest(): """A version of the vision model that can be run on a desktop. @@ -64,7 +65,7 @@ class VisionTest(): raise ValueError("Bad model name: {}".format(model)) prevdir = os.getcwd() - os.chdir(_visiond_dir) # tmp hack to find kernels + os.chdir(_visiond_dir) # tmp hack to find kernels os.environ['BASEDIR'] = BASEDIR self._visiontest_c = self.clib.visiontest_create( temporal_model, disable_model, self._input_size[0], self._input_size[1], @@ -103,10 +104,9 @@ class VisionTest(): transform) return result - def transform_output_buffer(self, yuv_data, y_out, u_out, v_out, transform): - assert len(yuv_data) == self.input_size[0] * self.input_size[1] * 3/2 + assert len(yuv_data) == self.input_size[0] * self.input_size[1] * 3 / 2 cast = self.ffi.cast from_buffer = self.ffi.from_buffer @@ -127,7 +127,7 @@ class VisionTest(): def __enter__(self): return self - def __exit__(self, type, value, traceback): + def __exit__(self, exc_type, exc_value, traceback): self.close() diff --git a/selfdrive/controls/dmonitoringd.py b/selfdrive/monitoring/dmonitoringd.py similarity index 77% rename from selfdrive/controls/dmonitoringd.py rename to selfdrive/monitoring/dmonitoringd.py index 06cf556005..6b0d184bfe 100755 --- a/selfdrive/controls/dmonitoringd.py +++ b/selfdrive/monitoring/dmonitoringd.py @@ -5,16 +5,13 @@ from common.realtime import set_realtime_priority from common.params import Params import cereal.messaging as messaging from selfdrive.controls.lib.events import Events -from selfdrive.controls.lib.driver_monitor import DriverStatus, MAX_TERMINAL_ALERTS, MAX_TERMINAL_DURATION +from selfdrive.monitoring.driver_monitor import DriverStatus, MAX_TERMINAL_ALERTS, MAX_TERMINAL_DURATION from selfdrive.locationd.calibration_helpers import Calibration + def dmonitoringd_thread(sm=None, pm=None): gc.disable() - - # start the loop - set_realtime_priority(3) - - params = Params() + set_realtime_priority(53) # Pub/Sub Sockets if pm is None: @@ -23,21 +20,23 @@ def dmonitoringd_thread(sm=None, pm=None): if sm is None: sm = messaging.SubMaster(['driverState', 'liveCalibration', 'carState', 'model']) + is_rhd = Params().get("IsRHD") + offroad = Params().get("IsOffroad") == b"1" + driver_status = DriverStatus() - is_rhd = params.get("IsRHD") - if is_rhd is not None: - driver_status.is_rhd_region = bool(int(is_rhd)) - driver_status.is_rhd_region_checked = True + driver_status.is_rhd_region = is_rhd == b"1" + driver_status.is_rhd_region_checked = is_rhd is not None sm['liveCalibration'].calStatus = Calibration.INVALID + sm['liveCalibration'].rpyCalib = [0, 0, 0] sm['carState'].vEgo = 0. sm['carState'].cruiseState.enabled = False sm['carState'].cruiseState.speed = 0. sm['carState'].buttonEvents = [] sm['carState'].steeringPressed = False + sm['carState'].gasPressed = False sm['carState'].standstill = True - cal_rpy = [0,0,0] v_cruise_last = 0 driver_engaged = False @@ -45,37 +44,33 @@ def dmonitoringd_thread(sm=None, pm=None): while True: sm.update() - # Handle calibration - if sm.updated['liveCalibration']: - if sm['liveCalibration'].calStatus == Calibration.CALIBRATED: - if len(sm['liveCalibration'].rpyCalib) == 3: - cal_rpy = sm['liveCalibration'].rpyCalib - # Get interaction if sm.updated['carState']: v_cruise = sm['carState'].cruiseState.speed driver_engaged = len(sm['carState'].buttonEvents) > 0 or \ v_cruise != v_cruise_last or \ - sm['carState'].steeringPressed + sm['carState'].steeringPressed or \ + sm['carState'].gasPressed if driver_engaged: driver_status.update(Events(), True, sm['carState'].cruiseState.enabled, sm['carState'].standstill) v_cruise_last = v_cruise - # Get model meta if sm.updated['model']: driver_status.set_policy(sm['model']) # Get data from dmonitoringmodeld if sm.updated['driverState']: events = Events() - driver_status.get_pose(sm['driverState'], cal_rpy, sm['carState'].vEgo, sm['carState'].cruiseState.enabled) - # Block any engage after certain distrations + driver_status.get_pose(sm['driverState'], sm['liveCalibration'].rpyCalib, sm['carState'].vEgo, sm['carState'].cruiseState.enabled) + + # Block engaging after max number of distrations if driver_status.terminal_alert_cnt >= MAX_TERMINAL_ALERTS or driver_status.terminal_time >= MAX_TERMINAL_DURATION: events.add(car.CarEvent.EventName.tooDistracted) + # Update events from driver state driver_status.update(events, driver_engaged, sm['carState'].cruiseState.enabled, sm['carState'].standstill) - # dMonitoringState packet + # build dMonitoringState packet dat = messaging.new_message('dMonitoringState') dat.dMonitoringState = { "events": events.to_msg(), @@ -93,7 +88,7 @@ def dmonitoringd_thread(sm=None, pm=None): "awarenessPassive": driver_status.awareness_passive, "isLowStd": driver_status.pose.low_std, "hiStdCount": driver_status.hi_stds, - "isPreview": False, + "isPreview": offroad, } pm.send('dMonitoringState', dat) diff --git a/selfdrive/controls/lib/driver_monitor.py b/selfdrive/monitoring/driver_monitor.py similarity index 87% rename from selfdrive/controls/lib/driver_monitor.py rename to selfdrive/monitoring/driver_monitor.py index 54785df073..76487e24e3 100644 --- a/selfdrive/controls/lib/driver_monitor.py +++ b/selfdrive/monitoring/driver_monitor.py @@ -21,33 +21,34 @@ _DISTRACTED_TIME = 11. _DISTRACTED_PRE_TIME_TILL_TERMINAL = 8. _DISTRACTED_PROMPT_TIME_TILL_TERMINAL = 6. -_FACE_THRESHOLD = 0.4 +_FACE_THRESHOLD = 0.6 _EYE_THRESHOLD = 0.6 -_BLINK_THRESHOLD = 0.5 # 0.225 +_SG_THRESHOLD = 0.5 +_BLINK_THRESHOLD = 0.5 # 0.225 _BLINK_THRESHOLD_SLACK = 0.65 _BLINK_THRESHOLD_STRICT = 0.5 -_PITCH_WEIGHT = 1.35 # 1.5 # pitch matters a lot more +_PITCH_WEIGHT = 1.35 # 1.5 # pitch matters a lot more _POSESTD_THRESHOLD = 0.14 _METRIC_THRESHOLD = 0.4 _METRIC_THRESHOLD_SLACK = 0.55 _METRIC_THRESHOLD_STRICT = 0.4 -_PITCH_POS_ALLOWANCE = 0.12 # rad, to not be too sensitive on positive pitch -_PITCH_NATURAL_OFFSET = 0.02 # people don't seem to look straight when they drive relaxed, rather a bit up -_YAW_NATURAL_OFFSET = 0.08 # people don't seem to look straight when they drive relaxed, rather a bit to the right (center of car) +_PITCH_POS_ALLOWANCE = 0.12 # rad, to not be too sensitive on positive pitch +_PITCH_NATURAL_OFFSET = 0.02 # people don't seem to look straight when they drive relaxed, rather a bit up +_YAW_NATURAL_OFFSET = 0.08 # people don't seem to look straight when they drive relaxed, rather a bit to the right (center of car) _HI_STD_TIMEOUT = 5 -_HI_STD_FALLBACK_TIME = 10 # fall back to wheel touch if model is uncertain for a long time +_HI_STD_FALLBACK_TIME = 10 # fall back to wheel touch if model is uncertain for a long time _DISTRACTED_FILTER_TS = 0.25 # 0.6Hz -_POSE_CALIB_MIN_SPEED = 13 # 30 mph -_POSE_OFFSET_MIN_COUNT = 600 # valid data counts before calibration completes, 1 seg is 600 counts -_POSE_OFFSET_MAX_COUNT = 3600 # stop deweighting new data after 6 min, aka "short term memory" +_POSE_CALIB_MIN_SPEED = 13 # 30 mph +_POSE_OFFSET_MIN_COUNT = 600 # valid data counts before calibration completes, 1 seg is 600 counts +_POSE_OFFSET_MAX_COUNT = 3600 # stop deweighting new data after 6 min, aka "short term memory" -_RECOVERY_FACTOR_MAX = 5. # relative to minus step change -_RECOVERY_FACTOR_MIN = 1.25 # relative to minus step change +_RECOVERY_FACTOR_MAX = 5. # relative to minus step change +_RECOVERY_FACTOR_MIN = 1.25 # relative to minus step change -MAX_TERMINAL_ALERTS = 3 # not allowed to engage after 3 terminal alerts -MAX_TERMINAL_DURATION = 300 # 30s +MAX_TERMINAL_ALERTS = 3 # not allowed to engage after 3 terminal alerts +MAX_TERMINAL_DURATION = 300 # 30s # model output refers to center of cropped image, so need to apply the x displacement offset RESIZED_FOCAL = 320.0 @@ -76,7 +77,7 @@ def face_orientation_from_net(angles_desc, pos_desc, rpy_calib, is_rhd): # no calib for roll pitch -= rpy_calib[1] - yaw -= rpy_calib[2] * (1 - 2 * int(is_rhd)) # lhd -> -=, rhd -> += + yaw -= rpy_calib[2] * (1 - 2 * int(is_rhd)) # lhd -> -=, rhd -> += return roll, pitch, yaw class DriverPose(): @@ -128,7 +129,7 @@ class DriverStatus(): self.step_change = DT_DMON / _DISTRACTED_TIME else: self.step_change = 0. - return # no exploit after orange alert + return # no exploit after orange alert elif self.awareness <= 0.: return @@ -189,8 +190,8 @@ class DriverStatus(): # self.pose.roll_std = driver_state.faceOrientationStd[2] model_std_max = max(self.pose.pitch_std, self.pose.yaw_std) self.pose.low_std = model_std_max < _POSESTD_THRESHOLD - self.blink.left_blink = driver_state.leftBlinkProb * (driver_state.leftEyeProb>_EYE_THRESHOLD) - self.blink.right_blink = driver_state.rightBlinkProb * (driver_state.rightEyeProb>_EYE_THRESHOLD) + self.blink.left_blink = driver_state.leftBlinkProb * (driver_state.leftEyeProb > _EYE_THRESHOLD) * (driver_state.sgProb < _SG_THRESHOLD) + self.blink.right_blink = driver_state.rightBlinkProb * (driver_state.rightEyeProb > _EYE_THRESHOLD) * (driver_state.sgProb < _SG_THRESHOLD) self.face_detected = driver_state.faceProb > _FACE_THRESHOLD and \ abs(driver_state.facePosition[0]) <= 0.4 and abs(driver_state.facePosition[1]) <= 0.45 @@ -200,7 +201,7 @@ class DriverStatus(): # update offseter # only update when driver is actively driving the car above a certain speed - if self.face_detected and car_speed>_POSE_CALIB_MIN_SPEED and self.pose.low_std and (not op_engaged or not self.driver_distracted): + if self.face_detected and car_speed > _POSE_CALIB_MIN_SPEED and self.pose.low_std and (not op_engaged or not self.driver_distracted): self.pose.pitch_offseter.push_and_update(self.pose.pitch) self.pose.yaw_offseter.push_and_update(self.pose.yaw) diff --git a/selfdrive/controls/tests/test_monitoring.py b/selfdrive/monitoring/test_monitoring.py similarity index 90% rename from selfdrive/controls/tests/test_monitoring.py rename to selfdrive/monitoring/test_monitoring.py index 67e97040cd..270f6fe067 100644 --- a/selfdrive/controls/tests/test_monitoring.py +++ b/selfdrive/monitoring/test_monitoring.py @@ -1,9 +1,11 @@ +# flake8: noqa + import unittest import numpy as np from cereal import car from common.realtime import DT_DMON from selfdrive.controls.lib.events import Events -from selfdrive.controls.lib.driver_monitor import DriverStatus, MAX_TERMINAL_ALERTS, \ +from selfdrive.monitoring.driver_monitor import DriverStatus, MAX_TERMINAL_ALERTS, \ _AWARENESS_TIME, _AWARENESS_PRE_TIME_TILL_TERMINAL, \ _AWARENESS_PROMPT_TIME_TILL_TERMINAL, _DISTRACTED_TIME, \ _DISTRACTED_PRE_TIME_TILL_TERMINAL, _DISTRACTED_PROMPT_TIME_TILL_TERMINAL, \ @@ -11,7 +13,7 @@ from selfdrive.controls.lib.driver_monitor import DriverStatus, MAX_TERMINAL_ALE EventName = car.CarEvent.EventName -_TEST_TIMESPAN = 120 # seconds +_TEST_TIMESPAN = 120 # seconds _DISTRACTED_SECONDS_TO_ORANGE = _DISTRACTED_TIME - _DISTRACTED_PROMPT_TIME_TILL_TERMINAL + 1 _DISTRACTED_SECONDS_TO_RED = _DISTRACTED_TIME + 1 _INVISIBLE_SECONDS_TO_ORANGE = _AWARENESS_TIME - _AWARENESS_PROMPT_TIME_TILL_TERMINAL + 1 @@ -20,15 +22,16 @@ _UNCERTAIN_SECONDS_TO_GREEN = _HI_STD_TIMEOUT + 0.5 class fake_DM_msg(): def __init__(self, is_face_detected, is_distracted=False, is_model_uncertain=False): - self.faceOrientation = [0.,0.,0.] - self.facePosition = [0.,0.] + self.faceOrientation = [0., 0., 0.] + self.facePosition = [0., 0.] self.faceProb = 1. * is_face_detected self.leftEyeProb = 1. self.rightEyeProb = 1. self.leftBlinkProb = 1. * is_distracted self.rightBlinkProb = 1. * is_distracted - self.faceOrientationStd = [1.*is_model_uncertain,1.*is_model_uncertain,1.*is_model_uncertain] - self.facePositionStd = [1.*is_model_uncertain,1.*is_model_uncertain] + self.faceOrientationStd = [1.*is_model_uncertain, 1.*is_model_uncertain, 1.*is_model_uncertain] + self.facePositionStd = [1.*is_model_uncertain, 1.*is_model_uncertain] + self.sgProb = 0. # driver state from neural net, 10Hz @@ -64,8 +67,8 @@ def run_DState_seq(driver_state_msgs, driver_car_interaction, openpilot_status, events_from_DM = [] for idx in range(len(driver_state_msgs)): e = Events() - DS.get_pose(driver_state_msgs[idx], [0,0,0], 0, openpilot_status[idx]) - # cal_rpy and car_speed don't matter here + DS.get_pose(driver_state_msgs[idx], [0, 0, 0], 0, openpilot_status[idx]) + # cal_rpy and car_speed don't matter here # evaluate events at 10Hz for tests DS.update(e, driver_car_interaction[idx], openpilot_status[idx], car_standstill_status[idx]) @@ -77,29 +80,29 @@ class TestMonitoring(unittest.TestCase): # 0. op engaged, driver is doing fine all the time def test_fully_aware_driver(self): events_output = run_DState_seq(always_attentive, always_false, always_true, always_false)[0] - self.assertTrue(np.sum([len(event) for event in events_output])==0) + self.assertTrue(np.sum([len(event) for event in events_output]) == 0) # 1. op engaged, driver is distracted and does nothing def test_fully_distracted_driver(self): events_output, d_status = run_DState_seq(always_distracted, always_false, always_true, always_false) - self.assertTrue(len(events_output[int((_DISTRACTED_TIME-_DISTRACTED_PRE_TIME_TILL_TERMINAL)/2/DT_DMON)])==0) - self.assertEqual(events_output[int((_DISTRACTED_TIME-_DISTRACTED_PRE_TIME_TILL_TERMINAL+\ + self.assertTrue(len(events_output[int((_DISTRACTED_TIME-_DISTRACTED_PRE_TIME_TILL_TERMINAL)/2/DT_DMON)]) == 0) + self.assertEqual(events_output[int((_DISTRACTED_TIME-_DISTRACTED_PRE_TIME_TILL_TERMINAL + ((_DISTRACTED_PRE_TIME_TILL_TERMINAL-_DISTRACTED_PROMPT_TIME_TILL_TERMINAL)/2))/DT_DMON)].names[0], EventName.preDriverDistracted) - self.assertEqual(events_output[int((_DISTRACTED_TIME-_DISTRACTED_PROMPT_TIME_TILL_TERMINAL+\ + self.assertEqual(events_output[int((_DISTRACTED_TIME-_DISTRACTED_PROMPT_TIME_TILL_TERMINAL + ((_DISTRACTED_PROMPT_TIME_TILL_TERMINAL)/2))/DT_DMON)].names[0], EventName.promptDriverDistracted) - self.assertEqual(events_output[int((_DISTRACTED_TIME+\ + self.assertEqual(events_output[int((_DISTRACTED_TIME + ((_TEST_TIMESPAN-10-_DISTRACTED_TIME)/2))/DT_DMON)].names[0], EventName.driverDistracted) self.assertIs(type(d_status.awareness), float) # 2. op engaged, no face detected the whole time, no action def test_fully_invisible_driver(self): events_output = run_DState_seq(always_no_face, always_false, always_true, always_false)[0] - self.assertTrue(len(events_output[int((_AWARENESS_TIME-_AWARENESS_PRE_TIME_TILL_TERMINAL)/2/DT_DMON)])==0) - self.assertEqual(events_output[int((_AWARENESS_TIME-_AWARENESS_PRE_TIME_TILL_TERMINAL+\ + self.assertTrue(len(events_output[int((_AWARENESS_TIME-_AWARENESS_PRE_TIME_TILL_TERMINAL)/2/DT_DMON)]) == 0) + self.assertEqual(events_output[int((_AWARENESS_TIME-_AWARENESS_PRE_TIME_TILL_TERMINAL + ((_AWARENESS_PRE_TIME_TILL_TERMINAL-_AWARENESS_PROMPT_TIME_TILL_TERMINAL)/2))/DT_DMON)].names[0], EventName.preDriverUnresponsive) - self.assertEqual(events_output[int((_AWARENESS_TIME-_AWARENESS_PROMPT_TIME_TILL_TERMINAL+\ + self.assertEqual(events_output[int((_AWARENESS_TIME-_AWARENESS_PROMPT_TIME_TILL_TERMINAL + ((_AWARENESS_PROMPT_TIME_TILL_TERMINAL)/2))/DT_DMON)].names[0], EventName.promptDriverUnresponsive) - self.assertEqual(events_output[int((_AWARENESS_TIME+\ + self.assertEqual(events_output[int((_AWARENESS_TIME + ((_TEST_TIMESPAN-10-_AWARENESS_TIME)/2))/DT_DMON)].names[0], EventName.driverUnresponsive) # 3. op engaged, down to orange, driver pays attention, back to normal; then down to orange, driver touches wheel @@ -111,17 +114,17 @@ class TestMonitoring(unittest.TestCase): interaction_vector = [car_interaction_NOT_DETECTED] * int(_DISTRACTED_SECONDS_TO_ORANGE*3/DT_DMON) + \ [car_interaction_DETECTED] * (int(_TEST_TIMESPAN/DT_DMON)-int(_DISTRACTED_SECONDS_TO_ORANGE*3/DT_DMON)) events_output = run_DState_seq(ds_vector, interaction_vector, always_true, always_false)[0] - self.assertTrue(len(events_output[int(_DISTRACTED_SECONDS_TO_ORANGE*0.5/DT_DMON)])==0) + self.assertTrue(len(events_output[int(_DISTRACTED_SECONDS_TO_ORANGE*0.5/DT_DMON)]) == 0) self.assertEqual(events_output[int((_DISTRACTED_SECONDS_TO_ORANGE-0.1)/DT_DMON)].names[0], EventName.promptDriverDistracted) - self.assertTrue(len(events_output[int(_DISTRACTED_SECONDS_TO_ORANGE*1.5/DT_DMON)])==0) + self.assertTrue(len(events_output[int(_DISTRACTED_SECONDS_TO_ORANGE*1.5/DT_DMON)]) == 0) self.assertEqual(events_output[int((_DISTRACTED_SECONDS_TO_ORANGE*3-0.1)/DT_DMON)].names[0], EventName.promptDriverDistracted) - self.assertTrue(len(events_output[int((_DISTRACTED_SECONDS_TO_ORANGE*3+0.1)/DT_DMON)])==0) + self.assertTrue(len(events_output[int((_DISTRACTED_SECONDS_TO_ORANGE*3+0.1)/DT_DMON)]) == 0) # 4. op engaged, down to orange, driver dodges camera, then comes back still distracted, down to red, \ # driver dodges, and then touches wheel to no avail, disengages and reengages # - orange/red alert should remain after disappearance, and only disengaging clears red def test_biggest_comma_fan(self): - _invisible_time = 2 # seconds + _invisible_time = 2 # seconds ds_vector = always_distracted[:] interaction_vector = always_false[:] op_vector = always_true[:] @@ -133,34 +136,34 @@ class TestMonitoring(unittest.TestCase): self.assertEqual(events_output[int((_DISTRACTED_SECONDS_TO_ORANGE+0.5*_invisible_time)/DT_DMON)].names[0], EventName.promptDriverDistracted) self.assertEqual(events_output[int((_DISTRACTED_SECONDS_TO_RED+1.5*_invisible_time)/DT_DMON)].names[0], EventName.driverDistracted) self.assertEqual(events_output[int((_DISTRACTED_SECONDS_TO_RED+2*_invisible_time+1.5)/DT_DMON)].names[0], EventName.driverDistracted) - self.assertTrue(len(events_output[int((_DISTRACTED_SECONDS_TO_RED+2*_invisible_time+3.5)/DT_DMON)])==0) + self.assertTrue(len(events_output[int((_DISTRACTED_SECONDS_TO_RED+2*_invisible_time+3.5)/DT_DMON)]) == 0) # 5. op engaged, invisible driver, down to orange, driver touches wheel; then down to orange again, driver appears # - both actions should clear the alert, but momentary appearence should not def test_sometimes_transparent_commuter(self): - _visible_time = np.random.choice([1,10]) # seconds + _visible_time = np.random.choice([1, 10]) # seconds # print _visible_time ds_vector = always_no_face[:]*2 interaction_vector = always_false[:]*2 ds_vector[int((2*_INVISIBLE_SECONDS_TO_ORANGE+1)/DT_DMON):int((2*_INVISIBLE_SECONDS_TO_ORANGE+1+_visible_time)/DT_DMON)] = [msg_ATTENTIVE] * int(_visible_time/DT_DMON) interaction_vector[int((_INVISIBLE_SECONDS_TO_ORANGE)/DT_DMON):int((_INVISIBLE_SECONDS_TO_ORANGE+1)/DT_DMON)] = [True] * int(1/DT_DMON) events_output = run_DState_seq(ds_vector, interaction_vector, 2*always_true, 2*always_false)[0] - self.assertTrue(len(events_output[int(_INVISIBLE_SECONDS_TO_ORANGE*0.5/DT_DMON)])==0) + self.assertTrue(len(events_output[int(_INVISIBLE_SECONDS_TO_ORANGE*0.5/DT_DMON)]) == 0) self.assertEqual(events_output[int((_INVISIBLE_SECONDS_TO_ORANGE-0.1)/DT_DMON)].names[0], EventName.promptDriverUnresponsive) - self.assertTrue(len(events_output[int((_INVISIBLE_SECONDS_TO_ORANGE+0.1)/DT_DMON)])==0) + self.assertTrue(len(events_output[int((_INVISIBLE_SECONDS_TO_ORANGE+0.1)/DT_DMON)]) == 0) if _visible_time == 1: self.assertEqual(events_output[int((_INVISIBLE_SECONDS_TO_ORANGE*2+1-0.1)/DT_DMON)].names[0], EventName.promptDriverUnresponsive) self.assertEqual(events_output[int((_INVISIBLE_SECONDS_TO_ORANGE*2+1+0.1+_visible_time)/DT_DMON)].names[0], EventName.preDriverUnresponsive) elif _visible_time == 10: self.assertEqual(events_output[int((_INVISIBLE_SECONDS_TO_ORANGE*2+1-0.1)/DT_DMON)].names[0], EventName.promptDriverUnresponsive) - self.assertTrue(len(events_output[int((_INVISIBLE_SECONDS_TO_ORANGE*2+1+0.1+_visible_time)/DT_DMON)])==0) + self.assertTrue(len(events_output[int((_INVISIBLE_SECONDS_TO_ORANGE*2+1+0.1+_visible_time)/DT_DMON)]) == 0) else: pass # 6. op engaged, invisible driver, down to red, driver appears and then touches wheel, then disengages/reengages # - only disengage will clear the alert def test_last_second_responder(self): - _visible_time = 2 # seconds + _visible_time = 2 # seconds ds_vector = always_no_face[:] interaction_vector = always_false[:] op_vector = always_true[:] @@ -168,23 +171,23 @@ class TestMonitoring(unittest.TestCase): interaction_vector[int((_INVISIBLE_SECONDS_TO_RED+_visible_time)/DT_DMON):int((_INVISIBLE_SECONDS_TO_RED+_visible_time+1)/DT_DMON)] = [True] * int(1/DT_DMON) op_vector[int((_INVISIBLE_SECONDS_TO_RED+_visible_time+1)/DT_DMON):int((_INVISIBLE_SECONDS_TO_RED+_visible_time+0.5)/DT_DMON)] = [False] * int(0.5/DT_DMON) events_output = run_DState_seq(ds_vector, interaction_vector, op_vector, always_false)[0] - self.assertTrue(len(events_output[int(_INVISIBLE_SECONDS_TO_ORANGE*0.5/DT_DMON)])==0) + self.assertTrue(len(events_output[int(_INVISIBLE_SECONDS_TO_ORANGE*0.5/DT_DMON)]) == 0) self.assertEqual(events_output[int((_INVISIBLE_SECONDS_TO_ORANGE-0.1)/DT_DMON)].names[0], EventName.promptDriverUnresponsive) self.assertEqual(events_output[int((_INVISIBLE_SECONDS_TO_RED-0.1)/DT_DMON)].names[0], EventName.driverUnresponsive) self.assertEqual(events_output[int((_INVISIBLE_SECONDS_TO_RED+0.5*_visible_time)/DT_DMON)].names[0], EventName.driverUnresponsive) self.assertEqual(events_output[int((_INVISIBLE_SECONDS_TO_RED+_visible_time+0.5)/DT_DMON)].names[0], EventName.driverUnresponsive) - self.assertTrue(len(events_output[int((_INVISIBLE_SECONDS_TO_RED+_visible_time+1+0.1)/DT_DMON)])==0) + self.assertTrue(len(events_output[int((_INVISIBLE_SECONDS_TO_RED+_visible_time+1+0.1)/DT_DMON)]) == 0) # 7. op not engaged, always distracted driver # - dm should stay quiet when not engaged def test_pure_dashcam_user(self): events_output = run_DState_seq(always_distracted, always_false, always_false, always_false)[0] - self.assertTrue(np.sum([len(event) for event in events_output])==0) + self.assertTrue(np.sum([len(event) for event in events_output]) == 0) # 8. op engaged, car stops at traffic light, down to orange, no action, then car starts moving # - should only reach green when stopped, but continues counting down on launch def test_long_traffic_light_victim(self): - _redlight_time = 60 # seconds + _redlight_time = 60 # seconds standstill_vector = always_true[:] standstill_vector[int(_redlight_time/DT_DMON):] = [False] * int((_TEST_TIMESPAN-_redlight_time)/DT_DMON) events_output = run_DState_seq(always_distracted, always_false, always_true, standstill_vector)[0] @@ -201,9 +204,9 @@ class TestMonitoring(unittest.TestCase): [msg_DISTRACTED_UNCERTAIN] * (int(_TEST_TIMESPAN/DT_DMON)-int((_DISTRACTED_SECONDS_TO_ORANGE+_UNCERTAIN_SECONDS_TO_GREEN)/DT_DMON)) interaction_vector = always_false[:] events_output = run_DState_seq(ds_vector, interaction_vector, always_true, always_false)[0] - self.assertTrue(len(events_output[int(_UNCERTAIN_SECONDS_TO_GREEN*0.5/DT_DMON)])==0) + self.assertTrue(len(events_output[int(_UNCERTAIN_SECONDS_TO_GREEN*0.5/DT_DMON)]) == 0) self.assertEqual(events_output[int((_UNCERTAIN_SECONDS_TO_GREEN-0.1)/DT_DMON)].names[0], EventName.driverMonitorLowAcc) - self.assertTrue(len(events_output[int((_UNCERTAIN_SECONDS_TO_GREEN+_DISTRACTED_SECONDS_TO_ORANGE-0.5)/DT_DMON)])==0) + self.assertTrue(len(events_output[int((_UNCERTAIN_SECONDS_TO_GREEN+_DISTRACTED_SECONDS_TO_ORANGE-0.5)/DT_DMON)]) == 0) self.assertEqual(events_output[int((_TEST_TIMESPAN-5.)/DT_DMON)].names[0], EventName.driverMonitorLowAcc) # 10. op engaged, model is somehow uncertain and driver is distracted @@ -212,12 +215,12 @@ class TestMonitoring(unittest.TestCase): ds_vector = [msg_DISTRACTED_BUT_SOMEHOW_UNCERTAIN] * int(_TEST_TIMESPAN/DT_DMON) interaction_vector = always_false[:] events_output = run_DState_seq(ds_vector, interaction_vector, always_true, always_false)[0] - self.assertTrue(len(events_output[int(_UNCERTAIN_SECONDS_TO_GREEN*0.5/DT_DMON)])==0) + self.assertTrue(len(events_output[int(_UNCERTAIN_SECONDS_TO_GREEN*0.5/DT_DMON)]) == 0) self.assertEqual(events_output[int((_UNCERTAIN_SECONDS_TO_GREEN)/DT_DMON)].names[0], EventName.driverMonitorLowAcc) self.assertEqual(events_output[int((2.5*(_DISTRACTED_TIME-_DISTRACTED_PRE_TIME_TILL_TERMINAL))/DT_DMON)].names[1], EventName.preDriverDistracted) self.assertEqual(events_output[int((2.5*(_DISTRACTED_TIME-_DISTRACTED_PROMPT_TIME_TILL_TERMINAL))/DT_DMON)].names[1], EventName.promptDriverDistracted) self.assertEqual(events_output[int((_DISTRACTED_TIME+1)/DT_DMON)].names[1], EventName.promptDriverDistracted) - self.assertEqual(events_output[int((_DISTRACTED_TIME*2.5)/DT_DMON)].names[1], EventName.promptDriverDistracted) # set_timer blocked + self.assertEqual(events_output[int((_DISTRACTED_TIME*2.5)/DT_DMON)].names[1], EventName.promptDriverDistracted) # set_timer blocked if __name__ == "__main__": print('MAX_TERMINAL_ALERTS', MAX_TERMINAL_ALERTS) diff --git a/selfdrive/proclogd/SConscript b/selfdrive/proclogd/SConscript index 2b87f8d5e5..e7677099e9 100644 --- a/selfdrive/proclogd/SConscript +++ b/selfdrive/proclogd/SConscript @@ -1,2 +1,2 @@ -Import('env', 'messaging') -env.Program('proclogd.cc', LIBS=[messaging, 'pthread', 'zmq', 'czmq', 'capnp', 'kj']) +Import('env', 'cereal', 'messaging') +env.Program('proclogd.cc', LIBS=[cereal, messaging, 'pthread', 'zmq', 'czmq', 'capnp', 'kj']) diff --git a/selfdrive/proclogd/proclogd.cc b/selfdrive/proclogd/proclogd.cc index 2e7503ca75..c8e5f65a50 100644 --- a/selfdrive/proclogd/proclogd.cc +++ b/selfdrive/proclogd/proclogd.cc @@ -5,9 +5,6 @@ #include #include - -#include -#include #include #include #include @@ -17,8 +14,6 @@ #include #include "messaging.hpp" -#include -#include "cereal/gen/cpp/log.capnp.h" #include "common/timing.h" #include "common/utilpp.h" @@ -34,11 +29,7 @@ struct ProcCache { } int main() { - int err; - - Context * c = Context::create(); - PubSocket * publisher = PubSocket::create(c, "procLog"); - assert(publisher != NULL); + PubMaster publisher({"procLog"}); double jiffy = sysconf(_SC_CLK_TCK); size_t page_size = sysconf(_SC_PAGE_SIZE); @@ -69,8 +60,8 @@ int main() { unsigned long utime, ntime, stime, itime; unsigned long iowtime, irqtime, sirqtime; - int count = sscanf(stat_line.data(), "cpu%d %lu %lu %lu %lu %lu %lu %lu", - &id, &utime, &ntime, &stime, &itime, &iowtime, &irqtime, &sirqtime); + sscanf(stat_line.data(), "cpu%d %lu %lu %lu %lu %lu %lu %lu", + &id, &utime, &ntime, &stime, &itime, &iowtime, &irqtime, &sirqtime); auto ltimeo = orphanage.newOrphan(); auto ltime = ltimeo.get(); @@ -107,14 +98,14 @@ int main() { uint64_t mem_cached = 0, mem_active = 0, mem_inactive = 0, mem_shared = 0; while (std::getline(smem, mem_line)) { - if (util::starts_with(mem_line, "MemTotal:")) sscanf(mem_line.data(), "MemTotal: %lu kB", &mem_total); - else if (util::starts_with(mem_line, "MemFree:")) sscanf(mem_line.data(), "MemFree: %lu kB", &mem_free); - else if (util::starts_with(mem_line, "MemAvailable:")) sscanf(mem_line.data(), "MemAvailable: %lu kB", &mem_available); - else if (util::starts_with(mem_line, "Buffers:")) sscanf(mem_line.data(), "Buffers: %lu kB", &mem_buffers); - else if (util::starts_with(mem_line, "Cached:")) sscanf(mem_line.data(), "Cached: %lu kB", &mem_cached); - else if (util::starts_with(mem_line, "Active:")) sscanf(mem_line.data(), "Active: %lu kB", &mem_active); - else if (util::starts_with(mem_line, "Inactive:")) sscanf(mem_line.data(), "Inactive: %lu kB", &mem_inactive); - else if (util::starts_with(mem_line, "Shmem:")) sscanf(mem_line.data(), "Shmem: %lu kB", &mem_shared); + if (util::starts_with(mem_line, "MemTotal:")) sscanf(mem_line.data(), "MemTotal: %" SCNu64 " kB", &mem_total); + else if (util::starts_with(mem_line, "MemFree:")) sscanf(mem_line.data(), "MemFree: %" SCNu64 " kB", &mem_free); + else if (util::starts_with(mem_line, "MemAvailable:")) sscanf(mem_line.data(), "MemAvailable: %" SCNu64 " kB", &mem_available); + else if (util::starts_with(mem_line, "Buffers:")) sscanf(mem_line.data(), "Buffers: %" SCNu64 " kB", &mem_buffers); + else if (util::starts_with(mem_line, "Cached:")) sscanf(mem_line.data(), "Cached: %" SCNu64 " kB", &mem_cached); + else if (util::starts_with(mem_line, "Active:")) sscanf(mem_line.data(), "Active: %" SCNu64 " kB", &mem_active); + else if (util::starts_with(mem_line, "Inactive:")) sscanf(mem_line.data(), "Inactive: %" SCNu64 " kB", &mem_inactive); + else if (util::starts_with(mem_line, "Shmem:")) sscanf(mem_line.data(), "Shmem: %" SCNu64 " kB", &mem_shared); } mem.setTotal(mem_total * 1024); @@ -233,15 +224,10 @@ int main() { } } - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - publisher->send((char*)bytes.begin(), bytes.size()); + publisher.send("procLog", msg); usleep(2000000); // 2 secs } - delete publisher; - delete c; - return 0; } diff --git a/selfdrive/registration.py b/selfdrive/registration.py index dbedcc9ebc..6e1596f35a 100644 --- a/selfdrive/registration.py +++ b/selfdrive/registration.py @@ -45,7 +45,7 @@ def register(): # late import import jwt - register_token = jwt.encode({'register':True, 'exp': datetime.utcnow() + timedelta(hours=1)}, private_key, algorithm='RS256') + register_token = jwt.encode({'register': True, 'exp': datetime.utcnow() + timedelta(hours=1)}, private_key, algorithm='RS256') try: cloudlog.info("getting pilotauth") diff --git a/selfdrive/sensord/SConscript b/selfdrive/sensord/SConscript index 4c9e24329a..b578ac9514 100644 --- a/selfdrive/sensord/SConscript +++ b/selfdrive/sensord/SConscript @@ -1,5 +1,5 @@ -Import('env', 'common', 'messaging') -env.Program('_sensord', 'sensors.cc', LIBS=['hardware', common, messaging, 'capnp', 'zmq', 'kj']) +Import('env', 'common', 'cereal', 'messaging') +env.Program('_sensord', 'sensors.cc', LIBS=['hardware', common, cereal, messaging, 'capnp', 'zmq', 'kj']) lenv = env.Clone() lenv['LIBPATH'] += ['/system/vendor/lib64'] -lenv.Program('_gpsd', ['gpsd.cc'], LIBS=['hardware', common, 'diag', 'time_genoff', messaging, 'capnp', 'zmq', 'kj']) +lenv.Program('_gpsd', ['gpsd.cc'], LIBS=['hardware', common, 'diag', 'time_genoff', cereal, messaging, 'capnp', 'zmq', 'kj']) diff --git a/selfdrive/sensord/gpsd.cc b/selfdrive/sensord/gpsd.cc index 4f3b7079b1..4bf71faf61 100644 --- a/selfdrive/sensord/gpsd.cc +++ b/selfdrive/sensord/gpsd.cc @@ -16,21 +16,15 @@ #include #include -#include - #include "messaging.hpp" #include "common/timing.h" #include "common/swaglog.h" -#include "cereal/gen/cpp/log.capnp.h" - volatile sig_atomic_t do_exit = 0; namespace { -Context *gps_context; -PubSocket *gps_publisher; -PubSocket *gps_location_publisher; +PubMaster *pm; const GpsInterface* gGpsInterface = NULL; const AGpsInterface* gAGpsInterface = NULL; @@ -53,10 +47,7 @@ void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length) { nmeaData.setLocalWallTime(log_time_wall); nmeaData.setNmea(nmea); - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - // printf("gps send %d\n", bytes.size()); - gps_publisher->send((char*)bytes.begin(), bytes.size()); + pm->send("gpsNMEA", msg); } void location_callback(GpsLocation* location) { @@ -78,9 +69,7 @@ void location_callback(GpsLocation* location) { locationData.setTimestamp(location->timestamp); locationData.setSource(cereal::GpsLocationData::SensorSource::ANDROID); - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - gps_location_publisher->send((char*)bytes.begin(), bytes.size()); + pm->send("gpsLocation", msg); } pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg) { @@ -125,9 +114,8 @@ AGpsCallbacks agps_callbacks = { create_thread_callback, }; - - void gps_init() { + pm = new PubMaster({"gpsNMEA", "gpsLocation"}); LOG("*** init GPS"); hw_module_t* module = NULL; hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); @@ -156,15 +144,10 @@ void gps_init() { GPS_POSITION_RECURRENCE_PERIODIC, 100, 0, 0); - gps_context = Context::create(); - gps_publisher = PubSocket::create(gps_context, "gpsNMEA"); - gps_location_publisher = PubSocket::create(gps_context, "gpsLocation"); - - assert(gps_publisher != NULL); - assert(gps_location_publisher != NULL); } void gps_destroy() { + delete pm; gGpsInterface->stop(); gGpsInterface->cleanup(); } @@ -172,7 +155,6 @@ void gps_destroy() { } int main() { - int err = 0; setpriority(PRIO_PROCESS, 0, -13); signal(SIGINT, (sighandler_t)set_do_exit); diff --git a/selfdrive/sensord/sensors.cc b/selfdrive/sensord/sensors.cc index 5e8741dbb3..b42482d853 100644 --- a/selfdrive/sensord/sensors.cc +++ b/selfdrive/sensord/sensors.cc @@ -13,18 +13,13 @@ #include #include - #include #include -#include - #include "messaging.hpp" #include "common/timing.h" #include "common/swaglog.h" -#include "cereal/gen/cpp/log.capnp.h" - #define SENSOR_ACCELEROMETER 1 #define SENSOR_MAGNETOMETER 2 #define SENSOR_GYRO 4 @@ -51,15 +46,10 @@ void sigpipe_handler(int sig) { re_init_sensors = true; } - void sensor_loop() { LOG("*** sensor loop"); - - while (!do_exit) { - Context * c = Context::create(); - PubSocket * sensor_events_sock = PubSocket::create(c, "sensorEvents"); - assert(sensor_events_sock != NULL); + PubMaster pm({"sensorEvents"}); struct sensors_poll_device_t* device; struct sensors_module_t* module; @@ -107,7 +97,6 @@ void sensor_loop() { static const size_t numEvents = 16; sensors_event_t buffer[numEvents]; - while (!do_exit) { int n = device->poll(device, buffer, numEvents); if (n == 0) continue; @@ -215,9 +204,7 @@ void sensor_loop() { log_i++; } - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - sensor_events_sock->send((char*)bytes.begin(), bytes.size()); + pm.send("sensorEvents", msg); if (re_init_sensors){ LOGE("Resetting sensors"); @@ -226,8 +213,6 @@ void sensor_loop() { } } sensors_close(device); - delete sensor_events_sock; - delete c; } } diff --git a/selfdrive/test/.gitignore b/selfdrive/test/.gitignore index 96feaba0c2..eb8c79a61a 100644 --- a/selfdrive/test/.gitignore +++ b/selfdrive/test/.gitignore @@ -1,2 +1,8 @@ out/ docker_out/ + +process_replay/diff.txt +process_replay/model_diff.txt + +*.bz2 +*.hevc diff --git a/selfdrive/test/eon_testing_slave.py b/selfdrive/test/eon_testing_slave.py index 008b8c6343..e4b8ae1c8b 100755 --- a/selfdrive/test/eon_testing_slave.py +++ b/selfdrive/test/eon_testing_slave.py @@ -36,11 +36,11 @@ def get_workdir(): def heartbeat(): work_dir = get_workdir() - env = { - "LD_LIBRARY_PATH": "", - "ANDROID_DATA": "/data", - "ANDROID_ROOT": "/system", - } + # env = { + # "LD_LIBRARY_PATH": "", + # "ANDROID_DATA": "/data", + # "ANDROID_ROOT": "/system", + # } while True: try: @@ -53,7 +53,7 @@ def heartbeat(): try: tmux = os.popen('tail -n 100 /tmp/tmux_out').read() - except: + except Exception: pass params = Params() diff --git a/selfdrive/test/helpers.py b/selfdrive/test/helpers.py new file mode 100644 index 0000000000..1e53ef4245 --- /dev/null +++ b/selfdrive/test/helpers.py @@ -0,0 +1,67 @@ +import subprocess +from functools import wraps +from nose.tools import nottest + +from common.android import ANDROID +from common.apk import update_apks, start_offroad, pm_apply_packages, android_packages +from common.params import Params +from selfdrive.version import training_version, terms_version +from selfdrive.manager import start_managed_process, kill_managed_process, get_running + +def set_params_enabled(): + params = Params() + params.put("HasAcceptedTerms", terms_version) + params.put("HasCompletedSetup", "1") + params.put("OpenpilotEnabledToggle", "1") + params.put("CommunityFeaturesToggle", "1") + params.put("Passive", "0") + params.put("CompletedTrainingVersion", training_version) + +def phone_only(x): + if ANDROID: + return x + else: + return nottest(x) + +def with_processes(processes): + def wrapper(func): + @wraps(func) + def wrap(): + # start and assert started + [start_managed_process(p) for p in processes] + assert all(get_running()[name].exitcode is None for name in processes) + + # call the function + try: + func() + # assert processes are still started + assert all(get_running()[name].exitcode is None for name in processes) + finally: + # kill and assert all stopped + [kill_managed_process(p) for p in processes] + assert len(get_running()) == 0 + return wrap + return wrapper + +def with_apks(): + def wrapper(func): + @wraps(func) + def wrap(): + update_apks() + pm_apply_packages('enable') + start_offroad() + + func() + + try: + for package in android_packages: + apk_is_running = (subprocess.call(["pidof", package]) == 0) + assert apk_is_running, package + finally: + pm_apply_packages('disable') + for package in android_packages: + apk_is_not_running = (subprocess.call(["pidof", package]) == 1) + assert apk_is_not_running, package + return wrap + return wrapper + diff --git a/selfdrive/test/leeco_selftest.sh b/selfdrive/test/leeco_selftest.sh deleted file mode 100755 index 27b43a914f..0000000000 --- a/selfdrive/test/leeco_selftest.sh +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/bash - -HOME=~/one - -if [ ! -d $HOME ]; then - HOME=/data/chffrplus -fi - -camera_test () { - printf "Running camera test...\n" - - cd $HOME/selfdrive/visiond - - if [ ! -e visiond ]; then - make > /dev/null - fi - - CAMERA_TEST=1 ./visiond > /dev/null - V4L_SUBDEVS=$(find -L /sys/class/video4linux/v4l-subdev* -maxdepth 1 -name name -exec cat {} \;) - CAMERA_COUNT=0 - for SUBDEV in $V4L_SUBDEVS; do - if [ "$SUBDEV" == "imx298" ] || [ "$SUBDEV" == "ov8865_sunny" ]; then - CAMERA_COUNT=$((CAMERA_COUNT + 1)) - fi - done - - if [ "$CAMERA_COUNT" == "2" ]; then - printf "Camera test: SUCCESS!\n" - else - printf "One or more cameras are missing! Camera count: $CAMERA_COUNT\n" - exit 1 - fi -} - -sensor_test () { - printf "Running sensor test...\n" - - cd $HOME/selfdrive/sensord - - if [ ! -e sensord ]; then - make > /dev/null - fi - - SENSOR_TEST=1 LD_LIBRARY_PATH=/system/lib64:$LD_LIBRARY_PATH ./sensord - SENSOR_COUNT=$? - - if [ "$SENSOR_COUNT" == "40" ]; then - printf "Sensor test: SUCCESS!\n" - else - printf "One or more sensors are missing! Sensor count: $SENSOR_COUNT, expected 40\n" - exit 1 - fi -} - -wifi_test () { - printf "Running WiFi test...\n" - - su -c 'svc wifi enable' - WIFI_STATUS=$(getprop wlan.driver.status) - - if [ "$WIFI_STATUS" == "ok" ]; then - printf "WiFi test: SUCCESS!\n" - else - printf "WiFi isn't working! Driver status: $WIFI_STATUS\n" - exit 1 - fi -} - -modem_test () { - printf "Running modem test...\n" - - BASEBAND_VERSION=$(getprop gsm.version.baseband | awk '{print $1}') - - if [ "$BASEBAND_VERSION" == "MPSS.TH.2.0.c1.9.1-00010" ]; then - printf "Modem test: SUCCESS!\n" - else - printf "Modem isn't working! Detected baseband version: $BASEBAND_VERSION\n" - exit 1 - fi -} - -fan_test () { - printf "Running fan test...\n" - - i2cget -f -y 7 0x67 0 1>/dev/null 2>&1 - IS_NORMAL_LEECO=$? - - if [ "$IS_NORMAL_LEECO" == "0" ]; then - /tmp/test_leeco_alt_fan.py > /dev/null - else - /tmp/test_leeco_fan.py > /dev/null - fi - - printf "Fan test: the fan should now be running at full speed, press Y or N\n" - - read -p "Is the fan running [Y/n]?\n" fan_running - case $fan_running in - [Nn]* ) - printf "Fan isn't working! (user says it isn't working)\n" - exit 1 - ;; - esac - - printf "Turning off the fan ...\n" - if [ "$IS_NORMAL_LEECO" == "0" ]; then - i2cset -f -y 7 0x67 0xa 0 - else - i2cset -f -y 7 0x3d 0 0x1 - fi -} - -camera_test -printf "\n" - -sensor_test -printf "\n" - -wifi_test -printf "\n" - -modem_test -printf "\n" - -fan_test diff --git a/selfdrive/test/longitudinal_maneuvers/maneuver.py b/selfdrive/test/longitudinal_maneuvers/maneuver.py index e79cf61d26..d60dcc4e31 100644 --- a/selfdrive/test/longitudinal_maneuvers/maneuver.py +++ b/selfdrive/test/longitudinal_maneuvers/maneuver.py @@ -25,9 +25,9 @@ class Maneuver(): def evaluate(self): """runs the plant sim and returns (score, run_data)""" plant = Plant( - lead_relevancy = self.lead_relevancy, - speed = self.speed, - distance_lead = self.distance_lead + lead_relevancy=self.lead_relevancy, + speed=self.speed, + distance_lead=self.distance_lead ) logs = defaultdict(list) diff --git a/selfdrive/test/longitudinal_maneuvers/maneuverplots.py b/selfdrive/test/longitudinal_maneuvers/maneuverplots.py index 3d52588100..503c184456 100644 --- a/selfdrive/test/longitudinal_maneuvers/maneuverplots.py +++ b/selfdrive/test/longitudinal_maneuvers/maneuverplots.py @@ -7,10 +7,10 @@ import pylab from selfdrive.config import Conversions as CV class ManeuverPlot(): - def __init__(self, title = None): + def __init__(self, title=None): self.time_array = [] - self.gas_array = [] + self.gas_array = [] self.brake_array = [] self.steer_torque_array = [] @@ -37,9 +37,9 @@ class ManeuverPlot(): self.fcw_array = [] self.title = title - - def add_data(self, time, gas, brake, steer_torque, distance, speed, - acceleration, up_accel_cmd, ui_accel_cmd, uf_accel_cmd, d_rel, v_rel, + + def add_data(self, time, gas, brake, steer_torque, distance, speed, + acceleration, up_accel_cmd, ui_accel_cmd, uf_accel_cmd, d_rel, v_rel, v_lead, v_target_lead, pid_speed, cruise_speed, jerk_factor, a_target, fcw): self.time_array.append(time) self.gas_array.append(gas) @@ -61,7 +61,6 @@ class ManeuverPlot(): self.a_target_array.append(a_target) self.fcw_array.append(fcw) - def write_plot(self, path, maneuver_name): # title = self.title or maneuver_name # TODO: Missing plots from the old one: @@ -70,7 +69,7 @@ class ManeuverPlot(): if not os.path.exists(path + "/" + maneuver_name): os.makedirs(path + "/" + maneuver_name) plt_num = 0 - + # speed chart =================== plt_num += 1 plt.figure(plt_num) @@ -140,4 +139,3 @@ class ManeuverPlot(): pylab.savefig("/".join([path, maneuver_name, 'distance.svg']), dpi=1000) plt.close("all") - diff --git a/selfdrive/test/longitudinal_maneuvers/plant.py b/selfdrive/test/longitudinal_maneuvers/plant.py index 7d6b24d438..9acb9cd282 100755 --- a/selfdrive/test/longitudinal_maneuvers/plant.py +++ b/selfdrive/test/longitudinal_maneuvers/plant.py @@ -29,7 +29,7 @@ CP = CarInterface.get_params(CAR.CIVIC, {0: {0x201: 6}, 1: {}, 2: {}, 3: {}}) def can_cksum(mm): s = 0 for c in mm: - s += (c>>4) + s += (c >> 4) s += c & 0xF s = 8-s s %= 0x10 @@ -45,7 +45,7 @@ def car_plant(pos, speed, grade, gas, brake): mass = 1700 aero_cd = 0.3 force_peak = mass*3. - force_brake_peak = -mass*10. #1g + force_brake_peak = -mass*10. # 1g power_peak = 100000 # 100kW speed_base = power_peak/force_peak rolling_res = 0.01 @@ -60,9 +60,9 @@ def car_plant(pos, speed, grade, gas, brake): #*** longitudinal model *** # find speed where peak torque meets peak power force_brake = brake * force_brake_peak * brake_to_peak_linear_slope - if speed < speed_base: # torque control + if speed < speed_base: # torque control force_gas = gas * force_peak * gas_to_peak_linear_slope - else: # power control + else: # power control force_gas = gas * power_peak / speed * gas_to_peak_linear_slope force_grade = - grade * mass # positive grade means uphill @@ -112,7 +112,9 @@ class Plant(): Plant.logcan = messaging.pub_sock('can') Plant.sendcan = messaging.sub_sock('sendcan') Plant.model = messaging.pub_sock('model') + Plant.frame_pub = messaging.pub_sock('frame') Plant.live_params = messaging.pub_sock('liveParameters') + Plant.live_location_kalman = messaging.pub_sock('liveLocationKalman') Plant.health = messaging.pub_sock('health') Plant.thermal = messaging.pub_sock('thermal') Plant.driverState = messaging.pub_sock('driverState') @@ -129,7 +131,7 @@ class Plant(): self.esp_disabled = 0 self.main_on = 1 self.user_gas = 0 - self.computer_brake,self.user_brake = 0,0 + self.computer_brake, self.user_brake = 0, 0 self.brake_pressed = 0 self.angle_steer_rate = 0 self.distance, self.distance_prev = 0., 0. @@ -160,10 +162,12 @@ class Plant(): def close(self): Plant.logcan.close() Plant.model.close() + Plant.frame_pub.close() Plant.live_params.close() + Plant.live_location_kalman.close() def speed_sensor(self, speed): - if speed<0.3: + if speed < 0.3: return 0 else: return speed * CV.MS_TO_KPH @@ -171,7 +175,7 @@ class Plant(): def current_time(self): return float(self.rk.frame) / self.rate - def step(self, v_lead=0.0, cruise_buttons=None, grade=0.0, publish_model = True): + def step(self, v_lead=0.0, cruise_buttons=None, grade=0.0, publish_model=True): gen_signals, gen_checks = get_can_signals(CP) sgs = [s[0] for s in gen_signals] msgs = [s[1] for s in gen_signals] @@ -237,7 +241,8 @@ class Plant(): # print at 5hz if (self.frame % (self.rate//5)) == 0: - print("%6.2f m %6.2f m/s %6.2f m/s2 %.2f ang gas: %.2f brake: %.2f steer: %5.2f lead_rel: %6.2f m %6.2f m/s" % (distance, speed, acceleration, self.angle_steer, gas, brake, steer_torque, d_rel, v_rel)) + print("%6.2f m %6.2f m/s %6.2f m/s2 %.2f ang gas: %.2f brake: %.2f steer: %5.2f lead_rel: %6.2f m %6.2f m/s" + % (distance, speed, acceleration, self.angle_steer, gas, brake, steer_torque, d_rel, v_rel)) # ******** publish the car ******** vls_tuple = namedtuple('vls', [ @@ -277,13 +282,13 @@ class Plant(): vls = vls_tuple( self.speed_sensor(speed), self.speed_sensor(speed), self.speed_sensor(speed), self.speed_sensor(speed), self.speed_sensor(speed), - self.angle_steer, self.angle_steer_rate, 0, 0,#Steer torque sensor + self.angle_steer, self.angle_steer_rate, 0, 0, # Steer torque sensor 0, 0, # Blinkers self.gear_choice, speed != 0, self.brake_error, self.brake_error, not self.seatbelt, self.seatbelt, # Seatbelt - self.brake_pressed, 0., #Brake pressed, Brake switch + self.brake_pressed, 0., # Brake pressed, Brake switch cruise_buttons, self.esp_disabled, 0, # HUD lead @@ -339,9 +344,9 @@ class Plant(): # TODO: use the DBC if self.frame % 5 == 0: radar_state_msg = b'\x79\x00\x00\x00\x00\x00\x00\x00' - radar_msg = to_3_byte(d_rel*16.0) + \ - to_3_byte(int(lateral_pos_rel*16.0)&0x3ff) + \ - to_3s_byte(int(v_rel*32.0)) + \ + radar_msg = to_3_byte(d_rel * 16.0) + \ + to_3_byte(int(lateral_pos_rel * 16.0) & 0x3ff) + \ + to_3s_byte(int(v_rel * 32.0)) + \ b"0f00000" radar_msg = binascii.unhexlify(radar_msg) @@ -355,7 +360,6 @@ class Plant(): msg_data = fix(msg_data, 0xe4) can_msgs.append([0xe4, 0, msg_data, 2]) - # Fake sockets that controlsd subscribes to live_parameters = messaging.new_message('liveParameters') live_parameters.liveParameters.valid = True @@ -379,11 +383,17 @@ class Plant(): thermal.thermal.batteryPercent = 100 Plant.thermal.send(thermal.to_bytes()) + live_location_kalman = messaging.new_message('liveLocationKalman') + live_location_kalman.liveLocationKalman.inputsOK = True + live_location_kalman.liveLocationKalman.gpsOK = True + Plant.live_location_kalman.send(live_location_kalman.to_bytes()) + # ******** publish a fake model going straight and fake calibration ******** # note that this is worst case for MPC, since model will delay long mpc by one time step if publish_model and self.frame % 5 == 0: md = messaging.new_message('model') cal = messaging.new_message('liveCalibration') + fp = messaging.new_message('frame') md.model.frameId = 0 for x in [md.model.path, md.model.leftLane, md.model.rightLane]: x.points = [0.0]*50 @@ -415,6 +425,7 @@ class Plant(): # fake values? Plant.model.send(md.to_bytes()) Plant.cal.send(cal.to_bytes()) + Plant.frame_pub.send(fp.to_bytes()) Plant.logcan.send(can_list_to_can_capnp(can_msgs)) diff --git a/selfdrive/test/longitudinal_maneuvers/plant_ui.py b/selfdrive/test/longitudinal_maneuvers/plant_ui.py deleted file mode 100755 index 3c73f83291..0000000000 --- a/selfdrive/test/longitudinal_maneuvers/plant_ui.py +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env python3 -import pygame # pylint: disable=import-error -from selfdrive.test.longitudinal_maneuvers.plant import Plant -from selfdrive.car.honda.values import CruiseButtons -import numpy as np -import cereal.messaging as messaging -import math - -CAR_WIDTH = 2.0 -CAR_LENGTH = 4.5 - -METER = 8 - -def rot_center(image, angle): - """rotate an image while keeping its center and size""" - orig_rect = image.get_rect() - rot_image = pygame.transform.rotate(image, angle) - rot_rect = orig_rect.copy() - rot_rect.center = rot_image.get_rect().center - rot_image = rot_image.subsurface(rot_rect).copy() - return rot_image - -def car_w_color(c): - car = pygame.Surface((METER*CAR_LENGTH, METER*CAR_LENGTH)) # pylint: disable=too-many-function-args - car.set_alpha(0) - car.fill((10,10,10)) - car.set_alpha(128) - pygame.draw.rect(car, c, (METER*1.25, 0, METER*CAR_WIDTH, METER*CAR_LENGTH), 1) - return car - -if __name__ == "__main__": - pygame.init() - display = pygame.display.set_mode((1000, 1000)) - pygame.display.set_caption('Plant UI') - - car = car_w_color((255,0,255)) - leadcar = car_w_color((255,0,0)) - - carx, cary, heading = 10.0, 50.0, 0.0 - - plant = Plant(100, distance_lead = 40.0) - - control_offset = 2.0 - control_pts = list(zip(np.arange(0, 100.0, 10.0), [50.0 + control_offset]*10)) - - def pt_to_car(pt): - x,y = pt - x -= carx - y -= cary - rx = x * math.cos(-heading) + y * -math.sin(-heading) - ry = x * math.sin(-heading) + y * math.cos(-heading) - return rx, ry - - def pt_from_car(pt): - x,y = pt - rx = x * math.cos(heading) + y * -math.sin(heading) - ry = x * math.sin(heading) + y * math.cos(heading) - rx += carx - ry += cary - return rx, ry - - while 1: - if plant.rk.frame%100 >= 20 and plant.rk.frame%100 <= 25: - cruise_buttons = CruiseButtons.RES_ACCEL - else: - cruise_buttons = 0 - - md = messaging.new_message('model') - md.model.frameId = 0 - for x in [md.model.path, md.model.leftLane, md.model.rightLane]: - x.points = [0.0]*50 - x.prob = 0.0 - x.std = 1.0 - - car_pts = [pt_to_car(pt) for pt in control_pts] - - print(car_pts) - - car_poly = np.polyfit([x[0] for x in car_pts], [x[1] for x in car_pts], 3) - md.model.path.points = np.polyval(car_poly, np.arange(0, 50)).tolist() - md.model.path.prob = 1.0 - Plant.model.send(md.to_bytes()) - - plant.step(cruise_buttons = cruise_buttons, v_lead = 2.0, publish_model = False) - - display.fill((10,10,10)) - - carx += plant.speed * plant.ts * math.cos(heading) - cary += plant.speed * plant.ts * math.sin(heading) - - # positive steering angle = steering right - print(plant.angle_steer) - heading += plant.angle_steer * plant.ts - print(heading) - - # draw my car - display.blit(pygame.transform.rotate(car, 90-math.degrees(heading)), (carx*METER, cary*METER)) - - # draw control pts - for x,y in control_pts: - pygame.draw.circle(display, (255,255,0), (int(x * METER),int(y * METER)), 2) - - # draw path - path_pts = zip(np.arange(0, 50), md.model.path.points) - - for x,y in path_pts: - x,y = pt_from_car((x,y)) - pygame.draw.circle(display, (0,255,0), (int(x * METER),int(y * METER)), 1) - - """ - # draw lead car - dl = (plant.distance_lead - plant.distance) + 4.5 - lx = carx + dl * math.cos(heading) - ly = cary + dl * math.sin(heading) - - display.blit(pygame.transform.rotate(leadcar, 90-math.degrees(heading)), (lx*METER, ly*METER)) - """ - - pygame.display.flip() diff --git a/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py b/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py index 02e4e63ca0..24f5015bd2 100755 --- a/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py +++ b/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py @@ -24,125 +24,128 @@ def create_dir(path): def check_no_collision(log): return min(log['d_rel']) > 0 + def check_fcw(log): return any(log['fcw']) + def check_engaged(log): return log['controls_state_msgs'][-1][-1].active + maneuvers = [ Maneuver( 'while cruising at 40 mph, change cruise speed to 50mph', duration=30., - initial_speed = 40. * CV.MPH_TO_MS, - cruise_button_presses = [(CB.DECEL_SET, 2.), (0, 2.3), - (CB.RES_ACCEL, 10.), (0, 10.1), - (CB.RES_ACCEL, 10.2), (0, 10.3)], + initial_speed=40. * CV.MPH_TO_MS, + cruise_button_presses=[(CB.DECEL_SET, 2.), (0, 2.3), + (CB.RES_ACCEL, 10.), (0, 10.1), + (CB.RES_ACCEL, 10.2), (0, 10.3)], checks=[check_engaged], ), Maneuver( 'while cruising at 60 mph, change cruise speed to 50mph', duration=30., initial_speed=60. * CV.MPH_TO_MS, - cruise_button_presses = [(CB.DECEL_SET, 2.), (0, 2.3), - (CB.DECEL_SET, 10.), (0, 10.1), - (CB.DECEL_SET, 10.2), (0, 10.3)], + cruise_button_presses=[(CB.DECEL_SET, 2.), (0, 2.3), + (CB.DECEL_SET, 10.), (0, 10.1), + (CB.DECEL_SET, 10.2), (0, 10.3)], checks=[check_engaged], ), Maneuver( 'while cruising at 20mph, grade change +10%', duration=25., initial_speed=20. * CV.MPH_TO_MS, - cruise_button_presses = [(CB.DECEL_SET, 1.2), (0, 1.3)], - grade_values = [0., 0., 1.0], - grade_breakpoints = [0., 10., 11.], + cruise_button_presses=[(CB.DECEL_SET, 1.2), (0, 1.3)], + grade_values=[0., 0., 1.0], + grade_breakpoints=[0., 10., 11.], checks=[check_engaged], ), Maneuver( 'while cruising at 20mph, grade change -10%', duration=25., initial_speed=20. * CV.MPH_TO_MS, - cruise_button_presses = [(CB.DECEL_SET, 1.2), (0, 1.3)], - grade_values = [0., 0., -1.0], - grade_breakpoints = [0., 10., 11.], + cruise_button_presses=[(CB.DECEL_SET, 1.2), (0, 1.3)], + grade_values=[0., 0., -1.0], + grade_breakpoints=[0., 10., 11.], checks=[check_engaged], ), Maneuver( 'approaching a 40mph car while cruising at 60mph from 100m away', duration=30., - initial_speed = 60. * CV.MPH_TO_MS, + initial_speed=60. * CV.MPH_TO_MS, lead_relevancy=True, initial_distance_lead=100., - speed_lead_values = [40.*CV.MPH_TO_MS, 40.*CV.MPH_TO_MS], - speed_lead_breakpoints = [0., 100.], - cruise_button_presses = [(CB.DECEL_SET, 1.2), (0, 1.3)], + speed_lead_values=[40. * CV.MPH_TO_MS, 40. * CV.MPH_TO_MS], + speed_lead_breakpoints=[0., 100.], + cruise_button_presses=[(CB.DECEL_SET, 1.2), (0, 1.3)], checks=[check_engaged, check_no_collision], ), Maneuver( 'approaching a 0mph car while cruising at 40mph from 150m away', duration=30., - initial_speed = 40. * CV.MPH_TO_MS, + initial_speed=40. * CV.MPH_TO_MS, lead_relevancy=True, initial_distance_lead=150., - speed_lead_values = [0.*CV.MPH_TO_MS, 0.*CV.MPH_TO_MS], - speed_lead_breakpoints = [0., 100.], - cruise_button_presses = [(CB.DECEL_SET, 1.2), (0, 1.3)], + speed_lead_values=[0. * CV.MPH_TO_MS, 0. * CV.MPH_TO_MS], + speed_lead_breakpoints=[0., 100.], + cruise_button_presses=[(CB.DECEL_SET, 1.2), (0, 1.3)], checks=[check_engaged, check_no_collision], ), Maneuver( 'steady state following a car at 20m/s, then lead decel to 0mph at 1m/s^2', duration=50., - initial_speed = 20., + initial_speed=20., lead_relevancy=True, initial_distance_lead=35., - speed_lead_values = [20., 20., 0.], - speed_lead_breakpoints = [0., 15., 35.0], - cruise_button_presses = [(CB.DECEL_SET, 1.2), (0, 1.3)], + speed_lead_values=[20., 20., 0.], + speed_lead_breakpoints=[0., 15., 35.0], + cruise_button_presses=[(CB.DECEL_SET, 1.2), (0, 1.3)], checks=[check_engaged, check_no_collision], ), Maneuver( 'steady state following a car at 20m/s, then lead decel to 0mph at 2m/s^2', duration=50., - initial_speed = 20., + initial_speed=20., lead_relevancy=True, initial_distance_lead=35., - speed_lead_values = [20., 20., 0.], - speed_lead_breakpoints = [0., 15., 25.0], - cruise_button_presses = [(CB.DECEL_SET, 1.2), (0, 1.3)], + speed_lead_values=[20., 20., 0.], + speed_lead_breakpoints=[0., 15., 25.0], + cruise_button_presses=[(CB.DECEL_SET, 1.2), (0, 1.3)], checks=[check_engaged, check_no_collision], ), Maneuver( 'steady state following a car at 20m/s, then lead decel to 0mph at 3m/s^2', duration=50., - initial_speed = 20., + initial_speed=20., lead_relevancy=True, initial_distance_lead=35., - speed_lead_values = [20., 20., 0.], - speed_lead_breakpoints = [0., 15., 21.66], - cruise_button_presses = [(CB.DECEL_SET, 1.2), (0, 1.3)], + speed_lead_values=[20., 20., 0.], + speed_lead_breakpoints=[0., 15., 21.66], + cruise_button_presses=[(CB.DECEL_SET, 1.2), (0, 1.3)], checks=[check_engaged, check_fcw], ), Maneuver( 'steady state following a car at 20m/s, then lead decel to 0mph at 5m/s^2', duration=40., - initial_speed = 20., + initial_speed=20., lead_relevancy=True, initial_distance_lead=35., - speed_lead_values = [20., 20., 0.], - speed_lead_breakpoints = [0., 15., 19.], - cruise_button_presses = [(CB.DECEL_SET, 1.2), (0, 1.3)], + speed_lead_values=[20., 20., 0.], + speed_lead_breakpoints=[0., 15., 19.], + cruise_button_presses=[(CB.DECEL_SET, 1.2), (0, 1.3)], checks=[check_engaged, check_fcw], ), Maneuver( 'starting at 0mph, approaching a stopped car 100m away', duration=30., - initial_speed = 0., + initial_speed=0., lead_relevancy=True, initial_distance_lead=100., - cruise_button_presses = [(CB.DECEL_SET, 1.2), (0, 1.3), - (CB.RES_ACCEL, 1.4), (0.0, 1.5), - (CB.RES_ACCEL, 1.6), (0.0, 1.7), - (CB.RES_ACCEL, 1.8), (0.0, 1.9)], + cruise_button_presses=[(CB.DECEL_SET, 1.2), (0, 1.3), + (CB.RES_ACCEL, 1.4), (0.0, 1.5), + (CB.RES_ACCEL, 1.6), (0.0, 1.7), + (CB.RES_ACCEL, 1.8), (0.0, 1.9)], checks=[check_engaged, check_no_collision], ), Maneuver( @@ -151,11 +154,11 @@ maneuvers = [ initial_speed=30., lead_relevancy=True, initial_distance_lead=49., - speed_lead_values=[30.,30.,29.,31.,29.,31.,29.], - speed_lead_breakpoints=[0., 6., 8., 12.,16.,20.,24.], - cruise_button_presses = [(CB.DECEL_SET, 1.2), (0, 1.3), - (CB.RES_ACCEL, 1.4), (0.0, 1.5), - (CB.RES_ACCEL, 1.6), (0.0, 1.7)], + speed_lead_values=[30., 30., 29., 31., 29., 31., 29.], + speed_lead_breakpoints=[0., 6., 8., 12., 16., 20., 24.], + cruise_button_presses=[(CB.DECEL_SET, 1.2), (0, 1.3), + (CB.RES_ACCEL, 1.4), (0.0, 1.5), + (CB.RES_ACCEL, 1.6), (0.0, 1.7)], checks=[check_engaged, check_no_collision], ), Maneuver( @@ -164,11 +167,11 @@ maneuvers = [ initial_speed=10., lead_relevancy=True, initial_distance_lead=20., - speed_lead_values=[10., 0., 0., 10., 0.,10.], + speed_lead_values=[10., 0., 0., 10., 0., 10.], speed_lead_breakpoints=[10., 20., 30., 40., 50., 60.], - cruise_button_presses = [(CB.DECEL_SET, 1.2), (0, 1.3), - (CB.RES_ACCEL, 1.4), (0.0, 1.5), - (CB.RES_ACCEL, 1.6), (0.0, 1.7)], + cruise_button_presses=[(CB.DECEL_SET, 1.2), (0, 1.3), + (CB.RES_ACCEL, 1.4), (0.0, 1.5), + (CB.RES_ACCEL, 1.6), (0.0, 1.7)], checks=[check_engaged, check_no_collision], ), Maneuver( @@ -177,14 +180,14 @@ maneuvers = [ initial_speed=0., lead_relevancy=True, initial_distance_lead=4., - speed_lead_values=[0, 0 , 45], + speed_lead_values=[0, 0, 45], speed_lead_breakpoints=[0, 10., 40.], - cruise_button_presses = [(CB.DECEL_SET, 1.2), (0, 1.3), - (CB.RES_ACCEL, 1.4), (0.0, 1.5), - (CB.RES_ACCEL, 1.6), (0.0, 1.7), - (CB.RES_ACCEL, 1.8), (0.0, 1.9), - (CB.RES_ACCEL, 2.0), (0.0, 2.1), - (CB.RES_ACCEL, 2.2), (0.0, 2.3)], + cruise_button_presses=[(CB.DECEL_SET, 1.2), (0, 1.3), + (CB.RES_ACCEL, 1.4), (0.0, 1.5), + (CB.RES_ACCEL, 1.6), (0.0, 1.7), + (CB.RES_ACCEL, 1.8), (0.0, 1.9), + (CB.RES_ACCEL, 2.0), (0.0, 2.1), + (CB.RES_ACCEL, 2.2), (0.0, 2.3)], checks=[check_engaged, check_no_collision], ), Maneuver( @@ -193,11 +196,11 @@ maneuvers = [ initial_speed=0., lead_relevancy=True, initial_distance_lead=20., - speed_lead_values=[10., 0., 0., 10., 0., 0.] , + speed_lead_values=[10., 0., 0., 10., 0., 0.], speed_lead_breakpoints=[10., 20., 30., 40., 50., 60.], - cruise_button_presses = [(CB.DECEL_SET, 1.2), (0, 1.3), - (CB.RES_ACCEL, 1.4), (0.0, 1.5), - (CB.RES_ACCEL, 1.6), (0.0, 1.7)], + cruise_button_presses=[(CB.DECEL_SET, 1.2), (0, 1.3), + (CB.RES_ACCEL, 1.4), (0.0, 1.5), + (CB.RES_ACCEL, 1.6), (0.0, 1.7)], checks=[check_engaged, check_no_collision], ), Maneuver( @@ -206,11 +209,11 @@ maneuvers = [ initial_speed=0., lead_relevancy=True, initial_distance_lead=20., - speed_lead_values=[10., 0., 0., 10., 0., 0.] , + speed_lead_values=[10., 0., 0., 10., 0., 0.], speed_lead_breakpoints=[10., 13., 26., 33., 36., 45.], - cruise_button_presses = [(CB.DECEL_SET, 1.2), (0, 1.3), - (CB.RES_ACCEL, 1.4), (0.0, 1.5), - (CB.RES_ACCEL, 1.6), (0.0, 1.7)], + cruise_button_presses=[(CB.DECEL_SET, 1.2), (0, 1.3), + (CB.RES_ACCEL, 1.4), (0.0, 1.5), + (CB.RES_ACCEL, 1.6), (0.0, 1.7)], checks=[check_engaged, check_no_collision], ), Maneuver( @@ -221,12 +224,12 @@ maneuvers = [ initial_distance_lead=10., speed_lead_values=[20., 10.], speed_lead_breakpoints=[1., 11.], - cruise_button_presses = [(CB.DECEL_SET, 1.2), (0, 1.3), - (CB.RES_ACCEL, 1.4), (0.0, 1.5), - (CB.RES_ACCEL, 1.6), (0.0, 1.7), - (CB.RES_ACCEL, 1.8), (0.0, 1.9), - (CB.RES_ACCEL, 2.0), (0.0, 2.1), - (CB.RES_ACCEL, 2.2), (0.0, 2.3)], + cruise_button_presses=[(CB.DECEL_SET, 1.2), (0, 1.3), + (CB.RES_ACCEL, 1.4), (0.0, 1.5), + (CB.RES_ACCEL, 1.6), (0.0, 1.7), + (CB.RES_ACCEL, 1.8), (0.0, 1.9), + (CB.RES_ACCEL, 2.0), (0.0, 2.1), + (CB.RES_ACCEL, 2.2), (0.0, 2.3)], checks=[check_engaged, check_no_collision], ), Maneuver( @@ -237,12 +240,12 @@ maneuvers = [ initial_distance_lead=10., speed_lead_values=[20., 0.], speed_lead_breakpoints=[1., 11.], - cruise_button_presses = [(CB.DECEL_SET, 1.2), (0, 1.3), - (CB.RES_ACCEL, 1.4), (0.0, 1.5), - (CB.RES_ACCEL, 1.6), (0.0, 1.7), - (CB.RES_ACCEL, 1.8), (0.0, 1.9), - (CB.RES_ACCEL, 2.0), (0.0, 2.1), - (CB.RES_ACCEL, 2.2), (0.0, 2.3)], + cruise_button_presses=[(CB.DECEL_SET, 1.2), (0, 1.3), + (CB.RES_ACCEL, 1.4), (0.0, 1.5), + (CB.RES_ACCEL, 1.6), (0.0, 1.7), + (CB.RES_ACCEL, 1.8), (0.0, 1.9), + (CB.RES_ACCEL, 2.0), (0.0, 2.1), + (CB.RES_ACCEL, 2.2), (0.0, 2.3)], checks=[check_engaged, check_no_collision], ), Maneuver( @@ -253,7 +256,7 @@ maneuvers = [ initial_distance_lead=100., speed_lead_values=[20.], speed_lead_breakpoints=[1.], - cruise_button_presses = [], + cruise_button_presses=[], checks=[check_fcw], ), Maneuver( @@ -264,7 +267,7 @@ maneuvers = [ initial_distance_lead=35., speed_lead_values=[20., 0.], speed_lead_breakpoints=[3., 23.], - cruise_button_presses = [], + cruise_button_presses=[], checks=[check_fcw], ), Maneuver( @@ -275,7 +278,7 @@ maneuvers = [ initial_distance_lead=35., speed_lead_values=[20., 0.], speed_lead_breakpoints=[3., 9.6], - cruise_button_presses = [], + cruise_button_presses=[], checks=[check_fcw], ), Maneuver( @@ -286,13 +289,11 @@ maneuvers = [ initial_distance_lead=35., speed_lead_values=[20., 0.], speed_lead_breakpoints=[3., 7.], - cruise_button_presses = [], + cruise_button_presses=[], checks=[check_fcw], ) ] -# maneuvers = [maneuvers[-11]] -# maneuvers = [maneuvers[6]] def setup_output(): output_dir = os.path.join(os.getcwd(), 'out/longitudinal') @@ -313,13 +314,14 @@ def setup_output(): for i, man in enumerate(maneuvers): view_html += "
%s
" % (man.title,) for c in ['distance.svg', 'speeds.svg', 'acceleration.svg', 'pedals.svg', 'pid.svg']: - view_html += "" % (os.path.join("maneuver" + str(i+1).zfill(2), c), ) + view_html += "" % (os.path.join("maneuver" + str(i + 1).zfill(2), c), ) view_html += "" create_dir(output_dir) with open(os.path.join(output_dir, "index.html"), "w") as f: f.write(view_html) + class LongitudinalControl(unittest.TestCase): @classmethod def setUpClass(cls): @@ -355,7 +357,7 @@ def run_maneuver_worker(k): print(man.title) valid = False - for retries in range(3): + for _ in range(3): manager.start_managed_process('radard') manager.start_managed_process('controlsd') manager.start_managed_process('plannerd') diff --git a/selfdrive/test/openpilotci_upload.py b/selfdrive/test/openpilotci.py old mode 100755 new mode 100644 similarity index 58% rename from selfdrive/test/openpilotci_upload.py rename to selfdrive/test/openpilotci.py index 177f854bfd..be8aefac78 --- a/selfdrive/test/openpilotci_upload.py +++ b/selfdrive/test/openpilotci.py @@ -3,12 +3,18 @@ import os import sys import subprocess +BASE_URL = "https://commadataci.blob.core.windows.net/openpilotci/" + +def get_url(route_name, segment_num, log_type="rlog"): + ext = "hevc" if log_type in ["fcamera", "dcamera"] else "bz2" + return BASE_URL + "%s/%s/%s.%s" % (route_name.replace("|", "/"), segment_num, log_type, ext) def upload_file(path, name): from azure.storage.blob import BlockBlobService sas_token = os.getenv("TOKEN", None) if sas_token is None: - sas_token = subprocess.check_output("az storage container generate-sas --account-name commadataci --name openpilotci --https-only --permissions lrw --expiry $(date -u '+%Y-%m-%dT%H:%M:%SZ' -d '+1 hour') --auth-mode login --as-user --output tsv", shell=True).decode().strip("\n") + sas_token = subprocess.check_output("az storage container generate-sas --account-name commadataci --name openpilotci --https-only --permissions lrw \ + --expiry $(date -u '+%Y-%m-%dT%H:%M:%SZ' -d '+1 hour') --auth-mode login --as-user --output tsv", shell=True).decode().strip("\n") service = BlockBlobService(account_name="commadataci", sas_token=sas_token) service.create_blob_from_path("openpilotci", name, path) return "https://commadataci.blob.core.windows.net/openpilotci/" + name diff --git a/selfdrive/test/process_replay/.gitignore b/selfdrive/test/process_replay/.gitignore deleted file mode 100644 index 6d339d54f6..0000000000 --- a/selfdrive/test/process_replay/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.bz2 -diff.txt diff --git a/selfdrive/test/process_replay/camera_replay.py b/selfdrive/test/process_replay/camera_replay.py new file mode 100755 index 0000000000..501f8f6111 --- /dev/null +++ b/selfdrive/test/process_replay/camera_replay.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +import os +import sys +import time +from typing import Any +from tqdm import tqdm + +from common.android import ANDROID +os.environ['CI'] = "1" +if ANDROID: + os.environ['QCOM_REPLAY'] = "1" +import selfdrive.manager as manager + +from common.spinner import Spinner +import cereal.messaging as messaging +from tools.lib.framereader import FrameReader +from tools.lib.logreader import LogReader +from selfdrive.test.openpilotci import BASE_URL, get_url +from selfdrive.test.process_replay.compare_logs import compare_logs, save_log +from selfdrive.test.process_replay.test_processes import format_diff +from selfdrive.version import get_git_commit + +TEST_ROUTE = "99c94dc769b5d96e|2019-08-03--14-19-59" + +def camera_replay(lr, fr): + + spinner = Spinner() + + pm = messaging.PubMaster(['frame', 'liveCalibration']) + sm = messaging.SubMaster(['model']) + + # TODO: add dmonitoringmodeld + print("preparing procs") + manager.prepare_managed_process("camerad") + manager.prepare_managed_process("modeld") + try: + print("starting procs") + manager.start_managed_process("camerad") + manager.start_managed_process("modeld") + time.sleep(5) + print("procs started") + + cal = [msg for msg in lr if msg.which() == "liveCalibration"] + for msg in cal[:5]: + pm.send(msg.which(), msg.as_builder()) + + log_msgs = [] + frame_idx = 0 + for msg in tqdm(lr): + if msg.which() == "liveCalibrationd": + pm.send(msg.which(), msg.as_builder()) + elif msg.which() == "frame": + f = msg.as_builder() + img = fr.get(frame_idx, pix_fmt="rgb24")[0][:, ::, -1] + f.frame.image = img.flatten().tobytes() + frame_idx += 1 + + pm.send(msg.which(), f) + log_msgs.append(messaging.recv_one(sm.sock['model'])) + + spinner.update("modeld replay %d/%d" % (frame_idx, fr.frame_count)) + + if frame_idx >= fr.frame_count: + break + except KeyboardInterrupt: + pass + + print("replay done") + spinner.close() + manager.kill_managed_process('modeld') + time.sleep(2) + manager.kill_managed_process('camerad') + return log_msgs + + +if __name__ == "__main__": + + update = "--update" in sys.argv + + lr = LogReader(get_url(TEST_ROUTE, 0)) + fr = FrameReader(get_url(TEST_ROUTE, 0, log_type="fcamera")) + + log_msgs = camera_replay(list(lr), fr) + + if update: + ref_commit = get_git_commit() + log_fn = "%s_%s_%s.bz2" % (TEST_ROUTE, "model", ref_commit) + save_log(log_fn, log_msgs) + with open("model_replay_ref_commit", "w") as f: + f.write(ref_commit) + else: + ref_commit = open("model_replay_ref_commit").read().strip() + log_fn = "%s_%s_%s.bz2" % (TEST_ROUTE, "model", ref_commit) + cmp_log = LogReader(BASE_URL + log_fn) + results: Any = {TEST_ROUTE: {}} + results[TEST_ROUTE]["modeld"] = compare_logs(cmp_log, log_msgs, ignore_fields=['logMonoTime', 'valid', 'model.frameDropPerc']) + diff1, diff2, failed = format_diff(results, ref_commit) + + print(diff1) + with open("model_diff.txt", "w") as f: + f.write(diff2) + + sys.exit(int(failed)) + diff --git a/selfdrive/test/process_replay/compare_logs.py b/selfdrive/test/process_replay/compare_logs.py index 731e716723..8cb4b2453f 100755 --- a/selfdrive/test/process_replay/compare_logs.py +++ b/selfdrive/test/process_replay/compare_logs.py @@ -5,13 +5,18 @@ import sys import numbers import dictdiffer + if "CI" in os.environ: - tqdm = lambda x: x + def tqdm(x): + return x else: - from tqdm import tqdm + from tqdm import tqdm # type: ignore from tools.lib.logreader import LogReader +EPSILON = sys.float_info.epsilon + + def save_log(dest, log_msgs): dat = b"" for msg in tqdm(log_msgs): @@ -21,6 +26,7 @@ def save_log(dest, log_msgs): with open(dest, "wb") as f: f.write(dat) + def remove_ignored_fields(msg, ignore): msg = msg.as_builder() for key in ignore: @@ -32,7 +38,7 @@ def remove_ignored_fields(msg, ignore): for k in keys[:-1]: try: attr = getattr(msg, k) - except: + except AttributeError: break else: v = getattr(attr, keys[-1]) @@ -45,10 +51,16 @@ def remove_ignored_fields(msg, ignore): setattr(attr, keys[-1], val) return msg.as_reader() -def compare_logs(log1, log2, ignore_fields=[], ignore_msgs=[]): - filter_msgs = lambda m: m.which() not in ignore_msgs - log1, log2 = [list(filter(filter_msgs, log)) for log in (log1, log2)] - assert len(log1) == len(log2), "logs are not same length: " + str(len(log1)) + " VS " + str(len(log2)) + +def compare_logs(log1, log2, ignore_fields=None, ignore_msgs=None, tolerance=None): + if ignore_fields is None: + ignore_fields = [] + if ignore_msgs is None: + ignore_msgs = [] + + log1, log2 = [list(filter(lambda m: m.which() not in ignore_msgs, log)) for log in (log1, log2)] + if len(log1) != len(log2): + raise Exception(f"logs are not same length: {len(log1)} VS {len(log2)}") diff = [] for msg1, msg2 in tqdm(zip(log1, log2)): @@ -62,10 +74,24 @@ def compare_logs(log1, log2, ignore_fields=[], ignore_msgs=[]): if msg1_bytes != msg2_bytes: msg1_dict = msg1.to_dict(verbose=True) msg2_dict = msg2.to_dict(verbose=True) - dd = dictdiffer.diff(msg1_dict, msg2_dict, ignore=ignore_fields, tolerance=0) + + tolerance = EPSILON if tolerance is None else tolerance + dd = dictdiffer.diff(msg1_dict, msg2_dict, ignore=ignore_fields) + + # Dictdiffer only supports relative tolerance, we also want to check for absolute + def outside_tolerance(diff): + if diff[0] == "change": + a, b = diff[2] + if isinstance(a, numbers.Number) and isinstance(b, numbers.Number): + return abs(a - b) > max(tolerance, tolerance * max(abs(a), abs(b))) + return True + + dd = list(filter(outside_tolerance, dd)) + diff.extend(dd) return diff + if __name__ == "__main__": log1 = list(LogReader(sys.argv[1])) log2 = list(LogReader(sys.argv[2])) diff --git a/selfdrive/test/process_replay/inject_model.py b/selfdrive/test/process_replay/inject_model.py index 08fd74a621..ee16846751 100755 --- a/selfdrive/test/process_replay/inject_model.py +++ b/selfdrive/test/process_replay/inject_model.py @@ -1,14 +1,12 @@ #!/usr/bin/env python3 -import os import time - from tqdm import tqdm + +import selfdrive.manager as manager from cereal.messaging import PubMaster, recv_one, sub_sock from tools.lib.framereader import FrameReader -import subprocess -import selfdrive.manager as manager def rreplace(s, old, new, occurrence): @@ -22,7 +20,6 @@ def regen_model(msgs, pm, frame_reader, model_sock): if msg.which() == 'liveCalibration': pm.send('liveCalibration', msg.as_builder()) - out_msgs = [] fidx = 0 for msg in tqdm(msgs): @@ -31,7 +28,7 @@ def regen_model(msgs, pm, frame_reader, model_sock): if w == 'frame': msg = msg.as_builder() - img = frame_reader.get(fidx, pix_fmt="rgb24")[0][:,::-1] + img = frame_reader.get(fidx, pix_fmt="rgb24")[0][:, ::-1] msg.frame.image = img.flatten().tobytes() @@ -68,7 +65,6 @@ def inject_model(msgs, segment_name): time.sleep(2) manager.kill_managed_process('camerad') - new_msgs = [] midx = 0 for msg in msgs: @@ -85,8 +81,3 @@ def inject_model(msgs, segment_name): assert abs(len(new_msgs) - len(list(msgs))) < 2 return new_msgs - - - -if __name__ == "__main__": - inject_model("0375fdf7b1ce594d|2019-06-13--08-32-25/3") diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit new file mode 100644 index 0000000000..40e490daf6 --- /dev/null +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -0,0 +1 @@ +55aee68ca0f3c5ba9fa5b100d21149cad79b732b \ No newline at end of file diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 106d871e5f..946e13f609 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -1,13 +1,15 @@ #!/usr/bin/env python3 +import capnp import os import sys import threading import importlib if "CI" in os.environ: - tqdm = lambda x: x + def tqdm(x): + return x else: - from tqdm import tqdm + from tqdm import tqdm # type: ignore from cereal import car, log from selfdrive.car.car_helpers import get_car @@ -17,7 +19,8 @@ from common.params import Params from cereal.services import service_list from collections import namedtuple -ProcessConfig = namedtuple('ProcessConfig', ['proc_name', 'pub_sub', 'ignore', 'init_callback', 'should_recv_callback']) +ProcessConfig = namedtuple('ProcessConfig', ['proc_name', 'pub_sub', 'ignore', 'init_callback', 'should_recv_callback', 'tolerance']) + def wait_for_event(evt): if not evt.wait(15): @@ -28,6 +31,7 @@ def wait_for_event(evt): # done testing this process, let it die sys.exit(0) + class FakeSocket: def __init__(self, wait=True): self.data = [] @@ -58,10 +62,15 @@ class FakeSocket: def wait_for_recv(self): wait_for_event(self.recv_called) + class DumbSocket: def __init__(self, s=None): if s is not None: - dat = messaging.new_message(s) + try: + dat = messaging.new_message(s) + except capnp.lib.capnp.KjException: # pylint: disable=c-extension-no-member + # lists + dat = messaging.new_message(s, 0) self.data = dat.to_bytes() def receive(self, non_blocking=False): @@ -70,6 +79,7 @@ class DumbSocket: def send(self, dat): pass + class FakeSubMaster(messaging.SubMaster): def __init__(self, services): super(FakeSubMaster, self).__init__(services, addr=None) @@ -92,7 +102,6 @@ class FakeSubMaster(messaging.SubMaster): wait_for_event(self.update_ready) self.update_ready.clear() - def update_msgs(self, cur_time, msgs): wait_for_event(self.update_called) self.update_called.clear() @@ -102,15 +111,16 @@ class FakeSubMaster(messaging.SubMaster): def wait_for_update(self): wait_for_event(self.update_called) + class FakePubMaster(messaging.PubMaster): - def __init__(self, services): + def __init__(self, services): # pylint: disable=super-init-not-called self.data = {} self.sock = {} self.last_updated = None for s in services: try: data = messaging.new_message(s) - except: + except capnp.lib.capnp.KjException: data = messaging.new_message(s, 0) self.data[s] = data.as_reader() self.sock[s] = DumbSocket() @@ -188,7 +198,7 @@ def calibration_rcv_callback(msg, CP, cfg, fsm): # calibrationd publishes 1 calibrationData every 5 cameraOdometry packets. # should_recv always true to increment frame if msg.which() == 'carState': - if ((fsm.frame +1)% 25) == 0: + if ((fsm.frame + 1) % 25) == 0: recv_socks = ["liveCalibration"] else: recv_socks = [] @@ -202,12 +212,13 @@ CONFIGS = [ proc_name="controlsd", pub_sub={ "can": ["controlsState", "carState", "carControl", "sendcan", "carEvents", "carParams"], - "thermal": [], "health": [], "liveCalibration": [], "dMonitoringState": [], "plan": [], "pathPlan": [], "gpsLocation": [], - "model": [], + "thermal": [], "health": [], "liveCalibration": [], "dMonitoringState": [], "plan": [], "pathPlan": [], "gpsLocation": [], "liveLocationKalman": [], + "model": [], "frame": [], }, ignore=["logMonoTime", "valid", "controlsState.startMonoTime", "controlsState.cumLagMs"], init_callback=fingerprint, should_recv_callback=None, + tolerance=None, ), ProcessConfig( proc_name="radard", @@ -218,6 +229,7 @@ CONFIGS = [ ignore=["logMonoTime", "valid", "radarState.cumLagMs"], init_callback=get_car_params, should_recv_callback=radar_rcv_callback, + tolerance=None, ), ProcessConfig( proc_name="plannerd", @@ -228,6 +240,7 @@ CONFIGS = [ ignore=["logMonoTime", "valid", "plan.processingDelay"], init_callback=get_car_params, should_recv_callback=None, + tolerance=None, ), ProcessConfig( proc_name="calibrationd", @@ -238,6 +251,7 @@ CONFIGS = [ ignore=["logMonoTime", "valid"], init_callback=get_car_params, should_recv_callback=calibration_rcv_callback, + tolerance=None, ), ProcessConfig( proc_name="dmonitoringd", @@ -248,7 +262,20 @@ CONFIGS = [ ignore=["logMonoTime", "valid"], init_callback=get_car_params, should_recv_callback=None, + tolerance=1e-7, ), + ProcessConfig( + proc_name="locationd", + pub_sub={ + "cameraOdometry": ["liveLocationKalman"], + "sensorEvents": [], "gpsLocationExternal": [], "liveCalibration": [], "carState": [], + }, + ignore=["logMonoTime", "valid"], + init_callback=get_car_params, + should_recv_callback=None, + tolerance=1e-7, # Numpy gives different results based on CPU features after version 19 + ), + ] def replay_process(cfg, lr): diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 880f969541..568aab2b73 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -76e577b86d113139167275b4a7379f3591abfa02 \ No newline at end of file +158743f002e82b62a67c6b91308db01d715f1643 \ No newline at end of file diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index 06f1b9bcd6..73939b0d97 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -2,13 +2,14 @@ import argparse import os import sys +from typing import Any from selfdrive.car.car_helpers import interface_names -from selfdrive.test.process_replay.process_replay import replay_process, CONFIGS from selfdrive.test.process_replay.compare_logs import compare_logs +from selfdrive.test.process_replay.process_replay import (CONFIGS, + replay_process) from tools.lib.logreader import LogReader - INJECT_MODEL = 0 segments = [ @@ -20,14 +21,15 @@ segments = [ ("HYUNDAI", "5b7c365c50084530|2020-04-15--16-13-24--3"), # HYUNDAI.SONATA #("CHRYSLER", "b6e1317e1bfbefa6|2020-03-04--13-11-40"), # CHRYSLER.JEEP_CHEROKEE ("SUBARU", "7873afaf022d36e2|2019-07-03--18-46-44--0"), # SUBARU.IMPREZA - ("VOLKSWAGEN", "76b83eb0245de90e|2020-03-05--19-16-05--3"), # VW.GOLF + ("VOLKSWAGEN", "76b83eb0245de90e|2020-03-05--19-16-05--3"), # VW.GOLF + ("NISSAN", "fbbfa6af821552b9|2020-03-03--08-09-43--0"), # NISSAN.XTRAIL # Enable when port is tested and dascamOnly is no longer set - ("NISSAN", "fbbfa6af821552b9|2020-03-03--08-09-43--0"), # NISSAN.XTRAIL + #("MAZDA", "32a319f057902bb3|2020-04-27--15-18-58--2"), # MAZDA.CX5 ] # ford doesn't need to be tested until a full port is done -excluded_interfaces = ["mock", "ford"] +excluded_interfaces = ["mock", "ford", "mazda"] BASE_URL = "https://commadataci.blob.core.windows.net/openpilotci/" @@ -47,7 +49,11 @@ def get_segment(segment_name, original=True): return rlog_url -def test_process(cfg, lr, cmp_log_fn, ignore_fields=[], ignore_msgs=[]): +def test_process(cfg, lr, cmp_log_fn, ignore_fields=None, ignore_msgs=None): + if ignore_fields is None: + ignore_fields = [] + if ignore_msgs is None: + ignore_msgs = [] url = BASE_URL + os.path.basename(cmp_log_fn) cmp_log_msgs = list(LogReader(url)) @@ -65,8 +71,10 @@ def test_process(cfg, lr, cmp_log_fn, ignore_fields=[], ignore_msgs=[]): segment = cmp_log_fn.split("/")[-1].split("_")[0] raise Exception("Route never enabled: %s" % segment) - return compare_logs(cmp_log_msgs, log_msgs, ignore_fields+cfg.ignore, ignore_msgs) - + try: + return compare_logs(cmp_log_msgs, log_msgs, ignore_fields+cfg.ignore, ignore_msgs, cfg.tolerance) + except Exception as e: + return str(e) def format_diff(results, ref_commit): diff1, diff2 = "", "" @@ -122,7 +130,7 @@ if __name__ == "__main__": process_replay_dir = os.path.dirname(os.path.abspath(__file__)) try: ref_commit = open(os.path.join(process_replay_dir, "ref_commit")).read().strip() - except: + except FileNotFoundError: print("couldn't find reference commit") sys.exit(1) @@ -134,10 +142,10 @@ if __name__ == "__main__": untested = (set(interface_names) - set(excluded_interfaces)) - tested_cars assert len(untested) == 0, "Cars missing routes: %s" % (str(untested)) - results = {} + results: Any = {} for car_brand, segment in segments: if (cars_whitelisted and car_brand.upper() not in args.whitelist_cars) or \ - (not cars_whitelisted and car_brand.upper() in args.blacklist_cars): + (not cars_whitelisted and car_brand.upper() in args.blacklist_cars): continue print("***** testing route segment %s *****\n" % segment) @@ -149,7 +157,7 @@ if __name__ == "__main__": for cfg in CONFIGS: if (procs_whitelisted and cfg.proc_name not in args.whitelist_procs) or \ - (not procs_whitelisted and cfg.proc_name in args.blacklist_procs): + (not procs_whitelisted and cfg.proc_name in args.blacklist_procs): continue cmp_log_fn = os.path.join(process_replay_dir, "%s_%s_%s.bz2" % (segment, cfg.proc_name, ref_commit)) diff --git a/selfdrive/test/process_replay/update_model.py b/selfdrive/test/process_replay/update_model.py index d3dab335ef..31629563e2 100755 --- a/selfdrive/test/process_replay/update_model.py +++ b/selfdrive/test/process_replay/update_model.py @@ -2,7 +2,7 @@ import os import sys -from selfdrive.test.openpilotci_upload import upload_file +from selfdrive.test.openpilotci import upload_file from selfdrive.test.process_replay.compare_logs import save_log from selfdrive.test.process_replay.test_processes import segments, get_segment from selfdrive.version import get_git_commit diff --git a/selfdrive/test/process_replay/update_refs.py b/selfdrive/test/process_replay/update_refs.py index 37997dad0d..b4243c56d3 100755 --- a/selfdrive/test/process_replay/update_refs.py +++ b/selfdrive/test/process_replay/update_refs.py @@ -2,7 +2,7 @@ import os import sys -from selfdrive.test.openpilotci_upload import upload_file +from selfdrive.test.openpilotci import upload_file from selfdrive.test.process_replay.compare_logs import save_log from selfdrive.test.process_replay.process_replay import replay_process, CONFIGS from selfdrive.test.process_replay.test_processes import segments, get_segment diff --git a/selfdrive/test/profiling/controlsd.py b/selfdrive/test/profiling/controlsd.py index 6ea3114429..329e6a8d93 100755 --- a/selfdrive/test/profiling/controlsd.py +++ b/selfdrive/test/profiling/controlsd.py @@ -1,10 +1,9 @@ #!/usr/bin/env python3 import os -import time -import cProfile -import pprofile -import pyprof2calltree +import cProfile # pylint: disable=import-error +import pprofile # pylint: disable=import-error +import pyprof2calltree # pylint: disable=import-error from tools.lib.logreader import LogReader from selfdrive.controls.controlsd import main as controlsd_thread diff --git a/selfdrive/test/profiling/lib.py b/selfdrive/test/profiling/lib.py index eb9b9b8e56..017b9a2588 100644 --- a/selfdrive/test/profiling/lib.py +++ b/selfdrive/test/profiling/lib.py @@ -36,7 +36,8 @@ class PubSocket(): class SubMaster(messaging.SubMaster): - def __init__(self, msgs, trigger, services): + def __init__(self, msgs, trigger, services): # pylint: disable=super-init-not-called + msgs = [m for m in msgs if m.which() in services] self.max_i = len(msgs) - 1 self.i = 0 self.frame = 0 @@ -82,11 +83,13 @@ class SubMaster(messaging.SubMaster): self.logMonoTime[w] = msg.logMonoTime self.i += 1 + if self.i == self.max_i: + raise ReplayDone if w == self.trigger: break class PubMaster(messaging.PubMaster): - def __init__(self): + def __init__(self): # pylint: disable=super-init-not-called self.sock = defaultdict(PubSocket) diff --git a/selfdrive/test/profiling/locationd.py b/selfdrive/test/profiling/locationd.py new file mode 100755 index 0000000000..4c478cf778 --- /dev/null +++ b/selfdrive/test/profiling/locationd.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 + +import cProfile # pylint: disable=import-error +import pprofile # pylint: disable=import-error +import pyprof2calltree # pylint: disable=import-error + +from tools.lib.logreader import LogReader +from selfdrive.locationd.locationd import locationd_thread +from selfdrive.test.profiling.lib import SubMaster, PubMaster, ReplayDone + +BASE_URL = "https://commadataci.blob.core.windows.net/openpilotci/" + +CARS = { + 'toyota': ("77611a1fac303767|2020-02-29--13-29-33/3", "TOYOTA COROLLA TSS2 2019"), +} + + +def get_inputs(msgs, process): + sub_socks = ['gpsLocationExternal', 'sensorEvents', 'cameraOdometry', 'liveCalibration', 'carState'] + trigger = 'cameraOdometry' + + sm = SubMaster(msgs, trigger, sub_socks) + pm = PubMaster() + return sm, pm + + +if __name__ == "__main__": + segment, fingerprint = CARS['toyota'] + segment = segment.replace('|', '/') + rlog_url = f"{BASE_URL}{segment}/rlog.bz2" + msgs = list(LogReader(rlog_url)) + + # Statistical + sm, pm = get_inputs(msgs, 'locationd') + with pprofile.StatisticalProfile()(period=0.00001) as pr: + try: + locationd_thread(sm, pm) + except ReplayDone: + pass + pr.dump_stats('cachegrind.out.locationd_statistical') + + # Deterministic + sm, pm = get_inputs(msgs, 'controlsd') + with cProfile.Profile() as pr: + try: + locationd_thread(sm, pm) + except ReplayDone: + pass + pyprof2calltree.convert(pr.getstats(), 'cachegrind.out.locationd_deterministic') diff --git a/selfdrive/test/setup_device_ci.sh b/selfdrive/test/setup_device_ci.sh new file mode 100755 index 0000000000..e8228ce7d4 --- /dev/null +++ b/selfdrive/test/setup_device_ci.sh @@ -0,0 +1,35 @@ +#!/usr/bin/bash -e + +export SOURCE_DIR="/data/openpilot_source/" + +if [ -z "$GIT_COMMIT" ]; then + echo "GIT_COMMIT must be set" + exit 1 +fi + +if [ -z "$TEST_DIR" ]; then + + echo "TEST_DIR must be set" + exit 1 +fi + +# TODO: never clear qcom_replay cache +# clear scons cache dirs that haven't been written to in one day +cd /tmp && find -name 'scons_cache_*' -type d -maxdepth 1 -mtime 1 -exec rm -rf '{}' \; + +# set up environment +cd $SOURCE_DIR +git reset --hard +git fetch origin +find . -maxdepth 1 -not -path './.git' -not -name '.' -not -name '..' -exec rm -rf '{}' \; +git reset --hard $GIT_COMMIT +git checkout $GIT_COMMIT +git clean -xdf +git submodule update --init +git submodule foreach --recursive git reset --hard +git submodule foreach --recursive git clean -xdf +echo "git checkout took $SECONDS seconds" + +rsync -a --delete $SOURCE_DIR $TEST_DIR + +echo "$TEST_DIR synced with $GIT_COMMIT, took $SECONDS seconds" diff --git a/selfdrive/test/test_car_models.py b/selfdrive/test/test_car_models.py index 63f42cf556..fb7d89dbc4 100755 --- a/selfdrive/test/test_car_models.py +++ b/selfdrive/test/test_car_models.py @@ -1,27 +1,29 @@ #!/usr/bin/env python3 -import time import os -import sys import signal import subprocess +import sys +import time +from typing import List, cast + import requests -from cereal import car -import selfdrive.manager as manager import cereal.messaging as messaging -from common.params import Params +import selfdrive.manager as manager +from cereal import car from common.basedir import BASEDIR +from common.params import Params +from selfdrive.car.chrysler.values import CAR as CHRYSLER from selfdrive.car.fingerprints import all_known_cars -from selfdrive.car.honda.values import CAR as HONDA -from selfdrive.car.toyota.values import CAR as TOYOTA -from selfdrive.car.gm.values import CAR as GM from selfdrive.car.ford.values import CAR as FORD +from selfdrive.car.gm.values import CAR as GM +from selfdrive.car.honda.values import CAR as HONDA from selfdrive.car.hyundai.values import CAR as HYUNDAI -from selfdrive.car.chrysler.values import CAR as CHRYSLER +from selfdrive.car.nissan.values import CAR as NISSAN +from selfdrive.car.mazda.values import CAR as MAZDA from selfdrive.car.subaru.values import CAR as SUBARU +from selfdrive.car.toyota.values import CAR as TOYOTA from selfdrive.car.volkswagen.values import CAR as VOLKSWAGEN -from selfdrive.car.nissan.values import CAR as NISSAN - os.environ['NOCRASH'] = '1' @@ -38,6 +40,7 @@ def wait_for_sockets(socks, timeout=10.0): recvd.append(s) return recvd + def get_route_log(route_name): log_path = os.path.join("/tmp", "%s--0--%s" % (route_name.replace("|", "_"), "rlog.bz2")) @@ -47,7 +50,7 @@ def get_route_log(route_name): # if request fails, try again once and let it throw exception if fails again try: r = requests.get(log_url, timeout=15) - except: + except Exception: r = requests.get(log_url, timeout=15) if r.status_code == 200: @@ -89,7 +92,7 @@ routes = { 'carFingerprint': GM.BUICK_REGAL, 'enableCamera': True, }, - "7d44af5b7a1b2c8e|2017-09-16--01-50-07": { + "a74b011b32b51b56|2020-07-26--17-09-36": { 'carFingerprint': HONDA.CIVIC, 'enableCamera': True, }, @@ -165,6 +168,14 @@ routes = { 'carFingerprint': HONDA.CIVIC_BOSCH, 'enableCamera': True, }, + "6fe86b4e410e4c37|2020-07-22--16-27-13": { + 'carFingerprint': HYUNDAI.HYUNDAI_GENESIS, + 'enableCamera': True, + }, + "70c5bec28ec8e345|2020-08-08--12-22-23": { + 'carFingerprint': HYUNDAI.GENESIS_G70, + 'enableCamera': True, + }, "38bfd238edecbcd7|2018-08-22--09-45-44": { 'carFingerprint': HYUNDAI.SANTA_FE, 'enableCamera': False, @@ -181,10 +192,38 @@ routes = { 'carFingerprint': HYUNDAI.SONATA, 'enableCamera': True, }, + "b2a38c712dcf90bd|2020-05-18--18-12-48": { + 'carFingerprint': HYUNDAI.SONATA_2019, + 'enableCamera': True, + }, + "5875672fc1d4bf57|2020-07-23--21-33-28": { + 'carFingerprint': HYUNDAI.KIA_SORENTO, + 'enableCamera': True, + }, "9c917ba0d42ffe78|2020-04-17--12-43-19": { 'carFingerprint': HYUNDAI.PALISADE, 'enableCamera': True, }, + "610ebb9faaad6b43|2020-06-13--15-28-36": { + 'carFingerprint': HYUNDAI.IONIQ_EV_LTD, + 'enableCamera': True, + }, + "2c5cf2dd6102e5da|2020-06-26--16-00-08": { + 'carFingerprint': HYUNDAI.IONIQ, + 'enableCamera': True, + }, + "22d955b2cd499c22|2020-08-10--19-58-21": { + 'carFingerprint': HYUNDAI.KONA, + 'enableCamera': True, + }, + "5dddcbca6eb66c62|2020-07-26--13-24-19": { + 'carFingerprint': HYUNDAI.KIA_STINGER, + 'enableCamera': True, + }, + "d624b3d19adce635|2020-08-01--14-59-12": { + 'carFingerprint': HYUNDAI.VELOSTER, + 'enableCamera': True, + }, "f7b6be73e3dfd36c|2019-05-12--18-07-16": { 'carFingerprint': TOYOTA.AVALON, 'enableCamera': False, @@ -194,6 +233,7 @@ routes = { 'carFingerprint': TOYOTA.CAMRY, 'enableCamera': True, 'enableDsu': False, + 'fingerprintSource': 'fixed', }, "f7b6be73e3dfd36c|2019-05-11--22-34-20": { 'carFingerprint': TOYOTA.AVALON, @@ -242,18 +282,25 @@ routes = { 'enableDsu': True, 'enableGasInterceptor': True, }, + "b14c5b4742e6fc85|2020-07-28--19-50-11": { + 'carFingerprint': TOYOTA.RAV4, + 'enableCamera': True, + 'enableDsu': False, + 'enableGasInterceptor': True, + }, "32a7df20486b0f70|2020-02-06--16-06-50": { 'carFingerprint': TOYOTA.RAV4H, 'enableCamera': True, 'enableDsu': True, 'enableGasInterceptor': False, + 'fingerprintSource': 'fixed', }, "cdf2f7de565d40ae|2019-04-25--03-53-41": { 'carFingerprint': TOYOTA.RAV4_TSS2, 'enableCamera': True, 'enableDsu': False, }, - "7e34a988419b5307|2019-12-18--19-13-30": { + "7e34a988419b5307|2019-12-18--19-13-30": { 'carFingerprint': TOYOTA.RAV4H_TSS2, 'enableCamera': True, 'fingerprintSource': 'fixed' @@ -278,12 +325,12 @@ routes = { 'enableCamera': True, 'enableDsu': False, }, - "886fcd8408d570e9|2020-01-29--05-11-22": { + "886fcd8408d570e9|2020-01-29--05-11-22": { 'carFingerprint': TOYOTA.LEXUS_RX, 'enableCamera': True, 'enableDsu': True, }, - "886fcd8408d570e9|2020-01-29--02-18-55": { + "886fcd8408d570e9|2020-01-29--02-18-55": { 'carFingerprint': TOYOTA.LEXUS_RX, 'enableCamera': True, 'enableDsu': False, @@ -293,9 +340,15 @@ routes = { 'enableCamera': True, 'enableDsu': True, }, - "01b22eb2ed121565|2020-02-02--11-25-51": { + "01b22eb2ed121565|2020-02-02--11-25-51": { 'carFingerprint': TOYOTA.LEXUS_RX_TSS2, 'enableCamera': True, + 'fingerprintSource': 'fixed', + }, + "b74758c690a49668|2020-05-20--15-58-57": { + 'carFingerprint': TOYOTA.LEXUS_RXH_TSS2, + 'enableCamera': True, + 'fingerprintSource': 'fixed', }, "ec429c0f37564e3c|2020-02-01--17-28-12": { 'carFingerprint': TOYOTA.LEXUS_NXH, @@ -328,19 +381,42 @@ routes = { 'enableCamera': False, 'enableDsu': False, }, - "1dd19ceed0ee2b48|2018-12-22--17-36-49": { - 'carFingerprint': TOYOTA.LEXUS_IS, # 300 hybrid - 'enableCamera': True, - 'enableDsu': False, - }, "76b83eb0245de90e|2019-10-20--15-42-29": { 'carFingerprint': VOLKSWAGEN.GOLF, 'enableCamera': True, }, + "3c8f0c502e119c1c|2020-06-30--12-58-02": { + 'carFingerprint': SUBARU.ASCENT, + 'enableCamera': True, + }, + "c321c6b697c5a5ff|2020-06-23--11-04-33": { + 'carFingerprint': SUBARU.FORESTER, + 'enableCamera': True, + }, "791340bc01ed993d|2019-03-10--16-28-08": { 'carFingerprint': SUBARU.IMPREZA, 'enableCamera': True, }, + # Dashcam + "95441c38ae8c130e|2020-06-08--12-10-17": { + 'carFingerprint': SUBARU.FORESTER_PREGLOBAL, + 'enableCamera': True, + }, + # Dashcam + "df5ca7660000fba8|2020-06-16--17-37-19": { + 'carFingerprint': SUBARU.LEGACY_PREGLOBAL, + 'enableCamera': True, + }, + # Dashcam + "5ab784f361e19b78|2020-06-08--16-30-41": { + 'carFingerprint': SUBARU.OUTBACK_PREGLOBAL, + 'enableCamera': True, + }, + # Dashcam + "e19eb5d5353b1ac1|2020-08-09--14-37-56": { + 'carFingerprint': SUBARU.OUTBACK_PREGLOBAL_2018, + 'enableCamera': True, + }, "fbbfa6af821552b9|2020-03-03--08-09-43": { 'carFingerprint': NISSAN.XTRAIL, 'enableCamera': True, @@ -349,15 +425,25 @@ routes = { 'carFingerprint': NISSAN.LEAF, 'enableCamera': True, }, + "059ab9162e23198e|2020-05-30--09-41-01": { + 'carFingerprint': NISSAN.ROGUE, + 'enableCamera': True, + }, + "32a319f057902bb3|2020-04-27--15-18-58": { + 'carFingerprint': MAZDA.CX5, + 'enableCamera': True, + }, } -passive_routes = [ +passive_routes: List[str] = [ ] forced_dashcam_routes = [ # Ford fusion "f1b4c567731f4a1b|2018-04-18--11-29-37", "f1b4c567731f4a1b|2018-04-30--10-15-35", + # Mazda + "32a319f057902bb3|2020-04-27--15-18-58", ] # TODO: add routes for these cars @@ -377,19 +463,13 @@ non_tested_cars = [ HYUNDAI.ELANTRA_GT_I30, HYUNDAI.GENESIS_G80, HYUNDAI.GENESIS_G90, - HYUNDAI.HYUNDAI_GENESIS, - HYUNDAI.IONIQ, - HYUNDAI.IONIQ_EV_LTD, HYUNDAI.KIA_FORTE, - HYUNDAI.KIA_OPTIMA, HYUNDAI.KIA_OPTIMA_H, - HYUNDAI.KIA_SORENTO, - HYUNDAI.KIA_STINGER, - HYUNDAI.KONA, HYUNDAI.KONA_EV, TOYOTA.CAMRYH, TOYOTA.CHR, TOYOTA.CHRH, + TOYOTA.HIGHLANDER, TOYOTA.HIGHLANDERH, TOYOTA.HIGHLANDERH_TSS2, ] @@ -415,9 +495,7 @@ if __name__ == "__main__": results = {} for route, checks in routes.items(): - print("GETTING ROUTE LOGS") get_route_log(route) - print("DONE GETTING ROUTE LOGS") params = Params() params.clear_all() @@ -426,8 +504,9 @@ if __name__ == "__main__": params.put("CommunityFeaturesToggle", "1") params.put("Passive", "1" if route in passive_routes else "0") + os.environ['SKIP_FW_QUERY'] = "1" if checks.get('fingerprintSource', None) == 'fixed': - os.environ['FINGERPRINT'] = checks['carFingerprint'] + os.environ['FINGERPRINT'] = cast(str, checks['carFingerprint']) else: os.environ['FINGERPRINT'] = "" @@ -439,7 +518,8 @@ if __name__ == "__main__": # Start unlogger print("Start unlogger") unlogger_cmd = [os.path.join(BASEDIR, 'tools/replay/unlogger.py'), route, '/tmp'] - unlogger = subprocess.Popen(unlogger_cmd + ['--disable', 'frame,encodeIdx,plan,pathPlan,liveLongitudinalMpc,radarState,controlsState,liveTracks,liveMpc,sendcan,carState,carControl,carEvents,carParams', '--no-interactive'], preexec_fn=os.setsid) + disable_socks = 'frame,encodeIdx,plan,pathPlan,liveLongitudinalMpc,radarState,controlsState,liveTracks,liveMpc,sendcan,carState,carControl,carEvents,carParams' + unlogger = subprocess.Popen(unlogger_cmd + ['--disable', disable_socks, '--no-interactive'], preexec_fn=os.setsid) # pylint: disable=subprocess-popen-preexec-fn print("Check sockets") extra_socks = [] diff --git a/selfdrive/test/test_cpu_usage.py b/selfdrive/test/test_cpu_usage.py new file mode 100755 index 0000000000..16f205e824 --- /dev/null +++ b/selfdrive/test/test_cpu_usage.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +import os +import time +import sys +import subprocess + +import cereal.messaging as messaging +from common.basedir import BASEDIR +from common.params import Params +from selfdrive.test.helpers import set_params_enabled + +def cputime_total(ct): + return ct.cpuUser + ct.cpuSystem + ct.cpuChildrenUser + ct.cpuChildrenSystem + + +def print_cpu_usage(first_proc, last_proc): + procs = [ + ("selfdrive.controls.controlsd", 66.15), + ("selfdrive.locationd.locationd", 34.38), + ("./loggerd", 33.90), + ("selfdrive.controls.plannerd", 19.77), + ("./_modeld", 12.74), + ("selfdrive.locationd.paramsd", 11.53), + ("selfdrive.controls.radard", 9.54), + ("./_ui", 9.54), + ("./camerad", 7.07), + ("selfdrive.locationd.calibrationd", 6.81), + ("./_sensord", 6.17), + ("selfdrive.monitoring.dmonitoringd", 5.48), + ("./boardd", 3.63), + ("./_dmonitoringmodeld", 2.67), + ("selfdrive.logmessaged", 2.71), + ("selfdrive.thermald.thermald", 2.41), + ("./proclogd", 1.54), + ("./_gpsd", 0.09), + ("./clocksd", 0.02), + ("./ubloxd", 0.02), + ("selfdrive.tombstoned", 0), + ("./logcatd", 0), + ] + + r = True + dt = (last_proc.logMonoTime - first_proc.logMonoTime) / 1e9 + result = "------------------------------------------------\n" + for proc_name, normal_cpu_usage in procs: + try: + first = [p for p in first_proc.procLog.procs if proc_name in p.cmdline][0] + last = [p for p in last_proc.procLog.procs if proc_name in p.cmdline][0] + cpu_time = cputime_total(last) - cputime_total(first) + cpu_usage = cpu_time / dt * 100. + if cpu_usage > max(normal_cpu_usage * 1.1, normal_cpu_usage + 5.0): + result += f"Warning {proc_name} using more CPU than normal\n" + r = False + elif cpu_usage < min(normal_cpu_usage * 0.3, max(normal_cpu_usage - 1.0, 0.0)): + result += f"Warning {proc_name} using less CPU than normal\n" + r = False + result += f"{proc_name.ljust(35)} {cpu_usage:.2f}%\n" + except IndexError: + result += f"{proc_name.ljust(35)} NO METRICS FOUND\n" + r = False + result += "------------------------------------------------\n" + print(result) + return r + +def test_cpu_usage(): + cpu_ok = False + + # start manager + manager_path = os.path.join(BASEDIR, "selfdrive/manager.py") + manager_proc = subprocess.Popen(["python", manager_path]) + try: + proc_sock = messaging.sub_sock('procLog', conflate=True, timeout=2000) + + # wait until everything's started + start_time = time.monotonic() + while time.monotonic() - start_time < 210: + if Params().get("CarParams") is not None: + break + time.sleep(2) + + # take first sample + time.sleep(5) + first_proc = messaging.recv_sock(proc_sock, wait=True) + if first_proc is None: + raise Exception("\n\nTEST FAILED: progLog recv timed out\n\n") + + # run for a minute and get last sample + time.sleep(60) + last_proc = messaging.recv_sock(proc_sock, wait=True) + cpu_ok = print_cpu_usage(first_proc, last_proc) + finally: + manager_proc.terminate() + ret = manager_proc.wait(20) + if ret is None: + manager_proc.kill() + return cpu_ok + +if __name__ == "__main__": + set_params_enabled() + Params().delete("CarParams") + + passed = False + try: + passed = test_cpu_usage() + finally: + sys.exit(int(not passed)) diff --git a/selfdrive/test/test_eon_fan.py b/selfdrive/test/test_eon_fan.py deleted file mode 100755 index 4d683cf4d1..0000000000 --- a/selfdrive/test/test_eon_fan.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python3 - -import sys -import time -from selfdrive.thermald import setup_eon_fan, set_eon_fan - -if __name__ == "__main__": - val = 0 - setup_eon_fan() - - if len(sys.argv) > 1: - set_eon_fan(int(sys.argv[1])) - exit(0) - - while True: - sys.stderr.write("setting fan to %d\n" % val) - set_eon_fan(val) - time.sleep(2) - val += 1 - val %= 4 - - diff --git a/selfdrive/test/test_leeco_alt_fan.py b/selfdrive/test/test_leeco_alt_fan.py deleted file mode 100755 index 882ca787a1..0000000000 --- a/selfdrive/test/test_leeco_alt_fan.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python3 -import time -from smbus2 import SMBus - -def setup_leon_fan(): - bus = SMBus(7, force=True) - - # http://www.ti.com/lit/ds/symlink/tusb320.pdf - for i in [0,1,2,3]: - print("FAN SPEED", i) - if i == 0: - ret = bus.write_i2c_block_data(0x67, 0xa, [0]) - else: - ret = bus.write_i2c_block_data(0x67, 0xa, [0x20]) - ret = bus.write_i2c_block_data(0x67, 0x8, [(i-1)<<6]) - time.sleep(1) - - bus.close() - -setup_leon_fan() - diff --git a/selfdrive/test/test_leeco_fan.py b/selfdrive/test/test_leeco_fan.py deleted file mode 100755 index 2ecccf3053..0000000000 --- a/selfdrive/test/test_leeco_fan.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python3 -import time -from smbus2 import SMBus - -def setup_leon_fan(): - bus = SMBus(7, force=True) - - # https://www.nxp.com/docs/en/data-sheet/PTN5150.pdf - j = 0 - for i in [0x1, 0x3 | 0, 0x3 | 0x08, 0x3 | 0x10]: - print("FAN SPEED", j) - ret = bus.read_i2c_block_data(0x3d, 0, 4) - print(ret) - ret = bus.write_i2c_block_data(0x3d, 0, [i]) - time.sleep(1) - ret = bus.read_i2c_block_data(0x3d, 0, 4) - print(ret) - j += 1 - - bus.close() - -setup_leon_fan() - diff --git a/selfdrive/test/test_models.py b/selfdrive/test/test_models.py new file mode 100755 index 0000000000..3a95136b52 --- /dev/null +++ b/selfdrive/test/test_models.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 +# pylint: disable=E1101 +import os +import importlib +import unittest +from collections import Counter +from parameterized import parameterized_class + +from cereal import log, car +from selfdrive.car.fingerprints import all_known_cars +from selfdrive.car.car_helpers import interfaces +from selfdrive.test.test_car_models import routes, non_tested_cars +from selfdrive.test.openpilotci import get_url +from tools.lib.logreader import LogReader + +from panda.tests.safety import libpandasafety_py +from panda.tests.safety.common import package_can_msg + +HwType = log.HealthData.HwType + +ROUTES = {v['carFingerprint']: k for k, v in routes.items() if v['enableCamera']} + +# TODO: get updated routes for these cars +ignore_can_valid = [ + "VOLKSWAGEN GOLF", + "ACURA ILX 2016 ACURAWATCH PLUS", + "TOYOTA PRIUS 2017", + "TOYOTA COROLLA 2017", + "LEXUS RX HYBRID 2017", + "TOYOTA AVALON 2016", + "HONDA PILOT 2019 ELITE", + "HYUNDAI SANTA FE LIMITED 2019", +] + +@parameterized_class(('car_model'), [(car,) for car in all_known_cars()]) +class TestCarModel(unittest.TestCase): + + @classmethod + def setUpClass(cls): + if cls.car_model not in ROUTES: + # TODO: get routes for missing cars and remove this + if cls.car_model in non_tested_cars: + print(f"Skipping tests for {cls.car_model}: missing route") + raise unittest.SkipTest + else: + raise Exception(f"missing test route for car {cls.car_model}") + + for seg in [2, 1, 0]: + try: + lr = LogReader(get_url(ROUTES[cls.car_model], seg)) + break + except Exception: + if seg == 0: + raise + + has_relay = False + can_msgs = [] + fingerprint = {i: dict() for i in range(3)} + for msg in lr: + if msg.which() == "can": + for m in msg.can: + if m.src < 128: + fingerprint[m.src][m.address] = len(m.dat) + can_msgs.append(msg) + elif msg.which() == "health": + has_relay = msg.health.hwType in [HwType.blackPanda, HwType.uno, HwType.dos] + cls.can_msgs = sorted(can_msgs, key=lambda msg: msg.logMonoTime) + + CarInterface, CarController, CarState = interfaces[cls.car_model] + + # TODO: test with relay and without + cls.car_params = CarInterface.get_params(cls.car_model, fingerprint, has_relay, []) + assert cls.car_params + + cls.CI = CarInterface(cls.car_params, CarController, CarState) + assert cls.CI + + def test_car_params(self): + if self.car_params.dashcamOnly: + self.skipTest("no need to check carParams for dashcamOnly") + + # make sure car params are within a valid range + self.assertGreater(self.car_params.mass, 1) + self.assertGreater(self.car_params.steerRateCost, 1e-3) + + tuning = self.car_params.lateralTuning.which() + if tuning == 'pid': + self.assertTrue(len(self.car_params.lateralTuning.pid.kpV)) + elif tuning == 'lqr': + self.assertTrue(len(self.car_params.lateralTuning.lqr.a)) + elif tuning == 'indi': + self.assertGreater(self.car_params.lateralTuning.indi.outerLoopGain, 1e-3) + + self.assertTrue(self.car_params.enableCamera) + + # TODO: check safetyModel is in release panda build + safety = libpandasafety_py.libpandasafety + set_status = safety.set_safety_hooks(self.car_params.safetyModel.raw, self.car_params.safetyParam) + self.assertEqual(0, set_status, f"failed to set safetyModel {self.car_params.safetyModel}") + + def test_car_interface(self): + # TODO: also check for checkusm and counter violations from can parser + can_invalid_cnt = 0 + CC = car.CarControl.new_message() + for i, msg in enumerate(self.can_msgs): + CS = self.CI.update(CC, (msg.as_builder().to_bytes(),)) + self.CI.apply(CC) + + # wait 2s for low frequency msgs to be seen + if i > 200: + can_invalid_cnt += not CS.canValid + + if self.car_model not in ignore_can_valid: + self.assertLess(can_invalid_cnt, 50) + + def test_radar_interface(self): + os.environ['NO_RADAR_SLEEP'] = "1" + RadarInterface = importlib.import_module('selfdrive.car.%s.radar_interface' % self.car_params.carName).RadarInterface + RI = RadarInterface(self.car_params) + assert RI + + error_cnt = 0 + for msg in self.can_msgs: + radar_data = RI.update((msg.as_builder().to_bytes(),)) + if radar_data is not None: + error_cnt += car.RadarData.Error.canError in radar_data.errors + self.assertLess(error_cnt, 20) + + def test_panda_safety_rx(self): + if self.car_params.dashcamOnly: + self.skipTest("no need to check panda safety for dashcamOnly") + + safety = libpandasafety_py.libpandasafety + set_status = safety.set_safety_hooks(self.car_params.safetyModel.raw, self.car_params.safetyParam) + self.assertEqual(0, set_status) + + failed_addrs = Counter() + for can in self.can_msgs: + for msg in can.can: + if msg.src >= 128: + continue + to_send = package_can_msg([msg.address, 0, msg.dat, msg.src]) + if not safety.safety_rx_hook(to_send): + failed_addrs[hex(msg.address)] += 1 + self.assertFalse(len(failed_addrs), f"panda safety RX check failed: {failed_addrs}") + + +if __name__ == "__main__": + unittest.main() diff --git a/selfdrive/test/test_openpilot.py b/selfdrive/test/test_openpilot.py index 624524de77..75e8192f4c 100644 --- a/selfdrive/test/test_openpilot.py +++ b/selfdrive/test/test_openpilot.py @@ -2,78 +2,23 @@ import os os.environ['FAKEUPLOAD'] = "1" -from common.apk import update_apks, start_offroad, pm_apply_packages, android_packages from common.params import Params from common.realtime import sec_since_boot -from common.testing import phone_only -from selfdrive.manager import manager_init, manager_prepare -from selfdrive.manager import start_managed_process, kill_managed_process, get_running -from selfdrive.manager import start_daemon_process -from functools import wraps +from selfdrive.manager import manager_init, manager_prepare, start_daemon_process +from selfdrive.test.helpers import phone_only, with_processes, set_params_enabled import json import requests import signal import subprocess import time -from datetime import datetime, timedelta -DID_INIT = False # must run first @phone_only def test_manager_prepare(): - global DID_INIT + set_params_enabled() manager_init() manager_prepare() - DID_INIT = True - -def with_processes(processes): - def wrapper(func): - @wraps(func) - def wrap(): - if not DID_INIT: - test_manager_prepare() - - # start and assert started - [start_managed_process(p) for p in processes] - assert all(get_running()[name].exitcode is None for name in processes) - - # call the function - try: - func() - # assert processes are still started - assert all(get_running()[name].exitcode is None for name in processes) - finally: - # kill and assert all stopped - [kill_managed_process(p) for p in processes] - assert len(get_running()) == 0 - return wrap - return wrapper - -def with_apks(): - def wrapper(func): - @wraps(func) - def wrap(): - if not DID_INIT: - test_manager_prepare() - - update_apks() - pm_apply_packages('enable') - start_offroad() - - func() - - try: - for package in android_packages: - apk_is_running = (subprocess.call(["pidof", package]) == 0) - assert apk_is_running, package - finally: - pm_apply_packages('disable') - for package in android_packages: - apk_is_not_running = (subprocess.call(["pidof", package]) == 1) - assert apk_is_not_running, package - return wrap - return wrapper @phone_only @with_processes(['loggerd', 'logmessaged', 'tombstoned', 'proclogd', 'logcatd']) diff --git a/selfdrive/test/test_sounds.py b/selfdrive/test/test_sounds.py new file mode 100755 index 0000000000..e9946efb0f --- /dev/null +++ b/selfdrive/test/test_sounds.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +import time +import subprocess + +from cereal import log, car +import cereal.messaging as messaging +from selfdrive.test.helpers import phone_only, with_processes +from common.android import get_sound_card_online +from common.realtime import DT_CTRL + +AudibleAlert = car.CarControl.HUDControl.AudibleAlert + +SOUNDS = { + # sound: total writes + AudibleAlert.none: 0, + AudibleAlert.chimeEngage: 85, + AudibleAlert.chimeDisengage: 85, + AudibleAlert.chimeError: 85, + AudibleAlert.chimePrompt: 85, + AudibleAlert.chimeWarning1: 80, + AudibleAlert.chimeWarning2: 107, + AudibleAlert.chimeWarningRepeat: 134, + AudibleAlert.chimeWarning2Repeat: 177, +} + +def get_total_writes(): + audio_flinger = subprocess.check_output('dumpsys media.audio_flinger', shell=True, encoding='utf-8').strip() + write_lines = [l for l in audio_flinger.split('\n') if l.strip().startswith('Total writes')] + return sum([int(l.split(':')[1]) for l in write_lines]) + +@phone_only +def test_sound_card_init(): + assert get_sound_card_online() + + +@phone_only +@with_processes(['ui', 'camerad']) +def test_alert_sounds(): + + pm = messaging.PubMaster(['thermal', 'controlsState']) + + # make sure they're all defined + alert_sounds = {v: k for k, v in car.CarControl.HUDControl.AudibleAlert.schema.enumerants.items()} + diff = set(SOUNDS.keys()).symmetric_difference(alert_sounds.keys()) + assert len(diff) == 0, f"not all sounds defined in test: {diff}" + + # wait for procs to init + time.sleep(5) + + msg = messaging.new_message('thermal') + msg.thermal.started = True + pm.send('thermal', msg) + + for sound, expected_writes in SOUNDS.items(): + print(f"testing {alert_sounds[sound]}") + start_writes = get_total_writes() + + for _ in range(int(9 / DT_CTRL)): + msg = messaging.new_message('controlsState') + msg.controlsState.enabled = True + msg.controlsState.active = True + msg.controlsState.alertSound = sound + msg.controlsState.alertType = str(sound) + msg.controlsState.alertText1 = "Testing Sounds" + msg.controlsState.alertText2 = f"playing {alert_sounds[sound]}" + msg.controlsState.alertSize = log.ControlsState.AlertSize.mid + pm.send('controlsState', msg) + time.sleep(DT_CTRL) + + actual_writes = get_total_writes() - start_writes + assert abs(expected_writes - actual_writes) <= 2, f"{alert_sounds[sound]}: expected {expected_writes} writes, got {actual_writes}" diff --git a/selfdrive/test/test_updated.py b/selfdrive/test/test_updated.py new file mode 100755 index 0000000000..8ecd27456d --- /dev/null +++ b/selfdrive/test/test_updated.py @@ -0,0 +1,300 @@ +#!/usr/bin/env python3 +import datetime +import os +import time +import tempfile +import unittest +import shutil +import signal +import subprocess +import random + +from common.basedir import BASEDIR +from common.params import Params + + +class TestUpdated(unittest.TestCase): + + def setUp(self): + self.updated_proc = None + + self.tmp_dir = tempfile.TemporaryDirectory() + org_dir = os.path.join(self.tmp_dir.name, "commaai") + + self.basedir = os.path.join(org_dir, "openpilot") + self.git_remote_dir = os.path.join(org_dir, "openpilot_remote") + self.staging_dir = os.path.join(org_dir, "safe_staging") + for d in [org_dir, self.basedir, self.git_remote_dir, self.staging_dir]: + os.mkdir(d) + + self.neos_version = os.path.join(org_dir, "neos_version") + self.neosupdate_dir = os.path.join(org_dir, "neosupdate") + with open(self.neos_version, "w") as f: + v = subprocess.check_output(r"bash -c 'source launch_env.sh && echo $REQUIRED_NEOS_VERSION'", + cwd=BASEDIR, shell=True, encoding='utf8').strip() + f.write(v) + + self.upper_dir = os.path.join(self.staging_dir, "upper") + self.merged_dir = os.path.join(self.staging_dir, "merged") + self.finalized_dir = os.path.join(self.staging_dir, "finalized") + + # setup local submodule remotes + submodules = subprocess.check_output("git submodule --quiet foreach 'echo $name'", + shell=True, cwd=BASEDIR, encoding='utf8').split() + for s in submodules: + sub_path = os.path.join(org_dir, s.split("_repo")[0]) + self._run(f"git clone {s} {sub_path}.git", cwd=BASEDIR) + + # setup two git repos, a remote and one we'll run updated in + self._run([ + f"git clone {BASEDIR} {self.git_remote_dir}", + f"git clone {self.git_remote_dir} {self.basedir}", + f"cd {self.basedir} && git submodule init && git submodule update", + f"cd {self.basedir} && scons -j{os.cpu_count()} cereal/ common/" + ]) + + self.params = Params(db=os.path.join(self.basedir, "persist/params")) + self.params.clear_all() + os.sync() + + def tearDown(self): + try: + if self.updated_proc is not None: + self.updated_proc.terminate() + self.updated_proc.wait(30) + except Exception as e: + print(e) + self.tmp_dir.cleanup() + + + # *** test helpers *** + + + def _run(self, cmd, cwd=None): + if not isinstance(cmd, list): + cmd = (cmd,) + + for c in cmd: + subprocess.check_output(c, cwd=cwd, shell=True) + + def _get_updated_proc(self): + os.environ["PYTHONPATH"] = self.basedir + os.environ["GIT_AUTHOR_NAME"] = "testy tester" + os.environ["GIT_COMMITTER_NAME"] = "testy tester" + os.environ["GIT_AUTHOR_EMAIL"] = "testy@tester.test" + os.environ["GIT_COMMITTER_EMAIL"] = "testy@tester.test" + os.environ["UPDATER_TEST_IP"] = "localhost" + os.environ["UPDATER_LOCK_FILE"] = os.path.join(self.tmp_dir.name, "updater.lock") + os.environ["UPDATER_STAGING_ROOT"] = self.staging_dir + os.environ["UPDATER_NEOS_VERSION"] = self.neos_version + os.environ["UPDATER_NEOSUPDATE_DIR"] = self.neosupdate_dir + updated_path = os.path.join(self.basedir, "selfdrive/updated.py") + return subprocess.Popen(updated_path, env=os.environ) + + def _start_updater(self, offroad=True, nosleep=False): + self.params.put("IsOffroad", "1" if offroad else "0") + self.updated_proc = self._get_updated_proc() + if not nosleep: + time.sleep(1) + + def _update_now(self): + self.updated_proc.send_signal(signal.SIGHUP) + + # TODO: this should be implemented in params + def _read_param(self, key, timeout=1): + ret = None + start_time = time.monotonic() + while ret is None: + ret = self.params.get(key, encoding='utf8') + if time.monotonic() - start_time > timeout: + break + time.sleep(0.01) + return ret + + def _wait_for_update(self, timeout=30, clear_param=False): + if clear_param: + self.params.delete("LastUpdateTime") + + self._update_now() + t = self._read_param("LastUpdateTime", timeout=timeout) + if t is None: + raise Exception("timed out waiting for update to complate") + + def _make_commit(self): + all_dirs, all_files = [], [] + for root, dirs, files in os.walk(self.git_remote_dir): + if ".git" in root: + continue + for d in dirs: + all_dirs.append(os.path.join(root, d)) + for f in files: + all_files.append(os.path.join(root, f)) + + # make a new dir and some new files + new_dir = os.path.join(self.git_remote_dir, "this_is_a_new_dir") + os.mkdir(new_dir) + for _ in range(random.randrange(5, 30)): + for d in (new_dir, random.choice(all_dirs)): + with tempfile.NamedTemporaryFile(dir=d, delete=False) as f: + f.write(os.urandom(random.randrange(1, 1000000))) + + # modify some files + for f in random.sample(all_files, random.randrange(5, 50)): + with open(f, "w+") as ff: + txt = ff.readlines() + ff.seek(0) + for line in txt: + ff.write(line[::-1]) + + # remove some files + for f in random.sample(all_files, random.randrange(5, 50)): + os.remove(f) + + # remove some dirs + for d in random.sample(all_dirs, random.randrange(1, 10)): + shutil.rmtree(d) + + # commit the changes + self._run([ + "git add -A", + "git commit -m 'an update'", + ], cwd=self.git_remote_dir) + + def _check_update_state(self, update_available): + # make sure LastUpdateTime is recent + t = self._read_param("LastUpdateTime") + last_update_time = datetime.datetime.fromisoformat(t) + td = datetime.datetime.utcnow() - last_update_time + self.assertLess(td.total_seconds(), 10) + self.params.delete("LastUpdateTime") + + # wait a bit for the rest of the params to be written + time.sleep(0.1) + + # check params + update = self._read_param("UpdateAvailable") + self.assertEqual(update == "1", update_available, f"UpdateAvailable: {repr(update)}") + self.assertEqual(self._read_param("UpdateFailedCount"), "0") + + # TODO: check that the finalized update actually matches remote + # check the .overlay_init and .overlay_consistent flags + self.assertTrue(os.path.isfile(os.path.join(self.basedir, ".overlay_init"))) + self.assertEqual(os.path.isfile(os.path.join(self.finalized_dir, ".overlay_consistent")), update_available) + + + # *** test cases *** + + + # Run updated for 100 cycles with no update + def test_no_update(self): + self._start_updater() + for _ in range(100): + self._wait_for_update(clear_param=True) + self._check_update_state(False) + + # Let the updater run with no update for a cycle, then write an update + def test_update(self): + self._start_updater() + + # run for a cycle with no update + self._wait_for_update(clear_param=True) + self._check_update_state(False) + + # write an update to our remote + self._make_commit() + + # run for a cycle to get the update + self._wait_for_update(timeout=60, clear_param=True) + self._check_update_state(True) + + # run another cycle with no update + self._wait_for_update(clear_param=True) + self._check_update_state(True) + + # Let the updater run for 10 cycles, and write an update every cycle + @unittest.skip("need to make this faster") + def test_update_loop(self): + self._start_updater() + + # run for a cycle with no update + self._wait_for_update(clear_param=True) + for _ in range(10): + time.sleep(0.5) + self._make_commit() + self._wait_for_update(timeout=90, clear_param=True) + self._check_update_state(True) + + # Test overlay re-creation after tracking a new file in basedir's git + def test_overlay_reinit(self): + self._start_updater() + + overlay_init_fn = os.path.join(self.basedir, ".overlay_init") + + # run for a cycle with no update + self._wait_for_update(clear_param=True) + self.params.delete("LastUpdateTime") + first_mtime = os.path.getmtime(overlay_init_fn) + + # touch a file in the basedir + self._run("touch new_file && git add new_file", cwd=self.basedir) + + # run another cycle, should have a new mtime + self._wait_for_update(clear_param=True) + second_mtime = os.path.getmtime(overlay_init_fn) + self.assertTrue(first_mtime != second_mtime) + + # run another cycle, mtime should be same as last cycle + self._wait_for_update(clear_param=True) + new_mtime = os.path.getmtime(overlay_init_fn) + self.assertTrue(second_mtime == new_mtime) + + # Make sure updated exits if another instance is running + def test_multiple_instances(self): + # start updated and let it run for a cycle + self._start_updater() + time.sleep(1) + self._wait_for_update(clear_param=True) + + # start another instance + second_updated = self._get_updated_proc() + ret_code = second_updated.wait(timeout=5) + self.assertTrue(ret_code is not None) + + + # *** test cases with NEOS updates *** + + + # Run updated with no update, make sure it clears the old NEOS update + def test_clear_neos_cache(self): + # make the dir and some junk files + os.mkdir(self.neosupdate_dir) + for _ in range(15): + with tempfile.NamedTemporaryFile(dir=self.neosupdate_dir, delete=False) as f: + f.write(os.urandom(random.randrange(1, 1000000))) + + self._start_updater() + self._wait_for_update(clear_param=True) + self._check_update_state(False) + self.assertFalse(os.path.isdir(self.neosupdate_dir)) + + # Let the updater run with no update for a cycle, then write an update + @unittest.skip("TODO: only runs on device") + def test_update_with_neos_update(self): + # bump the NEOS version and commit it + self._run([ + "echo 'export REQUIRED_NEOS_VERSION=3' >> launch_env.sh", + "git -c user.name='testy' -c user.email='testy@tester.test' \ + commit -am 'a neos update'", + ], cwd=self.git_remote_dir) + + # run for a cycle to get the update + self._start_updater() + self._wait_for_update(timeout=60, clear_param=True) + self._check_update_state(True) + + # TODO: more comprehensive check + self.assertTrue(os.path.isdir(self.neosupdate_dir)) + + +if __name__ == "__main__": + unittest.main() diff --git a/selfdrive/test/update_ci_routes.py b/selfdrive/test/update_ci_routes.py index 09b8d170d7..ee9dde6ee5 100755 --- a/selfdrive/test/update_ci_routes.py +++ b/selfdrive/test/update_ci_routes.py @@ -1,15 +1,13 @@ #!/usr/bin/env python3 -import tempfile -import shutil +import sys import subprocess from common.basedir import BASEDIR from azure.storage.blob import BlockBlobService from selfdrive.test.test_car_models import routes as test_car_models_routes from selfdrive.test.process_replay.test_processes import segments as replay_segments -from xx.chffr.lib import azureutil -from xx.chffr.lib.storage import upload_dir_serial, download_dir_tpe -from xx.chffr.lib.storage import _DATA_ACCOUNT_PRODUCTION, _DATA_ACCOUNT_CI, _DATA_BUCKET_PRODUCTION, _DATA_BUCKET_CI +from xx.chffr.lib import azureutil # pylint: disable=import-error +from xx.chffr.lib.storage import _DATA_ACCOUNT_PRODUCTION, _DATA_ACCOUNT_CI, _DATA_BUCKET_PRODUCTION # pylint: disable=import-error SOURCES = [ (_DATA_ACCOUNT_PRODUCTION, _DATA_BUCKET_PRODUCTION), @@ -57,18 +55,16 @@ def sync_to_ci_public(route): if __name__ == "__main__": failed_routes = [] - # sync process replay routes - for s in replay_segments: - route_name, _ = s[1].rsplit('--', 1) - if not sync_to_ci_public(route_name): - failed_routes.append(route_name) + to_sync = sys.argv[1:] - # sync test_car_models routes - for r in list(test_car_models_routes.keys()): + if not len(to_sync): + # sync routes from test_car_models and process replay + to_sync.extend(test_car_models_routes.keys()) + to_sync.extend([s[1].rsplit('--', 1)[0] for s in replay_segments]) + + for r in to_sync: if not sync_to_ci_public(r): failed_routes.append(r) - if len(failed_routes): - print("failed routes:") - print(failed_routes) + print("failed routes:", failed_routes) diff --git a/selfdrive/thermald/__init__.py b/selfdrive/thermald/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/selfdrive/thermald/power_monitoring.py b/selfdrive/thermald/power_monitoring.py index 378bee6f91..cd4bb7d7bc 100644 --- a/selfdrive/thermald/power_monitoring.py +++ b/selfdrive/thermald/power_monitoring.py @@ -1,14 +1,23 @@ -import datetime import random import threading import time from statistics import mean from cereal import log +from common.realtime import sec_since_boot +from common.params import Params, put_nonblocking from selfdrive.swaglog import cloudlog PANDA_OUTPUT_VOLTAGE = 5.28 +CAR_VOLTAGE_LOW_PASS_K = 0.091 # LPF gain for 5s tau (dt/tau / (dt/tau + 1)) +# A C2 uses about 1W while idling, and 30h seens like a good shutoff for most cars +# While driving, a battery charges completely in about 30-60 minutes +CAR_BATTERY_CAPACITY_uWh = 30e6 +CAR_CHARGING_RATE_W = 45 + +VBATT_PAUSE_CHARGING = 11.0 +MAX_TIME_OFFROAD_S = 30*3600 # Parameters def get_battery_capacity(): @@ -35,7 +44,7 @@ def get_usb_present(): def get_battery_charging(): # This does correspond with actually charging - return _read_param("/sys/class/power_supply/battery/charge_type", lambda x: x.strip() != "N/A", False) + return _read_param("/sys/class/power_supply/battery/charge_type", lambda x: x.strip() != "N/A", True) def set_battery_charging(on): @@ -59,91 +68,117 @@ def panda_current_to_actual_current(panda_current): class PowerMonitoring: def __init__(self): + self.params = Params() self.last_measurement_time = None # Used for integration delta + self.last_save_time = 0 # Used for saving current value in a param self.power_used_uWh = 0 # Integrated power usage in uWh since going into offroad self.next_pulsed_measurement_time = None + self.car_voltage_mV = 12e3 # Low-passed version of health voltage self.integration_lock = threading.Lock() + car_battery_capacity_uWh = self.params.get("CarBatteryCapacity") + if car_battery_capacity_uWh is None: + car_battery_capacity_uWh = 0 + + # Reset capacity if it's low + self.car_battery_capacity_uWh = max((CAR_BATTERY_CAPACITY_uWh / 10), int(car_battery_capacity_uWh)) + + # Calculation tick def calculate(self, health): try: - now = time.time() - - # Check that time is valid - if datetime.datetime.fromtimestamp(now).year < 2019: - return + now = sec_since_boot() - # Only integrate when there is no ignition # If health is None, we're probably not in a car, so we don't care - if health is None or (health.health.ignitionLine or health.health.ignitionCan) or \ - health.health.hwType == log.HealthData.HwType.unknown: + if health is None or health.health.hwType == log.HealthData.HwType.unknown: with self.integration_lock: self.last_measurement_time = None self.next_pulsed_measurement_time = None self.power_used_uWh = 0 return + # Low-pass battery voltage + self.car_voltage_mV = ((health.health.voltage * CAR_VOLTAGE_LOW_PASS_K) + (self.car_voltage_mV * (1 - CAR_VOLTAGE_LOW_PASS_K))) + + # Cap the car battery power and save it in a param every 10-ish seconds + self.car_battery_capacity_uWh = max(self.car_battery_capacity_uWh, 0) + self.car_battery_capacity_uWh = min(self.car_battery_capacity_uWh, CAR_BATTERY_CAPACITY_uWh) + if now - self.last_save_time >= 10: + put_nonblocking("CarBatteryCapacity", str(int(self.car_battery_capacity_uWh))) + self.last_save_time = now + # First measurement, set integration time with self.integration_lock: if self.last_measurement_time is None: self.last_measurement_time = now return - is_uno = health.health.hwType == log.HealthData.HwType.uno - # Get current power draw somehow - current_power = 0 - if get_battery_status() == 'Discharging': - # If the battery is discharging, we can use this measurement - # On C2: this is low by about 10-15%, probably mostly due to UNO draw not being factored in - current_power = ((get_battery_voltage() / 1000000) * (get_battery_current() / 1000000)) - elif (health.health.hwType in [log.HealthData.HwType.whitePanda, log.HealthData.HwType.greyPanda]) and (health.health.current > 1): - # If white/grey panda, use the integrated current measurements if the measurement is not 0 - # If the measurement is 0, the current is 400mA or greater, and out of the measurement range of the panda - # This seems to be accurate to about 5% - current_power = (PANDA_OUTPUT_VOLTAGE * panda_current_to_actual_current(health.health.current)) - elif (self.next_pulsed_measurement_time is not None) and (self.next_pulsed_measurement_time <= now): - # TODO: Figure out why this is off by a factor of 3/4??? - FUDGE_FACTOR = 1.33 - - # Turn off charging for about 10 sec in a thread that does not get killed on SIGINT, and perform measurement here to avoid blocking thermal - def perform_pulse_measurement(now): - try: - set_battery_charging(False) - time.sleep(5) - - # Measure for a few sec to get a good average - voltages = [] - currents = [] - for i in range(6): - voltages.append(get_battery_voltage()) - currents.append(get_battery_current()) - time.sleep(1) - current_power = ((mean(voltages) / 1000000) * (mean(currents) / 1000000)) - - self._perform_integration(now, current_power * FUDGE_FACTOR) - - # Enable charging again - set_battery_charging(True) - except Exception: - cloudlog.exception("Pulsed power measurement failed") - - # Start pulsed measurement and return - threading.Thread(target=perform_pulse_measurement, args=(now,)).start() - self.next_pulsed_measurement_time = None - return - - elif self.next_pulsed_measurement_time is None and not is_uno: - # On a charging EON with black panda, or drawing more than 400mA out of a white/grey one - # Only way to get the power draw is to turn off charging for a few sec and check what the discharging rate is - # We shouldn't do this very often, so make sure it has been some long-ish random time interval - self.next_pulsed_measurement_time = now + random.randint(120, 180) - return + if (health.health.ignitionLine or health.health.ignitionCan): + # If there is ignition, we integrate the charging rate of the car + with self.integration_lock: + self.power_used_uWh = 0 + integration_time_h = (now - self.last_measurement_time) / 3600 + if integration_time_h < 0: + raise ValueError(f"Negative integration time: {integration_time_h}h") + self.car_battery_capacity_uWh += (CAR_CHARGING_RATE_W * 1e6 * integration_time_h) + self.last_measurement_time = now else: - # Do nothing - return + # No ignition, we integrate the offroad power used by the device + is_uno = health.health.hwType == log.HealthData.HwType.uno + # Get current power draw somehow + current_power = 0 + if get_battery_status() == 'Discharging': + # If the battery is discharging, we can use this measurement + # On C2: this is low by about 10-15%, probably mostly due to UNO draw not being factored in + current_power = ((get_battery_voltage() / 1000000) * (get_battery_current() / 1000000)) + elif (health.health.hwType in [log.HealthData.HwType.whitePanda, log.HealthData.HwType.greyPanda]) and (health.health.current > 1): + # If white/grey panda, use the integrated current measurements if the measurement is not 0 + # If the measurement is 0, the current is 400mA or greater, and out of the measurement range of the panda + # This seems to be accurate to about 5% + current_power = (PANDA_OUTPUT_VOLTAGE * panda_current_to_actual_current(health.health.current)) + elif (self.next_pulsed_measurement_time is not None) and (self.next_pulsed_measurement_time <= now): + # TODO: Figure out why this is off by a factor of 3/4??? + FUDGE_FACTOR = 1.33 + + # Turn off charging for about 10 sec in a thread that does not get killed on SIGINT, and perform measurement here to avoid blocking thermal + def perform_pulse_measurement(now): + try: + set_battery_charging(False) + time.sleep(5) + + # Measure for a few sec to get a good average + voltages = [] + currents = [] + for _ in range(6): + voltages.append(get_battery_voltage()) + currents.append(get_battery_current()) + time.sleep(1) + current_power = ((mean(voltages) / 1000000) * (mean(currents) / 1000000)) + + self._perform_integration(now, current_power * FUDGE_FACTOR) + + # Enable charging again + set_battery_charging(True) + except Exception: + cloudlog.exception("Pulsed power measurement failed") + + # Start pulsed measurement and return + threading.Thread(target=perform_pulse_measurement, args=(now,)).start() + self.next_pulsed_measurement_time = None + return - # Do the integration - self._perform_integration(now, current_power) + elif self.next_pulsed_measurement_time is None and not is_uno: + # On a charging EON with black panda, or drawing more than 400mA out of a white/grey one + # Only way to get the power draw is to turn off charging for a few sec and check what the discharging rate is + # We shouldn't do this very often, so make sure it has been some long-ish random time interval + self.next_pulsed_measurement_time = now + random.randint(120, 180) + return + else: + # Do nothing + return + + # Do the integration + self._perform_integration(now, current_power) except Exception: cloudlog.exception("Power monitoring calculation failed") @@ -156,6 +191,7 @@ class PowerMonitoring: if power_used < 0: raise ValueError(f"Negative power used! Integration time: {integration_time_h} h Current Power: {power_used} uWh") self.power_used_uWh += power_used + self.car_battery_capacity_uWh -= power_used self.last_measurement_time = t except Exception: cloudlog.exception("Integration failed") @@ -163,3 +199,37 @@ class PowerMonitoring: # Get the power usage def get_power_used(self): return int(self.power_used_uWh) + + def get_car_battery_capacity(self): + return int(self.car_battery_capacity_uWh) + + # See if we need to disable charging + def should_disable_charging(self, health, offroad_timestamp): + if health is None or offroad_timestamp is None: + return False + + now = sec_since_boot() + disable_charging = False + disable_charging |= (now - offroad_timestamp) > MAX_TIME_OFFROAD_S + disable_charging |= (self.car_voltage_mV < (VBATT_PAUSE_CHARGING * 1e3)) + disable_charging |= (self.car_battery_capacity_uWh <= 0) + disable_charging &= (not health.health.ignitionLine and not health.health.ignitionCan) + disable_charging &= (self.params.get("DisablePowerDown") != b"1") + return disable_charging + + # See if we need to shutdown + def should_shutdown(self, health, offroad_timestamp, started_seen, LEON): + if health is None or offroad_timestamp is None: + return False + + now = sec_since_boot() + panda_charging = (health.health.usbPowerMode != log.HealthData.UsbPowerMode.client) + BATT_PERC_OFF = 10 if LEON else 3 + + should_shutdown = False + # Wait until we have shut down charging before powering down + should_shutdown |= (not panda_charging and self.should_disable_charging(health, offroad_timestamp)) + should_shutdown |= ((get_battery_capacity() < BATT_PERC_OFF) and (not get_battery_charging()) and ((now - offroad_timestamp) > 60)) + should_shutdown &= started_seen + return should_shutdown + diff --git a/selfdrive/thermald/tests/__init__.py b/selfdrive/thermald/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/selfdrive/thermald/tests/test_power_monitoring.py b/selfdrive/thermald/tests/test_power_monitoring.py new file mode 100755 index 0000000000..af46e447e5 --- /dev/null +++ b/selfdrive/thermald/tests/test_power_monitoring.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python3 +import unittest +from unittest.mock import patch +from parameterized import parameterized + +from cereal import log +import cereal.messaging as messaging +from common.params import Params +params = Params() + +# Create fake time +ssb = 0 +def mock_sec_since_boot(): + global ssb + ssb += 1 + return ssb + +with patch("common.realtime.sec_since_boot", new=mock_sec_since_boot): + with patch("common.params.put_nonblocking", new=params.put): + from selfdrive.thermald.power_monitoring import PowerMonitoring, CAR_BATTERY_CAPACITY_uWh, \ + PANDA_OUTPUT_VOLTAGE, CAR_CHARGING_RATE_W, \ + VBATT_PAUSE_CHARGING + +def actual_current_to_panda_current(actual_current): + return max(int(((3.3 - (actual_current * 8.25)) * 4096) / 3.3), 0) + +TEST_DURATION_S = 50 +ALL_PANDA_TYPES = [(hw_type,) for hw_type in [log.HealthData.HwType.whitePanda, + log.HealthData.HwType.greyPanda, + log.HealthData.HwType.blackPanda, + log.HealthData.HwType.uno]] + +def pm_patch(name, value, constant=False): + if constant: + return patch(f"selfdrive.thermald.power_monitoring.{name}", value) + return patch(f"selfdrive.thermald.power_monitoring.{name}", return_value=value) + +class TestPowerMonitoring(unittest.TestCase): + def setUp(self): + # Clear stored capacity before each test + params.delete("CarBatteryCapacity") + params.delete("DisablePowerDown") + + def mock_health(self, ignition, hw_type, car_voltage=12, current=0): + health = messaging.new_message('health') + health.health.hwType = hw_type + health.health.voltage = car_voltage * 1e3 + health.health.current = actual_current_to_panda_current(current) + health.health.ignitionLine = ignition + health.health.ignitionCan = False + return health + + # Test to see that it doesn't do anything when health is None + def test_health_present(self): + pm = PowerMonitoring() + for _ in range(10): + pm.calculate(None) + self.assertEqual(pm.get_power_used(), 0) + self.assertEqual(pm.get_car_battery_capacity(), (CAR_BATTERY_CAPACITY_uWh / 10)) + + # Test to see that it doesn't integrate offroad when ignition is True + @parameterized.expand(ALL_PANDA_TYPES) + def test_offroad_ignition(self, hw_type): + pm = PowerMonitoring() + for _ in range(10): + pm.calculate(self.mock_health(True, hw_type)) + self.assertEqual(pm.get_power_used(), 0) + + # Test to see that it integrates with white/grey panda while charging + @parameterized.expand([(log.HealthData.HwType.whitePanda,), (log.HealthData.HwType.greyPanda,)]) + def test_offroad_integration_white(self, hw_type): + with pm_patch("get_battery_voltage", 4e6), pm_patch("get_battery_current", 1e5), pm_patch("get_battery_status", "Charging"): + pm = PowerMonitoring() + for _ in range(TEST_DURATION_S + 1): + pm.calculate(self.mock_health(False, hw_type, current=0.1)) + expected_power_usage = ((TEST_DURATION_S/3600) * (0.1 * PANDA_OUTPUT_VOLTAGE) * 1e6) + self.assertLess(abs(pm.get_power_used() - expected_power_usage), 10) + + # Test to see that it integrates with discharging battery + @parameterized.expand(ALL_PANDA_TYPES) + def test_offroad_integration_discharging(self, hw_type): + BATT_VOLTAGE = 4 + BATT_CURRENT = 1 + with pm_patch("get_battery_voltage", BATT_VOLTAGE * 1e6), pm_patch("get_battery_current", BATT_CURRENT * 1e6), \ + pm_patch("get_battery_status", "Discharging"): + pm = PowerMonitoring() + for _ in range(TEST_DURATION_S + 1): + pm.calculate(self.mock_health(False, hw_type)) + expected_power_usage = ((TEST_DURATION_S/3600) * (BATT_VOLTAGE * BATT_CURRENT) * 1e6) + self.assertLess(abs(pm.get_power_used() - expected_power_usage), 10) + + # Test to check positive integration of car_battery_capacity + @parameterized.expand(ALL_PANDA_TYPES) + def test_car_battery_integration_onroad(self, hw_type): + BATT_VOLTAGE = 4 + BATT_CURRENT = 1 + with pm_patch("get_battery_voltage", BATT_VOLTAGE * 1e6), pm_patch("get_battery_current", BATT_CURRENT * 1e6), \ + pm_patch("get_battery_status", "Discharging"): + pm = PowerMonitoring() + pm.car_battery_capacity_uWh = 0 + for _ in range(TEST_DURATION_S + 1): + pm.calculate(self.mock_health(True, hw_type)) + expected_capacity = ((TEST_DURATION_S/3600) * CAR_CHARGING_RATE_W * 1e6) + self.assertLess(abs(pm.get_car_battery_capacity() - expected_capacity), 10) + + # Test to check positive integration upper limit + @parameterized.expand(ALL_PANDA_TYPES) + def test_car_battery_integration_upper_limit(self, hw_type): + BATT_VOLTAGE = 4 + BATT_CURRENT = 1 + with pm_patch("get_battery_voltage", BATT_VOLTAGE * 1e6), pm_patch("get_battery_current", BATT_CURRENT * 1e6), \ + pm_patch("get_battery_status", "Discharging"): + pm = PowerMonitoring() + pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh - 1000 + for _ in range(TEST_DURATION_S + 1): + pm.calculate(self.mock_health(True, hw_type)) + estimated_capacity = CAR_BATTERY_CAPACITY_uWh + (CAR_CHARGING_RATE_W / 3600 * 1e6) + self.assertLess(abs(pm.get_car_battery_capacity() - estimated_capacity), 10) + + # Test to check negative integration of car_battery_capacity + @parameterized.expand(ALL_PANDA_TYPES) + def test_car_battery_integration_offroad(self, hw_type): + BATT_VOLTAGE = 4 + BATT_CURRENT = 1 + with pm_patch("get_battery_voltage", BATT_VOLTAGE * 1e6), pm_patch("get_battery_current", BATT_CURRENT * 1e6), \ + pm_patch("get_battery_status", "Discharging"): + pm = PowerMonitoring() + pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh + for _ in range(TEST_DURATION_S + 1): + pm.calculate(self.mock_health(False, hw_type)) + expected_capacity = CAR_BATTERY_CAPACITY_uWh - ((TEST_DURATION_S/3600) * (BATT_VOLTAGE * BATT_CURRENT) * 1e6) + self.assertLess(abs(pm.get_car_battery_capacity() - expected_capacity), 10) + + # Test to check negative integration lower limit + @parameterized.expand(ALL_PANDA_TYPES) + def test_car_battery_integration_lower_limit(self, hw_type): + BATT_VOLTAGE = 4 + BATT_CURRENT = 1 + with pm_patch("get_battery_voltage", BATT_VOLTAGE * 1e6), pm_patch("get_battery_current", BATT_CURRENT * 1e6), \ + pm_patch("get_battery_status", "Discharging"): + pm = PowerMonitoring() + pm.car_battery_capacity_uWh = 1000 + for _ in range(TEST_DURATION_S + 1): + pm.calculate(self.mock_health(False, hw_type)) + estimated_capacity = 0 - ((1/3600) * (BATT_VOLTAGE * BATT_CURRENT) * 1e6) + self.assertLess(abs(pm.get_car_battery_capacity() - estimated_capacity), 10) + + # Test to check policy of stopping charging after MAX_TIME_OFFROAD_S + @parameterized.expand(ALL_PANDA_TYPES) + def test_max_time_offroad(self, hw_type): + global ssb + BATT_VOLTAGE = 4 + BATT_CURRENT = 0 # To stop shutting down for other reasons + MOCKED_MAX_OFFROAD_TIME = 3600 + with pm_patch("get_battery_voltage", BATT_VOLTAGE * 1e6), pm_patch("get_battery_current", BATT_CURRENT * 1e6), \ + pm_patch("get_battery_status", "Discharging"), pm_patch("MAX_TIME_OFFROAD_S", MOCKED_MAX_OFFROAD_TIME, constant=True): + pm = PowerMonitoring() + pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh + start_time = ssb + health = self.mock_health(False, hw_type) + while ssb <= start_time + MOCKED_MAX_OFFROAD_TIME: + pm.calculate(health) + if (ssb - start_time) % 1000 == 0 and ssb < start_time + MOCKED_MAX_OFFROAD_TIME: + self.assertFalse(pm.should_disable_charging(health, start_time)) + self.assertTrue(pm.should_disable_charging(health, start_time)) + + # Test to check policy of stopping charging when the car voltage is too low + @parameterized.expand(ALL_PANDA_TYPES) + def test_car_voltage(self, hw_type): + global ssb + BATT_VOLTAGE = 4 + BATT_CURRENT = 0 # To stop shutting down for other reasons + TEST_TIME = 100 + with pm_patch("get_battery_voltage", BATT_VOLTAGE * 1e6), pm_patch("get_battery_current", BATT_CURRENT * 1e6), \ + pm_patch("get_battery_status", "Discharging"): + pm = PowerMonitoring() + pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh + health = self.mock_health(False, hw_type, car_voltage=(VBATT_PAUSE_CHARGING - 1)) + for i in range(TEST_TIME): + pm.calculate(health) + if i % 10 == 0: + self.assertEqual(pm.should_disable_charging(health, ssb), (pm.car_voltage_mV < VBATT_PAUSE_CHARGING*1e3)) + self.assertTrue(pm.should_disable_charging(health, ssb)) + + # Test to check policy of not stopping charging when DisablePowerDown is set + def test_disable_power_down(self): + global ssb + BATT_VOLTAGE = 4 + BATT_CURRENT = 0 # To stop shutting down for other reasons + TEST_TIME = 100 + params.put("DisablePowerDown", b"1") + with pm_patch("get_battery_voltage", BATT_VOLTAGE * 1e6), pm_patch("get_battery_current", BATT_CURRENT * 1e6), \ + pm_patch("get_battery_status", "Discharging"): + pm = PowerMonitoring() + pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh + health = self.mock_health(False, log.HealthData.HwType.uno, car_voltage=(VBATT_PAUSE_CHARGING - 1)) + for i in range(TEST_TIME): + pm.calculate(health) + if i % 10 == 0: + self.assertFalse(pm.should_disable_charging(health, ssb)) + self.assertFalse(pm.should_disable_charging(health, ssb)) + + # Test to check policy of not stopping charging when ignition + def test_ignition(self): + global ssb + BATT_VOLTAGE = 4 + BATT_CURRENT = 0 # To stop shutting down for other reasons + TEST_TIME = 100 + with pm_patch("get_battery_voltage", BATT_VOLTAGE * 1e6), pm_patch("get_battery_current", BATT_CURRENT * 1e6), \ + pm_patch("get_battery_status", "Discharging"): + pm = PowerMonitoring() + pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh + health = self.mock_health(True, log.HealthData.HwType.uno, car_voltage=(VBATT_PAUSE_CHARGING - 1)) + for i in range(TEST_TIME): + pm.calculate(health) + if i % 10 == 0: + self.assertFalse(pm.should_disable_charging(health, ssb)) + self.assertFalse(pm.should_disable_charging(health, ssb)) + +if __name__ == "__main__": + unittest.main() diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index 1d69547cd4..d70625c792 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -1,23 +1,23 @@ #!/usr/bin/env python3 import os -import json -import copy import datetime import psutil +import time from smbus2 import SMBus from cereal import log from common.android import ANDROID, get_network_type, get_network_strength -from common.basedir import BASEDIR from common.params import Params, put_nonblocking from common.realtime import sec_since_boot, DT_TRML from common.numpy_fast import clip, interp from common.filter_simple import FirstOrderFilter -from selfdrive.version import terms_version, training_version +from selfdrive.version import terms_version, training_version, get_git_branch from selfdrive.swaglog import cloudlog import cereal.messaging as messaging +from selfdrive.controls.lib.alertmanager import set_offroad_alert from selfdrive.loggerd.config import get_available_percent from selfdrive.pandad import get_expected_signature -from selfdrive.thermald.power_monitoring import PowerMonitoring, get_battery_capacity, get_battery_status, get_battery_current, get_battery_voltage, get_usb_present +from selfdrive.thermald.power_monitoring import PowerMonitoring, get_battery_capacity, get_battery_status, \ + get_battery_current, get_battery_voltage, get_usb_present FW_SIGNATURE = get_expected_signature() @@ -34,10 +34,6 @@ LEON = False last_eon_fan_val = None -with open(BASEDIR + "/selfdrive/controls/lib/alerts_offroad.json") as json_file: - OFFROAD_ALERTS = json.load(json_file) - - def read_tz(x, clip=True): if not ANDROID: # we don't monitor thermal on PC @@ -100,7 +96,7 @@ def set_eon_fan(val): else: #bus.write_i2c_block_data(0x67, 0x45, [0]) bus.write_i2c_block_data(0x67, 0xa, [0x20]) - bus.write_i2c_block_data(0x67, 0x8, [(val-1)<<6]) + bus.write_i2c_block_data(0x67, 0x8, [(val - 1) << 6]) else: bus.write_byte_data(0x21, 0x04, 0x2) bus.write_byte_data(0x21, 0x03, (val*2)+1) @@ -149,9 +145,6 @@ def handle_fan_uno(max_cpu_temp, bat_temp, fan_speed, ignition): def thermald_thread(): - # prevent LEECO from undervoltage - BATT_PERC_OFF = 10 if LEON else 3 - health_timeout = int(1000 * 2.5 * DT_TRML) # 2.5x the expected health frequency # now loop @@ -170,6 +163,7 @@ def thermald_thread(): thermal_status_prev = ThermalStatus.green usb_power = True usb_power_prev = True + current_branch = get_git_branch() network_type = NetworkType.none network_strength = NetworkStrength.unknown @@ -178,11 +172,12 @@ def thermald_thread(): cpu_temp_filter = FirstOrderFilter(0., CPU_TEMP_TAU, DT_TRML) health_prev = None fw_version_match_prev = True - current_connectivity_alert = None + current_update_alert = None time_valid_prev = True should_start_prev = False handle_fan = None is_uno = False + has_relay = False params = Params() pm = PowerMonitoring() @@ -211,6 +206,7 @@ def thermald_thread(): # Setup fan handler on first connect to panda if handle_fan is None and health.health.hwType != log.HealthData.HwType.unknown: is_uno = health.health.hwType == log.HealthData.HwType.uno + has_relay = health.health.hwType in [log.HealthData.HwType.blackPanda, log.HealthData.HwType.uno, log.HealthData.HwType.dos] if is_uno or not ANDROID: cloudlog.info("Setting up UNO fan handler") @@ -250,6 +246,7 @@ def thermald_thread(): if is_uno: msg.thermal.batteryPercent = 100 msg.thermal.batteryStatus = "Charging" + msg.thermal.bat = 0 current_filter.update(msg.thermal.batteryCurrent / 1e6) @@ -267,14 +264,16 @@ def thermald_thread(): fan_speed = handle_fan(max_cpu_temp, bat_temp, fan_speed, ignition) msg.thermal.fanSpeed = fan_speed - # thermal logic with hysterisis - if max_cpu_temp > 107. or bat_temp >= 63.: + # If device is offroad we want to cool down before going onroad + # since going onroad increases load and can make temps go over 107 + # We only do this if there is a relay that prevents the car from faulting + if max_cpu_temp > 107. or bat_temp >= 63. or (has_relay and (started_ts is None) and max_cpu_temp > 70.0): # onroad not allowed thermal_status = ThermalStatus.danger - elif max_comp_temp > 92.5 or bat_temp > 60.: # CPU throttling starts around ~90C + elif max_comp_temp > 96.0 or bat_temp > 60.: # hysteresis between onroad not allowed and engage not allowed thermal_status = clip(thermal_status, ThermalStatus.red, ThermalStatus.danger) - elif max_cpu_temp > 87.5: + elif max_cpu_temp > 94.0: # hysteresis between engage not allowed and uploader not allowed thermal_status = clip(thermal_status, ThermalStatus.yellow, ThermalStatus.red) elif max_cpu_temp > 80.0: @@ -295,9 +294,9 @@ def thermald_thread(): # show invalid date/time alert time_valid = now.year >= 2019 if time_valid and not time_valid_prev: - params.delete("Offroad_InvalidTime") + set_offroad_alert("Offroad_InvalidTime", False) if not time_valid and time_valid_prev: - put_nonblocking("Offroad_InvalidTime", json.dumps(OFFROAD_ALERTS["Offroad_InvalidTime"])) + set_offroad_alert("Offroad_InvalidTime", True) time_valid_prev = time_valid # Show update prompt @@ -309,24 +308,37 @@ def thermald_thread(): update_failed_count = params.get("UpdateFailedCount") update_failed_count = 0 if update_failed_count is None else int(update_failed_count) + last_update_exception = params.get("LastUpdateException", encoding='utf8') - if dt.days > DAYS_NO_CONNECTIVITY_MAX and update_failed_count > 1: - if current_connectivity_alert != "expired": - current_connectivity_alert = "expired" - params.delete("Offroad_ConnectivityNeededPrompt") - put_nonblocking("Offroad_ConnectivityNeeded", json.dumps(OFFROAD_ALERTS["Offroad_ConnectivityNeeded"])) + if update_failed_count > 15 and last_update_exception is not None: + if current_branch in ["release2", "dashcam"]: + extra_text = "Ensure the software is correctly installed" + else: + extra_text = last_update_exception + + if current_update_alert != "update" + extra_text: + current_update_alert = "update" + extra_text + set_offroad_alert("Offroad_ConnectivityNeeded", False) + set_offroad_alert("Offroad_ConnectivityNeededPrompt", False) + set_offroad_alert("Offroad_UpdateFailed", True, extra_text=extra_text) + elif dt.days > DAYS_NO_CONNECTIVITY_MAX and update_failed_count > 1: + if current_update_alert != "expired": + current_update_alert = "expired" + set_offroad_alert("Offroad_UpdateFailed", False) + set_offroad_alert("Offroad_ConnectivityNeededPrompt", False) + set_offroad_alert("Offroad_ConnectivityNeeded", True) elif dt.days > DAYS_NO_CONNECTIVITY_PROMPT: remaining_time = str(max(DAYS_NO_CONNECTIVITY_MAX - dt.days, 0)) - if current_connectivity_alert != "prompt" + remaining_time: - current_connectivity_alert = "prompt" + remaining_time - alert_connectivity_prompt = copy.copy(OFFROAD_ALERTS["Offroad_ConnectivityNeededPrompt"]) - alert_connectivity_prompt["text"] += remaining_time + " days." - params.delete("Offroad_ConnectivityNeeded") - put_nonblocking("Offroad_ConnectivityNeededPrompt", json.dumps(alert_connectivity_prompt)) - elif current_connectivity_alert is not None: - current_connectivity_alert = None - params.delete("Offroad_ConnectivityNeeded") - params.delete("Offroad_ConnectivityNeededPrompt") + if current_update_alert != "prompt" + remaining_time: + current_update_alert = "prompt" + remaining_time + set_offroad_alert("Offroad_UpdateFailed", False) + set_offroad_alert("Offroad_ConnectivityNeeded", False) + set_offroad_alert("Offroad_ConnectivityNeededPrompt", True, extra_text=f"{remaining_time} days.") + elif current_update_alert is not None: + current_update_alert = None + set_offroad_alert("Offroad_UpdateFailed", False) + set_offroad_alert("Offroad_ConnectivityNeeded", False) + set_offroad_alert("Offroad_ConnectivityNeededPrompt", False) do_uninstall = params.get("DoUninstall") == b"1" accepted_terms = params.get("HasAcceptedTerms") == terms_version @@ -356,19 +368,19 @@ def thermald_thread(): should_start = should_start and (not is_taking_snapshot) and (not is_viewing_driver) if fw_version_match and not fw_version_match_prev: - params.delete("Offroad_PandaFirmwareMismatch") + set_offroad_alert("Offroad_PandaFirmwareMismatch", False) if not fw_version_match and fw_version_match_prev: - put_nonblocking("Offroad_PandaFirmwareMismatch", json.dumps(OFFROAD_ALERTS["Offroad_PandaFirmwareMismatch"])) + set_offroad_alert("Offroad_PandaFirmwareMismatch", True) # if any CPU gets above 107 or the battery gets above 63, kill all processes # controls will warn with CPU above 95 or battery above 60 if thermal_status >= ThermalStatus.danger: should_start = False if thermal_status_prev < ThermalStatus.danger: - put_nonblocking("Offroad_TemperatureTooHigh", json.dumps(OFFROAD_ALERTS["Offroad_TemperatureTooHigh"])) + set_offroad_alert("Offroad_TemperatureTooHigh", True) else: if thermal_status_prev >= ThermalStatus.danger: - params.delete("Offroad_TemperatureTooHigh") + set_offroad_alert("Offroad_TemperatureTooHigh", False) if should_start: if not should_start_prev: @@ -388,15 +400,20 @@ def thermald_thread(): off_ts = sec_since_boot() os.system('echo powersave > /sys/class/devfreq/soc:qcom,cpubw/governor') - # shutdown if the battery gets lower than 3%, it's discharging, we aren't running for - # more than a minute but we were running - if msg.thermal.batteryPercent < BATT_PERC_OFF and msg.thermal.batteryStatus == "Discharging" and \ - started_seen and (sec_since_boot() - off_ts) > 60: - os.system('LD_LIBRARY_PATH="" svc power shutdown') - # Offroad power monitoring pm.calculate(health) msg.thermal.offroadPowerUsage = pm.get_power_used() + msg.thermal.carBatteryCapacity = max(0, pm.get_car_battery_capacity()) + + # Check if we need to disable charging (handled by boardd) + msg.thermal.chargingDisabled = pm.should_disable_charging(health, off_ts) + + # Check if we need to shut down + if pm.should_shutdown(health, off_ts, started_seen, LEON): + cloudlog.info(f"shutting device down, offroad since {off_ts}") + # TODO: add function for blocking cloudlog instead of sleep + time.sleep(10) + os.system('LD_LIBRARY_PATH="" svc power shutdown') msg.thermal.chargingError = current_filter.x > 0. and msg.thermal.batteryPercent < 90 # if current is positive, then battery is being discharged msg.thermal.started = started_ts is not None @@ -406,9 +423,9 @@ def thermald_thread(): thermal_sock.send(msg.to_bytes()) if usb_power_prev and not usb_power: - put_nonblocking("Offroad_ChargeDisabled", json.dumps(OFFROAD_ALERTS["Offroad_ChargeDisabled"])) + set_offroad_alert("Offroad_ChargeDisabled", True) elif usb_power and not usb_power_prev: - params.delete("Offroad_ChargeDisabled") + set_offroad_alert("Offroad_ChargeDisabled", False) thermal_status_prev = thermal_status usb_power_prev = usb_power diff --git a/selfdrive/tombstoned.py b/selfdrive/tombstoned.py index 022f9fdfcf..4dc969b5c7 100755 --- a/selfdrive/tombstoned.py +++ b/selfdrive/tombstoned.py @@ -61,7 +61,7 @@ def main(): while True: now_tombstones = set(get_tombstones()) - for fn, ctime in (now_tombstones - initial_tombstones): + for fn, _ in (now_tombstones - initial_tombstones): try: cloudlog.info(f"reporting new tombstone {fn}") report_tombstone(fn, client) diff --git a/selfdrive/ui/.gitignore b/selfdrive/ui/.gitignore new file mode 100644 index 0000000000..27a652ceed --- /dev/null +++ b/selfdrive/ui/.gitignore @@ -0,0 +1 @@ +moc_* diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 88bde059ea..485a4fbfd0 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -1,17 +1,26 @@ -Import('env', 'arch', 'common', 'messaging', 'gpucommon', 'visionipc', 'cereal') +Import('env', 'qt_env', 'arch', 'common', 'messaging', 'gpucommon', 'visionipc', 'cereal') src = ['ui.cc', 'paint.cc', 'sidebar.cc', '#phonelibs/nanovg/nanovg.c'] libs = [common, 'zmq', 'czmq', 'capnp', 'kj', 'm', cereal, messaging, gpucommon, visionipc] -if arch == "aarch64": - src += ['sound.cc', 'slplay.c'] + +if qt_env is None: + src += ['sound.cc'] libs += ['EGL', 'GLESv3', 'gnustl_shared', 'log', 'utils', 'gui', 'hardware', 'ui', 'CB', 'gsl', 'adreno_utils', 'OpenSLES', 'cutils', 'uuid', 'OpenCL'] linkflags = ['-Wl,-rpath=/system/lib64,-rpath=/system/comma/usr/lib'] + + src = ["android_ui.cc"] + src + env.Program('_ui', src, + LINKFLAGS=linkflags, + LIBS=libs) + else: - src += ['linux.cc'] - libs += ['pthread', 'glfw'] - linkflags = [] + qt_libs = ["GL", "pthread"] + + if arch == "Darwin": + qt_env["FRAMEWORKS"] += ["QtWidgets", "QtGui", "QtCore", "QtDBus"] + else: + qt_libs += ["Qt5Widgets", "Qt5Gui", "Qt5Core", "Qt5DBus"] -env.Program('_ui', src, - LINKFLAGS=linkflags, - LIBS=libs) + qt_src = ["qt/ui.cc", "qt/window.cc", "qt/settings.cc"] + src + qt_env.Program("_ui", qt_src, LIBS=qt_libs + libs) diff --git a/selfdrive/ui/android_ui.cc b/selfdrive/ui/android_ui.cc new file mode 100644 index 0000000000..983d817e79 --- /dev/null +++ b/selfdrive/ui/android_ui.cc @@ -0,0 +1,360 @@ +#include +#include +#include +#include + +#include "common/util.h" +#include "common/utilpp.h" +#include "common/params.h" +#include "common/touch.h" +#include "common/timing.h" +#include "common/swaglog.h" + +#include "ui.hpp" +#include "paint.hpp" + +// Includes for light sensor +#include +#include +#include + +volatile sig_atomic_t do_exit = 0; +static void set_do_exit(int sig) { + do_exit = 1; +} + + +static void* light_sensor_thread(void *args) { + set_thread_name("light_sensor"); + + int err; + UIState *s = (UIState*)args; + s->light_sensor = 0.0; + + struct sensors_poll_device_t* device; + struct sensors_module_t* module; + + hw_get_module(SENSORS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); + sensors_open(&module->common, &device); + + // need to do this + struct sensor_t const* list; + module->get_sensors_list(module, &list); + + int SENSOR_LIGHT = 7; + + err = device->activate(device, SENSOR_LIGHT, 0); + if (err != 0) goto fail; + err = device->activate(device, SENSOR_LIGHT, 1); + if (err != 0) goto fail; + + device->setDelay(device, SENSOR_LIGHT, ms2ns(100)); + + while (!do_exit) { + static const size_t numEvents = 1; + sensors_event_t buffer[numEvents]; + + int n = device->poll(device, buffer, numEvents); + if (n < 0) { + LOG_100("light_sensor_poll failed: %d", n); + } + if (n > 0) { + s->light_sensor = buffer[0].light; + } + } + sensors_close(device); + return NULL; + +fail: + LOGE("LIGHT SENSOR IS MISSING"); + s->light_sensor = 255; + + return NULL; +} + +static void ui_set_brightness(UIState *s, int brightness) { + static int last_brightness = -1; + if (last_brightness != brightness && (s->awake || brightness == 0)) { + if (set_brightness(brightness)) { + last_brightness = brightness; + } + } +} + +int event_processing_enabled = -1; +static void enable_event_processing(bool yes) { + if (event_processing_enabled != 1 && yes) { + system("service call window 18 i32 1"); // enable event processing + event_processing_enabled = 1; + } else if (event_processing_enabled != 0 && !yes) { + system("service call window 18 i32 0"); // disable event processing + event_processing_enabled = 0; + } +} + +static void set_awake(UIState *s, bool awake) { + if (awake) { + // 30 second timeout + s->awake_timeout = 30*UI_FREQ; + } + if (s->awake != awake) { + s->awake = awake; + + // TODO: replace command_awake and command_sleep with direct calls to android + if (awake) { + LOGW("awake normal"); + framebuffer_set_power(s->fb, HWC_POWER_MODE_NORMAL); + enable_event_processing(true); + } else { + LOGW("awake off"); + ui_set_brightness(s, 0); + framebuffer_set_power(s->fb, HWC_POWER_MODE_OFF); + enable_event_processing(false); + } + } +} + +static void handle_vision_touch(UIState *s, int touch_x, int touch_y) { + if (s->started && (touch_x >= s->scene.ui_viz_rx - bdr_s) + && (s->active_app != cereal::UiLayoutState::App::SETTINGS)) { + if (!s->scene.frontview) { + s->scene.uilayout_sidebarcollapsed = !s->scene.uilayout_sidebarcollapsed; + } else { + write_db_value("IsDriverViewEnabled", "0", 1); + } + } +} + +static void handle_sidebar_touch(UIState *s, int touch_x, int touch_y) { + if (!s->scene.uilayout_sidebarcollapsed && touch_x <= sbr_w) { + if (touch_x >= settings_btn_x && touch_x < (settings_btn_x + settings_btn_w) + && touch_y >= settings_btn_y && touch_y < (settings_btn_y + settings_btn_h)) { + s->active_app = cereal::UiLayoutState::App::SETTINGS; + } + else if (touch_x >= home_btn_x && touch_x < (home_btn_x + home_btn_w) + && touch_y >= home_btn_y && touch_y < (home_btn_y + home_btn_h)) { + if (s->started) { + s->active_app = cereal::UiLayoutState::App::NONE; + s->scene.uilayout_sidebarcollapsed = true; + } else { + s->active_app = cereal::UiLayoutState::App::HOME; + } + } + } +} + +static void update_offroad_layout_state(UIState *s) { + static int timeout = 0; + static bool prev_collapsed = false; + static cereal::UiLayoutState::App prev_app = cereal::UiLayoutState::App::NONE; + if (timeout > 0) { + timeout--; + } + if (prev_collapsed != s->scene.uilayout_sidebarcollapsed || prev_app != s->active_app || timeout == 0) { + capnp::MallocMessageBuilder msg; + auto event = msg.initRoot(); + event.setLogMonoTime(nanos_since_boot()); + auto layout = event.initUiLayoutState(); + layout.setActiveApp(s->active_app); + layout.setSidebarCollapsed(s->scene.uilayout_sidebarcollapsed); + s->pm->send("offroadLayout", msg); + LOGD("setting active app to %d with sidebar %d", (int)s->active_app, s->scene.uilayout_sidebarcollapsed); + prev_collapsed = s->scene.uilayout_sidebarcollapsed; + prev_app = s->active_app; + timeout = 2 * UI_FREQ; + } +} + +int main(int argc, char* argv[]) { + int err; + setpriority(PRIO_PROCESS, 0, -14); + + zsys_handler_set(NULL); + signal(SIGINT, (sighandler_t)set_do_exit); + + UIState uistate = {}; + UIState *s = &uistate; + ui_init(s); + set_awake(s, true); + + enable_event_processing(true); + + pthread_t connect_thread_handle; + err = pthread_create(&connect_thread_handle, NULL, + vision_connect_thread, s); + assert(err == 0); + + pthread_t light_sensor_thread_handle; + err = pthread_create(&light_sensor_thread_handle, NULL, + light_sensor_thread, s); + assert(err == 0); + + TouchState touch = {0}; + touch_init(&touch); + s->touch_fd = touch.fd; + + // light sensor scaling params + const bool LEON = util::read_file("/proc/cmdline").find("letv") != std::string::npos; + + float brightness_b, brightness_m; + int result = read_param(&brightness_b, "BRIGHTNESS_B", true); + result += read_param(&brightness_m, "BRIGHTNESS_M", true); + + if(result != 0){ + brightness_b = LEON ? 10.0 : 5.0; + brightness_m = LEON ? 2.6 : 1.3; + write_param_float(brightness_b, "BRIGHTNESS_B", true); + write_param_float(brightness_m, "BRIGHTNESS_M", true); + } + + float smooth_brightness = brightness_b; + + const int MIN_VOLUME = LEON ? 12 : 9; + const int MAX_VOLUME = LEON ? 15 : 12; + assert(s->sound.init(MIN_VOLUME)); + + int draws = 0; + + while (!do_exit) { + bool should_swap = false; + if (!s->started) { + // Delay a while to avoid 9% cpu usage while car is not started and user is keeping touching on the screen. + // Don't hold the lock while sleeping, so that vision_connect_thread have chances to get the lock. + usleep(30 * 1000); + } + pthread_mutex_lock(&s->lock); + double u1 = millis_since_boot(); + + // light sensor is only exposed on EONs + float clipped_brightness = (s->light_sensor*brightness_m) + brightness_b; + if (clipped_brightness > 512) clipped_brightness = 512; + smooth_brightness = clipped_brightness * 0.01 + smooth_brightness * 0.99; + if (smooth_brightness > 255) smooth_brightness = 255; + ui_set_brightness(s, (int)smooth_brightness); + ui_update_sizes(s); + + // poll for touch events + int touch_x = -1, touch_y = -1; + int touched = touch_poll(&touch, &touch_x, &touch_y, 0); + if (touched == 1) { + set_awake(s, true); + handle_sidebar_touch(s, touch_x, touch_y); + handle_vision_touch(s, touch_x, touch_y); + } + + if (!s->started) { + // always process events offroad + check_messages(s); + + if (s->started) { + s->controls_timeout = 5 * UI_FREQ; + } + } else { + set_awake(s, true); + // Car started, fetch a new rgb image from ipc + if (s->vision_connected){ + ui_update(s); + } + + check_messages(s); + + // Visiond process is just stopped, force a redraw to make screen blank again. + if (!s->started) { + s->scene.uilayout_sidebarcollapsed = false; + ui_draw(s); + glFinish(); + should_swap = true; + } + } + + // manage wakefulness + if (s->awake_timeout > 0) { + s->awake_timeout--; + } else { + set_awake(s, false); + } + + // manage hardware disconnect + if (s->hardware_timeout > 0) { + s->hardware_timeout--; + } else { + s->scene.hwType = cereal::HealthData::HwType::UNKNOWN; + } + + // Don't waste resources on drawing in case screen is off + if (s->awake) { + ui_draw(s); + glFinish(); + should_swap = true; + } + + s->sound.setVolume(fmin(MAX_VOLUME, MIN_VOLUME + s->scene.controls_state.getVEgo() / 5)); // up one notch every 5 m/s + + if (s->controls_timeout > 0) { + s->controls_timeout--; + } else if (s->started && !s->scene.frontview) { + if (!s->controls_seen) { + // car is started, but controlsState hasn't been seen at all + s->scene.alert_text1 = "openpilot Unavailable"; + s->scene.alert_text2 = "Waiting for controls to start"; + s->scene.alert_size = cereal::ControlsState::AlertSize::MID; + } else { + // car is started, but controls is lagging or died + LOGE("Controls unresponsive"); + + if (s->scene.alert_text2 != "Controls Unresponsive") { + s->sound.play(AudibleAlert::CHIME_WARNING_REPEAT); + } + + s->scene.alert_text1 = "TAKE CONTROL IMMEDIATELY"; + s->scene.alert_text2 = "Controls Unresponsive"; + s->scene.alert_size = cereal::ControlsState::AlertSize::FULL; + update_status(s, STATUS_ALERT); + } + ui_draw_vision_alert(s, s->scene.alert_size, s->status, s->scene.alert_text1.c_str(), s->scene.alert_text2.c_str()); + } + + read_param_timeout(&s->is_metric, "IsMetric", &s->is_metric_timeout); + read_param_timeout(&s->longitudinal_control, "LongitudinalControl", &s->longitudinal_control_timeout); + read_param_timeout(&s->limit_set_speed, "LimitSetSpeed", &s->limit_set_speed_timeout); + read_param_timeout(&s->speed_lim_off, "SpeedLimitOffset", &s->limit_set_speed_timeout); + int param_read = read_param_timeout(&s->last_athena_ping, "LastAthenaPingTime", &s->last_athena_ping_timeout); + if (param_read != -1) { // Param was updated this loop + if (param_read != 0) { // Failed to read param + s->scene.athenaStatus = NET_DISCONNECTED; + } else if (nanos_since_boot() - s->last_athena_ping < 70e9) { + s->scene.athenaStatus = NET_CONNECTED; + } else { + s->scene.athenaStatus = NET_ERROR; + } + } + update_offroad_layout_state(s); + + pthread_mutex_unlock(&s->lock); + + // the bg thread needs to be scheduled, so the main thread needs time without the lock + // safe to do this outside the lock? + if (should_swap) { + double u2 = millis_since_boot(); + if (u2-u1 > 66) { + // warn on sub 15fps + LOGW("slow frame(%d) time: %.2f", draws, u2-u1); + } + draws++; + framebuffer_swap(s->fb); + } + } + + set_awake(s, true); + + // wake up bg thread to exit + pthread_mutex_lock(&s->lock); + pthread_mutex_unlock(&s->lock); + + // join light_sensor_thread? + err = pthread_join(connect_thread_handle, NULL); + assert(err == 0); + delete s->sm; + delete s->pm; + return 0; +} diff --git a/selfdrive/ui/linux.cc b/selfdrive/ui/linux.cc deleted file mode 100644 index 8e4a8492dc..0000000000 --- a/selfdrive/ui/linux.cc +++ /dev/null @@ -1,107 +0,0 @@ -#include -#include -#include -#include -#include - -#include "ui.hpp" - -#ifndef __APPLE__ -#define GLFW_INCLUDE_ES2 -#else -#define GLFW_INCLUDE_GLCOREARB -#endif - -#define GLFW_INCLUDE_GLEXT -#include - -typedef struct FramebufferState FramebufferState; -typedef struct TouchState TouchState; - -extern "C" { - -FramebufferState* framebuffer_init( - const char* name, int32_t layer, int alpha, - int *out_w, int *out_h) { - glfwInit(); - -#ifndef __APPLE__ - glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); -#else - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); -#endif - glfwWindowHint(GLFW_RESIZABLE, 0); - GLFWwindow* window; - window = glfwCreateWindow(1920, 1080, "ui", NULL, NULL); - if (!window) { - printf("glfwCreateWindow failed\n"); - } - - glfwMakeContextCurrent(window); - glfwSwapInterval(0); - - // clear screen - glClearColor(0.2f, 0.2f, 0.2f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - framebuffer_swap((FramebufferState*)window); - - if (out_w) *out_w = 1920; - if (out_h) *out_h = 1080; - - return (FramebufferState*)window; -} - -void framebuffer_set_power(FramebufferState *s, int mode) { -} - -void framebuffer_swap(FramebufferState *s) { - glfwSwapBuffers((GLFWwindow*)s); - glfwPollEvents(); -} - -void touch_init(TouchState *s) { - printf("touch_init\n"); -} - -int touch_poll(TouchState *s, int* out_x, int* out_y, int timeout) { - return -1; -} - -int touch_read(TouchState *s, int* out_x, int* out_y) { - return -1; -} - -} - -#include "sound.hpp" - -void ui_sound_init() {} -void ui_sound_destroy() {} - -void set_volume(int volume) {} - -void play_alert_sound(AudibleAlert alert) {} -void stop_alert_sound(AudibleAlert alert) {} - -#include "common/visionimg.h" -#include - -GLuint visionimg_to_gl(const VisionImg *img, EGLImageKHR *pkhr, void **pph) { - unsigned int texture; - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img->width, img->height, 0, GL_RGB, GL_UNSIGNED_BYTE, *pph); - glGenerateMipmap(GL_TEXTURE_2D); - *pkhr = (EGLImageKHR)1; // not NULL - return texture; -} - -void visionimg_destroy_gl(EGLImageKHR khr, void *ph) { - // empty -} - diff --git a/selfdrive/ui/paint.cc b/selfdrive/ui/paint.cc index ff1db9a251..f8e3675516 100644 --- a/selfdrive/ui/paint.cc +++ b/selfdrive/ui/paint.cc @@ -1,10 +1,11 @@ #include "ui.hpp" #include #include +#include +#include #include "common/util.h" #define NANOVG_GLES3_IMPLEMENTATION - #include "nanovg_gl.h" #include "nanovg_gl_utils.h" @@ -12,6 +13,9 @@ extern "C"{ #include "common/glutil.h" } +#include "paint.hpp" +#include "sidebar.hpp" + // TODO: this is also hardcoded in common/transformations/camera.py const mat3 intrinsic_matrix = (mat3){{ 910., 0., 582., @@ -109,11 +113,13 @@ static void ui_draw_circle_image(NVGcontext *vg, float x, float y, int size, int ui_draw_circle_image(vg, x, y, size, image, nvgRGBA(0, 0, 0, (255 * bg_alpha)), img_alpha); } -static void draw_lead(UIState *s, float d_rel, float v_rel, float y_rel){ +static void draw_lead(UIState *s, const cereal::RadarState::LeadData::Reader &lead){ // Draw lead car indicator float fillAlpha = 0; float speedBuff = 10.; float leadBuff = 40.; + float d_rel = lead.getDRel(); + float v_rel = lead.getVRel(); if (d_rel < leadBuff) { fillAlpha = 255*(1.0-(d_rel/leadBuff)); if (v_rel < 0) { @@ -121,24 +127,16 @@ static void draw_lead(UIState *s, float d_rel, float v_rel, float y_rel){ } fillAlpha = (int)(fmin(fillAlpha, 255)); } - draw_chevron(s, d_rel, y_rel, 25, nvgRGBA(201, 34, 49, fillAlpha), COLOR_YELLOW); + draw_chevron(s, d_rel, lead.getYRel(), 25, nvgRGBA(201, 34, 49, fillAlpha), COLOR_YELLOW); } static void ui_draw_lane_line(UIState *s, const model_path_vertices_data *pvd, NVGcolor color) { + if (pvd->cnt == 0) return; + nvgBeginPath(s->vg); - bool started = false; - for (int i=0; icnt; i++) { - float x = pvd->v[i].x; - float y = pvd->v[i].y; - if (x < 0 || y < 0.) { - continue; - } - if (!started) { - nvgMoveTo(s->vg, x, y); - started = true; - } else { - nvgLineTo(s->vg, x, y); - } + nvgMoveTo(s->vg, pvd->v[0].x, pvd->v[0].y); + for (int i=1; icnt; i++) { + nvgLineTo(s->vg, pvd->v[i].x, pvd->v[i].y); } nvgClosePath(s->vg); nvgFillColor(s->vg, color); @@ -147,15 +145,15 @@ static void ui_draw_lane_line(UIState *s, const model_path_vertices_data *pvd, N static void update_track_data(UIState *s, bool is_mpc, track_vertices_data *pvd) { const UIScene *scene = &s->scene; - const PathData path = scene->model.path; + const float *points = scene->path_points; const float *mpc_x_coords = &scene->mpc_x[0]; const float *mpc_y_coords = &scene->mpc_y[0]; - bool started = false; float off = is_mpc?0.3:0.5; - float lead_d = scene->lead_d_rel*2.; + float lead_d = scene->lead_data[0].getDRel()*2.; float path_height = is_mpc?(lead_d>5.)?fmin(lead_d, 25.)-fmin(lead_d*0.35, 10.):20. :(lead_d>0.)?fmin(lead_d, 50.)-fmin(lead_d*0.35, 10.):49.; + path_height = fmin(path_height, scene->model.getPath().getValidLen()); pvd->cnt = 0; // left side up for (int i=0; i<=path_height; i++) { @@ -166,7 +164,7 @@ static void update_track_data(UIState *s, bool is_mpc, track_vertices_data *pvd) py = mpc_y_coords[i] - off; } else { px = lerp(i+1.0, i, i/100.0); - py = path.points[i] - off; + py = points[i] - off; } vec4 p_car_space = (vec4){{px, py, 0., 1.}}; @@ -188,11 +186,14 @@ static void update_track_data(UIState *s, bool is_mpc, track_vertices_data *pvd) py = mpc_y_coords[i] + off; } else { px = lerp(i+1.0, i, i/100.0); - py = path.points[i] + off; + py = points[i] + off; } vec4 p_car_space = (vec4){{px, py, 0., 1.}}; vec3 p_full_frame = car_space_to_full_frame(s, p_car_space); + if (p_full_frame.v[0] < 0. || p_full_frame.v[1] < 0.) { + continue; + } pvd->v[pvd->cnt].x = p_full_frame.v[0]; pvd->v[pvd->cnt].y = p_full_frame.v[1]; pvd->cnt += 1; @@ -204,28 +205,19 @@ static void update_all_track_data(UIState *s) { // Draw vision path update_track_data(s, false, &s->track_vertices[0]); - if (scene->engaged) { + if (scene->controls_state.getEnabled()) { // Draw MPC path when engaged update_track_data(s, true, &s->track_vertices[1]); } } - static void ui_draw_track(UIState *s, bool is_mpc, track_vertices_data *pvd) { + if (pvd->cnt == 0) return; + nvgBeginPath(s->vg); - bool started = false; - for(int i = 0;i < pvd->cnt;i++) { - float x = pvd->v[i].x; - float y = pvd->v[i].y; - if (x < 0 || y < 0) { - continue; - } - if (!started) { - nvgMoveTo(s->vg, x, y); - started = true; - } else { - nvgLineTo(s->vg, x, y); - } + nvgMoveTo(s->vg, pvd->v[0].x, pvd->v[0].y); + for (int i=1; icnt; i++) { + nvgLineTo(s->vg, pvd->v[i].x, pvd->v[i].y); } nvgClosePath(s->vg); @@ -244,16 +236,6 @@ static void ui_draw_track(UIState *s, bool is_mpc, track_vertices_data *pvd) { nvgFill(s->vg); } -static void draw_steering(UIState *s, float curvature) { - float points[50]; - for (int i = 0; i < 50; i++) { - float y_actual = i * tan(asin(clamp(i * curvature, -0.999, 0.999)) / 2.); - points[i] = y_actual; - } - - // ui_draw_lane_edge(s, points, 0.0, nvgRGBA(0, 0, 255, 128), 5); -} - static void draw_frame(UIState *s) { const UIScene *scene = &s->scene; @@ -276,6 +258,7 @@ static void draw_frame(UIState *s) { glBindTexture(GL_TEXTURE_2D, s->frame_texs[s->cur_vision_idx]); #ifndef QCOM // TODO: a better way to do this? + //printf("%d\n", ((int*)s->priv_hnds[s->cur_vision_idx])[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1164, 874, 0, GL_RGB, GL_UNSIGNED_BYTE, s->priv_hnds[s->cur_vision_idx]); #endif } @@ -295,9 +278,10 @@ static inline bool valid_frame_pt(UIState *s, float x, float y) { return x >= 0 && x <= s->rgb_width && y >= 0 && y <= s->rgb_height; } -static void update_lane_line_data(UIState *s, const float *points, float off, bool is_ghost, model_path_vertices_data *pvd) { +static void update_lane_line_data(UIState *s, const float *points, float off, model_path_vertices_data *pvd, float valid_len) { pvd->cnt = 0; - for (int i = 0; i < MODEL_PATH_MAX_VERTICES_CNT / 2; i++) { + int rcount = fmin(MODEL_PATH_MAX_VERTICES_CNT / 2, valid_len); + for (int i = 0; i < rcount; i++) { float px = (float)i; float py = points[i] - off; const vec4 p_car_space = (vec4){{px, py, 0., 1.}}; @@ -308,9 +292,9 @@ static void update_lane_line_data(UIState *s, const float *points, float off, bo pvd->v[pvd->cnt].y = p_full_frame.v[1]; pvd->cnt += 1; } - for (int i = MODEL_PATH_MAX_VERTICES_CNT / 2; i > 0; i--) { + for (int i = rcount - 1; i > 0; i--) { float px = (float)i; - float py = is_ghost?(points[i]-off):(points[i]+off); + float py = points[i] + off; const vec4 p_car_space = (vec4){{px, py, 0., 1.}}; const vec3 p_full_frame = car_space_to_full_frame(s, p_car_space); if(!valid_frame_pt(s, p_full_frame.v[0], p_full_frame.v[1])) @@ -321,48 +305,40 @@ static void update_lane_line_data(UIState *s, const float *points, float off, bo } } -static void update_all_lane_lines_data(UIState *s, const PathData path, model_path_vertices_data *pstart) { - update_lane_line_data(s, path.points, 0.025*path.prob, false, pstart); - float var = fmin(path.std, 0.7); - update_lane_line_data(s, path.points, -var, true, pstart + 1); - update_lane_line_data(s, path.points, var, true, pstart + 2); +static void update_all_lane_lines_data(UIState *s, const cereal::ModelData::PathData::Reader &path, const float *points, model_path_vertices_data *pstart) { + update_lane_line_data(s, points, 0.025*path.getProb(), pstart, path.getValidLen()); + update_lane_line_data(s, points, fmin(path.getStd(), 0.7), pstart + 1, path.getValidLen()); } -static void ui_draw_lane(UIState *s, const PathData *path, model_path_vertices_data *pstart, NVGcolor color) { +static void ui_draw_lane(UIState *s, model_path_vertices_data *pstart, NVGcolor color) { ui_draw_lane_line(s, pstart, color); - float var = fmin(path->std, 0.7); - color.a /= 4; + color.a /= 25; ui_draw_lane_line(s, pstart + 1, color); - ui_draw_lane_line(s, pstart + 2, color); } static void ui_draw_vision_lanes(UIState *s) { const UIScene *scene = &s->scene; model_path_vertices_data *pvd = &s->model_path_vertices[0]; - if(s->model_changed) { - update_all_lane_lines_data(s, scene->model.left_lane, pvd); - update_all_lane_lines_data(s, scene->model.right_lane, pvd + MODEL_LANE_PATH_CNT); - s->model_changed = false; + if(s->sm->updated("model")) { + update_all_lane_lines_data(s, scene->model.getLeftLane(), scene->left_lane_points, pvd); + update_all_lane_lines_data(s, scene->model.getRightLane(), scene->right_lane_points, pvd + MODEL_LANE_PATH_CNT); } // Draw left lane edge ui_draw_lane( - s, &scene->model.left_lane, - pvd, - nvgRGBAf(1.0, 1.0, 1.0, scene->model.left_lane.prob)); + s, pvd, + nvgRGBAf(1.0, 1.0, 1.0, scene->model.getLeftLane().getProb())); // Draw right lane edge ui_draw_lane( - s, &scene->model.right_lane, - pvd + MODEL_LANE_PATH_CNT, - nvgRGBAf(1.0, 1.0, 1.0, scene->model.right_lane.prob)); + s, pvd + MODEL_LANE_PATH_CNT, + nvgRGBAf(1.0, 1.0, 1.0, scene->model.getRightLane().getProb())); - if(s->livempc_or_radarstate_changed) { + if(s->sm->updated("radarState")) { update_all_track_data(s); - s->livempc_or_radarstate_changed = false; } // Draw vision path ui_draw_track(s, false, &s->track_vertices[0]); - if (scene->engaged) { + if (scene->controls_state.getEnabled()) { // Draw MPC path when engaged ui_draw_track(s, true, &s->track_vertices[1]); } @@ -375,7 +351,7 @@ static void ui_draw_world(UIState *s) { return; } - const int inner_height = viz_w*9/16; + const int inner_height = float(viz_w) * vwp_h / vwp_w; const int ui_viz_rx = scene->ui_viz_rx; const int ui_viz_rw = scene->ui_viz_rw; const int ui_viz_ro = scene->ui_viz_ro; @@ -385,19 +361,25 @@ static void ui_draw_world(UIState *s) { nvgTranslate(s->vg, ui_viz_rx+ui_viz_ro, box_y + (box_h-inner_height)/2.0); nvgScale(s->vg, (float)viz_w / s->fb_w, (float)inner_height / s->fb_h); - nvgTranslate(s->vg, 240.0f, 0.0); - nvgTranslate(s->vg, -1440.0f / 2, -1080.0f / 2); + + float w = 1440.0f; // Why 1440? + nvgTranslate(s->vg, (vwp_w - w) / 2.0f, 0.0); + + nvgTranslate(s->vg, -w / 2, -1080.0f / 2); nvgScale(s->vg, 2.0, 2.0); - nvgScale(s->vg, 1440.0f / s->rgb_width, 1080.0f / s->rgb_height); + nvgScale(s->vg, w / s->rgb_width, 1080.0f / s->rgb_height); // Draw lane edges and vision/mpc tracks ui_draw_vision_lanes(s); - if (scene->lead_status) { - draw_lead(s, scene->lead_d_rel, scene->lead_v_rel, scene->lead_y_rel); - } - if ((scene->lead_status2) && (fabs(scene->lead_d_rel - scene->lead_d_rel2) > 3.0)) { - draw_lead(s, scene->lead_d_rel2, scene->lead_v_rel2, scene->lead_y_rel2); + // Draw lead indicators if openpilot is handling longitudinal + if (s->longitudinal_control) { + if (scene->lead_data[0].getStatus()) { + draw_lead(s, scene->lead_data[0]); + } + if (scene->lead_data[1].getStatus() && (std::abs(scene->lead_data[0].getDRel() - scene->lead_data[1].getDRel()) > 3.0)) { + draw_lead(s, scene->lead_data[1]); + } } nvgRestore(s->vg); } @@ -407,7 +389,7 @@ static void ui_draw_vision_maxspeed(UIState *s) { return; }*/ char maxspeed_str[32]; - float maxspeed = s->scene.v_cruise; + float maxspeed = s->scene.controls_state.getVCruise(); int maxspeed_calc = maxspeed * 0.6225 + 0.5; float speedlimit = s->scene.speedlimit; int speedlim_calc = speedlimit * 2.2369363 + 0.5; @@ -420,7 +402,7 @@ static void ui_draw_vision_maxspeed(UIState *s) { bool is_cruise_set = (maxspeed != 0 && maxspeed != SET_SPEED_NA); bool is_speedlim_valid = s->scene.speedlimit_valid; - bool is_set_over_limit = is_speedlim_valid && s->scene.engaged && + bool is_set_over_limit = is_speedlim_valid && s->scene.controls_state.getEnabled() && is_cruise_set && maxspeed_calc > (speedlim_calc + speed_lim_off); int viz_maxspeed_w = 184; @@ -462,6 +444,7 @@ static void ui_draw_vision_maxspeed(UIState *s) { } } +#ifdef SHOW_SPEEDLIMIT static void ui_draw_vision_speedlimit(UIState *s) { char speedlim_str[32]; float speedlimit = s->scene.speedlimit; @@ -475,7 +458,7 @@ static void ui_draw_vision_speedlimit(UIState *s) { if (s->is_ego_over_limit) { hysteresis_offset = 0.0; } - s->is_ego_over_limit = is_speedlim_valid && s->scene.v_ego > (speedlimit + s->speed_lim_off + hysteresis_offset); + s->is_ego_over_limit = is_speedlim_valid && s->scene.controls_state.getVEgo() > (speedlimit + s->speed_lim_off + hysteresis_offset); int viz_speedlim_w = 180; int viz_speedlim_h = 202; @@ -518,12 +501,14 @@ static void ui_draw_vision_speedlimit(UIState *s) { ui_draw_text(s->vg, text_x, viz_speedlim_y + (is_speedlim_valid ? 170 : 165), "N/A", 42*2.5, color, s->font_sans_semibold); } } +#endif static void ui_draw_vision_speed(UIState *s) { const UIScene *scene = &s->scene; - float speed = s->scene.v_ego * 2.2369363 + 0.5; + float v_ego = s->scene.controls_state.getVEgo(); + float speed = v_ego * 2.2369363 + 0.5; if (s->is_metric){ - speed = s->scene.v_ego * 3.6 + 0.5; + speed = v_ego * 3.6 + 0.5; } const int viz_speed_w = 280; const int viz_speed_x = scene->ui_viz_rx+((scene->ui_viz_rw/2)-(viz_speed_w/2)); @@ -535,14 +520,14 @@ static void ui_draw_vision_speed(UIState *s) { snprintf(speed_str, sizeof(speed_str), "%d", (int)speed); ui_draw_text(s->vg, viz_speed_x + viz_speed_w / 2, 240, speed_str, 96*2.5, COLOR_WHITE, s->font_sans_bold); - ui_draw_text(s->vg, viz_speed_x + viz_speed_w / 2, 320, s->is_metric?"kph":"mph", 36*2.5, COLOR_WHITE_ALPHA(200), s->font_sans_regular); + ui_draw_text(s->vg, viz_speed_x + viz_speed_w / 2, 320, s->is_metric?"km/h":"mph", 36*2.5, COLOR_WHITE_ALPHA(200), s->font_sans_regular); } static void ui_draw_vision_event(UIState *s) { const int viz_event_w = 220; const int viz_event_x = ((s->scene.ui_viz_rx + s->scene.ui_viz_rw) - (viz_event_w + (bdr_s*2))); const int viz_event_y = (box_y + (bdr_s*1.5)); - if (s->scene.decel_for_model && s->scene.engaged) { + if (s->scene.controls_state.getDecelForModel() && s->scene.controls_state.getEnabled()) { // draw winding road sign const int img_turn_size = 160*1.5; ui_draw_image(s->vg, viz_event_x - (img_turn_size / 4), viz_event_y + bdr_s - 25, img_turn_size, img_turn_size, s->img_turn, 1.0f); @@ -560,24 +545,26 @@ static void ui_draw_vision_event(UIState *s) { color = nvgRGBA(23, 51, 73, 255); } - if (s->scene.engageable){ + if (s->scene.controls_state.getEngageable()){ ui_draw_circle_image(s->vg, bg_wheel_x, bg_wheel_y, bg_wheel_size, s->img_wheel, color, 1.0f, bg_wheel_y - 25); } } } +#ifdef SHOW_SPEEDLIMIT static void ui_draw_vision_map(UIState *s) { const int map_size = 96; const int map_x = (s->scene.ui_viz_rx + (map_size * 3) + (bdr_s * 3)); const int map_y = (footer_y + ((footer_h - map_size) / 2)); ui_draw_circle_image(s->vg, map_x, map_y, map_size, s->img_map, s->scene.map_valid); } +#endif static void ui_draw_vision_face(UIState *s) { const int face_size = 96; const int face_x = (s->scene.ui_viz_rx + face_size + (bdr_s * 2)); const int face_y = (footer_y + ((footer_h - face_size) / 2)); - ui_draw_circle_image(s->vg, face_x, face_y, face_size, s->img_face, s->scene.monitoring_active); + ui_draw_circle_image(s->vg, face_x, face_y, face_size, s->img_face, s->scene.dmonitoring_state.getFaceDetected()); } static void ui_draw_driver_view(UIState *s) { @@ -589,19 +576,11 @@ static void ui_draw_driver_view(UIState *s) { const int valid_frame_x = frame_x + (frame_w - valid_frame_w) / 2 + ff_xoffset; // blackout - if (!scene->is_rhd) { - NVGpaint gradient = nvgLinearGradient(s->vg, valid_frame_x + valid_frame_w, - box_y, - valid_frame_x + box_h / 2, box_y, - nvgRGBAf(0,0,0,1), nvgRGBAf(0,0,0,0)); - ui_draw_rect(s->vg, valid_frame_x + box_h / 2, box_y, valid_frame_w - box_h / 2, box_h, gradient); - } else { - NVGpaint gradient = nvgLinearGradient(s->vg, valid_frame_x, - box_y, - valid_frame_w - box_h / 2, box_y, - nvgRGBAf(0,0,0,1), nvgRGBAf(0,0,0,0)); - ui_draw_rect(s->vg, valid_frame_x, box_y, valid_frame_w - box_h / 2, box_h, gradient); - } + NVGpaint gradient = nvgLinearGradient(s->vg, scene->is_rhd ? valid_frame_x : (valid_frame_x + valid_frame_w), + box_y, + scene->is_rhd ? (valid_frame_w - box_h / 2) : (valid_frame_x + box_h / 2), box_y, + COLOR_BLACK, COLOR_BLACK_ALPHA(0)); + ui_draw_rect(s->vg, scene->is_rhd ? valid_frame_x : (valid_frame_x + box_h / 2), box_y, valid_frame_w - box_h / 2, box_h, gradient); ui_draw_rect(s->vg, scene->is_rhd ? valid_frame_x : valid_frame_x + box_h / 2, box_y, valid_frame_w - box_h / 2, box_h, COLOR_BLACK_ALPHA(144)); // borders @@ -609,30 +588,32 @@ static void ui_draw_driver_view(UIState *s) { ui_draw_rect(s->vg, valid_frame_x + valid_frame_w, box_y, frame_w - valid_frame_w - (valid_frame_x - frame_x), box_h, nvgRGBA(23, 51, 73, 255)); // draw face box - if (scene->face_prob > 0.4) { - int fbox_x; - int fbox_y = box_y + (scene->face_y + 0.5) * box_h - 0.5 * 0.6 * box_h / 2;; + if (scene->dmonitoring_state.getFaceDetected()) { + auto fxy_list = scene->driver_state.getFacePosition(); + const float face_x = fxy_list[0]; + const float face_y = fxy_list[1]; + float fbox_x; + float fbox_y = box_y + (face_y + 0.5) * box_h - 0.5 * 0.6 * box_h / 2;; if (!scene->is_rhd) { - fbox_x = valid_frame_x + (1 - (scene->face_x + 0.5)) * (box_h / 2) - 0.5 * 0.6 * box_h / 2; + fbox_x = valid_frame_x + (1 - (face_x + 0.5)) * (box_h / 2) - 0.5 * 0.6 * box_h / 2; } else { - fbox_x = valid_frame_x + valid_frame_w - box_h / 2 + (scene->face_x + 0.5) * (box_h / 2) - 0.5 * 0.6 * box_h / 2; + fbox_x = valid_frame_x + valid_frame_w - box_h / 2 + (face_x + 0.5) * (box_h / 2) - 0.5 * 0.6 * box_h / 2; } - if (abs(scene->face_x) <= 0.35 && abs(scene->face_y) <= 0.4) { + + if (std::abs(face_x) <= 0.35 && std::abs(face_y) <= 0.4) { ui_draw_rect(s->vg, fbox_x, fbox_y, 0.6 * box_h / 2, 0.6 * box_h / 2, - nvgRGBAf(1.0, 1.0, 1.0, 0.8 - ((abs(scene->face_x) > abs(scene->face_y) ? abs(scene->face_x) : abs(scene->face_y))) * 0.6 / 0.375), + nvgRGBAf(1.0, 1.0, 1.0, 0.8 - ((std::abs(face_x) > std::abs(face_y) ? std::abs(face_x) : std::abs(face_y))) * 0.6 / 0.375), 35, 10); } else { ui_draw_rect(s->vg, fbox_x, fbox_y, 0.6 * box_h / 2, 0.6 * box_h / 2, nvgRGBAf(1.0, 1.0, 1.0, 0.2), 35, 10); } - } else { - ; } // draw face icon const int face_size = 85; - const int face_x = (valid_frame_x + face_size + (bdr_s * 2)) + (scene->is_rhd ? valid_frame_w - box_h / 2:0); - const int face_y = (box_y + box_h - face_size - bdr_s - (bdr_s * 1.5)); - ui_draw_circle_image(s->vg, face_x, face_y, face_size, s->img_face, scene->face_prob > 0.4); + const int x = (valid_frame_x + face_size + (bdr_s * 2)) + (scene->is_rhd ? valid_frame_w - box_h / 2:0); + const int y = (box_y + box_h - face_size - bdr_s - (bdr_s * 1.5)); + ui_draw_circle_image(s->vg, x, y, face_size, s->img_face, scene->dmonitoring_state.getFaceDetected()); } static void ui_draw_vision_header(UIState *s) { @@ -763,7 +744,7 @@ void ui_draw(UIState *s) { nvgBeginFrame(s->vg, s->fb_w, s->fb_h, 1.0f); ui_draw_sidebar(s); if (s->started && s->active_app == cereal::UiLayoutState::App::NONE && s->status != STATUS_STOPPED && s->vision_seen) { - ui_draw_vision(s); + ui_draw_vision(s); } nvgEndFrame(s->vg); glDisable(GL_BLEND); @@ -790,7 +771,7 @@ void ui_draw_rect(NVGcontext *vg, float x, float y, float w, float h, NVGcolor c } } -void ui_draw_rect(NVGcontext *vg, float x, float y, float w, float h, NVGpaint paint, float r){ +void ui_draw_rect(NVGcontext *vg, float x, float y, float w, float h, NVGpaint &paint, float r){ nvgBeginPath(vg); r > 0? nvgRoundedRect(vg, x, y, w, h, r) : nvgRect(vg, x, y, w, h); nvgFillPaint(vg, paint); @@ -813,10 +794,10 @@ static const char frame_fragment_shader[] = "#version 150 core\n" "precision mediump float;\n" "uniform sampler2D uTexture;\n" - "out vec4 vTexCoord;\n" - "out vec4 outColor;\n" + "in vec4 vTexCoord;\n" + "out vec4 colorOut;\n" "void main() {\n" - " outColor = texture(uTexture, vTexCoord.xy);\n" + " colorOut = texture(uTexture, vTexCoord.xy);\n" "}\n"; #else static const char frame_vertex_shader[] = @@ -863,11 +844,15 @@ static const mat4 full_to_wide_frame_transform = {{ void ui_nvg_init(UIState *s) { // init drawing +#ifdef QCOM + // on QCOM, we enable MSAA + s->vg = nvgCreate(0); +#else s->vg = nvgCreate(NVG_ANTIALIAS | NVG_STENCIL_STROKES | NVG_DEBUG); +#endif + assert(s->vg); - s->font_courbd = nvgCreateFont(s->vg, "courbd", "../assets/fonts/courbd.ttf"); - assert(s->font_courbd >= 0); s->font_sans_regular = nvgCreateFont(s->vg, "sans-regular", "../assets/fonts/opensans_regular.ttf"); assert(s->font_sans_regular >= 0); s->font_sans_semibold = nvgCreateFont(s->vg, "sans-semibold", "../assets/fonts/opensans_semibold.ttf"); @@ -959,9 +944,9 @@ void ui_nvg_init(UIState *s) { s->rear_frame_mat = matmul(device_transform, frame_transform); for(int i = 0;i < UI_BUF_COUNT; i++) { - s->khr[i] = NULL; + s->khr[i] = 0; s->priv_hnds[i] = NULL; - s->khr_front[i] = NULL; + s->khr_front[i] = 0; s->priv_hnds_front[i] = NULL; } } diff --git a/selfdrive/ui/paint.hpp b/selfdrive/ui/paint.hpp new file mode 100644 index 0000000000..e71a2a43ec --- /dev/null +++ b/selfdrive/ui/paint.hpp @@ -0,0 +1,11 @@ +#pragma once +#include "ui.hpp" + + +void ui_draw_vision_alert(UIState *s, cereal::ControlsState::AlertSize va_size, int va_color, + const char* va_text1, const char* va_text2); +void ui_draw(UIState *s); +void ui_draw_image(NVGcontext *vg, float x, float y, float w, float h, int image, float alpha); +void ui_draw_rect(NVGcontext *vg, float x, float y, float w, float h, NVGcolor color, float r = 0, int width = 0); +void ui_draw_rect(NVGcontext *vg, float x, float y, float w, float h, NVGpaint &paint, float r = 0); +void ui_nvg_init(UIState *s); diff --git a/selfdrive/ui/qt/settings.cc b/selfdrive/ui/qt/settings.cc new file mode 100644 index 0000000000..3da1934bc7 --- /dev/null +++ b/selfdrive/ui/qt/settings.cc @@ -0,0 +1,143 @@ +#include +#include +#include +#include + +#include "qt/settings.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/params.h" + +ParamsToggle::ParamsToggle(QString param, QString title, QString description, QString icon, QWidget *parent): QFrame(parent) , param(param) { + QHBoxLayout *hlayout = new QHBoxLayout; + QVBoxLayout *vlayout = new QVBoxLayout; + + hlayout->addSpacing(25); + if (icon.length()){ + QPixmap pix(icon); + QLabel *icon = new QLabel(); + icon->setPixmap(pix.scaledToWidth(100, Qt::SmoothTransformation)); + icon->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + hlayout->addWidget(icon); + } else{ + hlayout->addSpacing(100); + } + hlayout->addSpacing(25); + + checkbox = new QCheckBox(title); + QLabel *label = new QLabel(description); + label->setWordWrap(true); + + vlayout->addWidget(checkbox); + vlayout->addWidget(label); + hlayout->addLayout(vlayout); + + setLayout(hlayout); + + auto p = read_db_bytes(param.toStdString().c_str()); + if (p.size()){ + checkbox->setChecked(p[0] == '1'); + } + + setStyleSheet(R"( + QCheckBox { font-size: 70px } + QLabel { font-size: 40px } + * { + background-color: #114265; + } + )"); + + QObject::connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(checkboxClicked(int))); +} + +void ParamsToggle::checkboxClicked(int state){ + char value = state ? '1': '0'; + write_db_value(param.toStdString().c_str(), &value, 1); +} + +SettingsWindow::SettingsWindow(QWidget *parent) : QWidget(parent) { + QWidget *container = new QWidget(this); + + QVBoxLayout *settings_list = new QVBoxLayout(); + settings_list->addWidget(new ParamsToggle("OpenpilotEnabledToggle", + "Enable Openpilot", + "Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off.", + "../assets/offroad/icon_openpilot.png" + )); + settings_list->addWidget(new ParamsToggle("LaneChangeEnabled", + "Enable Lane Change Assist", + "Perform assisted lane changes with openpilot by checking your surroundings for safety, activating the turn signal and gently nudging the steering wheel towards your desired lane. openpilot is not capable of checking if a lane change is safe. You must continuously observe your surroundings to use this feature.", + "../assets/offroad/icon_road.png" + )); + settings_list->addWidget(new ParamsToggle("IsLdwEnabled", + "Enable Lane Departure Warnings", + "Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31mph (50kph).", + "../assets/offroad/icon_warning.png" + )); + settings_list->addWidget(new ParamsToggle("RecordFront", + "Record and Upload Driver Camera", + "Upload data from the driver facing camera and help improve the driver monitoring algorithm.", + "../assets/offroad/icon_network.png" + )); + settings_list->addWidget(new ParamsToggle("IsRHD", + "Enable Right-Hand Drive", + "Allow openpilot to obey left-hand traffic conventions and perform driver monitoring on right driver seat.", + "../assets/offroad/icon_openpilot_mirrored.png" + )); + settings_list->addWidget(new ParamsToggle("IsMetric", + "Use Metric System", + "Display speed in km/h instead of mp/h.", + "../assets/offroad/icon_metric.png" + )); + settings_list->addWidget(new ParamsToggle("CommunityFeaturesToggle", + "Enable Community Features", + "Use features from the open source community that are not maintained or supported by comma.ai and have not been confirmed to meet the standard safety model. These features include community supported cars and community supported hardware. Be extra cautious when using these features", + "../assets/offroad/icon_shell.png" + )); + + settings_list->setSpacing(25); + + container->setLayout(settings_list); + container->setFixedWidth(1650); + + QScrollArea *scrollArea = new QScrollArea; + scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + scrollArea->setWidget(container); + + QScrollerProperties sp; + sp.setScrollMetric(QScrollerProperties::DecelerationFactor, 2.0); + + QScroller* qs = QScroller::scroller(scrollArea); + qs->setScrollerProperties(sp); + + QHBoxLayout *main_layout = new QHBoxLayout; + main_layout->addSpacing(50); + main_layout->addWidget(scrollArea); + + QPushButton * button = new QPushButton("Close"); + main_layout->addWidget(button); + main_layout->addSpacing(20); + + setLayout(main_layout); + + QScroller::grabGesture(scrollArea, QScroller::LeftMouseButtonGesture); + QObject::connect(button, SIGNAL(clicked()), this, SIGNAL(closeSettings())); + + setStyleSheet(R"( + QPushButton { font-size: 40px } + * { + color: white; + background-color: #072339; + } + )"); +} diff --git a/selfdrive/ui/qt/settings.hpp b/selfdrive/ui/qt/settings.hpp new file mode 100644 index 0000000000..e65e75bc76 --- /dev/null +++ b/selfdrive/ui/qt/settings.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include +#include + +class ParamsToggle : public QFrame { + Q_OBJECT + +private: + QCheckBox *checkbox; + QString param; +public: + explicit ParamsToggle(QString param, QString title, QString description, QString icon, QWidget *parent = 0); +public slots: + void checkboxClicked(int state); +}; + + + +class SettingsWindow : public QWidget { + Q_OBJECT +public: + explicit SettingsWindow(QWidget *parent = 0); +signals: + void closeSettings(); +}; diff --git a/selfdrive/ui/qt/ui.cc b/selfdrive/ui/qt/ui.cc new file mode 100644 index 0000000000..40ade50df0 --- /dev/null +++ b/selfdrive/ui/qt/ui.cc @@ -0,0 +1,18 @@ +#include + +#include "window.hpp" + +int main(int argc, char *argv[]) +{ + QSurfaceFormat fmt; + fmt.setRenderableType(QSurfaceFormat::OpenGLES); + QSurfaceFormat::setDefaultFormat(fmt); + + QApplication a(argc, argv); + + MainWindow w; + w.setFixedSize(vwp_w, vwp_h); + w.show(); + + return a.exec(); +} diff --git a/selfdrive/ui/qt/wifi.cc b/selfdrive/ui/qt/wifi.cc new file mode 100644 index 0000000000..1d66c2c862 --- /dev/null +++ b/selfdrive/ui/qt/wifi.cc @@ -0,0 +1,69 @@ +#include +#include + +typedef QMap > Connection; +Q_DECLARE_METATYPE(Connection) + +void wifi_stuff(){ + qDBusRegisterMetaType(); + + QString nm_path = "/org/freedesktop/NetworkManager"; + QString nm_settings_path = "/org/freedesktop/NetworkManager/Settings"; + + QString nm_iface = "org.freedesktop.NetworkManager"; + QString props_iface = "org.freedesktop.DBus.Properties"; + QString nm_settings_iface = "org.freedesktop.NetworkManager.Settings"; + + QString nm_service = "org.freedesktop.NetworkManager"; + QString device_service = "org.freedesktop.NetworkManager.Device"; + + QDBusConnection bus = QDBusConnection::systemBus(); + + // Get devices + QDBusInterface nm(nm_service, nm_path, nm_iface, bus); + QDBusMessage response = nm.call("GetDevices"); + QVariant first = response.arguments().at(0); + + const QDBusArgument &args = first.value(); + args.beginArray(); + while (!args.atEnd()) { + QDBusObjectPath path; + args >> path; + + // Get device type + QDBusInterface device_props(nm_service, path.path(), props_iface, bus); + QDBusMessage response = device_props.call("Get", device_service, "DeviceType"); + QVariant first = response.arguments().at(0); + QDBusVariant dbvFirst = first.value(); + QVariant vFirst = dbvFirst.variant(); + uint device_type = vFirst.value(); + qDebug() << path.path() << device_type; + } + args.endArray(); + + + // Add connection + Connection connection; + connection["connection"]["type"] = "802-11-wireless"; + connection["connection"]["uuid"] = QUuid::createUuid().toString().remove('{').remove('}'); + connection["connection"]["id"] = "Connection 1"; + + connection["802-11-wireless"]["ssid"] = QByteArray(""); + connection["802-11-wireless"]["mode"] = "infrastructure"; + + connection["802-11-wireless-security"]["key-mgmt"] = "wpa-psk"; + connection["802-11-wireless-security"]["auth-alg"] = "open"; + connection["802-11-wireless-security"]["psk"] = ""; + + connection["ipv4"]["method"] = "auto"; + connection["ipv6"]["method"] = "ignore"; + + + QDBusInterface nm_settings(nm_service, nm_settings_path, nm_settings_iface, bus); + QDBusReply result = nm_settings.call("AddConnection", QVariant::fromValue(connection)); + if (!result.isValid()) { + qDebug() << result.error().name() << result.error().message(); + } else { + qDebug() << result.value().path(); + } +} diff --git a/selfdrive/ui/qt/window.cc b/selfdrive/ui/qt/window.cc new file mode 100644 index 0000000000..5b47c27dd7 --- /dev/null +++ b/selfdrive/ui/qt/window.cc @@ -0,0 +1,143 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "window.hpp" +#include "settings.hpp" + +#include "paint.hpp" +#include "sound.hpp" + +volatile sig_atomic_t do_exit = 0; + +MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { + main_layout = new QStackedLayout; + + GLWindow * glWindow = new GLWindow(this); + main_layout->addWidget(glWindow); + + SettingsWindow * settingsWindow = new SettingsWindow(this); + main_layout->addWidget(settingsWindow); + + + main_layout->setMargin(0); + setLayout(main_layout); + QObject::connect(glWindow, SIGNAL(openSettings()), this, SLOT(openSettings())); + QObject::connect(settingsWindow, SIGNAL(closeSettings()), this, SLOT(closeSettings())); + + setStyleSheet(R"( + * { + color: white; + background-color: #072339; + } + )"); +} + +void MainWindow::openSettings(){ + main_layout->setCurrentIndex(1); +} + +void MainWindow::closeSettings(){ + main_layout->setCurrentIndex(0); +} + + + +GLWindow::GLWindow(QWidget *parent) : QOpenGLWidget(parent) { + timer = new QTimer(this); + QObject::connect(timer, SIGNAL(timeout()), this, SLOT(timerUpdate())); +} + +GLWindow::~GLWindow() { + makeCurrent(); + doneCurrent(); +} + +void GLWindow::initializeGL() { + initializeOpenGLFunctions(); + + ui_state = new UIState(); + ui_init(ui_state); + ui_state->fb_w = vwp_w; + ui_state->fb_h = vwp_h; + + int err = pthread_create(&connect_thread_handle, NULL, + vision_connect_thread, ui_state); + assert(err == 0); + + timer->start(50); +} + +void GLWindow::timerUpdate(){ + pthread_mutex_lock(&ui_state->lock); + + ui_update_sizes(ui_state); + + check_messages(ui_state); + if (ui_state->vision_connected){ + ui_update(ui_state); + } + pthread_mutex_unlock(&ui_state->lock); + + update(); +} + +void GLWindow::resizeGL(int w, int h) { + std::cout << "resize " << w << "x" << h << std::endl; +} + +void GLWindow::paintGL() { + pthread_mutex_lock(&ui_state->lock); + ui_draw(ui_state); + pthread_mutex_unlock(&ui_state->lock); +} + +void GLWindow::mousePressEvent(QMouseEvent *e) { + // Settings button click + if (!ui_state->scene.uilayout_sidebarcollapsed && e->x() <= sbr_w) { + if (e->x() >= settings_btn_x && e->x() < (settings_btn_x + settings_btn_w) + && e->y() >= settings_btn_y && e->y() < (settings_btn_y + settings_btn_h)) { + emit openSettings(); + } + } + + // Vision click + if (ui_state->started && (e->x() >= ui_state->scene.ui_viz_rx - bdr_s)){ + ui_state->scene.uilayout_sidebarcollapsed = !ui_state->scene.uilayout_sidebarcollapsed; + } + +} + + +/* HACKS */ +bool Sound::init(int volume) { return true; } +bool Sound::play(AudibleAlert alert) { printf("play sound: %d\n", (int)alert); return true; } +void Sound::stop() {} +void Sound::setVolume(int volume) {} +Sound::~Sound() {} + +GLuint visionimg_to_gl(const VisionImg *img, EGLImageKHR *pkhr, void **pph) { + unsigned int texture; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img->width, img->height, 0, GL_RGB, GL_UNSIGNED_BYTE, *pph); + glGenerateMipmap(GL_TEXTURE_2D); + *pkhr = (EGLImageKHR)1; // not NULL + return texture; +} + +void visionimg_destroy_gl(EGLImageKHR khr, void *ph) { + // empty +} + +FramebufferState* framebuffer_init(const char* name, int32_t layer, int alpha, + int *out_w, int *out_h) { + return (FramebufferState*)1; // not null +} diff --git a/selfdrive/ui/qt/window.hpp b/selfdrive/ui/qt/window.hpp new file mode 100644 index 0000000000..9ab47c377b --- /dev/null +++ b/selfdrive/ui/qt/window.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "ui/ui.hpp" + +class MainWindow : public QWidget +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + +private: + QStackedLayout *main_layout; + +public slots: + void openSettings(); + void closeSettings(); + +}; + + +class GLWindow : public QOpenGLWidget, protected QOpenGLFunctions +{ + Q_OBJECT + +public: + using QOpenGLWidget::QOpenGLWidget; + explicit GLWindow(QWidget *parent = 0); + ~GLWindow(); + +protected: + void mousePressEvent(QMouseEvent *e) override; + void initializeGL() override; + void resizeGL(int w, int h) override; + void paintGL() override; + + +private: + QTimer * timer; + UIState * ui_state; + pthread_t connect_thread_handle; + +public slots: + void timerUpdate(); + +signals: + void openSettings(); +}; diff --git a/selfdrive/ui/sidebar.cc b/selfdrive/ui/sidebar.cc index 3b30ac7574..cc187f449e 100644 --- a/selfdrive/ui/sidebar.cc +++ b/selfdrive/ui/sidebar.cc @@ -2,7 +2,9 @@ #include #include #include -#include "ui.hpp" + +#include "paint.hpp" +#include "sidebar.hpp" static void ui_draw_sidebar_background(UIState *s) { int sbr_x = !s->scene.uilayout_sidebarcollapsed ? 0 : -(sbr_w) + bdr_s * 2; @@ -10,17 +12,13 @@ static void ui_draw_sidebar_background(UIState *s) { } static void ui_draw_sidebar_settings_button(UIState *s) { - bool settingsActive = s->active_app == cereal::UiLayoutState::App::SETTINGS; - const int settings_btn_xr = !s->scene.uilayout_sidebarcollapsed ? settings_btn_x : -(sbr_w); - - ui_draw_image(s->vg, settings_btn_xr, settings_btn_y, settings_btn_w, settings_btn_h, s->img_button_settings, settingsActive ? 1.0f : 0.65f); + const float alpha = s->active_app == cereal::UiLayoutState::App::SETTINGS ? 1.0f : 0.65f; + ui_draw_image(s->vg, settings_btn_x, settings_btn_y, settings_btn_w, settings_btn_h, s->img_button_settings, alpha); } static void ui_draw_sidebar_home_button(UIState *s) { - bool homeActive = s->active_app == cereal::UiLayoutState::App::HOME; - const int home_btn_xr = !s->scene.uilayout_sidebarcollapsed ? home_btn_x : -(sbr_w); - - ui_draw_image(s->vg, home_btn_xr, home_btn_y, home_btn_w, home_btn_h, s->img_button_home, homeActive ? 1.0f : 0.65f); + const float alpha = s->active_app == cereal::UiLayoutState::App::HOME ? 1.0f : 0.65f;; + ui_draw_image(s->vg, home_btn_x, home_btn_y, home_btn_w, home_btn_h, s->img_button_home, alpha); } static void ui_draw_sidebar_network_strength(UIState *s) { @@ -32,22 +30,22 @@ static void ui_draw_sidebar_network_strength(UIState *s) { {cereal::ThermalData::NetworkStrength::GREAT, 5}}; const int network_img_h = 27; const int network_img_w = 176; - const int network_img_x = !s->scene.uilayout_sidebarcollapsed ? 58 : -(sbr_w); + const int network_img_x = 58; const int network_img_y = 196; - const int img_idx = s->scene.networkType == cereal::ThermalData::NetworkType::NONE ? 0 : network_strength_map[s->scene.networkStrength]; + const int img_idx = s->scene.thermal.getNetworkType() == cereal::ThermalData::NetworkType::NONE ? 0 : network_strength_map[s->scene.thermal.getNetworkStrength()]; ui_draw_image(s->vg, network_img_x, network_img_y, network_img_w, network_img_h, s->img_network[img_idx], 1.0f); } static void ui_draw_sidebar_battery_icon(UIState *s) { const int battery_img_h = 36; const int battery_img_w = 76; - const int battery_img_x = !s->scene.uilayout_sidebarcollapsed ? 160 : -(sbr_w); + const int battery_img_x = 160; const int battery_img_y = 255; - int battery_img = s->scene.batteryCharging ? s->img_battery_charging : s->img_battery; + int battery_img = s->scene.thermal.getBatteryStatus() == "Charging" ? s->img_battery_charging : s->img_battery; ui_draw_rect(s->vg, battery_img_x + 6, battery_img_y + 5, - ((battery_img_w - 19) * (s->scene.batteryPercent * 0.01)), battery_img_h - 11, COLOR_WHITE); + ((battery_img_w - 19) * (s->scene.thermal.getBatteryPercent() * 0.01)), battery_img_h - 11, COLOR_WHITE); ui_draw_image(s->vg, battery_img_x, battery_img_y, battery_img_w, battery_img_h, battery_img, 1.0f); } @@ -60,11 +58,10 @@ static void ui_draw_sidebar_network_type(UIState *s) { {cereal::ThermalData::NetworkType::CELL3_G, "3G"}, {cereal::ThermalData::NetworkType::CELL4_G, "4G"}, {cereal::ThermalData::NetworkType::CELL5_G, "5G"}}; - const int network_x = !s->scene.uilayout_sidebarcollapsed ? 50 : -(sbr_w); + const int network_x = 50; const int network_y = 273; const int network_w = 100; - const int network_h = 100; - const char *network_type = network_type_map[s->scene.networkType]; + const char *network_type = network_type_map[s->scene.thermal.getNetworkType()]; nvgFillColor(s->vg, COLOR_WHITE); nvgFontSize(s->vg, 48); nvgFontFaceId(s->vg, s->font_sans_regular); @@ -73,7 +70,7 @@ static void ui_draw_sidebar_network_type(UIState *s) { } static void ui_draw_sidebar_metric(UIState *s, const char* label_str, const char* value_str, const int severity, const int y_offset, const char* message_str) { - const int metric_x = !s->scene.uilayout_sidebarcollapsed ? 30 : -(sbr_w); + const int metric_x = 30; const int metric_y = 338 + y_offset; const int metric_w = 240; const int metric_h = message_str ? strchr(message_str, '\n') ? 124 : 100 : 148; @@ -127,16 +124,16 @@ static void ui_draw_sidebar_temp_metric(UIState *s) { char temp_value_str[32]; char temp_value_unit[32]; const int temp_y_offset = 0; - snprintf(temp_value_str, sizeof(temp_value_str), "%d", s->scene.paTemp); + snprintf(temp_value_str, sizeof(temp_value_str), "%d", s->scene.thermal.getPa0()); snprintf(temp_value_unit, sizeof(temp_value_unit), "%s", "°C"); snprintf(temp_label_str, sizeof(temp_label_str), "%s", "TEMP"); strcat(temp_value_str, temp_value_unit); - ui_draw_sidebar_metric(s, temp_label_str, temp_value_str, temp_severity_map[s->scene.thermalStatus], temp_y_offset, NULL); + ui_draw_sidebar_metric(s, temp_label_str, temp_value_str, temp_severity_map[s->scene.thermal.getThermalStatus()], temp_y_offset, NULL); } static void ui_draw_sidebar_panda_metric(UIState *s) { - int panda_severity; + int panda_severity = 2; char panda_message_str[32]; const int panda_y_offset = 32 + 148; diff --git a/selfdrive/ui/sidebar.hpp b/selfdrive/ui/sidebar.hpp new file mode 100644 index 0000000000..f273e16f8b --- /dev/null +++ b/selfdrive/ui/sidebar.hpp @@ -0,0 +1,4 @@ +#pragma once +#include "ui.hpp" + +void ui_draw_sidebar(UIState *s); diff --git a/selfdrive/ui/slplay.c b/selfdrive/ui/slplay.c deleted file mode 100644 index ddfbad56c5..0000000000 --- a/selfdrive/ui/slplay.c +++ /dev/null @@ -1,184 +0,0 @@ -#include -#include -#include -#include -#include - -#include "common/timing.h" -#include "slplay.h" - -SLEngineItf engineInterface = NULL; -SLObjectItf outputMix = NULL; -SLObjectItf engine = NULL; -uri_player players[32] = {{NULL, NULL, NULL}}; - -uint64_t loop_start = 0; -uint64_t loop_start_ctx = 0; - -uri_player* get_player_by_uri(const char* uri) { - for (uri_player *s = players; s->uri != NULL; s++) { - if (strcmp(s->uri, uri) == 0) { - return s; - } - } - - return NULL; -} - -uri_player* slplay_create_player_for_uri(const char* uri, char **error) { - uri_player player = { uri, NULL, NULL }; - - SLresult result; - SLDataLocator_URI locUri = {SL_DATALOCATOR_URI, (SLchar *) uri}; - SLDataFormat_MIME formatMime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED}; - SLDataSource audioSrc = {&locUri, &formatMime}; - - SLDataLocator_OutputMix outMix = {SL_DATALOCATOR_OUTPUTMIX, outputMix}; - SLDataSink audioSnk = {&outMix, NULL}; - - result = (*engineInterface)->CreateAudioPlayer(engineInterface, &player.player, &audioSrc, &audioSnk, 0, NULL, NULL); - if (result != SL_RESULT_SUCCESS) { - *error = "Failed to create audio player"; - return NULL; - } - - result = (*(player.player))->Realize(player.player, SL_BOOLEAN_FALSE); - if (result != SL_RESULT_SUCCESS) { - *error = "Failed to realize audio player"; - return NULL; - } - - result = (*(player.player))->GetInterface(player.player, SL_IID_PLAY, &(player.playInterface)); - if (result != SL_RESULT_SUCCESS) { - *error = "Failed to get player interface"; - return NULL; - } - - result = (*(player.playInterface))->SetPlayState(player.playInterface, SL_PLAYSTATE_PAUSED); - if (result != SL_RESULT_SUCCESS) { - *error = "Failed to initialize playstate to SL_PLAYSTATE_PAUSED"; - return NULL; - } - - uri_player *p = players; - while (p->uri != NULL) { - p++; - } - *p = player; - - return p; -} - -void slplay_setup(char **error) { - SLresult result; - SLEngineOption engineOptions[] = {{SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE}}; - result = slCreateEngine(&engine, 1, engineOptions, 0, NULL, NULL); - if (result != SL_RESULT_SUCCESS) { - *error = "Failed to create OpenSL engine"; - } - - result = (*engine)->Realize(engine, SL_BOOLEAN_FALSE); - if (result != SL_RESULT_SUCCESS) { - *error = "Failed to realize OpenSL engine"; - } - - result = (*engine)->GetInterface(engine, SL_IID_ENGINE, &engineInterface); - if (result != SL_RESULT_SUCCESS) { - *error = "Failed to realize OpenSL engine"; - } - - const SLInterfaceID ids[1] = {SL_IID_VOLUME}; - const SLboolean req[1] = {SL_BOOLEAN_FALSE}; - result = (*engineInterface)->CreateOutputMix(engineInterface, &outputMix, 1, ids, req); - if (result != SL_RESULT_SUCCESS) { - *error = "Failed to create output mix"; - } - - result = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE); - if (result != SL_RESULT_SUCCESS) { - *error = "Failed to realize output mix"; - } -} - -void slplay_destroy() { - for (uri_player *player = players; player->uri != NULL; player++) { - if (player->player) { - (*(player->player))->Destroy(player->player); - } - } - - (*outputMix)->Destroy(outputMix); - (*engine)->Destroy(engine); -} - -void slplay_stop(uri_player* player, char **error) { - SLPlayItf playInterface = player->playInterface; - SLresult result; - - // stop a loop - loop_start = 0; - - result = (*playInterface)->SetPlayState(playInterface, SL_PLAYSTATE_PAUSED); - if (result != SL_RESULT_SUCCESS) { - *error = "Failed to set SL_PLAYSTATE_STOPPED"; - return; - } -} - -void slplay_stop_uri(const char* uri, char **error) { - uri_player* player = get_player_by_uri(uri); - slplay_stop(player, error); -} - -void SLAPIENTRY slplay_callback(SLPlayItf playItf, void *context, SLuint32 event) { - uint64_t cb_loop_start = *((uint64_t*)context); - if (event == SL_PLAYEVENT_HEADATEND && cb_loop_start == loop_start) { - (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED); - (*playItf)->SetMarkerPosition(playItf, 0); - (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING); - } -} - -void slplay_play (const char *uri, bool loop, char **error) { - SLresult result; - - uri_player* player = get_player_by_uri(uri); - if (player == NULL) { - player = slplay_create_player_for_uri(uri, error); - if (*error) { - return; - } - } - - SLPlayItf playInterface = player->playInterface; - if (loop) { - loop_start = nanos_since_boot(); - loop_start_ctx = loop_start; - result = (*playInterface)->RegisterCallback(playInterface, slplay_callback, &loop_start_ctx); - if (result != SL_RESULT_SUCCESS) { - char error[64]; - snprintf(error, sizeof(error), "Failed to register callback. %d", result); - *error = error[0]; - return; - } - - result = (*playInterface)->SetCallbackEventsMask(playInterface, SL_PLAYEVENT_HEADATEND); - if (result != SL_RESULT_SUCCESS) { - *error = "Failed to set callback event mask"; - return; - } - } - - // Reset the audio player - result = (*playInterface)->ClearMarkerPosition(playInterface); - if (result != SL_RESULT_SUCCESS) { - *error = "Failed to clear marker position"; - return; - } - result = (*playInterface)->SetPlayState(playInterface, SL_PLAYSTATE_PAUSED); - result = (*playInterface)->SetPlayState(playInterface, SL_PLAYSTATE_STOPPED); - result = (*playInterface)->SetPlayState(playInterface, SL_PLAYSTATE_PLAYING); - if (result != SL_RESULT_SUCCESS) { - *error = "Failed to set SL_PLAYSTATE_PLAYING"; - } -} diff --git a/selfdrive/ui/slplay.h b/selfdrive/ui/slplay.h deleted file mode 100644 index f8c39ceeb7..0000000000 --- a/selfdrive/ui/slplay.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef SLPLAY_H -#define SLPLAY_H - -#include -#include -#include - -typedef struct { - const char* uri; - SLObjectItf player; - SLPlayItf playInterface; -} uri_player; - -void slplay_setup(char **error); -uri_player* slplay_create_player_for_uri(const char* uri, char **error); -void slplay_play (const char *uri, bool loop, char **error); -void slplay_stop_uri (const char* uri, char **error); -void slplay_destroy(); - -#endif - diff --git a/selfdrive/ui/sound.cc b/selfdrive/ui/sound.cc index f64cde07ef..79a8fd6e26 100644 --- a/selfdrive/ui/sound.cc +++ b/selfdrive/ui/sound.cc @@ -1,91 +1,125 @@ -#include -#include "sound.hpp" +#include "sound.hpp" +#include +#include +#include #include "common/swaglog.h" +#include "common/timing.h" + +#define LogOnError(func, msg) \ + if ((func) != SL_RESULT_SUCCESS) { LOGW(msg); } + +#define ReturnOnError(func, msg) \ + if ((func) != SL_RESULT_SUCCESS) { LOGW(msg); return false; } + +static std::map> sound_map { + {AudibleAlert::CHIME_DISENGAGE, {"../assets/sounds/disengaged.wav", 0}}, + {AudibleAlert::CHIME_ENGAGE, {"../assets/sounds/engaged.wav", 0}}, + {AudibleAlert::CHIME_WARNING1, {"../assets/sounds/warning_1.wav", 0}}, + {AudibleAlert::CHIME_WARNING2, {"../assets/sounds/warning_2.wav", 0}}, + {AudibleAlert::CHIME_WARNING2_REPEAT, {"../assets/sounds/warning_2.wav", 3}}, + {AudibleAlert::CHIME_WARNING_REPEAT, {"../assets/sounds/warning_repeat.wav", 3}}, + {AudibleAlert::CHIME_ERROR, {"../assets/sounds/error.wav", 0}}, + {AudibleAlert::CHIME_PROMPT, {"../assets/sounds/error.wav", 0}}}; + +struct Sound::Player { + SLObjectItf player; + SLPlayItf playItf; + // slplay_callback runs on a background thread,use atomic to ensure thread safe. + std::atomic repeat; +}; -typedef struct { - AudibleAlert alert; - const char* uri; - bool loop; -} sound_file; +bool Sound::init(int volume) { + SLEngineOption engineOptions[] = {{SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE}}; + const SLInterfaceID ids[1] = {SL_IID_VOLUME}; + const SLboolean req[1] = {SL_BOOLEAN_FALSE}; + SLEngineItf engineInterface = NULL; + ReturnOnError(slCreateEngine(&engine_, 1, engineOptions, 0, NULL, NULL), "Failed to create OpenSL engine"); + ReturnOnError((*engine_)->Realize(engine_, SL_BOOLEAN_FALSE), "Failed to realize OpenSL engine"); + ReturnOnError((*engine_)->GetInterface(engine_, SL_IID_ENGINE, &engineInterface), "Failed to get OpenSL engine interface"); + ReturnOnError((*engineInterface)->CreateOutputMix(engineInterface, &outputMix_, 1, ids, req), "Failed to create output mix"); + ReturnOnError((*outputMix_)->Realize(outputMix_, SL_BOOLEAN_FALSE), "Failed to realize output mix"); + + for (auto &kv : sound_map) { + SLDataLocator_URI locUri = {SL_DATALOCATOR_URI, (SLchar *)kv.second.first}; + SLDataFormat_MIME formatMime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED}; + SLDataSource audioSrc = {&locUri, &formatMime}; + SLDataLocator_OutputMix outMix = {SL_DATALOCATOR_OUTPUTMIX, outputMix_}; + SLDataSink audioSnk = {&outMix, NULL}; + + SLObjectItf player = NULL; + SLPlayItf playItf = NULL; + ReturnOnError((*engineInterface)->CreateAudioPlayer(engineInterface, &player, &audioSrc, &audioSnk, 0, NULL, NULL), "Failed to create audio player"); + ReturnOnError((*player)->Realize(player, SL_BOOLEAN_FALSE), "Failed to realize audio player"); + ReturnOnError((*player)->GetInterface(player, SL_IID_PLAY, &playItf), "Failed to get player interface"); + ReturnOnError((*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PAUSED), "Failed to initialize playstate to SL_PLAYSTATE_PAUSED"); + + player_[kv.first] = new Sound::Player{player, playItf}; + } -extern "C"{ -#include "slplay.h" + setVolume(volume); + return true; } -int last_volume = 0; - -void set_volume(int volume) { - if (last_volume != volume) { - char volume_change_cmd[64]; - sprintf(volume_change_cmd, "service call audio 3 i32 3 i32 %d i32 1 &", volume); - - // 5 second timeout at 60fps - int volume_changed = system(volume_change_cmd); - last_volume = volume; +void SLAPIENTRY slplay_callback(SLPlayItf playItf, void *context, SLuint32 event) { + Sound::Player *s = reinterpret_cast(context); + if (event == SL_PLAYEVENT_HEADATEND && s->repeat > 1) { + --s->repeat; + (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED); + (*playItf)->SetMarkerPosition(playItf, 0); + (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING); } } - -sound_file sound_table[] = { - { cereal::CarControl::HUDControl::AudibleAlert::CHIME_DISENGAGE, "../assets/sounds/disengaged.wav", false }, - { cereal::CarControl::HUDControl::AudibleAlert::CHIME_ENGAGE, "../assets/sounds/engaged.wav", false }, - { cereal::CarControl::HUDControl::AudibleAlert::CHIME_WARNING1, "../assets/sounds/warning_1.wav", false }, - { cereal::CarControl::HUDControl::AudibleAlert::CHIME_WARNING2, "../assets/sounds/warning_2.wav", false }, - { cereal::CarControl::HUDControl::AudibleAlert::CHIME_WARNING2_REPEAT, "../assets/sounds/warning_2.wav", true }, - { cereal::CarControl::HUDControl::AudibleAlert::CHIME_WARNING_REPEAT, "../assets/sounds/warning_repeat.wav", true }, - { cereal::CarControl::HUDControl::AudibleAlert::CHIME_ERROR, "../assets/sounds/error.wav", false }, - { cereal::CarControl::HUDControl::AudibleAlert::CHIME_PROMPT, "../assets/sounds/error.wav", false }, - { cereal::CarControl::HUDControl::AudibleAlert::NONE, NULL, false }, -}; - -sound_file* get_sound_file(AudibleAlert alert) { - for (sound_file *s = sound_table; s->alert != cereal::CarControl::HUDControl::AudibleAlert::NONE; s++) { - if (s->alert == alert) { - return s; - } +bool Sound::play(AudibleAlert alert) { + if (currentSound_ != AudibleAlert::NONE) { + stop(); + } + auto player = player_.at(alert); + SLPlayItf playItf = player->playItf; + player->repeat = sound_map[alert].second; + if (player->repeat > 0) { + ReturnOnError((*playItf)->RegisterCallback(playItf, slplay_callback, player), "Failed to register callback"); + ReturnOnError((*playItf)->SetCallbackEventsMask(playItf, SL_PLAYEVENT_HEADATEND), "Failed to set callback event mask"); } - return NULL; -} - -void play_alert_sound(AudibleAlert alert) { - sound_file* sound = get_sound_file(alert); - char* error = NULL; - - slplay_play(sound->uri, sound->loop, &error); - if(error) { - LOGW("error playing sound: %s", error); + // Reset the audio player + ReturnOnError((*playItf)->ClearMarkerPosition(playItf), "Failed to clear marker position"); + uint32_t states[] = {SL_PLAYSTATE_PAUSED, SL_PLAYSTATE_STOPPED, SL_PLAYSTATE_PLAYING}; + for (auto state : states) { + ReturnOnError((*playItf)->SetPlayState(playItf, state), "Failed to set SL_PLAYSTATE_PLAYING"); } + currentSound_ = alert; + return true; } -void stop_alert_sound(AudibleAlert alert) { - sound_file* sound = get_sound_file(alert); - char* error = NULL; - - slplay_stop_uri(sound->uri, &error); - if(error) { - LOGW("error stopping sound: %s", error); +void Sound::stop() { + if (currentSound_ != AudibleAlert::NONE) { + auto player = player_.at(currentSound_); + player->repeat = 0; + LogOnError((*(player->playItf))->SetPlayState(player->playItf, SL_PLAYSTATE_PAUSED), "Failed to set SL_PLAYSTATE_PAUSED"); + currentSound_ = AudibleAlert::NONE; } } -void ui_sound_init() { - char *error = NULL; - slplay_setup(&error); - if (error) goto fail; - - for (sound_file *s = sound_table; s->alert != cereal::CarControl::HUDControl::AudibleAlert::NONE; s++) { - slplay_create_player_for_uri(s->uri, &error); - if (error) goto fail; +void Sound::setVolume(int volume) { + if (last_volume_ == volume) return; + + double current_time = nanos_since_boot(); + if ((current_time - last_set_volume_time_) > (5 * (1e+9))) { // 5s timeout on updating the volume + char volume_change_cmd[64]; + snprintf(volume_change_cmd, sizeof(volume_change_cmd), "service call audio 3 i32 3 i32 %d i32 1 &", volume); + system(volume_change_cmd); + last_volume_ = volume; + last_set_volume_time_ = current_time; } - return; - -fail: - LOGW(error); - exit(1); } -void ui_sound_destroy() { - slplay_destroy(); +Sound::~Sound() { + for (auto &kv : player_) { + (*(kv.second->player))->Destroy(kv.second->player); + delete kv.second; + } + if (outputMix_) (*outputMix_)->Destroy(outputMix_); + if (engine_) (*engine_)->Destroy(engine_); } - diff --git a/selfdrive/ui/sound.hpp b/selfdrive/ui/sound.hpp index ec8934ef38..d565f846ff 100644 --- a/selfdrive/ui/sound.hpp +++ b/selfdrive/ui/sound.hpp @@ -1,17 +1,32 @@ -#ifndef __SOUND_HPP -#define __SOUND_HPP - +#pragma once +#include #include "cereal/gen/cpp/log.capnp.h" -typedef cereal::CarControl::HUDControl::AudibleAlert AudibleAlert; - -void ui_sound_init(); -void ui_sound_destroy(); +#if defined(QCOM) +#include +#include +#endif -void set_volume(int volume); +typedef cereal::CarControl::HUDControl::AudibleAlert AudibleAlert; -void play_alert_sound(AudibleAlert alert); -void stop_alert_sound(AudibleAlert alert); +class Sound { + public: + Sound() = default; + bool init(int volume); + bool play(AudibleAlert alert); + void stop(); + void setVolume(int volume); + ~Sound(); +#if defined(QCOM) + private: + SLObjectItf engine_ = nullptr; + SLObjectItf outputMix_ = nullptr; + int last_volume_ = 0; + double last_set_volume_time_ = 0.; + AudibleAlert currentSound_ = AudibleAlert::NONE; + struct Player; + std::map player_; + friend void SLAPIENTRY slplay_callback(SLPlayItf playItf, void *context, SLuint32 event); #endif - +}; diff --git a/selfdrive/ui/test/build_play_sound.sh b/selfdrive/ui/test/build_play_sound.sh deleted file mode 100755 index 802bdee8fc..0000000000 --- a/selfdrive/ui/test/build_play_sound.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -clang -fPIC -o play_sound play_sound.c ../slplay.c -I ../../ -I ../ -lOpenSLES -Wl,-rpath=/system/lib64 - diff --git a/selfdrive/ui/test/play_sound.c b/selfdrive/ui/test/play_sound.c deleted file mode 100644 index 030a9f25a5..0000000000 --- a/selfdrive/ui/test/play_sound.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include "slplay.h" - -void play_sound(char *uri, int volume) { - char **error = NULL; - printf("call slplay_setup\n"); - slplay_setup(error); - if (error) { printf("%s\n", *error); return; } - - printf("call slplay_create_player_for_uri\n"); - slplay_create_player_for_uri(uri, error); - if (error) { printf("%s\n", *error); return; } - - printf("call slplay_play\n"); - - while (1) { - char volume_change_cmd[64]; - sprintf(volume_change_cmd, "service call audio 3 i32 3 i32 %d i32 1", volume); - system(volume_change_cmd); - - slplay_play(uri, false, error); - if (error) { printf("%s\n", *error); return; } - - sleep(1); - } -} - -int main(int argc, char *argv[]) { - int volume = 10; - if (argc > 2) { - volume = atoi(argv[2]); - } - printf("setting volume to %d\n", volume); - - play_sound(argv[1], volume); - return 0; -} diff --git a/selfdrive/ui/text/text.c b/selfdrive/ui/text/text.c index cd910cc80b..43c43e4689 100644 --- a/selfdrive/ui/text/text.c +++ b/selfdrive/ui/text/text.c @@ -14,7 +14,6 @@ #include "nanovg_gl.h" #include "nanovg_gl_utils.h" - #include "common/framebuffer.h" #include "common/touch.h" @@ -25,14 +24,6 @@ extern const unsigned char _binary_opensans_regular_ttf_start[]; extern const unsigned char _binary_opensans_regular_ttf_end[]; -static void set_brightness(int brightness) { - FILE *f = fopen("/sys/class/leds/lcd-backlight/brightness", "wb"); - if (f != NULL) { - fprintf(f, "%d", brightness); - fclose(f); - } -} - int main(int argc, char** argv) { int err; @@ -81,7 +72,7 @@ assert(font >= 0); float lineh; nvgTextMetrics(vg, NULL, NULL, &lineh); - + // nvgTextBox strips leading whitespace. We have to reimplement char * next = strtok(text, "\n"); while (next != NULL){ diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 03eed94192..5269beaab2 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -1,275 +1,45 @@ -#include "ui.hpp" #include #include #include #include #include #include -#include -#include #include + #include "common/util.h" -#include "common/timing.h" #include "common/swaglog.h" -#include "common/touch.h" #include "common/visionimg.h" -#include "common/params.h" - -static int last_brightness = -1; -static void set_brightness(UIState *s, int brightness) { - if (last_brightness != brightness && (s->awake || brightness == 0)) { - FILE *f = fopen("/sys/class/leds/lcd-backlight/brightness", "wb"); - if (f != NULL) { - fprintf(f, "%d", brightness); - fclose(f); - last_brightness = brightness; - } - } -} - -int event_processing_enabled = -1; -static void enable_event_processing(bool yes) { - if (event_processing_enabled != 1 && yes) { - system("service call window 18 i32 1"); // enable event processing - event_processing_enabled = 1; - } else if (event_processing_enabled != 0 && !yes) { - system("service call window 18 i32 0"); // disable event processing - event_processing_enabled = 0; - } -} - -static void set_awake(UIState *s, bool awake) { -#ifdef QCOM - if (awake) { - // 30 second timeout at 30 fps - s->awake_timeout = 30*30; - } - if (s->awake != awake) { - s->awake = awake; - - // TODO: replace command_awake and command_sleep with direct calls to android - if (awake) { - LOGW("awake normal"); - framebuffer_set_power(s->fb, HWC_POWER_MODE_NORMAL); - enable_event_processing(true); - } else { - LOGW("awake off"); - set_brightness(s, 0); - framebuffer_set_power(s->fb, HWC_POWER_MODE_OFF); - enable_event_processing(false); - } - } -#else - // computer UI doesn't sleep - s->awake = true; -#endif -} - -static void update_offroad_layout_state(UIState *s) { - capnp::MallocMessageBuilder msg; - auto event = msg.initRoot(); - event.setLogMonoTime(nanos_since_boot()); - auto layout = event.initUiLayoutState(); - layout.setActiveApp(s->active_app); - layout.setSidebarCollapsed(s->scene.uilayout_sidebarcollapsed); - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - s->offroad_sock->send((char*)bytes.begin(), bytes.size()); - LOGD("setting active app to %d with sidebar %d", (int)s->active_app, s->scene.uilayout_sidebarcollapsed); -} - -static void navigate_to_settings(UIState *s) { -#ifdef QCOM - s->active_app = cereal::UiLayoutState::App::SETTINGS; - update_offroad_layout_state(s); -#else - // computer UI doesn't have offroad settings -#endif -} - -static void navigate_to_home(UIState *s) { -#ifdef QCOM - if (s->started) { - s->active_app = cereal::UiLayoutState::App::NONE; - } else { - s->active_app = cereal::UiLayoutState::App::HOME; - } - update_offroad_layout_state(s); -#else - // computer UI doesn't have offroad home -#endif -} - -static void handle_sidebar_touch(UIState *s, int touch_x, int touch_y) { - if (!s->scene.uilayout_sidebarcollapsed && touch_x <= sbr_w) { - if (touch_x >= settings_btn_x && touch_x < (settings_btn_x + settings_btn_w) - && touch_y >= settings_btn_y && touch_y < (settings_btn_y + settings_btn_h)) { - navigate_to_settings(s); - } - if (touch_x >= home_btn_x && touch_x < (home_btn_x + home_btn_w) - && touch_y >= home_btn_y && touch_y < (home_btn_y + home_btn_h)) { - navigate_to_home(s); - if (s->started) { - s->scene.uilayout_sidebarcollapsed = true; - update_offroad_layout_state(s); - } - } - } -} - -static void handle_driver_view_touch(UIState *s, int touch_x, int touch_y) { - int err = write_db_value("IsDriverViewEnabled", "0", 1); -} - -static void handle_vision_touch(UIState *s, int touch_x, int touch_y) { - if (s->started && (touch_x >= s->scene.ui_viz_rx - bdr_s) - && (s->active_app != cereal::UiLayoutState::App::SETTINGS)) { - if (!s->scene.frontview) { - s->scene.uilayout_sidebarcollapsed = !s->scene.uilayout_sidebarcollapsed; - } else { - handle_driver_view_touch(s, touch_x, touch_y); - } - update_offroad_layout_state(s); - } -} - -volatile sig_atomic_t do_exit = 0; -static void set_do_exit(int sig) { - do_exit = 1; -} - -static void read_param_bool(bool* param, const char* param_name, bool persistent_param = false) { - char *s; - const int result = read_db_value(param_name, &s, NULL, persistent_param); - if (result == 0) { - *param = s[0] == '1'; - free(s); - } -} - -static int read_param_float(float* param, const char* param_name, bool persistent_param = false) { - char *s; - const int result = read_db_value(param_name, &s, NULL, persistent_param); - if (result == 0) { - *param = strtod(s, NULL); - free(s); - } - return result; -} - -static int read_param_uint64(uint64_t* dest, const char* param_name, bool persistent_param = false) { - char *s; - const int result = read_db_value(param_name, &s, NULL, persistent_param); - if (result == 0) { - *dest = strtoull(s, NULL, 0); - free(s); - } - return result; -} - -static void read_param_bool_timeout(bool* param, const char* param_name, int* timeout, bool persistent_param = false) { - if (*timeout > 0){ - (*timeout)--; - } else { - read_param_bool(param, param_name, persistent_param); - *timeout = 2 * UI_FREQ; // 0.5Hz - } -} +#include "common/utilpp.h" +#include "ui.hpp" +#include "paint.hpp" -static void read_param_float_timeout(float* param, const char* param_name, int* timeout, bool persistent_param = false) { - if (*timeout > 0){ - (*timeout)--; - } else { - read_param_float(param, param_name, persistent_param); - *timeout = 2 * UI_FREQ; // 0.5Hz - } -} +extern volatile sig_atomic_t do_exit; -static int read_param_uint64_timeout(uint64_t* dest, const char* param_name, int* timeout, bool persistent_param = false) { - if (*timeout > 0){ - (*timeout)--; - return 0; - } else { - *timeout = 2 * UI_FREQ; // 0.5Hz - return read_param_uint64(dest, param_name, persistent_param); - } -} -static int write_param_float(float param, const char* param_name, bool persistent_param = false) { +int write_param_float(float param, const char* param_name, bool persistent_param) { char s[16]; int size = snprintf(s, sizeof(s), "%f", param); return write_db_value(param_name, s, MIN(size, sizeof(s)), persistent_param); } -static void update_offroad_layout_timeout(UIState *s, int* timeout) { - if (*timeout > 0) { - (*timeout)--; - } else { - update_offroad_layout_state(s); - *timeout = 2 * UI_FREQ; - } -} - -static void ui_init(UIState *s) { - memset(s, 0, sizeof(UIState)); - +void ui_init(UIState *s) { pthread_mutex_init(&s->lock, NULL); - - s->ctx = Context::create(); - s->model_sock = SubSocket::create(s->ctx, "model"); - s->controlsstate_sock = SubSocket::create(s->ctx, "controlsState"); - s->uilayout_sock = SubSocket::create(s->ctx, "uiLayoutState"); - s->livecalibration_sock = SubSocket::create(s->ctx, "liveCalibration"); - s->radarstate_sock = SubSocket::create(s->ctx, "radarState"); - s->thermal_sock = SubSocket::create(s->ctx, "thermal"); - s->health_sock = SubSocket::create(s->ctx, "health"); - s->ubloxgnss_sock = SubSocket::create(s->ctx, "ubloxGnss"); - s->driverstate_sock = SubSocket::create(s->ctx, "driverState"); - s->dmonitoring_sock = SubSocket::create(s->ctx, "dMonitoringState"); - s->offroad_sock = PubSocket::create(s->ctx, "offroadLayout"); - - assert(s->model_sock != NULL); - assert(s->controlsstate_sock != NULL); - assert(s->uilayout_sock != NULL); - assert(s->livecalibration_sock != NULL); - assert(s->radarstate_sock != NULL); - assert(s->thermal_sock != NULL); - assert(s->health_sock != NULL); - assert(s->ubloxgnss_sock != NULL); - assert(s->driverstate_sock != NULL); - assert(s->dmonitoring_sock != NULL); - assert(s->offroad_sock != NULL); - - s->poller = Poller::create({ - s->model_sock, - s->controlsstate_sock, - s->uilayout_sock, - s->livecalibration_sock, - s->radarstate_sock, - s->thermal_sock, - s->health_sock, - s->ubloxgnss_sock, - s->driverstate_sock, - s->dmonitoring_sock - }); - + s->sm = new SubMaster({"model", "controlsState", "uiLayoutState", "liveCalibration", "radarState", "thermal", + "health", "ubloxGnss", "driverState", "dMonitoringState" #ifdef SHOW_SPEEDLIMIT - s->map_data_sock = SubSocket::create(s->ctx, "liveMapData"); - assert(s->map_data_sock != NULL); - s->poller->registerSocket(s->map_data_sock); + , "liveMapData" #endif + }); + s->pm = new PubMaster({"offroadLayout"}); s->ipc_fd = -1; + s->scene.satelliteCount = -1; + s->started = false; + s->vision_seen = false; - // init display s->fb = framebuffer_init("ui", 0, true, &s->fb_w, &s->fb_h); assert(s->fb); - set_awake(s, true); - - s->model_changed = false; - s->livempc_or_radarstate_changed = false; - ui_nvg_init(s); } @@ -277,8 +47,6 @@ static void ui_init_vision(UIState *s, const VisionStreamBufs back_bufs, int num_back_fds, const int *back_fds, const VisionStreamBufs front_bufs, int num_front_fds, const int *front_fds) { - const VisionUIInfo ui_info = back_bufs.buf_info.ui_info; - assert(num_back_fds == UI_BUF_COUNT); assert(num_front_fds == UI_BUF_COUNT); @@ -288,18 +56,9 @@ static void ui_init_vision(UIState *s, const VisionStreamBufs back_bufs, s->cur_vision_idx = -1; s->cur_vision_front_idx = -1; - s->scene = (UIScene){ - .frontview = getenv("FRONTVIEW") != NULL, - .fullview = getenv("FULLVIEW") != NULL, - .transformed_width = ui_info.transformed_width, - .transformed_height = ui_info.transformed_height, - .front_box_x = ui_info.front_box_x, - .front_box_y = ui_info.front_box_y, - .front_box_width = ui_info.front_box_width, - .front_box_height = ui_info.front_box_height, - .world_objects_visible = false, // Invisible until we receive a calibration message. - .gps_planner_active = false, - }; + s->scene.frontview = getenv("FRONTVIEW") != NULL; + s->scene.fullview = getenv("FULLVIEW") != NULL; + s->scene.world_objects_visible = false; // Invisible until we receive a calibration message. s->rgb_width = back_bufs.width; s->rgb_height = back_bufs.height; @@ -311,17 +70,10 @@ static void ui_init_vision(UIState *s, const VisionStreamBufs back_bufs, s->rgb_front_stride = front_bufs.stride; s->rgb_front_buf_len = front_bufs.buf_len; - s->rgb_transform = (mat4){{ - 2.0f/s->rgb_width, 0.0f, 0.0f, -1.0f, - 0.0f, 2.0f/s->rgb_height, 0.0f, -1.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, - }}; - - read_param_float(&s->speed_lim_off, "SpeedLimitOffset"); - read_param_bool(&s->is_metric, "IsMetric"); - read_param_bool(&s->longitudinal_control, "LongitudinalControl"); - read_param_bool(&s->limit_set_speed, "LimitSetSpeed"); + read_param(&s->speed_lim_off, "SpeedLimitOffset"); + read_param(&s->is_metric, "IsMetric"); + read_param(&s->longitudinal_control, "LongitudinalControl"); + read_param(&s->limit_set_speed, "LimitSetSpeed"); // Set offsets so params don't get read at the same time s->longitudinal_control_timeout = UI_FREQ / 3; @@ -329,229 +81,167 @@ static void ui_init_vision(UIState *s, const VisionStreamBufs back_bufs, s->limit_set_speed_timeout = UI_FREQ; } -static PathData read_path(cereal::ModelData::PathData::Reader pathp) { - PathData ret = {0}; - - ret.prob = pathp.getProb(); - ret.std = pathp.getStd(); - - auto polyp = pathp.getPoly(); - for (int i = 0; i < POLYFIT_DEGREE; i++) { - ret.poly[i] = polyp[i]; - } - - // Compute points locations - for (int i = 0; i < MODEL_PATH_DISTANCE; i++) { - ret.points[i] = ret.poly[0] * (i*i*i) + ret.poly[1] * (i*i)+ ret.poly[2] * i + ret.poly[3]; - } - - return ret; -} - -static ModelData read_model(cereal::ModelData::Reader model) { - ModelData d = {0}; - - d.path = read_path(model.getPath()); - d.left_lane = read_path(model.getLeftLane()); - d.right_lane = read_path(model.getRightLane()); - - auto leadd = model.getLead(); - d.lead = (LeadData){ - .dist = leadd.getDist(), .prob = leadd.getProb(), .std = leadd.getStd(), - }; - - return d; -} - -static void update_status(UIState *s, int status) { +void update_status(UIState *s, int status) { if (s->status != status) { s->status = status; } } -void handle_message(UIState *s, Message* msg) { - auto amsg = kj::heapArray((msg->getSize() / sizeof(capnp::word)) + 1); - memcpy(amsg.begin(), msg->getData(), msg->getSize()); - capnp::FlatArrayMessageReader cmsg(amsg); - cereal::Event::Reader event = cmsg.getRoot(); +static inline void fill_path_points(const cereal::ModelData::PathData::Reader &path, float *points) { + const capnp::List::Reader &poly = path.getPoly(); + for (int i = 0; i < path.getValidLen(); i++) { + points[i] = poly[0] * (i * i * i) + poly[1] * (i * i) + poly[2] * i + poly[3]; + } +} - auto which = event.which(); +void handle_message(UIState *s, SubMaster &sm) { UIScene &scene = s->scene; - if (which == cereal::Event::CONTROLS_STATE && s->started) { - auto data = event.getControlsState(); - + if (s->started && sm.updated("controlsState")) { + auto event = sm["controlsState"]; + scene.controls_state = event.getControlsState(); s->controls_timeout = 1 * UI_FREQ; - scene.frontview = data.getRearViewCam(); - if (!scene.frontview){ s->controls_seen = true; } - - if (data.getVCruise() != scene.v_cruise) { - scene.v_cruise_update_ts = event.getLogMonoTime(); - } - scene.v_cruise = data.getVCruise(); - scene.v_ego = data.getVEgo(); - scene.curvature = data.getCurvature(); - scene.engaged = data.getEnabled(); - scene.engageable = data.getEngageable(); - scene.gps_planner_active = data.getGpsPlannerActive(); - scene.monitoring_active = data.getDriverMonitoringOn(); + s->controls_seen = true; - scene.decel_for_model = data.getDecelForModel(); - auto alert_sound = data.getAlertSound(); - const auto sound_none = cereal::CarControl::HUDControl::AudibleAlert::NONE; - if (alert_sound != s->alert_sound){ - if (s->alert_sound != sound_none){ - stop_alert_sound(s->alert_sound); - } - if (alert_sound != sound_none){ - play_alert_sound(alert_sound); - s->alert_type = data.getAlertType(); + auto alert_sound = scene.controls_state.getAlertSound(); + if (scene.alert_type.compare(scene.controls_state.getAlertType()) != 0) { + if (alert_sound == AudibleAlert::NONE) { + s->sound.stop(); + } else { + s->sound.play(alert_sound); } - s->alert_sound = alert_sound; } - scene.alert_text1 = data.getAlertText1(); - scene.alert_text2 = data.getAlertText2(); - scene.alert_ts = event.getLogMonoTime(); - scene.alert_size = data.getAlertSize(); - auto alertStatus = data.getAlertStatus(); + scene.alert_text1 = scene.controls_state.getAlertText1(); + scene.alert_text2 = scene.controls_state.getAlertText2(); + scene.alert_size = scene.controls_state.getAlertSize(); + scene.alert_type = scene.controls_state.getAlertType(); + auto alertStatus = scene.controls_state.getAlertStatus(); if (alertStatus == cereal::ControlsState::AlertStatus::USER_PROMPT) { update_status(s, STATUS_WARNING); } else if (alertStatus == cereal::ControlsState::AlertStatus::CRITICAL) { update_status(s, STATUS_ALERT); } else{ - update_status(s, scene.engaged ? STATUS_ENGAGED : STATUS_DISENGAGED); + update_status(s, scene.controls_state.getEnabled() ? STATUS_ENGAGED : STATUS_DISENGAGED); } - scene.alert_blinkingrate = data.getAlertBlinkingRate(); - if (scene.alert_blinkingrate > 0.) { + float alert_blinkingrate = scene.controls_state.getAlertBlinkingRate(); + if (alert_blinkingrate > 0.) { if (s->alert_blinked) { if (s->alert_blinking_alpha > 0.0 && s->alert_blinking_alpha < 1.0) { - s->alert_blinking_alpha += (0.05*scene.alert_blinkingrate); + s->alert_blinking_alpha += (0.05*alert_blinkingrate); } else { s->alert_blinked = false; } } else { if (s->alert_blinking_alpha > 0.25) { - s->alert_blinking_alpha -= (0.05*scene.alert_blinkingrate); + s->alert_blinking_alpha -= (0.05*alert_blinkingrate); } else { s->alert_blinking_alpha += 0.25; s->alert_blinked = true; } } } - } else if (which == cereal::Event::RADAR_STATE) { - auto data = event.getRadarState(); - - auto leaddatad = data.getLeadOne(); - scene.lead_status = leaddatad.getStatus(); - scene.lead_d_rel = leaddatad.getDRel(); - scene.lead_y_rel = leaddatad.getYRel(); - scene.lead_v_rel = leaddatad.getVRel(); - auto leaddatad2 = data.getLeadTwo(); - scene.lead_status2 = leaddatad2.getStatus(); - scene.lead_d_rel2 = leaddatad2.getDRel(); - scene.lead_y_rel2 = leaddatad2.getYRel(); - scene.lead_v_rel2 = leaddatad2.getVRel(); - - s->livempc_or_radarstate_changed = true; - } else if (which == cereal::Event::LIVE_CALIBRATION) { + } + if (sm.updated("radarState")) { + auto data = sm["radarState"].getRadarState(); + scene.lead_data[0] = data.getLeadOne(); + scene.lead_data[1] = data.getLeadTwo(); + } + if (sm.updated("liveCalibration")) { scene.world_objects_visible = true; - auto extrinsicl = event.getLiveCalibration().getExtrinsicMatrix(); + auto extrinsicl = sm["liveCalibration"].getLiveCalibration().getExtrinsicMatrix(); for (int i = 0; i < 3 * 4; i++) { scene.extrinsic_matrix.v[i] = extrinsicl[i]; } - } else if (which == cereal::Event::MODEL) { - scene.model = read_model(event.getModel()); - s->model_changed = true; - } else if (which == cereal::Event::LIVE_MPC) { - auto data = event.getLiveMpc(); - - auto x_list = data.getX(); - auto y_list = data.getY(); - for (int i = 0; i < 50; i++){ - scene.mpc_x[i] = x_list[i]; - scene.mpc_y[i] = y_list[i]; - } - s->livempc_or_radarstate_changed = true; - } else if (which == cereal::Event::UI_LAYOUT_STATE) { - auto data = event.getUiLayoutState(); - + } + if (sm.updated("model")) { + scene.model = sm["model"].getModel(); + fill_path_points(scene.model.getPath(), scene.path_points); + fill_path_points(scene.model.getLeftLane(), scene.left_lane_points); + fill_path_points(scene.model.getRightLane(), scene.right_lane_points); + } + // else if (which == cereal::Event::LIVE_MPC) { + // auto data = event.getLiveMpc(); + // auto x_list = data.getX(); + // auto y_list = data.getY(); + // for (int i = 0; i < 50; i++){ + // scene.mpc_x[i] = x_list[i]; + // scene.mpc_y[i] = y_list[i]; + // } + // s->livempc_or_radarstate_changed = true; + // } + if (sm.updated("uiLayoutState")) { + auto data = sm["uiLayoutState"].getUiLayoutState(); s->active_app = data.getActiveApp(); scene.uilayout_sidebarcollapsed = data.getSidebarCollapsed(); - if (data.getMockEngaged() != scene.uilayout_mockengaged) { - scene.uilayout_mockengaged = data.getMockEngaged(); - } - } else if (which == cereal::Event::LIVE_MAP_DATA) { - scene.map_valid = event.getLiveMapData().getMapValid(); - } else if (which == cereal::Event::THERMAL) { - auto data = event.getThermal(); - - scene.networkType = data.getNetworkType(); - scene.networkStrength = data.getNetworkStrength(); - scene.batteryPercent = data.getBatteryPercent(); - scene.batteryCharging = data.getBatteryStatus() == "Charging"; - scene.freeSpace = data.getFreeSpace(); - scene.thermalStatus = data.getThermalStatus(); - scene.paTemp = data.getPa0(); - - s->thermal_started = data.getStarted(); - } else if (which == cereal::Event::UBLOX_GNSS) { - auto data = event.getUbloxGnss(); + } +#ifdef SHOW_SPEEDLIMIT + if (sm.updated("liveMapData")) { + scene.map_valid = sm["liveMapData"].getLiveMapData().getMapValid(); + } +#endif + if (sm.updated("thermal")) { + scene.thermal = sm["thermal"].getThermal(); + } + if (sm.updated("ubloxGnss")) { + auto data = sm["ubloxGnss"].getUbloxGnss(); if (data.which() == cereal::UbloxGnss::MEASUREMENT_REPORT) { scene.satelliteCount = data.getMeasurementReport().getNumMeas(); } - } else if (which == cereal::Event::HEALTH) { - scene.hwType = event.getHealth().getHwType(); - s->hardware_timeout = 5*30; // 5 seconds at 30 fps - } else if (which == cereal::Event::DRIVER_STATE) { - auto data = event.getDriverState(); - scene.face_prob = data.getFaceProb(); - auto fxy_list = data.getFacePosition(); - scene.face_x = fxy_list[0]; - scene.face_y = fxy_list[1]; - } else if (which == cereal::Event::D_MONITORING_STATE) { - auto data = event.getDMonitoringState(); - scene.is_rhd = data.getIsRHD(); - scene.awareness_status = data.getAwarenessStatus(); - s->preview_started = data.getIsPreview(); + } + if (sm.updated("health")) { + scene.hwType = sm["health"].getHealth().getHwType(); + s->hardware_timeout = 5*UI_FREQ; // 5 seconds + } + if (sm.updated("driverState")) { + scene.driver_state = sm["driverState"].getDriverState(); + } + if (sm.updated("dMonitoringState")) { + scene.dmonitoring_state = sm["dMonitoringState"].getDMonitoringState(); + scene.is_rhd = scene.dmonitoring_state.getIsRHD(); + scene.frontview = scene.dmonitoring_state.getIsPreview(); } - s->started = s->thermal_started || s->preview_started ; + // timeout on frontview + if ((sm.frame - sm.rcv_frame("dMonitoringState")) > 1*UI_FREQ) { + scene.frontview = false; + } + + s->started = scene.thermal.getStarted() || scene.frontview; // Handle onroad/offroad transition if (!s->started) { if (s->status != STATUS_STOPPED) { update_status(s, STATUS_STOPPED); - s->alert_sound_timeout = 0; s->vision_seen = false; s->controls_seen = false; s->active_app = cereal::UiLayoutState::App::HOME; - update_offroad_layout_state(s); + + #ifndef QCOM + // disconnect from visionipc on PC + close(s->ipc_fd); + s->ipc_fd = -1; + #endif } } else if (s->status == STATUS_STOPPED) { update_status(s, STATUS_DISENGAGED); - s->active_app = cereal::UiLayoutState::App::NONE; - update_offroad_layout_state(s); } } -static void check_messages(UIState *s) { - while(true) { - auto polls = s->poller->poll(0); - - if (polls.size() == 0) - break; - - for (auto sock : polls){ - Message *msg = sock->receive(); - if (msg) { - handle_message(s, msg); - delete msg; - } - } +void check_messages(UIState *s) { + if (s->sm->update(0) > 0){ + handle_message(s, *(s->sm)); } } -static void ui_update(UIState *s) { +void ui_update_sizes(UIState *s){ + // resize vision for collapsing sidebar + const bool hasSidebar = !s->scene.uilayout_sidebarcollapsed; + s->scene.ui_viz_rx = hasSidebar ? box_x : (box_x - sbr_w + (bdr_s * 2)); + s->scene.ui_viz_rw = hasSidebar ? box_w : (box_w + sbr_w - (bdr_s * 2)); + s->scene.ui_viz_ro = hasSidebar ? -(sbr_w - 6 * bdr_s) : 0; +} + +void ui_update(UIState *s) { int err; if (s->vision_connect_firstrun) { @@ -559,7 +249,7 @@ static void ui_update(UIState *s) { // do this here for now in lieu of a run_on_main_thread event for (int i=0; ikhr[i] != NULL) { + if(s->khr[i] != 0) { visionimg_destroy_gl(s->khr[i], s->priv_hnds[i]); glDeleteTextures(1, &s->frame_texs[i]); } @@ -589,7 +279,7 @@ static void ui_update(UIState *s) { } for (int i=0; ikhr_front[i] != NULL) { + if(s->khr_front[i] != 0) { visionimg_destroy_gl(s->khr_front[i], s->priv_hnds_front[i]); glDeleteTextures(1, &s->frame_front_texs[i]); } @@ -621,7 +311,6 @@ static void ui_update(UIState *s) { assert(glGetError() == GL_NO_ERROR); s->scene.uilayout_sidebarcollapsed = true; - update_offroad_layout_state(s); s->scene.ui_viz_rx = (box_x-sbr_w+bdr_s*2); s->scene.ui_viz_rw = (box_w+sbr_w-(bdr_s*2)); s->scene.ui_viz_ro = 0; @@ -634,8 +323,14 @@ static void ui_update(UIState *s) { zmq_pollitem_t polls[1] = {{0}}; // Take an rgb image from visiond if there is one + assert(s->ipc_fd >= 0); while(true) { - assert(s->ipc_fd >= 0); + if (s->ipc_fd < 0) { + // TODO: rethink this, for now it should only trigger on PC + LOGW("vision disconnected by other thread"); + s->vision_connected = false; + return; + } polls[0].fd = s->ipc_fd; polls[0].events = ZMQ_POLLIN; #ifdef UI_60FPS @@ -740,8 +435,7 @@ static int vision_subscribe(int fd, VisionPacket *rp, VisionStreamType type) { return 1; } -static void* vision_connect_thread(void *args) { - int err; +void* vision_connect_thread(void *args) { set_thread_name("vision_connect"); UIState *s = (UIState*)args; @@ -772,305 +466,9 @@ static void* vision_connect_thread(void *args) { s->vision_connect_firstrun = true; // Drain sockets - while (true){ - auto polls = s->poller->poll(0); - if (polls.size() == 0) - break; - - for (auto sock : polls){ - Message * msg = sock->receive(); - if (msg == NULL) continue; - delete msg; - } - } + s->sm->drain(); pthread_mutex_unlock(&s->lock); } return NULL; } - -#ifdef QCOM - -#include -#include -#include - -static void* light_sensor_thread(void *args) { - int err; - set_thread_name("light_sensor"); - - UIState *s = (UIState*)args; - s->light_sensor = 0.0; - - struct sensors_poll_device_t* device; - struct sensors_module_t* module; - - hw_get_module(SENSORS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); - sensors_open(&module->common, &device); - - // need to do this - struct sensor_t const* list; - int count = module->get_sensors_list(module, &list); - - int SENSOR_LIGHT = 7; - - err = device->activate(device, SENSOR_LIGHT, 0); - if (err != 0) goto fail; - err = device->activate(device, SENSOR_LIGHT, 1); - if (err != 0) goto fail; - - device->setDelay(device, SENSOR_LIGHT, ms2ns(100)); - - while (!do_exit) { - static const size_t numEvents = 1; - sensors_event_t buffer[numEvents]; - - int n = device->poll(device, buffer, numEvents); - if (n < 0) { - LOG_100("light_sensor_poll failed: %d", n); - } - if (n > 0) { - s->light_sensor = buffer[0].light; - } - } - sensors_close(device); - return NULL; - -fail: - LOGE("LIGHT SENSOR IS MISSING"); - s->light_sensor = 255; - return NULL; -} - -#endif - -int is_leon() { - #define MAXCHAR 1000 - FILE *fp; - char str[MAXCHAR]; - const char* filename = "/proc/cmdline"; - - fp = fopen(filename, "r"); - if (fp == NULL){ - printf("Could not open file %s",filename); - return 0; - } - fgets(str, MAXCHAR, fp); - fclose(fp); - return strstr(str, "letv") != NULL; -} - -int main(int argc, char* argv[]) { - int err; - setpriority(PRIO_PROCESS, 0, -14); - - zsys_handler_set(NULL); - signal(SIGINT, (sighandler_t)set_do_exit); - - UIState uistate; - UIState *s = &uistate; - ui_init(s); - enable_event_processing(true); - - pthread_t connect_thread_handle; - err = pthread_create(&connect_thread_handle, NULL, - vision_connect_thread, s); - assert(err == 0); - -#ifdef QCOM - pthread_t light_sensor_thread_handle; - err = pthread_create(&light_sensor_thread_handle, NULL, - light_sensor_thread, s); - assert(err == 0); -#endif - - TouchState touch = {0}; - touch_init(&touch); - s->touch_fd = touch.fd; - ui_sound_init(); - - // light sensor scaling params - const int LEON = is_leon(); - - float brightness_b, brightness_m; - int result = read_param_float(&brightness_b, "BRIGHTNESS_B", true); - result += read_param_float(&brightness_m, "BRIGHTNESS_M", true); - - if(result != 0){ - brightness_b = LEON ? 10.0 : 5.0; - brightness_m = LEON ? 2.6 : 1.3; - write_param_float(brightness_b, "BRIGHTNESS_B", true); - write_param_float(brightness_m, "BRIGHTNESS_M", true); - } - - float smooth_brightness = brightness_b; - - const int MIN_VOLUME = LEON ? 12 : 9; - const int MAX_VOLUME = LEON ? 15 : 12; - - set_volume(MIN_VOLUME); - s->volume_timeout = 5 * UI_FREQ; - int draws = 0; - - s->scene.satelliteCount = -1; - s->started = false; - s->vision_seen = false; - - while (!do_exit) { - bool should_swap = false; - if (!s->started) { - // Delay a while to avoid 9% cpu usage while car is not started and user is keeping touching on the screen. - // Don't hold the lock while sleeping, so that vision_connect_thread have chances to get the lock. - usleep(30 * 1000); - } - pthread_mutex_lock(&s->lock); - double u1 = millis_since_boot(); - - // light sensor is only exposed on EONs - float clipped_brightness = (s->light_sensor*brightness_m) + brightness_b; - if (clipped_brightness > 512) clipped_brightness = 512; - smooth_brightness = clipped_brightness * 0.01 + smooth_brightness * 0.99; - if (smooth_brightness > 255) smooth_brightness = 255; - set_brightness(s, (int)smooth_brightness); - - // resize vision for collapsing sidebar - const bool hasSidebar = !s->scene.uilayout_sidebarcollapsed; - s->scene.ui_viz_rx = hasSidebar ? box_x : (box_x - sbr_w + (bdr_s * 2)); - s->scene.ui_viz_rw = hasSidebar ? box_w : (box_w + sbr_w - (bdr_s * 2)); - s->scene.ui_viz_ro = hasSidebar ? -(sbr_w - 6 * bdr_s) : 0; - - // poll for touch events - int touch_x = -1, touch_y = -1; - int touched = touch_poll(&touch, &touch_x, &touch_y, 0); - if (touched == 1) { - set_awake(s, true); - handle_sidebar_touch(s, touch_x, touch_y); - handle_vision_touch(s, touch_x, touch_y); - } - - if (!s->started) { - // always process events offroad - check_messages(s); - } else { - set_awake(s, true); - // Car started, fetch a new rgb image from ipc - if (s->vision_connected){ - ui_update(s); - } - - check_messages(s); - - // Visiond process is just stopped, force a redraw to make screen blank again. - if (!s->started) { - s->scene.uilayout_sidebarcollapsed = false; - update_offroad_layout_state(s); - ui_draw(s); - glFinish(); - should_swap = true; - } - } - - // manage wakefulness - if (s->awake_timeout > 0) { - s->awake_timeout--; - } else { - set_awake(s, false); - } - - // manage hardware disconnect - if (s->hardware_timeout > 0) { - s->hardware_timeout--; - } else { - s->scene.hwType = cereal::HealthData::HwType::UNKNOWN; - } - - // Don't waste resources on drawing in case screen is off - if (s->awake) { - ui_draw(s); - glFinish(); - should_swap = true; - } - - if (s->volume_timeout > 0) { - s->volume_timeout--; - } else { - int volume = fmin(MAX_VOLUME, MIN_VOLUME + s->scene.v_ego / 5); // up one notch every 5 m/s - set_volume(volume); - s->volume_timeout = 5 * UI_FREQ; - } - - // If car is started and controlsState times out, display an alert - if (s->controls_timeout > 0) { - s->controls_timeout--; - } else { - if (s->started && s->controls_seen && s->scene.alert_text2 != "Controls Unresponsive") { - LOGE("Controls unresponsive"); - s->scene.alert_size = cereal::ControlsState::AlertSize::FULL; - update_status(s, STATUS_ALERT); - - s->scene.alert_text1 = "TAKE CONTROL IMMEDIATELY"; - s->scene.alert_text2 = "Controls Unresponsive"; - - ui_draw_vision_alert(s, s->scene.alert_size, s->status, s->scene.alert_text1.c_str(), s->scene.alert_text2.c_str()); - - s->alert_sound_timeout = 2 * UI_FREQ; - s->alert_sound = cereal::CarControl::HUDControl::AudibleAlert::CHIME_WARNING_REPEAT; - play_alert_sound(s->alert_sound); - } - - s->alert_sound_timeout--; - s->controls_seen = false; - } - - // stop playing alert sound - if ((!s->started || (s->started && s->alert_sound_timeout == 0)) && - s->alert_sound != cereal::CarControl::HUDControl::AudibleAlert::NONE) { - stop_alert_sound(s->alert_sound); - s->alert_sound = cereal::CarControl::HUDControl::AudibleAlert::NONE; - } - - read_param_bool_timeout(&s->is_metric, "IsMetric", &s->is_metric_timeout); - read_param_bool_timeout(&s->longitudinal_control, "LongitudinalControl", &s->longitudinal_control_timeout); - read_param_bool_timeout(&s->limit_set_speed, "LimitSetSpeed", &s->limit_set_speed_timeout); - read_param_float_timeout(&s->speed_lim_off, "SpeedLimitOffset", &s->limit_set_speed_timeout); - int param_read = read_param_uint64_timeout(&s->last_athena_ping, "LastAthenaPingTime", &s->last_athena_ping_timeout); - if (param_read != 0) { - s->scene.athenaStatus = NET_DISCONNECTED; - } else if (nanos_since_boot() - s->last_athena_ping < 70e9) { - s->scene.athenaStatus = NET_CONNECTED; - } else { - s->scene.athenaStatus = NET_ERROR; - } - update_offroad_layout_timeout(s, &s->offroad_layout_timeout); - - pthread_mutex_unlock(&s->lock); - - // the bg thread needs to be scheduled, so the main thread needs time without the lock - // safe to do this outside the lock? - if (should_swap) { - double u2 = millis_since_boot(); - if (u2-u1 > 66) { - // warn on sub 15fps - LOGW("slow frame(%d) time: %.2f", draws, u2-u1); - } - draws++; - framebuffer_swap(s->fb); - } - } - - set_awake(s, true); - ui_sound_destroy(); - - // wake up bg thread to exit - pthread_mutex_lock(&s->lock); - pthread_mutex_unlock(&s->lock); - -#ifdef QCOM - // join light_sensor_thread? -#endif - - err = pthread_join(connect_thread_handle, NULL); - assert(err == 0); - - return 0; -} diff --git a/selfdrive/ui/ui.hpp b/selfdrive/ui/ui.hpp index 771b5501cc..7db7f6f0a8 100644 --- a/selfdrive/ui/ui.hpp +++ b/selfdrive/ui/ui.hpp @@ -1,6 +1,6 @@ -#ifndef _UI_H -#define _UI_H -#include "cereal/gen/cpp/log.capnp.h" +#pragma once +#include "messaging.hpp" + #ifdef __APPLE__ #include #define NANOVG_GL3_IMPLEMENTATION @@ -11,9 +11,12 @@ #define NANOVG_GLES3_IMPLEMENTATION #define nvgCreate nvgCreateGLES3 #endif +#include -#include +#include +#include #include + #include "nanovg.h" #include "common/mat.h" @@ -21,7 +24,7 @@ #include "common/visionimg.h" #include "common/framebuffer.h" #include "common/modeldata.h" -#include "messaging.hpp" +#include "common/params.h" #include "sound.hpp" #define STATUS_STOPPED 0 @@ -50,12 +53,19 @@ //#define SHOW_SPEEDLIMIT 1 //#define DEBUG_TURN +// TODO: Detect dynamically +#ifdef QCOM2 +const int vwp_w = 2160; +#else const int vwp_w = 1920; +#endif + const int vwp_h = 1080; const int nav_w = 640; const int nav_ww= 760; const int sbr_w = 300; const int bdr_s = 30; + const int box_x = sbr_w+bdr_s; const int box_y = bdr_s; const int box_w = vwp_w-sbr_w-(bdr_s*2); @@ -77,7 +87,7 @@ const int home_btn_y = vwp_h - home_btn_h - 40; const int UI_FREQ = 30; // Hz const int MODEL_PATH_MAX_VERTICES_CNT = 98; -const int MODEL_LANE_PATH_CNT = 3; +const int MODEL_LANE_PATH_CNT = 2; const int TRACK_POINTS_MAX_CNT = 50 * 2; const int SET_SPEED_NA = 255; @@ -90,76 +100,46 @@ const uint8_t bg_colors[][4] = { [STATUS_ALERT] = {0xC9, 0x22, 0x31, 0xff}, }; - typedef struct UIScene { int frontview; int fullview; - int transformed_width, transformed_height; - - ModelData model; - float mpc_x[50]; float mpc_y[50]; bool world_objects_visible; mat4 extrinsic_matrix; // Last row is 0 so we can use mat4. - float v_cruise; - uint64_t v_cruise_update_ts; - float v_ego; - bool decel_for_model; - float speedlimit; bool speedlimit_valid; - bool map_valid; - - float curvature; - int engaged; - bool engageable; - bool monitoring_active; + bool is_rhd; + bool map_valid; bool uilayout_sidebarcollapsed; bool uilayout_mapenabled; - bool uilayout_mockengaged; // responsive layout int ui_viz_rx; int ui_viz_rw; int ui_viz_ro; - int lead_status; - float lead_d_rel, lead_y_rel, lead_v_rel; - - int lead_status2; - float lead_d_rel2, lead_y_rel2, lead_v_rel2; - - float face_prob; - bool is_rhd; - float face_x, face_y; - - int front_box_x, front_box_y, front_box_width, front_box_height; - - uint64_t alert_ts; std::string alert_text1; std::string alert_text2; + std::string alert_type; cereal::ControlsState::AlertSize alert_size; - float alert_blinkingrate; - float awareness_status; - - // Used to show gps planner status - bool gps_planner_active; - - cereal::ThermalData::NetworkType networkType; - cereal::ThermalData::NetworkStrength networkStrength; - int batteryPercent; - bool batteryCharging; - float freeSpace; - cereal::ThermalData::ThermalStatus thermalStatus; - int paTemp; cereal::HealthData::HwType hwType; int satelliteCount; uint8_t athenaStatus; + + cereal::ThermalData::Reader thermal; + cereal::RadarState::LeadData::Reader lead_data[2]; + cereal::ControlsState::Reader controls_state; + cereal::DriverState::Reader driver_state; + cereal::DMonitoringState::Reader dmonitoring_state; + cereal::ModelData::Reader model; + float left_lane_points[MODEL_PATH_DISTANCE]; + float path_points[MODEL_PATH_DISTANCE]; + float right_lane_points[MODEL_PATH_DISTANCE]; } UIScene; typedef struct { @@ -188,7 +168,6 @@ typedef struct UIState { NVGcontext *vg; // fonts and images - int font_courbd; int font_sans_regular; int font_sans_semibold; int font_sans_bold; @@ -203,21 +182,8 @@ typedef struct UIState { int img_network[6]; // sockets - Context *ctx; - SubSocket *model_sock; - SubSocket *controlsstate_sock; - SubSocket *livecalibration_sock; - SubSocket *radarstate_sock; - SubSocket *map_data_sock; - SubSocket *uilayout_sock; - SubSocket *thermal_sock; - SubSocket *health_sock; - SubSocket *ubloxgnss_sock; - SubSocket *driverstate_sock; - SubSocket *dmonitoring_sock; - PubSocket *offroad_sock; - Poller * poller; - Poller * ublox_poller; + SubMaster *sm; + PubMaster *pm; cereal::UiLayoutState::App active_app; @@ -244,7 +210,6 @@ typedef struct UIState { int rgb_width, rgb_height, rgb_stride; size_t rgb_buf_len; - mat4 rgb_transform; int rgb_front_width, rgb_front_height, rgb_front_stride; size_t rgb_front_buf_len; @@ -254,16 +219,13 @@ typedef struct UIState { // timeouts int awake_timeout; - int volume_timeout; int controls_timeout; - int alert_sound_timeout; int speed_lim_off_timeout; int is_metric_timeout; int longitudinal_control_timeout; int limit_set_speed_timeout; int hardware_timeout; int last_athena_ping_timeout; - int offroad_layout_timeout; bool controls_seen; @@ -274,38 +236,68 @@ typedef struct UIState { bool limit_set_speed; float speed_lim_off; bool is_ego_over_limit; - std::string alert_type; - AudibleAlert alert_sound; float alert_blinking_alpha; bool alert_blinked; bool started; - bool thermal_started, preview_started; bool vision_seen; - float light_sensor; + std::atomic light_sensor; int touch_fd; - // Hints for re-calculations and redrawing - bool model_changed; - bool livempc_or_radarstate_changed; - GLuint frame_vao[2], frame_vbo[2], frame_ibo[2]; mat4 rear_frame_mat, front_frame_mat; model_path_vertices_data model_path_vertices[MODEL_LANE_PATH_CNT * 2]; track_vertices_data track_vertices[2]; + + Sound sound; } UIState; -// API -void ui_draw_vision_alert(UIState *s, cereal::ControlsState::AlertSize va_size, int va_color, - const char* va_text1, const char* va_text2); -void ui_draw(UIState *s); -void ui_draw_sidebar(UIState *s); -void ui_draw_image(NVGcontext *vg, float x, float y, float w, float h, int image, float alpha); -void ui_draw_rect(NVGcontext *vg, float x, float y, float w, float h, NVGcolor color, float r = 0, int width = 0); -void ui_draw_rect(NVGcontext *vg, float x, float y, float w, float h, NVGpaint paint, float r = 0); -void ui_nvg_init(UIState *s); -#endif +void ui_init(UIState *s); +void ui_update(UIState *s); +void ui_update_sizes(UIState *s); + +void* vision_connect_thread(void *args); +void check_messages(UIState *s); +void update_status(UIState *s, int status); + + +int write_param_float(float param, const char* param_name, bool persistent_param = false); +template +int read_param(T* param, const char *param_name, bool persistent_param = false){ + T param_orig = *param; + char *value; + size_t sz; + + int result = read_db_value(param_name, &value, &sz, persistent_param); + if (result == 0){ + std::string s = std::string(value, sz); // value is not null terminated + free(value); + + // Parse result + std::istringstream iss(s); + iss >> *param; + + // Restore original value if parsing failed + if (iss.fail()) { + *param = param_orig; + result = -1; + } + } + return result; +} + +template +int read_param_timeout(T* param, const char* param_name, int* timeout, bool persistent_param = false) { + int result = -1; + if (*timeout > 0){ + (*timeout)--; + } else { + *timeout = 2 * UI_FREQ; // 0.5Hz + result = read_param(param, param_name, persistent_param); + } + return result; +} diff --git a/selfdrive/updated.py b/selfdrive/updated.py index c31ab9560f..2747e5753a 100755 --- a/selfdrive/updated.py +++ b/selfdrive/updated.py @@ -26,47 +26,50 @@ import os import datetime import subprocess import psutil -from stat import S_ISREG, S_ISDIR, S_ISLNK, S_IMODE, ST_MODE, ST_INO, ST_UID, ST_GID, ST_ATIME, ST_MTIME import shutil import signal -from pathlib import Path import fcntl +import time import threading -from cffi import FFI +from pathlib import Path from common.basedir import BASEDIR from common.params import Params from selfdrive.swaglog import cloudlog +from selfdrive.controls.lib.alertmanager import set_offroad_alert -STAGING_ROOT = "/data/safe_staging" +TEST_IP = os.getenv("UPDATER_TEST_IP", "8.8.8.8") +LOCK_FILE = os.getenv("UPDATER_LOCK_FILE", "/tmp/safe_staging_overlay.lock") +STAGING_ROOT = os.getenv("UPDATER_STAGING_ROOT", "/data/safe_staging") + +NEOS_VERSION = os.getenv("UPDATER_NEOS_VERSION", "/VERSION") +NEOSUPDATE_DIR = os.getenv("UPDATER_NEOSUPDATE_DIR", "/data/neoupdate") OVERLAY_UPPER = os.path.join(STAGING_ROOT, "upper") OVERLAY_METADATA = os.path.join(STAGING_ROOT, "metadata") OVERLAY_MERGED = os.path.join(STAGING_ROOT, "merged") FINALIZED = os.path.join(STAGING_ROOT, "finalized") -NICE_LOW_PRIORITY = ["nice", "-n", "19"] -SHORT = os.getenv("SHORT") is not None - -# Workaround for the EON/termux build of Python having os.link removed. -ffi = FFI() -ffi.cdef("int link(const char *oldpath, const char *newpath);") -libc = ffi.dlopen(None) - class WaitTimeHelper: - ready_event = threading.Event() - shutdown = False - - def __init__(self): + def __init__(self, proc): + self.proc = proc + self.ready_event = threading.Event() + self.shutdown = False signal.signal(signal.SIGTERM, self.graceful_shutdown) signal.signal(signal.SIGINT, self.graceful_shutdown) signal.signal(signal.SIGHUP, self.update_now) def graceful_shutdown(self, signum, frame): - # umount -f doesn't appear effective in avoiding "device busy" on EON, + # umount -f doesn't appear effective in avoiding "device busy" on NEOS, # so don't actually die until the next convenient opportunity in main(). cloudlog.info("caught SIGINT/SIGTERM, dismounting overlay at next opportunity") + + # forward the signal to all our child processes + child_procs = self.proc.children(recursive=True) + for p in child_procs: + p.send_signal(signum) + self.shutdown = True self.ready_event.set() @@ -74,42 +77,27 @@ class WaitTimeHelper: cloudlog.info("caught SIGHUP, running update check immediately") self.ready_event.set() - -def wait_between_updates(ready_event): - ready_event.clear() - if SHORT: - ready_event.wait(timeout=10) - else: - ready_event.wait(timeout=60 * 10) - - -def link(src, dest): - # Workaround for the EON/termux build of Python having os.link removed. - return libc.link(src.encode(), dest.encode()) + def sleep(self, t): + self.ready_event.wait(timeout=t) -def run(cmd, cwd=None): +def run(cmd, cwd=None, low_priority=False): + if low_priority: + cmd = ["nice", "-n", "19"] + cmd return subprocess.check_output(cmd, cwd=cwd, stderr=subprocess.STDOUT, encoding='utf8') -def remove_consistent_flag(): +def set_consistent_flag(consistent): os.system("sync") consistent_file = Path(os.path.join(FINALIZED, ".overlay_consistent")) - try: + if consistent: + consistent_file.touch() + elif not consistent and consistent_file.exists(): consistent_file.unlink() - except FileNotFoundError: - pass - os.system("sync") - - -def set_consistent_flag(): - consistent_file = Path(os.path.join(FINALIZED, ".overlay_consistent")) - os.system("sync") - consistent_file.touch() os.system("sync") -def set_update_available_params(new_version=False): +def set_update_available_params(new_version): params = Params() t = datetime.datetime.utcnow().isoformat() @@ -133,39 +121,35 @@ def dismount_ovfs(): def setup_git_options(cwd): - # We sync FS object atimes (which EON doesn't use) and mtimes, but ctimes + # We sync FS object atimes (which NEOS doesn't use) and mtimes, but ctimes # are outside user control. Make sure Git is set up to ignore system ctimes, # because they change when we make hard links during finalize. Otherwise, # there is a lot of unnecessary churn. This appears to be a common need on # OSX as well: https://www.git-tower.com/blog/make-git-rebase-safe-on-osx/ - try: - trustctime = run(["git", "config", "--get", "core.trustctime"], cwd) - trustctime_set = (trustctime.strip() == "false") - except subprocess.CalledProcessError: - trustctime_set = False - if not trustctime_set: - cloudlog.info("Setting core.trustctime false") - run(["git", "config", "core.trustctime", "false"], cwd) - - # We are temporarily using copytree to copy the directory, which also changes + # We are using copytree to copy the directory, which also changes # inode numbers. Ignore those changes too. - try: - checkstat = run(["git", "config", "--get", "core.checkStat"], cwd) - checkstat_set = (checkstat.strip() == "minimal") - except subprocess.CalledProcessError: - checkstat_set = False + git_cfg = [ + ("core.trustctime", "false"), + ("core.checkStat", "minimal"), + ] + for option, value in git_cfg: + try: + ret = run(["git", "config", "--get", option], cwd) + config_ok = ret.strip() == value + except subprocess.CalledProcessError: + config_ok = False - if not checkstat_set: - cloudlog.info("Setting core.checkState minimal") - run(["git", "config", "core.checkStat", "minimal"], cwd) + if not config_ok: + cloudlog.info(f"Setting git '{option}' to '{value}'") + run(["git", "config", option, value], cwd) def init_ovfs(): cloudlog.info("preparing new safe staging area") Params().put("UpdateAvailable", "0") - remove_consistent_flag() + set_consistent_flag(False) dismount_ovfs() if os.path.isdir(STAGING_ROOT): @@ -173,6 +157,7 @@ def init_ovfs(): for dirname in [STAGING_ROOT, OVERLAY_UPPER, OVERLAY_METADATA, OVERLAY_MERGED, FINALIZED]: os.mkdir(dirname, 0o755) + if not os.lstat(BASEDIR).st_dev == os.lstat(OVERLAY_MERGED).st_dev: raise RuntimeError("base and overlay merge directories are on different filesystems; not valid for overlay FS!") @@ -180,204 +165,191 @@ def init_ovfs(): if os.path.isfile(os.path.join(BASEDIR, ".overlay_consistent")): os.remove(os.path.join(BASEDIR, ".overlay_consistent")) - # Leave a timestamped canary in BASEDIR to check at startup. The EON clock + # Leave a timestamped canary in BASEDIR to check at startup. The device clock # should be correct by the time we get here. If the init file disappears, or # critical mtimes in BASEDIR are newer than .overlay_init, continue.sh can # assume that BASEDIR has used for local development or otherwise modified, # and skips the update activation attempt. Path(os.path.join(BASEDIR, ".overlay_init")).touch() + os.system("sync") overlay_opts = f"lowerdir={BASEDIR},upperdir={OVERLAY_UPPER},workdir={OVERLAY_METADATA}" run(["mount", "-t", "overlay", "-o", overlay_opts, "none", OVERLAY_MERGED]) -def inodes_in_tree(search_dir): - """Given a search root, produce a dictionary mapping of inodes to relative - pathnames of regular files (no directories, symlinks, or special files).""" - inode_map = {} - for root, dirs, files in os.walk(search_dir, topdown=True): - for file_name in files: - full_path_name = os.path.join(root, file_name) - st = os.lstat(full_path_name) - if S_ISREG(st[ST_MODE]): - inode_map[st[ST_INO]] = full_path_name - return inode_map - - -def dup_ovfs_object(inode_map, source_obj, target_dir): - """Given a relative pathname to copy, and a new target root, duplicate the - source object in the target root, using hardlinks for regular files.""" - - source_full_path = os.path.join(OVERLAY_MERGED, source_obj) - st = os.lstat(source_full_path) - target_full_path = os.path.join(target_dir, source_obj) - - if S_ISREG(st[ST_MODE]): - # Hardlink all regular files; ownership and permissions are shared. - link(inode_map[st[ST_INO]], target_full_path) - else: - # Recreate all directories and symlinks; copy ownership and permissions. - if S_ISDIR(st[ST_MODE]): - os.mkdir(os.path.join(FINALIZED, source_obj), S_IMODE(st[ST_MODE])) - elif S_ISLNK(st[ST_MODE]): - os.symlink(os.readlink(source_full_path), target_full_path) - os.chmod(target_full_path, S_IMODE(st[ST_MODE]), follow_symlinks=False) - else: - # Ran into a FIFO, socket, etc. Should not happen in OP install dir. - # Ignore without copying for the time being; revisit later if needed. - cloudlog.error("can't copy this file type: %s" % source_full_path) - os.chown(target_full_path, st[ST_UID], st[ST_GID], follow_symlinks=False) - - # Sync target mtimes to the cached lstat() value from each source object. - # Restores shared inode mtimes after linking, fixes symlinks and dirs. - os.utime(target_full_path, (st[ST_ATIME], st[ST_MTIME]), follow_symlinks=False) - - -def finalize_from_ovfs_hardlink(): - """Take the current OverlayFS merged view and finalize a copy outside of - OverlayFS, ready to be swapped-in at BASEDIR. Copy using hardlinks""" - - cloudlog.info("creating finalized version of the overlay") - - # The "copy" is done with hardlinks, but since the OverlayFS merge looks - # like a different filesystem, and hardlinks can't cross filesystems, we - # have to borrow a source pathname from the upper or lower layer. - inode_map = inodes_in_tree(BASEDIR) - inode_map.update(inodes_in_tree(OVERLAY_UPPER)) - - shutil.rmtree(FINALIZED) - os.umask(0o077) - os.mkdir(FINALIZED) - for root, dirs, files in os.walk(OVERLAY_MERGED, topdown=True): - for obj_name in dirs: - relative_path_name = os.path.relpath(os.path.join(root, obj_name), OVERLAY_MERGED) - dup_ovfs_object(inode_map, relative_path_name, FINALIZED) - for obj_name in files: - relative_path_name = os.path.relpath(os.path.join(root, obj_name), OVERLAY_MERGED) - dup_ovfs_object(inode_map, relative_path_name, FINALIZED) - cloudlog.info("done finalizing overlay") - - -def finalize_from_ovfs_copy(): +def finalize_from_ovfs(): """Take the current OverlayFS merged view and finalize a copy outside of OverlayFS, ready to be swapped-in at BASEDIR. Copy using shutil.copytree""" + # Remove the update ready flag and any old updates cloudlog.info("creating finalized version of the overlay") + set_consistent_flag(False) shutil.rmtree(FINALIZED) + + # Copy the merged overlay view and set the update ready flag shutil.copytree(OVERLAY_MERGED, FINALIZED, symlinks=True) + set_consistent_flag(True) cloudlog.info("done finalizing overlay") -def attempt_update(): +def attempt_update(wait_helper): cloudlog.info("attempting git update inside staging overlay") setup_git_options(OVERLAY_MERGED) - git_fetch_output = run(NICE_LOW_PRIORITY + ["git", "fetch"], OVERLAY_MERGED) + git_fetch_output = run(["git", "fetch"], OVERLAY_MERGED, low_priority=True) cloudlog.info("git fetch success: %s", git_fetch_output) cur_hash = run(["git", "rev-parse", "HEAD"], OVERLAY_MERGED).rstrip() upstream_hash = run(["git", "rev-parse", "@{u}"], OVERLAY_MERGED).rstrip() new_version = cur_hash != upstream_hash - git_fetch_result = len(git_fetch_output) > 0 and (git_fetch_output != "Failed to add the host to the list of known hosts (/data/data/com.termux/files/home/.ssh/known_hosts).\n") + err_msg = "Failed to add the host to the list of known hosts (/data/data/com.termux/files/home/.ssh/known_hosts).\n" + git_fetch_result = len(git_fetch_output) > 0 and (git_fetch_output != err_msg) cloudlog.info("comparing %s to %s" % (cur_hash, upstream_hash)) if new_version or git_fetch_result: cloudlog.info("Running update") + if new_version: cloudlog.info("git reset in progress") r = [ - run(NICE_LOW_PRIORITY + ["git", "reset", "--hard", "@{u}"], OVERLAY_MERGED), - run(NICE_LOW_PRIORITY + ["git", "clean", "-xdf"], OVERLAY_MERGED), - run(NICE_LOW_PRIORITY + ["git", "submodule", "init"], OVERLAY_MERGED), - run(NICE_LOW_PRIORITY + ["git", "submodule", "update"], OVERLAY_MERGED), + run(["git", "reset", "--hard", "@{u}"], OVERLAY_MERGED, low_priority=True), + run(["git", "clean", "-xdf"], OVERLAY_MERGED, low_priority=True ), + run(["git", "submodule", "init"], OVERLAY_MERGED, low_priority=True), + run(["git", "submodule", "update"], OVERLAY_MERGED, low_priority=True), ] cloudlog.info("git reset success: %s", '\n'.join(r)) - # Un-set the validity flag to prevent the finalized tree from being - # activated later if the finalize step is interrupted - remove_consistent_flag() - - finalize_from_ovfs_copy() - - # Make sure the validity flag lands on disk LAST, only when the local git - # repo and OP install are in a consistent state. - set_consistent_flag() - - cloudlog.info("update successful!") + # Download the accompanying NEOS version if it doesn't match the current version + with open(NEOS_VERSION, "r") as f: + cur_neos = f.read().strip() + + updated_neos = run(["bash", "-c", r"unset REQUIRED_NEOS_VERSION && source launch_env.sh && \ + echo -n $REQUIRED_NEOS_VERSION"], OVERLAY_MERGED).strip() + + cloudlog.info(f"NEOS version check: {cur_neos} vs {updated_neos}") + if cur_neos != updated_neos: + cloudlog.info(f"Beginning background download for NEOS {updated_neos}") + + set_offroad_alert("Offroad_NeosUpdate", True) + updater_path = os.path.join(OVERLAY_MERGED, "installer/updater/updater") + update_manifest = f"file://{OVERLAY_MERGED}/installer/updater/update.json" + + neos_downloaded = False + start_time = time.monotonic() + # Try to download for one day + while (time.monotonic() - start_time < 60*60*24) and not wait_helper.shutdown: + wait_helper.ready_event.clear() + try: + run([updater_path, "bgcache", update_manifest], OVERLAY_MERGED, low_priority=True) + neos_downloaded = True + break + except subprocess.CalledProcessError: + cloudlog.info("NEOS background download failed, retrying") + wait_helper.sleep(120) + + # If the download failed, we'll show the alert again when we retry + set_offroad_alert("Offroad_NeosUpdate", False) + if not neos_downloaded: + raise Exception("Failed to download NEOS update") + + cloudlog.info(f"NEOS background download successful, took {time.monotonic() - start_time} seconds") + + # Create the finalized, ready-to-swap update + finalize_from_ovfs() + cloudlog.info("openpilot update successful!") else: cloudlog.info("nothing new from git at this time") - set_update_available_params(new_version=new_version) + set_update_available_params(new_version) + return new_version def main(): - update_failed_count = 0 - overlay_init_done = False - wait_helper = WaitTimeHelper() params = Params() - if not os.geteuid() == 0: + if params.get("DisableUpdates") == b"1": + raise RuntimeError("updates are disabled by the DisableUpdates param") + + if os.geteuid() != 0: raise RuntimeError("updated must be launched as root!") # Set low io priority - p = psutil.Process() + proc = psutil.Process() if psutil.LINUX: - p.ionice(psutil.IOPRIO_CLASS_BE, value=7) + proc.ionice(psutil.IOPRIO_CLASS_BE, value=7) - ov_lock_fd = open('/tmp/safe_staging_overlay.lock', 'w') + ov_lock_fd = open(LOCK_FILE, 'w') try: fcntl.flock(ov_lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError: raise RuntimeError("couldn't get overlay lock; is another updated running?") - while True: - update_failed_count += 1 + # Wait for IsOffroad to be set before our first update attempt + wait_helper = WaitTimeHelper(proc) + wait_helper.sleep(30) + + update_failed_count = 0 + update_available = False + overlay_initialized = False + while not wait_helper.shutdown: + wait_helper.ready_event.clear() + + # Check for internet every 30s time_wrong = datetime.datetime.utcnow().year < 2019 - ping_failed = subprocess.call(["ping", "-W", "4", "-c", "1", "8.8.8.8"]) - - # Wait until we have a valid datetime to initialize the overlay - if not (ping_failed or time_wrong): - try: - # If the git directory has modifcations after we created the overlay - # we need to recreate the overlay - if overlay_init_done: - overlay_init_fn = os.path.join(BASEDIR, ".overlay_init") - git_dir_path = os.path.join(BASEDIR, ".git") - new_files = run(["find", git_dir_path, "-newer", overlay_init_fn]) - - if len(new_files.splitlines()): - cloudlog.info(".git directory changed, recreating overlay") - overlay_init_done = False - - if not overlay_init_done: - init_ovfs() - overlay_init_done = True - - if params.get("IsOffroad") == b"1": - attempt_update() - update_failed_count = 0 - else: - cloudlog.info("not running updater, openpilot running") - - except subprocess.CalledProcessError as e: - cloudlog.event( - "update process failed", - cmd=e.cmd, - output=e.output, - returncode=e.returncode - ) - overlay_init_done = False - except Exception: - cloudlog.exception("uncaught updated exception, shouldn't happen") + ping_failed = os.system(f"ping -W 4 -c 1 {TEST_IP}") != 0 + if ping_failed or time_wrong: + wait_helper.sleep(30) + continue + + # Attempt an update + exception = None + update_failed_count += 1 + try: + # Re-create the overlay if BASEDIR/.git has changed since we created the overlay + if overlay_initialized: + overlay_init_fn = os.path.join(BASEDIR, ".overlay_init") + git_dir_path = os.path.join(BASEDIR, ".git") + new_files = run(["find", git_dir_path, "-newer", overlay_init_fn]) + + if len(new_files.splitlines()): + cloudlog.info(".git directory changed, recreating overlay") + overlay_initialized = False + + if not overlay_initialized: + init_ovfs() + overlay_initialized = True + + if params.get("IsOffroad") == b"1": + update_available = attempt_update(wait_helper) or update_available + update_failed_count = 0 + if not update_available and os.path.isdir(NEOSUPDATE_DIR): + shutil.rmtree(NEOSUPDATE_DIR) + else: + cloudlog.info("not running updater, openpilot running") + + except subprocess.CalledProcessError as e: + cloudlog.event( + "update process failed", + cmd=e.cmd, + output=e.output, + returncode=e.returncode + ) + exception = e + overlay_initialized = False + except Exception: + cloudlog.exception("uncaught updated exception, shouldn't happen") params.put("UpdateFailedCount", str(update_failed_count)) - wait_between_updates(wait_helper.ready_event) - if wait_helper.shutdown: - break + if exception is None: + params.delete("LastUpdateException") + else: + params.put("LastUpdateException", f"command failed: {exception.cmd}\n{exception.output}") + + # Wait 10 minutes between update attempts + wait_helper.sleep(60*10) - # We've been signaled to shut down dismount_ovfs() if __name__ == "__main__": diff --git a/selfdrive/version.py b/selfdrive/version.py index b45fe384bd..4fec0b4cc7 100644 --- a/selfdrive/version.py +++ b/selfdrive/version.py @@ -1,81 +1,92 @@ #!/usr/bin/env python3 import os import subprocess +from common.basedir import BASEDIR from selfdrive.swaglog import cloudlog -def get_git_commit(default=None): +def run_cmd(cmd): + return subprocess.check_output(cmd, encoding='utf8').strip() + + +def run_cmd_default(cmd, default=None): try: - return subprocess.check_output(["git", "rev-parse", "HEAD"], encoding='utf8').strip() + return run_cmd(cmd) except subprocess.CalledProcessError: return default +def get_git_commit(branch="HEAD", default=None): + return run_cmd_default(["git", "rev-parse", branch], default=default) + + def get_git_branch(default=None): - try: - return subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"], encoding='utf8').strip() - except subprocess.CalledProcessError: - return default + return run_cmd_default(["git", "rev-parse", "--abbrev-ref", "HEAD"], default=default) def get_git_full_branchname(default=None): - try: - return subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"], encoding='utf8').strip() - except subprocess.CalledProcessError: - return default + return run_cmd_default(["git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"], default=default) def get_git_remote(default=None): try: - local_branch = subprocess.check_output(["git", "name-rev", "--name-only", "HEAD"], encoding='utf8').strip() - tracking_remote = subprocess.check_output(["git", "config", "branch." + local_branch + ".remote"], encoding='utf8').strip() - return subprocess.check_output(["git", "config", "remote." + tracking_remote + ".url"], encoding='utf8').strip() - - except subprocess.CalledProcessError: - try: - # Not on a branch, fallback - return subprocess.check_output(["git", "config", "--get", "remote.origin.url"], encoding='utf8').strip() - except subprocess.CalledProcessError: - return default + local_branch = run_cmd(["git", "name-rev", "--name-only", "HEAD"]) + tracking_remote = run_cmd(["git", "config", "branch." + local_branch + ".remote"]) + return run_cmd(["git", "config", "remote." + tracking_remote + ".url"]) + except subprocess.CalledProcessError: # Not on a branch, fallback + return run_cmd_default(["git", "config", "--get", "remote.origin.url"], default=default) with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "common", "version.h")) as _versionf: version = _versionf.read().split('"')[1] +prebuilt = os.path.exists(os.path.join(BASEDIR, 'prebuilt')) + training_version = b"0.2.0" terms_version = b"2" dirty = True +comma_remote = False +tested_branch = False origin = get_git_remote() branch = get_git_full_branchname() -try: - # This is needed otherwise touched files might show up as modified +if (origin is not None) and (branch is not None): try: - subprocess.check_call(["git", "update-index", "--refresh"]) - except subprocess.CalledProcessError: - pass - - if (origin is not None) and (branch is not None): comma_remote = origin.startswith('git@github.com:commaai') or origin.startswith('https://github.com/commaai') - - dirty = not comma_remote + tested_branch = get_git_branch() in ['devel', 'release2-staging', 'dashcam-staging', 'release2', 'dashcam'] + + dirty = False + + # Actually check dirty files + if not prebuilt: + # This is needed otherwise touched files might show up as modified + try: + subprocess.check_call(["git", "update-index", "--refresh"]) + except subprocess.CalledProcessError: + pass + dirty = (subprocess.call(["git", "diff-index", "--quiet", branch, "--"]) != 0) + + # Log dirty files + if dirty and comma_remote: + try: + dirty_files = run_cmd(["git", "diff-index", branch, "--"]) + cloudlog.event("dirty comma branch", version=version, dirty=dirty, origin=origin, branch=branch, + dirty_files=dirty_files, commit=get_git_commit(), origin_commit=get_git_commit(branch)) + except subprocess.CalledProcessError: + pass + + dirty = dirty or (not comma_remote) dirty = dirty or ('master' in branch) - dirty = dirty or (subprocess.call(["git", "diff-index", "--quiet", branch, "--"]) != 0) - if dirty: - dirty_files = subprocess.check_output(["git", "diff-index", branch, "--"], encoding='utf8') - commit = subprocess.check_output(["git", "rev-parse", "--verify", "HEAD"], encoding='utf8').rstrip() - origin_commit = subprocess.check_output(["git", "rev-parse", "--verify", branch], encoding='utf8').rstrip() - cloudlog.event("dirty comma branch", version=version, dirty=dirty, origin=origin, branch=branch, dirty_files=dirty_files, commit=commit, origin_commit=origin_commit) - -except subprocess.CalledProcessError: - dirty = True - cloudlog.exception("git subprocess failed while checking dirty") + except subprocess.CalledProcessError: + dirty = True + cloudlog.exception("git subprocess failed while checking dirty") if __name__ == "__main__": print("Dirty: %s" % dirty) print("Version: %s" % version) print("Remote: %s" % origin) - print("Branch %s" % branch) + print("Branch: %s" % branch) + print("Prebuilt: %s" % prebuilt) diff --git a/tools/README.md b/tools/README.md index ea0fd7d83a..9e0965ff6a 100644 --- a/tools/README.md +++ b/tools/README.md @@ -24,152 +24,15 @@ Table of Contents Requirements ============ -openpilot tools and the following setup steps are developed and tested on Ubuntu 16.04, MacOS 10.14.2 and Python 3.7.3. +openpilot tools and the following setup steps are developed and tested on Ubuntu 16.04, MacOS 10.14.2 and Python 3.8.2. Setup ============ - -1. Run ubuntu_setup.sh, make sure everything completed correctly +1. Run `ubuntu_setup.sh` or `mac_setup.sh`, make sure everything completed correctly 2. Compile openpilot by running ```scons``` in the openpilot directory -3. Add some folders to root - ```bash - sudo mkdir /data - sudo mkdir /data/params - sudo chown $USER /data/params - ``` - - -4. Try out some tools! +3. Try out some tools! Tool examples @@ -181,7 +44,7 @@ Replay driving data **Hardware needed**: none -`unlogger.py` replays data collected with [chffrplus](https://github.com/commaai/chffrplus) or [openpilot](https://github.com/commaai/openpilot). +`unlogger.py` replays data collected with [dashcam](https://github.com/commaai/openpilot/tree/dashcam) or [openpilot](https://github.com/commaai/openpilot). Unlogger with remote data: diff --git a/tools/carcontrols/debug_controls.py b/tools/carcontrols/debug_controls.py index 7d13a0b76b..cdb5e3af87 100755 --- a/tools/carcontrols/debug_controls.py +++ b/tools/carcontrols/debug_controls.py @@ -4,7 +4,7 @@ from common.params import Params from copy import copy from cereal import car, log import cereal.messaging as messaging -from selfdrive.car.car_helpers import get_car +from selfdrive.car.car_helpers import get_car, get_one_can from selfdrive.boardd.boardd import can_list_to_can_capnp HwType = log.HealthData.HwType @@ -26,9 +26,9 @@ def steer_thread(): # wait for health and CAN packets hw_type = messaging.recv_one(health).health.hwType - has_relay = hw_type in [HwType.blackPanda, HwType.uno] + has_relay = hw_type in [HwType.blackPanda, HwType.uno, HwType.dos] print("Waiting for CAN messages...") - messaging.get_one_can(logcan) + get_one_can(logcan) CI, CP = get_car(logcan, sendcan, has_relay) Params().put("CarParams", CP.to_bytes()) diff --git a/tools/carcontrols/joystick_test.py b/tools/carcontrols/joystick_test.py index e031fb506f..0d92c70423 100755 --- a/tools/carcontrols/joystick_test.py +++ b/tools/carcontrols/joystick_test.py @@ -1,9 +1,9 @@ #!/usr/bin/env python -import pygame +import pygame # pylint: disable=import-error # Define some colors -BLACK = ( 0, 0, 0) -WHITE = ( 255, 255, 255) +BLACK = ( 0, 0, 0) +WHITE = ( 255, 255, 255) # This is a simple class that will help us print to the screen # It has nothing to do with the joysticks, just outputting the @@ -17,21 +17,21 @@ class TextPrint: textBitmap = self.font.render(textString, True, BLACK) screen.blit(textBitmap, [self.x, self.y]) self.y += self.line_height - + def reset(self): self.x = 10 self.y = 10 self.line_height = 15 - + def indent(self): self.x += 10 - + def unindent(self): self.x -= 10 - + pygame.init() - + # Set the width and height of the screen [width,height] size = [500, 700] screen = pygame.display.set_mode(size) @@ -46,24 +46,23 @@ clock = pygame.time.Clock() # Initialize the joysticks pygame.joystick.init() - + # Get ready to print textPrint = TextPrint() # -------- Main Program Loop ----------- -while done==False: +while not done: # EVENT PROCESSING STEP - for event in pygame.event.get(): # User did something - if event.type == pygame.QUIT: # If user clicked close - done=True # Flag that we are done so we exit this loop - + for event in pygame.event.get(): # User did something + if event.type == pygame.QUIT: # If user clicked close + done = True # Flag that we are done so we exit this loop + # Possible joystick actions: JOYAXISMOTION JOYBALLMOTION JOYBUTTONDOWN JOYBUTTONUP JOYHATMOTION if event.type == pygame.JOYBUTTONDOWN: print("Joystick button pressed.") if event.type == pygame.JOYBUTTONUP: print("Joystick button released.") - - + # DRAWING STEP # First, clear the screen to white. Don't put other drawing commands # above this, or they will be erased with this command. @@ -75,51 +74,49 @@ while done==False: textPrint.printf(screen, "Number of joysticks: {}".format(joystick_count) ) textPrint.indent() - + # For each joystick: joystick = pygame.joystick.Joystick(0) joystick.init() - + textPrint.printf(screen, "Joystick {}".format(0) ) textPrint.indent() - + # Get the name from the OS for the controller/joystick name = joystick.get_name() textPrint.printf(screen, "Joystick name: {}".format(name) ) - + # Usually axis run in pairs, up/down for one, and left/right for # the other. axes = joystick.get_numaxes() textPrint.printf(screen, "Number of axes: {}".format(axes) ) textPrint.indent() - + for i in range( axes ): axis = joystick.get_axis( i ) textPrint.printf(screen, "Axis {} value: {:>6.3f}".format(i, axis) ) textPrint.unindent() - + buttons = joystick.get_numbuttons() textPrint.printf(screen, "Number of buttons: {}".format(buttons) ) textPrint.indent() for i in range( buttons ): button = joystick.get_button( i ) - textPrint.printf(screen, "Button {:>2} value: {}".format(i,button) ) + textPrint.printf(screen, "Button {:>2} value: {}".format(i, button) ) textPrint.unindent() - textPrint.unindent() - # ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT - + # Go ahead and update the screen with what we've drawn. pygame.display.flip() # Limit to 20 frames per second clock.tick(20) - + # Close the window and quit. # If you forget this line, the program will 'hang' # on exit if running from IDLE. -pygame.quit () +pygame.quit() diff --git a/tools/carcontrols/joystickd.py b/tools/carcontrols/joystickd.py index b262694e6f..9436dcb4d6 100755 --- a/tools/carcontrols/joystickd.py +++ b/tools/carcontrols/joystickd.py @@ -6,7 +6,7 @@ ### this process needs pygame and can't run on the EON ### -import pygame +import pygame # pylint: disable=import-error import cereal.messaging as messaging def joystick_thread(): @@ -30,8 +30,8 @@ def joystick_thread(): # -------- Main Program Loop ----------- while True: # EVENT PROCESSING STEP - for event in pygame.event.get(): # User did something - if event.type == pygame.QUIT: # If user clicked close + for event in pygame.event.get(): # User did something + if event.type == pygame.QUIT: # If user clicked close pass # Available joystick events: JOYAXISMOTION JOYBALLMOTION JOYBUTTONDOWN JOYBUTTONUP JOYHATMOTION if event.type == pygame.JOYBUTTONDOWN: diff --git a/tools/lib/auth.py b/tools/lib/auth.py index 57e0eb0ae4..b91eb3f7b0 100755 --- a/tools/lib/auth.py +++ b/tools/lib/auth.py @@ -5,9 +5,10 @@ from http.server import HTTPServer, BaseHTTPRequestHandler from urllib.parse import urlencode, parse_qs from tools.lib.api import CommaApi, APIError from tools.lib.auth_config import set_token +from typing import Dict, Any class ClientRedirectServer(HTTPServer): - query_params = {} + query_params: Dict[str, Any] = {} class ClientRedirectHandler(BaseHTTPRequestHandler): def do_GET(self): @@ -24,7 +25,7 @@ class ClientRedirectHandler(BaseHTTPRequestHandler): self.end_headers() self.wfile.write(b'Return to the CLI to continue') - def log_message(self, format, *args): + def log_message(self, format, *args): # pylint: disable=redefined-builtin pass # this prevent http server from dumping messages to stdout def auth_redirect_link(port): diff --git a/tools/lib/auth_config.py b/tools/lib/auth_config.py index 68bd535993..0cc3e33b51 100644 --- a/tools/lib/auth_config.py +++ b/tools/lib/auth_config.py @@ -1,11 +1,15 @@ import json import os +from common.android import ANDROID from common.file_helpers import mkdirs_exists_ok class MissingAuthConfigError(Exception): pass -CONFIG_DIR = os.path.expanduser('~/.comma') +if ANDROID: + CONFIG_DIR = "/tmp/.comma" +else: + CONFIG_DIR = os.path.expanduser('~/.comma') mkdirs_exists_ok(CONFIG_DIR) def get_token(): @@ -13,7 +17,7 @@ def get_token(): with open(os.path.join(CONFIG_DIR, 'auth.json')) as f: auth = json.load(f) return auth['access_token'] - except: + except Exception: raise MissingAuthConfigError('Authenticate with tools/lib/auth.py') def set_token(token): diff --git a/tools/lib/filereader.py b/tools/lib/filereader.py index c68462a08c..826bce5fdf 100644 --- a/tools/lib/filereader.py +++ b/tools/lib/filereader.py @@ -1,4 +1,10 @@ -from common.url_file import URLFile +import os + +if "COMMA_PARALLEL_DOWNLOADS" in os.environ: + from tools.lib.url_file_parallel import URLFileParallel as URLFile +else: + from tools.lib.url_file import URLFile # type: ignore + def FileReader(fn, debug=False): if fn.startswith("http://") or fn.startswith("https://"): diff --git a/tools/lib/framereader.py b/tools/lib/framereader.py index 87c6d6e944..d1b7acf72e 100644 --- a/tools/lib/framereader.py +++ b/tools/lib/framereader.py @@ -1,52 +1,51 @@ -import os -import sys +# pylint: skip-file import json +import os +import pickle +import queue import struct +import subprocess import tempfile import threading -import xml.etree.ElementTree as ET -import numpy as np -if sys.version_info >= (3,0): - import queue - import pickle - from io import BytesIO as StringIO -else: - import Queue as queue - import cPickle as pickle - from cStringIO import StringIO +from functools import wraps -import subprocess +import numpy as np from aenum import Enum from lru import LRU -from functools import wraps +import _io from tools.lib.cache import cache_path_for_file_path from tools.lib.exceptions import DataUnreadableError +from tools.lib.file_helpers import atomic_write_in_dir + try: from xx.chffr.lib.filereader import FileReader except ImportError: from tools.lib.filereader import FileReader -from tools.lib.file_helpers import atomic_write_in_dir -from tools.lib.mkvparse import mkvindex -from tools.lib.route import Route - -H264_SLICE_P = 0 -H264_SLICE_B = 1 -H264_SLICE_I = 2 HEVC_SLICE_B = 0 HEVC_SLICE_P = 1 HEVC_SLICE_I = 2 -SLICE_I = 2 # hevc and h264 are the same :) + +class GOPReader: + def get_gop(self, num): + # returns (start_frame_num, num_frames, frames_to_skip, gop_data) + raise NotImplementedError + + +class DoNothingContextManager: + def __enter__(self): + return self + + def __exit__(self, *x): + pass + class FrameType(Enum): raw = 1 h265_stream = 2 - h264_mp4 = 3 - h264_pstream = 4 - ffv1_mkv = 5 - ffvhuff_mkv = 6 + def fingerprint_video(fn): with FileReader(fn) as f: @@ -58,30 +57,24 @@ def fingerprint_video(fn): elif header == b"\x00\x00\x00\x01": if 'hevc' in fn: return FrameType.h265_stream - elif os.path.basename(fn) in ("camera", "acamera"): - return FrameType.h264_pstream else: raise NotImplementedError(fn) - elif header == b"\x00\x00\x00\x1c": - return FrameType.h264_mp4 - elif header == b"\x1a\x45\xdf\xa3": - return FrameType.ffv1_mkv else: raise NotImplementedError(fn) def ffprobe(fn, fmt=None): cmd = ["ffprobe", - "-v", "quiet", - "-print_format", "json", - "-show_format", "-show_streams"] + "-v", "quiet", + "-print_format", "json", + "-show_format", "-show_streams"] if fmt: cmd += ["-f", fmt] cmd += [fn] try: ffprobe_output = subprocess.check_output(cmd) - except subprocess.CalledProcessError as e: + except subprocess.CalledProcessError: raise DataUnreadableError(fn) return json.loads(ffprobe_output) @@ -91,13 +84,13 @@ def vidindex(fn, typ): vidindex_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "vidindex") vidindex = os.path.join(vidindex_dir, "vidindex") - subprocess.check_call(["make"], cwd=vidindex_dir, stdout=open("/dev/null","w")) + subprocess.check_call(["make"], cwd=vidindex_dir, stdout=open("/dev/null", "w")) with tempfile.NamedTemporaryFile() as prefix_f, \ tempfile.NamedTemporaryFile() as index_f: try: subprocess.check_call([vidindex, typ, fn, prefix_f.name, index_f.name]) - except subprocess.CalledProcessError as e: + except subprocess.CalledProcessError: raise DataUnreadableError("vidindex failed on file %s" % fn) with open(index_f.name, "rb") as f: index = f.read() @@ -135,9 +128,10 @@ def cache_fn(func): return cache_inner + @cache_fn def index_stream(fn, typ): - assert typ in ("hevc", "h264") + assert typ in ("hevc", ) with FileReader(fn) as f: assert os.path.exists(f.name), fn @@ -150,22 +144,6 @@ def index_stream(fn, typ): 'probe': probe } -@cache_fn -def index_mp4(fn): - with FileReader(fn) as f: - return vidindex_mp4(f.name) - -@cache_fn -def index_mkv(fn): - with FileReader(fn) as f: - probe = ffprobe(f.name, "matroska") - with open(f.name, "rb") as d_f: - config_record, index = mkvindex.mkvindex(d_f) - return { - 'probe': probe, - 'config_record': config_record, - 'index': index - } def index_videos(camera_paths, cache_prefix=None): """Requires that paths in camera_paths are contiguous and of the same type.""" @@ -173,11 +151,9 @@ def index_videos(camera_paths, cache_prefix=None): raise ValueError("must provide at least one video to index") frame_type = fingerprint_video(camera_paths[0]) - if frame_type == FrameType.h264_pstream: - index_pstream(camera_paths, "h264", cache_prefix) - else: - for fn in camera_paths: - index_video(fn, frame_type, cache_prefix) + for fn in camera_paths: + index_video(fn, frame_type, cache_prefix) + def index_video(fn, frame_type=None, cache_prefix=None): cache_path = cache_path_for_file_path(fn, cache_prefix) @@ -188,20 +164,11 @@ def index_video(fn, frame_type=None, cache_prefix=None): if frame_type is None: frame_type = fingerprint_video(fn[0]) - if frame_type == FrameType.h264_pstream: - #hack: try to index the whole route now - route = Route.from_file_path(fn) - - camera_paths = route.camera_paths() - if fn not in camera_paths: - raise DataUnreadableError("Not a contiguous route camera file: {}".format(fn)) - - print("no pstream cache for %s, indexing route %s now" % (fn, route.name)) - index_pstream(route.camera_paths(), "h264", cache_prefix) - elif frame_type == FrameType.h265_stream: + if frame_type == FrameType.h265_stream: index_stream(fn, "hevc", cache_prefix=cache_prefix) - elif frame_type == FrameType.h264_mp4: - index_mp4(fn, cache_prefix=cache_prefix) + else: + raise NotImplementedError("Only h265 supported") + def get_video_index(fn, frame_type, cache_prefix=None): cache_path = cache_path_for_file_path(fn, cache_prefix) @@ -214,204 +181,6 @@ def get_video_index(fn, frame_type, cache_prefix=None): with open(cache_path, "rb") as cache_file: return pickle.load(cache_file) -def pstream_predecompress(fns, probe, indexes, global_prefix, cache_prefix, multithreaded=False): - assert len(fns) == len(indexes) - out_fns = [cache_path_for_file_path(fn, cache_prefix, extension=".predecom.mkv") for fn in fns] - out_exists = map(os.path.exists, out_fns) - if all(out_exists): - return - - w = probe['streams'][0]['width'] - h = probe['streams'][0]['height'] - - frame_size = w*h*3/2 # yuv420p - - decompress_proc = subprocess.Popen( - ["ffmpeg", - "-threads", "0" if multithreaded else "1", - "-vsync", "0", - "-f", "h264", - "-i", "pipe:0", - "-threads", "0" if multithreaded else "1", - "-f", "rawvideo", - "-pix_fmt", "yuv420p", - "pipe:1"], - stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=open("/dev/null", "wb")) - - def write_thread(): - for fn in fns: - with FileReader(fn) as f: - decompress_proc.stdin.write(f.read()) - decompress_proc.stdin.close() - - def read_frame(): - frame = None - try: - frame = decompress_proc.stdout.read(frame_size) - except (IOError, ValueError): - pass - if frame is None or frame == "" or len(frame) != frame_size: - raise DataUnreadableError("pre-decompression failed for %s" % fn) - return frame - - t = threading.Thread(target=write_thread) - t.daemon = True - t.start() - - try: - for fn, out_fn, out_exist, index in zip(fns, out_fns, out_exists, indexes): - if out_exist: - for fi in range(index.shape[0]-1): - read_frame() - continue - - with atomic_write_in_dir(out_fn, mode="w+b", overwrite=True) as out_tmp: - compress_proc = subprocess.Popen( - ["ffmpeg", - "-threads", "0" if multithreaded else "1", - "-y", - "-vsync", "0", - "-f", "rawvideo", - "-pix_fmt", "yuv420p", - "-s", "%dx%d" % (w, h), - "-i", "pipe:0", - "-threads", "0" if multithreaded else "1", - "-f", "matroska", - "-vcodec", "ffv1", - "-g", "0", - out_tmp.name], - stdin=subprocess.PIPE, stderr=open("/dev/null", "wb")) - try: - for fi in range(index.shape[0]-1): - frame = read_frame() - compress_proc.stdin.write(frame) - compress_proc.stdin.close() - except: - compress_proc.kill() - raise - - assert compress_proc.wait() == 0 - - cache_path = cache_path_for_file_path(fn, cache_prefix) - with atomic_write_in_dir(cache_path, mode="wb", overwrite=True) as cache_file: - pickle.dump({ - 'predecom': os.path.basename(out_fn), - 'index': index, - 'probe': probe, - 'global_prefix': global_prefix, - }, cache_file, -1) - - except: - decompress_proc.kill() - raise - finally: - t.join() - - rc = decompress_proc.wait() - if rc != 0: - raise DataUnreadableError(fns[0]) - - -def index_pstream(fns, typ, cache_prefix=None): - if typ != "h264": - raise NotImplementedError(typ) - - if not fns: - raise DataUnreadableError("chffr h264 requires contiguous files") - - out_fns = [cache_path_for_file_path(fn, cache_prefix) for fn in fns] - out_exists = map(os.path.exists, out_fns) - if all(out_exists): return - - # load existing index files to avoid re-doing work - existing_indexes = [] - for out_fn, exists in zip(out_fns, out_exists): - existing = None - if exists: - with open(out_fn, "rb") as cache_file: - existing = pickle.load(cache_file) - existing_indexes.append(existing) - - # probe the first file - if existing_indexes[0]: - probe = existing_indexes[0]['probe'] - else: - with FileReader(fns[0]) as f: - probe = ffprobe(f.name, typ) - - global_prefix = None - - # get the video index of all the segments in this stream - indexes = [] - for i, fn in enumerate(fns): - if existing_indexes[i]: - index = existing_indexes[i]['index'] - prefix = existing_indexes[i]['global_prefix'] - else: - with FileReader(fn) as f: - index, prefix = vidindex(f.name, typ) - if i == 0: - # assert prefix - if not prefix: - raise DataUnreadableError("vidindex failed for %s" % fn) - global_prefix = prefix - indexes.append(index) - - assert global_prefix - - if np.sum(indexes[0][:, 0] == H264_SLICE_I) <= 1: - print("pstream %s is unseekable. pre-decompressing all the segments..." % (fns[0])) - pstream_predecompress(fns, probe, indexes, global_prefix, cache_prefix) - return - - # generate what's required to make each segment self-contained - # (the partial GOP from the end of each segments are put asside to add - # to the start of the following segment) - prefix_data = ["" for _ in fns] - prefix_index = [[] for _ in fns] - for i in range(len(fns)-1): - if indexes[i+1][0, 0] == H264_SLICE_I and indexes[i+1][0, 1] <= 1: - # next file happens to start with a i-frame, dont need use this file's end - continue - - index = indexes[i] - if i == 0 and np.sum(index[:, 0] == H264_SLICE_I) <= 1: - raise NotImplementedError("No I-frames in pstream.") - - # find the last GOP in the index - frame_b = len(index)-1 - while frame_b > 0 and index[frame_b, 0] != H264_SLICE_I: - frame_b -= 1 - - assert frame_b >= 0 - assert index[frame_b, 0] == H264_SLICE_I - - end_len = len(index)-frame_b - - with FileReader(fns[i]) as vid: - vid.seek(index[frame_b, 1]) - end_data = vid.read() - - prefix_data[i+1] = end_data - prefix_index[i+1] = index[frame_b:-1] - # indexes[i] = index[:frame_b] - - for i, fn in enumerate(fns): - cache_path = out_fns[i] - - if os.path.exists(cache_path): - continue - - segment_index = { - 'index': indexes[i], - 'global_prefix': global_prefix, - 'probe': probe, - 'prefix_frame_data': prefix_data[i], # data to prefix the first GOP with - 'num_prefix_frames': len(prefix_index[i]), # number of frames to skip in the first GOP - } - - with atomic_write_in_dir(cache_path, mode="wb", overwrite=True) as cache_file: - pickle.dump(segment_index, cache_file, -1) def read_file_check_size(f, sz, cookie): buff = bytearray(sz) @@ -420,118 +189,69 @@ def read_file_check_size(f, sz, cookie): return buff -import signal -import ctypes -def _set_pdeathsig(sig=signal.SIGTERM): - def f(): - libc = ctypes.CDLL('libc.so.6') - return libc.prctl(1, sig) - return f - -def vidindex_mp4(fn): - try: - xmls = subprocess.check_output(["MP4Box", fn, "-diso", "-out", "/dev/stdout"]) - except subprocess.CalledProcessError as e: - raise DataUnreadableError(fn) - - tree = ET.fromstring(xmls) - - def parse_content(s): - assert s.startswith("data:application/octet-string,") - return s[len("data:application/octet-string,"):].decode("hex") - - avc_element = tree.find(".//AVCSampleEntryBox") - width = int(avc_element.attrib['Width']) - height = int(avc_element.attrib['Height']) +def rgb24toyuv420(rgb): + yuv_from_rgb = np.array([[ 0.299 , 0.587 , 0.114 ], + [-0.14714119, -0.28886916, 0.43601035 ], + [ 0.61497538, -0.51496512, -0.10001026 ]]) + img = np.dot(rgb.reshape(-1, 3), yuv_from_rgb.T).reshape(rgb.shape) - sps_element = avc_element.find(".//AVCDecoderConfigurationRecord/SequenceParameterSet") - pps_element = avc_element.find(".//AVCDecoderConfigurationRecord/PictureParameterSet") + y_len = img.shape[0] * img.shape[1] + uv_len = y_len / 4 - sps = parse_content(sps_element.attrib['content']) - pps = parse_content(pps_element.attrib['content']) + ys = img[:, :, 0] + us = (img[::2, ::2, 1] + img[1::2, ::2, 1] + img[::2, 1::2, 1] + img[1::2, 1::2, 1]) / 4 + 128 + vs = (img[::2, ::2, 2] + img[1::2, ::2, 2] + img[::2, 1::2, 2] + img[1::2, 1::2, 2]) / 4 + 128 - media_header = tree.find("MovieBox/TrackBox/MediaBox/MediaHeaderBox") - time_scale = int(media_header.attrib['TimeScale']) + yuv420 = np.empty(y_len + 2 * uv_len, dtype=img.dtype) + yuv420[:y_len] = ys.reshape(-1) + yuv420[y_len:y_len + uv_len] = us.reshape(-1) + yuv420[y_len + uv_len:y_len + 2 * uv_len] = vs.reshape(-1) - sample_sizes = [ - int(entry.attrib['Size']) for entry in tree.findall( - "MovieBox/TrackBox/MediaBox/MediaInformationBox/SampleTableBox/SampleSizeBox/SampleSizeEntry") - ] + return yuv420.clip(0, 255).astype('uint8') - sample_dependency = [ - entry.attrib['dependsOnOther'] == "yes" for entry in tree.findall( - "MovieBox/TrackBox/MediaBox/MediaInformationBox/SampleTableBox/SampleDependencyTypeBox/SampleDependencyEntry") - ] - assert len(sample_sizes) == len(sample_dependency) +def decompress_video_data(rawdat, vid_fmt, w, h, pix_fmt): + # using a tempfile is much faster than proc.communicate for some reason - chunk_offsets = [ - int(entry.attrib['offset']) for entry in tree.findall( - "MovieBox/TrackBox/MediaBox/MediaInformationBox/SampleTableBox/ChunkOffsetBox/ChunkEntry") - ] + with tempfile.TemporaryFile() as tmpf: + tmpf.write(rawdat) + tmpf.seek(0) - sample_chunk_table = [ - (int(entry.attrib['FirstChunk'])-1, int(entry.attrib['SamplesPerChunk'])) for entry in tree.findall( - "MovieBox/TrackBox/MediaBox/MediaInformationBox/SampleTableBox/SampleToChunkBox/SampleToChunkEntry") - ] + threads = os.getenv("FFMPEG_THREADS", "0") + cuda = os.getenv("FFMPEG_CUDA", "0") == "1" + proc = subprocess.Popen( + ["ffmpeg", + "-threads", threads, + "-hwaccel", "none" if not cuda else "cuda", + "-c:v", "hevc", + "-vsync", "0", + "-f", vid_fmt, + "-flags2", "showall", + "-i", "pipe:0", + "-threads", threads, + "-f", "rawvideo", + "-pix_fmt", pix_fmt, + "pipe:1"], + stdin=tmpf, stdout=subprocess.PIPE, stderr=open("/dev/null")) - sample_offsets = [None for _ in sample_sizes] + # dat = proc.communicate()[0] + dat = proc.stdout.read() + if proc.wait() != 0: + raise DataUnreadableError("ffmpeg failed") - sample_i = 0 - for i, (first_chunk, samples_per_chunk) in enumerate(sample_chunk_table): - if i == len(sample_chunk_table)-1: - last_chunk = len(chunk_offsets)-1 - else: - last_chunk = sample_chunk_table[i+1][0]-1 - for k in range(first_chunk, last_chunk+1): - sample_offset = chunk_offsets[k] - for _ in range(samples_per_chunk): - sample_offsets[sample_i] = sample_offset - sample_offset += sample_sizes[sample_i] - sample_i += 1 - - assert sample_i == len(sample_sizes) - - pts_offset_table = [ - ( int(entry.attrib['CompositionOffset']), int(entry.attrib['SampleCount']) ) for entry in tree.findall( - "MovieBox/TrackBox/MediaBox/MediaInformationBox/SampleTableBox/CompositionOffsetBox/CompositionOffsetEntry") - ] - sample_pts_offset = [0 for _ in sample_sizes] - sample_i = 0 - for dt, count in pts_offset_table: - for _ in range(count): - sample_pts_offset[sample_i] = dt - sample_i += 1 - - sample_time_table = [ - ( int(entry.attrib['SampleDelta']), int(entry.attrib['SampleCount']) ) for entry in tree.findall( - "MovieBox/TrackBox/MediaBox/MediaInformationBox/SampleTableBox/TimeToSampleBox/TimeToSampleEntry") - ] - sample_time = [None for _ in sample_sizes] - cur_ts = 0 - sample_i = 0 - for dt, count in sample_time_table: - for _ in range(count): - sample_time[sample_i] = (cur_ts + sample_pts_offset[sample_i]) * 1000 / time_scale - - cur_ts += dt - sample_i += 1 - - sample_time.sort() # because we ony decode GOPs in PTS order + if pix_fmt == "rgb24": + ret = np.frombuffer(dat, dtype=np.uint8).reshape(-1, h, w, 3) + elif pix_fmt == "yuv420p": + ret = np.frombuffer(dat, dtype=np.uint8).reshape(-1, (h*w*3//2)) + elif pix_fmt == "yuv444p": + ret = np.frombuffer(dat, dtype=np.uint8).reshape(-1, 3, h, w) + else: + raise NotImplementedError - return { - 'width': width, - 'height': height, - 'sample_offsets': sample_offsets, - 'sample_sizes': sample_sizes, - 'sample_dependency': sample_dependency, - 'sample_time': sample_time, - 'sps': sps, - 'pps': pps - } + return ret -class BaseFrameReader(object): +class BaseFrameReader: # properties: frame_type, frame_count, w, h def __enter__(self): @@ -546,48 +266,20 @@ class BaseFrameReader(object): def get(self, num, count=1, pix_fmt="yuv420p"): raise NotImplementedError -def FrameReader(fn, cache_prefix=None, readahead=False, readbehind=False, multithreaded=True, index_data=None): + +def FrameReader(fn, cache_prefix=None, readahead=False, readbehind=False, index_data=None): frame_type = fingerprint_video(fn) if frame_type == FrameType.raw: return RawFrameReader(fn) - elif frame_type in (FrameType.h265_stream, FrameType.h264_pstream): + elif frame_type in (FrameType.h265_stream,): if not index_data: index_data = get_video_index(fn, frame_type, cache_prefix) - if index_data is not None and "predecom" in index_data: - cache_path = cache_path_for_file_path(fn, cache_prefix) - return MKVFrameReader( - os.path.join(os.path.dirname(cache_path), index_data["predecom"])) - else: - return StreamFrameReader(fn, frame_type, index_data, - readahead=readahead, readbehind=readbehind, multithreaded=multithreaded) - elif frame_type == FrameType.h264_mp4: - return MP4FrameReader(fn, readahead=readahead) - elif frame_type == FrameType.ffv1_mkv: - return MKVFrameReader(fn) + return StreamFrameReader(fn, frame_type, index_data, readahead=readahead, readbehind=readbehind) else: raise NotImplementedError(frame_type) -def rgb24toyuv420(rgb): - yuv_from_rgb = np.array([[ 0.299 , 0.587 , 0.114 ], - [-0.14714119, -0.28886916, 0.43601035 ], - [ 0.61497538, -0.51496512, -0.10001026 ]]) - img = np.dot(rgb.reshape(-1, 3), yuv_from_rgb.T).reshape(rgb.shape) - y_len = img.shape[0] * img.shape[1] - uv_len = y_len / 4 - - ys = img[:, :, 0] - us = (img[::2, ::2, 1] + img[1::2, ::2, 1] + img[::2, 1::2, 1] + img[1::2, 1::2, 1]) / 4 + 128 - vs = (img[::2, ::2, 2] + img[1::2, ::2, 2] + img[::2, 1::2, 2] + img[1::2, 1::2, 2]) / 4 + 128 - - yuv420 = np.empty(y_len + 2 * uv_len, dtype=img.dtype) - yuv420[:y_len] = ys.reshape(-1) - yuv420[y_len:y_len + uv_len] = us.reshape(-1) - yuv420[y_len + uv_len:y_len + 2 * uv_len] = vs.reshape(-1) - - return yuv420.clip(0,255).astype('uint8') - -class RawData(object): +class RawData: def __init__(self, f): self.f = _io.FileIO(f, 'rb') self.lenn = struct.unpack("I", self.f.read(4))[0] @@ -597,6 +289,7 @@ class RawData(object): self.f.seek((self.lenn+4)*i + 4) return self.f.read(self.lenn) + class RawFrameReader(BaseFrameReader): def __init__(self, fn): # raw camera @@ -608,12 +301,9 @@ class RawFrameReader(BaseFrameReader): def load_and_debayer(self, img): img = np.frombuffer(img, dtype='uint8').reshape(960, 1280) - cimg = np.dstack([img[0::2, 1::2], ( - (img[0::2, 0::2].astype("uint16") + img[1::2, 1::2].astype("uint16")) - >> 1).astype("uint8"), img[1::2, 0::2]]) + cimg = np.dstack([img[0::2, 1::2], ((img[0::2, 0::2].astype("uint16") + img[1::2, 1::2].astype("uint16")) >> 1).astype("uint8"), img[1::2, 0::2]]) return cimg - def get(self, num, count=1, pix_fmt="yuv420p"): assert self.frame_count is not None assert num+count <= self.frame_count @@ -634,51 +324,16 @@ class RawFrameReader(BaseFrameReader): return app -def decompress_video_data(rawdat, vid_fmt, w, h, pix_fmt, multithreaded=False): - # using a tempfile is much faster than proc.communicate for some reason - - with tempfile.TemporaryFile() as tmpf: - tmpf.write(rawdat) - tmpf.seek(0) - proc = subprocess.Popen( - ["ffmpeg", - "-threads", "0" if multithreaded else "1", - "-vsync", "0", - "-f", vid_fmt, - "-flags2", "showall", - "-i", "pipe:0", - "-threads", "0" if multithreaded else "1", - "-f", "rawvideo", - "-pix_fmt", pix_fmt, - "pipe:1"], - stdin=tmpf, stdout=subprocess.PIPE, stderr=open("/dev/null")) - - # dat = proc.communicate()[0] - dat = proc.stdout.read() - if proc.wait() != 0: - raise DataUnreadableError("ffmpeg failed") - - if pix_fmt == "rgb24": - ret = np.frombuffer(dat, dtype=np.uint8).reshape(-1, h, w, 3) - elif pix_fmt == "yuv420p": - ret = np.frombuffer(dat, dtype=np.uint8).reshape(-1, (h*w*3//2)) - elif pix_fmt == "yuv444p": - ret = np.frombuffer(dat, dtype=np.uint8).reshape(-1, 3, h, w) - else: - raise NotImplementedError - - return ret - -class VideoStreamDecompressor(object): - def __init__(self, vid_fmt, w, h, pix_fmt, multithreaded=False): +class VideoStreamDecompressor: + def __init__(self, vid_fmt, w, h, pix_fmt): self.vid_fmt = vid_fmt self.w = w self.h = h self.pix_fmt = pix_fmt if pix_fmt == "yuv420p": - self.out_size = w*h*3//2 # yuv420p + self.out_size = w*h*3//2 # yuv420p elif pix_fmt in ("rgb24", "yuv444p"): self.out_size = w*h*3 else: @@ -686,9 +341,13 @@ class VideoStreamDecompressor(object): self.out_q = queue.Queue() + threads = os.getenv("FFMPEG_THREADS", "0") + cuda = os.getenv("FFMPEG_CUDA", "0") == "1" self.proc = subprocess.Popen( ["ffmpeg", - "-threads", "0" if multithreaded else "1", + "-threads", threads, + "-hwaccel", "none" if not cuda else "cuda", + "-c:v", "hevc", # "-avioflags", "direct", "-analyzeduration", "0", "-probesize", "32", @@ -697,7 +356,7 @@ class VideoStreamDecompressor(object): "-vsync", "0", "-f", vid_fmt, "-i", "pipe:0", - "-threads", "0" if multithreaded else "1", + "-threads", threads, "-f", "rawvideo", "-pix_fmt", pix_fmt, "pipe:1"], @@ -749,65 +408,82 @@ class VideoStreamDecompressor(object): assert self.proc.wait() == 0 -class MKVFrameReader(BaseFrameReader): - def __init__(self, fn): +class StreamGOPReader(GOPReader): + def __init__(self, fn, frame_type, index_data): + assert frame_type == FrameType.h265_stream + self.fn = fn - #print("MKVFrameReader", fn) - index_data = index_mkv(fn) - stream = index_data['probe']['streams'][0] - self.w = stream['width'] - self.h = stream['height'] + self.frame_type = frame_type + self.frame_count = None + self.w, self.h = None, None - if stream['codec_name'] == 'ffv1': - self.frame_type = FrameType.ffv1_mkv - elif stream['codec_name'] == 'ffvhuff': - self.frame_type = FrameType.ffvhuff_mkv - else: - raise NotImplementedError + self.prefix = None + self.index = None - self.config_record = index_data['config_record'] self.index = index_data['index'] + self.prefix = index_data['global_prefix'] + probe = index_data['probe'] - self.frame_count = len(self.index) + self.prefix_frame_data = None + self.num_prefix_frames = 0 + self.vid_fmt = "hevc" - def get(self, num, count=1, pix_fmt="yuv420p"): - assert 0 < num+count <= self.frame_count + i = 0 + while i < self.index.shape[0] and self.index[i, 0] != HEVC_SLICE_I: + i += 1 + self.first_iframe = i - frame_dats = [] - with FileReader(self.fn) as f: - for i in range(num, num+count): - pos, length, _ = self.index[i] - f.seek(pos) - frame_dats.append(f.read(length)) + assert self.first_iframe == 0 + + self.frame_count = len(self.index) - 1 + + self.w = probe['streams'][0]['width'] + self.h = probe['streams'][0]['height'] - of = StringIO() - mkvindex.simple_gen(of, self.config_record, self.w, self.h, frame_dats) + def _lookup_gop(self, num): + frame_b = num + while frame_b > 0 and self.index[frame_b, 0] != HEVC_SLICE_I: + frame_b -= 1 - r = decompress_video_data(of.getvalue(), "matroska", self.w, self.h, pix_fmt) - assert len(r) == count + frame_e = num + 1 + while frame_e < (len(self.index) - 1) and self.index[frame_e, 0] != HEVC_SLICE_I: + frame_e += 1 - return r + offset_b = self.index[frame_b, 1] + offset_e = self.index[frame_e, 1] + return (frame_b, frame_e, offset_b, offset_e) -class GOPReader(object): def get_gop(self, num): - # returns (start_frame_num, num_frames, frames_to_skip, gop_data) - raise NotImplementedError + frame_b, frame_e, offset_b, offset_e = self._lookup_gop(num) + assert frame_b <= num < frame_e + + num_frames = frame_e - frame_b + + with FileReader(self.fn) as f: + f.seek(offset_b) + rawdat = f.read(offset_e - offset_b) + + if num < self.first_iframe: + assert self.prefix_frame_data + rawdat = self.prefix_frame_data + rawdat + + rawdat = self.prefix + rawdat + skip_frames = 0 + if num < self.first_iframe: + skip_frames = self.num_prefix_frames -class DoNothingContextManager(object): - def __enter__(self): return self - def __exit__(*x): pass + return frame_b, num_frames, skip_frames, rawdat class GOPFrameReader(BaseFrameReader): #FrameReader with caching and readahead for formats that are group-of-picture based - def __init__(self, readahead=False, readbehind=False, multithreaded=True): + def __init__(self, readahead=False, readbehind=False): self.open_ = True - self.multithreaded = multithreaded self.readahead = readahead self.readbehind = readbehind self.frame_cache = LRU(64) @@ -849,10 +525,10 @@ class GOPFrameReader(BaseFrameReader): num, pix_fmt = self.readahead_last if self.readbehind: - for k in range(num-1, max(0, num-self.readahead_len), -1): + for k in range(num - 1, max(0, num - self.readahead_len), -1): self._get_one(k, pix_fmt) else: - for k in range(num, min(self.frame_count, num+self.readahead_len)): + for k in range(num, min(self.frame_count, num + self.readahead_len)): self._get_one(k, pix_fmt) def _get_one(self, num, pix_fmt): @@ -867,8 +543,7 @@ class GOPFrameReader(BaseFrameReader): frame_b, num_frames, skip_frames, rawdat = self.get_gop(num) - ret = decompress_video_data(rawdat, self.vid_fmt, self.w, self.h, pix_fmt, - multithreaded=self.multithreaded) + ret = decompress_video_data(rawdat, self.vid_fmt, self.w, self.h, pix_fmt) ret = ret[skip_frames:] assert ret.shape[0] == num_frames @@ -896,168 +571,19 @@ class GOPFrameReader(BaseFrameReader): return ret -class MP4GOPReader(GOPReader): - def __init__(self, fn): - self.fn = fn - self.frame_type = FrameType.h264_mp4 - - self.index = index_mp4(fn) - - self.w = self.index['width'] - self.h = self.index['height'] - self.sample_sizes = self.index['sample_sizes'] - self.sample_offsets = self.index['sample_offsets'] - self.sample_dependency = self.index['sample_dependency'] - - self.vid_fmt = "h264" - - self.frame_count = len(self.sample_sizes) - - self.prefix = "\x00\x00\x00\x01"+self.index['sps']+"\x00\x00\x00\x01"+self.index['pps'] - - def _lookup_gop(self, num): - frame_b = num - while frame_b > 0 and self.sample_dependency[frame_b]: - frame_b -= 1 - - frame_e = num+1 - while frame_e < (len(self.sample_dependency)-1) and self.sample_dependency[frame_e]: - frame_e += 1 - - return (frame_b, frame_e) - - def get_gop(self, num): - frame_b, frame_e = self._lookup_gop(num) - assert frame_b <= num < frame_e - - num_frames = frame_e-frame_b - - with FileReader(self.fn) as f: - rawdat = [] - - sample_i = frame_b - while sample_i < frame_e: - size = self.sample_sizes[sample_i] - start_offset = self.sample_offsets[sample_i] - - # try to read contiguously because a read could actually be a http request - sample_i += 1 - while sample_i < frame_e and size < 10000000 and start_offset+size == self.sample_offsets[sample_i]: - size += self.sample_sizes[sample_i] - sample_i += 1 - - f.seek(start_offset) - sampledat = f.read(size) - - # read length-prefixed NALUs and output in Annex-B - i = 0 - while i < len(sampledat): - nal_len, = struct.unpack(">I", sampledat[i:i+4]) - rawdat.append("\x00\x00\x00\x01"+sampledat[i+4:i+4+nal_len]) - i = i+4+nal_len - assert i == len(sampledat) - - rawdat = self.prefix+''.join(rawdat) - - return frame_b, num_frames, 0, rawdat - -class MP4FrameReader(MP4GOPReader, GOPFrameReader): - def __init__(self, fn, readahead=False): - MP4GOPReader.__init__(self, fn) - GOPFrameReader.__init__(self, readahead) - -class StreamGOPReader(GOPReader): - def __init__(self, fn, frame_type, index_data): - self.fn = fn - - self.frame_type = frame_type - self.frame_count = None - self.w, self.h = None, None - - self.prefix = None - self.index = None - - self.index = index_data['index'] - self.prefix = index_data['global_prefix'] - probe = index_data['probe'] - - if self.frame_type == FrameType.h265_stream: - self.prefix_frame_data = None - self.num_prefix_frames = 0 - self.vid_fmt = "hevc" - - elif self.frame_type == FrameType.h264_pstream: - self.prefix_frame_data = index_data['prefix_frame_data'] - self.num_prefix_frames = index_data['num_prefix_frames'] - - self.vid_fmt = "h264" - - i = 0 - while i < self.index.shape[0] and self.index[i, 0] != SLICE_I: - i += 1 - self.first_iframe = i - - if self.frame_type == FrameType.h265_stream: - assert self.first_iframe == 0 - - self.frame_count = len(self.index)-1 - - self.w = probe['streams'][0]['width'] - self.h = probe['streams'][0]['height'] - - - def _lookup_gop(self, num): - frame_b = num - while frame_b > 0 and self.index[frame_b, 0] != SLICE_I: - frame_b -= 1 - - frame_e = num+1 - while frame_e < (len(self.index)-1) and self.index[frame_e, 0] != SLICE_I: - frame_e += 1 - - offset_b = self.index[frame_b, 1] - offset_e = self.index[frame_e, 1] - - return (frame_b, frame_e, offset_b, offset_e) - - def get_gop(self, num): - frame_b, frame_e, offset_b, offset_e = self._lookup_gop(num) - assert frame_b <= num < frame_e - - num_frames = frame_e-frame_b - - with FileReader(self.fn) as f: - f.seek(offset_b) - rawdat = f.read(offset_e-offset_b) - - if num < self.first_iframe: - assert self.prefix_frame_data - rawdat = self.prefix_frame_data + rawdat - - rawdat = self.prefix + rawdat - - skip_frames = 0 - if num < self.first_iframe: - skip_frames = self.num_prefix_frames - - return frame_b, num_frames, skip_frames, rawdat class StreamFrameReader(StreamGOPReader, GOPFrameReader): - def __init__(self, fn, frame_type, index_data, readahead=False, readbehind=False, multithreaded=False): + def __init__(self, fn, frame_type, index_data, readahead=False, readbehind=False): StreamGOPReader.__init__(self, fn, frame_type, index_data) - GOPFrameReader.__init__(self, readahead, readbehind, multithreaded) - + GOPFrameReader.__init__(self, readahead, readbehind) - -def GOPFrameIterator(gop_reader, pix_fmt, multithreaded=True): +def GOPFrameIterator(gop_reader, pix_fmt): # this is really ugly. ill think about how to refactor it when i can think good - IN_FLIGHT_GOPS = 6 # should be enough that the stream decompressor starts returning data - - with VideoStreamDecompressor( - gop_reader.vid_fmt, gop_reader.w, gop_reader.h, pix_fmt, multithreaded) as dec: + IN_FLIGHT_GOPS = 6 # should be enough that the stream decompressor starts returning data + with VideoStreamDecompressor(gop_reader.vid_fmt, gop_reader.w, gop_reader.h, pix_fmt) as dec: read_work = [] def readthing(): @@ -1082,79 +608,21 @@ def GOPFrameIterator(gop_reader, pix_fmt, multithreaded=True): read_work.append([skip_frames, num_frames]) while len(read_work) >= IN_FLIGHT_GOPS: - for v in readthing(): yield v + for v in readthing(): + yield v dec.eos() while read_work: - for v in readthing(): yield v + for v in readthing(): + yield v def FrameIterator(fn, pix_fmt, **kwargs): fr = FrameReader(fn, **kwargs) if isinstance(fr, GOPReader): - for v in GOPFrameIterator(fr, pix_fmt, kwargs.get("multithreaded", True)): yield v + for v in GOPFrameIterator(fr, pix_fmt): + yield v else: for i in range(fr.frame_count): yield fr.get(i, pix_fmt=pix_fmt)[0] - - -def FrameWriter(ofn, frames, vid_fmt=FrameType.ffvhuff_mkv, pix_fmt="rgb24", framerate=20, multithreaded=False): - if pix_fmt not in ("rgb24", "yuv420p"): - raise NotImplementedError - - if vid_fmt == FrameType.ffv1_mkv: - assert ofn.endswith(".mkv") - vcodec = "ffv1" - elif vid_fmt == FrameType.ffvhuff_mkv: - assert ofn.endswith(".mkv") - vcodec = "ffvhuff" - else: - raise NotImplementedError - - frame_gen = iter(frames) - first_frame = next(frame_gen) - - # assert len(frames) > 1 - if pix_fmt == "rgb24": - h, w = first_frame.shape[:2] - elif pix_fmt == "yuv420p": - w = first_frame.shape[1] - h = 2*first_frame.shape[0]//3 - else: - raise NotImplementedError - - compress_proc = subprocess.Popen( - ["ffmpeg", - "-threads", "0" if multithreaded else "1", - "-y", - "-framerate", str(framerate), - "-vsync", "0", - "-f", "rawvideo", - "-pix_fmt", pix_fmt, - "-s", "%dx%d" % (w, h), - "-i", "pipe:0", - "-threads", "0" if multithreaded else "1", - "-f", "matroska", - "-vcodec", vcodec, - "-g", "0", - ofn], - stdin=subprocess.PIPE, stderr=open("/dev/null", "wb")) - try: - compress_proc.stdin.write(first_frame.tobytes()) - for frame in frame_gen: - compress_proc.stdin.write(frame.tobytes()) - compress_proc.stdin.close() - except: - compress_proc.kill() - raise - - assert compress_proc.wait() == 0 - -if __name__ == "__main__": - fn = "cd:/1c79456b0c90f15a/2017-05-10--08-17-00/2/fcamera.hevc" - f = FrameReader(fn) - # print f.get(0, 1).shape - # print f.get(15, 1).shape - for v in GOPFrameIterator(f, "yuv420p"): - print(v) diff --git a/tools/lib/index_log/index_log.cc b/tools/lib/index_log/index_log.cc index 8eb4a5e34e..ee7c7502db 100644 --- a/tools/lib/index_log/index_log.cc +++ b/tools/lib/index_log/index_log.cc @@ -41,7 +41,6 @@ int main(int argc, char** argv) { auto words = kj::arrayPtr((const capnp::word*)log_data, log_size/sizeof(capnp::word)); while (words.size() > 0) { - uint64_t idx = ((uintptr_t)words.begin() - (uintptr_t)log_data); // printf("%llu - %ld\n", idx, words.size()); const char* idx_bytes = (const char*)&idx; @@ -49,11 +48,9 @@ int main(int argc, char** argv) { try { capnp::FlatArrayMessageReader reader(words); words = kj::arrayPtr(reader.getEnd(), words.end()); - } catch (kj::Exception exc) { + } catch (const kj::Exception& exc) { break; } - - } munmap(log_data, log_size); diff --git a/tools/lib/kbhit.py b/tools/lib/kbhit.py index 30587590a4..69f61d7a26 100644 --- a/tools/lib/kbhit.py +++ b/tools/lib/kbhit.py @@ -1,18 +1,17 @@ #!/usr/bin/env python -import os import sys import termios import atexit from select import select + class KBHit: - def __init__(self): '''Creates a KBHit object that you can call to do various keyboard things. ''' - self.set_kbhit_terminal() - + self.set_kbhit_terminal() + def set_kbhit_terminal(self): # Save the terminal settings self.fd = sys.stdin.fileno() @@ -29,20 +28,14 @@ class KBHit: def set_normal_term(self): ''' Resets to normal terminal. On Windows this is a no-op. ''' - - if os.name == 'nt': - pass - - else: - termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old_term) + termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old_term) def getch(self): ''' Returns a keyboard character after kbhit() has been called. Should not be called in the same program as getarrow(). ''' return sys.stdin.read(1) - def getarrow(self): ''' Returns an arrow-key code after kbhit() has been called. Codes are @@ -52,29 +45,22 @@ class KBHit: 3 : left Should not be called in the same program as getch(). ''' - - if os.name == 'nt': - msvcrt.getch() # skip 0xE0 - c = msvcrt.getch() - vals = [72, 77, 80, 75] - - else: - c = sys.stdin.read(3)[2] - vals = [65, 67, 66, 68] - + + c = sys.stdin.read(3)[2] + vals = [65, 67, 66, 68] + return vals.index(ord(c.decode('utf-8'))) - def kbhit(self): ''' Returns True if keyboard character was hit, False otherwise. - ''' - dr,dw,de = select([sys.stdin], [], [], 0) + ''' + dr, _, _ = select([sys.stdin], [], [], 0) return dr != [] - - -# Test + + +# Test if __name__ == "__main__": - + kb = KBHit() print('Hit any key, or ESC to exit') @@ -83,10 +69,8 @@ if __name__ == "__main__": if kb.kbhit(): c = kb.getch() - if ord(c) == 27: # ESC + if ord(c) == 27: # ESC break print(c) - - kb.set_normal_term() - + kb.set_normal_term() diff --git a/tools/lib/logreader.py b/tools/lib/logreader.py index 3a25ef21bc..4d08b8aaed 100755 --- a/tools/lib/logreader.py +++ b/tools/lib/logreader.py @@ -73,7 +73,8 @@ class MultiLogIterator(object): self._idx += 1 else: self._idx = 0 - self._current_log = next(i for i in range(self._current_log + 1, len(self._log_readers) + 1) if i == len(self._log_readers) or self._log_paths[i] is not None) + self._current_log = next(i for i in range(self._current_log + 1, len(self._log_readers) + 1) + if i == len(self._log_readers) or self._log_paths[i] is not None) # wraparound if self._current_log == len(self._log_readers): if self._wraparound: diff --git a/tools/lib/mkvparse/README.md b/tools/lib/mkvparse/README.md deleted file mode 100644 index 2d82f190b9..0000000000 --- a/tools/lib/mkvparse/README.md +++ /dev/null @@ -1,24 +0,0 @@ -Simple easy-to-use hacky matroska parser - -Define your handler class: - - class MyMatroskaHandler(mkvparse.MatroskaHandler): - def tracks_available(self): - ... - - def segment_info_available(self): - ... - - def frame(self, track_id, timestamp, data, more_laced_blocks, duration, keyframe_flag, invisible_flag, discardable_flag): - ... - -and `mkvparse.mkvparse(file, MyMatroskaHandler())` - - -Supports lacing and setting global timecode scale, subtitles (BlockGroup). Does not support cues, tags, chapters, seeking and so on. Supports resyncing when something bad is encountered in matroska stream. - -Also contains example of generation of Matroska files from python - -Subtitles should remain as text, binary data gets encoded to hex. - -Licence=MIT diff --git a/tools/lib/mkvparse/mkvgen.py b/tools/lib/mkvparse/mkvgen.py deleted file mode 100755 index 963d60d019..0000000000 --- a/tools/lib/mkvparse/mkvgen.py +++ /dev/null @@ -1,188 +0,0 @@ -#!/usr/bin/env python -import sys -import random -import math - -# Simple hacky Matroska generator -# Reads mp3 file "q.mp3" and jpeg images from img/0.jpg, img/1.jpg and so on and -# writes Matroska file with mjpeg and mp3 to stdout - -# License=MIT - -# unsigned -def big_endian_number(number): - if(number<0x100): - return chr(number) - return big_endian_number(number>>8) + chr(number&0xFF) - -ben=big_endian_number - -def ebml_encode_number(number): - def trailing_bits(rest_of_number, number_of_bits): - # like big_endian_number, but can do padding zeroes - if number_of_bits==8: - return chr(rest_of_number&0xFF); - else: - return trailing_bits(rest_of_number>>8, number_of_bits-8) + chr(rest_of_number&0xFF) - - if number == -1: - return chr(0xFF) - if number < 2**7 - 1: - return chr(number|0x80) - if number < 2**14 - 1: - return chr(0x40 | (number>>8)) + trailing_bits(number, 8) - if number < 2**21 - 1: - return chr(0x20 | (number>>16)) + trailing_bits(number, 16) - if number < 2**28 - 1: - return chr(0x10 | (number>>24)) + trailing_bits(number, 24) - if number < 2**35 - 1: - return chr(0x08 | (number>>32)) + trailing_bits(number, 32) - if number < 2**42 - 1: - return chr(0x04 | (number>>40)) + trailing_bits(number, 40) - if number < 2**49 - 1: - return chr(0x02 | (number>>48)) + trailing_bits(number, 48) - if number < 2**56 - 1: - return chr(0x01) + trailing_bits(number, 56) - raise Exception("NUMBER TOO BIG") - -def ebml_element(element_id, data, length=None): - if length==None: - length = len(data) - return big_endian_number(element_id) + ebml_encode_number(length) + data - - -def write_ebml_header(f, content_type, version, read_version): - f.write( - ebml_element(0x1A45DFA3, "" # EBML - + ebml_element(0x4286, ben(1)) # EBMLVersion - + ebml_element(0x42F7, ben(1)) # EBMLReadVersion - + ebml_element(0x42F2, ben(4)) # EBMLMaxIDLength - + ebml_element(0x42F3, ben(8)) # EBMLMaxSizeLength - + ebml_element(0x4282, content_type) # DocType - + ebml_element(0x4287, ben(version)) # DocTypeVersion - + ebml_element(0x4285, ben(read_version)) # DocTypeReadVersion - )) - -def write_infinite_segment_header(f): - # write segment element header - f.write(ebml_element(0x18538067,"",-1)) # Segment (unknown length) - -def random_uid(): - def rint(): - return int(random.random()*(0x100**4)) - return ben(rint()) + ben(rint()) + ben(rint()) + ben(rint()) - - -def example(): - write_ebml_header(sys.stdout, "matroska", 2, 2) - write_infinite_segment_header(sys.stdout) - - - # write segment info (optional) - sys.stdout.write(ebml_element(0x1549A966, "" # SegmentInfo - + ebml_element(0x73A4, random_uid()) # SegmentUID - + ebml_element(0x7BA9, "mkvgen.py test") # Title - + ebml_element(0x4D80, "mkvgen.py") # MuxingApp - + ebml_element(0x5741, "mkvgen.py") # WritingApp - )) - - # write trans data (codecs etc.) - sys.stdout.write(ebml_element(0x1654AE6B, "" # Tracks - + ebml_element(0xAE, "" # TrackEntry - + ebml_element(0xD7, ben(1)) # TrackNumber - + ebml_element(0x73C5, ben(0x77)) # TrackUID - + ebml_element(0x83, ben(0x01)) # TrackType - #0x01 track is a video track - #0x02 track is an audio track - #0x03 track is a complex track, i.e. a combined video and audio track - #0x10 track is a logo track - #0x11 track is a subtitle track - #0x12 track is a button track - #0x20 track is a control track - + ebml_element(0x536E, "mjpeg data") # Name - + ebml_element(0x86, "V_MJPEG") # CodecID - #+ ebml_element(0x23E383, ben(100000000)) # DefaultDuration (opt.), nanoseconds - #+ ebml_element(0x6DE7, ben(100)) # MinCache - + ebml_element(0xE0, "" # Video - + ebml_element(0xB0, ben(640)) # PixelWidth - + ebml_element(0xBA, ben(480)) # PixelHeight - ) - ) - + ebml_element(0xAE, "" # TrackEntry - + ebml_element(0xD7, ben(2)) # TrackNumber - + ebml_element(0x73C5, ben(0x78)) # TrackUID - + ebml_element(0x83, ben(0x02)) # TrackType - #0x01 track is a video track - #0x02 track is an audio track - #0x03 track is a complex track, i.e. a combined video and audio track - #0x10 track is a logo track - #0x11 track is a subtitle track - #0x12 track is a button track - #0x20 track is a control track - + ebml_element(0x536E, "content of mp3 file") # Name - #+ ebml_element(0x6DE7, ben(100)) # MinCache - + ebml_element(0x86, "A_MPEG/L3") # CodecID - #+ ebml_element(0xE1, "") # Audio - ) - )) - - - mp3file = open("q.mp3", "rb") - mp3file.read(500000); - - def mp3framesgenerator(f): - debt="" - while True: - for i in xrange(0,len(debt)+1): - if i >= len(debt)-1: - debt = debt + f.read(8192) - break - #sys.stderr.write("i="+str(i)+" len="+str(len(debt))+"\n") - if ord(debt[i])==0xFF and (ord(debt[i+1]) & 0xF0)==0XF0 and i>700: - if i>0: - yield debt[0:i] - # sys.stderr.write("len="+str(i)+"\n") - debt = debt[i:] - break - - - mp3 = mp3framesgenerator(mp3file) - mp3.next() - - - for i in xrange(0,530): - framefile = open("img/"+str(i)+".jpg", "rb") - framedata = framefile.read() - framefile.close() - - # write cluster (actual video data) - - if random.random()<1: - sys.stdout.write(ebml_element(0x1F43B675, "" # Cluster - + ebml_element(0xE7, ben(int(i*26*4))) # TimeCode, uint, milliseconds - # + ebml_element(0xA7, ben(0)) # Position, uint - + ebml_element(0xA3, "" # SimpleBlock - + ebml_encode_number(1) # track number - + chr(0x00) + chr(0x00) # timecode, relative to Cluster timecode, sint16, in milliseconds - + chr(0x00) # flags - + framedata - ))) - - for u in xrange(0,4): - mp3f=mp3.next() - if random.random()<1: - sys.stdout.write(ebml_element(0x1F43B675, "" # Cluster - + ebml_element(0xE7, ben(i*26*4+u*26)) # TimeCode, uint, milliseconds - + ebml_element(0xA3, "" # SimpleBlock - + ebml_encode_number(2) # track number - + chr(0x00) + chr(0x00) # timecode, relative to Cluster timecode, sint16, in milliseconds - + chr(0x00) # flags - + mp3f - ))) - - - - - -if __name__ == '__main__': - example() diff --git a/tools/lib/mkvparse/mkvindex.py b/tools/lib/mkvparse/mkvindex.py deleted file mode 100644 index c05423006a..0000000000 --- a/tools/lib/mkvparse/mkvindex.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2016, Comma.ai, Inc. - -import re -import binascii - -from tools.lib.mkvparse import mkvparse -from tools.lib.mkvparse import mkvgen -from tools.lib.mkvparse.mkvgen import ben, ebml_element, ebml_encode_number - -class MatroskaIndex(mkvparse.MatroskaHandler): - # def __init__(self, banlist, nocluster_mode): - # pass - def __init__(self): - self.frameindex = [] - - def tracks_available(self): - _, self.config_record = self.tracks[1]['CodecPrivate'] - - def frame(self, track_id, timestamp, pos, length, more_laced_frames, duration, - keyframe, invisible, discardable): - self.frameindex.append((pos, length, keyframe)) - - - -def mkvindex(f): - handler = MatroskaIndex() - mkvparse.mkvparse(f, handler) - return handler.config_record, handler.frameindex - - -def simple_gen(of, config_record, w, h, framedata): - mkvgen.write_ebml_header(of, "matroska", 2, 2) - mkvgen.write_infinite_segment_header(of) - - of.write(ebml_element(0x1654AE6B, "" # Tracks - + ebml_element(0xAE, "" # TrackEntry - + ebml_element(0xD7, ben(1)) # TrackNumber - + ebml_element(0x73C5, ben(1)) # TrackUID - + ebml_element(0x83, ben(1)) # TrackType = video track - + ebml_element(0x86, "V_MS/VFW/FOURCC") # CodecID - + ebml_element(0xE0, "" # Video - + ebml_element(0xB0, ben(w)) # PixelWidth - + ebml_element(0xBA, ben(h)) # PixelHeight - ) - + ebml_element(0x63A2, config_record) # CodecPrivate (ffv1 configuration record) - ) - )) - - blocks = [] - for fd in framedata: - blocks.append( - ebml_element(0xA3, "" # SimpleBlock - + ebml_encode_number(1) # track number - + chr(0x00) + chr(0x00) # timecode, relative to Cluster timecode, sint16, in milliseconds - + chr(0x80) # flags (keyframe) - + fd - ) - ) - - of.write(ebml_element(0x1F43B675, "" # Cluster - + ebml_element(0xE7, ben(0)) # TimeCode, uint, milliseconds - # + ebml_element(0xA7, ben(0)) # Position, uint - + ''.join(blocks))) - diff --git a/tools/lib/mkvparse/mkvparse.py b/tools/lib/mkvparse/mkvparse.py deleted file mode 100644 index 114fb4ccea..0000000000 --- a/tools/lib/mkvparse/mkvparse.py +++ /dev/null @@ -1,761 +0,0 @@ -# Licence==MIT; Vitaly "_Vi" Shukela 2012 - -# Simple easy-to-use hacky matroska parser - -# Supports SimpleBlock and BlockGroup, lacing, TimecodeScale. -# Does not support seeking, cues, chapters and other features. -# No proper EOF handling unfortunately - -# See "mkvuser.py" for the example - -import traceback -from struct import unpack - -import sys -import datetime - -if sys.version < '3': - range=xrange -else: - #identity=lambda x:x - def ord(something): - if type(something)==bytes: - if something == b"": - raise StopIteration - return something[0] - else: - return something - -def get_major_bit_number(n): - ''' - Takes uint8, returns number of the most significant bit plus the number with that bit cleared. - Examples: - 0b10010101 -> (0, 0b00010101) - 0b00010101 -> (3, 0b00000101) - 0b01111111 -> (1, 0b00111111) - ''' - if not n: - raise Exception("Bad number") - i=0x80; - r=0 - while not n&i: - r+=1 - i>>=1 - return (r,n&~i); - -def read_matroska_number(f, unmodified=False, signed=False): - ''' - Read ebml number. Unmodified means don't clear the length bit (as in Element IDs) - Returns the number and it's length as a tuple - - See examples in "parse_matroska_number" function - ''' - if unmodified and signed: - raise Exception("Contradictary arguments") - first_byte=f.read(1) - if(first_byte==""): - raise StopIteration - r = ord(first_byte) - (n,r2) = get_major_bit_number(r) - if not unmodified: - r=r2 - # from now "signed" means "negative" - i=n - while i: - r = r * 0x100 + ord(f.read(1)) - i-=1 - if signed: - r-=(2**(7*n+7)-1) - else: - if r==2**(7*n+7)-1: - return (-1, n+1) - return (r,n+1) - -def parse_matroska_number(data, pos, unmodified=False, signed=False): - ''' - Parse ebml number from buffer[pos:]. Just like read_matroska_number. - Unmodified means don't clear the length bit (as in Element IDs) - Returns the number plus the new position in input buffer - - Examples: - "\x81" -> (1, pos+1) - "\x40\x01" -> (1, pos+2) - "\x20\x00\x01" -> (1, pos+3) - "\x3F\xFF\xFF" -> (0x1FFFFF, pos+3) - "\x20\x00\x01" unmodified -> (0x200001, pos+3) - "\xBF" signed -> (0, pos+1) - "\xBE" signed -> (-1, pos+1) - "\xC0" signed -> (1, pos+1) - "\x5F\xEF" signed -> (-16, pos+2) - ''' - if unmodified and signed: - raise Exception("Contradictary arguments") - r = ord(data[pos]) - pos+=1 - (n,r2) = get_major_bit_number(r) - if not unmodified: - r=r2 - # from now "signed" means "negative" - i=n - while i: - r = r * 0x100 + ord(data[pos]) - pos+=1 - i-=1 - if signed: - r-=(2**(7*n+6)-1) - else: - if r==2**(7*n+7)-1: - return (-1, pos) - return (r,pos) - -def parse_xiph_number(data, pos): - ''' - Parse the Xiph lacing number from data[pos:] - Returns the number plus the new position - - Examples: - "\x01" -> (1, pos+1) - "\x55" -> (0x55, pos+1) - "\xFF\x04" -> (0x103, pos+2) - "\xFF\xFF\x04" -> (0x202, pos+3) - "\xFF\xFF\x00" -> (0x1FE, pos+3) - ''' - v = ord(data[pos]) - pos+=1 - - r=0 - while v==255: - r+=v - v = ord(data[pos]) - pos+=1 - - r+=v - return (r, pos) - - -def parse_fixedlength_number(data, pos, length, signed=False): - ''' - Read the big-endian number from data[pos:pos+length] - Returns the number plus the new position - - Examples: - "\x01" -> (0x1, pos+1) - "\x55" -> (0x55, pos+1) - "\x55" signed -> (0x55, pos+1) - "\xFF\x04" -> (0xFF04, pos+2) - "\xFF\x04" signed -> (-0x00FC, pos+2) - ''' - r=0 - for i in range(length): - r=r*0x100+ord(data[pos+i]) - if signed: - if ord(data[pos]) & 0x80: - r-=2**(8*length) - return (r, pos+length) - -def read_fixedlength_number(f, length, signed=False): - """ Read length bytes and parse (parse_fixedlength_number) it. - Returns only the number""" - buf = f.read(length) - (r, pos) = parse_fixedlength_number(buf, 0, length, signed) - return r - -def read_ebml_element_header(f): - ''' - Read Element ID and size - Returns id, element size and this header size - ''' - (id_, n) = read_matroska_number(f, unmodified=True) - (size, n2) = read_matroska_number(f) - return (id_, size, n+n2) - -class EbmlElementType: - VOID=0 - MASTER=1 # read all subelements and return tree. Don't use this too large things like Segment - UNSIGNED=2 - SIGNED=3 - TEXTA=4 - TEXTU=5 - BINARY=6 - FLOAT=7 - DATE=8 - - JUST_GO_ON=10 # For "Segment". - # Actually MASTER, but don't build the tree for all subelements, - # interpreting all child elements as if they were top-level elements - - -EET=EbmlElementType - -# lynx -width=10000 -dump http://matroska.org/technical/specs/index.html -# | sed 's/not 0/not0/g; s/> 0/>0/g; s/Sampling Frequency/SamplingFrequency/g' -# | awk '{print $1 " " $3 " " $8}' -# | grep '\[..\]' -# | perl -ne '/(\S+) (\S+) (.)/; -# $name=$1; $id=$2; $type=$3; -# $id=~s/\[|\]//g; -# %types = (m=>"EET.MASTER", -# u=>"EET.UNSIGNED", -# i=>"EET.SIGNED", -# 8=>"EET.TEXTU", -# s=>"EET.TEXTA", -# b=>"EET.BINARY", -# f=>"EET.FLOAT", -# d=>"EET.DATE"); -# $t=$types{$type}; -# next unless $t; -# $t="EET.JUST_GO_ON" if $name eq "Segment" or $name eq "Cluster"; -# print "\t0x$id: ($t, \"$name\"),\n";' - -element_types_names = { - 0x1A45DFA3: (EET.MASTER, "EBML"), - 0x4286: (EET.UNSIGNED, "EBMLVersion"), - 0x42F7: (EET.UNSIGNED, "EBMLReadVersion"), - 0x42F2: (EET.UNSIGNED, "EBMLMaxIDLength"), - 0x42F3: (EET.UNSIGNED, "EBMLMaxSizeLength"), - 0x4282: (EET.TEXTA, "DocType"), - 0x4287: (EET.UNSIGNED, "DocTypeVersion"), - 0x4285: (EET.UNSIGNED, "DocTypeReadVersion"), - 0xEC: (EET.BINARY, "Void"), - 0xBF: (EET.BINARY, "CRC-32"), - 0x1B538667: (EET.MASTER, "SignatureSlot"), - 0x7E8A: (EET.UNSIGNED, "SignatureAlgo"), - 0x7E9A: (EET.UNSIGNED, "SignatureHash"), - 0x7EA5: (EET.BINARY, "SignaturePublicKey"), - 0x7EB5: (EET.BINARY, "Signature"), - 0x7E5B: (EET.MASTER, "SignatureElements"), - 0x7E7B: (EET.MASTER, "SignatureElementList"), - 0x6532: (EET.BINARY, "SignedElement"), - 0x18538067: (EET.JUST_GO_ON, "Segment"), - 0x114D9B74: (EET.MASTER, "SeekHead"), - 0x4DBB: (EET.MASTER, "Seek"), - 0x53AB: (EET.BINARY, "SeekID"), - 0x53AC: (EET.UNSIGNED, "SeekPosition"), - 0x1549A966: (EET.MASTER, "Info"), - 0x73A4: (EET.BINARY, "SegmentUID"), - 0x7384: (EET.TEXTU, "SegmentFilename"), - 0x3CB923: (EET.BINARY, "PrevUID"), - 0x3C83AB: (EET.TEXTU, "PrevFilename"), - 0x3EB923: (EET.BINARY, "NextUID"), - 0x3E83BB: (EET.TEXTU, "NextFilename"), - 0x4444: (EET.BINARY, "SegmentFamily"), - 0x6924: (EET.MASTER, "ChapterTranslate"), - 0x69FC: (EET.UNSIGNED, "ChapterTranslateEditionUID"), - 0x69BF: (EET.UNSIGNED, "ChapterTranslateCodec"), - 0x69A5: (EET.BINARY, "ChapterTranslateID"), - 0x2AD7B1: (EET.UNSIGNED, "TimecodeScale"), - 0x4489: (EET.FLOAT, "Duration"), - 0x4461: (EET.DATE, "DateUTC"), - 0x7BA9: (EET.TEXTU, "Title"), - 0x4D80: (EET.TEXTU, "MuxingApp"), - 0x5741: (EET.TEXTU, "WritingApp"), - 0x1F43B675: (EET.JUST_GO_ON, "Cluster"), - 0xE7: (EET.UNSIGNED, "Timecode"), - 0x5854: (EET.MASTER, "SilentTracks"), - 0x58D7: (EET.UNSIGNED, "SilentTrackNumber"), - 0xA7: (EET.UNSIGNED, "Position"), - 0xAB: (EET.UNSIGNED, "PrevSize"), - 0xA3: (EET.BINARY, "SimpleBlock"), - 0xA0: (EET.MASTER, "BlockGroup"), - 0xA1: (EET.BINARY, "Block"), - 0xA2: (EET.BINARY, "BlockVirtual"), - 0x75A1: (EET.MASTER, "BlockAdditions"), - 0xA6: (EET.MASTER, "BlockMore"), - 0xEE: (EET.UNSIGNED, "BlockAddID"), - 0xA5: (EET.BINARY, "BlockAdditional"), - 0x9B: (EET.UNSIGNED, "BlockDuration"), - 0xFA: (EET.UNSIGNED, "ReferencePriority"), - 0xFB: (EET.SIGNED, "ReferenceBlock"), - 0xFD: (EET.SIGNED, "ReferenceVirtual"), - 0xA4: (EET.BINARY, "CodecState"), - 0x8E: (EET.MASTER, "Slices"), - 0xE8: (EET.MASTER, "TimeSlice"), - 0xCC: (EET.UNSIGNED, "LaceNumber"), - 0xCD: (EET.UNSIGNED, "FrameNumber"), - 0xCB: (EET.UNSIGNED, "BlockAdditionID"), - 0xCE: (EET.UNSIGNED, "Delay"), - 0xCF: (EET.UNSIGNED, "SliceDuration"), - 0xC8: (EET.MASTER, "ReferenceFrame"), - 0xC9: (EET.UNSIGNED, "ReferenceOffset"), - 0xCA: (EET.UNSIGNED, "ReferenceTimeCode"), - 0xAF: (EET.BINARY, "EncryptedBlock"), - 0x1654AE6B: (EET.MASTER, "Tracks"), - 0xAE: (EET.MASTER, "TrackEntry"), - 0xD7: (EET.UNSIGNED, "TrackNumber"), - 0x73C5: (EET.UNSIGNED, "TrackUID"), - 0x83: (EET.UNSIGNED, "TrackType"), - 0xB9: (EET.UNSIGNED, "FlagEnabled"), - 0x88: (EET.UNSIGNED, "FlagDefault"), - 0x55AA: (EET.UNSIGNED, "FlagForced"), - 0x9C: (EET.UNSIGNED, "FlagLacing"), - 0x6DE7: (EET.UNSIGNED, "MinCache"), - 0x6DF8: (EET.UNSIGNED, "MaxCache"), - 0x23E383: (EET.UNSIGNED, "DefaultDuration"), - 0x23314F: (EET.FLOAT, "TrackTimecodeScale"), - 0x537F: (EET.SIGNED, "TrackOffset"), - 0x55EE: (EET.UNSIGNED, "MaxBlockAdditionID"), - 0x536E: (EET.TEXTU, "Name"), - 0x22B59C: (EET.TEXTA, "Language"), - 0x86: (EET.TEXTA, "CodecID"), - 0x63A2: (EET.BINARY, "CodecPrivate"), - 0x258688: (EET.TEXTU, "CodecName"), - 0x7446: (EET.UNSIGNED, "AttachmentLink"), - 0x3A9697: (EET.TEXTU, "CodecSettings"), - 0x3B4040: (EET.TEXTA, "CodecInfoURL"), - 0x26B240: (EET.TEXTA, "CodecDownloadURL"), - 0xAA: (EET.UNSIGNED, "CodecDecodeAll"), - 0x6FAB: (EET.UNSIGNED, "TrackOverlay"), - 0x6624: (EET.MASTER, "TrackTranslate"), - 0x66FC: (EET.UNSIGNED, "TrackTranslateEditionUID"), - 0x66BF: (EET.UNSIGNED, "TrackTranslateCodec"), - 0x66A5: (EET.BINARY, "TrackTranslateTrackID"), - 0xE0: (EET.MASTER, "Video"), - 0x9A: (EET.UNSIGNED, "FlagInterlaced"), - 0x53B8: (EET.UNSIGNED, "StereoMode"), - 0x53B9: (EET.UNSIGNED, "OldStereoMode"), - 0xB0: (EET.UNSIGNED, "PixelWidth"), - 0xBA: (EET.UNSIGNED, "PixelHeight"), - 0x54AA: (EET.UNSIGNED, "PixelCropBottom"), - 0x54BB: (EET.UNSIGNED, "PixelCropTop"), - 0x54CC: (EET.UNSIGNED, "PixelCropLeft"), - 0x54DD: (EET.UNSIGNED, "PixelCropRight"), - 0x54B0: (EET.UNSIGNED, "DisplayWidth"), - 0x54BA: (EET.UNSIGNED, "DisplayHeight"), - 0x54B2: (EET.UNSIGNED, "DisplayUnit"), - 0x54B3: (EET.UNSIGNED, "AspectRatioType"), - 0x2EB524: (EET.BINARY, "ColourSpace"), - 0x2FB523: (EET.FLOAT, "GammaValue"), - 0x2383E3: (EET.FLOAT, "FrameRate"), - 0xE1: (EET.MASTER, "Audio"), - 0xB5: (EET.FLOAT, "SamplingFrequency"), - 0x78B5: (EET.FLOAT, "OutputSamplingFrequency"), - 0x9F: (EET.UNSIGNED, "Channels"), - 0x7D7B: (EET.BINARY, "ChannelPositions"), - 0x6264: (EET.UNSIGNED, "BitDepth"), - 0xE2: (EET.MASTER, "TrackOperation"), - 0xE3: (EET.MASTER, "TrackCombinePlanes"), - 0xE4: (EET.MASTER, "TrackPlane"), - 0xE5: (EET.UNSIGNED, "TrackPlaneUID"), - 0xE6: (EET.UNSIGNED, "TrackPlaneType"), - 0xE9: (EET.MASTER, "TrackJoinBlocks"), - 0xED: (EET.UNSIGNED, "TrackJoinUID"), - 0xC0: (EET.UNSIGNED, "TrickTrackUID"), - 0xC1: (EET.BINARY, "TrickTrackSegmentUID"), - 0xC6: (EET.UNSIGNED, "TrickTrackFlag"), - 0xC7: (EET.UNSIGNED, "TrickMasterTrackUID"), - 0xC4: (EET.BINARY, "TrickMasterTrackSegmentUID"), - 0x6D80: (EET.MASTER, "ContentEncodings"), - 0x6240: (EET.MASTER, "ContentEncoding"), - 0x5031: (EET.UNSIGNED, "ContentEncodingOrder"), - 0x5032: (EET.UNSIGNED, "ContentEncodingScope"), - 0x5033: (EET.UNSIGNED, "ContentEncodingType"), - 0x5034: (EET.MASTER, "ContentCompression"), - 0x4254: (EET.UNSIGNED, "ContentCompAlgo"), - 0x4255: (EET.BINARY, "ContentCompSettings"), - 0x5035: (EET.MASTER, "ContentEncryption"), - 0x47E1: (EET.UNSIGNED, "ContentEncAlgo"), - 0x47E2: (EET.BINARY, "ContentEncKeyID"), - 0x47E3: (EET.BINARY, "ContentSignature"), - 0x47E4: (EET.BINARY, "ContentSigKeyID"), - 0x47E5: (EET.UNSIGNED, "ContentSigAlgo"), - 0x47E6: (EET.UNSIGNED, "ContentSigHashAlgo"), - 0x1C53BB6B: (EET.MASTER, "Cues"), - 0xBB: (EET.MASTER, "CuePoint"), - 0xB3: (EET.UNSIGNED, "CueTime"), - 0xB7: (EET.MASTER, "CueTrackPositions"), - 0xF7: (EET.UNSIGNED, "CueTrack"), - 0xF1: (EET.UNSIGNED, "CueClusterPosition"), - 0x5378: (EET.UNSIGNED, "CueBlockNumber"), - 0xEA: (EET.UNSIGNED, "CueCodecState"), - 0xDB: (EET.MASTER, "CueReference"), - 0x96: (EET.UNSIGNED, "CueRefTime"), - 0x97: (EET.UNSIGNED, "CueRefCluster"), - 0x535F: (EET.UNSIGNED, "CueRefNumber"), - 0xEB: (EET.UNSIGNED, "CueRefCodecState"), - 0x1941A469: (EET.MASTER, "Attachments"), - 0x61A7: (EET.MASTER, "AttachedFile"), - 0x467E: (EET.TEXTU, "FileDescription"), - 0x466E: (EET.TEXTU, "FileName"), - 0x4660: (EET.TEXTA, "FileMimeType"), - 0x465C: (EET.BINARY, "FileData"), - 0x46AE: (EET.UNSIGNED, "FileUID"), - 0x4675: (EET.BINARY, "FileReferral"), - 0x4661: (EET.UNSIGNED, "FileUsedStartTime"), - 0x4662: (EET.UNSIGNED, "FileUsedEndTime"), - 0x1043A770: (EET.MASTER, "Chapters"), - 0x45B9: (EET.MASTER, "EditionEntry"), - 0x45BC: (EET.UNSIGNED, "EditionUID"), - 0x45BD: (EET.UNSIGNED, "EditionFlagHidden"), - 0x45DB: (EET.UNSIGNED, "EditionFlagDefault"), - 0x45DD: (EET.UNSIGNED, "EditionFlagOrdered"), - 0xB6: (EET.MASTER, "ChapterAtom"), - 0x73C4: (EET.UNSIGNED, "ChapterUID"), - 0x91: (EET.UNSIGNED, "ChapterTimeStart"), - 0x92: (EET.UNSIGNED, "ChapterTimeEnd"), - 0x98: (EET.UNSIGNED, "ChapterFlagHidden"), - 0x4598: (EET.UNSIGNED, "ChapterFlagEnabled"), - 0x6E67: (EET.BINARY, "ChapterSegmentUID"), - 0x6EBC: (EET.UNSIGNED, "ChapterSegmentEditionUID"), - 0x63C3: (EET.UNSIGNED, "ChapterPhysicalEquiv"), - 0x8F: (EET.MASTER, "ChapterTrack"), - 0x89: (EET.UNSIGNED, "ChapterTrackNumber"), - 0x80: (EET.MASTER, "ChapterDisplay"), - 0x85: (EET.TEXTU, "ChapString"), - 0x437C: (EET.TEXTA, "ChapLanguage"), - 0x437E: (EET.TEXTA, "ChapCountry"), - 0x6944: (EET.MASTER, "ChapProcess"), - 0x6955: (EET.UNSIGNED, "ChapProcessCodecID"), - 0x450D: (EET.BINARY, "ChapProcessPrivate"), - 0x6911: (EET.MASTER, "ChapProcessCommand"), - 0x6922: (EET.UNSIGNED, "ChapProcessTime"), - 0x6933: (EET.BINARY, "ChapProcessData"), - 0x1254C367: (EET.MASTER, "Tags"), - 0x7373: (EET.MASTER, "Tag"), - 0x63C0: (EET.MASTER, "Targets"), - 0x68CA: (EET.UNSIGNED, "TargetTypeValue"), - 0x63CA: (EET.TEXTA, "TargetType"), - 0x63C5: (EET.UNSIGNED, "TagTrackUID"), - 0x63C9: (EET.UNSIGNED, "TagEditionUID"), - 0x63C4: (EET.UNSIGNED, "TagChapterUID"), - 0x63C6: (EET.UNSIGNED, "TagAttachmentUID"), - 0x67C8: (EET.MASTER, "SimpleTag"), - 0x45A3: (EET.TEXTU, "TagName"), - 0x447A: (EET.TEXTA, "TagLanguage"), - 0x4484: (EET.UNSIGNED, "TagDefault"), - 0x4487: (EET.TEXTU, "TagString"), - 0x4485: (EET.BINARY, "TagBinary"), - 0x56AA: (EET.UNSIGNED, "CodecDelay"), - 0x56BB: (EET.UNSIGNED, "SeekPreRoll"), - 0xF0: (EET.UNSIGNED, "CueRelativePosition"), - 0x53C0: (EET.UNSIGNED, "AlphaMode"), - 0x55B2: (EET.UNSIGNED, "BitsPerChannel"), - 0x55B5: (EET.UNSIGNED, "CbSubsamplingHorz"), - 0x55B6: (EET.UNSIGNED, "CbSubsamplingVert"), - 0x5654: (EET.TEXTU, "ChapterStringUID"), - 0x55B7: (EET.UNSIGNED, "ChromaSitingHorz"), - 0x55B8: (EET.UNSIGNED, "ChromaSitingVert"), - 0x55B3: (EET.UNSIGNED, "ChromaSubsamplingHorz"), - 0x55B4: (EET.UNSIGNED, "ChromaSubsamplingVert"), - 0x55B0: (EET.MASTER, "Colour"), - 0x234E7A: (EET.UNSIGNED, "DefaultDecodedFieldDuration"), - 0x75A2: (EET.SIGNED, "DiscardPadding"), - 0x9D: (EET.UNSIGNED, "FieldOrder"), - 0x55D9: (EET.FLOAT, "LuminanceMax"), - 0x55DA: (EET.FLOAT, "LuminanceMin"), - 0x55D0: (EET.MASTER, "MasteringMetadata"), - 0x55B1: (EET.UNSIGNED, "MatrixCoefficients"), - 0x55BC: (EET.UNSIGNED, "MaxCLL"), - 0x55BD: (EET.UNSIGNED, "MaxFALL"), - 0x55BB: (EET.UNSIGNED, "Primaries"), - 0x55D5: (EET.FLOAT, "PrimaryBChromaticityX"), - 0x55D6: (EET.FLOAT, "PrimaryBChromaticityY"), - 0x55D3: (EET.FLOAT, "PrimaryGChromaticityX"), - 0x55D4: (EET.FLOAT, "PrimaryGChromaticityY"), - 0x55D1: (EET.FLOAT, "PrimaryRChromaticityX"), - 0x55D2: (EET.FLOAT, "PrimaryRChromaticityY"), - 0x55B9: (EET.UNSIGNED, "Range"), - 0x55BA: (EET.UNSIGNED, "TransferCharacteristics"), - 0x55D7: (EET.FLOAT, "WhitePointChromaticityX"), - 0x55D8: (EET.FLOAT, "WhitePointChromaticityY"), -} - -def read_simple_element(f, type_, size): - date = None - if size==0: - return "" - - if type_==EET.UNSIGNED: - data=read_fixedlength_number(f, size, False) - elif type_==EET.SIGNED: - data=read_fixedlength_number(f, size, True) - elif type_==EET.TEXTA: - data=f.read(size) - data = data.replace(b"\x00", b"") # filter out \0, for gstreamer - data = data.decode("ascii") - elif type_==EET.TEXTU: - data=f.read(size) - data = data.replace(b"\x00", b"") # filter out \0, for gstreamer - data = data.decode("UTF-8") - elif type_==EET.MASTER: - data=read_ebml_element_tree(f, size) - elif type_==EET.DATE: - data=read_fixedlength_number(f, size, True) - data*= 1e-9 - data+= (datetime.datetime(2001, 1, 1) - datetime.datetime(1970, 1, 1)).total_seconds() - # now should be UNIX date - elif type_==EET.FLOAT: - if size==4: - data = f.read(4) - data = unpack(">f", data)[0] - elif size==8: - data = f.read(8) - data = unpack(">d", data)[0] - else: - data=read_fixedlength_number(f, size, False) - sys.stderr.write("mkvparse: Floating point of size %d is not supported\n" % size) - data = None - else: - data=f.read(size) - return data - -def read_ebml_element_tree(f, total_size): - ''' - Build tree of elements, reading f until total_size reached - Don't use for the whole segment, it's not Haskell - - Returns list of pairs (element_name, element_value). - element_value can also be list of pairs - ''' - childs=[] - while(total_size>0): - (id_, size, hsize) = read_ebml_element_header(f) - if size == -1: - sys.stderr.write("mkvparse: Element %x without size? Damaged data? Skipping %d bytes\n" % (id_, size, total_size)) - f.read(total_size); - break; - if size>total_size: - sys.stderr.write("mkvparse: Element %x with size %d? Damaged data? Skipping %d bytes\n" % (id_, size, total_size)) - f.read(total_size); - break - type_ = EET.BINARY - name = "unknown_%x"%id_ - if id_ in element_types_names: - (type_, name) = element_types_names[id_] - data = read_simple_element(f, type_, size) - total_size-=(size+hsize) - childs.append((name, (type_, data))) - return childs - - -class MatroskaHandler: - """ User for mkvparse should override these methods """ - def tracks_available(self): - pass - def segment_info_available(self): - pass - def frame(self, track_id, timestamp, data, more_laced_frames, duration, keyframe, invisible, discardable): - pass - def ebml_top_element(self, id_, name_, type_, data_): - pass - def before_handling_an_element(self): - pass - def begin_handling_ebml_element(self, id_, name, type_, headersize, datasize): - return type_ - def element_data_available(self, id_, name, type_, headersize, data): - pass - -def handle_block(buffer, buffer_pos, handler, cluster_timecode, timecode_scale=1000000, duration=None, header_removal_headers_for_tracks={}): - ''' - Decode a block, handling all lacings, send it to handler with appropriate timestamp, track number - ''' - pos=0 - (tracknum, pos) = parse_matroska_number(buffer, pos, signed=False) - (tcode, pos) = parse_fixedlength_number(buffer, pos, 2, signed=True) - flags = ord(buffer[pos]); pos+=1 - f_keyframe = (flags&0x80 == 0x80) - f_invisible = (flags&0x08 == 0x08) - f_discardable = (flags&0x01 == 0x01) - laceflags=flags&0x06 - - block_timecode = (cluster_timecode + tcode)*(timecode_scale*0.000000001) - - header_removal_prefix = b"" - if tracknum in header_removal_headers_for_tracks: - # header_removal_prefix = header_removal_headers_for_tracks[tracknum] - raise NotImplementedError - - if laceflags == 0x00: # no lacing - # buf = buffer[pos:] - handler.frame(tracknum, block_timecode, buffer_pos+pos, len(buffer)-pos, - 0, duration, f_keyframe, f_invisible, f_discardable) - return - - numframes = ord(buffer[pos]); pos+=1 - numframes+=1 - - lengths=[] - - if laceflags == 0x02: # Xiph lacing - accumlength=0 - for i in range(numframes-1): - (l, pos) = parse_xiph_number(buffer, pos) - lengths.append(l) - accumlength+=l - lengths.append(len(buffer)-pos-accumlength) - elif laceflags == 0x06: # EBML lacing - accumlength=0 - if numframes: - (flength, pos) = parse_matroska_number(buffer, pos, signed=False) - lengths.append(flength) - accumlength+=flength - for i in range(numframes-2): - (l, pos) = parse_matroska_number(buffer, pos, signed=True) - flength+=l - lengths.append(flength) - accumlength+=flength - lengths.append(len(buffer)-pos-accumlength) - elif laceflags==0x04: # Fixed size lacing - fl=int((len(buffer)-pos)/numframes) - for i in range(numframes): - lengths.append(fl) - - more_laced_frames=numframes-1 - for i in lengths: - # buf = buffer[pos:pos+i] - handler.frame(tracknum, block_timecode, buffer_pos+pos, i, more_laced_frames, duration, - f_keyframe, f_invisible, f_discardable) - pos+=i - more_laced_frames-=1 - - -def resync(f): - sys.stderr.write("mvkparse: Resyncing\n") - while True: - b = f.read(1); - if b == b"": return (None, None); - if b == b"\x1F": - b2 = f.read(3); - if b2 == b"\x43\xB6\x75": - (seglen, x) = read_matroska_number(f) - return (0x1F43B675, seglen, x+4) # cluster - if b == b"\x18": - b2 = f.read(3) - if b2 == b"\x53\x80\x67": - (seglen, x) = read_matroska_number(f) - return (0x18538067, seglen, x+4) # segment - if b == b"\x16": - b2 = f.read(3) - if b2 == b"\x54\xAE\x6B": - (seglen ,x )= read_matroska_number(f) - return (0x1654AE6B, seglen, x+4) # tracks - - - - -def mkvparse(f, handler): - ''' - Read mkv file f and call handler methods when track or segment information is ready or when frame is read. - Handles lacing, timecodes (except of per-track scaling) - ''' - timecode_scale = 1000000 - current_cluster_timecode = 0 - resync_element_id = None - resync_element_size = None - resync_element_headersize = None - header_removal_headers_for_tracks = {} - while f: - (id_, size, hsize) = (None, None, None) - tree = None - data = None - (type_, name) = (None, None) - try: - if not resync_element_id: - try: - handler.before_handling_an_element() - (id_, size, hsize) = read_ebml_element_header(f) - except StopIteration: - break; - if not (id_ in element_types_names): - sys.stderr.write("mkvparse: Unknown element with id %x and size %d\n"%(id_, size)) - (resync_element_id, resync_element_size, resync_element_headersize) = resync(f) - if resync_element_id: - continue; - else: - break; - else: - id_ = resync_element_id - size=resync_element_size - hsize=resync_element_headersize - resync_element_id = None - resync_element_size = None - resync_element_headersize = None - - (type_, name) = element_types_names[id_] - (type_, name) = element_types_names[id_] - type_ = handler.begin_handling_ebml_element(id_, name, type_, hsize, size) - - if type_ == EET.MASTER: - tree = read_ebml_element_tree(f, size) - data = tree - - except Exception: - traceback.print_exc() - handler.before_handling_an_element() - (resync_element_id, resync_element_size, resync_element_headersize) = resync(f) - if resync_element_id: - continue; - else: - break; - - if name=="EBML" and type(data) == list: - d = dict(tree) - if 'EBMLReadVersion' in d: - if d['EBMLReadVersion'][1]>1: sys.stderr.write("mkvparse: Warning: EBMLReadVersion too big\n") - if 'DocTypeReadVersion' in d: - if d['DocTypeReadVersion'][1]>2: sys.stderr.write("mkvparse: Warning: DocTypeReadVersion too big\n") - dt = d['DocType'][1] - if dt != "matroska" and dt != "webm": - sys.stderr.write("mkvparse: Warning: EBML DocType is not \"matroska\" or \"webm\"") - elif name=="Info" and type(data) == list: - handler.segment_info = tree - handler.segment_info_available() - - d = dict(tree) - if "TimecodeScale" in d: - timecode_scale = d["TimecodeScale"][1] - elif name=="Tracks" and type(data) == list: - handler.tracks={} - for (ten, (_t, track)) in tree: - if ten != "TrackEntry": continue - d = dict(track) - n = d['TrackNumber'][1] - handler.tracks[n]=d - tt = d['TrackType'][1] - if tt==0x01: d['type']='video' - elif tt==0x02: d['type']='audio' - elif tt==0x03: d['type']='complex' - elif tt==0x10: d['type']='logo' - elif tt==0x11: d['type']='subtitle' - elif tt==0x12: d['type']='button' - elif tt==0x20: d['type']='control' - if 'TrackTimecodeScale' in d: - sys.stderr.write("mkvparse: Warning: TrackTimecodeScale is not supported\n") - if 'ContentEncodings' in d: - try: - compr = dict(d["ContentEncodings"][1][0][1][1][0][1][1]) - if compr["ContentCompAlgo"][1] == 3: - header_removal_headers_for_tracks[n] = compr["ContentCompSettings"][1] - else: - sys.stderr.write("mkvparse: Warning: compression other than " \ - "header removal is not supported\n") - except: - sys.stderr.write("mkvparse: Warning: unsuccessfully tried " \ - "to handle header removal compression\n") - handler.tracks_available() - # cluster contents: - elif name=="Timecode" and type_ == EET.UNSIGNED: - data=read_fixedlength_number(f, size, False) - current_cluster_timecode = data; - elif name=="SimpleBlock" and type_ == EET.BINARY: - pos = f.tell() - data=f.read(size) - handle_block(data, pos, handler, current_cluster_timecode, timecode_scale, None, header_removal_headers_for_tracks) - elif name=="BlockGroup" and type_ == EET.MASTER: - d2 = dict(tree) - duration=None - raise NotImplementedError - # if 'BlockDuration' in d2: - # duration = d2['BlockDuration'][1] - # duration = duration*0.000000001*timecode_scale - # if 'Block' in d2: - # handle_block(d2['Block'][1], None, handler, current_cluster_timecode, timecode_scale, duration, header_removal_headers_for_tracks) - else: - if type_!=EET.JUST_GO_ON and type_!=EET.MASTER: - data = read_simple_element(f, type_, size) - - handler.ebml_top_element(id_, name, type_, data); - - - -if __name__ == '__main__': - print("Run mkvuser.py for the example") diff --git a/tools/lib/route.py b/tools/lib/route.py index 2a5ab5e4ac..3060741541 100644 --- a/tools/lib/route.py +++ b/tools/lib/route.py @@ -111,10 +111,12 @@ class RouteSegment(object): self.camera_path = camera_path @property - def name(self): return str(self._name) + def name(self): + return str(self._name) @property - def canonical_name(self): return self._name + def canonical_name(self): + return self._name class RouteSegmentName(object): def __init__(self, name_str): @@ -123,6 +125,8 @@ class RouteSegmentName(object): self._num = int(num_str) @property - def segment_num(self): return self._num + def segment_num(self): + return self._num - def __str__(self): return self._segment_name_str + def __str__(self): + return self._segment_name_str diff --git a/tools/lib/route_framereader.py b/tools/lib/route_framereader.py index 47250383c5..b228275efc 100644 --- a/tools/lib/route_framereader.py +++ b/tools/lib/route_framereader.py @@ -1,6 +1,7 @@ """RouteFrameReader indexes and reads frames across routes, by frameId or segment indices.""" from tools.lib.framereader import FrameReader + class _FrameReaderDict(dict): def __init__(self, camera_paths, cache_paths, framereader_kwargs, *args, **kwargs): super(_FrameReaderDict, self).__init__(*args, **kwargs) @@ -8,7 +9,7 @@ class _FrameReaderDict(dict): if cache_paths is None: cache_paths = {} if not isinstance(cache_paths, dict): - cache_paths = { k: v for k, v in enumerate(cache_paths) } + cache_paths = {k: v for k, v in enumerate(cache_paths)} self._camera_paths = camera_paths self._cache_paths = cache_paths @@ -75,12 +76,14 @@ class RouteFrameReader(object): return self._frame_readers[segment_num].get(segment_id, **kwargs)[0] - def close(self): frs = self._frame_readers self._frame_readers.clear() for fr in frs: fr.close() - def __enter__(self): return self - def __exit__(self, type, value, traceback): self.close() + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.close() diff --git a/tools/lib/tests/test_readers.py b/tools/lib/tests/test_readers.py index c8688a4d85..cb6ba3e11a 100755 --- a/tools/lib/tests/test_readers.py +++ b/tools/lib/tests/test_readers.py @@ -18,7 +18,6 @@ class TestReaders(unittest.TestCase): self.assertEqual(hist['carControl'], 6000) self.assertEqual(hist['logMessage'], 6857) - with tempfile.NamedTemporaryFile(suffix=".bz2") as fp: r = requests.get("https://github.com/commaai/comma2k19/blob/master/Example_1/b0c9d2329ad1606b%7C2018-08-02--08-34-47/40/raw_log.bz2?raw=true") fp.write(r.content) @@ -36,11 +35,9 @@ class TestReaders(unittest.TestCase): self.assertEqual(f.w, 1164) self.assertEqual(f.h, 874) - frame_first_30 = f.get(0, 30) self.assertEqual(len(frame_first_30), 30) - print(frame_first_30[15]) print("frame_0") diff --git a/common/url_file.py b/tools/lib/url_file.py similarity index 89% rename from common/url_file.py rename to tools/lib/url_file.py index 1f6d4a0813..38637d90cc 100644 --- a/common/url_file.py +++ b/tools/lib/url_file.py @@ -1,3 +1,5 @@ +# pylint: skip-file + import os import time import tempfile @@ -7,6 +9,7 @@ import pycurl from io import BytesIO from tenacity import retry, wait_random_exponential, stop_after_attempt + class URLFile(object): _tlocal = threading.local() @@ -24,7 +27,7 @@ class URLFile(object): def __enter__(self): return self - def __exit__(self, type, value, traceback): + def __exit__(self, exc_type, exc_value, traceback): if self._local_file is not None: os.remove(self._local_file.name) self._local_file.close() @@ -35,7 +38,7 @@ class URLFile(object): if ll is None: trange = 'bytes=%d-' % self._pos else: - trange = 'bytes=%d-%d' % (self._pos, self._pos+ll-1) + trange = 'bytes=%d-%d' % (self._pos, self._pos + ll - 1) dats = BytesIO() c = self._curl @@ -48,12 +51,16 @@ class URLFile(object): if self._debug: print("downloading", self._url) + def header(x): if b'MISS' in x: print(x.strip()) + c.setopt(pycurl.HEADERFUNCTION, header) + def test(debug_type, debug_msg): print(" debug(%d): %s" % (debug_type, debug_msg.strip())) + c.setopt(pycurl.VERBOSE, 1) c.setopt(pycurl.DEBUGFUNCTION, test) t1 = time.time() @@ -62,16 +69,15 @@ class URLFile(object): if self._debug: t2 = time.time() - if t2-t1 > 0.1: - print("get %s %r %.f slow" % (self._url, trange, t2-t1)) + if t2 - t1 > 0.1: + print("get %s %r %.f slow" % (self._url, trange, t2 - t1)) response_code = c.getinfo(pycurl.RESPONSE_CODE) - if response_code == 416: # Requested Range Not Satisfiable + if response_code == 416: # Requested Range Not Satisfiable return "" if response_code != 206 and response_code != 200: raise Exception("Error {} ({}): {}".format(response_code, self._url, repr(dats.getvalue())[:500])) - ret = dats.getvalue() self._pos += len(ret) return ret @@ -91,7 +97,7 @@ class URLFile(object): try: os.write(local_fd, self.read()) local_file = open(local_path, "rb") - except: + except Exception: os.remove(local_path) raise finally: diff --git a/tools/lib/url_file_parallel.py b/tools/lib/url_file_parallel.py new file mode 100644 index 0000000000..f6dc37a3b4 --- /dev/null +++ b/tools/lib/url_file_parallel.py @@ -0,0 +1,81 @@ +# pylint: skip-file + +import os +import pycurl +from tools.lib.url_file import URLFile +from io import BytesIO +from tenacity import retry, wait_random_exponential, stop_after_attempt + +from multiprocessing import Pool + + +class URLFileParallel(URLFile): + def __init__(self, url, debug=False): + self._length = None + self._url = url + self._pos = 0 + self._local_file = None + + def get_curl(self): + curl = pycurl.Curl() + curl.setopt(pycurl.NOSIGNAL, 1) + curl.setopt(pycurl.TIMEOUT_MS, 500000) + curl.setopt(pycurl.FOLLOWLOCATION, True) + return curl + + @retry(wait=wait_random_exponential(multiplier=1, max=5), stop=stop_after_attempt(3), reraise=True) + def get_length(self): + if self._length is not None: + return self._length + + c = self.get_curl() + c.setopt(pycurl.URL, self._url) + c.setopt(c.NOBODY, 1) + c.perform() + + length = int(c.getinfo(c.CONTENT_LENGTH_DOWNLOAD)) + self._length = length + return length + + @retry(wait=wait_random_exponential(multiplier=1, max=5), stop=stop_after_attempt(3), reraise=True) + def download_chunk(self, start, end=None): + if end is None: + trange = f'bytes={start}-' + else: + trange = f'bytes={start}-{end}' + + dats = BytesIO() + c = self.get_curl() + c.setopt(pycurl.URL, self._url) + c.setopt(pycurl.WRITEDATA, dats) + c.setopt(pycurl.HTTPHEADER, ["Range: " + trange, "Connection: keep-alive"]) + c.perform() + + response_code = c.getinfo(pycurl.RESPONSE_CODE) + if response_code != 206 and response_code != 200: + raise Exception("Error {} ({}): {}".format(response_code, self._url, repr(dats.getvalue())[:500])) + + return dats.getvalue() + + def read(self, ll=None): + start = self._pos + end = None if ll is None else self._pos + ll - 1 + max_threads = int(os.environ.get("COMMA_PARALLEL_DOWNLOADS", "0")) + + end = self.get_length() if end is None else end + threads = min((end - start) // (512 * 1024), max_threads) # At least 512k per thread + + if threads > 1: + chunk_size = (end - start) // threads + chunks = [ + (start + chunk_size * i, + start + chunk_size * (i + 1) - 1 if i != threads - 1 else end) + for i in range(threads)] + + with Pool(threads) as pool: + ret = b"".join(pool.starmap(self.download_chunk, chunks)) + else: + ret = self.download_chunk(start, end) + + self._pos += len(ret) + return ret diff --git a/tools/lib/vidindex/vidindex.c b/tools/lib/vidindex/vidindex.c index a8d53d947e..4857c60dd2 100644 --- a/tools/lib/vidindex/vidindex.c +++ b/tools/lib/vidindex/vidindex.c @@ -18,7 +18,7 @@ static uint32_t read24be(const uint8_t* ptr) { } static void write32le(FILE *of, uint32_t v) { uint8_t va[4] = { - v & 0xff, (v >> 8) & 0xff, (v >> 16) & 0xff, (v >> 24) & 0xff + v & 0xff, (v >> 8) & 0xff, (v >> 16) & 0xff, (v >> 24) & 0xff }; fwrite(va, 1, sizeof(va), of); } @@ -135,7 +135,7 @@ static void hevc_index(const uint8_t *data, size_t file_size, FILE *of_prefix, F bs_get(&bs, 1); } uint32_t slice_type = bs_ue(&bs); - + // write the index write32le(of_index, slice_type); write32le(of_index, ptr - data); @@ -244,7 +244,7 @@ static void h264_index(const uint8_t *data, size_t file_size, FILE *of_prefix, F uint32_t pic_parameter_set_id = bs_ue(&bs); uint32_t frame_num = bs_get(&bs, sps_log2_max_frame_num_minus4+4); - + if (first_mb_in_slice == 0) { write32le(of_index, slice_type); write32le(of_index, ptr - data); diff --git a/tools/livedm/helpers.py b/tools/livedm/helpers.py index 47a79a67cb..023174e171 100644 --- a/tools/livedm/helpers.py +++ b/tools/livedm/helpers.py @@ -1,30 +1,29 @@ import numpy as np -import cv2 +import cv2 # pylint: disable=import-error def rot_matrix(roll, pitch, yaw): cr, sr = np.cos(roll), np.sin(roll) cp, sp = np.cos(pitch), np.sin(pitch) cy, sy = np.cos(yaw), np.sin(yaw) - rr = np.array([[1,0,0],[0, cr,-sr],[0, sr, cr]]) - rp = np.array([[cp,0,sp],[0, 1,0],[-sp, 0, cp]]) - ry = np.array([[cy,-sy,0],[sy, cy,0],[0, 0, 1]]) + rr = np.array([[1, 0, 0], [0, cr, -sr], [0, sr, cr]]) + rp = np.array([[cp, 0, sp], [0, 1, 0], [-sp, 0, cp]]) + ry = np.array([[cy, -sy, 0], [sy, cy, 0], [0, 0, 1]]) return ry.dot(rp.dot(rr)) -def draw_pose(img, pose, loc, W=160, H=320, xyoffset=(0,0), faceprob=0): - rcmat = np.zeros((3,4)) - rcmat[:,:3] = rot_matrix(*pose[0:3]) * 0.5 - rcmat[0,3] = (loc[0]+0.5) * W - rcmat[1,3] = (loc[1]+0.5) * H - rcmat[2,3] = 1.0 +def draw_pose(img, pose, loc, W=160, H=320, xyoffset=(0, 0), faceprob=0): + rcmat = np.zeros((3, 4)) + rcmat[:, :3] = rot_matrix(*pose[0:3]) * 0.5 + rcmat[0, 3] = (loc[0]+0.5) * W + rcmat[1, 3] = (loc[1]+0.5) * H + rcmat[2, 3] = 1.0 # draw nose - p1 = np.dot(rcmat, [0,0,0,1])[0:2] - p2 = np.dot(rcmat, [0,0,100,1])[0:2] - tr = tuple([int(round(x + xyoffset[i])) for i,x in enumerate(p1)]) - pr = tuple([int(round(x + xyoffset[i])) for i,x in enumerate(p2)]) + p1 = np.dot(rcmat, [0, 0, 0, 1])[0:2] + p2 = np.dot(rcmat, [0, 0, 100, 1])[0:2] + tr = tuple([int(round(x + xyoffset[i])) for i, x in enumerate(p1)]) + pr = tuple([int(round(x + xyoffset[i])) for i, x in enumerate(p2)]) if faceprob > 0.4: - color = (255,255,0) - cv2.line(img, tr, pr, color=(255,255,0), thickness=3) + color = (255, 255, 0) + cv2.line(img, tr, pr, color=(255, 255, 0), thickness=3) else: - color = (64,64,64) + color = (64, 64, 64) cv2.circle(img, tr, 7, color=color) - \ No newline at end of file diff --git a/tools/livedm/livedm.py b/tools/livedm/livedm.py index 60361d9207..d54b353680 100644 --- a/tools/livedm/livedm.py +++ b/tools/livedm/livedm.py @@ -1,9 +1,9 @@ #!/usr/bin/env python3 import os import argparse -import pygame +import pygame # pylint: disable=import-error import numpy as np -import cv2 +import cv2 # pylint: disable=import-error from cereal import log import cereal.messaging as messaging @@ -27,8 +27,8 @@ if __name__ == "__main__": pygame.init() pygame.display.set_caption('livedm') - screen = pygame.display.set_mode((320,640), pygame.DOUBLEBUF) - camera_surface = pygame.surface.Surface((160,320), 0, 24).convert() + screen = pygame.display.set_mode((320, 640), pygame.DOUBLEBUF) + camera_surface = pygame.surface.Surface((160, 320), 0, 24).convert() while 1: polld = poller.poll(1000) @@ -46,34 +46,34 @@ if __name__ == "__main__": faceOrientation[1] *= -1 facePosition[0] *= -1 - img = np.zeros((320,160,3)) + img = np.zeros((320, 160, 3)) if faceProb > 0.4: - cv2.putText(img, 'you', (int(facePosition[0]*160+40), int(facePosition[1]*320+110)), cv2.FONT_ITALIC, 0.5, (255,255,0)) - cv2.rectangle(img, (int(facePosition[0]*160+40), int(facePosition[1]*320+120)),\ - (int(facePosition[0]*160+120), int(facePosition[1]*320+200)), (255,255,0), 1) + cv2.putText(img, 'you', (int(facePosition[0]*160+40), int(facePosition[1]*320+110)), cv2.FONT_ITALIC, 0.5, (255, 255, 0)) + cv2.rectangle(img, (int(facePosition[0]*160+40), int(facePosition[1]*320+120)), + (int(facePosition[0]*160+120), int(facePosition[1]*320+200)), (255, 255, 0), 1) not_blink = evt.driverMonitoring.leftBlinkProb + evt.driverMonitoring.rightBlinkProb < 1 if evt.driverMonitoring.leftEyeProb > 0.6: - cv2.line(img, (int(facePosition[0]*160+95), int(facePosition[1]*320+140)),\ - (int(facePosition[0]*160+105), int(facePosition[1]*320+140)), (255,255,0), 2) + cv2.line(img, (int(facePosition[0]*160+95), int(facePosition[1]*320+140)), + (int(facePosition[0]*160+105), int(facePosition[1]*320+140)), (255, 255, 0), 2) if not_blink: - cv2.line(img, (int(facePosition[0]*160+99), int(facePosition[1]*320+143)),\ - (int(facePosition[0]*160+101), int(facePosition[1]*320+143)), (255,255,0), 2) + cv2.line(img, (int(facePosition[0]*160+99), int(facePosition[1]*320+143)), + (int(facePosition[0]*160+101), int(facePosition[1]*320+143)), (255, 255, 0), 2) if evt.driverMonitoring.rightEyeProb > 0.6: - cv2.line(img, (int(facePosition[0]*160+55), int(facePosition[1]*320+140)),\ - (int(facePosition[0]*160+65), int(facePosition[1]*320+140)), (255,255,0), 2) + cv2.line(img, (int(facePosition[0]*160+55), int(facePosition[1]*320+140)), + (int(facePosition[0]*160+65), int(facePosition[1]*320+140)), (255, 255, 0), 2) if not_blink: - cv2.line(img, (int(facePosition[0]*160+59), int(facePosition[1]*320+143)),\ - (int(facePosition[0]*160+61), int(facePosition[1]*320+143)), (255,255,0), 2) + cv2.line(img, (int(facePosition[0]*160+59), int(facePosition[1]*320+143)), + (int(facePosition[0]*160+61), int(facePosition[1]*320+143)), (255, 255, 0), 2) else: - cv2.putText(img, 'you not found', (int(facePosition[0]*160+40), int(facePosition[1]*320+110)), cv2.FONT_ITALIC, 0.5, (64,64,64)) + cv2.putText(img, 'you not found', (int(facePosition[0]*160+40), int(facePosition[1]*320+110)), cv2.FONT_ITALIC, 0.5, (64, 64, 64)) draw_pose(img, faceOrientation, facePosition, - W = 160, H = 320, xyoffset = (0, 0), faceprob=faceProb) + W=160, H=320, xyoffset=(0, 0), faceprob=faceProb) - pygame.surfarray.blit_array(camera_surface, img.swapaxes(0,1)) + pygame.surfarray.blit_array(camera_surface, img.swapaxes(0, 1)) camera_surface_2x = pygame.transform.scale2x(camera_surface) screen.blit(camera_surface_2x, (0, 0)) pygame.display.flip() diff --git a/tools/mac_setup.sh b/tools/mac_setup.sh new file mode 100755 index 0000000000..4993004a87 --- /dev/null +++ b/tools/mac_setup.sh @@ -0,0 +1,55 @@ +#!/bin/bash -e + +# Install brew if required. +if [[ $(command -v brew) == "" ]]; then + echo "Installing Hombrew" + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" +else + echo "Updating Homebrew" + brew update +fi + +brew install capnp \ + czmq \ + coreutils \ + eigen \ + ffmpeg \ + glfw \ + libarchive \ + libusb \ + libtool \ + llvm \ + pyenv \ + qt5 \ + zeromq + +# Detect shell and pick correct RC file. +if [[ $SHELL == "/bin/zsh" ]]; then + RC_FILE="$HOME/.zshrc" +elif [[ $SHELL == "/bin/bash" ]]; then + RC_FILE="$HOME/.bash_profile" +else + echo "-------------------------------------------------------------" + echo "Unsupported shell: \"$SHELL\", cannot install to RC file." + echo "Please run: echo \"source $OP_DIR/tools/openpilot_env.sh\" >> %YOUR SHELL's RC file%" + echo "-------------------------------------------------------------" +fi + +# Install to RC file (only non-CI). +if [ -z "$OPENPILOT_ENV" ] && [ -n "$RC_FILE" ] && [ -z "$CI" ]; then + OP_DIR=$(git rev-parse --show-toplevel) + echo "source $OP_DIR/tools/openpilot_env.sh" >> $RC_FILE + source $RC_FILE + echo "Added openpilot_env to RC file: $RC_FILE" +else + echo "Skipped RC file installation" +fi + +# Install python. +pyenv install -s 3.8.2 +pyenv global 3.8.2 +pyenv rehash +eval "$(pyenv init -)" # CI doesn't use .bash_profile, and will use python2.7 if this line isn't here. + +pip install pipenv==2018.11.26 +pipenv install --system --deploy diff --git a/tools/nui/FileReader.cpp b/tools/nui/FileReader.cpp index d52305b10e..fe360da98b 100644 --- a/tools/nui/FileReader.cpp +++ b/tools/nui/FileReader.cpp @@ -71,7 +71,7 @@ LogReader::LogReader(const QString& file, Events *events_, QReadWriteLock* event while (1) { mergeEvents(cdled.get()); } - }); + }); } void LogReader::mergeEvents(int dled) { diff --git a/tools/nui/Unlogger.cpp b/tools/nui/Unlogger.cpp index c217a06783..d48c607f45 100644 --- a/tools/nui/Unlogger.cpp +++ b/tools/nui/Unlogger.cpp @@ -4,7 +4,7 @@ #include #include -// include the dynamic struct +// include the dynamic struct #include "cereal/gen/cpp/car.capnp.c++" #include "cereal/gen/cpp/log.capnp.c++" @@ -24,7 +24,7 @@ static inline uint64_t nanos_since_boot() { } -Unlogger::Unlogger(Events *events_, QReadWriteLock* events_lock_, QMap *frs_, int seek) +Unlogger::Unlogger(Events *events_, QReadWriteLock* events_lock_, QMap *frs_, int seek) : events(events_), events_lock(events_lock_), frs(frs_) { ctx = Context::create(); YAML::Node service_list = YAML::LoadFile("../../cereal/service_list.yaml"); diff --git a/tools/nui/get_files_comma_api.py b/tools/nui/get_files_comma_api.py old mode 100644 new mode 100755 index 55b7788b36..b350e8488e --- a/tools/nui/get_files_comma_api.py +++ b/tools/nui/get_files_comma_api.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 import json import sys @@ -6,8 +7,8 @@ from tools.lib.route import Route route_name = sys.argv[1] routes = Route(route_name) data_dump = { - "camera":routes.camera_paths(), - "logs":routes.log_paths() + "camera": routes.camera_paths(), + "logs": routes.log_paths() } json.dump(data_dump, open("routes.json", "w")) diff --git a/tools/nui/main.cpp b/tools/nui/main.cpp index c05275542f..46dab5dff6 100644 --- a/tools/nui/main.cpp +++ b/tools/nui/main.cpp @@ -44,7 +44,7 @@ class Window : public QWidget { QMap lrs; QMap frs; - + // cache the bar QPixmap *px = NULL; @@ -72,7 +72,7 @@ Window::Window(QString route_, int seek, int use_api_) : route(route_), use_api( file.open(QIODevice::ReadOnly | QIODevice::Text); settings = file.readAll(); file.close(); - + QJsonDocument sd = QJsonDocument::fromJson(settings.toUtf8()); qWarning() << sd.isNull(); // <- print false :) QJsonObject sett2 = sd.object(); @@ -97,7 +97,7 @@ bool Window::addSegment(int i) { lrs.insert(i, new LogReader(fn, &events, &events_lock, &unlogger->eidx)); } else { QString log_fn = this->log_paths.at(i).toString(); - lrs.insert(i, new LogReader(log_fn, &events, &events_lock, &unlogger->eidx)); + lrs.insert(i, new LogReader(log_fn, &events, &events_lock, &unlogger->eidx)); } @@ -114,8 +114,8 @@ bool Window::addSegment(int i) { QString camera_fn = this->camera_paths.at(i).toString(); frs.insert(i, new FrameReader(qPrintable(camera_fn))); } - - + + return true; } return false; @@ -193,9 +193,9 @@ void Window::paintEvent(QPaintEvent *event) { tt.drawLine(lt, 300-lvv, rt, 300-vv); if (enabled) { - tt.setPen(Qt::green); + tt.setPen(Qt::green); } else { - tt.setPen(Qt::blue); + tt.setPen(Qt::blue); } tt.drawLine(rt, 300, rt, 600); @@ -237,7 +237,7 @@ int main(int argc, char *argv[]) { QApplication app(argc, argv); QString route(argv[1]); - + int use_api = QString::compare(QString("use_api"), route, Qt::CaseInsensitive) == 0; int seek = QString(argv[2]).toInt(); printf("seek: %d\n", seek); @@ -251,7 +251,7 @@ int main(int argc, char *argv[]) { } Window window(route, seek, use_api); - + window.resize(1920, 800); window.setWindowTitle("nui unlogger"); window.show(); diff --git a/tools/nui/nui b/tools/nui/nui index 35d3cfa68f..7c77df9559 100755 --- a/tools/nui/nui +++ b/tools/nui/nui @@ -1,12 +1,18 @@ -#!/bin/sh +#!/bin/bash -e if [ $# -gt 0 ]; then - if [ "$INTERNAL" = 1 ]; then - ./_nui "$1" + if [ "$INTERNAL" = 1 ]; then + ./_nui "$1" + else + ./get_files_comma_api.py $1 + if [ -f ./_nui ]; then + ./_nui use_api + elif [ -f _nui.app/Contents/MacOS/_nui ]; then + ./_nui.app/Contents/MacOS/_nui use_api else - python get_files_comma_api.py $1 && ./_nui use_api + echo "nui not found, please build it" fi + fi else - echo "Please Enter a Route" + echo "Please Enter a Route" fi - \ No newline at end of file diff --git a/tools/openpilot_env.sh b/tools/openpilot_env.sh old mode 100644 new mode 100755 index ccf76db2bc..ca25706b83 --- a/tools/openpilot_env.sh +++ b/tools/openpilot_env.sh @@ -4,17 +4,13 @@ if [ -z "$OPENPILOT_ENV" ]; then unamestr=`uname` if [[ "$unamestr" == 'Linux' ]]; then export PATH="$HOME/.pyenv/bin:$PATH" - eval "$(pyenv init -)" eval "$(pyenv virtualenv-init -)" - - export PATH="$PATH:$HOME/openpilot/external/capnp/bin" - export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$HOME/openpilot/external/capnp/lib" elif [[ "$unamestr" == 'Darwin' ]]; then # msgq doesn't work on mac export ZMQ=1 export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES fi + eval "$(pyenv init -)" export OPENPILOT_ENV=1 fi - diff --git a/tools/replay/camera.py b/tools/replay/camera.py index c312f52737..8a552785eb 100755 --- a/tools/replay/camera.py +++ b/tools/replay/camera.py @@ -1,14 +1,14 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import os from common.basedir import BASEDIR os.environ['BASEDIR'] = BASEDIR -SCALE = float(os.getenv("SCALE", 1.0)) +SCALE = float(os.getenv("SCALE", "1")) import argparse -import pygame +import pygame # pylint: disable=import-error import numpy as np -import cv2 +import cv2 # pylint: disable=import-error import sys import cereal.messaging as messaging @@ -19,7 +19,6 @@ _FULL_FRAME_TO_BB = np.linalg.inv(_BB_TO_FULL_FRAME) _FULL_FRAME_SIZE = 1164, 874 - def pygame_modules_have_loaded(): return pygame.display.get_init() and pygame.font.get_init() @@ -68,7 +67,7 @@ def ui_thread(addr, frame_address): else: # actually RGB img = np.frombuffer(yuv_img, dtype=np.uint8).reshape((_FULL_FRAME_SIZE[1], _FULL_FRAME_SIZE[0], 3)) - img = img[:, :, ::-1] # Convert BGR to RGB + img = img[:, :, ::-1] # Convert BGR to RGB height, width = img.shape[:2] img_resized = cv2.resize( diff --git a/tools/replay/lib/ui_helpers.py b/tools/replay/lib/ui_helpers.py index 8aaf40afcb..b95c8f63e4 100644 --- a/tools/replay/lib/ui_helpers.py +++ b/tools/replay/lib/ui_helpers.py @@ -1,15 +1,16 @@ from collections import namedtuple +from typing import Any, Dict, Tuple import matplotlib import matplotlib.pyplot as plt import numpy as np -import pygame +import pygame # pylint: disable=import-error -from tools.lib.lazy_property import lazy_property -from selfdrive.config import UIParams as UP from selfdrive.config import RADAR_TO_CAMERA +from selfdrive.config import UIParams as UP from selfdrive.controls.lib.lane_planner import (compute_path_pinv, model_polyfit) +from tools.lib.lazy_property import lazy_property RED = (255, 0, 0) GREEN = (0, 255, 0) @@ -22,7 +23,7 @@ _PATH_X = np.arange(192.) _PATH_XD = np.arange(192.) _PATH_PINV = compute_path_pinv(50) #_BB_OFFSET = 290, 332 -_BB_OFFSET = 0,0 +_BB_OFFSET = 0, 0 _BB_SCALE = 1164/640. _BB_TO_FULL_FRAME = np.asarray([ [_BB_SCALE, 0., _BB_OFFSET[0]], @@ -34,7 +35,7 @@ METER_WIDTH = 20 ModelUIData = namedtuple("ModelUIData", ["cpath", "lpath", "rpath", "lead", "lead_future"]) -_COLOR_CACHE = {} +_COLOR_CACHE : Dict[Tuple[int, int, int], Any] = {} def find_color(lidar_surface, color): if color in _COLOR_CACHE: return _COLOR_CACHE[color] @@ -72,7 +73,7 @@ def draw_path(y, x, color, img, calibration, top_down, lid_color=None): uv_model > 0, axis=1), uv_model[:, 0] < img.shape[1] - 1, uv_model[:, 1] < img.shape[0] - 1))] - for i, j in ((-1, 0), (0, -1), (0, 0), (0, 1), (1, 0)): + for i, j in ((-1, 0), (0, -1), (0, 0), (0, 1), (1, 0)): img[uv_model_dots[:, 1] + i, uv_model_dots[:, 0] + j] = color # draw lidar path point on lidar @@ -87,12 +88,12 @@ def draw_path(y, x, color, img, calibration, top_down, lid_color=None): def draw_steer_path(speed_ms, curvature, color, img, calibration, top_down, VM, lid_color=None): path_x = np.arange(101.) - path_y = np.multiply(path_x, np.tan(np.arcsin(np.clip(path_x * curvature, -0.999, 0.999)) / 2.)) + path_y = np.multiply(path_x, np.tan(np.arcsin(np.clip(path_x * curvature, -0.999, 0.999)) / 2.)) draw_path(path_y, path_x, color, img, calibration, top_down, lid_color) def draw_lead_car(closest, top_down): - if closest != None: + if closest is not None: closest_y = int(round(UP.lidar_car_y - closest * UP.lidar_zoom)) if closest_y > 0: top_down[1][int(round(UP.lidar_car_x - METER_WIDTH * 2)):int( @@ -109,32 +110,30 @@ def draw_lead_on(img, closest_x_m, closest_y_m, calibration, color, sz=10, img_o def init_plots(arr, name_to_arr_idx, plot_xlims, plot_ylims, plot_names, plot_colors, plot_styles, bigplots=False): - color_palette = { "r": (1,0,0), - "g": (0,1,0), - "b": (0,0,1), - "k": (0,0,0), - "y": (1,1,0), - "p": (0,1,1), - "m": (1,0,1) } - - if bigplots == True: + color_palette = { "r": (1, 0, 0), + "g": (0, 1, 0), + "b": (0, 0, 1), + "k": (0, 0, 0), + "y": (1, 1, 0), + "p": (0, 1, 1), + "m": (1, 0, 1) } + + if bigplots: fig = plt.figure(figsize=(6.4, 7.0)) - elif bigplots == False: - fig = plt.figure() else: - fig = plt.figure(figsize=bigplots) + fig = plt.figure() - fig.set_facecolor((0.2,0.2,0.2)) + fig.set_facecolor((0.2, 0.2, 0.2)) axs = [] for pn in range(len(plot_ylims)): - ax = fig.add_subplot(len(plot_ylims),1,len(axs)+1) + ax = fig.add_subplot(len(plot_ylims), 1, len(axs)+1) ax.set_xlim(plot_xlims[pn][0], plot_xlims[pn][1]) ax.set_ylim(plot_ylims[pn][0], plot_ylims[pn][1]) ax.patch.set_facecolor((0.4, 0.4, 0.4)) axs.append(ax) - plots = [] ;idxs = [] ;plot_select = [] + plots, idxs, plot_select = [], [], [] for i, pl_list in enumerate(plot_names): for j, item in enumerate(pl_list): plot, = axs[i].plot(arr[:, name_to_arr_idx[item]], @@ -188,7 +187,6 @@ def draw_mpc(liveMpc, top_down): top_down[1][px, py] = mpc_color - class CalibrationTransformsForWarpMatrix(object): def __init__(self, model_to_full_frame, K, E): self._model_to_full_frame = model_to_full_frame diff --git a/tools/replay/rqplot.py b/tools/replay/rqplot.py index 3c3c5239c5..8886cf7f37 100755 --- a/tools/replay/rqplot.py +++ b/tools/replay/rqplot.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# type: ignore import sys import matplotlib.pyplot as plt import numpy as np @@ -78,4 +79,3 @@ if __name__ == "__main__": # just a bit of wait to avoid 100% CPU usage time.sleep(0.001) - diff --git a/tools/replay/sensorium.py b/tools/replay/sensorium.py index b85d6ef8c0..10b2a960d1 100755 --- a/tools/replay/sensorium.py +++ b/tools/replay/sensorium.py @@ -3,7 +3,7 @@ # Question: Can a human drive from this data? import os -import cv2 +import cv2 # pylint: disable=import-error import numpy as np import cereal.messaging as messaging from common.window import Window @@ -31,23 +31,20 @@ if __name__ == "__main__": sm.update(timeout=1) rgb_img_raw = fpkt.frame.image imgff = np.frombuffer(rgb_img_raw, dtype=np.uint8).reshape((FULL_FRAME_SIZE[1], FULL_FRAME_SIZE[0], 3)) - imgff = imgff[:, :, ::-1] # Convert BGR to RGB + imgff = imgff[:, :, ::-1] # Convert BGR to RGB if sm.updated['liveCalibration']: intrinsic_matrix = eon_intrinsics - img_transform = np.array(fpkt.frame.transform).reshape(3,3) + img_transform = np.array(fpkt.frame.transform).reshape(3, 3) extrinsic_matrix = np.asarray(sm['liveCalibration'].extrinsicMatrix).reshape(3, 4) ke = intrinsic_matrix.dot(extrinsic_matrix) warp_matrix = get_camera_frame_from_medmodel_frame(ke) calibration = CalibrationTransformsForWarpMatrix(warp_matrix, intrinsic_matrix, extrinsic_matrix) transform = np.dot(img_transform, calibration.model_to_full_frame) - if calibration is not None: imgw = cv2.warpAffine(imgff, transform[:2], (MEDMODEL_INPUT_SIZE[0], MEDMODEL_INPUT_SIZE[1]), flags=cv2.WARP_INVERSE_MAP | cv2.INTER_CUBIC) win.draw(imgw) - - diff --git a/tools/replay/ui.py b/tools/replay/ui.py index 2a91c1b55b..37dfd5c18b 100755 --- a/tools/replay/ui.py +++ b/tools/replay/ui.py @@ -5,9 +5,9 @@ import sys os.environ["OMP_NUM_THREADS"] = "1" -import cv2 +import cv2 # pylint: disable=import-error import numpy as np -import pygame +import pygame # pylint: disable=import-error from common.basedir import BASEDIR from common.transformations.camera import FULL_FRAME_SIZE, eon_intrinsics @@ -63,11 +63,11 @@ def ui_thread(addr, frame_address): camera_surface = pygame.surface.Surface((640, 480), 0, 24).convert() cameraw_surface = pygame.surface.Surface(MODEL_INPUT_SIZE, 0, 24).convert() - cameraw_test_surface = pygame.surface.Surface(MODEL_INPUT_SIZE, 0, 24) - top_down_surface = pygame.surface.Surface((UP.lidar_x, UP.lidar_y),0,8) + top_down_surface = pygame.surface.Surface((UP.lidar_x, UP.lidar_y), 0, 8) frame = messaging.sub_sock('frame', addr=addr, conflate=True) - sm = messaging.SubMaster(['carState', 'plan', 'carControl', 'radarState', 'liveCalibration', 'controlsState', 'liveTracks', 'model', 'liveMpc', 'liveParameters', 'pathPlan'], addr=addr) + sm = messaging.SubMaster(['carState', 'plan', 'carControl', 'radarState', 'liveCalibration', 'controlsState', + 'liveTracks', 'model', 'liveMpc', 'liveParameters', 'pathPlan'], addr=addr) calibration = None img = np.zeros((480, 640, 3), dtype='uint8') @@ -114,7 +114,7 @@ def ui_thread(addr, frame_address): while 1: list(pygame.event.get()) - screen.fill((64,64,64)) + screen.fill((64, 64, 64)) lid_overlay = lid_overlay_blank.copy() top_down = top_down_surface, lid_overlay @@ -123,7 +123,7 @@ def ui_thread(addr, frame_address): rgb_img_raw = fpkt.frame.image if fpkt.frame.transform: - img_transform = np.array(fpkt.frame.transform).reshape(3,3) + img_transform = np.array(fpkt.frame.transform).reshape(3, 3) else: # assume frame is flipped img_transform = np.array([ @@ -132,10 +132,9 @@ def ui_thread(addr, frame_address): [ 0.0, 0.0, 1.0] ]) - if rgb_img_raw and len(rgb_img_raw) == FULL_FRAME_SIZE[0] * FULL_FRAME_SIZE[1] * 3: imgff = np.frombuffer(rgb_img_raw, dtype=np.uint8).reshape((FULL_FRAME_SIZE[1], FULL_FRAME_SIZE[0], 3)) - imgff = imgff[:, :, ::-1] # Convert BGR to RGB + imgff = imgff[:, :, ::-1] # Convert BGR to RGB cv2.warpAffine(imgff, np.dot(img_transform, _BB_TO_FULL_FRAME)[:2], (img.shape[1], img.shape[0]), dst=img, flags=cv2.WARP_INVERSE_MAP) @@ -190,7 +189,6 @@ def ui_thread(addr, frame_address): # draw all radar points maybe_update_radar_points(sm['liveTracks'], top_down[1]) - if sm.updated['liveCalibration']: extrinsic_matrix = np.asarray(sm['liveCalibration'].extrinsicMatrix).reshape(3, 4) ke = intrinsic_matrix.dot(extrinsic_matrix) @@ -201,17 +199,17 @@ def ui_thread(addr, frame_address): for lead in [sm['radarState'].leadOne, sm['radarState'].leadTwo]: if lead.status: if calibration is not None: - draw_lead_on(img, lead.dRel, lead.yRel, calibration, color=(192,0,0)) + draw_lead_on(img, lead.dRel, lead.yRel, calibration, color=(192, 0, 0)) draw_lead_car(lead.dRel, top_down) # *** blits *** - pygame.surfarray.blit_array(camera_surface, img.swapaxes(0,1)) + pygame.surfarray.blit_array(camera_surface, img.swapaxes(0, 1)) screen.blit(camera_surface, (0, 0)) # display alerts - alert_line1 = alert1_font.render(sm['controlsState'].alertText1, True, (255,0,0)) - alert_line2 = alert2_font.render(sm['controlsState'].alertText2, True, (255,0,0)) + alert_line1 = alert1_font.render(sm['controlsState'].alertText1, True, (255, 0, 0)) + alert_line2 = alert2_font.render(sm['controlsState'].alertText2, True, (255, 0, 0)) screen.blit(alert_line1, (180, 150)) screen.blit(alert_line2, (180, 190)) @@ -230,9 +228,8 @@ def ui_thread(addr, frame_address): screen.blit(cameraw_surface, (320, 480)) pygame.surfarray.blit_array(*top_down) - screen.blit(top_down[0], (640,0)) + screen.blit(top_down[0], (640, 0)) - i = 0 SPACING = 25 lines = [ diff --git a/tools/replay/unlog_segment.py b/tools/replay/unlog_segment.py index cea3c96971..94520b3baa 100755 --- a/tools/replay/unlog_segment.py +++ b/tools/replay/unlog_segment.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +# pylint: skip-file + import argparse import bisect import select @@ -100,6 +102,6 @@ if __name__ == "__main__": try: replay(args.segment, args.loop) termios.tcsetattr(sys.stdin, termios.TCSADRAIN, orig_settings) - except: + except Exception: termios.tcsetattr(sys.stdin, termios.TCSADRAIN, orig_settings) raise diff --git a/tools/replay/unlogger.py b/tools/replay/unlogger.py index 920d9d0b34..2cef80b770 100755 --- a/tools/replay/unlogger.py +++ b/tools/replay/unlogger.py @@ -5,10 +5,10 @@ import sys import zmq import time import signal +import multiprocessing from uuid import uuid4 from collections import namedtuple from collections import deque -from multiprocessing import Process, TimeoutError from datetime import datetime # strat 1: script to copy files @@ -110,7 +110,7 @@ class UnloggerWorker(object): print("FRAME(%d) LAG -- %.2f ms" % (frame_id, fr_time*1000.0)) if img is not None: - img = img[:, :, ::-1] # Convert RGB to BGR, which is what the camera outputs + img = img[:, :, ::-1] # Convert RGB to BGR, which is what the camera outputs img = img.flatten() smsg.frame.image = img.tobytes() @@ -259,7 +259,7 @@ def unlogger_thread(command_address, forward_commands_address, data_address, run msg_time_offset = msg_time_seconds - msg_start_time real_time_offset = realtime.sec_since_boot() - real_start_time lag = msg_time_offset - real_time_offset - if lag > 0 and lag < 30: # a large jump is OK, likely due to an out of order segment + if lag > 0 and lag < 30: # a large jump is OK, likely due to an out of order segment if lag > 1: print("sleeping for", lag) time.sleep(lag) @@ -312,19 +312,19 @@ def keyboard_controller_thread(q, route_start_time): kb = KBHit() while 1: c = kb.getch() - if c=='m': # Move forward by 1m + if c == 'm': # Move forward by 1m q.send_pyobj(SeekRelativeTime(60)) - elif c=='M': # Move backward by 1m + elif c == 'M': # Move backward by 1m q.send_pyobj(SeekRelativeTime(-60)) - elif c=='s': # Move forward by 10s + elif c == 's': # Move forward by 10s q.send_pyobj(SeekRelativeTime(10)) - elif c=='S': # Move backward by 10s + elif c == 'S': # Move backward by 10s q.send_pyobj(SeekRelativeTime(-10)) - elif c=='G': # Move backward by 10s + elif c == 'G': # Move backward by 10s q.send_pyobj(SeekAbsoluteTime(0.)) - elif c=="\x20": # Space bar. + elif c == "\x20": # Space bar. q.send_pyobj(TogglePause()) - elif c=="\n": + elif c == "\n": try: seek_time_input = input('time: ') seek_time = absolute_time_str(seek_time_input, route_start_time) @@ -341,15 +341,19 @@ def get_arg_parser(): parser.add_argument("route_name", type=(lambda x: x.replace("#", "|")), nargs="?", help="The route whose messages will be published.") parser.add_argument("data_dir", nargs='?', default=os.getenv('UNLOGGER_DATA_DIR'), - help="Path to directory in which log and camera files are located.") + help="Path to directory in which log and camera files are located.") parser.add_argument("--no-loop", action="store_true", help="Stop at the end of the replay.") - key_value_pair = lambda x: x.split("=") + def key_value_pair(x): + return x.split("=") + parser.add_argument("address_mapping", nargs="*", type=key_value_pair, help="Pairs = to publish on .") - comma_list = lambda x: x.split(",") + def comma_list(x): + return x.split(",") + to_mock_group = parser.add_mutually_exclusive_group() to_mock_group.add_argument("--min", action="store_true", default=os.getenv("MIN")) to_mock_group.add_argument("--enabled", default=os.getenv("ENABLED"), type=comma_list) @@ -400,28 +404,25 @@ def main(argv): subprocesses = {} try: - subprocesses["data"] = Process( + subprocesses["data"] = multiprocessing.Process( target=UnloggerWorker().run, args=(forward_commands_address, data_address, address_mapping.copy())) - subprocesses["control"] = Process( + subprocesses["control"] = multiprocessing.Process( target=unlogger_thread, args=(command_address, forward_commands_address, data_address, args.realtime, _get_address_mapping(args), args.publish_time_length, args.bind_early, args.no_loop)) - for p in subprocesses.values(): - p.daemon = True - subprocesses["data"].start() subprocesses["control"].start() # Exit if any of the children die. def exit_if_children_dead(*_): - for name, p in subprocesses.items(): + for _, p in subprocesses.items(): if not p.is_alive(): [p.terminate() for p in subprocesses.values()] exit() - signal.signal(signal.SIGCHLD, signal.SIGIGN) + signal.signal(signal.SIGCHLD, signal.SIG_IGN) signal.signal(signal.SIGCHLD, exit_if_children_dead) if args.interactive: @@ -435,7 +436,7 @@ def main(argv): if p.is_alive(): try: p.join(3.) - except TimeoutError: + except multiprocessing.TimeoutError: p.terminate() continue return 0 diff --git a/tools/requirements.txt b/tools/requirements.txt deleted file mode 100644 index d5887cb5ef..0000000000 --- a/tools/requirements.txt +++ /dev/null @@ -1,13 +0,0 @@ -aenum -atomicwrites -futures -libarchive -lru-dict -matplotlib -numpy -opencv-python -pygame -hexdump -pycurl -tenacity -av==0.5.0 diff --git a/tools/scripts/fetch_image_from_route.py b/tools/scripts/fetch_image_from_route.py new file mode 100755 index 0000000000..e9111d9de2 --- /dev/null +++ b/tools/scripts/fetch_image_from_route.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +import sys + +if len(sys.argv) < 4: + print("%s " % sys.argv[0]) + print('example: ./fetch_image_from_route.py "02c45f73a2e5c6e9|2020-06-01--18-03-08" 3 500') + exit(0) + +import requests +from PIL import Image +from tools.lib.auth_config import get_token +from tools.lib.framereader import FrameReader + +jwt = get_token() + +route = sys.argv[1] +segment = int(sys.argv[2]) +frame = int(sys.argv[3]) + +url = 'https://api.commadotai.com/v1/route/'+sys.argv[1]+"/files" +r = requests.get(url, headers={"Authorization": "JWT "+jwt}) +assert r.status_code == 200 +print("got api response") + +cameras = r.json()['cameras'] +if segment >= len(cameras): + raise Exception("segment %d not found, got %d segments" % (segment, len(cameras))) + +fr = FrameReader(cameras[segment]) +if frame >= fr.frame_count: + raise Exception("frame %d not found, got %d frames" % (frame, fr.frame_count)) + +im = Image.fromarray(fr.get(frame, count=1, pix_fmt="rgb24")[0]) +fn = "uxxx_"+route.replace("|", "_")+"_%d_%d.png" % (segment, frame) +im.save(fn) +print("saved %s" % fn) + diff --git a/tools/sim/README.md b/tools/sim/README.md index 8277ab1f10..06cb03907a 100644 --- a/tools/sim/README.md +++ b/tools/sim/README.md @@ -10,31 +10,31 @@ git clone https://github.com/commaai/openpilot.git # Add export PYTHONPATH=$HOME/openpilot to your bashrc # Have a working tensorflow+keras in python3.7.3 (with [packages] in openpilot/Pipfile) ``` -## Install (in tab 1) +## Install (in terminal 1) ``` cd ~/openpilot/tools/sim ./start_carla.sh # install CARLA 0.9.7 and start the server ``` -## openpilot (in tab 2) +## openpilot (in terminal 2) ``` cd ~/openpilot/selfdrive/ PASSIVE=0 NOBOARD=1 ./manager.py ``` -## bridge (in tab 3) +## bridge (in terminal 3) ``` # links carla to openpilot, will "start the car" according to manager cd ~/openpilot/tools/sim ./bridge.py ``` -## Controls -Now you can control the simulator with the keys: +## Controls +Now put the focus on the terminal running bridge.py and you can control +openpilot driving in the simulation with the following keys -1: Cruise up 5 mph - -2: Cruise down 5 mph - -3: Cruise cancel - -q: Exit all +| key | functionality | +| :---: | :---------------: | +| 1 | Cruise up 5 mph | +| 2 | Cruise down 5 mph | +| 3 | Cruise cancel | +| q | Exit all | diff --git a/tools/sim/bridge.py b/tools/sim/bridge.py index 0235e1d9ff..88ab3f9742 100755 --- a/tools/sim/bridge.py +++ b/tools/sim/bridge.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +# type: ignore import time import math import atexit @@ -21,12 +22,12 @@ args = parser.parse_args() pm = messaging.PubMaster(['frame', 'sensorEvents', 'can']) -W,H = 1164, 874 +W, H = 1164, 874 def cam_callback(image): img = np.frombuffer(image.raw_data, dtype=np.dtype("uint8")) img = np.reshape(img, (H, W, 4)) - img = img[:, :, [0,1,2]].copy() + img = img[:, :, [0, 1, 2]].copy() dat = messaging.new_message('frame') dat.frame = { @@ -59,7 +60,7 @@ def health_function(): dat.valid = True dat.health = { 'ignitionLine': True, - 'hwType': "whitePanda", + 'hwType': "greyPanda", 'controlsAllowed': True } pm.send('health', dat) @@ -79,7 +80,6 @@ def go(q): threading.Thread(target=health_function).start() threading.Thread(target=fake_driver_monitoring).start() - import carla client = carla.Client("127.0.0.1", 2000) client.set_timeout(5.0) world = client.load_world('Town04') @@ -97,11 +97,9 @@ def go(q): world.set_weather(weather) blueprint_library = world.get_blueprint_library() - """ - for blueprint in blueprint_library.filter('sensor.*'): - print(blueprint.id) - exit(0) - """ + # for blueprint in blueprint_library.filter('sensor.*'): + # print(blueprint.id) + # exit(0) world_map = world.get_map() vehicle_bp = random.choice(blueprint_library.filter('vehicle.tesla.*')) @@ -169,7 +167,7 @@ def go(q): m = message.split('_') if m[0] == "steer": steer_angle_out = float(m[1]) - fake_wheel.set_angle(steer_angle_out) # touching the wheel overrides fake wheel angle + fake_wheel.set_angle(steer_angle_out) # touching the wheel overrides fake wheel angle # print(" === steering overriden === ") if m[0] == "throttle": throttle_out = float(m[1]) / 100. @@ -200,7 +198,7 @@ def go(q): speed = math.sqrt(vel.x**2 + vel.y**2 + vel.z**2) * 3.6 can_function(pm, speed, fake_wheel.angle, rk.frame, cruise_button=cruise_button, is_engaged=is_openpilot_engaged) - if rk.frame%1 == 0: # 20Hz? + if rk.frame % 1 == 0: # 20Hz? throttle_op, brake_op, steer_torque_op = sendcan_function(sendcan) # print(" === torq, ",steer_torque_op, " ===") if is_openpilot_engaged: @@ -231,7 +229,7 @@ if __name__ == "__main__": print("WARNING: NO CARLA") while 1: time.sleep(1) - + from multiprocessing import Process, Queue q = Queue() p = Process(target=go, args=(q,)) @@ -246,4 +244,3 @@ if __name__ == "__main__": # start input poll for keyboard from lib.keyboard_ctrl import keyboard_poll_thread keyboard_poll_thread(q) - diff --git a/tools/sim/launch_openpilot.sh b/tools/sim/launch_openpilot.sh new file mode 100755 index 0000000000..207997c867 --- /dev/null +++ b/tools/sim/launch_openpilot.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +export PASSIVE="0" +export NOBOARD="1" + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +cd ../../selfdrive && ./manager.py diff --git a/tools/sim/lib/can.py b/tools/sim/lib/can.py index 3948e818b5..7ae7f3f7e8 100755 --- a/tools/sim/lib/can.py +++ b/tools/sim/lib/can.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 import cereal.messaging as messaging from opendbc.can.packer import CANPacker -from selfdrive.boardd.boardd_api_impl import can_list_to_can_capnp +from selfdrive.boardd.boardd_api_impl import can_list_to_can_capnp # pylint: disable=no-name-in-module,import-error from selfdrive.car.honda.values import FINGERPRINTS, CAR from selfdrive.car import crc8_pedal import math @@ -28,8 +28,8 @@ def can_function(pm, speed, angle, idx, cruise_button=0, is_engaged=False): msg.append(packer.make_can_msg("SCM_BUTTONS", 0, {"CRUISE_BUTTONS": cruise_button}, idx)) - values = {"COUNTER_PEDAL": idx&0xF} - checksum = crc8_pedal(packer.make_can_msg("GAS_SENSOR", 0, {"COUNTER_PEDAL": idx&0xF}, -1)[2][:-1]) + values = {"COUNTER_PEDAL": idx & 0xF} + checksum = crc8_pedal(packer.make_can_msg("GAS_SENSOR", 0, {"COUNTER_PEDAL": idx & 0xF}, -1)[2][:-1]) values["CHECKSUM_PEDAL"] = checksum msg.append(packer.make_can_msg("GAS_SENSOR", 0, values, -1)) @@ -37,8 +37,7 @@ def can_function(pm, speed, angle, idx, cruise_button=0, is_engaged=False): msg.append(packer.make_can_msg("GAS_PEDAL_2", 0, {}, idx)) msg.append(packer.make_can_msg("SEATBELT_STATUS", 0, {"SEATBELT_DRIVER_LATCHED": 1}, idx)) msg.append(packer.make_can_msg("STEER_STATUS", 0, {}, idx)) - msg.append(packer.make_can_msg("STEERING_SENSORS", 0, {"STEER_ANGLE":angle_to_sangle(angle)}, idx)) - msg.append(packer.make_can_msg("POWERTRAIN_DATA", 0, {}, idx)) + msg.append(packer.make_can_msg("STEERING_SENSORS", 0, {"STEER_ANGLE": angle_to_sangle(angle)}, idx)) msg.append(packer.make_can_msg("VSA_STATUS", 0, {}, idx)) msg.append(packer.make_can_msg("STANDSTILL", 0, {}, idx)) msg.append(packer.make_can_msg("STEER_MOTOR_TORQUE", 0, {}, idx)) @@ -56,14 +55,14 @@ def can_function(pm, speed, angle, idx, cruise_button=0, is_engaged=False): msg.append(packer.make_can_msg("BRAKE_COMMAND", 2, {}, idx)) # radar - if idx%5 == 0: + if idx % 5 == 0: msg.append(rpacker.make_can_msg("RADAR_DIAGNOSTIC", 1, {"RADAR_STATE": 0x79}, -1)) for i in range(16): msg.append(rpacker.make_can_msg("TRACK_%d" % i, 1, {"LONG_DIST": 255.5}, -1)) # fill in the rest for fingerprint done = set([x[0] for x in msg]) - for k,v in FINGERPRINTS[CAR.CIVIC][0].items(): + for k, v in FINGERPRINTS[CAR.CIVIC][0].items(): if k not in done and k not in [0xE4, 0x194]: msg.append([k, 0, b'\x00'*v, 0]) pm.send('can', can_list_to_can_capnp(msg)) @@ -88,4 +87,3 @@ def sendcan_function(sendcan): steer_torque = 0.0 return (gas, brake, steer_torque) - diff --git a/tools/sim/lib/helpers.py b/tools/sim/lib/helpers.py index 104d5e3633..f6bb4b8173 100644 --- a/tools/sim/lib/helpers.py +++ b/tools/sim/lib/helpers.py @@ -1,7 +1,7 @@ class FakeSteeringWheel(): def __init__(self, dt=0.01): # physical params - self.DAC = 4. / 0.625 # convert torque value from can to Nm + self.DAC = 4. / 0.625 # convert torque value from can to Nm self.k = 0.035 self.centering_k = 4.1 * 0.9 self.b = 0.1 * 0.8 @@ -9,7 +9,7 @@ class FakeSteeringWheel(): self.dt = dt # ... - self.angle = 0. # start centered + self.angle = 0. # start centered # self.omega = 0. def response(self, torque, vego=0): @@ -19,7 +19,7 @@ class FakeSteeringWheel(): # self.omega += self.dt * (exerted_torque + centering_torque + damping_torque) / self.I # self.omega = np.clip(self.omega, -1.1, 1.1) # self.angle += self.dt * self.omega - self.angle += self.dt * self.k * exerted_torque # aristotle + self.angle += self.dt * self.k * exerted_torque # aristotle # print(" ========== ") # print("angle,", self.angle) diff --git a/tools/sim/lib/keyboard_ctrl.py b/tools/sim/lib/keyboard_ctrl.py index 8be3ca0dda..18a491fec0 100644 --- a/tools/sim/lib/keyboard_ctrl.py +++ b/tools/sim/lib/keyboard_ctrl.py @@ -1,7 +1,9 @@ -import time import sys import termios -from termios import * +import time +from termios import (BRKINT, CS8, CSIZE, ECHO, ICANON, ICRNL, IEXTEN, INPCK, + ISIG, ISTRIP, IXON, PARENB, VMIN, VTIME) +from typing import Any # Indexes for termios list. IFLAG = 0 @@ -52,10 +54,9 @@ def test(q): if __name__ == '__main__': from multiprocessing import Process, Queue - q = Queue() + q : Any = Queue() p = Process(target=test, args=(q,)) p.daemon = True p.start() keyboard_poll_thread(q) - diff --git a/tools/sim/lib/manual_ctrl.py b/tools/sim/lib/manual_ctrl.py index a32d606d43..d943bdf1d9 100755 --- a/tools/sim/lib/manual_ctrl.py +++ b/tools/sim/lib/manual_ctrl.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 # set up wheel -import os, struct, array +import array +import os +import struct from fcntl import ioctl # Iterate over the joystick devices. @@ -97,22 +99,22 @@ def wheel_poll_thread(q): # Get the device name. #buf = bytearray(63) buf = array.array('B', [0] * 64) - ioctl(jsdev, 0x80006a13 + (0x10000 * len(buf)), buf) # JSIOCGNAME(len) + ioctl(jsdev, 0x80006a13 + (0x10000 * len(buf)), buf) # JSIOCGNAME(len) js_name = buf.tobytes().rstrip(b'\x00').decode('utf-8') print('Device name: %s' % js_name) # Get number of axes and buttons. buf = array.array('B', [0]) - ioctl(jsdev, 0x80016a11, buf) # JSIOCGAXES + ioctl(jsdev, 0x80016a11, buf) # JSIOCGAXES num_axes = buf[0] buf = array.array('B', [0]) - ioctl(jsdev, 0x80016a12, buf) # JSIOCGBUTTONS + ioctl(jsdev, 0x80016a12, buf) # JSIOCGBUTTONS num_buttons = buf[0] # Get the axis map. buf = array.array('B', [0] * 0x40) - ioctl(jsdev, 0x80406a32, buf) # JSIOCGAXMAP + ioctl(jsdev, 0x80406a32, buf) # JSIOCGAXMAP for axis in buf[:num_axes]: axis_name = axis_names.get(axis, 'unknown(0x%02x)' % axis) @@ -121,7 +123,7 @@ def wheel_poll_thread(q): # Get the button map. buf = array.array('H', [0] * 200) - ioctl(jsdev, 0x80406a34, buf) # JSIOCGBTNMAP + ioctl(jsdev, 0x80406a34, buf) # JSIOCGBTNMAP for btn in buf[:num_buttons]: btn_name = button_names.get(btn, 'unknown(0x%03x)' % btn) @@ -132,8 +134,8 @@ def wheel_poll_thread(q): print('%d buttons found: %s' % (num_buttons, ', '.join(button_map))) # Enable FF - import evdev - from evdev import ecodes, InputDevice, ff + import evdev # pylint: disable=import-error + from evdev import ecodes, InputDevice # pylint: disable=import-error device = evdev.list_devices()[0] evtdev = InputDevice(device) val = 24000 @@ -141,44 +143,44 @@ def wheel_poll_thread(q): while True: evbuf = jsdev.read(8) - time, value, mtype, number = struct.unpack('IhBB', evbuf) + _, value, mtype, number = struct.unpack('IhBB', evbuf) # print(mtype, number, value) - if mtype & 0x02: # wheel & paddles + if mtype & 0x02: # wheel & paddles axis = axis_map[number] - if axis == "z": # gas + if axis == "z": # gas fvalue = value / 32767.0 axis_states[axis] = fvalue normalized = (1 - fvalue) * 50 q.put(str("throttle_%f" % normalized)) - if axis == "rz": # brake + if axis == "rz": # brake fvalue = value / 32767.0 axis_states[axis] = fvalue normalized = (1 - fvalue) * 50 q.put(str("brake_%f" % normalized)) - if axis == "x": # steer angle + if axis == "x": # steer angle fvalue = value / 32767.0 axis_states[axis] = fvalue normalized = fvalue q.put(str("steer_%f" % normalized)) - if mtype & 0x01: # buttons - if number in [0,19]: # X - if value == 1: # press down + if mtype & 0x01: # buttons + if number in [0, 19]: # X + if value == 1: # press down q.put(str("cruise_down")) - if number in [3,18]: # triangle - if value == 1: # press down + if number in [3, 18]: # triangle + if value == 1: # press down q.put(str("cruise_up")) - if number in [1,6]: # square - if value == 1: # press down + if number in [1, 6]: # square + if value == 1: # press down q.put(str("cruise_cancel")) - if number in [10,21]: # R3 - if value == 1: # press down + if number in [10, 21]: # R3 + if value == 1: # press down q.put(str("reverse_switch")) if __name__ == '__main__': diff --git a/tools/sim/start_carla.sh b/tools/sim/start_carla.sh index 42c956c2f7..cc5e961b81 100755 --- a/tools/sim/start_carla.sh +++ b/tools/sim/start_carla.sh @@ -15,4 +15,4 @@ if [ ! -d carla ]; then fi cd carla -./CarlaUE4.sh +./CarlaUE4.sh diff --git a/tools/sim/start_carla_docker.sh b/tools/sim/start_carla_docker.sh new file mode 100755 index 0000000000..46619d5d6a --- /dev/null +++ b/tools/sim/start_carla_docker.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +# Requires nvidia docker - https://github.com/NVIDIA/nvidia-docker +docker pull carlasim/carla:0.9.7 +docker run -p 2000-2002:2000-2002 --runtime=nvidia --gpus all carlasim/carla:0.9.7 diff --git a/release/id_rsa_public b/tools/ssh/id_rsa similarity index 100% rename from release/id_rsa_public rename to tools/ssh/id_rsa diff --git a/tools/ssh/key/id_rsa b/tools/ssh/key/id_rsa deleted file mode 100644 index 6a8ecfcce9..0000000000 --- a/tools/ssh/key/id_rsa +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC+iXXq30Tq+J5N -Kat3KWHCzcmwZ55nGh6WggAqECa5CasBlM9VeROpVu3beA+5h0MibRgbD4DMtVXB -t6gEvZ8nd04E7eLA9LTZyFDZ7SkSOVj4oXOQsT0GnJmKrASW5KslTWqVzTfo2XCt -Z+004ikLxmyFeBO8NOcErW1pa8gFdQDToH9FrA7kgysic/XVESTOoe7XlzRoe/eZ -acEQ+jtnmFd21A4aEADkk00Ahjr0uKaJiLUAPatxs2icIXWpgYtfqqtaKF23wSt6 -1OTu6cAwXbOWr3m+IUSRUO0IRzEIQS3z1jfd1svgzSgSSwZ1Lhj4AoKxIEAIc8qJ -rO4uymCJAgMBAAECggEBAISFevxHGdoL3Z5xkw6oO5SQKO2GxEeVhRzNgmu/HA+q -x8OryqD6O1CWY4037kft6iWxlwiLOdwna2P25ueVM3LxqdQH2KS4DmlCx+kq6FwC -gv063fQPMhC9LpWimvaQSPEC7VUPjQlo4tPY6sTTYBUOh0A1ihRm/x7juKuQCWix -Cq8C/DVnB1X4mGj+W3nJc5TwVJtgJbbiBrq6PWrhvB/3qmkxHRL7dU2SBb2iNRF1 -LLY30dJx/cD73UDKNHrlrsjk3UJc29Mp4/MladKvUkRqNwlYxSuAtJV0nZ3+iFkL -s3adSTHdJpClQer45R51rFDlVsDz2ZBpb/hRNRoGDuECgYEA6A1EixLq7QYOh3cb -Xhyh3W4kpVvA/FPfKH1OMy3ONOD/Y9Oa+M/wthW1wSoRL2n+uuIW5OAhTIvIEivj -6bAZsTT3twrvOrvYu9rx9aln4p8BhyvdjeW4kS7T8FP5ol6LoOt2sTP3T1LOuJPO -uQvOjlKPKIMh3c3RFNWTnGzMPa0CgYEA0jNiPLxP3A2nrX0keKDI+VHuvOY88gdh -0W5BuLMLovOIDk9aQFIbBbMuW1OTjHKv9NK+Lrw+YbCFqOGf1dU/UN5gSyE8lX/Q -FsUGUqUZx574nJZnOIcy3ONOnQLcvHAQToLFAGUd7PWgP3CtHkt9hEv2koUwL4vo -ikTP1u9Gkc0CgYEA2apoWxPZrY963XLKBxNQecYxNbLFaWq67t3rFnKm9E8BAICi -4zUaE5J1tMVi7Vi9iks9Ml9SnNyZRQJKfQ+kaebHXbkyAaPmfv+26rqHKboA0uxA -nDOZVwXX45zBkp6g1sdHxJx8JLoGEnkC9eyvSi0C//tRLx86OhLErXwYcNkCf1it -VMRKrWYoXJTUNo6tRhvodM88UnnIo3u3CALjhgU4uC1RTMHV4ZCGBwiAOb8GozSl -s5YD1E1iKwEULloHnK6BIh6P5v8q7J6uf/xdqoKMjlWBHgq6/roxKvkSPA1DOZ3l -jTadcgKFnRUmc+JT9p/ZbCxkA/ALFg8++G+0ghECgYA8vG3M/utweLvq4RI7l7U7 -b+i2BajfK2OmzNi/xugfeLjY6k2tfQGRuv6ppTjehtji2uvgDWkgjJUgPfZpir3I -RsVMUiFgloWGHETOy0Qvc5AwtqTJFLTD1Wza2uBilSVIEsg6Y83Gickh+ejOmEsY -6co17RFaAZHwGfCFFjO76Q== ------END PRIVATE KEY----- diff --git a/tools/ssh/key/id_rsa.ppk b/tools/ssh/key/id_rsa.ppk new file mode 100644 index 0000000000..7183e69dd0 --- /dev/null +++ b/tools/ssh/key/id_rsa.ppk @@ -0,0 +1,26 @@ +PuTTY-User-Key-File-2: ssh-rsa +Encryption: none +Comment: imported-openssh-key +Public-Lines: 6 +AAAAB3NzaC1yc2EAAAADAQABAAABAQC+iXXq30Tq+J5NKat3KWHCzcmwZ55nGh6W +ggAqECa5CasBlM9VeROpVu3beA+5h0MibRgbD4DMtVXBt6gEvZ8nd04E7eLA9LTZ +yFDZ7SkSOVj4oXOQsT0GnJmKrASW5KslTWqVzTfo2XCtZ+004ikLxmyFeBO8NOcE +rW1pa8gFdQDToH9FrA7kgysic/XVESTOoe7XlzRoe/eZacEQ+jtnmFd21A4aEADk +k00Ahjr0uKaJiLUAPatxs2icIXWpgYtfqqtaKF23wSt61OTu6cAwXbOWr3m+IUSR +UO0IRzEIQS3z1jfd1svgzSgSSwZ1Lhj4AoKxIEAIc8qJrO4uymCJ +Private-Lines: 14 +AAABAQCEhXr8RxnaC92ecZMOqDuUkCjthsRHlYUczYJrvxwPqsfDq8qg+jtQlmON +N+5H7eolsZcIizncJ2tj9ubnlTNy8anUB9ikuA5pQsfpKuhcAoL9Ot30DzIQvS6V +opr2kEjxAu1VD40JaOLT2OrE02AVDodANYoUZv8e47irkAlosQqvAvw1ZwdV+Jho +/lt5yXOU8FSbYCW24ga6uj1q4bwf96ppMR0S+3VNkgW9ojURdSy2N9HScf3A+91A +yjR65a7I5N1CXNvTKePzJWnSr1JEajcJWMUrgLSVdJ2d/ohZC7N2nUkx3SaQpUHq ++OUedaxQ5VbA89mQaW/4UTUaBg7hAAAAgQDoDUSLEurtBg6HdxteHKHdbiSlW8D8 +U98ofU4zLc404P9j05r4z/C2FbXBKhEvaf664hbk4CFMi8gSK+PpsBmxNPe3Cu86 +u9i72vH1qWfinwGHK92N5biRLtPwU/miXoug63axM/dPUs64k865C86OUo8ogyHd +zdEU1ZOcbMw9rQAAAIEA0jNiPLxP3A2nrX0keKDI+VHuvOY88gdh0W5BuLMLovOI +Dk9aQFIbBbMuW1OTjHKv9NK+Lrw+YbCFqOGf1dU/UN5gSyE8lX/QFsUGUqUZx574 +nJZnOIcy3ONOnQLcvHAQToLFAGUd7PWgP3CtHkt9hEv2koUwL4voikTP1u9Gkc0A +AACAPLxtzP7rcHi76uESO5e1O2/otgWo3ytjpszYv8boH3i42OpNrX0Bkbr+qaU4 +3obY4trr4A1pIIyVID32aYq9yEbFTFIhYJaFhhxEzstEL3OQMLakyRS0w9Vs2trg +YpUlSBLIOmPNxonJIfnozphLGOnKNe0RWgGR8BnwhRYzu+k= +Private-MAC: 2af7f5a599fa35e22392b7770a2eb7a0be8718b7 \ No newline at end of file diff --git a/tools/streamer/streamerd.py b/tools/streamer/streamerd.py index 6ce940afc0..7bfaeb38d5 100755 --- a/tools/streamer/streamerd.py +++ b/tools/streamer/streamerd.py @@ -1,4 +1,6 @@ #!/usr/bin/env python +# pylint: skip-file + import os import sys import zmq @@ -24,8 +26,8 @@ def receiver_thread(): if PYGAME: pygame.init() pygame.display.set_caption("vnet debug UI") - screen = pygame.display.set_mode((1164,874), pygame.DOUBLEBUF) - camera_surface = pygame.surface.Surface((1164,874), 0, 24).convert() + screen = pygame.display.set_mode((1164, 874), pygame.DOUBLEBUF) + camera_surface = pygame.surface.Surface((1164, 874), 0, 24).convert() addr = "192.168.5.11" if len(sys.argv) >= 2: @@ -38,12 +40,12 @@ def receiver_thread(): ctx = av.codec.codec.Codec('hevc', 'r').create() ctx.decode(av.packet.Packet(start.decode("hex"))) - import time + # import time while 1: - t1 = time.time() + # t1 = time.time() ts, raw = s.recv_multipart() ts = struct.unpack('q', ts)[0] * 1000 - t1, t2 = time.time(), t1 + # t1, t2 = time.time(), t1 #print 'ms to get frame:', (t1-t2)*1000 pkt = av.packet.Packet(raw) @@ -51,14 +53,14 @@ def receiver_thread(): if not f: continue f = f[0] - t1, t2 = time.time(), t1 + # t1, t2 = time.time(), t1 #print 'ms to decode:', (t1-t2)*1000 y_plane = np.frombuffer(f.planes[0], np.uint8).reshape((874, 1216))[:, 0:1164] u_plane = np.frombuffer(f.planes[1], np.uint8).reshape((437, 608))[:, 0:582] v_plane = np.frombuffer(f.planes[2], np.uint8).reshape((437, 608))[:, 0:582] yuv_img = y_plane.tobytes() + u_plane.tobytes() + v_plane.tobytes() - t1, t2 = time.time(), t1 + # t1, t2 = time.time(), t1 #print 'ms to make yuv:', (t1-t2)*1000 #print 'tsEof:', ts @@ -75,7 +77,7 @@ def receiver_thread(): #scipy.misc.imsave("tmp.png", imgff) - pygame.surfarray.blit_array(camera_surface, imgff.swapaxes(0,1)) + pygame.surfarray.blit_array(camera_surface, imgff.swapaxes(0, 1)) screen.blit(camera_surface, (0, 0)) pygame.display.flip() diff --git a/tools/ubuntu_setup.sh b/tools/ubuntu_setup.sh index a70def87a2..6b36369771 100755 --- a/tools/ubuntu_setup.sh +++ b/tools/ubuntu_setup.sh @@ -33,12 +33,15 @@ sudo apt-get update && sudo apt-get install -y \ libusb-1.0-0-dev \ libzmq3-dev \ libczmq-dev \ + libsdl-image1.2-dev libsdl-mixer1.2-dev libsdl-ttf2.0-dev libsmpeg-dev \ + libsdl1.2-dev libportmidi-dev libswscale-dev libavformat-dev libavcodec-dev libfreetype6-dev \ locales \ ocl-icd-libopencl1 \ ocl-icd-opencl-dev \ opencl-headers \ python-dev \ python-pip \ + qt5-default \ screen \ sudo \ vim \ @@ -59,7 +62,8 @@ fi # install bashrc source ~/.bashrc if [ -z "$OPENPILOT_ENV" ]; then - echo "source $HOME/openpilot/tools/openpilot_env.sh" >> ~/.bashrc + OP_DIR=$(git rev-parse --show-toplevel) + echo "source $OP_DIR/tools/openpilot_env.sh" >> ~/.bashrc source ~/.bashrc echo "added openpilot_env to bashrc" fi @@ -83,13 +87,7 @@ pyenv rehash pip install pipenv==2018.11.26 # pipenv setup (in openpilot dir) -pipenv install --system --deploy - -# to make tools work -pip install -r tools/requirements.txt - -# to make modeld work on PC with nvidia GPU -pip install tensorflow-gpu==2.1 +pipenv install --dev --system --deploy # for loggerd to work on ubuntu # TODO: PC should log somewhere else diff --git a/tools/webcam/README.md b/tools/webcam/README.md index 89f1ac3a62..c1e7d27d07 100644 --- a/tools/webcam/README.md +++ b/tools/webcam/README.md @@ -1,49 +1,48 @@ Run openpilot with webcam on PC/laptop ===================== -What's needed: -- Ubuntu 16.04 -- Python 3.7.3 -- GPU (recommended) -- Two USB webcams, at least 720p and 78 degrees FOV (e.g. Logitech C920/C615) -- [Car harness](https://comma.ai/shop/products/comma-car-harness) w/ black panda (or the outdated grey panda/giraffe combo) to connect to your car -- [Panda paw](https://comma.ai/shop/products/panda-paw) (or USB-A to USB-A cable) to connect panda to your computer -- Tape, Charger, ... -That's it! +What's needed: +- Ubuntu 16.04 +- Python 3.7.3 +- GPU (recommended) +- Two USB webcams, at least 720p and 78 degrees FOV (e.g. Logitech C920/C615) +- [Car harness](https://comma.ai/shop/products/comma-car-harness) with black panda (or the outdated grey panda/giraffe combo) to connect to your car +- [Panda paw](https://comma.ai/shop/products/panda-paw) (or USB-A to USB-A cable) to connect panda to your computer +- Tape, Charger, ... +That's it! -## Clone openpilot and install the requirements +## Clone openpilot and install the requirements ``` -cd ~ -git clone https://github.com/commaai/openpilot.git +cd ~ +git clone https://github.com/commaai/openpilot.git ``` -- Follow [this readme](https://github.com/commaai/openpilot/tree/master/tools) to install the requirements -- Add line "export PYTHONPATH=$HOME/openpilot" to your ~/.bashrc -- You also need to install tensorflow-gpu 2.1.0 (if not working, try 2.0.0) and nvidia drivers: nvidia-xxx/cuda10.0/cudnn7.6.5 -- Install [OpenCL Driver](http://registrationcenter-download.intel.com/akdlm/irc_nas/12556/opencl_runtime_16.1.2_x64_rh_6.4.0.37.tgz) -- (Note: the code assumes cl platforms order to be 0.GPU/1.CPU when running clinfo; if reverse, change the -1 to -2 in selfdrive/modeld/modeld.cc#L130; helping us refactor this mess is encouraged) -- Install [OpenCV4](https://www.pyimagesearch.com/2018/08/15/how-to-install-opencv-4-on-ubuntu/) (ignore the Python part) +- Follow [this readme](https://github.com/commaai/openpilot/tree/master/tools) to install the requirements +- Add line "export PYTHONPATH=$HOME/openpilot" to your ~/.bashrc +- Install tensorflow 2.2 and nvidia drivers: nvidia-xxx/cuda10.0/cudnn7.6.5 +- Install [OpenCL Driver](http://registrationcenter-download.intel.com/akdlm/irc_nas/vcp/15532/l_opencl_p_18.1.0.015.tgz) +- Install [OpenCV4](https://www.pyimagesearch.com/2018/08/15/how-to-install-opencv-4-on-ubuntu/) (ignore the Python part) -## Build openpilot for webcam +## Build openpilot for webcam ``` -cd ~/openpilot +cd ~/openpilot ``` -- check out selfdrive/camerad/cameras/camera_webcam.cc line72&146 before building if any camera is upside down +- check out selfdrive/camerad/cameras/camera_webcam.cc lines 72 and 146 before building if any camera is upside down ``` -scons use_webcam=1 -touch prebuilt +scons use_webcam=1 +touch prebuilt ``` -## Connect the hardwares -- Connect the road facing camera first, then the driver facing camera -- (default indexes are 1 and 2; can be modified in selfdrive/camerad/cameras/camera_webcam.cc) -- Connect your computer to panda +## Connect the hardware +- Connect the road facing camera first, then the driver facing camera +- (default indexes are 1 and 2; can be modified in selfdrive/camerad/cameras/camera_webcam.cc) +- Connect your computer to panda -## GO +## GO ``` -cd ~/openpilot/tools/webcam -./accept_terms.py # accept the user terms so that thermald can detect the car started -cd ~/openpilot/selfdrive -PASSIVE=0 NOSENSOR=1 WEBCAM=1 ./manager.py +cd ~/openpilot/tools/webcam +./accept_terms.py # accept the user terms so that thermald can detect the car started +cd ~/openpilot/selfdrive +PASSIVE=0 NOSENSOR=1 WEBCAM=1 ./manager.py ``` -- Start the car, then the UI should show the road webcam's view -- Adjust and secure the webcams (you can run tools/webcam/front_mount_helper.py to help mount the driver camera) -- Finish calibration and engage! +- Start the car, then the UI should show the road webcam's view +- Adjust and secure the webcams (you can run tools/webcam/front_mount_helper.py to help mount the driver camera) +- Finish calibration and engage! diff --git a/tools/webcam/accept_terms.py b/tools/webcam/accept_terms.py index e7757511d8..a5445a5719 100755 --- a/tools/webcam/accept_terms.py +++ b/tools/webcam/accept_terms.py @@ -6,4 +6,4 @@ if __name__ == '__main__': params = Params() params.put("HasAcceptedTerms", str(terms_version, 'utf-8')) params.put("CompletedTrainingVersion", str(training_version, 'utf-8')) - print("Terms Accepted!") \ No newline at end of file + print("Terms Accepted!") diff --git a/tools/webcam/front_mount_helper.py b/tools/webcam/front_mount_helper.py index 1fdca3225a..2ae35992ec 100755 --- a/tools/webcam/front_mount_helper.py +++ b/tools/webcam/front_mount_helper.py @@ -2,8 +2,8 @@ import numpy as np # copied from common.transformations/camera.py -eon_dcam_focal_length = 860.0 # pixels -webcam_focal_length = 908.0 # pixels +eon_dcam_focal_length = 860.0 # pixels +webcam_focal_length = 908.0 # pixels eon_dcam_intrinsics = np.array([ [eon_dcam_focal_length, 0, 1152/2.], @@ -18,9 +18,9 @@ webcam_intrinsics = np.array([ cam_id = 2 if __name__ == "__main__": - import cv2 + import cv2 # pylint: disable=import-error - trans_webcam_to_eon_front = np.dot(eon_dcam_intrinsics,np.linalg.inv(webcam_intrinsics)) + trans_webcam_to_eon_front = np.dot(eon_dcam_intrinsics, np.linalg.inv(webcam_intrinsics)) cap = cv2.VideoCapture(cam_id) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) @@ -29,7 +29,7 @@ if __name__ == "__main__": while (True): ret, img = cap.read() if ret: - img = cv2.warpPerspective(img, trans_webcam_to_eon_front, (1152,864), borderMode=cv2.BORDER_CONSTANT, borderValue=0) - img = img[:,-864//2:,:] + img = cv2.warpPerspective(img, trans_webcam_to_eon_front, (1152, 864), borderMode=cv2.BORDER_CONSTANT, borderValue=0) + img = img[:, -864//2:, :] cv2.imshow('preview', img) - cv2.waitKey(10) \ No newline at end of file + cv2.waitKey(10) diff --git a/tools/webcam/warp_vis.py b/tools/webcam/warp_vis.py index 547f1be99a..4331614acf 100755 --- a/tools/webcam/warp_vis.py +++ b/tools/webcam/warp_vis.py @@ -2,10 +2,10 @@ import numpy as np # copied from common.transformations/camera.py -eon_focal_length = 910.0 # pixels -eon_dcam_focal_length = 860.0 # pixels +eon_focal_length = 910.0 # pixels +eon_dcam_focal_length = 860.0 # pixels -webcam_focal_length = -908.0/1.5 # pixels +webcam_focal_length = -908.0/1.5 # pixels eon_intrinsics = np.array([ [eon_focal_length, 0., 1164/2.], @@ -23,9 +23,9 @@ webcam_intrinsics = np.array([ [ 0., 0., 1.]]) if __name__ == "__main__": - import cv2 - trans_webcam_to_eon_rear = np.dot(eon_intrinsics,np.linalg.inv(webcam_intrinsics)) - trans_webcam_to_eon_front = np.dot(eon_dcam_intrinsics,np.linalg.inv(webcam_intrinsics)) + import cv2 # pylint: disable=import-error + trans_webcam_to_eon_rear = np.dot(eon_intrinsics, np.linalg.inv(webcam_intrinsics)) + trans_webcam_to_eon_front = np.dot(eon_dcam_intrinsics, np.linalg.inv(webcam_intrinsics)) print("trans_webcam_to_eon_rear:\n", trans_webcam_to_eon_rear) print("trans_webcam_to_eon_front:\n", trans_webcam_to_eon_front) @@ -37,9 +37,7 @@ if __name__ == "__main__": ret, img = cap.read() if ret: # img = cv2.warpPerspective(img, trans_webcam_to_eon_rear, (1164,874), borderMode=cv2.BORDER_CONSTANT, borderValue=0) - img = cv2.warpPerspective(img, trans_webcam_to_eon_front, (1164,874), borderMode=cv2.BORDER_CONSTANT, borderValue=0) + img = cv2.warpPerspective(img, trans_webcam_to_eon_front, (1164, 874), borderMode=cv2.BORDER_CONSTANT, borderValue=0) print(img.shape, end='\r') cv2.imshow('preview', img) cv2.waitKey(10) - - diff --git a/update_requirements.sh b/update_requirements.sh index 2c9175ecdd..d1fdfd4633 100755 --- a/update_requirements.sh +++ b/update_requirements.sh @@ -3,4 +3,4 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" cd "$DIR" -sudo -- bash -c "source /etc/profile.d/comma_dev.sh; pip install pip==19.2.3 git+git://github.com/pypa/pipenv.git@7a12dbb5cacc71d1dd2d74d8cce8eb50ce2db121; pipenv install --dev --deploy --system" +sudo -- bash -c "source /etc/profile.d/comma_dev.sh; pip install pip==20.1.1 git+git://github.com/pypa/pipenv.git@7a12dbb5cacc71d1dd2d74d8cce8eb50ce2db121; pipenv install --dev --deploy --system"