mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-07-18 06:12:07 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 41ce29af86 |
@@ -0,0 +1,18 @@
|
|||||||
|
**/.git
|
||||||
|
.DS_Store
|
||||||
|
*.dylib
|
||||||
|
*.DSYM
|
||||||
|
*.d
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
.*.swp
|
||||||
|
.*.swo
|
||||||
|
.*.un~
|
||||||
|
*.tmp
|
||||||
|
*.o
|
||||||
|
*.o-*
|
||||||
|
*.os
|
||||||
|
*.os-*
|
||||||
|
|
||||||
|
venv/
|
||||||
|
.venv/
|
||||||
+11
-2
@@ -10,5 +10,14 @@
|
|||||||
*.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/tici/updater filter=lfs diff=lfs merge=lfs -text
|
system/hardware/tici/updater_weston filter=lfs diff=lfs merge=lfs -text
|
||||||
|
system/hardware/tici/updater_magic filter=lfs diff=lfs merge=lfs -text
|
||||||
|
third_party/**/*.a filter=lfs diff=lfs merge=lfs -text
|
||||||
|
third_party/**/*.so filter=lfs diff=lfs merge=lfs -text
|
||||||
|
third_party/**/*.so.* filter=lfs diff=lfs merge=lfs -text
|
||||||
|
third_party/**/*.dylib filter=lfs diff=lfs merge=lfs -text
|
||||||
|
third_party/acados/*/t_renderer filter=lfs diff=lfs merge=lfs -text
|
||||||
|
third_party/qt5/larch64/bin/lrelease filter=lfs diff=lfs merge=lfs -text
|
||||||
|
third_party/qt5/larch64/bin/lupdate filter=lfs diff=lfs merge=lfs -text
|
||||||
|
third_party/catch2/include/catch2/catch.hpp filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
name: Enhancement
|
||||||
|
about: For openpilot enhancement suggestions
|
||||||
|
title: ''
|
||||||
|
labels: 'enhancement'
|
||||||
|
assignees: ''
|
||||||
|
---
|
||||||
|
|
||||||
@@ -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/**}"
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ Explain how you tested this bug fix.
|
|||||||
|
|
||||||
**Checklist**
|
**Checklist**
|
||||||
|
|
||||||
- [ ] added entry to CAR in openpilot/selfdrive/car/*/values.py and ran `openpilot/selfdrive/car/docs.py` to generate new docs
|
- [ ] 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/openpilot/selfdrive/car/tests/routes.py)
|
- [ ] test route added to [routes.py](https://github.com/commaai/openpilot/blob/master/selfdrive/car/tests/routes.py)
|
||||||
- [ ] route with openpilot:
|
- [ ] route with openpilot:
|
||||||
- [ ] route with stock system:
|
- [ ] route with stock system:
|
||||||
- [ ] car harness used (if comma doesn't sell it, put N/A):
|
- [ ] car harness used (if comma doesn't sell it, put N/A):
|
||||||
|
|||||||
@@ -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 }}
|
||||||
|
|||||||
@@ -120,7 +120,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
upstream_branch: ${{ matrix.model.ref }}
|
upstream_branch: ${{ matrix.model.ref }}
|
||||||
custom_name: ${{ matrix.model.display_name }}
|
custom_name: ${{ matrix.model.display_name }}
|
||||||
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 }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
@@ -158,7 +157,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
upstream_branch: ${{ matrix.model.ref }}
|
upstream_branch: ${{ matrix.model.ref }}
|
||||||
custom_name: ${{ matrix.model.display_name }}
|
custom_name: ${{ matrix.model.display_name }}
|
||||||
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 }}
|
||||||
artifact_suffix: -retry
|
artifact_suffix: -retry
|
||||||
|
|||||||
@@ -24,11 +24,6 @@ on:
|
|||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
default: ''
|
default: ''
|
||||||
is_20hz:
|
|
||||||
description: 'Is this a 20Hz model'
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: true
|
|
||||||
bypass_push:
|
bypass_push:
|
||||||
description: 'Bypass pushing to GitLab for build-all'
|
description: 'Bypass pushing to GitLab for build-all'
|
||||||
required: false
|
required: false
|
||||||
@@ -44,11 +39,6 @@ on:
|
|||||||
description: 'Custom name for the model (no date, only name)'
|
description: 'Custom name for the model (no date, only name)'
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
is_20hz:
|
|
||||||
description: 'Is this a 20Hz model'
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: true
|
|
||||||
recompiled_dir:
|
recompiled_dir:
|
||||||
description: 'Existing recompiled directory number (e.g. 3 for recompiled3)'
|
description: 'Existing recompiled directory number (e.g. 3 for recompiled3)'
|
||||||
required: true
|
required: true
|
||||||
@@ -92,7 +82,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
upstream_branch: ${{ inputs.upstream_branch }}
|
upstream_branch: ${{ inputs.upstream_branch }}
|
||||||
custom_name: ${{ inputs.custom_name || inputs.upstream_branch }}
|
custom_name: ${{ inputs.custom_name || inputs.upstream_branch }}
|
||||||
is_20hz: ${{ inputs.is_20hz }}
|
is_20hz: true
|
||||||
artifact_suffix: ${{ inputs.artifact_suffix }}
|
artifact_suffix: ${{ inputs.artifact_suffix }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
|
|||||||
@@ -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,68 +30,36 @@ 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
|
- name: Checkout upstream openpilot cereal
|
||||||
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
|
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
repository: 'commaai/openpilot'
|
repository: 'commaai/openpilot'
|
||||||
path: upstream_openpilot
|
path: upstream_openpilot
|
||||||
|
sparse-checkout: cereal
|
||||||
ref: "refs/heads/master"
|
ref: "refs/heads/master"
|
||||||
|
|
||||||
- name: Init upstream opendbc submodule
|
- name: Init upstream opendbc submodule
|
||||||
working-directory: upstream_openpilot
|
working-directory: upstream_openpilot
|
||||||
run: git submodule update --init --depth 1 opendbc_repo
|
run: git submodule update --init --depth 1 opendbc_repo
|
||||||
|
|
||||||
- name: Locate upstream capnp paths
|
- name: Install uv
|
||||||
id: locate-capnp
|
run: pip install uv
|
||||||
run: |
|
|
||||||
CEREAL_DIR=$(find upstream_openpilot -maxdepth 4 -name log.capnp -path '*/cereal/log.capnp' -printf '%h\n' -quit)
|
|
||||||
if [ -z "$CEREAL_DIR" ]; then
|
|
||||||
echo "::error::Could not locate cereal/log.capnp in upstream openpilot"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "cereal_dir=$CEREAL_DIR" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "Found upstream cereal at: $CEREAL_DIR"
|
|
||||||
|
|
||||||
IMPORT_ARGS=""
|
|
||||||
CAR_CAPNP=$(find upstream_openpilot -maxdepth 5 -name car.capnp -path '*/opendbc/car/car.capnp' -printf '%h\n' -quit)
|
|
||||||
if [ -n "$CAR_CAPNP" ]; then
|
|
||||||
IMPORT_ARGS="-I $CAR_CAPNP"
|
|
||||||
echo "Found car.capnp at: $CAR_CAPNP"
|
|
||||||
fi
|
|
||||||
echo "import_args=$IMPORT_ARGS" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Install pycapnp
|
|
||||||
run: |
|
|
||||||
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))")
|
||||||
-r -f /tmp/sp_schema.json --cereal-dir ${{ steps.locate-capnp.outputs.cereal_dir }} \
|
uv run --isolated --with "pycapnp==${PYCAPNP_VER}" \
|
||||||
${{ steps.locate-capnp.outputs.import_args }}
|
python3 cereal/messaging/tests/validate_sp_cereal_upstream.py \
|
||||||
|
-r -f /tmp/sp_schema.json --cereal-dir upstream_openpilot/cereal
|
||||||
|
|||||||
@@ -17,41 +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'
|
||||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
|
uses: dawidd6/action-download-artifact@v6
|
||||||
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'
|
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 }}
|
||||||
|
|||||||
@@ -22,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
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ jobs:
|
|||||||
python scripts/docs.py build
|
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
|
||||||
@@ -45,7 +45,7 @@ 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
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, reopened, synchronize]
|
types: [opened, reopened, synchronize]
|
||||||
paths:
|
paths:
|
||||||
- 'openpilot/selfdrive/modeld/models/*.onnx'
|
- 'selfdrive/modeld/models/*.onnx'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -16,11 +16,11 @@ jobs:
|
|||||||
if: github.repository == 'commaai/openpilot'
|
if: github.repository == 'commaai/openpilot'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v7
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Checkout master
|
- name: Checkout master
|
||||||
uses: actions/checkout@v7
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
ref: master
|
ref: master
|
||||||
path: base
|
path: base
|
||||||
@@ -36,7 +36,7 @@ jobs:
|
|||||||
echo "EOF" >> $GITHUB_OUTPUT
|
echo "EOF" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Post model report comment
|
- name: Post model report comment
|
||||||
uses: marocchino/sticky-pull-request-comment@0ea0beb66eb9baf113663a64ec522f60e49231c0
|
uses: marocchino/sticky-pull-request-comment@baa7203ed60924babbe5dcd0ac8eae3b66ec5e16
|
||||||
with:
|
with:
|
||||||
header: model-review
|
header: model-review
|
||||||
message: ${{ steps.report.outputs.content }}
|
message: ${{ steps.report.outputs.content }}
|
||||||
@@ -15,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,8 +3,6 @@ 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:
|
||||||
@@ -14,11 +12,9 @@ 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
|
||||||
@@ -54,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 }}
|
||||||
@@ -79,43 +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'
|
|
||||||
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}`;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -164,54 +164,18 @@ jobs:
|
|||||||
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
|
||||||
export PYTHONPATH="${PYTHONPATH}:${{ env.TINYGRAD_PATH }}:${{ github.workspace }}"
|
export PYTHONPATH="${PYTHONPATH}:${{ env.TINYGRAD_PATH }}"
|
||||||
|
|
||||||
COMPILE_MODELD="${{ github.workspace }}/sunnypilot/modeld_v2/compile_modeld.py"
|
# Loop through all .onnx files
|
||||||
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}')")
|
|
||||||
TG_FLAGS="DEV=QCOM IMAGE=1 FLOAT16=1 NOLOCALS=1 JIT_BATCH_SIZE=0 OPENPILOT_HACKS=1"
|
|
||||||
|
|
||||||
# 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"
|
base_name=$(basename "$onnx_file" .onnx)
|
||||||
env ${TG_FLAGS} python3 "${{ env.MODELS_DIR }}/../get_model_metadata.py" "$onnx_file" || true
|
output_file="${{ env.MODELS_DIR }}/${base_name}_tinygrad.pkl"
|
||||||
|
|
||||||
|
echo "Compiling: $onnx_file -> $output_file"
|
||||||
|
QCOM=1 python3 "${{ env.TINYGRAD_PATH }}/examples/openpilot/compile3.py" "$onnx_file" "$output_file"
|
||||||
|
DEV=QCOM FLOAT16=1 NOLOCALS=1 JIT_BATCH_SIZE=0 python3 "${{ env.MODELS_DIR }}/../get_model_metadata.py" "$onnx_file" || true
|
||||||
done
|
done
|
||||||
|
|
||||||
# Detect model type and build compile args
|
|
||||||
VISION_ONNX="${{ env.MODELS_DIR }}/driving_vision.onnx"
|
|
||||||
POLICY_ONNX="${{ env.MODELS_DIR }}/driving_policy.onnx"
|
|
||||||
OFF_POLICY_ONNX="${{ env.MODELS_DIR }}/driving_off_policy.onnx"
|
|
||||||
ON_POLICY_ONNX="${{ env.MODELS_DIR }}/driving_on_policy.onnx"
|
|
||||||
SUPERCOMBO_ONNX="${{ env.MODELS_DIR }}/supercombo.onnx"
|
|
||||||
|
|
||||||
MODEL_TYPE="" ONNX_ARGS="" OUTPUT_NAME=""
|
|
||||||
if [ -f "$VISION_ONNX" ]; then
|
|
||||||
ONNX_ARGS="--vision-onnx $VISION_ONNX"
|
|
||||||
if [ -f "$ON_POLICY_ONNX" ] && [ -f "$OFF_POLICY_ONNX" ]; then
|
|
||||||
MODEL_TYPE=vision_multi_policy
|
|
||||||
ONNX_ARGS="$ONNX_ARGS --off-policy-onnx $OFF_POLICY_ONNX --on-policy-onnx $ON_POLICY_ONNX"
|
|
||||||
elif [ -f "$OFF_POLICY_ONNX" ] && [ -f "$POLICY_ONNX" ]; then
|
|
||||||
MODEL_TYPE=vision_multi_policy
|
|
||||||
ONNX_ARGS="$ONNX_ARGS --policy-onnx $POLICY_ONNX --off-policy-onnx $OFF_POLICY_ONNX"
|
|
||||||
elif [ -f "$POLICY_ONNX" ]; then
|
|
||||||
MODEL_TYPE=vision_policy
|
|
||||||
ONNX_ARGS="$ONNX_ARGS --policy-onnx $POLICY_ONNX"
|
|
||||||
fi
|
|
||||||
elif [ -f "$SUPERCOMBO_ONNX" ]; then
|
|
||||||
MODEL_TYPE=supercombo
|
|
||||||
ONNX_ARGS="--supercombo-onnx $SUPERCOMBO_ONNX"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$MODEL_TYPE" ]; then
|
|
||||||
echo "Detected: $MODEL_TYPE -> driving_tinygrad.pkl"
|
|
||||||
env ${TG_FLAGS} python3 "$COMPILE_MODELD" \
|
|
||||||
--model-type $MODEL_TYPE \
|
|
||||||
--model-size $MODEL_SIZE \
|
|
||||||
--camera-resolutions $CAMERA_RES \
|
|
||||||
$ONNX_ARGS \
|
|
||||||
--output "${{ env.MODELS_DIR }}/driving_tinygrad.pkl"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Validate Model Outputs
|
- name: Validate Model Outputs
|
||||||
run: |
|
run: |
|
||||||
source /etc/profile
|
source /etc/profile
|
||||||
@@ -230,8 +194,6 @@ jobs:
|
|||||||
rsync -avm \
|
rsync -avm \
|
||||||
--include='*.dlc' \
|
--include='*.dlc' \
|
||||||
--include='*.pkl' \
|
--include='*.pkl' \
|
||||||
--include='*.chunk*' \
|
|
||||||
--include='*.chunkmanifest' \
|
|
||||||
--include='*.onnx' \
|
--include='*.onnx' \
|
||||||
--exclude='*' \
|
--exclude='*' \
|
||||||
--delete-excluded \
|
--delete-excluded \
|
||||||
|
|||||||
@@ -79,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
|
||||||
@@ -177,7 +177,7 @@ jobs:
|
|||||||
- name: Build Main Project
|
- name: Build Main Project
|
||||||
run: |
|
run: |
|
||||||
export PYTHONPATH="$BUILD_DIR"
|
export PYTHONPATH="$BUILD_DIR"
|
||||||
./tools/release/release_files.py | sort | uniq | rsync -rRl${RUNNER_DEBUG:+v} --files-from=- . $BUILD_DIR/
|
./release/release_files.py | sort | uniq | rsync -rRl${RUNNER_DEBUG:+v} --files-from=- . $BUILD_DIR/
|
||||||
cd $BUILD_DIR
|
cd $BUILD_DIR
|
||||||
sed -i '/from .board.jungle import PandaJungle, PandaJungleDFU/s/^/#/' panda/__init__.py
|
sed -i '/from .board.jungle import PandaJungle, PandaJungleDFU/s/^/#/' panda/__init__.py
|
||||||
echo "Building sunnypilot's modeld_v2..."
|
echo "Building sunnypilot's modeld_v2..."
|
||||||
@@ -208,17 +208,17 @@ jobs:
|
|||||||
--exclude='Jenkinsfile' \
|
--exclude='Jenkinsfile' \
|
||||||
--exclude='**/release/' \
|
--exclude='**/release/' \
|
||||||
--exclude='**/.github/' \
|
--exclude='**/.github/' \
|
||||||
--exclude='**/openpilot/selfdrive/ui/replay/' \
|
--exclude='**/selfdrive/ui/replay/' \
|
||||||
--exclude='**/__pycache__/' \
|
--exclude='**/__pycache__/' \
|
||||||
--exclude='${{env.SCONS_CACHE_DIR}}' \
|
--exclude='${{env.SCONS_CACHE_DIR}}' \
|
||||||
--exclude='**/.git/' \
|
--exclude='**/.git/' \
|
||||||
--exclude='**/SConstruct' \
|
--exclude='**/SConstruct' \
|
||||||
--exclude='**/SConscript' \
|
--exclude='**/SConscript' \
|
||||||
--exclude='**/.venv/' \
|
--exclude='**/.venv/' \
|
||||||
--exclude='openpilot/selfdrive/modeld/models/*.onnx*' \
|
--exclude='selfdrive/modeld/models/driving_vision.onnx' \
|
||||||
--exclude='openpilot/sunnypilot/modeld*/models/*.onnx*' \
|
--exclude='selfdrive/modeld/models/driving_policy.onnx' \
|
||||||
--exclude='openpilot/third_party/*x86*' \
|
--exclude='third_party/*x86*' \
|
||||||
--exclude='openpilot/third_party/*Darwin*' \
|
--exclude='third_party/*Darwin*' \
|
||||||
--delete-excluded \
|
--delete-excluded \
|
||||||
--chown=comma:comma \
|
--chown=comma:comma \
|
||||||
${BUILD_DIR}/ ${OUTPUT_DIR}/
|
${BUILD_DIR}/ ${OUTPUT_DIR}/
|
||||||
|
|||||||
@@ -35,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
|
||||||
@@ -75,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' ':')
|
||||||
@@ -99,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
|
||||||
@@ -114,18 +118,16 @@ 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 -j$(nproc)
|
||||||
- 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:
|
|
||||||
RAYLIB_BACKEND: headless
|
|
||||||
run: |
|
run: |
|
||||||
|
source selfdrive/test/setup_xvfb.sh
|
||||||
# Pre-compile Python bytecode so each pytest worker doesn't need to
|
# Pre-compile Python bytecode so each pytest worker doesn't need to
|
||||||
$PYTEST --collect-only -m 'not slow' -qq
|
$PYTEST --collect-only -m 'not slow' -qq
|
||||||
MAX_EXAMPLES=1 $PYTEST -m 'not slow'
|
MAX_EXAMPLES=1 $PYTEST -m 'not slow'
|
||||||
@@ -140,42 +142,44 @@ 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 -j$(nproc)
|
||||||
- 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 == 'commaai/openpilot' && 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: commaai/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: Push refs
|
||||||
if: github.repository == 'commaai/openpilot' && 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: |
|
||||||
@@ -183,23 +187,17 @@ jobs:
|
|||||||
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
|
git push origin process-replay --force
|
||||||
if: github.repository == 'commaai/openpilot' && github.ref == 'refs/heads/master'
|
|
||||||
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60
|
|
||||||
with:
|
|
||||||
timeout_minutes: 2
|
|
||||||
max_attempts: 3
|
|
||||||
command: cd ${{ github.workspace }}/ci-artifacts && git push origin process-replay --force
|
|
||||||
- name: Run regen
|
- name: Run regen
|
||||||
if: false
|
if: false
|
||||||
timeout-minutes: 4
|
timeout-minutes: 4
|
||||||
env:
|
env:
|
||||||
ONNXCPU: 1
|
ONNXCPU: 1
|
||||||
run: $PYTEST openpilot/selfdrive/test/process_replay/test_regen.py
|
run: $PYTEST selfdrive/test/process_replay/test_regen.py
|
||||||
|
|
||||||
simulator_driving:
|
simulator_driving:
|
||||||
name: simulator driving
|
name: simulator driving
|
||||||
@@ -211,16 +209,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 -j$(nproc)
|
||||||
- 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: pytest -s openpilot/tools/sim/tests/test_metadrive_bridge.py
|
|
||||||
|
|
||||||
create_ui_report:
|
create_ui_report:
|
||||||
name: Create UI Report
|
name: Create UI Report
|
||||||
@@ -231,21 +230,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 -j$(nproc)
|
||||||
- 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:
|
||||||
@@ -34,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 }}
|
||||||
@@ -53,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 }}
|
||||||
@@ -62,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 }}
|
||||||
@@ -70,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 }}
|
||||||
@@ -97,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'
|
||||||
@@ -115,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
|
||||||
@@ -156,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"
|
||||||
@@ -164,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 }}
|
||||||
|
|||||||
+9
-16
@@ -15,13 +15,6 @@ a.out
|
|||||||
.cache/
|
.cache/
|
||||||
bin/
|
bin/
|
||||||
|
|
||||||
# created at launch for TICI PYTHONPATH (PC uses editable installs via pyproject.toml)
|
|
||||||
/msgq
|
|
||||||
/opendbc
|
|
||||||
/rednose
|
|
||||||
/teleoprtc
|
|
||||||
/tinygrad
|
|
||||||
|
|
||||||
*.mp4
|
*.mp4
|
||||||
*.dylib
|
*.dylib
|
||||||
*.DSYM
|
*.DSYM
|
||||||
@@ -51,18 +44,18 @@ bin/
|
|||||||
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_compiled_flags.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
|
||||||
|
|||||||
+2
-2
@@ -6,7 +6,7 @@
|
|||||||
url = https://github.com/sunnypilot/opendbc.git
|
url = https://github.com/sunnypilot/opendbc.git
|
||||||
[submodule "msgq"]
|
[submodule "msgq"]
|
||||||
path = msgq_repo
|
path = msgq_repo
|
||||||
url = https://github.com/sunnypilot/msgq.git
|
url = https://github.com/commaai/msgq.git
|
||||||
[submodule "rednose_repo"]
|
[submodule "rednose_repo"]
|
||||||
path = rednose_repo
|
path = rednose_repo
|
||||||
url = https://github.com/commaai/rednose.git
|
url = https://github.com/commaai/rednose.git
|
||||||
@@ -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
+6
@@ -17,5 +17,11 @@
|
|||||||
"**/.git",
|
"**/.git",
|
||||||
"**/.venv",
|
"**/.venv",
|
||||||
"**/__pycache__",
|
"**/__pycache__",
|
||||||
|
// exclude directories that should be using the symlinked version
|
||||||
|
"common/**",
|
||||||
|
"selfdrive/**",
|
||||||
|
"system/**",
|
||||||
|
"third_party/**",
|
||||||
|
"tools/**",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-30
@@ -1,34 +1,5 @@
|
|||||||
sunnypilot Version 2026.002.000 (2026-06-28)
|
sunnypilot Version 2026.002.000 (2026-xx-xx)
|
||||||
========================
|
========================
|
||||||
* What's Changed (sunnypilot/sunnypilot)
|
|
||||||
* ui: update gates for certain toggles by @sunnyhaibin in https://github.com/sunnypilot/sunnypilot/pull/1830
|
|
||||||
* release: ignore upstream IsReleaseBranch by @sunnyhaibin in https://github.com/sunnypilot/sunnypilot/pull/1831
|
|
||||||
* manager: disable DEVELOPMENT_ONLY reset by @sunnyhaibin in https://github.com/sunnypilot/sunnypilot/pull/1833
|
|
||||||
* sunnylink: fix max time offroad values by @nayan8teen in https://github.com/sunnypilot/sunnypilot/pull/1835
|
|
||||||
* ui: show default model name by @nayan8teen in https://github.com/sunnypilot/sunnypilot/pull/1837
|
|
||||||
* sunnylink: add CarParams fallback for brand-specific capabilities by @sunnyhaibin in https://github.com/sunnypilot/sunnypilot/pull/1839
|
|
||||||
* sunnylink SDUI: tweak DisableUpdate param for clarity by @sunnyhaibin in https://github.com/sunnypilot/sunnypilot/pull/1842
|
|
||||||
* Revert "DM: Lancia Delta HF Integrale model" by @sunnyhaibin in https://github.com/sunnypilot/sunnypilot/pull/1849
|
|
||||||
* modeld_v2: safe model validation by @Discountchubbs in https://github.com/sunnypilot/sunnypilot/pull/1855
|
|
||||||
* Revert "deprecate `carState.brake`" for Honda Gas Interceptor by @mvl-boston in https://github.com/sunnypilot/sunnypilot/pull/1860
|
|
||||||
* sunnylink: deprecate legacy params metadata by @sunnyhaibin in https://github.com/sunnypilot/sunnypilot/pull/1862
|
|
||||||
* ui: reset Enforce Torque Control and NNLC if both are enabled by @sunnyhaibin in https://github.com/sunnypilot/sunnypilot/pull/1863
|
|
||||||
* What's Changed (sunnypilot/opendbc)
|
|
||||||
* Rivian: suppress ACM hold-the-wheel warning during MADS-only lateral by @lukasloetkolben in https://github.com/sunnypilot/opendbc/pull/465
|
|
||||||
* Sync: `commaai/opendbc:master` → `sunnypilot/opendbc:master` by @sunnyhaibin in https://github.com/sunnypilot/opendbc/pull/479
|
|
||||||
* safety: add option to ignore frequency check for RX checks by @sunnyhaibin in https://github.com/sunnypilot/opendbc/pull/480
|
|
||||||
* Revert "deprecate carState.brake" for Honda Gas Interceptor by @mvl-boston in https://github.com/sunnypilot/opendbc/pull/481
|
|
||||||
* New Contributors (sunnypilot/sunnypilot)
|
|
||||||
* @mvl-boston made their first contribution in https://github.com/sunnypilot/sunnypilot/pull/1860
|
|
||||||
* Full Changelog: https://github.com/sunnypilot/sunnypilot/compare/v2026.001.007...v2026.002.000
|
|
||||||
************************
|
|
||||||
* Synced with commaai's openpilot (v0.11.1)
|
|
||||||
* master commit 69e2c321e49760e52f7983eaa0a5f77cb95de637 (June 02, 2026)
|
|
||||||
* New driver monitoring model
|
|
||||||
* Improved image processing pipeline for driver camera
|
|
||||||
* Improved thermal policy for comma four
|
|
||||||
* Acura MDX 2022-24 support thanks to mvl-boston!
|
|
||||||
* Rivian R1S and R1T 2025 support thanks to lukasloetkolben!
|
|
||||||
|
|
||||||
sunnypilot Version 2026.001.000 (2026-05-06)
|
sunnypilot Version 2026.001.000 (2026-05-06)
|
||||||
========================
|
========================
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
FROM ubuntu:24.04
|
||||||
|
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends sudo tzdata locales && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen
|
||||||
|
ENV LANG=en_US.UTF-8
|
||||||
|
ENV LANGUAGE=en_US:en
|
||||||
|
ENV LC_ALL=en_US.UTF-8
|
||||||
|
|
||||||
|
ENV NVIDIA_VISIBLE_DEVICES=all
|
||||||
|
ENV NVIDIA_DRIVER_CAPABILITIES=graphics,utility,compute
|
||||||
|
|
||||||
|
ARG USER=batman
|
||||||
|
ARG USER_UID=1001
|
||||||
|
RUN useradd -m -s /bin/bash -u $USER_UID $USER
|
||||||
|
RUN usermod -aG sudo $USER
|
||||||
|
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
||||||
|
USER $USER
|
||||||
|
|
||||||
|
ENV OPENPILOT_PATH=/home/$USER/openpilot
|
||||||
|
RUN mkdir -p ${OPENPILOT_PATH}
|
||||||
|
WORKDIR ${OPENPILOT_PATH}
|
||||||
|
|
||||||
|
COPY --chown=$USER . ${OPENPILOT_PATH}/
|
||||||
|
|
||||||
|
ENV UV_BIN="/home/$USER/.local/bin/"
|
||||||
|
ENV VIRTUAL_ENV=${OPENPILOT_PATH}/.venv
|
||||||
|
ENV PATH="$UV_BIN:$VIRTUAL_ENV/bin:$PATH"
|
||||||
|
RUN tools/setup_dependencies.sh && \
|
||||||
|
sudo rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
USER root
|
||||||
|
RUN git config --global --add safe.directory '*'
|
||||||
Vendored
+29
-30
@@ -12,7 +12,7 @@ def retryWithDelay(int maxRetries, int delay, Closure body) {
|
|||||||
def device(String ip, String step_label, String cmd) {
|
def device(String ip, String step_label, String cmd) {
|
||||||
withCredentials([file(credentialsId: 'id_rsa', variable: 'key_file')]) {
|
withCredentials([file(credentialsId: 'id_rsa', variable: 'key_file')]) {
|
||||||
def ssh_cmd = """
|
def ssh_cmd = """
|
||||||
ssh -o ControlMaster=auto -o ControlPath=/tmp/ssh_control_%C -o ControlPersist=yes -o ConnectTimeout=5 -o ServerAliveInterval=5 -o ServerAliveCountMax=2 -o BatchMode=yes -o StrictHostKeyChecking=no -i ${key_file} 'comma@${ip}' exec /usr/bin/bash <<'END'
|
ssh -o ConnectTimeout=5 -o ServerAliveInterval=5 -o ServerAliveCountMax=2 -o BatchMode=yes -o StrictHostKeyChecking=no -i ${key_file} 'comma@${ip}' exec /usr/bin/bash <<'END'
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
@@ -63,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
|
||||||
@@ -95,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]
|
||||||
@@ -168,8 +166,8 @@ node {
|
|||||||
env.GIT_BRANCH = checkout(scm).GIT_BRANCH
|
env.GIT_BRANCH = checkout(scm).GIT_BRANCH
|
||||||
env.GIT_COMMIT = checkout(scm).GIT_COMMIT
|
env.GIT_COMMIT = checkout(scm).GIT_COMMIT
|
||||||
|
|
||||||
def excludeBranches = ['__nightly', 'devel', 'devel-staging',
|
def excludeBranches = ['__nightly', 'devel', 'devel-staging', 'release3', 'release3-staging',
|
||||||
'release-tizi', 'release-tizi-staging', 'release-mici', 'release-mici-staging', 'testing-closet*', 'hotfix-*']
|
'release-tici', 'release-tizi', 'release-tizi-staging', 'release-mici-staging', 'testing-closet*', 'hotfix-*']
|
||||||
def excludeRegex = excludeBranches.join('|').replaceAll('\\*', '.*')
|
def excludeRegex = excludeBranches.join('|').replaceAll('\\*', '.*')
|
||||||
|
|
||||||
if (env.BRANCH_NAME != 'master' && !env.BRANCH_NAME.contains('__jenkins_loop_')) {
|
if (env.BRANCH_NAME != 'master' && !env.BRANCH_NAME.contains('__jenkins_loop_')) {
|
||||||
@@ -181,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 $SOURCE_DIR/release/build_release.sh && git push -f origin release-tizi-staging:release-mici-staging"),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,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"),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -204,51 +202,52 @@ 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", "pytest openpilot/selfdrive/test/test_onroad.py -s", [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", "pytest -s openpilot/selfdrive/test//test_power_draw.py"),
|
step("test power draw", "pytest -s system/hardware/tici/tests/test_power_draw.py"),
|
||||||
step("test encoder", "pytest 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", "pytest 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", "pytest openpilot/selfdrive/pandad/tests/test_pandad.py"),
|
step("test pandad", "pytest selfdrive/pandad/tests/test_pandad.py"),
|
||||||
step("test camerad", "pytest 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", "pytest openpilot/selfdrive/pandad/tests/test_pandad.py"),
|
step("test pandad", "pytest selfdrive/pandad/tests/test_pandad.py"),
|
||||||
step("test camerad", "pytest 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", "pytest 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", "pytest openpilot/selfdrive/pandad/tests/test_pandad_loopback.py"),
|
step("test pandad loopback", "pytest selfdrive/pandad/tests/test_pandad_loopback.py"),
|
||||||
step("test pandad spi", "pytest openpilot/selfdrive/pandad/tests/test_pandad_spi.py"),
|
step("test pandad spi", "pytest selfdrive/pandad/tests/test_pandad_spi.py"),
|
||||||
step("test amp", "pytest openpilot/common/hardware/tici/tests/test_amplifier.py"),
|
step("test amp", "pytest system/hardware/tici/tests/test_amplifier.py"),
|
||||||
|
step("test qcomgpsd", "pytest system/qcomgpsd/tests/test_qcomgpsd.py", [diffPaths: ["system/qcomgpsd/"]]),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
+2
-8
@@ -1,13 +1,7 @@
|
|||||||
Version 0.11.2 (2026-06-15)
|
Version 0.11.1 (2026-04-22)
|
||||||
========================
|
|
||||||
|
|
||||||
|
|
||||||
Version 0.11.1 (2026-05-18)
|
|
||||||
========================
|
========================
|
||||||
* New driver monitoring model
|
* New driver monitoring model
|
||||||
* Improved image processing pipeline for driver camera
|
* Improved image processing pipeline for driver camera
|
||||||
* Improved thermal policy for comma four
|
|
||||||
* Acura MDX 2022-24 support thanks to mvl-boston!
|
|
||||||
* Rivian R1S and R1T 2025 support thanks to lukasloetkolben!
|
* Rivian R1S and R1T 2025 support thanks to lukasloetkolben!
|
||||||
|
|
||||||
Version 0.11.0 (2026-03-17)
|
Version 0.11.0 (2026-03-17)
|
||||||
@@ -1104,7 +1098,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
|
||||||
|
|||||||
+55
-132
@@ -10,43 +10,25 @@ import numpy as np
|
|||||||
import SCons.Errors
|
import SCons.Errors
|
||||||
from SCons.Defaults import _stripixes
|
from SCons.Defaults import _stripixes
|
||||||
|
|
||||||
TICI = os.path.isfile('/TICI')
|
|
||||||
|
|
||||||
SCons.Warnings.warningAsException(True)
|
SCons.Warnings.warningAsException(True)
|
||||||
|
|
||||||
Decider('MD5-timestamp')
|
Decider('MD5-timestamp')
|
||||||
|
|
||||||
SetOption('num_jobs', max(1, int(os.cpu_count()/(1 if "CI" in os.environ else 2))))
|
SetOption('num_jobs', max(1, int(os.cpu_count()/2)))
|
||||||
|
|
||||||
AddOption('--ccflags', action='store', type='string', default='', help='pass arbitrary flags over the command line')
|
AddOption('--ccflags', action='store', type='string', default='', help='pass arbitrary flags over the command line')
|
||||||
AddOption('--verbose', action='store_true', default=False, help='show full build commands')
|
AddOption('--verbose', action='store_true', default=False, help='show full build commands')
|
||||||
release = not os.path.exists(File('#.gitattributes').abspath) # file absent on release branch, see release_files.py
|
|
||||||
AddOption('--minimal',
|
AddOption('--minimal',
|
||||||
action='store_false',
|
action='store_false',
|
||||||
dest='extras',
|
dest='extras',
|
||||||
default=(not TICI and not release),
|
default=os.path.exists(File('#.gitattributes').abspath), # minimal by default on release branch (where there's no LFS)
|
||||||
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 TICI:
|
elif arch == "aarch64" and os.path.isfile('/TICI'):
|
||||||
arch = "larch64"
|
arch = "larch64"
|
||||||
assert arch in [
|
assert arch in [
|
||||||
"larch64", # linux tici arm64
|
"larch64", # linux tici arm64
|
||||||
@@ -55,29 +37,8 @@ assert arch in [
|
|||||||
"Darwin", # macOS arm64 (x86 not supported)
|
"Darwin", # macOS arm64 (x86 not supported)
|
||||||
]
|
]
|
||||||
|
|
||||||
pkg_names = ['acados', 'bzip2', 'capnproto', 'catch2', 'eigen', 'ffmpeg', 'json11', 'ncurses', 'zeromq', 'zstd']
|
pkg_names = ['bzip2', 'capnproto', 'eigen', 'ffmpeg', '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')]
|
|
||||||
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
|
|
||||||
# TICI 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_DIR,
|
|
||||||
os.path.join(acados.INCLUDE_DIR, "blasfeo", "include"),
|
|
||||||
os.path.join(acados.INCLUDE_DIR, "hpipm", "include"),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# ***** enforce a whitelist of system libraries *****
|
# ***** enforce a whitelist of system libraries *****
|
||||||
@@ -121,10 +82,10 @@ 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 + ':' + Dir(f"#third_party/acados").abspath,
|
||||||
"ACADOS_SOURCE_DIR": acados.DIR,
|
"ACADOS_SOURCE_DIR": Dir("#third_party/acados").abspath,
|
||||||
"ACADOS_PYTHON_INTERFACE_PATH": acados.TEMPLATE_DIR,
|
"ACADOS_PYTHON_INTERFACE_PATH": Dir("#third_party/acados/acados_template").abspath,
|
||||||
"TERA_PATH": acados.TERA_PATH
|
"TERA_PATH": Dir("#").abspath + f"/third_party/acados/{arch}/t_renderer"
|
||||||
},
|
},
|
||||||
CCFLAGS=[
|
CCFLAGS=[
|
||||||
"-g",
|
"-g",
|
||||||
@@ -142,27 +103,30 @@ env = Environment(
|
|||||||
CFLAGS=["-std=gnu11"],
|
CFLAGS=["-std=gnu11"],
|
||||||
CXXFLAGS=["-std=c++1z"],
|
CXXFLAGS=["-std=c++1z"],
|
||||||
CPPPATH=[
|
CPPPATH=[
|
||||||
"#openpilot",
|
|
||||||
"#msgq_repo", # #include "msgq/..."
|
|
||||||
"#opendbc_repo", # #include "opendbc/..."
|
|
||||||
"#rednose_repo", # #include "rednose/..."
|
|
||||||
"#rednose_repo/rednose", # #include "logger/..." (rednose package root)
|
|
||||||
"#openpilot/cereal/gen/cpp",
|
|
||||||
acados_include_dirs,
|
|
||||||
[x.INCLUDE_DIR for x in pkgs],
|
|
||||||
"#",
|
"#",
|
||||||
|
"#msgq",
|
||||||
|
"#third_party",
|
||||||
|
"#third_party/json11",
|
||||||
|
"#third_party/linux/include",
|
||||||
|
"#third_party/acados/include",
|
||||||
|
"#third_party/acados/include/blasfeo/include",
|
||||||
|
"#third_party/acados/include/hpipm/include",
|
||||||
|
"#third_party/catch2/include",
|
||||||
|
[x.INCLUDE_DIR for x in pkgs],
|
||||||
],
|
],
|
||||||
LIBPATH=[
|
LIBPATH=[
|
||||||
"#openpilot/common",
|
"#common",
|
||||||
"#msgq_repo",
|
"#msgq_repo",
|
||||||
"#openpilot/selfdrive/pandad",
|
"#third_party",
|
||||||
"#rednose_repo/rednose/helpers",
|
"#selfdrive/pandad",
|
||||||
|
"#rednose/helpers",
|
||||||
|
f"#third_party/acados/{arch}/lib",
|
||||||
[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=["#site_scons/site_tools", "#rednose_repo/site_scons/site_tools"],
|
toolpath=["#site_scons/site_tools", "#rednose_repo/site_scons/site_tools"],
|
||||||
)
|
)
|
||||||
@@ -210,6 +174,16 @@ if not GetOption('verbose'):
|
|||||||
):
|
):
|
||||||
env[f"{action}COMSTR"] = f" [{short}] $TARGET"
|
env[f"{action}COMSTR"] = f" [{short}] $TARGET"
|
||||||
|
|
||||||
|
# progress output
|
||||||
|
node_interval = 5
|
||||||
|
node_count = 0
|
||||||
|
def progress_function(node):
|
||||||
|
global node_count
|
||||||
|
node_count += node_interval
|
||||||
|
sys.stderr.write("progress: %d\n" % node_count)
|
||||||
|
if os.environ.get('SCONS_PROGRESS'):
|
||||||
|
Progress(progress_function, interval=node_interval)
|
||||||
|
|
||||||
# ********** Cython build environment **********
|
# ********** Cython build environment **********
|
||||||
envCython = env.Clone()
|
envCython = env.Clone()
|
||||||
envCython["CPPPATH"] += [sysconfig.get_paths()['include'], np.get_include()]
|
envCython["CPPPATH"] += [sysconfig.get_paths()['include'], np.get_include()]
|
||||||
@@ -225,28 +199,18 @@ 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')
|
||||||
|
|
||||||
# Setup cache dir
|
# Setup cache dir
|
||||||
default_cache_dir = '/data/scons_cache' if arch == "larch64" 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
|
|
||||||
CacheDir(cache_dir)
|
CacheDir(cache_dir)
|
||||||
Clean(["."], cache_dir)
|
Clean(["."], cache_dir)
|
||||||
|
|
||||||
def prune_cache_dir(target=None, source=None, env=None):
|
|
||||||
cache_files = sorted((os.path.join(root, f) for root, _, files in os.walk(cache_dir) for f in files), key=os.path.getmtime)
|
|
||||||
cache_size = sum(os.path.getsize(f) for f in cache_files)
|
|
||||||
for f in cache_files:
|
|
||||||
if cache_size < cache_size_limit:
|
|
||||||
break
|
|
||||||
cache_size -= os.path.getsize(f)
|
|
||||||
os.unlink(f)
|
|
||||||
|
|
||||||
# ********** 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')
|
||||||
@@ -257,7 +221,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',]
|
||||||
@@ -268,79 +232,38 @@ 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 == "larch64":
|
if arch == "larch64":
|
||||||
SConscript(['openpilot/system/camerad/SConscript'])
|
SConscript(['system/camerad/SConscript'])
|
||||||
|
|
||||||
|
# Build openpilot
|
||||||
|
SConscript(['third_party/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 tools
|
||||||
if GetOption('extras') and arch != "larch64":
|
if 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',
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
env.CompilationDatabase('compile_commands.json')
|
env.CompilationDatabase('compile_commands.json')
|
||||||
|
|
||||||
# progress output
|
|
||||||
def count_scons_nodes(nodes):
|
|
||||||
seen = set()
|
|
||||||
stack = list(nodes)
|
|
||||||
|
|
||||||
while stack:
|
|
||||||
node = stack.pop().disambiguate()
|
|
||||||
if node in seen:
|
|
||||||
continue
|
|
||||||
seen.add(node)
|
|
||||||
if hasattr(node, 'has_builder') and node.has_builder():
|
|
||||||
build_product_nodes.add(node)
|
|
||||||
executor = node.get_executor()
|
|
||||||
if executor is not None:
|
|
||||||
stack += executor.get_all_prerequisites() + executor.get_all_children()
|
|
||||||
|
|
||||||
return len(seen)
|
|
||||||
|
|
||||||
progress_interval = 5
|
|
||||||
progress_count = 0
|
|
||||||
build_product_nodes = set()
|
|
||||||
progress_total = max(1, count_scons_nodes(env.arg2nodes(BUILD_TARGETS or [Dir('.')], env.fs.Entry)))
|
|
||||||
|
|
||||||
def progress_function(node):
|
|
||||||
global progress_count
|
|
||||||
if progress_count >= progress_total:
|
|
||||||
return
|
|
||||||
progress_count = min(progress_count + progress_interval, progress_total)
|
|
||||||
progress = round(100. * progress_count / progress_total, 1)
|
|
||||||
sys.stderr.write("\rBuilding: %5.1f%%" % progress if sys.stderr.isatty() else "progress: %.1f\n" % progress)
|
|
||||||
if progress == 100. and sys.stderr.isatty():
|
|
||||||
sys.stderr.write("\n")
|
|
||||||
sys.stderr.flush()
|
|
||||||
|
|
||||||
Progress(progress_function, interval=progress_interval)
|
|
||||||
AddPostAction(BUILD_TARGETS or [Dir('.')], prune_cache_dir)
|
|
||||||
|
|
||||||
def check_build_product_size(target, source, env):
|
|
||||||
limit = 50 * 1024 * 1024 # GitHub max size
|
|
||||||
for t in target:
|
|
||||||
if hasattr(t, 'isfile') and t.isfile() and (size := os.path.getsize(t.abspath)) > limit:
|
|
||||||
raise SCons.Errors.UserError(f"{t} is {size / (1024 * 1024):.1f} MiB, exceeding the {limit / (1024 * 1024):.1f} MiB limit")
|
|
||||||
if not GetOption('extras'):
|
|
||||||
AddPostAction(list(build_product_nodes), Action(check_build_product_size, None))
|
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -194,6 +194,13 @@ struct LongitudinalPlanSP @0xf35cc4560bbf6ec2 {
|
|||||||
aTarget @5 :Float32;
|
aTarget @5 :Float32;
|
||||||
events @6 :List(OnroadEventSP.Event);
|
events @6 :List(OnroadEventSP.Event);
|
||||||
e2eAlerts @7 :E2eAlerts;
|
e2eAlerts @7 :E2eAlerts;
|
||||||
|
accelPersonality @8 :AccelerationPersonality;
|
||||||
|
|
||||||
|
enum AccelerationPersonality {
|
||||||
|
sport @0;
|
||||||
|
normal @1;
|
||||||
|
eco @2;
|
||||||
|
}
|
||||||
|
|
||||||
struct DynamicExperimentalControl {
|
struct DynamicExperimentalControl {
|
||||||
state @0 :DynamicExperimentalControlState;
|
state @0 :DynamicExperimentalControlState;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using Cxx = import "/include/c++.capnp";
|
using Cxx = import "./include/c++.capnp";
|
||||||
$Cxx.namespace("cereal");
|
$Cxx.namespace("cereal");
|
||||||
|
|
||||||
@0x80ef1ec4889c2a63;
|
@0x80ef1ec4889c2a63;
|
||||||
@@ -760,6 +760,18 @@ struct LateralLQRState @0x9024e2d790c82ade {
|
|||||||
steeringAngleDesiredDeg @6 :Float32;
|
steeringAngleDesiredDeg @6 :Float32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct LateralCurvatureState @0xad9d8095c06f7c61 {
|
||||||
|
active @0 :Bool;
|
||||||
|
actualCurvature @1 :Float32;
|
||||||
|
desiredCurvature @2 :Float32;
|
||||||
|
error @3 :Float32;
|
||||||
|
p @4 :Float32;
|
||||||
|
i @5 :Float32;
|
||||||
|
f @6 :Float32;
|
||||||
|
output @7 :Float32;
|
||||||
|
saturated @8 :Bool;
|
||||||
|
}
|
||||||
|
|
||||||
struct LateralPlannerSolution @0x84caeca5a6b4acfe {
|
struct LateralPlannerSolution @0x84caeca5a6b4acfe {
|
||||||
x @0 :List(Float32);
|
x @0 :List(Float32);
|
||||||
y @1 :List(Float32);
|
y @1 :List(Float32);
|
||||||
@@ -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";
|
||||||
|
|
||||||
@@ -273,7 +273,11 @@ struct GPSNMEAData {
|
|||||||
nmea @2 :Text;
|
nmea @2 :Text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# android sensor_event_t
|
||||||
struct SensorEventData {
|
struct SensorEventData {
|
||||||
|
version @0 :Int32;
|
||||||
|
sensor @1 :Int32;
|
||||||
|
type @2 :Int32;
|
||||||
timestamp @3 :Int64;
|
timestamp @3 :Int64;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
@@ -292,10 +296,7 @@ struct SensorEventData {
|
|||||||
|
|
||||||
struct SensorVec {
|
struct SensorVec {
|
||||||
v @0 :List(Float32);
|
v @0 :List(Float32);
|
||||||
|
status @1 :Int8;
|
||||||
deprecated :group {
|
|
||||||
status @1 :Int8;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SensorSource {
|
enum SensorSource {
|
||||||
@@ -313,11 +314,7 @@ struct SensorEventData {
|
|||||||
mmc5603nj @11;
|
mmc5603nj @11;
|
||||||
}
|
}
|
||||||
|
|
||||||
# formerly based on android sensor_event_t
|
|
||||||
deprecated :group {
|
deprecated :group {
|
||||||
version @0 :Int32;
|
|
||||||
sensor @1 :Int32;
|
|
||||||
type @2 :Int32;
|
|
||||||
uncalibrated @10 :Bool;
|
uncalibrated @10 :Bool;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -414,10 +411,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;
|
||||||
@@ -464,10 +457,10 @@ struct DeviceState @0xa4d8b5af2aa492eb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum ThermalStatus {
|
enum ThermalStatus {
|
||||||
ok @0;
|
green @0;
|
||||||
warmDEPRECATED @1;
|
yellow @1;
|
||||||
overheated @2;
|
red @2;
|
||||||
critical @3;
|
danger @3;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum NetworkType {
|
enum NetworkType {
|
||||||
@@ -688,47 +681,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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -741,7 +720,6 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -790,30 +768,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;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum OpenpilotState @0xdbe58b96d2d1ac61 {
|
enum OpenpilotState @0xdbe58b96d2d1ac61 {
|
||||||
disabled @0;
|
disabled @0;
|
||||||
preEnabled @1;
|
preEnabled @1;
|
||||||
@@ -834,10 +795,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 {
|
||||||
@@ -858,7 +815,7 @@ struct ControlsState @0x97ff69c53601abf1 {
|
|||||||
debugState @59 :LateralDebugState;
|
debugState @59 :LateralDebugState;
|
||||||
torqueState @60 :LateralTorqueState;
|
torqueState @60 :LateralTorqueState;
|
||||||
|
|
||||||
curvatureState @65 :LateralCurvatureState;
|
curvatureStateDEPRECATED @65 :Deprecated.LateralCurvatureState;
|
||||||
lqrStateDEPRECATED @55 :Deprecated.LateralLQRState;
|
lqrStateDEPRECATED @55 :Deprecated.LateralLQRState;
|
||||||
indiStateDEPRECATED @52 :Deprecated.LateralINDIState;
|
indiStateDEPRECATED @52 :Deprecated.LateralINDIState;
|
||||||
}
|
}
|
||||||
@@ -907,18 +864,6 @@ struct ControlsState @0x97ff69c53601abf1 {
|
|||||||
saturated @3 :Bool;
|
saturated @3 :Bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LateralCurvatureState @0xad9d8095c06f7c61 {
|
|
||||||
active @0 :Bool;
|
|
||||||
actualCurvature @1 :Float32;
|
|
||||||
desiredCurvature @2 :Float32;
|
|
||||||
error @3 :Float32;
|
|
||||||
p @4 :Float32;
|
|
||||||
i @5 :Float32;
|
|
||||||
f @6 :Float32;
|
|
||||||
output @7 :Float32;
|
|
||||||
saturated @8 :Bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated :group {
|
deprecated :group {
|
||||||
vEgo @0 :Float32;
|
vEgo @0 :Float32;
|
||||||
vEgoRaw @32 :Float32;
|
vEgoRaw @32 :Float32;
|
||||||
@@ -958,7 +903,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;
|
||||||
@@ -1041,6 +986,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;
|
||||||
@@ -1050,9 +996,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;
|
||||||
|
|
||||||
@@ -1172,7 +1117,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;
|
||||||
@@ -1310,7 +1255,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;
|
||||||
@@ -1367,7 +1312,7 @@ struct LiveLocationKalman {
|
|||||||
|
|
||||||
struct LivePose {
|
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;
|
||||||
@@ -2115,7 +2060,6 @@ struct DriverStateV2 {
|
|||||||
rightBlinkProb @8 :Float32;
|
rightBlinkProb @8 :Float32;
|
||||||
sunglassesProb @9 :Float32;
|
sunglassesProb @9 :Float32;
|
||||||
phoneProb @13 :Float32;
|
phoneProb @13 :Float32;
|
||||||
sleepProb @14 :Float32;
|
|
||||||
|
|
||||||
deprecated :group {
|
deprecated :group {
|
||||||
notReadyProb @12 :List(Float32);
|
notReadyProb @12 :List(Float32);
|
||||||
@@ -2130,7 +2074,7 @@ struct DriverStateV2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DriverMonitoringStateDEPRECATED @0xb83cda094a1da284 {
|
struct DriverMonitoringState @0xb83cda094a1da284 {
|
||||||
events @18 :List(OnroadEvent);
|
events @18 :List(OnroadEvent);
|
||||||
faceDetected @1 :Bool;
|
faceDetected @1 :Bool;
|
||||||
isDistracted @2 :Bool;
|
isDistracted @2 :Bool;
|
||||||
@@ -2158,82 +2102,6 @@ struct DriverMonitoringStateDEPRECATED @0xb83cda094a1da284 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DriverMonitoringState {
|
|
||||||
lockout @0 :Bool;
|
|
||||||
lockoutRecoveryPercent @11 :Int8;
|
|
||||||
alert3Count @12 :Int8;
|
|
||||||
noResponseCount @13 :Int8;
|
|
||||||
noResponseForceDecel @14 :Bool;
|
|
||||||
|
|
||||||
alwaysOn @3 :Bool;
|
|
||||||
alwaysOnLockout @4 :Bool;
|
|
||||||
|
|
||||||
alertLevel @5 :AlertLevel;
|
|
||||||
activePolicy @6 :MonitoringPolicy;
|
|
||||||
isRHD @7 :Bool;
|
|
||||||
rhdCalibration @8 :CalibrationState;
|
|
||||||
|
|
||||||
visionPolicyState @9 :VisionPolicyState;
|
|
||||||
wheeltouchPolicyState @10 :WheeltouchPolicyState;
|
|
||||||
|
|
||||||
enum AlertLevel {
|
|
||||||
# ordinal must match the name to prevent bugs
|
|
||||||
# comparing against the raw ordinal value
|
|
||||||
none @0;
|
|
||||||
one @1;
|
|
||||||
two @2;
|
|
||||||
three @3;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum MonitoringPolicy {
|
|
||||||
wheeltouch @0;
|
|
||||||
vision @1;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VisionPolicyState {
|
|
||||||
awarenessPercent @0 :Int8;
|
|
||||||
awarenessStep @1 :Float32;
|
|
||||||
isDistracted @2 :Bool;
|
|
||||||
distractedTypes @3 :DistractedTypes;
|
|
||||||
|
|
||||||
faceDetected @4 :Bool;
|
|
||||||
pose @5 :Pose;
|
|
||||||
wheeltouchFallbackPercent @6 :Int8;
|
|
||||||
uncertainOffroadAlertPercent @7 :Int8;
|
|
||||||
|
|
||||||
struct DistractedTypes {
|
|
||||||
pose @0: Bool;
|
|
||||||
eye @1: Bool;
|
|
||||||
phone @2: Bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Pose {
|
|
||||||
pitch @0 :Float32;
|
|
||||||
yaw @1 :Float32;
|
|
||||||
pitchCalib @2 :CalibrationState;
|
|
||||||
yawCalib @3 :CalibrationState;
|
|
||||||
calibrated @4 :Bool;
|
|
||||||
uncertainty @5 :Float32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct WheeltouchPolicyState {
|
|
||||||
awarenessPercent @0 :Int8;
|
|
||||||
awarenessStep @1 :Float32;
|
|
||||||
driverInteracting @2 :Bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CalibrationState {
|
|
||||||
calibratedPercent @0 :Int8;
|
|
||||||
offset @1 :Float32;
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated :group {
|
|
||||||
alertCountLockoutPercent @1 :Int8;
|
|
||||||
alertTimeLockoutPercent @2 :Int8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Boot {
|
struct Boot {
|
||||||
wallTimeNanos @0 :UInt64;
|
wallTimeNanos @0 :UInt64;
|
||||||
pstore @4 :Map(Text, Data);
|
pstore @4 :Map(Text, Data);
|
||||||
@@ -2306,7 +2174,6 @@ struct LiveDelayData {
|
|||||||
lateralDelayEstimateStd @5 :Float32;
|
lateralDelayEstimateStd @5 :Float32;
|
||||||
points @4 :List(Float32);
|
points @4 :List(Float32);
|
||||||
calPerc @6 :Int8;
|
calPerc @6 :Int8;
|
||||||
version @7 :Int32;
|
|
||||||
|
|
||||||
enum Status {
|
enum Status {
|
||||||
unestimated @0;
|
unestimated @0;
|
||||||
@@ -2360,8 +2227,7 @@ struct Sentinel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct UIDebug {
|
struct UIDebug {
|
||||||
cpuTimeMillis @0 :Float32;
|
drawTimeMillis @0 :Float32;
|
||||||
frameTimeMillis @1 :Float32;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ManagerState {
|
struct ManagerState {
|
||||||
@@ -2509,6 +2375,7 @@ struct Event {
|
|||||||
boot @60 :Boot;
|
boot @60 :Boot;
|
||||||
|
|
||||||
# ********** openpilot daemon msgs **********
|
# ********** openpilot daemon msgs **********
|
||||||
|
gpsNMEA @3 :GPSNMEAData;
|
||||||
can @5 :List(CanData);
|
can @5 :List(CanData);
|
||||||
controlsState @7 :ControlsState;
|
controlsState @7 :ControlsState;
|
||||||
selfdriveState @130 :SelfdriveState;
|
selfdriveState @130 :SelfdriveState;
|
||||||
@@ -2533,6 +2400,7 @@ struct Event {
|
|||||||
qcomGnss @31 :QcomGnss;
|
qcomGnss @31 :QcomGnss;
|
||||||
gpsLocationExternal @48 :GpsLocationData;
|
gpsLocationExternal @48 :GpsLocationData;
|
||||||
gpsLocation @21 :GpsLocationData;
|
gpsLocation @21 :GpsLocationData;
|
||||||
|
gnssMeasurements @91 :GnssMeasurements;
|
||||||
liveParameters @61 :LiveParametersData;
|
liveParameters @61 :LiveParametersData;
|
||||||
liveTorqueParameters @94 :LiveTorqueParametersData;
|
liveTorqueParameters @94 :LiveTorqueParametersData;
|
||||||
liveDelay @146 : LiveDelayData;
|
liveDelay @146 : LiveDelayData;
|
||||||
@@ -2540,7 +2408,7 @@ struct Event {
|
|||||||
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 @71: DriverMonitoringState;
|
||||||
livePose @129 :LivePose;
|
livePose @129 :LivePose;
|
||||||
modelV2 @75 :ModelDataV2;
|
modelV2 @75 :ModelDataV2;
|
||||||
drivingModelData @128 :DrivingModelData;
|
drivingModelData @128 :DrivingModelData;
|
||||||
@@ -2564,8 +2432,9 @@ struct Event {
|
|||||||
rawAudioData @147 :AudioData;
|
rawAudioData @147 :AudioData;
|
||||||
|
|
||||||
# systems stuff
|
# systems stuff
|
||||||
operatingSystemLog @20 :OperatingSystemLogEntry;
|
androidLog @20 :AndroidLogEntry;
|
||||||
managerState @78 :ManagerState;
|
managerState @78 :ManagerState;
|
||||||
|
uploaderState @79 :UploaderState;
|
||||||
procLog @33 :ProcLog;
|
procLog @33 :ProcLog;
|
||||||
clocks @35 :Clocks;
|
clocks @35 :Clocks;
|
||||||
deviceState @6 :DeviceState;
|
deviceState @6 :DeviceState;
|
||||||
@@ -2575,6 +2444,12 @@ struct Event {
|
|||||||
# touch frame
|
# touch frame
|
||||||
touch @135 :List(Touch);
|
touch @135 :List(Touch);
|
||||||
|
|
||||||
|
# navigation
|
||||||
|
navInstruction @82 :NavInstruction;
|
||||||
|
navRoute @83 :NavRoute;
|
||||||
|
navThumbnail @84: Thumbnail;
|
||||||
|
mapRenderState @105: MapRenderState;
|
||||||
|
|
||||||
# UI services
|
# UI services
|
||||||
uiDebug @102 :UIDebug;
|
uiDebug @102 :UIDebug;
|
||||||
|
|
||||||
@@ -2676,13 +2551,5 @@ struct Event {
|
|||||||
gyroscope2DEPRECATED @100 :SensorEventData;
|
gyroscope2DEPRECATED @100 :SensorEventData;
|
||||||
accelerometer2DEPRECATED @101 :SensorEventData;
|
accelerometer2DEPRECATED @101 :SensorEventData;
|
||||||
temperatureSensor2DEPRECATED @123 :SensorEventData;
|
temperatureSensor2DEPRECATED @123 :SensorEventData;
|
||||||
driverMonitoringStateDEPRECATED @71 :DriverMonitoringStateDEPRECATED;
|
|
||||||
gpsNMEADEPRECATED @3 :GPSNMEAData;
|
|
||||||
uploaderStateDEPRECATED @79 :UploaderState;
|
|
||||||
navInstructionDEPRECATED @82 :NavInstruction;
|
|
||||||
navRouteDEPRECATED @83 :NavRoute;
|
|
||||||
navThumbnailDEPRECATED @84 :Thumbnail;
|
|
||||||
gnssMeasurementsDEPRECATED @91 :GnssMeasurements;
|
|
||||||
mapRenderStateDEPRECATED @105: MapRenderState;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,8 +9,8 @@ import time
|
|||||||
|
|
||||||
from typing import Optional, List, Union, Dict
|
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
|
||||||
|
|
||||||
NO_TRAVERSAL_LIMIT = 2**64-1
|
NO_TRAVERSAL_LIMIT = 2**64-1
|
||||||
@@ -259,11 +259,11 @@ class PubMaster:
|
|||||||
self.sock[s].send(dat)
|
self.sock[s].send(dat)
|
||||||
|
|
||||||
def wait_for_readers_to_update(self, s: str, timeout: int, dt: float = 0.05) -> bool:
|
def wait_for_readers_to_update(self, s: str, timeout: int, dt: float = 0.05) -> bool:
|
||||||
try:
|
for _ in range(int(timeout*(1./dt))):
|
||||||
self.sock[s].wait_for_readers(timeout=timeout, interval=dt)
|
if self.sock[s].all_readers_updated():
|
||||||
return True
|
return True
|
||||||
except TimeoutError:
|
time.sleep(dt)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def all_readers_updated(self, s: str) -> bool:
|
def all_readers_updated(self, s: str) -> bool:
|
||||||
return self.sock[s].all_readers_updated()
|
return self.sock[s].all_readers_updated() # type: ignore
|
||||||
@@ -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");
|
||||||
|
|
||||||
+4
-5
@@ -8,10 +8,9 @@ import time
|
|||||||
from openpilot.common.parameterized import parameterized
|
from openpilot.common.parameterized import parameterized
|
||||||
import pytest
|
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()]
|
||||||
|
|
||||||
@@ -31,7 +30,7 @@ def zmq_sleep(t=1):
|
|||||||
|
|
||||||
# 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():
|
||||||
fields = ["vEgo", "aEgo", "steeringTorque", "steeringAngleDeg"]
|
fields = ["vEgo", "aEgo", "brake", "steeringAngleDeg"]
|
||||||
msg = messaging.new_message("carState")
|
msg = messaging.new_message("carState")
|
||||||
cs = msg.carState
|
cs = msg.carState
|
||||||
for f in fields:
|
for f in fields:
|
||||||
+3
-3
@@ -2,11 +2,11 @@ import random
|
|||||||
import time
|
import time
|
||||||
from typing import Sized, cast
|
from typing import Sized, cast
|
||||||
|
|
||||||
import openpilot.cereal.messaging as messaging
|
import cereal.messaging as messaging
|
||||||
from openpilot.cereal.messaging.tests.test_messaging import events, random_sock, random_socks, \
|
from 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
|
zmq_sleep
|
||||||
from openpilot.cereal.services import SERVICE_LIST
|
from cereal.services import SERVICE_LIST
|
||||||
|
|
||||||
|
|
||||||
class TestSubMaster:
|
class TestSubMaster:
|
||||||
+5
-5
@@ -1,10 +1,10 @@
|
|||||||
import subprocess
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
|
from typing import Dict
|
||||||
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:
|
class TestServices:
|
||||||
@@ -17,5 +17,5 @@ class TestServices:
|
|||||||
|
|
||||||
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"
|
||||||
+256
@@ -0,0 +1,256 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Schema-level cereal compat check between sunnypilot and upstream openpilot.
|
||||||
|
|
||||||
|
Rules (per struct matched across sides by typeId):
|
||||||
|
R1 shared ordinal must reference the same type.
|
||||||
|
R2 sunnypilot-only ordinal in a union -> FAIL (unknown discriminant upstream).
|
||||||
|
R3 sunnypilot-only ordinal on a regular field -> OK (additive struct evolution).
|
||||||
|
R4 upstream-only ordinal -> OK.
|
||||||
|
R5 sunnypilot-only struct referenced via an upstream-shared field -> FAIL.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
NO_DISCRIMINANT = 0xFFFF
|
||||||
|
|
||||||
|
|
||||||
|
def hex_id(value: int) -> str:
|
||||||
|
return f"0x{value:016x}"
|
||||||
|
|
||||||
|
|
||||||
|
def encode_type(type_node: Any) -> dict:
|
||||||
|
which = type_node.which()
|
||||||
|
if which == "struct":
|
||||||
|
return {"kind": "struct", "typeId": hex_id(type_node.struct.typeId)}
|
||||||
|
if which == "enum":
|
||||||
|
return {"kind": "enum", "typeId": hex_id(type_node.enum.typeId)}
|
||||||
|
if which == "interface":
|
||||||
|
return {"kind": "interface", "typeId": hex_id(type_node.interface.typeId)}
|
||||||
|
if which == "list":
|
||||||
|
return {"kind": "list", "element": encode_type(type_node.list.elementType)}
|
||||||
|
if which == "anyPointer":
|
||||||
|
return {"kind": "anyPointer"}
|
||||||
|
return {"kind": which}
|
||||||
|
|
||||||
|
|
||||||
|
def encode_field(name: str, field: Any) -> dict:
|
||||||
|
proto = field.proto
|
||||||
|
ordinal = proto.ordinal.explicit if proto.ordinal.which() == "explicit" else None
|
||||||
|
discriminant = proto.discriminantValue if proto.discriminantValue != NO_DISCRIMINANT else None
|
||||||
|
|
||||||
|
if proto.which() == "group":
|
||||||
|
type_desc = {"kind": "group", "typeId": hex_id(proto.group.typeId)}
|
||||||
|
else:
|
||||||
|
type_desc = encode_type(proto.slot.type)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"name": name,
|
||||||
|
"ordinal": ordinal,
|
||||||
|
"discriminant": discriminant,
|
||||||
|
"type": type_desc,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def encode_struct(schema: Any) -> dict:
|
||||||
|
node = schema.node
|
||||||
|
return {
|
||||||
|
"typeId": hex_id(node.id),
|
||||||
|
"displayName": node.displayName,
|
||||||
|
"hasUnion": node.struct.discriminantCount > 0,
|
||||||
|
"fields": [encode_field(name, field) for name, field in schema.fields.items()],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _child_struct_schema(field: Any) -> Any:
|
||||||
|
proto = field.proto
|
||||||
|
if proto.which() == "group":
|
||||||
|
return field.schema
|
||||||
|
type_node = proto.slot.type
|
||||||
|
which = type_node.which()
|
||||||
|
if which == "struct":
|
||||||
|
return field.schema
|
||||||
|
if which == "list":
|
||||||
|
container = field.schema
|
||||||
|
element_type = type_node.list.elementType
|
||||||
|
while element_type.which() == "list":
|
||||||
|
container = container.elementType
|
||||||
|
element_type = element_type.list.elementType
|
||||||
|
if element_type.which() == "struct":
|
||||||
|
return container.elementType
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def collect_schema(root: Any) -> dict[str, dict]:
|
||||||
|
structs: dict[str, dict] = {}
|
||||||
|
stack = [root]
|
||||||
|
while stack:
|
||||||
|
schema = stack.pop()
|
||||||
|
type_id = hex_id(schema.node.id)
|
||||||
|
if type_id in structs:
|
||||||
|
continue
|
||||||
|
structs[type_id] = encode_struct(schema)
|
||||||
|
for _name, field in schema.fields.items():
|
||||||
|
try:
|
||||||
|
child = _child_struct_schema(field)
|
||||||
|
except Exception:
|
||||||
|
child = None
|
||||||
|
if child is not None:
|
||||||
|
stack.append(child)
|
||||||
|
return structs
|
||||||
|
|
||||||
|
|
||||||
|
def load_log(cereal_dir: str) -> Any:
|
||||||
|
import capnp
|
||||||
|
cereal_dir = os.path.abspath(cereal_dir)
|
||||||
|
capnp.remove_import_hook()
|
||||||
|
return capnp.load(os.path.join(cereal_dir, "log.capnp"), imports=[cereal_dir])
|
||||||
|
|
||||||
|
|
||||||
|
def dump_schema(cereal_dir: str, path: str) -> None:
|
||||||
|
log = load_log(cereal_dir)
|
||||||
|
payload = {
|
||||||
|
"root": hex_id(log.Event.schema.node.id),
|
||||||
|
"structs": collect_schema(log.Event.schema),
|
||||||
|
}
|
||||||
|
with open(path, "w", encoding="utf-8") as handle:
|
||||||
|
json.dump(payload, handle, indent=2, sort_keys=True)
|
||||||
|
print(f"wrote schema dump with {len(payload['structs'])} structs to {path}")
|
||||||
|
|
||||||
|
|
||||||
|
def types_equal(a: dict, b: dict) -> bool:
|
||||||
|
if a.get("kind") != b.get("kind"):
|
||||||
|
return False
|
||||||
|
kind = a["kind"]
|
||||||
|
if kind in ("struct", "enum", "interface", "group"):
|
||||||
|
return a.get("typeId") == b.get("typeId")
|
||||||
|
if kind == "list":
|
||||||
|
return types_equal(a["element"], b["element"])
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def type_repr(t: dict) -> str:
|
||||||
|
kind = t.get("kind", "?")
|
||||||
|
if kind in ("struct", "enum", "interface", "group"):
|
||||||
|
return f"{kind}({t.get('typeId')})"
|
||||||
|
if kind == "list":
|
||||||
|
return f"list<{type_repr(t['element'])}>"
|
||||||
|
return kind
|
||||||
|
|
||||||
|
|
||||||
|
def field_is_union_variant(field: dict) -> bool:
|
||||||
|
return field.get("discriminant") is not None
|
||||||
|
|
||||||
|
|
||||||
|
def index_fields_by_ordinal(struct: dict) -> dict[int, dict]:
|
||||||
|
indexed: dict[int, dict] = {}
|
||||||
|
for field in struct["fields"]:
|
||||||
|
ordinal = field.get("ordinal")
|
||||||
|
if ordinal is None:
|
||||||
|
continue
|
||||||
|
indexed[ordinal] = field
|
||||||
|
return indexed
|
||||||
|
|
||||||
|
|
||||||
|
def compare(sunnypilot_dump: dict, upstream_dump: dict) -> list[str]:
|
||||||
|
violations: list[str] = []
|
||||||
|
sunnypilot_structs: dict[str, dict] = sunnypilot_dump["structs"]
|
||||||
|
upstream_structs: dict[str, dict] = upstream_dump["structs"]
|
||||||
|
|
||||||
|
sunnypilot_struct_referenced_from_shared: set[str] = set()
|
||||||
|
|
||||||
|
for type_id, sunnypilot_struct in sunnypilot_structs.items():
|
||||||
|
upstream_struct = upstream_structs.get(type_id)
|
||||||
|
if upstream_struct is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
sunnypilot_fields = index_fields_by_ordinal(sunnypilot_struct)
|
||||||
|
upstream_fields = index_fields_by_ordinal(upstream_struct)
|
||||||
|
display = sunnypilot_struct["displayName"]
|
||||||
|
|
||||||
|
for ordinal, sunnypilot_field in sunnypilot_fields.items():
|
||||||
|
upstream_field = upstream_fields.get(ordinal)
|
||||||
|
if upstream_field is None:
|
||||||
|
if field_is_union_variant(sunnypilot_field):
|
||||||
|
violations.append(
|
||||||
|
f"[R2] {display} @{ordinal} ('{sunnypilot_field['name']}', {type_repr(sunnypilot_field['type'])}): "
|
||||||
|
f"union variant not present upstream. upstream cannot parse this discriminant."
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not types_equal(sunnypilot_field["type"], upstream_field["type"]):
|
||||||
|
violations.append(
|
||||||
|
f"[R1] {display} @{ordinal}: type mismatch. "
|
||||||
|
f"sunnypilot='{sunnypilot_field['name']}' {type_repr(sunnypilot_field['type'])} vs "
|
||||||
|
f"upstream='{upstream_field['name']}' {type_repr(upstream_field['type'])}."
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
cursor = sunnypilot_field["type"]
|
||||||
|
while cursor.get("kind") == "list":
|
||||||
|
cursor = cursor["element"]
|
||||||
|
if cursor.get("kind") in ("struct", "group", "interface") and cursor.get("typeId"):
|
||||||
|
sunnypilot_struct_referenced_from_shared.add(cursor["typeId"])
|
||||||
|
|
||||||
|
for type_id, sunnypilot_struct in sunnypilot_structs.items():
|
||||||
|
if type_id in upstream_structs:
|
||||||
|
continue
|
||||||
|
if type_id in sunnypilot_struct_referenced_from_shared:
|
||||||
|
violations.append(
|
||||||
|
f"[R5] struct {sunnypilot_struct['displayName']} ({type_id}) exists only on sunnypilot "
|
||||||
|
f"but is referenced from an upstream-shared field. upstream cannot resolve this type."
|
||||||
|
)
|
||||||
|
|
||||||
|
return violations
|
||||||
|
|
||||||
|
|
||||||
|
def load_peer(path: str) -> dict:
|
||||||
|
with open(path, "r", encoding="utf-8") as handle:
|
||||||
|
return json.load(handle)
|
||||||
|
|
||||||
|
|
||||||
|
def run_read(cereal_dir: str, peer_path: str) -> int:
|
||||||
|
log = load_log(cereal_dir)
|
||||||
|
peer_dump = load_peer(peer_path)
|
||||||
|
local_dump = {
|
||||||
|
"root": hex_id(log.Event.schema.node.id),
|
||||||
|
"structs": collect_schema(log.Event.schema),
|
||||||
|
}
|
||||||
|
violations = compare(sunnypilot_dump=peer_dump, upstream_dump=local_dump)
|
||||||
|
|
||||||
|
if not violations:
|
||||||
|
print("cereal compat OK: upstream openpilot can parse sunnypilot routes "
|
||||||
|
"(no leaked structs, no ordinal collisions).")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
print(f"cereal compat FAIL: upstream openpilot would misparse sunnypilot routes "
|
||||||
|
f"({len(violations)} violation(s)):")
|
||||||
|
for v in violations:
|
||||||
|
print(f" {v}")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="sunnypilot <-> upstream cereal compatibility validator (schema-level)."
|
||||||
|
)
|
||||||
|
mode = parser.add_mutually_exclusive_group(required=True)
|
||||||
|
mode.add_argument("-g", "--generate", action="store_true", help="dump local schema to JSON")
|
||||||
|
mode.add_argument("-r", "--read", action="store_true", help="load peer JSON and diff against local")
|
||||||
|
parser.add_argument("-f", "--file", default="schema.json", help="JSON file path (default: schema.json)")
|
||||||
|
parser.add_argument("--cereal-dir", required=True, help="path to cereal directory containing log.capnp")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.generate:
|
||||||
|
dump_schema(args.cereal_dir, args.file)
|
||||||
|
return 0
|
||||||
|
return run_read(args.cereal_dir, args.file)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
@@ -24,7 +24,10 @@ _services: dict[str, tuple] = {
|
|||||||
# note: the "EncodeIdx" packets will still be in the log
|
# note: the "EncodeIdx" packets will still be in the log
|
||||||
"gyroscope": (True, 104., 104),
|
"gyroscope": (True, 104., 104),
|
||||||
"accelerometer": (True, 104., 104),
|
"accelerometer": (True, 104., 104),
|
||||||
|
"magnetometer": (True, 25.),
|
||||||
|
"lightSensor": (True, 100., 100),
|
||||||
"temperatureSensor": (True, 2., 200),
|
"temperatureSensor": (True, 2., 200),
|
||||||
|
"gpsNMEA": (True, 9.),
|
||||||
"deviceState": (True, 2., 1),
|
"deviceState": (True, 2., 1),
|
||||||
"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
|
||||||
@@ -41,7 +44,7 @@ _services: dict[str, tuple] = {
|
|||||||
"liveCalibration": (True, 4., 4),
|
"liveCalibration": (True, 4., 4),
|
||||||
"liveTorqueParameters": (True, 4., 1),
|
"liveTorqueParameters": (True, 4., 1),
|
||||||
"liveDelay": (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),
|
||||||
@@ -53,6 +56,7 @@ _services: dict[str, tuple] = {
|
|||||||
"gpsLocation": (True, 1., 1),
|
"gpsLocation": (True, 1., 1),
|
||||||
"ubloxGnss": (True, 10.),
|
"ubloxGnss": (True, 10.),
|
||||||
"qcomGnss": (True, 2.),
|
"qcomGnss": (True, 2.),
|
||||||
|
"gnssMeasurements": (True, 10., 10),
|
||||||
"clocks": (True, 0.1, 1),
|
"clocks": (True, 0.1, 1),
|
||||||
"ubloxRaw": (True, 20.),
|
"ubloxRaw": (True, 20.),
|
||||||
"livePose": (True, 20., 4),
|
"livePose": (True, 20., 4),
|
||||||
@@ -71,6 +75,10 @@ _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),
|
||||||
|
"uploaderState": (True, 0., 1),
|
||||||
|
"navInstruction": (True, 1., 10),
|
||||||
|
"navRoute": (True, 0.),
|
||||||
|
"navThumbnail": (True, 0.),
|
||||||
"qRoadEncodeIdx": (False, 20.),
|
"qRoadEncodeIdx": (False, 20.),
|
||||||
"userBookmark": (True, 0., 1),
|
"userBookmark": (True, 0., 1),
|
||||||
"soundPressure": (True, 10., 10),
|
"soundPressure": (True, 10., 10),
|
||||||
@@ -106,6 +114,8 @@ _services: dict[str, tuple] = {
|
|||||||
"livestreamRoadEncodeData": (False, 20., None, QueueSize.MEDIUM),
|
"livestreamRoadEncodeData": (False, 20., None, QueueSize.MEDIUM),
|
||||||
"livestreamDriverEncodeData": (False, 20., None, QueueSize.MEDIUM),
|
"livestreamDriverEncodeData": (False, 20., None, QueueSize.MEDIUM),
|
||||||
"customReservedRawData0": (True, 0.),
|
"customReservedRawData0": (True, 0.),
|
||||||
|
"customReservedRawData1": (True, 0.),
|
||||||
|
"customReservedRawData2": (True, 0.),
|
||||||
}
|
}
|
||||||
SERVICE_LIST = {name: Service(*vals) for
|
SERVICE_LIST = {name: Service(*vals) for
|
||||||
idx, (name, vals) in enumerate(_services.items())}
|
idx, (name, vals) in enumerate(_services.items())}
|
||||||
@@ -5,7 +5,6 @@ common_libs = [
|
|||||||
'swaglog.cc',
|
'swaglog.cc',
|
||||||
'util.cc',
|
'util.cc',
|
||||||
'ratekeeper.cc',
|
'ratekeeper.cc',
|
||||||
'yuv.cc',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
_common = env.Library('common', common_libs, LIBS="json11")
|
_common = env.Library('common', common_libs, LIBS="json11")
|
||||||
@@ -13,7 +12,7 @@ Export('_common')
|
|||||||
|
|
||||||
if GetOption('extras'):
|
if GetOption('extras'):
|
||||||
env.Program('tests/test_common',
|
env.Program('tests/test_common',
|
||||||
['tests/test_runner.cc', 'tests/test_util.cc', 'tests/test_swaglog.cc'],
|
['tests/test_runner.cc', 'tests/test_params.cc', 'tests/test_util.cc', 'tests/test_swaglog.cc'],
|
||||||
LIBS=[_common, 'json11', 'zmq', 'pthread'])
|
LIBS=[_common, 'json11', 'zmq', 'pthread'])
|
||||||
|
|
||||||
# Cython bindings
|
# Cython bindings
|
||||||
@@ -3,8 +3,8 @@ import os
|
|||||||
import requests
|
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.system.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",
|
||||||
@@ -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__)), "../"))
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import math
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
CHUNK_SIZE = 45 * 1024 * 1024 # 45MB, under GitHub's 50MB limit
|
||||||
|
|
||||||
|
def get_chunk_name(name, idx, num_chunks):
|
||||||
|
return f"{name}.chunk{idx+1:02d}of{num_chunks:02d}"
|
||||||
|
|
||||||
|
def get_manifest_path(name):
|
||||||
|
return f"{name}.chunkmanifest"
|
||||||
|
|
||||||
|
def get_chunk_paths(path, file_size):
|
||||||
|
num_chunks = math.ceil(file_size / CHUNK_SIZE)
|
||||||
|
return [get_manifest_path(path)] + [get_chunk_name(path, i, num_chunks) for i in range(num_chunks)]
|
||||||
|
|
||||||
|
def chunk_file(path, targets):
|
||||||
|
manifest_path, *chunk_paths = targets
|
||||||
|
with open(path, 'rb') as f:
|
||||||
|
data = f.read()
|
||||||
|
actual_num_chunks = max(1, math.ceil(len(data) / 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)))
|
||||||
|
os.remove(path)
|
||||||
|
|
||||||
|
|
||||||
|
def read_file_chunked(path):
|
||||||
|
manifest_path = get_manifest_path(path)
|
||||||
|
if os.path.isfile(manifest_path):
|
||||||
|
num_chunks = int(Path(manifest_path).read_text().strip())
|
||||||
|
return b''.join(Path(get_chunk_name(path, i, num_chunks)).read_bytes() for i in range(num_chunks))
|
||||||
|
if os.path.isfile(path):
|
||||||
|
return Path(path).read_bytes()
|
||||||
|
raise FileNotFoundError(path)
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
"""
|
"""
|
||||||
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_livePose
|
from openpilot.common.mock.generators import generate_livePose
|
||||||
from openpilot.common.realtime import Ratekeeper
|
from openpilot.common.realtime import Ratekeeper
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
from openpilot.cereal import messaging
|
from cereal import messaging
|
||||||
|
|
||||||
|
|
||||||
def generate_livePose():
|
def generate_livePose():
|
||||||
@@ -1,13 +1,8 @@
|
|||||||
import re
|
|
||||||
import sys
|
import sys
|
||||||
import pytest
|
import pytest
|
||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
|
|
||||||
def _to_safe_name(s):
|
|
||||||
return re.sub(r"[^a-zA-Z0-9_]+", "_", str(s)).strip("_")
|
|
||||||
|
|
||||||
|
|
||||||
class parameterized:
|
class parameterized:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def expand(cases):
|
def expand(cases):
|
||||||
@@ -39,9 +34,7 @@ def parameterized_class(attrs, input_list=None):
|
|||||||
def decorator(cls):
|
def decorator(cls):
|
||||||
globs = sys._getframe(1).f_globals
|
globs = sys._getframe(1).f_globals
|
||||||
for i, params in enumerate(params_list):
|
for i, params in enumerate(params_list):
|
||||||
# append sanitized string param values so pytest -k can filter by them
|
name = f"{cls.__name__}_{i}"
|
||||||
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 = type(name, (cls,), dict(params))
|
||||||
new_cls.__module__ = cls.__module__
|
new_cls.__module__ = cls.__module__
|
||||||
new_cls.__test__ = True # override inherited False so pytest collects this subclass
|
new_cls.__test__ = True # override inherited False so pytest collects this subclass
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
#include "common/queue.h"
|
#include "common/queue.h"
|
||||||
#include "common/swaglog.h"
|
#include "common/swaglog.h"
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
#include "common/hardware/hw.h"
|
#include "system/hardware/hw.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -14,6 +14,6 @@ if __name__ == "__main__":
|
|||||||
if len(sys.argv) == 3:
|
if len(sys.argv) == 3:
|
||||||
val = sys.argv[2]
|
val = sys.argv[2]
|
||||||
print(f"SET: {key} = {val}")
|
print(f"SET: {key} = {val}")
|
||||||
params.put(key, val, block=True)
|
params.put(key, val)
|
||||||
elif len(sys.argv) == 2:
|
elif len(sys.argv) == 2:
|
||||||
print(f"GET: {key} = {params.get(key)}")
|
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}},
|
||||||
@@ -58,11 +58,12 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"IsDriverViewEnabled", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"IsDriverViewEnabled", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||||
{"IsEngaged", {PERSISTENT, BOOL}},
|
{"IsEngaged", {PERSISTENT, BOOL}},
|
||||||
{"IsLdwEnabled", {PERSISTENT | BACKUP, BOOL}},
|
{"IsLdwEnabled", {PERSISTENT | BACKUP, 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"}},
|
||||||
@@ -79,8 +80,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"LiveDelay", {PERSISTENT | BACKUP, BYTES}},
|
{"LiveDelay", {PERSISTENT | BACKUP, BYTES}},
|
||||||
{"LiveParameters", {PERSISTENT, JSON}},
|
{"LiveParameters", {PERSISTENT, JSON}},
|
||||||
{"LiveParametersV2", {PERSISTENT, BYTES}},
|
{"LiveParametersV2", {PERSISTENT, BYTES}},
|
||||||
{"LivestreamEncoderBitrate", {CLEAR_ON_MANAGER_START | DONT_LOG, INT}},
|
|
||||||
{"LivestreamRequestKeyframe", {CLEAR_ON_MANAGER_START | DONT_LOG, BOOL}},
|
|
||||||
{"LiveTorqueParameters", {PERSISTENT | DONT_LOG, BYTES}},
|
{"LiveTorqueParameters", {PERSISTENT | DONT_LOG, BYTES}},
|
||||||
{"LocationFilterInitialState", {PERSISTENT, BYTES}},
|
{"LocationFilterInitialState", {PERSISTENT, BYTES}},
|
||||||
{"LateralManeuverMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
{"LateralManeuverMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||||
@@ -93,6 +92,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"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_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}},
|
||||||
@@ -103,6 +103,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"OnroadCycleRequested", {CLEAR_ON_MANAGER_START, BOOL}},
|
{"OnroadCycleRequested", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||||
{"OpenpilotEnabledToggle", {PERSISTENT | BACKUP, BOOL, "1"}},
|
{"OpenpilotEnabledToggle", {PERSISTENT | BACKUP, BOOL, "1"}},
|
||||||
{"PandaHeartbeatLost", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
{"PandaHeartbeatLost", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||||
|
{"PandaSomResetTriggered", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||||
|
{"PandaSignatures", {CLEAR_ON_MANAGER_START, BYTES}},
|
||||||
{"PrimeType", {PERSISTENT, INT}},
|
{"PrimeType", {PERSISTENT, INT}},
|
||||||
{"RecordAudio", {PERSISTENT | BACKUP, BOOL}},
|
{"RecordAudio", {PERSISTENT | BACKUP, BOOL}},
|
||||||
{"RecordAudioFeedback", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"RecordAudioFeedback", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
@@ -130,11 +132,11 @@ 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"}},
|
||||||
{"UsbGpuPresent", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
|
||||||
{"UsbGpuCompiled", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
|
||||||
{"Version", {PERSISTENT, STRING}},
|
{"Version", {PERSISTENT, STRING}},
|
||||||
|
|
||||||
// --- sunnypilot params --- //
|
// --- sunnypilot params --- //
|
||||||
|
{"AccelPersonality", {PERSISTENT | BACKUP, INT, std::to_string(static_cast<int>(cereal::LongitudinalPlanSP::AccelerationPersonality::NORMAL))}},
|
||||||
|
{"AccelPersonalityEnabled", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
{"ApiCache_DriveStats", {PERSISTENT, JSON}},
|
{"ApiCache_DriveStats", {PERSISTENT, JSON}},
|
||||||
{"AutoLaneChangeBsmDelay", {PERSISTENT | BACKUP, BOOL, "0"}},
|
{"AutoLaneChangeBsmDelay", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||||
{"AutoLaneChangeTimer", {PERSISTENT | BACKUP, INT, "0"}},
|
{"AutoLaneChangeTimer", {PERSISTENT | BACKUP, INT, "0"}},
|
||||||
@@ -142,28 +142,33 @@ cdef class Params:
|
|||||||
cdef ParamKeyType t = self.p.getKeyType(k)
|
cdef ParamKeyType t = self.p.getKeyType(k)
|
||||||
return ensure_bytes(self.python2cpp(type(dat), t, dat, key))
|
return ensure_bytes(self.python2cpp(type(dat), t, dat, key))
|
||||||
|
|
||||||
def put(self, key, dat, bool block = False):
|
def put(self, key, dat):
|
||||||
"""
|
"""
|
||||||
Warning: block=True blocks until the param is written to disk!
|
Warning: This function blocks until the param is written to disk!
|
||||||
In very rare cases this can take over a second, and your code will hang.
|
In very rare cases this can take over a second, and your code will hang.
|
||||||
Use block=False in time sensitive code, but in general try to avoid
|
Use the put_nonblocking, put_bool_nonblocking in time sensitive code, but
|
||||||
writing params as much as possible.
|
in general try to avoid writing params as much as possible.
|
||||||
"""
|
"""
|
||||||
cdef string k = self.check_key(key)
|
cdef string k = self.check_key(key)
|
||||||
cdef string dat_bytes = self._put_cast(key, dat)
|
cdef string dat_bytes = self._put_cast(key, dat)
|
||||||
with nogil:
|
with nogil:
|
||||||
if block:
|
self.p.put(k, dat_bytes)
|
||||||
self.p.put(k, dat_bytes)
|
|
||||||
else:
|
|
||||||
self.p.putNonBlocking(k, dat_bytes)
|
|
||||||
|
|
||||||
def put_bool(self, key, bool val, bool block = False):
|
def put_bool(self, key, bool val):
|
||||||
cdef string k = self.check_key(key)
|
cdef string k = self.check_key(key)
|
||||||
with nogil:
|
with nogil:
|
||||||
if block:
|
self.p.putBool(k, val)
|
||||||
self.p.putBool(k, val)
|
|
||||||
else:
|
def put_nonblocking(self, key, dat):
|
||||||
self.p.putBoolNonBlocking(k, val)
|
cdef string k = self.check_key(key)
|
||||||
|
cdef string dat_bytes = self._put_cast(key, dat)
|
||||||
|
with nogil:
|
||||||
|
self.p.putNonBlocking(k, dat_bytes)
|
||||||
|
|
||||||
|
def put_bool_nonblocking(self, key, bool val):
|
||||||
|
cdef string k = self.check_key(key)
|
||||||
|
with nogil:
|
||||||
|
self.p.putBoolNonBlocking(k, val)
|
||||||
|
|
||||||
def remove(self, key):
|
def remove(self, key):
|
||||||
cdef string k = self.check_key(key)
|
cdef string k = self.check_key(key)
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include "common/params.h"
|
#include "common/params.h"
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
#include "common/hardware/hw.h"
|
#include "system/hardware/hw.h"
|
||||||
|
|
||||||
class OpenpilotPrefix {
|
class OpenpilotPrefix {
|
||||||
public:
|
public:
|
||||||
@@ -5,9 +5,9 @@ import uuid
|
|||||||
|
|
||||||
|
|
||||||
from openpilot.common.params import Params
|
from openpilot.common.params import Params
|
||||||
from openpilot.common.hardware import PC
|
from openpilot.system.hardware import PC
|
||||||
from openpilot.common.hardware.hw import Paths
|
from openpilot.system.hardware.hw import Paths
|
||||||
from openpilot.common.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT
|
from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT
|
||||||
|
|
||||||
class OpenpilotPrefix:
|
class OpenpilotPrefix:
|
||||||
def __init__(self, prefix: str | None = None, create_dirs_on_enter: bool = True, clean_dirs_on_exit: bool = True, shared_download_cache: bool = False):
|
def __init__(self, prefix: str | None = None, create_dirs_on_enter: bool = True, clean_dirs_on_exit: bool = True, shared_download_cache: bool = False):
|
||||||
@@ -7,7 +7,7 @@ import time
|
|||||||
from setproctitle import getproctitle
|
from setproctitle import getproctitle
|
||||||
|
|
||||||
from openpilot.common.utils import MovingAverage
|
from openpilot.common.utils import MovingAverage
|
||||||
from openpilot.common.hardware import PC
|
from openpilot.system.hardware import PC
|
||||||
|
|
||||||
|
|
||||||
# time step for each process
|
# time step for each process
|
||||||
@@ -28,11 +28,6 @@ class Priority:
|
|||||||
CTRL_HIGH = 53
|
CTRL_HIGH = 53
|
||||||
|
|
||||||
|
|
||||||
def drop_realtime() -> None:
|
|
||||||
if sys.platform == 'linux' and not PC:
|
|
||||||
os.sched_setscheduler(0, os.SCHED_OTHER, os.sched_param(0))
|
|
||||||
|
|
||||||
|
|
||||||
def set_core_affinity(cores: list[int]) -> None:
|
def set_core_affinity(cores: list[int]) -> None:
|
||||||
if sys.platform == 'linux' and not PC:
|
if sys.platform == 'linux' and not PC:
|
||||||
os.sched_setaffinity(0, cores)
|
os.sched_setaffinity(0, cores)
|
||||||
@@ -8,7 +8,7 @@ class Spinner:
|
|||||||
try:
|
try:
|
||||||
self.spinner_proc = subprocess.Popen(["./spinner.py"],
|
self.spinner_proc = subprocess.Popen(["./spinner.py"],
|
||||||
stdin=subprocess.PIPE,
|
stdin=subprocess.PIPE,
|
||||||
cwd=os.path.join(BASEDIR, "openpilot/system", "ui"),
|
cwd=os.path.join(BASEDIR, "system", "ui"),
|
||||||
close_fds=True)
|
close_fds=True)
|
||||||
except OSError:
|
except OSError:
|
||||||
self.spinner_proc = None
|
self.spinner_proc = None
|
||||||
@@ -11,9 +11,9 @@
|
|||||||
|
|
||||||
#include <zmq.h>
|
#include <zmq.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include "json11/json11.hpp"
|
#include "third_party/json11/json11.hpp"
|
||||||
#include "common/version.h"
|
#include "common/version.h"
|
||||||
#include "common/hardware/hw.h"
|
#include "system/hardware/hw.h"
|
||||||
|
|
||||||
#include "sunnypilot/common/version.h"
|
#include "sunnypilot/common/version.h"
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ from logging.handlers import BaseRotatingHandler
|
|||||||
import zmq
|
import zmq
|
||||||
|
|
||||||
from openpilot.common.logging_extra import SwagLogger, SwagFormatter, SwagLogFileFormatter
|
from openpilot.common.logging_extra import SwagLogger, SwagFormatter, SwagLogFileFormatter
|
||||||
from openpilot.common.hardware.hw import Paths
|
from openpilot.system.hardware.hw import Paths
|
||||||
|
|
||||||
|
|
||||||
def get_file_handler():
|
def get_file_handler():
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#include "catch2/catch.hpp"
|
||||||
|
#define private public
|
||||||
|
#include "common/params.h"
|
||||||
|
#include "common/util.h"
|
||||||
|
|
||||||
|
TEST_CASE("params_nonblocking_put") {
|
||||||
|
char tmp_path[] = "/tmp/asyncWriter_XXXXXX";
|
||||||
|
const std::string param_path = mkdtemp(tmp_path);
|
||||||
|
auto param_names = {"CarParams", "IsMetric"};
|
||||||
|
{
|
||||||
|
Params params(param_path);
|
||||||
|
for (const auto &name : param_names) {
|
||||||
|
params.putNonBlocking(name, "1");
|
||||||
|
// param is empty
|
||||||
|
REQUIRE(params.get(name).empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if thread is running
|
||||||
|
REQUIRE(params.future.valid());
|
||||||
|
REQUIRE(params.future.wait_for(std::chrono::milliseconds(0)) == std::future_status::timeout);
|
||||||
|
}
|
||||||
|
// check results
|
||||||
|
Params p(param_path);
|
||||||
|
for (const auto &name : param_names) {
|
||||||
|
REQUIRE(p.get(name) == "1");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,17 +12,17 @@ class TestParams:
|
|||||||
self.params = Params()
|
self.params = Params()
|
||||||
|
|
||||||
def test_params_put_and_get(self):
|
def test_params_put_and_get(self):
|
||||||
self.params.put("DongleId", "cb38263377b873ee", block=True)
|
self.params.put("DongleId", "cb38263377b873ee")
|
||||||
assert self.params.get("DongleId") == "cb38263377b873ee"
|
assert self.params.get("DongleId") == "cb38263377b873ee"
|
||||||
|
|
||||||
def test_params_non_ascii(self):
|
def test_params_non_ascii(self):
|
||||||
st = b"\xe1\x90\xff"
|
st = b"\xe1\x90\xff"
|
||||||
self.params.put("CarParams", st, block=True)
|
self.params.put("CarParams", st)
|
||||||
assert self.params.get("CarParams") == st
|
assert self.params.get("CarParams") == st
|
||||||
|
|
||||||
def test_params_get_cleared_manager_start(self):
|
def test_params_get_cleared_manager_start(self):
|
||||||
self.params.put("CarParams", b"test", block=True)
|
self.params.put("CarParams", b"test")
|
||||||
self.params.put("DongleId", "cb38263377b873ee", block=True)
|
self.params.put("DongleId", "cb38263377b873ee")
|
||||||
assert self.params.get("CarParams") == b"test"
|
assert self.params.get("CarParams") == b"test"
|
||||||
|
|
||||||
undefined_param = self.params.get_param_path(uuid.uuid4().hex)
|
undefined_param = self.params.get_param_path(uuid.uuid4().hex)
|
||||||
@@ -36,15 +36,15 @@ class TestParams:
|
|||||||
assert not os.path.isfile(undefined_param)
|
assert not os.path.isfile(undefined_param)
|
||||||
|
|
||||||
def test_params_two_things(self):
|
def test_params_two_things(self):
|
||||||
self.params.put("DongleId", "bob", block=True)
|
self.params.put("DongleId", "bob")
|
||||||
self.params.put("AthenadPid", 123, block=True)
|
self.params.put("AthenadPid", 123)
|
||||||
assert self.params.get("DongleId") == "bob"
|
assert self.params.get("DongleId") == "bob"
|
||||||
assert self.params.get("AthenadPid") == 123
|
assert self.params.get("AthenadPid") == 123
|
||||||
|
|
||||||
def test_params_get_block(self):
|
def test_params_get_block(self):
|
||||||
def _delayed_writer():
|
def _delayed_writer():
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
self.params.put("CarParams", b"test", block=True)
|
self.params.put("CarParams", b"test")
|
||||||
threading.Thread(target=_delayed_writer).start()
|
threading.Thread(target=_delayed_writer).start()
|
||||||
assert self.params.get("CarParams") is None
|
assert self.params.get("CarParams") is None
|
||||||
assert self.params.get("CarParams", block=True) == b"test"
|
assert self.params.get("CarParams", block=True) == b"test"
|
||||||
@@ -57,10 +57,10 @@ class TestParams:
|
|||||||
self.params.get_bool("swag")
|
self.params.get_bool("swag")
|
||||||
|
|
||||||
with pytest.raises(UnknownKeyName):
|
with pytest.raises(UnknownKeyName):
|
||||||
self.params.put("swag", "abc", block=True)
|
self.params.put("swag", "abc")
|
||||||
|
|
||||||
with pytest.raises(UnknownKeyName):
|
with pytest.raises(UnknownKeyName):
|
||||||
self.params.put_bool("swag", True, block=True)
|
self.params.put_bool("swag", True)
|
||||||
|
|
||||||
def test_remove_not_there(self):
|
def test_remove_not_there(self):
|
||||||
assert self.params.get("CarParams") is None
|
assert self.params.get("CarParams") is None
|
||||||
@@ -71,23 +71,23 @@ class TestParams:
|
|||||||
self.params.remove("IsMetric")
|
self.params.remove("IsMetric")
|
||||||
assert not self.params.get_bool("IsMetric")
|
assert not self.params.get_bool("IsMetric")
|
||||||
|
|
||||||
self.params.put_bool("IsMetric", True, block=True)
|
self.params.put_bool("IsMetric", True)
|
||||||
assert self.params.get_bool("IsMetric")
|
assert self.params.get_bool("IsMetric")
|
||||||
|
|
||||||
self.params.put_bool("IsMetric", False, block=True)
|
self.params.put_bool("IsMetric", False)
|
||||||
assert not self.params.get_bool("IsMetric")
|
assert not self.params.get_bool("IsMetric")
|
||||||
|
|
||||||
self.params.put("IsMetric", True, block=True)
|
self.params.put("IsMetric", True)
|
||||||
assert self.params.get_bool("IsMetric")
|
assert self.params.get_bool("IsMetric")
|
||||||
|
|
||||||
self.params.put("IsMetric", False, block=True)
|
self.params.put("IsMetric", False)
|
||||||
assert not self.params.get_bool("IsMetric")
|
assert not self.params.get_bool("IsMetric")
|
||||||
|
|
||||||
def test_put_non_blocking_with_get_block(self):
|
def test_put_non_blocking_with_get_block(self):
|
||||||
q = Params()
|
q = Params()
|
||||||
def _delayed_writer():
|
def _delayed_writer():
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
Params().put("CarParams", b"test")
|
Params().put_nonblocking("CarParams", b"test")
|
||||||
threading.Thread(target=_delayed_writer).start()
|
threading.Thread(target=_delayed_writer).start()
|
||||||
assert q.get("CarParams") is None
|
assert q.get("CarParams") is None
|
||||||
assert q.get("CarParams", True) == b"test"
|
assert q.get("CarParams", True) == b"test"
|
||||||
@@ -96,7 +96,7 @@ class TestParams:
|
|||||||
q = Params()
|
q = Params()
|
||||||
def _delayed_writer():
|
def _delayed_writer():
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
Params().put_bool("CarParams", True)
|
Params().put_bool_nonblocking("CarParams", True)
|
||||||
threading.Thread(target=_delayed_writer).start()
|
threading.Thread(target=_delayed_writer).start()
|
||||||
assert q.get("CarParams") is None
|
assert q.get("CarParams") is None
|
||||||
assert q.get("CarParams", True) == b"1"
|
assert q.get("CarParams", True) == b"1"
|
||||||
@@ -123,19 +123,19 @@ class TestParams:
|
|||||||
|
|
||||||
def test_params_get_type(self):
|
def test_params_get_type(self):
|
||||||
# json
|
# json
|
||||||
self.params.put("ApiCache_FirehoseStats", {"a": 0}, block=True)
|
self.params.put("ApiCache_FirehoseStats", {"a": 0})
|
||||||
assert self.params.get("ApiCache_FirehoseStats") == {"a": 0}
|
assert self.params.get("ApiCache_FirehoseStats") == {"a": 0}
|
||||||
|
|
||||||
# int
|
# int
|
||||||
self.params.put("BootCount", 1441, block=True)
|
self.params.put("BootCount", 1441)
|
||||||
assert self.params.get("BootCount") == 1441
|
assert self.params.get("BootCount") == 1441
|
||||||
|
|
||||||
# bool
|
# bool
|
||||||
self.params.put("AdbEnabled", True, block=True)
|
self.params.put("AdbEnabled", True)
|
||||||
assert self.params.get("AdbEnabled")
|
assert self.params.get("AdbEnabled")
|
||||||
assert isinstance(self.params.get("AdbEnabled"), bool)
|
assert isinstance(self.params.get("AdbEnabled"), bool)
|
||||||
|
|
||||||
# time
|
# time
|
||||||
now = datetime.datetime.now(datetime.UTC)
|
now = datetime.datetime.now(datetime.UTC)
|
||||||
self.params.put("InstallDate", now, block=True)
|
self.params.put("InstallDate", now)
|
||||||
assert self.params.get("InstallDate") == now
|
assert self.params.get("InstallDate") == now
|
||||||
@@ -6,8 +6,8 @@
|
|||||||
#include "common/swaglog.h"
|
#include "common/swaglog.h"
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
#include "common/version.h"
|
#include "common/version.h"
|
||||||
#include "common/hardware/hw.h"
|
#include "system/hardware/hw.h"
|
||||||
#include "json11/json11.hpp"
|
#include "third_party/json11/json11.hpp"
|
||||||
|
|
||||||
#include "sunnypilot/common/version.h"
|
#include "sunnypilot/common/version.h"
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ class TextWindow:
|
|||||||
try:
|
try:
|
||||||
self.text_proc = subprocess.Popen(["./text.py", text],
|
self.text_proc = subprocess.Popen(["./text.py", text],
|
||||||
stdin=subprocess.PIPE,
|
stdin=subprocess.PIPE,
|
||||||
cwd=os.path.join(BASEDIR, "openpilot/system", "ui"),
|
cwd=os.path.join(BASEDIR, "system", "ui"),
|
||||||
close_fds=True)
|
close_fds=True)
|
||||||
except OSError:
|
except OSError:
|
||||||
self.text_proc = None
|
self.text_proc = None
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user