mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-08-24 17:53:43 +08:00
Compare commits
118 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4474b9b371 | |||
| 26e966852c | |||
| 75ac92b90f | |||
| 852166f5cc | |||
| b68f3f7781 | |||
| 96f8e5158e | |||
| 36bef17224 | |||
| 715771bcff | |||
| 8e264baaa2 | |||
| 8ff147de6d | |||
| 71057c586f | |||
| fac22f4038 | |||
| 40094779d7 | |||
| 2552aa45c3 | |||
| c2972a80f9 | |||
| 791a440709 | |||
| 13145dd9a7 | |||
| e9c477dcf2 | |||
| 8eebd19884 | |||
| a54b35a4d6 | |||
| 8a6f7a5e78 | |||
| 6752959d4a | |||
| da52d065a4 | |||
| 255e45ca58 | |||
| b731b7cf12 | |||
| 5f014635e1 | |||
| ef3d8314d3 | |||
| 7ef3fd567f | |||
| b773e27ad1 | |||
| a77c0a1098 | |||
| c7b5fb9116 | |||
| 57b9ddf20e | |||
| ba97d0e838 | |||
| b8085e2c42 | |||
| c251b312d8 | |||
| 14fb17e22f | |||
| a34c87ab46 | |||
| 1ad9cc8c67 | |||
| 5627d0d7fd | |||
| 2cfdbefde8 | |||
| 7dabcdace8 | |||
| 187a70f760 | |||
| 48303589e9 | |||
| 8385b27cad | |||
| abd75aedd7 | |||
| daf54ad54d | |||
| 94fe677f91 | |||
| 3de85098e5 | |||
| 5524dc8773 | |||
| 19dd5f3e32 | |||
| 99cb610b12 | |||
| 9d3963559a | |||
| 1b8c44b506 | |||
| 6f46f988d9 | |||
| 68485aa4e4 | |||
| 1581fdc198 | |||
| 317ae0fb37 | |||
| 5bf4196aed | |||
| 38aa03e0f7 | |||
| 9a9dc3ab23 | |||
| e4aa959e2c | |||
| 2aa9a56f40 | |||
| 721ed4ec0e | |||
| 70be4ceab1 | |||
| 5cf91d0496 | |||
| 6fee0bdb2d | |||
| e40c161125 | |||
| 97eb55cc55 | |||
| 65134be0d1 | |||
| dbf71a23aa | |||
| 7fec3db1d6 | |||
| 26b573c1d0 | |||
| 5ec1e7307e | |||
| 8bc36b7f21 | |||
| 3b909eb693 | |||
| 57e39c4472 | |||
| ff7672339c | |||
| 6e824a2c22 | |||
| 32fa49e093 | |||
| 2250eac58f | |||
| 97be6b3a0e | |||
| 942655c947 | |||
| 615db3f7fd | |||
| 0bb75c5389 | |||
| 7b5ee81d2d | |||
| 7fe46f1e1d | |||
| 50c0d1c9da | |||
| 6dbf544d06 | |||
| 41e3a0f699 | |||
| c5d8aec28b | |||
| 4653a9aef0 | |||
| ab3492bb90 | |||
| ed7cbb3866 | |||
| a30626cfe3 | |||
| d2c087b3e2 | |||
| 0a747f991d | |||
| f5a1e86d85 | |||
| 693bcb0f83 | |||
| 0d0daed86e | |||
| 95a349abcc | |||
| c6ba5dc539 | |||
| 6c3afeec0f | |||
| 29c58b4588 | |||
| ecc565aa3f | |||
| db61810f98 | |||
| 48f203ad5b | |||
| 6ab4ac2dfb | |||
| 9cb3c7b6e6 | |||
| adaa4ed350 | |||
| a64b9aa9b8 | |||
| 0138eca61d | |||
| 139a40de29 | |||
| 17d9becd3c | |||
| 449b482cc3 | |||
| a7e099c946 | |||
| 610462be5a | |||
| 207d32668f | |||
| e94a30bec0 |
@@ -1,277 +0,0 @@
|
||||
name: Compile FrogPilot
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
runner:
|
||||
description: "Select the runner"
|
||||
required: true
|
||||
default: "c3"
|
||||
type: choice
|
||||
options:
|
||||
- c3
|
||||
- c3x
|
||||
not_vetted:
|
||||
description: "This branch is not vetted"
|
||||
required: false
|
||||
default: "false"
|
||||
type: boolean
|
||||
publish_frogpilot:
|
||||
description: "Push to FrogPilot"
|
||||
required: false
|
||||
default: "false"
|
||||
type: boolean
|
||||
publish_staging:
|
||||
description: "Push to FrogPilot-Staging"
|
||||
required: false
|
||||
default: "false"
|
||||
type: boolean
|
||||
publish_testing:
|
||||
description: "Push to FrogPilot-Testing"
|
||||
required: false
|
||||
default: "false"
|
||||
type: boolean
|
||||
publish_custom_branch:
|
||||
description: "Push to custom branch:"
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
update_translations:
|
||||
description: "Update missing/outdated translations"
|
||||
required: false
|
||||
default: "false"
|
||||
type: boolean
|
||||
vet_existing_translations:
|
||||
description: "Vet existing translations"
|
||||
required: false
|
||||
default: "false"
|
||||
type: boolean
|
||||
|
||||
env:
|
||||
BASEDIR: "${{ github.workspace }}"
|
||||
BUILD_DIR: /data/openpilot
|
||||
OPENAI_API_KEY: "${{ secrets.OPENAI_API_KEY }}"
|
||||
|
||||
jobs:
|
||||
get_branch:
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ${{ github.event.inputs.runner }}
|
||||
outputs:
|
||||
branch: ${{ steps.get_branch.outputs.branch }}
|
||||
python_version: ${{ steps.get_python_version.outputs.python_version }}
|
||||
steps:
|
||||
- name: Determine Current Branch on Runner
|
||||
id: get_branch
|
||||
run: |
|
||||
cd $BUILD_DIR
|
||||
|
||||
BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
echo "branch=$BRANCH" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Get Python Version from Runner
|
||||
id: get_python_version
|
||||
run: |
|
||||
PYTHON_VERSION=$(tr -d '[:space:]' < "$BUILD_DIR/.python-version")
|
||||
echo "python_version=$PYTHON_VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
translate:
|
||||
if: inputs.update_translations
|
||||
needs: get_branch
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Configure Git Identity
|
||||
run: |
|
||||
git config --global user.name "James"
|
||||
git config --global user.email "91348155+FrogAi@users.noreply.github.com"
|
||||
|
||||
- name: Checkout Required Files
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ needs.get_branch.outputs.branch }}
|
||||
sparse-checkout: |
|
||||
frogpilot/ui/
|
||||
selfdrive/controls/lib/alerts_offroad.json
|
||||
selfdrive/ui/
|
||||
selfdrive/ui/update_translations.py
|
||||
selfdrive/ui/translations/
|
||||
selfdrive/ui/translations/auto_translate.py
|
||||
|
||||
- name: Set Up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "${{ needs.get_branch.outputs.python_version }}"
|
||||
|
||||
- name: Install Dependencies
|
||||
run: pip install requests
|
||||
|
||||
- name: Install Qt5 Tools
|
||||
run: sudo apt update && sudo apt install -y qttools5-dev-tools
|
||||
|
||||
- name: Update Translations
|
||||
run: python selfdrive/ui/update_translations.py --vanish
|
||||
|
||||
- name: Update Missing Translations
|
||||
continue-on-error: true
|
||||
run: python selfdrive/ui/translations/auto_translate.py --all-files
|
||||
timeout-minutes: 300
|
||||
|
||||
- name: Vet Existing Translations
|
||||
if: github.event.inputs.vet_existing_translations == 'true'
|
||||
continue-on-error: true
|
||||
run: python selfdrive/ui/translations/auto_translate.py --all-files --vet-translations
|
||||
timeout-minutes: 300
|
||||
|
||||
- name: Commit and Push Translation Updates
|
||||
run: |
|
||||
if git diff --quiet selfdrive/ui/translations/*.ts; then
|
||||
echo "No translation updates detected."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git fetch --unshallow origin ${{ needs.get_branch.outputs.branch }}
|
||||
git checkout ${{ needs.get_branch.outputs.branch }}
|
||||
git add selfdrive/ui/translations/*.ts
|
||||
git commit --amend --no-edit
|
||||
git push --force origin ${{ needs.get_branch.outputs.branch }}
|
||||
|
||||
build_and_push:
|
||||
needs:
|
||||
- get_branch
|
||||
- translate
|
||||
if: always()
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ${{ github.event.inputs.runner }}
|
||||
permissions:
|
||||
contents: write
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
steps:
|
||||
- name: Configure Git Identity
|
||||
run: |
|
||||
git config --global http.postBuffer 104857600
|
||||
|
||||
git config --global user.name "James"
|
||||
git config --global user.email "91348155+FrogAi@users.noreply.github.com"
|
||||
|
||||
- name: Update Repository
|
||||
run: |
|
||||
git remote set-url origin https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/FrogAi/FrogPilot.git
|
||||
|
||||
if [ "${{ github.event.inputs.update_translations }}" = "true" ]; then
|
||||
git fetch origin ${{ needs.get_branch.outputs.branch }}
|
||||
git reset --hard FETCH_HEAD
|
||||
fi
|
||||
|
||||
- name: Take Ownership of Build
|
||||
run: |
|
||||
sudo chown -R $(whoami):$(whoami) .
|
||||
|
||||
- name: Finalize Build
|
||||
run: |
|
||||
rm -f .clang-tidy
|
||||
rm -f .dockerignore
|
||||
rm -f .editorconfig
|
||||
rm -f .gitattributes
|
||||
rm -f .gitmodules
|
||||
rm -f .lfsconfig
|
||||
rm -f .overlay_init
|
||||
rm -f .pre-commit-config.yaml
|
||||
rm -f .sconsign.dblite
|
||||
rm -f codecov.yml
|
||||
rm -f conftest.py
|
||||
rm -f poetry.lock
|
||||
rm -f pyproject.toml
|
||||
rm -f teleoprtc
|
||||
rm -f Dockerfile.openpilot
|
||||
rm -f Dockerfile.openpilot_base
|
||||
rm -f Jenkinsfile
|
||||
|
||||
rm -f panda/board/obj/.placeholder
|
||||
rm -f panda/board/obj/bootstub.panda.elf
|
||||
rm -f panda/board/obj/bootstub.panda_h7.elf
|
||||
rm -f panda/board/obj/panda.bin
|
||||
rm -f panda/board/obj/panda.elf
|
||||
rm -f panda/board/obj/panda_h7.bin
|
||||
rm -f panda/board/obj/panda_h7.elf
|
||||
rm -f panda/board/obj/version
|
||||
|
||||
find . -name '*.a' -delete
|
||||
find . -name '*.o' -delete
|
||||
find . -name '*.onnx' -delete
|
||||
find . -name '*.os' -delete
|
||||
find . -name '*.pyc' -delete
|
||||
find . -name 'moc_*' -delete
|
||||
|
||||
rm -rf .devcontainer/
|
||||
rm -rf .vscode/
|
||||
rm -rf body/
|
||||
rm -rf opendbc/generator/
|
||||
rm -rf release/
|
||||
rm -rf scripts/
|
||||
rm -rf site_scons/
|
||||
rm -rf teleoprtc_repo/
|
||||
|
||||
find .github -mindepth 1 -maxdepth 1 ! -name 'workflows' -exec rm -rf {} +
|
||||
|
||||
find .github/workflows -mindepth 1 ! \( \
|
||||
-type f \( \
|
||||
-name 'compile_frogpilot.yaml' -o \
|
||||
-name 'review_pull_request.yaml' -o \
|
||||
-name 'schedule_update.yaml' -o \
|
||||
-name 'update_pr_branch.yaml' -o \
|
||||
-name 'update_release_branch.yaml' -o \
|
||||
-name 'update_tinygrad.yaml' \
|
||||
\) \
|
||||
\) -exec rm -rf {} +
|
||||
|
||||
find panda/board/jungle -type f ! -name '__init__.py' -delete
|
||||
find panda/board/jungle -type d -empty -delete
|
||||
|
||||
find third_party/ -name '*x86*' -exec rm -rf {} +
|
||||
find third_party/ -name '*Darwin*' -exec rm -rf {} +
|
||||
|
||||
find tools/ -mindepth 1 -maxdepth 1 ! \( -name '__init__.py' -o -name 'bodyteleop' -o -name 'lib' -o -name 'scripts' \) -exec rm -rf {} +
|
||||
|
||||
find . -name 'SConstruct' -delete
|
||||
find . -name 'SConscript' -delete
|
||||
|
||||
find . -type d \( -iname "debug" -o -iname "test" -o -iname "tests" \) -exec rm -rf {} +
|
||||
find . -type d -empty ! -path "./.git*" -delete
|
||||
find . -type d -name '__pycache__' -exec rm -rf {} +
|
||||
find . -type f -regex '.*matlab.*\.md' -delete
|
||||
|
||||
touch prebuilt
|
||||
|
||||
if [ "${{ github.event.inputs.not_vetted }}" = "true" ]; then
|
||||
touch not_vetted
|
||||
fi
|
||||
|
||||
- name: Add the update_date file
|
||||
if: github.event.inputs.publish_staging == 'true'
|
||||
run: |
|
||||
curl -fLsS https://raw.githubusercontent.com/FrogAi/FrogPilot/FrogPilot-Staging/.github/update_date -o .github/update_date || echo "No update_date found, skipping."
|
||||
|
||||
- name: Commit Build
|
||||
run: |
|
||||
git add -f .
|
||||
git commit -m "Compile FrogPilot"
|
||||
git push --force origin HEAD
|
||||
|
||||
if [ "${{ github.event.inputs.publish_frogpilot }}" = "true" ]; then
|
||||
git push --force origin HEAD:"FrogPilot"
|
||||
fi
|
||||
|
||||
if [ "${{ github.event.inputs.publish_staging }}" = "true" ]; then
|
||||
git push --force origin HEAD:"FrogPilot-Staging"
|
||||
fi
|
||||
|
||||
if [ "${{ github.event.inputs.publish_testing }}" = "true" ]; then
|
||||
git push --force origin HEAD:"FrogPilot-Testing"
|
||||
fi
|
||||
|
||||
if [ -n "${{ github.event.inputs.publish_custom_branch }}" ]; then
|
||||
git push --force origin HEAD:"${{ github.event.inputs.publish_custom_branch }}"
|
||||
fi
|
||||
@@ -1,34 +0,0 @@
|
||||
name: Review Pull Request
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, reopened]
|
||||
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||
|
||||
jobs:
|
||||
pr_check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Exit If PR Opened by FrogAi
|
||||
if: ${{ github.actor == 'FrogAi' }}
|
||||
run: |
|
||||
echo PR opened or reopened by FrogAi. No action needed.
|
||||
exit 0
|
||||
|
||||
- name: Close PR for Invalid Target Branch
|
||||
if: ${{ github.base_ref != 'MAKE-PRS-HERE' }}
|
||||
run: |
|
||||
gh api repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments \
|
||||
-f body="Please submit your pull request to the \"MAKE-PRS-HERE\" branch."
|
||||
|
||||
gh api repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }} \
|
||||
-X PATCH \
|
||||
-f state="closed"
|
||||
|
||||
- name: Acknowledge PR for Valid Target Branch
|
||||
if: ${{ github.base_ref == 'MAKE-PRS-HERE' }}
|
||||
run: |
|
||||
gh api repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments \
|
||||
-f body="Thank you for your PR! If you're not already in the FrogPilot Discord, [feel free to join](https://discord.FrogPilot.download) and let me know you've opened a PR!"
|
||||
@@ -1,57 +0,0 @@
|
||||
name: Schedule FrogPilot Update
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
scheduled_date:
|
||||
description: "Enter the date to update the \"FrogPilot\" branch (YYYY-MM-DD)"
|
||||
required: true
|
||||
|
||||
env:
|
||||
BRANCH: FrogPilot-Staging
|
||||
|
||||
jobs:
|
||||
schedule-update:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Configure Git Identity
|
||||
run: |
|
||||
git config --global user.name "James"
|
||||
git config --global user.email "91348155+FrogAi@users.noreply.github.com"
|
||||
|
||||
- name: Checkout ${{ env.BRANCH }}
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ env.BRANCH }}
|
||||
fetch-depth: 3
|
||||
|
||||
- name: Schedule Update for ${{ github.event.inputs.scheduled_date }}
|
||||
run: |
|
||||
echo "${{ github.event.inputs.scheduled_date }}" > .github/update_date
|
||||
git add .github/update_date
|
||||
|
||||
- name: Get Target Commit (Second Most Recent)
|
||||
id: get_target
|
||||
run: |
|
||||
TARGET_COMMIT=$(git rev-parse HEAD~1)
|
||||
|
||||
AUTHOR_DATE=$(git show -s --format=%aD "$TARGET_COMMIT")
|
||||
COMMITTER_DATE=$(git show -s --format=%cD "$TARGET_COMMIT")
|
||||
|
||||
echo "AUTHOR_DATE=$AUTHOR_DATE" >> $GITHUB_ENV
|
||||
echo "COMMITTER_DATE=$COMMITTER_DATE" >> $GITHUB_ENV
|
||||
echo "TARGET_COMMIT=$TARGET_COMMIT" >> $GITHUB_ENV
|
||||
|
||||
- name: Create Fixup Commit for ${{ env.TARGET_COMMIT }}
|
||||
run: git commit --fixup="${{ env.TARGET_COMMIT }}"
|
||||
|
||||
- name: Autosquash Fixup into Target Commit
|
||||
run: |
|
||||
GIT_SEQUENCE_EDITOR=: git rebase --autosquash -i HEAD~3
|
||||
|
||||
- name: Restore Timestamps on Final Two Commits
|
||||
run: |
|
||||
git rebase --exec "GIT_COMMITTER_DATE='${{ env.COMMITTER_DATE }}' git commit --amend --no-edit --date='${{ env.AUTHOR_DATE }}'" HEAD~2
|
||||
|
||||
- name: Push Updated ${{ env.BRANCH }} Branch
|
||||
run: git push origin "${{ env.BRANCH }}" --force-with-lease
|
||||
@@ -1,85 +0,0 @@
|
||||
name: Update MAKE-PRS-HERE
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- FrogPilot-Staging
|
||||
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||
|
||||
SOURCE_BRANCH: FrogPilot-Staging
|
||||
TARGET_BRANCH: MAKE-PRS-HERE
|
||||
|
||||
jobs:
|
||||
update_branch:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Configure Git Identity
|
||||
run: |
|
||||
git config --global user.name "James"
|
||||
git config --global user.email "91348155+FrogAi@users.noreply.github.com"
|
||||
|
||||
- name: Checkout ${{ env.SOURCE_BRANCH }}
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
fetch-depth: 0
|
||||
|
||||
ref: ${{ env.SOURCE_BRANCH }}
|
||||
|
||||
- name: Find "Compile FrogPilot" Commit in ${{ env.SOURCE_BRANCH }}
|
||||
id: find_parent
|
||||
run: |
|
||||
COMMIT=$(git rev-list HEAD -n 1 --grep="Compile FrogPilot")
|
||||
[ -z "$COMMIT" ] && echo "Compile commit not found." >&2 && exit 1
|
||||
|
||||
PARENT=$(git rev-list --parents -n 1 "$COMMIT" | awk '{print $2}')
|
||||
[ -z "$PARENT" ] && echo "Parent commit not found." >&2 && exit 1
|
||||
|
||||
echo "parent_commit=$PARENT" >> "$GITHUB_OUTPUT"
|
||||
echo "compile_commit=$COMMIT" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Fetch and Checkout ${{ env.TARGET_BRANCH }}
|
||||
run: |
|
||||
git fetch origin "${{ env.TARGET_BRANCH }}"
|
||||
git checkout "${{ env.TARGET_BRANCH }}"
|
||||
|
||||
- name: Clean ${{ env.TARGET_BRANCH }} and Apply Updates from ${{ env.SOURCE_BRANCH }}
|
||||
run: |
|
||||
git rm -r --ignore-unmatch .
|
||||
git clean -fdx
|
||||
git checkout "${{ steps.find_parent.outputs.parent_commit }}" -- .
|
||||
|
||||
COMPILE_COMMIT="${{ steps.find_parent.outputs.compile_commit }}"
|
||||
SOURCE_HEAD=$(git rev-parse "origin/${{ env.SOURCE_BRANCH }}")
|
||||
|
||||
[ "$COMPILE_COMMIT" != "$SOURCE_HEAD" ] && git cherry-pick --no-commit "${COMPILE_COMMIT}".."$SOURCE_HEAD"
|
||||
|
||||
rm -f .github/update_date
|
||||
|
||||
git add --all
|
||||
|
||||
- name: Commit and Push to ${{ env.TARGET_BRANCH }}
|
||||
run: |
|
||||
TZ_VALUE="America/Phoenix"
|
||||
day=$(TZ="$TZ_VALUE" date +"%-d")
|
||||
month=$(TZ="$TZ_VALUE" date +"%B")
|
||||
year=$(TZ="$TZ_VALUE" date +"%Y")
|
||||
|
||||
case $day in
|
||||
11|12|13) s=th ;;
|
||||
*) case $((day % 10)) in 1) s=st ;; 2) s=nd ;; 3) s=rd ;; *) s=th ;; esac ;;
|
||||
esac
|
||||
|
||||
commit_message="${month} ${day}${s}, ${year} Update"
|
||||
|
||||
if git log -1 --pretty=%s | grep -q "$commit_message"; then
|
||||
git commit --amend --no-edit
|
||||
else
|
||||
git commit -m "$commit_message"
|
||||
fi
|
||||
|
||||
git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}
|
||||
git push origin "${{ env.TARGET_BRANCH }}" --force
|
||||
@@ -1,131 +0,0 @@
|
||||
name: Update FrogPilot Branch
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 18 * * 6"
|
||||
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||
|
||||
BRANCH_FROGPILOT: FrogPilot
|
||||
BRANCH_PREVIOUS: FrogPilot-Previous
|
||||
BRANCH_STAGING: FrogPilot-Staging
|
||||
|
||||
TZ: America/Phoenix
|
||||
|
||||
UPDATE_FILE: .github/update_date
|
||||
|
||||
jobs:
|
||||
check_update:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
update_due: ${{ steps.check_update.outputs.update_due }}
|
||||
scheduled_date: ${{ steps.check_update.outputs.scheduled_date }}
|
||||
steps:
|
||||
- name: Download the "update_date" File
|
||||
id: download_update
|
||||
run: |
|
||||
curl -fLsS "https://raw.githubusercontent.com/FrogAi/FrogPilot/${{ env.BRANCH_STAGING }}/${{ env.UPDATE_FILE }}" -o update_date || touch update_date_missing
|
||||
|
||||
- name: Check If Update Is Due
|
||||
id: check_update
|
||||
run: |
|
||||
if [ -f update_date_missing ]; then
|
||||
echo "update_due=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
SCHEDULED_DATE=$(cat update_date)
|
||||
CURRENT_DATE=$(TZ="${{ env.TZ }}" date +%F)
|
||||
|
||||
if [ "$SCHEDULED_DATE" != "$CURRENT_DATE" ]; then
|
||||
echo "update_due=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "update_due=true" >> "$GITHUB_OUTPUT"
|
||||
echo "scheduled_date=$SCHEDULED_DATE" >> "$GITHUB_OUTPUT"
|
||||
|
||||
update_branch:
|
||||
needs: check_update
|
||||
if: ${{ needs.check_update.outputs.update_due == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Configure Git Identity
|
||||
run: |
|
||||
git config --global user.name "James"
|
||||
git config --global user.email "91348155+FrogAi@users.noreply.github.com"
|
||||
|
||||
- name: Checkout ${{ env.BRANCH_STAGING }}
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ env.BRANCH_STAGING }}
|
||||
|
||||
- name: Authenticate with GITHUB_TOKEN
|
||||
run: |
|
||||
git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}
|
||||
|
||||
- name: Update README Date and Remove update file
|
||||
run: |
|
||||
DAY=$(TZ="${{ env.TZ }}" date +'%d' | sed 's/^0//')
|
||||
|
||||
case "$DAY" in
|
||||
1|21|31) SUFFIX="st" ;;
|
||||
2|22) SUFFIX="nd" ;;
|
||||
3|23) SUFFIX="rd" ;;
|
||||
*) SUFFIX="th" ;;
|
||||
esac
|
||||
|
||||
MONTH=$(TZ="${{ env.TZ }}" date +'%B')
|
||||
YEAR=$(TZ="${{ env.TZ }}" date +'%Y')
|
||||
|
||||
DATE="${MONTH} ${DAY}${SUFFIX}, ${YEAR}"
|
||||
DATE_ESCAPED=$(printf '%s' "$DATE" | sed -E 's/ /%20/g; s/,/%2C/g')
|
||||
|
||||
sed -i -E "s|(Last%20Updated-)[^-)]*|\1${DATE_ESCAPED}|g" README.md
|
||||
|
||||
git add README.md
|
||||
git rm -f "${{ env.UPDATE_FILE }}"
|
||||
git commit -m "Updated README date to ${DATE}"
|
||||
|
||||
- name: Squash Commits
|
||||
run: |
|
||||
COMMIT_MSG=$(git log -1 --pretty=%B HEAD~1)
|
||||
|
||||
git reset --soft HEAD~2
|
||||
git commit -m "$COMMIT_MSG"
|
||||
|
||||
- name: Rewrite Commit Dates to Noon ${{ env.TZ }}
|
||||
run: |
|
||||
COMMIT_DATETIME="${{ needs.check_update.outputs.scheduled_date }} 12:00"
|
||||
COMMIT_PHX=$(TZ="${{ env.TZ }}" date -d "$COMMIT_DATETIME" +"%Y-%m-%dT%H:%M:%S %z")
|
||||
|
||||
git filter-branch --env-filter "export GIT_AUTHOR_DATE='$COMMIT_PHX'; export GIT_COMMITTER_DATE='$COMMIT_PHX'" "${{ env.BRANCH_STAGING }}"
|
||||
|
||||
- name: Fetch ${{ env.BRANCH_PREVIOUS }} and ${{ env.BRANCH_FROGPILOT }}
|
||||
run: |
|
||||
git fetch origin ${{ env.BRANCH_PREVIOUS }} ${{ env.BRANCH_FROGPILOT }}
|
||||
|
||||
- name: Wait Until Noon ${{ env.TZ }}
|
||||
run: |
|
||||
NOW=$(TZ="${{ env.TZ }}" date +%s)
|
||||
TARGET=$(TZ="${{ env.TZ }}" date -d "12:00" +%s)
|
||||
|
||||
[ "$NOW" -lt "$TARGET" ] && sleep $((TARGET - NOW))
|
||||
|
||||
- name: Push ${{ env.BRANCH_STAGING }}
|
||||
run: |
|
||||
git push origin "${{ env.BRANCH_STAGING }}" --force
|
||||
|
||||
- name: Reset ${{ env.BRANCH_PREVIOUS }} to Match ${{ env.BRANCH_FROGPILOT }}
|
||||
run: |
|
||||
git switch "${{ env.BRANCH_PREVIOUS }}"
|
||||
git reset --hard "origin/${{ env.BRANCH_FROGPILOT }}"
|
||||
git push origin "${{ env.BRANCH_PREVIOUS }}" --force
|
||||
|
||||
- name: Reset ${{ env.BRANCH_FROGPILOT }} to Match ${{ env.BRANCH_STAGING }}
|
||||
run: |
|
||||
git switch "${{ env.BRANCH_FROGPILOT }}"
|
||||
git reset --hard "origin/${{ env.BRANCH_STAGING }}"
|
||||
git push origin "${{ env.BRANCH_FROGPILOT }}" --force
|
||||
@@ -1,79 +0,0 @@
|
||||
name: Update Tinygrad
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
runner:
|
||||
description: "Select the runner"
|
||||
required: true
|
||||
default: "c3"
|
||||
type: choice
|
||||
options:
|
||||
- c3
|
||||
- c3x
|
||||
|
||||
jobs:
|
||||
update_tinygrad:
|
||||
name: Update Tinygrad
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ${{ github.event.inputs.runner }}
|
||||
|
||||
steps:
|
||||
- name: Get version
|
||||
id: get_version
|
||||
run: |
|
||||
VERSION=$(grep -oP '^VERSION\s*=\s*"\K[^"]+' /data/openpilot/frogpilot/assets/model_manager.py)
|
||||
echo "VERSION=$VERSION"
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Clone GitLab repo
|
||||
env:
|
||||
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }}
|
||||
run: |
|
||||
rm -rf /data/tmp/frogpilot_tinygrad
|
||||
mkdir -p /data/tmp/frogpilot_tinygrad
|
||||
cd /data/tmp/frogpilot_tinygrad
|
||||
|
||||
git clone --depth 1 --branch Tinygrad "https://oauth2:${GITLAB_TOKEN}@gitlab.com/FrogAi/FrogPilot-Resources.git"
|
||||
|
||||
- name: Create Tinygrad Archive
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd /data/openpilot
|
||||
|
||||
ARCHIVE_DIR="/data/tmp/frogpilot_tinygrad/FrogPilot-Resources"
|
||||
ARCHIVE_NAME="Tinygrad_${{ steps.get_version.outputs.version }}.tar.gz"
|
||||
|
||||
TMPDIR="$(mktemp -d)"
|
||||
touch "$TMPDIR/SConscript"
|
||||
|
||||
tar -czf "$ARCHIVE_NAME" \
|
||||
--exclude="*.a" \
|
||||
--exclude="*.o" \
|
||||
--exclude="*.onnx" \
|
||||
--exclude="*__pycache__*" \
|
||||
--exclude="*tests*" \
|
||||
--exclude="frogpilot/tinygrad_modeld/SConscript" \
|
||||
frogpilot/tinygrad_modeld tinygrad_repo \
|
||||
-C "$TMPDIR" \
|
||||
--transform 's|^SConscript$|frogpilot/tinygrad_modeld/SConscript|' \
|
||||
SConscript
|
||||
|
||||
mv "$ARCHIVE_NAME" "$ARCHIVE_DIR/"
|
||||
rm -rf "$TMPDIR"
|
||||
|
||||
- name: Push updated Tinygrad
|
||||
run: |
|
||||
cd /data/tmp/frogpilot_tinygrad/FrogPilot-Resources
|
||||
|
||||
git config user.name "James"
|
||||
git config user.email "91348155+FrogAi@users.noreply.github.com"
|
||||
|
||||
git add Tinygrad_*.tar.gz
|
||||
git commit -m "Updated Tinygrad: ${{ steps.get_version.outputs.version }}" || echo "No changes to commit"
|
||||
git push origin Tinygrad
|
||||
|
||||
- name: Cleanup temporary files
|
||||
run: |
|
||||
rm -rf /data/tmp/frogpilot_tinygrad
|
||||
+4
-59
@@ -1,20 +1,9 @@
|
||||
venv/
|
||||
.venv/
|
||||
.ci_cache
|
||||
.env
|
||||
.clang-format
|
||||
.DS_Store
|
||||
.tags
|
||||
.ipynb_checkpoints
|
||||
.idea
|
||||
.overlay_init
|
||||
.overlay_consistent
|
||||
.sconsign.dblite
|
||||
model2.png
|
||||
a.out
|
||||
.hypothesis
|
||||
|
||||
*.dylib
|
||||
*.DSYM
|
||||
*.d
|
||||
*.pyc
|
||||
@@ -22,64 +11,20 @@ a.out
|
||||
.*.swp
|
||||
.*.swo
|
||||
.*.un~
|
||||
*.tmp
|
||||
*.o
|
||||
*.o-*
|
||||
*.os
|
||||
*.os-*
|
||||
*.so
|
||||
*.a
|
||||
*.clb
|
||||
*.class
|
||||
*.pyxbldc
|
||||
*.vcd
|
||||
*.qm
|
||||
config.json
|
||||
clcache
|
||||
compile_commands.json
|
||||
compare_runtime*.html
|
||||
|
||||
persist
|
||||
selfdrive/pandad/pandad
|
||||
cereal/services.h
|
||||
cereal/gen
|
||||
board/obj/
|
||||
selfdrive/boardd/boardd
|
||||
selfdrive/logcatd/logcatd
|
||||
selfdrive/mapd/default_speeds_by_region.json
|
||||
system/proclogd/proclogd
|
||||
selfdrive/ui/translations/alerts_generated.h
|
||||
selfdrive/ui/translations/tmp
|
||||
selfdrive/test/longitudinal_maneuvers/out
|
||||
selfdrive/car/tests/cars_dump
|
||||
system/camerad/camerad
|
||||
system/camerad/test/ae_gray_test
|
||||
selfdrive/modeld/_modeld
|
||||
selfdrive/modeld/_dmonitoringmodeld
|
||||
selfdrive/proclogd/proclogd
|
||||
selfdrive/ui/ui
|
||||
/src/
|
||||
|
||||
notebooks
|
||||
hyperthneed
|
||||
provisioning
|
||||
|
||||
.coverage*
|
||||
coverage.xml
|
||||
htmlcov
|
||||
pandaextra
|
||||
|
||||
.mypy_cache/
|
||||
flycheck_*
|
||||
|
||||
cppcheck_report.txt
|
||||
comma*.sh
|
||||
|
||||
selfdrive/modeld/thneed/compile
|
||||
selfdrive/modeld/models/*.thneed
|
||||
selfdrive/modeld/models/*.pkl
|
||||
|
||||
*.bz2
|
||||
|
||||
build/
|
||||
|
||||
!**/.gitkeep
|
||||
|
||||
poetry.toml
|
||||
Pipfile
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
3.11.4
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
sudo: required
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
install:
|
||||
- docker build -t tmppilot -f Dockerfile.openpilot .
|
||||
|
||||
script:
|
||||
- docker run --rm
|
||||
-v "$(pwd)"/selfdrive/test/tests/plant/out:/tmp/openpilot/selfdrive/test/tests/plant/out
|
||||
tmppilot /bin/sh -c 'cd /tmp/openpilot/selfdrive/test/tests/plant && OPTEST=1 ./test_longitudinal.py'
|
||||
@@ -0,0 +1,19 @@
|
||||
FROM ubuntu:16.04
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
|
||||
RUN apt-get update && apt-get install -y build-essential clang vim screen wget bzip2 git libglib2.0-0 python-pip capnproto libcapnp-dev libzmq5-dev libffi-dev libusb-1.0-0
|
||||
RUN pip install numpy==1.11.2 scipy==0.18.1 matplotlib
|
||||
|
||||
COPY requirements_openpilot.txt /tmp/
|
||||
RUN pip install -r /tmp/requirements_openpilot.txt
|
||||
|
||||
ENV PYTHONPATH /tmp/openpilot:$PYTHONPATH
|
||||
|
||||
COPY ./common /tmp/openpilot/common
|
||||
COPY ./cereal /tmp/openpilot/cereal
|
||||
COPY ./opendbc /tmp/openpilot/opendbc
|
||||
COPY ./selfdrive /tmp/openpilot/selfdrive
|
||||
COPY ./phonelibs /tmp/openpilot/phonelibs
|
||||
COPY ./pyextra /tmp/openpilot/pyextra
|
||||
|
||||
RUN mkdir -p /tmp/openpilot/selfdrive/test/out
|
||||
@@ -1,7 +0,0 @@
|
||||
Copyright (c) 2018, Comma.ai, Inc.
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,7 @@
|
||||
Copyright (c) 2016, Comma.ai, Inc.
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
code_dir := $(shell pwd)
|
||||
|
||||
# TODO: Add a global build system
|
||||
|
||||
.PHONY: all
|
||||
all:
|
||||
cd selfdrive && PYTHONPATH=$(code_dir) PREPAREONLY=1 ./manager.py
|
||||
|
||||
@@ -1,252 +1,145 @@
|
||||
<div align="center" style="text-align: center;">
|
||||
Welcome to openpilot
|
||||
======
|
||||
|
||||
<h1>openpilot</h1>
|
||||
[openpilot](http://github.com/commaai/openpilot) is an open source driving agent.
|
||||
|
||||
<p>
|
||||
<b>openpilot is an operating system for robotics.</b>
|
||||
<br>
|
||||
Currently, it upgrades the driver assistance system in 300+ supported cars.
|
||||
</p>
|
||||
Currently it performs the functions of Adaptive Cruise Control (ACC) and Lane Keeping Assist System (LKAS) for Hondas, Acuras and Toyotas. It's about on par with Tesla Autopilot at launch, and better than [all other manufacturers](http://www.thedrive.com/tech/5707/the-war-for-autonomous-driving-part-iii-us-vs-germany-vs-japan).
|
||||
|
||||
<h3>
|
||||
<a href="https://docs.comma.ai">Docs</a>
|
||||
<span> · </span>
|
||||
<a href="https://docs.comma.ai/contributing/roadmap/">Roadmap</a>
|
||||
<span> · </span>
|
||||
<a href="https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md">Contribute</a>
|
||||
<span> · </span>
|
||||
<a href="https://discord.comma.ai">Community</a>
|
||||
<span> · </span>
|
||||
<a href="https://comma.ai/shop">Try it on a comma 3X</a>
|
||||
</h3>
|
||||
The openpilot codebase has been written to be concise and enable rapid prototyping. We look forward to your contributions - improving real vehicle automation has never been easier.
|
||||
|
||||
Quick start: `bash <(curl -fsSL openpilot.comma.ai)`
|
||||
Here are [some](https://www.youtube.com/watch?v=9OwTJFuDI7g) [videos](https://www.youtube.com/watch?v=64Wvt5pYQmE) [of](https://www.youtube.com/watch?v=6IW7Nejsr3A) [it](https://www.youtube.com/watch?v=-VN1YcC83nA) [running](https://www.youtube.com/watch?v=EQJZvVeihZk). And a really cool [tutorial](https://www.youtube.com/watch?v=PwOnsT2UW5o).
|
||||
|
||||
[](https://github.com/commaai/openpilot/actions/workflows/selfdrive_tests.yaml)
|
||||
[](LICENSE)
|
||||
[](https://x.com/comma_ai)
|
||||
[](https://discord.comma.ai)
|
||||
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="https://youtu.be/NmBfgOanCyk" title="Video By Greer Viau"><img src="https://github.com/commaai/openpilot/assets/8762862/2f7112ae-f748-4f39-b617-fabd689c3772"></a></td>
|
||||
<td><a href="https://youtu.be/VHKyqZ7t8Gw" title="Video By Logan LeGrand"><img src="https://github.com/commaai/openpilot/assets/8762862/92351544-2833-40d7-9e0b-7ef7ae37ec4c"></a></td>
|
||||
<td><a href="https://youtu.be/SUIZYzxtMQs" title="A drive to Taco Bell"><img src="https://github.com/commaai/openpilot/assets/8762862/05ceefc5-2628-439c-a9b2-89ce77dc6f63"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
Using openpilot in a car
|
||||
Hardware
|
||||
------
|
||||
|
||||
To use openpilot in a car, you need four things:
|
||||
1. **Supported Device:** a comma 3/3X, available at [comma.ai/shop](https://comma.ai/shop/comma-3x).
|
||||
2. **Software:** The setup procedure for the comma 3/3X allows users to enter a URL for custom software. Use the URL `openpilot.comma.ai` to install the release version.
|
||||
3. **Supported Car:** Ensure that you have one of [the 275+ supported cars](docs/CARS.md).
|
||||
4. **Car Harness:** You will also need a [car harness](https://comma.ai/shop/car-harness) to connect your comma 3/3X to your car.
|
||||
Right now openpilot supports the [NEO research platform](http://github.com/commaai/neo) and the [EON Dashcam DevKit](https://shop.comma.ai/products/eon-dashcam-devkit). We'd like to support other platforms as well.
|
||||
|
||||
We have detailed instructions for [how to install the harness and device in a car](https://comma.ai/setup). Note that it's possible to run openpilot on [other hardware](https://blog.comma.ai/self-driving-car-for-free/), although it's not plug-and-play.
|
||||
Install openpilot on a neo device by entering ``https://openpilot.comma.ai`` during NEOS setup.
|
||||
|
||||
Supported Cars
|
||||
------
|
||||
|
||||
<div align="center" style="text-align: center;">
|
||||
- Acura ILX 2016 with AcuraWatch Plus
|
||||
- Due to use of the cruise control for gas, it can only be enabled above 25 mph
|
||||
|
||||
<h1>FrogPilot 🐸</h1>
|
||||
- Honda Civic 2016-2017 with Honda Sensing
|
||||
- Due to limitations in steering firmware, steering is disabled below 12 mph
|
||||
- Note that the hatchback model is not supported
|
||||
|
||||
[](https://deepwiki.com/FrogAi/FrogPilot)
|
||||
[](https://discord.frogpilot.download)
|
||||
[](https://github.com/FrogAi/FrogPilot/releases/latest)
|
||||
[](https://frogpilot.wiki.gg/)
|
||||
- Honda CR-V Touring 2015-2016
|
||||
- Can only be enabled above 25 mph
|
||||
|
||||
</div>
|
||||
- Honda Odyssey 2018 with Honda Sensing (alpha!)
|
||||
- Can only be enabled above 25 mph
|
||||
|
||||
- Toyota RAV-4 2016+ non-hybrid with TSS-P
|
||||
- By default it uses stock Toyota ACC for longitudinal control
|
||||
- openpilot longitudinal control available after unplugging the [Driving Support ECU](https://community.comma.ai/wiki/index.php/Toyota#Rav4_.28for_openpilot.29) and can be enabled above 20 mph
|
||||
|
||||
- Toyota Prius 2017 (alpha!)
|
||||
- By default it uses stock Toyota ACC for longitudinal control
|
||||
- openpilot longitudinal control available after unplugging the [Driving Support ECU](https://community.comma.ai/wiki/index.php/Toyota#Prius_.28for_openpilot.29)
|
||||
- Lateral control needs improvements
|
||||
|
||||
- Toyota RAV-4 2017 hybrid (alpha!)
|
||||
- By default it uses stock Toyota ACC for longitudinal control
|
||||
- openpilot longitudinal control available after unplugging the [Driving Support ECU](https://community.comma.ai/wiki/index.php/Toyota#Rav4_.28for_openpilot.29) and can do stop and go
|
||||
|
||||
- Toyota Corolla 2017 (alpha!)
|
||||
- By default it uses stock Toyota ACC for longitudinal control
|
||||
- openpilot longitudinal control available after unplugging the [Driving Support ECU](https://community.comma.ai/wiki/index.php/Toyota#Corolla_.28for_openpilot.29) and can be enabled above 20 mph
|
||||
|
||||
In Progress Cars
|
||||
------
|
||||
- Probably all TSS-P Toyota with Steering Assist.
|
||||
- 'Full Speed Range Dynamic Radar Cruise Control' is required to enable stop-and-go. Only the Prius, Camry and C-HR have this option.
|
||||
- Even though the Tundra, Sequoia and the Land Cruiser have TSS-P, they don't have Steering Assist and are not supported.
|
||||
|
||||
Community WIP Cars
|
||||
------
|
||||
|
||||
**FrogPilot** is a custom frog-themed fork of openpilot that embraces a collaborative, community-driven approach to push the project forward. It delivers bleeding-edge features and experimental improvements far ahead of official releases. As an unofficial and highly experimental version of openpilot, **FrogPilot** should always be used with caution!
|
||||
- [Chevy Volt 2016-2018 Premier with Driver Confidence II](https://github.com/commaai/openpilot/pull/104)
|
||||
|
||||
openpilot vs **FrogPilot**
|
||||
- [Classic Tesla Model S (pre-AP)](https://github.com/commaai/openpilot/pull/145)
|
||||
|
||||
- [Honda Pilot 2017 with Honda Sensing](https://github.com/commaai/openpilot/pull/161)
|
||||
|
||||
- [Acura RDX 2018 with AcuraWatch Plus](https://github.com/commaai/openpilot/pull/162)
|
||||
|
||||
Directory structure
|
||||
------
|
||||
|
||||
#### Community
|
||||
| Feature | openpilot | **FrogPilot** |
|
||||
|---------|:---------:|:---------:|
|
||||
| A Welcoming Community | ❌ | ✅ |
|
||||
| Erich / Primary Moderators / 🦇 | ✅ | ❌ |
|
||||
- cereal -- The messaging spec used for all logs on the phone
|
||||
- common -- Library like functionality we've developed here
|
||||
- opendbc -- Files showing how to interpret data from cars
|
||||
- panda -- Code used to communicate on CAN and LIN
|
||||
- phonelibs -- Libraries used on the phone
|
||||
- selfdrive -- Code needed to drive the car
|
||||
- assets -- Fonts for ui
|
||||
- boardd -- Daemon to talk to the board
|
||||
- car -- Code that talks to the car and implements CarInterface
|
||||
- common -- Shared C/C++ code for the daemons
|
||||
- controls -- Python controls (PID loops etc) for the car
|
||||
- debug -- Tools to help you debug and do car ports
|
||||
- logcatd -- Android logcat as a service
|
||||
- loggerd -- Logger and uploader of car data
|
||||
- proclogd -- Logs information from proc
|
||||
- sensord -- IMU / GPS interface code
|
||||
- test/plant -- Car simulator running code through virtual maneuvers
|
||||
- ui -- The UI
|
||||
- visiond -- embedded vision pipeline
|
||||
|
||||
#### Core Features
|
||||
| Feature | openpilot | **FrogPilot** |
|
||||
|---------|:---------:|:---------:|
|
||||
| Always On Lateral (Steering) | ❌ | ✅ |
|
||||
| Blind Spot Integration | ✅ | ✅ |
|
||||
| Conditional Experimental Mode | ❌ | ✅ |
|
||||
| Custom Themes | ❌ | ✅ |
|
||||
| Driver Monitoring | ✅ | ✅ |
|
||||
| Driving Model Selector | ❌ | ✅ |
|
||||
| Holiday Themes | ❌ | ✅ |
|
||||
| Speed Limit Support | ❌ | ✅ |
|
||||
| Weather Detection | ❌ | ✅ |
|
||||
To understand how the services interact, see `selfdrive/service_list.yaml`
|
||||
|
||||
#### Device & Hardware
|
||||
| Feature | openpilot | **FrogPilot** |
|
||||
|---------|:---------:|:---------:|
|
||||
| Advanced Volume Controller | ❌ | ✅ |
|
||||
| Automatic Version Backups | ❌ | ✅ |
|
||||
| C3 Support | ❌ | ✅ |
|
||||
| comma Pedal Support | ❌ | ✅ |
|
||||
| High Quality Recordings | ❌ | ✅ |
|
||||
| SDSU Support | ❌ | ✅ |
|
||||
| ZSS Support | ❌ | ✅ |
|
||||
|
||||
#### Gas/Brake
|
||||
| Feature | openpilot | **FrogPilot** |
|
||||
|---------|:---------:|:---------:|
|
||||
| Adaptive Cruise Control (ACC) | ✅ | ✅ |
|
||||
| Advanced Live Tuning | ❌ | ✅ |
|
||||
| Custom Following Distances | ❌ | ✅ |
|
||||
| Faster Human-Like Acceleration | ❌ | ✅ |
|
||||
| Human-Like Speed Control in Curves | ❌ | ✅ |
|
||||
| Smoother Human-Like Braking | ❌ | ✅ |
|
||||
|
||||
#### Steering
|
||||
| Feature | openpilot | **FrogPilot** |
|
||||
|---------|:---------:|:---------:|
|
||||
| Advanced Live Tuning | ❌ | ✅ |
|
||||
| Automatic Lane Changes | ❌ | ✅ |
|
||||
| Increased Steering Torque* | ❌ | ✅ |
|
||||
| Lane Centering (LKAS) | ✅ | ✅ |
|
||||
| Lane Change Assist | ✅ | ✅ |
|
||||
|
||||
*Select vehicles only
|
||||
|
||||
And much much more!
|
||||
|
||||
🌟 Highlight Features
|
||||
Testing on PC
|
||||
------
|
||||
|
||||
### 🚗 Always On Lateral (AOL)
|
||||
There is rudimentary infrastructure to run a basic simulation and generate a report of openpilot's behavior in different scenarios.
|
||||
|
||||
With **"Always On Lateral"**, lane-centering stays active whenever cruise control is on, even when you press the accelerator or brake. This means steering assist won't cut out during manual speed adjustments giving you continuous support through curves, traffic, or mountain roads!
|
||||
|
||||
---
|
||||
|
||||
### 🧠 Conditional Experimental Mode (CEM)
|
||||
|
||||
**["Experimental Mode"](https://blog.comma.ai/090release/#experimental-mode)** lets openpilot drive at the speed it thinks a human would to allow slowing for curves, stopping at stoplights/stop signs, and adapting to traffic. This makes it powerful in complex scenarios, but it's still, well, "experimental" and less predictable than **"Chill Mode"**. But **"Conditional Experimental Mode"** gives you the best of both worlds by automatically switching between **"Chill Mode"** for steady cruising and **"Experimental Mode"** for more advanced situations to help fully automate your driving experience!
|
||||
|
||||
**"Conditional Experimental Mode"** switches into **"Experimental Mode"** when conditions like these are met:
|
||||
- Approaching curves and turns
|
||||
- Detecting slower or stopped lead vehicles
|
||||
- Driving below a set speed
|
||||
- Predicting an upcoming stop (e.g. stoplight or stop sign)
|
||||
|
||||
Once conditions clear it returns to **"Chill Mode"** for stability and predictability.
|
||||
|
||||
**Note: Stay attentive as "Experimental Mode" is an alpha feature and mistakes are expected!**
|
||||
|
||||
---
|
||||
|
||||
### 🎭 Driving Personalities
|
||||
|
||||
With **"Driving Personalities"**, you choose how the vehicle behaves with four adjustable profiles:
|
||||
|
||||
- **Traffic:** Catered towards stop-and-go traffic by minimizing gaps and delays
|
||||
- **Aggressive:** Aimed to provide tighter following distances and quicker reactions
|
||||
- **Standard:** Useful for a balanced, all-purpose driving
|
||||
- **Relaxed:** A smoother driving experience with larger following distance gaps
|
||||
|
||||
Each profile can be fine-tuned to change the desired following distance, acceleration, and braking style letting you shape **FrogPilot**'s behavior to match your own driving preferences! Profiles can be switched instantly using the following distance button on the steering wheel, while **"Traffic Mode"** can be enabled by simply holding down the following distance button.
|
||||
|
||||
---
|
||||
|
||||
### 📏 Speed Limit Controller (SLC)
|
||||
|
||||
With **"Speed Limit Controller"**, **FrogPilot** automatically adapts to the road's posted speed using information from downloaded **["OpenStreetMap"](https://www.openstreetmap.org)** maps, online **["Mapbox"](https://www.mapbox.com)** data, and the vehicle's dashboard (if supported).
|
||||
|
||||
Offsets let you fine-tune how closely **FrogPilot** follows posted limits across different speed ranges allowing you to cruise slightly above or below for a more natural driving experience. If no speed limit is available, you can choose whether **FrogPilot** drives at the set speed, falls back to the last known speed limit, or uses **"Experimental Mode"** to estimate one with the driving model.
|
||||
|
||||
Maps can be downloaded directly in settings and updated automatically on a schedule ensuring your device always has the latest speed limits!
|
||||
|
||||
**Note: Speed limits are only as accurate as the available speed limit data. Always stay attentive and adjust your speed when necessary!**
|
||||
|
||||
---
|
||||
|
||||
### 🎨 Themes
|
||||
|
||||
With **"Themes"**, you can personalize **FrogPilot**'s driving screen to make it uniquely yours! Choose from:
|
||||
|
||||
- **Color Schemes**
|
||||
- **Icon Packs**
|
||||
- **Sound Packs**
|
||||
- **Turn Signal Animations**
|
||||
- **Steering Wheel Icons**
|
||||
|
||||
Enjoy pre-existing **FrogPilot** and seasonal holiday themes, or you can create your own with the **"Theme Maker"** and even share them with the community! For extra fun, enable features like the Mario Kart–style **"Rainbow Path"** or **"Random Events"** that add playful visual effects while you drive!
|
||||
|
||||
---
|
||||
|
||||
And lots more! From safety enhancements to personalization options, **FrogPilot** continues to evolve with features that put you in control. Check it out today for yourself!
|
||||
|
||||
---
|
||||
|
||||
🔧 Branches
|
||||
------
|
||||
| Branch | Install URL | Description | Recommended For |
|
||||
|----------------------------|---------------------------|--------------------------------------------------------|--------------------------|
|
||||
| FrogPilot | frogpilot.download | The main release branch. | Everyone |
|
||||
| FrogPilot‑Staging | staging.frogpilot.download| Beta branch with upcoming features. Expect bugs! | Early Adopters |
|
||||
| FrogPilot‑Testing | testing.frogpilot.download| Alpha branch with bleeding-edge features. Breaks often!| Advanced Testers |
|
||||
| FrogPilot‑Development| No :) | Active development branch. Don't use! | **FrogPilot** Developers|
|
||||
| MAKE‑PRS‑HERE | No :) | Workspace for pull requests. Don't use! | Contributors |
|
||||
|
||||
🧰 How to Install
|
||||
------
|
||||
|
||||
The easiest way to install **FrogPilot** is by entering this URL on the installation screen:
|
||||
|
||||
```
|
||||
frogpilot.download
|
||||
```bash
|
||||
# Requires working docker
|
||||
./run_docker_tests.sh
|
||||
```
|
||||
|
||||
**DO NOT** install the **FrogPilot-Development** branch. I'm constantly breaking things on there, so unless you don't want to use **FrogPilot**, **NEVER** install it!
|
||||
The results are written to `selfdrive/test/plant/out/index.html`
|
||||
|
||||

|
||||
More extensive testing infrastructure and simulation environments are coming soon.
|
||||
|
||||
🐞 Bug Reports / Feature Requests
|
||||
Adding Car Support
|
||||
------
|
||||
|
||||
If you run into bugs, issues, or have ideas for new features, please post about it on the **[FrogPilot Discord](https://discord.gg/frogpilot)**! Feedback helps improve **FrogPilot** and create a better experience for everyone!
|
||||
comma.ai offers [bounties](http://comma.ai/bounties.html) for adding additional car support.
|
||||
|
||||
To report a bug, please post it in [**#bug-reports**](https://discord.com/channels/1137853399715549214/1162100167110053888).
|
||||
To request a feature, please post it in [**#feature-requests**](https://discord.com/channels/1137853399715549214/1160318669839147259).
|
||||
CR-V Touring support came in through this program. Chevy Volt is close. Accord is close as well.
|
||||
|
||||
Please include as much detail as possible! Photos, videos, log files, or anything that can help explain the issue or idea are very helpful!
|
||||
|
||||
I'll do my best to respond promptly, but not every request can be addressed right away. Your feedback is always appreciated and helps make **FrogPilot** the best it can be!
|
||||
|
||||
📋 Credits
|
||||
User Data / chffr Account / Crash Reporting
|
||||
------
|
||||
|
||||
* [Aidenir](https://github.com/Aidenir)
|
||||
* [AlexandreSato](https://github.com/AlexandreSato)
|
||||
* [cfranyota](https://github.com/cfranyota)
|
||||
* [cydia2020](https://github.com/cydia2020)
|
||||
* [dragonpilot-community](https://github.com/dragonpilot-community)
|
||||
* [ErichMoraga](https://github.com/ErichMoraga)
|
||||
* [garrettpall](https://github.com/garrettpall)
|
||||
* [jakethesnake420](https://github.com/jakethesnake420)
|
||||
* [jyoung8607](https://github.com/jyoung8607)
|
||||
* [mike8643](https://github.com/mike8643)
|
||||
* [neokii](https://github.com/neokii)
|
||||
* [OPGM](https://github.com/opgm)
|
||||
* [OPKR](https://github.com/openpilotkr)
|
||||
* [pfeiferj](https://github.com/pfeiferj)
|
||||
* [realfast](https://github.com/realfast)
|
||||
* [syncword](https://github.com/syncword)
|
||||
* [twilsonco](https://github.com/twilsonco)
|
||||
By default openpilot creates an account and includes a client for chffr, our dashcam app. We use your data to train better models and improve openpilot for everyone.
|
||||
|
||||
Star History
|
||||
It's open source software, so you are free to disable it if you wish.
|
||||
|
||||
It logs the road facing camera, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs.
|
||||
It does not log the user facing camera or the microphone.
|
||||
|
||||
By using it, you agree to [our privacy policy](https://beta.comma.ai/privacy.html). You understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma.ai. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma.ai for the use of this data.
|
||||
|
||||
Contributing
|
||||
------
|
||||
|
||||
[](https://www.star-history.com/#FrogAi/FrogPilot&Date)
|
||||
We welcome both pull requests and issues on
|
||||
[github](http://github.com/commaai/openpilot). See the TODO file for a list of
|
||||
good places to start.
|
||||
|
||||
Want to get paid to work on openpilot? [comma.ai is hiring](http://comma.ai/positions.html)
|
||||
|
||||
Licensing
|
||||
------
|
||||
|
||||
openpilot is released under the MIT license.
|
||||
|
||||
Any user of this software shall indemnify and hold harmless Comma.ai, Inc. and its directors, officers, employees, agents, stockholders, affiliates, subcontractors and customers from and against all allegations, claims, actions, suits, demands, damages, liabilities, obligations, losses, settlements, judgments, costs and expenses (including without limitation attorneys’ fees and costs) which arise out of, relate to or result from any use of this software by user.
|
||||
|
||||
**THIS IS ALPHA QUALITY SOFTWARE FOR RESEARCH PURPOSES ONLY. THIS IS NOT A PRODUCT.
|
||||
YOU ARE RESPONSIBLE FOR COMPLYING WITH LOCAL LAWS AND REGULATIONS.
|
||||
NO WARRANTY EXPRESSED OR IMPLIED.**
|
||||
|
||||
+51
-913
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,73 @@
|
||||
openpilot Safety
|
||||
======
|
||||
|
||||
openpilot is an Adaptive Cruise Control (ACC) and Lane Keeping Assist (LKA) system.
|
||||
Like other ACC and LKA systems, openpilot requires the driver to be alert and to
|
||||
pay attention at all times. We repeat, **driver alertness is necessary, but not
|
||||
sufficient, for openpilot to be used safely**.
|
||||
|
||||
Even with an attentive driver, we must make further efforts for the system to be
|
||||
safe. We have designed openpilot with two other safety considerations.
|
||||
|
||||
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
|
||||
to operate within reasonable limits.
|
||||
|
||||
Following are details of the car specific safety implementations:
|
||||
|
||||
Honda/Acura
|
||||
------
|
||||
|
||||
- While the system is engaged, gas, brake and steer limits are subject to the same limits used by
|
||||
the stock system.
|
||||
|
||||
- Without an interceptor, the gas is controlled by the Powertrain Control Module (PCM).
|
||||
The PCM limits acceleration to what is reasonable for a cruise control system. With an
|
||||
interceptor, the gas is clipped to 60%.
|
||||
|
||||
- The brake is controlled by the 0x1FA CAN message. This message allows full
|
||||
braking, although the board and the software clip it to 1/4th of the max.
|
||||
This is around .3g of braking.
|
||||
|
||||
- Steering is controlled by the 0xE4 CAN message. The Electronic Power Steering (EPS)
|
||||
controller in the car limits the torque to a very small amount, so regardless of the
|
||||
message, the controller cannot jerk the wheel.
|
||||
|
||||
- Brake and gas pedal pressed signals are contained in the 0x17C CAN message. A rising edge of
|
||||
either signal triggers a disengagement, which is enforced by the board and in software. The
|
||||
green led on the board signifies if the board is allowing control messages.
|
||||
|
||||
- Honda CAN uses both a counter and a checksum to ensure integrity and prevent
|
||||
replay of the same message.
|
||||
|
||||
Toyota
|
||||
------
|
||||
|
||||
- While the system is engaged, gas, brake and steer limits are subject to the same limits used by
|
||||
the stock system.
|
||||
|
||||
- With the stock Driving Support Unit (DSU) enabled, the acceleration is controlled
|
||||
by the stock system and is subject to the stock adaptive cruise control limits. Without the
|
||||
stock DSU connected, the acceleration command is controlled by the 0x343 CAN message and its
|
||||
value is limited by the board and the software to between .3g of deceleration and .15g of
|
||||
acceleration. The acceleration command is ignored by the Engine Control Module (ECM) while the
|
||||
cruise control system is disengaged.
|
||||
|
||||
- Steering torque is controlled through the 0x2E4 CAN message and it's limited by the board and in
|
||||
software to a value of -1500 and 1500. In addition, the vehicle EPS unit will not respond to
|
||||
commands outside these limits. A steering torque rate limit is enforced by the board and in
|
||||
software so that the commanded steering torque must rise from 0 to max value no faster than
|
||||
1.5s. Commanded steering torque is limited by the board and in software to be no more than 500
|
||||
units above the actual EPS generated motor torque to ensure limited differences between
|
||||
commanded and actual torques.
|
||||
|
||||
- Brake and gas pedal pressed signals are contained in the 0x224 and 0x1D2 CAN messages,
|
||||
respectively. A rising edge of either signal triggers a disengagement, which is enforced by the
|
||||
board and in software. Additionally, the cruise control system disengages on the rising edge of
|
||||
the brake pedal pressed signal.
|
||||
|
||||
- The cruise control system state is contained in the 0x1D2 message. No control messages are
|
||||
allowed if the cruise control system is not active. This is enforced by the software and the
|
||||
board. The green led on the board signifies if the board is allowing control messages.
|
||||
@@ -1,5 +0,0 @@
|
||||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Suspected vulnerabilities can be reported to both `adeeb@comma.ai` and `security@comma.ai`.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,2 @@
|
||||
src/*
|
||||
out/*
|
||||
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
+122
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env python2.7
|
||||
|
||||
import os
|
||||
import sys
|
||||
import glob
|
||||
import shutil
|
||||
import urllib2
|
||||
import hashlib
|
||||
import subprocess
|
||||
|
||||
|
||||
EXTERNAL_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
if os.path.exists("/init.qcom.rc"):
|
||||
# android
|
||||
APKPATCH = os.path.join(EXTERNAL_PATH, 'tools/apkpatch_android')
|
||||
SIGNAPK = os.path.join(EXTERNAL_PATH, 'tools/signapk_android')
|
||||
else:
|
||||
APKPATCH = os.path.join(EXTERNAL_PATH, 'tools/apkpatch')
|
||||
SIGNAPK = os.path.join(EXTERNAL_PATH, 'tools/signapk')
|
||||
|
||||
APKS = {
|
||||
'com.waze': {
|
||||
'src': 'https://apkcache.s3.amazonaws.com/com.waze_1021278.apk',
|
||||
'src_sha256': 'f00957e93e2389f9e30502ac54994b98ac769314b0963c263d4e8baa625ab0c2',
|
||||
'patch': 'com.waze.apkpatch',
|
||||
'out_sha256': '9ec8b0ea3c78c666342865b1bfb66e368a3f5c911df2ad12835206ec8b19f444'
|
||||
},
|
||||
'com.spotify.music': {
|
||||
'src': 'https://apkcache.s3.amazonaws.com/com.spotify.music_24382006.apk',
|
||||
'src_sha256': '0610fea68ee7ba5f8e4e0732ad429d729dd6cbb8bc21222c4c99db6cb09fbff4',
|
||||
'patch': 'com.spotify.music.apkpatch',
|
||||
'out_sha256': '5a3d6f478c7e40403a98ccc8906d7e0ae12b06543b41f5df52149dd09c647c11'
|
||||
},
|
||||
}
|
||||
|
||||
def sha256_path(path):
|
||||
with open(path, 'rb') as f:
|
||||
return hashlib.sha256(f.read()).hexdigest()
|
||||
|
||||
def remove(path):
|
||||
try:
|
||||
os.remove(path)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def process(download, patch):
|
||||
# clean up any junk apks
|
||||
for out_apk in glob.glob(os.path.join(EXTERNAL_PATH, 'out/*.apk')):
|
||||
app = os.path.basename(out_apk)[:-4]
|
||||
if app not in APKS:
|
||||
print "remove junk", out_apk
|
||||
remove(out_apk)
|
||||
|
||||
complete = True
|
||||
for k,v in APKS.iteritems():
|
||||
apk_path = os.path.join(EXTERNAL_PATH, 'out', k+'.apk')
|
||||
print "checking", apk_path
|
||||
if os.path.exists(apk_path) and sha256_path(apk_path) == v['out_sha256']:
|
||||
# nothing to do
|
||||
continue
|
||||
|
||||
complete = False
|
||||
|
||||
remove(apk_path)
|
||||
|
||||
src_path = os.path.join(EXTERNAL_PATH, 'src', v['src_sha256'])
|
||||
if not os.path.exists(src_path) or sha256_path(src_path) != v['src_sha256']:
|
||||
if not download:
|
||||
continue
|
||||
|
||||
print "downloading", v['src'], "to", src_path
|
||||
# download it
|
||||
resp = urllib2.urlopen(v['src'])
|
||||
data = resp.read()
|
||||
with open(src_path, 'wb') as src_f:
|
||||
src_f.write(data)
|
||||
|
||||
if sha256_path(src_path) != v['src_sha256']:
|
||||
print "download was corrupted..."
|
||||
continue
|
||||
|
||||
if not patch:
|
||||
continue
|
||||
|
||||
# ignoring lots of TOCTTOU here...
|
||||
|
||||
apk_temp = "/tmp/"+k+".patched"
|
||||
remove(apk_temp)
|
||||
apk_temp2 = "/tmp/"+k+".signed"
|
||||
remove(apk_temp2)
|
||||
|
||||
try:
|
||||
print "patching", v['patch']
|
||||
subprocess.check_call([APKPATCH, 'apply', src_path, apk_temp, os.path.join(EXTERNAL_PATH, v['patch'])])
|
||||
print "signing", apk_temp
|
||||
subprocess.check_call([SIGNAPK,
|
||||
os.path.join(EXTERNAL_PATH, 'tools/certificate.pem'), os.path.join(EXTERNAL_PATH, 'tools/key.pk8'),
|
||||
apk_temp, apk_temp2])
|
||||
|
||||
out_sha256 = sha256_path(apk_temp2) if os.path.exists(apk_temp2) else None
|
||||
|
||||
if out_sha256 == v['out_sha256']:
|
||||
print "done", apk_path
|
||||
shutil.move(apk_temp2, apk_path)
|
||||
else:
|
||||
print "patch was corrupted", apk_temp2, out_sha256
|
||||
finally:
|
||||
remove(apk_temp)
|
||||
remove(apk_temp2)
|
||||
|
||||
return complete
|
||||
|
||||
if __name__ == "__main__":
|
||||
ret = True
|
||||
if len(sys.argv) == 2 and sys.argv[1] == "download":
|
||||
ret = process(True, False)
|
||||
elif len(sys.argv) == 2 and sys.argv[1] == "patch":
|
||||
ret = process(False, True)
|
||||
else:
|
||||
ret = process(True, True)
|
||||
sys.exit(0 if ret else 1)
|
||||
BIN
Binary file not shown.
+7
@@ -0,0 +1,7 @@
|
||||
#!/system/bin/sh
|
||||
|
||||
DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
export LD_LIBRARY_PATH=/system/lib64
|
||||
export CLASSPATH="$DIR"/ApkPatch.android.jar
|
||||
exec app_process "$DIR" ApkPatch "$@"
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICtTCCAh4CCQDm79UqF+Dc5zANBgkqhkiG9w0BAQUFADCBnjELMAkGA1UEBhMC
|
||||
SUQxEzARBgNVBAgTCkphd2EgQmFyYXQxEDAOBgNVBAcTB0JhbmR1bmcxEjAQBgNV
|
||||
BAoTCUxvbmRhdGlnYTETMBEGA1UECxMKQW5kcm9pZERldjEaMBgGA1UEAxMRTG9y
|
||||
ZW5zaXVzIFcuIEwuIFQxIzAhBgkqhkiG9w0BCQEWFGxvcmVuekBsb25kYXRpZ2Eu
|
||||
bmV0MB4XDTEwMDUwNTA5MjEzOFoXDTEzMDEyODA5MjEzOFowgZ4xCzAJBgNVBAYT
|
||||
AklEMRMwEQYDVQQIEwpKYXdhIEJhcmF0MRAwDgYDVQQHEwdCYW5kdW5nMRIwEAYD
|
||||
VQQKEwlMb25kYXRpZ2ExEzARBgNVBAsTCkFuZHJvaWREZXYxGjAYBgNVBAMTEUxv
|
||||
cmVuc2l1cyBXLiBMLiBUMSMwIQYJKoZIhvcNAQkBFhRsb3JlbnpAbG9uZGF0aWdh
|
||||
Lm5ldDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAy2oWtbdVXMHGiS6cA3qi
|
||||
3VfZt5Vz9jTlux+TEcGx5h18ZKwclyo+z2B0L/p5bYdnrTdFEiD7IxvX+h3lu0JV
|
||||
B9rdXZdyrzXNOw5YFrsn2k7hKvB8KEBaga1gZEwodlc6N14H3FbZdZkIA9V716Pu
|
||||
e5CWBZ2VqU03lUJmKnpH8c8CAwEAATANBgkqhkiG9w0BAQUFAAOBgQBpNgXh8dw9
|
||||
uMjZxzLUXovV5ptHd61jAcZlQlffqPsz6/2QNfIShVdGH9jkm0IudfKkbvvOKive
|
||||
a77t9c4sDh2Sat2L/rx6BfTuS1+y9wFr1Ee8Rrr7wGHhRkx2qqGrXGVWqXn8aE3E
|
||||
P6e7BTPF0ibS+tG8cdDPEisqGFxw36nTNQ==
|
||||
-----END CERTIFICATE-----
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+7
@@ -0,0 +1,7 @@
|
||||
#!/system/bin/sh
|
||||
|
||||
DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
export LD_LIBRARY_PATH=/system/lib64
|
||||
export CLASSPATH="$DIR"/signapk.android.jar
|
||||
exec app_process "$DIR" com.android.signapk.SignApk "$@"
|
||||
@@ -0,0 +1 @@
|
||||
gen
|
||||
@@ -0,0 +1,52 @@
|
||||
PWD := $(shell pwd)
|
||||
|
||||
SRCS := log.capnp car.capnp
|
||||
|
||||
GENS := gen/cpp/car.capnp.c++ gen/cpp/log.capnp.c++
|
||||
|
||||
UNAME_M ?= $(shell uname -m)
|
||||
|
||||
# only generate C++ for docker tests
|
||||
ifneq ($(OPTEST),1)
|
||||
GENS += gen/c/car.capnp.c gen/c/log.capnp.c gen/c/c++.capnp.h gen/c/java.capnp.h
|
||||
|
||||
# Dont build java on the phone...
|
||||
ifeq ($(UNAME_M),x86_64)
|
||||
GENS += gen/java/Car.java gen/java/Log.java
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(UNAME_M),aarch64)
|
||||
CAPNPC=PATH=$(PWD)/../phonelibs/capnp-cpp/aarch64/bin/:$$PATH capnpc
|
||||
else
|
||||
CAPNPC=capnpc
|
||||
endif
|
||||
|
||||
.PHONY: all
|
||||
all: $(GENS)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf gen
|
||||
|
||||
gen/c/%.capnp.c: %.capnp
|
||||
@echo "[ CAPNPC C ] $@"
|
||||
mkdir -p gen/c/
|
||||
$(CAPNPC) '$<' -o c:gen/c/
|
||||
|
||||
gen/cpp/%.capnp.c++: %.capnp
|
||||
@echo "[ CAPNPC C++ ] $@"
|
||||
mkdir -p gen/cpp/
|
||||
$(CAPNPC) '$<' -o c++:gen/cpp/
|
||||
|
||||
gen/java/Car.java gen/java/Log.java: $(SRCS)
|
||||
@echo "[ CAPNPC java ] $@"
|
||||
mkdir -p gen/java/
|
||||
$(CAPNPC) $^ -o java:gen/java
|
||||
|
||||
# c-capnproto needs some empty headers
|
||||
gen/c/c++.capnp.h gen/c/java.capnp.h:
|
||||
mkdir -p gen/c/
|
||||
touch '$@'
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
# What is cereal? [](https://github.com/commaai/cereal/actions) [](https://codecov.io/gh/commaai/cereal)
|
||||
|
||||
cereal is both a messaging spec for robotics systems as well as generic high performance IPC pub sub messaging with a single publisher and multiple subscribers.
|
||||
|
||||
Imagine this use case:
|
||||
* A sensor process reads gyro measurements directly from an IMU and publishes a `sensorEvents` packet
|
||||
* A calibration process subscribes to the `sensorEvents` packet to use the IMU
|
||||
* A localization process subscribes to the `sensorEvents` packet to use the IMU also
|
||||
|
||||
|
||||
## Messaging Spec
|
||||
|
||||
You'll find the message types in [log.capnp](log.capnp). It uses [Cap'n proto](https://capnproto.org/capnp-tool.html) and defines one struct called `Event`.
|
||||
|
||||
All `Events` have a `logMonoTime` and a `valid`. Then a big union defines the packet type.
|
||||
|
||||
### Best Practices
|
||||
|
||||
- **All fields must describe quantities in SI units**, unless otherwise specified in the field name.
|
||||
- In the context of the message they are in, field names should be completely unambiguous.
|
||||
- All values should be easy to plot and be human-readable with minimal parsing.
|
||||
|
||||
### Maintaining backwards-compatibility
|
||||
|
||||
When making changes to the messaging spec you want to maintain backwards-compatibility, such that old logs can
|
||||
be parsed with a new version of cereal. Adding structs and adding members to structs is generally safe, most other
|
||||
things are not. Read more details [here](https://capnproto.org/language.html).
|
||||
|
||||
### Custom forks
|
||||
|
||||
Forks of [openpilot](https://github.com/commaai/openpilot) might want to add things to the messaging
|
||||
spec, however this could conflict with future changes made in mainline cereal/openpilot. Rebasing against mainline openpilot
|
||||
then means breaking backwards-compatibility with all old logs of your fork. So we added reserved events in
|
||||
[custom.capnp](custom.capnp) that we will leave empty in mainline cereal/openpilot. **If you only modify those, you can ensure your
|
||||
fork will remain backwards-compatible with all versions of mainline cereal/openpilot and your fork.**
|
||||
|
||||
## Pub Sub Backends
|
||||
|
||||
cereal supports two backends, one based on [zmq](https://zeromq.org/) and another called [msgq](messaging/msgq.cc), a custom pub sub based on shared memory that doesn't require the bytes to pass through the kernel.
|
||||
|
||||
Example
|
||||
---
|
||||
```python
|
||||
import cereal.messaging as messaging
|
||||
|
||||
# in subscriber
|
||||
sm = messaging.SubMaster(['sensorEvents'])
|
||||
while 1:
|
||||
sm.update()
|
||||
print(sm['sensorEvents'])
|
||||
|
||||
```
|
||||
|
||||
```python
|
||||
# in publisher
|
||||
pm = messaging.PubMaster(['sensorEvents'])
|
||||
dat = messaging.new_message('sensorEvents', size=1)
|
||||
dat.sensorEvents[0] = {"gyro": {"v": [0.1, -0.1, 0.1]}}
|
||||
pm.send('sensorEvents', dat)
|
||||
```
|
||||
+14
-3
@@ -4,6 +4,17 @@ import capnp
|
||||
CEREAL_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||
capnp.remove_import_hook()
|
||||
|
||||
log = capnp.load(os.path.join(CEREAL_PATH, "log.capnp"))
|
||||
car = capnp.load(os.path.join(CEREAL_PATH, "car.capnp"))
|
||||
custom = capnp.load(os.path.join(CEREAL_PATH, "custom.capnp"))
|
||||
if os.getenv("NEWCAPNP"):
|
||||
import tempfile
|
||||
import pyximport
|
||||
|
||||
importers = pyximport.install(build_dir=os.path.join(tempfile.gettempdir(), ".pyxbld"))
|
||||
try:
|
||||
import cereal.gen.cython.log_capnp_cython as log
|
||||
import cereal.gen.cython.car_capnp_cython as car
|
||||
finally:
|
||||
pyximport.uninstall(*importers)
|
||||
del importers
|
||||
else:
|
||||
log = capnp.load(os.path.join(CEREAL_PATH, "log.capnp"))
|
||||
car = capnp.load(os.path.join(CEREAL_PATH, "car.capnp"))
|
||||
|
||||
+100
-490
@@ -1,28 +1,31 @@
|
||||
using Cxx = import "./include/c++.capnp";
|
||||
using Cxx = import "c++.capnp";
|
||||
$Cxx.namespace("cereal");
|
||||
|
||||
using Java = import "java.capnp";
|
||||
$Java.package("ai.comma.openpilot.cereal");
|
||||
$Java.outerClassname("Car");
|
||||
|
||||
@0x8e2af1e708af8b8d;
|
||||
|
||||
# ******* events causing controls state machine transition *******
|
||||
|
||||
struct CarEvent @0x9b1657f34caf3ad3 {
|
||||
name @0 :EventName;
|
||||
|
||||
# event types
|
||||
enable @1 :Bool;
|
||||
noEntry @2 :Bool;
|
||||
warning @3 :Bool; # alerts presented only when enabled or soft disabling
|
||||
warning @3 :Bool;
|
||||
userDisable @4 :Bool;
|
||||
softDisable @5 :Bool;
|
||||
immediateDisable @6 :Bool;
|
||||
preEnable @7 :Bool;
|
||||
permanent @8 :Bool; # alerts presented regardless of openpilot state
|
||||
overrideLateral @10 :Bool;
|
||||
overrideLongitudinal @9 :Bool;
|
||||
permanent @8 :Bool;
|
||||
|
||||
enum EventName @0xbaa8c5d505f727de {
|
||||
canError @0;
|
||||
# TODO: copy from error list
|
||||
commIssue @0;
|
||||
steerUnavailable @1;
|
||||
brakeUnavailable @2;
|
||||
gasUnavailable @3;
|
||||
wrongGear @4;
|
||||
doorOpen @5;
|
||||
seatbeltNotLatched @6;
|
||||
@@ -32,118 +35,25 @@ struct CarEvent @0x9b1657f34caf3ad3 {
|
||||
reverseGear @10;
|
||||
buttonCancel @11;
|
||||
buttonEnable @12;
|
||||
pedalPressed @13; # exits active state
|
||||
preEnableStandstill @73; # added during pre-enable state with brake
|
||||
gasPressedOverride @108; # added when user is pressing gas with no disengage on gas
|
||||
steerOverride @114;
|
||||
pedalPressed @13;
|
||||
cruiseDisabled @14;
|
||||
radarCommIssue @15;
|
||||
dataNeeded @16;
|
||||
speedTooLow @17;
|
||||
outOfSpace @18;
|
||||
overheat @19;
|
||||
calibrationIncomplete @20;
|
||||
calibrationInProgress @20;
|
||||
calibrationInvalid @21;
|
||||
calibrationRecalibrating @117;
|
||||
controlsMismatch @22;
|
||||
pcmEnable @23;
|
||||
pcmDisable @24;
|
||||
noTarget @25;
|
||||
radarFault @26;
|
||||
modelCommIssue @27;
|
||||
brakeHold @28;
|
||||
parkBrake @29;
|
||||
manualRestart @30;
|
||||
lowSpeedLockout @31;
|
||||
joystickDebug @34;
|
||||
steerTempUnavailableSilent @35;
|
||||
resumeRequired @36;
|
||||
preDriverDistracted @37;
|
||||
promptDriverDistracted @38;
|
||||
driverDistracted @39;
|
||||
preDriverUnresponsive @43;
|
||||
promptDriverUnresponsive @44;
|
||||
driverUnresponsive @45;
|
||||
belowSteerSpeed @46;
|
||||
lowBattery @48;
|
||||
accFaulted @51;
|
||||
sensorDataInvalid @52;
|
||||
commIssue @53;
|
||||
commIssueAvgFreq @109;
|
||||
tooDistracted @54;
|
||||
posenetInvalid @55;
|
||||
soundsUnavailable @56;
|
||||
preLaneChangeLeft @57;
|
||||
preLaneChangeRight @58;
|
||||
laneChange @59;
|
||||
lowMemory @63;
|
||||
stockAeb @64;
|
||||
ldw @65;
|
||||
carUnrecognized @66;
|
||||
invalidLkasSetting @69;
|
||||
speedTooHigh @70;
|
||||
laneChangeBlocked @71;
|
||||
relayMalfunction @72;
|
||||
stockFcw @74;
|
||||
startup @75;
|
||||
startupNoCar @76;
|
||||
startupNoControl @77;
|
||||
startupNoSecOcKey @121;
|
||||
startupMaster @78;
|
||||
startupNoFw @104;
|
||||
fcw @79;
|
||||
steerSaturated @80;
|
||||
belowEngageSpeed @84;
|
||||
noGps @85;
|
||||
wrongCruiseMode @87;
|
||||
modeldLagging @89;
|
||||
deviceFalling @90;
|
||||
fanMalfunction @91;
|
||||
cameraMalfunction @92;
|
||||
cameraFrameRate @110;
|
||||
processNotRunning @95;
|
||||
dashcamMode @96;
|
||||
controlsInitializing @98;
|
||||
usbError @99;
|
||||
roadCameraError @100;
|
||||
driverCameraError @101;
|
||||
wideRoadCameraError @102;
|
||||
highCpuUsage @105;
|
||||
cruiseMismatch @106;
|
||||
lkasDisabled @107;
|
||||
canBusMissing @111;
|
||||
controlsdLagging @112;
|
||||
resumeBlocked @113;
|
||||
steerTimeLimit @115;
|
||||
vehicleSensorsInvalid @116;
|
||||
locationdTemporaryError @103;
|
||||
locationdPermanentError @118;
|
||||
paramsdTemporaryError @50;
|
||||
paramsdPermanentError @119;
|
||||
actuatorsApiUnavailable @120;
|
||||
|
||||
radarCanErrorDEPRECATED @15;
|
||||
communityFeatureDisallowedDEPRECATED @62;
|
||||
radarCommIssueDEPRECATED @67;
|
||||
driverMonitorLowAccDEPRECATED @68;
|
||||
gasUnavailableDEPRECATED @3;
|
||||
dataNeededDEPRECATED @16;
|
||||
modelCommIssueDEPRECATED @27;
|
||||
ipasOverrideDEPRECATED @33;
|
||||
geofenceDEPRECATED @40;
|
||||
driverMonitorOnDEPRECATED @41;
|
||||
driverMonitorOffDEPRECATED @42;
|
||||
calibrationProgressDEPRECATED @47;
|
||||
invalidGiraffeHondaDEPRECATED @49;
|
||||
invalidGiraffeToyotaDEPRECATED @60;
|
||||
internetConnectivityNeededDEPRECATED @61;
|
||||
whitePandaUnsupportedDEPRECATED @81;
|
||||
commIssueWarningDEPRECATED @83;
|
||||
focusRecoverActiveDEPRECATED @86;
|
||||
neosUpdateRequiredDEPRECATED @88;
|
||||
modelLagWarningDEPRECATED @93;
|
||||
startupOneplusDEPRECATED @82;
|
||||
startupFuzzyFingerprintDEPRECATED @97;
|
||||
noTargetDEPRECATED @25;
|
||||
brakeUnavailableDEPRECATED @2;
|
||||
plannerErrorDEPRECATED @32;
|
||||
gpsMalfunctionDEPRECATED @94;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,50 +61,31 @@ struct CarEvent @0x9b1657f34caf3ad3 {
|
||||
# all speeds in m/s
|
||||
|
||||
struct CarState {
|
||||
errorsDEPRECATED @0 :List(CarEvent.EventName);
|
||||
events @13 :List(CarEvent);
|
||||
|
||||
# CAN health
|
||||
canValid @26 :Bool; # invalid counter/checksums
|
||||
canTimeout @40 :Bool; # CAN bus dropped out
|
||||
canErrorCounter @48 :UInt32;
|
||||
|
||||
# car speed
|
||||
vEgo @1 :Float32; # best estimate of speed
|
||||
aEgo @16 :Float32; # best estimate of acceleration
|
||||
vEgoRaw @17 :Float32; # unfiltered speed from CAN sensors
|
||||
vEgoCluster @44 :Float32; # best estimate of speed shown on car's instrument cluster, used for UI
|
||||
|
||||
vEgo @1 :Float32; # best estimate of speed
|
||||
aEgo @16 :Float32; # best estimate of acceleration
|
||||
vEgoRaw @17 :Float32; # unfiltered speed from CAN sensors
|
||||
yawRate @22 :Float32; # best estimate of yaw rate
|
||||
standstill @18 :Bool;
|
||||
wheelSpeeds @2 :WheelSpeeds;
|
||||
|
||||
# gas pedal, 0.0-1.0
|
||||
gas @3 :Float32; # this is user pedal only
|
||||
gas @3 :Float32; # this is user + computer
|
||||
gasPressed @4 :Bool; # this is user pedal only
|
||||
|
||||
engineRpm @46 :Float32;
|
||||
|
||||
# brake pedal, 0.0-1.0
|
||||
brake @5 :Float32; # this is user pedal only
|
||||
brakePressed @6 :Bool; # this is user pedal only
|
||||
regenBraking @45 :Bool; # this is user pedal only
|
||||
parkingBrake @39 :Bool;
|
||||
brakeHoldActive @38 :Bool;
|
||||
brakeLights @19 :Bool;
|
||||
|
||||
# steering wheel
|
||||
steeringAngleDeg @7 :Float32;
|
||||
steeringAngleOffsetDeg @37 :Float32; # Offset betweens sensors in case there multiple
|
||||
steeringRateDeg @15 :Float32;
|
||||
steeringTorque @8 :Float32; # TODO: standardize units
|
||||
steeringTorqueEps @27 :Float32; # TODO: standardize units
|
||||
steeringPressed @9 :Bool; # if the user is using the steering wheel
|
||||
steerFaultTemporary @35 :Bool; # temporary EPS fault
|
||||
steerFaultPermanent @36 :Bool; # permanent EPS fault
|
||||
stockAeb @30 :Bool;
|
||||
stockFcw @31 :Bool;
|
||||
espDisabled @32 :Bool;
|
||||
accFaulted @42 :Bool;
|
||||
carFaultedNonCritical @47 :Bool; # some ECU is faulted, but car remains controllable
|
||||
steeringAngle @7 :Float32; # deg
|
||||
steeringRate @15 :Float32; # deg/s
|
||||
steeringTorque @8 :Float32; # TODO: standardize units
|
||||
steeringPressed @9 :Bool; # if the user is using the steering wheel
|
||||
|
||||
# cruise state
|
||||
cruiseState @10 :CruiseState;
|
||||
@@ -212,18 +103,8 @@ struct CarState {
|
||||
doorOpen @24 :Bool;
|
||||
seatbeltUnlatched @25 :Bool;
|
||||
|
||||
# clutch (manual transmission only)
|
||||
clutchPressed @28 :Bool;
|
||||
|
||||
# blindspot sensors
|
||||
leftBlindspot @33 :Bool; # Is there something blocking the left lane change
|
||||
rightBlindspot @34 :Bool; # Is there something blocking the right lane change
|
||||
|
||||
fuelGauge @41 :Float32; # battery or fuel tank level from 0.0 to 1.0
|
||||
charging @43 :Bool;
|
||||
|
||||
# process meta
|
||||
cumLagMs @50 :Float32;
|
||||
# which packets this state came from
|
||||
canMonoTimes @12: List(UInt64);
|
||||
|
||||
struct WheelSpeeds {
|
||||
# optional wheel speeds
|
||||
@@ -236,11 +117,9 @@ struct CarState {
|
||||
struct CruiseState {
|
||||
enabled @0 :Bool;
|
||||
speed @1 :Float32;
|
||||
speedCluster @6 :Float32; # Set speed as shown on instrument cluster
|
||||
available @2 :Bool;
|
||||
speedOffset @3 :Float32;
|
||||
standstill @4 :Bool;
|
||||
nonAdaptive @5 :Bool;
|
||||
}
|
||||
|
||||
enum GearShifter {
|
||||
@@ -252,10 +131,9 @@ struct CarState {
|
||||
sport @5;
|
||||
low @6;
|
||||
brake @7;
|
||||
eco @8;
|
||||
manumatic @9;
|
||||
}
|
||||
|
||||
|
||||
# send on change
|
||||
struct ButtonEvent {
|
||||
pressed @0 :Bool;
|
||||
@@ -271,30 +149,22 @@ struct CarState {
|
||||
altButton1 @6;
|
||||
altButton2 @7;
|
||||
altButton3 @8;
|
||||
setCruise @9;
|
||||
resumeCruise @10;
|
||||
gapAdjustCruise @11;
|
||||
}
|
||||
}
|
||||
|
||||
# deprecated
|
||||
errorsDEPRECATED @0 :List(CarEvent.EventName);
|
||||
brakeLightsDEPRECATED @19 :Bool;
|
||||
steeringRateLimitedDEPRECATED @29 :Bool;
|
||||
canMonoTimesDEPRECATED @12: List(UInt64);
|
||||
canRcvTimeoutDEPRECATED @49 :Bool;
|
||||
}
|
||||
|
||||
# ******* radar state @ 20hz *******
|
||||
|
||||
struct RadarData @0x888ad6581cf0aacb {
|
||||
struct RadarState {
|
||||
errors @0 :List(Error);
|
||||
points @1 :List(RadarPoint);
|
||||
|
||||
# which packets this state came from
|
||||
canMonoTimes @2 :List(UInt64);
|
||||
|
||||
enum Error {
|
||||
canError @0;
|
||||
commIssue @0;
|
||||
fault @1;
|
||||
wrongConfig @2;
|
||||
}
|
||||
|
||||
# similar to LiveTracks
|
||||
@@ -314,9 +184,6 @@ struct RadarData @0x888ad6581cf0aacb {
|
||||
# some radars flag measurements VS estimates
|
||||
measured @6 :Bool;
|
||||
}
|
||||
|
||||
# deprecated
|
||||
canMonoTimesDEPRECATED @2 :List(UInt64);
|
||||
}
|
||||
|
||||
# ******* car controls @ 100hz *******
|
||||
@@ -324,21 +191,13 @@ struct RadarData @0x888ad6581cf0aacb {
|
||||
struct CarControl {
|
||||
# must be true for any actuator commands to work
|
||||
enabled @0 :Bool;
|
||||
latActive @11: Bool;
|
||||
longActive @12: Bool;
|
||||
|
||||
# Actuator commands as computed by controlsd
|
||||
gasDEPRECATED @1 :Float32;
|
||||
brakeDEPRECATED @2 :Float32;
|
||||
steeringTorqueDEPRECATED @3 :Float32;
|
||||
|
||||
actuators @6 :Actuators;
|
||||
|
||||
# moved to CarOutput
|
||||
actuatorsOutputDEPRECATED @10 :Actuators;
|
||||
|
||||
leftBlinker @15: Bool;
|
||||
rightBlinker @16: Bool;
|
||||
|
||||
orientationNED @13 :List(Float32);
|
||||
angularVelocity @14 :List(Float32);
|
||||
|
||||
cruiseControl @4 :CruiseControl;
|
||||
hudControl @5 :HUDControl;
|
||||
|
||||
@@ -348,30 +207,13 @@ struct CarControl {
|
||||
brake @1: Float32;
|
||||
# range from -1.0 - 1.0
|
||||
steer @2: Float32;
|
||||
# value sent over can to the car
|
||||
steerOutputCan @8: Float32;
|
||||
steeringAngleDeg @3: Float32;
|
||||
|
||||
curvature @7: Float32;
|
||||
|
||||
speed @6: Float32; # m/s
|
||||
accel @4: Float32; # m/s^2
|
||||
longControlState @5: LongControlState;
|
||||
|
||||
enum LongControlState @0xe40f3a917d908282{
|
||||
off @0;
|
||||
pid @1;
|
||||
stopping @2;
|
||||
starting @3;
|
||||
}
|
||||
}
|
||||
|
||||
struct CruiseControl {
|
||||
cancel @0: Bool;
|
||||
resume @1: Bool;
|
||||
override @4: Bool;
|
||||
speedOverrideDEPRECATED @2: Float32;
|
||||
accelOverrideDEPRECATED @3: Float32;
|
||||
override @1: Bool;
|
||||
speedOverride @2: Float32;
|
||||
accelOverride @3: Float32;
|
||||
}
|
||||
|
||||
struct HUDControl {
|
||||
@@ -381,11 +223,6 @@ struct CarControl {
|
||||
leadVisible @3: Bool;
|
||||
visualAlert @4: VisualAlert;
|
||||
audibleAlert @5: AudibleAlert;
|
||||
rightLaneVisible @6: Bool;
|
||||
leftLaneVisible @7: Bool;
|
||||
rightLaneDepart @8: Bool;
|
||||
leftLaneDepart @9: Bool;
|
||||
leadDistanceBars @10: Int8; # 1-3: 1 is closest, 3 is farthest. some ports may utilize 2-4 bars instead
|
||||
|
||||
enum VisualAlert {
|
||||
# these are the choices from the Honda
|
||||
@@ -397,315 +234,88 @@ struct CarControl {
|
||||
wrongGear @4;
|
||||
seatbeltUnbuckled @5;
|
||||
speedTooHigh @6;
|
||||
ldw @7;
|
||||
}
|
||||
|
||||
enum AudibleAlert {
|
||||
# these are the choices from the Honda
|
||||
# map as good as you can for your car
|
||||
none @0;
|
||||
|
||||
engage @1;
|
||||
disengage @2;
|
||||
refuse @3;
|
||||
|
||||
warningSoft @4;
|
||||
warningImmediate @5;
|
||||
|
||||
prompt @6;
|
||||
promptRepeat @7;
|
||||
promptDistracted @8;
|
||||
beepSingle @1;
|
||||
beepTriple @2;
|
||||
beepRepeated @3;
|
||||
chimeSingle @4;
|
||||
chimeDouble @5;
|
||||
chimeRepeated @6;
|
||||
chimeContinuous @7;
|
||||
}
|
||||
}
|
||||
|
||||
gasDEPRECATED @1 :Float32;
|
||||
brakeDEPRECATED @2 :Float32;
|
||||
steeringTorqueDEPRECATED @3 :Float32;
|
||||
activeDEPRECATED @7 :Bool;
|
||||
rollDEPRECATED @8 :Float32;
|
||||
pitchDEPRECATED @9 :Float32;
|
||||
}
|
||||
|
||||
struct CarOutput {
|
||||
# Any car specific rate limits or quirks applied by
|
||||
# the CarController are reflected in actuatorsOutput
|
||||
# and matches what is sent to the car
|
||||
actuatorsOutput @0 :CarControl.Actuators;
|
||||
}
|
||||
|
||||
# ****** car param ******
|
||||
|
||||
struct CarParams {
|
||||
carName @0 :Text;
|
||||
carFingerprint @1 :Text;
|
||||
fuzzyFingerprint @55 :Bool;
|
||||
radarNameDEPRECATED @1 :Text;
|
||||
carFingerprint @2 :Text;
|
||||
|
||||
notCar @66 :Bool; # flag for non-car robotics platforms
|
||||
enableSteer @3 :Bool;
|
||||
enableGas @4 :Bool;
|
||||
enableBrake @5 :Bool;
|
||||
enableCruise @6 :Bool;
|
||||
enableCamera @26 :Bool;
|
||||
enableDsu @27 :Bool; # driving support unit
|
||||
enableApgs @28 :Bool; # advanced parking guidance system
|
||||
|
||||
pcmCruise @3 :Bool; # is openpilot's state tied to the PCM's cruise state?
|
||||
enableDsu @5 :Bool; # driving support unit
|
||||
enableBsm @56 :Bool; # blind spot monitoring
|
||||
flags @64 :UInt32; # flags for car specific quirks
|
||||
experimentalLongitudinalAvailable @71 :Bool;
|
||||
minEnableSpeed @17 :Float32;
|
||||
safetyModel @18 :Int16;
|
||||
safetyParam @41 :Int16;
|
||||
|
||||
minEnableSpeed @7 :Float32;
|
||||
minSteerSpeed @8 :Float32;
|
||||
safetyConfigs @62 :List(SafetyConfig);
|
||||
alternativeExperience @65 :Int16; # panda flag for features like no disengage on gas
|
||||
steerMaxBP @19 :List(Float32);
|
||||
steerMaxV @20 :List(Float32);
|
||||
gasMaxBP @21 :List(Float32);
|
||||
gasMaxV @22 :List(Float32);
|
||||
brakeMaxBP @23 :List(Float32);
|
||||
brakeMaxV @24 :List(Float32);
|
||||
|
||||
# Car docs fields
|
||||
maxLateralAccel @68 :Float32;
|
||||
autoResumeSng @69 :Bool; # describes whether car can resume from a stop automatically
|
||||
longPidDeadzoneBP @32 :List(Float32);
|
||||
longPidDeadzoneV @33 :List(Float32);
|
||||
|
||||
# things about the car in the manual
|
||||
mass @17 :Float32; # [kg] curb weight: all fluids no cargo
|
||||
wheelbase @18 :Float32; # [m] distance from rear axle to front axle
|
||||
centerToFront @19 :Float32; # [m] distance from center of mass to front axle
|
||||
steerRatio @20 :Float32; # [] ratio of steering wheel angle to front wheel angle
|
||||
steerRatioRear @21 :Float32; # [] ratio of steering wheel angle to rear wheel angle (usually 0)
|
||||
|
||||
# things we can derive
|
||||
rotationalInertia @22 :Float32; # [kg*m2] body rotational inertia
|
||||
tireStiffnessFactor @72 :Float32; # scaling factor used in calculating tireStiffness[Front,Rear]
|
||||
tireStiffnessFront @23 :Float32; # [N/rad] front tire coeff of stiff
|
||||
tireStiffnessRear @24 :Float32; # [N/rad] rear tire coeff of stiff
|
||||
|
||||
longitudinalTuning @25 :LongitudinalPIDTuning;
|
||||
lateralParams @48 :LateralParams;
|
||||
lateralTuning :union {
|
||||
pid @26 :LateralPIDTuning;
|
||||
indiDEPRECATED @27 :LateralINDITuning;
|
||||
lqrDEPRECATED @40 :LateralLQRTuning;
|
||||
torque @67 :LateralTorqueTuning;
|
||||
}
|
||||
|
||||
steerLimitAlert @28 :Bool;
|
||||
steerLimitTimer @47 :Float32; # time before steerLimitAlert is issued
|
||||
|
||||
vEgoStopping @29 :Float32; # Speed at which the car goes into stopping state
|
||||
vEgoStarting @59 :Float32; # Speed at which the car goes into starting state
|
||||
stoppingControl @31 :Bool; # Does the car allow full control even at lows speeds when stopping
|
||||
steerControlType @34 :SteerControlType;
|
||||
radarUnavailable @35 :Bool; # True when radar objects aren't visible on CAN or aren't parsed out
|
||||
stopAccel @60 :Float32; # Required acceleration to keep vehicle stationary
|
||||
stoppingDecelRate @52 :Float32; # m/s^2/s while trying to stop
|
||||
startAccel @32 :Float32; # Required acceleration to get car moving
|
||||
startingState @70 :Bool; # Does this car make use of special starting state
|
||||
|
||||
steerActuatorDelay @36 :Float32; # Steering wheel actuator delay in seconds
|
||||
longitudinalActuatorDelay @58 :Float32; # Gas/Brake actuator delay in seconds
|
||||
openpilotLongitudinalControl @37 :Bool; # is openpilot doing the longitudinal control?
|
||||
carVin @38 :Text; # VIN number queried during fingerprinting
|
||||
dashcamOnly @41: Bool;
|
||||
passive @73: Bool; # is openpilot in control?
|
||||
transmissionType @43 :TransmissionType;
|
||||
carFw @44 :List(CarFw);
|
||||
|
||||
radarTimeStep @45: Float32 = 0.05; # time delta between radar updates, 20Hz is very standard
|
||||
fingerprintSource @49: FingerprintSource;
|
||||
networkLocation @50 :NetworkLocation; # Where Panda/C2 is integrated into the car's CAN network
|
||||
|
||||
wheelSpeedFactor @63 :Float32; # Multiplier on wheels speeds to computer actual speeds
|
||||
|
||||
secOcRequired @74 :Bool; # Car requires SecOC message authentication to operate
|
||||
secOcKeyAvailable @75 :Bool; # Stored SecOC key loaded from params
|
||||
|
||||
struct SafetyConfig {
|
||||
safetyModel @0 :SafetyModel;
|
||||
safetyParam @3 :UInt16;
|
||||
safetyParamDEPRECATED @1 :Int16;
|
||||
safetyParam2DEPRECATED @2 :UInt32;
|
||||
}
|
||||
|
||||
struct LateralParams {
|
||||
torqueBP @0 :List(Int32);
|
||||
torqueV @1 :List(Int32);
|
||||
}
|
||||
|
||||
struct LateralPIDTuning {
|
||||
kpBP @0 :List(Float32);
|
||||
kpV @1 :List(Float32);
|
||||
kiBP @2 :List(Float32);
|
||||
kiV @3 :List(Float32);
|
||||
kf @4 :Float32;
|
||||
}
|
||||
|
||||
struct LateralTorqueTuning {
|
||||
useSteeringAngle @0 :Bool;
|
||||
kp @1 :Float32;
|
||||
ki @2 :Float32;
|
||||
kd @8 : Float32;
|
||||
friction @3 :Float32;
|
||||
steeringAngleDeadzoneDeg @5 :Float32;
|
||||
latAccelFactor @6 :Float32;
|
||||
latAccelOffset @7 :Float32;
|
||||
kfDEPRECATED @4 :Float32;
|
||||
}
|
||||
|
||||
struct LongitudinalPIDTuning {
|
||||
kpBP @0 :List(Float32);
|
||||
kpV @1 :List(Float32);
|
||||
kiBP @2 :List(Float32);
|
||||
kiV @3 :List(Float32);
|
||||
kfDEPRECATED @6 :Float32;
|
||||
deadzoneBP @4 :List(Float32);
|
||||
deadzoneV @5 :List(Float32);
|
||||
}
|
||||
|
||||
struct LateralINDITuning {
|
||||
outerLoopGainBP @4 :List(Float32);
|
||||
outerLoopGainV @5 :List(Float32);
|
||||
innerLoopGainBP @6 :List(Float32);
|
||||
innerLoopGainV @7 :List(Float32);
|
||||
timeConstantBP @8 :List(Float32);
|
||||
timeConstantV @9 :List(Float32);
|
||||
actuatorEffectivenessBP @10 :List(Float32);
|
||||
actuatorEffectivenessV @11 :List(Float32);
|
||||
|
||||
outerLoopGainDEPRECATED @0 :Float32;
|
||||
innerLoopGainDEPRECATED @1 :Float32;
|
||||
timeConstantDEPRECATED @2 :Float32;
|
||||
actuatorEffectivenessDEPRECATED @3 :Float32;
|
||||
}
|
||||
|
||||
struct LateralLQRTuning {
|
||||
scale @0 :Float32;
|
||||
ki @1 :Float32;
|
||||
dcGain @2 :Float32;
|
||||
|
||||
# State space system
|
||||
a @3 :List(Float32);
|
||||
b @4 :List(Float32);
|
||||
c @5 :List(Float32);
|
||||
|
||||
k @6 :List(Float32); # LQR gain
|
||||
l @7 :List(Float32); # Kalman gain
|
||||
}
|
||||
|
||||
enum SafetyModel {
|
||||
silent @0;
|
||||
hondaNidec @1;
|
||||
enum SafetyModels {
|
||||
# does NOT match board setting
|
||||
noOutput @0;
|
||||
honda @1;
|
||||
toyota @2;
|
||||
elm327 @3;
|
||||
gm @4;
|
||||
hondaBoschGiraffe @5;
|
||||
ford @6;
|
||||
cadillac @7;
|
||||
hyundai @8;
|
||||
chrysler @9;
|
||||
tesla @10;
|
||||
subaru @11;
|
||||
gmPassive @12;
|
||||
mazda @13;
|
||||
nissan @14;
|
||||
volkswagen @15;
|
||||
toyotaIpas @16;
|
||||
allOutput @17;
|
||||
gmAscm @18;
|
||||
noOutput @19; # like silent but without silent CAN TXs
|
||||
hondaBosch @20;
|
||||
volkswagenPq @21;
|
||||
subaruPreglobal @22; # pre-Global platform
|
||||
hyundaiLegacy @23;
|
||||
hyundaiCommunity @24;
|
||||
volkswagenMlb @25;
|
||||
hongqi @26;
|
||||
body @27;
|
||||
hyundaiCanfd @28;
|
||||
volkswagenMqbEvo @29;
|
||||
chryslerCusw @30;
|
||||
psa @31;
|
||||
}
|
||||
|
||||
enum SteerControlType {
|
||||
torque @0;
|
||||
angle @1;
|
||||
# things about the car in the manual
|
||||
mass @7 :Float32; # [kg] running weight
|
||||
wheelbase @8 :Float32; # [m] distance from rear to front axle
|
||||
centerToFront @9 :Float32; # [m] GC distance to front axle
|
||||
steerRatio @10 :Float32; # [] ratio between front wheels and steering wheel angles
|
||||
steerRatioRear @11 :Float32; # [] rear steering ratio wrt front steering (usually 0)
|
||||
|
||||
curvatureDEPRECATED @2;
|
||||
}
|
||||
# things we can derive
|
||||
rotationalInertia @12 :Float32; # [kg*m2] body rotational inertia
|
||||
tireStiffnessFront @13 :Float32; # [N/rad] front tire coeff of stiff
|
||||
tireStiffnessRear @14 :Float32; # [N/rad] rear tire coeff of stiff
|
||||
|
||||
enum TransmissionType {
|
||||
unknown @0;
|
||||
automatic @1; # Traditional auto, including DSG
|
||||
manual @2; # True "stick shift" only
|
||||
direct @3; # Electric vehicle or other direct drive
|
||||
cvt @4;
|
||||
}
|
||||
# Kp and Ki for the lateral control
|
||||
steerKp @15 :Float32;
|
||||
steerKi @16 :Float32;
|
||||
steerKf @25 :Float32;
|
||||
|
||||
struct CarFw {
|
||||
ecu @0 :Ecu;
|
||||
fwVersion @1 :Data;
|
||||
address @2 :UInt32;
|
||||
subAddress @3 :UInt8;
|
||||
responseAddress @4 :UInt32;
|
||||
request @5 :List(Data);
|
||||
brand @6 :Text;
|
||||
bus @7 :UInt8;
|
||||
logging @8 :Bool;
|
||||
obdMultiplexing @9 :Bool;
|
||||
}
|
||||
# Kp and Ki for the longitudinal control
|
||||
longitudinalKpBP @36 :List(Float32);
|
||||
longitudinalKpV @37 :List(Float32);
|
||||
longitudinalKiBP @38 :List(Float32);
|
||||
longitudinalKiV @39 :List(Float32);
|
||||
|
||||
enum Ecu {
|
||||
eps @0;
|
||||
abs @1;
|
||||
fwdRadar @2;
|
||||
fwdCamera @3;
|
||||
engine @4;
|
||||
unknown @5;
|
||||
transmission @8; # Transmission Control Module
|
||||
hybrid @18; # hybrid control unit, e.g. Chrysler's HCP, Honda's IMA Control Unit, Toyota's hybrid control computer
|
||||
srs @9; # airbag
|
||||
gateway @10; # can gateway
|
||||
hud @11; # heads up display
|
||||
combinationMeter @12; # instrument cluster
|
||||
electricBrakeBooster @15;
|
||||
shiftByWire @16;
|
||||
adas @19;
|
||||
cornerRadar @21;
|
||||
hvac @20;
|
||||
parkingAdas @7; # parking assist system ECU, e.g. Toyota's IPAS, Hyundai's RSPA, etc.
|
||||
epb @22; # electronic parking brake
|
||||
telematics @23;
|
||||
body @24; # body control module
|
||||
steerLimitAlert @29 :Bool;
|
||||
|
||||
# Toyota only
|
||||
dsu @6;
|
||||
|
||||
# Honda only
|
||||
vsa @13; # Vehicle Stability Assist
|
||||
programmedFuelInjection @14;
|
||||
|
||||
debug @17;
|
||||
}
|
||||
|
||||
enum FingerprintSource {
|
||||
can @0;
|
||||
fw @1;
|
||||
fixed @2;
|
||||
}
|
||||
|
||||
enum NetworkLocation {
|
||||
fwdCamera @0; # Standard/default integration at LKAS camera
|
||||
gateway @1; # Integration at vehicle's CAN gateway
|
||||
}
|
||||
|
||||
enableGasInterceptor @2 :Bool;
|
||||
enableCameraDEPRECATED @4 :Bool;
|
||||
enableApgsDEPRECATED @6 :Bool;
|
||||
steerRateCostDEPRECATED @33 :Float32;
|
||||
isPandaBlackDEPRECATED @39 :Bool;
|
||||
hasStockCameraDEPRECATED @57 :Bool;
|
||||
safetyParamDEPRECATED @10 :Int16;
|
||||
safetyModelDEPRECATED @9 :SafetyModel;
|
||||
safetyModelPassiveDEPRECATED @42 :SafetyModel = silent;
|
||||
minSpeedCanDEPRECATED @51 :Float32;
|
||||
communityFeatureDEPRECATED @46: Bool;
|
||||
startingAccelRateDEPRECATED @53 :Float32;
|
||||
steerMaxBPDEPRECATED @11 :List(Float32);
|
||||
steerMaxVDEPRECATED @12 :List(Float32);
|
||||
gasMaxBPDEPRECATED @13 :List(Float32);
|
||||
gasMaxVDEPRECATED @14 :List(Float32);
|
||||
brakeMaxBPDEPRECATED @15 :List(Float32);
|
||||
brakeMaxVDEPRECATED @16 :List(Float32);
|
||||
directAccelControlDEPRECATED @30 :Bool;
|
||||
maxSteeringAngleDegDEPRECATED @54 :Float32;
|
||||
longitudinalActuatorDelayLowerBoundDEPRECATEDDEPRECATED @61 :Float32;
|
||||
vEgoStopping @30 :Float32; # Speed at which the car goes into stopping state
|
||||
directAccelControl @31 :Bool; # Does the car have direct accel control or just gas/brake
|
||||
stoppingControl @34 :Bool; # Does the car allows full control even at lows speeds when stopping
|
||||
startAccel @35 :Float32; # Required acceleraton to overcome creep braking
|
||||
steerRateCost @40 :Float32; # Lateral MPC cost on steering rate
|
||||
}
|
||||
|
||||
@@ -1,246 +0,0 @@
|
||||
using Cxx = import "./include/c++.capnp";
|
||||
$Cxx.namespace("cereal");
|
||||
|
||||
using Car = import "car.capnp";
|
||||
|
||||
@0xb526ba661d550a59;
|
||||
|
||||
# custom.capnp: a home for empty structs reserved for custom forks
|
||||
# These structs are guaranteed to remain reserved and empty in mainline
|
||||
# cereal, so use these if you want custom events in your fork.
|
||||
|
||||
# you can rename the struct, but don't change the identifier
|
||||
struct FrogPilotCarControl {
|
||||
hudControl @0 :HUDControl;
|
||||
|
||||
struct HUDControl {
|
||||
audibleAlert @0 :AudibleAlert;
|
||||
|
||||
enum AudibleAlert {
|
||||
none @0;
|
||||
|
||||
engage @1;
|
||||
disengage @2;
|
||||
refuse @3;
|
||||
|
||||
warningSoft @4;
|
||||
warningImmediate @5;
|
||||
|
||||
prompt @6;
|
||||
promptRepeat @7;
|
||||
promptDistracted @8;
|
||||
|
||||
# Random Events
|
||||
angry @9;
|
||||
continued @10;
|
||||
dejaVu @11;
|
||||
doc @12;
|
||||
fart @13;
|
||||
firefox @14;
|
||||
goat @15;
|
||||
hal9000 @16;
|
||||
mail @17;
|
||||
nessie @18;
|
||||
noice @19;
|
||||
startup @20;
|
||||
thisIsFine @21;
|
||||
uwu @22;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FrogPilotCarEvent @0x81c2f05a394cf4af {
|
||||
name @0 :EventName;
|
||||
|
||||
enable @1 :Bool;
|
||||
noEntry @2 :Bool;
|
||||
warning @3 :Bool;
|
||||
userDisable @4 :Bool;
|
||||
softDisable @5 :Bool;
|
||||
immediateDisable @6 :Bool;
|
||||
preEnable @7 :Bool;
|
||||
permanent @8 :Bool;
|
||||
overrideLateral @10 :Bool;
|
||||
overrideLongitudinal @9 :Bool;
|
||||
|
||||
enum EventName @0xaedffd8f31e7b55d {
|
||||
blockUser @0;
|
||||
customStartupAlert @1;
|
||||
forcingStop @2;
|
||||
goatSteerSaturated @3;
|
||||
greenLight @4;
|
||||
holidayActive @5;
|
||||
laneChangeBlockedLoud @6;
|
||||
leadDeparting @7;
|
||||
noLaneAvailable @8;
|
||||
openpilotCrashed @9;
|
||||
pedalInterceptorNoBrake @10;
|
||||
speedLimitChanged @11;
|
||||
torqueNNLoad @12;
|
||||
trafficModeActive @13;
|
||||
trafficModeInactive @14;
|
||||
turningLeft @15;
|
||||
turningRight @16;
|
||||
|
||||
# Random Events
|
||||
accel30 @17;
|
||||
accel35 @18;
|
||||
accel40 @19;
|
||||
dejaVuCurve @20;
|
||||
firefoxSteerSaturated @21;
|
||||
hal9000 @22;
|
||||
openpilotCrashedRandomEvent @23;
|
||||
thisIsFineSteerSaturated @24;
|
||||
toBeContinued @25;
|
||||
vCruise69 @26;
|
||||
yourFrogTriedToKillMe @27;
|
||||
youveGotMail @28;
|
||||
}
|
||||
}
|
||||
|
||||
struct FrogPilotCarParams @0xf35cc4560bbf6ec2 {
|
||||
canUsePedal @0 :Bool;
|
||||
canUseSDSU @1 :Bool;
|
||||
fpFlags @2 :UInt32;
|
||||
isHDA2 @3 :Bool;
|
||||
openpilotLongitudinalControlDisabled @4 :Bool;
|
||||
safetyConfigs @5 :List(SafetyConfig);
|
||||
canUseSASCM @6 :Bool;
|
||||
|
||||
struct SafetyConfig {
|
||||
safetyParam @0 :UInt16;
|
||||
}
|
||||
}
|
||||
|
||||
struct FrogPilotCarState @0xda96579883444c35 {
|
||||
accelPressed @0 :Bool;
|
||||
alwaysOnLateralAllowed @1 :Bool;
|
||||
alwaysOnLateralEnabled @2 :Bool;
|
||||
brakeLights @3 :Bool;
|
||||
dashboardSpeedLimit @4 :Float32;
|
||||
decelPressed @5 :Bool;
|
||||
distancePressed @6 :Bool;
|
||||
distanceLongPressed @7 :Bool;
|
||||
distanceVeryLongPressed @8 :Bool;
|
||||
ecoGear @9 :Bool;
|
||||
forceCoast @10 :Bool;
|
||||
pauseLateral @11 :Bool;
|
||||
pauseLongitudinal @12 :Bool;
|
||||
sportGear @13 :Bool;
|
||||
trafficModeEnabled @14 :Bool;
|
||||
|
||||
struct ButtonEvent {
|
||||
enum Type {
|
||||
lkas @0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FrogPilotControlsState @0x80ae746ee2596b11 {
|
||||
alertStatus @0 :AlertStatus;
|
||||
alertText1 @1 :Text;
|
||||
alertText2 @2 :Text;
|
||||
alertSize @3 :AlertSize;
|
||||
alertBlinkingRate @4 :Float32;
|
||||
alertType @5 :Text;
|
||||
alertSound @6 :Car.CarControl.HUDControl.AudibleAlert;
|
||||
|
||||
enum AlertSize {
|
||||
none @0; # don't display the alert
|
||||
small @1; # small box
|
||||
mid @2; # mid screen
|
||||
full @3; # full screen
|
||||
}
|
||||
|
||||
enum AlertStatus {
|
||||
normal @0; # low priority alert for user's convenience
|
||||
userPrompt @1; # mid priority alert that might require user intervention
|
||||
critical @2; # high priority alert that needs immediate user intervention
|
||||
frogpilot @3; # FrogPilot startup alert
|
||||
}
|
||||
}
|
||||
|
||||
struct FrogPilotDeviceState @0xa5cd762cd951a455 {
|
||||
freeSpace @0 :Int16;
|
||||
usedSpace @1 :Int16;
|
||||
}
|
||||
|
||||
struct FrogPilotModelDataV2 @0xf98d843bfd7004a3 {
|
||||
turnDirection @0 :TurnDirection;
|
||||
|
||||
enum TurnDirection {
|
||||
none @0;
|
||||
turnLeft @1;
|
||||
turnRight @2;
|
||||
}
|
||||
}
|
||||
|
||||
struct FrogPilotNavigation @0xf416ec09499d9d19 {
|
||||
approachingIntersection @0 :Bool;
|
||||
approachingTurn @1 :Bool;
|
||||
navigationSpeedLimit @2 :Float32;
|
||||
}
|
||||
|
||||
struct FrogPilotPlan @0xa1680744031fdb2d {
|
||||
accelerationJerk @0 :Float32;
|
||||
accelerationJerkStock @1 :Float32;
|
||||
cscControllingSpeed @2 :Bool;
|
||||
cscSpeed @3 :Float32;
|
||||
cscTraining @4 :Bool;
|
||||
dangerJerk @5 :Float32;
|
||||
desiredFollowDistance @6 :Int64;
|
||||
disableThrottle @7 :Bool;
|
||||
experimentalMode @8 :Bool;
|
||||
forcingStop @9 :Bool;
|
||||
forcingStopLength @10 :Float32;
|
||||
frogpilotEvents @11 :List(FrogPilotCarEvent);
|
||||
increasedStoppedDistance @12 :Float32;
|
||||
lateralCheck @13 :Bool;
|
||||
laneWidthLeft @14 :Float32;
|
||||
laneWidthRight @15 :Float32;
|
||||
maxAcceleration @16 :Float32;
|
||||
minAcceleration @17 :Float32;
|
||||
redLight @18 :Bool;
|
||||
roadCurvature @19 :Float32;
|
||||
slcMapSpeedLimit @20 :Float32;
|
||||
slcMapboxSpeedLimit @21 :Float32;
|
||||
slcNextSpeedLimit @22 :Float32;
|
||||
slcOverriddenSpeed @23 :Float32;
|
||||
slcSpeedLimit @24 :Float32;
|
||||
slcSpeedLimitOffset @25 :Float32;
|
||||
slcSpeedLimitSource @26 :Text;
|
||||
speedJerk @27 :Float32;
|
||||
speedJerkStock @28 :Float32;
|
||||
speedLimitChanged @29 :Bool;
|
||||
tFollow @30 :Float32;
|
||||
themeUpdated @31 :Bool;
|
||||
togglesUpdated @32 :Bool;
|
||||
trackingLead @33 :Bool;
|
||||
unconfirmedSlcSpeedLimit @34 :Float32;
|
||||
vCruise @35 :Float32;
|
||||
}
|
||||
|
||||
struct FrogPilotRadarState @0xcb9fd56c7057593a {
|
||||
leadLeft @0 :LeadData;
|
||||
leadRight @1 :LeadData;
|
||||
|
||||
struct LeadData {
|
||||
dRel @0 :Float32;
|
||||
yRel @1 :Float32;
|
||||
vRel @2 :Float32;
|
||||
aRel @3 :Float32;
|
||||
vLead @4 :Float32;
|
||||
dPath @6 :Float32;
|
||||
vLat @7 :Float32;
|
||||
vLeadK @8 :Float32;
|
||||
aLeadK @9 :Float32;
|
||||
fcw @10 :Bool;
|
||||
status @11 :Bool;
|
||||
aLeadTau @12 :Float32;
|
||||
modelProb @13 :Float32;
|
||||
radar @14 :Bool;
|
||||
radarTrackId @15 :Int32 = -1;
|
||||
|
||||
aLeadDEPRECATED @5 :Float32;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,28 @@
|
||||
# Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
|
||||
# Licensed under the MIT License:
|
||||
#
|
||||
# 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.
|
||||
|
||||
@0xc5f1af96651f70ea;
|
||||
|
||||
annotation package @0x9ee4c8f803b3b596 (file) : Text;
|
||||
# Name of the package, such as "org.example.foo", in which the generated code will reside.
|
||||
|
||||
annotation outerClassname @0x9b066bb4881f7cd3 (file) : Text;
|
||||
# Name of the outer class that will wrap the generated code.
|
||||
@@ -1,574 +0,0 @@
|
||||
using Cxx = import "./include/c++.capnp";
|
||||
$Cxx.namespace("cereal");
|
||||
|
||||
@0x80ef1ec4889c2a63;
|
||||
|
||||
# legacy.capnp: a home for deprecated structs
|
||||
|
||||
struct LogRotate @0x9811e1f38f62f2d1 {
|
||||
segmentNum @0 :Int32;
|
||||
path @1 :Text;
|
||||
}
|
||||
|
||||
struct LiveUI @0xc08240f996aefced {
|
||||
rearViewCam @0 :Bool;
|
||||
alertText1 @1 :Text;
|
||||
alertText2 @2 :Text;
|
||||
awarenessStatus @3 :Float32;
|
||||
}
|
||||
|
||||
struct UiLayoutState @0x88dcce08ad29dda0 {
|
||||
activeApp @0 :App;
|
||||
sidebarCollapsed @1 :Bool;
|
||||
mapEnabled @2 :Bool;
|
||||
mockEngaged @3 :Bool;
|
||||
|
||||
enum App @0x9917470acf94d285 {
|
||||
home @0;
|
||||
music @1;
|
||||
nav @2;
|
||||
settings @3;
|
||||
none @4;
|
||||
}
|
||||
}
|
||||
|
||||
struct OrbslamCorrection @0x8afd33dc9b35e1aa {
|
||||
correctionMonoTime @0 :UInt64;
|
||||
prePositionECEF @1 :List(Float64);
|
||||
postPositionECEF @2 :List(Float64);
|
||||
prePoseQuatECEF @3 :List(Float32);
|
||||
postPoseQuatECEF @4 :List(Float32);
|
||||
numInliers @5 :UInt32;
|
||||
}
|
||||
|
||||
struct EthernetPacket @0xa99a9d5b33cf5859 {
|
||||
pkt @0 :Data;
|
||||
ts @1 :Float32;
|
||||
}
|
||||
|
||||
struct CellInfo @0xcff7566681c277ce {
|
||||
timestamp @0 :UInt64;
|
||||
repr @1 :Text; # android toString() for now
|
||||
}
|
||||
|
||||
struct WifiScan @0xd4df5a192382ba0b {
|
||||
bssid @0 :Text;
|
||||
ssid @1 :Text;
|
||||
capabilities @2 :Text;
|
||||
frequency @3 :Int32;
|
||||
level @4 :Int32;
|
||||
timestamp @5 :Int64;
|
||||
|
||||
centerFreq0 @6 :Int32;
|
||||
centerFreq1 @7 :Int32;
|
||||
channelWidth @8 :ChannelWidth;
|
||||
operatorFriendlyName @9 :Text;
|
||||
venueName @10 :Text;
|
||||
is80211mcResponder @11 :Bool;
|
||||
passpoint @12 :Bool;
|
||||
|
||||
distanceCm @13 :Int32;
|
||||
distanceSdCm @14 :Int32;
|
||||
|
||||
enum ChannelWidth @0xcb6a279f015f6b51 {
|
||||
w20Mhz @0;
|
||||
w40Mhz @1;
|
||||
w80Mhz @2;
|
||||
w160Mhz @3;
|
||||
w80Plus80Mhz @4;
|
||||
}
|
||||
}
|
||||
|
||||
struct LiveEventData @0x94b7baa90c5c321e {
|
||||
name @0 :Text;
|
||||
value @1 :Int32;
|
||||
}
|
||||
|
||||
struct ModelData @0xb8aad62cffef28a9 {
|
||||
frameId @0 :UInt32;
|
||||
frameAge @12 :UInt32;
|
||||
frameDropPerc @13 :Float32;
|
||||
timestampEof @9 :UInt64;
|
||||
modelExecutionTime @14 :Float32;
|
||||
gpuExecutionTime @16 :Float32;
|
||||
rawPred @15 :Data;
|
||||
|
||||
path @1 :PathData;
|
||||
leftLane @2 :PathData;
|
||||
rightLane @3 :PathData;
|
||||
lead @4 :LeadData;
|
||||
freePath @6 :List(Float32);
|
||||
|
||||
settings @5 :ModelSettings;
|
||||
leadFuture @7 :LeadData;
|
||||
speed @8 :List(Float32);
|
||||
meta @10 :MetaData;
|
||||
longitudinal @11 :LongitudinalData;
|
||||
|
||||
struct PathData @0x8817eeea389e9f08 {
|
||||
points @0 :List(Float32);
|
||||
prob @1 :Float32;
|
||||
std @2 :Float32;
|
||||
stds @3 :List(Float32);
|
||||
poly @4 :List(Float32);
|
||||
validLen @5 :Float32;
|
||||
}
|
||||
|
||||
struct LeadData @0xd1c9bef96d26fa91 {
|
||||
dist @0 :Float32;
|
||||
prob @1 :Float32;
|
||||
std @2 :Float32;
|
||||
relVel @3 :Float32;
|
||||
relVelStd @4 :Float32;
|
||||
relY @5 :Float32;
|
||||
relYStd @6 :Float32;
|
||||
relA @7 :Float32;
|
||||
relAStd @8 :Float32;
|
||||
}
|
||||
|
||||
struct ModelSettings @0xa26e3710efd3e914 {
|
||||
bigBoxX @0 :UInt16;
|
||||
bigBoxY @1 :UInt16;
|
||||
bigBoxWidth @2 :UInt16;
|
||||
bigBoxHeight @3 :UInt16;
|
||||
boxProjection @4 :List(Float32);
|
||||
yuvCorrection @5 :List(Float32);
|
||||
inputTransform @6 :List(Float32);
|
||||
}
|
||||
|
||||
struct MetaData @0x9744f25fb60f2bf8 {
|
||||
engagedProb @0 :Float32;
|
||||
desirePrediction @1 :List(Float32);
|
||||
brakeDisengageProb @2 :Float32;
|
||||
gasDisengageProb @3 :Float32;
|
||||
steerOverrideProb @4 :Float32;
|
||||
desireState @5 :List(Float32);
|
||||
}
|
||||
|
||||
struct LongitudinalData @0xf98f999c6a071122 {
|
||||
distances @2 :List(Float32);
|
||||
speeds @0 :List(Float32);
|
||||
accelerations @1 :List(Float32);
|
||||
}
|
||||
}
|
||||
|
||||
struct ECEFPoint @0xc25bbbd524983447 {
|
||||
x @0 :Float64;
|
||||
y @1 :Float64;
|
||||
z @2 :Float64;
|
||||
}
|
||||
|
||||
struct ECEFPointDEPRECATED @0xe10e21168db0c7f7 {
|
||||
x @0 :Float32;
|
||||
y @1 :Float32;
|
||||
z @2 :Float32;
|
||||
}
|
||||
|
||||
struct GPSPlannerPoints @0xab54c59699f8f9f3 {
|
||||
curPosDEPRECATED @0 :ECEFPointDEPRECATED;
|
||||
pointsDEPRECATED @1 :List(ECEFPointDEPRECATED);
|
||||
curPos @6 :ECEFPoint;
|
||||
points @7 :List(ECEFPoint);
|
||||
valid @2 :Bool;
|
||||
trackName @3 :Text;
|
||||
speedLimit @4 :Float32;
|
||||
accelTarget @5 :Float32;
|
||||
}
|
||||
|
||||
struct GPSPlannerPlan @0xf5ad1d90cdc1dd6b {
|
||||
valid @0 :Bool;
|
||||
poly @1 :List(Float32);
|
||||
trackName @2 :Text;
|
||||
speed @3 :Float32;
|
||||
acceleration @4 :Float32;
|
||||
pointsDEPRECATED @5 :List(ECEFPointDEPRECATED);
|
||||
points @6 :List(ECEFPoint);
|
||||
xLookahead @7 :Float32;
|
||||
}
|
||||
|
||||
struct UiNavigationEvent @0x90c8426c3eaddd3b {
|
||||
type @0: Type;
|
||||
status @1: Status;
|
||||
distanceTo @2: Float32;
|
||||
endRoadPointDEPRECATED @3: ECEFPointDEPRECATED;
|
||||
endRoadPoint @4: ECEFPoint;
|
||||
|
||||
enum Type @0xe8db07dcf8fcea05 {
|
||||
none @0;
|
||||
laneChangeLeft @1;
|
||||
laneChangeRight @2;
|
||||
mergeLeft @3;
|
||||
mergeRight @4;
|
||||
turnLeft @5;
|
||||
turnRight @6;
|
||||
}
|
||||
|
||||
enum Status @0xb9aa88c75ef99a1f {
|
||||
none @0;
|
||||
passive @1;
|
||||
approaching @2;
|
||||
active @3;
|
||||
}
|
||||
}
|
||||
|
||||
struct LiveLocationData @0xb99b2bc7a57e8128 {
|
||||
status @0 :UInt8;
|
||||
|
||||
# 3D fix
|
||||
lat @1 :Float64;
|
||||
lon @2 :Float64;
|
||||
alt @3 :Float32; # m
|
||||
|
||||
# speed
|
||||
speed @4 :Float32; # m/s
|
||||
|
||||
# NED velocity components
|
||||
vNED @5 :List(Float32);
|
||||
|
||||
# roll, pitch, heading (x,y,z)
|
||||
roll @6 :Float32; # WRT to center of earth?
|
||||
pitch @7 :Float32; # WRT to center of earth?
|
||||
heading @8 :Float32; # WRT to north?
|
||||
|
||||
# what are these?
|
||||
wanderAngle @9 :Float32;
|
||||
trackAngle @10 :Float32;
|
||||
|
||||
# car frame -- https://upload.wikimedia.org/wikipedia/commons/f/f5/RPY_angles_of_cars.png
|
||||
|
||||
# gyro, in car frame, deg/s
|
||||
gyro @11 :List(Float32);
|
||||
|
||||
# accel, in car frame, m/s^2
|
||||
accel @12 :List(Float32);
|
||||
|
||||
accuracy @13 :Accuracy;
|
||||
|
||||
source @14 :SensorSource;
|
||||
# if we are fixing a location in the past
|
||||
fixMonoTime @15 :UInt64;
|
||||
|
||||
gpsWeek @16 :Int32;
|
||||
timeOfWeek @17 :Float64;
|
||||
|
||||
positionECEF @18 :List(Float64);
|
||||
poseQuatECEF @19 :List(Float32);
|
||||
pitchCalibration @20 :Float32;
|
||||
yawCalibration @21 :Float32;
|
||||
imuFrame @22 :List(Float32);
|
||||
|
||||
struct Accuracy @0x943dc4625473b03f {
|
||||
pNEDError @0 :List(Float32);
|
||||
vNEDError @1 :List(Float32);
|
||||
rollError @2 :Float32;
|
||||
pitchError @3 :Float32;
|
||||
headingError @4 :Float32;
|
||||
ellipsoidSemiMajorError @5 :Float32;
|
||||
ellipsoidSemiMinorError @6 :Float32;
|
||||
ellipsoidOrientationError @7 :Float32;
|
||||
}
|
||||
|
||||
enum SensorSource @0xc871d3cc252af657 {
|
||||
applanix @0;
|
||||
kalman @1;
|
||||
orbslam @2;
|
||||
timing @3;
|
||||
dummy @4;
|
||||
}
|
||||
}
|
||||
|
||||
struct OrbOdometry @0xd7700859ed1f5b76 {
|
||||
# timing first
|
||||
startMonoTime @0 :UInt64;
|
||||
endMonoTime @1 :UInt64;
|
||||
|
||||
# fundamental matrix and error
|
||||
f @2: List(Float64);
|
||||
err @3: Float64;
|
||||
|
||||
# number of inlier points
|
||||
inliers @4: Int32;
|
||||
|
||||
# for debug only
|
||||
# indexed by endMonoTime features
|
||||
# value is startMonoTime feature match
|
||||
# -1 if no match
|
||||
matches @5: List(Int16);
|
||||
}
|
||||
|
||||
struct OrbFeatures @0xcd60164a8a0159ef {
|
||||
timestampEof @0 :UInt64;
|
||||
# transposed arrays of normalized image coordinates
|
||||
# len(xs) == len(ys) == len(descriptors) * 32
|
||||
xs @1 :List(Float32);
|
||||
ys @2 :List(Float32);
|
||||
descriptors @3 :Data;
|
||||
octaves @4 :List(Int8);
|
||||
|
||||
# match index to last OrbFeatures
|
||||
# -1 if no match
|
||||
timestampLastEof @5 :UInt64;
|
||||
matches @6: List(Int16);
|
||||
}
|
||||
|
||||
struct OrbFeaturesSummary @0xd500d30c5803fa4f {
|
||||
timestampEof @0 :UInt64;
|
||||
timestampLastEof @1 :UInt64;
|
||||
|
||||
featureCount @2 :UInt16;
|
||||
matchCount @3 :UInt16;
|
||||
computeNs @4 :UInt64;
|
||||
}
|
||||
|
||||
struct OrbKeyFrame @0xc8233c0345e27e24 {
|
||||
# this is a globally unique id for the KeyFrame
|
||||
id @0: UInt64;
|
||||
|
||||
# this is the location of the KeyFrame
|
||||
pos @1: ECEFPoint;
|
||||
|
||||
# these are the features in the world
|
||||
# len(dpos) == len(descriptors) * 32
|
||||
dpos @2 :List(ECEFPoint);
|
||||
descriptors @3 :Data;
|
||||
}
|
||||
|
||||
struct KalmanOdometry @0x92e21bb7ea38793a {
|
||||
trans @0 :List(Float32); # m/s in device frame
|
||||
rot @1 :List(Float32); # rad/s in device frame
|
||||
transStd @2 :List(Float32); # std m/s in device frame
|
||||
rotStd @3 :List(Float32); # std rad/s in device frame
|
||||
}
|
||||
|
||||
struct OrbObservation @0x9b326d4e436afec7 {
|
||||
observationMonoTime @0 :UInt64;
|
||||
normalizedCoordinates @1 :List(Float32);
|
||||
locationECEF @2 :List(Float64);
|
||||
matchDistance @3: UInt32;
|
||||
}
|
||||
|
||||
struct CalibrationFeatures @0x8fdfadb254ea867a {
|
||||
frameId @0 :UInt32;
|
||||
|
||||
p0 @1 :List(Float32);
|
||||
p1 @2 :List(Float32);
|
||||
status @3 :List(Int8);
|
||||
}
|
||||
|
||||
struct NavStatus @0xbd8822120928120c {
|
||||
isNavigating @0 :Bool;
|
||||
currentAddress @1 :Address;
|
||||
|
||||
struct Address @0xce7cd672cacc7814 {
|
||||
title @0 :Text;
|
||||
lat @1 :Float64;
|
||||
lng @2 :Float64;
|
||||
house @3 :Text;
|
||||
address @4 :Text;
|
||||
street @5 :Text;
|
||||
city @6 :Text;
|
||||
state @7 :Text;
|
||||
country @8 :Text;
|
||||
}
|
||||
}
|
||||
|
||||
struct NavUpdate @0xdb98be6565516acb {
|
||||
isNavigating @0 :Bool;
|
||||
curSegment @1 :Int32;
|
||||
segments @2 :List(Segment);
|
||||
|
||||
struct LatLng @0x9eaef9187cadbb9b {
|
||||
lat @0 :Float64;
|
||||
lng @1 :Float64;
|
||||
}
|
||||
|
||||
struct Segment @0xa5b39b4fc4d7da3f {
|
||||
from @0 :LatLng;
|
||||
to @1 :LatLng;
|
||||
updateTime @2 :Int32;
|
||||
distance @3 :Int32;
|
||||
crossTime @4 :Int32;
|
||||
exitNo @5 :Int32;
|
||||
instruction @6 :Instruction;
|
||||
|
||||
parts @7 :List(LatLng);
|
||||
|
||||
enum Instruction @0xc5417a637451246f {
|
||||
turnLeft @0;
|
||||
turnRight @1;
|
||||
keepLeft @2;
|
||||
keepRight @3;
|
||||
straight @4;
|
||||
roundaboutExitNumber @5;
|
||||
roundaboutExit @6;
|
||||
roundaboutTurnLeft @7;
|
||||
unkn8 @8;
|
||||
roundaboutStraight @9;
|
||||
unkn10 @10;
|
||||
roundaboutTurnRight @11;
|
||||
unkn12 @12;
|
||||
roundaboutUturn @13;
|
||||
unkn14 @14;
|
||||
arrive @15;
|
||||
exitLeft @16;
|
||||
exitRight @17;
|
||||
unkn18 @18;
|
||||
uturn @19;
|
||||
# ...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TrafficEvent @0xacfa74a094e62626 {
|
||||
type @0 :Type;
|
||||
distance @1 :Float32;
|
||||
action @2 :Action;
|
||||
resuming @3 :Bool;
|
||||
|
||||
enum Type @0xd85d75253435bf4b {
|
||||
stopSign @0;
|
||||
lightRed @1;
|
||||
lightYellow @2;
|
||||
lightGreen @3;
|
||||
stopLight @4;
|
||||
}
|
||||
|
||||
enum Action @0xa6f6ce72165ccb49 {
|
||||
none @0;
|
||||
yield @1;
|
||||
stop @2;
|
||||
resumeReady @3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
struct AndroidGnss @0xdfdf30d03fc485bd {
|
||||
union {
|
||||
measurements @0 :Measurements;
|
||||
navigationMessage @1 :NavigationMessage;
|
||||
}
|
||||
|
||||
struct Measurements @0xa20710d4f428d6cd {
|
||||
clock @0 :Clock;
|
||||
measurements @1 :List(Measurement);
|
||||
|
||||
struct Clock @0xa0e27b453a38f450 {
|
||||
timeNanos @0 :Int64;
|
||||
hardwareClockDiscontinuityCount @1 :Int32;
|
||||
|
||||
hasTimeUncertaintyNanos @2 :Bool;
|
||||
timeUncertaintyNanos @3 :Float64;
|
||||
|
||||
hasLeapSecond @4 :Bool;
|
||||
leapSecond @5 :Int32;
|
||||
|
||||
hasFullBiasNanos @6 :Bool;
|
||||
fullBiasNanos @7 :Int64;
|
||||
|
||||
hasBiasNanos @8 :Bool;
|
||||
biasNanos @9 :Float64;
|
||||
|
||||
hasBiasUncertaintyNanos @10 :Bool;
|
||||
biasUncertaintyNanos @11 :Float64;
|
||||
|
||||
hasDriftNanosPerSecond @12 :Bool;
|
||||
driftNanosPerSecond @13 :Float64;
|
||||
|
||||
hasDriftUncertaintyNanosPerSecond @14 :Bool;
|
||||
driftUncertaintyNanosPerSecond @15 :Float64;
|
||||
}
|
||||
|
||||
struct Measurement @0xd949bf717d77614d {
|
||||
svId @0 :Int32;
|
||||
constellation @1 :Constellation;
|
||||
|
||||
timeOffsetNanos @2 :Float64;
|
||||
state @3 :Int32;
|
||||
receivedSvTimeNanos @4 :Int64;
|
||||
receivedSvTimeUncertaintyNanos @5 :Int64;
|
||||
cn0DbHz @6 :Float64;
|
||||
pseudorangeRateMetersPerSecond @7 :Float64;
|
||||
pseudorangeRateUncertaintyMetersPerSecond @8 :Float64;
|
||||
accumulatedDeltaRangeState @9 :Int32;
|
||||
accumulatedDeltaRangeMeters @10 :Float64;
|
||||
accumulatedDeltaRangeUncertaintyMeters @11 :Float64;
|
||||
|
||||
hasCarrierFrequencyHz @12 :Bool;
|
||||
carrierFrequencyHz @13 :Float32;
|
||||
hasCarrierCycles @14 :Bool;
|
||||
carrierCycles @15 :Int64;
|
||||
hasCarrierPhase @16 :Bool;
|
||||
carrierPhase @17 :Float64;
|
||||
hasCarrierPhaseUncertainty @18 :Bool;
|
||||
carrierPhaseUncertainty @19 :Float64;
|
||||
hasSnrInDb @20 :Bool;
|
||||
snrInDb @21 :Float64;
|
||||
|
||||
multipathIndicator @22 :MultipathIndicator;
|
||||
|
||||
enum Constellation @0x9ef1f3ff0deb5ffb {
|
||||
unknown @0;
|
||||
gps @1;
|
||||
sbas @2;
|
||||
glonass @3;
|
||||
qzss @4;
|
||||
beidou @5;
|
||||
galileo @6;
|
||||
}
|
||||
|
||||
enum State @0xcbb9490adce12d72 {
|
||||
unknown @0;
|
||||
codeLock @1;
|
||||
bitSync @2;
|
||||
subframeSync @3;
|
||||
towDecoded @4;
|
||||
msecAmbiguous @5;
|
||||
symbolSync @6;
|
||||
gloStringSync @7;
|
||||
gloTodDecoded @8;
|
||||
bdsD2BitSync @9;
|
||||
bdsD2SubframeSync @10;
|
||||
galE1bcCodeLock @11;
|
||||
galE1c2ndCodeLock @12;
|
||||
galE1bPageSync @13;
|
||||
sbasSync @14;
|
||||
}
|
||||
|
||||
enum MultipathIndicator @0xc04e7b6231d4caa8 {
|
||||
unknown @0;
|
||||
detected @1;
|
||||
notDetected @2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct NavigationMessage @0xe2517b083095fd4e {
|
||||
type @0 :Int32;
|
||||
svId @1 :Int32;
|
||||
messageId @2 :Int32;
|
||||
submessageId @3 :Int32;
|
||||
data @4 :Data;
|
||||
status @5 :Status;
|
||||
|
||||
enum Status @0xec1ff7996b35366f {
|
||||
unknown @0;
|
||||
parityPassed @1;
|
||||
parityRebuilt @2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LidarPts @0xe3d6685d4e9d8f7a {
|
||||
r @0 :List(UInt16); # uint16 m*500.0
|
||||
theta @1 :List(UInt16); # uint16 deg*100.0
|
||||
reflect @2 :List(UInt8); # uint8 0-255
|
||||
|
||||
# For storing out of file.
|
||||
idx @3 :UInt64;
|
||||
|
||||
# For storing in file
|
||||
pkt @4 :Data;
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
+708
-1737
File diff suppressed because it is too large
Load Diff
@@ -1,49 +0,0 @@
|
||||
using Cxx = import "./include/c++.capnp";
|
||||
$Cxx.namespace("cereal");
|
||||
|
||||
@0xa086df597ef5d7a0;
|
||||
|
||||
# Geometry
|
||||
struct Point {
|
||||
x @0: Float64;
|
||||
y @1: Float64;
|
||||
z @2: Float64;
|
||||
}
|
||||
|
||||
struct PolyLine {
|
||||
points @0: List(Point);
|
||||
}
|
||||
|
||||
# Map features
|
||||
struct Lane {
|
||||
id @0 :Text;
|
||||
|
||||
leftBoundary @1 :LaneBoundary;
|
||||
rightBoundary @2 :LaneBoundary;
|
||||
|
||||
leftAdjacentId @3 :Text;
|
||||
rightAdjacentId @4 :Text;
|
||||
|
||||
inboundIds @5 :List(Text);
|
||||
outboundIds @6 :List(Text);
|
||||
|
||||
struct LaneBoundary {
|
||||
polyLine @0 :PolyLine;
|
||||
startHeading @1 :Float32; # WRT north
|
||||
}
|
||||
}
|
||||
|
||||
# Map tiles
|
||||
struct TileSummary {
|
||||
version @0 :Text;
|
||||
updatedAt @1 :UInt64; # Millis since epoch
|
||||
|
||||
level @2 :UInt8;
|
||||
x @3 :UInt16;
|
||||
y @4 :UInt16;
|
||||
}
|
||||
|
||||
struct MapTile {
|
||||
summary @0 :TileSummary;
|
||||
lanes @1 :List(Lane);
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
demo
|
||||
bridge
|
||||
test_runner
|
||||
*.o
|
||||
*.os
|
||||
*.d
|
||||
*.a
|
||||
*.so
|
||||
messaging_pyx.cpp
|
||||
build/
|
||||
@@ -1,252 +0,0 @@
|
||||
# must be built with scons
|
||||
from msgq.ipc_pyx import Context, Poller, SubSocket, PubSocket, SocketEventHandle, toggle_fake_events, \
|
||||
set_fake_prefix, get_fake_prefix, delete_fake_prefix, wait_for_one_event
|
||||
from msgq.ipc_pyx import MultiplePublishersError, IpcError
|
||||
from msgq import fake_event_handle, pub_sock, sub_sock, drain_sock_raw, context
|
||||
|
||||
import os
|
||||
import capnp
|
||||
import time
|
||||
|
||||
from typing import Optional, List, Union, Dict, Deque
|
||||
from collections import deque
|
||||
|
||||
from cereal import log
|
||||
from cereal.services import SERVICE_LIST
|
||||
|
||||
NO_TRAVERSAL_LIMIT = 2**64-1
|
||||
|
||||
|
||||
def log_from_bytes(dat: bytes) -> capnp.lib.capnp._DynamicStructReader:
|
||||
with log.Event.from_bytes(dat, traversal_limit_in_words=NO_TRAVERSAL_LIMIT) as msg:
|
||||
return msg
|
||||
|
||||
|
||||
def new_message(service: Optional[str], size: Optional[int] = None, **kwargs) -> capnp.lib.capnp._DynamicStructBuilder:
|
||||
args = {
|
||||
'valid': False,
|
||||
'logMonoTime': int(time.monotonic() * 1e9),
|
||||
**kwargs
|
||||
}
|
||||
dat = log.Event.new_message(**args)
|
||||
if service is not None:
|
||||
if size is None:
|
||||
dat.init(service)
|
||||
else:
|
||||
dat.init(service, size)
|
||||
return dat
|
||||
|
||||
|
||||
def drain_sock(sock: SubSocket, wait_for_one: bool = False) -> List[capnp.lib.capnp._DynamicStructReader]:
|
||||
"""Receive all message currently available on the queue"""
|
||||
msgs = drain_sock_raw(sock, wait_for_one=wait_for_one)
|
||||
return [log_from_bytes(m) for m in msgs]
|
||||
|
||||
|
||||
# TODO: print when we drop packets?
|
||||
def recv_sock(sock: SubSocket, wait: bool = False) -> Optional[capnp.lib.capnp._DynamicStructReader]:
|
||||
"""Same as drain sock, but only returns latest message. Consider using conflate instead."""
|
||||
dat = None
|
||||
|
||||
while 1:
|
||||
if wait and dat is None:
|
||||
recv = sock.receive()
|
||||
else:
|
||||
recv = sock.receive(non_blocking=True)
|
||||
|
||||
if recv is None: # Timeout hit
|
||||
break
|
||||
|
||||
dat = recv
|
||||
|
||||
if dat is not None:
|
||||
dat = log_from_bytes(dat)
|
||||
|
||||
return dat
|
||||
|
||||
|
||||
def recv_one(sock: SubSocket) -> Optional[capnp.lib.capnp._DynamicStructReader]:
|
||||
dat = sock.receive()
|
||||
if dat is not None:
|
||||
dat = log_from_bytes(dat)
|
||||
return dat
|
||||
|
||||
|
||||
def recv_one_or_none(sock: SubSocket) -> Optional[capnp.lib.capnp._DynamicStructReader]:
|
||||
dat = sock.receive(non_blocking=True)
|
||||
if dat is not None:
|
||||
dat = log_from_bytes(dat)
|
||||
return dat
|
||||
|
||||
|
||||
def recv_one_retry(sock: SubSocket) -> capnp.lib.capnp._DynamicStructReader:
|
||||
"""Keep receiving until we get a message"""
|
||||
while True:
|
||||
dat = sock.receive()
|
||||
if dat is not None:
|
||||
return log_from_bytes(dat)
|
||||
|
||||
|
||||
class SubMaster:
|
||||
def __init__(self, services: List[str], poll: Optional[str] = None,
|
||||
ignore_alive: Optional[List[str]] = None, ignore_avg_freq: Optional[List[str]] = None,
|
||||
ignore_valid: Optional[List[str]] = None, addr: str = "127.0.0.1", frequency: Optional[float] = None):
|
||||
self.frame = -1
|
||||
self.seen = {s: False for s in services}
|
||||
self.updated = {s: False for s in services}
|
||||
self.recv_time = {s: 0. for s in services}
|
||||
self.recv_frame = {s: 0 for s in services}
|
||||
self.alive = {s: False for s in services}
|
||||
self.freq_ok = {s: False for s in services}
|
||||
self.recv_dts: Dict[str, Deque[float]] = {}
|
||||
self.sock = {}
|
||||
self.data = {}
|
||||
self.valid = {}
|
||||
self.logMonoTime = {}
|
||||
|
||||
self.max_freq = {}
|
||||
self.min_freq = {}
|
||||
|
||||
self.poller = Poller()
|
||||
polled_services = set([poll, ] if poll is not None else services)
|
||||
self.non_polled_services = set(services) - polled_services
|
||||
|
||||
self.ignore_average_freq = [] if ignore_avg_freq is None else ignore_avg_freq
|
||||
self.ignore_alive = [] if ignore_alive is None else ignore_alive
|
||||
self.ignore_valid = [] if ignore_valid is None else ignore_valid
|
||||
|
||||
self.simulation = bool(int(os.getenv("SIMULATION", "0")))
|
||||
|
||||
# if freq and poll aren't specified, assume the max to be conservative
|
||||
assert frequency is None or poll is None, "Do not specify 'frequency' - frequency of the polled service will be used."
|
||||
self.update_freq = frequency or max([SERVICE_LIST[s].frequency for s in polled_services])
|
||||
|
||||
for s in services:
|
||||
p = self.poller if s not in self.non_polled_services else None
|
||||
self.sock[s] = sub_sock(s, poller=p, addr=addr, conflate=True)
|
||||
|
||||
try:
|
||||
data = new_message(s)
|
||||
except capnp.lib.capnp.KjException:
|
||||
data = new_message(s, 0) # lists
|
||||
|
||||
self.data[s] = getattr(data.as_reader(), s)
|
||||
self.logMonoTime[s] = 0
|
||||
self.valid[s] = True # FIXME: this should default to False
|
||||
|
||||
freq = max(min([SERVICE_LIST[s].frequency, self.update_freq]), 1.)
|
||||
if s == poll:
|
||||
max_freq = freq
|
||||
min_freq = freq
|
||||
else:
|
||||
max_freq = min(freq, self.update_freq)
|
||||
if SERVICE_LIST[s].frequency >= 2*self.update_freq:
|
||||
min_freq = self.update_freq
|
||||
elif self.update_freq >= 2*SERVICE_LIST[s].frequency:
|
||||
min_freq = freq
|
||||
else:
|
||||
min_freq = min(freq, freq / 2.)
|
||||
self.max_freq[s] = max_freq*1.2
|
||||
self.min_freq[s] = min_freq*0.8
|
||||
self.recv_dts[s] = deque(maxlen=int(10*freq))
|
||||
|
||||
def __getitem__(self, s: str) -> capnp.lib.capnp._DynamicStructReader:
|
||||
return self.data[s]
|
||||
|
||||
def _check_avg_freq(self, s: str) -> bool:
|
||||
return SERVICE_LIST[s].frequency > 0.99 and (s not in self.ignore_average_freq) and (s not in self.ignore_alive)
|
||||
|
||||
def update(self, timeout: int = 100) -> None:
|
||||
msgs = []
|
||||
for sock in self.poller.poll(timeout):
|
||||
msgs.append(recv_one_or_none(sock))
|
||||
|
||||
# non-blocking receive for non-polled sockets
|
||||
for s in self.non_polled_services:
|
||||
msgs.append(recv_one_or_none(self.sock[s]))
|
||||
self.update_msgs(time.monotonic(), msgs)
|
||||
|
||||
def update_msgs(self, cur_time: float, msgs: List[capnp.lib.capnp._DynamicStructReader]) -> None:
|
||||
self.frame += 1
|
||||
self.updated = dict.fromkeys(self.updated, False)
|
||||
for msg in msgs:
|
||||
if msg is None:
|
||||
continue
|
||||
|
||||
s = msg.which()
|
||||
self.seen[s] = True
|
||||
self.updated[s] = True
|
||||
|
||||
if self.recv_time[s] > 1e-5:
|
||||
self.recv_dts[s].append(cur_time - self.recv_time[s])
|
||||
self.recv_time[s] = cur_time
|
||||
self.recv_frame[s] = self.frame
|
||||
self.data[s] = getattr(msg, s)
|
||||
self.logMonoTime[s] = msg.logMonoTime
|
||||
self.valid[s] = msg.valid
|
||||
|
||||
for s in self.data:
|
||||
if SERVICE_LIST[s].frequency > 1e-5 and not self.simulation:
|
||||
# alive if delay is within 10x the expected frequency
|
||||
self.alive[s] = (cur_time - self.recv_time[s]) < (10. / SERVICE_LIST[s].frequency)
|
||||
|
||||
# check average frequency; slow to fall, quick to recover
|
||||
dts = self.recv_dts[s]
|
||||
assert dts.maxlen is not None
|
||||
recent_dts = list(dts)[-int(dts.maxlen / 10):]
|
||||
try:
|
||||
avg_freq = 1 / (sum(dts) / len(dts))
|
||||
avg_freq_recent = 1 / (sum(recent_dts) / len(recent_dts))
|
||||
except ZeroDivisionError:
|
||||
avg_freq = 0
|
||||
avg_freq_recent = 0
|
||||
|
||||
avg_freq_ok = self.min_freq[s] <= avg_freq <= self.max_freq[s]
|
||||
recent_freq_ok = self.min_freq[s] <= avg_freq_recent <= self.max_freq[s]
|
||||
self.freq_ok[s] = avg_freq_ok or recent_freq_ok
|
||||
else:
|
||||
self.freq_ok[s] = True
|
||||
if self.simulation:
|
||||
self.alive[s] = self.seen[s] # alive is defined as seen when simulation flag set
|
||||
else:
|
||||
self.alive[s] = True
|
||||
|
||||
def all_alive(self, service_list: Optional[List[str]] = None) -> bool:
|
||||
if service_list is None:
|
||||
service_list = list(self.sock.keys())
|
||||
return all(self.alive[s] for s in service_list if s not in self.ignore_alive)
|
||||
|
||||
def all_freq_ok(self, service_list: Optional[List[str]] = None) -> bool:
|
||||
if service_list is None:
|
||||
service_list = list(self.sock.keys())
|
||||
return all(self.freq_ok[s] for s in service_list if self._check_avg_freq(s))
|
||||
|
||||
def all_valid(self, service_list: Optional[List[str]] = None) -> bool:
|
||||
if service_list is None:
|
||||
service_list = list(self.sock.keys())
|
||||
return all(self.valid[s] for s in service_list if s not in self.ignore_valid)
|
||||
|
||||
def all_checks(self, service_list: Optional[List[str]] = None) -> bool:
|
||||
return self.all_alive(service_list) and self.all_freq_ok(service_list) and self.all_valid(service_list)
|
||||
|
||||
|
||||
class PubMaster:
|
||||
def __init__(self, services: List[str]):
|
||||
self.sock = {}
|
||||
for s in services:
|
||||
self.sock[s] = pub_sock(s)
|
||||
|
||||
def send(self, s: str, dat: Union[bytes, capnp.lib.capnp._DynamicStructBuilder]) -> None:
|
||||
if not isinstance(dat, bytes):
|
||||
dat = dat.to_bytes()
|
||||
self.sock[s].send(dat)
|
||||
|
||||
def wait_for_readers_to_update(self, s: str, timeout: int, dt: float = 0.05) -> bool:
|
||||
for _ in range(int(timeout*(1./dt))):
|
||||
if self.sock[s].all_readers_updated():
|
||||
return True
|
||||
time.sleep(dt)
|
||||
return False
|
||||
|
||||
def all_readers_updated(self, s: str) -> bool:
|
||||
return self.sock[s].all_readers_updated() # type: ignore
|
||||
Binary file not shown.
@@ -1,92 +0,0 @@
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <csignal>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
typedef void (*sighandler_t)(int sig);
|
||||
|
||||
#include "cereal/services.h"
|
||||
#include "msgq/impl_msgq.h"
|
||||
#include "msgq/impl_zmq.h"
|
||||
|
||||
std::atomic<bool> do_exit = false;
|
||||
static void set_do_exit(int sig) {
|
||||
do_exit = true;
|
||||
}
|
||||
|
||||
void sigpipe_handler(int sig) {
|
||||
assert(sig == SIGPIPE);
|
||||
std::cout << "SIGPIPE received" << std::endl;
|
||||
}
|
||||
|
||||
static std::vector<std::string> get_services(std::string whitelist_str, bool zmq_to_msgq) {
|
||||
std::vector<std::string> service_list;
|
||||
for (const auto& it : services) {
|
||||
std::string name = it.second.name;
|
||||
bool in_whitelist = whitelist_str.find(name) != std::string::npos;
|
||||
if (name == "plusFrame" || name == "uiLayoutState" || (zmq_to_msgq && !in_whitelist)) {
|
||||
continue;
|
||||
}
|
||||
service_list.push_back(name);
|
||||
}
|
||||
return service_list;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
signal(SIGPIPE, (sighandler_t)sigpipe_handler);
|
||||
signal(SIGINT, (sighandler_t)set_do_exit);
|
||||
signal(SIGTERM, (sighandler_t)set_do_exit);
|
||||
|
||||
bool zmq_to_msgq = argc > 2;
|
||||
std::string ip = zmq_to_msgq ? argv[1] : "127.0.0.1";
|
||||
std::string whitelist_str = zmq_to_msgq ? std::string(argv[2]) : "";
|
||||
|
||||
Poller *poller;
|
||||
Context *pub_context;
|
||||
Context *sub_context;
|
||||
if (zmq_to_msgq) { // republishes zmq debugging messages as msgq
|
||||
poller = new ZMQPoller();
|
||||
pub_context = new MSGQContext();
|
||||
sub_context = new ZMQContext();
|
||||
} else {
|
||||
poller = new MSGQPoller();
|
||||
pub_context = new ZMQContext();
|
||||
sub_context = new MSGQContext();
|
||||
}
|
||||
|
||||
std::map<SubSocket*, PubSocket*> sub2pub;
|
||||
for (auto endpoint : get_services(whitelist_str, zmq_to_msgq)) {
|
||||
PubSocket * pub_sock;
|
||||
SubSocket * sub_sock;
|
||||
if (zmq_to_msgq) {
|
||||
pub_sock = new MSGQPubSocket();
|
||||
sub_sock = new ZMQSubSocket();
|
||||
} else {
|
||||
pub_sock = new ZMQPubSocket();
|
||||
sub_sock = new MSGQSubSocket();
|
||||
}
|
||||
pub_sock->connect(pub_context, endpoint);
|
||||
sub_sock->connect(sub_context, endpoint, ip, false);
|
||||
|
||||
poller->registerSocket(sub_sock);
|
||||
sub2pub[sub_sock] = pub_sock;
|
||||
}
|
||||
|
||||
while (!do_exit) {
|
||||
for (auto sub_sock : poller->poll(100)) {
|
||||
Message * msg = sub_sock->receive();
|
||||
if (msg == NULL) continue;
|
||||
int ret;
|
||||
do {
|
||||
ret = sub2pub[sub_sock]->sendMessage(msg);
|
||||
} while (ret == -1 && errno == EINTR && !do_exit);
|
||||
assert(ret >= 0 || do_exit);
|
||||
delete msg;
|
||||
|
||||
if (do_exit) break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <time.h>
|
||||
|
||||
#include <capnp/serialize.h>
|
||||
|
||||
#include "cereal/gen/cpp/log.capnp.h"
|
||||
#include "msgq/ipc.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define CLOCK_BOOTTIME CLOCK_MONOTONIC
|
||||
#endif
|
||||
|
||||
#define MSG_MULTIPLE_PUBLISHERS 100
|
||||
|
||||
|
||||
class SubMaster {
|
||||
public:
|
||||
SubMaster(const std::vector<const char *> &service_list, const std::vector<const char *> &poll = {},
|
||||
const char *address = nullptr, const std::vector<const char *> &ignore_alive = {});
|
||||
void update(int timeout = 1000);
|
||||
void update_msgs(uint64_t current_time, const std::vector<std::pair<std::string, cereal::Event::Reader>> &messages);
|
||||
inline bool allAlive(const std::vector<const char *> &service_list = {}) { return all_(service_list, false, true); }
|
||||
inline bool allValid(const std::vector<const char *> &service_list = {}) { return all_(service_list, true, false); }
|
||||
inline bool allAliveAndValid(const std::vector<const char *> &service_list = {}) { return all_(service_list, true, true); }
|
||||
void drain();
|
||||
~SubMaster();
|
||||
|
||||
uint64_t frame = 0;
|
||||
bool updated(const char *name) const;
|
||||
bool alive(const char *name) const;
|
||||
bool valid(const char *name) const;
|
||||
uint64_t rcv_frame(const char *name) const;
|
||||
uint64_t rcv_time(const char *name) const;
|
||||
cereal::Event::Reader &operator[](const char *name) const;
|
||||
|
||||
private:
|
||||
bool all_(const std::vector<const char *> &service_list, bool valid, bool alive);
|
||||
Poller *poller_ = nullptr;
|
||||
struct SubMessage;
|
||||
std::map<SubSocket *, SubMessage *> messages_;
|
||||
std::map<std::string, SubMessage *> services_;
|
||||
};
|
||||
|
||||
class MessageBuilder : public capnp::MallocMessageBuilder {
|
||||
public:
|
||||
MessageBuilder() = default;
|
||||
|
||||
cereal::Event::Builder initEvent(bool valid = true) {
|
||||
cereal::Event::Builder event = initRoot<cereal::Event>();
|
||||
struct timespec t;
|
||||
clock_gettime(CLOCK_BOOTTIME, &t);
|
||||
uint64_t current_time = t.tv_sec * 1000000000ULL + t.tv_nsec;
|
||||
event.setLogMonoTime(current_time);
|
||||
event.setValid(valid);
|
||||
return event;
|
||||
}
|
||||
|
||||
kj::ArrayPtr<capnp::byte> toBytes() {
|
||||
heapArray_ = capnp::messageToFlatArray(*this);
|
||||
return heapArray_.asBytes();
|
||||
}
|
||||
|
||||
size_t getSerializedSize() {
|
||||
return capnp::computeSerializedSizeInWords(*this) * sizeof(capnp::word);
|
||||
}
|
||||
|
||||
int serializeToBuffer(unsigned char *buffer, size_t buffer_size) {
|
||||
size_t serialized_size = getSerializedSize();
|
||||
if (serialized_size > buffer_size) { return -1; }
|
||||
kj::ArrayOutputStream out(kj::ArrayPtr<capnp::byte>(buffer, buffer_size));
|
||||
capnp::writeMessage(out, *this);
|
||||
return serialized_size;
|
||||
}
|
||||
|
||||
private:
|
||||
kj::Array<capnp::word> heapArray_;
|
||||
};
|
||||
|
||||
class PubMaster {
|
||||
public:
|
||||
PubMaster(const std::vector<const char *> &service_list);
|
||||
inline int send(const char *name, capnp::byte *data, size_t size) { return sockets_.at(name)->send((char *)data, size); }
|
||||
int send(const char *name, MessageBuilder &msg);
|
||||
~PubMaster();
|
||||
|
||||
private:
|
||||
std::map<std::string, PubSocket *> sockets_;
|
||||
};
|
||||
|
||||
class AlignedBuffer {
|
||||
public:
|
||||
kj::ArrayPtr<const capnp::word> align(const char *data, const size_t size) {
|
||||
words_size = size / sizeof(capnp::word) + 1;
|
||||
if (aligned_buf.size() < words_size) {
|
||||
aligned_buf = kj::heapArray<capnp::word>(words_size < 512 ? 512 : words_size);
|
||||
}
|
||||
memcpy(aligned_buf.begin(), data, size);
|
||||
return aligned_buf.slice(0, words_size);
|
||||
}
|
||||
inline kj::ArrayPtr<const capnp::word> align(Message *m) {
|
||||
return align(m->getData(), m->getSize());
|
||||
}
|
||||
private:
|
||||
kj::Array<capnp::word> aligned_buf;
|
||||
size_t words_size;
|
||||
};
|
||||
@@ -1,211 +0,0 @@
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
|
||||
#include "cereal/services.h"
|
||||
#include "cereal/messaging/messaging.h"
|
||||
|
||||
|
||||
const bool SIMULATION = (getenv("SIMULATION") != nullptr) && (std::string(getenv("SIMULATION")) == "1");
|
||||
|
||||
static inline uint64_t nanos_since_boot() {
|
||||
struct timespec t;
|
||||
clock_gettime(CLOCK_BOOTTIME, &t);
|
||||
return t.tv_sec * 1000000000ULL + t.tv_nsec;
|
||||
}
|
||||
|
||||
static inline bool inList(const std::vector<const char *> &list, const char *value) {
|
||||
for (auto &v : list) {
|
||||
if (strcmp(value, v) == 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class MessageContext {
|
||||
public:
|
||||
MessageContext() : ctx_(nullptr) {}
|
||||
~MessageContext() { delete ctx_; }
|
||||
inline Context *context() {
|
||||
std::call_once(init_flag, [=]() { ctx_ = Context::create(); });
|
||||
return ctx_;
|
||||
}
|
||||
private:
|
||||
Context *ctx_;
|
||||
std::once_flag init_flag;
|
||||
};
|
||||
|
||||
MessageContext message_context;
|
||||
|
||||
struct SubMaster::SubMessage {
|
||||
std::string name;
|
||||
SubSocket *socket = nullptr;
|
||||
int freq = 0;
|
||||
bool updated = false, alive = false, valid = true, ignore_alive;
|
||||
uint64_t rcv_time = 0, rcv_frame = 0;
|
||||
void *allocated_msg_reader = nullptr;
|
||||
bool is_polled = false;
|
||||
capnp::FlatArrayMessageReader *msg_reader = nullptr;
|
||||
AlignedBuffer aligned_buf;
|
||||
cereal::Event::Reader event;
|
||||
};
|
||||
|
||||
SubMaster::SubMaster(const std::vector<const char *> &service_list, const std::vector<const char *> &poll,
|
||||
const char *address, const std::vector<const char *> &ignore_alive) {
|
||||
poller_ = Poller::create();
|
||||
for (auto name : service_list) {
|
||||
assert(services.count(std::string(name)) > 0);
|
||||
|
||||
service serv = services.at(std::string(name));
|
||||
SubSocket *socket = SubSocket::create(message_context.context(), name, address ? address : "127.0.0.1", true);
|
||||
assert(socket != 0);
|
||||
bool is_polled = inList(poll, name) || poll.empty();
|
||||
if (is_polled) poller_->registerSocket(socket);
|
||||
SubMessage *m = new SubMessage{
|
||||
.name = name,
|
||||
.socket = socket,
|
||||
.freq = serv.frequency,
|
||||
.ignore_alive = inList(ignore_alive, name),
|
||||
.allocated_msg_reader = malloc(sizeof(capnp::FlatArrayMessageReader)),
|
||||
.is_polled = is_polled};
|
||||
m->msg_reader = new (m->allocated_msg_reader) capnp::FlatArrayMessageReader({});
|
||||
messages_[socket] = m;
|
||||
services_[name] = m;
|
||||
}
|
||||
}
|
||||
|
||||
void SubMaster::update(int timeout) {
|
||||
for (auto &kv : messages_) kv.second->updated = false;
|
||||
|
||||
auto sockets = poller_->poll(timeout);
|
||||
|
||||
// add non-polled sockets for non-blocking receive
|
||||
for (auto &kv : messages_) {
|
||||
SubMessage *m = kv.second;
|
||||
SubSocket *s = kv.first;
|
||||
if (!m->is_polled) sockets.push_back(s);
|
||||
}
|
||||
|
||||
uint64_t current_time = nanos_since_boot();
|
||||
|
||||
std::vector<std::pair<std::string, cereal::Event::Reader>> messages;
|
||||
|
||||
for (auto s : sockets) {
|
||||
Message *msg = s->receive(true);
|
||||
if (msg == nullptr) continue;
|
||||
|
||||
SubMessage *m = messages_.at(s);
|
||||
|
||||
m->msg_reader->~FlatArrayMessageReader();
|
||||
capnp::ReaderOptions options;
|
||||
options.traversalLimitInWords = kj::maxValue; // Don't limit
|
||||
m->msg_reader = new (m->allocated_msg_reader) capnp::FlatArrayMessageReader(m->aligned_buf.align(msg), options);
|
||||
delete msg;
|
||||
messages.push_back({m->name, m->msg_reader->getRoot<cereal::Event>()});
|
||||
}
|
||||
|
||||
update_msgs(current_time, messages);
|
||||
}
|
||||
|
||||
void SubMaster::update_msgs(uint64_t current_time, const std::vector<std::pair<std::string, cereal::Event::Reader>> &messages){
|
||||
if (++frame == UINT64_MAX) frame = 1;
|
||||
|
||||
for (auto &kv : messages) {
|
||||
auto m_find = services_.find(kv.first);
|
||||
if (m_find == services_.end()){
|
||||
continue;
|
||||
}
|
||||
SubMessage *m = m_find->second;
|
||||
m->event = kv.second;
|
||||
m->updated = true;
|
||||
m->rcv_time = current_time;
|
||||
m->rcv_frame = frame;
|
||||
m->valid = m->event.getValid();
|
||||
if (SIMULATION) m->alive = true;
|
||||
}
|
||||
|
||||
if (!SIMULATION) {
|
||||
for (auto &kv : messages_) {
|
||||
SubMessage *m = kv.second;
|
||||
m->alive = (m->freq <= (1e-5) || ((current_time - m->rcv_time) * (1e-9)) < (10.0 / m->freq));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SubMaster::all_(const std::vector<const char *> &service_list, bool valid, bool alive) {
|
||||
int found = 0;
|
||||
for (auto &kv : messages_) {
|
||||
SubMessage *m = kv.second;
|
||||
if (service_list.size() == 0 || inList(service_list, m->name.c_str())) {
|
||||
found += (!valid || m->valid) && (!alive || (m->alive || m->ignore_alive));
|
||||
}
|
||||
}
|
||||
return service_list.size() == 0 ? found == messages_.size() : found == service_list.size();
|
||||
}
|
||||
|
||||
void SubMaster::drain() {
|
||||
while (true) {
|
||||
auto polls = poller_->poll(0);
|
||||
if (polls.size() == 0)
|
||||
break;
|
||||
|
||||
for (auto sock : polls) {
|
||||
Message *msg = sock->receive(true);
|
||||
delete msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SubMaster::updated(const char *name) const {
|
||||
return services_.at(name)->updated;
|
||||
}
|
||||
|
||||
bool SubMaster::alive(const char *name) const {
|
||||
return services_.at(name)->alive;
|
||||
}
|
||||
|
||||
bool SubMaster::valid(const char *name) const {
|
||||
return services_.at(name)->valid;
|
||||
}
|
||||
|
||||
uint64_t SubMaster::rcv_frame(const char *name) const {
|
||||
return services_.at(name)->rcv_frame;
|
||||
}
|
||||
|
||||
uint64_t SubMaster::rcv_time(const char *name) const {
|
||||
return services_.at(name)->rcv_time;
|
||||
}
|
||||
|
||||
cereal::Event::Reader &SubMaster::operator[](const char *name) const {
|
||||
return services_.at(name)->event;
|
||||
}
|
||||
|
||||
SubMaster::~SubMaster() {
|
||||
delete poller_;
|
||||
for (auto &kv : messages_) {
|
||||
SubMessage *m = kv.second;
|
||||
m->msg_reader->~FlatArrayMessageReader();
|
||||
free(m->allocated_msg_reader);
|
||||
delete m->socket;
|
||||
delete m;
|
||||
}
|
||||
}
|
||||
|
||||
PubMaster::PubMaster(const std::vector<const char *> &service_list) {
|
||||
for (auto name : service_list) {
|
||||
assert(services.count(name) > 0);
|
||||
PubSocket *socket = PubSocket::create(message_context.context(), name);
|
||||
assert(socket);
|
||||
sockets_[name] = socket;
|
||||
}
|
||||
}
|
||||
|
||||
int PubMaster::send(const char *name, MessageBuilder &msg) {
|
||||
auto bytes = msg.toBytes();
|
||||
return send(name, bytes.begin(), bytes.size());
|
||||
}
|
||||
|
||||
PubMaster::~PubMaster() {
|
||||
for (auto s : sockets_) delete s.second;
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/* THIS IS AN AUTOGENERATED FILE, PLEASE EDIT services.py */
|
||||
#ifndef __SERVICES_H
|
||||
#define __SERVICES_H
|
||||
#include <map>
|
||||
#include <string>
|
||||
struct service { std::string name; bool should_log; int frequency; int decimation; };
|
||||
static std::map<std::string, service> services = {
|
||||
{ "gyroscope", {"gyroscope", true, 104, 104}},
|
||||
{ "gyroscope2", {"gyroscope2", true, 100, 100}},
|
||||
{ "accelerometer", {"accelerometer", true, 104, 104}},
|
||||
{ "accelerometer2", {"accelerometer2", true, 100, 100}},
|
||||
{ "magnetometer", {"magnetometer", true, 25, 25}},
|
||||
{ "lightSensor", {"lightSensor", true, 100, 100}},
|
||||
{ "temperatureSensor", {"temperatureSensor", true, 2, 200}},
|
||||
{ "temperatureSensor2", {"temperatureSensor2", true, 2, 200}},
|
||||
{ "gpsNMEA", {"gpsNMEA", true, 9, -1}},
|
||||
{ "deviceState", {"deviceState", true, 2, 1}},
|
||||
{ "can", {"can", true, 100, 1223}},
|
||||
{ "controlsState", {"controlsState", true, 100, 10}},
|
||||
{ "pandaStates", {"pandaStates", true, 10, 1}},
|
||||
{ "peripheralState", {"peripheralState", true, 2, 1}},
|
||||
{ "radarState", {"radarState", true, 20, 5}},
|
||||
{ "roadEncodeIdx", {"roadEncodeIdx", false, 20, 1}},
|
||||
{ "liveTracks", {"liveTracks", true, 20, -1}},
|
||||
{ "sendcan", {"sendcan", true, 100, 139}},
|
||||
{ "logMessage", {"logMessage", true, 0, -1}},
|
||||
{ "errorLogMessage", {"errorLogMessage", true, 0, 1}},
|
||||
{ "liveCalibration", {"liveCalibration", true, 4, 4}},
|
||||
{ "liveTorqueParameters", {"liveTorqueParameters", true, 4, 1}},
|
||||
{ "liveDelay", {"liveDelay", true, 4, 1}},
|
||||
{ "androidLog", {"androidLog", true, 0, -1}},
|
||||
{ "carState", {"carState", true, 100, 10}},
|
||||
{ "carControl", {"carControl", true, 100, 10}},
|
||||
{ "carOutput", {"carOutput", true, 100, 10}},
|
||||
{ "longitudinalPlan", {"longitudinalPlan", true, 20, 5}},
|
||||
{ "procLog", {"procLog", true, 0, 15}},
|
||||
{ "gpsLocationExternal", {"gpsLocationExternal", true, 10, 10}},
|
||||
{ "gpsLocation", {"gpsLocation", true, 1, 1}},
|
||||
{ "ubloxGnss", {"ubloxGnss", true, 10, -1}},
|
||||
{ "qcomGnss", {"qcomGnss", true, 2, -1}},
|
||||
{ "gnssMeasurements", {"gnssMeasurements", true, 10, 10}},
|
||||
{ "clocks", {"clocks", true, 0, 1}},
|
||||
{ "ubloxRaw", {"ubloxRaw", true, 20, -1}},
|
||||
{ "livePose", {"livePose", true, 20, 4}},
|
||||
{ "liveLocationKalman", {"liveLocationKalman", true, 20, -1}},
|
||||
{ "liveParameters", {"liveParameters", true, 20, 5}},
|
||||
{ "cameraOdometry", {"cameraOdometry", true, 20, 5}},
|
||||
{ "thumbnail", {"thumbnail", true, 0, 1}},
|
||||
{ "onroadEvents", {"onroadEvents", true, 1, 1}},
|
||||
{ "carParams", {"carParams", true, 0, 1}},
|
||||
{ "roadCameraState", {"roadCameraState", true, 20, 20}},
|
||||
{ "driverCameraState", {"driverCameraState", true, 20, 20}},
|
||||
{ "driverEncodeIdx", {"driverEncodeIdx", false, 20, 1}},
|
||||
{ "driverStateV2", {"driverStateV2", true, 20, 10}},
|
||||
{ "driverMonitoringState", {"driverMonitoringState", true, 20, 10}},
|
||||
{ "wideRoadEncodeIdx", {"wideRoadEncodeIdx", false, 20, 1}},
|
||||
{ "wideRoadCameraState", {"wideRoadCameraState", true, 20, 20}},
|
||||
{ "drivingModelData", {"drivingModelData", true, 20, 10}},
|
||||
{ "modelV2", {"modelV2", true, 20, 40}},
|
||||
{ "managerState", {"managerState", true, 2, 1}},
|
||||
{ "uploaderState", {"uploaderState", true, 0, 1}},
|
||||
{ "navInstruction", {"navInstruction", true, 1, 10}},
|
||||
{ "navRoute", {"navRoute", true, 0, -1}},
|
||||
{ "navThumbnail", {"navThumbnail", true, 0, -1}},
|
||||
{ "navModel", {"navModel", true, 2, 4}},
|
||||
{ "mapRenderState", {"mapRenderState", true, 2, 1}},
|
||||
{ "uiPlan", {"uiPlan", true, 20, 40}},
|
||||
{ "qRoadEncodeIdx", {"qRoadEncodeIdx", false, 20, -1}},
|
||||
{ "userFlag", {"userFlag", true, 0, 1}},
|
||||
{ "microphone", {"microphone", true, 10, 10}},
|
||||
{ "uiDebug", {"uiDebug", true, 0, 1}},
|
||||
{ "testJoystick", {"testJoystick", true, 0, -1}},
|
||||
{ "roadEncodeData", {"roadEncodeData", false, 20, -1}},
|
||||
{ "driverEncodeData", {"driverEncodeData", false, 20, -1}},
|
||||
{ "wideRoadEncodeData", {"wideRoadEncodeData", false, 20, -1}},
|
||||
{ "qRoadEncodeData", {"qRoadEncodeData", false, 20, -1}},
|
||||
{ "livestreamWideRoadEncodeIdx", {"livestreamWideRoadEncodeIdx", false, 20, -1}},
|
||||
{ "livestreamRoadEncodeIdx", {"livestreamRoadEncodeIdx", false, 20, -1}},
|
||||
{ "livestreamDriverEncodeIdx", {"livestreamDriverEncodeIdx", false, 20, -1}},
|
||||
{ "livestreamWideRoadEncodeData", {"livestreamWideRoadEncodeData", false, 20, -1}},
|
||||
{ "livestreamRoadEncodeData", {"livestreamRoadEncodeData", false, 20, -1}},
|
||||
{ "livestreamDriverEncodeData", {"livestreamDriverEncodeData", false, 20, -1}},
|
||||
{ "customReservedRawData0", {"customReservedRawData0", true, 0, -1}},
|
||||
{ "customReservedRawData1", {"customReservedRawData1", true, 0, -1}},
|
||||
{ "customReservedRawData2", {"customReservedRawData2", true, 0, -1}},
|
||||
{ "frogpilotCarControl", {"frogpilotCarControl", true, 100, 10}},
|
||||
{ "frogpilotCarParams", {"frogpilotCarParams", true, 0, 1}},
|
||||
{ "frogpilotCarState", {"frogpilotCarState", true, 100, 10}},
|
||||
{ "frogpilotControlsState", {"frogpilotControlsState", true, 100, 10}},
|
||||
{ "frogpilotDeviceState", {"frogpilotDeviceState", true, 2, 1}},
|
||||
{ "frogpilotModelV2", {"frogpilotModelV2", true, 20, 40}},
|
||||
{ "frogpilotNavigation", {"frogpilotNavigation", true, 1, 10}},
|
||||
{ "frogpilotOnroadEvents", {"frogpilotOnroadEvents", true, 1, 1}},
|
||||
{ "frogpilotPlan", {"frogpilotPlan", true, 20, 5}},
|
||||
{ "frogpilotRadarState", {"frogpilotRadarState", true, 20, 5}},
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class Service:
|
||||
def __init__(self, should_log: bool, frequency: float, decimation: Optional[int] = None):
|
||||
self.should_log = should_log
|
||||
self.frequency = frequency
|
||||
self.decimation = decimation
|
||||
|
||||
|
||||
_services: dict[str, tuple] = {
|
||||
# service: (should_log, frequency, qlog decimation (optional))
|
||||
# note: the "EncodeIdx" packets will still be in the log
|
||||
"gyroscope": (True, 104., 104),
|
||||
"gyroscope2": (True, 100., 100),
|
||||
"accelerometer": (True, 104., 104),
|
||||
"accelerometer2": (True, 100., 100),
|
||||
"magnetometer": (True, 25., 25),
|
||||
"lightSensor": (True, 100., 100),
|
||||
"temperatureSensor": (True, 2., 200),
|
||||
"temperatureSensor2": (True, 2., 200),
|
||||
"gpsNMEA": (True, 9.),
|
||||
"deviceState": (True, 2., 1),
|
||||
"can": (True, 100., 1223), # decimation gives ~5 msgs in a full segment
|
||||
"controlsState": (True, 100., 10),
|
||||
"pandaStates": (True, 10., 1),
|
||||
"peripheralState": (True, 2., 1),
|
||||
"radarState": (True, 20., 5),
|
||||
"roadEncodeIdx": (False, 20., 1),
|
||||
"liveTracks": (True, 20.),
|
||||
"sendcan": (True, 100., 139),
|
||||
"logMessage": (True, 0.),
|
||||
"errorLogMessage": (True, 0., 1),
|
||||
"liveCalibration": (True, 4., 4),
|
||||
"liveTorqueParameters": (True, 4., 1),
|
||||
"liveDelay": (True, 4., 1),
|
||||
"androidLog": (True, 0.),
|
||||
"carState": (True, 100., 10),
|
||||
"carControl": (True, 100., 10),
|
||||
"carOutput": (True, 100., 10),
|
||||
"longitudinalPlan": (True, 20., 5),
|
||||
"procLog": (True, 0.5, 15),
|
||||
"gpsLocationExternal": (True, 10., 10),
|
||||
"gpsLocation": (True, 1., 1),
|
||||
"ubloxGnss": (True, 10.),
|
||||
"qcomGnss": (True, 2.),
|
||||
"gnssMeasurements": (True, 10., 10),
|
||||
"clocks": (True, 0.1, 1),
|
||||
"ubloxRaw": (True, 20.),
|
||||
"livePose": (True, 20., 4),
|
||||
"liveLocationKalman": (True, 20.),
|
||||
"liveParameters": (True, 20., 5),
|
||||
"cameraOdometry": (True, 20., 5),
|
||||
"thumbnail": (True, 0.2, 1),
|
||||
"onroadEvents": (True, 1., 1),
|
||||
"carParams": (True, 0.02, 1),
|
||||
"roadCameraState": (True, 20., 20),
|
||||
"driverCameraState": (True, 20., 20),
|
||||
"driverEncodeIdx": (False, 20., 1),
|
||||
"driverStateV2": (True, 20., 10),
|
||||
"driverMonitoringState": (True, 20., 10),
|
||||
"wideRoadEncodeIdx": (False, 20., 1),
|
||||
"wideRoadCameraState": (True, 20., 20),
|
||||
"drivingModelData": (True, 20., 10),
|
||||
"modelV2": (True, 20., 40),
|
||||
"managerState": (True, 2., 1),
|
||||
"uploaderState": (True, 0., 1),
|
||||
"navInstruction": (True, 1., 10),
|
||||
"navRoute": (True, 0.),
|
||||
"navThumbnail": (True, 0.),
|
||||
"navModel": (True, 2., 4.),
|
||||
"mapRenderState": (True, 2., 1.),
|
||||
"uiPlan": (True, 20., 40.),
|
||||
"qRoadEncodeIdx": (False, 20.),
|
||||
"userFlag": (True, 0., 1),
|
||||
"microphone": (True, 10., 10),
|
||||
|
||||
# debug
|
||||
"uiDebug": (True, 0., 1),
|
||||
"testJoystick": (True, 0.),
|
||||
"roadEncodeData": (False, 20.),
|
||||
"driverEncodeData": (False, 20.),
|
||||
"wideRoadEncodeData": (False, 20.),
|
||||
"qRoadEncodeData": (False, 20.),
|
||||
"livestreamWideRoadEncodeIdx": (False, 20.),
|
||||
"livestreamRoadEncodeIdx": (False, 20.),
|
||||
"livestreamDriverEncodeIdx": (False, 20.),
|
||||
"livestreamWideRoadEncodeData": (False, 20.),
|
||||
"livestreamRoadEncodeData": (False, 20.),
|
||||
"livestreamDriverEncodeData": (False, 20.),
|
||||
"customReservedRawData0": (True, 0.),
|
||||
"customReservedRawData1": (True, 0.),
|
||||
"customReservedRawData2": (True, 0.),
|
||||
|
||||
# FrogPilot
|
||||
"frogpilotCarControl": (True, 100., 10),
|
||||
"frogpilotCarParams": (True, 0.02, 1),
|
||||
"frogpilotCarState": (True, 100., 10),
|
||||
"frogpilotControlsState": (True, 100., 10),
|
||||
"frogpilotDeviceState": (True, 2., 1),
|
||||
"frogpilotModelV2": (True, 20., 40),
|
||||
"frogpilotNavigation": (True, 1., 10),
|
||||
"frogpilotOnroadEvents": (True, 1., 1),
|
||||
"frogpilotPlan": (True, 20., 5),
|
||||
"frogpilotRadarState": (True, 20., 5),
|
||||
}
|
||||
SERVICE_LIST = {name: Service(*vals) for
|
||||
idx, (name, vals) in enumerate(_services.items())}
|
||||
|
||||
|
||||
def build_header():
|
||||
h = ""
|
||||
h += "/* THIS IS AN AUTOGENERATED FILE, PLEASE EDIT services.py */\n"
|
||||
h += "#ifndef __SERVICES_H\n"
|
||||
h += "#define __SERVICES_H\n"
|
||||
|
||||
h += "#include <map>\n"
|
||||
h += "#include <string>\n"
|
||||
|
||||
h += "struct service { std::string name; bool should_log; int frequency; int decimation; };\n"
|
||||
h += "static std::map<std::string, service> services = {\n"
|
||||
for k, v in SERVICE_LIST.items():
|
||||
should_log = "true" if v.should_log else "false"
|
||||
decimation = -1 if v.decimation is None else v.decimation
|
||||
h += ' { "%s", {"%s", %s, %d, %d}},\n' % \
|
||||
(k, k, should_log, v.frequency, decimation)
|
||||
h += "};\n"
|
||||
|
||||
h += "#endif\n"
|
||||
return h
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(build_header())
|
||||
@@ -1 +0,0 @@
|
||||
*.cpp
|
||||
+7
-41
@@ -1,49 +1,15 @@
|
||||
import jwt
|
||||
import os
|
||||
import requests
|
||||
from datetime import datetime, timedelta
|
||||
from openpilot.system.hardware.hw import Paths
|
||||
from openpilot.system.version import get_version
|
||||
|
||||
from openpilot.frogpilot.common.frogpilot_utilities import use_konik_server
|
||||
|
||||
API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com')
|
||||
KONIK_API_HOST = os.getenv('API_HOST', 'https://api.konik.ai')
|
||||
|
||||
class Api:
|
||||
def __init__(self, dongle_id):
|
||||
self.dongle_id = dongle_id
|
||||
with open(Paths.persist_root()+'/comma/id_rsa') as f:
|
||||
self.private_key = f.read()
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
return self.request('GET', *args, **kwargs)
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
return self.request('POST', *args, **kwargs)
|
||||
|
||||
def request(self, method, endpoint, timeout=None, access_token=None, **params):
|
||||
return api_get(endpoint, method=method, timeout=timeout, access_token=access_token, **params)
|
||||
|
||||
def get_token(self, expiry_hours=1):
|
||||
now = datetime.utcnow()
|
||||
payload = {
|
||||
'identity': self.dongle_id,
|
||||
'nbf': now,
|
||||
'iat': now,
|
||||
'exp': now + timedelta(hours=expiry_hours)
|
||||
}
|
||||
token = jwt.encode(payload, self.private_key, algorithm='RS256')
|
||||
if isinstance(token, bytes):
|
||||
token = token.decode('utf8')
|
||||
return token
|
||||
|
||||
from selfdrive.version import version
|
||||
|
||||
def api_get(endpoint, method='GET', timeout=None, access_token=None, **params):
|
||||
backend = "https://api.commadotai.com/"
|
||||
|
||||
headers = {}
|
||||
if access_token is not None:
|
||||
headers['Authorization'] = "JWT " + access_token
|
||||
headers['Authorization'] = "JWT "+access_token
|
||||
|
||||
headers['User-Agent'] = "openpilot-" + get_version()
|
||||
headers['User-Agent'] = "openpilot-" + version
|
||||
|
||||
return requests.request(method, backend+endpoint, timeout=timeout, headers = headers, params=params)
|
||||
|
||||
return requests.request(method, (KONIK_API_HOST if use_konik_server() else API_HOST) + "/" + endpoint, timeout=timeout, headers=headers, params=params)
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import os
|
||||
|
||||
|
||||
BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../"))
|
||||
|
||||
|
||||
|
||||
@@ -1,204 +0,0 @@
|
||||
#include "common/clutil.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include "common/util.h"
|
||||
#include "common/swaglog.h"
|
||||
|
||||
namespace { // helper functions
|
||||
|
||||
template <typename Func, typename Id, typename Name>
|
||||
std::string get_info(Func get_info_func, Id id, Name param_name) {
|
||||
size_t size = 0;
|
||||
CL_CHECK(get_info_func(id, param_name, 0, NULL, &size));
|
||||
std::string info(size, '\0');
|
||||
CL_CHECK(get_info_func(id, param_name, size, info.data(), NULL));
|
||||
return info;
|
||||
}
|
||||
inline std::string get_platform_info(cl_platform_id id, cl_platform_info name) { return get_info(&clGetPlatformInfo, id, name); }
|
||||
inline std::string get_device_info(cl_device_id id, cl_device_info name) { return get_info(&clGetDeviceInfo, id, name); }
|
||||
|
||||
void cl_print_info(cl_platform_id platform, cl_device_id device) {
|
||||
size_t work_group_size = 0;
|
||||
cl_device_type device_type = 0;
|
||||
clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(work_group_size), &work_group_size, NULL);
|
||||
clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(device_type), &device_type, NULL);
|
||||
const char *type_str = "Other...";
|
||||
switch (device_type) {
|
||||
case CL_DEVICE_TYPE_CPU: type_str ="CL_DEVICE_TYPE_CPU"; break;
|
||||
case CL_DEVICE_TYPE_GPU: type_str = "CL_DEVICE_TYPE_GPU"; break;
|
||||
case CL_DEVICE_TYPE_ACCELERATOR: type_str = "CL_DEVICE_TYPE_ACCELERATOR"; break;
|
||||
}
|
||||
|
||||
LOGD("vendor: %s", get_platform_info(platform, CL_PLATFORM_VENDOR).c_str());
|
||||
LOGD("platform version: %s", get_platform_info(platform, CL_PLATFORM_VERSION).c_str());
|
||||
LOGD("profile: %s", get_platform_info(platform, CL_PLATFORM_PROFILE).c_str());
|
||||
LOGD("extensions: %s", get_platform_info(platform, CL_PLATFORM_EXTENSIONS).c_str());
|
||||
LOGD("name: %s", get_device_info(device, CL_DEVICE_NAME).c_str());
|
||||
LOGD("device version: %s", get_device_info(device, CL_DEVICE_VERSION).c_str());
|
||||
LOGD("max work group size: %zu", work_group_size);
|
||||
LOGD("type = %d, %s", (int)device_type, type_str);
|
||||
}
|
||||
|
||||
void cl_print_build_errors(cl_program program, cl_device_id device) {
|
||||
cl_build_status status;
|
||||
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_STATUS, sizeof(status), &status, NULL);
|
||||
size_t log_size;
|
||||
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size);
|
||||
std::string log(log_size, '\0');
|
||||
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, log_size, &log[0], NULL);
|
||||
|
||||
LOGE("build failed; status=%d, log: %s", status, log.c_str());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
cl_device_id cl_get_device_id(cl_device_type device_type) {
|
||||
cl_uint num_platforms = 0;
|
||||
CL_CHECK(clGetPlatformIDs(0, NULL, &num_platforms));
|
||||
std::unique_ptr<cl_platform_id[]> platform_ids = std::make_unique<cl_platform_id[]>(num_platforms);
|
||||
CL_CHECK(clGetPlatformIDs(num_platforms, &platform_ids[0], NULL));
|
||||
|
||||
for (size_t i = 0; i < num_platforms; ++i) {
|
||||
LOGD("platform[%zu] CL_PLATFORM_NAME: %s", i, get_platform_info(platform_ids[i], CL_PLATFORM_NAME).c_str());
|
||||
|
||||
// Get first device
|
||||
if (cl_device_id device_id = NULL; clGetDeviceIDs(platform_ids[i], device_type, 1, &device_id, NULL) == 0 && device_id) {
|
||||
cl_print_info(platform_ids[i], device_id);
|
||||
return device_id;
|
||||
}
|
||||
}
|
||||
LOGE("No valid openCL platform found");
|
||||
assert(0);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cl_context cl_create_context(cl_device_id device_id) {
|
||||
return CL_CHECK_ERR(clCreateContext(NULL, 1, &device_id, NULL, NULL, &err));
|
||||
}
|
||||
|
||||
void cl_release_context(cl_context context) {
|
||||
clReleaseContext(context);
|
||||
}
|
||||
|
||||
cl_program cl_program_from_file(cl_context ctx, cl_device_id device_id, const char* path, const char* args) {
|
||||
return cl_program_from_source(ctx, device_id, util::read_file(path), args);
|
||||
}
|
||||
|
||||
cl_program cl_program_from_source(cl_context ctx, cl_device_id device_id, const std::string& src, const char* args) {
|
||||
const char *csrc = src.c_str();
|
||||
cl_program prg = CL_CHECK_ERR(clCreateProgramWithSource(ctx, 1, &csrc, NULL, &err));
|
||||
if (int err = clBuildProgram(prg, 1, &device_id, args, NULL, NULL); err != 0) {
|
||||
cl_print_build_errors(prg, device_id);
|
||||
assert(0);
|
||||
}
|
||||
return prg;
|
||||
}
|
||||
|
||||
cl_program cl_program_from_binary(cl_context ctx, cl_device_id device_id, const uint8_t* binary, size_t length, const char* args) {
|
||||
cl_program prg = CL_CHECK_ERR(clCreateProgramWithBinary(ctx, 1, &device_id, &length, &binary, NULL, &err));
|
||||
if (int err = clBuildProgram(prg, 1, &device_id, args, NULL, NULL); err != 0) {
|
||||
cl_print_build_errors(prg, device_id);
|
||||
assert(0);
|
||||
}
|
||||
return prg;
|
||||
}
|
||||
|
||||
// Given a cl code and return a string representation
|
||||
#define CL_ERR_TO_STR(err) case err: return #err
|
||||
const char* cl_get_error_string(int err) {
|
||||
switch (err) {
|
||||
CL_ERR_TO_STR(CL_SUCCESS);
|
||||
CL_ERR_TO_STR(CL_DEVICE_NOT_FOUND);
|
||||
CL_ERR_TO_STR(CL_DEVICE_NOT_AVAILABLE);
|
||||
CL_ERR_TO_STR(CL_COMPILER_NOT_AVAILABLE);
|
||||
CL_ERR_TO_STR(CL_MEM_OBJECT_ALLOCATION_FAILURE);
|
||||
CL_ERR_TO_STR(CL_OUT_OF_RESOURCES);
|
||||
CL_ERR_TO_STR(CL_OUT_OF_HOST_MEMORY);
|
||||
CL_ERR_TO_STR(CL_PROFILING_INFO_NOT_AVAILABLE);
|
||||
CL_ERR_TO_STR(CL_MEM_COPY_OVERLAP);
|
||||
CL_ERR_TO_STR(CL_IMAGE_FORMAT_MISMATCH);
|
||||
CL_ERR_TO_STR(CL_IMAGE_FORMAT_NOT_SUPPORTED);
|
||||
CL_ERR_TO_STR(CL_MAP_FAILURE);
|
||||
CL_ERR_TO_STR(CL_MISALIGNED_SUB_BUFFER_OFFSET);
|
||||
CL_ERR_TO_STR(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
|
||||
CL_ERR_TO_STR(CL_COMPILE_PROGRAM_FAILURE);
|
||||
CL_ERR_TO_STR(CL_LINKER_NOT_AVAILABLE);
|
||||
CL_ERR_TO_STR(CL_LINK_PROGRAM_FAILURE);
|
||||
CL_ERR_TO_STR(CL_DEVICE_PARTITION_FAILED);
|
||||
CL_ERR_TO_STR(CL_KERNEL_ARG_INFO_NOT_AVAILABLE);
|
||||
CL_ERR_TO_STR(CL_INVALID_VALUE);
|
||||
CL_ERR_TO_STR(CL_INVALID_DEVICE_TYPE);
|
||||
CL_ERR_TO_STR(CL_INVALID_PLATFORM);
|
||||
CL_ERR_TO_STR(CL_INVALID_DEVICE);
|
||||
CL_ERR_TO_STR(CL_INVALID_CONTEXT);
|
||||
CL_ERR_TO_STR(CL_INVALID_QUEUE_PROPERTIES);
|
||||
CL_ERR_TO_STR(CL_INVALID_COMMAND_QUEUE);
|
||||
CL_ERR_TO_STR(CL_INVALID_HOST_PTR);
|
||||
CL_ERR_TO_STR(CL_INVALID_MEM_OBJECT);
|
||||
CL_ERR_TO_STR(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR);
|
||||
CL_ERR_TO_STR(CL_INVALID_IMAGE_SIZE);
|
||||
CL_ERR_TO_STR(CL_INVALID_SAMPLER);
|
||||
CL_ERR_TO_STR(CL_INVALID_BINARY);
|
||||
CL_ERR_TO_STR(CL_INVALID_BUILD_OPTIONS);
|
||||
CL_ERR_TO_STR(CL_INVALID_PROGRAM);
|
||||
CL_ERR_TO_STR(CL_INVALID_PROGRAM_EXECUTABLE);
|
||||
CL_ERR_TO_STR(CL_INVALID_KERNEL_NAME);
|
||||
CL_ERR_TO_STR(CL_INVALID_KERNEL_DEFINITION);
|
||||
CL_ERR_TO_STR(CL_INVALID_KERNEL);
|
||||
CL_ERR_TO_STR(CL_INVALID_ARG_INDEX);
|
||||
CL_ERR_TO_STR(CL_INVALID_ARG_VALUE);
|
||||
CL_ERR_TO_STR(CL_INVALID_ARG_SIZE);
|
||||
CL_ERR_TO_STR(CL_INVALID_KERNEL_ARGS);
|
||||
CL_ERR_TO_STR(CL_INVALID_WORK_DIMENSION);
|
||||
CL_ERR_TO_STR(CL_INVALID_WORK_GROUP_SIZE);
|
||||
CL_ERR_TO_STR(CL_INVALID_WORK_ITEM_SIZE);
|
||||
CL_ERR_TO_STR(CL_INVALID_GLOBAL_OFFSET);
|
||||
CL_ERR_TO_STR(CL_INVALID_EVENT_WAIT_LIST);
|
||||
CL_ERR_TO_STR(CL_INVALID_EVENT);
|
||||
CL_ERR_TO_STR(CL_INVALID_OPERATION);
|
||||
CL_ERR_TO_STR(CL_INVALID_GL_OBJECT);
|
||||
CL_ERR_TO_STR(CL_INVALID_BUFFER_SIZE);
|
||||
CL_ERR_TO_STR(CL_INVALID_MIP_LEVEL);
|
||||
CL_ERR_TO_STR(CL_INVALID_GLOBAL_WORK_SIZE);
|
||||
CL_ERR_TO_STR(CL_INVALID_PROPERTY);
|
||||
CL_ERR_TO_STR(CL_INVALID_IMAGE_DESCRIPTOR);
|
||||
CL_ERR_TO_STR(CL_INVALID_COMPILER_OPTIONS);
|
||||
CL_ERR_TO_STR(CL_INVALID_LINKER_OPTIONS);
|
||||
CL_ERR_TO_STR(CL_INVALID_DEVICE_PARTITION_COUNT);
|
||||
case -69: return "CL_INVALID_PIPE_SIZE";
|
||||
case -70: return "CL_INVALID_DEVICE_QUEUE";
|
||||
case -71: return "CL_INVALID_SPEC_ID";
|
||||
case -72: return "CL_MAX_SIZE_RESTRICTION_EXCEEDED";
|
||||
case -1002: return "CL_INVALID_D3D10_DEVICE_KHR";
|
||||
case -1003: return "CL_INVALID_D3D10_RESOURCE_KHR";
|
||||
case -1004: return "CL_D3D10_RESOURCE_ALREADY_ACQUIRED_KHR";
|
||||
case -1005: return "CL_D3D10_RESOURCE_NOT_ACQUIRED_KHR";
|
||||
case -1006: return "CL_INVALID_D3D11_DEVICE_KHR";
|
||||
case -1007: return "CL_INVALID_D3D11_RESOURCE_KHR";
|
||||
case -1008: return "CL_D3D11_RESOURCE_ALREADY_ACQUIRED_KHR";
|
||||
case -1009: return "CL_D3D11_RESOURCE_NOT_ACQUIRED_KHR";
|
||||
case -1010: return "CL_INVALID_DX9_MEDIA_ADAPTER_KHR";
|
||||
case -1011: return "CL_INVALID_DX9_MEDIA_SURFACE_KHR";
|
||||
case -1012: return "CL_DX9_MEDIA_SURFACE_ALREADY_ACQUIRED_KHR";
|
||||
case -1013: return "CL_DX9_MEDIA_SURFACE_NOT_ACQUIRED_KHR";
|
||||
case -1093: return "CL_INVALID_EGL_OBJECT_KHR";
|
||||
case -1092: return "CL_EGL_RESOURCE_NOT_ACQUIRED_KHR";
|
||||
case -1001: return "CL_PLATFORM_NOT_FOUND_KHR";
|
||||
case -1057: return "CL_DEVICE_PARTITION_FAILED_EXT";
|
||||
case -1058: return "CL_INVALID_PARTITION_COUNT_EXT";
|
||||
case -1059: return "CL_INVALID_PARTITION_NAME_EXT";
|
||||
case -1094: return "CL_INVALID_ACCELERATOR_INTEL";
|
||||
case -1095: return "CL_INVALID_ACCELERATOR_TYPE_INTEL";
|
||||
case -1096: return "CL_INVALID_ACCELERATOR_DESCRIPTOR_INTEL";
|
||||
case -1097: return "CL_ACCELERATOR_TYPE_NOT_SUPPORTED_INTEL";
|
||||
case -1000: return "CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR";
|
||||
case -1098: return "CL_INVALID_VA_API_MEDIA_ADAPTER_INTEL";
|
||||
case -1099: return "CL_INVALID_VA_API_MEDIA_SURFACE_INTEL";
|
||||
case -1100: return "CL_VA_API_MEDIA_SURFACE_ALREADY_ACQUIRED_INTEL";
|
||||
case -1101: return "CL_VA_API_MEDIA_SURFACE_NOT_ACQUIRED_INTEL";
|
||||
default: return "CL_UNKNOWN_ERROR";
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <OpenCL/cl.h>
|
||||
#else
|
||||
#include <CL/cl.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
#define CL_CHECK(_expr) \
|
||||
do { \
|
||||
assert(CL_SUCCESS == (_expr)); \
|
||||
} while (0)
|
||||
|
||||
#define CL_CHECK_ERR(_expr) \
|
||||
({ \
|
||||
cl_int err = CL_INVALID_VALUE; \
|
||||
__typeof__(_expr) _ret = _expr; \
|
||||
assert(_ret&& err == CL_SUCCESS); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
cl_device_id cl_get_device_id(cl_device_type device_type);
|
||||
cl_context cl_create_context(cl_device_id device_id);
|
||||
void cl_release_context(cl_context context);
|
||||
cl_program cl_program_from_source(cl_context ctx, cl_device_id device_id, const std::string& src, const char* args = nullptr);
|
||||
cl_program cl_program_from_binary(cl_context ctx, cl_device_id device_id, const uint8_t* binary, size_t length, const char* args = nullptr);
|
||||
cl_program cl_program_from_file(cl_context ctx, cl_device_id device_id, const char* path, const char* args);
|
||||
const char* cl_get_error_string(int err);
|
||||
@@ -1,27 +0,0 @@
|
||||
import numpy as np
|
||||
|
||||
class Conversions:
|
||||
# Speed
|
||||
MPH_TO_KPH = 1.609344
|
||||
KPH_TO_MPH = 1. / MPH_TO_KPH
|
||||
MS_TO_KPH = 3.6
|
||||
KPH_TO_MS = 1. / MS_TO_KPH
|
||||
MS_TO_MPH = MS_TO_KPH * KPH_TO_MPH
|
||||
MPH_TO_MS = MPH_TO_KPH * KPH_TO_MS
|
||||
MS_TO_KNOTS = 1.9438
|
||||
KNOTS_TO_MS = 1. / MS_TO_KNOTS
|
||||
|
||||
# Distance
|
||||
METER_TO_FOOT = 3.28084
|
||||
FOOT_TO_METER = 1. / METER_TO_FOOT
|
||||
METER_TO_MILE = METER_TO_FOOT / 5280
|
||||
MILE_TO_METER = 1. / METER_TO_MILE
|
||||
CM_TO_INCH = 1. / 2.54
|
||||
INCH_TO_CM = 1. / CM_TO_INCH
|
||||
|
||||
# Angle
|
||||
DEG_TO_RAD = np.pi / 180.
|
||||
RAD_TO_DEG = 1. / DEG_TO_RAD
|
||||
|
||||
# Mass
|
||||
LB_TO_KG = 0.453592
|
||||
Executable
+222
@@ -0,0 +1,222 @@
|
||||
import re
|
||||
import os
|
||||
import struct
|
||||
import bitstring
|
||||
import sys
|
||||
import numbers
|
||||
from collections import namedtuple
|
||||
|
||||
def int_or_float(s):
|
||||
# return number, trying to maintain int format
|
||||
try:
|
||||
return int(s)
|
||||
except ValueError:
|
||||
return float(s)
|
||||
|
||||
DBCSignal = namedtuple(
|
||||
"DBCSignal", ["name", "start_bit", "size", "is_little_endian", "is_signed",
|
||||
"factor", "offset", "tmin", "tmax", "units"])
|
||||
|
||||
class dbc(object):
|
||||
def __init__(self, fn):
|
||||
self.name, _ = os.path.splitext(os.path.basename(fn))
|
||||
with open(fn) as f:
|
||||
self.txt = f.read().split("\n")
|
||||
self._warned_addresses = set()
|
||||
|
||||
# regexps from https://github.com/ebroecker/canmatrix/blob/master/canmatrix/importdbc.py
|
||||
bo_regexp = re.compile("^BO\_ (\w+) (\w+) *: (\w+) (\w+)")
|
||||
sg_regexp = re.compile("^SG\_ (\w+) : (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*)")
|
||||
sgm_regexp = re.compile("^SG\_ (\w+) (\w+) *: (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*)")
|
||||
|
||||
# A dictionary which maps message ids to tuples ((name, size), signals).
|
||||
# name is the ASCII name of the message.
|
||||
# size is the size of the message in bytes.
|
||||
# signals is a list signals contained in the message.
|
||||
# signals is a list of DBCSignal in order of increasing start_bit.
|
||||
self.msgs = {}
|
||||
|
||||
# lookup to bit reverse each byte
|
||||
self.bits_index = [(i & ~0b111) + ((-i-1) & 0b111) for i in xrange(64)]
|
||||
|
||||
for l in self.txt:
|
||||
l = l.strip()
|
||||
|
||||
if l.startswith("BO_ "):
|
||||
# new group
|
||||
dat = bo_regexp.match(l)
|
||||
|
||||
if dat is None:
|
||||
print "bad BO", l
|
||||
name = dat.group(2)
|
||||
size = int(dat.group(3))
|
||||
ids = int(dat.group(1), 0) # could be hex
|
||||
if ids in self.msgs:
|
||||
sys.exit("Duplicate address detected %d %s" % (ids, self.name))
|
||||
|
||||
self.msgs[ids] = ((name, size), [])
|
||||
|
||||
if l.startswith("SG_ "):
|
||||
# new signal
|
||||
dat = sg_regexp.match(l)
|
||||
go = 0
|
||||
if dat is None:
|
||||
dat = sgm_regexp.match(l)
|
||||
go = 1
|
||||
if dat is None:
|
||||
print "bad SG", l
|
||||
|
||||
sgname = dat.group(1)
|
||||
start_bit = int(dat.group(go+2))
|
||||
signal_size = int(dat.group(go+3))
|
||||
is_little_endian = int(dat.group(go+4))==1
|
||||
is_signed = dat.group(go+5)=='-'
|
||||
factor = int_or_float(dat.group(go+6))
|
||||
offset = int_or_float(dat.group(go+7))
|
||||
tmin = int_or_float(dat.group(go+8))
|
||||
tmax = int_or_float(dat.group(go+9))
|
||||
units = dat.group(go+10)
|
||||
|
||||
self.msgs[ids][1].append(
|
||||
DBCSignal(sgname, start_bit, signal_size, is_little_endian,
|
||||
is_signed, factor, offset, tmin, tmax, units))
|
||||
|
||||
for msg in self.msgs.viewvalues():
|
||||
msg[1].sort(key=lambda x: x.start_bit)
|
||||
|
||||
self.msg_name_to_address = {}
|
||||
for address, m in self.msgs.items():
|
||||
name = m[0][0]
|
||||
self.msg_name_to_address[name] = address
|
||||
|
||||
def lookup_msg_id(self, msg_id):
|
||||
if not isinstance(msg_id, numbers.Number):
|
||||
msg_id = self.msg_name_to_address[msg_id]
|
||||
return msg_id
|
||||
|
||||
def encode(self, msg_id, dd):
|
||||
"""Encode a CAN message using the dbc.
|
||||
|
||||
Inputs:
|
||||
msg_id: The message ID.
|
||||
dd: A dictionary mapping signal name to signal data.
|
||||
"""
|
||||
msg_id = self.lookup_msg_id(msg_id)
|
||||
|
||||
# TODO: Stop using bitstring, which is super slow.
|
||||
msg_def = self.msgs[msg_id]
|
||||
size = msg_def[0][1]
|
||||
|
||||
bsf = bitstring.Bits(hex="00"*size)
|
||||
for s in msg_def[1]:
|
||||
ival = dd.get(s.name)
|
||||
if ival is not None:
|
||||
ival = (ival / s.factor) - s.offset
|
||||
ival = int(round(ival))
|
||||
|
||||
# should pack this
|
||||
if s.is_little_endian:
|
||||
ss = s.start_bit
|
||||
else:
|
||||
ss = self.bits_index[s.start_bit]
|
||||
|
||||
|
||||
if s.is_signed:
|
||||
tbs = bitstring.Bits(int=ival, length=s.size)
|
||||
else:
|
||||
tbs = bitstring.Bits(uint=ival, length=s.size)
|
||||
|
||||
lpad = bitstring.Bits(bin="0b"+"0"*ss)
|
||||
rpad = bitstring.Bits(bin="0b"+"0"*(8*size-(ss+s.size)))
|
||||
tbs = lpad+tbs+rpad
|
||||
|
||||
bsf |= tbs
|
||||
return bsf.tobytes()
|
||||
|
||||
def decode(self, x, arr=None, debug=False):
|
||||
"""Decode a CAN message using the dbc.
|
||||
|
||||
Inputs:
|
||||
x: A collection with elements (address, time, data), where address is
|
||||
the CAN address, time is the bus time, and data is the CAN data as a
|
||||
hex string.
|
||||
arr: Optional list of signals which should be decoded and returned.
|
||||
debug: True to print debugging statements.
|
||||
|
||||
Returns:
|
||||
A tuple (name, data), where name is the name of the CAN message and data
|
||||
is the decoded result. If arr is None, data is a dict of properties.
|
||||
Otherwise data is a list of the same length as arr.
|
||||
|
||||
Returns (None, None) if the message could not be decoded.
|
||||
"""
|
||||
|
||||
if arr is None:
|
||||
out = {}
|
||||
else:
|
||||
out = [None]*len(arr)
|
||||
|
||||
msg = self.msgs.get(x[0])
|
||||
if msg is None:
|
||||
if x[0] not in self._warned_addresses:
|
||||
#print("WARNING: Unknown message address {}".format(x[0]))
|
||||
self._warned_addresses.add(x[0])
|
||||
return None, None
|
||||
|
||||
name = msg[0][0]
|
||||
if debug:
|
||||
print name
|
||||
|
||||
blen = 8*len(x[2])
|
||||
|
||||
st = x[2].rjust(8, '\x00')
|
||||
le, be = None, None
|
||||
|
||||
for s in msg[1]:
|
||||
if arr is not None and s[0] not in arr:
|
||||
continue
|
||||
|
||||
# big or little endian?
|
||||
# see http://vi-firmware.openxcplatform.com/en/master/config/bit-numbering.html
|
||||
if s[3] is False:
|
||||
ss = self.bits_index[s[1]]
|
||||
if be is None:
|
||||
be = struct.unpack(">Q", st)[0]
|
||||
x2_int = be
|
||||
data_bit_pos = (blen - (ss + s[2]))
|
||||
else:
|
||||
if le is None:
|
||||
le = struct.unpack("<Q", st)[0]
|
||||
x2_int = le
|
||||
ss = s[1]
|
||||
data_bit_pos = ss
|
||||
|
||||
if data_bit_pos < 0:
|
||||
continue
|
||||
ival = (x2_int >> data_bit_pos) & ((1 << (s[2])) - 1)
|
||||
|
||||
if s[4] and (ival & (1<<(s[2]-1))): # signed
|
||||
ival -= (1<<s[2])
|
||||
|
||||
# control the offset
|
||||
ival = (ival * s[5]) + s[6]
|
||||
#if debug:
|
||||
# print "%40s %2d %2d %7.2f %s" % (s[0], s[1], s[2], ival, s[-1])
|
||||
|
||||
if arr is None:
|
||||
out[s[0]] = ival
|
||||
else:
|
||||
out[arr.index(s[0])] = ival
|
||||
return name, out
|
||||
|
||||
def get_signals(self, msg):
|
||||
msg = self.lookup_msg_id(msg)
|
||||
return [sgs.name for sgs in self.msgs[msg][1]]
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
import os
|
||||
from opendbc import DBC_PATH
|
||||
|
||||
dbc_test = dbc(os.path.join(DBC_PATH, sys.argv[1]))
|
||||
print dbc_test.get_signals(0xe4)
|
||||
@@ -1,9 +0,0 @@
|
||||
# remove all keys that end in DEPRECATED
|
||||
def strip_deprecated_keys(d):
|
||||
for k in list(d.keys()):
|
||||
if isinstance(k, str):
|
||||
if k.endswith('DEPRECATED'):
|
||||
d.pop(k)
|
||||
elif isinstance(d[k], dict):
|
||||
strip_deprecated_keys(d[k])
|
||||
return d
|
||||
@@ -1,8 +0,0 @@
|
||||
import platform
|
||||
|
||||
|
||||
def suffix():
|
||||
if platform.system() == "Darwin":
|
||||
return ".dylib"
|
||||
else:
|
||||
return ".so"
|
||||
@@ -1,37 +0,0 @@
|
||||
import os
|
||||
import tempfile
|
||||
import contextlib
|
||||
|
||||
|
||||
class CallbackReader:
|
||||
"""Wraps a file, but overrides the read method to also
|
||||
call a callback function with the number of bytes read so far."""
|
||||
def __init__(self, f, callback, *args):
|
||||
self.f = f
|
||||
self.callback = callback
|
||||
self.cb_args = args
|
||||
self.total_read = 0
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self.f, attr)
|
||||
|
||||
def read(self, *args, **kwargs):
|
||||
chunk = self.f.read(*args, **kwargs)
|
||||
self.total_read += len(chunk)
|
||||
self.callback(*self.cb_args, self.total_read)
|
||||
return chunk
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def atomic_write_in_dir(path: str, mode: str = 'w', buffering: int = -1, encoding: str = None, newline: str = None,
|
||||
overwrite: bool = False):
|
||||
"""Write to a file atomically using a temporary file in the same directory as the destination file."""
|
||||
dir_name = os.path.dirname(path)
|
||||
|
||||
if not overwrite and os.path.exists(path):
|
||||
raise FileExistsError(f"File '{path}' already exists. To overwrite it, set 'overwrite' to True.")
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode=mode, buffering=buffering, encoding=encoding, newline=newline, dir=dir_name, delete=False) as tmp_file:
|
||||
yield tmp_file
|
||||
tmp_file_name = tmp_file.name
|
||||
os.replace(tmp_file_name, path)
|
||||
@@ -1,18 +0,0 @@
|
||||
class FirstOrderFilter:
|
||||
# first order filter
|
||||
def __init__(self, x0, rc, dt, initialized=True):
|
||||
self.x = x0
|
||||
self.dt = dt
|
||||
self.update_alpha(rc)
|
||||
self.initialized = initialized
|
||||
|
||||
def update_alpha(self, rc):
|
||||
self.alpha = self.dt / (rc + self.dt)
|
||||
|
||||
def update(self, x):
|
||||
if self.initialized:
|
||||
self.x = (1. - self.alpha) * self.x + self.alpha * x
|
||||
else:
|
||||
self.initialized = True
|
||||
self.x = x
|
||||
return self.x
|
||||
@@ -0,0 +1,96 @@
|
||||
class HONDA:
|
||||
CIVIC = "HONDA CIVIC 2016 TOURING"
|
||||
ACURA_ILX = "ACURA ILX 2016 ACURAWATCH PLUS"
|
||||
CRV = "HONDA CR-V 2016 TOURING"
|
||||
ODYSSEY = "HONDA ODYSSEY 2018 EX-L"
|
||||
|
||||
|
||||
class TOYOTA:
|
||||
PRIUS = "TOYOTA PRIUS 2017"
|
||||
RAV4H = "TOYOTA RAV4 2017 HYBRID"
|
||||
RAV4 = "TOYOTA RAV4 2017"
|
||||
COROLLA = "TOYOTA COROLLA 2017"
|
||||
|
||||
|
||||
_FINGERPRINTS = {
|
||||
HONDA.ACURA_ILX: {
|
||||
1024L: 5, 513L: 5, 1027L: 5, 1029L: 8, 929L: 4, 1057L: 5, 777L: 8, 1034L: 5, 1036L: 8, 398L: 3, 399L: 7, 145L: 8, 660L: 8, 985L: 3, 923L: 2, 542L: 7, 773L: 7, 800L: 8, 432L: 7, 419L: 8, 420L: 8, 1030L: 5, 422L: 8, 808L: 8, 428L: 8, 304L: 8, 819L: 7, 821L: 5, 57L: 3, 316L: 8, 545L: 4, 464L: 8, 1108L: 8, 597L: 8, 342L: 6, 983L: 8, 344L: 8, 804L: 8, 1039L: 8, 476L: 4, 892L: 8, 490L: 8, 1064L: 7, 882L: 2, 884L: 7, 887L: 8, 888L: 8, 380L: 8, 1365L: 5,
|
||||
# sent messages
|
||||
0xe4: 5, 0x1fa: 8, 0x200: 3, 0x30c: 8, 0x33d: 5,
|
||||
},
|
||||
HONDA.CIVIC: {
|
||||
1024L: 5, 513L: 5, 1027L: 5, 1029L: 8, 777L: 8, 1036L: 8, 1039L: 8, 1424L: 5, 401L: 8, 148L: 8, 662L: 4, 985L: 3, 795L: 8, 773L: 7, 800L: 8, 545L: 6, 420L: 8, 806L: 8, 808L: 8, 1322L: 5, 427L: 3, 428L: 8, 304L: 8, 432L: 7, 57L: 3, 450L: 8, 929L: 8, 330L: 8, 1302L: 8, 464L: 8, 1361L: 5, 1108L: 8, 597L: 8, 470L: 2, 344L: 8, 804L: 8, 399L: 7, 476L: 7, 1633L: 8, 487L: 4, 892L: 8, 490L: 8, 493L: 5, 884L: 8, 891L: 8, 380L: 8, 1365L: 5,
|
||||
# sent messages
|
||||
0xe4: 5, 0x1fa: 8, 0x200: 3, 0x30c: 8, 0x33d: 5, 0x35e: 8, 0x39f: 8,
|
||||
},
|
||||
HONDA.CRV: {
|
||||
57L: 3, 145L: 8, 316L: 8, 340L: 8, 342L: 6, 344L: 8, 380L: 8, 398L: 3, 399L: 6, 401L: 8, 420L: 8, 422L: 8, 426L: 8, 432L: 7, 464L: 8, 474L: 5, 476L: 4, 487L: 4, 490L: 8, 493L: 3, 507L: 1, 542L: 7, 545L: 4, 597L: 8, 660L: 8, 661L: 4, 773L: 7, 777L: 8, 800L: 8, 804L: 8, 808L: 8, 882L: 2, 884L: 7, 888L: 8, 891L: 8, 892L: 8, 923L: 2, 929L: 8, 983L: 8, 985L: 3, 1024L: 5, 1027L: 5, 1029L: 8, 1033L: 5, 1036L: 8, 1039L: 8, 1057L: 5, 1064L: 7, 1108L: 8, 1125L: 8, 1296L: 8, 1365L: 5, 1424L: 5, 1600L: 5, 1601L: 8,
|
||||
# sent messages
|
||||
0x194: 4, 0x1fa: 8, 0x30c: 8, 0x33d: 5,
|
||||
},
|
||||
HONDA.ODYSSEY: {
|
||||
57L: 3, 148L: 8, 228L: 5, 229L: 4, 316L: 8, 342L: 6, 344L: 8, 380L: 8, 399L: 7, 411L: 5, 419L: 8, 420L: 8, 427L: 3, 432L: 7, 450L: 8, 463L: 8, 464L: 8, 476L: 4, 490L: 8, 506L: 8, 542L: 7, 545L: 6, 597L: 8, 662L: 4, 773L: 7, 777L: 8, 780L: 8, 795L: 8, 800L: 8, 804L: 8, 806L: 8, 808L: 8, 817L: 4, 819L: 7, 821L: 5, 825L: 4, 829L: 5, 837L: 5, 856L: 7, 862L: 8, 871L: 8, 881L: 8, 882L: 4, 884L: 8, 891L: 8, 892L: 8, 905L: 8, 923L: 2, 927L: 8, 929L: 8, 963L: 8, 965L: 8, 966L: 8, 967L: 8, 983L: 8, 985L: 3, 1029L: 8, 1036L: 8, 1052L: 8, 1064L: 7, 1088L: 8, 1089L: 8, 1092L: 1, 1108L: 8, 1110L: 8, 1125L: 8, 1296L: 8, 1302L: 8, 1600L: 5, 1601L: 8, 1612L: 5, 1613L: 5, 1614L: 5, 1615L: 8, 1616L: 5, 1619L: 5, 1623L: 5, 1668L: 5
|
||||
},
|
||||
TOYOTA.RAV4: {
|
||||
36L: 8, 37L: 8, 170L: 8, 180L: 8, 186L: 4, 426L: 6, 452L: 8, 464L: 8, 466L: 8, 467L: 8, 547L: 8, 548L: 8, 552L: 4, 562L: 4, 608L: 8, 610L: 5, 643L: 7, 705L: 8, 725L: 2, 740L: 5, 800L: 8, 835L: 8, 836L: 8, 849L: 4, 869L: 7, 870L: 7, 871L: 2, 896L: 8, 897L: 8, 900L: 6, 902L: 6, 905L: 8, 911L: 8, 916L: 3, 918L: 7, 921L: 8, 933L: 8, 944L: 8, 945L: 8, 951L: 8, 955L: 4, 956L: 8, 979L: 2, 998L: 5, 999L: 7, 1000L: 8, 1001L: 8, 1008L: 2, 1014L: 8, 1017L: 8, 1041L: 8, 1042L: 8, 1043L: 8, 1044L: 8, 1056L: 8, 1059L: 1, 1114L: 8, 1161L: 8, 1162L: 8, 1163L: 8, 1176L: 8, 1177L: 8, 1178L: 8, 1179L: 8, 1180L: 8, 1181L: 8, 1190L: 8, 1191L: 8, 1192L: 8, 1196L: 8, 1227L: 8, 1228L: 8, 1235L: 8, 1237L: 8, 1263L: 8, 1279L: 8, 1408L: 8, 1409L: 8, 1410L: 8, 1552L: 8, 1553L: 8, 1554L: 8, 1555L: 8, 1556L: 8, 1557L: 8, 1561L: 8, 1562L: 8, 1568L: 8, 1569L: 8, 1570L: 8, 1571L: 8, 1572L: 8, 1584L: 8, 1589L: 8, 1592L: 8, 1593L: 8, 1595L: 8, 1596L: 8, 1597L: 8, 1600L: 8, 1656L: 8, 1664L: 8, 1728L: 8, 1745L: 8, 1779L: 8, 1904L: 8, 1912L: 8, 1990L: 8, 1998L: 8
|
||||
},
|
||||
TOYOTA.RAV4H: {
|
||||
36L: 8, 37L: 8, 170L: 8, 180L: 8, 186L: 4, 426L: 6, 452L: 8, 464L: 8, 466L: 8, 467L: 8, 547L: 8, 548L: 8, 552L: 4, 562L: 4, 608L: 8, 610L: 5, 643L: 7, 705L: 8, 725L: 2, 740L: 5, 800L: 8, 835L: 8, 836L: 8, 849L: 4, 869L: 7, 870L: 7, 871L: 2, 896L: 8, 897L: 8, 900L: 6, 902L: 6, 905L: 8, 911L: 8, 916L: 3, 918L: 7, 921L: 8, 933L: 8, 944L: 8, 945L: 8, 951L: 8, 955L: 8, 956L: 8, 979L: 2, 998L: 5, 999L: 7, 1000L: 8, 1001L: 8, 1008L: 2, 1014L: 8, 1017L: 8, 1041L: 8, 1042L: 8, 1043L: 8, 1044L: 8, 1056L: 8, 1059L: 1, 1114L: 8, 1161L: 8, 1162L: 8, 1163L: 8, 1176L: 8, 1177L: 8, 1178L: 8, 1179L: 8, 1180L: 8, 1181L: 8, 1190L: 8, 1191L: 8, 1192L: 8, 1196L: 8, 1227L: 8, 1228L: 8, 1235L: 8, 1237L: 8, 1263L: 8, 1279L: 8, 1408L: 8, 1409L: 8, 1410L: 8, 1552L: 8, 1553L: 8, 1554L: 8, 1555L: 8, 1556L: 8, 1557L: 8, 1561L: 8, 1562L: 8, 1568L: 8, 1569L: 8, 1570L: 8, 1571L: 8, 1572L: 8, 1584L: 8, 1589L: 8, 1592L: 8, 1593L: 8, 1595L: 8, 1596L: 8, 1597L: 8, 1600L: 8, 1656L: 8, 1664L: 8, 1728L: 8, 1745L: 8, 1779L: 8, 1904L: 8, 1912L: 8, 1990L: 8, 1998L: 8, 581L: 5, 296: 8, 552L: 8, 560L: 7, 552L: 4, 713L: 8, 550L: 8, 608L: 8, 37L: 8, 36L: 8, 950L: 8, 1198L: 8, 1197L: 8, 1199L: 8, 1212L: 8, 953L: 3, 1264L: 8, 1184L: 8, 1005L: 2, 1185L: 8, 1232L: 8, 1186L: 8
|
||||
},
|
||||
TOYOTA.PRIUS: [{
|
||||
36L: 8, 37L: 8, 166L: 8, 170L: 8, 180L: 8, 295L: 8, 296L: 8, 426L: 6, 452L: 8, 466L: 8, 467L: 8, 550L: 8, 552L: 4, 560L: 7, 562L: 6, 581L: 5, 608L: 8, 610L: 8, 614L: 8, 643L: 7, 658L: 8, 713L: 8, 740L: 5, 742L: 8, 743L: 8, 800L: 8, 810L: 2, 814L: 8, 829L: 2, 830L: 7, 835L: 8, 836L: 8, 863L: 8, 869L: 7, 870L: 7, 871L: 2, 898L: 8, 900L: 6, 902L: 6, 905L: 8, 918L: 8, 921L: 8, 933L: 8, 944L: 8, 945L: 8, 950L: 8, 951L: 8, 953L: 8, 955L: 8, 956L: 8, 971L: 7, 975L: 5, 993L: 8, 998L: 5, 999L: 7, 1000L: 8, 1001L: 8, 1014L: 8, 1017L: 8, 1020L: 8, 1041L: 8, 1042L: 8, 1044L: 8, 1056L: 8, 1057L: 8, 1059L: 1, 1071L: 8, 1077L: 8, 1082L: 8, 1083L: 8, 1084L: 8, 1085L: 8, 1086L: 8, 1114L: 8, 1132L: 8, 1161L: 8, 1162L: 8, 1163L: 8, 1175L: 8, 1227L: 8, 1228L: 8, 1235L: 8, 1237L: 8, 1279L: 8, 1552L: 8, 1553L: 8, 1556L: 8, 1557L: 8, 1568L: 8, 1570L: 8, 1571L: 8, 1572L: 8, 1595L: 8, 1777L: 8, 1779L: 8, 1904L: 8, 1912L: 8, 1990L: 8, 1998L: 8
|
||||
},
|
||||
# Prius Prime
|
||||
{
|
||||
36L: 8, 37L: 8, 166L: 8, 170L: 8, 180L: 8, 295L: 8, 296L: 8, 426L: 6, 452L: 8, 466L: 8, 467L: 8, 550L: 8, 552L: 4, 560L: 7, 562L: 6, 581L: 5, 608L: 8, 610L: 8, 614L: 8, 643L: 7, 658L: 8, 713L: 8, 740L: 5, 742L: 8, 743L: 8, 800L: 8, 810L: 2, 814L: 8, 824L: 2, 829L: 2, 830L: 7, 835L: 8, 836L: 8, 863L: 8, 869L: 7, 870L: 7, 871L: 2,898L: 8, 900L: 6, 902L: 6, 905L: 8, 913L: 8, 918L: 8, 921L: 8, 933L: 8, 944L: 8, 945L: 8, 950L: 8, 951L: 8, 953L: 8, 955L: 8, 956L: 8, 971L: 7, 974L: 8, 975L: 5, 993L: 8, 998L: 5, 999L: 7, 1000L: 8, 1001L: 8, 1014L: 8, 1017L: 8, 1020L: 8, 1041L: 8, 1042L: 8, 1044L: 8, 1056L: 8, 1057L: 8, 1059L: 1, 1071L: 8, 1076L: 8, 1077L: 8, 1082L: 8, 1083L: 8, 1084L: 8, 1085L: 8, 1086L: 8, 1114L: 8, 1132L: 8, 1161L: 8, 1162L: 8, 1163L: 8, 1164L: 8, 1165L: 8, 1166L: 8, 1167L: 8, 1175L: 8, 1227L: 8, 1228L: 8, 1235L: 8, 1237L: 8, 1279L: 8, 1552L: 8, 1553L: 8, 1556L: 8, 1557L: 8, 1568L: 8, 1570L: 8, 1571L: 8, 1572L: 8, 1595L: 8, 1777L: 8, 1779L: 8, 1904L: 8, 1912L: 8, 1990L: 8, 1998L: 8
|
||||
},
|
||||
# Taiwanese Prius Prime
|
||||
{
|
||||
36L: 8, 37L: 8, 166L: 8, 170L: 8, 180L: 8, 295L: 8, 296L: 8, 426L: 6, 452L: 8, 466L: 8, 467L: 8, 550L: 8, 552L: 4, 560L: 7, 562L: 6, 581L: 5, 608L: 8, 610L: 8, 614L: 8, 643L: 7, 658L: 8, 713L: 8, 740L: 5, 742L: 8, 743L: 8, 800L: 8, 810L: 2, 814L: 8, 824L: 2, 829L: 2, 830L: 7, 835L: 8, 836L: 8, 863L: 8, 869L: 7, 870L: 7, 871L: 2,898L: 8, 900L: 6, 902L: 6, 905L: 8, 913L: 8, 918L: 8, 921L: 8, 933L: 8, 944L: 8, 945L: 8, 950L: 8, 951L: 8, 953L: 8, 955L: 8, 956L: 8, 971L: 7, 974L: 8, 975L: 5, 993L: 8, 998L: 5, 999L: 7, 1000L: 8, 1001L: 8, 1014L: 8, 1017L: 8, 1020L: 8, 1041L: 8, 1042L: 8, 1044L: 8, 1056L: 8, 1057L: 8, 1059L: 1, 1071L: 8, 1076L: 8, 1077L: 8, 1082L: 8, 1083L: 8, 1084L: 8, 1085L: 8, 1086L: 8, 1114L: 8, 1132L: 8, 1161L: 8, 1162L: 8, 1163L: 8, 1164L: 8, 1165L: 8, 1166L: 8, 1167L: 8, 1175L: 8, 1227L: 8, 1228L: 8, 1235L: 8, 1237L: 8, 1279L: 8, 1552L: 8, 1553L: 8, 1556L: 8, 1557L: 8, 1568L: 8, 1570L: 8, 1571L: 8, 1572L: 8, 1595L: 8, 1777L: 8, 1779L: 8, 1904L: 8, 1912L: 8, 1990L: 8, 1998L: 8
|
||||
}
|
||||
],
|
||||
TOYOTA.COROLLA: {
|
||||
36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 547: 8, 548: 8, 552: 4, 608: 8, 610: 5, 643: 7, 705: 8, 740: 5, 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
|
||||
},
|
||||
}
|
||||
|
||||
# support additional internal only fingerprints
|
||||
try:
|
||||
from common.fingerprints_internal import add_additional_fingerprints
|
||||
add_additional_fingerprints(_FINGERPRINTS)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
def is_valid_for_fingerprint(msg, car_fingerprint):
|
||||
adr = msg.address
|
||||
return msg.src != 0 or (adr in car_fingerprint and car_fingerprint[adr] == len(msg.dat))
|
||||
|
||||
|
||||
def eliminate_incompatible_cars(msg, candidate_cars):
|
||||
"""Removes cars that could not have sent msg.
|
||||
|
||||
Inputs:
|
||||
msg: A cereal/log CanData message from the car.
|
||||
candidate_cars: A list of cars to consider.
|
||||
|
||||
Returns:
|
||||
A list containing the subset of candidate_cars that could have sent msg.
|
||||
"""
|
||||
compatible_cars = []
|
||||
for car_name in candidate_cars:
|
||||
car_fingerprints = _FINGERPRINTS[car_name]
|
||||
if not isinstance(car_fingerprints, list):
|
||||
car_fingerprints = [car_fingerprints]
|
||||
|
||||
for fingerprint in car_fingerprints:
|
||||
if is_valid_for_fingerprint(msg, fingerprint):
|
||||
compatible_cars.append(car_name)
|
||||
break
|
||||
|
||||
return compatible_cars
|
||||
|
||||
|
||||
def all_known_cars():
|
||||
"""Returns a list of all known car strings."""
|
||||
return _FINGERPRINTS.keys()
|
||||
@@ -1,42 +0,0 @@
|
||||
from functools import cache
|
||||
import subprocess
|
||||
from openpilot.common.run import run_cmd, run_cmd_default
|
||||
|
||||
|
||||
@cache
|
||||
def get_commit(cwd: str = None, branch: str = "HEAD") -> str:
|
||||
return run_cmd_default(["git", "rev-parse", branch], cwd=cwd)
|
||||
|
||||
|
||||
@cache
|
||||
def get_commit_date(cwd: str = None, commit: str = "HEAD") -> str:
|
||||
return run_cmd_default(["git", "show", "--no-patch", "--format='%ct %ci'", commit], cwd=cwd)
|
||||
|
||||
|
||||
@cache
|
||||
def get_short_branch(cwd: str = None) -> str:
|
||||
return run_cmd_default(["git", "rev-parse", "--abbrev-ref", "HEAD"], cwd=cwd)
|
||||
|
||||
|
||||
@cache
|
||||
def get_branch(cwd: str = None) -> str:
|
||||
return run_cmd_default(["git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"], cwd=cwd)
|
||||
|
||||
|
||||
@cache
|
||||
def get_origin(cwd: str = None) -> str:
|
||||
try:
|
||||
local_branch = run_cmd(["git", "name-rev", "--name-only", "HEAD"], cwd=cwd)
|
||||
tracking_remote = run_cmd(["git", "config", "branch." + local_branch + ".remote"], cwd=cwd)
|
||||
return run_cmd(["git", "config", "remote." + tracking_remote + ".url"], cwd=cwd)
|
||||
except subprocess.CalledProcessError: # Not on a branch, fallback
|
||||
return run_cmd_default(["git", "config", "--get", "remote.origin.url"], cwd=cwd)
|
||||
|
||||
|
||||
@cache
|
||||
def get_normalized_origin(cwd: str = None) -> str:
|
||||
return get_origin(cwd) \
|
||||
.replace("git@", "", 1) \
|
||||
.replace(".git", "", 1) \
|
||||
.replace("https://", "", 1) \
|
||||
.replace(":", "/", 1)
|
||||
@@ -1,84 +0,0 @@
|
||||
#include "common/gpio.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef __APPLE__
|
||||
int gpio_init(int pin_nr, bool output) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpio_set(int pin_nr, bool high) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpiochip_get_ro_value_fd(const char* consumer_label, int gpiochiop_id, int pin_nr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <linux/gpio.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "common/util.h"
|
||||
#include "common/swaglog.h"
|
||||
|
||||
int gpio_init(int pin_nr, bool output) {
|
||||
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) {
|
||||
return -1;
|
||||
}
|
||||
const char *value = output ? "out" : "in";
|
||||
return util::write_file(pin_dir_path, (void*)value, strlen(value));
|
||||
}
|
||||
|
||||
int gpio_set(int pin_nr, bool high) {
|
||||
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) {
|
||||
return -1;
|
||||
}
|
||||
return util::write_file(pin_val_path, (void*)(high ? "1" : "0"), 1);
|
||||
}
|
||||
|
||||
int gpiochip_get_ro_value_fd(const char* consumer_label, int gpiochiop_id, int pin_nr) {
|
||||
|
||||
// Assumed that all interrupt pins are unexported and rights are given to
|
||||
// read from gpiochip0.
|
||||
std::string gpiochip_path = "/dev/gpiochip" + std::to_string(gpiochiop_id);
|
||||
int fd = open(gpiochip_path.c_str(), O_RDONLY);
|
||||
if (fd < 0) {
|
||||
LOGE("Error opening gpiochip0 fd");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Setup event
|
||||
struct gpioevent_request rq;
|
||||
rq.lineoffset = pin_nr;
|
||||
rq.handleflags = GPIOHANDLE_REQUEST_INPUT;
|
||||
|
||||
/* Requesting both edges as the data ready pulse from the lsm6ds sensor is
|
||||
very short(75us) and is mostly detected as falling edge instead of rising.
|
||||
So if it is detected as rising the following falling edge is skipped. */
|
||||
rq.eventflags = GPIOEVENT_REQUEST_BOTH_EDGES;
|
||||
|
||||
strncpy(rq.consumer_label, consumer_label, std::size(rq.consumer_label) - 1);
|
||||
int ret = util::safe_ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &rq);
|
||||
if (ret == -1) {
|
||||
LOGE("Unable to get line event from ioctl : %s", strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return rq.fd;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Pin definitions
|
||||
#ifdef QCOM2
|
||||
#define GPIO_HUB_RST_N 30
|
||||
#define GPIO_UBLOX_RST_N 32
|
||||
#define GPIO_UBLOX_SAFEBOOT_N 33
|
||||
#define GPIO_GNSS_PWR_EN 34 /* SCHEMATIC LABEL: GPIO_UBLOX_PWR_EN */
|
||||
#define GPIO_STM_RST_N 124
|
||||
#define GPIO_STM_BOOT0 134
|
||||
#define GPIO_BMX_ACCEL_INT 21
|
||||
#define GPIO_BMX_GYRO_INT 23
|
||||
#define GPIO_BMX_MAGN_INT 87
|
||||
#define GPIO_LSM_INT 84
|
||||
#define GPIOCHIP_INT 0
|
||||
#else
|
||||
#define GPIO_HUB_RST_N 0
|
||||
#define GPIO_UBLOX_RST_N 0
|
||||
#define GPIO_UBLOX_SAFEBOOT_N 0
|
||||
#define GPIO_GNSS_PWR_EN 0 /* SCHEMATIC LABEL: GPIO_UBLOX_PWR_EN */
|
||||
#define GPIO_STM_RST_N 0
|
||||
#define GPIO_STM_BOOT0 0
|
||||
#define GPIO_BMX_ACCEL_INT 0
|
||||
#define GPIO_BMX_GYRO_INT 0
|
||||
#define GPIO_BMX_MAGN_INT 0
|
||||
#define GPIO_LSM_INT 0
|
||||
#define GPIOCHIP_INT 0
|
||||
#endif
|
||||
|
||||
int gpio_init(int pin_nr, bool output);
|
||||
int gpio_set(int pin_nr, bool high);
|
||||
|
||||
int gpiochip_get_ro_value_fd(const char* consumer_label, int gpiochiop_id, int pin_nr);
|
||||
@@ -1,54 +0,0 @@
|
||||
import os
|
||||
from functools import cache
|
||||
|
||||
def gpio_init(pin: int, output: bool) -> None:
|
||||
try:
|
||||
with open(f"/sys/class/gpio/gpio{pin}/direction", 'wb') as f:
|
||||
f.write(b"out" if output else b"in")
|
||||
except Exception as e:
|
||||
print(f"Failed to set gpio {pin} direction: {e}")
|
||||
|
||||
def gpio_set(pin: int, high: bool) -> None:
|
||||
try:
|
||||
with open(f"/sys/class/gpio/gpio{pin}/value", 'wb') as f:
|
||||
f.write(b"1" if high else b"0")
|
||||
except Exception as e:
|
||||
print(f"Failed to set gpio {pin} value: {e}")
|
||||
|
||||
def gpio_read(pin: int) -> bool | None:
|
||||
val = None
|
||||
try:
|
||||
with open(f"/sys/class/gpio/gpio{pin}/value", 'rb') as f:
|
||||
val = bool(int(f.read().strip()))
|
||||
except Exception as e:
|
||||
print(f"Failed to set gpio {pin} value: {e}")
|
||||
|
||||
return val
|
||||
|
||||
def gpio_export(pin: int) -> None:
|
||||
if os.path.isdir(f"/sys/class/gpio/gpio{pin}"):
|
||||
return
|
||||
|
||||
try:
|
||||
with open("/sys/class/gpio/export", 'w') as f:
|
||||
f.write(str(pin))
|
||||
except Exception:
|
||||
print(f"Failed to export gpio {pin}")
|
||||
|
||||
@cache
|
||||
def get_irq_action(irq: int) -> list[str]:
|
||||
try:
|
||||
with open(f"/sys/kernel/irq/{irq}/actions") as f:
|
||||
actions = f.read().strip().split(',')
|
||||
return actions
|
||||
except FileNotFoundError:
|
||||
return []
|
||||
|
||||
def get_irqs_for_action(action: str) -> list[str]:
|
||||
ret = []
|
||||
with open("/proc/interrupts") as f:
|
||||
for l in f.readlines():
|
||||
irq = l.split(':')[0].strip()
|
||||
if irq.isdigit() and action in get_irq_action(irq):
|
||||
ret.append(irq)
|
||||
return ret
|
||||
@@ -1,92 +0,0 @@
|
||||
#include "common/i2c.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "common/swaglog.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
#ifdef QCOM2
|
||||
// TODO: decide if we want to install libi2c-dev everywhere
|
||||
extern "C" {
|
||||
#include <linux/i2c-dev.h>
|
||||
#include <i2c/smbus.h>
|
||||
}
|
||||
|
||||
I2CBus::I2CBus(uint8_t bus_id) {
|
||||
char bus_name[20];
|
||||
snprintf(bus_name, 20, "/dev/i2c-%d", bus_id);
|
||||
|
||||
i2c_fd = HANDLE_EINTR(open(bus_name, O_RDWR));
|
||||
if (i2c_fd < 0) {
|
||||
throw std::runtime_error("Failed to open I2C bus");
|
||||
}
|
||||
}
|
||||
|
||||
I2CBus::~I2CBus() {
|
||||
if (i2c_fd >= 0) {
|
||||
close(i2c_fd);
|
||||
}
|
||||
}
|
||||
|
||||
int I2CBus::read_register(uint8_t device_address, uint register_address, uint8_t *buffer, uint8_t len) {
|
||||
std::lock_guard lk(m);
|
||||
|
||||
int ret = 0;
|
||||
|
||||
ret = HANDLE_EINTR(ioctl(i2c_fd, I2C_SLAVE, device_address));
|
||||
if (ret < 0) { goto fail; }
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(i2c_fd, register_address, len, buffer);
|
||||
if ((ret < 0) || (ret != len)) { goto fail; }
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int I2CBus::set_register(uint8_t device_address, uint register_address, uint8_t data) {
|
||||
std::lock_guard lk(m);
|
||||
|
||||
int ret = 0;
|
||||
|
||||
ret = HANDLE_EINTR(ioctl(i2c_fd, I2C_SLAVE, device_address));
|
||||
if (ret < 0) { goto fail; }
|
||||
|
||||
ret = i2c_smbus_write_byte_data(i2c_fd, register_address, data);
|
||||
if (ret < 0) { goto fail; }
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
I2CBus::I2CBus(uint8_t bus_id) {
|
||||
UNUSED(bus_id);
|
||||
i2c_fd = -1;
|
||||
}
|
||||
|
||||
I2CBus::~I2CBus() {}
|
||||
|
||||
int I2CBus::read_register(uint8_t device_address, uint register_address, uint8_t *buffer, uint8_t len) {
|
||||
UNUSED(device_address);
|
||||
UNUSED(register_address);
|
||||
UNUSED(buffer);
|
||||
UNUSED(len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int I2CBus::set_register(uint8_t device_address, uint register_address, uint8_t data) {
|
||||
UNUSED(device_address);
|
||||
UNUSED(register_address);
|
||||
UNUSED(data);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
@@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
class I2CBus {
|
||||
private:
|
||||
int i2c_fd;
|
||||
std::mutex m;
|
||||
|
||||
public:
|
||||
I2CBus(uint8_t bus_id);
|
||||
~I2CBus();
|
||||
|
||||
int read_register(uint8_t device_address, uint register_address, uint8_t *buffer, uint8_t len);
|
||||
int set_register(uint8_t device_address, uint register_address, uint8_t data);
|
||||
};
|
||||
@@ -0,0 +1,252 @@
|
||||
import abc
|
||||
import numpy as np
|
||||
import numpy.matlib
|
||||
# The EKF class contains the framework for an Extended Kalman Filter, but must be subclassed to use.
|
||||
# A subclass must implement:
|
||||
# 1) calc_transfer_fun(); see bottom of file for more info.
|
||||
# 2) __init__() to initialize self.state, self.covar, and self.process_noise appropriately
|
||||
|
||||
# Alternatively, the existing implementations of EKF can be used (e.g. EKF2D)
|
||||
|
||||
# Sensor classes are optionally used to pass measurement information into the EKF, to keep
|
||||
# sensor parameters and processing methods for a each sensor together.
|
||||
# Sensor classes have a read() method which takes raw sensor data and returns
|
||||
# a SensorReading object, which can be passed to the EKF update() method.
|
||||
|
||||
# For usage, see run_ekf1d.py in selfdrive/new for a simple example.
|
||||
# ekf.predict(dt) should be called between update cycles with the time since it was last called.
|
||||
# Ideally, predict(dt) should be called at a relatively constant rate.
|
||||
# update() should be called once per sensor, and can be called multiple times between predict steps.
|
||||
# Access and set the state of the filter directly with ekf.state and ekf.covar.
|
||||
|
||||
|
||||
class SensorReading:
|
||||
# Given a perfect model and no noise, data = obs_model * state
|
||||
def __init__(self, data, covar, obs_model):
|
||||
self.data = data
|
||||
self.obs_model = obs_model
|
||||
self.covar = covar
|
||||
|
||||
def __repr__(self):
|
||||
return "SensorReading(data={}, covar={}, obs_model={})".format(
|
||||
repr(self.data), repr(self.covar), repr(self.obs_model))
|
||||
|
||||
|
||||
# A generic sensor class that does no pre-processing of data
|
||||
class SimpleSensor:
|
||||
# obs_model can be
|
||||
# a full observation model matrix, or
|
||||
# an integer or tuple of indices into ekf.state, indicating which variables are being directly observed
|
||||
# covar can be
|
||||
# a full covariance matrix
|
||||
# a float or tuple of individual covars for each component of the sensor reading
|
||||
# dims is the number of states in the EKF
|
||||
def __init__(self, obs_model, covar, dims):
|
||||
# Allow for integer covar/obs_model
|
||||
if not hasattr(obs_model, "__len__"):
|
||||
obs_model = (obs_model, )
|
||||
if not hasattr(covar, "__len__"):
|
||||
covar = (covar, )
|
||||
|
||||
# Full observation model passed
|
||||
if dims in np.array(obs_model).shape:
|
||||
self.obs_model = np.asmatrix(obs_model)
|
||||
self.covar = np.asmatrix(covar)
|
||||
# Indices of unit observations passed
|
||||
else:
|
||||
self.obs_model = np.matlib.zeros((len(obs_model), dims))
|
||||
self.obs_model[:, list(obs_model)] = np.identity(len(obs_model))
|
||||
if np.asarray(covar).ndim == 2:
|
||||
self.covar = np.asmatrix(covar)
|
||||
elif len(covar) == len(obs_model):
|
||||
self.covar = np.matlib.diag(covar)
|
||||
else:
|
||||
self.covar = np.matlib.identity(len(obs_model)) * covar
|
||||
|
||||
def read(self, data, covar=None):
|
||||
if covar:
|
||||
self.covar = covar
|
||||
return SensorReading(data, self.covar, self.obs_model)
|
||||
|
||||
|
||||
class EKF:
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
def __init__(self, debug=False):
|
||||
self.DEBUG = debug
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return "EKF(state={}, covar={})".format(self.state, self.covar)
|
||||
|
||||
# Measurement update
|
||||
# Reading should be a SensorReading object with data, covar, and obs_model attributes
|
||||
def update(self, reading):
|
||||
# Potential improvements:
|
||||
# deal with negative covars
|
||||
# add noise to really low covars to ensure stability
|
||||
# use mahalanobis distance to reject outliers
|
||||
# wrap angles after state updates and innovation
|
||||
|
||||
# y = z - H*x
|
||||
innovation = reading.data - reading.obs_model * self.state
|
||||
|
||||
if self.DEBUG:
|
||||
print "reading:\n",reading.data
|
||||
print "innovation:\n",innovation
|
||||
|
||||
# S = H*P*H' + R
|
||||
innovation_covar = reading.obs_model * self.covar * reading.obs_model.T + reading.covar
|
||||
|
||||
# K = P*H'*S^-1
|
||||
kalman_gain = self.covar * reading.obs_model.T * np.linalg.inv(
|
||||
innovation_covar)
|
||||
|
||||
if self.DEBUG:
|
||||
print "gain:\n", kalman_gain
|
||||
print "innovation_covar:\n", innovation_covar
|
||||
print "innovation: ", innovation
|
||||
print "test: ", self.covar * reading.obs_model.T * (
|
||||
reading.obs_model * self.covar * reading.obs_model.T + reading.covar *
|
||||
0).I
|
||||
|
||||
# x = x + K*y
|
||||
self.state += kalman_gain*innovation
|
||||
|
||||
# print "covar", np.diag(self.covar)
|
||||
#self.state[(roll_vel, yaw_vel, pitch_vel),:] = reading.data
|
||||
|
||||
# Standard form: P = (I - K*H)*P
|
||||
# self.covar = (self.identity - kalman_gain*reading.obs_model) * self.covar
|
||||
|
||||
# Use the Joseph form for numerical stability: P = (I-K*H)*P*(I - K*H)' + K*R*K'
|
||||
aux_mtrx = (self.identity - kalman_gain * reading.obs_model)
|
||||
self.covar = aux_mtrx * self.covar * aux_mtrx.T + kalman_gain * reading.covar * kalman_gain.T
|
||||
|
||||
if self.DEBUG:
|
||||
print "After update"
|
||||
print "state\n", self.state
|
||||
print "covar:\n",self.covar
|
||||
|
||||
def update_scalar(self, reading):
|
||||
# like update but knowing that measurement is a scalar
|
||||
# this avoids matrix inversions and speeds up (surprisingly) drived.py a lot
|
||||
|
||||
# innovation = reading.data - np.matmul(reading.obs_model, self.state)
|
||||
# innovation_covar = np.matmul(np.matmul(reading.obs_model, self.covar), reading.obs_model.T) + reading.covar
|
||||
# kalman_gain = np.matmul(self.covar, reading.obs_model.T)/innovation_covar
|
||||
# self.state += np.matmul(kalman_gain, innovation)
|
||||
# aux_mtrx = self.identity - np.matmul(kalman_gain, reading.obs_model)
|
||||
# self.covar = np.matmul(aux_mtrx, np.matmul(self.covar, aux_mtrx.T)) + np.matmul(kalman_gain, np.matmul(reading.covar, kalman_gain.T))
|
||||
|
||||
# written without np.matmul
|
||||
es = np.einsum
|
||||
ABC_T = "ij,jk,lk->il"
|
||||
AB_T = "ij,kj->ik"
|
||||
AB = "ij,jk->ik"
|
||||
innovation = reading.data - es(AB, reading.obs_model, self.state)
|
||||
innovation_covar = es(ABC_T, reading.obs_model, self.covar,
|
||||
reading.obs_model) + reading.covar
|
||||
kalman_gain = es(AB_T, self.covar, reading.obs_model) / innovation_covar
|
||||
|
||||
self.state += es(AB, kalman_gain, innovation)
|
||||
aux_mtrx = self.identity - es(AB, kalman_gain, reading.obs_model)
|
||||
self.covar = es(ABC_T, aux_mtrx, self.covar, aux_mtrx) + \
|
||||
es(ABC_T, kalman_gain, reading.covar, kalman_gain)
|
||||
|
||||
# Prediction update
|
||||
def predict(self, dt):
|
||||
es = np.einsum
|
||||
ABC_T = "ij,jk,lk->il"
|
||||
AB = "ij,jk->ik"
|
||||
|
||||
# State update
|
||||
transfer_fun, transfer_fun_jacobian = self.calc_transfer_fun(dt)
|
||||
|
||||
# self.state = np.matmul(transfer_fun, self.state)
|
||||
# self.covar = np.matmul(np.matmul(transfer_fun_jacobian, self.covar), transfer_fun_jacobian.T) + self.process_noise * dt
|
||||
|
||||
# x = f(x, u), written in the form x = A(x, u)*x
|
||||
self.state = es(AB, transfer_fun, self.state)
|
||||
|
||||
# P = J*P*J' + Q
|
||||
self.covar = es(ABC_T, transfer_fun_jacobian, self.covar,
|
||||
transfer_fun_jacobian) + self.process_noise * dt #!dt
|
||||
|
||||
#! Clip covariance to avoid explosions
|
||||
self.covar = np.clip(self.covar,-1e10,1e10)
|
||||
|
||||
@abc.abstractmethod
|
||||
def calc_transfer_fun(self, dt):
|
||||
"""Return a tuple with the transfer function and transfer function jacobian
|
||||
The transfer function and jacobian should both be a numpy matrix of size DIMSxDIMS
|
||||
|
||||
The transfer function matrix A should satisfy the state-update equation
|
||||
x_(k+1) = A * x_k
|
||||
|
||||
The jacobian J is the direct jacobian A*x_k. For linear systems J=A.
|
||||
|
||||
Current implementations calculate A and J as functions of state. Control input
|
||||
can be added trivially by adding a control parameter to predict() and calc_tranfer_update(),
|
||||
and using it during calculation of A and J
|
||||
"""
|
||||
|
||||
|
||||
class FastEKF1D(EKF):
|
||||
"""Fast version of EKF for 1D problems with scalar readings."""
|
||||
|
||||
def __init__(self, dt, var_init, Q):
|
||||
super(FastEKF1D, self).__init__(False)
|
||||
self.state = [0, 0]
|
||||
self.covar = [var_init, var_init, 0]
|
||||
|
||||
# Process Noise
|
||||
self.dtQ0 = dt * Q[0]
|
||||
self.dtQ1 = dt * Q[1]
|
||||
|
||||
def update(self, reading):
|
||||
raise NotImplementedError
|
||||
|
||||
def update_scalar(self, reading):
|
||||
# TODO(mgraczyk): Delete this for speed.
|
||||
# assert np.all(reading.obs_model == [1, 0])
|
||||
|
||||
rcov = reading.covar[0, 0]
|
||||
|
||||
x = self.state
|
||||
S = self.covar
|
||||
|
||||
innovation = reading.data - x[0]
|
||||
innovation_covar = S[0] + rcov
|
||||
|
||||
k0 = S[0] / innovation_covar
|
||||
k1 = S[2] / innovation_covar
|
||||
|
||||
x[0] += k0 * innovation
|
||||
x[1] += k1 * innovation
|
||||
|
||||
mk = 1 - k0
|
||||
S[1] += k1 * (k1 * (S[0] + rcov) - 2 * S[2])
|
||||
S[2] = mk * (S[2] - k1 * S[0]) + rcov * k0 * k1
|
||||
S[0] = mk * mk * S[0] + rcov * k0 * k0
|
||||
|
||||
def predict(self, dt):
|
||||
# State update
|
||||
x = self.state
|
||||
|
||||
x[0] += dt * x[1]
|
||||
|
||||
# P = J*P*J' + Q
|
||||
S = self.covar
|
||||
S[0] += dt * (2 * S[2] + dt * S[1]) + self.dtQ0
|
||||
S[2] += dt * S[1]
|
||||
S[1] += self.dtQ1
|
||||
|
||||
# Clip covariance to avoid explosions
|
||||
S = max(-1e10, min(S, 1e10))
|
||||
|
||||
def calc_transfer_fun(self, dt):
|
||||
tf = np.identity(2)
|
||||
tf[0, 1] = dt
|
||||
tfj = tf
|
||||
return tf, tfj
|
||||
@@ -0,0 +1,23 @@
|
||||
import numpy as np
|
||||
|
||||
|
||||
class KF1D:
|
||||
# this EKF assumes constant covariance matrix, so calculations are much simpler
|
||||
# the Kalman gain also needs to be precomputed using the control module
|
||||
|
||||
def __init__(self, x0, A, C, K):
|
||||
self.x = x0
|
||||
self.A = A
|
||||
self.C = C
|
||||
self.K = K
|
||||
|
||||
self.A_K = self.A - np.dot(self.K, self.C)
|
||||
|
||||
# K matrix needs to be pre-computed as follow:
|
||||
# import control
|
||||
# (x, l, K) = control.dare(np.transpose(self.A), np.transpose(self.C), Q, R)
|
||||
# self.K = np.transpose(K)
|
||||
|
||||
def update(self, meas):
|
||||
self.x = np.dot(self.A_K, self.x) + np.dot(self.K, meas)
|
||||
return self.x
|
||||
+29
-134
@@ -1,19 +1,13 @@
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
import copy
|
||||
import json
|
||||
import time
|
||||
import uuid
|
||||
import socket
|
||||
import logging
|
||||
import traceback
|
||||
from threading import local
|
||||
from collections import OrderedDict
|
||||
from contextlib import contextmanager
|
||||
|
||||
LOG_TIMESTAMPS = "LOG_TIMESTAMPS" in os.environ
|
||||
|
||||
def json_handler(obj):
|
||||
# if isinstance(obj, (datetime.date, datetime.time)):
|
||||
# return obj.isoformat()
|
||||
@@ -24,7 +18,7 @@ def json_robust_dumps(obj):
|
||||
|
||||
class NiceOrderedDict(OrderedDict):
|
||||
def __str__(self):
|
||||
return json_robust_dumps(self)
|
||||
return '{'+', '.join("%r: %r" % p for p in self.iteritems())+'}'
|
||||
|
||||
class SwagFormatter(logging.Formatter):
|
||||
def __init__(self, swaglogger):
|
||||
@@ -66,57 +60,10 @@ class SwagFormatter(logging.Formatter):
|
||||
return record_dict
|
||||
|
||||
def format(self, record):
|
||||
if self.swaglogger is None:
|
||||
raise Exception("must set swaglogger before calling format()")
|
||||
return json_robust_dumps(self.format_dict(record))
|
||||
|
||||
class SwagLogFileFormatter(SwagFormatter):
|
||||
def fix_kv(self, k, v):
|
||||
# append type to names to preserve legacy naming in logs
|
||||
# avoids overlapping key namespaces with different types
|
||||
# e.g. log.info() creates 'msg' -> 'msg$s'
|
||||
# log.event() creates 'msg.health.logMonoTime' -> 'msg.health.logMonoTime$i'
|
||||
# because overlapping namespace 'msg' caused problems
|
||||
if isinstance(v, (str, bytes)):
|
||||
k += "$s"
|
||||
elif isinstance(v, float):
|
||||
k += "$f"
|
||||
elif isinstance(v, bool):
|
||||
k += "$b"
|
||||
elif isinstance(v, int):
|
||||
k += "$i"
|
||||
elif isinstance(v, dict):
|
||||
nv = {}
|
||||
for ik, iv in v.items():
|
||||
ik, iv = self.fix_kv(ik, iv)
|
||||
nv[ik] = iv
|
||||
v = nv
|
||||
elif isinstance(v, list):
|
||||
k += "$a"
|
||||
return k, v
|
||||
|
||||
def format(self, record):
|
||||
if isinstance(record, str):
|
||||
v = json.loads(record)
|
||||
else:
|
||||
v = self.format_dict(record)
|
||||
|
||||
mk, mv = self.fix_kv('msg', v['msg'])
|
||||
del v['msg']
|
||||
v[mk] = mv
|
||||
v['id'] = uuid.uuid4().hex
|
||||
|
||||
return json_robust_dumps(v)
|
||||
|
||||
class SwagErrorFilter(logging.Filter):
|
||||
def filter(self, record):
|
||||
return record.levelno < logging.ERROR
|
||||
|
||||
def _tmpfunc():
|
||||
return 0
|
||||
|
||||
def _srcfile():
|
||||
return os.path.normcase(_tmpfunc.__code__.co_filename)
|
||||
_tmpfunc = lambda: 0
|
||||
_srcfile = os.path.normcase(_tmpfunc.__code__.co_filename)
|
||||
|
||||
class SwagLogger(logging.Logger):
|
||||
def __init__(self):
|
||||
@@ -127,6 +74,28 @@ class SwagLogger(logging.Logger):
|
||||
self.log_local = local()
|
||||
self.log_local.ctx = {}
|
||||
|
||||
def findCaller(self):
|
||||
"""
|
||||
Find the stack frame of the caller so that we can note the source
|
||||
file name, line number and function name.
|
||||
"""
|
||||
# f = currentframe()
|
||||
f = sys._getframe(3)
|
||||
#On some versions of IronPython, currentframe() returns None if
|
||||
#IronPython isn't run with -X:Frames.
|
||||
if f is not None:
|
||||
f = f.f_back
|
||||
rv = "(unknown file)", 0, "(unknown function)"
|
||||
while hasattr(f, "f_code"):
|
||||
co = f.f_code
|
||||
filename = os.path.normcase(co.co_filename)
|
||||
if filename in (logging._srcfile, _srcfile):
|
||||
f = f.f_back
|
||||
continue
|
||||
rv = (co.co_filename, f.f_lineno, co.co_name)
|
||||
break
|
||||
return rv
|
||||
|
||||
def local_ctx(self):
|
||||
try:
|
||||
return self.log_local.ctx
|
||||
@@ -153,95 +122,21 @@ class SwagLogger(logging.Logger):
|
||||
def bind_global(self, **kwargs):
|
||||
self.global_ctx.update(kwargs)
|
||||
|
||||
def event(self, event, *args, **kwargs):
|
||||
def event(self, event_name, *args, **kwargs):
|
||||
evt = NiceOrderedDict()
|
||||
evt['event'] = event
|
||||
evt['event'] = event_name
|
||||
if args:
|
||||
evt['args'] = args
|
||||
evt.update(kwargs)
|
||||
if 'error' in kwargs:
|
||||
self.error(evt)
|
||||
elif 'debug' in kwargs:
|
||||
self.debug(evt)
|
||||
else:
|
||||
self.info(evt)
|
||||
|
||||
def timestamp(self, event_name):
|
||||
if LOG_TIMESTAMPS:
|
||||
t = time.monotonic()
|
||||
tstp = NiceOrderedDict()
|
||||
tstp['timestamp'] = NiceOrderedDict()
|
||||
tstp['timestamp']["event"] = event_name
|
||||
tstp['timestamp']["time"] = t*1e9
|
||||
self.debug(tstp)
|
||||
|
||||
def findCaller(self, stack_info=False, stacklevel=1):
|
||||
"""
|
||||
Find the stack frame of the caller so that we can note the source
|
||||
file name, line number and function name.
|
||||
"""
|
||||
f = sys._getframe(3)
|
||||
#On some versions of IronPython, currentframe() returns None if
|
||||
#IronPython isn't run with -X:Frames.
|
||||
if f is not None:
|
||||
f = f.f_back
|
||||
orig_f = f
|
||||
while f and stacklevel > 1:
|
||||
f = f.f_back
|
||||
stacklevel -= 1
|
||||
if not f:
|
||||
f = orig_f
|
||||
rv = "(unknown file)", 0, "(unknown function)", None
|
||||
while hasattr(f, "f_code"):
|
||||
co = f.f_code
|
||||
filename = os.path.normcase(co.co_filename)
|
||||
|
||||
# TODO: is this pylint exception correct?
|
||||
if filename == _srcfile:
|
||||
f = f.f_back
|
||||
continue
|
||||
sinfo = None
|
||||
if stack_info:
|
||||
sio = io.StringIO()
|
||||
sio.write('Stack (most recent call last):\n')
|
||||
traceback.print_stack(f, file=sio)
|
||||
sinfo = sio.getvalue()
|
||||
if sinfo[-1] == '\n':
|
||||
sinfo = sinfo[:-1]
|
||||
sio.close()
|
||||
rv = (co.co_filename, f.f_lineno, co.co_name, sinfo)
|
||||
break
|
||||
return rv
|
||||
self.info(evt)
|
||||
|
||||
if __name__ == "__main__":
|
||||
log = SwagLogger()
|
||||
|
||||
stdout_handler = logging.StreamHandler(sys.stdout)
|
||||
stdout_handler.setLevel(logging.INFO)
|
||||
stdout_handler.addFilter(SwagErrorFilter())
|
||||
log.addHandler(stdout_handler)
|
||||
|
||||
stderr_handler = logging.StreamHandler(sys.stderr)
|
||||
stderr_handler.setLevel(logging.ERROR)
|
||||
log.addHandler(stderr_handler)
|
||||
|
||||
log.info("asdasd %s", "a")
|
||||
log.info({'wut': 1})
|
||||
log.warning("warning")
|
||||
log.error("error")
|
||||
log.critical("critical")
|
||||
log.event("test", x="y")
|
||||
|
||||
with log.ctx():
|
||||
stdout_handler.setFormatter(SwagFormatter(log))
|
||||
stderr_handler.setFormatter(SwagFormatter(log))
|
||||
log.bind(user="some user")
|
||||
log.info("in req")
|
||||
print("")
|
||||
log.warning("warning")
|
||||
print("")
|
||||
log.error("error")
|
||||
print("")
|
||||
log.critical("critical")
|
||||
print("")
|
||||
log.event("do_req", a=1, b="c")
|
||||
log.event("do_req")
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
HTML_REPLACEMENTS = [
|
||||
(r'&', r'&'),
|
||||
(r'"', r'"'),
|
||||
]
|
||||
|
||||
def parse_markdown(text: str, tab_length: int = 2) -> str:
|
||||
lines = text.split("\n")
|
||||
output: list[str] = []
|
||||
list_level = 0
|
||||
|
||||
def end_outstanding_lists(level: int, end_level: int) -> int:
|
||||
while level > end_level:
|
||||
level -= 1
|
||||
output.append("</ul>")
|
||||
if level > 0:
|
||||
output.append("</li>")
|
||||
return end_level
|
||||
|
||||
for i, line in enumerate(lines):
|
||||
if i + 1 < len(lines) and lines[i + 1].startswith("==="): # heading
|
||||
output.append(f"<h1>{line}</h1>")
|
||||
elif line.startswith("==="):
|
||||
pass
|
||||
elif line.lstrip().startswith("* "): # list
|
||||
line_level = 1 + line.count(" " * tab_length, 0, line.index("*"))
|
||||
if list_level >= line_level:
|
||||
list_level = end_outstanding_lists(list_level, line_level)
|
||||
else:
|
||||
list_level += 1
|
||||
if list_level > 1:
|
||||
output[-1] = output[-1].replace("</li>", "")
|
||||
output.append("<ul>")
|
||||
output.append(f"<li>{line.replace('*', '', 1).lstrip()}</li>")
|
||||
else:
|
||||
list_level = end_outstanding_lists(list_level, 0)
|
||||
if len(line) > 0:
|
||||
output.append(line)
|
||||
|
||||
end_outstanding_lists(list_level, 0)
|
||||
output_str = "\n".join(output) + "\n"
|
||||
|
||||
for (fr, to) in HTML_REPLACEMENTS:
|
||||
output_str = output_str.replace(fr, to)
|
||||
|
||||
return output_str
|
||||
@@ -1,50 +0,0 @@
|
||||
"""
|
||||
Utilities for generating mock messages for testing.
|
||||
example in common/tests/test_mock.py
|
||||
"""
|
||||
|
||||
|
||||
import functools
|
||||
import threading
|
||||
from cereal.messaging import PubMaster
|
||||
from cereal.services import SERVICE_LIST
|
||||
from openpilot.common.mock.generators import generate_liveLocationKalman
|
||||
from openpilot.common.realtime import Ratekeeper
|
||||
|
||||
|
||||
MOCK_GENERATOR = {
|
||||
"liveLocationKalman": generate_liveLocationKalman
|
||||
}
|
||||
|
||||
|
||||
def generate_messages_loop(services: list[str], done: threading.Event):
|
||||
pm = PubMaster(services)
|
||||
rk = Ratekeeper(100)
|
||||
i = 0
|
||||
while not done.is_set():
|
||||
for s in services:
|
||||
should_send = i % (100/SERVICE_LIST[s].frequency) == 0
|
||||
if should_send:
|
||||
message = MOCK_GENERATOR[s]()
|
||||
pm.send(s, message)
|
||||
i += 1
|
||||
rk.keep_time()
|
||||
|
||||
|
||||
def mock_messages(services: list[str] | str):
|
||||
if isinstance(services, str):
|
||||
services = [services]
|
||||
|
||||
def decorator(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
done = threading.Event()
|
||||
t = threading.Thread(target=generate_messages_loop, args=(services, done))
|
||||
t.start()
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
finally:
|
||||
done.set()
|
||||
t.join()
|
||||
return wrapper
|
||||
return decorator
|
||||
@@ -1,20 +0,0 @@
|
||||
from cereal import messaging
|
||||
|
||||
|
||||
LOCATION1 = (32.7174, -117.16277)
|
||||
LOCATION2 = (32.7558, -117.2037)
|
||||
|
||||
LLK_DECIMATION = 10
|
||||
RENDER_FRAMES = 15
|
||||
DEFAULT_ITERATIONS = RENDER_FRAMES * LLK_DECIMATION
|
||||
|
||||
|
||||
def generate_liveLocationKalman(location=LOCATION1):
|
||||
msg = messaging.new_message('liveLocationKalman')
|
||||
msg.liveLocationKalman.positionGeodetic = {'value': [*location, 0], 'std': [0., 0., 0.], 'valid': True}
|
||||
msg.liveLocationKalman.positionECEF = {'value': [0., 0., 0.], 'std': [0., 0., 0.], 'valid': True}
|
||||
msg.liveLocationKalman.calibratedOrientationNED = {'value': [0., 0., 0.], 'std': [0., 0., 0.], 'valid': True}
|
||||
msg.liveLocationKalman.velocityCalibrated = {'value': [0., 0., 0.], 'std': [0., 0., 0.], 'valid': True}
|
||||
msg.liveLocationKalman.status = 'valid'
|
||||
msg.liveLocationKalman.gpsOK = True
|
||||
return msg
|
||||
+19
-9
@@ -1,19 +1,29 @@
|
||||
def int_rnd(x):
|
||||
return int(round(x))
|
||||
|
||||
|
||||
def clip(x, lo, hi):
|
||||
return max(lo, min(hi, x))
|
||||
|
||||
|
||||
def interp(x, xp, fp):
|
||||
N = len(xp)
|
||||
|
||||
def get_interp(xv):
|
||||
if not hasattr(x, '__iter__'):
|
||||
hi = 0
|
||||
while hi < N and xv > xp[hi]:
|
||||
while hi < N and x > xp[hi]:
|
||||
hi += 1
|
||||
low = hi - 1
|
||||
return fp[-1] if hi == N and xv > xp[low] else (
|
||||
return fp[-1] if hi == N and x > xp[low] else (
|
||||
fp[0] if hi == 0 else
|
||||
(xv - xp[low]) * (fp[hi] - fp[low]) / (xp[hi] - xp[low]) + fp[low])
|
||||
(x - 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)
|
||||
|
||||
def mean(x):
|
||||
return sum(x) / len(x)
|
||||
result = []
|
||||
for v in x:
|
||||
hi = 0
|
||||
while hi < N and v > xp[hi]:
|
||||
hi += 1
|
||||
low = hi - 1
|
||||
result.append(fp[-1] if hi == N and v > xp[low] else (fp[
|
||||
0] if hi == 0 else (v - xp[low]) * (fp[hi] - fp[low]) / (xp[hi] - xp[low]
|
||||
) + fp[low]))
|
||||
return result
|
||||
|
||||
@@ -1,741 +0,0 @@
|
||||
#include "common/params.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <csignal>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "common/queue.h"
|
||||
#include "common/swaglog.h"
|
||||
#include "common/util.h"
|
||||
#include "system/hardware/hw.h"
|
||||
|
||||
namespace {
|
||||
|
||||
volatile sig_atomic_t params_do_exit = 0;
|
||||
void params_sig_handler(int signal) {
|
||||
params_do_exit = 1;
|
||||
}
|
||||
|
||||
int fsync_dir(const std::string &path) {
|
||||
int result = -1;
|
||||
int fd = HANDLE_EINTR(open(path.c_str(), O_RDONLY, 0755));
|
||||
if (fd >= 0) {
|
||||
result = fsync(fd);
|
||||
close(fd);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool create_params_path(const std::string ¶m_path, const std::string &key_path) {
|
||||
// Make sure params path exists
|
||||
if (!util::file_exists(param_path) && !util::create_directories(param_path, 0775)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// See if the symlink exists, otherwise create it
|
||||
if (!util::file_exists(key_path)) {
|
||||
// 1) Create temp folder
|
||||
// 2) Symlink it to temp link
|
||||
// 3) Move symlink to <params>/d
|
||||
|
||||
std::string tmp_path = param_path + "/.tmp_XXXXXX";
|
||||
// this should be OK since mkdtemp just replaces characters in place
|
||||
char *tmp_dir = mkdtemp((char *)tmp_path.c_str());
|
||||
if (tmp_dir == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string link_path = std::string(tmp_dir) + ".link";
|
||||
if (symlink(tmp_dir, link_path.c_str()) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// don't return false if it has been created by other
|
||||
if (rename(link_path.c_str(), key_path.c_str()) != 0 && errno != EEXIST) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string ensure_params_path(const std::string &prefix, const std::string &path = {}) {
|
||||
std::string params_path = path.empty() ? Path::params() : path;
|
||||
if (!create_params_path(params_path, params_path + prefix)) {
|
||||
throw std::runtime_error(util::string_format(
|
||||
"Failed to ensure params path, errno=%d, path=%s, param_prefix=%s",
|
||||
errno, params_path.c_str(), prefix.c_str()));
|
||||
}
|
||||
return params_path;
|
||||
}
|
||||
|
||||
class FileLock {
|
||||
public:
|
||||
FileLock(const std::string &fn) {
|
||||
if (fn.rfind("/cache", 0) == 0 || fn.rfind("/data/params_backup", 0) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
fd_ = HANDLE_EINTR(open(fn.c_str(), O_CREAT, 0775));
|
||||
if (fd_ < 0 || HANDLE_EINTR(flock(fd_, LOCK_EX)) < 0) {
|
||||
LOGE("Failed to lock file %s, errno=%d", fn.c_str(), errno);
|
||||
}
|
||||
}
|
||||
~FileLock() { close(fd_); }
|
||||
|
||||
private:
|
||||
int fd_ = -1;
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG},
|
||||
{"AlwaysOnDM", PERSISTENT},
|
||||
{"ApiCache_Device", PERSISTENT},
|
||||
{"ApiCache_NavDestinations", PERSISTENT},
|
||||
{"AssistNowToken", PERSISTENT},
|
||||
{"AthenadPid", PERSISTENT},
|
||||
{"AthenadUploadQueue", PERSISTENT},
|
||||
{"AthenadRecentlyViewedRoutes", PERSISTENT},
|
||||
{"BootCount", PERSISTENT},
|
||||
{"CalibrationParams", PERSISTENT},
|
||||
{"CameraDebugExpGain", CLEAR_ON_MANAGER_START},
|
||||
{"CameraDebugExpTime", CLEAR_ON_MANAGER_START},
|
||||
{"CarBatteryCapacity", PERSISTENT},
|
||||
{"CarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"CarParamsCache", CLEAR_ON_MANAGER_START},
|
||||
{"CarParamsPersistent", PERSISTENT},
|
||||
{"CarParamsPrevRoute", PERSISTENT},
|
||||
{"CarVin", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"CompletedTrainingVersion", PERSISTENT},
|
||||
{"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"CurrentBootlog", PERSISTENT},
|
||||
{"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"DisablePowerDown", PERSISTENT},
|
||||
{"DisableUpdates", PERSISTENT},
|
||||
{"DisengageOnAccelerator", PERSISTENT},
|
||||
{"DmModelInitialized", CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"DongleId", PERSISTENT},
|
||||
{"DoReboot", CLEAR_ON_MANAGER_START},
|
||||
{"DoShutdown", CLEAR_ON_MANAGER_START},
|
||||
{"DoUninstall", CLEAR_ON_MANAGER_START},
|
||||
{"ExperimentalLongitudinalEnabled", PERSISTENT | DEVELOPMENT_ONLY},
|
||||
{"ExperimentalMode", PERSISTENT},
|
||||
{"ExperimentalModeConfirmed", PERSISTENT},
|
||||
{"FirmwareQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"ForcePowerDown", PERSISTENT},
|
||||
{"GitBranch", PERSISTENT},
|
||||
{"GitCommit", PERSISTENT},
|
||||
{"GitCommitDate", PERSISTENT},
|
||||
{"GitDiff", PERSISTENT},
|
||||
{"GithubSshKeys", PERSISTENT},
|
||||
{"GithubUsername", PERSISTENT},
|
||||
{"GitRemote", PERSISTENT},
|
||||
{"GsmApn", PERSISTENT},
|
||||
{"GsmMetered", PERSISTENT},
|
||||
{"GsmRoaming", PERSISTENT},
|
||||
{"HardwareSerial", PERSISTENT},
|
||||
{"HasAcceptedTerms", PERSISTENT},
|
||||
{"IMEI", PERSISTENT},
|
||||
{"InstallDate", PERSISTENT},
|
||||
{"IsDriverViewEnabled", CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"IsEngaged", PERSISTENT},
|
||||
{"IsLdwEnabled", PERSISTENT},
|
||||
{"IsMetric", PERSISTENT},
|
||||
{"IsOffroad", CLEAR_ON_MANAGER_START},
|
||||
{"IsOnroad", PERSISTENT},
|
||||
{"IsRhdDetected", PERSISTENT},
|
||||
{"IsReleaseBranch", CLEAR_ON_MANAGER_START},
|
||||
{"IsTakingSnapshot", CLEAR_ON_MANAGER_START},
|
||||
{"IsTestedBranch", CLEAR_ON_MANAGER_START},
|
||||
{"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"LanguageSetting", PERSISTENT},
|
||||
{"LastAthenaPingTime", CLEAR_ON_MANAGER_START},
|
||||
{"LastGPSPosition", PERSISTENT},
|
||||
{"LastManagerExitReason", CLEAR_ON_MANAGER_START},
|
||||
{"LastOffroadStatusPacket", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"LastPowerDropDetected", CLEAR_ON_MANAGER_START},
|
||||
{"LastUpdateException", CLEAR_ON_MANAGER_START},
|
||||
{"LastUpdateTime", PERSISTENT},
|
||||
{"LiveDelay", PERSISTENT},
|
||||
{"LiveParameters", PERSISTENT},
|
||||
{"LiveTorqueParameters", PERSISTENT | DONT_LOG},
|
||||
{"LongitudinalPersonality", PERSISTENT},
|
||||
{"NavDestination", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"NavDestinationWaypoints", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"NavPastDestinations", PERSISTENT},
|
||||
{"NavSettingLeftSide", PERSISTENT},
|
||||
{"NavSettingTime24h", PERSISTENT},
|
||||
{"NetworkMetered", PERSISTENT},
|
||||
{"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"ObdMultiplexingEnabled", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"Offroad_BadNvme", CLEAR_ON_MANAGER_START},
|
||||
{"Offroad_CarUnrecognized", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"Offroad_ConnectivityNeeded", CLEAR_ON_MANAGER_START},
|
||||
{"Offroad_ConnectivityNeededPrompt", CLEAR_ON_MANAGER_START},
|
||||
{"Offroad_IsTakingSnapshot", CLEAR_ON_MANAGER_START},
|
||||
{"Offroad_NeosUpdate", CLEAR_ON_MANAGER_START},
|
||||
{"Offroad_NoFirmware", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"Offroad_Recalibration", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"Offroad_StorageMissing", CLEAR_ON_MANAGER_START},
|
||||
{"Offroad_TemperatureTooHigh", CLEAR_ON_MANAGER_START},
|
||||
{"Offroad_UnofficialHardware", CLEAR_ON_MANAGER_START},
|
||||
{"Offroad_UpdateFailed", CLEAR_ON_MANAGER_START},
|
||||
{"OpenpilotEnabledToggle", PERSISTENT},
|
||||
{"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"PandaSomResetTriggered", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"PandaSignatures", CLEAR_ON_MANAGER_START},
|
||||
{"PrimeType", PERSISTENT},
|
||||
{"RecordFront", PERSISTENT},
|
||||
{"RecordFrontLock", PERSISTENT}, // for the internal fleet
|
||||
{"ReplayControlsState", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"RouteCount", PERSISTENT},
|
||||
{"SecOCKey", PERSISTENT | DONT_LOG},
|
||||
{"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"SshEnabled", PERSISTENT},
|
||||
{"TermsVersion", PERSISTENT},
|
||||
{"Timezone", PERSISTENT},
|
||||
{"TrainingVersion", PERSISTENT},
|
||||
{"UbloxAvailable", PERSISTENT},
|
||||
{"UpdateAvailable", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"UpdateFailedCount", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterAvailableBranches", PERSISTENT},
|
||||
{"UpdaterCurrentDescription", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterCurrentReleaseNotes", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterFetchAvailable", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterNewDescription", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterNewReleaseNotes", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterState", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterTargetBranch", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterLastFetchTime", PERSISTENT},
|
||||
{"Version", PERSISTENT},
|
||||
|
||||
// FrogPilot parameters
|
||||
{"AccelerationPath", PERSISTENT},
|
||||
{"AccelerationProfile", PERSISTENT},
|
||||
{"AdjacentLeadsUI", PERSISTENT},
|
||||
{"AdjacentPath", PERSISTENT},
|
||||
{"AdjacentPathMetrics", PERSISTENT},
|
||||
{"AdvancedCustomUI", PERSISTENT},
|
||||
{"AdvancedLateralTune", PERSISTENT},
|
||||
{"AdvancedLongitudinalTune", PERSISTENT},
|
||||
{"AggressiveFollow", PERSISTENT},
|
||||
{"AggressiveFollowHigh", PERSISTENT},
|
||||
{"AggressiveJerkAcceleration", PERSISTENT},
|
||||
{"AggressiveJerkDanger", PERSISTENT},
|
||||
{"AggressiveJerkDeceleration", PERSISTENT},
|
||||
{"AggressiveJerkSpeed", PERSISTENT},
|
||||
{"AggressiveJerkSpeedDecrease", PERSISTENT},
|
||||
{"AggressivePersonalityProfile", PERSISTENT},
|
||||
{"AlertVolumeControl", PERSISTENT},
|
||||
{"AlwaysOnLateral", PERSISTENT},
|
||||
{"AlwaysOnLateralLKAS", PERSISTENT},
|
||||
{"AlwaysOnLateralMain", PERSISTENT},
|
||||
{"AMapKey1", PERSISTENT | DONT_LOG},
|
||||
{"AMapKey2", PERSISTENT | DONT_LOG},
|
||||
{"ApiCache_DriveStats", PERSISTENT},
|
||||
{"AutomaticallyDownloadModels", PERSISTENT},
|
||||
{"AutomaticUpdates", PERSISTENT},
|
||||
{"AvailableModelNames", PERSISTENT},
|
||||
{"AvailableModelSeries", PERSISTENT},
|
||||
{"AvailableModels", PERSISTENT},
|
||||
{"BigMap", PERSISTENT},
|
||||
{"BlacklistedModels", PERSISTENT},
|
||||
{"BlindSpotMetrics", PERSISTENT},
|
||||
{"BlindSpotPath", PERSISTENT},
|
||||
{"BorderMetrics", PERSISTENT},
|
||||
{"CalibratedLateralAcceleration", PERSISTENT},
|
||||
{"CalibrationProgress", PERSISTENT},
|
||||
{"CameraView", PERSISTENT},
|
||||
{"CancelModelDownload", CLEAR_ON_MANAGER_START},
|
||||
{"CancelThemeDownload", CLEAR_ON_MANAGER_START},
|
||||
{"CarMake", PERSISTENT},
|
||||
{"CarModel", PERSISTENT},
|
||||
{"CarModelName", PERSISTENT},
|
||||
{"CECurves", PERSISTENT},
|
||||
{"CECurvesLead", PERSISTENT},
|
||||
{"CELead", PERSISTENT},
|
||||
{"CEModelStopTime", PERSISTENT},
|
||||
{"CENavigation", PERSISTENT},
|
||||
{"CENavigationIntersections", PERSISTENT},
|
||||
{"CENavigationLead", PERSISTENT},
|
||||
{"CENavigationTurns", PERSISTENT},
|
||||
{"CESignalSpeed", PERSISTENT},
|
||||
{"CESignalLaneDetection", PERSISTENT},
|
||||
{"CESlowerLead", PERSISTENT},
|
||||
{"CESpeed", PERSISTENT},
|
||||
{"CESpeedLead", PERSISTENT},
|
||||
{"CEStatus", CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"CEStoppedLead", PERSISTENT},
|
||||
{"ClusterOffset", PERSISTENT},
|
||||
{"ColorToDownload", CLEAR_ON_MANAGER_START},
|
||||
{"Compass", PERSISTENT},
|
||||
{"ConditionalExperimental", PERSISTENT},
|
||||
{"CurvatureData", PERSISTENT | DONT_LOG},
|
||||
{"CurveSpeedController", PERSISTENT},
|
||||
{"CustomAlerts", PERSISTENT},
|
||||
{"CustomColors", PERSISTENT},
|
||||
{"CustomCruise", PERSISTENT},
|
||||
{"CustomCruiseLong", PERSISTENT},
|
||||
{"CustomDistanceIcons", PERSISTENT},
|
||||
{"CustomIcons", PERSISTENT},
|
||||
{"CustomPersonalities", PERSISTENT},
|
||||
{"CustomSignals", PERSISTENT},
|
||||
{"CustomSounds", PERSISTENT},
|
||||
{"CustomUI", PERSISTENT},
|
||||
{"DebugMode", CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"DecelerationProfile", PERSISTENT},
|
||||
{"DeveloperMetrics", PERSISTENT},
|
||||
{"DeveloperSidebar", PERSISTENT},
|
||||
{"DeveloperSidebarMetric1", PERSISTENT},
|
||||
{"DeveloperSidebarMetric2", PERSISTENT},
|
||||
{"DeveloperSidebarMetric3", PERSISTENT},
|
||||
{"DeveloperSidebarMetric4", PERSISTENT},
|
||||
{"DeveloperSidebarMetric5", PERSISTENT},
|
||||
{"DeveloperSidebarMetric6", PERSISTENT},
|
||||
{"DeveloperSidebarMetric7", PERSISTENT},
|
||||
{"DeveloperWidgets", PERSISTENT},
|
||||
{"DeveloperUI", PERSISTENT},
|
||||
{"DeviceManagement", PERSISTENT},
|
||||
{"DeviceShutdown", PERSISTENT},
|
||||
{"DisableOnroadUploads", PERSISTENT},
|
||||
{"DisableOpenpilotLongitudinal", PERSISTENT},
|
||||
{"DiscordUsername", PERSISTENT},
|
||||
{"DistanceButtonControl", PERSISTENT},
|
||||
{"DistanceIconToDownload", CLEAR_ON_MANAGER_START},
|
||||
{"DisengageVolume", PERSISTENT},
|
||||
{"DoToggleReset", PERSISTENT},
|
||||
{"DoToggleResetStock", PERSISTENT},
|
||||
{"DownloadableColors", PERSISTENT},
|
||||
{"DownloadableDistanceIcons", PERSISTENT},
|
||||
{"DownloadableIcons", PERSISTENT},
|
||||
{"DownloadableSignals", PERSISTENT},
|
||||
{"DownloadableSounds", PERSISTENT},
|
||||
{"DownloadableWheels", PERSISTENT},
|
||||
{"DownloadAllModels", CLEAR_ON_MANAGER_START},
|
||||
{"DriverCamera", PERSISTENT},
|
||||
{"DynamicPathWidth", PERSISTENT},
|
||||
{"DynamicPedalsOnUI", PERSISTENT},
|
||||
{"EngageVolume", PERSISTENT},
|
||||
{"ExperimentalGMTune", PERSISTENT},
|
||||
{"EVTuning", PERSISTENT},
|
||||
{"Fahrenheit", PERSISTENT},
|
||||
{"FavoriteDestinations", PERSISTENT | DONT_LOG},
|
||||
{"FlashPanda", CLEAR_ON_MANAGER_START},
|
||||
{"ForceAutoTune", PERSISTENT},
|
||||
{"ForceAutoTuneOff", PERSISTENT},
|
||||
{"ForceFingerprint", PERSISTENT},
|
||||
{"ForceMPHDashboard", PERSISTENT},
|
||||
{"ForceOffroad", CLEAR_ON_MANAGER_START},
|
||||
{"ForceOnroad", CLEAR_ON_MANAGER_START},
|
||||
{"ForceStops", PERSISTENT},
|
||||
{"ForceTorqueController", PERSISTENT},
|
||||
{"FPSCounter", PERSISTENT},
|
||||
{"FrogPilotCarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"FrogPilotCarParamsPersistent", PERSISTENT},
|
||||
{"FrogPilotDongleId", PERSISTENT | DONT_LOG},
|
||||
{"FrogPilotDrives", PERSISTENT},
|
||||
{"FrogPilotKilometers", PERSISTENT},
|
||||
{"FrogPilotMinutes", PERSISTENT},
|
||||
{"FrogPilotStats", PERSISTENT | DONT_LOG},
|
||||
{"FrogPilotToggles", CLEAR_ON_MANAGER_START},
|
||||
{"FrogPilotTogglesUpdated", CLEAR_ON_MANAGER_START},
|
||||
{"FrogPilotTuningLevels", CLEAR_ON_MANAGER_START},
|
||||
{"FrogsGoMoosTweak", PERSISTENT},
|
||||
{"FullMap", PERSISTENT},
|
||||
{"GasRegenCmd", PERSISTENT},
|
||||
{"GMPedalLongitudinal", PERSISTENT},
|
||||
{"GoatScream", PERSISTENT},
|
||||
{"GreenLightAlert", PERSISTENT},
|
||||
{"HideAlerts", PERSISTENT},
|
||||
{"HideLeadMarker", PERSISTENT},
|
||||
{"HideMap", PERSISTENT},
|
||||
{"HideMapIcon", PERSISTENT},
|
||||
{"HideMaxSpeed", PERSISTENT},
|
||||
{"HideSpeed", PERSISTENT},
|
||||
{"HideSpeedLimit", PERSISTENT},
|
||||
{"HigherBitrate", PERSISTENT},
|
||||
{"HolidayThemes", PERSISTENT},
|
||||
{"HumanAcceleration", PERSISTENT},
|
||||
{"HumanFollowing", PERSISTENT},
|
||||
{"IconToDownload", CLEAR_ON_MANAGER_START},
|
||||
{"IncreasedStoppedDistance", PERSISTENT},
|
||||
{"IncreaseThermalLimits", PERSISTENT},
|
||||
{"IssueReported", CLEAR_ON_MANAGER_START},
|
||||
{"KonikDongleId", PERSISTENT},
|
||||
{"KonikMinutes", PERSISTENT},
|
||||
{"LaneChanges", PERSISTENT},
|
||||
{"LaneChangeTime", PERSISTENT},
|
||||
{"LaneDetectionWidth", PERSISTENT},
|
||||
{"LaneLinesWidth", PERSISTENT},
|
||||
{"LastMapsUpdate", PERSISTENT},
|
||||
{"LateralTune", PERSISTENT},
|
||||
{"LeadDepartingAlert", PERSISTENT},
|
||||
{"LeadDetectionThreshold", PERSISTENT},
|
||||
{"LeadInfo", PERSISTENT},
|
||||
{"LKASButtonControl", PERSISTENT},
|
||||
{"LockDoors", PERSISTENT},
|
||||
{"LockDoorsTimer", PERSISTENT},
|
||||
{"LongDistanceButtonControl", PERSISTENT},
|
||||
{"LongitudinalActuatorDelay", PERSISTENT},
|
||||
{"LongitudinalActuatorDelayStock", PERSISTENT},
|
||||
{"LongitudinalTune", PERSISTENT},
|
||||
{"LongPitch", PERSISTENT},
|
||||
{"LoudBlindspotAlert", PERSISTENT},
|
||||
{"LowVoltageShutdown", PERSISTENT},
|
||||
{"ManualUpdateInitiated", CLEAR_ON_MANAGER_START},
|
||||
{"MapAcceleration", PERSISTENT},
|
||||
{"MapboxPublicKey", PERSISTENT | DONT_LOG},
|
||||
{"MapBoxRequests", PERSISTENT},
|
||||
{"MapboxSecretKey", PERSISTENT | DONT_LOG},
|
||||
{"MapDeceleration", PERSISTENT},
|
||||
{"MapdLogLevel", CLEAR_ON_MANAGER_START},
|
||||
{"MapGears", PERSISTENT},
|
||||
{"MapsSelected", PERSISTENT},
|
||||
{"MapSpeedLimit", CLEAR_ON_MANAGER_START},
|
||||
{"MapStyle", PERSISTENT},
|
||||
{"MaxDesiredAcceleration", PERSISTENT},
|
||||
{"MinimumBackupSize", PERSISTENT},
|
||||
{"MinimumLaneChangeSpeed", PERSISTENT},
|
||||
{"Model", PERSISTENT},
|
||||
{"ModelVersion", PERSISTENT},
|
||||
{"ModelDownloadProgress", CLEAR_ON_MANAGER_START},
|
||||
{"ModelDrivesAndScores", PERSISTENT},
|
||||
{"ModelRandomizer", PERSISTENT},
|
||||
{"ModelToDownload", CLEAR_ON_MANAGER_START},
|
||||
{"ModelUI", PERSISTENT},
|
||||
{"ModelVersions", PERSISTENT},
|
||||
{"ModelReleasedDates", PERSISTENT},
|
||||
{"CommunityFavorites", PERSISTENT},
|
||||
{"UserFavorites", PERSISTENT},
|
||||
{"SortModelsByDate", PERSISTENT},
|
||||
{"NavigationUI", PERSISTENT},
|
||||
{"NextMapSpeedLimit", CLEAR_ON_MANAGER_START},
|
||||
{"NewLongAPI", PERSISTENT},
|
||||
{"NNFF", PERSISTENT},
|
||||
{"NNFFLite", PERSISTENT},
|
||||
{"NNFFModelName", CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"NoLogging", PERSISTENT},
|
||||
{"NoUploads", PERSISTENT},
|
||||
{"NudgelessLaneChange", PERSISTENT},
|
||||
{"NumericalTemp", PERSISTENT},
|
||||
{"Offset1", PERSISTENT},
|
||||
{"Offset2", PERSISTENT},
|
||||
{"Offset3", PERSISTENT},
|
||||
{"Offset4", PERSISTENT},
|
||||
{"Offset5", PERSISTENT},
|
||||
{"Offset6", PERSISTENT},
|
||||
{"Offset7", PERSISTENT},
|
||||
{"OneLaneChange", PERSISTENT},
|
||||
{"OnroadDistanceButton", PERSISTENT},
|
||||
{"OnroadDistanceButtonPressed", CLEAR_ON_MANAGER_START},
|
||||
{"openpilotMinutes", PERSISTENT},
|
||||
{"OSMDownloadBounds", PERSISTENT},
|
||||
{"OSMDownloadLocations", PERSISTENT},
|
||||
{"OSMDownloadProgress", CLEAR_ON_MANAGER_START},
|
||||
{"OverpassRequests", PERSISTENT},
|
||||
{"PathEdgeWidth", PERSISTENT},
|
||||
{"PathWidth", PERSISTENT},
|
||||
{"PauseAOLOnBrake", PERSISTENT},
|
||||
{"PauseLateralOnSignal", PERSISTENT},
|
||||
{"PauseLateralSpeed", PERSISTENT},
|
||||
{"PedalsOnUI", PERSISTENT},
|
||||
{"PersonalizeOpenpilot", PERSISTENT},
|
||||
{"PreferredSchedule", PERSISTENT},
|
||||
{"PreviousSpeedLimit", PERSISTENT},
|
||||
{"PromptDistractedVolume", PERSISTENT},
|
||||
{"PromptVolume", PERSISTENT},
|
||||
{"QOLLateral", PERSISTENT},
|
||||
{"QOLLongitudinal", PERSISTENT},
|
||||
{"QOLVisuals", PERSISTENT},
|
||||
{"RadarTracksUI", PERSISTENT},
|
||||
{"RainbowPath", PERSISTENT},
|
||||
{"RandomEvents", PERSISTENT},
|
||||
{"RandomThemes", PERSISTENT},
|
||||
{"RefuseVolume", PERSISTENT},
|
||||
{"RelaxedFollow", PERSISTENT},
|
||||
{"RelaxedFollowHigh", PERSISTENT},
|
||||
{"RelaxedJerkAcceleration", PERSISTENT},
|
||||
{"RelaxedJerkDanger", PERSISTENT},
|
||||
{"RelaxedJerkDeceleration", PERSISTENT},
|
||||
{"RelaxedJerkSpeed", PERSISTENT},
|
||||
{"RelaxedJerkSpeedDecrease", PERSISTENT},
|
||||
{"RelaxedPersonalityProfile", PERSISTENT},
|
||||
{"ReverseCruise", PERSISTENT},
|
||||
{"RoadEdgesWidth", PERSISTENT},
|
||||
{"RoadName", CLEAR_ON_MANAGER_START},
|
||||
{"RoadNameUI", PERSISTENT},
|
||||
{"RotatingWheel", PERSISTENT},
|
||||
{"ScreenBrightness", PERSISTENT},
|
||||
{"ScreenBrightnessOnroad", PERSISTENT},
|
||||
{"ScreenManagement", PERSISTENT},
|
||||
{"ScreenRecorder", PERSISTENT},
|
||||
{"ScreenTimeout", PERSISTENT},
|
||||
{"ScreenTimeoutOnroad", PERSISTENT},
|
||||
{"SearchInput", PERSISTENT},
|
||||
{"SecOCKeys", PERSISTENT | DONT_LOG},
|
||||
{"SetSpeedLimit", PERSISTENT},
|
||||
{"SetSpeedOffset", PERSISTENT},
|
||||
{"ShowCEMStatus", PERSISTENT},
|
||||
{"ShowCPU", PERSISTENT},
|
||||
{"ShowCSCStatus", PERSISTENT},
|
||||
{"ShowGPU", PERSISTENT},
|
||||
{"ShowIP", PERSISTENT},
|
||||
{"ShowMemoryUsage", PERSISTENT},
|
||||
{"ShownToggleDescriptions", PERSISTENT},
|
||||
{"ShowSLCOffset", PERSISTENT},
|
||||
{"ShowSpeedLimits", PERSISTENT},
|
||||
{"ShowSteering", PERSISTENT},
|
||||
{"ShowStoppingPoint", PERSISTENT},
|
||||
{"ShowStoppingPointMetrics", PERSISTENT},
|
||||
{"ShowStorageLeft", PERSISTENT},
|
||||
{"ShowStorageUsed", PERSISTENT},
|
||||
{"Sidebar", PERSISTENT},
|
||||
{"SignalMetrics", PERSISTENT},
|
||||
{"SignalToDownload", CLEAR_ON_MANAGER_START},
|
||||
{"SLCConfirmation", PERSISTENT},
|
||||
{"SLCConfirmationHigher", PERSISTENT},
|
||||
{"SLCConfirmationLower", PERSISTENT},
|
||||
{"SLCFallback", PERSISTENT},
|
||||
{"SLCLookaheadHigher", PERSISTENT},
|
||||
{"SLCLookaheadLower", PERSISTENT},
|
||||
{"SLCMapboxFiller", PERSISTENT},
|
||||
{"SLCOverride", PERSISTENT},
|
||||
{"SLCPriority1", PERSISTENT},
|
||||
{"SLCPriority2", PERSISTENT},
|
||||
{"SLCPriority3", PERSISTENT},
|
||||
{"SNGHack", PERSISTENT},
|
||||
{"SoundToDownload", CLEAR_ON_MANAGER_START},
|
||||
{"SpeedLimitAccepted", CLEAR_ON_MANAGER_START},
|
||||
{"SpeedLimitChangedAlert", PERSISTENT},
|
||||
{"SpeedLimitController", PERSISTENT},
|
||||
{"SpeedLimitFiller", PERSISTENT},
|
||||
{"SpeedLimits", PERSISTENT | DONT_LOG},
|
||||
{"SpeedLimitsFiltered", PERSISTENT | DONT_LOG},
|
||||
{"SpeedLimitSources", PERSISTENT},
|
||||
{"StandardFollow", PERSISTENT},
|
||||
{"StandardFollowHigh", PERSISTENT},
|
||||
{"StandardJerkAcceleration", PERSISTENT},
|
||||
{"StandardJerkDanger", PERSISTENT},
|
||||
{"StandardJerkDeceleration", PERSISTENT},
|
||||
{"StandardJerkSpeed", PERSISTENT},
|
||||
{"StandardJerkSpeedDecrease", PERSISTENT},
|
||||
{"StandardPersonalityProfile", PERSISTENT},
|
||||
{"StandbyMode", PERSISTENT},
|
||||
{"StartAccel", PERSISTENT},
|
||||
{"StartAccelStock", PERSISTENT},
|
||||
{"StartupMessageBottom", PERSISTENT},
|
||||
{"StartupMessageTop", PERSISTENT},
|
||||
{"StaticPedalsOnUI", PERSISTENT},
|
||||
{"SteerDelay", PERSISTENT},
|
||||
{"SteerDelayStock", PERSISTENT},
|
||||
{"SteerFriction", PERSISTENT},
|
||||
{"SteerFrictionStock", PERSISTENT},
|
||||
{"SteerOffset", PERSISTENT},
|
||||
{"SteerOffsetStock", PERSISTENT},
|
||||
{"SteerLatAccel", PERSISTENT},
|
||||
{"SteerLatAccelStock", PERSISTENT},
|
||||
{"SteerKP", PERSISTENT},
|
||||
{"SteerKPStock", PERSISTENT},
|
||||
{"SteerRatio", PERSISTENT},
|
||||
{"SteerRatioStock", PERSISTENT},
|
||||
{"StockDongleId", PERSISTENT},
|
||||
{"StopAccel", PERSISTENT},
|
||||
{"StopAccelStock", PERSISTENT},
|
||||
{"StoppingDecelRate", PERSISTENT},
|
||||
{"StoppingDecelRateStock", PERSISTENT},
|
||||
{"StoppedTimer", PERSISTENT},
|
||||
{"TacoTune", PERSISTENT},
|
||||
{"TacoTuneHacks", PERSISTENT},
|
||||
{"TrailerLoad", PERSISTENT},
|
||||
{"TestAlert", CLEAR_ON_MANAGER_START},
|
||||
{"TetheringEnabled", PERSISTENT},
|
||||
{"ThemeDownloadProgress", CLEAR_ON_MANAGER_START},
|
||||
{"ThemesDownloaded", PERSISTENT},
|
||||
{"TinygradUpdateAvailable", PERSISTENT},
|
||||
{"TogglesUpdated", PERSISTENT},
|
||||
{"ToyotaDoors", PERSISTENT},
|
||||
{"TrafficFollow", PERSISTENT},
|
||||
{"TrafficJerkAcceleration", PERSISTENT},
|
||||
{"TrafficJerkDanger", PERSISTENT},
|
||||
{"TrafficJerkDeceleration", PERSISTENT},
|
||||
{"TrafficJerkSpeed", PERSISTENT},
|
||||
{"TrafficJerkSpeedDecrease", PERSISTENT},
|
||||
{"TrafficPersonalityProfile", PERSISTENT},
|
||||
{"TuningLevel", PERSISTENT},
|
||||
{"TuningLevelConfirmed", PERSISTENT},
|
||||
{"TurnDesires", PERSISTENT},
|
||||
{"UnlimitedLength", PERSISTENT},
|
||||
{"UnlockDoors", PERSISTENT},
|
||||
{"Updated", PERSISTENT},
|
||||
{"UpdateSpeedLimits", CLEAR_ON_MANAGER_START},
|
||||
{"UpdateSpeedLimitsStatus", CLEAR_ON_MANAGER_START},
|
||||
{"UpdateTinygrad", CLEAR_ON_MANAGER_START},
|
||||
{"UpdateWheelImage", CLEAR_ON_MANAGER_START},
|
||||
{"UseActiveTheme", CLEAR_ON_MANAGER_START},
|
||||
{"UseKonikServer", PERSISTENT},
|
||||
{"UseSI", PERSISTENT},
|
||||
{"UseVienna", PERSISTENT},
|
||||
{"VEgoStarting", PERSISTENT},
|
||||
{"VEgoStartingStock", PERSISTENT},
|
||||
{"VEgoStopping", PERSISTENT},
|
||||
{"VEgoStoppingStock", PERSISTENT},
|
||||
{"VeryLongDistanceButtonControl", PERSISTENT},
|
||||
{"VoltSNG", PERSISTENT},
|
||||
{"WarningImmediateVolume", PERSISTENT},
|
||||
{"WarningSoftVolume", PERSISTENT},
|
||||
{"WheelIcon", PERSISTENT},
|
||||
{"WheelSpeed", PERSISTENT},
|
||||
{"StopDistance", PERSISTENT},
|
||||
{"RecoveryPower", PERSISTENT},
|
||||
{"WheelToDownload", CLEAR_ON_MANAGER_START},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
Params::Params(const std::string &path) {
|
||||
params_prefix = "/" + util::getenv("OPENPILOT_PREFIX", "d");
|
||||
params_path = ensure_params_path(params_prefix, path);
|
||||
}
|
||||
|
||||
Params::~Params() {
|
||||
if (future.valid()) {
|
||||
future.wait();
|
||||
}
|
||||
assert(queue.empty());
|
||||
}
|
||||
|
||||
std::vector<std::string> Params::allKeys() const {
|
||||
std::vector<std::string> ret;
|
||||
for (auto &p : keys) {
|
||||
ret.push_back(p.first);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Params::checkKey(const std::string &key) {
|
||||
return keys.find(key) != keys.end();
|
||||
}
|
||||
|
||||
ParamKeyType Params::getKeyType(const std::string &key) {
|
||||
return static_cast<ParamKeyType>(keys[key]);
|
||||
}
|
||||
|
||||
int Params::put(const char* key, const char* value, size_t value_size) {
|
||||
// Information about safely and atomically writing a file: https://lwn.net/Articles/457667/
|
||||
// 1) Create temp file
|
||||
// 2) Write data to temp file
|
||||
// 3) fsync() the temp file
|
||||
// 4) rename the temp file to the real name
|
||||
// 5) fsync() the containing directory
|
||||
std::string tmp_path = params_path + "/.tmp_value_XXXXXX";
|
||||
int tmp_fd = mkstemp((char*)tmp_path.c_str());
|
||||
if (tmp_fd < 0) return -1;
|
||||
|
||||
int result = -1;
|
||||
do {
|
||||
// Write value to temp.
|
||||
ssize_t bytes_written = HANDLE_EINTR(write(tmp_fd, value, value_size));
|
||||
if (bytes_written < 0 || (size_t)bytes_written != value_size) {
|
||||
result = -20;
|
||||
break;
|
||||
}
|
||||
|
||||
// fsync to force persist the changes.
|
||||
if ((result = fsync(tmp_fd)) < 0) break;
|
||||
|
||||
FileLock file_lock(params_path + "/.lock");
|
||||
|
||||
// Move temp into place.
|
||||
if ((result = rename(tmp_path.c_str(), getParamPath(key).c_str())) < 0) break;
|
||||
|
||||
// fsync parent directory
|
||||
result = fsync_dir(getParamPath());
|
||||
} while (false);
|
||||
|
||||
close(tmp_fd);
|
||||
if (result != 0) {
|
||||
::unlink(tmp_path.c_str());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int Params::remove(const std::string &key) {
|
||||
FileLock file_lock(params_path + "/.lock");
|
||||
int result = unlink(getParamPath(key).c_str());
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
return fsync_dir(getParamPath());
|
||||
}
|
||||
|
||||
std::string Params::get(const std::string &key, bool block) {
|
||||
if (!block) {
|
||||
return util::read_file(getParamPath(key));
|
||||
} else {
|
||||
// blocking read until successful
|
||||
params_do_exit = 0;
|
||||
void (*prev_handler_sigint)(int) = std::signal(SIGINT, params_sig_handler);
|
||||
void (*prev_handler_sigterm)(int) = std::signal(SIGTERM, params_sig_handler);
|
||||
|
||||
std::string value;
|
||||
while (!params_do_exit) {
|
||||
if (value = util::read_file(getParamPath(key)); !value.empty()) {
|
||||
break;
|
||||
}
|
||||
util::sleep_for(100); // 0.1 s
|
||||
}
|
||||
|
||||
std::signal(SIGINT, prev_handler_sigint);
|
||||
std::signal(SIGTERM, prev_handler_sigterm);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> Params::readAll() {
|
||||
FileLock file_lock(params_path + "/.lock");
|
||||
return util::read_files_in_dir(getParamPath());
|
||||
}
|
||||
|
||||
void Params::clearAll(ParamKeyType key_type) {
|
||||
FileLock file_lock(params_path + "/.lock");
|
||||
|
||||
// 1) delete params of key_type
|
||||
// 2) delete files that are not defined in the keys.
|
||||
if (DIR *d = opendir(getParamPath().c_str())) {
|
||||
struct dirent *de = NULL;
|
||||
while ((de = readdir(d))) {
|
||||
if (de->d_type != DT_DIR) {
|
||||
auto it = keys.find(de->d_name);
|
||||
if (it == keys.end() || (it->second & key_type)) {
|
||||
unlink(getParamPath(de->d_name).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
|
||||
fsync_dir(getParamPath());
|
||||
}
|
||||
|
||||
void Params::putNonBlocking(const std::string &key, const std::string &val) {
|
||||
queue.push(std::make_pair(key, val));
|
||||
// start thread on demand
|
||||
if (!future.valid() || future.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready) {
|
||||
future = std::async(std::launch::async, &Params::asyncWriteThread, this);
|
||||
}
|
||||
}
|
||||
|
||||
void Params::asyncWriteThread() {
|
||||
// TODO: write the latest one if a key has multiple values in the queue.
|
||||
std::pair<std::string, std::string> p;
|
||||
while (queue.try_pop(p, 0)) {
|
||||
// Params::put is Thread-Safe
|
||||
put(p.first, p.second);
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <future>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "common/queue.h"
|
||||
|
||||
enum ParamKeyType {
|
||||
PERSISTENT = 0x02,
|
||||
CLEAR_ON_MANAGER_START = 0x04,
|
||||
CLEAR_ON_ONROAD_TRANSITION = 0x08,
|
||||
CLEAR_ON_OFFROAD_TRANSITION = 0x10,
|
||||
DONT_LOG = 0x20,
|
||||
DEVELOPMENT_ONLY = 0x40,
|
||||
ALL = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
class Params {
|
||||
public:
|
||||
explicit Params(const std::string &path = {});
|
||||
~Params();
|
||||
// Not copyable.
|
||||
Params(const Params&) = delete;
|
||||
Params& operator=(const Params&) = delete;
|
||||
|
||||
std::vector<std::string> allKeys() const;
|
||||
bool checkKey(const std::string &key);
|
||||
ParamKeyType getKeyType(const std::string &key);
|
||||
inline std::string getParamPath(const std::string &key = {}) {
|
||||
return params_path + params_prefix + (key.empty() ? "" : "/" + key);
|
||||
}
|
||||
|
||||
// Delete a value
|
||||
int remove(const std::string &key);
|
||||
void clearAll(ParamKeyType type);
|
||||
|
||||
// helpers for reading values
|
||||
std::string get(const std::string &key, bool block = false);
|
||||
inline bool getBool(const std::string &key, bool block = false) {
|
||||
return get(key, block) == "1";
|
||||
}
|
||||
inline int getInt(const std::string &key, bool block = false) {
|
||||
std::string value = get(key, block);
|
||||
return value.empty() ? 0 : std::stoi(value);
|
||||
}
|
||||
inline float getFloat(const std::string &key, bool block = false) {
|
||||
std::string value = get(key, block);
|
||||
return value.empty() ? 0.0 : std::stof(value);
|
||||
}
|
||||
std::map<std::string, std::string> readAll();
|
||||
|
||||
// helpers for writing values
|
||||
int put(const char *key, const char *val, size_t value_size);
|
||||
inline int put(const std::string &key, const std::string &val) {
|
||||
return put(key.c_str(), val.data(), val.size());
|
||||
}
|
||||
inline int putBool(const std::string &key, bool val) {
|
||||
return put(key.c_str(), val ? "1" : "0", 1);
|
||||
}
|
||||
inline int putInt(const std::string &key, int val) {
|
||||
return put(key.c_str(), std::to_string(val).c_str(), std::to_string(val).size());
|
||||
}
|
||||
inline int putFloat(const std::string &key, float val) {
|
||||
return put(key.c_str(), std::to_string(val).c_str(), std::to_string(val).size());
|
||||
}
|
||||
void putNonBlocking(const std::string &key, const std::string &val);
|
||||
inline void putBoolNonBlocking(const std::string &key, bool val) {
|
||||
putNonBlocking(key, val ? "1" : "0");
|
||||
}
|
||||
inline void putIntNonBlocking(const std::string &key, int val) {
|
||||
putNonBlocking(key, std::to_string(val));
|
||||
}
|
||||
inline void putFloatNonBlocking(const std::string &key, float val) {
|
||||
putNonBlocking(key, std::to_string(val));
|
||||
}
|
||||
|
||||
private:
|
||||
void asyncWriteThread();
|
||||
|
||||
std::string params_path;
|
||||
std::string params_prefix;
|
||||
|
||||
// for nonblocking write
|
||||
std::future<void> future;
|
||||
SafeQueue<std::pair<std::string, std::string>> queue;
|
||||
};
|
||||
Regular → Executable
+326
-14
@@ -1,18 +1,330 @@
|
||||
from openpilot.common.params_pyx import Params, ParamKeyType, UnknownKeyName
|
||||
assert Params
|
||||
assert ParamKeyType
|
||||
assert UnknownKeyName
|
||||
#!/usr/bin/env python
|
||||
"""ROS has a parameter server, we have files.
|
||||
|
||||
The parameter store is a persistent key value store, implemented as a directory with a writer lock.
|
||||
On Android, we store params under params_dir = /data/params. The writer lock is a file
|
||||
"<params_dir>/.lock" taken using flock(), and data is stored in a directory symlinked to by
|
||||
"<params_dir>/d".
|
||||
|
||||
Each key, value pair is stored as a file with named <key> with contents <value>, located in
|
||||
<params_dir>/d/<key>
|
||||
|
||||
Readers of a single key can just open("<params_dir>/d/<key>") and read the file contents.
|
||||
Readers who want a consistent snapshot of multiple keys should take the lock.
|
||||
|
||||
Writers should take the lock before modifying anything. Writers should also leave the DB in a
|
||||
consistent state after a crash. The implementation below does this by copying all params to a temp
|
||||
directory <params_dir>/<tmp>, then atomically symlinking <params_dir>/<d> to <params_dir>/<tmp>
|
||||
before deleting the old <params_dir>/<d> directory.
|
||||
|
||||
Writers that only modify a single key can simply take the lock, then swap the corresponding value
|
||||
file in place without messing with <params_dir>/d.
|
||||
"""
|
||||
import time
|
||||
import os
|
||||
import errno
|
||||
import sys
|
||||
import shutil
|
||||
import fcntl
|
||||
import tempfile
|
||||
from enum import Enum
|
||||
|
||||
def mkdirs_exists_ok(path):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError:
|
||||
if not os.path.isdir(path):
|
||||
raise
|
||||
|
||||
class TxType(Enum):
|
||||
PERSISTANT = 1
|
||||
CLEAR_ON_MANAGER_START = 2
|
||||
CLEAR_ON_CAR_START = 3
|
||||
|
||||
class UnknownKeyName(Exception):
|
||||
pass
|
||||
|
||||
keys = {
|
||||
# written: manager
|
||||
# read: loggerd, uploaderd, baseui
|
||||
"DongleId": TxType.PERSISTANT,
|
||||
"AccessToken": TxType.PERSISTANT,
|
||||
"Version": TxType.PERSISTANT,
|
||||
"GitCommit": TxType.PERSISTANT,
|
||||
"GitBranch": TxType.PERSISTANT,
|
||||
"GitRemote": TxType.PERSISTANT,
|
||||
# written: baseui
|
||||
# read: ui, controls
|
||||
"IsMetric": TxType.PERSISTANT,
|
||||
"IsRearViewMirror": TxType.PERSISTANT,
|
||||
"IsFcwEnabled": TxType.PERSISTANT,
|
||||
"HasAcceptedTerms": TxType.PERSISTANT,
|
||||
"IsUploadVideoOverCellularEnabled": TxType.PERSISTANT,
|
||||
# written: visiond
|
||||
# read: visiond, controlsd
|
||||
"CalibrationParams": TxType.PERSISTANT,
|
||||
# written: visiond
|
||||
# read: visiond, ui
|
||||
"CloudCalibration": TxType.PERSISTANT,
|
||||
# written: controlsd
|
||||
# read: radard
|
||||
"CarParams": TxType.CLEAR_ON_CAR_START,
|
||||
|
||||
"Passive": TxType.PERSISTANT,
|
||||
"DoUninstall": TxType.CLEAR_ON_MANAGER_START,
|
||||
}
|
||||
|
||||
def fsync_dir(path):
|
||||
fd = os.open(path, os.O_RDONLY)
|
||||
try:
|
||||
os.fsync(fd)
|
||||
finally:
|
||||
os.close(fd)
|
||||
|
||||
|
||||
class FileLock(object):
|
||||
def __init__(self, path, create):
|
||||
self._path = path
|
||||
self._create = create
|
||||
self._fd = None
|
||||
|
||||
def acquire(self):
|
||||
self._fd = os.open(self._path, os.O_CREAT if self._create else 0)
|
||||
fcntl.flock(self._fd, fcntl.LOCK_EX)
|
||||
|
||||
def release(self):
|
||||
if self._fd is not None:
|
||||
os.close(self._fd)
|
||||
self._fd = None
|
||||
|
||||
|
||||
class DBAccessor(object):
|
||||
def __init__(self, path):
|
||||
self._path = path
|
||||
self._vals = None
|
||||
|
||||
def keys(self):
|
||||
self._check_entered()
|
||||
return self._vals.keys()
|
||||
|
||||
def get(self, key):
|
||||
self._check_entered()
|
||||
try:
|
||||
return self._vals[key]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def _get_lock(self, create):
|
||||
lock = FileLock(os.path.join(self._path, ".lock"), create)
|
||||
lock.acquire()
|
||||
return lock
|
||||
|
||||
def _read_values_locked(self):
|
||||
"""Callers should hold a lock while calling this method."""
|
||||
vals = {}
|
||||
try:
|
||||
data_path = self._data_path()
|
||||
keys = os.listdir(data_path)
|
||||
for key in keys:
|
||||
with open(os.path.join(data_path, key), "rb") as f:
|
||||
vals[key] = f.read()
|
||||
except (OSError, IOError) as e:
|
||||
# Either the DB hasn't been created yet, or somebody wrote a bug and left the DB in an
|
||||
# inconsistent state. Either way, return empty.
|
||||
if e.errno == errno.ENOENT:
|
||||
return {}
|
||||
|
||||
return vals
|
||||
|
||||
def _data_path(self):
|
||||
return os.path.join(self._path, "d")
|
||||
|
||||
def _check_entered(self):
|
||||
if self._vals is None:
|
||||
raise Exception("Must call __enter__ before using DB")
|
||||
|
||||
|
||||
class DBReader(DBAccessor):
|
||||
def __enter__(self):
|
||||
try:
|
||||
lock = self._get_lock(False)
|
||||
except OSError as e:
|
||||
# Do not create lock if it does not exist.
|
||||
if e.errno == errno.ENOENT:
|
||||
self._vals = {}
|
||||
return self
|
||||
|
||||
try:
|
||||
# Read everything.
|
||||
self._vals = self._read_values_locked()
|
||||
return self
|
||||
finally:
|
||||
lock.release()
|
||||
|
||||
def __exit__(self, type, value, traceback): pass
|
||||
|
||||
|
||||
class DBWriter(DBAccessor):
|
||||
def __init__(self, path):
|
||||
super(DBWriter, self).__init__(path)
|
||||
self._lock = None
|
||||
self._prev_umask = None
|
||||
|
||||
def put(self, key, value):
|
||||
self._vals[key] = value
|
||||
|
||||
def delete(self, key):
|
||||
self._vals.pop(key, None)
|
||||
|
||||
def __enter__(self):
|
||||
mkdirs_exists_ok(self._path)
|
||||
|
||||
# Make sure we can write and that permissions are correct.
|
||||
self._prev_umask = os.umask(0)
|
||||
|
||||
try:
|
||||
os.chmod(self._path, 0o777)
|
||||
self._lock = self._get_lock(True)
|
||||
self._vals = self._read_values_locked()
|
||||
except:
|
||||
os.umask(self._prev_umask)
|
||||
self._prev_umask = None
|
||||
raise
|
||||
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
self._check_entered()
|
||||
|
||||
try:
|
||||
# data_path refers to the externally used path to the params. It is a symlink.
|
||||
# old_data_path is the path currently pointed to by data_path.
|
||||
# tempdir_path is a path where the new params will go, which the new data path will point to.
|
||||
# new_data_path is a temporary symlink that will atomically overwrite data_path.
|
||||
#
|
||||
# The current situation is:
|
||||
# data_path -> old_data_path
|
||||
# We're going to write params data to tempdir_path
|
||||
# tempdir_path -> params data
|
||||
# Then point new_data_path to tempdir_path
|
||||
# new_data_path -> tempdir_path
|
||||
# Then atomically overwrite data_path with new_data_path
|
||||
# data_path -> tempdir_path
|
||||
old_data_path = None
|
||||
new_data_path = None
|
||||
tempdir_path = tempfile.mkdtemp(prefix=".tmp", dir=self._path)
|
||||
|
||||
try:
|
||||
# Write back all keys.
|
||||
os.chmod(tempdir_path, 0o777)
|
||||
for k, v in self._vals.items():
|
||||
with open(os.path.join(tempdir_path, k), "wb") as f:
|
||||
f.write(v)
|
||||
f.flush()
|
||||
os.fsync(f.fileno())
|
||||
fsync_dir(tempdir_path)
|
||||
|
||||
data_path = self._data_path()
|
||||
try:
|
||||
old_data_path = os.path.join(self._path, os.readlink(data_path))
|
||||
except (OSError, IOError) as e:
|
||||
# NOTE(mgraczyk): If other DB implementations have bugs, this could cause
|
||||
# copies to be left behind, but we still want to overwrite.
|
||||
pass
|
||||
|
||||
new_data_path = "{}.link".format(tempdir_path)
|
||||
os.symlink(os.path.basename(tempdir_path), new_data_path)
|
||||
os.rename(new_data_path, data_path)
|
||||
fsync_dir(self._path)
|
||||
finally:
|
||||
# If the rename worked, we can delete the old data. Otherwise delete the new one.
|
||||
success = new_data_path is not None and os.path.exists(data_path) and (
|
||||
os.readlink(data_path) == os.path.basename(tempdir_path))
|
||||
|
||||
if success:
|
||||
if old_data_path is not None:
|
||||
shutil.rmtree(old_data_path)
|
||||
else:
|
||||
shutil.rmtree(tempdir_path)
|
||||
|
||||
# Regardless of what happened above, there should be no link at new_data_path.
|
||||
if new_data_path is not None and os.path.islink(new_data_path):
|
||||
os.remove(new_data_path)
|
||||
finally:
|
||||
os.umask(self._prev_umask)
|
||||
self._prev_umask = None
|
||||
|
||||
# Always release the lock.
|
||||
self._lock.release()
|
||||
self._lock = None
|
||||
|
||||
|
||||
|
||||
class JSDB(object):
|
||||
def __init__(self, fn):
|
||||
self._fn = fn
|
||||
|
||||
def begin(self, write=False):
|
||||
if write:
|
||||
return DBWriter(self._fn)
|
||||
else:
|
||||
return DBReader(self._fn)
|
||||
|
||||
class Params(object):
|
||||
def __init__(self, db='/data/params'):
|
||||
self.env = JSDB(db)
|
||||
|
||||
def _clear_keys_with_type(self, tx_type):
|
||||
with self.env.begin(write=True) as txn:
|
||||
for key in keys:
|
||||
if keys[key] == tx_type:
|
||||
txn.delete(key)
|
||||
|
||||
def manager_start(self):
|
||||
self._clear_keys_with_type(TxType.CLEAR_ON_MANAGER_START)
|
||||
|
||||
def car_start(self):
|
||||
self._clear_keys_with_type(TxType.CLEAR_ON_CAR_START)
|
||||
|
||||
def delete(self, key):
|
||||
with self.env.begin(write=True) as txn:
|
||||
txn.delete(key)
|
||||
|
||||
def get(self, key, block=False):
|
||||
if key not in keys:
|
||||
raise UnknownKeyName(key)
|
||||
|
||||
while 1:
|
||||
with self.env.begin() as txn:
|
||||
ret = txn.get(key)
|
||||
if not block or ret is not None:
|
||||
break
|
||||
# is polling really the best we can do?
|
||||
time.sleep(0.05)
|
||||
return ret
|
||||
|
||||
def put(self, key, dat):
|
||||
if key not in keys:
|
||||
raise UnknownKeyName(key)
|
||||
|
||||
with self.env.begin(write=True) as txn:
|
||||
txn.put(key, dat)
|
||||
print "set", key
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
|
||||
params = Params()
|
||||
key = sys.argv[1]
|
||||
assert params.check_key(key), f"unknown param: {key}"
|
||||
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 k, "is None"
|
||||
elif all(ord(c) < 128 and ord(c) >= 32 for c in pp):
|
||||
print k, pp
|
||||
else:
|
||||
print k, pp.encode("hex")
|
||||
|
||||
if len(sys.argv) == 3:
|
||||
val = sys.argv[2]
|
||||
print(f"SET: {key} = {val}")
|
||||
params.put(key, val)
|
||||
elif len(sys.argv) == 2:
|
||||
print(f"GET: {key} = {params.get(key)}")
|
||||
# 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
|
||||
|
||||
-19684
File diff suppressed because it is too large
Load Diff
@@ -1,158 +0,0 @@
|
||||
# distutils: language = c++
|
||||
# cython: language_level = 3
|
||||
from libcpp cimport bool
|
||||
from libcpp.string cimport string
|
||||
from libcpp.vector cimport vector
|
||||
|
||||
cdef extern from "common/params.h":
|
||||
cpdef enum ParamKeyType:
|
||||
PERSISTENT
|
||||
CLEAR_ON_MANAGER_START
|
||||
CLEAR_ON_ONROAD_TRANSITION
|
||||
CLEAR_ON_OFFROAD_TRANSITION
|
||||
DEVELOPMENT_ONLY
|
||||
ALL
|
||||
|
||||
cdef cppclass c_Params "Params":
|
||||
c_Params(string) except + nogil
|
||||
string get(string, bool) nogil
|
||||
bool getBool(string, bool) nogil
|
||||
int getInt(string, bool) nogil
|
||||
float getFloat(string, bool) nogil
|
||||
int remove(string) nogil
|
||||
int put(string, string) nogil
|
||||
void putNonBlocking(string, string) nogil
|
||||
void putBoolNonBlocking(string, bool) nogil
|
||||
void putIntNonBlocking(string, int) nogil
|
||||
void putFloatNonBlocking(string, float) nogil
|
||||
int putBool(string, bool) nogil
|
||||
int putInt(string, int) nogil
|
||||
int putFloat(string, float) nogil
|
||||
bool checkKey(string) nogil
|
||||
string getParamPath(string) nogil
|
||||
void clearAll(ParamKeyType)
|
||||
vector[string] allKeys()
|
||||
|
||||
|
||||
def ensure_bytes(v):
|
||||
return v.encode() if isinstance(v, str) else v
|
||||
|
||||
class UnknownKeyName(Exception):
|
||||
pass
|
||||
|
||||
cdef class Params:
|
||||
cdef c_Params* p
|
||||
|
||||
def __cinit__(self, d=""):
|
||||
cdef string path = <string>d.encode()
|
||||
with nogil:
|
||||
self.p = new c_Params(path)
|
||||
|
||||
def __dealloc__(self):
|
||||
del self.p
|
||||
|
||||
def clear_all(self, tx_type=ParamKeyType.ALL):
|
||||
self.p.clearAll(tx_type)
|
||||
|
||||
def check_key(self, key):
|
||||
key = ensure_bytes(key)
|
||||
if not self.p.checkKey(key):
|
||||
raise UnknownKeyName(key)
|
||||
return key
|
||||
|
||||
def get(self, key, bool block=False, encoding=None):
|
||||
cdef string k = self.check_key(key)
|
||||
cdef string val
|
||||
with nogil:
|
||||
val = self.p.get(k, block)
|
||||
|
||||
if val == b"":
|
||||
if block:
|
||||
# If we got no value while running in blocked mode
|
||||
# it means we got an interrupt while waiting
|
||||
raise KeyboardInterrupt
|
||||
else:
|
||||
return None
|
||||
|
||||
return val if encoding is None else val.decode(encoding)
|
||||
|
||||
def get_bool(self, key, bool block=False):
|
||||
cdef string k = self.check_key(key)
|
||||
cdef bool r
|
||||
with nogil:
|
||||
r = self.p.getBool(k, block)
|
||||
return r
|
||||
|
||||
def get_int(self, key, bool block=False):
|
||||
cdef string k = self.check_key(key)
|
||||
cdef int r
|
||||
with nogil:
|
||||
r = self.p.getInt(k, block)
|
||||
return r
|
||||
|
||||
def get_float(self, key, bool block=False):
|
||||
cdef string k = self.check_key(key)
|
||||
cdef float r
|
||||
with nogil:
|
||||
r = self.p.getFloat(k, block)
|
||||
return r
|
||||
|
||||
def put(self, key, dat):
|
||||
"""
|
||||
Warning: This function blocks until the param is written to disk!
|
||||
In very rare cases this can take over a second, and your code will hang.
|
||||
Use the put_nonblocking, put_bool_nonblocking in time sensitive code, but
|
||||
in general try to avoid writing params as much as possible.
|
||||
"""
|
||||
cdef string k = self.check_key(key)
|
||||
cdef string dat_bytes = ensure_bytes(dat)
|
||||
with nogil:
|
||||
self.p.put(k, dat_bytes)
|
||||
|
||||
def put_bool(self, key, bool val):
|
||||
cdef string k = self.check_key(key)
|
||||
with nogil:
|
||||
self.p.putBool(k, val)
|
||||
|
||||
def put_int(self, key, int val):
|
||||
cdef string k = self.check_key(key)
|
||||
with nogil:
|
||||
self.p.putInt(k, val)
|
||||
|
||||
def put_float(self, key, float val):
|
||||
cdef string k = self.check_key(key)
|
||||
with nogil:
|
||||
self.p.putFloat(k, val)
|
||||
|
||||
def put_nonblocking(self, key, dat):
|
||||
cdef string k = self.check_key(key)
|
||||
cdef string dat_bytes = ensure_bytes(dat)
|
||||
with nogil:
|
||||
self.p.putNonBlocking(k, dat_bytes)
|
||||
|
||||
def put_bool_nonblocking(self, key, bool val):
|
||||
cdef string k = self.check_key(key)
|
||||
with nogil:
|
||||
self.p.putBoolNonBlocking(k, val)
|
||||
|
||||
def put_int_nonblocking(self, key, int val):
|
||||
cdef string k = self.check_key(key)
|
||||
with nogil:
|
||||
self.p.putIntNonBlocking(k, val)
|
||||
|
||||
def put_float_nonblocking(self, key, float val):
|
||||
cdef string k = self.check_key(key)
|
||||
with nogil:
|
||||
self.p.putFloatNonBlocking(k, val)
|
||||
|
||||
def remove(self, key):
|
||||
cdef string k = self.check_key(key)
|
||||
with nogil:
|
||||
self.p.remove(k)
|
||||
|
||||
def get_param_path(self, key=""):
|
||||
cdef string key_bytes = ensure_bytes(key)
|
||||
return self.p.getParamPath(key_bytes).decode("utf-8")
|
||||
|
||||
def all_keys(self):
|
||||
return self.p.allKeys()
|
||||
Binary file not shown.
@@ -1,39 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
#include "common/params.h"
|
||||
#include "common/util.h"
|
||||
#include "system/hardware/hw.h"
|
||||
|
||||
class OpenpilotPrefix {
|
||||
public:
|
||||
OpenpilotPrefix(std::string prefix = {}) {
|
||||
if (prefix.empty()) {
|
||||
prefix = util::random_string(15);
|
||||
}
|
||||
msgq_path = "/dev/shm/" + prefix;
|
||||
bool ret = util::create_directories(msgq_path, 0777);
|
||||
assert(ret);
|
||||
setenv("OPENPILOT_PREFIX", prefix.c_str(), 1);
|
||||
}
|
||||
|
||||
~OpenpilotPrefix() {
|
||||
auto param_path = Params().getParamPath();
|
||||
if (util::file_exists(param_path)) {
|
||||
std::string real_path = util::readlink(param_path);
|
||||
system(util::string_format("rm %s -rf", real_path.c_str()).c_str());
|
||||
unlink(param_path.c_str());
|
||||
}
|
||||
if (getenv("COMMA_CACHE") == nullptr) {
|
||||
system(util::string_format("rm %s -rf", Path::download_cache_root().c_str()).c_str());
|
||||
}
|
||||
system(util::string_format("rm %s -rf", Path::comma_home().c_str()).c_str());
|
||||
system(util::string_format("rm %s -rf", msgq_path.c_str()).c_str());
|
||||
unsetenv("OPENPILOT_PREFIX");
|
||||
}
|
||||
|
||||
private:
|
||||
std::string msgq_path;
|
||||
};
|
||||
@@ -1,53 +0,0 @@
|
||||
import os
|
||||
import shutil
|
||||
import uuid
|
||||
|
||||
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.system.hardware import PC
|
||||
from openpilot.system.hardware.hw import Paths
|
||||
from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT
|
||||
|
||||
class OpenpilotPrefix:
|
||||
def __init__(self, prefix: str = None, clean_dirs_on_exit: bool = True, shared_download_cache: bool = False):
|
||||
self.prefix = prefix if prefix else str(uuid.uuid4().hex[0:15])
|
||||
self.msgq_path = os.path.join('/dev/shm', self.prefix)
|
||||
self.clean_dirs_on_exit = clean_dirs_on_exit
|
||||
self.shared_download_cache = shared_download_cache
|
||||
|
||||
def __enter__(self):
|
||||
self.original_prefix = os.environ.get('OPENPILOT_PREFIX', None)
|
||||
os.environ['OPENPILOT_PREFIX'] = self.prefix
|
||||
try:
|
||||
os.mkdir(self.msgq_path)
|
||||
except FileExistsError:
|
||||
pass
|
||||
os.makedirs(Paths.log_root(), exist_ok=True)
|
||||
|
||||
if self.shared_download_cache:
|
||||
os.environ["COMMA_CACHE"] = DEFAULT_DOWNLOAD_CACHE_ROOT
|
||||
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_obj, exc_tb):
|
||||
if self.clean_dirs_on_exit:
|
||||
self.clean_dirs()
|
||||
try:
|
||||
del os.environ['OPENPILOT_PREFIX']
|
||||
if self.original_prefix is not None:
|
||||
os.environ['OPENPILOT_PREFIX'] = self.original_prefix
|
||||
except KeyError:
|
||||
pass
|
||||
return False
|
||||
|
||||
def clean_dirs(self):
|
||||
symlink_path = Params().get_param_path()
|
||||
if os.path.exists(symlink_path):
|
||||
shutil.rmtree(os.path.realpath(symlink_path), ignore_errors=True)
|
||||
os.remove(symlink_path)
|
||||
shutil.rmtree(self.msgq_path, ignore_errors=True)
|
||||
if PC:
|
||||
shutil.rmtree(Paths.log_root(), ignore_errors=True)
|
||||
if not os.environ.get("COMMA_CACHE", False):
|
||||
shutil.rmtree(Paths.download_cache_root(), ignore_errors=True)
|
||||
shutil.rmtree(Paths.comma_home(), ignore_errors=True)
|
||||
@@ -0,0 +1,47 @@
|
||||
import time
|
||||
|
||||
class Profiler(object):
|
||||
def __init__(self, enabled=False):
|
||||
self.enabled = enabled
|
||||
self.cp = {}
|
||||
self.cp_ignored = []
|
||||
self.iter = 0
|
||||
self.start_time = time.clock()
|
||||
self.last_time = self.start_time
|
||||
self.tot = 0.
|
||||
|
||||
def reset(self, enabled=False):
|
||||
self.enabled = enabled
|
||||
self.cp = {}
|
||||
self.cp_ignored = []
|
||||
self.iter = 0
|
||||
self.start_time = time.clock()
|
||||
self.last_time = self.start_time
|
||||
|
||||
def checkpoint(self, name, ignore=False):
|
||||
# ignore flag needed when benchmarking threads with ratekeeper
|
||||
if not self.enabled:
|
||||
return
|
||||
tt = time.clock()
|
||||
if name not in self.cp:
|
||||
self.cp[name] = 0.
|
||||
if ignore:
|
||||
self.cp_ignored.append(name)
|
||||
self.cp[name] += tt - self.last_time
|
||||
if not ignore:
|
||||
self.tot += tt - self.last_time
|
||||
self.last_time = tt
|
||||
|
||||
def display(self):
|
||||
if not self.enabled:
|
||||
return
|
||||
self.iter += 1
|
||||
print "******* Profiling *******"
|
||||
for n in self.cp:
|
||||
ms = self.cp[n]
|
||||
if n in self.cp_ignored:
|
||||
print "%30s: %7.2f perc: %1.0f" % (n, ms*1000.0, ms/self.tot*100), " IGNORED"
|
||||
else:
|
||||
print "%30s: %7.2f perc: %1.0f" % (n, ms*1000.0, ms/self.tot*100)
|
||||
print "Iter clock: %2.6f TOTAL: %2.2f" % (self.tot/self.iter, self.tot)
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
template <class T>
|
||||
class SafeQueue {
|
||||
public:
|
||||
SafeQueue() = default;
|
||||
|
||||
void push(const T& v) {
|
||||
{
|
||||
std::unique_lock lk(m);
|
||||
q.push(v);
|
||||
}
|
||||
cv.notify_one();
|
||||
}
|
||||
|
||||
T pop() {
|
||||
std::unique_lock lk(m);
|
||||
cv.wait(lk, [this] { return !q.empty(); });
|
||||
T v = q.front();
|
||||
q.pop();
|
||||
return v;
|
||||
}
|
||||
|
||||
bool try_pop(T& v, int timeout_ms = 0) {
|
||||
std::unique_lock lk(m);
|
||||
if (!cv.wait_for(lk, std::chrono::milliseconds(timeout_ms), [this] { return !q.empty(); })) {
|
||||
return false;
|
||||
}
|
||||
v = q.front();
|
||||
q.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
std::scoped_lock lk(m);
|
||||
return q.empty();
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
std::scoped_lock lk(m);
|
||||
return q.size();
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::mutex m;
|
||||
std::condition_variable cv;
|
||||
std::queue<T> q;
|
||||
};
|
||||
@@ -1,40 +0,0 @@
|
||||
#include "common/ratekeeper.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common/swaglog.h"
|
||||
#include "common/timing.h"
|
||||
#include "common/util.h"
|
||||
|
||||
RateKeeper::RateKeeper(const std::string &name, float rate, float print_delay_threshold)
|
||||
: name(name),
|
||||
print_delay_threshold(std::max(0.f, print_delay_threshold)) {
|
||||
interval = 1 / rate;
|
||||
last_monitor_time = seconds_since_boot();
|
||||
next_frame_time = last_monitor_time + interval;
|
||||
}
|
||||
|
||||
bool RateKeeper::keepTime() {
|
||||
bool lagged = monitorTime();
|
||||
if (remaining_ > 0) {
|
||||
util::sleep_for(remaining_ * 1000);
|
||||
}
|
||||
return lagged;
|
||||
}
|
||||
|
||||
bool RateKeeper::monitorTime() {
|
||||
++frame_;
|
||||
last_monitor_time = seconds_since_boot();
|
||||
remaining_ = next_frame_time - last_monitor_time;
|
||||
|
||||
bool lagged = remaining_ < 0;
|
||||
if (lagged) {
|
||||
if (print_delay_threshold > 0 && remaining_ < -print_delay_threshold) {
|
||||
LOGW("%s lagging by %.2f ms", name.c_str(), -remaining_ * 1000);
|
||||
}
|
||||
next_frame_time = last_monitor_time + interval;
|
||||
} else {
|
||||
next_frame_time += interval;
|
||||
}
|
||||
return lagged;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
class RateKeeper {
|
||||
public:
|
||||
RateKeeper(const std::string &name, float rate, float print_delay_threshold = 0);
|
||||
~RateKeeper() {}
|
||||
bool keepTime();
|
||||
bool monitorTime();
|
||||
inline uint64_t frame() const { return frame_; }
|
||||
inline double remaining() const { return remaining_; }
|
||||
|
||||
private:
|
||||
double interval;
|
||||
double next_frame_time;
|
||||
double last_monitor_time;
|
||||
double remaining_ = 0;
|
||||
float print_delay_threshold = 0;
|
||||
uint64_t frame_ = 0;
|
||||
std::string name;
|
||||
};
|
||||
+76
-70
@@ -1,105 +1,111 @@
|
||||
"""Utilities for reading real time clocks and keeping soft real time constraints."""
|
||||
import gc
|
||||
import os
|
||||
import time
|
||||
from collections import deque
|
||||
import ctypes
|
||||
import platform
|
||||
import threading
|
||||
import subprocess
|
||||
import multiprocessing
|
||||
|
||||
from setproctitle import getproctitle
|
||||
from cffi import FFI
|
||||
ffi = FFI()
|
||||
ffi.cdef("""
|
||||
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
from openpilot.system.hardware import PC
|
||||
typedef int clockid_t;
|
||||
struct timespec {
|
||||
long tv_sec; /* Seconds. */
|
||||
long tv_nsec; /* Nanoseconds. */
|
||||
};
|
||||
int clock_gettime (clockid_t clk_id, struct timespec *tp);
|
||||
|
||||
long syscall(long number, ...);
|
||||
|
||||
"""
|
||||
)
|
||||
libc = ffi.dlopen(None)
|
||||
|
||||
|
||||
# time step for each process
|
||||
DT_CTRL = 0.01 # controlsd
|
||||
DT_MDL = 0.05 # model
|
||||
DT_HW = 0.5 # hardwared and manager
|
||||
DT_DMON = 0.05 # driver monitoring
|
||||
# see <linux/time.h>
|
||||
CLOCK_MONOTONIC_RAW = 4
|
||||
CLOCK_BOOTTIME = 7
|
||||
|
||||
if platform.system() != 'Darwin' and hasattr(libc, 'clock_gettime'):
|
||||
c_clock_gettime = libc.clock_gettime
|
||||
|
||||
tlocal = threading.local()
|
||||
def clock_gettime(clk_id):
|
||||
if not hasattr(tlocal, 'ts'):
|
||||
tlocal.ts = ffi.new('struct timespec *')
|
||||
|
||||
ts = tlocal.ts
|
||||
|
||||
r = c_clock_gettime(clk_id, ts)
|
||||
if r != 0:
|
||||
raise OSError("clock_gettime")
|
||||
return ts.tv_sec + ts.tv_nsec * 1e-9
|
||||
else:
|
||||
# hack. only for OS X < 10.12
|
||||
def clock_gettime(clk_id):
|
||||
return time.time()
|
||||
|
||||
def monotonic_time():
|
||||
return clock_gettime(CLOCK_MONOTONIC_RAW)
|
||||
|
||||
def sec_since_boot():
|
||||
return clock_gettime(CLOCK_BOOTTIME)
|
||||
|
||||
|
||||
class Priority:
|
||||
# CORE 2
|
||||
# - modeld = 55
|
||||
# - camerad = 54
|
||||
CTRL_LOW = 51 # plannerd & radard
|
||||
def set_realtime_priority(level):
|
||||
if os.getuid() != 0:
|
||||
print("not setting priority, not root")
|
||||
return
|
||||
if platform.machine() == "x86_64":
|
||||
NR_gettid = 186
|
||||
elif platform.machine() == "aarch64":
|
||||
NR_gettid = 178
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
# CORE 3
|
||||
# - pandad = 55
|
||||
CTRL_HIGH = 53
|
||||
tid = libc.syscall(NR_gettid)
|
||||
return subprocess.call(['chrt', '-f', '-p', str(level), str(tid)])
|
||||
|
||||
|
||||
def set_realtime_priority(level: int) -> None:
|
||||
if not PC:
|
||||
os.sched_setscheduler(0, os.SCHED_FIFO, os.sched_param(level))
|
||||
|
||||
|
||||
def set_core_affinity(cores: list[int]) -> None:
|
||||
if not PC:
|
||||
for attempt in range(3): # Retry up to 3 times
|
||||
try:
|
||||
os.sched_setaffinity(0, cores)
|
||||
return
|
||||
except OSError as e:
|
||||
if e.errno == 22: # EINVAL
|
||||
time.sleep(0.1) # Brief delay before retry
|
||||
else:
|
||||
raise # Re-raise other errors
|
||||
# If all retries fail, log and continue without affinity
|
||||
cloudlog.error(f"Failed to set core affinity after retries: {cores}")
|
||||
|
||||
|
||||
def config_realtime_process(cores: int | list[int], priority: int) -> None:
|
||||
gc.disable()
|
||||
set_realtime_priority(priority)
|
||||
c = cores if isinstance(cores, list) else [cores, ]
|
||||
set_core_affinity(c)
|
||||
|
||||
|
||||
class Ratekeeper:
|
||||
def __init__(self, rate: float, print_delay_threshold: float | None = 0.0) -> None:
|
||||
class Ratekeeper(object):
|
||||
def __init__(self, rate, print_delay_threshold=0.):
|
||||
"""Rate in Hz for ratekeeping. print_delay_threshold must be nonnegative."""
|
||||
self._interval = 1. / rate
|
||||
self._next_frame_time = time.monotonic() + self._interval
|
||||
self._next_frame_time = sec_since_boot() + self._interval
|
||||
self._print_delay_threshold = print_delay_threshold
|
||||
self._frame = 0
|
||||
self._remaining = 0.0
|
||||
self._process_name = getproctitle()
|
||||
self._dts = deque([self._interval], maxlen=100)
|
||||
self._last_monitor_time = time.monotonic()
|
||||
self._remaining = 0
|
||||
self._process_name = multiprocessing.current_process().name
|
||||
|
||||
@property
|
||||
def frame(self) -> int:
|
||||
def frame(self):
|
||||
return self._frame
|
||||
|
||||
@property
|
||||
def remaining(self) -> float:
|
||||
def remaining(self):
|
||||
return self._remaining
|
||||
|
||||
@property
|
||||
def lagging(self) -> bool:
|
||||
avg_dt = sum(self._dts) / len(self._dts)
|
||||
expected_dt = self._interval * (1 / 0.9)
|
||||
return avg_dt > expected_dt
|
||||
|
||||
# Maintain loop rate by calling this at the end of each loop
|
||||
def keep_time(self) -> bool:
|
||||
def keep_time(self):
|
||||
lagged = self.monitor_time()
|
||||
if self._remaining > 0:
|
||||
time.sleep(self._remaining)
|
||||
return lagged
|
||||
|
||||
# Monitors the cumulative lag, but does not enforce a rate
|
||||
def monitor_time(self) -> bool:
|
||||
prev = self._last_monitor_time
|
||||
self._last_monitor_time = time.monotonic()
|
||||
self._dts.append(self._last_monitor_time - prev)
|
||||
|
||||
# this only monitor the cumulative lag, but does not enforce a rate
|
||||
def monitor_time(self):
|
||||
lagged = False
|
||||
remaining = self._next_frame_time - time.monotonic()
|
||||
remaining = self._next_frame_time - sec_since_boot()
|
||||
self._next_frame_time += self._interval
|
||||
if self._print_delay_threshold is not None and remaining < -self._print_delay_threshold:
|
||||
print(f"{self._process_name} lagging by {-remaining * 1000:.2f} ms")
|
||||
if remaining < -self._print_delay_threshold:
|
||||
print("%s lagging by %.2f ms" % (self._process_name, -remaining * 1000))
|
||||
lagged = True
|
||||
self._frame += 1
|
||||
self._remaining = remaining
|
||||
return lagged
|
||||
|
||||
if __name__ == "__main__":
|
||||
print sec_since_boot()
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import time
|
||||
import functools
|
||||
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
|
||||
|
||||
def retry(attempts=3, delay=1.0, ignore_failure=False):
|
||||
def decorator(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
for _ in range(attempts):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except Exception:
|
||||
cloudlog.exception(f"{func.__name__} failed, trying again")
|
||||
time.sleep(delay)
|
||||
|
||||
if ignore_failure:
|
||||
cloudlog.error(f"{func.__name__} failed after retry")
|
||||
else:
|
||||
raise Exception(f"{func.__name__} failed after retry")
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@retry(attempts=10)
|
||||
def abc():
|
||||
raise ValueError("abc failed :(")
|
||||
abc()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user