mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-08-23 06:43:47 +08:00
Compare commits
176 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2bf5f45ffe | |||
| f76da384cd | |||
| aa636e75c8 | |||
| 5ff3c3bd8d | |||
| 1e11b52290 | |||
| 76e0204025 | |||
| cc88f2cbd6 | |||
| ee0ac199a4 | |||
| d5ed828eaa | |||
| 9fca585f2a | |||
| bb1259303e | |||
| e135051ca8 | |||
| 12bef55d8a | |||
| 2f7a45e6c8 | |||
| 936ebfc12b | |||
| aa0c9dc0eb | |||
| 7476a866e7 | |||
| 610d857e33 | |||
| d2f47407d0 | |||
| db75ec76ea | |||
| 24066465d7 | |||
| a7abbd6e25 | |||
| 878982447c | |||
| 576527a36b | |||
| ef8c35da24 | |||
| 85688b1040 | |||
| 0fb2199130 | |||
| d48d756c1d | |||
| 2ed298a0c9 | |||
| d68f038949 | |||
| 7231571e57 | |||
| b37f1419d3 | |||
| cd85a66790 | |||
| 305ea87daf | |||
| 4bbfc793e0 | |||
| d5d983676e | |||
| de8a96a398 | |||
| 0cbf45f699 | |||
| 0d68a3a2ab | |||
| 9e85a85059 | |||
| 0373c327c0 | |||
| efe9e5c200 | |||
| 8a249a45dc | |||
| bdbefe67f6 | |||
| 675bb166ad | |||
| 1b717a7e88 | |||
| 86f55a8ba9 | |||
| 629392d2f7 | |||
| bc414bdc8b | |||
| 7ca5649f2c | |||
| 641ee8fa87 | |||
| 56c276158c | |||
| c65308a8bd | |||
| 994e526460 | |||
| 1defae36b7 | |||
| 8f029fd0ef | |||
| ddb46284dc | |||
| 9effc754d9 | |||
| e49ffc2a2d | |||
| 2cacd0b3e5 | |||
| c4b8859dff | |||
| 8fb0953205 | |||
| 63d1c8835f | |||
| 17a185606d | |||
| da10131392 | |||
| 7107c2ba14 | |||
| 95b6e877ac | |||
| eb02c6570e | |||
| 1be8ae31c4 | |||
| 04dcd38856 | |||
| 22ccf0d72f | |||
| 3c969bb627 | |||
| 20f8011feb | |||
| 9cf17e74a1 | |||
| 2c4efdf557 | |||
| 4cd3d3c16c | |||
| 637f3ae9c8 | |||
| 464ee80f71 | |||
| 2743a04613 | |||
| 7f9978d001 | |||
| 4b83961c67 | |||
| c00eaf428a | |||
| 0a9993e8d4 | |||
| 0af214a985 | |||
| af43385e3a | |||
| 0ab2b8c590 | |||
| 67ab18a0de | |||
| e87dc15b30 | |||
| 192d08516c | |||
| 3cf001c59c | |||
| f2ccd021da | |||
| c9fc900f64 | |||
| 3c37c5ce5d | |||
| 7c45889e4e | |||
| 2aabb7aee8 | |||
| 3859e9962f | |||
| 810efbab72 | |||
| ec27bec326 | |||
| 250d553157 | |||
| cea54a0ca8 | |||
| 8e72d783bd | |||
| 1b0dc103dc | |||
| 6c364d292b | |||
| bcdec2ce84 | |||
| 3deaeb3759 | |||
| c669f0984a | |||
| 46dd946740 | |||
| 9da4b3653e | |||
| 4e21ae7c50 | |||
| bb91e92237 | |||
| 14b4c4f85b | |||
| 0660b542c3 | |||
| 2b893b90c9 | |||
| f5139178ed | |||
| fb43b755f2 | |||
| 07f5b967d8 | |||
| ea19c7d3bb | |||
| e461842cbb | |||
| a73c9659d5 | |||
| cb796fbc76 | |||
| 6bf75fc557 | |||
| 9a1fc28819 | |||
| 0741d05e92 | |||
| 1ad008107d | |||
| feebd9df93 | |||
| c2e5ced3e5 | |||
| 15e5d2efb9 | |||
| a3929d0b54 | |||
| 794f8f9991 | |||
| 68fa5e3f21 | |||
| 86c6cc1f48 | |||
| eb7ffbf093 | |||
| 3919095752 | |||
| 74d63be1c3 | |||
| 8894486a1a | |||
| 810599315d | |||
| 6f3ab810c8 | |||
| 230f78b8d3 | |||
| f1affec088 | |||
| 97d8ef242c | |||
| a63fff9b45 | |||
| cb3893daaa | |||
| 29f60df74b | |||
| c6c072e1f4 | |||
| d101cbb83e | |||
| 1536d59633 | |||
| dc99b865ae | |||
| e59bc027ff | |||
| cf7e5efaca | |||
| 4b44f2eb31 | |||
| 107d2ab400 | |||
| 5432d9062c | |||
| f533f6c843 | |||
| 58e9ac763c | |||
| cb50d54169 | |||
| bd5de4ed0a | |||
| 0d4073fadb | |||
| ebc70dcb52 | |||
| 4d0426999e | |||
| 286da42573 | |||
| 8a836710a9 | |||
| 5d515bcf33 | |||
| 1c7f6d5133 | |||
| 05d57c7aeb | |||
| e4b0eaf352 | |||
| a710276472 | |||
| af086db671 | |||
| 0d9eb0e25e | |||
| 0616caed6d | |||
| 095337b3c1 | |||
| 1edec2d22c | |||
| affabb9ee0 | |||
| dc27e8711c | |||
| cf7329a264 | |||
| 5ee5ecd820 | |||
| b064f730dd |
+5
-2
@@ -10,5 +10,8 @@
|
|||||||
*.otf filter=lfs diff=lfs merge=lfs -text
|
*.otf filter=lfs diff=lfs merge=lfs -text
|
||||||
*.wav filter=lfs diff=lfs merge=lfs -text
|
*.wav filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|
||||||
openpilot/selfdrive/car/tests/test_models_segs.txt filter=lfs diff=lfs merge=lfs -text
|
selfdrive/car/tests/test_models_segs.txt filter=lfs diff=lfs merge=lfs -text
|
||||||
openpilot/common/hardware/comma/updater filter=lfs diff=lfs merge=lfs -text
|
common/hardware/tici/updater filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|
||||||
|
# Small vendored Leaflet UI icons are kept directly in Git.
|
||||||
|
tools/clustermaps/web/vendor/leaflet/images/*.png -filter -diff -merge -text
|
||||||
|
|||||||
@@ -8,24 +8,24 @@ chore:
|
|||||||
|
|
||||||
car:
|
car:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-all-files: '{openpilot/selfdrive/car/**,opendbc_repo}'
|
- any-glob-to-all-files: '{selfdrive/car/**,opendbc_repo}'
|
||||||
|
|
||||||
simulation:
|
simulation:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-all-files: 'openpilot/tools/sim/**'
|
- any-glob-to-all-files: 'tools/sim/**'
|
||||||
|
|
||||||
ui:
|
ui:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-all-files: '{openpilot/selfdrive/assets/**,openpilot/selfdrive/ui/**,openpilot/system/ui/**}'
|
- any-glob-to-all-files: '{selfdrive/assets/**,selfdrive/ui/**,system/ui/**}'
|
||||||
|
|
||||||
tools:
|
tools:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-all-files: 'openpilot/tools/**'
|
- any-glob-to-all-files: 'tools/**'
|
||||||
|
|
||||||
multilanguage:
|
multilanguage:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-all-files: 'openpilot/selfdrive/ui/translations/**'
|
- any-glob-to-all-files: 'selfdrive/ui/translations/**'
|
||||||
|
|
||||||
autonomy:
|
autonomy:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-all-files: "{openpilot/selfdrive/modeld/models/**,openpilot/selfdrive/test/process_replay/model_replay_ref_commit,openpilot/sunnypilot/modeld*/models/**}"
|
- any-glob-to-all-files: "{selfdrive/modeld/models/**,selfdrive/test/process_replay/model_replay_ref_commit,sunnypilot/modeld*/models/**}"
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
<!-- Please copy and paste the relevant template -->
|
||||||
|
|
||||||
|
<!--- ***** Template: Fingerprint *****
|
||||||
|
|
||||||
|
**Car**
|
||||||
|
Which car (make, model, year) this fingerprint is for
|
||||||
|
|
||||||
|
**Route**
|
||||||
|
A route with the fingerprint
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!--- ***** Template: Car Bugfix *****
|
||||||
|
|
||||||
|
**Description**
|
||||||
|
|
||||||
|
A description of the bug and the fix. Also link the issue if it exists.
|
||||||
|
|
||||||
|
**Verification**
|
||||||
|
|
||||||
|
Explain how you tested this bug fix.
|
||||||
|
|
||||||
|
**Route**
|
||||||
|
|
||||||
|
Route: [a route with the bug fix]
|
||||||
|
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!--- ***** Template: Bugfix *****
|
||||||
|
|
||||||
|
**Description**
|
||||||
|
|
||||||
|
A description of the bug and the fix. Also link the issue if it exists.
|
||||||
|
|
||||||
|
**Verification**
|
||||||
|
|
||||||
|
Explain how you tested this bug fix.
|
||||||
|
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!--- ***** Template: Car Port *****
|
||||||
|
|
||||||
|
**Checklist**
|
||||||
|
|
||||||
|
- [ ] added entry to CAR in selfdrive/car/*/values.py and ran `selfdrive/car/docs.py` to generate new docs
|
||||||
|
- [ ] test route added to [routes.py](https://github.com/commaai/openpilot/blob/master/selfdrive/car/tests/routes.py)
|
||||||
|
- [ ] route with openpilot:
|
||||||
|
- [ ] route with stock system:
|
||||||
|
- [ ] car harness used (if comma doesn't sell it, put N/A):
|
||||||
|
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!--- ***** Template: Refactor *****
|
||||||
|
|
||||||
|
**Description**
|
||||||
|
|
||||||
|
A description of the refactor, including the goals it accomplishes.
|
||||||
|
|
||||||
|
**Verification**
|
||||||
|
|
||||||
|
Explain how you tested the refactor for regressions.
|
||||||
|
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ jobs:
|
|||||||
issues: write
|
issues: write
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
submodules: false
|
submodules: false
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
|
|
||||||
# Check PR target branch
|
# Check PR target branch
|
||||||
- name: check branch
|
- name: check branch
|
||||||
uses: Vankka/pr-target-branch-action@5da68a42bcb7b43d39104295a876a6f3f8d7908b
|
uses: Vankka/pr-target-branch-action@def32ec9d93514138d6ac0132ee62e120a72aed5
|
||||||
if: github.repository == 'sunnypilot/sunnypilot'
|
if: github.repository == 'sunnypilot/sunnypilot'
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
name: badges
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 * * * *'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
PYTHONPATH: ${{ github.workspace }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
badges:
|
||||||
|
name: create badges
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.repository == 'sunnypilot/sunnypilot'
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- run: ./tools/op.sh setup
|
||||||
|
- name: Push badges
|
||||||
|
run: |
|
||||||
|
python3 selfdrive/ui/translations/create_badges.py
|
||||||
|
|
||||||
|
rm .gitattributes
|
||||||
|
|
||||||
|
git checkout --orphan badges
|
||||||
|
git rm -rf --cached .
|
||||||
|
git config user.email "badge-researcher@sunnypilot.ai"
|
||||||
|
git config user.name "Badge Researcher"
|
||||||
|
|
||||||
|
git add translation_badge.svg
|
||||||
|
git commit -m "Add/Update badges"
|
||||||
|
git push -f origin HEAD
|
||||||
@@ -7,19 +7,6 @@ on:
|
|||||||
description: 'Minimum selector version required for the models (see helpers.py or readme.md)'
|
description: 'Minimum selector version required for the models (see helpers.py or readme.md)'
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
target_hardware:
|
|
||||||
description: 'Hardware target to compile for (qcom or usbgpu)'
|
|
||||||
required: true
|
|
||||||
type: choice
|
|
||||||
default: 'qcom'
|
|
||||||
options:
|
|
||||||
- qcom
|
|
||||||
- usbgpu
|
|
||||||
hf_repo:
|
|
||||||
description: 'Hugging Face dataset repository'
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
default: 'sunnypilot/sunnypilot_models_v1'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
setup:
|
setup:
|
||||||
@@ -43,7 +30,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd sunnypilot
|
cd sunnypilot
|
||||||
export PYTHONPATH=$(pwd)
|
export PYTHONPATH=$(pwd)
|
||||||
ref=$(python3 openpilot/sunnypilot/models/tinygrad_ref.py)
|
ref=$(python3 sunnypilot/models/tinygrad_ref.py)
|
||||||
echo "tinygrad_ref=$ref" >> $GITHUB_OUTPUT
|
echo "tinygrad_ref=$ref" >> $GITHUB_OUTPUT
|
||||||
echo "tinygrad_ref is $ref"
|
echo "tinygrad_ref is $ref"
|
||||||
|
|
||||||
@@ -59,14 +46,13 @@ jobs:
|
|||||||
id: get-json
|
id: get-json
|
||||||
run: |
|
run: |
|
||||||
cd docs/docs
|
cd docs/docs
|
||||||
PREFIX="driving_models_${{ inputs.target_hardware == 'usbgpu' && 'usbgpu_' || '' }}v"
|
latest=$(ls driving_models_v*.json | sed -E 's/.*_v([0-9]+)\.json/\1/' | sort -n | tail -1)
|
||||||
latest=$(ls ${PREFIX}*.json | sed -E "s/${PREFIX}([0-9]+)\.json/\1/" | sort -n | tail -1)
|
|
||||||
next=$((latest+1))
|
next=$((latest+1))
|
||||||
json_file="${PREFIX}${next}.json"
|
json_file="driving_models_v${next}.json"
|
||||||
cp "${PREFIX}${latest}.json" "$json_file"
|
cp "driving_models_v${latest}.json" "$json_file"
|
||||||
echo "json_file=docs/docs/$json_file" >> $GITHUB_OUTPUT
|
echo "json_file=docs/docs/$json_file" >> $GITHUB_OUTPUT
|
||||||
echo "json_version=$((next+0))" >> $GITHUB_OUTPUT
|
echo "json_version=$((next+0))" >> $GITHUB_OUTPUT
|
||||||
echo "SRC_JSON_FILE=docs/docs/${PREFIX}${latest}.json" >> $GITHUB_ENV
|
echo "SRC_JSON_FILE=docs/docs/driving_models_v${latest}.json" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Extract tinygrad models
|
- name: Extract tinygrad models
|
||||||
id: set-matrix
|
id: set-matrix
|
||||||
@@ -75,23 +61,45 @@ jobs:
|
|||||||
jq -c '[.bundles[] | select(.runner=="tinygrad") | {ref, display_name: (.display_name | gsub(" \\([^)]*\\)"; "")), is_20hz}]' "$(basename "${SRC_JSON_FILE}")" > matrix.json
|
jq -c '[.bundles[] | select(.runner=="tinygrad") | {ref, display_name: (.display_name | gsub(" \\([^)]*\\)"; "")), is_20hz}]' "$(basename "${SRC_JSON_FILE}")" > matrix.json
|
||||||
echo "model_matrix=$(cat matrix.json)" >> $GITHUB_OUTPUT
|
echo "model_matrix=$(cat matrix.json)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Get next recompiled dir number
|
- name: Set up SSH
|
||||||
|
uses: webfactory/ssh-agent@v0.9.0
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.GITLAB_SSH_PRIVATE_KEY }}
|
||||||
|
- run: |
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
- name: Clone GitLab docs repo and create new recompiled dir
|
||||||
id: create-recompiled-dir
|
id: create-recompiled-dir
|
||||||
env:
|
env:
|
||||||
HF_REPO: ${{ github.event.inputs.hf_repo }}
|
GIT_SSH_COMMAND: 'ssh -o UserKnownHostsFile=~/.ssh/known_hosts'
|
||||||
run: |
|
run: |
|
||||||
pip install huggingface_hub
|
git clone --depth 1 --filter=tree:0 --sparse git@gitlab.com:sunnypilot/public/${{ vars.MODELS_GITLAB }} gitlab_docs
|
||||||
recompiled_dir=$(python3 -c "
|
cd gitlab_docs
|
||||||
from huggingface_hub import HfApi
|
git checkout main
|
||||||
import re, sys
|
git sparse-checkout set --no-cone models/
|
||||||
api = HfApi()
|
cd models
|
||||||
files = api.list_repo_files(repo_id=sys.argv[1], repo_type='dataset')
|
latest_dir=$(ls -d recompiled* 2>/dev/null | sed -E 's/recompiled([0-9]+)/\1/' | sort -n | tail -1)
|
||||||
dirs = [re.search(r'models/recompiled([0-9]+)', f) for f in files]
|
if [[ -z "$latest_dir" ]]; then
|
||||||
nums = [int(m.group(1)) for m in dirs if m]
|
next_dir=1
|
||||||
print(max(nums) + 1)
|
else
|
||||||
" "$HF_REPO")
|
next_dir=$((latest_dir+1))
|
||||||
|
fi
|
||||||
|
recompiled_dir="${next_dir}"
|
||||||
|
mkdir -p "recompiled${recompiled_dir}"
|
||||||
|
touch "recompiled${recompiled_dir}/.gitkeep"
|
||||||
|
cd ../..
|
||||||
echo "recompiled_dir=$recompiled_dir" >> $GITHUB_OUTPUT
|
echo "recompiled_dir=$recompiled_dir" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Push empty recompiled dir to GitLab
|
||||||
|
run: |
|
||||||
|
cd gitlab_docs
|
||||||
|
git add models/recompiled${{ steps.create-recompiled-dir.outputs.recompiled_dir }}
|
||||||
|
git config --global user.name "GitHub Action"
|
||||||
|
git config --global user.email "action@github.com"
|
||||||
|
git commit -m "Add recompiled${{ steps.create-recompiled-dir.outputs.recompiled_dir }} for build-all" || echo "No changes to commit"
|
||||||
|
git push origin main
|
||||||
|
|
||||||
- name: Push new JSON to GitHub docs repo
|
- name: Push new JSON to GitHub docs repo
|
||||||
run: |
|
run: |
|
||||||
cd docs
|
cd docs
|
||||||
@@ -115,30 +123,25 @@ jobs:
|
|||||||
is_20hz: ${{ matrix.model.is_20hz }}
|
is_20hz: ${{ matrix.model.is_20hz }}
|
||||||
recompiled_dir: ${{ needs.setup.outputs.recompiled_dir }}
|
recompiled_dir: ${{ needs.setup.outputs.recompiled_dir }}
|
||||||
json_version: ${{ needs.setup.outputs.json_version }}
|
json_version: ${{ needs.setup.outputs.json_version }}
|
||||||
target_hardware: ${{ github.event.inputs.target_hardware }}
|
|
||||||
hf_repo: ${{ github.event.inputs.hf_repo }}
|
|
||||||
set_min_version: ${{ github.event.inputs.set_min_version }}
|
|
||||||
tinygrad_ref: ${{ needs.setup.outputs.tinygrad_ref }}
|
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
retry_failed_models:
|
retry_failed_models:
|
||||||
needs: [setup, get_and_build]
|
needs: [setup, get_and_build]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: ${{ !cancelled() && needs.setup.result == 'success' && (needs.get_and_build.result == 'success' || needs.get_and_build.result == 'failure') }}
|
if: ${{ needs.setup.result != 'failure' && !cancelled() }}
|
||||||
outputs:
|
outputs:
|
||||||
retry_matrix: ${{ steps.set-retry-matrix.outputs.retry_matrix }}
|
retry_matrix: ${{ steps.set-retry-matrix.outputs.retry_matrix }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/download-artifact@v4
|
- uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
pattern: artifact-name-*
|
pattern: model-*
|
||||||
path: output
|
path: output
|
||||||
continue-on-error: true
|
|
||||||
|
|
||||||
- id: set-retry-matrix
|
- id: set-retry-matrix
|
||||||
run: |
|
run: |
|
||||||
echo '${{ needs.setup.outputs.model_matrix }}' > matrix.json
|
echo '${{ needs.setup.outputs.model_matrix }}' > matrix.json
|
||||||
built=(); while IFS= read -r line; do [ -n "$line" ] && built+=("$line"); done < <(
|
built=(); while IFS= read -r line; do built+=("$line"); done < <(
|
||||||
find output -maxdepth 1 -name 'artifact-name-*' -printf "%f\n" 2>/dev/null | sed -E 's/^artifact-name-//' | awk '{gsub(/^ +| +$/, ""); print}'
|
find output -maxdepth 1 -name 'model-*' -printf "%f\n" | sed -E 's/^model-//' | sed -E 's/-[0-9]+$//' | sed -E 's/ \([^)]*\)//' | awk '{gsub(/^ +| +$/, ""); print}'
|
||||||
)
|
)
|
||||||
jq -c --argjson built "$(printf '%s\n' "${built[@]}" | jq -R . | jq -s .)" \
|
jq -c --argjson built "$(printf '%s\n' "${built[@]}" | jq -R . | jq -s .)" \
|
||||||
'map(select(.display_name as $n | ($built | index($n | gsub("^ +| +$"; "")) | not)))' matrix.json > retry_matrix.json
|
'map(select(.display_name as $n | ($built | index($n | gsub("^ +| +$"; "")) | not)))' matrix.json > retry_matrix.json
|
||||||
@@ -146,7 +149,7 @@ jobs:
|
|||||||
|
|
||||||
retry_get_and_build:
|
retry_get_and_build:
|
||||||
needs: [setup, get_and_build, retry_failed_models]
|
needs: [setup, get_and_build, retry_failed_models]
|
||||||
if: ${{ !cancelled() && needs.retry_failed_models.result == 'success' && needs.retry_failed_models.outputs.retry_matrix != '[]' && needs.retry_failed_models.outputs.retry_matrix != '' }}
|
if: ${{ needs.get_and_build.result == 'failure' || (needs.retry_failed_models.outputs.retry_matrix != '[]' && needs.retry_failed_models.outputs.retry_matrix != '') }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
model: ${{ fromJson(needs.retry_failed_models.outputs.retry_matrix) }}
|
model: ${{ fromJson(needs.retry_failed_models.outputs.retry_matrix) }}
|
||||||
@@ -158,9 +161,146 @@ jobs:
|
|||||||
is_20hz: ${{ matrix.model.is_20hz }}
|
is_20hz: ${{ matrix.model.is_20hz }}
|
||||||
recompiled_dir: ${{ needs.setup.outputs.recompiled_dir }}
|
recompiled_dir: ${{ needs.setup.outputs.recompiled_dir }}
|
||||||
json_version: ${{ needs.setup.outputs.json_version }}
|
json_version: ${{ needs.setup.outputs.json_version }}
|
||||||
target_hardware: ${{ github.event.inputs.target_hardware }}
|
|
||||||
artifact_suffix: -retry
|
artifact_suffix: -retry
|
||||||
hf_repo: ${{ github.event.inputs.hf_repo }}
|
|
||||||
set_min_version: ${{ github.event.inputs.set_min_version }}
|
|
||||||
tinygrad_ref: ${{ needs.setup.outputs.tinygrad_ref }}
|
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
|
publish_models:
|
||||||
|
name: Publish models sequentially
|
||||||
|
needs: [setup, get_and_build, retry_failed_models, retry_get_and_build]
|
||||||
|
if: ${{ !cancelled() && (needs.get_and_build.result != 'failure' || needs.retry_get_and_build.result == 'success' || (needs.retry_failed_models.outputs.retry_matrix != '[]' && needs.retry_failed_models.outputs.retry_matrix != '')) }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
max-parallel: 1
|
||||||
|
matrix:
|
||||||
|
model: ${{ fromJson(needs.setup.outputs.model_matrix) }}
|
||||||
|
env:
|
||||||
|
RECOMPILED_DIR: recompiled${{ needs.setup.outputs.recompiled_dir }}
|
||||||
|
JSON_FILE: ${{ needs.setup.outputs.json_file }}
|
||||||
|
ARTIFACT_NAME_INPUT: ${{ matrix.model.display_name }}
|
||||||
|
steps:
|
||||||
|
- name: Set up SSH
|
||||||
|
uses: webfactory/ssh-agent@v0.9.0
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.GITLAB_SSH_PRIVATE_KEY }}
|
||||||
|
|
||||||
|
- name: Add GitLab.com SSH key to known_hosts
|
||||||
|
run: |
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
- name: Clone GitLab docs repo
|
||||||
|
env:
|
||||||
|
GIT_SSH_COMMAND: 'ssh -o UserKnownHostsFile=~/.ssh/known_hosts'
|
||||||
|
run: |
|
||||||
|
echo "Cloning GitLab"
|
||||||
|
git clone --depth 1 --filter=tree:0 --sparse git@gitlab.com:sunnypilot/public/${{ vars.MODELS_GITLAB }} gitlab_docs
|
||||||
|
cd gitlab_docs
|
||||||
|
echo "checkout models/${RECOMPILED_DIR}"
|
||||||
|
git sparse-checkout set --no-cone models/${RECOMPILED_DIR}
|
||||||
|
git checkout main
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
- name: Checkout docs repo
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: sunnypilot/sunnypilot-models
|
||||||
|
ref: gh-pages
|
||||||
|
path: docs
|
||||||
|
ssh-key: ${{ secrets.CI_SUNNYPILOT_DOCS_PRIVATE_KEY }}
|
||||||
|
|
||||||
|
- name: Validate recompiled dir and JSON version
|
||||||
|
run: |
|
||||||
|
if [ ! -d "gitlab_docs/models/$RECOMPILED_DIR" ]; then
|
||||||
|
echo "Recompiled dir $RECOMPILED_DIR does not exist in GitLab repo"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ ! -f "$JSON_FILE" ]; then
|
||||||
|
echo "JSON file $JSON_FILE does not exist!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Download artifact name file
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: artifact-name-${{ env.ARTIFACT_NAME_INPUT }}
|
||||||
|
path: artifact_name
|
||||||
|
|
||||||
|
- name: Read artifact name
|
||||||
|
id: read-artifact-name
|
||||||
|
run: |
|
||||||
|
ARTIFACT_NAME=$(cat artifact_name/artifact_name.txt)
|
||||||
|
echo "artifact_name=$ARTIFACT_NAME" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Download model artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ steps.read-artifact-name.outputs.artifact_name }}
|
||||||
|
path: output
|
||||||
|
|
||||||
|
- name: Remove onnx files bc not needed for recompiled dir since they already exist from single build
|
||||||
|
run: |
|
||||||
|
find output -type f -name '*.onnx' -delete
|
||||||
|
find output -type f -name 'big_*.pkl' -delete
|
||||||
|
find output -type f -name 'dmonitoring_model_tinygrad.pkl' -delete
|
||||||
|
|
||||||
|
- name: Copy model artifacts to gitlab
|
||||||
|
env:
|
||||||
|
ARTIFACT_NAME: ${{ steps.read-artifact-name.outputs.artifact_name }}
|
||||||
|
run: |
|
||||||
|
ARTIFACT_DIR="gitlab_docs/models/${RECOMPILED_DIR}/${ARTIFACT_NAME}"
|
||||||
|
mkdir -p "$ARTIFACT_DIR"
|
||||||
|
for path in output/*; do
|
||||||
|
if [ "$(basename "$path")" = "artifact_name.txt" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
name="$(basename "$path")"
|
||||||
|
if [ -d "$path" ]; then
|
||||||
|
mkdir -p "$ARTIFACT_DIR/$name"
|
||||||
|
cp -r "$path"/* "$ARTIFACT_DIR/$name/"
|
||||||
|
echo "Copied dir $name -> $ARTIFACT_DIR/$name"
|
||||||
|
else
|
||||||
|
cp "$path" "$ARTIFACT_DIR/"
|
||||||
|
echo "Copied file $name -> $ARTIFACT_DIR/"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Push recompiled dir to GitLab
|
||||||
|
env:
|
||||||
|
GITLAB_SSH_PRIVATE_KEY: ${{ secrets.GITLAB_SSH_PRIVATE_KEY }}
|
||||||
|
run: |
|
||||||
|
cd gitlab_docs
|
||||||
|
git checkout main
|
||||||
|
git pull origin main
|
||||||
|
for d in models/"$RECOMPILED_DIR"/*/; do
|
||||||
|
git sparse-checkout add "$d"
|
||||||
|
done
|
||||||
|
git add models/"$RECOMPILED_DIR"
|
||||||
|
git config --global user.name "GitHub Action"
|
||||||
|
git config --global user.email "action@github.com"
|
||||||
|
git commit -m "Update $RECOMPILED_DIR with model from build-all-tinygrad-models" || echo "No changes to commit"
|
||||||
|
git push origin main
|
||||||
|
- run: |
|
||||||
|
cd docs
|
||||||
|
git pull origin gh-pages
|
||||||
|
|
||||||
|
- name: update json
|
||||||
|
run: |
|
||||||
|
ARGS=""
|
||||||
|
[ -n "${{ inputs.set_min_version }}" ] && ARGS="$ARGS --set-min-version \"${{ inputs.set_min_version }}\""
|
||||||
|
ARGS="$ARGS --sort-by-date"
|
||||||
|
ARGS="$ARGS --tinygrad-ref \"${{ needs.setup.outputs.tinygrad_ref }}\""
|
||||||
|
eval python3 docs/json_parser.py \
|
||||||
|
--json-path "$JSON_FILE" \
|
||||||
|
--recompiled-dir "gitlab_docs/models/$RECOMPILED_DIR" \
|
||||||
|
$ARGS
|
||||||
|
|
||||||
|
- name: Push updated json to GitHub
|
||||||
|
run: |
|
||||||
|
cd docs
|
||||||
|
git config --global user.name "GitHub Action"
|
||||||
|
git config --global user.email "action@github.com"
|
||||||
|
git checkout gh-pages
|
||||||
|
git add docs/"$(basename $JSON_FILE)"
|
||||||
|
git commit -m "Update $(basename $JSON_FILE) after recompiling model" || echo "No changes to commit"
|
||||||
|
git push origin gh-pages
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
name: Build default big model
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
env:
|
|
||||||
HF_REPO: sunnypilot/sunnypilot_models_v1
|
|
||||||
HF_DEFAULTS_PATH: models/defaults/big
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build_model:
|
|
||||||
uses: ./.github/workflows/sunnypilot-build-model.yaml
|
|
||||||
with:
|
|
||||||
upstream_branch: ${{ github.sha }}
|
|
||||||
custom_name: default-big-model
|
|
||||||
target_hardware: usbgpu
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
upload_defaults:
|
|
||||||
needs: build_model
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
- run: git lfs pull -I "openpilot/selfdrive/modeld/models/big_driving_supercombo.onnx"
|
|
||||||
|
|
||||||
- name: Install huggingface_hub
|
|
||||||
run: pip install --upgrade "huggingface_hub>=0.22.0"
|
|
||||||
|
|
||||||
- name: Download artifact name
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: artifact-name-default-big-model
|
|
||||||
path: artifact_name
|
|
||||||
|
|
||||||
- name: Read artifact name
|
|
||||||
id: artifact
|
|
||||||
run: |
|
|
||||||
ARTIFACT_NAME=$(cat artifact_name/artifact_name.txt)
|
|
||||||
echo "artifact_name=$ARTIFACT_NAME" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Download model artifact
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: ${{ steps.artifact.outputs.artifact_name }}
|
|
||||||
path: output
|
|
||||||
|
|
||||||
- name: Upload model to HF defaults
|
|
||||||
env:
|
|
||||||
HF_OIDC_RESOURCE: datasets/${{ env.HF_REPO }}
|
|
||||||
ARTIFACT_NAME: ${{ steps.artifact.outputs.artifact_name }}
|
|
||||||
run: |
|
|
||||||
rm -f output/artifact_name.txt
|
|
||||||
hf upload ${{ env.HF_REPO }} \
|
|
||||||
output/ \
|
|
||||||
"${HF_DEFAULTS_PATH}/${ARTIFACT_NAME}/" \
|
|
||||||
--repo-type=dataset
|
|
||||||
|
|
||||||
- name: Get tinygrad ref and ONNX hash
|
|
||||||
id: meta
|
|
||||||
run: |
|
|
||||||
export PYTHONPATH=$(pwd)
|
|
||||||
echo "tinygrad_ref=$(python3 openpilot/sunnypilot/models/tinygrad_ref.py)" >> $GITHUB_OUTPUT
|
|
||||||
echo "onnx_sha256=$(sha256sum openpilot/selfdrive/modeld/models/big_driving_supercombo.onnx | cut -d' ' -f1)" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Update default_models.json on HF
|
|
||||||
env:
|
|
||||||
HF_OIDC_RESOURCE: datasets/${{ env.HF_REPO }}
|
|
||||||
ARTIFACT_NAME: ${{ steps.artifact.outputs.artifact_name }}
|
|
||||||
run: |
|
|
||||||
python3 release/ci/upload_default_model.py \
|
|
||||||
--hf-repo "${{ env.HF_REPO }}" \
|
|
||||||
--hf-defaults-path "${{ env.HF_DEFAULTS_PATH }}" \
|
|
||||||
--artifact-name "$ARTIFACT_NAME" \
|
|
||||||
--metadata-path "output/metadata.json" \
|
|
||||||
--onnx-sha256 "${{ steps.meta.outputs.onnx_sha256 }}" \
|
|
||||||
--tinygrad-ref "${{ steps.meta.outputs.tinygrad_ref }}"
|
|
||||||
@@ -12,11 +12,11 @@ on:
|
|||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
recompiled_dir:
|
recompiled_dir:
|
||||||
description: 'Existing recompiled directory number (e.g. 1 for recompiled1)'
|
description: 'Existing recompiled directory number (e.g. 3 for recompiled3)'
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
json_version:
|
json_version:
|
||||||
description: 'driving_models version number to update (e.g. 18 for driving_models_v18.json)'
|
description: 'driving_models version number to update (e.g. 5 for driving_models_v5.json)'
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
artifact_suffix:
|
artifact_suffix:
|
||||||
@@ -29,24 +29,11 @@ on:
|
|||||||
required: false
|
required: false
|
||||||
type: boolean
|
type: boolean
|
||||||
default: true
|
default: true
|
||||||
target_hardware:
|
bypass_push:
|
||||||
description: 'Hardware target to compile for (qcom or usbgpu)'
|
description: 'Bypass pushing to GitLab for build-all'
|
||||||
required: false
|
required: false
|
||||||
type: string
|
default: true
|
||||||
default: 'qcom'
|
type: boolean
|
||||||
hf_repo:
|
|
||||||
description: 'Hugging Face dataset repository (e.g. sunnypilot/sunnypilot_models_v1)'
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
default: 'sunnypilot/sunnypilot_models_v1'
|
|
||||||
set_min_version:
|
|
||||||
description: 'Minimum selector version'
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
tinygrad_ref:
|
|
||||||
description: 'Tinygrad reference'
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
upstream_branch:
|
upstream_branch:
|
||||||
@@ -76,11 +63,12 @@ on:
|
|||||||
default: 'None'
|
default: 'None'
|
||||||
options:
|
options:
|
||||||
- None
|
- None
|
||||||
- Master Models
|
- Simple Plan Models
|
||||||
- Release Models
|
- Space Lab Models
|
||||||
- 2026 World Models
|
- TR Models
|
||||||
- 2026 Deep RL Models
|
- DTR Models
|
||||||
- Custom Merge Models
|
- Custom Merge Models
|
||||||
|
- FOF series models
|
||||||
- Other
|
- Other
|
||||||
custom_model_folder:
|
custom_model_folder:
|
||||||
description: 'Custom model folder name (if "Other" selected)'
|
description: 'Custom model folder name (if "Other" selected)'
|
||||||
@@ -94,22 +82,9 @@ on:
|
|||||||
description: 'Minimum selector version'
|
description: 'Minimum selector version'
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
target_hardware:
|
|
||||||
description: 'Hardware target to compile for'
|
|
||||||
required: false
|
|
||||||
type: choice
|
|
||||||
default: 'qcom'
|
|
||||||
options:
|
|
||||||
- qcom
|
|
||||||
- usbgpu
|
|
||||||
hf_repo:
|
|
||||||
description: 'Hugging Face dataset repository'
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
default: 'sunnypilot/sunnypilot_models_v1'
|
|
||||||
env:
|
env:
|
||||||
RECOMPILED_DIR: recompiled${{ inputs.recompiled_dir }}
|
RECOMPILED_DIR: recompiled${{ inputs.recompiled_dir }}
|
||||||
JSON_FILE: docs/docs/driving_models_${{ inputs.target_hardware == 'usbgpu' && 'usbgpu_v' || 'v' }}${{ inputs.json_version }}.json
|
JSON_FILE: docs/docs/driving_models_v${{ inputs.json_version }}.json
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_model:
|
build_model:
|
||||||
@@ -119,20 +94,38 @@ jobs:
|
|||||||
custom_name: ${{ inputs.custom_name || inputs.upstream_branch }}
|
custom_name: ${{ inputs.custom_name || inputs.upstream_branch }}
|
||||||
is_20hz: ${{ inputs.is_20hz }}
|
is_20hz: ${{ inputs.is_20hz }}
|
||||||
artifact_suffix: ${{ inputs.artifact_suffix }}
|
artifact_suffix: ${{ inputs.artifact_suffix }}
|
||||||
target_hardware: ${{ inputs.target_hardware }}
|
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
publish_model:
|
publish_model:
|
||||||
if: ${{ !cancelled() && needs.build_model.result == 'success' }}
|
if: ${{ !inputs.bypass_push && !cancelled() }}
|
||||||
concurrency:
|
concurrency:
|
||||||
group: hf-push-${{ inputs.recompiled_dir }}
|
group: gitlab-push-${{ inputs.recompiled_dir }}
|
||||||
cancel-in-progress: false
|
cancel-in-progress: false
|
||||||
needs: build_model
|
needs: build_model
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
|
||||||
id-token: write
|
|
||||||
contents: write
|
|
||||||
steps:
|
steps:
|
||||||
|
- name: Set up SSH
|
||||||
|
uses: webfactory/ssh-agent@v0.9.0
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.GITLAB_SSH_PRIVATE_KEY }}
|
||||||
|
|
||||||
|
- name: Add GitLab.com SSH key to known_hosts
|
||||||
|
run: |
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
- name: Clone GitLab docs repo
|
||||||
|
env:
|
||||||
|
GIT_SSH_COMMAND: 'ssh -o UserKnownHostsFile=~/.ssh/known_hosts'
|
||||||
|
run: |
|
||||||
|
echo "Cloning GitLab"
|
||||||
|
git clone --depth 1 --filter=tree:0 --sparse git@gitlab.com:sunnypilot/public/${{ vars.MODELS_GITLAB }} gitlab_docs
|
||||||
|
cd gitlab_docs
|
||||||
|
echo "checkout models/${RECOMPILED_DIR}"
|
||||||
|
git sparse-checkout set --no-cone models/${RECOMPILED_DIR}
|
||||||
|
git checkout main
|
||||||
|
cd ..
|
||||||
|
|
||||||
- name: Checkout docs repo
|
- name: Checkout docs repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -141,28 +134,16 @@ jobs:
|
|||||||
path: docs
|
path: docs
|
||||||
ssh-key: ${{ secrets.CI_SUNNYPILOT_DOCS_PRIVATE_KEY }}
|
ssh-key: ${{ secrets.CI_SUNNYPILOT_DOCS_PRIVATE_KEY }}
|
||||||
|
|
||||||
- name: Install huggingface_hub
|
- name: Validate recompiled dir and JSON version
|
||||||
run: pip install --upgrade "huggingface_hub>=0.22.0"
|
|
||||||
|
|
||||||
- name: Validate hf_repo and JSON version
|
|
||||||
env:
|
|
||||||
HF_OIDC_RESOURCE: datasets/${{ inputs.hf_repo }}
|
|
||||||
run: |
|
run: |
|
||||||
|
if [ ! -d "gitlab_docs/models/$RECOMPILED_DIR" ]; then
|
||||||
|
echo "Recompiled dir $RECOMPILED_DIR does not exist in GitLab repo"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
if [ ! -f "$JSON_FILE" ]; then
|
if [ ! -f "$JSON_FILE" ]; then
|
||||||
echo "JSON file $JSON_FILE does not exist!"
|
echo "JSON file $JSON_FILE does not exist!"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
python3 -c "
|
|
||||||
import sys
|
|
||||||
from huggingface_hub import HfApi
|
|
||||||
try:
|
|
||||||
api = HfApi()
|
|
||||||
api.repo_info(repo_id=sys.argv[1], repo_type='dataset')
|
|
||||||
print(f'Success: Repo {sys.argv[1]} exists.')
|
|
||||||
except Exception as e:
|
|
||||||
print('HF validation failed:', e)
|
|
||||||
sys.exit(1)
|
|
||||||
" "${{ inputs.hf_repo }}"
|
|
||||||
|
|
||||||
- name: Download artifact name file
|
- name: Download artifact name file
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
@@ -182,26 +163,49 @@ jobs:
|
|||||||
name: ${{ steps.read-artifact-name.outputs.artifact_name }}
|
name: ${{ steps.read-artifact-name.outputs.artifact_name }}
|
||||||
path: output
|
path: output
|
||||||
|
|
||||||
- name: Create models folder
|
- name: Remove unwanted files
|
||||||
|
run: |
|
||||||
|
find output -type f -name 'dmonitoring_model_tinygrad.pkl' -delete
|
||||||
|
find output -type f -name 'dmonitoring_model.onnx' -delete
|
||||||
|
|
||||||
|
- name: Copy model artifact(s) to GitLab recompiled dir
|
||||||
env:
|
env:
|
||||||
ARTIFACT_NAME: ${{ steps.read-artifact-name.outputs.artifact_name }}
|
ARTIFACT_NAME: ${{ steps.read-artifact-name.outputs.artifact_name }}
|
||||||
run: |
|
run: |
|
||||||
mkdir -p "local_models/${RECOMPILED_DIR}/${ARTIFACT_NAME}"
|
ARTIFACT_DIR="gitlab_docs/models/${RECOMPILED_DIR}/${ARTIFACT_NAME}"
|
||||||
cp -r output/* "local_models/${RECOMPILED_DIR}/${ARTIFACT_NAME}/"
|
mkdir -p "$ARTIFACT_DIR"
|
||||||
rm -f "local_models/${RECOMPILED_DIR}/${ARTIFACT_NAME}/artifact_name.txt"
|
for path in output/*; do
|
||||||
|
if [ "$(basename "$path")" = "artifact_name.txt" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
name="$(basename "$path")"
|
||||||
|
if [ -d "$path" ]; then
|
||||||
|
mkdir -p "$ARTIFACT_DIR/$name"
|
||||||
|
cp -r "$path"/* "$ARTIFACT_DIR/$name/"
|
||||||
|
echo "Copied dir $name -> $ARTIFACT_DIR/$name"
|
||||||
|
else
|
||||||
|
cp "$path" "$ARTIFACT_DIR/"
|
||||||
|
echo "Copied file $name -> $ARTIFACT_DIR/"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
- name: Upload to Hugging Face
|
- name: Push recompiled dir to GitLab
|
||||||
env:
|
env:
|
||||||
HF_OIDC_RESOURCE: datasets/${{ inputs.hf_repo }}
|
GITLAB_SSH_PRIVATE_KEY: ${{ secrets.GITLAB_SSH_PRIVATE_KEY }}
|
||||||
ARTIFACT_NAME: ${{ steps.read-artifact-name.outputs.artifact_name }}
|
|
||||||
run: |
|
run: |
|
||||||
hf upload ${{ inputs.hf_repo }} \
|
cd gitlab_docs
|
||||||
output/ \
|
git checkout main
|
||||||
"models/${RECOMPILED_DIR}/${ARTIFACT_NAME}/" \
|
git pull origin main
|
||||||
--repo-type=dataset
|
for d in models/"$RECOMPILED_DIR"/*/; do
|
||||||
|
git sparse-checkout add "$d"
|
||||||
|
done
|
||||||
|
git add models/"$RECOMPILED_DIR"
|
||||||
|
git config --global user.name "GitHub Action"
|
||||||
|
git config --global user.email "action@github.com"
|
||||||
|
git commit -m "Create/Update $RECOMPILED_DIR with new/updated model from build-single-tinygrad-model" || echo "No changes to commit"
|
||||||
|
git push origin main
|
||||||
|
|
||||||
- name: Pull gh-pages
|
- run: |
|
||||||
run: |
|
|
||||||
cd docs
|
cd docs
|
||||||
git pull origin gh-pages
|
git pull origin gh-pages
|
||||||
|
|
||||||
@@ -217,11 +221,9 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
[ -n "${{ inputs.generation }}" ] && ARGS="$ARGS --generation \"${{ inputs.generation }}\""
|
[ -n "${{ inputs.generation }}" ] && ARGS="$ARGS --generation \"${{ inputs.generation }}\""
|
||||||
[ -n "${{ inputs.version }}" ] && ARGS="$ARGS --version \"${{ inputs.version }}\""
|
[ -n "${{ inputs.version }}" ] && ARGS="$ARGS --version \"${{ inputs.version }}\""
|
||||||
[ -n "${{ inputs.set_min_version }}" ] && ARGS="$ARGS --set-min-version \"${{ inputs.set_min_version }}\""
|
|
||||||
[ -n "${{ inputs.tinygrad_ref }}" ] && ARGS="$ARGS --tinygrad-ref \"${{ inputs.tinygrad_ref }}\""
|
|
||||||
eval python3 docs/json_parser.py \
|
eval python3 docs/json_parser.py \
|
||||||
--json-path "$JSON_FILE" \
|
--json-path "$JSON_FILE" \
|
||||||
--recompiled-dir "local_models/$RECOMPILED_DIR" \
|
--recompiled-dir "gitlab_docs/models/$RECOMPILED_DIR" \
|
||||||
--sort-by-date \
|
--sort-by-date \
|
||||||
$ARGS
|
$ARGS
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ on:
|
|||||||
- master
|
- master
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- 'openpilot/cereal/**'
|
- 'cereal/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
@@ -30,25 +30,11 @@ jobs:
|
|||||||
- name: Checkout sunnypilot cereal
|
- name: Checkout sunnypilot cereal
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
sparse-checkout: |
|
sparse-checkout: cereal
|
||||||
openpilot/cereal
|
|
||||||
uv.lock
|
|
||||||
submodules: false
|
|
||||||
|
|
||||||
- name: Init sunnypilot opendbc submodule
|
- name: Init sunnypilot opendbc submodule
|
||||||
run: git submodule update --init --depth 1 opendbc_repo
|
run: git submodule update --init --depth 1 opendbc_repo
|
||||||
|
|
||||||
- name: Locate sunnypilot capnp import paths
|
|
||||||
id: locate-sp-capnp
|
|
||||||
run: |
|
|
||||||
SP_IMPORT_ARGS=""
|
|
||||||
SP_CAR_CAPNP=$(find opendbc_repo -maxdepth 4 -name car.capnp -path '*/opendbc/car/car.capnp' -printf '%h\n' -quit)
|
|
||||||
if [ -n "$SP_CAR_CAPNP" ]; then
|
|
||||||
SP_IMPORT_ARGS="-I $SP_CAR_CAPNP"
|
|
||||||
echo "Found sunnypilot car.capnp at: $SP_CAR_CAPNP"
|
|
||||||
fi
|
|
||||||
echo "import_args=$SP_IMPORT_ARGS" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Checkout upstream openpilot
|
- name: Checkout upstream openpilot
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
@@ -79,19 +65,20 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
echo "import_args=$IMPORT_ARGS" >> "$GITHUB_OUTPUT"
|
echo "import_args=$IMPORT_ARGS" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Install pycapnp
|
- name: Install uv
|
||||||
run: |
|
run: pip install uv
|
||||||
PYCAPNP_VER=$(python3 -c "import re; m=re.search(r'name = \"pycapnp\"\nversion = \"([^\"]+)\"', open('uv.lock').read()); print(m.group(1))")
|
|
||||||
pip install "pycapnp==${PYCAPNP_VER}"
|
|
||||||
|
|
||||||
- name: Generate sunnypilot schema
|
- name: Generate sunnypilot schema
|
||||||
run: |
|
run: |
|
||||||
python3 openpilot/cereal/messaging/tests/validate_sp_cereal_upstream.py \
|
PYCAPNP_VER=$(python3 -c "import re; m=re.search(r'name = \"pycapnp\"\nversion = \"([^\"]+)\"', open('uv.lock').read()); print(m.group(1))")
|
||||||
-g -f /tmp/sp_schema.json --cereal-dir openpilot/cereal \
|
uv run --isolated --with "pycapnp==${PYCAPNP_VER}" \
|
||||||
${{ steps.locate-sp-capnp.outputs.import_args }}
|
python3 cereal/messaging/tests/validate_sp_cereal_upstream.py \
|
||||||
|
-g -f /tmp/sp_schema.json --cereal-dir cereal
|
||||||
|
|
||||||
- name: Validate against upstream
|
- name: Validate against upstream
|
||||||
run: |
|
run: |
|
||||||
python3 openpilot/cereal/messaging/tests/validate_sp_cereal_upstream.py \
|
PYCAPNP_VER=$(python3 -c "import re; m=re.search(r'name = \"pycapnp\"\nversion = \"([^\"]+)\"', open('uv.lock').read()); print(m.group(1))")
|
||||||
|
uv run --isolated --with "pycapnp==${PYCAPNP_VER}" \
|
||||||
|
python3 cereal/messaging/tests/validate_sp_cereal_upstream.py \
|
||||||
-r -f /tmp/sp_schema.json --cereal-dir ${{ steps.locate-capnp.outputs.cereal_dir }} \
|
-r -f /tmp/sp_schema.json --cereal-dir ${{ steps.locate-capnp.outputs.cereal_dir }} \
|
||||||
${{ steps.locate-capnp.outputs.import_args }}
|
${{ steps.locate-capnp.outputs.import_args }}
|
||||||
|
|||||||
@@ -17,42 +17,29 @@ jobs:
|
|||||||
- name: Wait for process replay
|
- name: Wait for process replay
|
||||||
id: wait
|
id: wait
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
uses: lewagon/wait-on-check-action@1d57e2c51a58d812d2765e036a028b6bdb5a6154
|
uses: lewagon/wait-on-check-action@v1.3.4
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
check-name: process replay
|
check-name: process replay
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
allowed-conclusions: success,failure
|
allowed-conclusions: success,failure
|
||||||
wait-interval: 20
|
wait-interval: 20
|
||||||
- name: Get tests run ID
|
|
||||||
if: steps.wait.outcome == 'success'
|
|
||||||
id: tests-run
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
run_id=$(gh api \
|
|
||||||
"repos/${{ github.repository }}/actions/workflows/tests.yaml/runs?event=pull_request&head_sha=${{ github.event.pull_request.head.sha }}&per_page=1" \
|
|
||||||
--jq '.workflow_runs[0].id // empty')
|
|
||||||
if [ -z "$run_id" ]; then
|
|
||||||
echo "No tests.yaml run found for ${{ github.event.pull_request.head.sha }}" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "run-id=$run_id" >> "$GITHUB_OUTPUT"
|
|
||||||
- name: Download diff
|
- name: Download diff
|
||||||
if: steps.wait.outcome == 'success'
|
if: steps.wait.outcome == 'success'
|
||||||
continue-on-error: true
|
uses: dawidd6/action-download-artifact@v6
|
||||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
|
|
||||||
with:
|
with:
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
repository: ${{ github.repository }}
|
workflow: tests.yaml
|
||||||
run-id: ${{ steps.tests-run.outputs.run-id }}
|
workflow_conclusion: ''
|
||||||
|
pr: ${{ github.event.number }}
|
||||||
name: diff_report_${{ github.event.number }}
|
name: diff_report_${{ github.event.number }}
|
||||||
path: .
|
path: .
|
||||||
|
allow_forks: true
|
||||||
- name: Comment on PR
|
- name: Comment on PR
|
||||||
if: steps.wait.outcome == 'success' && hashFiles('diff_report.txt') != ''
|
if: steps.wait.outcome == 'success'
|
||||||
uses: thollander/actions-comment-pull-request@24bffb9b452ba05a4f3f77933840a6a841d1b32b
|
uses: thollander/actions-comment-pull-request@v2
|
||||||
with:
|
with:
|
||||||
file-path: diff_report.txt
|
filePath: diff_report.txt
|
||||||
comment-tag: diff_report
|
comment_tag: diff_report
|
||||||
pr-number: ${{ github.event.number }}
|
pr_number: ${{ github.event.number }}
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
@@ -15,11 +15,6 @@ concurrency:
|
|||||||
group: docs-tests-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
|
group: docs-tests-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
env:
|
|
||||||
GIT_CONFIG_COUNT: 1
|
|
||||||
GIT_CONFIG_KEY_0: lfs.fetchexclude
|
|
||||||
GIT_CONFIG_VALUE_0: openpilot/selfdrive/modeld/models/big_driving_supercombo.onnx
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
docs:
|
docs:
|
||||||
name: build docs
|
name: build docs
|
||||||
@@ -27,7 +22,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: commaai/timeout@v1
|
- uses: commaai/timeout@v1
|
||||||
|
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
|
|
||||||
@@ -35,10 +30,11 @@ jobs:
|
|||||||
- name: Build docs
|
- name: Build docs
|
||||||
run: |
|
run: |
|
||||||
git lfs pull
|
git lfs pull
|
||||||
python docs/serve.py --build
|
pip install zensical
|
||||||
|
python scripts/docs.py build
|
||||||
|
|
||||||
# Push to docs.comma.ai
|
# Push to docs.comma.ai
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v6
|
||||||
if: github.ref == 'refs/heads/master' && github.repository == 'sunnypilot/sunnypilot'
|
if: github.ref == 'refs/heads/master' && github.repository == 'sunnypilot/sunnypilot'
|
||||||
with:
|
with:
|
||||||
path: openpilot-docs
|
path: openpilot-docs
|
||||||
@@ -49,14 +45,14 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
source tools/release/identity.sh
|
source release/identity.sh
|
||||||
|
|
||||||
cd openpilot-docs
|
cd openpilot-docs
|
||||||
git checkout --orphan tmp
|
git checkout --orphan tmp
|
||||||
git rm -rf .
|
git rm -rf .
|
||||||
|
|
||||||
# copy over docs
|
# copy over docs
|
||||||
cp -r ../docs/_site/ docs/
|
cp -r ../docs_site/ docs/
|
||||||
|
|
||||||
# GitHub pages config
|
# GitHub pages config
|
||||||
touch docs/.nojekyll
|
touch docs/.nojekyll
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ jobs:
|
|||||||
contents: write
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- name: Delete stale Jenkins branches
|
- name: Delete stale Jenkins branches
|
||||||
uses: actions/github-script@v9
|
uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const cutoff = Date.now() - 24 * 60 * 60 * 1000;
|
const cutoff = Date.now() - 24 * 60 * 60 * 1000;
|
||||||
@@ -52,7 +52,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Check for trigger phrase
|
- name: Check for trigger phrase
|
||||||
id: check_comment
|
id: check_comment
|
||||||
uses: actions/github-script@v9
|
uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const triggerPhrase = "trigger-jenkins";
|
const triggerPhrase = "trigger-jenkins";
|
||||||
@@ -72,7 +72,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
if: steps.check_comment.outputs.result == 'true'
|
if: steps.check_comment.outputs.result == 'true'
|
||||||
uses: actions/checkout@v7
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
ref: refs/pull/${{ github.event.issue.number }}/head
|
ref: refs/pull/${{ github.event.issue.number }}/head
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Delete trigger comment
|
- name: Delete trigger comment
|
||||||
if: steps.check_comment.outputs.result == 'true' && always()
|
if: steps.check_comment.outputs.result == 'true' && always()
|
||||||
uses: actions/github-script@v9
|
uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
await github.rest.issues.deleteComment({
|
await github.rest.issues.deleteComment({
|
||||||
|
|||||||
@@ -65,21 +65,8 @@ jobs:
|
|||||||
echo ' pushurl = ${{ env.LFS_PUSH_URL }}' >> .lfsconfig
|
echo ' pushurl = ${{ env.LFS_PUSH_URL }}' >> .lfsconfig
|
||||||
echo ' locksverify = false' >> .lfsconfig
|
echo ' locksverify = false' >> .lfsconfig
|
||||||
|
|
||||||
- name: Configure LFS transfer settings
|
|
||||||
run: |
|
|
||||||
git config lfs.activitytimeout 300
|
|
||||||
git config lfs.transfer.maxretries 5
|
|
||||||
git config lfs.concurrenttransfers 4
|
|
||||||
|
|
||||||
- name: Push LFS
|
- name: Push LFS
|
||||||
id: sync-and-commit
|
id: sync-and-commit
|
||||||
run: |
|
run: |
|
||||||
git lfs ls-files -l
|
git lfs ls-files -l
|
||||||
for attempt in 1 2 3; do
|
git lfs push --all origin
|
||||||
echo "Push attempt $attempt..."
|
|
||||||
git lfs push --all origin && exit 0
|
|
||||||
echo "Attempt $attempt failed, retrying in 30s..."
|
|
||||||
sleep 30
|
|
||||||
done
|
|
||||||
echo "All push attempts failed"
|
|
||||||
exit 1
|
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
name: "model review"
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, reopened, synchronize]
|
||||||
|
paths:
|
||||||
|
- 'selfdrive/modeld/models/*.onnx'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
comment:
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.repository == 'commaai/openpilot'
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- name: Checkout master
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
ref: master
|
||||||
|
path: base
|
||||||
|
- run: git lfs pull
|
||||||
|
- run: cd base && git lfs pull
|
||||||
|
|
||||||
|
- name: scripts/reporter.py
|
||||||
|
id: report
|
||||||
|
run: |
|
||||||
|
echo "content<<EOF" >> $GITHUB_OUTPUT
|
||||||
|
echo "## Model Review" >> $GITHUB_OUTPUT
|
||||||
|
PYTHONPATH=${{ github.workspace }} MASTER_PATH=${{ github.workspace }}/base python scripts/reporter.py >> $GITHUB_OUTPUT
|
||||||
|
echo "EOF" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Post model report comment
|
||||||
|
uses: marocchino/sticky-pull-request-comment@baa7203ed60924babbe5dcd0ac8eae3b66ec5e16
|
||||||
|
with:
|
||||||
|
header: model-review
|
||||||
|
message: ${{ steps.report.outputs.content }}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
name: prebuilt
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 * * * *'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
BUILD: release/ci/docker_build_sp.sh
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build_prebuilt:
|
||||||
|
name: build prebuilt
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.repository == 'sunnypilot/sunnypilot'
|
||||||
|
env:
|
||||||
|
PUSH_IMAGE: true
|
||||||
|
permissions:
|
||||||
|
checks: read
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
steps:
|
||||||
|
- name: Wait for green check mark
|
||||||
|
if: ${{ github.event_name != 'workflow_dispatch' }}
|
||||||
|
uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc
|
||||||
|
with:
|
||||||
|
ref: master
|
||||||
|
wait-interval: 30
|
||||||
|
running-workflow-name: 'build prebuilt'
|
||||||
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
check-regexp: ^((?!.*(build master-ci|create badges).*).)*$
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- run: git lfs pull
|
||||||
|
- name: Build and Push docker image
|
||||||
|
run: |
|
||||||
|
$DOCKER_LOGIN
|
||||||
|
eval "$BUILD"
|
||||||
@@ -4,11 +4,6 @@ on:
|
|||||||
- cron: '0 9 * * *'
|
- cron: '0 9 * * *'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
|
||||||
GIT_CONFIG_COUNT: 1
|
|
||||||
GIT_CONFIG_KEY_0: lfs.fetchexclude
|
|
||||||
GIT_CONFIG_VALUE_0: openpilot/selfdrive/modeld/models/big_driving_supercombo.onnx
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build___nightly:
|
build___nightly:
|
||||||
name: build __nightly
|
name: build __nightly
|
||||||
@@ -20,17 +15,17 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Wait for green check mark
|
- name: Wait for green check mark
|
||||||
if: ${{ github.event_name == 'schedule' }}
|
if: ${{ github.event_name == 'schedule' }}
|
||||||
uses: lewagon/wait-on-check-action@1d57e2c51a58d812d2765e036a028b6bdb5a6154
|
uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc
|
||||||
with:
|
with:
|
||||||
ref: master
|
ref: master
|
||||||
wait-interval: 30
|
wait-interval: 30
|
||||||
running-workflow-name: 'build __nightly'
|
running-workflow-name: 'build __nightly'
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
check-regexp: ^((?!.*(build prebuilt|create badges).*).)*$
|
check-regexp: ^((?!.*(build prebuilt|create badges).*).)*$
|
||||||
- uses: actions/checkout@v4 # checkout version > v4 breaks nightly release script
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- run: ./tools/op.sh setup
|
- run: ./tools/op.sh setup
|
||||||
- name: Push __nightly
|
- name: Push __nightly
|
||||||
run: BRANCH=__nightly tools/release/build_stripped.sh
|
run: BRANCH=__nightly release/build_stripped.sh
|
||||||
|
|||||||
@@ -3,25 +3,18 @@ name: repo maintenance
|
|||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "0 14 * * 1" # every Monday at 2am UTC (6am PST)
|
- cron: "0 14 * * 1" # every Monday at 2am UTC (6am PST)
|
||||||
pull_request:
|
|
||||||
types: [closed]
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
PYTHONPATH: ${{ github.workspace }}
|
PYTHONPATH: ${{ github.workspace }}
|
||||||
GIT_CONFIG_COUNT: 1
|
|
||||||
GIT_CONFIG_KEY_0: lfs.fetchexclude
|
|
||||||
GIT_CONFIG_VALUE_0: openpilot/selfdrive/modeld/models/big_driving_supercombo.onnx
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
package_updates:
|
package_updates:
|
||||||
name: package_updates
|
name: package_updates
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: >-
|
if: github.repository == 'sunnypilot/sunnypilot'
|
||||||
github.repository == 'sunnypilot/sunnypilot' &&
|
|
||||||
(github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- run: ./tools/op.sh setup
|
- run: ./tools/op.sh setup
|
||||||
@@ -57,10 +50,10 @@ jobs:
|
|||||||
git add .
|
git add .
|
||||||
- name: update car docs
|
- name: update car docs
|
||||||
run: |
|
run: |
|
||||||
python openpilot/selfdrive/car/docs.py
|
python selfdrive/car/docs.py
|
||||||
git add docs/CARS.md
|
git add docs/CARS.md
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1
|
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0
|
||||||
with:
|
with:
|
||||||
author: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
|
author: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
|
||||||
token: ${{ github.repository == 'commaai/openpilot' && secrets.ACTIONS_CREATE_PR_PAT || secrets.GITHUB_TOKEN }}
|
token: ${{ github.repository == 'commaai/openpilot' && secrets.ACTIONS_CREATE_PR_PAT || secrets.GITHUB_TOKEN }}
|
||||||
@@ -82,51 +75,3 @@ jobs:
|
|||||||
${{ steps.pip_tree.outputs.PIP_TREE }}
|
${{ steps.pip_tree.outputs.PIP_TREE }}
|
||||||
```
|
```
|
||||||
labels: bot
|
labels: bot
|
||||||
|
|
||||||
cleanup_closed_branches:
|
|
||||||
if: github.repository == 'commaai/openpilot' && github.event_name == 'pull_request'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: read
|
|
||||||
steps:
|
|
||||||
- uses: actions/github-script@v9
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
const { owner, repo } = context.repo;
|
|
||||||
const upstream = `${owner}/${repo}`;
|
|
||||||
|
|
||||||
const closed = context.payload.pull_request;
|
|
||||||
if (closed) {
|
|
||||||
if (closed.head.repo?.full_name === upstream) {
|
|
||||||
await github.rest.git.deleteRef({ owner, repo, ref: `heads/${closed.head.ref}` }).catch(console.log);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for await (const response of github.paginate.iterator(github.rest.pulls.list, {
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
state: 'closed',
|
|
||||||
per_page: 100,
|
|
||||||
})) {
|
|
||||||
for (const pr of response.data) {
|
|
||||||
if (pr.head.repo?.full_name !== upstream) continue;
|
|
||||||
|
|
||||||
const branch = pr.head.ref;
|
|
||||||
try {
|
|
||||||
await github.rest.git.deleteRef({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
ref: `heads/${branch}`,
|
|
||||||
});
|
|
||||||
console.log(`Deleted branch ${branch} (PR #${pr.number})`);
|
|
||||||
} catch (error) {
|
|
||||||
if (error.status === 422 || error.status === 403) {
|
|
||||||
console.log(`Skipping branch ${branch} (PR #${pr.number}): ${error.message}`);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ env:
|
|||||||
SCONS_CACHE_DIR: ${{ github.workspace }}/release/ci/scons_cache
|
SCONS_CACHE_DIR: ${{ github.workspace }}/release/ci/scons_cache
|
||||||
UPSTREAM_REPO: "commaai/openpilot"
|
UPSTREAM_REPO: "commaai/openpilot"
|
||||||
TINYGRAD_PATH: ${{ github.workspace }}/tinygrad_repo
|
TINYGRAD_PATH: ${{ github.workspace }}/tinygrad_repo
|
||||||
MODELS_DIR: ${{ github.workspace }}/openpilot/selfdrive/modeld/models
|
MODELS_DIR: ${{ github.workspace }}/selfdrive/modeld/models
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
@@ -30,11 +30,6 @@ on:
|
|||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
default: ''
|
default: ''
|
||||||
target_hardware:
|
|
||||||
description: 'Hardware target to compile for (qcom or usbgpu)'
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
default: 'qcom'
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
upstream_branch:
|
upstream_branch:
|
||||||
@@ -51,14 +46,6 @@ on:
|
|||||||
required: false
|
required: false
|
||||||
type: boolean
|
type: boolean
|
||||||
default: true
|
default: true
|
||||||
target_hardware:
|
|
||||||
description: 'Hardware target to compile for'
|
|
||||||
required: true
|
|
||||||
type: choice
|
|
||||||
options:
|
|
||||||
- qcom
|
|
||||||
- usbgpu
|
|
||||||
default: 'qcom'
|
|
||||||
|
|
||||||
|
|
||||||
run-name: Build model [${{ inputs.custom_name || inputs.upstream_branch }}] from ref [${{ inputs.upstream_branch }}]
|
run-name: Build model [${{ inputs.custom_name || inputs.upstream_branch }}] from ref [${{ inputs.upstream_branch }}]
|
||||||
@@ -80,7 +67,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
repository: commaai/openpilot
|
repository: commaai/openpilot
|
||||||
ref: ${{ inputs.upstream_branch }}
|
ref: ${{ inputs.upstream_branch }}
|
||||||
fetch-depth: 1
|
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
path: openpilot
|
path: openpilot
|
||||||
|
|
||||||
@@ -90,38 +76,26 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
repository: sunnypilot/sunnypilot
|
repository: sunnypilot/sunnypilot
|
||||||
ref: ${{ inputs.upstream_branch }}
|
ref: ${{ inputs.upstream_branch }}
|
||||||
fetch-depth: 1
|
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
path: openpilot
|
path: openpilot
|
||||||
- name: Get commit date
|
- name: Get commit date
|
||||||
id: commit-date
|
id: commit-date
|
||||||
run: |
|
run: |
|
||||||
cd ${{ github.workspace }}/openpilot/openpilot
|
cd ${{ github.workspace }}/openpilot
|
||||||
commit_date=$(git log -1 --format=%cd --date=format:'%B %d, %Y')
|
commit_date=$(git log -1 --format=%cd --date=format:'%B %d, %Y')
|
||||||
echo "model_date=${commit_date}" >> $GITHUB_OUTPUT
|
echo "model_date=${commit_date}" >> $GITHUB_OUTPUT
|
||||||
cat $GITHUB_OUTPUT
|
cat $GITHUB_OUTPUT
|
||||||
- run: |
|
- run: |
|
||||||
cd ${{ github.workspace }}/openpilot/openpilot
|
cd ${{ github.workspace }}/openpilot
|
||||||
if [ "${{ inputs.target_hardware }}" != "usbgpu" ]; then
|
git lfs pull
|
||||||
git lfs pull -X "**/selfdrive/modeld/models/big_*.onnx,**/selfdrive/modeld/models/dmonitoring_*.onnx"
|
|
||||||
rm -f selfdrive/modeld/models/big_*.onnx selfdrive/modeld/models/dmonitoring_*.onnx
|
|
||||||
else
|
|
||||||
git lfs pull -I "**/selfdrive/modeld/models/big_*.onnx" -X ""
|
|
||||||
find selfdrive/modeld/models -name "*.onnx" ! -name "big_*.onnx" -delete
|
|
||||||
fi
|
|
||||||
if grep -lIF "version https://git-lfs.github.com/spec/v1" selfdrive/modeld/models/*.onnx; then
|
|
||||||
echo "::error::the ONNX files above are still LFS pointers, not real models"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
- name: 'Upload Artifact'
|
- name: 'Upload Artifact'
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: models-${{ env.REF }}${{ inputs.artifact_suffix }}
|
name: models-${{ env.REF }}${{ inputs.artifact_suffix }}
|
||||||
path: ${{ github.workspace }}/openpilot/openpilot/selfdrive/modeld/models/*.onnx
|
path: ${{ github.workspace }}/openpilot/selfdrive/modeld/models/*.onnx
|
||||||
if-no-files-found: error
|
|
||||||
|
|
||||||
build_model:
|
build_model:
|
||||||
runs-on: [self-hosted, usbgpu]
|
runs-on: [self-hosted, tici]
|
||||||
needs: get_model
|
needs: get_model
|
||||||
env:
|
env:
|
||||||
MODEL_NAME: ${{ inputs.custom_name || inputs.upstream_branch }} (${{ needs.get_model.outputs.model_date }})
|
MODEL_NAME: ${{ inputs.custom_name || inputs.upstream_branch }} (${{ needs.get_model.outputs.model_date }})
|
||||||
@@ -129,9 +103,24 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 1
|
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
|
- run: git lfs pull
|
||||||
|
- name: Cache SCons
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ${{env.SCONS_CACHE_DIR}}
|
||||||
|
key: scons-${{ runner.os }}-${{ runner.arch }}-${{ github.head_ref || github.ref_name }}-model-${{ github.sha }}
|
||||||
|
# Note: GitHub Actions enforces cache isolation between different build sources (PR builds, workflow dispatches, etc.)
|
||||||
|
# for security. Only caches from the default branch are shared across all builds. This is by design and cannot be overridden.
|
||||||
|
restore-keys: |
|
||||||
|
scons-${{ runner.os }}-${{ runner.arch }}-${{ github.head_ref || github.ref_name }}-model
|
||||||
|
scons-${{ runner.os }}-${{ runner.arch }}-${{ github.head_ref || github.ref_name }}
|
||||||
|
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.MASTER_NEW_BRANCH }}-model
|
||||||
|
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.MASTER_BRANCH }}-model
|
||||||
|
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.MASTER_NEW_BRANCH }}
|
||||||
|
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.MASTER_BRANCH }}
|
||||||
|
scons-${{ runner.os }}-${{ runner.arch }}
|
||||||
|
|
||||||
- name: Set environment variables
|
- name: Set environment variables
|
||||||
id: set-env
|
id: set-env
|
||||||
@@ -139,10 +128,7 @@ jobs:
|
|||||||
# Set up common environment
|
# Set up common environment
|
||||||
source /etc/profile;
|
source /etc/profile;
|
||||||
export UV_PROJECT_ENVIRONMENT=${HOME}/venv
|
export UV_PROJECT_ENVIRONMENT=${HOME}/venv
|
||||||
export UV_PYTHON_PREFERENCE=managed
|
|
||||||
export UV_PYTHON_INSTALL_DIR=${HOME}/uv/python
|
|
||||||
export VIRTUAL_ENV=$UV_PROJECT_ENVIRONMENT
|
export VIRTUAL_ENV=$UV_PROJECT_ENVIRONMENT
|
||||||
uv sync --frozen
|
|
||||||
printenv >> $GITHUB_ENV
|
printenv >> $GITHUB_ENV
|
||||||
if [[ "${{ runner.debug }}" == "1" ]]; then
|
if [[ "${{ runner.debug }}" == "1" ]]; then
|
||||||
cat $GITHUB_OUTPUT
|
cat $GITHUB_OUTPUT
|
||||||
@@ -162,71 +148,41 @@ jobs:
|
|||||||
if [[ "${{ runner.debug }}" == "1" ]]; then
|
if [[ "${{ runner.debug }}" == "1" ]]; then
|
||||||
printenv
|
printenv
|
||||||
fi
|
fi
|
||||||
source ${UV_PROJECT_ENVIRONMENT}/bin/activate
|
|
||||||
PYTHONPATH=$PYTHONPATH:${{ github.workspace }}/ ${{ github.workspace }}/scripts/manage-powersave.py --disable
|
PYTHONPATH=$PYTHONPATH:${{ github.workspace }}/ ${{ github.workspace }}/scripts/manage-powersave.py --disable
|
||||||
rm -rf ${{ env.MODELS_DIR }}/*.onnx*
|
rm -rf ${{ env.MODELS_DIR }}/*.onnx
|
||||||
|
|
||||||
- name: Download model artifacts
|
- name: Download model artifacts
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: models-${{ env.REF }}${{ inputs.artifact_suffix }}
|
name: models-${{ env.REF }}${{ inputs.artifact_suffix }}
|
||||||
path: ${{ env.MODELS_DIR }}
|
path: ${{ github.workspace }}/selfdrive/modeld/models
|
||||||
|
- run: |
|
||||||
|
rm -f ${{ github.workspace }}/selfdrive/modeld/models/{dmonitoring_model,big_driving_policy,big_driving_vision}.onnx
|
||||||
|
|
||||||
- name: Build Model
|
- name: Build Model
|
||||||
run: |
|
run: |
|
||||||
source /etc/profile
|
source /etc/profile
|
||||||
export UV_PROJECT_ENVIRONMENT=${HOME}/venv
|
export UV_PROJECT_ENVIRONMENT=${HOME}/venv
|
||||||
export VIRTUAL_ENV=$UV_PROJECT_ENVIRONMENT
|
export VIRTUAL_ENV=$UV_PROJECT_ENVIRONMENT
|
||||||
source ${UV_PROJECT_ENVIRONMENT}/bin/activate
|
|
||||||
export PYTHONPATH="${PYTHONPATH}:${{ env.TINYGRAD_PATH }}:${{ github.workspace }}"
|
export PYTHONPATH="${PYTHONPATH}:${{ env.TINYGRAD_PATH }}:${{ github.workspace }}"
|
||||||
|
|
||||||
COMPILE_MODELD="${{ github.workspace }}/openpilot/sunnypilot/modeld_v2/compile_modeld.py"
|
COMPILE_MODELD="${{ github.workspace }}/sunnypilot/modeld_v2/compile_modeld.py"
|
||||||
MODEL_SIZE=$(python3 -c "from openpilot.common.transformations.model import MEDMODEL_INPUT_SIZE as s; print(f'{s[0]}x{s[1]}')")
|
MODEL_SIZE=$(python3 -c "from openpilot.common.transformations.model import MEDMODEL_INPUT_SIZE as s; print(f'{s[0]}x{s[1]}')")
|
||||||
CAMERA_RES=$(python3 -c "from openpilot.common.transformations.camera import _ar_ox_fisheye as a, _os_fisheye as o; print(f'{a.width}x{a.height} {o.width}x{o.height}')")
|
CAMERA_RES=$(python3 -c "from openpilot.common.transformations.camera import _ar_ox_fisheye as a, _os_fisheye as o; print(f'{a.width}x{a.height} {o.width}x{o.height}')")
|
||||||
|
TG_FLAGS="DEV=QCOM IMAGE=1 FLOAT16=1 NOLOCALS=1 JIT_BATCH_SIZE=0 OPENPILOT_HACKS=1"
|
||||||
TG_FLAGS_QCOM="DEV=QCOM IMAGE=1 FLOAT16=1 NOLOCALS=1 JIT_BATCH_SIZE=0 OPENPILOT_HACKS=1"
|
|
||||||
if [ "${{ inputs.target_hardware }}" == "usbgpu" ]; then
|
|
||||||
echo "USBGPU build"
|
|
||||||
export USBGPU=1
|
|
||||||
TG_FLAGS="DEBUG=2 DEV=USB+AMD:LLVM WARP_DEV=QCOM FLOAT16=1 JIT_BATCH_SIZE=0 GMMU=0 TC_OPT=2"
|
|
||||||
OUTPUT_PKL="${{ env.MODELS_DIR }}/big_driving_tinygrad.pkl"
|
|
||||||
else
|
|
||||||
echo "QCOM build"
|
|
||||||
TG_FLAGS="$TG_FLAGS_QCOM"
|
|
||||||
OUTPUT_PKL="${{ env.MODELS_DIR }}/driving_tinygrad.pkl"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Generate metadata for all ONNX files
|
# Generate metadata for all ONNX files
|
||||||
find "${{ env.MODELS_DIR }}" -maxdepth 1 -name '*.onnx' | while IFS= read -r onnx_file; do
|
find "${{ env.MODELS_DIR }}" -maxdepth 1 -name '*.onnx' | while IFS= read -r onnx_file; do
|
||||||
echo "Generating metadata: $onnx_file"
|
echo "Generating metadata: $onnx_file"
|
||||||
env ${TG_FLAGS_QCOM} python3 "${{ env.MODELS_DIR }}/../get_model_metadata.py" "$onnx_file" || true
|
env ${TG_FLAGS} python3 "${{ env.MODELS_DIR }}/../get_model_metadata.py" "$onnx_file" || true
|
||||||
done
|
done
|
||||||
|
|
||||||
# Detect model type and build compile args
|
# Detect model type and build compile args
|
||||||
VISION_ONNX=""
|
VISION_ONNX="${{ env.MODELS_DIR }}/driving_vision.onnx"
|
||||||
for f in "${{ env.MODELS_DIR }}/driving_vision.onnx" "${{ env.MODELS_DIR }}/big_driving_vision.onnx"; do
|
POLICY_ONNX="${{ env.MODELS_DIR }}/driving_policy.onnx"
|
||||||
[ -f "$f" ] && VISION_ONNX="$f" && break
|
OFF_POLICY_ONNX="${{ env.MODELS_DIR }}/driving_off_policy.onnx"
|
||||||
done
|
ON_POLICY_ONNX="${{ env.MODELS_DIR }}/driving_on_policy.onnx"
|
||||||
|
SUPERCOMBO_ONNX="${{ env.MODELS_DIR }}/supercombo.onnx"
|
||||||
POLICY_ONNX=""
|
|
||||||
for f in "${{ env.MODELS_DIR }}/driving_policy.onnx" "${{ env.MODELS_DIR }}/big_driving_policy.onnx"; do
|
|
||||||
[ -f "$f" ] && POLICY_ONNX="$f" && break
|
|
||||||
done
|
|
||||||
|
|
||||||
OFF_POLICY_ONNX=""
|
|
||||||
for f in "${{ env.MODELS_DIR }}/driving_off_policy.onnx" "${{ env.MODELS_DIR }}/big_driving_off_policy.onnx"; do
|
|
||||||
[ -f "$f" ] && OFF_POLICY_ONNX="$f" && break
|
|
||||||
done
|
|
||||||
|
|
||||||
ON_POLICY_ONNX=""
|
|
||||||
for f in "${{ env.MODELS_DIR }}/driving_on_policy.onnx" "${{ env.MODELS_DIR }}/big_driving_on_policy.onnx"; do
|
|
||||||
[ -f "$f" ] && ON_POLICY_ONNX="$f" && break
|
|
||||||
done
|
|
||||||
|
|
||||||
SUPERCOMBO_ONNX=""
|
|
||||||
for f in "${{ env.MODELS_DIR }}/supercombo.onnx" "${{ env.MODELS_DIR }}/driving_supercombo.onnx" "${{ env.MODELS_DIR }}/big_supercombo.onnx" "${{ env.MODELS_DIR }}/big_driving_supercombo.onnx"; do
|
|
||||||
[ -f "$f" ] && SUPERCOMBO_ONNX="$f" && break
|
|
||||||
done
|
|
||||||
|
|
||||||
MODEL_TYPE="" ONNX_ARGS="" OUTPUT_NAME=""
|
MODEL_TYPE="" ONNX_ARGS="" OUTPUT_NAME=""
|
||||||
if [ -f "$VISION_ONNX" ]; then
|
if [ -f "$VISION_ONNX" ]; then
|
||||||
@@ -247,15 +203,24 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$MODEL_TYPE" ]; then
|
if [ -n "$MODEL_TYPE" ]; then
|
||||||
echo "Detected: $MODEL_TYPE -> $OUTPUT_PKL"
|
echo "Detected: $MODEL_TYPE -> driving_tinygrad.pkl"
|
||||||
env ${TG_FLAGS} python3 "$COMPILE_MODELD" \
|
env ${TG_FLAGS} python3 "$COMPILE_MODELD" \
|
||||||
--model-type $MODEL_TYPE \
|
--model-type $MODEL_TYPE \
|
||||||
--model-size $MODEL_SIZE \
|
--model-size $MODEL_SIZE \
|
||||||
--camera-resolutions $CAMERA_RES \
|
--camera-resolutions $CAMERA_RES \
|
||||||
$ONNX_ARGS \
|
$ONNX_ARGS \
|
||||||
--output "$OUTPUT_PKL"
|
--output "${{ env.MODELS_DIR }}/driving_tinygrad.pkl"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
- name: Validate Model Outputs
|
||||||
|
run: |
|
||||||
|
source /etc/profile
|
||||||
|
export UV_PROJECT_ENVIRONMENT=${HOME}/venv
|
||||||
|
export VIRTUAL_ENV=$UV_PROJECT_ENVIRONMENT
|
||||||
|
python3 "${{ github.workspace }}/release/ci/model_generator.py" \
|
||||||
|
--validate-only \
|
||||||
|
--model-dir "${{ env.MODELS_DIR }}"
|
||||||
|
|
||||||
- name: Prepare Output
|
- name: Prepare Output
|
||||||
run: |
|
run: |
|
||||||
sudo rm -rf ${{ env.OUTPUT_DIR }}
|
sudo rm -rf ${{ env.OUTPUT_DIR }}
|
||||||
@@ -264,8 +229,10 @@ jobs:
|
|||||||
# Copy the model files
|
# Copy the model files
|
||||||
rsync -avm \
|
rsync -avm \
|
||||||
--include='*.dlc' \
|
--include='*.dlc' \
|
||||||
|
--include='*.pkl' \
|
||||||
--include='*.chunk*' \
|
--include='*.chunk*' \
|
||||||
--include='*.chunkmanifest' \
|
--include='*.chunkmanifest' \
|
||||||
|
--include='*.onnx' \
|
||||||
--exclude='*' \
|
--exclude='*' \
|
||||||
--delete-excluded \
|
--delete-excluded \
|
||||||
--chown=comma:comma \
|
--chown=comma:comma \
|
||||||
@@ -297,5 +264,4 @@ jobs:
|
|||||||
- name: Re-enable powersave
|
- name: Re-enable powersave
|
||||||
if: always()
|
if: always()
|
||||||
run: |
|
run: |
|
||||||
source ${UV_PROJECT_ENVIRONMENT}/bin/activate
|
|
||||||
PYTHONPATH=$PYTHONPATH:${{ github.workspace }}/ ${{ github.workspace }}/scripts/manage-powersave.py --enable
|
PYTHONPATH=$PYTHONPATH:${{ github.workspace }}/ ${{ github.workspace }}/scripts/manage-powersave.py --enable
|
||||||
|
|||||||
@@ -4,8 +4,12 @@ env:
|
|||||||
BUILD_DIR: "/data/openpilot"
|
BUILD_DIR: "/data/openpilot"
|
||||||
OUTPUT_DIR: ${{ github.workspace }}/output
|
OUTPUT_DIR: ${{ github.workspace }}/output
|
||||||
CI_DIR: ${{ github.workspace }}/release/ci
|
CI_DIR: ${{ github.workspace }}/release/ci
|
||||||
|
SCONS_CACHE_DIR: ${{ github.workspace }}/release/ci/scons_cache
|
||||||
PUBLIC_REPO_URL: "https://github.com/sunnypilot/sunnypilot"
|
PUBLIC_REPO_URL: "https://github.com/sunnypilot/sunnypilot"
|
||||||
|
|
||||||
|
# Branch configurations
|
||||||
|
STAGING_SOURCE_BRANCH: 'master'
|
||||||
|
|
||||||
# Runtime configuration
|
# Runtime configuration
|
||||||
SOURCE_BRANCH: "${{ github.head_ref || github.ref_name }}"
|
SOURCE_BRANCH: "${{ github.head_ref || github.ref_name }}"
|
||||||
|
|
||||||
@@ -75,7 +79,7 @@ jobs:
|
|||||||
is_stable_branch="$(echo "$CONFIG" | jq -r '.stable_branch // false')";
|
is_stable_branch="$(echo "$CONFIG" | jq -r '.stable_branch // false')";
|
||||||
echo "is_stable_branch=$is_stable_branch" >> $GITHUB_OUTPUT
|
echo "is_stable_branch=$is_stable_branch" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
stable_version=$(cat openpilot/sunnypilot/common/version.h | grep SUNNYPILOT_VERSION | sed -e 's/[^0-9|.]//g');
|
stable_version=$(cat sunnypilot/common/version.h | grep SUNNYPILOT_VERSION | sed -e 's/[^0-9|.]//g');
|
||||||
echo "version=$([ "$is_stable_branch" = "true" ] && echo "$stable_version" || echo "$BUILD")" >> $GITHUB_OUTPUT
|
echo "version=$([ "$is_stable_branch" = "true" ] && echo "$stable_version" || echo "$BUILD")" >> $GITHUB_OUTPUT
|
||||||
echo "extra_version_identifier=${environment}" >> $GITHUB_OUTPUT
|
echo "extra_version_identifier=${environment}" >> $GITHUB_OUTPUT
|
||||||
fi
|
fi
|
||||||
@@ -105,6 +109,11 @@ jobs:
|
|||||||
group: build-${{ github.head_ref || github.ref_name }}
|
group: build-${{ github.head_ref || github.ref_name }}
|
||||||
cancel-in-progress: false
|
cancel-in-progress: false
|
||||||
runs-on: [self-hosted, tici]
|
runs-on: [self-hosted, tici]
|
||||||
|
outputs:
|
||||||
|
new_branch: ${{ needs.prepare_strategy.outputs.new_branch }}
|
||||||
|
version: ${{ needs.prepare_strategy.outputs.version }}
|
||||||
|
extra_version_identifier: ${{ needs.prepare_strategy.outputs.extra_version_identifier }}
|
||||||
|
commit_sha: ${{ github.sha }}
|
||||||
if: ${{
|
if: ${{
|
||||||
(always() && !cancelled() && !failure()) &&
|
(always() && !cancelled() && !failure()) &&
|
||||||
needs.prepare_strategy.result == 'success' &&
|
needs.prepare_strategy.result == 'success' &&
|
||||||
@@ -120,16 +129,34 @@ jobs:
|
|||||||
repository: ${{ github.event.pull_request.head.repo.fork && github.event.pull_request.head.repo.full_name || github.repository }}
|
repository: ${{ github.event.pull_request.head.repo.fork && github.event.pull_request.head.repo.full_name || github.repository }}
|
||||||
- run: git lfs pull
|
- run: git lfs pull
|
||||||
|
|
||||||
|
- name: Cache SCons
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ${{env.SCONS_CACHE_DIR}}
|
||||||
|
key: scons-${{ runner.os }}-${{ runner.arch }}-${{ env.SOURCE_BRANCH }}-${{ github.sha }}
|
||||||
|
# Note: GitHub Actions enforces cache isolation between different build sources (PR builds, workflow dispatches, etc.)
|
||||||
|
# for security. Only caches from the default branch are shared across all builds. This is by design and cannot be overridden.
|
||||||
|
restore-keys: |
|
||||||
|
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.SOURCE_BRANCH }}
|
||||||
|
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.STAGING_SOURCE_BRANCH }}
|
||||||
|
scons-${{ runner.os }}-${{ runner.arch }}
|
||||||
|
|
||||||
- name: Set environment variables
|
- name: Set environment variables
|
||||||
|
id: set-env
|
||||||
run: |
|
run: |
|
||||||
|
echo "new_branch=${{ needs.prepare_strategy.outputs.new_branch }}" >> $GITHUB_OUTPUT
|
||||||
|
echo "version=${{ needs.prepare_strategy.outputs.version }}" >> $GITHUB_OUTPUT
|
||||||
|
echo "extra_version_identifier=${{ needs.prepare_strategy.outputs.extra_version_identifier }}" >> $GITHUB_OUTPUT
|
||||||
|
echo "commit_sha=${{ github.sha }}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
# Set up common environment
|
# Set up common environment
|
||||||
source /etc/profile;
|
source /etc/profile;
|
||||||
export UV_PROJECT_ENVIRONMENT=${HOME}/venv
|
export UV_PROJECT_ENVIRONMENT=${HOME}/venv
|
||||||
export UV_PYTHON_PREFERENCE=managed
|
|
||||||
export UV_PYTHON_INSTALL_DIR=${HOME}/uv/python
|
|
||||||
export VIRTUAL_ENV=$UV_PROJECT_ENVIRONMENT
|
export VIRTUAL_ENV=$UV_PROJECT_ENVIRONMENT
|
||||||
uv sync
|
|
||||||
printenv >> $GITHUB_ENV
|
printenv >> $GITHUB_ENV
|
||||||
|
if [[ "${{ runner.debug }}" == "1" ]]; then
|
||||||
|
cat $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Setup build environment
|
- name: Setup build environment
|
||||||
run: |
|
run: |
|
||||||
@@ -138,56 +165,67 @@ jobs:
|
|||||||
echo "Starting build stage..."
|
echo "Starting build stage..."
|
||||||
echo "BUILD_DIR: ${BUILD_DIR}"
|
echo "BUILD_DIR: ${BUILD_DIR}"
|
||||||
echo "CI_DIR: ${CI_DIR}"
|
echo "CI_DIR: ${CI_DIR}"
|
||||||
echo "VERSION: ${{ needs.prepare_strategy.outputs.version }}"
|
echo "VERSION: ${{ steps.set-env.outputs.version }}"
|
||||||
echo "UV_PROJECT_ENVIRONMENT: ${UV_PROJECT_ENVIRONMENT}"
|
echo "UV_PROJECT_ENVIRONMENT: ${UV_PROJECT_ENVIRONMENT}"
|
||||||
echo "VIRTUAL_ENV: ${VIRTUAL_ENV}"
|
echo "VIRTUAL_ENV: ${VIRTUAL_ENV}"
|
||||||
echo "-------"
|
echo "-------"
|
||||||
if [[ "${{ runner.debug }}" == "1" ]]; then
|
if [[ "${{ runner.debug }}" == "1" ]]; then
|
||||||
printenv
|
printenv
|
||||||
fi
|
fi
|
||||||
source ${UV_PROJECT_ENVIRONMENT}/bin/activate
|
|
||||||
PYTHONPATH=$PYTHONPATH:${{ github.workspace }}/ ${{ github.workspace }}/scripts/manage-powersave.py --disable
|
PYTHONPATH=$PYTHONPATH:${{ github.workspace }}/ ${{ github.workspace }}/scripts/manage-powersave.py --disable
|
||||||
|
|
||||||
- name: Build Main Project
|
- name: Build Main Project
|
||||||
run: |
|
run: |
|
||||||
export PYTHONPATH="$BUILD_DIR:$BUILD_DIR/msgq_repo:$BUILD_DIR/opendbc_repo:$BUILD_DIR/rednose_repo:$BUILD_DIR/teleoprtc_repo:$BUILD_DIR/tinygrad_repo"
|
export PYTHONPATH="$BUILD_DIR"
|
||||||
./tools/release/release_files.py | xargs -0 cp -pR --parents -t "$BUILD_DIR" --
|
./release/release_files.py | sort | uniq | rsync -rRl${RUNNER_DEBUG:+v} --files-from=- . $BUILD_DIR/
|
||||||
# outside the checkout, which is wiped each run. /data/scons_cache is the device's, not ours.
|
|
||||||
SCONS_CACHE="$RUNNER_WORKSPACE/scons_cache"
|
|
||||||
mkdir -p "$SCONS_CACHE"
|
|
||||||
cd $BUILD_DIR
|
cd $BUILD_DIR
|
||||||
echo "Building locationd..."
|
sed -i '/from .board.jungle import PandaJungle, PandaJungleDFU/s/^/#/' panda/__init__.py
|
||||||
# -j1: parallel rednose generators OOM the device
|
echo "Building sunnypilot's modeld_v2..."
|
||||||
scons -j1 cache_dir="$SCONS_CACHE" --minimal \
|
scons -j$(nproc) cache_dir=${{env.SCONS_CACHE_DIR}} --minimal sunnypilot/modeld_v2
|
||||||
openpilot/selfdrive/locationd openpilot/sunnypilot/selfdrive/locationd
|
echo "Building sunnypilot's locationd..."
|
||||||
|
scons -j2 cache_dir=${{env.SCONS_CACHE_DIR}} --minimal sunnypilot/selfdrive/locationd
|
||||||
|
echo "Building openpilot's locationd..."
|
||||||
|
scons -j1 cache_dir=${{env.SCONS_CACHE_DIR}} --minimal selfdrive/locationd
|
||||||
echo "Building rest of sunnypilot"
|
echo "Building rest of sunnypilot"
|
||||||
/usr/bin/time -v scons -j$(nproc) cache_dir="$SCONS_CACHE" --minimal
|
scons -j$(nproc) cache_dir=${{env.SCONS_CACHE_DIR}} --minimal
|
||||||
touch ${BUILD_DIR}/prebuilt
|
touch ${BUILD_DIR}/prebuilt
|
||||||
if [[ "${{ runner.debug }}" == "1" ]]; then
|
if [[ "${{ runner.debug }}" == "1" ]]; then
|
||||||
ls -la ${BUILD_DIR}
|
ls -la ${BUILD_DIR}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Strip release tree
|
- name: Prepare Output
|
||||||
run: |
|
run: |
|
||||||
cd $BUILD_DIR
|
sudo rm -rf ${OUTPUT_DIR}
|
||||||
find . -name '*.a' -delete
|
mkdir -p ${OUTPUT_DIR}
|
||||||
find . -name '*.o' -delete
|
rsync -am${RUNNER_DEBUG:+v} \
|
||||||
find . -name '*.os' -delete
|
--exclude='.sconsign.dblite' \
|
||||||
find . -name '*.pyc' -delete
|
--exclude='*.a' \
|
||||||
find . -name 'moc_*' -delete
|
--exclude='*.o' \
|
||||||
find . -name '__pycache__' -type d -exec rm -rf {} +
|
--exclude='*.os' \
|
||||||
find . -name 'SConstruct' -delete
|
--exclude='*.pyc' \
|
||||||
find . -name 'SConscript' -delete
|
--exclude='moc_*' \
|
||||||
rm -rf .sconsign.dblite Jenkinsfile tools/release/ release/
|
--exclude='__pycache__' \
|
||||||
rm -f openpilot/selfdrive/modeld/models/*.onnx*
|
--exclude='Jenkinsfile' \
|
||||||
rm -f openpilot/sunnypilot/modeld*/models/*.onnx*
|
--exclude='**/release/' \
|
||||||
find openpilot/third_party/ -name '*x86*' -exec rm -r {} +
|
--exclude='**/.github/' \
|
||||||
find openpilot/third_party/ -name '*Darwin*' -exec rm -r {} +
|
--exclude='**/selfdrive/ui/replay/' \
|
||||||
cd -
|
--exclude='**/__pycache__/' \
|
||||||
|
--exclude='${{env.SCONS_CACHE_DIR}}' \
|
||||||
|
--exclude='**/.git/' \
|
||||||
|
--exclude='**/SConstruct' \
|
||||||
|
--exclude='**/SConscript' \
|
||||||
|
--exclude='**/.venv/' \
|
||||||
|
--exclude='selfdrive/modeld/models/*.onnx*' \
|
||||||
|
--exclude='sunnypilot/modeld*/models/*.onnx*' \
|
||||||
|
--exclude='third_party/*x86*' \
|
||||||
|
--exclude='third_party/*Darwin*' \
|
||||||
|
--delete-excluded \
|
||||||
|
--chown=comma:comma \
|
||||||
|
${BUILD_DIR}/ ${OUTPUT_DIR}/
|
||||||
|
|
||||||
- name: 'Tar.gz files'
|
- name: 'Tar.gz files'
|
||||||
run: |
|
run: |
|
||||||
tar czf prebuilt.tar.gz -C ${{ env.BUILD_DIR }} .
|
tar czf prebuilt.tar.gz -C ${{ env.OUTPUT_DIR }} .
|
||||||
ls -la prebuilt.tar.gz
|
ls -la prebuilt.tar.gz
|
||||||
|
|
||||||
- name: 'Upload Artifact'
|
- name: 'Upload Artifact'
|
||||||
@@ -195,12 +233,10 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: prebuilt
|
name: prebuilt
|
||||||
path: prebuilt.tar.gz
|
path: prebuilt.tar.gz
|
||||||
compression-level: 0
|
|
||||||
|
|
||||||
- name: Re-enable powersave
|
- name: Re-enable powersave
|
||||||
if: always()
|
if: always()
|
||||||
run: |
|
run: |
|
||||||
source ${UV_PROJECT_ENVIRONMENT}/bin/activate
|
|
||||||
PYTHONPATH=$PYTHONPATH:${{ github.workspace }}/ ${{ github.workspace }}/scripts/manage-powersave.py --enable
|
PYTHONPATH=$PYTHONPATH:${{ github.workspace }}/ ${{ github.workspace }}/scripts/manage-powersave.py --enable
|
||||||
|
|
||||||
|
|
||||||
@@ -237,22 +273,29 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
echo '${{ toJSON(needs.prepare_strategy.outputs) }}'
|
echo '${{ toJSON(needs.build.outputs) }}'
|
||||||
ls -la ${{ env.OUTPUT_DIR }}
|
ls -la ${{ env.OUTPUT_DIR }}
|
||||||
|
|
||||||
${{ env.CI_DIR }}/publish.sh \
|
${{ env.CI_DIR }}/publish.sh \
|
||||||
"${{ github.workspace }}" \
|
"${{ github.workspace }}" \
|
||||||
"${{ env.OUTPUT_DIR }}" \
|
"${{ env.OUTPUT_DIR }}" \
|
||||||
"${{ needs.prepare_strategy.outputs.new_branch }}" \
|
"${{ needs.build.outputs.new_branch }}" \
|
||||||
"${{ needs.prepare_strategy.outputs.version }}" \
|
"${{ needs.build.outputs.version }}" \
|
||||||
"https://x-access-token:${{github.token}}@github.com/sunnypilot/sunnypilot.git" \
|
"https://x-access-token:${{github.token}}@github.com/sunnypilot/sunnypilot.git" \
|
||||||
"${{ needs.prepare_strategy.outputs.extra_version_identifier }}"
|
"${{ needs.build.outputs.extra_version_identifier }}"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "---- ℹ️ To update the list of branches that auto deploy prebuilts -----"
|
||||||
|
echo ""
|
||||||
|
echo "1. Go to: ${{ github.server_url }}/${{ github.repository }}/settings/variables/actions/AUTO_DEPLOY_PREBUILT_BRANCHES"
|
||||||
|
echo "2. Current value: ${{ vars.AUTO_DEPLOY_PREBUILT_BRANCHES }}"
|
||||||
|
echo "3. Update as needed (JSON array with no spaces)"
|
||||||
|
|
||||||
- name: Tag ${{ needs.prepare_strategy.outputs.environment }}
|
- name: Tag ${{ needs.prepare_strategy.outputs.environment }}
|
||||||
if: ${{ needs.prepare_strategy.outputs.is_stable_branch == 'true' && (github.event_name != 'push' || !startsWith(github.ref, 'refs/tags/')) }}
|
if: ${{ needs.prepare_strategy.outputs.is_stable_branch == 'true' && (github.event_name != 'push' || !startsWith(github.ref, 'refs/tags/')) }}
|
||||||
run: |
|
run: |
|
||||||
TAG="${{ needs.prepare_strategy.outputs.environment }}/${{ needs.prepare_strategy.outputs.version }}/${{ needs.prepare_strategy.outputs.build }}"
|
TAG="${{ needs.prepare_strategy.outputs.environment }}/${{ needs.prepare_strategy.outputs.version }}/${{ needs.prepare_strategy.outputs.build }}"
|
||||||
git tag -f -a ${TAG} -m "${{ needs.prepare_strategy.outputs.environment }} @ ${{ needs.prepare_strategy.outputs.version }} of build ${{ needs.prepare_strategy.outputs.build }}."
|
git tag -f -a ${TAG} -m "${{ needs.prepare_strategy.outputs.environment }} @ ${{ needs.prepare_strategy.outputs.version }} of build ${{ needs.build.outputs.build }}."
|
||||||
git push -f origin ${TAG}
|
git push -f origin ${TAG}
|
||||||
|
|
||||||
notify:
|
notify:
|
||||||
@@ -271,6 +314,7 @@ jobs:
|
|||||||
- name: Prepare notification message
|
- name: Prepare notification message
|
||||||
id: message
|
id: message
|
||||||
run: |
|
run: |
|
||||||
|
TEMPLATE='${{ vars.DISCOURSE_GENERAL_UPDATE_NOTICE }}'
|
||||||
export VERSION="${{ needs.prepare_strategy.outputs.version }}"
|
export VERSION="${{ needs.prepare_strategy.outputs.version }}"
|
||||||
export branch_name="${{ env.SOURCE_BRANCH }}"
|
export branch_name="${{ env.SOURCE_BRANCH }}"
|
||||||
export new_branch="${{ needs.prepare_strategy.outputs.new_branch }}"
|
export new_branch="${{ needs.prepare_strategy.outputs.new_branch }}"
|
||||||
|
|||||||
@@ -20,9 +20,7 @@ concurrency:
|
|||||||
env:
|
env:
|
||||||
CI: 1
|
CI: 1
|
||||||
PYTHONPATH: ${{ github.workspace }}
|
PYTHONPATH: ${{ github.workspace }}
|
||||||
GIT_CONFIG_COUNT: 1
|
PYTEST: pytest --continue-on-collection-errors --durations=0 -n logical
|
||||||
GIT_CONFIG_KEY_0: lfs.fetchexclude
|
|
||||||
GIT_CONFIG_VALUE_0: openpilot/selfdrive/modeld/models/big_driving_supercombo.onnx
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_release:
|
build_release:
|
||||||
@@ -37,27 +35,27 @@ jobs:
|
|||||||
STRIPPED_DIR: /tmp/releasepilot
|
STRIPPED_DIR: /tmp/releasepilot
|
||||||
PYTHONPATH: /tmp/releasepilot
|
PYTHONPATH: /tmp/releasepilot
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Getting LFS files
|
- name: Getting LFS files
|
||||||
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60
|
uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e
|
||||||
with:
|
with:
|
||||||
timeout_minutes: 2
|
timeout_minutes: 2
|
||||||
max_attempts: 3
|
max_attempts: 3
|
||||||
command: git lfs pull
|
command: git lfs pull
|
||||||
- name: Build devel
|
- name: Build devel
|
||||||
timeout-minutes: 3
|
timeout-minutes: 1
|
||||||
run: TARGET_DIR=$STRIPPED_DIR tools/release/build_stripped.sh
|
run: TARGET_DIR=$STRIPPED_DIR release/build_stripped.sh
|
||||||
- run: ./tools/op.sh setup
|
- run: ./tools/op.sh setup
|
||||||
- name: Build openpilot and run checks
|
- name: Build openpilot and run checks
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
working-directory: ${{ env.STRIPPED_DIR }}
|
working-directory: ${{ env.STRIPPED_DIR }}
|
||||||
run: python3 openpilot/system/manager/build.py
|
run: python3 system/manager/build.py
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
timeout-minutes: 1
|
timeout-minutes: 1
|
||||||
working-directory: ${{ env.STRIPPED_DIR }}
|
working-directory: ${{ env.STRIPPED_DIR }}
|
||||||
run: tools/release/check-dirty.sh
|
run: release/check-dirty.sh
|
||||||
- name: Check submodules
|
- name: Check submodules
|
||||||
if: github.repository == 'sunnypilot/sunnypilot'
|
if: github.repository == 'sunnypilot/sunnypilot'
|
||||||
timeout-minutes: 3
|
timeout-minutes: 3
|
||||||
@@ -77,13 +75,15 @@ jobs:
|
|||||||
export CHECK_PR_REFS=true
|
export CHECK_PR_REFS=true
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
tools/release/check-submodules.sh
|
release/check-submodules.sh
|
||||||
|
|
||||||
build_mac:
|
build_mac:
|
||||||
name: build macOS
|
name: build macOS
|
||||||
runs-on: ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-macos-8x14' || 'macos-latest' }}
|
runs-on: ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-macos-8x14' || 'macos-latest' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
- name: Remove Homebrew from environment
|
- name: Remove Homebrew from environment
|
||||||
run: |
|
run: |
|
||||||
FILTERED=$(echo "$PATH" | tr ':' '\n' | grep -v '/opt/homebrew' | tr '\n' ':')
|
FILTERED=$(echo "$PATH" | tr ':' '\n' | grep -v '/opt/homebrew' | tr '\n' ':')
|
||||||
@@ -101,7 +101,9 @@ jobs:
|
|||||||
&& fromJSON('["namespace-profile-amd64-8x16"]')
|
&& fromJSON('["namespace-profile-amd64-8x16"]')
|
||||||
|| fromJSON('["ubuntu-24.04"]') }}
|
|| fromJSON('["ubuntu-24.04"]') }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
- run: ./tools/op.sh setup
|
- run: ./tools/op.sh setup
|
||||||
- name: Static analysis
|
- name: Static analysis
|
||||||
timeout-minutes: 1
|
timeout-minutes: 1
|
||||||
@@ -116,21 +118,23 @@ jobs:
|
|||||||
&& fromJSON('["namespace-profile-amd64-8x16"]')
|
&& fromJSON('["namespace-profile-amd64-8x16"]')
|
||||||
|| fromJSON('["ubuntu-24.04"]') }}
|
|| fromJSON('["ubuntu-24.04"]') }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
- run: ./tools/op.sh setup
|
- run: ./tools/op.sh setup
|
||||||
- name: Install raylib headless dependencies
|
|
||||||
if: ${{ !contains(runner.name, 'nsc') }}
|
|
||||||
run: sudo apt-get install -y --no-install-recommends libgles2 libegl1
|
|
||||||
- name: Build openpilot
|
- name: Build openpilot
|
||||||
run: scons
|
run: scons
|
||||||
- name: Run unit tests
|
- name: Run unit tests
|
||||||
timeout-minutes: ${{ contains(runner.name, 'nsc') && 2 || 999 }}
|
timeout-minutes: ${{ contains(runner.name, 'nsc') && 2 || 999 }}
|
||||||
env:
|
run: |
|
||||||
RAYLIB_BACKEND: headless
|
source selfdrive/test/setup_xvfb.sh
|
||||||
run: tools/op.sh test
|
# Pre-compile Python bytecode so each pytest worker doesn't need to
|
||||||
|
$PYTEST --collect-only -m 'not slow' -qq
|
||||||
|
MAX_EXAMPLES=1 $PYTEST -m 'not slow'
|
||||||
|
|
||||||
process_replay:
|
process_replay:
|
||||||
name: process replay
|
name: process replay
|
||||||
|
if: false # disable process_replay for forks
|
||||||
runs-on: ${{
|
runs-on: ${{
|
||||||
(github.repository == 'commaai/openpilot') &&
|
(github.repository == 'commaai/openpilot') &&
|
||||||
((github.event_name != 'pull_request') ||
|
((github.event_name != 'pull_request') ||
|
||||||
@@ -138,60 +142,68 @@ jobs:
|
|||||||
&& fromJSON('["namespace-profile-amd64-8x16"]')
|
&& fromJSON('["namespace-profile-amd64-8x16"]')
|
||||||
|| fromJSON('["ubuntu-24.04"]') }}
|
|| fromJSON('["ubuntu-24.04"]') }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
- run: ./tools/op.sh setup
|
- run: ./tools/op.sh setup
|
||||||
- name: Build openpilot
|
- name: Build openpilot
|
||||||
run: scons
|
run: scons
|
||||||
- name: Run replay
|
- name: Run replay
|
||||||
timeout-minutes: ${{ contains(runner.name, 'nsc') && 2 || 20 }}
|
timeout-minutes: ${{ contains(runner.name, 'nsc') && 2 || 20 }}
|
||||||
continue-on-error: ${{ github.ref == 'refs/heads/master' }}
|
continue-on-error: ${{ github.ref == 'refs/heads/master' }}
|
||||||
run: openpilot/selfdrive/test/process_replay/test_processes.py -j$(nproc)
|
run: selfdrive/test/process_replay/test_processes.py -j$(nproc)
|
||||||
- name: Print diff
|
- name: Print diff
|
||||||
id: print-diff
|
id: print-diff
|
||||||
if: always()
|
if: always()
|
||||||
run: cat openpilot/selfdrive/test/process_replay/diff.txt
|
run: cat selfdrive/test/process_replay/diff.txt
|
||||||
- name: Print diff report
|
- name: Print diff report
|
||||||
if: always()
|
if: always()
|
||||||
run: cat openpilot/selfdrive/test/process_replay/diff_report.txt
|
run: cat selfdrive/test/process_replay/diff_report.txt
|
||||||
- uses: actions/upload-artifact@v7
|
- uses: actions/upload-artifact@v6
|
||||||
if: always()
|
if: always()
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
name: process_replay_diff.txt
|
name: process_replay_diff.txt
|
||||||
path: openpilot/selfdrive/test/process_replay/diff.txt
|
path: selfdrive/test/process_replay/diff.txt
|
||||||
- name: Upload diff report
|
- name: Upload diff report
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v6
|
||||||
if: always() && github.event_name == 'pull_request'
|
if: always() && github.event_name == 'pull_request'
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
name: diff_report_${{ github.event.number }}
|
name: diff_report_${{ github.event.number }}
|
||||||
path: openpilot/selfdrive/test/process_replay/diff_report.txt
|
path: selfdrive/test/process_replay/diff_report.txt
|
||||||
- name: Checkout ci-artifacts
|
- name: Checkout ci-artifacts
|
||||||
if: github.repository == 'sunnypilot/sunnypilot' && github.ref == 'refs/heads/master'
|
if: github.repository == 'commaai/openpilot' && github.ref == 'refs/heads/master'
|
||||||
uses: actions/checkout@v7
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: sunnypilot/ci-artifacts
|
repository: commaai/ci-artifacts
|
||||||
ssh-key: ${{ secrets.CI_ARTIFACTS_DEPLOY_KEY }}
|
ssh-key: ${{ secrets.CI_ARTIFACTS_DEPLOY_KEY }}
|
||||||
path: ${{ github.workspace }}/ci-artifacts
|
path: ${{ github.workspace }}/ci-artifacts
|
||||||
- name: Prepare refs
|
- name: Prepare refs
|
||||||
if: github.repository == 'sunnypilot/sunnypilot' && github.ref == 'refs/heads/master'
|
if: github.repository == 'commaai/openpilot' && github.ref == 'refs/heads/master'
|
||||||
working-directory: ${{ github.workspace }}/ci-artifacts
|
working-directory: ${{ github.workspace }}/ci-artifacts
|
||||||
run: |
|
run: |
|
||||||
git config user.name "GitHub Actions Bot"
|
git config user.name "GitHub Actions Bot"
|
||||||
git config user.email "<>"
|
git config user.email "<>"
|
||||||
git fetch origin process-replay || true
|
git fetch origin process-replay || true
|
||||||
git checkout process-replay 2>/dev/null || git checkout --orphan process-replay
|
git checkout process-replay 2>/dev/null || git checkout --orphan process-replay
|
||||||
cp ${{ github.workspace }}/openpilot/selfdrive/test/process_replay/fakedata/*.zst .
|
cp ${{ github.workspace }}/selfdrive/test/process_replay/fakedata/*.zst .
|
||||||
echo "${{ github.sha }}" > ref_commit
|
echo "${{ github.sha }}" > ref_commit
|
||||||
git add .
|
git add .
|
||||||
git commit -m "process-replay refs for ${{ github.repository }}@${{ github.sha }}" || echo "No changes to commit"
|
git commit -m "process-replay refs for ${{ github.repository }}@${{ github.sha }}" || echo "No changes to commit"
|
||||||
- name: Push refs
|
- name: Push refs
|
||||||
if: github.repository == 'sunnypilot/sunnypilot' && github.ref == 'refs/heads/master'
|
if: github.repository == 'commaai/openpilot' && github.ref == 'refs/heads/master'
|
||||||
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60
|
uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e
|
||||||
with:
|
with:
|
||||||
timeout_minutes: 2
|
timeout_minutes: 2
|
||||||
max_attempts: 3
|
max_attempts: 3
|
||||||
command: cd ${{ github.workspace }}/ci-artifacts && git push origin process-replay --force
|
command: cd ${{ github.workspace }}/ci-artifacts && git push origin process-replay --force
|
||||||
|
- name: Run regen
|
||||||
|
if: false
|
||||||
|
timeout-minutes: 4
|
||||||
|
env:
|
||||||
|
ONNXCPU: 1
|
||||||
|
run: $PYTEST selfdrive/test/process_replay/test_regen.py
|
||||||
|
|
||||||
simulator_driving:
|
simulator_driving:
|
||||||
name: simulator driving
|
name: simulator driving
|
||||||
@@ -203,16 +215,17 @@ jobs:
|
|||||||
|| fromJSON('["ubuntu-24.04"]') }}
|
|| fromJSON('["ubuntu-24.04"]') }}
|
||||||
if: false # FIXME: Started to timeout recently
|
if: false # FIXME: Started to timeout recently
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
- run: ./tools/op.sh setup
|
- run: ./tools/op.sh setup
|
||||||
- name: Build openpilot
|
- name: Build openpilot
|
||||||
run: scons
|
run: scons
|
||||||
- name: Driving test
|
- name: Driving test
|
||||||
timeout-minutes: 2
|
timeout-minutes: 2
|
||||||
env:
|
run: |
|
||||||
# MetaDrive renders offscreen through panda3d's EGL pipe on llvmpipe
|
source selfdrive/test/setup_xvfb.sh
|
||||||
EGL_PLATFORM: surfaceless
|
pytest -s tools/sim/tests/test_metadrive_bridge.py
|
||||||
run: python openpilot/tools/sim/tests/test_metadrive_bridge.py
|
|
||||||
|
|
||||||
create_ui_report:
|
create_ui_report:
|
||||||
name: Create UI Report
|
name: Create UI Report
|
||||||
@@ -223,21 +236,19 @@ jobs:
|
|||||||
&& fromJSON('["namespace-profile-amd64-8x16"]')
|
&& fromJSON('["namespace-profile-amd64-8x16"]')
|
||||||
|| fromJSON('["ubuntu-24.04"]') }}
|
|| fromJSON('["ubuntu-24.04"]') }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
- run: ./tools/op.sh setup
|
- run: ./tools/op.sh setup
|
||||||
- name: Install raylib headless dependencies
|
|
||||||
if: ${{ !contains(runner.name, 'nsc') }}
|
|
||||||
run: sudo apt-get install -y --no-install-recommends libgles2 libegl1
|
|
||||||
- name: Build openpilot
|
- name: Build openpilot
|
||||||
run: scons
|
run: scons
|
||||||
- name: Create UI Report
|
- name: Create UI Report
|
||||||
env:
|
|
||||||
RAYLIB_BACKEND: headless
|
|
||||||
run: |
|
run: |
|
||||||
python3 openpilot/selfdrive/ui/tests/diff/replay.py
|
source selfdrive/test/setup_xvfb.sh
|
||||||
python3 openpilot/selfdrive/ui/tests/diff/replay.py --big
|
python3 selfdrive/ui/tests/diff/replay.py
|
||||||
|
python3 selfdrive/ui/tests/diff/replay.py --big
|
||||||
- name: Upload UI Report
|
- name: Upload UI Report
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: ui-report-${{ inputs.run_number || '1' }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master' || github.event.number }}
|
name: ui-report-${{ inputs.run_number || '1' }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master' || github.event.number }}
|
||||||
path: openpilot/selfdrive/ui/tests/diff/report
|
path: selfdrive/ui/tests/diff/report
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- 'master'
|
- 'master'
|
||||||
paths:
|
paths:
|
||||||
- 'openpilot/selfdrive/assets/**'
|
- 'selfdrive/assets/**'
|
||||||
- 'openpilot/selfdrive/ui/**'
|
- 'selfdrive/ui/**'
|
||||||
- 'openpilot/system/ui/**'
|
- 'system/ui/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
@@ -25,8 +25,7 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
preview:
|
preview:
|
||||||
if: false # tmp disable due to GH API rate limiting flakiness
|
if: github.repository == 'sunnypilot/sunnypilot'
|
||||||
#if: github.repository == 'sunnypilot/sunnypilot'
|
|
||||||
name: preview
|
name: preview
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 20
|
timeout-minutes: 20
|
||||||
@@ -35,12 +34,12 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
actions: read
|
actions: read
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
|
|
||||||
- name: Waiting for ui generation to end
|
- name: Waiting for ui generation to end
|
||||||
uses: lewagon/wait-on-check-action@1d57e2c51a58d812d2765e036a028b6bdb5a6154
|
uses: lewagon/wait-on-check-action@v1.3.4
|
||||||
with:
|
with:
|
||||||
ref: ${{ env.SHA }}
|
ref: ${{ env.SHA }}
|
||||||
check-name: ${{ env.UI_JOB_NAME }}
|
check-name: ${{ env.UI_JOB_NAME }}
|
||||||
@@ -54,7 +53,7 @@ jobs:
|
|||||||
echo "run_id=$(curl https://api.github.com/repos/${{ github.repository }}/commits/${{ env.SHA }}/check-runs | jq -r '.check_runs[] | select(.name == "${{ env.UI_JOB_NAME }}") | .html_url | capture("(?<number>[0-9]+)") | .number')" >> $GITHUB_OUTPUT
|
echo "run_id=$(curl https://api.github.com/repos/${{ github.repository }}/commits/${{ env.SHA }}/check-runs | jq -r '.check_runs[] | select(.name == "${{ env.UI_JOB_NAME }}") | .html_url | capture("(?<number>[0-9]+)") | .number')" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Getting proposed ui
|
- name: Getting proposed ui
|
||||||
uses: dawidd6/action-download-artifact@b6e2e70617bc3265edd6dab6c906732b2f1ae151
|
uses: dawidd6/action-download-artifact@v6
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run_id: ${{ steps.get_run_id.outputs.run_id }}
|
run_id: ${{ steps.get_run_id.outputs.run_id }}
|
||||||
@@ -63,7 +62,7 @@ jobs:
|
|||||||
path: ${{ github.workspace }}/pr_ui
|
path: ${{ github.workspace }}/pr_ui
|
||||||
|
|
||||||
- name: Getting mici master ui
|
- name: Getting mici master ui
|
||||||
uses: actions/checkout@v7
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
repository: sunnypilot/ci-artifacts
|
repository: sunnypilot/ci-artifacts
|
||||||
ssh-key: ${{ secrets.CI_ARTIFACTS_DEPLOY_KEY }}
|
ssh-key: ${{ secrets.CI_ARTIFACTS_DEPLOY_KEY }}
|
||||||
@@ -71,7 +70,7 @@ jobs:
|
|||||||
ref: openpilot_master_ui_mici_raylib
|
ref: openpilot_master_ui_mici_raylib
|
||||||
|
|
||||||
- name: Getting big master ui
|
- name: Getting big master ui
|
||||||
uses: actions/checkout@v7
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
repository: sunnypilot/ci-artifacts
|
repository: sunnypilot/ci-artifacts
|
||||||
ssh-key: ${{ secrets.CI_ARTIFACTS_DEPLOY_KEY }}
|
ssh-key: ${{ secrets.CI_ARTIFACTS_DEPLOY_KEY }}
|
||||||
@@ -98,7 +97,7 @@ jobs:
|
|||||||
done
|
done
|
||||||
|
|
||||||
- name: Setup FFmpeg
|
- name: Setup FFmpeg
|
||||||
uses: AnimMouse/setup-ffmpeg@178e0b4a408f06ce40d896c3cd79f50fa6f8b0c3
|
uses: AnimMouse/setup-ffmpeg@ae28d57dabbb148eff63170b6bf7f2b60062cbae
|
||||||
|
|
||||||
- name: Finding diffs
|
- name: Finding diffs
|
||||||
if: github.event_name == 'pull_request_target'
|
if: github.event_name == 'pull_request_target'
|
||||||
@@ -116,13 +115,13 @@ jobs:
|
|||||||
cp "${{ github.workspace }}/master_${name}/${video}.mp4" "${{ github.workspace }}/pr_ui/${video}_master.mp4"
|
cp "${{ github.workspace }}/master_${name}/${video}.mp4" "${{ github.workspace }}/pr_ui/${video}_master.mp4"
|
||||||
|
|
||||||
diff_exit_code=0
|
diff_exit_code=0
|
||||||
python3 ${{ github.workspace }}/openpilot/selfdrive/ui/tests/diff/diff.py \
|
python3 ${{ github.workspace }}/selfdrive/ui/tests/diff/diff.py \
|
||||||
"${{ github.workspace }}/pr_ui/${video}_master.mp4" \
|
"${{ github.workspace }}/pr_ui/${video}_master.mp4" \
|
||||||
"${{ github.workspace }}/pr_ui/${video}_proposed.mp4" \
|
"${{ github.workspace }}/pr_ui/${video}_proposed.mp4" \
|
||||||
"${diff_name}.html" --basedir "$baseurl" --no-open || diff_exit_code=$?
|
"${diff_name}.html" --basedir "$baseurl" --no-open || diff_exit_code=$?
|
||||||
|
|
||||||
cp "${{ github.workspace }}/openpilot/selfdrive/ui/tests/diff/report/${diff_name}.html" "${{ github.workspace }}/pr_ui/"
|
cp "${{ github.workspace }}/selfdrive/ui/tests/diff/report/${diff_name}.html" "${{ github.workspace }}/pr_ui/"
|
||||||
cp "${{ github.workspace }}/openpilot/selfdrive/ui/tests/diff/report/${diff_name}.mp4" "${{ github.workspace }}/pr_ui/"
|
cp "${{ github.workspace }}/selfdrive/ui/tests/diff/report/${diff_name}.mp4" "${{ github.workspace }}/pr_ui/"
|
||||||
|
|
||||||
REPORT_URL="https://sunnypilot.github.io/ci-artifacts/${diff_name}_pr_${{ github.event.number }}.html"
|
REPORT_URL="https://sunnypilot.github.io/ci-artifacts/${diff_name}_pr_${{ github.event.number }}.html"
|
||||||
if [ $diff_exit_code -eq 0 ]; then
|
if [ $diff_exit_code -eq 0 ]; then
|
||||||
@@ -157,7 +156,7 @@ jobs:
|
|||||||
for variant in $VARIANTS; do
|
for variant in $VARIANTS; do
|
||||||
IFS=':' read -r name _ _ <<< "$variant"
|
IFS=':' read -r name _ _ <<< "$variant"
|
||||||
diff_name="${name}_diff"
|
diff_name="${name}_diff"
|
||||||
cp "${{ github.workspace }}/openpilot/selfdrive/ui/tests/diff/report/${diff_name}.html" "${diff_name}_pr_${{ github.event.number }}.html"
|
cp "${{ github.workspace }}/selfdrive/ui/tests/diff/report/${diff_name}.html" "${diff_name}_pr_${{ github.event.number }}.html"
|
||||||
git add "${diff_name}_pr_${{ github.event.number }}.html"
|
git add "${diff_name}_pr_${{ github.event.number }}.html"
|
||||||
done
|
done
|
||||||
git commit -m "ui diff reports for PR #${{ github.event.number }}" || echo "No changes to commit"
|
git commit -m "ui diff reports for PR #${{ github.event.number }}" || echo "No changes to commit"
|
||||||
@@ -165,12 +164,12 @@ jobs:
|
|||||||
|
|
||||||
- name: Comment on PR
|
- name: Comment on PR
|
||||||
if: github.event_name == 'pull_request_target'
|
if: github.event_name == 'pull_request_target'
|
||||||
uses: thollander/actions-comment-pull-request@24bffb9b452ba05a4f3f77933840a6a841d1b32b
|
uses: thollander/actions-comment-pull-request@v2
|
||||||
with:
|
with:
|
||||||
message: |
|
message: |
|
||||||
<!-- _(run_id_ui_preview **${{ github.run_id }}**)_ -->
|
<!-- _(run_id_ui_preview **${{ github.run_id }}**)_ -->
|
||||||
## UI Preview
|
## UI Preview
|
||||||
${{ steps.find_diff.outputs.COMMENT }}
|
${{ steps.find_diff.outputs.COMMENT }}
|
||||||
comment-tag: run_id_ui_preview
|
comment_tag: run_id_ui_preview
|
||||||
pr-number: ${{ github.event.number }}
|
pr_number: ${{ github.event.number }}
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
+10
-19
@@ -15,13 +15,6 @@ a.out
|
|||||||
.cache/
|
.cache/
|
||||||
bin/
|
bin/
|
||||||
|
|
||||||
# created at launch for comma hardware PYTHONPATH (PC uses editable installs via pyproject.toml)
|
|
||||||
/msgq
|
|
||||||
/opendbc
|
|
||||||
/rednose
|
|
||||||
/teleoprtc
|
|
||||||
/tinygrad
|
|
||||||
|
|
||||||
*.mp4
|
*.mp4
|
||||||
*.dylib
|
*.dylib
|
||||||
*.DSYM
|
*.DSYM
|
||||||
@@ -39,8 +32,6 @@ bin/
|
|||||||
*.os-*
|
*.os-*
|
||||||
*.so
|
*.so
|
||||||
*.a
|
*.a
|
||||||
st[0-9A-Za-z][0-9A-Za-z][0-9A-Za-z][0-9A-Za-z][0-9A-Za-z][0-9A-Za-z]
|
|
||||||
*.unchunked
|
|
||||||
*.clb
|
*.clb
|
||||||
*.class
|
*.class
|
||||||
*.pyxbldc
|
*.pyxbldc
|
||||||
@@ -53,18 +44,18 @@ st[0-9A-Za-z][0-9A-Za-z][0-9A-Za-z][0-9A-Za-z][0-9A-Za-z][0-9A-Za-z]
|
|||||||
config.json
|
config.json
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
compare_runtime*.html
|
compare_runtime*.html
|
||||||
openpilot/selfdrive/modeld/models/tg_input_devices.json
|
selfdrive/modeld/models/tg_input_devices.json
|
||||||
|
|
||||||
# build artifacts
|
# build artifacts
|
||||||
docs/_site/
|
docs_site/
|
||||||
openpilot/selfdrive/pandad/pandad
|
selfdrive/pandad/pandad
|
||||||
openpilot/cereal/services.h
|
cereal/services.h
|
||||||
openpilot/cereal/gen
|
cereal/gen
|
||||||
openpilot/cereal/messaging/bridge
|
cereal/messaging/bridge
|
||||||
openpilot/selfdrive/ui/translations/tmp
|
selfdrive/ui/translations/tmp
|
||||||
openpilot/selfdrive/car/tests/cars_dump
|
selfdrive/car/tests/cars_dump
|
||||||
openpilot/system/camerad/camerad
|
system/camerad/camerad
|
||||||
openpilot/system/camerad/test/ae_gray_test
|
system/camerad/test/ae_gray_test
|
||||||
|
|
||||||
.coverage*
|
.coverage*
|
||||||
coverage.xml
|
coverage.xml
|
||||||
|
|||||||
+1
-1
@@ -17,5 +17,5 @@
|
|||||||
path = tinygrad_repo
|
path = tinygrad_repo
|
||||||
url = https://github.com/sunnypilot/tinygrad.git
|
url = https://github.com/sunnypilot/tinygrad.git
|
||||||
[submodule "sunnypilot/neural_network_data"]
|
[submodule "sunnypilot/neural_network_data"]
|
||||||
path = openpilot/sunnypilot/neural_network_data
|
path = sunnypilot/neural_network_data
|
||||||
url = https://github.com/sunnypilot/neural-network-data.git
|
url = https://github.com/sunnypilot/neural-network-data.git
|
||||||
|
|||||||
Vendored
+4
-4
@@ -6,9 +6,9 @@
|
|||||||
"type": "pickString",
|
"type": "pickString",
|
||||||
"description": "Select the process to debug",
|
"description": "Select the process to debug",
|
||||||
"options": [
|
"options": [
|
||||||
"openpilot/selfdrive/controls/controlsd.py",
|
"selfdrive/controls/controlsd.py",
|
||||||
"openpilot/system/timed/timed.py",
|
"system/timed/timed.py",
|
||||||
"openpilot/tools/sim/run_bridge.py"
|
"tools/sim/run_bridge.py"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
"type": "pickString",
|
"type": "pickString",
|
||||||
"description": "Select the process to debug",
|
"description": "Select the process to debug",
|
||||||
"options": [
|
"options": [
|
||||||
"openpilot/selfdrive/ui/ui"
|
"selfdrive/ui/ui"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+5
@@ -17,5 +17,10 @@
|
|||||||
"**/.git",
|
"**/.git",
|
||||||
"**/.venv",
|
"**/.venv",
|
||||||
"**/__pycache__",
|
"**/__pycache__",
|
||||||
|
// exclude directories that should be using the symlinked version
|
||||||
|
"common/**",
|
||||||
|
"selfdrive/**",
|
||||||
|
"system/**",
|
||||||
|
"tools/**",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+27
-30
@@ -22,7 +22,6 @@ shopt -s huponexit # kill all child processes when the shell exits
|
|||||||
|
|
||||||
export CI=1
|
export CI=1
|
||||||
export PYTHONWARNINGS=error
|
export PYTHONWARNINGS=error
|
||||||
export COMMA_CACHE=/data/tmp/comma_download_cache
|
|
||||||
#export LOGPRINT=debug # this has gotten too spammy...
|
#export LOGPRINT=debug # this has gotten too spammy...
|
||||||
export TEST_DIR=${env.TEST_DIR}
|
export TEST_DIR=${env.TEST_DIR}
|
||||||
export SOURCE_DIR=${env.SOURCE_DIR}
|
export SOURCE_DIR=${env.SOURCE_DIR}
|
||||||
@@ -31,14 +30,14 @@ export GIT_COMMIT=${env.GIT_COMMIT}
|
|||||||
export CI_ARTIFACTS_TOKEN=${env.CI_ARTIFACTS_TOKEN}
|
export CI_ARTIFACTS_TOKEN=${env.CI_ARTIFACTS_TOKEN}
|
||||||
export GITHUB_COMMENTS_TOKEN=${env.GITHUB_COMMENTS_TOKEN}
|
export GITHUB_COMMENTS_TOKEN=${env.GITHUB_COMMENTS_TOKEN}
|
||||||
export AZURE_TOKEN='${env.AZURE_TOKEN}'
|
export AZURE_TOKEN='${env.AZURE_TOKEN}'
|
||||||
# only use 1 thread since most require real hardware that can't be shared
|
# only use 1 thread for tici tests since most require HIL
|
||||||
export PYTEST_ADDOPTS="-n0 -s"
|
export PYTEST_ADDOPTS="-n0 -s"
|
||||||
|
|
||||||
|
|
||||||
export GIT_SSH_COMMAND="ssh -i /data/gitkey"
|
export GIT_SSH_COMMAND="ssh -i /data/gitkey"
|
||||||
|
|
||||||
source ~/.bash_profile
|
source ~/.bash_profile
|
||||||
if [ -f /AGNOS ]; then
|
if [ -f /TICI ]; then
|
||||||
source /etc/profile
|
source /etc/profile
|
||||||
|
|
||||||
rm -rf /tmp/tmp*
|
rm -rf /tmp/tmp*
|
||||||
@@ -64,8 +63,6 @@ if [ -f /data/openpilot/launch_env.sh ]; then
|
|||||||
source /data/openpilot/launch_env.sh
|
source /data/openpilot/launch_env.sh
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export LD_LIBRARY_PATH="\$(python -c 'import ffmpeg; print(ffmpeg.LIB_DIR)'):/usr/local/lib:\${LD_LIBRARY_PATH:-}"
|
|
||||||
|
|
||||||
ln -snf ${env.TEST_DIR} /data/pythonpath
|
ln -snf ${env.TEST_DIR} /data/pythonpath
|
||||||
|
|
||||||
cd ${env.TEST_DIR} || true
|
cd ${env.TEST_DIR} || true
|
||||||
@@ -96,7 +93,7 @@ def deviceStage(String stageName, String deviceType, List extra_env, def steps)
|
|||||||
retry (3) {
|
retry (3) {
|
||||||
def date = sh(script: 'date', returnStdout: true).trim();
|
def date = sh(script: 'date', returnStdout: true).trim();
|
||||||
device(device_ip, "set time", "date -s '" + date + "'")
|
device(device_ip, "set time", "date -s '" + date + "'")
|
||||||
device(device_ip, "git checkout", extra + "\n" + readFile("openpilot/selfdrive/test/setup_device_ci.sh"))
|
device(device_ip, "git checkout", extra + "\n" + readFile("selfdrive/test/setup_device_ci.sh"))
|
||||||
}
|
}
|
||||||
steps.each { item ->
|
steps.each { item ->
|
||||||
def name = item[0]
|
def name = item[0]
|
||||||
@@ -182,7 +179,7 @@ node {
|
|||||||
try {
|
try {
|
||||||
if (env.BRANCH_NAME == 'devel-staging') {
|
if (env.BRANCH_NAME == 'devel-staging') {
|
||||||
deviceStage("build release-tizi-staging", "tizi-needs-can", [], [
|
deviceStage("build release-tizi-staging", "tizi-needs-can", [], [
|
||||||
step("build release-tizi-staging", "RELEASE_BRANCH=release-tizi-staging,release-mici-staging $SOURCE_DIR/tools/release/build_release.sh"),
|
step("build release-tizi-staging", "RELEASE_BRANCH=release-tizi-staging,release-mici-staging $SOURCE_DIR/release/build_release.sh"),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,12 +187,12 @@ node {
|
|||||||
parallel (
|
parallel (
|
||||||
'nightly': {
|
'nightly': {
|
||||||
deviceStage("build nightly", "tizi-needs-can", [], [
|
deviceStage("build nightly", "tizi-needs-can", [], [
|
||||||
step("build nightly", "RELEASE_BRANCH=nightly $SOURCE_DIR/tools/release/build_release.sh"),
|
step("build nightly", "RELEASE_BRANCH=nightly $SOURCE_DIR/release/build_release.sh"),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
'nightly-dev': {
|
'nightly-dev': {
|
||||||
deviceStage("build nightly-dev", "tizi-needs-can", [], [
|
deviceStage("build nightly-dev", "tizi-needs-can", [], [
|
||||||
step("build nightly-dev", "PANDA_DEBUG_BUILD=1 RELEASE_BRANCH=nightly-dev $SOURCE_DIR/tools/release/build_release.sh"),
|
step("build nightly-dev", "PANDA_DEBUG_BUILD=1 RELEASE_BRANCH=nightly-dev $SOURCE_DIR/release/build_release.sh"),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -205,51 +202,51 @@ node {
|
|||||||
parallel (
|
parallel (
|
||||||
'onroad tests': {
|
'onroad tests': {
|
||||||
deviceStage("onroad", "tizi-needs-can", ["UNSAFE=1"], [
|
deviceStage("onroad", "tizi-needs-can", ["UNSAFE=1"], [
|
||||||
step("build openpilot", "cd openpilot/system/manager && ./build.py"),
|
step("build openpilot", "cd system/manager && ./build.py"),
|
||||||
step("check dirty", "tools/release/check-dirty.sh"),
|
step("check dirty", "release/check-dirty.sh"),
|
||||||
step("onroad tests", "./openpilot/selfdrive/test/test_onroad.py", [timeout: 60]),
|
step("onroad tests", "pytest selfdrive/test/test_onroad.py -s", [timeout: 60]),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
'HW + Unit Tests': {
|
'HW + Unit Tests': {
|
||||||
deviceStage("tizi-hardware", "tizi-common", ["UNSAFE=1"], [
|
deviceStage("tizi-hardware", "tizi-common", ["UNSAFE=1"], [
|
||||||
step("build", "cd openpilot/system/manager && ./build.py"),
|
step("build", "cd system/manager && ./build.py"),
|
||||||
step("test power draw", "./openpilot/selfdrive/test/test_power_draw.py"),
|
step("test power draw", "pytest -s selfdrive/test//test_power_draw.py"),
|
||||||
step("test encoder", "./openpilot/system/loggerd/tests/test_encoder.py", [diffPaths: ["openpilot/system/loggerd/"]]),
|
step("test encoder", "LD_LIBRARY_PATH=/usr/local/lib pytest system/loggerd/tests/test_encoder.py", [diffPaths: ["system/loggerd/"]]),
|
||||||
step("test manager", "./openpilot/system/manager/test/test_manager.py"),
|
step("test manager", "pytest system/manager/test/test_manager.py"),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
'camerad OX03C10': {
|
'camerad OX03C10': {
|
||||||
deviceStage("OX03C10", "tizi-ox03c10", ["UNSAFE=1"], [
|
deviceStage("OX03C10", "tizi-ox03c10", ["UNSAFE=1"], [
|
||||||
step("build", "cd openpilot/system/manager && ./build.py"),
|
step("build", "cd system/manager && ./build.py"),
|
||||||
step("test pandad", "./openpilot/selfdrive/pandad/tests/test_pandad.py"),
|
step("test pandad", "pytest selfdrive/pandad/tests/test_pandad.py"),
|
||||||
step("test camerad", "./openpilot/system/camerad/test/test_camerad.py", [timeout: 90]),
|
step("test camerad", "pytest system/camerad/test/test_camerad.py", [timeout: 90]),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
'camerad OS04C10': {
|
'camerad OS04C10': {
|
||||||
deviceStage("OS04C10", "tici-os04c10", ["UNSAFE=1"], [
|
deviceStage("OS04C10", "tici-os04c10", ["UNSAFE=1"], [
|
||||||
step("build", "cd openpilot/system/manager && ./build.py"),
|
step("build", "cd system/manager && ./build.py"),
|
||||||
step("test pandad", "./openpilot/selfdrive/pandad/tests/test_pandad.py"),
|
step("test pandad", "pytest selfdrive/pandad/tests/test_pandad.py"),
|
||||||
step("test camerad", "./openpilot/system/camerad/test/test_camerad.py", [timeout: 90]),
|
step("test camerad", "pytest system/camerad/test/test_camerad.py", [timeout: 90]),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
'sensord': {
|
'sensord': {
|
||||||
deviceStage("LSM + MMC", "tizi-lsmc", ["UNSAFE=1"], [
|
deviceStage("LSM + MMC", "tizi-lsmc", ["UNSAFE=1"], [
|
||||||
step("build", "cd openpilot/system/manager && ./build.py"),
|
step("build", "cd system/manager && ./build.py"),
|
||||||
step("test sensord", "./openpilot/system/sensord/tests/test_sensord.py"),
|
step("test sensord", "pytest system/sensord/tests/test_sensord.py"),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
'replay': {
|
'replay': {
|
||||||
deviceStage("model-replay", "tizi-replay", ["UNSAFE=1"], [
|
deviceStage("model-replay", "tizi-replay", ["UNSAFE=1"], [
|
||||||
step("build", "cd openpilot/system/manager && ./build.py", [diffPaths: ["openpilot/selfdrive/modeld/", "tinygrad_repo", "openpilot/selfdrive/test/process_replay/model_replay.py"]]),
|
step("build", "cd system/manager && ./build.py", [diffPaths: ["selfdrive/modeld/", "tinygrad_repo", "selfdrive/test/process_replay/model_replay.py"]]),
|
||||||
step("model replay", "openpilot/selfdrive/test/process_replay/model_replay.py", [diffPaths: ["openpilot/selfdrive/modeld/", "tinygrad_repo", "openpilot/selfdrive/test/process_replay/model_replay.py"]]),
|
step("model replay", "selfdrive/test/process_replay/model_replay.py", [diffPaths: ["selfdrive/modeld/", "tinygrad_repo", "selfdrive/test/process_replay/model_replay.py"]]),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
'tizi': {
|
'tizi': {
|
||||||
deviceStage("tizi", "tizi", ["UNSAFE=1"], [
|
deviceStage("tizi", "tizi", ["UNSAFE=1"], [
|
||||||
step("build openpilot", "cd openpilot/system/manager && ./build.py"),
|
step("build openpilot", "cd system/manager && ./build.py"),
|
||||||
step("test pandad loopback", "./openpilot/selfdrive/pandad/tests/test_pandad_loopback.py"),
|
step("test pandad loopback", "pytest selfdrive/pandad/tests/test_pandad_loopback.py"),
|
||||||
step("test pandad spi", "./openpilot/selfdrive/pandad/tests/test_pandad_spi.py"),
|
step("test pandad spi", "pytest selfdrive/pandad/tests/test_pandad_spi.py"),
|
||||||
step("test amp", "./openpilot/common/hardware/comma/tests/test_amplifier.py"),
|
step("test amp", "pytest common/hardware/tici/tests/test_amplifier.py"),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
+4
-12
@@ -1,14 +1,6 @@
|
|||||||
Version 0.11.2 (2026-08-12)
|
Version 0.11.2 (2026-06-15)
|
||||||
=======================
|
========================
|
||||||
* New driving model
|
|
||||||
* Big model with 880M parameters
|
|
||||||
* Support for big models running on an external GPU
|
|
||||||
* Live stream cameras from comma connect
|
|
||||||
* Generate dashcam clips from comma connect
|
|
||||||
* Remote comma body control from comma connect
|
|
||||||
* New alert sounds
|
|
||||||
* CUPRA Born 2021-2023 support thanks to DaHansi!
|
|
||||||
* Volkswagen ID.4 2021-2025 support thanks to DaHansi!
|
|
||||||
|
|
||||||
Version 0.11.1 (2026-05-18)
|
Version 0.11.1 (2026-05-18)
|
||||||
========================
|
========================
|
||||||
@@ -1112,7 +1104,7 @@ Version 0.2.1 (2016-12-14)
|
|||||||
|
|
||||||
Version 0.2 (2016-12-12)
|
Version 0.2 (2016-12-12)
|
||||||
=========================
|
=========================
|
||||||
* Car/Radar abstraction layers have shipped, see openpilot/cereal/car.capnp
|
* Car/Radar abstraction layers have shipped, see cereal/car.capnp
|
||||||
* controlsd has been refactored
|
* controlsd has been refactored
|
||||||
* Shipped plant model and testing maneuvers
|
* Shipped plant model and testing maneuvers
|
||||||
* visiond exits more gracefully now
|
* visiond exits more gracefully now
|
||||||
|
|||||||
+41
-81
@@ -10,7 +10,7 @@ import numpy as np
|
|||||||
import SCons.Errors
|
import SCons.Errors
|
||||||
from SCons.Defaults import _stripixes
|
from SCons.Defaults import _stripixes
|
||||||
|
|
||||||
COMMA_HARDWARE = os.path.isfile('/AGNOS')
|
TICI = os.path.isfile('/TICI')
|
||||||
|
|
||||||
SCons.Warnings.warningAsException(True)
|
SCons.Warnings.warningAsException(True)
|
||||||
|
|
||||||
@@ -24,55 +24,25 @@ release = not os.path.exists(File('#.gitattributes').abspath) # file absent on r
|
|||||||
AddOption('--minimal',
|
AddOption('--minimal',
|
||||||
action='store_false',
|
action='store_false',
|
||||||
dest='extras',
|
dest='extras',
|
||||||
default=(not COMMA_HARDWARE and not release),
|
default=(not TICI and not release),
|
||||||
help='the minimum build to run openpilot. no tests, tools, etc.')
|
help='the minimum build to run openpilot. no tests, tools, etc.')
|
||||||
|
|
||||||
submodule_python_paths = [
|
|
||||||
Dir("#").abspath,
|
|
||||||
Dir("#msgq_repo").abspath,
|
|
||||||
Dir("#opendbc_repo").abspath,
|
|
||||||
Dir("#rednose_repo").abspath,
|
|
||||||
Dir("#teleoprtc_repo").abspath,
|
|
||||||
Dir("#tinygrad_repo").abspath,
|
|
||||||
]
|
|
||||||
for p in reversed(submodule_python_paths):
|
|
||||||
if p not in sys.path:
|
|
||||||
sys.path.insert(0, p)
|
|
||||||
|
|
||||||
if external_pythonpath := os.environ.get("PYTHONPATH"):
|
|
||||||
submodule_python_paths += [p for p in external_pythonpath.split(os.pathsep) if p and p not in submodule_python_paths]
|
|
||||||
|
|
||||||
# Detect platform
|
# Detect platform
|
||||||
arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip()
|
arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip()
|
||||||
if platform.system() == "Darwin":
|
if platform.system() == "Darwin":
|
||||||
arch = "Darwin"
|
arch = "Darwin"
|
||||||
elif arch == "aarch64" and COMMA_HARDWARE:
|
elif arch == "aarch64" and TICI:
|
||||||
arch = "comma_arm64"
|
arch = "larch64"
|
||||||
assert arch in [
|
assert arch in [
|
||||||
"comma_arm64", # linux comma hardware (AGNOS) arm64
|
"larch64", # linux tici arm64
|
||||||
"aarch64", # linux pc arm64
|
"aarch64", # linux pc arm64
|
||||||
"x86_64", # linux pc x64
|
"x86_64", # linux pc x64
|
||||||
"Darwin", # macOS arm64 (x86 not supported)
|
"Darwin", # macOS arm64 (x86 not supported)
|
||||||
]
|
]
|
||||||
|
|
||||||
pkg_names = ['acados', 'capnproto', 'eigen', 'ffmpeg', 'json11', 'ncurses', 'zeromq', 'zstd']
|
pkg_names = ['acados', 'bzip2', 'capnproto', 'catch2', 'eigen', 'ffmpeg', 'json11', 'libjpeg', 'libyuv', 'ncurses', 'zeromq', 'zstd']
|
||||||
pkgs = [importlib.import_module(name) for name in pkg_names]
|
pkgs = [importlib.import_module(name) for name in pkg_names]
|
||||||
acados = pkgs[pkg_names.index('acados')]
|
acados = pkgs[pkg_names.index('acados')]
|
||||||
ffmpeg = pkgs[pkg_names.index('ffmpeg')]
|
|
||||||
# Shared package ships .so/.dylib; older device venvs still have static .a only.
|
|
||||||
# Keep static link deps (x264/z/va/drm) when the installed package is static so
|
|
||||||
# COMMA_HARDWARE CI works without upgrading the device venv yet.
|
|
||||||
# TODO: drop the static fallback once device venvs have comma-deps-ffmpeg>=7.1.0.post94
|
|
||||||
_ffmpeg_lib_names = os.listdir(ffmpeg.LIB_DIR) if os.path.isdir(ffmpeg.LIB_DIR) else []
|
|
||||||
ffmpeg_shared = any(
|
|
||||||
n.startswith('libavcodec.so') or (n.startswith('libavcodec') and n.endswith('.dylib'))
|
|
||||||
for n in _ffmpeg_lib_names
|
|
||||||
)
|
|
||||||
ffmpeg_libs = ['avformat', 'avcodec', 'swresample', 'avutil']
|
|
||||||
if not ffmpeg_shared:
|
|
||||||
ffmpeg_libs += ['x264', 'z']
|
|
||||||
if arch != "Darwin":
|
|
||||||
ffmpeg_libs += ['va', 'va-drm', 'drm']
|
|
||||||
acados_include_dirs = [
|
acados_include_dirs = [
|
||||||
acados.INCLUDE_DIR,
|
acados.INCLUDE_DIR,
|
||||||
os.path.join(acados.INCLUDE_DIR, "blasfeo", "include"),
|
os.path.join(acados.INCLUDE_DIR, "blasfeo", "include"),
|
||||||
@@ -121,7 +91,7 @@ def _libflags(target, source, env, for_signature):
|
|||||||
env = Environment(
|
env = Environment(
|
||||||
ENV={
|
ENV={
|
||||||
"PATH": os.environ['PATH'],
|
"PATH": os.environ['PATH'],
|
||||||
"PYTHONPATH": os.pathsep.join(submodule_python_paths),
|
"PYTHONPATH": Dir("#").abspath,
|
||||||
"ACADOS_SOURCE_DIR": acados.DIR,
|
"ACADOS_SOURCE_DIR": acados.DIR,
|
||||||
"ACADOS_PYTHON_INTERFACE_PATH": acados.TEMPLATE_DIR,
|
"ACADOS_PYTHON_INTERFACE_PATH": acados.TEMPLATE_DIR,
|
||||||
"TERA_PATH": acados.TERA_PATH
|
"TERA_PATH": acados.TERA_PATH
|
||||||
@@ -129,11 +99,10 @@ env = Environment(
|
|||||||
CCFLAGS=[
|
CCFLAGS=[
|
||||||
"-g",
|
"-g",
|
||||||
"-fPIC",
|
"-fPIC",
|
||||||
"-pipe",
|
|
||||||
"-O2",
|
"-O2",
|
||||||
"-Wunused",
|
"-Wunused",
|
||||||
"-Werror",
|
"-Werror",
|
||||||
"-Wshadow" if arch in ("Darwin", "comma_arm64") else "-Wshadow=local",
|
"-Wshadow" if arch in ("Darwin", "larch64") else "-Wshadow=local",
|
||||||
"-Wno-unknown-warning-option",
|
"-Wno-unknown-warning-option",
|
||||||
"-Wno-inconsistent-missing-override",
|
"-Wno-inconsistent-missing-override",
|
||||||
"-Wno-c99-designator",
|
"-Wno-c99-designator",
|
||||||
@@ -143,46 +112,36 @@ env = Environment(
|
|||||||
CFLAGS=["-std=gnu11"],
|
CFLAGS=["-std=gnu11"],
|
||||||
CXXFLAGS=["-std=c++1z"],
|
CXXFLAGS=["-std=c++1z"],
|
||||||
CPPPATH=[
|
CPPPATH=[
|
||||||
"#openpilot",
|
"#",
|
||||||
"#msgq_repo", # #include "msgq/..."
|
"#msgq",
|
||||||
"#opendbc_repo", # #include "opendbc/..."
|
|
||||||
"#rednose_repo", # #include "rednose/..."
|
|
||||||
"#rednose_repo/rednose", # #include "logger/..." (rednose package root)
|
|
||||||
"#openpilot/cereal/gen/cpp",
|
|
||||||
acados_include_dirs,
|
acados_include_dirs,
|
||||||
[x.INCLUDE_DIR for x in pkgs],
|
[x.INCLUDE_DIR for x in pkgs],
|
||||||
"#",
|
|
||||||
],
|
],
|
||||||
LIBPATH=[
|
LIBPATH=[
|
||||||
"#openpilot/common",
|
"#common",
|
||||||
"#msgq_repo",
|
"#msgq_repo",
|
||||||
"#openpilot/selfdrive/pandad",
|
"#selfdrive/pandad",
|
||||||
"#rednose_repo/rednose/helpers",
|
"#rednose/helpers",
|
||||||
[x.LIB_DIR for x in pkgs],
|
[x.LIB_DIR for x in pkgs],
|
||||||
],
|
],
|
||||||
RPATH=[ffmpeg.LIB_DIR] if ffmpeg_shared else [],
|
RPATH=[],
|
||||||
CYTHONCFILESUFFIX=".cpp",
|
CYTHONCFILESUFFIX=".cpp",
|
||||||
COMPILATIONDB_USE_ABSPATH=True,
|
COMPILATIONDB_USE_ABSPATH=True,
|
||||||
REDNOSE_ROOT="#rednose_repo",
|
REDNOSE_ROOT="#",
|
||||||
tools=["default", "cython", "compilation_db", "rednose_filter"],
|
tools=["default", "cython", "compilation_db", "rednose_filter"],
|
||||||
toolpath=["#msgq_repo/site_scons/site_tools", "#rednose_repo/site_scons/site_tools"],
|
toolpath=["#site_scons/site_tools", "#rednose_repo/site_scons/site_tools"],
|
||||||
)
|
)
|
||||||
# SCons' Darwin linker tool doesn't define the variables used to expand RPATH.
|
if arch != "larch64":
|
||||||
if arch == "Darwin":
|
|
||||||
env["RPATHPREFIX"] = "-Wl,-rpath,"
|
|
||||||
env["RPATHSUFFIX"] = ""
|
|
||||||
env["_RPATH"] = "${_concat(RPATHPREFIX, RPATH, RPATHSUFFIX, __env__)}"
|
|
||||||
if arch != "comma_arm64":
|
|
||||||
env['_LIBFLAGS'] = _libflags
|
env['_LIBFLAGS'] = _libflags
|
||||||
|
|
||||||
# Arch-specific flags and paths
|
# Arch-specific flags and paths
|
||||||
if arch == "comma_arm64":
|
if arch == "larch64":
|
||||||
env["CC"] = "clang"
|
env["CC"] = "clang"
|
||||||
env["CXX"] = "clang++"
|
env["CXX"] = "clang++"
|
||||||
env.Append(LIBPATH=[
|
env.Append(LIBPATH=[
|
||||||
"/usr/lib/aarch64-linux-gnu",
|
"/usr/lib/aarch64-linux-gnu",
|
||||||
])
|
])
|
||||||
arch_flags = ["-D__COMMA_HARDWARE__", "-mcpu=cortex-a57"]
|
arch_flags = ["-D__TICI__", "-mcpu=cortex-a57", "-DQCOM2"]
|
||||||
env.Append(CCFLAGS=arch_flags)
|
env.Append(CCFLAGS=arch_flags)
|
||||||
env.Append(CXXFLAGS=arch_flags)
|
env.Append(CXXFLAGS=arch_flags)
|
||||||
elif arch == "Darwin":
|
elif arch == "Darwin":
|
||||||
@@ -231,10 +190,10 @@ else:
|
|||||||
np_version = SCons.Script.Value(np.__version__)
|
np_version = SCons.Script.Value(np.__version__)
|
||||||
Export('envCython', 'np_version')
|
Export('envCython', 'np_version')
|
||||||
|
|
||||||
Export('env', 'arch', 'acados', 'release', 'ffmpeg_libs')
|
Export('env', 'arch', 'acados', 'release')
|
||||||
|
|
||||||
# Setup cache dir
|
# Setup cache dir
|
||||||
default_cache_dir = '/data/scons_cache' if arch == "comma_arm64" else '/tmp/scons_cache'
|
default_cache_dir = '/data/scons_cache' if arch == "larch64" else '/tmp/scons_cache'
|
||||||
cache_dir = ARGUMENTS.get('cache_dir', default_cache_dir)
|
cache_dir = ARGUMENTS.get('cache_dir', default_cache_dir)
|
||||||
cache_size_limit = 4e9 if "CI" in os.environ else 2e9
|
cache_size_limit = 4e9 if "CI" in os.environ else 2e9
|
||||||
CacheDir(cache_dir)
|
CacheDir(cache_dir)
|
||||||
@@ -252,7 +211,7 @@ def prune_cache_dir(target=None, source=None, env=None):
|
|||||||
# ********** start building stuff **********
|
# ********** start building stuff **********
|
||||||
|
|
||||||
# Build common module
|
# Build common module
|
||||||
SConscript(['openpilot/common/SConscript'])
|
SConscript(['common/SConscript'])
|
||||||
Import('_common')
|
Import('_common')
|
||||||
common = [_common, 'json11', 'zmq']
|
common = [_common, 'json11', 'zmq']
|
||||||
Export('common')
|
Export('common')
|
||||||
@@ -263,7 +222,7 @@ env_swaglog = env.Clone()
|
|||||||
env_swaglog['CXXFLAGS'].append('-DSWAGLOG="\\"common/swaglog.h\\""')
|
env_swaglog['CXXFLAGS'].append('-DSWAGLOG="\\"common/swaglog.h\\""')
|
||||||
SConscript(['msgq_repo/SConscript'], exports={'env': env_swaglog})
|
SConscript(['msgq_repo/SConscript'], exports={'env': env_swaglog})
|
||||||
|
|
||||||
SConscript(['openpilot/cereal/SConscript'])
|
SConscript(['cereal/SConscript'])
|
||||||
|
|
||||||
Import('socketmaster', 'msgq')
|
Import('socketmaster', 'msgq')
|
||||||
messaging = [socketmaster, msgq, 'capnp', 'kj',]
|
messaging = [socketmaster, msgq, 'capnp', 'kj',]
|
||||||
@@ -274,33 +233,34 @@ Export('messaging')
|
|||||||
SConscript(['panda/SConscript'])
|
SConscript(['panda/SConscript'])
|
||||||
|
|
||||||
# Build rednose library
|
# Build rednose library
|
||||||
SConscript(['rednose_repo/rednose/SConscript'])
|
SConscript(['rednose/SConscript'])
|
||||||
|
|
||||||
# Build system services
|
# Build system services
|
||||||
SConscript([
|
SConscript([
|
||||||
'openpilot/system/loggerd/SConscript',
|
'system/loggerd/SConscript',
|
||||||
])
|
])
|
||||||
|
|
||||||
if arch == "comma_arm64":
|
if arch == "larch64":
|
||||||
SConscript(['openpilot/system/camerad/SConscript'])
|
SConscript(['system/camerad/SConscript'])
|
||||||
|
|
||||||
# Build selfdrive
|
# Build selfdrive
|
||||||
SConscript([
|
SConscript([
|
||||||
'openpilot/selfdrive/pandad/SConscript',
|
'selfdrive/pandad/SConscript',
|
||||||
'openpilot/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript',
|
'selfdrive/controls/lib/lateral_mpc_lib/SConscript',
|
||||||
'openpilot/selfdrive/locationd/SConscript',
|
'selfdrive/controls/lib/longitudinal_mpc_lib/SConscript',
|
||||||
'openpilot/selfdrive/modeld/SConscript',
|
'selfdrive/locationd/SConscript',
|
||||||
'openpilot/selfdrive/ui/SConscript',
|
'selfdrive/modeld/SConscript',
|
||||||
|
'selfdrive/ui/SConscript',
|
||||||
])
|
])
|
||||||
|
|
||||||
SConscript(['openpilot/sunnypilot/SConscript'])
|
SConscript(['sunnypilot/SConscript'])
|
||||||
|
|
||||||
# Build desktop-only tools
|
# Build desktop-only tools
|
||||||
if GetOption('extras') and arch != "comma_arm64":
|
if GetOption('extras') and arch != "larch64":
|
||||||
SConscript([
|
SConscript([
|
||||||
'openpilot/tools/replay/SConscript',
|
'tools/replay/SConscript',
|
||||||
'openpilot/tools/cabana/SConscript',
|
'tools/cabana/SConscript',
|
||||||
'openpilot/tools/jotpluggler/SConscript',
|
'tools/jotpluggler/SConscript',
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -24,17 +24,17 @@ things are not. Read more details [here](https://capnproto.org/language.html).
|
|||||||
### Custom forks
|
### Custom forks
|
||||||
|
|
||||||
Forks of [openpilot](https://github.com/commaai/openpilot) might want to add things to the messaging
|
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 openpilot's cereal spec. Rebasing against mainline openpilot
|
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
|
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 openpilot's cereal spec. **If you only modify those, you can ensure your
|
[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 openpilot and your fork.**
|
fork will remain backwards-compatible with all versions of mainline openpilot and your fork.**
|
||||||
|
|
||||||
An example of compatible changes:
|
An example of compatible changes:
|
||||||
```diff
|
```diff
|
||||||
diff --git a/openpilot/cereal/custom.capnp b/openpilot/cereal/custom.capnp
|
diff --git a/cereal/custom.capnp b/cereal/custom.capnp
|
||||||
index 3348e859e..3365c7b98 100644
|
index 3348e859e..3365c7b98 100644
|
||||||
--- a/openpilot/cereal/custom.capnp
|
--- a/cereal/custom.capnp
|
||||||
+++ b/openpilot/cereal/custom.capnp
|
+++ b/cereal/custom.capnp
|
||||||
@@ -10,7 +10,11 @@ $Cxx.namespace("cereal");
|
@@ -10,7 +10,11 @@ $Cxx.namespace("cereal");
|
||||||
# DO rename the structs
|
# DO rename the structs
|
||||||
# DON'T change the identifier (e.g. @0x81c2f05a394cf4af)
|
# DON'T change the identifier (e.g. @0x81c2f05a394cf4af)
|
||||||
@@ -48,10 +48,10 @@ index 3348e859e..3365c7b98 100644
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct CustomReserved1 @0xaedffd8f31e7b55d {
|
struct CustomReserved1 @0xaedffd8f31e7b55d {
|
||||||
diff --git a/openpilot/cereal/log.capnp b/openpilot/cereal/log.capnp
|
diff --git a/cereal/log.capnp b/cereal/log.capnp
|
||||||
index 1209f3fd9..b189f58b6 100644
|
index 1209f3fd9..b189f58b6 100644
|
||||||
--- a/openpilot/cereal/log.capnp
|
--- a/cereal/log.capnp
|
||||||
+++ b/openpilot/cereal/log.capnp
|
+++ b/cereal/log.capnp
|
||||||
@@ -2558,14 +2558,14 @@ struct Event {
|
@@ -2558,14 +2558,14 @@ struct Event {
|
||||||
|
|
||||||
# DO change the name of the field
|
# DO change the name of the field
|
||||||
@@ -76,7 +76,7 @@ index 1209f3fd9..b189f58b6 100644
|
|||||||
Example
|
Example
|
||||||
---
|
---
|
||||||
```python
|
```python
|
||||||
import openpilot.cereal.messaging as messaging
|
import cereal.messaging as messaging
|
||||||
|
|
||||||
# in subscriber
|
# in subscriber
|
||||||
sm = messaging.SubMaster(['sensorEvents'])
|
sm = messaging.SubMaster(['sensorEvents'])
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
Import('env', 'common', 'msgq')
|
||||||
|
|
||||||
|
cereal_dir = Dir('.')
|
||||||
|
gen_dir = Dir('gen')
|
||||||
|
|
||||||
|
# Build cereal
|
||||||
|
schema_files = ['log.capnp', 'car.capnp', 'deprecated.capnp', 'custom.capnp']
|
||||||
|
env.Command([f'gen/cpp/{s}.c++' for s in schema_files] + [f'gen/cpp/{s}.h' for s in schema_files],
|
||||||
|
schema_files,
|
||||||
|
f"capnpc --src-prefix={cereal_dir.path} $SOURCES -o c++:{gen_dir.path}/cpp/")
|
||||||
|
|
||||||
|
cereal = env.Library('cereal', [f'gen/cpp/{s}.c++' for s in schema_files])
|
||||||
|
|
||||||
|
# Build messaging
|
||||||
|
services_h = env.Command(['services.h'], ['services.py'], 'python3 ' + cereal_dir.path + '/services.py > $TARGET')
|
||||||
|
env.Program('messaging/bridge', ['messaging/bridge.cc', 'messaging/msgq_to_zmq.cc', 'messaging/bridge_zmq.cc'], LIBS=[msgq, common, 'pthread'])
|
||||||
|
|
||||||
|
socketmaster = env.Library('socketmaster', ['messaging/socketmaster.cc'])
|
||||||
|
|
||||||
|
Export('cereal', 'socketmaster')
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import os
|
||||||
|
import capnp
|
||||||
|
from importlib.resources import as_file, files
|
||||||
|
|
||||||
|
capnp.remove_import_hook()
|
||||||
|
|
||||||
|
with as_file(files("cereal")) as fspath:
|
||||||
|
CEREAL_PATH = fspath.as_posix()
|
||||||
|
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"))
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../opendbc_repo/opendbc/car/car.capnp
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using Cxx = import "/include/c++.capnp";
|
using Cxx = import "./include/c++.capnp";
|
||||||
$Cxx.namespace("cereal");
|
$Cxx.namespace("cereal");
|
||||||
|
|
||||||
@0xb526ba661d550a59;
|
@0xb526ba661d550a59;
|
||||||
@@ -69,8 +69,6 @@ struct LeadData {
|
|||||||
struct SelfdriveStateSP @0x81c2f05a394cf4af {
|
struct SelfdriveStateSP @0x81c2f05a394cf4af {
|
||||||
mads @0 :ModularAssistiveDrivingSystem;
|
mads @0 :ModularAssistiveDrivingSystem;
|
||||||
intelligentCruiseButtonManagement @1 :IntelligentCruiseButtonManagement;
|
intelligentCruiseButtonManagement @1 :IntelligentCruiseButtonManagement;
|
||||||
buttonsPressed @2 :UInt16;
|
|
||||||
buttonsReleaseToggle @3 :UInt16;
|
|
||||||
|
|
||||||
enum AudibleAlert {
|
enum AudibleAlert {
|
||||||
none @0;
|
none @0;
|
||||||
@@ -139,16 +137,10 @@ struct ModelManagerSP @0xaedffd8f31e7b55d {
|
|||||||
eta @2 :UInt32;
|
eta @2 :UInt32;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Chunk {
|
|
||||||
fileName @0 :Text;
|
|
||||||
sha256 @1 :Text;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Artifact {
|
struct Artifact {
|
||||||
fileName @0 :Text;
|
fileName @0 :Text;
|
||||||
downloadUri @1 :DownloadUri;
|
downloadUri @1 :DownloadUri;
|
||||||
downloadProgress @2 :DownloadProgress;
|
downloadProgress @2 :DownloadProgress;
|
||||||
chunks @3 :List(Chunk);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Model {
|
struct Model {
|
||||||
@@ -163,7 +155,6 @@ struct ModelManagerSP @0xaedffd8f31e7b55d {
|
|||||||
policy @3;
|
policy @3;
|
||||||
offPolicy @4;
|
offPolicy @4;
|
||||||
onPolicy @5;
|
onPolicy @5;
|
||||||
chunked @6;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,7 +342,6 @@ struct OnroadEventSP @0xda96579883444c35 {
|
|||||||
speedLimitChanged @21;
|
speedLimitChanged @21;
|
||||||
speedLimitPending @22;
|
speedLimitPending @22;
|
||||||
e2eChime @23;
|
e2eChime @23;
|
||||||
laneChangeRoadEdge @24;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,8 +448,6 @@ struct LiveMapDataSP @0xf416ec09499d9d19 {
|
|||||||
|
|
||||||
struct ModelDataV2SP @0xa1680744031fdb2d {
|
struct ModelDataV2SP @0xa1680744031fdb2d {
|
||||||
laneTurnDirection @0 :TurnDirection;
|
laneTurnDirection @0 :TurnDirection;
|
||||||
leftLaneChangeEdgeBlock @1 :Bool;
|
|
||||||
rightLaneChangeEdgeBlock @2 :Bool;
|
|
||||||
|
|
||||||
enum TurnDirection {
|
enum TurnDirection {
|
||||||
none @0;
|
none @0;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using Cxx = import "/include/c++.capnp";
|
using Cxx = import "./include/c++.capnp";
|
||||||
$Cxx.namespace("cereal");
|
$Cxx.namespace("cereal");
|
||||||
|
|
||||||
@0x80ef1ec4889c2a63;
|
@0x80ef1ec4889c2a63;
|
||||||
@@ -775,13 +775,3 @@ struct GpsTrajectory @0x8cfeb072f5301000 {
|
|||||||
x @0 :List(Float32);
|
x @0 :List(Float32);
|
||||||
y @1 :List(Float32);
|
y @1 :List(Float32);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AudioFeedbackDEPRECATED @0xed47e3c075be372a {
|
|
||||||
audio @0 :AudioData;
|
|
||||||
blockNum @1 :UInt16;
|
|
||||||
|
|
||||||
struct AudioData {
|
|
||||||
data @0 :Data;
|
|
||||||
sampleRate @1 :UInt32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using Cxx = import "/include/c++.capnp";
|
using Cxx = import "./include/c++.capnp";
|
||||||
$Cxx.namespace("cereal");
|
$Cxx.namespace("cereal");
|
||||||
|
|
||||||
using Car = import "/car.capnp";
|
using Car = import "car.capnp";
|
||||||
using Deprecated = import "deprecated.capnp";
|
using Deprecated = import "deprecated.capnp";
|
||||||
using Custom = import "custom.capnp";
|
using Custom = import "custom.capnp";
|
||||||
|
|
||||||
@@ -75,6 +75,7 @@ struct OnroadEvent @0xc4fa6047f024e718 {
|
|||||||
driverUnresponsive2 @37;
|
driverUnresponsive2 @37;
|
||||||
driverUnresponsive3 @38;
|
driverUnresponsive3 @38;
|
||||||
belowSteerSpeed @39;
|
belowSteerSpeed @39;
|
||||||
|
lowBattery @40;
|
||||||
accFaulted @41;
|
accFaulted @41;
|
||||||
sensorDataInvalid @42;
|
sensorDataInvalid @42;
|
||||||
commIssue @43;
|
commIssue @43;
|
||||||
@@ -106,17 +107,18 @@ struct OnroadEvent @0xc4fa6047f024e718 {
|
|||||||
noGps @68;
|
noGps @68;
|
||||||
wrongCruiseMode @69;
|
wrongCruiseMode @69;
|
||||||
modeldLagging @70;
|
modeldLagging @70;
|
||||||
|
deviceFalling @71;
|
||||||
fanMalfunction @72;
|
fanMalfunction @72;
|
||||||
cameraMalfunction @73;
|
cameraMalfunction @73;
|
||||||
cameraFrameRate @74;
|
cameraFrameRate @74;
|
||||||
processNotRunning @75;
|
processNotRunning @75;
|
||||||
dashcamMode @76;
|
dashcamMode @76;
|
||||||
selfdriveInitializing @77;
|
selfdriveInitializing @77;
|
||||||
|
usbError @78;
|
||||||
cruiseMismatch @79;
|
cruiseMismatch @79;
|
||||||
canBusMissing @80;
|
canBusMissing @80;
|
||||||
selfdrivedLagging @81;
|
selfdrivedLagging @81;
|
||||||
resumeBlocked @82;
|
resumeBlocked @82;
|
||||||
carNotReady @103;
|
|
||||||
steerTimeLimit @83;
|
steerTimeLimit @83;
|
||||||
vehicleSensorsInvalid @84;
|
vehicleSensorsInvalid @84;
|
||||||
locationdTemporaryError @85;
|
locationdTemporaryError @85;
|
||||||
@@ -129,15 +131,9 @@ struct OnroadEvent @0xc4fa6047f024e718 {
|
|||||||
aeb @92;
|
aeb @92;
|
||||||
userBookmark @95;
|
userBookmark @95;
|
||||||
excessiveActuation @96;
|
excessiveActuation @96;
|
||||||
bigModelLoading @100;
|
audioFeedback @97;
|
||||||
bigModelFailed @102;
|
|
||||||
|
|
||||||
lowBatteryDEPRECATED @40;
|
|
||||||
soundsUnavailableDEPRECATED @47;
|
soundsUnavailableDEPRECATED @47;
|
||||||
deviceFallingDEPRECATED @71;
|
|
||||||
usbErrorDEPRECATED @78;
|
|
||||||
audioFeedbackDEPRECATED @97;
|
|
||||||
bigModelReadyDEPRECATED @101;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,13 +176,13 @@ struct InitData {
|
|||||||
|
|
||||||
enum DeviceType {
|
enum DeviceType {
|
||||||
unknown @0;
|
unknown @0;
|
||||||
neo @1; # NEO, EON, & comma two
|
neo @1;
|
||||||
chffrAndroid @2;
|
chffrAndroid @2;
|
||||||
chffrIos @3;
|
chffrIos @3;
|
||||||
tici @4; # comma three
|
tici @4;
|
||||||
pc @5;
|
pc @5;
|
||||||
tizi @6; # comma 3X
|
tizi @6;
|
||||||
mici @7; # comma four
|
mici @7;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PandaInfo {
|
struct PandaInfo {
|
||||||
@@ -418,10 +414,6 @@ struct CanData {
|
|||||||
struct DeviceState @0xa4d8b5af2aa492eb {
|
struct DeviceState @0xa4d8b5af2aa492eb {
|
||||||
deviceType @45 :InitData.DeviceType;
|
deviceType @45 :InitData.DeviceType;
|
||||||
|
|
||||||
# usb
|
|
||||||
chestnutPresent @51 :Bool;
|
|
||||||
usbState @52 :UsbState;
|
|
||||||
|
|
||||||
networkType @22 :NetworkType;
|
networkType @22 :NetworkType;
|
||||||
networkInfo @31 :NetworkInfo;
|
networkInfo @31 :NetworkInfo;
|
||||||
networkStrength @24 :NetworkStrength;
|
networkStrength @24 :NetworkStrength;
|
||||||
@@ -692,67 +684,33 @@ struct PeripheralState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UsbState {
|
|
||||||
devices @0 :List(Device);
|
|
||||||
|
|
||||||
struct Device {
|
|
||||||
busnum @0 :UInt8;
|
|
||||||
devnum @1 :UInt8;
|
|
||||||
vendorId @2 :UInt16;
|
|
||||||
productId @3 :UInt16;
|
|
||||||
speedMbps @4 :UInt16;
|
|
||||||
manufacturer @6 :Text;
|
|
||||||
product @5 :Text;
|
|
||||||
linkErrorCount @7 :UInt16;
|
|
||||||
usb3Lane @8 :Usb3Lane;
|
|
||||||
|
|
||||||
enum Usb3Lane {
|
|
||||||
unknown @0;
|
|
||||||
a @1;
|
|
||||||
b @2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ChestnutState {
|
|
||||||
tempC @0 :Float32;
|
|
||||||
memoryTempC @1 :Float32;
|
|
||||||
powerDrawW @2 :Float32;
|
|
||||||
powerLimitW @3 :Float32;
|
|
||||||
gpuUsagePercent @4 :UInt8;
|
|
||||||
gpuClockMhz @5 :UInt16;
|
|
||||||
fanSpeedRpm @6 :UInt16;
|
|
||||||
pcieLtssm @7 :UInt8;
|
|
||||||
supplyVoltage @8 :UInt16; # mV
|
|
||||||
supplyCurrent @9 :Int16; # mA
|
|
||||||
}
|
|
||||||
|
|
||||||
struct RadarState @0x9a185389d6fdd05f {
|
struct RadarState @0x9a185389d6fdd05f {
|
||||||
mdMonoTime @6 :UInt64; # for debugging
|
mdMonoTime @6 :UInt64;
|
||||||
|
carStateMonoTime @11 :UInt64;
|
||||||
radarErrors @13 :Car.RadarData.Error;
|
radarErrors @13 :Car.RadarData.Error;
|
||||||
|
|
||||||
leadOne @3 :LeadData;
|
leadOne @3 :LeadData;
|
||||||
leadTwo @4 :LeadData;
|
leadTwo @4 :LeadData;
|
||||||
|
|
||||||
struct LeadData {
|
struct LeadData {
|
||||||
dRel @0 :Float32; # m from the front bumper of the car
|
dRel @0 :Float32;
|
||||||
yRel @1 :Float32; # m in car frame, left positive
|
yRel @1 :Float32;
|
||||||
vRel @2 :Float32; # m/s relative longitudinal speed
|
vRel @2 :Float32;
|
||||||
vLead @4 :Float32; # m/s absolute lead speed
|
aRel @3 :Float32;
|
||||||
vLeadK @8 :Float32; # kalman-filtered lead speed
|
vLead @4 :Float32;
|
||||||
aLeadK @9 :Float32; # kalman-filtered lead accel
|
dPath @6 :Float32;
|
||||||
present @11 :Bool; # true if a lead is present
|
vLat @7 :Float32;
|
||||||
aLeadTau @12 :Float32; # lead accel time constant
|
vLeadK @8 :Float32;
|
||||||
modelProb @13 :Float32; # vision model lead probability
|
aLeadK @9 :Float32;
|
||||||
radar @14 :Bool; # true if lead is radar-matched (vs vision-only)
|
fcw @10 :Bool;
|
||||||
radarTrackId @15 :Int32 = -1; # for debugging
|
status @11 :Bool;
|
||||||
|
aLeadTau @12 :Float32;
|
||||||
|
modelProb @13 :Float32;
|
||||||
|
radar @14 :Bool;
|
||||||
|
radarTrackId @15 :Int32 = -1;
|
||||||
|
|
||||||
deprecated :group {
|
deprecated :group {
|
||||||
aRel @3 :Float32;
|
|
||||||
aLead @5 :Float32;
|
aLead @5 :Float32;
|
||||||
dPath @6 :Float32;
|
|
||||||
vLat @7 :Float32;
|
|
||||||
fcw @10 :Bool;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -765,12 +723,11 @@ struct RadarState @0x9a185389d6fdd05f {
|
|||||||
calPerc @9 :Int8;
|
calPerc @9 :Int8;
|
||||||
canMonoTimes @10 :List(UInt64);
|
canMonoTimes @10 :List(UInt64);
|
||||||
cumLagMs @5 :Float32;
|
cumLagMs @5 :Float32;
|
||||||
carStateMonoTime @11 :UInt64;
|
|
||||||
radarErrors @12 :List(Car.RadarData.ErrorDEPRECATED);
|
radarErrors @12 :List(Car.RadarData.ErrorDEPRECATED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ExtrinsicsCalibration @0x96df70754d8390bc {
|
struct LiveCalibrationData {
|
||||||
calStatus @11 :Status;
|
calStatus @11 :Status;
|
||||||
calCycle @2 :Int32;
|
calCycle @2 :Int32;
|
||||||
calPerc @3 :Int8;
|
calPerc @3 :Int8;
|
||||||
@@ -814,31 +771,13 @@ struct SelfdriveState {
|
|||||||
alertStatus @5 :AlertStatus;
|
alertStatus @5 :AlertStatus;
|
||||||
alertSize @6 :AlertSize;
|
alertSize @6 :AlertSize;
|
||||||
alertType @7 :Text;
|
alertType @7 :Text;
|
||||||
alertSound @13 :AudibleAlert;
|
alertSound @8 :Car.CarControl.HUDControl.AudibleAlert;
|
||||||
alertHudVisual @12 :Car.CarControl.HUDControl.VisualAlert;
|
alertHudVisual @12 :Car.CarControl.HUDControl.VisualAlert;
|
||||||
|
|
||||||
# configurable driving settings
|
# configurable driving settings
|
||||||
experimentalMode @10 :Bool;
|
experimentalMode @10 :Bool;
|
||||||
personality @11 :LongitudinalPersonality;
|
personality @11 :LongitudinalPersonality;
|
||||||
|
|
||||||
enum AudibleAlert {
|
|
||||||
none @0;
|
|
||||||
|
|
||||||
engage @1;
|
|
||||||
disengage @2;
|
|
||||||
refuse @3;
|
|
||||||
|
|
||||||
warningSoft @4;
|
|
||||||
warningImmediate @5;
|
|
||||||
|
|
||||||
prompt @6;
|
|
||||||
promptRepeat @7;
|
|
||||||
promptDistracted @8;
|
|
||||||
|
|
||||||
preAlert @9;
|
|
||||||
complete @10;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OpenpilotState @0xdbe58b96d2d1ac61 {
|
enum OpenpilotState @0xdbe58b96d2d1ac61 {
|
||||||
disabled @0;
|
disabled @0;
|
||||||
preEnabled @1;
|
preEnabled @1;
|
||||||
@@ -859,10 +798,6 @@ struct SelfdriveState {
|
|||||||
mid @2;
|
mid @2;
|
||||||
full @3;
|
full @3;
|
||||||
}
|
}
|
||||||
|
|
||||||
deprecated :group {
|
|
||||||
alertSound @8 :Car.CarControl.HUDControl.AudibleAlert;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ControlsState @0x97ff69c53601abf1 {
|
struct ControlsState @0x97ff69c53601abf1 {
|
||||||
@@ -983,7 +918,7 @@ struct ControlsState @0x97ff69c53601abf1 {
|
|||||||
alertStatus @38 :SelfdriveState.AlertStatus;
|
alertStatus @38 :SelfdriveState.AlertStatus;
|
||||||
alertSize @39 :SelfdriveState.AlertSize;
|
alertSize @39 :SelfdriveState.AlertSize;
|
||||||
alertType @44 :Text;
|
alertType @44 :Text;
|
||||||
alertSound2 @56 :SelfdriveState.AudibleAlert;
|
alertSound2 @56 :Car.CarControl.HUDControl.AudibleAlert;
|
||||||
engageable @41 :Bool; # can OP be engaged?
|
engageable @41 :Bool; # can OP be engaged?
|
||||||
state @31 :SelfdriveState.OpenpilotState;
|
state @31 :SelfdriveState.OpenpilotState;
|
||||||
enabled @19 :Bool;
|
enabled @19 :Bool;
|
||||||
@@ -1050,7 +985,6 @@ struct ModelDataV2 {
|
|||||||
timestampEof @3 :UInt64;
|
timestampEof @3 :UInt64;
|
||||||
modelExecutionTime @15 :Float32;
|
modelExecutionTime @15 :Float32;
|
||||||
rawPredictions @16 :Data;
|
rawPredictions @16 :Data;
|
||||||
big @27 :Bool;
|
|
||||||
|
|
||||||
# predicted future position, orientation, etc..
|
# predicted future position, orientation, etc..
|
||||||
position @4 :XYZTData;
|
position @4 :XYZTData;
|
||||||
@@ -1067,6 +1001,7 @@ struct ModelDataV2 {
|
|||||||
roadEdgeStds @14 :List(Float32);
|
roadEdgeStds @14 :List(Float32);
|
||||||
|
|
||||||
# predicted lead cars
|
# predicted lead cars
|
||||||
|
leads @11 :List(LeadDataV2);
|
||||||
leadsV3 @18 :List(LeadDataV3);
|
leadsV3 @18 :List(LeadDataV3);
|
||||||
|
|
||||||
meta @12 :MetaData;
|
meta @12 :MetaData;
|
||||||
@@ -1076,9 +1011,8 @@ struct ModelDataV2 {
|
|||||||
action @26: Action;
|
action @26: Action;
|
||||||
|
|
||||||
lateralPlannerSolutionDEPRECATED @25: Deprecated.LateralPlannerSolution;
|
lateralPlannerSolutionDEPRECATED @25: Deprecated.LateralPlannerSolution;
|
||||||
leadsDEPRECATED @11 :List(LeadDataV2DEPRECATED);
|
|
||||||
|
|
||||||
struct LeadDataV2DEPRECATED {
|
struct LeadDataV2 {
|
||||||
prob @0 :Float32; # probability that car is your lead at time t
|
prob @0 :Float32; # probability that car is your lead at time t
|
||||||
t @1 :Float32;
|
t @1 :Float32;
|
||||||
|
|
||||||
@@ -1198,7 +1132,7 @@ struct EncodeIndex {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OperatingSystemLogEntry {
|
struct AndroidLogEntry {
|
||||||
id @0 :UInt8;
|
id @0 :UInt8;
|
||||||
ts @1 :UInt64;
|
ts @1 :UInt64;
|
||||||
priority @2 :UInt8;
|
priority @2 :UInt8;
|
||||||
@@ -1336,7 +1270,7 @@ struct LateralPlan @0xe1e9318e2ae8b51e {
|
|||||||
struct LiveLocationKalman {
|
struct LiveLocationKalman {
|
||||||
|
|
||||||
# More info on reference frames:
|
# More info on reference frames:
|
||||||
# https://github.com/commaai/openpilot/tree/master/openpilot/common/transformations
|
# https://github.com/commaai/openpilot/tree/master/common/transformations
|
||||||
|
|
||||||
positionECEF @0 : Measurement;
|
positionECEF @0 : Measurement;
|
||||||
positionGeodetic @1 : Measurement;
|
positionGeodetic @1 : Measurement;
|
||||||
@@ -1391,9 +1325,9 @@ struct LiveLocationKalman {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct DeviceMotion @0xc24ca2b57206b44d {
|
struct LivePose {
|
||||||
# More info on reference frames:
|
# More info on reference frames:
|
||||||
# https://github.com/commaai/openpilot/tree/master/openpilot/common/transformations
|
# https://github.com/commaai/openpilot/tree/master/common/transformations
|
||||||
orientationNED @0 :XYZMeasurement;
|
orientationNED @0 :XYZMeasurement;
|
||||||
velocityDevice @1 :XYZMeasurement;
|
velocityDevice @1 :XYZMeasurement;
|
||||||
accelerationDevice @2 :XYZMeasurement;
|
accelerationDevice @2 :XYZMeasurement;
|
||||||
@@ -2186,11 +2120,8 @@ struct DriverMonitoringStateDEPRECATED @0xb83cda094a1da284 {
|
|||||||
|
|
||||||
struct DriverMonitoringState {
|
struct DriverMonitoringState {
|
||||||
lockout @0 :Bool;
|
lockout @0 :Bool;
|
||||||
lockoutCount @15 :Int8;
|
alertCountLockoutPercent @1 :Int8;
|
||||||
lockoutMinutesRemaining @11 :Int8;
|
alertTimeLockoutPercent @2 :Int8;
|
||||||
alert3Count @12 :Int8;
|
|
||||||
noResponseCount @13 :Int8;
|
|
||||||
noResponseForceDecel @14 :Bool;
|
|
||||||
|
|
||||||
alwaysOn @3 :Bool;
|
alwaysOn @3 :Bool;
|
||||||
alwaysOnLockout @4 :Bool;
|
alwaysOnLockout @4 :Bool;
|
||||||
@@ -2254,11 +2185,6 @@ struct DriverMonitoringState {
|
|||||||
calibratedPercent @0 :Int8;
|
calibratedPercent @0 :Int8;
|
||||||
offset @1 :Float32;
|
offset @1 :Float32;
|
||||||
}
|
}
|
||||||
|
|
||||||
deprecated :group {
|
|
||||||
alertCountLockoutPercent @1 :Int8;
|
|
||||||
alertTimeLockoutPercent @2 :Int8;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Boot {
|
struct Boot {
|
||||||
@@ -2273,7 +2199,7 @@ struct Boot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VehicleParameters @0xd9058dcb967c2753 {
|
struct LiveParametersData {
|
||||||
valid @0 :Bool;
|
valid @0 :Bool;
|
||||||
gyroBias @1 :Float32;
|
gyroBias @1 :Float32;
|
||||||
angleOffsetDeg @2 :Float32;
|
angleOffsetDeg @2 :Float32;
|
||||||
@@ -2307,8 +2233,8 @@ struct VehicleParameters @0xd9058dcb967c2753 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LateralTorqueParameters @0xe61690eb0b091692 {
|
struct LiveTorqueParametersData {
|
||||||
valid @0 :Bool;
|
liveValid @0 :Bool;
|
||||||
latAccelFactorRaw @1 :Float32;
|
latAccelFactorRaw @1 :Float32;
|
||||||
latAccelOffsetRaw @2 :Float32;
|
latAccelOffsetRaw @2 :Float32;
|
||||||
frictionCoefficientRaw @3 :Float32;
|
frictionCoefficientRaw @3 :Float32;
|
||||||
@@ -2324,7 +2250,7 @@ struct LateralTorqueParameters @0xe61690eb0b091692 {
|
|||||||
calPerc @13 :Int8;
|
calPerc @13 :Int8;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LateralDelay @0x98dfdb22c44df8d4 {
|
struct LiveDelayData {
|
||||||
lateralDelay @0 :Float32;
|
lateralDelay @0 :Float32;
|
||||||
validBlocks @1 :Int32;
|
validBlocks @1 :Int32;
|
||||||
status @2 :Status;
|
status @2 :Status;
|
||||||
@@ -2510,6 +2436,11 @@ struct AudioData {
|
|||||||
sampleRate @1 :UInt32;
|
sampleRate @1 :UInt32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct AudioFeedback {
|
||||||
|
audio @0 :AudioData;
|
||||||
|
blockNum @1 :UInt16;
|
||||||
|
}
|
||||||
|
|
||||||
struct Touch {
|
struct Touch {
|
||||||
sec @0 :Int64;
|
sec @0 :Int64;
|
||||||
usec @1 :Int64;
|
usec @1 :Int64;
|
||||||
@@ -2542,9 +2473,9 @@ struct Event {
|
|||||||
pandaStates @81 :List(PandaState);
|
pandaStates @81 :List(PandaState);
|
||||||
peripheralState @80 :PeripheralState;
|
peripheralState @80 :PeripheralState;
|
||||||
radarState @13 :RadarState;
|
radarState @13 :RadarState;
|
||||||
radarTracks @131 :Car.RadarData;
|
liveTracks @131 :Car.RadarData;
|
||||||
sendcan @17 :List(CanData);
|
sendcan @17 :List(CanData);
|
||||||
extrinsicsCalibration @19 :ExtrinsicsCalibration;
|
liveCalibration @19 :LiveCalibrationData;
|
||||||
carState @22 :Car.CarState;
|
carState @22 :Car.CarState;
|
||||||
carControl @23 :Car.CarControl;
|
carControl @23 :Car.CarControl;
|
||||||
carOutput @127 :Car.CarOutput;
|
carOutput @127 :Car.CarOutput;
|
||||||
@@ -2555,43 +2486,42 @@ struct Event {
|
|||||||
qcomGnss @31 :QcomGnss;
|
qcomGnss @31 :QcomGnss;
|
||||||
gpsLocationExternal @48 :GpsLocationData;
|
gpsLocationExternal @48 :GpsLocationData;
|
||||||
gpsLocation @21 :GpsLocationData;
|
gpsLocation @21 :GpsLocationData;
|
||||||
vehicleParameters @61 :VehicleParameters;
|
liveParameters @61 :LiveParametersData;
|
||||||
lateralTorqueParameters @94 :LateralTorqueParameters;
|
liveTorqueParameters @94 :LiveTorqueParametersData;
|
||||||
lateralDelay @146 : LateralDelay;
|
liveDelay @146 : LiveDelayData;
|
||||||
cameraOdometry @63 :CameraOdometry;
|
cameraOdometry @63 :CameraOdometry;
|
||||||
thumbnail @66: Thumbnail;
|
thumbnail @66: Thumbnail;
|
||||||
onroadEvents @134: List(OnroadEvent);
|
onroadEvents @134: List(OnroadEvent);
|
||||||
carParams @69: Car.CarParams;
|
carParams @69: Car.CarParams;
|
||||||
driverMonitoringState @151 :DriverMonitoringState;
|
driverMonitoringState @151 :DriverMonitoringState;
|
||||||
deviceMotion @129 :DeviceMotion;
|
livePose @129 :LivePose;
|
||||||
modelV2 @75 :ModelDataV2;
|
modelV2 @75 :ModelDataV2;
|
||||||
drivingModelData @128 :DrivingModelData;
|
drivingModelData @128 :DrivingModelData;
|
||||||
driverStateV2 @92 :DriverStateV2;
|
driverStateV2 @92 :DriverStateV2;
|
||||||
|
|
||||||
# camera stuff, each camera state has a matching encode idx
|
# camera stuff, each camera state has a matching encode idx
|
||||||
narrowRoadCameraState @2 :FrameData;
|
roadCameraState @2 :FrameData;
|
||||||
cabinCameraState @70: FrameData;
|
driverCameraState @70: FrameData;
|
||||||
wideRoadCameraState @74: FrameData;
|
wideRoadCameraState @74: FrameData;
|
||||||
narrowRoadEncodeIdx @15 :EncodeIndex;
|
roadEncodeIdx @15 :EncodeIndex;
|
||||||
cabinEncodeIdx @76 :EncodeIndex;
|
driverEncodeIdx @76 :EncodeIndex;
|
||||||
wideRoadEncodeIdx @77 :EncodeIndex;
|
wideRoadEncodeIdx @77 :EncodeIndex;
|
||||||
qNarrowRoadEncodeIdx @90 :EncodeIndex;
|
qRoadEncodeIdx @90 :EncodeIndex;
|
||||||
|
|
||||||
livestreamNarrowRoadEncodeIdx @117 :EncodeIndex;
|
livestreamRoadEncodeIdx @117 :EncodeIndex;
|
||||||
livestreamWideRoadEncodeIdx @118 :EncodeIndex;
|
livestreamWideRoadEncodeIdx @118 :EncodeIndex;
|
||||||
livestreamCabinEncodeIdx @119 :EncodeIndex;
|
livestreamDriverEncodeIdx @119 :EncodeIndex;
|
||||||
|
|
||||||
# microphone data
|
# microphone data
|
||||||
soundPressure @103 :SoundPressure;
|
soundPressure @103 :SoundPressure;
|
||||||
rawAudioData @147 :AudioData;
|
rawAudioData @147 :AudioData;
|
||||||
|
|
||||||
# systems stuff
|
# systems stuff
|
||||||
operatingSystemLog @20 :OperatingSystemLogEntry;
|
androidLog @20 :AndroidLogEntry;
|
||||||
managerState @78 :ManagerState;
|
managerState @78 :ManagerState;
|
||||||
procLog @33 :ProcLog;
|
procLog @33 :ProcLog;
|
||||||
clocks @35 :Clocks;
|
clocks @35 :Clocks;
|
||||||
deviceState @6 :DeviceState;
|
deviceState @6 :DeviceState;
|
||||||
chestnutState @152 :ChestnutState;
|
|
||||||
logMessage @18 :Text;
|
logMessage @18 :Text;
|
||||||
errorLogMessage @85 :Text;
|
errorLogMessage @85 :Text;
|
||||||
|
|
||||||
@@ -2604,20 +2534,21 @@ struct Event {
|
|||||||
# driving feedback
|
# driving feedback
|
||||||
userBookmark @93 :UserBookmark;
|
userBookmark @93 :UserBookmark;
|
||||||
bookmarkButton @148 :UserBookmark;
|
bookmarkButton @148 :UserBookmark;
|
||||||
|
audioFeedback @149 :AudioFeedback;
|
||||||
|
|
||||||
lateralManeuverPlan @150 :LateralManeuverPlan;
|
lateralManeuverPlan @150 :LateralManeuverPlan;
|
||||||
|
|
||||||
# *********** debug ***********
|
# *********** debug ***********
|
||||||
testJoystick @52 :Joystick;
|
testJoystick @52 :Joystick;
|
||||||
narrowRoadEncodeData @86 :EncodeData;
|
roadEncodeData @86 :EncodeData;
|
||||||
cabinEncodeData @87 :EncodeData;
|
driverEncodeData @87 :EncodeData;
|
||||||
wideRoadEncodeData @88 :EncodeData;
|
wideRoadEncodeData @88 :EncodeData;
|
||||||
qNarrowRoadEncodeData @89 :EncodeData;
|
qRoadEncodeData @89 :EncodeData;
|
||||||
alertDebug @133 :DebugAlert;
|
alertDebug @133 :DebugAlert;
|
||||||
|
|
||||||
livestreamNarrowRoadEncodeData @120 :EncodeData;
|
livestreamRoadEncodeData @120 :EncodeData;
|
||||||
livestreamWideRoadEncodeData @121 :EncodeData;
|
livestreamWideRoadEncodeData @121 :EncodeData;
|
||||||
livestreamCabinEncodeData @122 :EncodeData;
|
livestreamDriverEncodeData @122 :EncodeData;
|
||||||
|
|
||||||
# *********** Custom: reserved for forks ***********
|
# *********** Custom: reserved for forks ***********
|
||||||
|
|
||||||
@@ -2653,7 +2584,6 @@ struct Event {
|
|||||||
|
|
||||||
# *********** legacy + deprecated ***********
|
# *********** legacy + deprecated ***********
|
||||||
model @9 :Deprecated.ModelData; # TODO: rename modelV2 and mark this as deprecated
|
model @9 :Deprecated.ModelData; # TODO: rename modelV2 and mark this as deprecated
|
||||||
audioFeedbackDEPRECATED @149 :Deprecated.AudioFeedbackDEPRECATED;
|
|
||||||
liveMpcDEPRECATED @36 :Deprecated.LiveMpcData;
|
liveMpcDEPRECATED @36 :Deprecated.LiveMpcData;
|
||||||
liveLongitudinalMpcDEPRECATED @37 :Deprecated.LiveLongitudinalMpcData;
|
liveLongitudinalMpcDEPRECATED @37 :Deprecated.LiveLongitudinalMpcData;
|
||||||
liveLocationKalmanDeprecatedDEPRECATED @51 :Deprecated.LiveLocationData;
|
liveLocationKalmanDeprecatedDEPRECATED @51 :Deprecated.LiveLocationData;
|
||||||
@@ -7,43 +7,12 @@ import os
|
|||||||
import capnp
|
import capnp
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from typing import Union
|
from typing import Optional, List, Union, Dict
|
||||||
|
|
||||||
from openpilot.cereal import log
|
from cereal import log
|
||||||
from openpilot.cereal.services import SERVICE_LIST
|
from cereal.services import SERVICE_LIST
|
||||||
from openpilot.common.utils import MovingAverage
|
from openpilot.common.utils import MovingAverage
|
||||||
|
|
||||||
__all__ = (
|
|
||||||
"NO_TRAVERSAL_LIMIT",
|
|
||||||
"Context",
|
|
||||||
"FrequencyTracker",
|
|
||||||
"IpcError",
|
|
||||||
"MultiplePublishersError",
|
|
||||||
"Poller",
|
|
||||||
"PubMaster",
|
|
||||||
"PubSocket",
|
|
||||||
"SocketEventHandle",
|
|
||||||
"SubMaster",
|
|
||||||
"SubSocket",
|
|
||||||
"delete_fake_prefix",
|
|
||||||
"drain_sock",
|
|
||||||
"drain_sock_raw",
|
|
||||||
"fake_event_handle",
|
|
||||||
"get_fake_prefix",
|
|
||||||
"log_from_bytes",
|
|
||||||
"new_message",
|
|
||||||
"pub_sock",
|
|
||||||
"recv_one",
|
|
||||||
"recv_one_or_none",
|
|
||||||
"recv_one_retry",
|
|
||||||
"recv_sock",
|
|
||||||
"reset_context",
|
|
||||||
"set_fake_prefix",
|
|
||||||
"sub_sock",
|
|
||||||
"toggle_fake_events",
|
|
||||||
"wait_for_one_event",
|
|
||||||
)
|
|
||||||
|
|
||||||
NO_TRAVERSAL_LIMIT = 2**64-1
|
NO_TRAVERSAL_LIMIT = 2**64-1
|
||||||
|
|
||||||
|
|
||||||
@@ -53,8 +22,8 @@ def pub_sock(endpoint: str) -> PubSocket:
|
|||||||
return msgq.pub_sock(endpoint, segment_size)
|
return msgq.pub_sock(endpoint, segment_size)
|
||||||
|
|
||||||
|
|
||||||
def sub_sock(endpoint: str, poller: Poller | None = None, addr: str = "127.0.0.1",
|
def sub_sock(endpoint: str, poller: Optional[Poller] = None, addr: str = "127.0.0.1",
|
||||||
conflate: bool = False, timeout: int | None = None) -> SubSocket:
|
conflate: bool = False, timeout: Optional[int] = None) -> SubSocket:
|
||||||
service = SERVICE_LIST.get(endpoint)
|
service = SERVICE_LIST.get(endpoint)
|
||||||
segment_size = service.queue_size if service else 0
|
segment_size = service.queue_size if service else 0
|
||||||
return msgq.sub_sock(endpoint, poller=poller, addr=addr, conflate=conflate,
|
return msgq.sub_sock(endpoint, poller=poller, addr=addr, conflate=conflate,
|
||||||
@@ -70,7 +39,7 @@ def log_from_bytes(dat: bytes, struct: capnp.lib.capnp._StructModule = log.Event
|
|||||||
return msg
|
return msg
|
||||||
|
|
||||||
|
|
||||||
def new_message(service: str | None, size: int | None = None, **kwargs) -> capnp.lib.capnp._DynamicStructBuilder:
|
def new_message(service: Optional[str], size: Optional[int] = None, **kwargs) -> capnp.lib.capnp._DynamicStructBuilder:
|
||||||
args = {
|
args = {
|
||||||
'valid': False,
|
'valid': False,
|
||||||
'logMonoTime': int(time.monotonic() * 1e9),
|
'logMonoTime': int(time.monotonic() * 1e9),
|
||||||
@@ -85,14 +54,14 @@ def new_message(service: str | None, size: int | None = None, **kwargs) -> capnp
|
|||||||
return dat
|
return dat
|
||||||
|
|
||||||
|
|
||||||
def drain_sock(sock: SubSocket, wait_for_one: bool = False) -> list[capnp.lib.capnp._DynamicStructReader]:
|
def drain_sock(sock: SubSocket, wait_for_one: bool = False) -> List[capnp.lib.capnp._DynamicStructReader]:
|
||||||
"""Receive all message currently available on the queue"""
|
"""Receive all message currently available on the queue"""
|
||||||
msgs = drain_sock_raw(sock, wait_for_one=wait_for_one)
|
msgs = drain_sock_raw(sock, wait_for_one=wait_for_one)
|
||||||
return [log_from_bytes(m) for m in msgs]
|
return [log_from_bytes(m) for m in msgs]
|
||||||
|
|
||||||
|
|
||||||
# TODO: print when we drop packets?
|
# TODO: print when we drop packets?
|
||||||
def recv_sock(sock: SubSocket, wait: bool = False) -> capnp.lib.capnp._DynamicStructReader | None:
|
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."""
|
"""Same as drain sock, but only returns latest message. Consider using conflate instead."""
|
||||||
dat = None
|
dat = None
|
||||||
|
|
||||||
@@ -113,14 +82,14 @@ def recv_sock(sock: SubSocket, wait: bool = False) -> capnp.lib.capnp._DynamicSt
|
|||||||
return dat
|
return dat
|
||||||
|
|
||||||
|
|
||||||
def recv_one(sock: SubSocket) -> capnp.lib.capnp._DynamicStructReader | None:
|
def recv_one(sock: SubSocket) -> Optional[capnp.lib.capnp._DynamicStructReader]:
|
||||||
dat = sock.receive()
|
dat = sock.receive()
|
||||||
if dat is not None:
|
if dat is not None:
|
||||||
dat = log_from_bytes(dat)
|
dat = log_from_bytes(dat)
|
||||||
return dat
|
return dat
|
||||||
|
|
||||||
|
|
||||||
def recv_one_or_none(sock: SubSocket) -> capnp.lib.capnp._DynamicStructReader | None:
|
def recv_one_or_none(sock: SubSocket) -> Optional[capnp.lib.capnp._DynamicStructReader]:
|
||||||
dat = sock.receive(non_blocking=True)
|
dat = sock.receive(non_blocking=True)
|
||||||
if dat is not None:
|
if dat is not None:
|
||||||
dat = log_from_bytes(dat)
|
dat = log_from_bytes(dat)
|
||||||
@@ -179,27 +148,27 @@ class FrequencyTracker:
|
|||||||
|
|
||||||
|
|
||||||
class SubMaster:
|
class SubMaster:
|
||||||
def __init__(self, services: list[str], poll: str | None = None,
|
def __init__(self, services: List[str], poll: Optional[str] = None,
|
||||||
ignore_alive: list[str] | None = None, ignore_avg_freq: list[str] | None = None,
|
ignore_alive: Optional[List[str]] = None, ignore_avg_freq: Optional[List[str]] = None,
|
||||||
ignore_valid: list[str] | None = None, addr: str = "127.0.0.1", frequency: float | None = None):
|
ignore_valid: Optional[List[str]] = None, addr: str = "127.0.0.1", frequency: Optional[float] = None):
|
||||||
self.frame = -1
|
self.frame = -1
|
||||||
self.services = services
|
self.services = services
|
||||||
self.seen = dict.fromkeys(services, False)
|
self.seen = {s: False for s in services}
|
||||||
self.updated = dict.fromkeys(services, False)
|
self.updated = {s: False for s in services}
|
||||||
self.recv_time = dict.fromkeys(services, 0.0)
|
self.recv_time = {s: 0. for s in services}
|
||||||
self.recv_frame = dict.fromkeys(services, 0)
|
self.recv_frame = {s: 0 for s in services}
|
||||||
self.sock = {}
|
self.sock = {}
|
||||||
self.data = {}
|
self.data = {}
|
||||||
self.logMonoTime = dict.fromkeys(services, 0)
|
self.logMonoTime = {s: 0 for s in services}
|
||||||
|
|
||||||
# zero-frequency / on-demand services are always alive and presumed valid; all others must pass checks
|
# zero-frequency / on-demand services are always alive and presumed valid; all others must pass checks
|
||||||
on_demand = {s: SERVICE_LIST[s].frequency <= 1e-5 for s in services}
|
on_demand = {s: SERVICE_LIST[s].frequency <= 1e-5 for s in services}
|
||||||
self.static_freq_services = {s for s in services if not on_demand[s]}
|
self.static_freq_services = set(s for s in services if not on_demand[s])
|
||||||
self.alive = {s: on_demand[s] for s in services}
|
self.alive = {s: on_demand[s] for s in services}
|
||||||
self.freq_ok = {s: on_demand[s] for s in services}
|
self.freq_ok = {s: on_demand[s] for s in services}
|
||||||
self.valid = {s: on_demand[s] for s in services}
|
self.valid = {s: on_demand[s] for s in services}
|
||||||
|
|
||||||
self.freq_tracker: dict[str, FrequencyTracker] = {}
|
self.freq_tracker: Dict[str, FrequencyTracker] = {}
|
||||||
self.poller = Poller()
|
self.poller = Poller()
|
||||||
polled_services = set([poll, ] if poll is not None else services)
|
polled_services = set([poll, ] if poll is not None else services)
|
||||||
self.non_polled_services = set(services) - polled_services
|
self.non_polled_services = set(services) - polled_services
|
||||||
@@ -242,7 +211,7 @@ class SubMaster:
|
|||||||
msgs.append(recv_one_or_none(self.sock[s]))
|
msgs.append(recv_one_or_none(self.sock[s]))
|
||||||
self.update_msgs(time.monotonic(), msgs)
|
self.update_msgs(time.monotonic(), msgs)
|
||||||
|
|
||||||
def update_msgs(self, cur_time: float, msgs: list[capnp.lib.capnp._DynamicStructReader]) -> None:
|
def update_msgs(self, cur_time: float, msgs: List[capnp.lib.capnp._DynamicStructReader]) -> None:
|
||||||
self.frame += 1
|
self.frame += 1
|
||||||
self.updated = dict.fromkeys(self.services, False)
|
self.updated = dict.fromkeys(self.services, False)
|
||||||
for msg in msgs:
|
for msg in msgs:
|
||||||
@@ -265,21 +234,21 @@ class SubMaster:
|
|||||||
self.alive[s] = (cur_time - self.recv_time[s]) < (10. / SERVICE_LIST[s].frequency) or (self.seen[s] and self.simulation)
|
self.alive[s] = (cur_time - self.recv_time[s]) < (10. / SERVICE_LIST[s].frequency) or (self.seen[s] and self.simulation)
|
||||||
self.freq_ok[s] = self.freq_tracker[s].valid or self.simulation
|
self.freq_ok[s] = self.freq_tracker[s].valid or self.simulation
|
||||||
|
|
||||||
def all_alive(self, service_list: list[str] | None = None) -> bool:
|
def all_alive(self, service_list: Optional[List[str]] = None) -> bool:
|
||||||
return all(self.alive[s] for s in (service_list or self.services) if s not in self.ignore_alive)
|
return all(self.alive[s] for s in (service_list or self.services) if s not in self.ignore_alive)
|
||||||
|
|
||||||
def all_freq_ok(self, service_list: list[str] | None = None) -> bool:
|
def all_freq_ok(self, service_list: Optional[List[str]] = None) -> bool:
|
||||||
return all(self.freq_ok[s] for s in (service_list or self.services) if self._check_avg_freq(s))
|
return all(self.freq_ok[s] for s in (service_list or self.services) if self._check_avg_freq(s))
|
||||||
|
|
||||||
def all_valid(self, service_list: list[str] | None = None) -> bool:
|
def all_valid(self, service_list: Optional[List[str]] = None) -> bool:
|
||||||
return all(self.valid[s] for s in (service_list or self.services) if s not in self.ignore_valid)
|
return all(self.valid[s] for s in (service_list or self.services) if s not in self.ignore_valid)
|
||||||
|
|
||||||
def all_checks(self, service_list: list[str] | None = None) -> bool:
|
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)
|
return self.all_alive(service_list) and self.all_freq_ok(service_list) and self.all_valid(service_list)
|
||||||
|
|
||||||
|
|
||||||
class PubMaster:
|
class PubMaster:
|
||||||
def __init__(self, services: list[str]):
|
def __init__(self, services: List[str]):
|
||||||
self.sock = {}
|
self.sock = {}
|
||||||
for s in services:
|
for s in services:
|
||||||
self.sock[s] = pub_sock(s)
|
self.sock[s] = pub_sock(s)
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include "openpilot/cereal/messaging/msgq_to_zmq.h"
|
#include "cereal/messaging/msgq_to_zmq.h"
|
||||||
#include "openpilot/cereal/services.h"
|
#include "cereal/services.h"
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
|
|
||||||
ExitHandler do_exit;
|
ExitHandler do_exit;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "openpilot/cereal/messaging/bridge_zmq.h"
|
#include "cereal/messaging/bridge_zmq.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#include <capnp/serialize.h>
|
#include <capnp/serialize.h>
|
||||||
|
|
||||||
#include "openpilot/cereal/gen/cpp/log.capnp.h"
|
#include "cereal/gen/cpp/log.capnp.h"
|
||||||
#include "common/timing.h"
|
#include "common/timing.h"
|
||||||
#include "msgq/ipc.h"
|
#include "msgq/ipc.h"
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
#include "openpilot/cereal/messaging/msgq_to_zmq.h"
|
#include "cereal/messaging/msgq_to_zmq.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include "openpilot/cereal/services.h"
|
#include "cereal/services.h"
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
|
|
||||||
extern ExitHandler do_exit;
|
extern ExitHandler do_exit;
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "msgq/impl_msgq.h"
|
#include "msgq/impl_msgq.h"
|
||||||
#include "openpilot/cereal/messaging/bridge_zmq.h"
|
#include "cereal/messaging/bridge_zmq.h"
|
||||||
|
|
||||||
class MsgqToZmq {
|
class MsgqToZmq {
|
||||||
public:
|
public:
|
||||||
@@ -3,8 +3,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include "openpilot/cereal/services.h"
|
#include "cereal/services.h"
|
||||||
#include "openpilot/cereal/messaging/messaging.h"
|
#include "cereal/messaging/messaging.h"
|
||||||
|
|
||||||
const bool SIMULATION = (getenv("SIMULATION") != nullptr) && (std::string(getenv("SIMULATION")) == "1");
|
const bool SIMULATION = (getenv("SIMULATION") != nullptr) && (std::string(getenv("SIMULATION")) == "1");
|
||||||
|
|
||||||
+37
-16
@@ -1,16 +1,16 @@
|
|||||||
|
import os
|
||||||
import capnp
|
import capnp
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import numbers
|
import numbers
|
||||||
import random
|
import random
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from openpilot.common.test import OpenpilotTestCase
|
|
||||||
from openpilot.common.parameterized import parameterized
|
from openpilot.common.parameterized import parameterized
|
||||||
|
import pytest
|
||||||
|
|
||||||
from openpilot.cereal import log
|
from cereal import log, car
|
||||||
from opendbc.car.structs import car
|
import cereal.messaging as messaging
|
||||||
import openpilot.cereal.messaging as messaging
|
from cereal.services import SERVICE_LIST
|
||||||
from openpilot.cereal.services import SERVICE_LIST
|
|
||||||
|
|
||||||
events = [evt for evt in log.Event.schema.union_fields if evt in SERVICE_LIST.keys()]
|
events = [evt for evt in log.Event.schema.union_fields if evt in SERVICE_LIST.keys()]
|
||||||
|
|
||||||
@@ -23,6 +23,10 @@ def random_socks(num_socks=10):
|
|||||||
def random_bytes(length=1000):
|
def random_bytes(length=1000):
|
||||||
return bytes([random.randrange(0xFF) for _ in range(length)])
|
return bytes([random.randrange(0xFF) for _ in range(length)])
|
||||||
|
|
||||||
|
def zmq_sleep(t=1):
|
||||||
|
if "ZMQ" in os.environ:
|
||||||
|
time.sleep(t)
|
||||||
|
|
||||||
|
|
||||||
# TODO: this should take any capnp struct and returrn a msg with random populated data
|
# TODO: this should take any capnp struct and returrn a msg with random populated data
|
||||||
def random_carstate():
|
def random_carstate():
|
||||||
@@ -47,7 +51,17 @@ def delayed_send(delay, sock, dat):
|
|||||||
threading.Timer(delay, send_func).start()
|
threading.Timer(delay, send_func).start()
|
||||||
|
|
||||||
|
|
||||||
class TestMessaging(OpenpilotTestCase):
|
class TestMessaging:
|
||||||
|
def setUp(self):
|
||||||
|
# TODO: ZMQ tests are too slow; all sleeps will need to be
|
||||||
|
# replaced with logic to block on the necessary condition
|
||||||
|
if "ZMQ" in os.environ:
|
||||||
|
pytest.skip()
|
||||||
|
|
||||||
|
# ZMQ pub socket takes too long to die
|
||||||
|
# sleep to prevent multiple publishers error between tests
|
||||||
|
zmq_sleep()
|
||||||
|
|
||||||
@parameterized.expand(events)
|
@parameterized.expand(events)
|
||||||
def test_new_message(self, evt):
|
def test_new_message(self, evt):
|
||||||
try:
|
try:
|
||||||
@@ -74,6 +88,7 @@ class TestMessaging(OpenpilotTestCase):
|
|||||||
sock = "carState"
|
sock = "carState"
|
||||||
pub_sock = messaging.pub_sock(sock)
|
pub_sock = messaging.pub_sock(sock)
|
||||||
sub_sock = messaging.sub_sock(sock, timeout=1000)
|
sub_sock = messaging.sub_sock(sock, timeout=1000)
|
||||||
|
zmq_sleep()
|
||||||
|
|
||||||
# no wait and no msgs in queue
|
# no wait and no msgs in queue
|
||||||
msgs = func(sub_sock)
|
msgs = func(sub_sock)
|
||||||
@@ -81,11 +96,10 @@ class TestMessaging(OpenpilotTestCase):
|
|||||||
assert len(msgs) == 0
|
assert len(msgs) == 0
|
||||||
|
|
||||||
# no wait but msgs are queued up
|
# no wait but msgs are queued up
|
||||||
pub_sock.send(messaging.new_message(sock).to_bytes())
|
|
||||||
assert sub_sock.receive() is not None # synchronize the PUB/SUB connection
|
|
||||||
num_msgs = random.randrange(3, 10)
|
num_msgs = random.randrange(3, 10)
|
||||||
for _ in range(num_msgs):
|
for _ in range(num_msgs):
|
||||||
pub_sock.send(messaging.new_message(sock).to_bytes())
|
pub_sock.send(messaging.new_message(sock).to_bytes())
|
||||||
|
time.sleep(0.1)
|
||||||
msgs = func(sub_sock)
|
msgs = func(sub_sock)
|
||||||
assert isinstance(msgs, list)
|
assert isinstance(msgs, list)
|
||||||
assert all(isinstance(msg, expected_type) for msg in msgs)
|
assert all(isinstance(msg, expected_type) for msg in msgs)
|
||||||
@@ -95,6 +109,7 @@ class TestMessaging(OpenpilotTestCase):
|
|||||||
sock = "carState"
|
sock = "carState"
|
||||||
pub_sock = messaging.pub_sock(sock)
|
pub_sock = messaging.pub_sock(sock)
|
||||||
sub_sock = messaging.sub_sock(sock, timeout=100)
|
sub_sock = messaging.sub_sock(sock, timeout=100)
|
||||||
|
zmq_sleep()
|
||||||
|
|
||||||
# no wait and no msg in queue, socket should timeout
|
# no wait and no msg in queue, socket should timeout
|
||||||
recvd = messaging.recv_sock(sub_sock)
|
recvd = messaging.recv_sock(sub_sock)
|
||||||
@@ -112,7 +127,8 @@ class TestMessaging(OpenpilotTestCase):
|
|||||||
def test_recv_one(self):
|
def test_recv_one(self):
|
||||||
sock = "carState"
|
sock = "carState"
|
||||||
pub_sock = messaging.pub_sock(sock)
|
pub_sock = messaging.pub_sock(sock)
|
||||||
sub_sock = messaging.sub_sock(sock, timeout=10)
|
sub_sock = messaging.sub_sock(sock, timeout=1000)
|
||||||
|
zmq_sleep()
|
||||||
|
|
||||||
# no msg in queue, socket should timeout
|
# no msg in queue, socket should timeout
|
||||||
recvd = messaging.recv_one(sub_sock)
|
recvd = messaging.recv_one(sub_sock)
|
||||||
@@ -125,10 +141,12 @@ class TestMessaging(OpenpilotTestCase):
|
|||||||
assert isinstance(recvd, capnp._DynamicStructReader)
|
assert isinstance(recvd, capnp._DynamicStructReader)
|
||||||
assert_carstate(msg.carState, recvd.carState)
|
assert_carstate(msg.carState, recvd.carState)
|
||||||
|
|
||||||
|
@pytest.mark.xfail(condition="ZMQ" in os.environ, reason='ZMQ detected')
|
||||||
def test_recv_one_or_none(self):
|
def test_recv_one_or_none(self):
|
||||||
sock = "carState"
|
sock = "carState"
|
||||||
pub_sock = messaging.pub_sock(sock)
|
pub_sock = messaging.pub_sock(sock)
|
||||||
sub_sock = messaging.sub_sock(sock)
|
sub_sock = messaging.sub_sock(sock)
|
||||||
|
zmq_sleep()
|
||||||
|
|
||||||
# no msg in queue, socket shouldn't block
|
# no msg in queue, socket shouldn't block
|
||||||
recvd = messaging.recv_one_or_none(sub_sock)
|
recvd = messaging.recv_one_or_none(sub_sock)
|
||||||
@@ -143,16 +161,19 @@ class TestMessaging(OpenpilotTestCase):
|
|||||||
|
|
||||||
def test_recv_one_retry(self):
|
def test_recv_one_retry(self):
|
||||||
sock = "carState"
|
sock = "carState"
|
||||||
sock_timeout = 0.005
|
sock_timeout = 0.1
|
||||||
pub_sock = messaging.pub_sock(sock)
|
pub_sock = messaging.pub_sock(sock)
|
||||||
sub_sock = messaging.sub_sock(sock, timeout=round(sock_timeout*1000))
|
sub_sock = messaging.sub_sock(sock, timeout=round(sock_timeout*1000))
|
||||||
|
zmq_sleep()
|
||||||
|
|
||||||
# wait 5 socket timeouts and make sure it's still retrying
|
# this test doesn't work with ZMQ since multiprocessing interrupts it
|
||||||
p = multiprocessing.Process(target=messaging.recv_one_retry, args=(sub_sock,))
|
if "ZMQ" not in os.environ:
|
||||||
p.start()
|
# wait 5 socket timeouts and make sure it's still retrying
|
||||||
time.sleep(sock_timeout*5)
|
p = multiprocessing.Process(target=messaging.recv_one_retry, args=(sub_sock,))
|
||||||
assert p.is_alive()
|
p.start()
|
||||||
p.terminate()
|
time.sleep(sock_timeout*5)
|
||||||
|
assert p.is_alive()
|
||||||
|
p.terminate()
|
||||||
|
|
||||||
# wait 5 socket timeouts before sending
|
# wait 5 socket timeouts before sending
|
||||||
msg = random_carstate()
|
msg = random_carstate()
|
||||||
+35
-17
@@ -1,16 +1,20 @@
|
|||||||
import random
|
import random
|
||||||
import time
|
import time
|
||||||
from typing import cast
|
from typing import Sized, cast
|
||||||
from collections.abc import Sized
|
|
||||||
|
|
||||||
from openpilot.common.test import OpenpilotTestCase
|
import cereal.messaging as messaging
|
||||||
import openpilot.cereal.messaging as messaging
|
from cereal.messaging.tests.test_messaging import events, random_sock, random_socks, \
|
||||||
from openpilot.cereal.messaging.tests.test_messaging import events, random_sock, random_socks, \
|
random_bytes, random_carstate, assert_carstate, \
|
||||||
random_bytes, random_carstate, assert_carstate
|
zmq_sleep
|
||||||
from openpilot.cereal.services import SERVICE_LIST
|
from cereal.services import SERVICE_LIST
|
||||||
|
|
||||||
|
|
||||||
class TestSubMaster(OpenpilotTestCase):
|
class TestSubMaster:
|
||||||
|
|
||||||
|
def setup_method(self):
|
||||||
|
# ZMQ pub socket takes too long to die
|
||||||
|
# sleep to prevent multiple publishers error between tests
|
||||||
|
zmq_sleep(3)
|
||||||
|
|
||||||
def test_init(self):
|
def test_init(self):
|
||||||
sm = messaging.SubMaster(events)
|
sm = messaging.SubMaster(events)
|
||||||
@@ -38,6 +42,7 @@ class TestSubMaster(OpenpilotTestCase):
|
|||||||
sock = "carState"
|
sock = "carState"
|
||||||
pub_sock = messaging.pub_sock(sock)
|
pub_sock = messaging.pub_sock(sock)
|
||||||
sm = messaging.SubMaster([sock,])
|
sm = messaging.SubMaster([sock,])
|
||||||
|
zmq_sleep()
|
||||||
|
|
||||||
msg = random_carstate()
|
msg = random_carstate()
|
||||||
pub_sock.send(msg.to_bytes())
|
pub_sock.send(msg.to_bytes())
|
||||||
@@ -49,6 +54,7 @@ class TestSubMaster(OpenpilotTestCase):
|
|||||||
sock = "carState"
|
sock = "carState"
|
||||||
pub_sock = messaging.pub_sock(sock)
|
pub_sock = messaging.pub_sock(sock)
|
||||||
sm = messaging.SubMaster([sock,])
|
sm = messaging.SubMaster([sock,])
|
||||||
|
zmq_sleep()
|
||||||
|
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
msg = messaging.new_message(sock)
|
msg = messaging.new_message(sock)
|
||||||
@@ -60,17 +66,17 @@ class TestSubMaster(OpenpilotTestCase):
|
|||||||
def test_update_timeout(self):
|
def test_update_timeout(self):
|
||||||
sock = random_sock()
|
sock = random_sock()
|
||||||
sm = messaging.SubMaster([sock,])
|
sm = messaging.SubMaster([sock,])
|
||||||
timeout = random.randrange(10, 30)
|
timeout = random.randrange(1000, 3000)
|
||||||
start_time = time.monotonic()
|
start_time = time.monotonic()
|
||||||
sm.update(timeout)
|
sm.update(timeout)
|
||||||
t = time.monotonic() - start_time
|
t = time.monotonic() - start_time
|
||||||
assert t >= timeout/1000.
|
assert t >= timeout/1000.
|
||||||
assert t < 0.1
|
assert t < 3
|
||||||
assert not any(sm.updated.values())
|
assert not any(sm.updated.values())
|
||||||
|
|
||||||
def test_avg_frequency_checks(self):
|
def test_avg_frequency_checks(self):
|
||||||
for poll in (True, False):
|
for poll in (True, False):
|
||||||
sm = messaging.SubMaster(["modelV2", "carParams", "carState", "cameraOdometry", "extrinsicsCalibration"],
|
sm = messaging.SubMaster(["modelV2", "carParams", "carState", "cameraOdometry", "liveCalibration"],
|
||||||
poll=("modelV2" if poll else None),
|
poll=("modelV2" if poll else None),
|
||||||
frequency=(20. if not poll else None))
|
frequency=(20. if not poll else None))
|
||||||
|
|
||||||
@@ -78,39 +84,50 @@ class TestSubMaster(OpenpilotTestCase):
|
|||||||
"carState": (20, 20),
|
"carState": (20, 20),
|
||||||
"modelV2": (20, 20 if poll else 10),
|
"modelV2": (20, 20 if poll else 10),
|
||||||
"cameraOdometry": (20, 10),
|
"cameraOdometry": (20, 10),
|
||||||
"extrinsicsCalibration": (4, 4),
|
"liveCalibration": (4, 4),
|
||||||
"carParams": (None, None),
|
"carParams": (None, None),
|
||||||
"userBookmark": (None, None),
|
"userBookmark": (None, None),
|
||||||
}
|
}
|
||||||
|
|
||||||
for service, (max_freq, min_freq) in checks.items():
|
for service, (max_freq, min_freq) in checks.items():
|
||||||
if max_freq is not None:
|
if max_freq is not None:
|
||||||
assert min_freq is not None
|
|
||||||
assert sm._check_avg_freq(service)
|
assert sm._check_avg_freq(service)
|
||||||
assert sm.freq_tracker[service].max_freq == max_freq*1.2
|
assert sm.freq_tracker[service].max_freq == max_freq*1.2
|
||||||
assert sm.freq_tracker[service].min_freq == min_freq*0.8
|
assert sm.freq_tracker[service].min_freq == min_freq*0.8
|
||||||
else:
|
else:
|
||||||
assert not sm._check_avg_freq(service)
|
assert not sm._check_avg_freq(service)
|
||||||
|
|
||||||
|
def test_alive(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_ignore_alive(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_valid(self):
|
||||||
|
pass
|
||||||
|
|
||||||
# SubMaster should always conflate
|
# SubMaster should always conflate
|
||||||
def test_conflate(self):
|
def test_conflate(self):
|
||||||
sock = "carState"
|
sock = "carState"
|
||||||
pub_sock = messaging.pub_sock(sock)
|
pub_sock = messaging.pub_sock(sock)
|
||||||
sm = messaging.SubMaster([sock,])
|
sm = messaging.SubMaster([sock,])
|
||||||
|
|
||||||
pub_sock.send(messaging.new_message(sock).to_bytes())
|
|
||||||
sm.update(1000) # synchronize the PUB/SUB connection
|
|
||||||
|
|
||||||
n = 10
|
n = 10
|
||||||
for i in range(n+1):
|
for i in range(n+1):
|
||||||
msg = messaging.new_message(sock)
|
msg = messaging.new_message(sock)
|
||||||
msg.carState.vEgo = i
|
msg.carState.vEgo = i
|
||||||
pub_sock.send(msg.to_bytes())
|
pub_sock.send(msg.to_bytes())
|
||||||
|
time.sleep(0.01)
|
||||||
sm.update(1000)
|
sm.update(1000)
|
||||||
assert sm[sock].vEgo == n
|
assert sm[sock].vEgo == n
|
||||||
|
|
||||||
|
|
||||||
class TestPubMaster(OpenpilotTestCase):
|
class TestPubMaster:
|
||||||
|
|
||||||
|
def setup_method(self):
|
||||||
|
# ZMQ pub socket takes too long to die
|
||||||
|
# sleep to prevent multiple publishers error between tests
|
||||||
|
zmq_sleep(3)
|
||||||
|
|
||||||
def test_init(self):
|
def test_init(self):
|
||||||
messaging.PubMaster(events)
|
messaging.PubMaster(events)
|
||||||
@@ -119,6 +136,7 @@ class TestPubMaster(OpenpilotTestCase):
|
|||||||
socks = random_socks()
|
socks = random_socks()
|
||||||
pm = messaging.PubMaster(socks)
|
pm = messaging.PubMaster(socks)
|
||||||
sub_socks = {s: messaging.sub_sock(s, conflate=True, timeout=1000) for s in socks}
|
sub_socks = {s: messaging.sub_sock(s, conflate=True, timeout=1000) for s in socks}
|
||||||
|
zmq_sleep()
|
||||||
|
|
||||||
# PubMaster accepts either a capnp msg builder or bytes
|
# PubMaster accepts either a capnp msg builder or bytes
|
||||||
for capnp in [True, False]:
|
for capnp in [True, False]:
|
||||||
+6
-7
@@ -1,14 +1,13 @@
|
|||||||
import subprocess
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
|
from typing import Dict
|
||||||
from openpilot.common.test import OpenpilotTestCase
|
|
||||||
from openpilot.common.parameterized import parameterized
|
from openpilot.common.parameterized import parameterized
|
||||||
|
|
||||||
import openpilot.cereal.services as services
|
import cereal.services as services
|
||||||
from openpilot.cereal.services import SERVICE_LIST
|
from cereal.services import SERVICE_LIST
|
||||||
|
|
||||||
|
|
||||||
class TestServices(OpenpilotTestCase):
|
class TestServices:
|
||||||
|
|
||||||
@parameterized.expand(SERVICE_LIST.keys())
|
@parameterized.expand(SERVICE_LIST.keys())
|
||||||
def test_services(self, s):
|
def test_services(self, s):
|
||||||
@@ -18,5 +17,5 @@ class TestServices(OpenpilotTestCase):
|
|||||||
|
|
||||||
def test_generated_header(self):
|
def test_generated_header(self):
|
||||||
with tempfile.NamedTemporaryFile(suffix=".h") as f:
|
with tempfile.NamedTemporaryFile(suffix=".h") as f:
|
||||||
ret = subprocess.run(f"python3 {services.__file__} > {f.name} && clang++ {f.name} -std=c++11", shell=True).returncode
|
ret = os.system(f"python3 {services.__file__} > {f.name} && clang++ {f.name} -std=c++11")
|
||||||
assert ret == 0, "generated services header is not valid C"
|
assert ret == 0, "generated services header is not valid C"
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
# TODO: this should be automatically determined using the capnp schema
|
# TODO: this should be automatically determined using the capnp schema
|
||||||
@@ -10,7 +11,7 @@ class QueueSize(IntEnum):
|
|||||||
|
|
||||||
|
|
||||||
class Service:
|
class Service:
|
||||||
def __init__(self, should_log: bool, frequency: float, decimation: int | None = None,
|
def __init__(self, should_log: bool, frequency: float, decimation: Optional[int] = None,
|
||||||
queue_size: QueueSize = QueueSize.SMALL):
|
queue_size: QueueSize = QueueSize.SMALL):
|
||||||
self.should_log = should_log
|
self.should_log = should_log
|
||||||
self.frequency = frequency
|
self.frequency = frequency
|
||||||
@@ -25,7 +26,6 @@ _services: dict[str, tuple] = {
|
|||||||
"accelerometer": (True, 104., 104),
|
"accelerometer": (True, 104., 104),
|
||||||
"temperatureSensor": (True, 2., 200),
|
"temperatureSensor": (True, 2., 200),
|
||||||
"deviceState": (True, 2., 1),
|
"deviceState": (True, 2., 1),
|
||||||
"chestnutState": (True, 10., 10),
|
|
||||||
"touch": (True, 20., 1),
|
"touch": (True, 20., 1),
|
||||||
"can": (True, 100., 2053, QueueSize.BIG), # decimation gives ~3 msgs in a full segment
|
"can": (True, 100., 2053, QueueSize.BIG), # decimation gives ~3 msgs in a full segment
|
||||||
"controlsState": (True, 100., 10, QueueSize.MEDIUM),
|
"controlsState": (True, 100., 10, QueueSize.MEDIUM),
|
||||||
@@ -33,15 +33,15 @@ _services: dict[str, tuple] = {
|
|||||||
"pandaStates": (True, 10., 1),
|
"pandaStates": (True, 10., 1),
|
||||||
"peripheralState": (True, 2., 1),
|
"peripheralState": (True, 2., 1),
|
||||||
"radarState": (True, 20., 5),
|
"radarState": (True, 20., 5),
|
||||||
"narrowRoadEncodeIdx": (False, 20., 1),
|
"roadEncodeIdx": (False, 20., 1),
|
||||||
"radarTracks": (True, 20.),
|
"liveTracks": (True, 20.),
|
||||||
"sendcan": (True, 100., 139, QueueSize.MEDIUM),
|
"sendcan": (True, 100., 139, QueueSize.MEDIUM),
|
||||||
"logMessage": (True, 0., None, QueueSize.BIG),
|
"logMessage": (True, 0., None, QueueSize.BIG),
|
||||||
"errorLogMessage": (True, 0., 1, QueueSize.BIG),
|
"errorLogMessage": (True, 0., 1, QueueSize.BIG),
|
||||||
"extrinsicsCalibration": (True, 4., 4),
|
"liveCalibration": (True, 4., 4),
|
||||||
"lateralTorqueParameters": (True, 4., 1),
|
"liveTorqueParameters": (True, 4., 1),
|
||||||
"lateralDelay": (True, 4., 1),
|
"liveDelay": (True, 4., 1),
|
||||||
"operatingSystemLog": (True, 0.),
|
"androidLog": (True, 0.),
|
||||||
"carState": (True, 100., 10),
|
"carState": (True, 100., 10),
|
||||||
"carControl": (True, 100., 10),
|
"carControl": (True, 100., 10),
|
||||||
"carOutput": (True, 100., 10),
|
"carOutput": (True, 100., 10),
|
||||||
@@ -55,15 +55,15 @@ _services: dict[str, tuple] = {
|
|||||||
"qcomGnss": (True, 2.),
|
"qcomGnss": (True, 2.),
|
||||||
"clocks": (True, 0.1, 1),
|
"clocks": (True, 0.1, 1),
|
||||||
"ubloxRaw": (True, 20.),
|
"ubloxRaw": (True, 20.),
|
||||||
"deviceMotion": (True, 20., 4),
|
"livePose": (True, 20., 4),
|
||||||
"vehicleParameters": (True, 20., 5),
|
"liveParameters": (True, 20., 5),
|
||||||
"cameraOdometry": (True, 20., 10),
|
"cameraOdometry": (True, 20., 10),
|
||||||
"thumbnail": (True, 1 / 60., 1),
|
"thumbnail": (True, 1 / 60., 1),
|
||||||
"onroadEvents": (True, 1., 1),
|
"onroadEvents": (True, 1., 1),
|
||||||
"carParams": (True, 0.02, 1),
|
"carParams": (True, 0.02, 1),
|
||||||
"narrowRoadCameraState": (True, 20., 20),
|
"roadCameraState": (True, 20., 20),
|
||||||
"cabinCameraState": (True, 20., 20),
|
"driverCameraState": (True, 20., 20),
|
||||||
"cabinEncodeIdx": (False, 20., 1),
|
"driverEncodeIdx": (False, 20., 1),
|
||||||
"driverStateV2": (True, 20., 10),
|
"driverStateV2": (True, 20., 10),
|
||||||
"driverMonitoringState": (True, 20., 10),
|
"driverMonitoringState": (True, 20., 10),
|
||||||
"wideRoadEncodeIdx": (False, 20., 1),
|
"wideRoadEncodeIdx": (False, 20., 1),
|
||||||
@@ -71,15 +71,16 @@ _services: dict[str, tuple] = {
|
|||||||
"drivingModelData": (True, 20., 10),
|
"drivingModelData": (True, 20., 10),
|
||||||
"modelV2": (True, 20., None, QueueSize.BIG),
|
"modelV2": (True, 20., None, QueueSize.BIG),
|
||||||
"managerState": (True, 2., 1),
|
"managerState": (True, 2., 1),
|
||||||
"qNarrowRoadEncodeIdx": (False, 20.),
|
"qRoadEncodeIdx": (False, 20.),
|
||||||
"userBookmark": (True, 0., 1),
|
"userBookmark": (True, 0., 1),
|
||||||
"soundPressure": (True, 10., 10),
|
"soundPressure": (True, 10., 10),
|
||||||
"rawAudioData": (False, 20.),
|
"rawAudioData": (False, 20.),
|
||||||
"bookmarkButton": (True, 0., 1),
|
"bookmarkButton": (True, 0., 1),
|
||||||
"narrowRoadEncodeData": (False, 20., None, QueueSize.BIG),
|
"audioFeedback": (True, 0., 1),
|
||||||
"cabinEncodeData": (False, 20., None, QueueSize.BIG),
|
"roadEncodeData": (False, 20., None, QueueSize.BIG),
|
||||||
|
"driverEncodeData": (False, 20., None, QueueSize.BIG),
|
||||||
"wideRoadEncodeData": (False, 20., None, QueueSize.BIG),
|
"wideRoadEncodeData": (False, 20., None, QueueSize.BIG),
|
||||||
"qNarrowRoadEncodeData": (False, 20., None, QueueSize.BIG),
|
"qRoadEncodeData": (False, 20., None, QueueSize.BIG),
|
||||||
|
|
||||||
# sunnypilot
|
# sunnypilot
|
||||||
"modelManagerSP": (False, 1., 1, QueueSize.BIG),
|
"modelManagerSP": (False, 1., 1, QueueSize.BIG),
|
||||||
@@ -99,11 +100,11 @@ _services: dict[str, tuple] = {
|
|||||||
"testJoystick": (True, 0.),
|
"testJoystick": (True, 0.),
|
||||||
"alertDebug": (True, 20., 5),
|
"alertDebug": (True, 20., 5),
|
||||||
"livestreamWideRoadEncodeIdx": (False, 20.),
|
"livestreamWideRoadEncodeIdx": (False, 20.),
|
||||||
"livestreamNarrowRoadEncodeIdx": (False, 20.),
|
"livestreamRoadEncodeIdx": (False, 20.),
|
||||||
"livestreamCabinEncodeIdx": (False, 20.),
|
"livestreamDriverEncodeIdx": (False, 20.),
|
||||||
"livestreamWideRoadEncodeData": (False, 20., None, QueueSize.MEDIUM),
|
"livestreamWideRoadEncodeData": (False, 20., None, QueueSize.MEDIUM),
|
||||||
"livestreamNarrowRoadEncodeData": (False, 20., None, QueueSize.MEDIUM),
|
"livestreamRoadEncodeData": (False, 20., None, QueueSize.MEDIUM),
|
||||||
"livestreamCabinEncodeData": (False, 20., None, QueueSize.MEDIUM),
|
"livestreamDriverEncodeData": (False, 20., None, QueueSize.MEDIUM),
|
||||||
"customReservedRawData0": (True, 0.),
|
"customReservedRawData0": (True, 0.),
|
||||||
}
|
}
|
||||||
SERVICE_LIST = {name: Service(*vals) for
|
SERVICE_LIST = {name: Service(*vals) for
|
||||||
@@ -124,7 +125,8 @@ def build_header():
|
|||||||
for k, v in SERVICE_LIST.items():
|
for k, v in SERVICE_LIST.items():
|
||||||
should_log = "true" if v.should_log else "false"
|
should_log = "true" if v.should_log else "false"
|
||||||
decimation = -1 if v.decimation is None else v.decimation
|
decimation = -1 if v.decimation is None else v.decimation
|
||||||
h += f' {{ "{k}", {{"{k}", {should_log}, {v.frequency:f}, {decimation:d}, {v.queue_size:d}}}}},\n'
|
h += ' { "%s", {"%s", %s, %f, %d, %d}},\n' % \
|
||||||
|
(k, k, should_log, v.frequency, decimation, v.queue_size)
|
||||||
h += "};\n"
|
h += "};\n"
|
||||||
|
|
||||||
h += "#endif\n"
|
h += "#endif\n"
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
Import('env', 'envCython')
|
||||||
|
|
||||||
|
common_libs = [
|
||||||
|
'params.cc',
|
||||||
|
'swaglog.cc',
|
||||||
|
'util.cc',
|
||||||
|
'ratekeeper.cc',
|
||||||
|
]
|
||||||
|
|
||||||
|
_common = env.Library('common', common_libs, LIBS="json11")
|
||||||
|
Export('_common')
|
||||||
|
|
||||||
|
if GetOption('extras'):
|
||||||
|
env.Program('tests/test_common',
|
||||||
|
['tests/test_runner.cc', 'tests/test_params.cc', 'tests/test_util.cc', 'tests/test_swaglog.cc'],
|
||||||
|
LIBS=[_common, 'json11', 'zmq', 'pthread'])
|
||||||
|
|
||||||
|
# Cython bindings
|
||||||
|
params_python = envCython.Program('params_pyx.so', 'params_pyx.pyx', LIBS=envCython['LIBS'] + [_common, 'zmq', 'json11'])
|
||||||
|
|
||||||
|
common_python = [params_python]
|
||||||
|
|
||||||
|
Export('common_python')
|
||||||
@@ -4,7 +4,7 @@ import requests
|
|||||||
import unicodedata
|
import unicodedata
|
||||||
from datetime import datetime, timedelta, UTC
|
from datetime import datetime, timedelta, UTC
|
||||||
from openpilot.common.hardware.hw import Paths
|
from openpilot.common.hardware.hw import Paths
|
||||||
from openpilot.common.version import get_version
|
from openpilot.system.version import get_version
|
||||||
|
|
||||||
# name: jwt signature algorithm
|
# name: jwt signature algorithm
|
||||||
KEYS = {"id_rsa": "RS256",
|
KEYS = {"id_rsa": "RS256",
|
||||||
@@ -38,7 +38,6 @@ class BaseApi:
|
|||||||
}
|
}
|
||||||
if payload_extra is not None:
|
if payload_extra is not None:
|
||||||
payload.update(payload_extra)
|
payload.update(payload_extra)
|
||||||
assert self.private_key is not None
|
|
||||||
token = jwt.encode(payload, self.private_key, algorithm=self.jwt_algorithm)
|
token = jwt.encode(payload, self.private_key, algorithm=self.jwt_algorithm)
|
||||||
if isinstance(token, bytes):
|
if isinstance(token, bytes):
|
||||||
token = token.decode('utf8')
|
token = token.decode('utf8')
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../.."))
|
BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../"))
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
from openpilot.common.hardware import HARDWARE
|
from openpilot.common.hardware import HARDWARE
|
||||||
from openpilot.common.esim.base import LPABase, Profile
|
from openpilot.common.esim.base import LPABase, Profile
|
||||||
|
|
||||||
@@ -29,17 +27,6 @@ def print_profiles(lpa: LPABase) -> None:
|
|||||||
print(f'{i}. {p.iccid} (nickname: {p.nickname or "<none provided>"}) (provider: {p.provider}) - {"enabled" if p.enabled else "disabled"}')
|
print(f'{i}. {p.iccid} (nickname: {p.nickname or "<none provided>"}) (provider: {p.provider}) - {"enabled" if p.enabled else "disabled"}')
|
||||||
|
|
||||||
|
|
||||||
def execute_and_process_notifications(lpa: LPABase, operation) -> None:
|
|
||||||
try:
|
|
||||||
operation()
|
|
||||||
finally:
|
|
||||||
time.sleep(1) # Need to wait for 1s after the operation is finished so the eUICC/modem can settle down.
|
|
||||||
try:
|
|
||||||
lpa.process_notifications()
|
|
||||||
except Exception as e:
|
|
||||||
print(f'failed to process eSIM notifications: {e}', file=sys.stderr)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
parser = argparse.ArgumentParser(prog='esim.py', description='manage eSIM profiles on your comma device', epilog='comma.ai')
|
parser = argparse.ArgumentParser(prog='esim.py', description='manage eSIM profiles on your comma device', epilog='comma.ai')
|
||||||
sub = parser.add_subparsers(dest='cmd')
|
sub = parser.add_subparsers(dest='cmd')
|
||||||
@@ -63,21 +50,18 @@ if __name__ == '__main__':
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
lpa = HARDWARE.get_sim_lpa()
|
lpa = HARDWARE.get_sim_lpa()
|
||||||
if not lpa.is_euicc():
|
|
||||||
raise SystemExit("no eUICC detected")
|
|
||||||
if args.cmd == 'switch':
|
if args.cmd == 'switch':
|
||||||
iccid = resolve_iccid(lpa, args.profile)
|
lpa.switch_profile(resolve_iccid(lpa, args.profile))
|
||||||
execute_and_process_notifications(lpa, lambda: lpa.switch_profile(iccid))
|
|
||||||
elif args.cmd == 'delete':
|
elif args.cmd == 'delete':
|
||||||
iccid = resolve_iccid(lpa, args.profile)
|
iccid = resolve_iccid(lpa, args.profile)
|
||||||
confirm = input(f'are you sure you want to delete profile {iccid}? (y/N) ')
|
confirm = input(f'are you sure you want to delete profile {iccid}? (y/N) ')
|
||||||
if confirm == 'y':
|
if confirm == 'y':
|
||||||
execute_and_process_notifications(lpa, lambda: lpa.delete_profile(iccid))
|
lpa.delete_profile(iccid)
|
||||||
else:
|
else:
|
||||||
print('cancelled')
|
print('cancelled')
|
||||||
exit(0)
|
exit(0)
|
||||||
elif args.cmd == 'download':
|
elif args.cmd == 'download':
|
||||||
execute_and_process_notifications(lpa, lambda: lpa.download_profile(args.qr, args.name))
|
lpa.download_profile(args.qr, args.name)
|
||||||
elif args.cmd == 'nickname':
|
elif args.cmd == 'nickname':
|
||||||
lpa.nickname_profile(resolve_iccid(lpa, args.profile), args.name)
|
lpa.nickname_profile(resolve_iccid(lpa, args.profile), args.name)
|
||||||
else:
|
else:
|
||||||
@@ -6,6 +6,7 @@ import fcntl
|
|||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
import requests
|
import requests
|
||||||
|
import serial
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import termios
|
import termios
|
||||||
@@ -19,7 +20,6 @@ from pathlib import Path
|
|||||||
|
|
||||||
from openpilot.common.time_helpers import system_time_valid
|
from openpilot.common.time_helpers import system_time_valid
|
||||||
from openpilot.common.esim.base import LPABase, LPAError, LPAProfileNotFoundError, Profile
|
from openpilot.common.esim.base import LPABase, LPAError, LPAProfileNotFoundError, Profile
|
||||||
from openpilot.common.serial import Serial, SerialException
|
|
||||||
|
|
||||||
GSMA_CI_BUNDLE = str(Path(__file__).parent / "gsma_ci_bundle.pem")
|
GSMA_CI_BUNDLE = str(Path(__file__).parent / "gsma_ci_bundle.pem")
|
||||||
|
|
||||||
@@ -133,7 +133,7 @@ class AtClient:
|
|||||||
self._device = device
|
self._device = device
|
||||||
self._baud = baud
|
self._baud = baud
|
||||||
self._timeout = timeout
|
self._timeout = timeout
|
||||||
self._serial: Serial | None = None
|
self._serial: serial.Serial | None = None
|
||||||
|
|
||||||
def send_raw(self, data: bytes) -> None:
|
def send_raw(self, data: bytes) -> None:
|
||||||
self._ensure_serial()
|
self._ensure_serial()
|
||||||
@@ -185,14 +185,14 @@ class AtClient:
|
|||||||
pass
|
pass
|
||||||
self._serial = None
|
self._serial = None
|
||||||
if self._serial is None:
|
if self._serial is None:
|
||||||
self._serial = Serial(self._device, baudrate=self._baud, timeout=self._timeout)
|
self._serial = serial.Serial(self._device, baudrate=self._baud, timeout=self._timeout)
|
||||||
|
|
||||||
def query(self, cmd: str) -> list[str]:
|
def query(self, cmd: str) -> list[str]:
|
||||||
self._ensure_serial()
|
self._ensure_serial()
|
||||||
try:
|
try:
|
||||||
self._send(cmd)
|
self._send(cmd)
|
||||||
return self._expect()
|
return self._expect()
|
||||||
except SerialException:
|
except serial.SerialException:
|
||||||
self._ensure_serial(reconnect=True)
|
self._ensure_serial(reconnect=True)
|
||||||
self._send(cmd)
|
self._send(cmd)
|
||||||
return self._expect()
|
return self._expect()
|
||||||
@@ -208,7 +208,7 @@ class AtClient:
|
|||||||
if self._serial:
|
if self._serial:
|
||||||
try:
|
try:
|
||||||
self._serial.reset_input_buffer()
|
self._serial.reset_input_buffer()
|
||||||
except (OSError, SerialException, termios.error):
|
except (OSError, serial.SerialException, termios.error):
|
||||||
self._ensure_serial(reconnect=True)
|
self._ensure_serial(reconnect=True)
|
||||||
for line in self.query(f'AT+CCHO="{ISDR_AID}"'):
|
for line in self.query(f'AT+CCHO="{ISDR_AID}"'):
|
||||||
if line.startswith("+CCHO:") and (ch := line.split(":", 1)[1].strip()):
|
if line.startswith("+CCHO:") and (ch := line.split(":", 1)[1].strip()):
|
||||||
@@ -230,7 +230,7 @@ class AtClient:
|
|||||||
try:
|
try:
|
||||||
self._open_isdr_once()
|
self._open_isdr_once()
|
||||||
return
|
return
|
||||||
except (RuntimeError, TimeoutError, termios.error, SerialException):
|
except (RuntimeError, TimeoutError, termios.error, serial.SerialException):
|
||||||
time.sleep(OPEN_ISDR_RETRY_DELAY_S)
|
time.sleep(OPEN_ISDR_RETRY_DELAY_S)
|
||||||
if attempt == OPEN_ISDR_RESET_ATTEMPT:
|
if attempt == OPEN_ISDR_RESET_ATTEMPT:
|
||||||
self._reset_modem()
|
self._reset_modem()
|
||||||
@@ -451,7 +451,7 @@ def process_notifications(client: AtClient) -> None:
|
|||||||
response = es10x_command(client, request)
|
response = es10x_command(client, request)
|
||||||
content = require_tag(require_tag(response, TAG_RETRIEVE_NOTIFICATION, "RetrieveNotificationsListResponse"),
|
content = require_tag(require_tag(response, TAG_RETRIEVE_NOTIFICATION, "RetrieveNotificationsListResponse"),
|
||||||
TAG_OK, "RetrieveNotificationsListResponse")
|
TAG_OK, "RetrieveNotificationsListResponse")
|
||||||
pending_notif = next((content[start:end] for t, _, start, end in iter_tlv(content, with_positions=True) if t in (TAG_PROFILE_INSTALL_RESULT, 0x30)), None)
|
pending_notif = next((v for t, v in iter_tlv(content) if t in (TAG_PROFILE_INSTALL_RESULT, 0x30)), None)
|
||||||
if pending_notif is None:
|
if pending_notif is None:
|
||||||
raise RuntimeError("Missing PendingNotification")
|
raise RuntimeError("Missing PendingNotification")
|
||||||
|
|
||||||
@@ -682,7 +682,7 @@ def download_profile(client: AtClient, activation_code: str) -> str:
|
|||||||
session.close()
|
session.close()
|
||||||
|
|
||||||
|
|
||||||
class LPA(LPABase):
|
class TiciLPA(LPABase):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
if hasattr(self, '_client'):
|
if hasattr(self, '_client'):
|
||||||
return
|
return
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import io
|
|
||||||
import sys
|
import sys
|
||||||
import math
|
import math
|
||||||
import os
|
import os
|
||||||
@@ -22,12 +21,13 @@ def get_chunk_targets(path, file_size):
|
|||||||
|
|
||||||
def chunk_file(path, targets):
|
def chunk_file(path, targets):
|
||||||
manifest_path, *chunk_paths = targets
|
manifest_path, *chunk_paths = targets
|
||||||
actual_num_chunks = max(1, math.ceil(os.path.getsize(path) / CHUNK_SIZE))
|
|
||||||
assert len(chunk_paths) >= actual_num_chunks, f"Allowed {len(chunk_paths)} chunks but needs at least {actual_num_chunks}, for path {path}"
|
|
||||||
with open(path, 'rb') as f:
|
with open(path, 'rb') as f:
|
||||||
for chunk_path in chunk_paths:
|
data = f.read()
|
||||||
with open(chunk_path, 'wb') as out:
|
actual_num_chunks = max(1, math.ceil(len(data) / CHUNK_SIZE))
|
||||||
out.write(f.read(CHUNK_SIZE))
|
assert len(chunk_paths) >= actual_num_chunks, f"Allowed {len(chunk_paths)} chunks but needs at least {actual_num_chunks}, for path {path}"
|
||||||
|
for i, chunk_path in enumerate(chunk_paths):
|
||||||
|
with open(chunk_path, 'wb') as f:
|
||||||
|
f.write(data[i * CHUNK_SIZE:(i + 1) * CHUNK_SIZE])
|
||||||
Path(manifest_path).write_text(str(len(chunk_paths)))
|
Path(manifest_path).write_text(str(len(chunk_paths)))
|
||||||
os.remove(path)
|
os.remove(path)
|
||||||
|
|
||||||
@@ -39,41 +39,14 @@ def get_existing_chunks(path):
|
|||||||
return _chunk_paths(path, num_chunks)
|
return _chunk_paths(path, num_chunks)
|
||||||
raise FileNotFoundError(path)
|
raise FileNotFoundError(path)
|
||||||
|
|
||||||
class ChunkStream(io.RawIOBase):
|
def read_file_chunked(path):
|
||||||
def __init__(self, paths):
|
|
||||||
self._paths = iter(paths)
|
|
||||||
self._f = None
|
|
||||||
|
|
||||||
def readable(self):
|
|
||||||
return True
|
|
||||||
|
|
||||||
def readinto(self, b):
|
|
||||||
n = 0
|
|
||||||
view = memoryview(b)
|
|
||||||
while n < len(b):
|
|
||||||
if self._f is None:
|
|
||||||
p = next(self._paths, None)
|
|
||||||
if p is None:
|
|
||||||
break
|
|
||||||
self._f = open(p, 'rb')
|
|
||||||
count = self._f.readinto(view[n:])
|
|
||||||
if not count:
|
|
||||||
self._f.close()
|
|
||||||
self._f = None
|
|
||||||
continue
|
|
||||||
n += count
|
|
||||||
return n
|
|
||||||
|
|
||||||
def open_file_chunked(path):
|
|
||||||
manifest_path = get_manifest_path(path)
|
manifest_path = get_manifest_path(path)
|
||||||
if os.path.isfile(manifest_path):
|
if os.path.isfile(manifest_path):
|
||||||
num_chunks = int(Path(manifest_path).read_text().strip())
|
num_chunks = int(Path(manifest_path).read_text().strip())
|
||||||
paths = [get_chunk_name(path, i, num_chunks) for i in range(num_chunks)]
|
return b''.join(Path(get_chunk_name(path, i, num_chunks)).read_bytes() for i in range(num_chunks))
|
||||||
elif os.path.isfile(path):
|
if os.path.isfile(path):
|
||||||
paths = [path]
|
return Path(path).read_bytes()
|
||||||
else:
|
raise FileNotFoundError(path)
|
||||||
raise FileNotFoundError(path)
|
|
||||||
return io.BufferedReader(ChunkStream(paths))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
@@ -31,3 +31,12 @@ def get_origin(cwd: str | None = None) -> str:
|
|||||||
return run_cmd(["git", "config", "remote." + tracking_remote + ".url"], cwd=cwd)
|
return run_cmd(["git", "config", "remote." + tracking_remote + ".url"], cwd=cwd)
|
||||||
except subprocess.CalledProcessError: # Not on a branch, fallback
|
except subprocess.CalledProcessError: # Not on a branch, fallback
|
||||||
return run_cmd_default(["git", "config", "--get", "remote.origin.url"], cwd=cwd)
|
return run_cmd_default(["git", "config", "--get", "remote.origin.url"], cwd=cwd)
|
||||||
|
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def get_normalized_origin(cwd: str | None = None) -> str:
|
||||||
|
return get_origin(cwd) \
|
||||||
|
.replace("git@", "", 1) \
|
||||||
|
.replace(".git", "", 1) \
|
||||||
|
.replace("https://", "", 1) \
|
||||||
|
.replace(":", "/", 1)
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import os
|
||||||
|
from typing import cast
|
||||||
|
|
||||||
|
from openpilot.common.hardware.base import HardwareBase
|
||||||
|
from openpilot.common.hardware.tici.hardware import Tici
|
||||||
|
from openpilot.common.hardware.pc.hardware import Pc
|
||||||
|
|
||||||
|
TICI = os.path.isfile('/TICI')
|
||||||
|
AGNOS = os.path.isfile('/AGNOS')
|
||||||
|
PC = not TICI
|
||||||
|
|
||||||
|
|
||||||
|
if TICI:
|
||||||
|
HARDWARE = cast(HardwareBase, Tici())
|
||||||
|
else:
|
||||||
|
HARDWARE = cast(HardwareBase, Pc())
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "openpilot/cereal/gen/cpp/log.capnp.h"
|
#include "cereal/gen/cpp/log.capnp.h"
|
||||||
|
|
||||||
// no-op base hw class
|
// no-op base hw class
|
||||||
class HardwareNone {
|
class HardwareNone {
|
||||||
@@ -15,7 +15,7 @@ public:
|
|||||||
|
|
||||||
static std::string get_serial() { return "cccccc"; }
|
static std::string get_serial() { return "cccccc"; }
|
||||||
|
|
||||||
static std::map<std::string, std::string> get_init_logs(bool route_log = false) {
|
static std::map<std::string, std::string> get_init_logs() {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@ import os
|
|||||||
from abc import abstractmethod, ABC
|
from abc import abstractmethod, ABC
|
||||||
from dataclasses import dataclass, fields
|
from dataclasses import dataclass, fields
|
||||||
|
|
||||||
from openpilot.cereal import log
|
from cereal import log
|
||||||
from openpilot.common.esim.base import LPABase
|
from openpilot.common.esim.base import LPABase
|
||||||
|
|
||||||
NetworkType = log.DeviceState.NetworkType
|
NetworkType = log.DeviceState.NetworkType
|
||||||
@@ -5,9 +5,9 @@
|
|||||||
#include "common/hardware/base.h"
|
#include "common/hardware/base.h"
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
|
|
||||||
#if __COMMA_HARDWARE__
|
#if __TICI__
|
||||||
#include "common/hardware/comma/hardware.h"
|
#include "common/hardware/tici/hardware.h"
|
||||||
#define Hardware HardwareComma
|
#define Hardware HardwareTici
|
||||||
#else
|
#else
|
||||||
#include "common/hardware/pc/hardware.h"
|
#include "common/hardware/pc/hardware.h"
|
||||||
#define Hardware HardwarePC
|
#define Hardware HardwarePC
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
from openpilot.cereal import log
|
from cereal import log
|
||||||
from openpilot.common.hardware.base import HardwareBase
|
from openpilot.common.hardware.base import HardwareBase
|
||||||
|
|
||||||
class HardwarePc(HardwareBase):
|
class Pc(HardwareBase):
|
||||||
def get_device_type(self):
|
def get_device_type(self):
|
||||||
return "pc"
|
return "pc"
|
||||||
|
|
||||||
@@ -23,14 +23,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "abl",
|
"name": "abl",
|
||||||
"url": "https://commadist.azureedge.net/agnosupdate/abl-29fd7ed1c012e599420764840f9f11286d34dbff4adaf102a447f06d8c5e0b35.img.xz",
|
"url": "https://commadist.azureedge.net/agnosupdate/abl-b6fba807b9bcd66a31f2afb0eba5163ec239693ad32e2e4200f6c356adfe098c.img.xz",
|
||||||
"hash": "29fd7ed1c012e599420764840f9f11286d34dbff4adaf102a447f06d8c5e0b35",
|
"hash": "b6fba807b9bcd66a31f2afb0eba5163ec239693ad32e2e4200f6c356adfe098c",
|
||||||
"hash_raw": "29fd7ed1c012e599420764840f9f11286d34dbff4adaf102a447f06d8c5e0b35",
|
"hash_raw": "b6fba807b9bcd66a31f2afb0eba5163ec239693ad32e2e4200f6c356adfe098c",
|
||||||
"size": 274432,
|
"size": 274432,
|
||||||
"sparse": false,
|
"sparse": false,
|
||||||
"full_check": true,
|
"full_check": true,
|
||||||
"has_ab": true,
|
"has_ab": true,
|
||||||
"ondevice_hash": "29fd7ed1c012e599420764840f9f11286d34dbff4adaf102a447f06d8c5e0b35"
|
"ondevice_hash": "b6fba807b9bcd66a31f2afb0eba5163ec239693ad32e2e4200f6c356adfe098c"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "aop",
|
"name": "aop",
|
||||||
@@ -56,29 +56,29 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "boot",
|
"name": "boot",
|
||||||
"url": "https://commadist.azureedge.net/agnosupdate/boot-b30f5eef65ec3878f3aa3dcaf2cc95c09e2c1e661cd3a38e94da37dee76f68bd.img.xz",
|
"url": "https://commadist.azureedge.net/agnosupdate/boot-8806802b195a5b1396a3ae8dd92a8b7711dc522f6aceafd820e871bae5c8a6d8.img.xz",
|
||||||
"hash": "b30f5eef65ec3878f3aa3dcaf2cc95c09e2c1e661cd3a38e94da37dee76f68bd",
|
"hash": "8806802b195a5b1396a3ae8dd92a8b7711dc522f6aceafd820e871bae5c8a6d8",
|
||||||
"hash_raw": "b30f5eef65ec3878f3aa3dcaf2cc95c09e2c1e661cd3a38e94da37dee76f68bd",
|
"hash_raw": "8806802b195a5b1396a3ae8dd92a8b7711dc522f6aceafd820e871bae5c8a6d8",
|
||||||
"size": 46897152,
|
"size": 17487872,
|
||||||
"sparse": false,
|
"sparse": false,
|
||||||
"full_check": true,
|
"full_check": true,
|
||||||
"has_ab": true,
|
"has_ab": true,
|
||||||
"ondevice_hash": "6650e4c46df99ae6dfd6ee895a34b8a2a3cc490a8ce18e16cc3c451c3f822b6e"
|
"ondevice_hash": "edca8bee1531e66953d107eeceeed2dc7b3ca46417e49d55508f94e58bf95db8"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "system",
|
"name": "system",
|
||||||
"url": "https://commadist.azureedge.net/agnosupdate/system-5b6ce7965904a157fd3a134ccfcb854f9ca5c1cc2a26b7cb80a4fa4e1cc4aaa3.img.xz",
|
"url": "https://commadist.azureedge.net/agnosupdate/system-ef0d879302cb29e72110e9c8d3f947c830fd7d37c8192744fc9dbea1af78501f.img.xz",
|
||||||
"hash": "b134fd04e9da27fa1d359ea0f2742c216fa21a08b5c47e9be22ab3b0563d9b9b",
|
"hash": "78acfe16a7b62a3a91fc7a81f40a693e4468cec1c69df7d0b1e550aacc646113",
|
||||||
"hash_raw": "5b6ce7965904a157fd3a134ccfcb854f9ca5c1cc2a26b7cb80a4fa4e1cc4aaa3",
|
"hash_raw": "ef0d879302cb29e72110e9c8d3f947c830fd7d37c8192744fc9dbea1af78501f",
|
||||||
"size": 4718592000,
|
"size": 4718592000,
|
||||||
"sparse": true,
|
"sparse": true,
|
||||||
"full_check": false,
|
"full_check": false,
|
||||||
"has_ab": true,
|
"has_ab": true,
|
||||||
"ondevice_hash": "91242772af771ae96fe2eebc105f2b80a7e1dbaaf6003c2574b62d51b806f468",
|
"ondevice_hash": "743142c5a898f27b2a1029cca42c8a5d5d1fc0096414422b850fe84c8d0b8342",
|
||||||
"alt": {
|
"alt": {
|
||||||
"hash": "5b6ce7965904a157fd3a134ccfcb854f9ca5c1cc2a26b7cb80a4fa4e1cc4aaa3",
|
"hash": "ef0d879302cb29e72110e9c8d3f947c830fd7d37c8192744fc9dbea1af78501f",
|
||||||
"url": "https://commadist.azureedge.net/agnosupdate/system-5b6ce7965904a157fd3a134ccfcb854f9ca5c1cc2a26b7cb80a4fa4e1cc4aaa3.img",
|
"url": "https://commadist.azureedge.net/agnosupdate/system-ef0d879302cb29e72110e9c8d3f947c830fd7d37c8192744fc9dbea1af78501f.img",
|
||||||
"size": 4718592000
|
"size": 4718592000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -12,14 +12,14 @@ import requests
|
|||||||
|
|
||||||
SPARSE_CHUNK_FMT = struct.Struct('H2xI4x')
|
SPARSE_CHUNK_FMT = struct.Struct('H2xI4x')
|
||||||
|
|
||||||
AGNOS_MANIFEST_FILE = "openpilot/system/hardware/comma/agnos.json"
|
AGNOS_MANIFEST_FILE = "system/hardware/tici/agnos.json"
|
||||||
|
|
||||||
|
|
||||||
class StreamingDecompressor:
|
class StreamingDecompressor:
|
||||||
def __init__(self, url: str) -> None:
|
def __init__(self, url: str) -> None:
|
||||||
self.buf = b""
|
self.buf = b""
|
||||||
|
|
||||||
self.req = requests.get(url, stream=True, headers={'Accept-Encoding': 'identity'}, timeout=60)
|
self.req = requests.get(url, stream=True, headers={'Accept-Encoding': None}, timeout=60)
|
||||||
self.it = self.req.iter_content(chunk_size=1024 * 1024)
|
self.it = self.req.iter_content(chunk_size=1024 * 1024)
|
||||||
self.decompressor = lzma.LZMADecompressor(format=lzma.FORMAT_AUTO)
|
self.decompressor = lzma.LZMADecompressor(format=lzma.FORMAT_AUTO)
|
||||||
self.eof = False
|
self.eof = False
|
||||||
@@ -228,7 +228,7 @@ def flash_agnos_update(manifest_path: str, target_slot_number: int, cloudlog, st
|
|||||||
cloudlog.info(f"Target slot {target_slot_number}")
|
cloudlog.info(f"Target slot {target_slot_number}")
|
||||||
|
|
||||||
# set target slot as unbootable
|
# set target slot as unbootable
|
||||||
subprocess.run(f"abctl --set_unbootable {target_slot_number}", shell=True)
|
os.system(f"abctl --set_unbootable {target_slot_number}")
|
||||||
|
|
||||||
for partition in update:
|
for partition in update:
|
||||||
success = False
|
success = False
|
||||||
+19
-19
@@ -339,51 +339,51 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "boot",
|
"name": "boot",
|
||||||
"url": "https://commadist.azureedge.net/agnosupdate/boot-5463317ca7a231f2ddd55a667a8c2b0d6692982359773ca875a99a0e6fd67fb4.img.xz",
|
"url": "https://commadist.azureedge.net/agnosupdate/boot-8806802b195a5b1396a3ae8dd92a8b7711dc522f6aceafd820e871bae5c8a6d8.img.xz",
|
||||||
"hash": "5463317ca7a231f2ddd55a667a8c2b0d6692982359773ca875a99a0e6fd67fb4",
|
"hash": "8806802b195a5b1396a3ae8dd92a8b7711dc522f6aceafd820e871bae5c8a6d8",
|
||||||
"hash_raw": "5463317ca7a231f2ddd55a667a8c2b0d6692982359773ca875a99a0e6fd67fb4",
|
"hash_raw": "8806802b195a5b1396a3ae8dd92a8b7711dc522f6aceafd820e871bae5c8a6d8",
|
||||||
"size": 46897152,
|
"size": 17487872,
|
||||||
"sparse": false,
|
"sparse": false,
|
||||||
"full_check": true,
|
"full_check": true,
|
||||||
"has_ab": true,
|
"has_ab": true,
|
||||||
"ondevice_hash": "daefa6f897bdcc277e50dbf562fd63e57d50d9fc7a599f2d171208a490e725d9"
|
"ondevice_hash": "edca8bee1531e66953d107eeceeed2dc7b3ca46417e49d55508f94e58bf95db8"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "system",
|
"name": "system",
|
||||||
"url": "https://commadist.azureedge.net/agnosupdate/system-2e1ca22762e66898aae384fcc21f488cb015c020b6b588862a64fc8128f0ad1d.img.xz",
|
"url": "https://commadist.azureedge.net/agnosupdate/system-ef0d879302cb29e72110e9c8d3f947c830fd7d37c8192744fc9dbea1af78501f.img.xz",
|
||||||
"hash": "14ab660bb955604ab6c482b3f59e5239e2c40c54e798201afcaed43d5cb0dcfd",
|
"hash": "78acfe16a7b62a3a91fc7a81f40a693e4468cec1c69df7d0b1e550aacc646113",
|
||||||
"hash_raw": "2e1ca22762e66898aae384fcc21f488cb015c020b6b588862a64fc8128f0ad1d",
|
"hash_raw": "ef0d879302cb29e72110e9c8d3f947c830fd7d37c8192744fc9dbea1af78501f",
|
||||||
"size": 4718592000,
|
"size": 4718592000,
|
||||||
"sparse": true,
|
"sparse": true,
|
||||||
"full_check": false,
|
"full_check": false,
|
||||||
"has_ab": true,
|
"has_ab": true,
|
||||||
"ondevice_hash": "18666ca3b529304f5e7a8fc2e3c9dce715b55941e3965a7af43c613f8e18cfce",
|
"ondevice_hash": "743142c5a898f27b2a1029cca42c8a5d5d1fc0096414422b850fe84c8d0b8342",
|
||||||
"alt": {
|
"alt": {
|
||||||
"hash": "2e1ca22762e66898aae384fcc21f488cb015c020b6b588862a64fc8128f0ad1d",
|
"hash": "ef0d879302cb29e72110e9c8d3f947c830fd7d37c8192744fc9dbea1af78501f",
|
||||||
"url": "https://commadist.azureedge.net/agnosupdate/system-2e1ca22762e66898aae384fcc21f488cb015c020b6b588862a64fc8128f0ad1d.img",
|
"url": "https://commadist.azureedge.net/agnosupdate/system-ef0d879302cb29e72110e9c8d3f947c830fd7d37c8192744fc9dbea1af78501f.img",
|
||||||
"size": 4718592000
|
"size": 4718592000
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "userdata_90",
|
"name": "userdata_90",
|
||||||
"url": "https://commadist.azureedge.net/agnosupdate/userdata_90-871adca25cb254ad1704ce427f3faaae1027f74aff43a3e150188c8a1c3d3cb8.img.xz",
|
"url": "https://commadist.azureedge.net/agnosupdate/userdata_90-14a3fc6e9bd148b9deebf6ae9df2f1b3b759e629b337e41b6895864cdd51f630.img.xz",
|
||||||
"hash": "e4f59e5dcf4758759da9284479163e420febf1c118bf33c83b402e80e241608d",
|
"hash": "52160dd01b30b3dc572226e8d549a034b03bc328e80f1f4cd6a857b6dd447687",
|
||||||
"hash_raw": "871adca25cb254ad1704ce427f3faaae1027f74aff43a3e150188c8a1c3d3cb8",
|
"hash_raw": "14a3fc6e9bd148b9deebf6ae9df2f1b3b759e629b337e41b6895864cdd51f630",
|
||||||
"size": 96636764160,
|
"size": 96636764160,
|
||||||
"sparse": true,
|
"sparse": true,
|
||||||
"full_check": true,
|
"full_check": true,
|
||||||
"has_ab": false,
|
"has_ab": false,
|
||||||
"ondevice_hash": "17b4ec7449e62c52be5df551542684b953e5c7ffc95103008043602f79ae7112"
|
"ondevice_hash": "3bbc052c7793087946b0cd668c1778f930084f6b00896aeebd193dfce53fa518"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "userdata_89",
|
"name": "userdata_89",
|
||||||
"url": "https://commadist.azureedge.net/agnosupdate/userdata_89-9d84bd64ef237a32675f936594c16932f8acbb52cf2dd82373a0e718cd32dfcf.img.xz",
|
"url": "https://commadist.azureedge.net/agnosupdate/userdata_89-425c69d021f4ee2f767963bf7b991d1a492485fa465c5f5d001e1cf7de3d62a0.img.xz",
|
||||||
"hash": "652e61ecb5b12250dbfeb9f12fd74af16b867b5ea9bf8a08b5731ffd63a76317",
|
"hash": "02a8c5512754d7781d930d242be3fad01fbce652297c69dfe8722dc92b18dc09",
|
||||||
"hash_raw": "9d84bd64ef237a32675f936594c16932f8acbb52cf2dd82373a0e718cd32dfcf",
|
"hash_raw": "425c69d021f4ee2f767963bf7b991d1a492485fa465c5f5d001e1cf7de3d62a0",
|
||||||
"size": 95563022336,
|
"size": 95563022336,
|
||||||
"sparse": true,
|
"sparse": true,
|
||||||
"full_check": true,
|
"full_check": true,
|
||||||
"has_ab": false,
|
"has_ab": false,
|
||||||
"ondevice_hash": "acad63821bb48823c871910b1a363ab924d2635a7574cc5045e877c438d3012f"
|
"ondevice_hash": "3667d500f91b08a4671d7c09623eb6ae8fc905d9273893b50689e214005c7fa6"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
#include "common/hardware/base.h"
|
#include "common/hardware/base.h"
|
||||||
|
|
||||||
class HardwareComma : public HardwareNone {
|
class HardwareTici : public HardwareNone {
|
||||||
public:
|
public:
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
static const std::string name = []() {
|
static const std::string name = []() {
|
||||||
@@ -59,7 +59,7 @@ public:
|
|||||||
std::ofstream("/sys/class/leds/led:switch_2/brightness") << value << "\n";
|
std::ofstream("/sys/class/leds/led:switch_2/brightness") << value << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::map<std::string, std::string> get_init_logs(bool route_log = false) {
|
static std::map<std::string, std::string> get_init_logs() {
|
||||||
std::map<std::string, std::string> ret = {
|
std::map<std::string, std::string> ret = {
|
||||||
{"/BUILD", util::read_file("/BUILD")},
|
{"/BUILD", util::read_file("/BUILD")},
|
||||||
{"lsblk", util::check_output("lsblk -o NAME,SIZE,STATE,VENDOR,MODEL,REV,SERIAL")},
|
{"lsblk", util::check_output("lsblk -o NAME,SIZE,STATE,VENDOR,MODEL,REV,SERIAL")},
|
||||||
@@ -73,14 +73,12 @@ public:
|
|||||||
temp.erase(temp.find_last_not_of(std::string("\0\r\n", 3))+1);
|
temp.erase(temp.find_last_not_of(std::string("\0\r\n", 3))+1);
|
||||||
ret["boot temp"] = temp;
|
ret["boot temp"] = temp;
|
||||||
|
|
||||||
// TODO: these are too slow to do on route log inits. need to do it async?
|
// TODO: log something from system and boot
|
||||||
if (!route_log) {
|
for (std::string part : {"xbl", "abl", "aop", "devcfg", "xbl_config"}) {
|
||||||
for (std::string part : {"xbl", "abl", "aop", "devcfg", "xbl_config"}) {
|
for (std::string slot : {"a", "b"}) {
|
||||||
for (std::string slot : {"a", "b"}) {
|
std::string partition = part + "_" + slot;
|
||||||
std::string partition = part + "_" + slot;
|
std::string hash = util::check_output("sha256sum /dev/disk/by-partlabel/" + partition);
|
||||||
std::string hash = util::check_output("sha256sum /dev/disk/by-partlabel/" + partition);
|
ret[partition] = hash.substr(0, hash.find_first_of(" "));
|
||||||
ret[partition] = hash.substr(0, hash.find_first_of(" "));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7,13 +7,14 @@ import time
|
|||||||
from functools import cached_property, lru_cache
|
from functools import cached_property, lru_cache
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from openpilot.cereal import log
|
from cereal import log
|
||||||
from openpilot.common.utils import sudo_read, sudo_write
|
from openpilot.common.utils import sudo_read, sudo_write
|
||||||
from openpilot.common.gpio import gpio_set, gpio_init, get_irqs_for_action
|
from openpilot.common.gpio import gpio_set, gpio_init, get_irqs_for_action
|
||||||
from openpilot.common.esim.base import LPABase
|
from openpilot.common.esim.base import LPABase
|
||||||
from openpilot.common.hardware.base import HardwareBase, ThermalConfig, ThermalZone
|
from openpilot.common.hardware.base import HardwareBase, ThermalConfig, ThermalZone
|
||||||
from openpilot.common.hardware.comma.pins import GPIO
|
from openpilot.common.esim.lpa import TiciLPA
|
||||||
from openpilot.common.hardware.comma.amplifier import Amplifier
|
from openpilot.common.hardware.tici.pins import GPIO
|
||||||
|
from openpilot.common.hardware.tici.amplifier import Amplifier
|
||||||
|
|
||||||
MODEM_STATE_PATH = "/dev/shm/modem"
|
MODEM_STATE_PATH = "/dev/shm/modem"
|
||||||
|
|
||||||
@@ -57,17 +58,7 @@ def get_default_route_iface():
|
|||||||
routes = [(int(route[6]), route[0]) for line in f.readlines()[1:] if (route := line.split())[1] == "00000000" and int(route[3], 16) & 0x1]
|
routes = [(int(route[6]), route[0]) for line in f.readlines()[1:] if (route := line.split())[1] == "00000000" and int(route[3], 16) & 0x1]
|
||||||
return min(routes)[1] if routes else None
|
return min(routes)[1] if routes else None
|
||||||
|
|
||||||
class HardwareComma(HardwareBase):
|
class Tici(HardwareBase):
|
||||||
"""
|
|
||||||
This platform covers the Snapdragon 845-based comma devices:
|
|
||||||
- tici = comma three
|
|
||||||
- tizi = comma 3X
|
|
||||||
- mici = comma four
|
|
||||||
|
|
||||||
We strictly use only the device codenames in this codebase for
|
|
||||||
consistency, though all user-facing UI should use the product names.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def amplifier(self):
|
def amplifier(self):
|
||||||
if self.get_device_type() == "mici":
|
if self.get_device_type() == "mici":
|
||||||
@@ -154,8 +145,7 @@ class HardwareComma(HardwareBase):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def get_sim_lpa(self) -> LPABase:
|
def get_sim_lpa(self) -> LPABase:
|
||||||
from openpilot.common.esim.lpa import LPA
|
return TiciLPA()
|
||||||
return LPA()
|
|
||||||
|
|
||||||
def get_imei(self):
|
def get_imei(self):
|
||||||
return self.get_modem_state().get('imei', '')
|
return self.get_modem_state().get('imei', '')
|
||||||
@@ -251,7 +241,7 @@ class HardwareComma(HardwareBase):
|
|||||||
return (self.read_param_file("/sys/class/power_supply/bms/voltage_now", int) * self.read_param_file("/sys/class/power_supply/bms/current_now", int) / 1e12)
|
return (self.read_param_file("/sys/class/power_supply/bms/voltage_now", int) * self.read_param_file("/sys/class/power_supply/bms/current_now", int) / 1e12)
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
subprocess.run("sudo poweroff", shell=True)
|
os.system("sudo poweroff")
|
||||||
|
|
||||||
def get_thermal_config(self):
|
def get_thermal_config(self):
|
||||||
intake, exhaust, gnss, bottomSoc = None, None, None, None
|
intake, exhaust, gnss, bottomSoc = None, None, None, None
|
||||||
@@ -345,11 +335,11 @@ class HardwareComma(HardwareBase):
|
|||||||
self.amplifier.initialize_configuration()
|
self.amplifier.initialize_configuration()
|
||||||
|
|
||||||
# Allow hardwared to write engagement status to kmsg
|
# Allow hardwared to write engagement status to kmsg
|
||||||
subprocess.run("sudo chmod a+w /dev/kmsg", shell=True)
|
os.system("sudo chmod a+w /dev/kmsg")
|
||||||
|
|
||||||
# Ensure fan gpio is enabled so fan runs until shutdown, also turned on at boot by the ABL
|
# Ensure fan gpio is enabled so fan runs until shutdown, also turned on at boot by the ABL
|
||||||
gpio_init(GPIO.SOM_ST_IO, True)
|
gpio_init(GPIO.SOM_ST_IO, True)
|
||||||
gpio_set(GPIO.SOM_ST_IO, True)
|
gpio_set(GPIO.SOM_ST_IO, 1)
|
||||||
|
|
||||||
# *** IRQ config ***
|
# *** IRQ config ***
|
||||||
|
|
||||||
@@ -399,21 +389,21 @@ class HardwareComma(HardwareBase):
|
|||||||
gpio_init(GPIO.STM_RST_N, True)
|
gpio_init(GPIO.STM_RST_N, True)
|
||||||
gpio_init(GPIO.STM_BOOT0, True)
|
gpio_init(GPIO.STM_BOOT0, True)
|
||||||
|
|
||||||
gpio_set(GPIO.STM_RST_N, True)
|
gpio_set(GPIO.STM_RST_N, 1)
|
||||||
gpio_set(GPIO.STM_BOOT0, False)
|
gpio_set(GPIO.STM_BOOT0, 0)
|
||||||
time.sleep(0.01)
|
time.sleep(0.01)
|
||||||
gpio_set(GPIO.STM_RST_N, False)
|
gpio_set(GPIO.STM_RST_N, 0)
|
||||||
|
|
||||||
def recover_internal_panda(self):
|
def recover_internal_panda(self):
|
||||||
gpio_init(GPIO.STM_RST_N, True)
|
gpio_init(GPIO.STM_RST_N, True)
|
||||||
gpio_init(GPIO.STM_BOOT0, True)
|
gpio_init(GPIO.STM_BOOT0, True)
|
||||||
|
|
||||||
gpio_set(GPIO.STM_RST_N, True)
|
gpio_set(GPIO.STM_RST_N, 1)
|
||||||
gpio_set(GPIO.STM_BOOT0, True)
|
gpio_set(GPIO.STM_BOOT0, 1)
|
||||||
time.sleep(0.01)
|
time.sleep(0.01)
|
||||||
gpio_set(GPIO.STM_RST_N, False)
|
gpio_set(GPIO.STM_RST_N, 0)
|
||||||
time.sleep(0.01)
|
time.sleep(0.01)
|
||||||
gpio_set(GPIO.STM_BOOT0, False)
|
gpio_set(GPIO.STM_BOOT0, 0)
|
||||||
|
|
||||||
def booted(self):
|
def booted(self):
|
||||||
# this normally boots within 8s, but on rare occasions takes 30+s
|
# this normally boots within 8s, but on rare occasions takes 30+s
|
||||||
@@ -423,7 +413,7 @@ class HardwareComma(HardwareBase):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
t = HardwareComma()
|
t = Tici()
|
||||||
t.initialize_hardware()
|
t.initialize_hardware()
|
||||||
t.set_power_save(False)
|
t.set_power_save(False)
|
||||||
print(t.get_sim_info())
|
print(t.get_sim_info())
|
||||||
@@ -3,15 +3,12 @@ import fcntl
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import select
|
import serial
|
||||||
import signal
|
import signal
|
||||||
import struct
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
import termios
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from contextlib import contextmanager
|
|
||||||
from ipaddress import IPv4Address, AddressValueError
|
from ipaddress import IPv4Address, AddressValueError
|
||||||
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
@@ -54,7 +51,7 @@ PPPD_CMD = [
|
|||||||
"novj", "novjccomp", "ipcp-accept-local", "ipcp-accept-remote", "nomagic",
|
"novj", "novjccomp", "ipcp-accept-local", "ipcp-accept-remote", "nomagic",
|
||||||
"user", '""', "password", '""',
|
"user", '""', "password", '""',
|
||||||
]
|
]
|
||||||
INITIAL_STATE: dict[str, object] = {
|
INITIAL_STATE = {
|
||||||
"seconds_since_boot": 0,
|
"seconds_since_boot": 0,
|
||||||
"state": "INITIALIZING",
|
"state": "INITIALIZING",
|
||||||
"connected": False, "ip_address": "",
|
"connected": False, "ip_address": "",
|
||||||
@@ -66,39 +63,6 @@ INITIAL_STATE: dict[str, object] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
|
||||||
def _serial_port(port: str, baudrate: int):
|
|
||||||
fd = os.open(port, os.O_RDWR | os.O_NOCTTY)
|
|
||||||
try:
|
|
||||||
attrs = termios.tcgetattr(fd)
|
|
||||||
attrs[0] = 0
|
|
||||||
attrs[1] = 0
|
|
||||||
attrs[2] = termios.CLOCAL | termios.CREAD | termios.CS8
|
|
||||||
attrs[3] = 0
|
|
||||||
attrs[4] = attrs[5] = getattr(termios, f"B{baudrate}")
|
|
||||||
attrs[6][termios.VMIN] = 0
|
|
||||||
attrs[6][termios.VTIME] = 0
|
|
||||||
termios.tcsetattr(fd, termios.TCSANOW, attrs)
|
|
||||||
yield fd
|
|
||||||
finally:
|
|
||||||
os.close(fd)
|
|
||||||
|
|
||||||
|
|
||||||
def _read_line(fd: int, timeout: float) -> bytes:
|
|
||||||
data = bytearray()
|
|
||||||
deadline = time.monotonic() + timeout
|
|
||||||
while True:
|
|
||||||
readable, _, _ = select.select([fd], [], [], max(0.0, deadline - time.monotonic()))
|
|
||||||
if not readable:
|
|
||||||
return bytes(data)
|
|
||||||
byte = os.read(fd, 1)
|
|
||||||
if not byte:
|
|
||||||
return bytes(data)
|
|
||||||
data.extend(byte)
|
|
||||||
if byte == b"\n":
|
|
||||||
return bytes(data)
|
|
||||||
|
|
||||||
|
|
||||||
class State(Enum):
|
class State(Enum):
|
||||||
INITIALIZING = "INITIALIZING"
|
INITIALIZING = "INITIALIZING"
|
||||||
SEARCHING = "SEARCHING"
|
SEARCHING = "SEARCHING"
|
||||||
@@ -132,11 +96,10 @@ class PPPSession:
|
|||||||
def reset_data_port():
|
def reset_data_port():
|
||||||
"""Drop DTR on PPP_PORT so the modem terminates any stuck PPP session."""
|
"""Drop DTR on PPP_PORT so the modem terminates any stuck PPP session."""
|
||||||
try:
|
try:
|
||||||
with _serial_port(PPP_PORT, 460800) as fd:
|
with serial.Serial(PPP_PORT, 460800, timeout=1) as s:
|
||||||
dtr = struct.pack("I", termios.TIOCM_DTR)
|
s.dtr = False
|
||||||
fcntl.ioctl(fd, termios.TIOCMBIC, dtr)
|
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
fcntl.ioctl(fd, termios.TIOCMBIS, dtr)
|
s.dtr = True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.warning(f"data port reset failed: {e}")
|
logging.warning(f"data port reset failed: {e}")
|
||||||
|
|
||||||
@@ -257,14 +220,12 @@ class Modem:
|
|||||||
os.close(fd)
|
os.close(fd)
|
||||||
return []
|
return []
|
||||||
try:
|
try:
|
||||||
with _serial_port(AT_PORT, 9600) as serial_fd:
|
with serial.Serial(AT_PORT, 9600, timeout=5) as ser:
|
||||||
termios.tcflush(serial_fd, termios.TCIFLUSH)
|
ser.reset_input_buffer()
|
||||||
command = (cmd + "\r").encode()
|
ser.write((cmd + "\r").encode())
|
||||||
while command:
|
|
||||||
command = command[os.write(serial_fd, command):]
|
|
||||||
lines = []
|
lines = []
|
||||||
while True:
|
while True:
|
||||||
raw = _read_line(serial_fd, 5)
|
raw = ser.readline()
|
||||||
if not raw:
|
if not raw:
|
||||||
raise TimeoutError("AT timeout")
|
raise TimeoutError("AT timeout")
|
||||||
line = raw.decode(errors="ignore").strip()
|
line = raw.decode(errors="ignore").strip()
|
||||||
@@ -544,11 +505,7 @@ class Modem:
|
|||||||
except (AddressValueError, ValueError):
|
except (AddressValueError, ValueError):
|
||||||
pass
|
pass
|
||||||
if not dns_servers:
|
if not dns_servers:
|
||||||
dns_servers = [
|
logging.warning(f"no cellular DNS servers reported by modem: {v!r}")
|
||||||
"8.8.8.8", # Google
|
|
||||||
"1.1.1.1", # Cloudflare
|
|
||||||
]
|
|
||||||
logging.warning(f"no cellular DNS servers reported by modem: {v!r}; using fallback {dns_servers}")
|
|
||||||
return dns_servers
|
return dns_servers
|
||||||
|
|
||||||
def _poll_byte_counters(self) -> dict:
|
def _poll_byte_counters(self) -> dict:
|
||||||
+1
-2
@@ -6,8 +6,7 @@ TEST_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)))
|
|||||||
MANIFEST = os.path.join(TEST_DIR, "../agnos.json")
|
MANIFEST = os.path.join(TEST_DIR, "../agnos.json")
|
||||||
|
|
||||||
|
|
||||||
from openpilot.common.test import OpenpilotTestCase
|
class TestAgnosUpdater:
|
||||||
class TestAgnosUpdater(OpenpilotTestCase):
|
|
||||||
|
|
||||||
def test_manifest(self):
|
def test_manifest(self):
|
||||||
with open(MANIFEST) as f:
|
with open(MANIFEST) as f:
|
||||||
Executable → Regular
+12
-14
@@ -1,17 +1,19 @@
|
|||||||
#!/usr/bin/env python3
|
import pytest
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
import random
|
||||||
import subprocess
|
import subprocess
|
||||||
import unittest
|
|
||||||
|
|
||||||
from panda import Panda
|
from panda import Panda
|
||||||
from openpilot.common.test import OpenpilotTestCase
|
from openpilot.common.hardware import TICI, HARDWARE
|
||||||
from openpilot.common.hardware import HARDWARE
|
from openpilot.common.hardware.tici.amplifier import Amplifier
|
||||||
from openpilot.common.hardware.comma.amplifier import Amplifier
|
|
||||||
|
|
||||||
|
|
||||||
class TestAmplifier(OpenpilotTestCase):
|
class TestAmplifier:
|
||||||
COMMA_HARDWARE_TEST = True
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
if not TICI:
|
||||||
|
pytest.skip()
|
||||||
|
|
||||||
def setup_method(self):
|
def setup_method(self):
|
||||||
# clear dmesg
|
# clear dmesg
|
||||||
@@ -55,7 +57,7 @@ class TestAmplifier(OpenpilotTestCase):
|
|||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|
||||||
self.panda.set_siren(True)
|
self.panda.set_siren(True)
|
||||||
time.sleep(0.1)
|
time.sleep(random.randint(0, 5))
|
||||||
|
|
||||||
amp = Amplifier(debug=True)
|
amp = Amplifier(debug=True)
|
||||||
r = amp.initialize_configuration()
|
r = amp.initialize_configuration()
|
||||||
@@ -64,8 +66,4 @@ class TestAmplifier(OpenpilotTestCase):
|
|||||||
if self._check_for_i2c_errors(True):
|
if self._check_for_i2c_errors(True):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
self.fail("didn't hit any i2c errors")
|
pytest.fail("didn't hit any i2c errors")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
unittest.main()
|
|
||||||
@@ -1,19 +1,19 @@
|
|||||||
"""
|
"""
|
||||||
Utilities for generating mock messages for testing.
|
Utilities for generating mock messages for testing.
|
||||||
example in openpilot/common/tests/test_mock.py
|
example in common/tests/test_mock.py
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
import threading
|
import threading
|
||||||
from openpilot.cereal.messaging import PubMaster
|
from cereal.messaging import PubMaster
|
||||||
from openpilot.cereal.services import SERVICE_LIST
|
from cereal.services import SERVICE_LIST
|
||||||
from openpilot.common.mock.generators import generate_deviceMotion
|
from openpilot.common.mock.generators import generate_livePose
|
||||||
from openpilot.common.realtime import Ratekeeper
|
from openpilot.common.realtime import Ratekeeper
|
||||||
|
|
||||||
|
|
||||||
MOCK_GENERATOR = {
|
MOCK_GENERATOR = {
|
||||||
"deviceMotion": generate_deviceMotion
|
"livePose": generate_livePose
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
from cereal import messaging
|
||||||
|
|
||||||
|
|
||||||
|
def generate_livePose():
|
||||||
|
msg = messaging.new_message('livePose')
|
||||||
|
meas = {'x': 0.0, 'y': 0.0, 'z': 0.0, 'xStd': 0.0, 'yStd': 0.0, 'zStd': 0.0, 'valid': True}
|
||||||
|
msg.livePose.orientationNED = meas
|
||||||
|
msg.livePose.velocityDevice = meas
|
||||||
|
msg.livePose.angularVelocityDevice = meas
|
||||||
|
msg.livePose.accelerationDevice = meas
|
||||||
|
msg.livePose.inputsOK = True
|
||||||
|
msg.livePose.posenetOK = True
|
||||||
|
msg.livePose.sensorsOK = True
|
||||||
|
return msg
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import pytest
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
|
||||||
|
def _to_safe_name(s):
|
||||||
|
return re.sub(r"[^a-zA-Z0-9_]+", "_", str(s)).strip("_")
|
||||||
|
|
||||||
|
|
||||||
|
class parameterized:
|
||||||
|
@staticmethod
|
||||||
|
def expand(cases):
|
||||||
|
cases = list(cases)
|
||||||
|
|
||||||
|
if not cases:
|
||||||
|
return lambda func: pytest.mark.skip("no parameterized cases")(func)
|
||||||
|
|
||||||
|
def decorator(func):
|
||||||
|
params = [p for p in inspect.signature(func).parameters if p != 'self']
|
||||||
|
normalized = [c if isinstance(c, tuple) else (c,) for c in cases]
|
||||||
|
# Infer arg count from first case so extra params (e.g. from @given) are left untouched
|
||||||
|
expand_params = params[: len(normalized[0])]
|
||||||
|
if len(expand_params) == 1:
|
||||||
|
return pytest.mark.parametrize(expand_params[0], [c[0] for c in normalized])(func)
|
||||||
|
return pytest.mark.parametrize(', '.join(expand_params), normalized)(func)
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def parameterized_class(attrs, input_list=None):
|
||||||
|
if isinstance(attrs, list) and (not attrs or isinstance(attrs[0], dict)):
|
||||||
|
params_list = attrs
|
||||||
|
else:
|
||||||
|
assert input_list is not None
|
||||||
|
attr_names = (attrs,) if isinstance(attrs, str) else tuple(attrs)
|
||||||
|
params_list = [dict(zip(attr_names, v if isinstance(v, (tuple, list)) else (v,), strict=False)) for v in input_list]
|
||||||
|
|
||||||
|
def decorator(cls):
|
||||||
|
globs = sys._getframe(1).f_globals
|
||||||
|
for i, params in enumerate(params_list):
|
||||||
|
# append sanitized string param values so pytest -k can filter by them
|
||||||
|
suffix = "_".join(filter(None, (_to_safe_name(v) for v in params.values() if isinstance(v, str))))
|
||||||
|
name = f"{cls.__name__}_{i}" + (f"_{suffix}" if suffix else "")
|
||||||
|
new_cls = type(name, (cls,), dict(params))
|
||||||
|
new_cls.__module__ = cls.__module__
|
||||||
|
new_cls.__test__ = True # override inherited False so pytest collects this subclass
|
||||||
|
globs[name] = new_cls
|
||||||
|
# Don't collect the un-parametrised base, but return it so outer decorators
|
||||||
|
# (e.g. @pytest.mark.skip) land on it and propagate to subclasses via MRO.
|
||||||
|
cls.__test__ = False
|
||||||
|
return cls
|
||||||
|
|
||||||
|
return decorator
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
from openpilot.common.params_pyx import Params, ParamKeyFlag, ParamKeyType, UnknownKeyName
|
||||||
|
assert Params
|
||||||
|
assert ParamKeyFlag
|
||||||
|
assert ParamKeyType
|
||||||
|
assert UnknownKeyName
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
|
||||||
|
params = Params()
|
||||||
|
key = sys.argv[1]
|
||||||
|
assert params.check_key(key), f"unknown param: {key}"
|
||||||
|
|
||||||
|
if len(sys.argv) == 3:
|
||||||
|
val = sys.argv[2]
|
||||||
|
print(f"SET: {key} = {val}")
|
||||||
|
params.put(key, val, block=True)
|
||||||
|
elif len(sys.argv) == 2:
|
||||||
|
print(f"GET: {key} = {params.get(key)}")
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "openpilot/cereal/gen/cpp/log.capnp.h"
|
#include "cereal/gen/cpp/log.capnp.h"
|
||||||
|
|
||||||
inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||||
{"AccessToken", {CLEAR_ON_MANAGER_START | DONT_LOG, STRING}},
|
{"AccessToken", {CLEAR_ON_MANAGER_START | DONT_LOG, STRING}},
|
||||||
@@ -37,7 +37,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"DoShutdown", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"DoShutdown", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||||
{"DoUninstall", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"DoUninstall", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||||
{"DriverTooDistracted", {CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON, BOOL}},
|
{"DriverTooDistracted", {CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON, BOOL}},
|
||||||
{"DriverLockoutCount", {CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON, INT, "0"}},
|
|
||||||
{"AlphaLongitudinalEnabled", {PERSISTENT | DEVELOPMENT_ONLY | BACKUP, BOOL}},
|
{"AlphaLongitudinalEnabled", {PERSISTENT | DEVELOPMENT_ONLY | BACKUP, BOOL}},
|
||||||
{"ExperimentalMode", {PERSISTENT | BACKUP, BOOL}},
|
{"ExperimentalMode", {PERSISTENT | BACKUP, BOOL}},
|
||||||
{"ExperimentalModeConfirmed", {PERSISTENT | BACKUP, BOOL}},
|
{"ExperimentalModeConfirmed", {PERSISTENT | BACKUP, BOOL}},
|
||||||
@@ -62,8 +61,10 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"IsLiveStreaming", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"IsLiveStreaming", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||||
{"IsMetric", {PERSISTENT | BACKUP, BOOL}},
|
{"IsMetric", {PERSISTENT | BACKUP, BOOL}},
|
||||||
{"IsOffroad", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"IsOffroad", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||||
|
{"IsOnroad", {PERSISTENT, BOOL}},
|
||||||
{"IsRhdDetected", {PERSISTENT, BOOL}},
|
{"IsRhdDetected", {PERSISTENT, BOOL}},
|
||||||
{"IsReleaseBranch", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"IsReleaseBranch", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||||
|
{"IsTakingSnapshot", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||||
{"IsTestedBranch", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"IsTestedBranch", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||||
{"JoystickDebugMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
{"JoystickDebugMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||||
{"LanguageSetting", {PERSISTENT | BACKUP, STRING, "en"}},
|
{"LanguageSetting", {PERSISTENT | BACKUP, STRING, "en"}},
|
||||||
@@ -91,10 +92,11 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"ObdMultiplexingChanged", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
|
{"ObdMultiplexingChanged", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
|
||||||
{"ObdMultiplexingEnabled", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
|
{"ObdMultiplexingEnabled", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
|
||||||
{"Offroad_CarUnrecognized", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
|
{"Offroad_CarUnrecognized", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
|
||||||
{"Offroad_ChestnutBranch", {CLEAR_ON_MANAGER_START, JSON}},
|
|
||||||
{"Offroad_ConnectivityNeeded", {CLEAR_ON_MANAGER_START, JSON}},
|
{"Offroad_ConnectivityNeeded", {CLEAR_ON_MANAGER_START, JSON}},
|
||||||
{"Offroad_ConnectivityNeededPrompt", {CLEAR_ON_MANAGER_START, JSON}},
|
{"Offroad_ConnectivityNeededPrompt", {CLEAR_ON_MANAGER_START, JSON}},
|
||||||
{"Offroad_ExcessiveActuation", {PERSISTENT, JSON}},
|
{"Offroad_ExcessiveActuation", {PERSISTENT, JSON}},
|
||||||
|
{"Offroad_IsTakingSnapshot", {CLEAR_ON_MANAGER_START, JSON}},
|
||||||
|
{"Offroad_NeosUpdate", {CLEAR_ON_MANAGER_START, JSON}},
|
||||||
{"Offroad_NoFirmware", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
|
{"Offroad_NoFirmware", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
|
||||||
{"Offroad_Recalibration", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
|
{"Offroad_Recalibration", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
|
||||||
{"Offroad_TemperatureTooHigh", {CLEAR_ON_MANAGER_START, JSON}},
|
{"Offroad_TemperatureTooHigh", {CLEAR_ON_MANAGER_START, JSON}},
|
||||||
@@ -106,6 +108,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"PandaHeartbeatLost", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
{"PandaHeartbeatLost", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||||
{"PrimeType", {PERSISTENT, INT}},
|
{"PrimeType", {PERSISTENT, INT}},
|
||||||
{"RecordAudio", {PERSISTENT | BACKUP, BOOL}},
|
{"RecordAudio", {PERSISTENT | BACKUP, BOOL}},
|
||||||
|
{"RecordAudioFeedback", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
{"RecordFront", {PERSISTENT | BACKUP, BOOL}},
|
{"RecordFront", {PERSISTENT | BACKUP, BOOL}},
|
||||||
{"RecordFrontLock", {PERSISTENT, BOOL}}, // for the internal fleet
|
{"RecordFrontLock", {PERSISTENT, BOOL}}, // for the internal fleet
|
||||||
{"SecOCKey", {PERSISTENT | DONT_LOG | BACKUP, STRING}},
|
{"SecOCKey", {PERSISTENT | DONT_LOG | BACKUP, STRING}},
|
||||||
@@ -130,8 +133,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"UpdaterLastFetchTime", {PERSISTENT, TIME}},
|
{"UpdaterLastFetchTime", {PERSISTENT, TIME}},
|
||||||
{"UptimeOffroad", {PERSISTENT, FLOAT, "0.0"}},
|
{"UptimeOffroad", {PERSISTENT, FLOAT, "0.0"}},
|
||||||
{"UptimeOnroad", {PERSISTENT, FLOAT, "0.0"}},
|
{"UptimeOnroad", {PERSISTENT, FLOAT, "0.0"}},
|
||||||
{"UsbGpuActive", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION | CLEAR_ON_IGNITION_ON, BOOL}},
|
{"UsbGpuPresent", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||||
{"UsbGpuLoading", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION | CLEAR_ON_IGNITION_ON, BOOL}},
|
{"UsbGpuCompiled", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||||
{"Version", {PERSISTENT, STRING}},
|
{"Version", {PERSISTENT, STRING}},
|
||||||
|
|
||||||
// --- sunnypilot params --- //
|
// --- sunnypilot params --- //
|
||||||
@@ -178,10 +181,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"QuickBootToggle", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"QuickBootToggle", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
{"QuietMode", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"QuietMode", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
{"RainbowMode", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"RainbowMode", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
{"RoadEdgeLaneChangeEnabled", {PERSISTENT | BACKUP, BOOL, "0"}},
|
|
||||||
{"RocketFuel", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"RocketFuel", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
{"ScreenSaverEnabled", {PERSISTENT | BACKUP, BOOL, "1"}},
|
|
||||||
{"ScreenSaverTimeout", {PERSISTENT | BACKUP, INT, "300"}},
|
|
||||||
{"ShowAdvancedControls", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"ShowAdvancedControls", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
{"ShowTurnSignals", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"ShowTurnSignals", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
{"StandstillTimer", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"StandstillTimer", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
@@ -195,14 +195,11 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
|
|
||||||
// Model Manager params
|
// Model Manager params
|
||||||
{"ModelManager_ActiveBundle", {PERSISTENT, JSON}},
|
{"ModelManager_ActiveBundle", {PERSISTENT, JSON}},
|
||||||
{"ModelManager_ActiveJson", {CLEAR_ON_MANAGER_START, STRING}},
|
|
||||||
{"ModelManager_ClearCache", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"ModelManager_ClearCache", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||||
{"ModelManager_DownloadIndex", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, INT}},
|
{"ModelManager_DownloadIndex", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, INT}},
|
||||||
{"ModelManager_Favs", {PERSISTENT | BACKUP, STRING}},
|
{"ModelManager_Favs", {PERSISTENT | BACKUP, STRING}},
|
||||||
{"ModelManager_LastSyncTime", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, INT, "0"}},
|
{"ModelManager_LastSyncTime", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, INT, "0"}},
|
||||||
{"ModelManager_LastSyncTime_USBGPU", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, INT, "0"}},
|
|
||||||
{"ModelManager_ModelsCache", {PERSISTENT | BACKUP, JSON}},
|
{"ModelManager_ModelsCache", {PERSISTENT | BACKUP, JSON}},
|
||||||
{"ModelManager_ModelsCache_USBGPU", {PERSISTENT | BACKUP, JSON}},
|
|
||||||
|
|
||||||
// Neural Network Lateral Control
|
// Neural Network Lateral Control
|
||||||
{"NeuralNetworkLateralControl", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"NeuralNetworkLateralControl", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
@@ -227,7 +224,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"SubaruStopAndGo", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"SubaruStopAndGo", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
{"SubaruStopAndGoManualParkingBrake", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"SubaruStopAndGoManualParkingBrake", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
{"TeslaCoopSteering", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"TeslaCoopSteering", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
{"TeslaMadsScreenButton", {PERSISTENT | BACKUP, INT, "0"}},
|
|
||||||
{"ToyotaEnforceStockLongitudinal", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"ToyotaEnforceStockLongitudinal", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
{"ToyotaStopAndGoHack", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"ToyotaStopAndGoHack", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
|
|
||||||
@@ -278,7 +274,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
// Torque lateral control custom params
|
// Torque lateral control custom params
|
||||||
{"CustomTorqueParams", {PERSISTENT | BACKUP , BOOL}},
|
{"CustomTorqueParams", {PERSISTENT | BACKUP , BOOL}},
|
||||||
{"EnforceTorqueControl", {PERSISTENT | BACKUP, BOOL}},
|
{"EnforceTorqueControl", {PERSISTENT | BACKUP, BOOL}},
|
||||||
{"LateralJerkTorqueController", {PERSISTENT | BACKUP, BOOL, "0"}},
|
|
||||||
{"LiveTorqueParamsToggle", {PERSISTENT | BACKUP , BOOL}},
|
{"LiveTorqueParamsToggle", {PERSISTENT | BACKUP , BOOL}},
|
||||||
{"LiveTorqueParamsRelaxedToggle", {PERSISTENT | BACKUP , BOOL}},
|
{"LiveTorqueParamsRelaxedToggle", {PERSISTENT | BACKUP , BOOL}},
|
||||||
{"TorqueControlTune", {PERSISTENT | BACKUP, FLOAT, "0.0"}},
|
{"TorqueControlTune", {PERSISTENT | BACKUP, FLOAT, "0.0"}},
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user