mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-06-20 09:12:05 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7bf90d5372 |
@@ -1,4 +0,0 @@
|
|||||||
Wen
|
|
||||||
REGIST
|
|
||||||
PullRequest
|
|
||||||
cancelled
|
|
||||||
@@ -18,19 +18,6 @@
|
|||||||
|
|
||||||
venv/
|
venv/
|
||||||
.venv/
|
.venv/
|
||||||
**/.idea
|
|
||||||
**/.hypothesis
|
|
||||||
**/.mypy_cache
|
|
||||||
|
|
||||||
**/.venv
|
|
||||||
**/.venv/
|
|
||||||
|
|
||||||
**/.ci_cache
|
|
||||||
**/*.rlog
|
|
||||||
|
|
||||||
**/Dockerfile*
|
|
||||||
**/dockerfile*
|
|
||||||
**/build_output
|
|
||||||
|
|
||||||
notebooks
|
notebooks
|
||||||
phone
|
phone
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ end_of_line = lf
|
|||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
[*.{py,pyx,pxd}]
|
[{*.py, *.pyx, *.pxd}]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
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
|
||||||
system/hardware/tici/updater filter=lfs diff=lfs merge=lfs -text
|
system/hardware/tici/updater filter=lfs diff=lfs merge=lfs -text
|
||||||
|
selfdrive/ui/qt/spinner_larch64 filter=lfs diff=lfs merge=lfs -text
|
||||||
|
selfdrive/ui/qt/text_larch64 filter=lfs diff=lfs merge=lfs -text
|
||||||
third_party/**/*.a 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/**/*.so.* filter=lfs diff=lfs merge=lfs -text
|
third_party/**/*.so.* filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
* @sunnypilot/dev-internal
|
|
||||||
/.github/ @devtekve @sunnyhaibin
|
|
||||||
/release/ci/ @devtekve @sunnyhaibin
|
|
||||||
/tinygrad_repo @devtekve @Discountchubbs
|
|
||||||
/tinygrad/ @devtekve @Discountchubbs
|
|
||||||
/selfdrive/controls/lib/longitudinal_planner.py @devtekve @Discountchubbs
|
|
||||||
/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py @devtekve @Discountchubbs
|
|
||||||
/selfdrive/modeld/ @devtekve @Discountchubbs
|
|
||||||
/sunnypilot/model* @devtekve @Discountchubbs
|
|
||||||
/sunnypilot/sunnylink/ @devtekve
|
|
||||||
/system/athena/ @devtekve
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
name: Car bug report
|
||||||
|
description: For issues with a particular car make or model
|
||||||
|
labels: ["car", "bug"]
|
||||||
|
body:
|
||||||
|
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: >
|
||||||
|
Before creating a **bug report**, please check the following:
|
||||||
|
* Ensure you're running the latest openpilot release.
|
||||||
|
* Ensure you're using officially supported hardware. Issues running on PCs have a different issue template.
|
||||||
|
* Ensure there isn't an existing issue for your bug. If there is, leave a comment on the existing issue.
|
||||||
|
* Ensure you're running stock openpilot. We cannot look into bug reports from forks.
|
||||||
|
|
||||||
|
If you're unsure whether you've hit a bug, check out the #installation-help channel in the [community Discord server](https://discord.comma.ai).
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Describe the bug
|
||||||
|
description: Also include a description of how to reproduce the bug
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: car
|
||||||
|
attributes:
|
||||||
|
label: Which car does this affect?
|
||||||
|
placeholder: Toyota Prius 2017
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: route
|
||||||
|
attributes:
|
||||||
|
label: Provide a route where the issue occurs
|
||||||
|
description: Ensure the route is fully uploaded at https://useradmin.comma.ai
|
||||||
|
placeholder: 77611a1fac303767|2020-05-11--16-37-07
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: version
|
||||||
|
attributes:
|
||||||
|
label: openpilot version
|
||||||
|
description: If you're not on release, provide the commit hash
|
||||||
|
placeholder: 0.8.10
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Additional info
|
||||||
|
|
||||||
@@ -1,12 +1,9 @@
|
|||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Car bug report
|
|
||||||
url: https://github.com/commaai/opendbc/issues/new
|
|
||||||
about: For issues with a particular car make or model
|
|
||||||
- name: Join the Discord
|
- name: Join the Discord
|
||||||
url: https://discord.comma.ai
|
url: https://discord.comma.ai
|
||||||
about: The community Discord is for both openpilot development and experience discussion
|
about: The community Discord is for both openpilot development and experience discussion
|
||||||
- name: Report driving behavior feedback
|
- name: Report model bugs
|
||||||
url: https://discord.com/channels/469524606043160576/1254834193066623017
|
url: https://discord.com/channels/469524606043160576/1254834193066623017
|
||||||
about: Feedback for the driving and driver monitoring models goes in the #driving-feedback in Discord
|
about: Feedback for the driving and driver monitoring models goes in the #driving-feedback in Discord
|
||||||
- name: Community Wiki
|
- name: Community Wiki
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
name: Bug fix
|
||||||
|
about: For openpilot bug fixes
|
||||||
|
title: ''
|
||||||
|
labels: 'bugfix'
|
||||||
|
assignees: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
**Description**
|
||||||
|
|
||||||
|
<!-- A description of the bug and the fix. Also link the issue if it exists. -->
|
||||||
|
|
||||||
|
**Verification**
|
||||||
|
|
||||||
|
<!-- Explain how you tested this bug fix. -->
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
name: Car Bug fix
|
||||||
|
about: For vehicle/brand specific bug fixes
|
||||||
|
title: ''
|
||||||
|
labels: 'car bug fix'
|
||||||
|
assignees: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
**Description**
|
||||||
|
|
||||||
|
<!-- A description of the bug and the fix. Also link the issue if it exists. -->
|
||||||
|
|
||||||
|
**Verification**
|
||||||
|
|
||||||
|
<!-- Explain how you tested this bug fix. -->
|
||||||
|
|
||||||
|
**Route**
|
||||||
|
|
||||||
|
Route: [a route with the bug fix]
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
name: Car port
|
||||||
|
about: For new car ports
|
||||||
|
title: ''
|
||||||
|
labels: 'car port'
|
||||||
|
assignees: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
**Checklist**
|
||||||
|
|
||||||
|
- [ ] added entry to CAR in selfdrive/car/*/values.py and ran `selfdrive/car/docs.py` to generate new docs
|
||||||
|
- [ ] test route added to [routes.py](https://github.com/commaai/openpilot/blob/master/selfdrive/car/tests/routes.py)
|
||||||
|
- [ ] route with openpilot:
|
||||||
|
- [ ] route with stock system:
|
||||||
|
- [ ] car harness used (if comma doesn't sell it, put N/A):
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
name: Fingerprint
|
||||||
|
about: For adding fingerprints to existing cars
|
||||||
|
title: ''
|
||||||
|
labels: 'fingerprint'
|
||||||
|
assignees: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
**Car**
|
||||||
|
Which car (make, model, year) this fingerprint is for
|
||||||
|
|
||||||
|
**Route**
|
||||||
|
A route with the fingerprint
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
name: Refactor
|
||||||
|
about: For code refactors
|
||||||
|
title: ''
|
||||||
|
labels: 'refactor'
|
||||||
|
assignees: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
**Description**
|
||||||
|
|
||||||
|
<!-- A description of the refactor, including the goals it accomplishes. -->
|
||||||
|
|
||||||
|
**Verification**
|
||||||
|
|
||||||
|
<!-- Explain how you tested the refactor for regressions. -->
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
name: Tuning
|
||||||
|
about: For openpilot tuning changes
|
||||||
|
title: ''
|
||||||
|
labels: 'tuning'
|
||||||
|
assignees: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
**Description**
|
||||||
|
|
||||||
|
<!-- A description of what is wrong with the current tuning and how the PR addresses this. -->
|
||||||
|
|
||||||
|
**Verification**
|
||||||
|
|
||||||
|
<!-- To verify tuning, capture the following scenarios (broadly, not exactly), with current tune and this tune.
|
||||||
|
Use the PlotJuggler tuning layout to compare planned versus actual behavior.
|
||||||
|
|
||||||
|
Run ./juggle.py <route> --layout layouts/tuning.xml , screenshot the full tab of interest, and paste into this PR.
|
||||||
|
|
||||||
|
Longitudinal:
|
||||||
|
* Maintaining speed at 25, 40, 65mph
|
||||||
|
* Driving up and down hills
|
||||||
|
* Accelerating from a stop
|
||||||
|
* Decelerating to a stop
|
||||||
|
* Following large changes in set speed
|
||||||
|
* Coming to a stop behind a lead car
|
||||||
|
|
||||||
|
Lateral:
|
||||||
|
* Straight driving at ~25, ~45 and ~65mph
|
||||||
|
* Turns driving at ~25, ~45 and ~65mph
|
||||||
|
-->
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import pathlib
|
||||||
|
|
||||||
|
GITHUB_FOLDER = pathlib.Path(__file__).parent
|
||||||
|
|
||||||
|
PULL_REQUEST_TEMPLATES = (GITHUB_FOLDER / "PULL_REQUEST_TEMPLATE")
|
||||||
|
|
||||||
|
order = ["fingerprint", "car_bugfix", "bugfix", "car_port", "refactor"]
|
||||||
|
|
||||||
|
def create_pull_request_template():
|
||||||
|
with open(GITHUB_FOLDER / "pull_request_template.md", "w") as f:
|
||||||
|
f.write("<!-- Please copy and paste the relevant template -->\n\n")
|
||||||
|
|
||||||
|
for t in order:
|
||||||
|
template = PULL_REQUEST_TEMPLATES / f"{t}.md"
|
||||||
|
text = template.read_text()
|
||||||
|
|
||||||
|
# Remove metadata for GitHub
|
||||||
|
start = text.find("---")
|
||||||
|
end = text.find("---", start+1)
|
||||||
|
text = text[end + 4:]
|
||||||
|
|
||||||
|
# Remove comments
|
||||||
|
text = text.replace("<!-- ", "").replace("-->", "")
|
||||||
|
|
||||||
|
f.write(f"<!--- ***** Template: {template.stem.replace('_', ' ').title()} *****\n")
|
||||||
|
f.write(text)
|
||||||
|
f.write("\n\n")
|
||||||
|
f.write("-->\n\n")
|
||||||
|
|
||||||
|
create_pull_request_template()
|
||||||
@@ -1,11 +1,7 @@
|
|||||||
ci:
|
CI / testing:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-all-files: "{.github/**,**/test_*,Jenkinsfile}"
|
- any-glob-to-all-files: "{.github/**,**/test_*,Jenkinsfile}"
|
||||||
|
|
||||||
chore:
|
|
||||||
- changed-files:
|
|
||||||
- any-glob-to-all-files: "{.github/**}"
|
|
||||||
|
|
||||||
car:
|
car:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-all-files: '{selfdrive/car/**,opendbc_repo}'
|
- any-glob-to-all-files: '{selfdrive/car/**,opendbc_repo}'
|
||||||
@@ -16,7 +12,7 @@ simulation:
|
|||||||
|
|
||||||
ui:
|
ui:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-all-files: '{selfdrive/ui/**,system/ui/**}'
|
- any-glob-to-all-files: 'selfdrive/ui/**'
|
||||||
|
|
||||||
tools:
|
tools:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
@@ -28,4 +24,4 @@ multilanguage:
|
|||||||
|
|
||||||
autonomy:
|
autonomy:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-all-files: "{selfdrive/modeld/models/**,selfdrive/test/process_replay/model_replay_ref_commit,sunnypilot/modeld*/models/**}"
|
- any-glob-to-all-files: "{selfdrive/modeld/models/**,selfdrive/test/process_replay/model_replay_ref_commit}"
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
exclude-labels:
|
|
||||||
- 'no-changelog'
|
|
||||||
categories:
|
|
||||||
- title: '🚀 Features'
|
|
||||||
labels:
|
|
||||||
- 'feature'
|
|
||||||
- 'enhancement'
|
|
||||||
- title: '🐛 Bug Fixes'
|
|
||||||
collapse-after: 5
|
|
||||||
labels:
|
|
||||||
- 'fix'
|
|
||||||
- 'bugfix'
|
|
||||||
- 'bug'
|
|
||||||
- title: '🧰 Maintenance'
|
|
||||||
collapse-after: 5
|
|
||||||
label: 'chore'
|
|
||||||
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
|
|
||||||
change-title-escapes: '\<*_&'
|
|
||||||
replacers:
|
|
||||||
- search: '/[Ss][Uu][Nn][Nn][Yy][Pp][Ii][Ll][Oo][Tt]/g'
|
|
||||||
replace: 'sunnypilot'
|
|
||||||
- search: '/\b[Ss][Pp]\b/g'
|
|
||||||
replace: 'SP'
|
|
||||||
version-resolver:
|
|
||||||
major:
|
|
||||||
labels:
|
|
||||||
- 'major'
|
|
||||||
minor:
|
|
||||||
labels:
|
|
||||||
- 'minor'
|
|
||||||
patch:
|
|
||||||
labels:
|
|
||||||
- 'patch'
|
|
||||||
default: patch
|
|
||||||
name-template: 'v$RESOLVED_VERSION 🚀'
|
|
||||||
tag-template: 'v$RESOLVED_VERSION'
|
|
||||||
version-template: "0.$MAJOR.$MINOR.$PATCH" # The day OP becomes v1, we need to bump this
|
|
||||||
tag-prefix: "v0." # The day OP becomes v1, we need to bump this
|
|
||||||
prerelease-identifier: "staging"
|
|
||||||
template: |
|
|
||||||
## Changes
|
|
||||||
|
|
||||||
$CHANGES
|
|
||||||
@@ -12,7 +12,7 @@ inputs:
|
|||||||
required: true
|
required: true
|
||||||
save:
|
save:
|
||||||
description: 'whether to save the cache'
|
description: 'whether to save the cache'
|
||||||
default: 'true'
|
default: 'false'
|
||||||
required: false
|
required: false
|
||||||
outputs:
|
outputs:
|
||||||
cache-hit:
|
cache-hit:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
name: "PR review"
|
name: "PR review"
|
||||||
on:
|
on:
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [opened, reopened, synchronize, edited]
|
types: [opened, reopened, synchronize, edited, edited]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
labeler:
|
labeler:
|
||||||
@@ -9,7 +9,6 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
issues: write
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -25,67 +24,30 @@ jobs:
|
|||||||
# Check PR target branch
|
# Check PR target branch
|
||||||
- name: check branch
|
- name: check branch
|
||||||
uses: Vankka/pr-target-branch-action@def32ec9d93514138d6ac0132ee62e120a72aed5
|
uses: Vankka/pr-target-branch-action@def32ec9d93514138d6ac0132ee62e120a72aed5
|
||||||
if: github.repository == 'sunnypilot/sunnypilot'
|
if: github.repository == 'commaai/openpilot'
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
target: /^(?!master-new$).*/
|
target: /^(?!master$).*/
|
||||||
exclude: /sunnypilot:.*/
|
exclude: /commaai:.*/
|
||||||
change-to: ${{ github.base_ref }}
|
change-to: ${{ github.base_ref }}
|
||||||
already-exists-action: close_this
|
already-exists-action: close_this
|
||||||
already-exists-comment: "Your PR should be made against the `master-new` branch"
|
already-exists-comment: "Your PR should be made against the `master` branch"
|
||||||
|
|
||||||
update-pr-labels:
|
# Welcome comment
|
||||||
name: Update fork's PR Labels
|
- name: "First timers PR"
|
||||||
runs-on: ubuntu-latest
|
uses: actions/first-interaction@v1
|
||||||
if: (github.event.pull_request.head.repo.fork && (contains(github.event_name, 'pull_request') && github.event.action == 'synchronize'))
|
if: github.event.pull_request.head.repo.full_name != 'commaai/openpilot'
|
||||||
env:
|
with:
|
||||||
PR_LABEL: 'dev-c3'
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
TRUST_FORK_PR_LABEL: 'trust-fork-pr'
|
pr-message: |
|
||||||
steps:
|
<!-- _(run_id **${{ github.run_id }}**)_ -->
|
||||||
- name: Check if PR has dev-c3 label
|
Thanks for contributing to openpilot! In order for us to review your PR as quickly as possible, check the following:
|
||||||
id: check-labels
|
* Convert your PR to a draft unless it's ready to review
|
||||||
uses: actions/github-script@v7
|
* Read the [contributing docs](https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md)
|
||||||
with:
|
* Before marking as "ready for review", ensure:
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
* the goal is clearly stated in the description
|
||||||
script: |
|
* all the tests are passing
|
||||||
const prNumber = context.payload.pull_request.number;
|
* the change is [something we merge](https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md#what-gets-merged)
|
||||||
const { data: labels } = await github.rest.issues.listLabelsOnIssue({
|
* include a route or your device' dongle ID if relevant
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
issue_number: prNumber
|
|
||||||
});
|
|
||||||
|
|
||||||
const hasDevC3Label = labels.some(label => label.name === process.env.PR_LABEL);
|
|
||||||
const hasTrustLabel = labels.some(label => label.name === process.env.TRUST_FORK_PR_LABEL);
|
|
||||||
|
|
||||||
console.log(`PR #${prNumber} has ${process.env.PR_LABEL} label: ${hasDevC3Label}`);
|
|
||||||
console.log(`PR #${prNumber} has ${process.env.TRUST_FORK_PR_LABEL} label: ${hasTrustLabel}`);
|
|
||||||
|
|
||||||
core.setOutput('has-dev-c3', hasDevC3Label ? 'true' : 'false');
|
|
||||||
core.setOutput('has-trust', hasTrustLabel ? 'true' : 'false');
|
|
||||||
|
|
||||||
- name: Remove trust-fork-pr label if present
|
|
||||||
if: steps.check-labels.outputs.has-dev-c3 == 'true' && steps.check-labels.outputs.has-trust == 'true'
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
with:
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
script: |
|
|
||||||
const prNumber = context.payload.pull_request.number;
|
|
||||||
|
|
||||||
await github.rest.issues.removeLabel({
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
issue_number: prNumber,
|
|
||||||
name: process.env.TRUST_FORK_PR_LABEL
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`Removed '${process.env.TRUST_FORK_PR_LABEL}' label from PR #${prNumber} as it received new commits`);
|
|
||||||
|
|
||||||
// Add a comment to the PR
|
|
||||||
await github.rest.issues.createComment({
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
issue_number: prNumber,
|
|
||||||
body: `The \`${process.env.TRUST_FORK_PR_LABEL}\` label has been automatically removed because new commits were pushed to this PR. This PR will need to be re-reviewed before the label can be applied again.`
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ jobs:
|
|||||||
badges:
|
badges:
|
||||||
name: create badges
|
name: create badges
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.repository == 'sunnypilot/sunnypilot'
|
if: github.repository == 'commaai/openpilot'
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
|
|
||||||
git checkout --orphan badges
|
git checkout --orphan badges
|
||||||
git rm -rf --cached .
|
git rm -rf --cached .
|
||||||
git config user.email "badge-researcher@sunnypilot.ai"
|
git config user.email "badge-researcher@comma.ai"
|
||||||
git config user.name "Badge Researcher"
|
git config user.name "Badge Researcher"
|
||||||
|
|
||||||
git add translation_badge.svg
|
git add translation_badge.svg
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
name: cereal validation
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
- master-new
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- 'cereal/**'
|
|
||||||
workflow_dispatch:
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
run_number:
|
|
||||||
default: '1'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: cereal-validation-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new') && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
env:
|
|
||||||
PYTHONWARNINGS: error
|
|
||||||
BASE_IMAGE: openpilot-base
|
|
||||||
BUILD: selfdrive/test/docker_build.sh base
|
|
||||||
RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
generate_cereal_artifact:
|
|
||||||
name: Generate cereal validation artifacts
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
- uses: ./.github/workflows/setup-with-retry
|
|
||||||
- name: Build openpilot
|
|
||||||
run: ${{ env.RUN }} "scons -j$(nproc) cereal"
|
|
||||||
- name: Generate the log file
|
|
||||||
run: |
|
|
||||||
${{ env.RUN }} "cereal/messaging/tests/validate_sp_cereal_upstream.py -g -f schema_instances.bin" && \
|
|
||||||
ls -la
|
|
||||||
ls -la cereal/messaging/tests
|
|
||||||
- name: 'Prepare artifact'
|
|
||||||
run: |
|
|
||||||
mkdir -p "cereal/messaging/tests/cereal_validations"
|
|
||||||
cp cereal/messaging/tests/validate_sp_cereal_upstream.py "cereal/messaging/tests/cereal_validations/validate_sp_cereal_upstream.py"
|
|
||||||
cp schema_instances.bin "cereal/messaging/tests/cereal_validations/schema_instances.bin"
|
|
||||||
- name: 'Upload Artifact'
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: cereal_validations
|
|
||||||
path: cereal/messaging/tests/cereal_validations
|
|
||||||
|
|
||||||
validate_cereal_with_upstream:
|
|
||||||
name: Validate cereal with Upstream
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
needs: generate_cereal_artifact
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: 'commaai/openpilot'
|
|
||||||
submodules: true
|
|
||||||
ref: "refs/heads/master"
|
|
||||||
- uses: ./.github/workflows/setup-with-retry
|
|
||||||
- name: Build openpilot
|
|
||||||
run: ${{ env.RUN }} "scons -j$(nproc) cereal"
|
|
||||||
- name: Download build artifacts
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: cereal_validations
|
|
||||||
path: cereal/messaging/tests/cereal_validations
|
|
||||||
- name: 'Run the validation'
|
|
||||||
run: |
|
|
||||||
chmod +x cereal/messaging/tests/cereal_validations/validate_sp_cereal_upstream.py
|
|
||||||
${{ env.RUN }} "cereal/messaging/tests/cereal_validations/validate_sp_cereal_upstream.py -r -f cereal/messaging/tests/cereal_validations/schema_instances.bin"
|
|
||||||
@@ -15,7 +15,7 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
setup:
|
setup:
|
||||||
if: github.repository == 'sunnypilot/sunnypilot'
|
if: github.repository == 'commaai/openpilot'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
outputs:
|
||||||
ci_runs: ${{ steps.ci_runs_setup.outputs.matrix }}
|
ci_runs: ${{ steps.ci_runs_setup.outputs.matrix }}
|
||||||
@@ -31,7 +31,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix: ${{fromJSON(needs.setup.outputs.ci_runs)}}
|
matrix: ${{fromJSON(needs.setup.outputs.ci_runs)}}
|
||||||
uses: sunnypilot/sunnypilot/.github/workflows/ci_weekly_run.yaml@master
|
uses: commaai/openpilot/.github/workflows/ci_weekly_run.yaml@master
|
||||||
with:
|
with:
|
||||||
run_number: ${{ matrix.run_number }}
|
run_number: ${{ matrix.run_number }}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,6 @@ concurrency:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
selfdrive_tests:
|
selfdrive_tests:
|
||||||
uses: sunnypilot/sunnypilot/.github/workflows/selfdrive_tests.yaml@master
|
uses: commaai/openpilot/.github/workflows/selfdrive_tests.yaml@master
|
||||||
with:
|
with:
|
||||||
run_number: ${{ inputs.run_number }}
|
run_number: ${{ inputs.run_number }}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ runs:
|
|||||||
scons -j$(nproc) --cache-populate"
|
scons -j$(nproc) --cache-populate"
|
||||||
- name: Save scons cache
|
- name: Save scons cache
|
||||||
uses: actions/cache/save@v4
|
uses: actions/cache/save@v4
|
||||||
if: (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new')
|
if: github.ref == 'refs/heads/master'
|
||||||
with:
|
with:
|
||||||
path: .ci_cache/scons_cache
|
path: .ci_cache/scons_cache
|
||||||
key: scons-${{ runner.arch }}-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
key: scons-${{ runner.arch }}-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ concurrency:
|
|||||||
jobs:
|
jobs:
|
||||||
docs:
|
docs:
|
||||||
name: build docs
|
name: build docs
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: commaai/timeout@v1
|
- uses: commaai/timeout@v1
|
||||||
|
|
||||||
@@ -35,13 +35,13 @@ jobs:
|
|||||||
|
|
||||||
# Push to docs.comma.ai
|
# Push to docs.comma.ai
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
if: github.ref == 'refs/heads/master' && github.repository == 'sunnypilot/sunnypilot'
|
if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot'
|
||||||
with:
|
with:
|
||||||
path: openpilot-docs
|
path: openpilot-docs
|
||||||
ssh-key: ${{ secrets.OPENPILOT_DOCS_KEY }}
|
ssh-key: ${{ secrets.OPENPILOT_DOCS_KEY }}
|
||||||
repository: sunnypilot/sunnypilot-docs
|
repository: commaai/openpilot-docs
|
||||||
- name: Push
|
- name: Push
|
||||||
if: github.ref == 'refs/heads/master' && github.repository == 'sunnypilot/sunnypilot'
|
if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot'
|
||||||
run: |
|
run: |
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
name: Sync comma's LFS
|
|
||||||
|
|
||||||
env:
|
|
||||||
LFS_URL: 'https://gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git/info/lfs'
|
|
||||||
LFS_PUSH_URL: 'ssh://git@gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git'
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 0 * * *' # Runs at 00:00 UTC every day
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- 'master-new'
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- 'master-new'
|
|
||||||
workflow_dispatch: # enables manual triggering
|
|
||||||
inputs:
|
|
||||||
upstream_branch:
|
|
||||||
default: 'master'
|
|
||||||
type: string
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
sync:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
# Skip if PR is in draft mode
|
|
||||||
if: (github.event_name != 'pull_request' || (github.event_name == 'pull_request' && github.event.pull_request.draft == false)) && !github.event.pull_request.head.repo.fork
|
|
||||||
steps:
|
|
||||||
- name: Checkout Repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: 'commaai/openpilot'
|
|
||||||
ref: ${{ inputs.upstream_branch }}
|
|
||||||
|
|
||||||
- name: LFS Fetch
|
|
||||||
run: |
|
|
||||||
git lfs fetch
|
|
||||||
|
|
||||||
- name: Set up Git
|
|
||||||
run: |
|
|
||||||
git config --global user.name 'GitHub Action'
|
|
||||||
git config --global user.email 'action@github.com'
|
|
||||||
|
|
||||||
- name: Set up SSH
|
|
||||||
uses: webfactory/ssh-agent@v0.9.0
|
|
||||||
with:
|
|
||||||
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: Add GitLab public keys
|
|
||||||
run: |
|
|
||||||
ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts
|
|
||||||
|
|
||||||
- name: Ensure branch
|
|
||||||
run: |
|
|
||||||
if git symbolic-ref -q HEAD >/dev/null; then
|
|
||||||
echo "Already on a branch, proceeding with push"
|
|
||||||
else
|
|
||||||
echo "Detached HEAD state detected, creating temporary branch"
|
|
||||||
git checkout -b temp_branch
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Update LFS Config
|
|
||||||
run: |
|
|
||||||
echo '[lfs]' > .lfsconfig
|
|
||||||
echo ' url = ${{ env.LFS_URL }}' >> .lfsconfig
|
|
||||||
echo ' pushurl = ${{ env.LFS_PUSH_URL }}' >> .lfsconfig
|
|
||||||
echo ' locksverify = false' >> .lfsconfig
|
|
||||||
|
|
||||||
- name: Push LFS
|
|
||||||
id: sync-and-commit
|
|
||||||
run: |
|
|
||||||
git lfs ls-files -l
|
|
||||||
git lfs push --all origin
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
name: "model review"
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, reopened, synchronize]
|
|
||||||
paths:
|
|
||||||
- 'selfdrive/modeld/models/*.onnx'
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
comment:
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
pull-requests: write
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.repository == 'commaai/openpilot'
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Checkout master
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: master
|
|
||||||
path: base
|
|
||||||
- run: git lfs pull
|
|
||||||
- run: cd base && git lfs pull
|
|
||||||
|
|
||||||
- run: pip install onnx
|
|
||||||
|
|
||||||
- name: scripts/reporter.py
|
|
||||||
id: report
|
|
||||||
run: |
|
|
||||||
echo "content<<EOF" >> $GITHUB_OUTPUT
|
|
||||||
echo "## Model Review" >> $GITHUB_OUTPUT
|
|
||||||
MASTER_PATH=${{ github.workspace }}/base python scripts/reporter.py >> $GITHUB_OUTPUT
|
|
||||||
echo "EOF" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Post model report comment
|
|
||||||
uses: marocchino/sticky-pull-request-comment@baa7203ed60924babbe5dcd0ac8eae3b66ec5e16
|
|
||||||
with:
|
|
||||||
header: model-review
|
|
||||||
message: ${{ steps.report.outputs.content }}
|
|
||||||
@@ -12,7 +12,7 @@ jobs:
|
|||||||
build_prebuilt:
|
build_prebuilt:
|
||||||
name: build prebuilt
|
name: build prebuilt
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.repository == 'sunnypilot/sunnypilot'
|
if: github.repository == 'commaai/openpilot'
|
||||||
env:
|
env:
|
||||||
PUSH_IMAGE: true
|
PUSH_IMAGE: true
|
||||||
permissions:
|
permissions:
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
name: Release Drafter
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master-new
|
|
||||||
- master
|
|
||||||
tags:
|
|
||||||
- 'v*'
|
|
||||||
pull_request_target:
|
|
||||||
types: [opened, reopened, synchronize]
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
update_release_draft:
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: release-drafter/release-drafter@v6
|
|
||||||
with:
|
|
||||||
config-name: release-drafter.yml
|
|
||||||
prerelease: ${{ !startsWith(github.ref, 'refs/tags/v') }}
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
@@ -8,11 +8,12 @@ jobs:
|
|||||||
build_masterci:
|
build_masterci:
|
||||||
name: build master-ci
|
name: build master-ci
|
||||||
env:
|
env:
|
||||||
ImageOS: ubuntu24
|
TARGET_DIR: /tmp/openpilot
|
||||||
|
ImageOS: ubuntu20
|
||||||
container:
|
container:
|
||||||
image: ghcr.io/commaai/openpilot-base:latest
|
image: ghcr.io/commaai/openpilot-base:latest
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.repository == 'sunnypilot/sunnypilot'
|
if: github.repository == 'commaai/openpilot'
|
||||||
permissions:
|
permissions:
|
||||||
checks: read
|
checks: read
|
||||||
contents: write
|
contents: write
|
||||||
@@ -22,7 +23,7 @@ jobs:
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y libyaml-dev
|
sudo apt-get install -y libyaml-dev
|
||||||
- name: Wait for green check mark
|
- name: Wait for green check mark
|
||||||
if: ${{ github.event_name == 'schedule' }}
|
if: ${{ github.event_name != 'workflow_dispatch' }}
|
||||||
uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc
|
uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc
|
||||||
with:
|
with:
|
||||||
ref: master
|
ref: master
|
||||||
@@ -38,5 +39,16 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
git config --global --add safe.directory '*'
|
git config --global --add safe.directory '*'
|
||||||
git lfs pull
|
git lfs pull
|
||||||
|
- name: Build master-ci
|
||||||
|
run: |
|
||||||
|
release/build_devel.sh
|
||||||
|
- name: Run tests
|
||||||
|
run: |
|
||||||
|
export PYTHONPATH=$TARGET_DIR
|
||||||
|
cd $TARGET_DIR
|
||||||
|
scons -j$(nproc)
|
||||||
|
pytest -n logical selfdrive/car/tests/test_car_interfaces.py
|
||||||
- name: Push master-ci
|
- name: Push master-ci
|
||||||
run: BRANCH=__nightly release/build_devel.sh
|
run: |
|
||||||
|
unset TARGET_DIR
|
||||||
|
BRANCH=master-ci release/build_devel.sh
|
||||||
|
|||||||
@@ -5,39 +5,13 @@ on:
|
|||||||
- cron: "0 14 * * 1" # every Monday at 2am UTC (6am PST)
|
- cron: "0 14 * * 1" # every Monday at 2am UTC (6am PST)
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
|
||||||
BASE_IMAGE: openpilot-base
|
|
||||||
BUILD: selfdrive/test/docker_build.sh base
|
|
||||||
RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update_translations:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.repository == 'commaai/openpilot'
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: ./.github/workflows/setup-with-retry
|
|
||||||
- name: Update translations
|
|
||||||
run: |
|
|
||||||
${{ env.RUN }} "python3 selfdrive/ui/update_translations.py --vanish"
|
|
||||||
- name: Create Pull Request
|
|
||||||
uses: peter-evans/create-pull-request@9153d834b60caba6d51c9b9510b087acf9f33f83
|
|
||||||
with:
|
|
||||||
author: Vehicle Researcher <user@comma.ai>
|
|
||||||
commit-message: "Update translations"
|
|
||||||
title: "[bot] Update translations"
|
|
||||||
body: "Automatic PR from repo-maintenance -> update_translations"
|
|
||||||
branch: "update-translations"
|
|
||||||
base: "master"
|
|
||||||
delete-branch: true
|
|
||||||
labels: bot
|
|
||||||
|
|
||||||
package_updates:
|
package_updates:
|
||||||
name: package_updates
|
name: package_updates
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: ghcr.io/commaai/openpilot-base:latest
|
image: ghcr.io/commaai/openpilot-base:latest
|
||||||
if: github.repository == 'sunnypilot/sunnypilot'
|
if: github.repository == 'commaai/openpilot'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -50,13 +24,12 @@ jobs:
|
|||||||
- name: bump submodules
|
- name: bump submodules
|
||||||
run: |
|
run: |
|
||||||
git config --global --add safe.directory '*'
|
git config --global --add safe.directory '*'
|
||||||
git submodule update --remote
|
git -c submodule."tinygrad".update=none submodule update --remote
|
||||||
git add .
|
git add .
|
||||||
- name: update car docs
|
- name: update car docs
|
||||||
run: |
|
run: |
|
||||||
export PYTHONPATH="$PWD"
|
|
||||||
scons -j$(nproc) --minimal opendbc_repo
|
scons -j$(nproc) --minimal opendbc_repo
|
||||||
python selfdrive/car/docs.py
|
PYTHONPATH=. 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@9153d834b60caba6d51c9b9510b087acf9f33f83
|
uses: peter-evans/create-pull-request@9153d834b60caba6d51c9b9510b087acf9f33f83
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- master-new
|
|
||||||
pull_request:
|
pull_request:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
@@ -15,11 +14,10 @@ on:
|
|||||||
type: string
|
type: string
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: selfdrive-tests-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new') && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
|
group: selfdrive-tests-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
env:
|
env:
|
||||||
REPORT_NAME: report-${{ inputs.run_number || '1' }}-${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new') && 'master' || github.event.number }}
|
|
||||||
PYTHONWARNINGS: error
|
PYTHONWARNINGS: error
|
||||||
BASE_IMAGE: openpilot-base
|
BASE_IMAGE: openpilot-base
|
||||||
AZURE_TOKEN: ${{ secrets.AZURE_COMMADATACI_OPENPILOTCI_TOKEN }}
|
AZURE_TOKEN: ${{ secrets.AZURE_COMMADATACI_OPENPILOTCI_TOKEN }}
|
||||||
@@ -33,10 +31,10 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_release:
|
build_release:
|
||||||
if: github.repository == 'commaai/openpilot' # build_release blocked for the time being to only comma as we may have a different process.
|
|
||||||
name: build release
|
name: build release
|
||||||
runs-on:
|
runs-on:
|
||||||
- 'ubuntu-24.04'
|
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||||
|
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||||
env:
|
env:
|
||||||
STRIPPED_DIR: /tmp/releasepilot
|
STRIPPED_DIR: /tmp/releasepilot
|
||||||
steps:
|
steps:
|
||||||
@@ -53,6 +51,10 @@ jobs:
|
|||||||
timeout-minutes: 1
|
timeout-minutes: 1
|
||||||
run: TARGET_DIR=$STRIPPED_DIR release/build_devel.sh
|
run: TARGET_DIR=$STRIPPED_DIR release/build_devel.sh
|
||||||
- uses: ./.github/workflows/setup-with-retry
|
- uses: ./.github/workflows/setup-with-retry
|
||||||
|
- name: Check submodules
|
||||||
|
if: github.repository == 'commaai/openpilot'
|
||||||
|
timeout-minutes: 3
|
||||||
|
run: release/check-submodules.sh
|
||||||
- name: Build openpilot and run checks
|
- name: Build openpilot and run checks
|
||||||
timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 10 || 30) }} # allow more time when we missed the scons cache
|
timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 10 || 30) }} # allow more time when we missed the scons cache
|
||||||
run: |
|
run: |
|
||||||
@@ -62,15 +64,20 @@ jobs:
|
|||||||
timeout-minutes: 1
|
timeout-minutes: 1
|
||||||
run: |
|
run: |
|
||||||
cd $STRIPPED_DIR
|
cd $STRIPPED_DIR
|
||||||
${{ env.RUN }} "release/check-dirty.sh"
|
${{ env.RUN }} "release/check-dirty.sh && \
|
||||||
- name: Check submodules
|
MAX_EXAMPLES=5 $PYTEST -m 'not slow' selfdrive/car system/manager"
|
||||||
if: github.repository == 'sunnypilot/sunnypilot'
|
- name: Static analysis
|
||||||
timeout-minutes: 3
|
timeout-minutes: 1
|
||||||
run: release/check-submodules.sh
|
run: |
|
||||||
|
cd $GITHUB_WORKSPACE
|
||||||
|
cp pyproject.toml $STRIPPED_DIR
|
||||||
|
cd $STRIPPED_DIR
|
||||||
|
${{ env.RUN }} "scripts/lint/lint.sh --skip check_added_large_files"
|
||||||
|
|
||||||
build:
|
build:
|
||||||
runs-on:
|
runs-on:
|
||||||
- 'ubuntu-24.04'
|
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||||
|
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -86,53 +93,34 @@ jobs:
|
|||||||
|
|
||||||
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' && 'namespace-profile-macos-8x14' || 'macos-latest' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- run: echo "CACHE_COMMIT_DATE=$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M')" >> $GITHUB_ENV
|
|
||||||
- name: Homebrew cache
|
- name: Homebrew cache
|
||||||
uses: ./.github/workflows/auto-cache
|
uses: ./.github/workflows/auto-cache
|
||||||
with:
|
with:
|
||||||
path: ~/Library/Caches/Homebrew
|
path: ~/Library/Caches/Homebrew
|
||||||
key: brew-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
|
||||||
restore-keys: |
|
|
||||||
brew-macos-${{ env.CACHE_COMMIT_DATE }}
|
|
||||||
brew-macos
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: ./tools/mac_setup.sh
|
run: ./tools/mac_setup.sh
|
||||||
env:
|
env:
|
||||||
# package install has DeprecationWarnings
|
# package install has DeprecationWarnings
|
||||||
PYTHONWARNINGS: default
|
PYTHONWARNINGS: default
|
||||||
- name: Save Homebrew cache
|
|
||||||
uses: actions/cache/save@v4
|
|
||||||
if: (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new')
|
|
||||||
with:
|
|
||||||
path: ~/Library/Caches/Homebrew
|
|
||||||
key: brew-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
|
||||||
- run: git lfs pull
|
- run: git lfs pull
|
||||||
|
- run: echo "CACHE_COMMIT_DATE=$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M')" >> $GITHUB_ENV
|
||||||
- name: Getting scons cache
|
- name: Getting scons cache
|
||||||
uses: ./.github/workflows/auto-cache
|
uses: ./.github/workflows/auto-cache
|
||||||
with:
|
with:
|
||||||
path: /tmp/scons_cache
|
path: /tmp/scons_cache
|
||||||
key: scons-${{ runner.arch }}-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
|
||||||
restore-keys: |
|
|
||||||
scons-${{ runner.arch }}-macos-${{ env.CACHE_COMMIT_DATE }}
|
|
||||||
scons-${{ runner.arch }}-macos
|
|
||||||
- name: Building openpilot
|
- name: Building openpilot
|
||||||
run: . .venv/bin/activate && scons -j$(nproc)
|
run: . .venv/bin/activate && scons -j$(nproc)
|
||||||
- name: Save scons cache
|
|
||||||
uses: actions/cache/save@v4
|
|
||||||
if: (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new')
|
|
||||||
with:
|
|
||||||
path: /tmp/scons_cache
|
|
||||||
key: scons-${{ runner.arch }}-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
|
||||||
|
|
||||||
static_analysis:
|
static_analysis:
|
||||||
name: static analysis
|
name: static analysis
|
||||||
runs-on:
|
runs-on:
|
||||||
- 'ubuntu-latest'
|
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||||
|
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||||
env:
|
env:
|
||||||
PYTHONWARNINGS: default
|
PYTHONWARNINGS: default
|
||||||
steps:
|
steps:
|
||||||
@@ -147,7 +135,8 @@ jobs:
|
|||||||
unit_tests:
|
unit_tests:
|
||||||
name: unit tests
|
name: unit tests
|
||||||
runs-on:
|
runs-on:
|
||||||
- 'ubuntu-24.04'
|
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||||
|
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -172,9 +161,9 @@ jobs:
|
|||||||
|
|
||||||
process_replay:
|
process_replay:
|
||||||
name: process replay
|
name: process replay
|
||||||
if: github.repository == 'commaai/openpilot' # disable process_replay for forks
|
|
||||||
runs-on:
|
runs-on:
|
||||||
- 'ubuntu-24.04'
|
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||||
|
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -226,7 +215,8 @@ jobs:
|
|||||||
test_cars:
|
test_cars:
|
||||||
name: cars
|
name: cars
|
||||||
runs-on:
|
runs-on:
|
||||||
- 'ubuntu-24.04'
|
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||||
|
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -241,11 +231,11 @@ jobs:
|
|||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: .ci_cache/comma_download_cache
|
path: .ci_cache/comma_download_cache
|
||||||
key: car_models-${{ hashFiles('selfdrive/car/tests/test_models.py', 'opendbc/car/tests/routes.py') }}-${{ matrix.job }}
|
key: car_models-${{ hashFiles('selfdrive/car/tests/test_models.py', 'selfdrive/car/tests/routes.py') }}-${{ matrix.job }}
|
||||||
- name: Build openpilot
|
- name: Build openpilot
|
||||||
run: ${{ env.RUN }} "scons -j$(nproc)"
|
run: ${{ env.RUN }} "scons -j$(nproc)"
|
||||||
- name: Test car models
|
- name: Test car models
|
||||||
timeout-minutes: ${{ contains(runner.name, 'nsc') && (steps.routes-cache.outputs.cache-hit == 'true') && 1 || 6 }}
|
timeout-minutes: ${{ contains(runner.name, 'nsc') && (steps.routes-cache.outputs.cache-hit == 'true') && 1 || 20 }}
|
||||||
run: |
|
run: |
|
||||||
${{ env.RUN }} "MAX_EXAMPLES=1 $PYTEST selfdrive/car/tests/test_models.py && \
|
${{ env.RUN }} "MAX_EXAMPLES=1 $PYTEST selfdrive/car/tests/test_models.py && \
|
||||||
chmod -R 777 /tmp/comma_download_cache"
|
chmod -R 777 /tmp/comma_download_cache"
|
||||||
@@ -317,8 +307,8 @@ jobs:
|
|||||||
simulator_driving:
|
simulator_driving:
|
||||||
name: simulator driving
|
name: simulator driving
|
||||||
runs-on:
|
runs-on:
|
||||||
- 'ubuntu-24.04'
|
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||||
if: (github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))
|
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -332,13 +322,14 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
${{ env.RUN }} "source selfdrive/test/setup_xvfb.sh && \
|
${{ env.RUN }} "source selfdrive/test/setup_xvfb.sh && \
|
||||||
source selfdrive/test/setup_vsound.sh && \
|
source selfdrive/test/setup_vsound.sh && \
|
||||||
CI=1 pytest -s tools/sim/tests/test_metadrive_bridge.py"
|
CI=1 pytest tools/sim/tests/test_metadrive_bridge.py"
|
||||||
|
|
||||||
create_ui_report:
|
create_ui_report:
|
||||||
# This job name needs to be the same as UI_JOB_NAME in ui_preview.yaml
|
# This job name needs to be the same as UI_JOB_NAME in ui_preview.yaml
|
||||||
name: Create UI Report
|
name: Create UI Report
|
||||||
runs-on:
|
runs-on:
|
||||||
- 'ubuntu-24.04'
|
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||||
|
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -353,7 +344,7 @@ jobs:
|
|||||||
- name: Build openpilot
|
- name: Build openpilot
|
||||||
run: ${{ env.RUN }} "scons -j$(nproc)"
|
run: ${{ env.RUN }} "scons -j$(nproc)"
|
||||||
- name: Create Test Report
|
- name: Create Test Report
|
||||||
timeout-minutes: ${{ ((steps.frames-cache.outputs.cache-hit == 'true') && 2 || 4) }}
|
timeout-minutes: ${{ ((steps.frames-cache.outputs.cache-hit == 'true') && 1 || 3) }}
|
||||||
run: >
|
run: >
|
||||||
${{ env.RUN }} "PYTHONWARNINGS=ignore &&
|
${{ env.RUN }} "PYTHONWARNINGS=ignore &&
|
||||||
source selfdrive/test/setup_xvfb.sh &&
|
source selfdrive/test/setup_xvfb.sh &&
|
||||||
@@ -362,5 +353,5 @@ jobs:
|
|||||||
- name: Upload Test Report
|
- name: Upload Test Report
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ env.REPORT_NAME }}
|
name: report-${{ inputs.run_number || '1' }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master' || github.event.number }}
|
||||||
path: selfdrive/ui/tests/test_ui/report_1/screenshots
|
path: selfdrive/ui/tests/test_ui/report_1/screenshots
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ runs:
|
|||||||
- shell: bash
|
- shell: bash
|
||||||
name: No retries!
|
name: No retries!
|
||||||
run: |
|
run: |
|
||||||
if [ "${{ github.run_attempt }}" -gt ${{ github.event.pull_request.head.repo.fork && github.event.pull_request.author_association == 'NONE' && 2 || 1}} ]; then
|
if [ "${{ github.run_attempt }}" -gt 1 ]; then
|
||||||
echo -e "\033[0;31m##################################################"
|
echo -e "\033[0;31m##################################################"
|
||||||
echo -e "\033[0;31m Retries not allowed! Fix the flaky test! "
|
echo -e "\033[0;31m Retries not allowed! Fix the flaky test! "
|
||||||
echo -e "\033[0;31m##################################################\033[0m"
|
echo -e "\033[0;31m##################################################\033[0m"
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ jobs:
|
|||||||
stale-pr-message: 'This PR has had no activity for ${{ env.DAYS_BEFORE_PR_STALE }} days. It will be automatically closed in ${{ env.DAYS_BEFORE_PR_CLOSE }} days if there is no activity.'
|
stale-pr-message: 'This PR has had no activity for ${{ env.DAYS_BEFORE_PR_STALE }} days. It will be automatically closed in ${{ env.DAYS_BEFORE_PR_CLOSE }} days if there is no activity.'
|
||||||
close-pr-message: 'This PR has been automatically closed due to inactivity. Feel free to re-open once activity resumes.'
|
close-pr-message: 'This PR has been automatically closed due to inactivity. Feel free to re-open once activity resumes.'
|
||||||
stale-pr-label: stale
|
stale-pr-label: stale
|
||||||
delete-branch: ${{ github.event.pull_request.head.repo.full_name == 'sunnypilot/sunnypilot' }} # only delete branches on the main repo
|
delete-branch: ${{ github.event.pull_request.head.repo.full_name == 'commaai/openpilot' }} # only delete branches on the main repo
|
||||||
exempt-pr-labels: "ignore stale,needs testing" # if wip or it needs testing from the community, don't mark as stale
|
exempt-pr-labels: "ignore stale,needs testing" # if wip or it needs testing from the community, don't mark as stale
|
||||||
days-before-pr-stale: ${{ env.DAYS_BEFORE_PR_STALE }}
|
days-before-pr-stale: ${{ env.DAYS_BEFORE_PR_STALE }}
|
||||||
days-before-pr-close: ${{ env.DAYS_BEFORE_PR_CLOSE }}
|
days-before-pr-close: ${{ env.DAYS_BEFORE_PR_CLOSE }}
|
||||||
|
|||||||
@@ -1,169 +0,0 @@
|
|||||||
name: Build Model from Upstream
|
|
||||||
|
|
||||||
env:
|
|
||||||
BUILD_DIR: "/data/openpilot"
|
|
||||||
OUTPUT_DIR: ${{ github.workspace }}/output
|
|
||||||
SCONS_CACHE_DIR: ${{ github.workspace }}/release/ci/scons_cache
|
|
||||||
UPSTREAM_REPO: "commaai/openpilot"
|
|
||||||
TINYGRAD_PATH: ${{ github.workspace }}/tinygrad_repo
|
|
||||||
MODELS_DIR: ${{ github.workspace }}/selfdrive/modeld/models
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
upstream_branch:
|
|
||||||
description: 'Upstream branch to build from'
|
|
||||||
required: true
|
|
||||||
default: 'master'
|
|
||||||
type: string
|
|
||||||
custom_name:
|
|
||||||
description: 'Custom name for the model (no date, only name)'
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
is_20hz:
|
|
||||||
description: 'Is this a 20Hz model'
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: true
|
|
||||||
|
|
||||||
|
|
||||||
run-name: Build model [${{ inputs.custom_name || inputs.upstream_branch }}] from ref [${{ inputs.upstream_branch }}]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
get_model:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
model_date: ${{ steps.commit-date.outputs.model_date }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: ${{ env.UPSTREAM_REPO }}
|
|
||||||
ref: ${{ github.event.inputs.upstream_branch }}
|
|
||||||
submodules: recursive
|
|
||||||
- name: Get commit date
|
|
||||||
id: commit-date
|
|
||||||
run: |
|
|
||||||
# Get the commit date in YYYY-MM-DD format
|
|
||||||
commit_date=$(git log -1 --format=%cd --date=format:'%B %d, %Y')
|
|
||||||
echo "model_date=${commit_date}" >> $GITHUB_OUTPUT
|
|
||||||
cat $GITHUB_OUTPUT
|
|
||||||
- run: git lfs pull
|
|
||||||
- name: 'Upload Artifact'
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: models
|
|
||||||
path: ${{ github.workspace }}/selfdrive/modeld/models/*.onnx
|
|
||||||
|
|
||||||
build_model:
|
|
||||||
runs-on: self-hosted
|
|
||||||
needs: get_model
|
|
||||||
env:
|
|
||||||
MODEL_NAME: ${{ inputs.custom_name || inputs.upstream_branch }} (${{ needs.get_model.outputs.model_date }})
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
|
|
||||||
- run: git lfs pull
|
|
||||||
- name: Cache SCons
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ${{env.SCONS_CACHE_DIR}}
|
|
||||||
key: scons-${{ runner.os }}-${{ runner.arch }}-${{ github.head_ref || github.ref_name }}-model-${{ github.sha }}
|
|
||||||
# Note: GitHub Actions enforces cache isolation between different build sources (PR builds, workflow dispatches, etc.)
|
|
||||||
# for security. Only caches from the default branch are shared across all builds. This is by design and cannot be overridden.
|
|
||||||
restore-keys: |
|
|
||||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ github.head_ref || github.ref_name }}-model
|
|
||||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ github.head_ref || github.ref_name }}
|
|
||||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.MASTER_NEW_BRANCH }}-model
|
|
||||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.MASTER_BRANCH }}-model
|
|
||||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.MASTER_NEW_BRANCH }}
|
|
||||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.MASTER_BRANCH }}
|
|
||||||
scons-${{ runner.os }}-${{ runner.arch }}
|
|
||||||
|
|
||||||
- name: Set environment variables
|
|
||||||
id: set-env
|
|
||||||
run: |
|
|
||||||
# Set up common environment
|
|
||||||
source /etc/profile;
|
|
||||||
export UV_PROJECT_ENVIRONMENT=${HOME}/venv
|
|
||||||
export VIRTUAL_ENV=$UV_PROJECT_ENVIRONMENT
|
|
||||||
printenv >> $GITHUB_ENV
|
|
||||||
if [[ "${{ runner.debug }}" == "1" ]]; then
|
|
||||||
cat $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Setup build environment
|
|
||||||
run: |
|
|
||||||
mkdir -p "${BUILD_DIR}/"
|
|
||||||
sudo find $BUILD_DIR/ -mindepth 1 -delete
|
|
||||||
echo "Starting build stage..."
|
|
||||||
echo "BUILD_DIR: ${BUILD_DIR}"
|
|
||||||
echo "CI_DIR: ${CI_DIR}"
|
|
||||||
echo "VERSION: ${{ steps.set-env.outputs.version }}"
|
|
||||||
echo "UV_PROJECT_ENVIRONMENT: ${UV_PROJECT_ENVIRONMENT}"
|
|
||||||
echo "VIRTUAL_ENV: ${VIRTUAL_ENV}"
|
|
||||||
echo "-------"
|
|
||||||
if [[ "${{ runner.debug }}" == "1" ]]; then
|
|
||||||
printenv
|
|
||||||
fi
|
|
||||||
PYTHONPATH=$PYTHONPATH:${{ github.workspace }}/ ${{ github.workspace }}/scripts/manage-powersave.py --disable
|
|
||||||
rm -rf ${{ env.MODELS_DIR }}/*.onnx
|
|
||||||
|
|
||||||
- name: Download model artifacts
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: models
|
|
||||||
path: ${{ github.workspace }}/selfdrive/modeld/models
|
|
||||||
|
|
||||||
- name: Build Model
|
|
||||||
run: |
|
|
||||||
source /etc/profile
|
|
||||||
export UV_PROJECT_ENVIRONMENT=${HOME}/venv
|
|
||||||
export VIRTUAL_ENV=$UV_PROJECT_ENVIRONMENT
|
|
||||||
export PYTHONPATH="${PYTHONPATH}:${{ env.TINYGRAD_PATH }}"
|
|
||||||
|
|
||||||
# Loop through all .onnx files
|
|
||||||
find "${{ env.MODELS_DIR }}" -maxdepth 1 -name '*.onnx' | while IFS= read -r onnx_file; do
|
|
||||||
base_name=$(basename "$onnx_file" .onnx)
|
|
||||||
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"
|
|
||||||
QCOM=1 python3 "${{ env.MODELS_DIR }}/../get_model_metadata.py" "$onnx_file" || true
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Prepare Output
|
|
||||||
run: |
|
|
||||||
sudo rm -rf ${{ env.OUTPUT_DIR }}
|
|
||||||
mkdir -p ${{ env.OUTPUT_DIR }}
|
|
||||||
|
|
||||||
# Copy the model files
|
|
||||||
rsync -avm \
|
|
||||||
--include='*.dlc' \
|
|
||||||
--include='*.thneed' \
|
|
||||||
--include='*.pkl' \
|
|
||||||
--include='*.onnx' \
|
|
||||||
--exclude='*' \
|
|
||||||
--delete-excluded \
|
|
||||||
--chown=comma:comma \
|
|
||||||
${{ env.MODELS_DIR }}/ ${{ env.OUTPUT_DIR }}/
|
|
||||||
|
|
||||||
python3 "${{ github.workspace }}/release/ci/model_generator.py" \
|
|
||||||
--model-dir "${{ env.MODELS_DIR }}" \
|
|
||||||
--output-dir "${{ env.OUTPUT_DIR }}" \
|
|
||||||
--custom-name "${{ env.MODEL_NAME }}" \
|
|
||||||
--upstream-branch "${{ inputs.upstream_branch }}" \
|
|
||||||
${{ inputs.is_20hz && '--is-20hz' || '' }}
|
|
||||||
|
|
||||||
- name: Upload Build Artifacts
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: model-${{ env.MODEL_NAME }}-${{ github.run_number }}
|
|
||||||
path: ${{ env.OUTPUT_DIR }}
|
|
||||||
|
|
||||||
- name: Re-enable powersave
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
PYTHONPATH=$PYTHONPATH:${{ github.workspace }}/ ${{ github.workspace }}/scripts/manage-powersave.py --enable
|
|
||||||
@@ -1,332 +0,0 @@
|
|||||||
name: sunnypilot prebuilt action
|
|
||||||
|
|
||||||
env:
|
|
||||||
BUILD_DIR: "/data/openpilot"
|
|
||||||
OUTPUT_DIR: ${{ github.workspace }}/output
|
|
||||||
CI_DIR: ${{ github.workspace }}/release/ci
|
|
||||||
SCONS_CACHE_DIR: ${{ github.workspace }}/release/ci/scons_cache
|
|
||||||
PUBLIC_REPO_URL: "https://github.com/sunnypilot/sunnypilot"
|
|
||||||
|
|
||||||
# Branch configurations
|
|
||||||
STAGING_C3_SOURCE_BRANCH: ${{ vars.STAGING_C3_SOURCE_BRANCH || 'master-new' }} # vars are set on repo settings.
|
|
||||||
DEV_C3_SOURCE_BRANCH: ${{ vars.DEV_C3_SOURCE_BRANCH || 'master-dev-c3-new' }} # vars are set on repo settings.
|
|
||||||
|
|
||||||
# Target branch configurations
|
|
||||||
STAGING_TARGET_BRANCH: ${{ vars.STAGING_TARGET_BRANCH || 'staging-c3-new' }} # vars are set on repo settings.
|
|
||||||
DEV_TARGET_BRANCH: ${{ vars.DEV_TARGET_BRANCH || 'dev-c3-new' }} # vars are set on repo settings.
|
|
||||||
RELEASE_TARGET_BRANCH: ${{ vars.RELEASE_TARGET_BRANCH || 'release-c3-new' }} # vars are set on repo settings.
|
|
||||||
|
|
||||||
# Runtime configuration
|
|
||||||
SOURCE_BRANCH: "${{ github.head_ref || github.ref_name }}"
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master, master-new, master-dev-c3-new ]
|
|
||||||
tags: [ '*' ]
|
|
||||||
pull_request_target:
|
|
||||||
types: [ labeled ]
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
wait_for_tests:
|
|
||||||
description: 'Wait for selfdrive_tests to finish'
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: false
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
validate_tests:
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
if: ((github.event_name == 'workflow_dispatch' && inputs.wait_for_tests) || contains(github.event_name, 'pull_request') && (github.event.action == 'labeled' && github.event.label.name == 'prebuilt'))
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Wait for Tests
|
|
||||||
uses: ./.github/workflows/wait-for-action # Path to where you place the action
|
|
||||||
with:
|
|
||||||
workflow: selfdrive_tests.yaml # The workflow file to monitor
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
build:
|
|
||||||
needs: [ validate_tests ]
|
|
||||||
concurrency:
|
|
||||||
group: build-${{ github.head_ref || github.ref_name }}
|
|
||||||
cancel-in-progress: false
|
|
||||||
runs-on: self-hosted
|
|
||||||
outputs:
|
|
||||||
new_branch: ${{ steps.set-env.outputs.new_branch }}
|
|
||||||
version: ${{ steps.set-env.outputs.version }}
|
|
||||||
extra_version_identifier: ${{ steps.set-env.outputs.extra_version_identifier }}
|
|
||||||
commit_sha: ${{ steps.set-env.outputs.commit_sha }}
|
|
||||||
if: ${{ (always() && !failure() && !cancelled()) && (!contains(github.event_name, 'pull_request') || (github.event.action == 'labeled' && github.event.label.name == 'prebuilt')) }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
ref: ${{ env.SOURCE_BRANCH }}
|
|
||||||
repository: ${{ github.event.pull_request.head.repo.fork && github.event.pull_request.head.repo.full_name || github.repository }}
|
|
||||||
- run: git lfs pull
|
|
||||||
|
|
||||||
- name: Cache SCons
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ${{env.SCONS_CACHE_DIR}}
|
|
||||||
key: scons-${{ runner.os }}-${{ runner.arch }}-${{ env.SOURCE_BRANCH }}-${{ github.sha }}
|
|
||||||
# Note: GitHub Actions enforces cache isolation between different build sources (PR builds, workflow dispatches, etc.)
|
|
||||||
# for security. Only caches from the default branch are shared across all builds. This is by design and cannot be overridden.
|
|
||||||
restore-keys: |
|
|
||||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.SOURCE_BRANCH }}
|
|
||||||
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.STAGING_C3_SOURCE_BRANCH }}
|
|
||||||
scons-${{ runner.os }}-${{ runner.arch }}
|
|
||||||
|
|
||||||
- name: Set Feature Branch Prebuilt Configuration
|
|
||||||
id: set_feature_configuration
|
|
||||||
if: (
|
|
||||||
!(env.SOURCE_BRANCH == env.DEV_C3_SOURCE_BRANCH) &&
|
|
||||||
!(env.SOURCE_BRANCH == env.STAGING_C3_SOURCE_BRANCH) &&
|
|
||||||
!(startsWith(github.ref, 'refs/tags/'))
|
|
||||||
)
|
|
||||||
run: |
|
|
||||||
echo "NEW_BRANCH=${{ env.SOURCE_BRANCH }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}-prebuilt" >> $GITHUB_ENV
|
|
||||||
echo "VERSION=$(date '+%Y.%m.%d')-${{ github.run_number }}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Set dev-c3-new prebuilt Configuration
|
|
||||||
id: set_dev_configuration
|
|
||||||
if: (
|
|
||||||
steps.set_feature_configuration.outcome == 'skipped' &&
|
|
||||||
env.SOURCE_BRANCH == env.DEV_C3_SOURCE_BRANCH
|
|
||||||
)
|
|
||||||
run: |
|
|
||||||
echo "NEW_BRANCH=${{ env.DEV_TARGET_BRANCH }}" >> $GITHUB_ENV
|
|
||||||
echo "VERSION=$(date '+%Y.%m.%d')-${{ github.run_number }}" >> $GITHUB_ENV
|
|
||||||
echo "EXTRA_VERSION_IDENTIFIER=${{ github.run_number }}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Set staging-c3-new prebuilt Configuration
|
|
||||||
id: set_staging_configuration
|
|
||||||
if: (
|
|
||||||
steps.set_feature_configuration.outcome == 'skipped' &&
|
|
||||||
!contains(github.event_name, 'pull_request') &&
|
|
||||||
steps.set_dev_configuration.outcome == 'skipped' &&
|
|
||||||
(env.SOURCE_BRANCH == env.STAGING_C3_SOURCE_BRANCH)
|
|
||||||
)
|
|
||||||
run: |
|
|
||||||
echo "NEW_BRANCH=${{ env.STAGING_TARGET_BRANCH }}" >> $GITHUB_ENV
|
|
||||||
echo "EXTRA_VERSION_IDENTIFIER=staging" >> $GITHUB_ENV
|
|
||||||
echo "VERSION=$(cat common/version.h | grep COMMA_VERSION | sed -e 's/[^0-9|.]//g')-staging" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Set release-c3-new prebuilt Configuration
|
|
||||||
id: set_tag_configuration
|
|
||||||
if: (
|
|
||||||
steps.set_feature_configuration.outcome == 'skipped' &&
|
|
||||||
!contains(github.event_name, 'pull_request') &&
|
|
||||||
steps.set_staging_configuration.outcome == 'skipped' &&
|
|
||||||
startsWith(github.ref, 'refs/tags/')
|
|
||||||
)
|
|
||||||
run: |
|
|
||||||
echo "NEW_BRANCH=${{ env.RELEASE_TARGET_BRANCH }}" >> $GITHUB_ENV
|
|
||||||
echo "EXTRA_VERSION_IDENTIFIER=release" >> $GITHUB_ENV
|
|
||||||
echo "VERSION=$(cat common/version.h | grep COMMA_VERSION | sed -e 's/[^0-9|.]//g')-release" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Set environment variables
|
|
||||||
id: set-env
|
|
||||||
run: |
|
|
||||||
# Write to GITHUB_OUTPUT from environment variables
|
|
||||||
echo "new_branch=$NEW_BRANCH" >> $GITHUB_OUTPUT
|
|
||||||
[[ ! -z "$EXTRA_VERSION_IDENTIFIER" ]] && echo "extra_version_identifier=$EXTRA_VERSION_IDENTIFIER" >> $GITHUB_OUTPUT
|
|
||||||
[[ ! -z "$VERSION" ]] && echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
||||||
echo "commit_sha=${{ github.sha }}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
# Set up common environment
|
|
||||||
source /etc/profile;
|
|
||||||
export UV_PROJECT_ENVIRONMENT=${HOME}/venv
|
|
||||||
export VIRTUAL_ENV=$UV_PROJECT_ENVIRONMENT
|
|
||||||
printenv >> $GITHUB_ENV
|
|
||||||
if [[ "${{ runner.debug }}" == "1" ]]; then
|
|
||||||
cat $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Setup build environment
|
|
||||||
run: |
|
|
||||||
mkdir -p "${BUILD_DIR}/"
|
|
||||||
sudo find $BUILD_DIR/ -mindepth 1 -delete
|
|
||||||
echo "Starting build stage..."
|
|
||||||
echo "BUILD_DIR: ${BUILD_DIR}"
|
|
||||||
echo "CI_DIR: ${CI_DIR}"
|
|
||||||
echo "VERSION: ${{ steps.set-env.outputs.version }}"
|
|
||||||
echo "UV_PROJECT_ENVIRONMENT: ${UV_PROJECT_ENVIRONMENT}"
|
|
||||||
echo "VIRTUAL_ENV: ${VIRTUAL_ENV}"
|
|
||||||
echo "-------"
|
|
||||||
if [[ "${{ runner.debug }}" == "1" ]]; then
|
|
||||||
printenv
|
|
||||||
fi
|
|
||||||
PYTHONPATH=$PYTHONPATH:${{ github.workspace }}/ ${{ github.workspace }}/scripts/manage-powersave.py --disable
|
|
||||||
|
|
||||||
- name: Build Main Project
|
|
||||||
run: |
|
|
||||||
export PYTHONPATH="$BUILD_DIR"
|
|
||||||
./release/release_files.py | sort | uniq | rsync -rRl${RUNNER_DEBUG:+v} --files-from=- . $BUILD_DIR/
|
|
||||||
cd $BUILD_DIR
|
|
||||||
sed -i '/from .board.jungle import PandaJungle, PandaJungleDFU/s/^/#/' panda/__init__.py
|
|
||||||
scons -j$(nproc) cache_dir=${{env.SCONS_CACHE_DIR}} --minimal
|
|
||||||
touch ${BUILD_DIR}/prebuilt
|
|
||||||
if [[ "${{ runner.debug }}" == "1" ]]; then
|
|
||||||
ls -la ${BUILD_DIR}
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Prepare Output
|
|
||||||
run: |
|
|
||||||
sudo rm -rf ${OUTPUT_DIR}
|
|
||||||
mkdir -p ${OUTPUT_DIR}
|
|
||||||
rsync -am${RUNNER_DEBUG:+v} \
|
|
||||||
--include='**/panda/board/' \
|
|
||||||
--include='**/panda/board/obj' \
|
|
||||||
--include='**/panda/board/obj/panda.bin.signed' \
|
|
||||||
--include='**/panda/board/obj/panda_h7.bin.signed' \
|
|
||||||
--include='**/panda/board/obj/bootstub.panda.bin' \
|
|
||||||
--include='**/panda/board/obj/bootstub.panda_h7.bin' \
|
|
||||||
--exclude='.sconsign.dblite' \
|
|
||||||
--exclude='*.a' \
|
|
||||||
--exclude='*.o' \
|
|
||||||
--exclude='*.os' \
|
|
||||||
--exclude='*.pyc' \
|
|
||||||
--exclude='moc_*' \
|
|
||||||
--exclude='*.cc' \
|
|
||||||
--exclude='Jenkinsfile' \
|
|
||||||
--exclude='supercombo.onnx' \
|
|
||||||
--exclude='**/panda/board/*' \
|
|
||||||
--exclude='**/panda/board/obj/**' \
|
|
||||||
--exclude='**/panda/certs/' \
|
|
||||||
--exclude='**/panda/crypto/' \
|
|
||||||
--exclude='**/release/' \
|
|
||||||
--exclude='**/.github/' \
|
|
||||||
--exclude='**/selfdrive/ui/replay/' \
|
|
||||||
--exclude='**/__pycache__/' \
|
|
||||||
--exclude='**/selfdrive/ui/*.h' \
|
|
||||||
--exclude='**/selfdrive/ui/**/*.h' \
|
|
||||||
--exclude='**/selfdrive/ui/qt/offroad/sunnypilot/' \
|
|
||||||
--exclude='${{env.SCONS_CACHE_DIR}}' \
|
|
||||||
--exclude='**/.git/' \
|
|
||||||
--exclude='**/SConstruct' \
|
|
||||||
--exclude='**/SConscript' \
|
|
||||||
--exclude='**/.venv/' \
|
|
||||||
--delete-excluded \
|
|
||||||
--chown=comma:comma \
|
|
||||||
${BUILD_DIR}/ ${OUTPUT_DIR}/
|
|
||||||
|
|
||||||
- name: 'Tar.gz files'
|
|
||||||
run: |
|
|
||||||
tar czf prebuilt.tar.gz -C ${{ env.OUTPUT_DIR }} .
|
|
||||||
ls -la prebuilt.tar.gz
|
|
||||||
|
|
||||||
- name: 'Upload Artifact'
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: prebuilt
|
|
||||||
path: prebuilt.tar.gz
|
|
||||||
|
|
||||||
- name: Re-enable powersave
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
PYTHONPATH=$PYTHONPATH:${{ github.workspace }}/ ${{ github.workspace }}/scripts/manage-powersave.py --enable
|
|
||||||
|
|
||||||
|
|
||||||
publish:
|
|
||||||
concurrency:
|
|
||||||
group: publish-${{ github.head_ref || github.ref_name }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
if: ${{ (always() && !failure() && !cancelled()) && (!contains(github.event_name, 'pull_request') || (github.event.action == 'labeled' && github.event.label.name == 'prebuilt')) }}
|
|
||||||
needs: [ build ]
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
environment: ${{ (contains(fromJSON(vars.AUTO_DEPLOY_PREBUILT_BRANCHES), github.head_ref || github.ref_name) || contains(github.event.pull_request.labels.*.name, 'prebuilt')) && 'auto-deploy' || 'feature-branch' }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Download build artifacts
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: prebuilt
|
|
||||||
|
|
||||||
- name: Untar prebuilt
|
|
||||||
run: |
|
|
||||||
mkdir -p ${{ env.OUTPUT_DIR }}
|
|
||||||
tar xzf prebuilt.tar.gz -C ${{ env.OUTPUT_DIR }}
|
|
||||||
|
|
||||||
- name: Configure Git
|
|
||||||
run: |
|
|
||||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
|
||||||
git config --global user.name "github-actions[bot]"
|
|
||||||
|
|
||||||
- name: Publish to Public Repository
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
echo '${{ toJSON(needs.build.outputs) }}'
|
|
||||||
ls -la ${{ env.OUTPUT_DIR }}
|
|
||||||
|
|
||||||
${{ env.CI_DIR }}/publish.sh \
|
|
||||||
"${{ github.workspace }}" \
|
|
||||||
"${{ env.OUTPUT_DIR }}" \
|
|
||||||
"${{ needs.build.outputs.new_branch }}" \
|
|
||||||
"${{ needs.build.outputs.version }}" \
|
|
||||||
"https://x-access-token:${{github.token}}@github.com/sunnypilot/sunnypilot.git" \
|
|
||||||
"-${{ needs.build.outputs.extra_version_identifier }}"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "---- ℹ️ To update the list of branches that auto deploy prebuilts -----"
|
|
||||||
echo ""
|
|
||||||
echo "1. Go to: ${{ github.server_url }}/${{ github.repository }}/settings/variables/actions/AUTO_DEPLOY_PREBUILT_BRANCHES"
|
|
||||||
echo "2. Current value: ${{ vars.AUTO_DEPLOY_PREBUILT_BRANCHES }}"
|
|
||||||
echo "3. Update as needed (JSON array with no spaces)"
|
|
||||||
|
|
||||||
notify:
|
|
||||||
needs: [ build, publish ]
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
if: ${{ (always() && !failure() && !cancelled()) && (!contains(github.event_name, 'pull_request') || (github.event.action == 'labeled' && github.event.label.name == 'prebuilt')) }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Setup Alpine Linux environment
|
|
||||||
uses: jirutka/setup-alpine@v1.2.0
|
|
||||||
with:
|
|
||||||
packages: 'jq gettext curl'
|
|
||||||
|
|
||||||
- name: Send Discord Notification
|
|
||||||
env:
|
|
||||||
DISCORD_WEBHOOK: ${{ contains(fromJSON(vars.DEV_FEEDBACK_NOTIFICATION_BRANCHES), env.SOURCE_BRANCH) && secrets.DISCORD_DEV_FEEDBACK_CHANNEL_WEBHOOK || secrets.DISCORD_DEV_PRIVATE_CHANNEL_WEBHOOK }}
|
|
||||||
run: |
|
|
||||||
TEMPLATE='${{ vars.DISCORD_GENERAL_UPDATE_NOTICE }}'
|
|
||||||
export EXTRA_VERSION_IDENTIFIER="${{ needs.build.outputs.extra_version_identifier }}"
|
|
||||||
export VERSION="${{ needs.build.outputs.version }}"
|
|
||||||
export branch_name=${{ env.SOURCE_BRANCH }}
|
|
||||||
export new_branch=${{ needs.build.outputs.new_branch }}
|
|
||||||
export extra_version_identifier=${{ needs.build.outputs.extra_version_identifier || github.run_number}}
|
|
||||||
echo ${TEMPLATE} | envsubst | jq -c '.' | tee payload.json
|
|
||||||
curl -X POST -H "Content-Type: application/json" -d @payload.json $DISCORD_WEBHOOK
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "---- ℹ️ To update the list of branches that notify to dev-feedback -----"
|
|
||||||
echo ""
|
|
||||||
echo "1. Go to: ${{ github.server_url }}/${{ github.repository }}/settings/variables/actions/DEV_FEEDBACK_NOTIFICATION_BRANCHES"
|
|
||||||
echo "2. Current value: ${{ vars.DEV_FEEDBACK_NOTIFICATION_BRANCHES }}"
|
|
||||||
echo "3. Update as needed (JSON array with no spaces)"
|
|
||||||
shell: alpine.sh {0}
|
|
||||||
|
|
||||||
manage-pr-labels:
|
|
||||||
name: Remove prebuilt label
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: (always() && contains(github.event_name, 'pull_request') && (github.event.action == 'labeled' && github.event.label.name == 'prebuilt'))
|
|
||||||
env:
|
|
||||||
LABEL: prebuilt
|
|
||||||
steps:
|
|
||||||
- name: Remove trust-fork-pr label if present
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
with:
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
script: |
|
|
||||||
const prNumber = context.payload.pull_request.number;
|
|
||||||
|
|
||||||
await github.rest.issues.removeLabel({
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
issue_number: prNumber,
|
|
||||||
name: process.env.LABEL
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`Removed '${process.env.LABEL}' label from PR #${prNumber}`);
|
|
||||||
@@ -1,224 +0,0 @@
|
|||||||
name: Build dev-c3-new
|
|
||||||
|
|
||||||
env:
|
|
||||||
DEFAULT_SOURCE_BRANCH: "master-new"
|
|
||||||
DEFAULT_TARGET_BRANCH: "master-dev-c3-new"
|
|
||||||
PR_LABEL: "dev-c3"
|
|
||||||
LFS_URL: 'https://gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git/info/lfs'
|
|
||||||
LFS_PUSH_URL: 'ssh://git@gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git'
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
- master-new
|
|
||||||
pull_request_target:
|
|
||||||
types: [ labeled ]
|
|
||||||
branches:
|
|
||||||
- 'master'
|
|
||||||
- 'master-new'
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
source_branch:
|
|
||||||
description: 'Source branch to reset from'
|
|
||||||
required: true
|
|
||||||
default: 'master-new'
|
|
||||||
type: string
|
|
||||||
target_branch:
|
|
||||||
description: 'Target branch to reset and squash into'
|
|
||||||
required: true
|
|
||||||
default: 'master-dev-c3-new'
|
|
||||||
type: string
|
|
||||||
cancel_in_progress:
|
|
||||||
description: 'Cancel any in-progress runs of this workflow'
|
|
||||||
required: false
|
|
||||||
default: true
|
|
||||||
type: boolean
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}
|
|
||||||
cancel-in-progress: ${{ inputs.cancel_in_progress || github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
reset-and-squash:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: (
|
|
||||||
(github.event_name == 'workflow_dispatch')
|
|
||||||
|| (github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch))
|
|
||||||
|| (contains(github.event_name, 'pull_request') && ((github.event.action == 'labeled' && (github.event.label.name == 'dev-c3' || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, 'dev-c3'))))
|
|
||||||
)
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0 # Fetch all history for all branches
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Wait for Tests
|
|
||||||
uses: ./.github/workflows/wait-for-action # Path to where you place the action
|
|
||||||
if: (
|
|
||||||
(github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch))
|
|
||||||
|| (contains(github.event_name, 'pull_request') && ((github.event.action == 'labeled' && (github.event.label.name == 'dev-c3' || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, 'dev-c3'))))
|
|
||||||
)
|
|
||||||
with:
|
|
||||||
workflow: selfdrive_tests.yaml # The workflow file to monitor
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Configure Git
|
|
||||||
run: |
|
|
||||||
git config --global user.name 'github-actions[bot]'
|
|
||||||
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
|
|
||||||
|
|
||||||
- name: Set up SSH
|
|
||||||
uses: webfactory/ssh-agent@v0.9.0
|
|
||||||
with:
|
|
||||||
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: Add GitLab public keys
|
|
||||||
run: |
|
|
||||||
ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts
|
|
||||||
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: '3.10'
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
pip install PyGithub
|
|
||||||
|
|
||||||
- name: Check branches exist
|
|
||||||
run: |
|
|
||||||
# Check if source branch exists
|
|
||||||
if ! git ls-remote --heads origin ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }} | grep -q "${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}"; then
|
|
||||||
echo "Source branch ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }} does not exist!"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Make sure we have the latest source branch
|
|
||||||
git fetch origin ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}
|
|
||||||
|
|
||||||
# Check if target branch exists
|
|
||||||
if ! git ls-remote --heads origin ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} | grep -q "${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}"; then
|
|
||||||
echo "Target branch ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} does not exist, creating it from ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}"
|
|
||||||
git checkout -b ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} origin/${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}
|
|
||||||
git push origin ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}
|
|
||||||
else
|
|
||||||
# Fetch target branch if it exists
|
|
||||||
git fetch origin ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Reset target branch
|
|
||||||
run: |
|
|
||||||
echo "Resetting ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} to match ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}"
|
|
||||||
# Delete if exists and recreate pointing to source
|
|
||||||
git branch -D ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} || true
|
|
||||||
git branch ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} origin/${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}
|
|
||||||
|
|
||||||
- name: Get PRs to squash
|
|
||||||
id: get-prs
|
|
||||||
run: |
|
|
||||||
# Use GitHub API to get PRs with specific label, ordered by creation date
|
|
||||||
PR_LIST=$(gh api graphql -f query='
|
|
||||||
query($label:String!) {
|
|
||||||
search(query: $label, type:ISSUE, first:100) {
|
|
||||||
nodes {
|
|
||||||
... on PullRequest {
|
|
||||||
number
|
|
||||||
headRefName
|
|
||||||
title
|
|
||||||
createdAt
|
|
||||||
labels(last:10) {
|
|
||||||
nodes {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
headRepository {
|
|
||||||
name
|
|
||||||
nameWithOwner
|
|
||||||
url
|
|
||||||
isFork
|
|
||||||
}
|
|
||||||
commits(last: 1) {
|
|
||||||
nodes {
|
|
||||||
commit {
|
|
||||||
statusCheckRollup {
|
|
||||||
state
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}' -F label="is:pr is:open label:${PR_LABEL} draft:false sort:created-asc")
|
|
||||||
|
|
||||||
echo "PR_LIST=${PR_LIST}" >> $GITHUB_OUTPUT
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Process PRs
|
|
||||||
run: |
|
|
||||||
cp ${{ github.workspace }}/release/ci/squash_and_merge.py /tmp/squash_and_merge.py && \
|
|
||||||
chmod +x /tmp/squash_and_merge.py && \
|
|
||||||
python3 ${{ github.workspace }}/release/ci/squash_and_merge_prs.py \
|
|
||||||
--pr-data '${{ steps.get-prs.outputs.PR_LIST }}' \
|
|
||||||
--target-branch ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} \
|
|
||||||
--squash-script-path '/tmp/squash_and_merge.py'
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Update LFS Config
|
|
||||||
run: |
|
|
||||||
echo '[lfs]' > .lfsconfig
|
|
||||||
echo ' url = ${{ env.LFS_URL }}' >> .lfsconfig
|
|
||||||
echo ' pushurl = ${{ env.LFS_PUSH_URL }}' >> .lfsconfig
|
|
||||||
echo ' locksverify = false' >> .lfsconfig
|
|
||||||
|
|
||||||
- name: Push changes if there are diffs
|
|
||||||
id: push-changes # Add an id so we can reference this step
|
|
||||||
run: |
|
|
||||||
TARGET_BRANCH="${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}"
|
|
||||||
|
|
||||||
# Fetch the latest from remote
|
|
||||||
git fetch origin $TARGET_BRANCH
|
|
||||||
|
|
||||||
# Check for diffs between local and remote
|
|
||||||
if git diff $TARGET_BRANCH origin/$TARGET_BRANCH --quiet; then
|
|
||||||
echo "No changes to push - local and remote branches are identical"
|
|
||||||
echo "has_changes=false" >> $GITHUB_OUTPUT
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If we get here, there are diffs, so push
|
|
||||||
if ! git push origin $TARGET_BRANCH --force; then
|
|
||||||
echo "Failed to push changes to $TARGET_BRANCH"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Branch $TARGET_BRANCH has been reset and updated with squashed PRs"
|
|
||||||
echo "has_changes=true" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Trigger and wait for selfdrive tests
|
|
||||||
if: steps.push-changes.outputs.has_changes == 'true'
|
|
||||||
run: |
|
|
||||||
echo "Triggering selfdrive tests..."
|
|
||||||
gh workflow run selfdrive_tests.yaml --ref "${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}"
|
|
||||||
|
|
||||||
echo "Sleeping for 120s to give plenty of time for the action to start and then we wait"
|
|
||||||
sleep 120
|
|
||||||
|
|
||||||
echo "Getting latest run ID..."
|
|
||||||
RUN_ID=$(gh run list --workflow=selfdrive_tests.yaml --branch="${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}" --limit=1 --json databaseId --jq '.[0].databaseId')
|
|
||||||
|
|
||||||
echo "Watching run ID: $RUN_ID"
|
|
||||||
gh run watch "$RUN_ID"
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Trigger prebuilt workflow
|
|
||||||
if: success() && steps.push-changes.outputs.has_changes == 'true'
|
|
||||||
run: |
|
|
||||||
gh workflow run sunnypilot-build-prebuilt.yaml --ref "${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}"
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
@@ -3,25 +3,23 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- master-new
|
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [assigned, opened, synchronize, reopened, edited]
|
types: [assigned, opened, synchronize, reopened, edited]
|
||||||
branches:
|
branches:
|
||||||
- 'master'
|
- 'master'
|
||||||
- 'master-new'
|
|
||||||
paths:
|
paths:
|
||||||
- 'selfdrive/ui/**'
|
- 'selfdrive/ui/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
UI_JOB_NAME: "Create UI Report"
|
UI_JOB_NAME: "Create UI Report"
|
||||||
REPORT_NAME: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new') && 'master' || github.event.number }}
|
REPORT_NAME: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master' || github.event.number }}
|
||||||
SHA: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new') && github.sha || github.event.pull_request.head.sha }}
|
SHA: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.sha || github.event.pull_request.head.sha }}
|
||||||
BRANCH_NAME: "openpilot/pr-${{ github.event.number }}"
|
BRANCH_NAME: "openpilot/pr-${{ github.event.number }}"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
preview:
|
preview:
|
||||||
if: github.repository == 'sunnypilot/sunnypilot'
|
if: github.repository == 'commaai/openpilot'
|
||||||
name: preview
|
name: preview
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 20
|
timeout-minutes: 20
|
||||||
@@ -60,13 +58,13 @@ jobs:
|
|||||||
- name: Getting master ui
|
- name: Getting master ui
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: sunnypilot/ci-artifacts
|
repository: commaai/ci-artifacts
|
||||||
ssh-key: ${{ secrets.CI_ARTIFACTS_DEPLOY_KEY }}
|
ssh-key: ${{ secrets.CI_ARTIFACTS_DEPLOY_KEY }}
|
||||||
path: ${{ github.workspace }}/master_ui
|
path: ${{ github.workspace }}/master_ui
|
||||||
ref: openpilot_master_ui
|
ref: openpilot_master_ui
|
||||||
|
|
||||||
- name: Saving new master ui
|
- name: Saving new master ui
|
||||||
if: (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/master-new') && github.event_name == 'push'
|
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
||||||
working-directory: ${{ github.workspace }}/master_ui
|
working-directory: ${{ github.workspace }}/master_ui
|
||||||
run: |
|
run: |
|
||||||
git checkout --orphan=new_master_ui
|
git checkout --orphan=new_master_ui
|
||||||
@@ -84,9 +82,9 @@ jobs:
|
|||||||
if: github.event_name == 'pull_request_target'
|
if: github.event_name == 'pull_request_target'
|
||||||
id: find_diff
|
id: find_diff
|
||||||
run: >-
|
run: >-
|
||||||
sudo apt-get update && sudo apt-get install -y imagemagick
|
sudo apt-get install -y imagemagick
|
||||||
|
|
||||||
scenes=$(find ${{ github.workspace }}/pr_ui/*.png -type f -printf "%f\n" | cut -d '.' -f 1 | grep -v 'pair_device')
|
scenes="homescreen settings_device settings_software settings_toggles settings_developer offroad_alert update_available prime onroad onroad_disengaged onroad_override onroad_sidebar onroad_wide onroad_wide_sidebar onroad_alert_small onroad_alert_mid onroad_alert_full driver_camera body keyboard"
|
||||||
A=($scenes)
|
A=($scenes)
|
||||||
|
|
||||||
DIFF=""
|
DIFF=""
|
||||||
@@ -95,20 +93,8 @@ jobs:
|
|||||||
|
|
||||||
for ((i=0; i<${#A[*]}; i=i+1));
|
for ((i=0; i<${#A[*]}; i=i+1));
|
||||||
do
|
do
|
||||||
# Check if the master file exists
|
|
||||||
if [ ! -f "${{ github.workspace }}/master_ui/${A[$i]}.png" ]; then
|
|
||||||
# This is a new file in PR UI that doesn't exist in master
|
|
||||||
DIFF="${DIFF}<details open>"
|
|
||||||
DIFF="${DIFF}<summary>${A[$i]} : \$\${\\color{cyan}\\text{NEW}}\$\$</summary>"
|
|
||||||
DIFF="${DIFF}<table>"
|
|
||||||
|
|
||||||
DIFF="${DIFF}<tr>"
|
if ! compare -fuzz 2% -highlight-color DeepSkyBlue1 -lowlight-color Black -compose Src ${{ github.workspace }}/master_ui/${A[$i]}.png ${{ github.workspace }}/pr_ui/${A[$i]}.png ${{ github.workspace }}/pr_ui/${A[$i]}_diff.png; then
|
||||||
DIFF="${DIFF} <td> <img src=\"https://raw.githubusercontent.com/sunnypilot/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}.png\"> </td>"
|
|
||||||
DIFF="${DIFF}</tr>"
|
|
||||||
|
|
||||||
DIFF="${DIFF}</table>"
|
|
||||||
DIFF="${DIFF}</details>"
|
|
||||||
elif ! compare -fuzz 2% -highlight-color DeepSkyBlue1 -lowlight-color Black -compose Src ${{ github.workspace }}/master_ui/${A[$i]}.png ${{ github.workspace }}/pr_ui/${A[$i]}.png ${{ github.workspace }}/pr_ui/${A[$i]}_diff.png; then
|
|
||||||
convert ${{ github.workspace }}/pr_ui/${A[$i]}_diff.png -transparent black mask.png
|
convert ${{ github.workspace }}/pr_ui/${A[$i]}_diff.png -transparent black mask.png
|
||||||
composite mask.png ${{ github.workspace }}/master_ui/${A[$i]}.png composite_diff.png
|
composite mask.png ${{ github.workspace }}/master_ui/${A[$i]}.png composite_diff.png
|
||||||
convert -delay 100 ${{ github.workspace }}/master_ui/${A[$i]}.png composite_diff.png -loop 0 ${{ github.workspace }}/pr_ui/${A[$i]}_diff.gif
|
convert -delay 100 ${{ github.workspace }}/master_ui/${A[$i]}.png composite_diff.png -loop 0 ${{ github.workspace }}/pr_ui/${A[$i]}_diff.gif
|
||||||
@@ -120,13 +106,13 @@ jobs:
|
|||||||
DIFF="${DIFF}<table>"
|
DIFF="${DIFF}<table>"
|
||||||
|
|
||||||
DIFF="${DIFF}<tr>"
|
DIFF="${DIFF}<tr>"
|
||||||
DIFF="${DIFF} <td> master <img src=\"https://raw.githubusercontent.com/sunnypilot/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}_master_ref.png\"> </td>"
|
DIFF="${DIFF} <td> master <img src=\"https://raw.githubusercontent.com/commaai/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}_master_ref.png\"> </td>"
|
||||||
DIFF="${DIFF} <td> proposed <img src=\"https://raw.githubusercontent.com/sunnypilot/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}.png\"> </td>"
|
DIFF="${DIFF} <td> proposed <img src=\"https://raw.githubusercontent.com/commaai/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}.png\"> </td>"
|
||||||
DIFF="${DIFF}</tr>"
|
DIFF="${DIFF}</tr>"
|
||||||
|
|
||||||
DIFF="${DIFF}<tr>"
|
DIFF="${DIFF}<tr>"
|
||||||
DIFF="${DIFF} <td> diff <img src=\"https://raw.githubusercontent.com/sunnypilot/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}_diff.png\"> </td>"
|
DIFF="${DIFF} <td> diff <img src=\"https://raw.githubusercontent.com/commaai/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}_diff.png\"> </td>"
|
||||||
DIFF="${DIFF} <td> composite diff <img src=\"https://raw.githubusercontent.com/sunnypilot/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}_diff.gif\"> </td>"
|
DIFF="${DIFF} <td> composite diff <img src=\"https://raw.githubusercontent.com/commaai/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}_diff.gif\"> </td>"
|
||||||
DIFF="${DIFF}</tr>"
|
DIFF="${DIFF}</tr>"
|
||||||
|
|
||||||
DIFF="${DIFF}</table>"
|
DIFF="${DIFF}</table>"
|
||||||
@@ -139,7 +125,7 @@ jobs:
|
|||||||
if [[ $INDEX -eq 0 ]]; then
|
if [[ $INDEX -eq 0 ]]; then
|
||||||
TABLE="${TABLE}<tr>"
|
TABLE="${TABLE}<tr>"
|
||||||
fi
|
fi
|
||||||
TABLE="${TABLE} <td> <img src=\"https://raw.githubusercontent.com/sunnypilot/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}.png\"> </td>"
|
TABLE="${TABLE} <td> <img src=\"https://raw.githubusercontent.com/commaai/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}.png\"> </td>"
|
||||||
if [[ $INDEX -eq 1 || $(($i + 1)) -eq ${#A[*]} ]]; then
|
if [[ $INDEX -eq 1 || $(($i + 1)) -eq ${#A[*]} ]]; then
|
||||||
TABLE="${TABLE}</tr>"
|
TABLE="${TABLE}</tr>"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
name: 'Wait for Tests'
|
|
||||||
description: 'Action to wait for workflow tests to start and complete'
|
|
||||||
inputs:
|
|
||||||
workflow:
|
|
||||||
description: 'The workflow file name to monitor'
|
|
||||||
required: true
|
|
||||||
default: 'selfdrive_tests.yaml'
|
|
||||||
branch:
|
|
||||||
description: 'The branch to monitor (defaults to current branch)'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
github-token:
|
|
||||||
description: 'GitHub token for API access'
|
|
||||||
required: true
|
|
||||||
wait-time:
|
|
||||||
description: 'Initial sleep time in seconds before monitoring starts'
|
|
||||||
required: false
|
|
||||||
default: '30'
|
|
||||||
should-wait-for-start:
|
|
||||||
description: 'Whether to wait for tests to start'
|
|
||||||
required: false
|
|
||||||
default: false
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: 'composite'
|
|
||||||
steps:
|
|
||||||
- name: Wait for tests to start
|
|
||||||
if: inputs.should-wait-for-start == 'true'
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "Sleeping for ${{ inputs.wait-time }} seconds to give some time for the action to start and then we'll wait"
|
|
||||||
sleep ${{ inputs.wait-time }}
|
|
||||||
|
|
||||||
- name: Wait for tests to finish
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
BRANCH="${{ inputs.branch || github.head_ref || github.ref_name }}"
|
|
||||||
|
|
||||||
echo "Looking for workflow runs of ${{ inputs.workflow }} on branch $BRANCH"
|
|
||||||
RUN_ID=$(gh run list --workflow=${{ inputs.workflow }} --branch="$BRANCH" --limit=1 --json databaseId --jq '.[0].databaseId')
|
|
||||||
echo "Watching run ID: $RUN_ID"
|
|
||||||
gh run watch "$RUN_ID"
|
|
||||||
|
|
||||||
CONCLUSION=$(gh run view "$RUN_ID" --json conclusion --jq '.conclusion')
|
|
||||||
echo "Run concluded with: $CONCLUSION"
|
|
||||||
|
|
||||||
if [[ "$CONCLUSION" != "success" ]]; then
|
|
||||||
echo "❌ Workflow run failed with conclusion: $CONCLUSION"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ inputs.github-token }}
|
|
||||||
+2
-9
@@ -36,7 +36,6 @@ a.out
|
|||||||
*.pyxbldc
|
*.pyxbldc
|
||||||
*.vcd
|
*.vcd
|
||||||
*.qm
|
*.qm
|
||||||
*_pyx.cpp
|
|
||||||
config.json
|
config.json
|
||||||
clcache
|
clcache
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
@@ -47,8 +46,10 @@ selfdrive/pandad/pandad
|
|||||||
cereal/services.h
|
cereal/services.h
|
||||||
cereal/gen
|
cereal/gen
|
||||||
cereal/messaging/bridge
|
cereal/messaging/bridge
|
||||||
|
selfdrive/logcatd/logcatd
|
||||||
selfdrive/mapd/default_speeds_by_region.json
|
selfdrive/mapd/default_speeds_by_region.json
|
||||||
system/proclogd/proclogd
|
system/proclogd/proclogd
|
||||||
|
selfdrive/ui/translations/alerts_generated.h
|
||||||
selfdrive/ui/translations/tmp
|
selfdrive/ui/translations/tmp
|
||||||
selfdrive/test/longitudinal_maneuvers/out
|
selfdrive/test/longitudinal_maneuvers/out
|
||||||
selfdrive/car/tests/cars_dump
|
selfdrive/car/tests/cars_dump
|
||||||
@@ -73,9 +74,6 @@ comma*.sh
|
|||||||
selfdrive/modeld/thneed/compile
|
selfdrive/modeld/thneed/compile
|
||||||
selfdrive/modeld/models/*.thneed
|
selfdrive/modeld/models/*.thneed
|
||||||
selfdrive/modeld/models/*.pkl
|
selfdrive/modeld/models/*.pkl
|
||||||
sunnypilot/modeld*/thneed/compile
|
|
||||||
sunnypilot/modeld*/models/*.thneed
|
|
||||||
sunnypilot/modeld*/models/*.pkl
|
|
||||||
|
|
||||||
*.bz2
|
*.bz2
|
||||||
*.zst
|
*.zst
|
||||||
@@ -105,8 +103,3 @@ Pipfile
|
|||||||
# Ignore all local history of files
|
# Ignore all local history of files
|
||||||
.history
|
.history
|
||||||
.ionide
|
.ionide
|
||||||
|
|
||||||
### JetBrains ###
|
|
||||||
!.idea/customTargets.xml
|
|
||||||
!.idea/tools/*
|
|
||||||
!.run/*
|
|
||||||
|
|||||||
+6
-9
@@ -1,21 +1,18 @@
|
|||||||
[submodule "panda"]
|
[submodule "panda"]
|
||||||
path = panda
|
path = panda
|
||||||
url = https://github.com/sunnyhaibin/panda.git
|
url = ../../commaai/panda.git
|
||||||
[submodule "opendbc"]
|
[submodule "opendbc"]
|
||||||
path = opendbc_repo
|
path = opendbc_repo
|
||||||
url = https://github.com/sunnypilot/opendbc.git
|
url = ../../commaai/opendbc.git
|
||||||
[submodule "msgq"]
|
[submodule "msgq"]
|
||||||
path = msgq_repo
|
path = msgq_repo
|
||||||
url = https://github.com/sunnypilot/msgq.git
|
url = ../../commaai/msgq.git
|
||||||
[submodule "rednose_repo"]
|
[submodule "rednose_repo"]
|
||||||
path = rednose_repo
|
path = rednose_repo
|
||||||
url = https://github.com/commaai/rednose.git
|
url = ../../commaai/rednose.git
|
||||||
[submodule "teleoprtc_repo"]
|
[submodule "teleoprtc_repo"]
|
||||||
path = teleoprtc_repo
|
path = teleoprtc_repo
|
||||||
url = https://github.com/commaai/teleoprtc
|
url = ../../commaai/teleoprtc
|
||||||
[submodule "tinygrad"]
|
[submodule "tinygrad"]
|
||||||
path = tinygrad_repo
|
path = tinygrad_repo
|
||||||
url = https://github.com/tinygrad/tinygrad.git
|
url = https://github.com/commaai/tinygrad.git
|
||||||
[submodule "sunnypilot/neural_network_data"]
|
|
||||||
path = sunnypilot/neural_network_data
|
|
||||||
url = https://github.com/sunnypilot/neural-network-data.git
|
|
||||||
|
|||||||
Generated
-25
@@ -1,25 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CLionExternalBuildManager">
|
|
||||||
<target id="a62f99e8-5ec4-434c-8122-49efed5af108" name="uv Scons Build Debug" defaultType="TOOL">
|
|
||||||
<configuration id="b93ec964-16e5-4962-a12e-3ed360ce8f02" name="uv Scons Build Debug">
|
|
||||||
<build type="TOOL">
|
|
||||||
<tool actionId="Tool_External Tools_uv Scons Build Debug" />
|
|
||||||
</build>
|
|
||||||
<clean type="TOOL">
|
|
||||||
<tool actionId="Tool_External Tools_uv Scons Clean" />
|
|
||||||
</clean>
|
|
||||||
</configuration>
|
|
||||||
</target>
|
|
||||||
<target id="edd8ad9d-183b-467c-a355-0d9a0ecab026" name="uv Scons Build Release" defaultType="TOOL">
|
|
||||||
<configuration id="09523339-5ce3-4223-ab9e-904f38ad7752" name="uv Scons Build Release">
|
|
||||||
<build type="TOOL">
|
|
||||||
<tool actionId="Tool_External Tools_uv Scons Build Release" />
|
|
||||||
</build>
|
|
||||||
<clean type="TOOL">
|
|
||||||
<tool actionId="Tool_External Tools_uv Scons Clean" />
|
|
||||||
</clean>
|
|
||||||
</configuration>
|
|
||||||
</target>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
Generated
-23
@@ -1,23 +0,0 @@
|
|||||||
<toolSet name="External Tools">
|
|
||||||
<tool name="uv Scons Build Debug" showInMainMenu="false" showInEditor="false" showInProject="false" showInSearchPopup="false" disabled="false" useConsole="true" showConsoleOnStdOut="false" showConsoleOnStdErr="false" synchronizeAfterRun="true">
|
|
||||||
<exec>
|
|
||||||
<option name="COMMAND" value="bash" />
|
|
||||||
<option name="PARAMETERS" value="-c "source .venv/bin/activate && scons -u -j$(nproc) --compile_db --ccflags=\"-fno-inline\""" />
|
|
||||||
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
|
|
||||||
</exec>
|
|
||||||
</tool>
|
|
||||||
<tool name="uv Scons Clean" showInMainMenu="false" showInEditor="false" showInProject="false" showInSearchPopup="false" disabled="false" useConsole="true" showConsoleOnStdOut="false" showConsoleOnStdErr="false" synchronizeAfterRun="true">
|
|
||||||
<exec>
|
|
||||||
<option name="COMMAND" value="bash" />
|
|
||||||
<option name="PARAMETERS" value="-c "source .venv/bin/activate && scons -c" " />
|
|
||||||
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
|
|
||||||
</exec>
|
|
||||||
</tool>
|
|
||||||
<tool name="uv Scons Build Release" showInMainMenu="false" showInEditor="false" showInProject="false" showInSearchPopup="false" disabled="false" useConsole="true" showConsoleOnStdOut="false" showConsoleOnStdErr="false" synchronizeAfterRun="true">
|
|
||||||
<exec>
|
|
||||||
<option name="COMMAND" value="bash" />
|
|
||||||
<option name="PARAMETERS" value="-c "source .venv/bin/activate && scons -u -j$(nproc) --compile_db" " />
|
|
||||||
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
|
|
||||||
</exec>
|
|
||||||
</tool>
|
|
||||||
</toolSet>
|
|
||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
[lfs]
|
[lfs]
|
||||||
url = https://gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git/info/lfs
|
url = https://gitlab.com/commaai/openpilot-lfs.git/info/lfs
|
||||||
pushurl = ssh://git@gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git
|
pushurl = ssh://git@gitlab.com/commaai/openpilot-lfs.git
|
||||||
locksverify = false
|
locksverify = false
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
[lfs]
|
|
||||||
url = https://gitlab.com/commaai/openpilot-lfs.git/info/lfs
|
|
||||||
pushurl = ssh://git@gitlab.com/commaai/openpilot-lfs.git
|
|
||||||
locksverify = false
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Build Debug" type="CLionExternalRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$ProjectFileDir$/selfdrive/ui" PASS_PARENT_ENVS_2="true" PROJECT_NAME="sunnypilot" TARGET_NAME="uv Scons Build Debug" CONFIG_NAME="uv Scons Build Debug" RUN_PATH="ui">
|
|
||||||
<envs>
|
|
||||||
<env name="QT_DBL_CLICK_DIST" value="150" />
|
|
||||||
</envs>
|
|
||||||
<method v="2">
|
|
||||||
<option name="CLION.EXTERNAL.BUILD" enabled="true" />
|
|
||||||
</method>
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Build Release" type="CLionExternalRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$ProjectFileDir$/selfdrive/ui" PASS_PARENT_ENVS_2="true" PROJECT_NAME="sunnypilot" TARGET_NAME="uv Scons Build Release" CONFIG_NAME="uv Scons Build Release" RUN_PATH="ui">
|
|
||||||
<envs>
|
|
||||||
<env name="QT_DBL_CLICK_DIST" value="150" />
|
|
||||||
</envs>
|
|
||||||
<method v="2">
|
|
||||||
<option name="CLION.EXTERNAL.BUILD" enabled="true" />
|
|
||||||
</method>
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
FROM ghcr.io/commaai/openpilot-base:latest
|
FROM ghcr.io/commaai/openpilot-base:latest
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED 1
|
||||||
|
|
||||||
ENV OPENPILOT_PATH=/home/batman/openpilot
|
ENV OPENPILOT_PATH /home/batman/openpilot
|
||||||
|
ENV PYTHONPATH ${OPENPILOT_PATH}:${PYTHONPATH}
|
||||||
|
|
||||||
RUN mkdir -p ${OPENPILOT_PATH}
|
RUN mkdir -p ${OPENPILOT_PATH}
|
||||||
WORKDIR ${OPENPILOT_PATH}
|
WORKDIR ${OPENPILOT_PATH}
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
FROM ubuntu:24.04
|
FROM ubuntu:24.04
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED 1
|
||||||
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y --no-install-recommends sudo tzdata locales ssh pulseaudio xvfb x11-xserver-utils gnome-screenshot python3-tk python3-dev && \
|
apt-get install -y --no-install-recommends sudo tzdata locales ssh pulseaudio xvfb x11-xserver-utils gnome-screenshot && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
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
|
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 LANG en_US.UTF-8
|
||||||
ENV LANGUAGE=en_US:en
|
ENV LANGUAGE en_US:en
|
||||||
ENV LC_ALL=en_US.UTF-8
|
ENV LC_ALL en_US.UTF-8
|
||||||
|
|
||||||
COPY tools/install_ubuntu_dependencies.sh /tmp/tools/
|
COPY tools/install_ubuntu_dependencies.sh /tmp/tools/
|
||||||
RUN /tmp/tools/install_ubuntu_dependencies.sh && \
|
RUN /tmp/tools/install_ubuntu_dependencies.sh && \
|
||||||
@@ -55,12 +55,11 @@ RUN mkdir -p /tmp/opencl-driver-intel && \
|
|||||||
cd / && \
|
cd / && \
|
||||||
rm -rf /tmp/opencl-driver-intel
|
rm -rf /tmp/opencl-driver-intel
|
||||||
|
|
||||||
ENV NVIDIA_VISIBLE_DEVICES=all
|
ENV NVIDIA_VISIBLE_DEVICES all
|
||||||
ENV NVIDIA_DRIVER_CAPABILITIES=graphics,utility,compute
|
ENV NVIDIA_DRIVER_CAPABILITIES graphics,utility,compute
|
||||||
ENV QTWEBENGINE_DISABLE_SANDBOX=1
|
ENV QTWEBENGINE_DISABLE_SANDBOX 1
|
||||||
|
|
||||||
RUN dbus-uuidgen > /etc/machine-id
|
RUN dbus-uuidgen > /etc/machine-id
|
||||||
RUN apt-get update && apt-get install -y fonts-noto-cjk fonts-noto-color-emoji
|
|
||||||
|
|
||||||
ARG USER=batman
|
ARG USER=batman
|
||||||
ARG USER_UID=1001
|
ARG USER_UID=1001
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
FROM sunnypilot-base
|
|
||||||
|
|
||||||
ARG RUNNER_DEBUG=0
|
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED=1
|
|
||||||
ENV OPENPILOT_SRC_PATH=/tmp/openpilot
|
|
||||||
ENV BUILD_DIR=/data/openpilot
|
|
||||||
ENV OUTPUT_DIR=/output
|
|
||||||
|
|
||||||
RUN sudo apt update && sudo apt install -y rsync
|
|
||||||
|
|
||||||
RUN mkdir -p ${OPENPILOT_SRC_PATH}
|
|
||||||
RUN mkdir -p ${BUILD_DIR}
|
|
||||||
COPY . ${OPENPILOT_SRC_PATH}
|
|
||||||
ENV PYTHONPATH=${BUILD_DIR}
|
|
||||||
|
|
||||||
WORKDIR ${OPENPILOT_SRC_PATH}
|
|
||||||
RUN ./tools/ubuntu_setup.sh
|
|
||||||
|
|
||||||
RUN ./release/release_files.py | sort | uniq | rsync -rRl${RUNNER_DEBUG:+v} --files-from=- . $BUILD_DIR/
|
|
||||||
WORKDIR ${BUILD_DIR}
|
|
||||||
RUN sed -i '/from .board.jungle import PandaJungle, PandaJungleDFU/s/^/#/' panda/__init__.py
|
|
||||||
RUN scons --cache-readonly -j$(nproc) --minimal
|
|
||||||
RUN touch ${BUILD_DIR}/prebuilt
|
|
||||||
RUN sudo rm -rf ${OUTPUT_DIR}
|
|
||||||
RUN mkdir -p ${OUTPUT_DIR}
|
|
||||||
|
|
||||||
ENTRYPOINT [\
|
|
||||||
"rsync", \
|
|
||||||
"-am", \
|
|
||||||
"--include=**/panda/board/", \
|
|
||||||
"--include=**/panda/board/obj", \
|
|
||||||
"--include=**/panda/board/obj/panda.bin.signed", \
|
|
||||||
"--include=**/panda/board/obj/panda_h7.bin.signed", \
|
|
||||||
"--include=**/panda/board/obj/bootstub.panda.bin", \
|
|
||||||
"--include=**/panda/board/obj/bootstub.panda_h7.bin", \
|
|
||||||
"--exclude=.sconsign.dblite", \
|
|
||||||
"--exclude=*.a", \
|
|
||||||
"--exclude=*.o", \
|
|
||||||
"--exclude=*.os", \
|
|
||||||
"--exclude=*.pyc", \
|
|
||||||
"--exclude=moc_*", \
|
|
||||||
"--exclude=*.cc", \
|
|
||||||
"--exclude=Jenkinsfile", \
|
|
||||||
"--exclude=supercombo.onnx", \
|
|
||||||
"--exclude=**/panda/board/*", \
|
|
||||||
"--exclude=**/panda/board/obj/**", \
|
|
||||||
"--exclude=**/panda/certs/", \
|
|
||||||
"--exclude=**/panda/crypto/", \
|
|
||||||
"--exclude=**/release/", \
|
|
||||||
"--exclude=**/.github/", \
|
|
||||||
"--exclude=**/selfdrive/ui/replay/", \
|
|
||||||
"--exclude=**/__pycache__/", \
|
|
||||||
"--exclude=**/selfdrive/ui/*.h", \
|
|
||||||
"--exclude=**/selfdrive/ui/**/*.h", \
|
|
||||||
"--exclude=**/selfdrive/ui/qt/offroad/sunnypilot/", \
|
|
||||||
#"--exclude=${SCONS_CACHE_DIR:-}", \
|
|
||||||
"--exclude=**/.git/", \
|
|
||||||
"--exclude=**/SConstruct", \
|
|
||||||
"--exclude=**/SConscript", \
|
|
||||||
"--exclude=**/.venv/", \
|
|
||||||
"--delete-excluded", \
|
|
||||||
"--chown=1000:1000", \
|
|
||||||
"/data/openpilot/", \
|
|
||||||
"/output/" \
|
|
||||||
]
|
|
||||||
Vendored
+9
-17
@@ -31,7 +31,7 @@ export CI_ARTIFACTS_TOKEN=${env.CI_ARTIFACTS_TOKEN}
|
|||||||
export GITHUB_COMMENTS_TOKEN=${env.GITHUB_COMMENTS_TOKEN}
|
export GITHUB_COMMENTS_TOKEN=${env.GITHUB_COMMENTS_TOKEN}
|
||||||
export AZURE_TOKEN='${env.AZURE_TOKEN}'
|
export AZURE_TOKEN='${env.AZURE_TOKEN}'
|
||||||
# only use 1 thread for tici tests since most require HIL
|
# only use 1 thread for tici tests since most require HIL
|
||||||
export PYTEST_ADDOPTS="-n0 -s"
|
export PYTEST_ADDOPTS="-n 0"
|
||||||
|
|
||||||
|
|
||||||
export GIT_SSH_COMMAND="ssh -i /data/gitkey"
|
export GIT_SSH_COMMAND="ssh -i /data/gitkey"
|
||||||
@@ -103,7 +103,7 @@ def deviceStage(String stageName, String deviceType, List extra_env, def steps)
|
|||||||
def diffPaths = args.diffPaths ?: []
|
def diffPaths = args.diffPaths ?: []
|
||||||
def cmdTimeout = args.timeout ?: 9999
|
def cmdTimeout = args.timeout ?: 9999
|
||||||
|
|
||||||
if (branch != "master" && !branch.contains("__jenkins_loop_") && diffPaths && !hasPathChanged(gitDiff, diffPaths)) {
|
if (branch != "master" && diffPaths && !hasPathChanged(gitDiff, diffPaths)) {
|
||||||
println "Skipping ${name}: no changes in ${diffPaths}."
|
println "Skipping ${name}: no changes in ${diffPaths}."
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
@@ -166,11 +166,11 @@ 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', 'release3', 'release3-staging',
|
def excludeBranches = ['master-ci', 'devel', 'devel-staging', 'release3', 'release3-staging',
|
||||||
'testing-closet*', 'hotfix-*']
|
'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') {
|
||||||
properties([
|
properties([
|
||||||
disableConcurrentBuilds(abortPrevious: true)
|
disableConcurrentBuilds(abortPrevious: true)
|
||||||
])
|
])
|
||||||
@@ -183,7 +183,7 @@ node {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (env.BRANCH_NAME == '__nightly') {
|
if (env.BRANCH_NAME == 'master-ci') {
|
||||||
parallel (
|
parallel (
|
||||||
'nightly': {
|
'nightly': {
|
||||||
deviceStage("build nightly", "tici-needs-can", [], [
|
deviceStage("build nightly", "tici-needs-can", [], [
|
||||||
@@ -203,9 +203,12 @@ node {
|
|||||||
// tici tests
|
// tici tests
|
||||||
'onroad tests': {
|
'onroad tests': {
|
||||||
deviceStage("onroad", "tici-needs-can", ["UNSAFE=1"], [
|
deviceStage("onroad", "tici-needs-can", ["UNSAFE=1"], [
|
||||||
|
// TODO: ideally, this test runs in master-ci, but it takes 5+m to build it
|
||||||
|
//["build master-ci", "cd $SOURCE_DIR/release && TARGET_DIR=$TEST_DIR $SOURCE_DIR/scripts/retry.sh ./build_devel.sh"],
|
||||||
step("build openpilot", "cd system/manager && ./build.py"),
|
step("build openpilot", "cd system/manager && ./build.py"),
|
||||||
step("check dirty", "release/check-dirty.sh"),
|
step("check dirty", "release/check-dirty.sh"),
|
||||||
step("onroad tests", "pytest selfdrive/test/test_onroad.py -s", [timeout: 60]),
|
step("onroad tests", "pytest selfdrive/test/test_onroad.py -s", [timeout: 60]),
|
||||||
|
//["time to onroad", "pytest selfdrive/test/test_time_to_onroad.py"],
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
'HW + Unit Tests': {
|
'HW + Unit Tests': {
|
||||||
@@ -224,27 +227,18 @@ node {
|
|||||||
step("test pandad loopback", "pytest selfdrive/pandad/tests/test_pandad_loopback.py"),
|
step("test pandad loopback", "pytest selfdrive/pandad/tests/test_pandad_loopback.py"),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
'camerad AR0231': {
|
'camerad': {
|
||||||
deviceStage("AR0231", "tici-ar0231", ["UNSAFE=1"], [
|
deviceStage("AR0231", "tici-ar0231", ["UNSAFE=1"], [
|
||||||
step("build", "cd system/manager && ./build.py"),
|
step("build", "cd system/manager && ./build.py"),
|
||||||
step("test camerad", "pytest system/camerad/test/test_camerad.py", [timeout: 60]),
|
step("test camerad", "pytest system/camerad/test/test_camerad.py", [timeout: 60]),
|
||||||
step("test exposure", "pytest system/camerad/test/test_exposure.py"),
|
step("test exposure", "pytest system/camerad/test/test_exposure.py"),
|
||||||
])
|
])
|
||||||
},
|
|
||||||
'camerad OX03C10': {
|
|
||||||
deviceStage("OX03C10", "tici-ox03c10", ["UNSAFE=1"], [
|
deviceStage("OX03C10", "tici-ox03c10", ["UNSAFE=1"], [
|
||||||
step("build", "cd system/manager && ./build.py"),
|
step("build", "cd system/manager && ./build.py"),
|
||||||
step("test camerad", "pytest system/camerad/test/test_camerad.py", [timeout: 60]),
|
step("test camerad", "pytest system/camerad/test/test_camerad.py", [timeout: 60]),
|
||||||
step("test exposure", "pytest system/camerad/test/test_exposure.py"),
|
step("test exposure", "pytest system/camerad/test/test_exposure.py"),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
'camerad OS04C10': {
|
|
||||||
deviceStage("OS04C10", "tici-os04c10", ["UNSAFE=1"], [
|
|
||||||
step("build", "cd system/manager && ./build.py"),
|
|
||||||
step("test camerad", "pytest system/camerad/test/test_camerad.py", [timeout: 60]),
|
|
||||||
step("test exposure", "pytest system/camerad/test/test_exposure.py"),
|
|
||||||
])
|
|
||||||
},
|
|
||||||
'sensord': {
|
'sensord': {
|
||||||
deviceStage("LSM + MMC", "tici-lsmc", ["UNSAFE=1"], [
|
deviceStage("LSM + MMC", "tici-lsmc", ["UNSAFE=1"], [
|
||||||
step("build", "cd system/manager && ./build.py"),
|
step("build", "cd system/manager && ./build.py"),
|
||||||
@@ -268,8 +262,6 @@ node {
|
|||||||
step("test pandad spi", "pytest selfdrive/pandad/tests/test_pandad_spi.py"),
|
step("test pandad spi", "pytest selfdrive/pandad/tests/test_pandad_spi.py"),
|
||||||
step("test pandad", "pytest selfdrive/pandad/tests/test_pandad.py", [diffPaths: ["panda", "selfdrive/pandad/"]]),
|
step("test pandad", "pytest selfdrive/pandad/tests/test_pandad.py", [diffPaths: ["panda", "selfdrive/pandad/"]]),
|
||||||
step("test amp", "pytest system/hardware/tici/tests/test_amplifier.py"),
|
step("test amp", "pytest system/hardware/tici/tests/test_amplifier.py"),
|
||||||
// TODO: enable once new AGNOS is available
|
|
||||||
// step("test esim", "pytest system/hardware/tici/tests/test_esim.py"),
|
|
||||||
step("test qcomgpsd", "pytest system/qcomgpsd/tests/test_qcomgpsd.py", [diffPaths: ["system/qcomgpsd/"]]),
|
step("test qcomgpsd", "pytest system/qcomgpsd/tests/test_qcomgpsd.py", [diffPaths: ["system/qcomgpsd/"]]),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
|
|||||||
-21
@@ -1,21 +0,0 @@
|
|||||||
# Custom MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2024, Haibin Wen, SUNNYPILOT LLC
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to view and modify the Software, subject to the following conditions:
|
|
||||||
|
|
||||||
1. **Permission Required**: Permission Required for Commercial, For-Profit, or Closed Source Use: Use of the Software, in whole or in part, for any commercial purposes, for-profit projects, or in closed source projects requires explicit written permission from the original author(s).
|
|
||||||
|
|
||||||
2. **Redistribution**: Any redistribution of the Software, modified or unmodified, must retain this license notice and the following acknowledgment:
|
|
||||||
"This software is licensed under a custom license requiring permission for use."
|
|
||||||
|
|
||||||
3. **Visibility**: Any project that uses the Software must visibly mention the following acknowledgment:
|
|
||||||
"This project uses software from Haibin Wen and SUNNYPILOT LLC and is licensed under a custom license requiring permission for use."
|
|
||||||
|
|
||||||
4. **No Warranty**: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
Contact sunnypilot Support <support@sunnypilot.ai> for permission requests.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Haibin Wen, SUNNYPILOT LLC
|
|
||||||
@@ -1,119 +1,98 @@
|
|||||||

|
<div align="center" style="text-align: center;">
|
||||||
|
|
||||||
## 🌞 What is sunnypilot?
|
<h1>openpilot</h1>
|
||||||
[sunnypilot](https://github.com/sunnyhaibin/sunnypilot) is a fork of comma.ai's openpilot, an open source driver assistance system. sunnypilot offers the user a unique driving experience for over 300+ supported car makes and models with modified behaviors of driving assist engagements. sunnypilot complies with comma.ai's safety rules as accurately as possible.
|
|
||||||
|
|
||||||
## 💭 Join our Discord
|
<p>
|
||||||
Join the official sunnypilot Discord server to stay up to date with all the latest features and be a part of shaping the future of sunnypilot!
|
<b>openpilot is an operating system for robotics.</b>
|
||||||
* https://discord.gg/sunnypilot
|
<br>
|
||||||
|
Currently, it upgrades the driver assistance system in 275+ supported cars.
|
||||||
|
</p>
|
||||||
|
|
||||||
 
|
<h3>
|
||||||
|
<a href="https://docs.comma.ai">Docs</a>
|
||||||
|
<span> · </span>
|
||||||
|
<a href="https://docs.comma.ai/contributing/roadmap/">Roadmap</a>
|
||||||
|
<span> · </span>
|
||||||
|
<a href="https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md">Contribute</a>
|
||||||
|
<span> · </span>
|
||||||
|
<a href="https://discord.comma.ai">Community</a>
|
||||||
|
<span> · </span>
|
||||||
|
<a href="https://comma.ai/shop">Try it on a comma 3X</a>
|
||||||
|
</h3>
|
||||||
|
|
||||||
## Documentation
|
Quick start: `bash <(curl -fsSL openpilot.comma.ai)`
|
||||||
https://docs.sunnypilot.ai/ is your one stop shop for everything from features to installation to FAQ about the sunnypilot
|
|
||||||
|
|
||||||
## 🚘 Running on a dedicated device in a car
|

|
||||||
* A supported device to run this software
|
[](https://codecov.io/gh/commaai/openpilot)
|
||||||
* a [comma three](https://comma.ai/shop/products/three) or a [C3X](https://comma.ai/shop/comma-3x)
|
[](LICENSE)
|
||||||
* This software
|
[](https://x.com/comma_ai)
|
||||||
* One of [the 300+ supported cars](https://github.com/commaai/openpilot/blob/master/docs/CARS.md). We support Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, Ford and more. If your car is not supported but has adaptive cruise control and lane-keeping assist, it's likely able to run sunnypilot.
|
[](https://discord.comma.ai)
|
||||||
* A [car harness](https://comma.ai/shop/products/car-harness) to connect to your car
|
|
||||||
|
|
||||||
Detailed instructions for [how to mount the device in a car](https://comma.ai/setup).
|
</div>
|
||||||
|
|
||||||
## Installation
|
<table>
|
||||||
Please refer to [Recommended Branches](#-recommended-branches) to find your preferred/supported branch. This guide will assume you want to install the latest `release-c3` branch.
|
<tr>
|
||||||
|
<td><a href="https://youtu.be/NmBfgOanCyk" title="Video By Greer Viau"><img src="https://github.com/commaai/openpilot/assets/8762862/2f7112ae-f748-4f39-b617-fabd689c3772"></a></td>
|
||||||
|
<td><a href="https://youtu.be/VHKyqZ7t8Gw" title="Video By Logan LeGrand"><img src="https://github.com/commaai/openpilot/assets/8762862/92351544-2833-40d7-9e0b-7ef7ae37ec4c"></a></td>
|
||||||
|
<td><a href="https://youtu.be/SUIZYzxtMQs" title="A drive to Taco Bell"><img src="https://github.com/commaai/openpilot/assets/8762862/05ceefc5-2628-439c-a9b2-89ce77dc6f63"></a></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
* sunnypilot not installed or you installed a version before 0.8.17?
|
To start using openpilot in a car
|
||||||
1. [Factory reset/uninstall](https://github.com/commaai/openpilot/wiki/FAQ#how-can-i-reset-the-device) the previous software if you have another software/fork installed.
|
------
|
||||||
2. After factory reset/uninstall and upon reboot, select `Custom Software` when given the option.
|
|
||||||
3. Input the installation URL per [Recommended Branches](#-recommended-branches). Example: ```release-c3.sunnypilot.ai```.
|
|
||||||
4. Complete the rest of the installation following the onscreen instructions.
|
|
||||||
|
|
||||||
* sunnypilot already installed and you installed a version after 0.8.17?
|
To use openpilot in a car, you need four things:
|
||||||
1. On the comma three, go to `Settings` ▶️ `Software`.
|
1. **Supported Device:** a comma 3/3X, available at [comma.ai/shop](https://comma.ai/shop/comma-3x).
|
||||||
2. At the `Download` option, press `CHECK`. This will fetch the list of latest branches from sunnypilot.
|
2. **Software:** The setup procedure for the comma 3/3X allows users to enter a URL for custom software. Use the URL `openpilot.comma.ai` to install the release version.
|
||||||
3. At the `Target Branch` option, press `SELECT` to open the Target Branch selector.
|
3. **Supported Car:** Ensure that you have one of [the 275+ supported cars](docs/CARS.md).
|
||||||
4. Scroll to select the desired branch per Recommended Branches (see below). Example: `release-c3`
|
4. **Car Harness:** You will also need a [car harness](https://comma.ai/shop/car-harness) to connect your comma 3/3X to your car.
|
||||||
|
|
||||||
| Branch | Installation URL |
|
We have detailed instructions for [how to install the harness and device in a car](https://comma.ai/setup). Note that it's possible to run openpilot on [other hardware](https://blog.comma.ai/self-driving-car-for-free/), although it's not plug-and-play.
|
||||||
|:------------:|:--------------------------------:|
|
|
||||||
| `release-c3` | https://release-c3.sunnypilot.ai |
|
|
||||||
| `staging-c3` | https://staging-c3.sunnypilot.ai |
|
|
||||||
| `dev-c3` | https://dev-c3.sunnypilot.ai |
|
|
||||||
|
|
||||||
### If you want to use our newest branches (our rewrite)
|
To start developing openpilot
|
||||||
> [!TIP]
|
------
|
||||||
>You can see the rewrite state on our [rewrite project board](https://github.com/orgs/sunnypilot/projects/2), and to install the new branches, you can use the following links
|
|
||||||
|
|
||||||
|
openpilot is developed by [comma](https://comma.ai/) and by users like you. We welcome both pull requests and issues on [GitHub](http://github.com/commaai/openpilot).
|
||||||
|
|
||||||
> [!IMPORTANT]
|
* Join the [community Discord](https://discord.comma.ai)
|
||||||
> It is recommended to [re-flash AGNOS](https://flash.comma.ai/) if you intend to downgrade from the new branches.
|
* Check out [the contributing docs](docs/CONTRIBUTING.md)
|
||||||
> You can still restore the latest sunnylink backup made on the old branches.
|
* Check out the [openpilot tools](tools/)
|
||||||
|
* Read about the [development workflow](docs/WORKFLOW.md)
|
||||||
|
* Code documentation lives at https://docs.comma.ai
|
||||||
|
* Information about running openpilot lives on the [community wiki](https://github.com/commaai/openpilot/wiki)
|
||||||
|
|
||||||
| Branch | Installation URL |
|
Want to get paid to work on openpilot? [comma is hiring](https://comma.ai/jobs#open-positions) and offers lots of [bounties](https://comma.ai/bounties) for external contributors.
|
||||||
|:----------------:|:---------------------------------------------:|
|
|
||||||
| `staging-c3-new` | `https://staging-c3-new.sunnypilot.ai` |
|
|
||||||
| `dev-c3-new` | `https://dev-c3-new.sunnypilot.ai` |
|
|
||||||
| `custom-branch` | `https://install.sunnypilot.ai/{branch_name}` |
|
|
||||||
| `release-c3-new` | **Not yet available**. |
|
|
||||||
|
|
||||||
> [!TIP]
|
Safety and Testing
|
||||||
> Do you require further assistance with software installation? Join the [sunnypilot Discord server](https://discord.sunnypilot.com) and message us in the `#installation-help` channel.
|
----
|
||||||
|
|
||||||
## 🎆 Pull Requests
|
* openpilot observes [ISO26262](https://en.wikipedia.org/wiki/ISO_26262) guidelines, see [SAFETY.md](docs/SAFETY.md) for more details.
|
||||||
We welcome both pull requests and issues on GitHub. Bug fixes are encouraged.
|
* openpilot has software-in-the-loop [tests](.github/workflows/selfdrive_tests.yaml) that run on every commit.
|
||||||
|
* The code enforcing the safety model lives in panda and is written in C, see [code rigor](https://github.com/commaai/panda#code-rigor) for more details.
|
||||||
|
* panda has software-in-the-loop [safety tests](https://github.com/commaai/panda/tree/master/tests/safety).
|
||||||
|
* Internally, we have a hardware-in-the-loop Jenkins test suite that builds and unit tests the various processes.
|
||||||
|
* panda has additional hardware-in-the-loop [tests](https://github.com/commaai/panda/blob/master/Jenkinsfile).
|
||||||
|
* We run the latest openpilot in a testing closet containing 10 comma devices continuously replaying routes.
|
||||||
|
|
||||||
Pull requests should be against the most current `master-new` branch.
|
Licensing
|
||||||
|
------
|
||||||
|
|
||||||
## 📊 User Data
|
openpilot is released under the MIT license. Some parts of the software are released under other licenses as specified.
|
||||||
|
|
||||||
By default, sunnypilot uploads the driving data to comma servers. You can also access your data through [comma connect](https://connect.comma.ai/).
|
Any user of this software shall indemnify and hold harmless Comma.ai, Inc. and its directors, officers, employees, agents, stockholders, affiliates, subcontractors and customers from and against all allegations, claims, actions, suits, demands, damages, liabilities, obligations, losses, settlements, judgments, costs and expenses (including without limitation attorneys’ fees and costs) which arise out of, relate to or result from any use of this software by user.
|
||||||
|
|
||||||
sunnypilot is open source software. The user is free to disable data collection if they wish to do so.
|
**THIS IS ALPHA QUALITY SOFTWARE FOR RESEARCH PURPOSES ONLY. THIS IS NOT A PRODUCT.
|
||||||
|
YOU ARE RESPONSIBLE FOR COMPLYING WITH LOCAL LAWS AND REGULATIONS.
|
||||||
|
NO WARRANTY EXPRESSED OR IMPLIED.**
|
||||||
|
|
||||||
sunnypilot logs the road-facing camera, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs.
|
User Data and comma Account
|
||||||
|
------
|
||||||
|
|
||||||
|
By default, openpilot uploads the driving data to our servers. You can also access your data through [comma connect](https://connect.comma.ai/). We use your data to train better models and improve openpilot for everyone.
|
||||||
|
|
||||||
|
openpilot is open source software: the user is free to disable data collection if they wish to do so.
|
||||||
|
|
||||||
|
openpilot logs the road-facing cameras, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs.
|
||||||
The driver-facing camera is only logged if you explicitly opt-in in settings. The microphone is not recorded.
|
The driver-facing camera is only logged if you explicitly opt-in in settings. The microphone is not recorded.
|
||||||
|
|
||||||
By using this software, you understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma for the use of this data.
|
By using openpilot, you agree to [our Privacy Policy](https://comma.ai/privacy). You understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma for the use of this data.
|
||||||
|
|
||||||
## Licensing
|
|
||||||
|
|
||||||
sunnypilot is released under the [MIT License](LICENSE). This repository includes original work as well as significant portions of code derived from [openpilot by comma.ai](https://github.com/commaai/openpilot), which is also released under the MIT license with additional disclaimers.
|
|
||||||
|
|
||||||
The original openpilot license notice, including comma.ai’s indemnification and alpha software disclaimer, is reproduced below as required:
|
|
||||||
|
|
||||||
> openpilot is released under the MIT license. Some parts of the software are released under other licenses as specified.
|
|
||||||
>
|
|
||||||
> Any user of this software shall indemnify and hold harmless Comma.ai, Inc. and its directors, officers, employees, agents, stockholders, affiliates, subcontractors and customers from and against all allegations, claims, actions, suits, demands, damages, liabilities, obligations, losses, settlements, judgments, costs and expenses (including without limitation attorneys’ fees and costs) which arise out of, relate to or result from any use of this software by user.
|
|
||||||
>
|
|
||||||
> **THIS IS ALPHA QUALITY SOFTWARE FOR RESEARCH PURPOSES ONLY. THIS IS NOT A PRODUCT.
|
|
||||||
> YOU ARE RESPONSIBLE FOR COMPLYING WITH LOCAL LAWS AND REGULATIONS.
|
|
||||||
> NO WARRANTY EXPRESSED OR IMPLIED.**
|
|
||||||
|
|
||||||
For full license terms, please see the [`LICENSE`](LICENSE) file.
|
|
||||||
|
|
||||||
## 💰 Support sunnypilot
|
|
||||||
If you find any of the features useful, consider becoming a [sponsor on GitHub](https://github.com/sponsors/sunnyhaibin) to support future feature development and improvements.
|
|
||||||
|
|
||||||
|
|
||||||
By becoming a sponsor, you will gain access to exclusive content, early access to new features, and the opportunity to directly influence the project's development.
|
|
||||||
|
|
||||||
|
|
||||||
<h3>GitHub Sponsor</h3>
|
|
||||||
|
|
||||||
<a href="https://github.com/sponsors/sunnyhaibin">
|
|
||||||
<img src="https://user-images.githubusercontent.com/47793918/244135584-9800acbd-69fd-4b2b-bec9-e5fa2d85c817.png" alt="Become a Sponsor" width="300" style="max-width: 100%; height: auto;">
|
|
||||||
</a>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<h3>PayPal</h3>
|
|
||||||
|
|
||||||
<a href="https://paypal.me/sunnyhaibin0850" target="_blank">
|
|
||||||
<img src="https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif" alt="PayPal this" title="PayPal - The safer, easier way to pay online!" border="0" />
|
|
||||||
</a>
|
|
||||||
<br></br>
|
|
||||||
|
|
||||||
Your continuous love and support are greatly appreciated! Enjoy 🥰
|
|
||||||
|
|
||||||
<span>-</span> Jason, Founder of sunnypilot
|
|
||||||
|
|||||||
+5
-22
@@ -1,33 +1,16 @@
|
|||||||
Version 0.9.10 (2025-06-30)
|
Version 0.9.8 (2024-XX-XX)
|
||||||
========================
|
|
||||||
|
|
||||||
Version 0.9.9 (2025-05-23)
|
|
||||||
========================
|
========================
|
||||||
* New driving model
|
* New driving model
|
||||||
* New training architecture using parts from MLSIM
|
* Trained in brand new ML simulator
|
||||||
* Steering actuation delay is now learned online
|
* Model now gates applying positive accel in Chill mode
|
||||||
* Ford Escape 2023-24 support thanks to incognitojam!
|
* New driving monitoring model
|
||||||
* Ford Kuga 2024 support thanks to incognitojam!
|
|
||||||
* Hyundai Nexo 2021 support thanks to sunnyhaibin!
|
|
||||||
* Tesla Model 3 and Y support thanks to lukasloetkolben!
|
|
||||||
* Lexus RC 2023 support thanks to nelsonjchen!
|
|
||||||
|
|
||||||
Version 0.9.8 (2025-02-28)
|
|
||||||
========================
|
|
||||||
* New driving model
|
|
||||||
* Model now gates applying positive acceleration in Chill mode
|
|
||||||
* New driver monitoring model
|
|
||||||
* Reduced false positives related to passengers
|
* Reduced false positives related to passengers
|
||||||
* Image processing pipeline moved to the ISP
|
* Image processing pipeline moved to the ISP
|
||||||
* More GPU time for bigger driving models
|
* More GPU time for driving models
|
||||||
* Power draw reduced 0.5W, which means your device runs cooler
|
* Power draw reduced 0.5W, which means your device runs cooler
|
||||||
* Added toggle to enable driver monitoring even when openpilot is not engaged
|
* Added toggle to enable driver monitoring even when openpilot is not engaged
|
||||||
* Localizer rewritten to remove GPS dependency at runtime
|
|
||||||
* Firehose Mode for maximizing your training data uploads
|
|
||||||
* Enable openpilot longitudinal control for Ford Q3 vehicles
|
* Enable openpilot longitudinal control for Ford Q3 vehicles
|
||||||
* New Toyota TSS2 longitudinal tune
|
* New Toyota TSS2 longitudinal tune
|
||||||
* Rivian R1S and R1T support thanks to lukasloetkolben!
|
|
||||||
* Ford F-150, F-150 Hybrid, Mach-E, and Ranger support
|
|
||||||
|
|
||||||
Version 0.9.7 (2024-06-13)
|
Version 0.9.7 (2024-06-13)
|
||||||
========================
|
========================
|
||||||
|
|||||||
+20
-17
@@ -49,12 +49,21 @@ AddOption('--ccflags',
|
|||||||
default='',
|
default='',
|
||||||
help='pass arbitrary flags over the command line')
|
help='pass arbitrary flags over the command line')
|
||||||
|
|
||||||
|
AddOption('--snpe',
|
||||||
|
action='store_true',
|
||||||
|
help='use SNPE on PC')
|
||||||
|
|
||||||
AddOption('--external-sconscript',
|
AddOption('--external-sconscript',
|
||||||
action='store',
|
action='store',
|
||||||
metavar='FILE',
|
metavar='FILE',
|
||||||
dest='external_sconscript',
|
dest='external_sconscript',
|
||||||
help='add an external SConscript to the build')
|
help='add an external SConscript to the build')
|
||||||
|
|
||||||
|
AddOption('--pc-thneed',
|
||||||
|
action='store_true',
|
||||||
|
dest='pc_thneed',
|
||||||
|
help='use thneed on pc')
|
||||||
|
|
||||||
AddOption('--mutation',
|
AddOption('--mutation',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
help='generate mutation-ready code')
|
help='generate mutation-ready code')
|
||||||
@@ -65,12 +74,6 @@ AddOption('--minimal',
|
|||||||
default=os.path.exists(File('#.lfsconfig').abspath), # minimal by default on release branch (where there's no LFS)
|
default=os.path.exists(File('#.lfsconfig').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.')
|
||||||
|
|
||||||
AddOption('--stock-ui',
|
|
||||||
action='store_true',
|
|
||||||
dest='stock_ui',
|
|
||||||
default=False,
|
|
||||||
help='Build stock openpilot UI instead of sunnypilot UI')
|
|
||||||
|
|
||||||
## Architecture name breakdown (arch)
|
## Architecture name breakdown (arch)
|
||||||
## - larch64: linux tici aarch64
|
## - larch64: linux tici aarch64
|
||||||
## - aarch64: linux pc aarch64
|
## - aarch64: linux pc aarch64
|
||||||
@@ -169,10 +172,6 @@ else:
|
|||||||
if arch != "Darwin":
|
if arch != "Darwin":
|
||||||
ldflags += ["-Wl,--as-needed", "-Wl,--no-undefined"]
|
ldflags += ["-Wl,--as-needed", "-Wl,--no-undefined"]
|
||||||
|
|
||||||
if not GetOption('stock_ui'):
|
|
||||||
cflags += ["-DSUNNYPILOT"]
|
|
||||||
cxxflags += ["-DSUNNYPILOT"]
|
|
||||||
|
|
||||||
ccflags_option = GetOption('ccflags')
|
ccflags_option = GetOption('ccflags')
|
||||||
if ccflags_option:
|
if ccflags_option:
|
||||||
ccflags += ccflags_option.split(' ')
|
ccflags += ccflags_option.split(' ')
|
||||||
@@ -238,8 +237,7 @@ if GetOption('compile_db'):
|
|||||||
env.CompilationDatabase('compile_commands.json')
|
env.CompilationDatabase('compile_commands.json')
|
||||||
|
|
||||||
# Setup cache dir
|
# Setup cache dir
|
||||||
default_cache_dir = '/data/scons_cache' if AGNOS else '/tmp/scons_cache'
|
cache_dir = '/data/scons_cache' if AGNOS else '/tmp/scons_cache'
|
||||||
cache_dir = ARGUMENTS.get('cache_dir', default_cache_dir)
|
|
||||||
CacheDir(cache_dir)
|
CacheDir(cache_dir)
|
||||||
Clean(["."], cache_dir)
|
Clean(["."], cache_dir)
|
||||||
|
|
||||||
@@ -304,7 +302,12 @@ else:
|
|||||||
elif arch != "Darwin":
|
elif arch != "Darwin":
|
||||||
qt_libs += ["GL"]
|
qt_libs += ["GL"]
|
||||||
qt_env['QT3DIR'] = qt_env['QTDIR']
|
qt_env['QT3DIR'] = qt_env['QTDIR']
|
||||||
qt_env.Tool('qt3')
|
|
||||||
|
# compatibility for older SCons versions
|
||||||
|
try:
|
||||||
|
qt_env.Tool('qt3')
|
||||||
|
except SCons.Errors.UserError:
|
||||||
|
qt_env.Tool('qt')
|
||||||
|
|
||||||
qt_env['CPPPATH'] += qt_dirs + ["#third_party/qrcode"]
|
qt_env['CPPPATH'] += qt_dirs + ["#third_party/qrcode"]
|
||||||
qt_flags = [
|
qt_flags = [
|
||||||
@@ -351,7 +354,7 @@ SConscript(['opendbc_repo/SConscript'], exports={'env': env_swaglog})
|
|||||||
SConscript(['cereal/SConscript'])
|
SConscript(['cereal/SConscript'])
|
||||||
|
|
||||||
Import('socketmaster', 'msgq')
|
Import('socketmaster', 'msgq')
|
||||||
messaging = [socketmaster, msgq, 'capnp', 'kj',]
|
messaging = [socketmaster, msgq, 'zmq', 'capnp', 'kj',]
|
||||||
Export('messaging')
|
Export('messaging')
|
||||||
|
|
||||||
|
|
||||||
@@ -363,13 +366,15 @@ SConscript(['rednose/SConscript'])
|
|||||||
|
|
||||||
# Build system services
|
# Build system services
|
||||||
SConscript([
|
SConscript([
|
||||||
|
'system/ui/SConscript',
|
||||||
|
'system/proclogd/SConscript',
|
||||||
'system/ubloxd/SConscript',
|
'system/ubloxd/SConscript',
|
||||||
'system/loggerd/SConscript',
|
'system/loggerd/SConscript',
|
||||||
])
|
])
|
||||||
if arch != "Darwin":
|
if arch != "Darwin":
|
||||||
SConscript([
|
SConscript([
|
||||||
|
'system/sensord/SConscript',
|
||||||
'system/logcatd/SConscript',
|
'system/logcatd/SConscript',
|
||||||
'system/proclogd/SConscript',
|
|
||||||
])
|
])
|
||||||
|
|
||||||
if arch == "larch64":
|
if arch == "larch64":
|
||||||
@@ -380,8 +385,6 @@ SConscript(['third_party/SConscript'])
|
|||||||
|
|
||||||
SConscript(['selfdrive/SConscript'])
|
SConscript(['selfdrive/SConscript'])
|
||||||
|
|
||||||
SConscript(['sunnypilot/SConscript'])
|
|
||||||
|
|
||||||
if Dir('#tools/cabana/').exists() and GetOption('extras'):
|
if Dir('#tools/cabana/').exists() and GetOption('extras'):
|
||||||
SConscript(['tools/replay/SConscript'])
|
SConscript(['tools/replay/SConscript'])
|
||||||
if arch != "larch64":
|
if arch != "larch64":
|
||||||
|
|||||||
@@ -29,50 +29,6 @@ then means breaking backwards-compatibility with all old logs of your fork. So w
|
|||||||
[custom.capnp](custom.capnp) that we will leave empty in mainline cereal/openpilot. **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:
|
|
||||||
```diff
|
|
||||||
diff --git a/cereal/custom.capnp b/cereal/custom.capnp
|
|
||||||
index 3348e859e..3365c7b98 100644
|
|
||||||
--- a/cereal/custom.capnp
|
|
||||||
+++ b/cereal/custom.capnp
|
|
||||||
@@ -10,7 +10,11 @@ $Cxx.namespace("cereal");
|
|
||||||
# DO rename the structs
|
|
||||||
# DON'T change the identifier (e.g. @0x81c2f05a394cf4af)
|
|
||||||
|
|
||||||
-struct CustomReserved0 @0x81c2f05a394cf4af {
|
|
||||||
+struct SteeringInfo @0x81c2f05a394cf4af {
|
|
||||||
+ active @0 :Bool;
|
|
||||||
+ steeringAngleDeg @1 :Float32;
|
|
||||||
+ steeringRateDeg @2 :Float32;
|
|
||||||
+ steeringAccelDeg @3 :Float32;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CustomReserved1 @0xaedffd8f31e7b55d {
|
|
||||||
diff --git a/cereal/log.capnp b/cereal/log.capnp
|
|
||||||
index 1209f3fd9..b189f58b6 100644
|
|
||||||
--- a/cereal/log.capnp
|
|
||||||
+++ b/cereal/log.capnp
|
|
||||||
@@ -2558,14 +2558,14 @@ struct Event {
|
|
||||||
|
|
||||||
# DO change the name of the field
|
|
||||||
# DON'T change anything after the "@"
|
|
||||||
- customReservedRawData0 @124 :Data;
|
|
||||||
+ rawCanData @124 :Data;
|
|
||||||
customReservedRawData1 @125 :Data;
|
|
||||||
customReservedRawData2 @126 :Data;
|
|
||||||
|
|
||||||
# DO change the name of the field and struct
|
|
||||||
# DON'T change the ID (e.g. @107)
|
|
||||||
# DON'T change which struct it points to
|
|
||||||
- customReserved0 @107 :Custom.CustomReserved0;
|
|
||||||
+ steeringInfo @107 :Custom.SteeringInfo;
|
|
||||||
customReserved1 @108 :Custom.CustomReserved1;
|
|
||||||
customReserved2 @109 :Custom.CustomReserved2;
|
|
||||||
customReserved3 @110 :Custom.CustomReserved3;
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Example
|
Example
|
||||||
---
|
---
|
||||||
```python
|
```python
|
||||||
|
|||||||
+4
-6
@@ -1,11 +1,9 @@
|
|||||||
import os
|
import os
|
||||||
import capnp
|
import capnp
|
||||||
from importlib.resources import as_file, files
|
|
||||||
|
|
||||||
|
CEREAL_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||||
capnp.remove_import_hook()
|
capnp.remove_import_hook()
|
||||||
|
|
||||||
with as_file(files("cereal")) as fspath:
|
log = capnp.load(os.path.join(CEREAL_PATH, "log.capnp"))
|
||||||
CEREAL_PATH = fspath.as_posix()
|
car = capnp.load(os.path.join(CEREAL_PATH, "car.capnp"))
|
||||||
log = capnp.load(os.path.join(CEREAL_PATH, "log.capnp"))
|
custom = capnp.load(os.path.join(CEREAL_PATH, "custom.capnp"))
|
||||||
car = capnp.load(os.path.join(CEREAL_PATH, "car.capnp"))
|
|
||||||
custom = capnp.load(os.path.join(CEREAL_PATH, "custom.capnp"))
|
|
||||||
|
|||||||
+10
-240
@@ -7,263 +7,33 @@ $Cxx.namespace("cereal");
|
|||||||
# These structs are guaranteed to remain reserved and empty in mainline
|
# These structs are guaranteed to remain reserved and empty in mainline
|
||||||
# cereal, so use these if you want custom events in your fork.
|
# cereal, so use these if you want custom events in your fork.
|
||||||
|
|
||||||
# DO rename the structs
|
# you can rename the struct, but don't change the identifier
|
||||||
# DON'T change the identifier (e.g. @0x81c2f05a394cf4af)
|
struct CustomReserved0 @0x81c2f05a394cf4af {
|
||||||
|
|
||||||
struct ModularAssistiveDrivingSystem {
|
|
||||||
state @0 :ModularAssistiveDrivingSystemState;
|
|
||||||
enabled @1 :Bool;
|
|
||||||
active @2 :Bool;
|
|
||||||
available @3 :Bool;
|
|
||||||
|
|
||||||
enum ModularAssistiveDrivingSystemState {
|
|
||||||
disabled @0;
|
|
||||||
paused @1;
|
|
||||||
enabled @2;
|
|
||||||
softDisabling @3;
|
|
||||||
overriding @4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SelfdriveStateSP @0x81c2f05a394cf4af {
|
struct CustomReserved1 @0xaedffd8f31e7b55d {
|
||||||
mads @0 :ModularAssistiveDrivingSystem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ModelManagerSP @0xaedffd8f31e7b55d {
|
struct CustomReserved2 @0xf35cc4560bbf6ec2 {
|
||||||
activeBundle @0 :ModelBundle;
|
|
||||||
selectedBundle @1 :ModelBundle;
|
|
||||||
availableBundles @2 :List(ModelBundle);
|
|
||||||
|
|
||||||
struct DownloadUri {
|
|
||||||
uri @0 :Text;
|
|
||||||
sha256 @1 :Text;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum DownloadStatus {
|
|
||||||
notDownloading @0;
|
|
||||||
downloading @1;
|
|
||||||
downloaded @2;
|
|
||||||
cached @3;
|
|
||||||
failed @4;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DownloadProgress {
|
|
||||||
status @0 :DownloadStatus;
|
|
||||||
progress @1 :Float32;
|
|
||||||
eta @2 :UInt32;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Artifact {
|
|
||||||
fileName @0 :Text;
|
|
||||||
downloadUri @1 :DownloadUri;
|
|
||||||
downloadProgress @2 :DownloadProgress;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Model {
|
|
||||||
type @0 :Type;
|
|
||||||
artifact @1 :Artifact; # Main artifact
|
|
||||||
metadata @2 :Artifact; # Metadata artifact
|
|
||||||
|
|
||||||
enum Type {
|
|
||||||
supercombo @0;
|
|
||||||
navigation @1;
|
|
||||||
vision @2;
|
|
||||||
policy @3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Runner {
|
|
||||||
snpe @0;
|
|
||||||
tinygrad @1;
|
|
||||||
stock @2;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Override {
|
|
||||||
key @0 :Text;
|
|
||||||
value @1 :Text;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ModelBundle {
|
|
||||||
index @0 :UInt32;
|
|
||||||
internalName @1 :Text;
|
|
||||||
displayName @2 :Text;
|
|
||||||
models @3 :List(Model);
|
|
||||||
status @4 :DownloadStatus;
|
|
||||||
generation @5 :UInt32;
|
|
||||||
environment @6 :Text;
|
|
||||||
runner @7 :Runner;
|
|
||||||
is20hz @8 :Bool;
|
|
||||||
ref @9 :Text;
|
|
||||||
minimumSelectorVersion @10 :UInt32;
|
|
||||||
overrides @11 :List(Override);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LongitudinalPlanSP @0xf35cc4560bbf6ec2 {
|
struct CustomReserved3 @0xda96579883444c35 {
|
||||||
dec @0 :DynamicExperimentalControl;
|
|
||||||
|
|
||||||
struct DynamicExperimentalControl {
|
|
||||||
state @0 :DynamicExperimentalControlState;
|
|
||||||
enabled @1 :Bool;
|
|
||||||
active @2 :Bool;
|
|
||||||
|
|
||||||
enum DynamicExperimentalControlState {
|
|
||||||
acc @0;
|
|
||||||
blended @1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OnroadEventSP @0xda96579883444c35 {
|
struct CustomReserved4 @0x80ae746ee2596b11 {
|
||||||
events @0 :List(Event);
|
|
||||||
|
|
||||||
struct Event {
|
|
||||||
name @0 :EventName;
|
|
||||||
|
|
||||||
# event types
|
|
||||||
enable @1 :Bool;
|
|
||||||
noEntry @2 :Bool;
|
|
||||||
warning @3 :Bool; # alerts presented only when enabled or soft disabling
|
|
||||||
userDisable @4 :Bool;
|
|
||||||
softDisable @5 :Bool;
|
|
||||||
immediateDisable @6 :Bool;
|
|
||||||
preEnable @7 :Bool;
|
|
||||||
permanent @8 :Bool; # alerts presented regardless of openpilot state
|
|
||||||
overrideLateral @10 :Bool;
|
|
||||||
overrideLongitudinal @9 :Bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum EventName {
|
|
||||||
lkasEnable @0;
|
|
||||||
lkasDisable @1;
|
|
||||||
manualSteeringRequired @2;
|
|
||||||
manualLongitudinalRequired @3;
|
|
||||||
silentLkasEnable @4;
|
|
||||||
silentLkasDisable @5;
|
|
||||||
silentBrakeHold @6;
|
|
||||||
silentWrongGear @7;
|
|
||||||
silentReverseGear @8;
|
|
||||||
silentDoorOpen @9;
|
|
||||||
silentSeatbeltNotLatched @10;
|
|
||||||
silentParkBrake @11;
|
|
||||||
controlsMismatchLateral @12;
|
|
||||||
hyundaiRadarTracksConfirmed @13;
|
|
||||||
experimentalModeSwitched @14;
|
|
||||||
wrongCarModeAlertOnly @15;
|
|
||||||
pedalPressedAlertOnly @16;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CarParamsSP @0x80ae746ee2596b11 {
|
struct CustomReserved5 @0xa5cd762cd951a455 {
|
||||||
flags @0 :UInt32; # flags for car specific quirks in sunnypilot
|
|
||||||
safetyParam @1 : Int16; # flags for sunnypilot's custom safety flags
|
|
||||||
|
|
||||||
neuralNetworkLateralControl @2 :NeuralNetworkLateralControl;
|
|
||||||
|
|
||||||
struct NeuralNetworkLateralControl {
|
|
||||||
model @0 :Model;
|
|
||||||
fuzzyFingerprint @1 :Bool;
|
|
||||||
|
|
||||||
struct Model {
|
|
||||||
path @0 :Text;
|
|
||||||
name @1 :Text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CarControlSP @0xa5cd762cd951a455 {
|
struct CustomReserved6 @0xf98d843bfd7004a3 {
|
||||||
mads @0 :ModularAssistiveDrivingSystem;
|
|
||||||
params @1 :List(Param);
|
|
||||||
|
|
||||||
struct Param {
|
|
||||||
key @0 :Text;
|
|
||||||
value @1 :Text;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BackupManagerSP @0xf98d843bfd7004a3 {
|
struct CustomReserved7 @0xb86e6369214c01c8 {
|
||||||
backupStatus @0 :Status;
|
|
||||||
restoreStatus @1 :Status;
|
|
||||||
backupProgress @2 :Float32;
|
|
||||||
restoreProgress @3 :Float32;
|
|
||||||
lastError @4 :Text;
|
|
||||||
currentBackup @5 :BackupInfo;
|
|
||||||
backupHistory @6 :List(BackupInfo);
|
|
||||||
|
|
||||||
enum Status {
|
|
||||||
idle @0;
|
|
||||||
inProgress @1;
|
|
||||||
completed @2;
|
|
||||||
failed @3;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Version {
|
|
||||||
major @0 :UInt16;
|
|
||||||
minor @1 :UInt16;
|
|
||||||
patch @2 :UInt16;
|
|
||||||
build @3 :UInt16;
|
|
||||||
branch @4 :Text;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MetadataEntry {
|
|
||||||
key @0 :Text;
|
|
||||||
value @1 :Text;
|
|
||||||
tags @2 :List(Text);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct BackupInfo {
|
|
||||||
deviceId @0 :Text;
|
|
||||||
version @1 :UInt32;
|
|
||||||
config @2 :Text;
|
|
||||||
isEncrypted @3 :Bool;
|
|
||||||
createdAt @4 :Text; # ISO timestamp
|
|
||||||
updatedAt @5 :Text; # ISO timestamp
|
|
||||||
sunnypilotVersion @6 :Version;
|
|
||||||
backupMetadata @7 :List(MetadataEntry);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CarStateSP @0xb86e6369214c01c8 {
|
struct CustomReserved8 @0xf416ec09499d9d19 {
|
||||||
}
|
|
||||||
|
|
||||||
struct LiveMapDataSP @0xf416ec09499d9d19 {
|
|
||||||
speedLimitValid @0 :Bool;
|
|
||||||
speedLimit @1 :Float32;
|
|
||||||
speedLimitAheadValid @2 :Bool;
|
|
||||||
speedLimitAhead @3 :Float32;
|
|
||||||
speedLimitAheadDistance @4 :Float32;
|
|
||||||
roadName @5 :Text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CustomReserved9 @0xa1680744031fdb2d {
|
struct CustomReserved9 @0xa1680744031fdb2d {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CustomReserved10 @0xcb9fd56c7057593a {
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CustomReserved11 @0xc2243c65e0340384 {
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CustomReserved12 @0x9ccdc8676701b412 {
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CustomReserved13 @0xcd96dafb67a082d0 {
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CustomReserved14 @0xb057204d7deadf3f {
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CustomReserved15 @0xbd443b539493bc68 {
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CustomReserved16 @0xfc6241ed8877b611 {
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CustomReserved17 @0xa30662f84033036c {
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CustomReserved18 @0xc86a3d38d13eb3ef {
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CustomReserved19 @0xa4f1eb3323f5f582 {
|
|
||||||
}
|
|
||||||
|
|||||||
+11
-78
@@ -48,7 +48,6 @@ struct OnroadEvent @0xc4fa6047f024e718 {
|
|||||||
preEnableStandstill @12; # added during pre-enable state with brake
|
preEnableStandstill @12; # added during pre-enable state with brake
|
||||||
gasPressedOverride @13; # added when user is pressing gas with no disengage on gas
|
gasPressedOverride @13; # added when user is pressing gas with no disengage on gas
|
||||||
steerOverride @14;
|
steerOverride @14;
|
||||||
steerDisengage @94; # exits active state
|
|
||||||
cruiseDisabled @15;
|
cruiseDisabled @15;
|
||||||
speedTooLow @16;
|
speedTooLow @16;
|
||||||
outOfSpace @17;
|
outOfSpace @17;
|
||||||
@@ -60,7 +59,6 @@ struct OnroadEvent @0xc4fa6047f024e718 {
|
|||||||
pcmEnable @23;
|
pcmEnable @23;
|
||||||
pcmDisable @24;
|
pcmDisable @24;
|
||||||
radarFault @25;
|
radarFault @25;
|
||||||
radarTempUnavailable @93;
|
|
||||||
brakeHold @26;
|
brakeHold @26;
|
||||||
parkBrake @27;
|
parkBrake @27;
|
||||||
manualRestart @28;
|
manualRestart @28;
|
||||||
@@ -127,7 +125,6 @@ struct OnroadEvent @0xc4fa6047f024e718 {
|
|||||||
espActive @90;
|
espActive @90;
|
||||||
personalityChanged @91;
|
personalityChanged @91;
|
||||||
aeb @92;
|
aeb @92;
|
||||||
userFlag @95;
|
|
||||||
|
|
||||||
soundsUnavailableDEPRECATED @47;
|
soundsUnavailableDEPRECATED @47;
|
||||||
}
|
}
|
||||||
@@ -154,10 +151,6 @@ struct InitData {
|
|||||||
gitBranch @11 :Text;
|
gitBranch @11 :Text;
|
||||||
gitRemote @13 :Text;
|
gitRemote @13 :Text;
|
||||||
|
|
||||||
# this is source commit for prebuilt branches
|
|
||||||
gitSrcCommit @23 :Text;
|
|
||||||
gitSrcCommitDate @24 :Text;
|
|
||||||
|
|
||||||
androidProperties @16 :Map(Text, Text);
|
androidProperties @16 :Map(Text, Text);
|
||||||
|
|
||||||
pandaInfo @8 :PandaInfo;
|
pandaInfo @8 :PandaInfo;
|
||||||
@@ -416,7 +409,6 @@ struct GpsLocationData {
|
|||||||
speedAccuracy @12 :Float32;
|
speedAccuracy @12 :Float32;
|
||||||
|
|
||||||
hasFix @13 :Bool;
|
hasFix @13 :Bool;
|
||||||
satelliteCount @14 :Int8;
|
|
||||||
|
|
||||||
enum SensorSource {
|
enum SensorSource {
|
||||||
android @0;
|
android @0;
|
||||||
@@ -490,7 +482,6 @@ struct DeviceState @0xa4d8b5af2aa492eb {
|
|||||||
# device thermals
|
# device thermals
|
||||||
cpuTempC @26 :List(Float32);
|
cpuTempC @26 :List(Float32);
|
||||||
gpuTempC @27 :List(Float32);
|
gpuTempC @27 :List(Float32);
|
||||||
dspTempC @49 :Float32;
|
|
||||||
memoryTempC @28 :Float32;
|
memoryTempC @28 :Float32;
|
||||||
nvmeTempC @35 :List(Float32);
|
nvmeTempC @35 :List(Float32);
|
||||||
modemTempC @36 :List(Float32);
|
modemTempC @36 :List(Float32);
|
||||||
@@ -732,7 +723,7 @@ struct PeripheralState {
|
|||||||
struct RadarState @0x9a185389d6fdd05f {
|
struct RadarState @0x9a185389d6fdd05f {
|
||||||
mdMonoTime @6 :UInt64;
|
mdMonoTime @6 :UInt64;
|
||||||
carStateMonoTime @11 :UInt64;
|
carStateMonoTime @11 :UInt64;
|
||||||
radarErrors @13 :Car.RadarData.Error;
|
radarErrors @12 :List(Car.RadarData.Error);
|
||||||
|
|
||||||
leadOne @3 :LeadData;
|
leadOne @3 :LeadData;
|
||||||
leadTwo @4 :LeadData;
|
leadTwo @4 :LeadData;
|
||||||
@@ -766,7 +757,6 @@ struct RadarState @0x9a185389d6fdd05f {
|
|||||||
calPercDEPRECATED @9 :Int8;
|
calPercDEPRECATED @9 :Int8;
|
||||||
canMonoTimesDEPRECATED @10 :List(UInt64);
|
canMonoTimesDEPRECATED @10 :List(UInt64);
|
||||||
cumLagMsDEPRECATED @5 :Float32;
|
cumLagMsDEPRECATED @5 :Float32;
|
||||||
radarErrorsDEPRECATED @12 :List(Car.RadarData.ErrorDEPRECATED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LiveCalibrationData {
|
struct LiveCalibrationData {
|
||||||
@@ -1177,8 +1167,6 @@ struct ModelDataV2 {
|
|||||||
|
|
||||||
struct Action {
|
struct Action {
|
||||||
desiredCurvature @0 :Float32;
|
desiredCurvature @0 :Float32;
|
||||||
desiredAcceleration @1 :Float32;
|
|
||||||
shouldStop @2 :Bool;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1591,10 +1579,6 @@ struct UbloxGnss {
|
|||||||
svId @0 :UInt8;
|
svId @0 :UInt8;
|
||||||
gnssId @1 :UInt8;
|
gnssId @1 :UInt8;
|
||||||
flagsBitfield @2 :UInt32;
|
flagsBitfield @2 :UInt32;
|
||||||
cno @3 :UInt8;
|
|
||||||
elevationDeg @4 :Int8;
|
|
||||||
azimuthDeg @5 :Int16;
|
|
||||||
pseudorangeResidual @6 :Float32;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2253,11 +2237,6 @@ struct LiveParametersData {
|
|||||||
roll @14 :Float32;
|
roll @14 :Float32;
|
||||||
debugFilterState @16 :FilterState;
|
debugFilterState @16 :FilterState;
|
||||||
|
|
||||||
angleOffsetValid @17 :Bool = true;
|
|
||||||
angleOffsetAverageValid @18 :Bool = true;
|
|
||||||
steerRatioValid @19 :Bool = true;
|
|
||||||
stiffnessFactorValid @20 :Bool = true;
|
|
||||||
|
|
||||||
yawRateDEPRECATED @7 :Float32;
|
yawRateDEPRECATED @7 :Float32;
|
||||||
filterStateDEPRECATED @15 :LiveLocationKalman.Measurement;
|
filterStateDEPRECATED @15 :LiveLocationKalman.Measurement;
|
||||||
|
|
||||||
@@ -2281,24 +2260,6 @@ struct LiveTorqueParametersData {
|
|||||||
points @10 :List(List(Float32));
|
points @10 :List(List(Float32));
|
||||||
version @11 :Int32;
|
version @11 :Int32;
|
||||||
useParams @12 :Bool;
|
useParams @12 :Bool;
|
||||||
calPerc @13 :Int8;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct LiveDelayData {
|
|
||||||
lateralDelay @0 :Float32;
|
|
||||||
validBlocks @1 :Int32;
|
|
||||||
status @2 :Status;
|
|
||||||
|
|
||||||
lateralDelayEstimate @3 :Float32;
|
|
||||||
lateralDelayEstimateStd @5 :Float32;
|
|
||||||
points @4 :List(Float32);
|
|
||||||
calPerc @6 :Int8;
|
|
||||||
|
|
||||||
enum Status {
|
|
||||||
unestimated @0;
|
|
||||||
estimated @1;
|
|
||||||
invalid @2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LiveMapDataDEPRECATED {
|
struct LiveMapDataDEPRECATED {
|
||||||
@@ -2479,14 +2440,6 @@ struct Microphone {
|
|||||||
filteredSoundPressureWeightedDb @2 :Float32;
|
filteredSoundPressureWeightedDb @2 :Float32;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Touch {
|
|
||||||
sec @0 :Int64;
|
|
||||||
usec @1 :Int64;
|
|
||||||
type @2 :UInt8;
|
|
||||||
code @3 :Int32;
|
|
||||||
value @4 :Int32;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Event {
|
struct Event {
|
||||||
logMonoTime @0 :UInt64; # nanoseconds
|
logMonoTime @0 :UInt64; # nanoseconds
|
||||||
valid @67 :Bool = true;
|
valid @67 :Bool = true;
|
||||||
@@ -2531,7 +2484,6 @@ struct Event {
|
|||||||
gnssMeasurements @91 :GnssMeasurements;
|
gnssMeasurements @91 :GnssMeasurements;
|
||||||
liveParameters @61 :LiveParametersData;
|
liveParameters @61 :LiveParametersData;
|
||||||
liveTorqueParameters @94 :LiveTorqueParametersData;
|
liveTorqueParameters @94 :LiveTorqueParametersData;
|
||||||
liveDelay @146 : LiveDelayData;
|
|
||||||
cameraOdometry @63 :CameraOdometry;
|
cameraOdometry @63 :CameraOdometry;
|
||||||
thumbnail @66: Thumbnail;
|
thumbnail @66: Thumbnail;
|
||||||
onroadEvents @134: List(OnroadEvent);
|
onroadEvents @134: List(OnroadEvent);
|
||||||
@@ -2568,9 +2520,6 @@ struct Event {
|
|||||||
logMessage @18 :Text;
|
logMessage @18 :Text;
|
||||||
errorLogMessage @85 :Text;
|
errorLogMessage @85 :Text;
|
||||||
|
|
||||||
# touch frame
|
|
||||||
touch @135 :List(Touch);
|
|
||||||
|
|
||||||
# navigation
|
# navigation
|
||||||
navInstruction @82 :NavInstruction;
|
navInstruction @82 :NavInstruction;
|
||||||
navRoute @83 :NavRoute;
|
navRoute @83 :NavRoute;
|
||||||
@@ -2593,37 +2542,21 @@ struct Event {
|
|||||||
livestreamWideRoadEncodeData @121 :EncodeData;
|
livestreamWideRoadEncodeData @121 :EncodeData;
|
||||||
livestreamDriverEncodeData @122 :EncodeData;
|
livestreamDriverEncodeData @122 :EncodeData;
|
||||||
|
|
||||||
# *********** Custom: reserved for forks ***********
|
|
||||||
|
|
||||||
# DO change the name of the field
|
|
||||||
# DON'T change anything after the "@"
|
|
||||||
customReservedRawData0 @124 :Data;
|
customReservedRawData0 @124 :Data;
|
||||||
customReservedRawData1 @125 :Data;
|
customReservedRawData1 @125 :Data;
|
||||||
customReservedRawData2 @126 :Data;
|
customReservedRawData2 @126 :Data;
|
||||||
|
|
||||||
# DO change the name of the field and struct
|
# *********** Custom: reserved for forks ***********
|
||||||
# DON'T change the ID (e.g. @107)
|
customReserved0 @107 :Custom.CustomReserved0;
|
||||||
# DON'T change which struct it points to
|
customReserved1 @108 :Custom.CustomReserved1;
|
||||||
selfdriveStateSP @107 :Custom.SelfdriveStateSP;
|
customReserved2 @109 :Custom.CustomReserved2;
|
||||||
modelManagerSP @108 :Custom.ModelManagerSP;
|
customReserved3 @110 :Custom.CustomReserved3;
|
||||||
longitudinalPlanSP @109 :Custom.LongitudinalPlanSP;
|
customReserved4 @111 :Custom.CustomReserved4;
|
||||||
onroadEventsSP @110 :Custom.OnroadEventSP;
|
customReserved5 @112 :Custom.CustomReserved5;
|
||||||
carParamsSP @111 :Custom.CarParamsSP;
|
customReserved6 @113 :Custom.CustomReserved6;
|
||||||
carControlSP @112 :Custom.CarControlSP;
|
customReserved7 @114 :Custom.CustomReserved7;
|
||||||
backupManagerSP @113 :Custom.BackupManagerSP;
|
customReserved8 @115 :Custom.CustomReserved8;
|
||||||
carStateSP @114 :Custom.CarStateSP;
|
|
||||||
liveMapDataSP @115 :Custom.LiveMapDataSP;
|
|
||||||
customReserved9 @116 :Custom.CustomReserved9;
|
customReserved9 @116 :Custom.CustomReserved9;
|
||||||
customReserved10 @136 :Custom.CustomReserved10;
|
|
||||||
customReserved11 @137 :Custom.CustomReserved11;
|
|
||||||
customReserved12 @138 :Custom.CustomReserved12;
|
|
||||||
customReserved13 @139 :Custom.CustomReserved13;
|
|
||||||
customReserved14 @140 :Custom.CustomReserved14;
|
|
||||||
customReserved15 @141 :Custom.CustomReserved15;
|
|
||||||
customReserved16 @142 :Custom.CustomReserved16;
|
|
||||||
customReserved17 @143 :Custom.CustomReserved17;
|
|
||||||
customReserved18 @144 :Custom.CustomReserved18;
|
|
||||||
customReserved19 @145 :Custom.CustomReserved19;
|
|
||||||
|
|
||||||
# *********** legacy + deprecated ***********
|
# *********** legacy + deprecated ***********
|
||||||
model @9 :Legacy.ModelData; # TODO: rename modelV2 and mark this as deprecated
|
model @9 :Legacy.ModelData; # TODO: rename modelV2 and mark this as deprecated
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
using Cxx = import "./include/c++.capnp";
|
||||||
|
$Cxx.namespace("cereal");
|
||||||
|
|
||||||
|
@0xa086df597ef5d7a0;
|
||||||
|
|
||||||
|
# Geometry
|
||||||
|
struct Point {
|
||||||
|
x @0: Float64;
|
||||||
|
y @1: Float64;
|
||||||
|
z @2: Float64;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PolyLine {
|
||||||
|
points @0: List(Point);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Map features
|
||||||
|
struct Lane {
|
||||||
|
id @0 :Text;
|
||||||
|
|
||||||
|
leftBoundary @1 :LaneBoundary;
|
||||||
|
rightBoundary @2 :LaneBoundary;
|
||||||
|
|
||||||
|
leftAdjacentId @3 :Text;
|
||||||
|
rightAdjacentId @4 :Text;
|
||||||
|
|
||||||
|
inboundIds @5 :List(Text);
|
||||||
|
outboundIds @6 :List(Text);
|
||||||
|
|
||||||
|
struct LaneBoundary {
|
||||||
|
polyLine @0 :PolyLine;
|
||||||
|
startHeading @1 :Float32; # WRT north
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Map tiles
|
||||||
|
struct TileSummary {
|
||||||
|
version @0 :Text;
|
||||||
|
updatedAt @1 :UInt64; # Millis since epoch
|
||||||
|
|
||||||
|
level @2 :UInt8;
|
||||||
|
x @3 :UInt16;
|
||||||
|
y @4 :UInt16;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MapTile {
|
||||||
|
summary @0 :TileSummary;
|
||||||
|
lanes @1 :List(Lane);
|
||||||
|
}
|
||||||
@@ -9,11 +9,11 @@ import os
|
|||||||
import capnp
|
import capnp
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from typing import Optional, List, Union, Dict
|
from typing import Optional, List, Union, Dict, Deque
|
||||||
|
from collections import deque
|
||||||
|
|
||||||
from cereal import log
|
from cereal import log
|
||||||
from cereal.services import SERVICE_LIST
|
from cereal.services import SERVICE_LIST
|
||||||
from openpilot.common.util import MovingAverage
|
|
||||||
|
|
||||||
NO_TRAVERSAL_LIMIT = 2**64-1
|
NO_TRAVERSAL_LIMIT = 2**64-1
|
||||||
|
|
||||||
@@ -108,8 +108,10 @@ class FrequencyTracker:
|
|||||||
|
|
||||||
self.min_freq = min_freq * 0.8
|
self.min_freq = min_freq * 0.8
|
||||||
self.max_freq = max_freq * 1.2
|
self.max_freq = max_freq * 1.2
|
||||||
self.avg_dt = MovingAverage(int(10 * freq))
|
self.recv_dts: Deque[float] = deque(maxlen=int(10 * freq))
|
||||||
self.recent_avg_dt = MovingAverage(int(freq))
|
self.recv_dts_sum = 0.0
|
||||||
|
self.recent_recv_dts: Deque[float] = deque(maxlen=int(freq))
|
||||||
|
self.recent_recv_dts_sum = 0.0
|
||||||
self.prev_time = 0.0
|
self.prev_time = 0.0
|
||||||
|
|
||||||
def record_recv_time(self, cur_time: float) -> None:
|
def record_recv_time(self, cur_time: float) -> None:
|
||||||
@@ -117,21 +119,28 @@ class FrequencyTracker:
|
|||||||
if self.prev_time > 1e-5:
|
if self.prev_time > 1e-5:
|
||||||
dt = cur_time - self.prev_time
|
dt = cur_time - self.prev_time
|
||||||
|
|
||||||
self.avg_dt.add_value(dt)
|
if len(self.recv_dts) == self.recv_dts.maxlen:
|
||||||
self.recent_avg_dt.add_value(dt)
|
self.recv_dts_sum -= self.recv_dts[0]
|
||||||
|
self.recv_dts.append(dt)
|
||||||
|
self.recv_dts_sum += dt
|
||||||
|
|
||||||
|
if len(self.recent_recv_dts) == self.recent_recv_dts.maxlen:
|
||||||
|
self.recent_recv_dts_sum -= self.recent_recv_dts[0]
|
||||||
|
self.recent_recv_dts.append(dt)
|
||||||
|
self.recent_recv_dts_sum += dt
|
||||||
|
|
||||||
self.prev_time = cur_time
|
self.prev_time = cur_time
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def valid(self) -> bool:
|
def valid(self) -> bool:
|
||||||
if self.avg_dt.count == 0:
|
if not self.recv_dts:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
avg_freq = 1.0 / self.avg_dt.get_average()
|
avg_freq = len(self.recv_dts) / self.recv_dts_sum
|
||||||
if self.min_freq <= avg_freq <= self.max_freq:
|
if self.min_freq <= avg_freq <= self.max_freq:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
avg_freq_recent = 1.0 / self.recent_avg_dt.get_average()
|
avg_freq_recent = len(self.recent_recv_dts) / self.recent_recv_dts_sum
|
||||||
return self.min_freq <= avg_freq_recent <= self.max_freq
|
return self.min_freq <= avg_freq_recent <= self.max_freq
|
||||||
|
|
||||||
|
|
||||||
@@ -145,16 +154,12 @@ class SubMaster:
|
|||||||
self.updated = {s: False for s in services}
|
self.updated = {s: False for s in services}
|
||||||
self.recv_time = {s: 0. for s in services}
|
self.recv_time = {s: 0. for s in services}
|
||||||
self.recv_frame = {s: 0 for s in services}
|
self.recv_frame = {s: 0 for s in services}
|
||||||
|
self.alive = {s: False for s in services}
|
||||||
|
self.freq_ok = {s: False for s in services}
|
||||||
self.sock = {}
|
self.sock = {}
|
||||||
self.data = {}
|
self.data = {}
|
||||||
self.logMonoTime = {s: 0 for s in services}
|
self.valid = {}
|
||||||
|
self.logMonoTime = {}
|
||||||
# zero-frequency / on-demand services are always alive and presumed valid; all others must pass checks
|
|
||||||
on_demand = {s: SERVICE_LIST[s].frequency <= 1e-5 for s in services}
|
|
||||||
self.static_freq_services = set(s for s in services if not on_demand[s])
|
|
||||||
self.alive = {s: on_demand[s] for s in services}
|
|
||||||
self.freq_ok = {s: on_demand[s] for s in services}
|
|
||||||
self.valid = {s: on_demand[s] for s in services}
|
|
||||||
|
|
||||||
self.freq_tracker: Dict[str, FrequencyTracker] = {}
|
self.freq_tracker: Dict[str, FrequencyTracker] = {}
|
||||||
self.poller = Poller()
|
self.poller = Poller()
|
||||||
@@ -181,6 +186,8 @@ class SubMaster:
|
|||||||
data = new_message(s, 0) # lists
|
data = new_message(s, 0) # lists
|
||||||
|
|
||||||
self.data[s] = getattr(data.as_reader(), s)
|
self.data[s] = getattr(data.as_reader(), s)
|
||||||
|
self.logMonoTime[s] = 0
|
||||||
|
self.valid[s] = False
|
||||||
self.freq_tracker[s] = FrequencyTracker(SERVICE_LIST[s].frequency, self.update_freq, s == poll)
|
self.freq_tracker[s] = FrequencyTracker(SERVICE_LIST[s].frequency, self.update_freq, s == poll)
|
||||||
|
|
||||||
def __getitem__(self, s: str) -> capnp.lib.capnp._DynamicStructReader:
|
def __getitem__(self, s: str) -> capnp.lib.capnp._DynamicStructReader:
|
||||||
@@ -217,10 +224,14 @@ class SubMaster:
|
|||||||
self.logMonoTime[s] = msg.logMonoTime
|
self.logMonoTime[s] = msg.logMonoTime
|
||||||
self.valid[s] = msg.valid
|
self.valid[s] = msg.valid
|
||||||
|
|
||||||
for s in self.static_freq_services:
|
for s in self.services:
|
||||||
# alive if delay is within 10x the expected frequency; checks relaxed in simulator
|
if SERVICE_LIST[s].frequency > 1e-5 and not self.simulation:
|
||||||
self.alive[s] = (cur_time - self.recv_time[s]) < (10. / SERVICE_LIST[s].frequency) or (self.seen[s] and self.simulation)
|
# alive if delay is within 10x the expected frequency
|
||||||
self.freq_ok[s] = self.freq_tracker[s].valid or self.simulation
|
self.alive[s] = (cur_time - self.recv_time[s]) < (10. / SERVICE_LIST[s].frequency)
|
||||||
|
self.freq_ok[s] = self.freq_tracker[s].valid
|
||||||
|
else:
|
||||||
|
self.freq_ok[s] = True
|
||||||
|
self.alive[s] = self.seen[s] if self.simulation else True
|
||||||
|
|
||||||
def all_alive(self, service_list: Optional[List[str]] = None) -> bool:
|
def all_alive(self, service_list: Optional[List[str]] = None) -> bool:
|
||||||
return all(self.alive[s] for s in (service_list or self.services) if s not in self.ignore_alive)
|
return all(self.alive[s] for s in (service_list or self.services) if s not in self.ignore_alive)
|
||||||
|
|||||||
@@ -6,12 +6,12 @@
|
|||||||
|
|
||||||
ExitHandler do_exit;
|
ExitHandler do_exit;
|
||||||
|
|
||||||
static std::vector<std::string> get_services(const std::string &whitelist_str, bool zmq_to_msgq) {
|
static std::vector<std::string> get_services(std::string whitelist_str, bool zmq_to_msgq) {
|
||||||
std::vector<std::string> service_list;
|
std::vector<std::string> service_list;
|
||||||
for (const auto& it : services) {
|
for (const auto& it : services) {
|
||||||
std::string name = it.second.name;
|
std::string name = it.second.name;
|
||||||
bool in_whitelist = whitelist_str.find(name) != std::string::npos;
|
bool in_whitelist = whitelist_str.find(name) != std::string::npos;
|
||||||
if (zmq_to_msgq && !in_whitelist) {
|
if (name == "plusFrame" || name == "uiLayoutState" || (zmq_to_msgq && !in_whitelist)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
service_list.push_back(name);
|
service_list.push_back(name);
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import cereal.messaging as messaging
|
|||||||
from 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 cereal.services import SERVICE_LIST
|
|
||||||
|
|
||||||
|
|
||||||
class TestSubMaster:
|
class TestSubMaster:
|
||||||
@@ -27,9 +26,7 @@ class TestSubMaster:
|
|||||||
sm = messaging.SubMaster(socks)
|
sm = messaging.SubMaster(socks)
|
||||||
assert sm.frame == -1
|
assert sm.frame == -1
|
||||||
assert not any(sm.updated.values())
|
assert not any(sm.updated.values())
|
||||||
assert not any(sm.seen.values())
|
assert not any(sm.alive.values())
|
||||||
on_demand = {s: SERVICE_LIST[s].frequency <= 1e-5 for s in sm.services}
|
|
||||||
assert all(sm.alive[s] == sm.valid[s] == sm.freq_ok[s] == on_demand[s] for s in sm.services)
|
|
||||||
assert all(t == 0. for t in sm.recv_time.values())
|
assert all(t == 0. for t in sm.recv_time.values())
|
||||||
assert all(f == 0 for f in sm.recv_frame.values())
|
assert all(f == 0 for f in sm.recv_frame.values())
|
||||||
assert all(t == 0 for t in sm.logMonoTime.values())
|
assert all(t == 0 for t in sm.logMonoTime.values())
|
||||||
@@ -86,7 +83,6 @@ class TestSubMaster:
|
|||||||
"cameraOdometry": (20, 10),
|
"cameraOdometry": (20, 10),
|
||||||
"liveCalibration": (4, 4),
|
"liveCalibration": (4, 4),
|
||||||
"carParams": (None, None),
|
"carParams": (None, None),
|
||||||
"userFlag": (None, None),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for service, (max_freq, min_freq) in checks.items():
|
for service, (max_freq, min_freq) in checks.items():
|
||||||
|
|||||||
@@ -1,222 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
import argparse
|
|
||||||
import sys
|
|
||||||
from typing import Any, List, Tuple
|
|
||||||
|
|
||||||
DEBUG = False
|
|
||||||
|
|
||||||
|
|
||||||
def print_debug(string: str) -> None:
|
|
||||||
if DEBUG:
|
|
||||||
print(string)
|
|
||||||
|
|
||||||
|
|
||||||
def create_schema_instance(struct: Any, prop: Tuple[str, Any]) -> Any:
|
|
||||||
"""
|
|
||||||
Create a new instance of a schema type, handling different field types.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
struct: The Cap'n Proto schema structure
|
|
||||||
prop: A tuple containing the field name and field metadata
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
A new initialized schema instance
|
|
||||||
"""
|
|
||||||
struct_instance = struct.new_message()
|
|
||||||
field_name, field_metadata = prop
|
|
||||||
|
|
||||||
try:
|
|
||||||
field_type = field_metadata.proto.slot.type.which()
|
|
||||||
|
|
||||||
# Initialize different types of fields
|
|
||||||
if field_type in ('list', 'text', 'data'):
|
|
||||||
struct_instance.init(field_name, 1)
|
|
||||||
print_debug(f"Initialized list/text/data field: {field_name}")
|
|
||||||
elif field_type in ('struct', 'object'):
|
|
||||||
struct_instance.init(field_name)
|
|
||||||
print_debug(f"Initialized struct/object field: {field_name}")
|
|
||||||
|
|
||||||
return struct_instance
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error creating instance for {field_name}: {e}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def get_schema_fields(schema_struct: Any) -> List[Tuple[str, Any]]:
|
|
||||||
"""
|
|
||||||
Retrieve all fields from a given schema structure.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
schema_struct: The Cap'n Proto schema structure
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
A list of field names and their metadata
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# Get all fields from the schema
|
|
||||||
schema_fields = list(schema_struct.schema.fields.items())
|
|
||||||
|
|
||||||
print_debug("Discovered schema fields:")
|
|
||||||
for field_name, field_metadata in schema_fields:
|
|
||||||
print_debug(f"- {field_name}")
|
|
||||||
|
|
||||||
return schema_fields
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error retrieving schema fields: {e}")
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
def generate_schema_instances(schema_struct: Any) -> List[Any]:
|
|
||||||
"""
|
|
||||||
Generate instances for all fields in a given schema.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
schema_struct: The Cap'n Proto schema structure
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
A list of schema instances
|
|
||||||
"""
|
|
||||||
schema_fields = get_schema_fields(schema_struct)
|
|
||||||
instances = []
|
|
||||||
|
|
||||||
for field_prop in schema_fields:
|
|
||||||
try:
|
|
||||||
instance = create_schema_instance(schema_struct, field_prop)
|
|
||||||
if instance is not None:
|
|
||||||
instances.append(instance)
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Skipping field due to error: {e}")
|
|
||||||
|
|
||||||
print(f"Generated {len(instances)} schema instances")
|
|
||||||
return instances
|
|
||||||
|
|
||||||
|
|
||||||
def persist_instances(instances: List[Any], filename: str) -> None:
|
|
||||||
"""
|
|
||||||
Write schema instances to a binary file.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
instances: List of schema instances
|
|
||||||
filename: Output file path
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
with open(filename, 'wb') as f:
|
|
||||||
for instance in instances:
|
|
||||||
f.write(instance.to_bytes())
|
|
||||||
|
|
||||||
print(f"Successfully wrote {len(instances)} instances to {filename}")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error persisting instances: {e}")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def read_instances(filename: str, schema_type: Any) -> List[Any]:
|
|
||||||
"""
|
|
||||||
Read schema instances from a binary file.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
filename: Input file path
|
|
||||||
schema_type: The schema type to use for reading
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
A list of read schema instances
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
with open(filename, 'rb') as f:
|
|
||||||
data = f.read()
|
|
||||||
|
|
||||||
instances = list(schema_type.read_multiple_bytes(data))
|
|
||||||
|
|
||||||
print(f"Read {len(instances)} instances from {filename}")
|
|
||||||
return instances
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error reading instances: {e}")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def compare_schemas(original_instances: List[Any], read_instances: List[Any]) -> bool:
|
|
||||||
"""
|
|
||||||
Compare original and read-back instances to detect potential breaking changes.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
original_instances: List of originally generated instances
|
|
||||||
read_instances: List of instances read back from file
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Boolean indicating whether schemas appear compatible
|
|
||||||
"""
|
|
||||||
if len(original_instances) != len(read_instances):
|
|
||||||
print("❌ Schema Compatibility Warning: Instance count mismatch")
|
|
||||||
return False
|
|
||||||
|
|
||||||
compatible = True
|
|
||||||
for struct in read_instances:
|
|
||||||
try:
|
|
||||||
getattr(struct, struct.which()) # Attempting to access the field to validate readability
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Structural change detected: {struct.which()} is not readable.\nFull error: {e}")
|
|
||||||
compatible = False
|
|
||||||
|
|
||||||
return compatible
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""
|
|
||||||
CLI entry point for schema compatibility testing.
|
|
||||||
"""
|
|
||||||
# Setup argument parser
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description='Cap\'n Proto Schema Compatibility Testing Tool',
|
|
||||||
epilog='Test schema compatibility by generating and reading back instances.'
|
|
||||||
)
|
|
||||||
|
|
||||||
# Add mutually exclusive group for generation or reading mode
|
|
||||||
mode_group = parser.add_mutually_exclusive_group(required=True)
|
|
||||||
mode_group.add_argument('-g', '--generate', action='store_true',
|
|
||||||
help='Generate schema instances')
|
|
||||||
mode_group.add_argument('-r', '--read', action='store_true',
|
|
||||||
help='Read and validate schema instances')
|
|
||||||
|
|
||||||
# Common arguments
|
|
||||||
parser.add_argument('-f', '--file',
|
|
||||||
default='schema_instances.bin',
|
|
||||||
help='Output/input binary file (default: schema_instances.bin)')
|
|
||||||
|
|
||||||
# Parse arguments
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
# Import the schema dynamically
|
|
||||||
try:
|
|
||||||
from cereal import log
|
|
||||||
schema_type = log.Event
|
|
||||||
except ImportError:
|
|
||||||
print("Error: Unable to import schema. Ensure 'cereal' is installed.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Execute based on mode
|
|
||||||
if args.generate:
|
|
||||||
print("🔧 Generating Schema Instances")
|
|
||||||
instances = generate_schema_instances(schema_type)
|
|
||||||
persist_instances(instances, args.file)
|
|
||||||
print("✅ Instance generation complete")
|
|
||||||
|
|
||||||
elif args.read:
|
|
||||||
print("🔍 Reading and Validating Schema Instances")
|
|
||||||
generated_instances = generate_schema_instances(schema_type)
|
|
||||||
read_back_instances = read_instances(args.file, schema_type)
|
|
||||||
|
|
||||||
# Compare schemas
|
|
||||||
if compare_schemas(generated_instances, read_back_instances):
|
|
||||||
print("✅ Schema Compatibility: No breaking changes detected")
|
|
||||||
sys.exit(0)
|
|
||||||
else:
|
|
||||||
print("❌ Potential Schema Breaking Changes Detected")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
+1
-14
@@ -22,7 +22,6 @@ _services: dict[str, tuple] = {
|
|||||||
"temperatureSensor2": (True, 2., 200),
|
"temperatureSensor2": (True, 2., 200),
|
||||||
"gpsNMEA": (True, 9.),
|
"gpsNMEA": (True, 9.),
|
||||||
"deviceState": (True, 2., 1),
|
"deviceState": (True, 2., 1),
|
||||||
"touch": (True, 20., 1),
|
|
||||||
"can": (True, 100., 2053), # decimation gives ~3 msgs in a full segment
|
"can": (True, 100., 2053), # decimation gives ~3 msgs in a full segment
|
||||||
"controlsState": (True, 100., 10),
|
"controlsState": (True, 100., 10),
|
||||||
"selfdriveState": (True, 100., 10),
|
"selfdriveState": (True, 100., 10),
|
||||||
@@ -36,7 +35,6 @@ _services: dict[str, tuple] = {
|
|||||||
"errorLogMessage": (True, 0., 1),
|
"errorLogMessage": (True, 0., 1),
|
||||||
"liveCalibration": (True, 4., 4),
|
"liveCalibration": (True, 4., 4),
|
||||||
"liveTorqueParameters": (True, 4., 1),
|
"liveTorqueParameters": (True, 4., 1),
|
||||||
"liveDelay": (True, 4., 1),
|
|
||||||
"androidLog": (True, 0.),
|
"androidLog": (True, 0.),
|
||||||
"carState": (True, 100., 10),
|
"carState": (True, 100., 10),
|
||||||
"carControl": (True, 100., 10),
|
"carControl": (True, 100., 10),
|
||||||
@@ -54,7 +52,7 @@ _services: dict[str, tuple] = {
|
|||||||
"livePose": (True, 20., 4),
|
"livePose": (True, 20., 4),
|
||||||
"liveParameters": (True, 20., 5),
|
"liveParameters": (True, 20., 5),
|
||||||
"cameraOdometry": (True, 20., 10),
|
"cameraOdometry": (True, 20., 10),
|
||||||
"thumbnail": (True, 1 / 60., 1),
|
"thumbnail": (True, 0.2, 1),
|
||||||
"onroadEvents": (True, 1., 1),
|
"onroadEvents": (True, 1., 1),
|
||||||
"carParams": (True, 0.02, 1),
|
"carParams": (True, 0.02, 1),
|
||||||
"roadCameraState": (True, 20., 20),
|
"roadCameraState": (True, 20., 20),
|
||||||
@@ -75,17 +73,6 @@ _services: dict[str, tuple] = {
|
|||||||
"userFlag": (True, 0., 1),
|
"userFlag": (True, 0., 1),
|
||||||
"microphone": (True, 10., 10),
|
"microphone": (True, 10., 10),
|
||||||
|
|
||||||
# sunnypilot
|
|
||||||
"modelManagerSP": (False, 1., 1),
|
|
||||||
"backupManagerSP": (False, 1., 1),
|
|
||||||
"selfdriveStateSP": (True, 100., 10),
|
|
||||||
"longitudinalPlanSP": (True, 20., 10),
|
|
||||||
"onroadEventsSP": (True, 1., 1),
|
|
||||||
"carParamsSP": (True, 0.02, 1),
|
|
||||||
"carControlSP": (True, 100., 10),
|
|
||||||
"carStateSP": (True, 100., 10),
|
|
||||||
"liveMapDataSP": (True, 1., 1),
|
|
||||||
|
|
||||||
# debug
|
# debug
|
||||||
"uiDebug": (True, 0., 1),
|
"uiDebug": (True, 0., 1),
|
||||||
"testJoystick": (True, 0.),
|
"testJoystick": (True, 0.),
|
||||||
|
|||||||
@@ -4,10 +4,14 @@ common_libs = [
|
|||||||
'params.cc',
|
'params.cc',
|
||||||
'swaglog.cc',
|
'swaglog.cc',
|
||||||
'util.cc',
|
'util.cc',
|
||||||
|
'i2c.cc',
|
||||||
'watchdog.cc',
|
'watchdog.cc',
|
||||||
'ratekeeper.cc'
|
'ratekeeper.cc'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if arch != "Darwin":
|
||||||
|
common_libs.append('gpio.cc')
|
||||||
|
|
||||||
_common = env.Library('common', common_libs, LIBS="json11")
|
_common = env.Library('common', common_libs, LIBS="json11")
|
||||||
|
|
||||||
files = [
|
files = [
|
||||||
|
|||||||
+33
-9
@@ -1,22 +1,46 @@
|
|||||||
from openpilot.common.api.comma_connect import CommaConnectApi
|
import jwt
|
||||||
|
import os
|
||||||
|
import requests
|
||||||
|
from datetime import datetime, timedelta, UTC
|
||||||
|
from openpilot.system.hardware.hw import Paths
|
||||||
|
from openpilot.system.version import get_version
|
||||||
|
|
||||||
|
API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com')
|
||||||
|
|
||||||
class Api:
|
class Api:
|
||||||
def __init__(self, dongle_id):
|
def __init__(self, dongle_id):
|
||||||
self.service = CommaConnectApi(dongle_id)
|
self.dongle_id = dongle_id
|
||||||
|
with open(Paths.persist_root()+'/comma/id_rsa') as f:
|
||||||
def request(self, method, endpoint, **params):
|
self.private_key = f.read()
|
||||||
return self.service.request(method, endpoint, **params)
|
|
||||||
|
|
||||||
def get(self, *args, **kwargs):
|
def get(self, *args, **kwargs):
|
||||||
return self.service.get(*args, **kwargs)
|
return self.request('GET', *args, **kwargs)
|
||||||
|
|
||||||
def post(self, *args, **kwargs):
|
def post(self, *args, **kwargs):
|
||||||
return self.service.post(*args, **kwargs)
|
return self.request('POST', *args, **kwargs)
|
||||||
|
|
||||||
|
def request(self, method, endpoint, timeout=None, access_token=None, **params):
|
||||||
|
return api_get(endpoint, method=method, timeout=timeout, access_token=access_token, **params)
|
||||||
|
|
||||||
def get_token(self, expiry_hours=1):
|
def get_token(self, expiry_hours=1):
|
||||||
return self.service.get_token(expiry_hours)
|
now = datetime.now(UTC).replace(tzinfo=None)
|
||||||
|
payload = {
|
||||||
|
'identity': self.dongle_id,
|
||||||
|
'nbf': now,
|
||||||
|
'iat': now,
|
||||||
|
'exp': now + timedelta(hours=expiry_hours)
|
||||||
|
}
|
||||||
|
token = jwt.encode(payload, self.private_key, algorithm='RS256')
|
||||||
|
if isinstance(token, bytes):
|
||||||
|
token = token.decode('utf8')
|
||||||
|
return token
|
||||||
|
|
||||||
|
|
||||||
def api_get(endpoint, method='GET', timeout=None, access_token=None, **params):
|
def api_get(endpoint, method='GET', timeout=None, access_token=None, **params):
|
||||||
return CommaConnectApi(None).api_get(endpoint, method, timeout, access_token, **params)
|
headers = {}
|
||||||
|
if access_token is not None:
|
||||||
|
headers['Authorization'] = "JWT " + access_token
|
||||||
|
|
||||||
|
headers['User-Agent'] = "openpilot-" + get_version()
|
||||||
|
|
||||||
|
return requests.request(method, API_HOST + "/" + endpoint, timeout=timeout, headers=headers, params=params)
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
import jwt
|
|
||||||
import requests
|
|
||||||
import unicodedata
|
|
||||||
from datetime import datetime, timedelta, UTC
|
|
||||||
from openpilot.system.hardware.hw import Paths
|
|
||||||
from openpilot.system.version import get_version
|
|
||||||
|
|
||||||
|
|
||||||
class BaseApi:
|
|
||||||
def __init__(self, dongle_id, api_host, user_agent="openpilot-"):
|
|
||||||
self.dongle_id = dongle_id
|
|
||||||
self.api_host = api_host
|
|
||||||
self.user_agent = user_agent
|
|
||||||
with open(f'{Paths.persist_root()}/comma/id_rsa') as f:
|
|
||||||
self.private_key = f.read()
|
|
||||||
|
|
||||||
def get(self, *args, **kwargs):
|
|
||||||
return self.request('GET', *args, **kwargs)
|
|
||||||
|
|
||||||
def post(self, *args, **kwargs):
|
|
||||||
return self.request('POST', *args, **kwargs)
|
|
||||||
|
|
||||||
def request(self, method, endpoint, timeout=None, access_token=None, **params):
|
|
||||||
return self.api_get(endpoint, method=method, timeout=timeout, access_token=access_token, **params)
|
|
||||||
|
|
||||||
def _get_token(self, expiry_hours=1, **extra_payload):
|
|
||||||
now = datetime.now(UTC).replace(tzinfo=None)
|
|
||||||
payload = {
|
|
||||||
'identity': self.dongle_id,
|
|
||||||
'nbf': now,
|
|
||||||
'iat': now,
|
|
||||||
'exp': now + timedelta(hours=expiry_hours),
|
|
||||||
**extra_payload
|
|
||||||
}
|
|
||||||
token = jwt.encode(payload, self.private_key, algorithm='RS256')
|
|
||||||
if isinstance(token, bytes):
|
|
||||||
token = token.decode('utf8')
|
|
||||||
return token
|
|
||||||
|
|
||||||
def get_token(self, expiry_hours=1):
|
|
||||||
return self._get_token(expiry_hours)
|
|
||||||
|
|
||||||
def remove_non_ascii_chars(self, text):
|
|
||||||
normalized_text = unicodedata.normalize('NFD', text)
|
|
||||||
ascii_encoded_text = normalized_text.encode('ascii', 'ignore')
|
|
||||||
return ascii_encoded_text.decode()
|
|
||||||
|
|
||||||
def api_get(self, endpoint, method='GET', timeout=None, access_token=None, json=None, **params):
|
|
||||||
headers = {}
|
|
||||||
if access_token is not None:
|
|
||||||
headers['Authorization'] = "JWT " + access_token
|
|
||||||
|
|
||||||
version = self.remove_non_ascii_chars(get_version())
|
|
||||||
headers['User-Agent'] = self.user_agent + version
|
|
||||||
|
|
||||||
return requests.request(method, f"{self.api_host}/{endpoint}", timeout=timeout, headers=headers, json=json, params=params)
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
from openpilot.common.api.base import BaseApi
|
|
||||||
|
|
||||||
API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com')
|
|
||||||
|
|
||||||
|
|
||||||
class CommaConnectApi(BaseApi):
|
|
||||||
def __init__(self, dongle_id):
|
|
||||||
super().__init__(dongle_id, API_HOST)
|
|
||||||
self.user_agent = "openpilot-"
|
|
||||||
+106
-4
@@ -79,10 +79,6 @@ cl_context cl_create_context(cl_device_id device_id) {
|
|||||||
return CL_CHECK_ERR(clCreateContext(NULL, 1, &device_id, NULL, NULL, &err));
|
return CL_CHECK_ERR(clCreateContext(NULL, 1, &device_id, NULL, NULL, &err));
|
||||||
}
|
}
|
||||||
|
|
||||||
void cl_release_context(cl_context context) {
|
|
||||||
clReleaseContext(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
cl_program cl_program_from_file(cl_context ctx, cl_device_id device_id, const char* path, const char* args) {
|
cl_program cl_program_from_file(cl_context ctx, cl_device_id device_id, const char* path, const char* args) {
|
||||||
return cl_program_from_source(ctx, device_id, util::read_file(path), args);
|
return cl_program_from_source(ctx, device_id, util::read_file(path), args);
|
||||||
}
|
}
|
||||||
@@ -96,3 +92,109 @@ cl_program cl_program_from_source(cl_context ctx, cl_device_id device_id, const
|
|||||||
}
|
}
|
||||||
return prg;
|
return prg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cl_program cl_program_from_binary(cl_context ctx, cl_device_id device_id, const uint8_t* binary, size_t length, const char* args) {
|
||||||
|
cl_program prg = CL_CHECK_ERR(clCreateProgramWithBinary(ctx, 1, &device_id, &length, &binary, NULL, &err));
|
||||||
|
if (int err = clBuildProgram(prg, 1, &device_id, args, NULL, NULL); err != 0) {
|
||||||
|
cl_print_build_errors(prg, device_id);
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
return prg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a cl code and return a string representation
|
||||||
|
#define CL_ERR_TO_STR(err) case err: return #err
|
||||||
|
const char* cl_get_error_string(int err) {
|
||||||
|
switch (err) {
|
||||||
|
CL_ERR_TO_STR(CL_SUCCESS);
|
||||||
|
CL_ERR_TO_STR(CL_DEVICE_NOT_FOUND);
|
||||||
|
CL_ERR_TO_STR(CL_DEVICE_NOT_AVAILABLE);
|
||||||
|
CL_ERR_TO_STR(CL_COMPILER_NOT_AVAILABLE);
|
||||||
|
CL_ERR_TO_STR(CL_MEM_OBJECT_ALLOCATION_FAILURE);
|
||||||
|
CL_ERR_TO_STR(CL_OUT_OF_RESOURCES);
|
||||||
|
CL_ERR_TO_STR(CL_OUT_OF_HOST_MEMORY);
|
||||||
|
CL_ERR_TO_STR(CL_PROFILING_INFO_NOT_AVAILABLE);
|
||||||
|
CL_ERR_TO_STR(CL_MEM_COPY_OVERLAP);
|
||||||
|
CL_ERR_TO_STR(CL_IMAGE_FORMAT_MISMATCH);
|
||||||
|
CL_ERR_TO_STR(CL_IMAGE_FORMAT_NOT_SUPPORTED);
|
||||||
|
CL_ERR_TO_STR(CL_MAP_FAILURE);
|
||||||
|
CL_ERR_TO_STR(CL_MISALIGNED_SUB_BUFFER_OFFSET);
|
||||||
|
CL_ERR_TO_STR(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
|
||||||
|
CL_ERR_TO_STR(CL_COMPILE_PROGRAM_FAILURE);
|
||||||
|
CL_ERR_TO_STR(CL_LINKER_NOT_AVAILABLE);
|
||||||
|
CL_ERR_TO_STR(CL_LINK_PROGRAM_FAILURE);
|
||||||
|
CL_ERR_TO_STR(CL_DEVICE_PARTITION_FAILED);
|
||||||
|
CL_ERR_TO_STR(CL_KERNEL_ARG_INFO_NOT_AVAILABLE);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_VALUE);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_DEVICE_TYPE);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_PLATFORM);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_DEVICE);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_CONTEXT);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_QUEUE_PROPERTIES);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_COMMAND_QUEUE);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_HOST_PTR);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_MEM_OBJECT);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_IMAGE_SIZE);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_SAMPLER);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_BINARY);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_BUILD_OPTIONS);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_PROGRAM);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_PROGRAM_EXECUTABLE);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_KERNEL_NAME);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_KERNEL_DEFINITION);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_KERNEL);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_ARG_INDEX);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_ARG_VALUE);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_ARG_SIZE);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_KERNEL_ARGS);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_WORK_DIMENSION);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_WORK_GROUP_SIZE);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_WORK_ITEM_SIZE);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_GLOBAL_OFFSET);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_EVENT_WAIT_LIST);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_EVENT);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_OPERATION);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_GL_OBJECT);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_BUFFER_SIZE);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_MIP_LEVEL);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_GLOBAL_WORK_SIZE);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_PROPERTY);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_IMAGE_DESCRIPTOR);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_COMPILER_OPTIONS);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_LINKER_OPTIONS);
|
||||||
|
CL_ERR_TO_STR(CL_INVALID_DEVICE_PARTITION_COUNT);
|
||||||
|
case -69: return "CL_INVALID_PIPE_SIZE";
|
||||||
|
case -70: return "CL_INVALID_DEVICE_QUEUE";
|
||||||
|
case -71: return "CL_INVALID_SPEC_ID";
|
||||||
|
case -72: return "CL_MAX_SIZE_RESTRICTION_EXCEEDED";
|
||||||
|
case -1002: return "CL_INVALID_D3D10_DEVICE_KHR";
|
||||||
|
case -1003: return "CL_INVALID_D3D10_RESOURCE_KHR";
|
||||||
|
case -1004: return "CL_D3D10_RESOURCE_ALREADY_ACQUIRED_KHR";
|
||||||
|
case -1005: return "CL_D3D10_RESOURCE_NOT_ACQUIRED_KHR";
|
||||||
|
case -1006: return "CL_INVALID_D3D11_DEVICE_KHR";
|
||||||
|
case -1007: return "CL_INVALID_D3D11_RESOURCE_KHR";
|
||||||
|
case -1008: return "CL_D3D11_RESOURCE_ALREADY_ACQUIRED_KHR";
|
||||||
|
case -1009: return "CL_D3D11_RESOURCE_NOT_ACQUIRED_KHR";
|
||||||
|
case -1010: return "CL_INVALID_DX9_MEDIA_ADAPTER_KHR";
|
||||||
|
case -1011: return "CL_INVALID_DX9_MEDIA_SURFACE_KHR";
|
||||||
|
case -1012: return "CL_DX9_MEDIA_SURFACE_ALREADY_ACQUIRED_KHR";
|
||||||
|
case -1013: return "CL_DX9_MEDIA_SURFACE_NOT_ACQUIRED_KHR";
|
||||||
|
case -1093: return "CL_INVALID_EGL_OBJECT_KHR";
|
||||||
|
case -1092: return "CL_EGL_RESOURCE_NOT_ACQUIRED_KHR";
|
||||||
|
case -1001: return "CL_PLATFORM_NOT_FOUND_KHR";
|
||||||
|
case -1057: return "CL_DEVICE_PARTITION_FAILED_EXT";
|
||||||
|
case -1058: return "CL_INVALID_PARTITION_COUNT_EXT";
|
||||||
|
case -1059: return "CL_INVALID_PARTITION_NAME_EXT";
|
||||||
|
case -1094: return "CL_INVALID_ACCELERATOR_INTEL";
|
||||||
|
case -1095: return "CL_INVALID_ACCELERATOR_TYPE_INTEL";
|
||||||
|
case -1096: return "CL_INVALID_ACCELERATOR_DESCRIPTOR_INTEL";
|
||||||
|
case -1097: return "CL_ACCELERATOR_TYPE_NOT_SUPPORTED_INTEL";
|
||||||
|
case -1000: return "CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR";
|
||||||
|
case -1098: return "CL_INVALID_VA_API_MEDIA_ADAPTER_INTEL";
|
||||||
|
case -1099: return "CL_INVALID_VA_API_MEDIA_SURFACE_INTEL";
|
||||||
|
case -1100: return "CL_VA_API_MEDIA_SURFACE_ALREADY_ACQUIRED_INTEL";
|
||||||
|
case -1101: return "CL_VA_API_MEDIA_SURFACE_NOT_ACQUIRED_INTEL";
|
||||||
|
default: return "CL_UNKNOWN_ERROR";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+2
-1
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
cl_device_id cl_get_device_id(cl_device_type device_type);
|
cl_device_id cl_get_device_id(cl_device_type device_type);
|
||||||
cl_context cl_create_context(cl_device_id device_id);
|
cl_context cl_create_context(cl_device_id device_id);
|
||||||
void cl_release_context(cl_context context);
|
|
||||||
cl_program cl_program_from_source(cl_context ctx, cl_device_id device_id, const std::string& src, const char* args = nullptr);
|
cl_program cl_program_from_source(cl_context ctx, cl_device_id device_id, const std::string& src, const char* args = nullptr);
|
||||||
|
cl_program cl_program_from_binary(cl_context ctx, cl_device_id device_id, const uint8_t* binary, size_t length, const char* args = nullptr);
|
||||||
cl_program cl_program_from_file(cl_context ctx, cl_device_id device_id, const char* path, const char* args);
|
cl_program cl_program_from_file(cl_context ctx, cl_device_id device_id, const char* path, const char* args);
|
||||||
|
const char* cl_get_error_string(int err);
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import platform
|
||||||
|
|
||||||
|
|
||||||
|
def suffix():
|
||||||
|
if platform.system() == "Darwin":
|
||||||
|
return ".dylib"
|
||||||
|
else:
|
||||||
|
return ".so"
|
||||||
@@ -1,10 +1,6 @@
|
|||||||
import io
|
|
||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
import contextlib
|
import contextlib
|
||||||
import zstandard as zstd
|
|
||||||
|
|
||||||
LOG_COMPRESSION_LEVEL = 10 # little benefit up to level 15. level ~17 is a small step change
|
|
||||||
|
|
||||||
|
|
||||||
class CallbackReader:
|
class CallbackReader:
|
||||||
@@ -39,20 +35,3 @@ def atomic_write_in_dir(path: str, mode: str = 'w', buffering: int = -1, encodin
|
|||||||
yield tmp_file
|
yield tmp_file
|
||||||
tmp_file_name = tmp_file.name
|
tmp_file_name = tmp_file.name
|
||||||
os.replace(tmp_file_name, path)
|
os.replace(tmp_file_name, path)
|
||||||
|
|
||||||
|
|
||||||
def get_upload_stream(filepath: str, should_compress: bool) -> tuple[io.BufferedIOBase, int]:
|
|
||||||
if not should_compress:
|
|
||||||
file_size = os.path.getsize(filepath)
|
|
||||||
file_stream = open(filepath, "rb")
|
|
||||||
return file_stream, file_size
|
|
||||||
|
|
||||||
# Compress the file on the fly
|
|
||||||
compressed_stream = io.BytesIO()
|
|
||||||
compressor = zstd.ZstdCompressor(level=LOG_COMPRESSION_LEVEL)
|
|
||||||
|
|
||||||
with open(filepath, "rb") as f:
|
|
||||||
compressor.copy_stream(f, compressed_stream)
|
|
||||||
compressed_size = compressed_stream.tell()
|
|
||||||
compressed_stream.seek(0)
|
|
||||||
return compressed_stream, compressed_size
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
class FirstOrderFilter:
|
class FirstOrderFilter:
|
||||||
|
# first order filter
|
||||||
def __init__(self, x0, rc, dt, initialized=True):
|
def __init__(self, x0, rc, dt, initialized=True):
|
||||||
self.x = x0
|
self.x = x0
|
||||||
self.dt = dt
|
self.dt = dt
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
#include "common/gpio.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
int gpio_init(int pin_nr, bool output) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpio_set(int pin_nr, bool high) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpiochip_get_ro_value_fd(const char* consumer_label, int gpiochiop_id, int pin_nr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <linux/gpio.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#include "common/util.h"
|
||||||
|
#include "common/swaglog.h"
|
||||||
|
|
||||||
|
int gpio_init(int pin_nr, bool output) {
|
||||||
|
char pin_dir_path[50];
|
||||||
|
int pin_dir_path_len = snprintf(pin_dir_path, sizeof(pin_dir_path),
|
||||||
|
"/sys/class/gpio/gpio%d/direction", pin_nr);
|
||||||
|
if (pin_dir_path_len <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
const char *value = output ? "out" : "in";
|
||||||
|
return util::write_file(pin_dir_path, (void*)value, strlen(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpio_set(int pin_nr, bool high) {
|
||||||
|
char pin_val_path[50];
|
||||||
|
int pin_val_path_len = snprintf(pin_val_path, sizeof(pin_val_path),
|
||||||
|
"/sys/class/gpio/gpio%d/value", pin_nr);
|
||||||
|
if (pin_val_path_len <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return util::write_file(pin_val_path, (void*)(high ? "1" : "0"), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpiochip_get_ro_value_fd(const char* consumer_label, int gpiochiop_id, int pin_nr) {
|
||||||
|
|
||||||
|
// Assumed that all interrupt pins are unexported and rights are given to
|
||||||
|
// read from gpiochip0.
|
||||||
|
std::string gpiochip_path = "/dev/gpiochip" + std::to_string(gpiochiop_id);
|
||||||
|
int fd = open(gpiochip_path.c_str(), O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
LOGE("Error opening gpiochip0 fd");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup event
|
||||||
|
struct gpioevent_request rq;
|
||||||
|
rq.lineoffset = pin_nr;
|
||||||
|
rq.handleflags = GPIOHANDLE_REQUEST_INPUT;
|
||||||
|
|
||||||
|
/* Requesting both edges as the data ready pulse from the lsm6ds sensor is
|
||||||
|
very short(75us) and is mostly detected as falling edge instead of rising.
|
||||||
|
So if it is detected as rising the following falling edge is skipped. */
|
||||||
|
rq.eventflags = GPIOEVENT_REQUEST_BOTH_EDGES;
|
||||||
|
|
||||||
|
strncpy(rq.consumer_label, consumer_label, std::size(rq.consumer_label) - 1);
|
||||||
|
int ret = util::safe_ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &rq);
|
||||||
|
if (ret == -1) {
|
||||||
|
LOGE("Unable to get line event from ioctl : %s", strerror(errno));
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return rq.fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Pin definitions
|
||||||
|
#ifdef QCOM2
|
||||||
|
#define GPIO_HUB_RST_N 30
|
||||||
|
#define GPIO_UBLOX_RST_N 32
|
||||||
|
#define GPIO_UBLOX_SAFEBOOT_N 33
|
||||||
|
#define GPIO_GNSS_PWR_EN 34 /* SCHEMATIC LABEL: GPIO_UBLOX_PWR_EN */
|
||||||
|
#define GPIO_STM_RST_N 124
|
||||||
|
#define GPIO_STM_BOOT0 134
|
||||||
|
#define GPIO_BMX_ACCEL_INT 21
|
||||||
|
#define GPIO_BMX_GYRO_INT 23
|
||||||
|
#define GPIO_BMX_MAGN_INT 87
|
||||||
|
#define GPIO_LSM_INT 84
|
||||||
|
#define GPIOCHIP_INT 0
|
||||||
|
#else
|
||||||
|
#define GPIO_HUB_RST_N 0
|
||||||
|
#define GPIO_UBLOX_RST_N 0
|
||||||
|
#define GPIO_UBLOX_SAFEBOOT_N 0
|
||||||
|
#define GPIO_GNSS_PWR_EN 0 /* SCHEMATIC LABEL: GPIO_UBLOX_PWR_EN */
|
||||||
|
#define GPIO_STM_RST_N 0
|
||||||
|
#define GPIO_STM_BOOT0 0
|
||||||
|
#define GPIO_BMX_ACCEL_INT 0
|
||||||
|
#define GPIO_BMX_GYRO_INT 0
|
||||||
|
#define GPIO_BMX_MAGN_INT 0
|
||||||
|
#define GPIO_LSM_INT 0
|
||||||
|
#define GPIOCHIP_INT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int gpio_init(int pin_nr, bool output);
|
||||||
|
int gpio_set(int pin_nr, bool high);
|
||||||
|
|
||||||
|
int gpiochip_get_ro_value_fd(const char* consumer_label, int gpiochiop_id, int pin_nr);
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
import os
|
import os
|
||||||
import fcntl
|
|
||||||
import ctypes
|
|
||||||
from functools import cache
|
from functools import cache
|
||||||
|
|
||||||
def gpio_init(pin: int, output: bool) -> None:
|
def gpio_init(pin: int, output: bool) -> None:
|
||||||
@@ -54,36 +52,3 @@ def get_irqs_for_action(action: str) -> list[str]:
|
|||||||
if irq.isdigit() and action in get_irq_action(irq):
|
if irq.isdigit() and action in get_irq_action(irq):
|
||||||
ret.append(irq)
|
ret.append(irq)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
# *** gpiochip ***
|
|
||||||
|
|
||||||
class gpioevent_data(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
("timestamp", ctypes.c_uint64),
|
|
||||||
("id", ctypes.c_uint32),
|
|
||||||
]
|
|
||||||
|
|
||||||
class gpioevent_request(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
("lineoffset", ctypes.c_uint32),
|
|
||||||
("handleflags", ctypes.c_uint32),
|
|
||||||
("eventflags", ctypes.c_uint32),
|
|
||||||
("label", ctypes.c_char * 32),
|
|
||||||
("fd", ctypes.c_int)
|
|
||||||
]
|
|
||||||
|
|
||||||
def gpiochip_get_ro_value_fd(label: str, gpiochip_id: int, pin: int) -> int:
|
|
||||||
GPIOEVENT_REQUEST_BOTH_EDGES = 0x3
|
|
||||||
GPIOHANDLE_REQUEST_INPUT = 0x1
|
|
||||||
GPIO_GET_LINEEVENT_IOCTL = 0xc030b404
|
|
||||||
|
|
||||||
rq = gpioevent_request()
|
|
||||||
rq.lineoffset = pin
|
|
||||||
rq.handleflags = GPIOHANDLE_REQUEST_INPUT
|
|
||||||
rq.eventflags = GPIOEVENT_REQUEST_BOTH_EDGES
|
|
||||||
rq.label = label.encode('utf-8')[:31] + b'\0'
|
|
||||||
|
|
||||||
fd = os.open(f"/dev/gpiochip{gpiochip_id}", os.O_RDONLY)
|
|
||||||
fcntl.ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, rq)
|
|
||||||
os.close(fd)
|
|
||||||
return int(rq.fd)
|
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
#include "common/i2c.h"
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "common/swaglog.h"
|
||||||
|
#include "common/util.h"
|
||||||
|
|
||||||
|
#define UNUSED(x) (void)(x)
|
||||||
|
|
||||||
|
#ifdef QCOM2
|
||||||
|
// TODO: decide if we want to install libi2c-dev everywhere
|
||||||
|
extern "C" {
|
||||||
|
#include <linux/i2c-dev.h>
|
||||||
|
#include <i2c/smbus.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
I2CBus::I2CBus(uint8_t bus_id) {
|
||||||
|
char bus_name[20];
|
||||||
|
snprintf(bus_name, 20, "/dev/i2c-%d", bus_id);
|
||||||
|
|
||||||
|
i2c_fd = HANDLE_EINTR(open(bus_name, O_RDWR));
|
||||||
|
if (i2c_fd < 0) {
|
||||||
|
throw std::runtime_error("Failed to open I2C bus");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
I2CBus::~I2CBus() {
|
||||||
|
if (i2c_fd >= 0) {
|
||||||
|
close(i2c_fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int I2CBus::read_register(uint8_t device_address, uint register_address, uint8_t *buffer, uint8_t len) {
|
||||||
|
std::lock_guard lk(m);
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ret = HANDLE_EINTR(ioctl(i2c_fd, I2C_SLAVE, device_address));
|
||||||
|
if (ret < 0) { goto fail; }
|
||||||
|
|
||||||
|
ret = i2c_smbus_read_i2c_block_data(i2c_fd, register_address, len, buffer);
|
||||||
|
if ((ret < 0) || (ret != len)) { goto fail; }
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int I2CBus::set_register(uint8_t device_address, uint register_address, uint8_t data) {
|
||||||
|
std::lock_guard lk(m);
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ret = HANDLE_EINTR(ioctl(i2c_fd, I2C_SLAVE, device_address));
|
||||||
|
if (ret < 0) { goto fail; }
|
||||||
|
|
||||||
|
ret = i2c_smbus_write_byte_data(i2c_fd, register_address, data);
|
||||||
|
if (ret < 0) { goto fail; }
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
I2CBus::I2CBus(uint8_t bus_id) {
|
||||||
|
UNUSED(bus_id);
|
||||||
|
i2c_fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
I2CBus::~I2CBus() {}
|
||||||
|
|
||||||
|
int I2CBus::read_register(uint8_t device_address, uint register_address, uint8_t *buffer, uint8_t len) {
|
||||||
|
UNUSED(device_address);
|
||||||
|
UNUSED(register_address);
|
||||||
|
UNUSED(buffer);
|
||||||
|
UNUSED(len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int I2CBus::set_register(uint8_t device_address, uint register_address, uint8_t data) {
|
||||||
|
UNUSED(device_address);
|
||||||
|
UNUSED(register_address);
|
||||||
|
UNUSED(data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
class I2CBus {
|
||||||
|
private:
|
||||||
|
int i2c_fd;
|
||||||
|
std::mutex m;
|
||||||
|
|
||||||
|
public:
|
||||||
|
I2CBus(uint8_t bus_id);
|
||||||
|
~I2CBus();
|
||||||
|
|
||||||
|
int read_register(uint8_t device_address, uint register_address, uint8_t *buffer, uint8_t len);
|
||||||
|
int set_register(uint8_t device_address, uint register_address, uint8_t data);
|
||||||
|
};
|
||||||
@@ -8,7 +8,6 @@ import uuid
|
|||||||
import socket
|
import socket
|
||||||
import logging
|
import logging
|
||||||
import traceback
|
import traceback
|
||||||
import numpy as np
|
|
||||||
from threading import local
|
from threading import local
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
@@ -16,8 +15,6 @@ from contextlib import contextmanager
|
|||||||
LOG_TIMESTAMPS = "LOG_TIMESTAMPS" in os.environ
|
LOG_TIMESTAMPS = "LOG_TIMESTAMPS" in os.environ
|
||||||
|
|
||||||
def json_handler(obj):
|
def json_handler(obj):
|
||||||
if isinstance(obj, np.bool_):
|
|
||||||
return bool(obj)
|
|
||||||
# if isinstance(obj, (datetime.date, datetime.time)):
|
# if isinstance(obj, (datetime.date, datetime.time)):
|
||||||
# return obj.isoformat()
|
# return obj.isoformat()
|
||||||
return repr(obj)
|
return repr(obj)
|
||||||
@@ -199,6 +196,7 @@ class SwagLogger(logging.Logger):
|
|||||||
co = f.f_code
|
co = f.f_code
|
||||||
filename = os.path.normcase(co.co_filename)
|
filename = os.path.normcase(co.co_filename)
|
||||||
|
|
||||||
|
# TODO: is this pylint exception correct?
|
||||||
if filename == _srcfile:
|
if filename == _srcfile:
|
||||||
f = f.f_back
|
f = f.f_back
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
#define DEFAULT_MODEL "Vegetarian Filet o Fish (Default)"
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
def clip(x, lo, hi):
|
||||||
|
return max(lo, min(hi, x))
|
||||||
|
|
||||||
|
def interp(x, xp, fp):
|
||||||
|
N = len(xp)
|
||||||
|
|
||||||
|
def get_interp(xv):
|
||||||
|
hi = 0
|
||||||
|
while hi < N and xv > xp[hi]:
|
||||||
|
hi += 1
|
||||||
|
low = hi - 1
|
||||||
|
return fp[-1] if hi == N and xv > xp[low] else (
|
||||||
|
fp[0] if hi == 0 else
|
||||||
|
(xv - xp[low]) * (fp[hi] - fp[low]) / (xp[hi] - xp[low]) + fp[low])
|
||||||
|
|
||||||
|
return [get_interp(v) for v in x] if hasattr(x, '__iter__') else get_interp(x)
|
||||||
|
|
||||||
|
def mean(x):
|
||||||
|
return sum(x) / len(x)
|
||||||
+118
-6
@@ -8,7 +8,6 @@
|
|||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "common/params_keys.h"
|
|
||||||
#include "common/queue.h"
|
#include "common/queue.h"
|
||||||
#include "common/swaglog.h"
|
#include "common/swaglog.h"
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
@@ -88,6 +87,121 @@ private:
|
|||||||
int fd_ = -1;
|
int fd_ = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::unordered_map<std::string, uint32_t> keys = {
|
||||||
|
{"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG},
|
||||||
|
{"AlwaysOnDM", PERSISTENT},
|
||||||
|
{"ApiCache_Device", PERSISTENT},
|
||||||
|
{"AssistNowToken", PERSISTENT},
|
||||||
|
{"AthenadPid", PERSISTENT},
|
||||||
|
{"AthenadUploadQueue", PERSISTENT},
|
||||||
|
{"AthenadRecentlyViewedRoutes", PERSISTENT},
|
||||||
|
{"BootCount", PERSISTENT},
|
||||||
|
{"CalibrationParams", PERSISTENT},
|
||||||
|
{"CameraDebugExpGain", CLEAR_ON_MANAGER_START},
|
||||||
|
{"CameraDebugExpTime", CLEAR_ON_MANAGER_START},
|
||||||
|
{"CarBatteryCapacity", PERSISTENT},
|
||||||
|
{"CarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
|
{"CarParamsCache", CLEAR_ON_MANAGER_START},
|
||||||
|
{"CarParamsPersistent", PERSISTENT},
|
||||||
|
{"CarParamsPrevRoute", PERSISTENT},
|
||||||
|
{"CompletedTrainingVersion", PERSISTENT},
|
||||||
|
{"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
|
{"CurrentBootlog", PERSISTENT},
|
||||||
|
{"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
|
{"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
|
{"DisablePowerDown", PERSISTENT},
|
||||||
|
{"DisableUpdates", PERSISTENT},
|
||||||
|
{"DisengageOnAccelerator", PERSISTENT},
|
||||||
|
{"DongleId", PERSISTENT},
|
||||||
|
{"DoReboot", CLEAR_ON_MANAGER_START},
|
||||||
|
{"DoShutdown", CLEAR_ON_MANAGER_START},
|
||||||
|
{"DoUninstall", CLEAR_ON_MANAGER_START},
|
||||||
|
{"ExperimentalLongitudinalEnabled", PERSISTENT | DEVELOPMENT_ONLY},
|
||||||
|
{"ExperimentalMode", PERSISTENT},
|
||||||
|
{"ExperimentalModeConfirmed", PERSISTENT},
|
||||||
|
{"FirmwareQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
|
{"ForcePowerDown", PERSISTENT},
|
||||||
|
{"GitBranch", PERSISTENT},
|
||||||
|
{"GitCommit", PERSISTENT},
|
||||||
|
{"GitCommitDate", PERSISTENT},
|
||||||
|
{"GitDiff", PERSISTENT},
|
||||||
|
{"GithubSshKeys", PERSISTENT},
|
||||||
|
{"GithubUsername", PERSISTENT},
|
||||||
|
{"GitRemote", PERSISTENT},
|
||||||
|
{"GsmApn", PERSISTENT},
|
||||||
|
{"GsmMetered", PERSISTENT},
|
||||||
|
{"GsmRoaming", PERSISTENT},
|
||||||
|
{"HardwareSerial", PERSISTENT},
|
||||||
|
{"HasAcceptedTerms", PERSISTENT},
|
||||||
|
{"IMEI", PERSISTENT},
|
||||||
|
{"InstallDate", PERSISTENT},
|
||||||
|
{"IsDriverViewEnabled", CLEAR_ON_MANAGER_START},
|
||||||
|
{"IsEngaged", PERSISTENT},
|
||||||
|
{"IsLdwEnabled", PERSISTENT},
|
||||||
|
{"IsMetric", PERSISTENT},
|
||||||
|
{"IsOffroad", CLEAR_ON_MANAGER_START},
|
||||||
|
{"IsOnroad", PERSISTENT},
|
||||||
|
{"IsRhdDetected", PERSISTENT},
|
||||||
|
{"IsReleaseBranch", CLEAR_ON_MANAGER_START},
|
||||||
|
{"IsTakingSnapshot", CLEAR_ON_MANAGER_START},
|
||||||
|
{"IsTestedBranch", CLEAR_ON_MANAGER_START},
|
||||||
|
{"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||||
|
{"LanguageSetting", PERSISTENT},
|
||||||
|
{"LastAthenaPingTime", CLEAR_ON_MANAGER_START},
|
||||||
|
{"LastGPSPosition", PERSISTENT},
|
||||||
|
{"LastManagerExitReason", CLEAR_ON_MANAGER_START},
|
||||||
|
{"LastOffroadStatusPacket", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||||
|
{"LastPowerDropDetected", CLEAR_ON_MANAGER_START},
|
||||||
|
{"LastUpdateException", CLEAR_ON_MANAGER_START},
|
||||||
|
{"LastUpdateTime", PERSISTENT},
|
||||||
|
{"LiveParameters", PERSISTENT},
|
||||||
|
{"LiveTorqueParameters", PERSISTENT | DONT_LOG},
|
||||||
|
{"LocationFilterInitialState", PERSISTENT},
|
||||||
|
{"LongitudinalManeuverMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||||
|
{"LongitudinalPersonality", PERSISTENT},
|
||||||
|
{"NetworkMetered", PERSISTENT},
|
||||||
|
{"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
|
{"ObdMultiplexingEnabled", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
|
{"Offroad_BadNvme", CLEAR_ON_MANAGER_START},
|
||||||
|
{"Offroad_CarUnrecognized", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
|
{"Offroad_ConnectivityNeeded", CLEAR_ON_MANAGER_START},
|
||||||
|
{"Offroad_ConnectivityNeededPrompt", CLEAR_ON_MANAGER_START},
|
||||||
|
{"Offroad_IsTakingSnapshot", CLEAR_ON_MANAGER_START},
|
||||||
|
{"Offroad_NeosUpdate", CLEAR_ON_MANAGER_START},
|
||||||
|
{"Offroad_NoFirmware", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
|
{"Offroad_Recalibration", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
|
{"Offroad_StorageMissing", CLEAR_ON_MANAGER_START},
|
||||||
|
{"Offroad_TemperatureTooHigh", CLEAR_ON_MANAGER_START},
|
||||||
|
{"Offroad_UnofficialHardware", CLEAR_ON_MANAGER_START},
|
||||||
|
{"Offroad_UpdateFailed", CLEAR_ON_MANAGER_START},
|
||||||
|
{"OpenpilotEnabledToggle", PERSISTENT},
|
||||||
|
{"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||||
|
{"PandaSomResetTriggered", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||||
|
{"PandaSignatures", CLEAR_ON_MANAGER_START},
|
||||||
|
{"PrimeType", PERSISTENT},
|
||||||
|
{"RecordFront", PERSISTENT},
|
||||||
|
{"RecordFrontLock", PERSISTENT}, // for the internal fleet
|
||||||
|
{"SecOCKey", PERSISTENT | DONT_LOG},
|
||||||
|
{"RouteCount", PERSISTENT},
|
||||||
|
{"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||||
|
{"SshEnabled", PERSISTENT},
|
||||||
|
{"TermsVersion", PERSISTENT},
|
||||||
|
{"TrainingVersion", PERSISTENT},
|
||||||
|
{"UbloxAvailable", PERSISTENT},
|
||||||
|
{"UpdateAvailable", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
|
{"UpdateFailedCount", CLEAR_ON_MANAGER_START},
|
||||||
|
{"UpdaterAvailableBranches", PERSISTENT},
|
||||||
|
{"UpdaterCurrentDescription", CLEAR_ON_MANAGER_START},
|
||||||
|
{"UpdaterCurrentReleaseNotes", CLEAR_ON_MANAGER_START},
|
||||||
|
{"UpdaterFetchAvailable", CLEAR_ON_MANAGER_START},
|
||||||
|
{"UpdaterNewDescription", CLEAR_ON_MANAGER_START},
|
||||||
|
{"UpdaterNewReleaseNotes", CLEAR_ON_MANAGER_START},
|
||||||
|
{"UpdaterState", CLEAR_ON_MANAGER_START},
|
||||||
|
{"UpdaterTargetBranch", CLEAR_ON_MANAGER_START},
|
||||||
|
{"UpdaterLastFetchTime", PERSISTENT},
|
||||||
|
{"Version", PERSISTENT},
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
@@ -103,12 +217,10 @@ Params::~Params() {
|
|||||||
assert(queue.empty());
|
assert(queue.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> Params::allKeys(ParamKeyType type) const {
|
std::vector<std::string> Params::allKeys() const {
|
||||||
std::vector<std::string> ret;
|
std::vector<std::string> ret;
|
||||||
for (auto &p : keys) {
|
for (auto &p : keys) {
|
||||||
if (type == ALL || (p.second & type)) {
|
ret.push_back(p.first);
|
||||||
ret.push_back(p.first);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -142,7 +254,7 @@ int Params::put(const char* key, const char* value, size_t value_size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fsync to force persist the changes.
|
// fsync to force persist the changes.
|
||||||
if ((result = HANDLE_EINTR(fsync(tmp_fd))) < 0) break;
|
if ((result = fsync(tmp_fd)) < 0) break;
|
||||||
|
|
||||||
FileLock file_lock(params_path + "/.lock");
|
FileLock file_lock(params_path + "/.lock");
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -16,7 +16,6 @@ enum ParamKeyType {
|
|||||||
CLEAR_ON_OFFROAD_TRANSITION = 0x10,
|
CLEAR_ON_OFFROAD_TRANSITION = 0x10,
|
||||||
DONT_LOG = 0x20,
|
DONT_LOG = 0x20,
|
||||||
DEVELOPMENT_ONLY = 0x40,
|
DEVELOPMENT_ONLY = 0x40,
|
||||||
BACKUP = 0x80,
|
|
||||||
ALL = 0xFFFFFFFF
|
ALL = 0xFFFFFFFF
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -28,7 +27,7 @@ public:
|
|||||||
Params(const Params&) = delete;
|
Params(const Params&) = delete;
|
||||||
Params& operator=(const Params&) = delete;
|
Params& operator=(const Params&) = delete;
|
||||||
|
|
||||||
std::vector<std::string> allKeys(ParamKeyType type = ALL) const;
|
std::vector<std::string> allKeys() const;
|
||||||
bool checkKey(const std::string &key);
|
bool checkKey(const std::string &key);
|
||||||
ParamKeyType getKeyType(const std::string &key);
|
ParamKeyType getKeyType(const std::string &key);
|
||||||
inline std::string getParamPath(const std::string &key = {}) {
|
inline std::string getParamPath(const std::string &key = {}) {
|
||||||
|
|||||||
@@ -1,204 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
inline static std::unordered_map<std::string, uint32_t> keys = {
|
|
||||||
{"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG},
|
|
||||||
{"AdbEnabled", PERSISTENT},
|
|
||||||
{"AlwaysOnDM", PERSISTENT},
|
|
||||||
{"ApiCache_Device", PERSISTENT},
|
|
||||||
{"ApiCache_FirehoseStats", PERSISTENT},
|
|
||||||
{"AssistNowToken", PERSISTENT},
|
|
||||||
{"AthenadPid", PERSISTENT},
|
|
||||||
{"AthenadUploadQueue", PERSISTENT},
|
|
||||||
{"AthenadRecentlyViewedRoutes", PERSISTENT},
|
|
||||||
{"BootCount", PERSISTENT},
|
|
||||||
{"CalibrationParams", PERSISTENT},
|
|
||||||
{"CameraDebugExpGain", CLEAR_ON_MANAGER_START},
|
|
||||||
{"CameraDebugExpTime", CLEAR_ON_MANAGER_START},
|
|
||||||
{"CarBatteryCapacity", PERSISTENT},
|
|
||||||
{"CarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
|
||||||
{"CarParamsCache", CLEAR_ON_MANAGER_START},
|
|
||||||
{"CarParamsPersistent", PERSISTENT},
|
|
||||||
{"CarParamsPrevRoute", PERSISTENT},
|
|
||||||
{"CompletedTrainingVersion", PERSISTENT},
|
|
||||||
{"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
|
||||||
{"CurrentBootlog", PERSISTENT},
|
|
||||||
{"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
|
||||||
{"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
|
||||||
{"DisablePowerDown", PERSISTENT | BACKUP},
|
|
||||||
{"DisableUpdates", PERSISTENT | BACKUP},
|
|
||||||
{"DisengageOnAccelerator", PERSISTENT | BACKUP},
|
|
||||||
{"DongleId", PERSISTENT},
|
|
||||||
{"DoReboot", CLEAR_ON_MANAGER_START},
|
|
||||||
{"DoShutdown", CLEAR_ON_MANAGER_START},
|
|
||||||
{"DoUninstall", CLEAR_ON_MANAGER_START},
|
|
||||||
{"AlphaLongitudinalEnabled", PERSISTENT | DEVELOPMENT_ONLY | BACKUP},
|
|
||||||
{"ExperimentalMode", PERSISTENT | BACKUP},
|
|
||||||
{"ExperimentalModeConfirmed", PERSISTENT | BACKUP},
|
|
||||||
{"FirmwareQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
|
||||||
{"ForcePowerDown", PERSISTENT},
|
|
||||||
{"GitBranch", PERSISTENT},
|
|
||||||
{"GitCommit", PERSISTENT},
|
|
||||||
{"GitCommitDate", PERSISTENT},
|
|
||||||
{"GitDiff", PERSISTENT},
|
|
||||||
{"GithubSshKeys", PERSISTENT | BACKUP},
|
|
||||||
{"GithubUsername", PERSISTENT | BACKUP},
|
|
||||||
{"GitRemote", PERSISTENT},
|
|
||||||
{"GsmApn", PERSISTENT | BACKUP},
|
|
||||||
{"GsmMetered", PERSISTENT | BACKUP},
|
|
||||||
{"GsmRoaming", PERSISTENT | BACKUP},
|
|
||||||
{"HardwareSerial", PERSISTENT},
|
|
||||||
{"HasAcceptedTerms", PERSISTENT},
|
|
||||||
{"InstallDate", PERSISTENT},
|
|
||||||
{"IsDriverViewEnabled", CLEAR_ON_MANAGER_START},
|
|
||||||
{"IsEngaged", PERSISTENT},
|
|
||||||
{"IsLdwEnabled", PERSISTENT | BACKUP},
|
|
||||||
{"IsMetric", PERSISTENT | BACKUP},
|
|
||||||
{"IsOffroad", CLEAR_ON_MANAGER_START},
|
|
||||||
{"IsOnroad", PERSISTENT},
|
|
||||||
{"IsRhdDetected", PERSISTENT},
|
|
||||||
{"IsReleaseBranch", CLEAR_ON_MANAGER_START},
|
|
||||||
{"IsTakingSnapshot", CLEAR_ON_MANAGER_START},
|
|
||||||
{"IsTestedBranch", CLEAR_ON_MANAGER_START},
|
|
||||||
{"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
|
||||||
{"LanguageSetting", PERSISTENT | BACKUP},
|
|
||||||
{"LastAthenaPingTime", CLEAR_ON_MANAGER_START},
|
|
||||||
{"LastGPSPosition", PERSISTENT},
|
|
||||||
{"LastManagerExitReason", CLEAR_ON_MANAGER_START},
|
|
||||||
{"LastOffroadStatusPacket", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
|
||||||
{"LastPowerDropDetected", CLEAR_ON_MANAGER_START},
|
|
||||||
{"LastUpdateException", CLEAR_ON_MANAGER_START},
|
|
||||||
{"LastUpdateTime", PERSISTENT},
|
|
||||||
{"LiveDelay", PERSISTENT | BACKUP},
|
|
||||||
{"LiveParameters", PERSISTENT},
|
|
||||||
{"LiveParametersV2", PERSISTENT},
|
|
||||||
{"LiveTorqueParameters", PERSISTENT | DONT_LOG},
|
|
||||||
{"LocationFilterInitialState", PERSISTENT},
|
|
||||||
{"LongitudinalManeuverMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
|
||||||
{"LongitudinalPersonality", PERSISTENT | BACKUP},
|
|
||||||
{"NetworkMetered", PERSISTENT},
|
|
||||||
{"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
|
||||||
{"ObdMultiplexingEnabled", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
|
||||||
{"Offroad_BadNvme", CLEAR_ON_MANAGER_START},
|
|
||||||
{"Offroad_CarUnrecognized", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
|
||||||
{"Offroad_ConnectivityNeeded", CLEAR_ON_MANAGER_START},
|
|
||||||
{"Offroad_ConnectivityNeededPrompt", CLEAR_ON_MANAGER_START},
|
|
||||||
{"Offroad_IsTakingSnapshot", CLEAR_ON_MANAGER_START},
|
|
||||||
{"Offroad_NeosUpdate", CLEAR_ON_MANAGER_START},
|
|
||||||
{"Offroad_NoFirmware", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
|
||||||
{"Offroad_Recalibration", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
|
||||||
{"Offroad_StorageMissing", CLEAR_ON_MANAGER_START},
|
|
||||||
{"Offroad_TemperatureTooHigh", CLEAR_ON_MANAGER_START},
|
|
||||||
{"Offroad_UnofficialHardware", CLEAR_ON_MANAGER_START},
|
|
||||||
{"Offroad_UpdateFailed", CLEAR_ON_MANAGER_START},
|
|
||||||
{"OnroadCycleRequested", CLEAR_ON_MANAGER_START},
|
|
||||||
{"OpenpilotEnabledToggle", PERSISTENT | BACKUP},
|
|
||||||
{"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
|
||||||
{"PandaSomResetTriggered", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
|
||||||
{"PandaSignatures", CLEAR_ON_MANAGER_START},
|
|
||||||
{"PrimeType", PERSISTENT},
|
|
||||||
{"RecordFront", PERSISTENT | BACKUP},
|
|
||||||
{"RecordFrontLock", PERSISTENT}, // for the internal fleet
|
|
||||||
{"SecOCKey", PERSISTENT | DONT_LOG}, // Candidate for | BACKUP
|
|
||||||
{"RouteCount", PERSISTENT},
|
|
||||||
{"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
|
||||||
{"SshEnabled", PERSISTENT | BACKUP},
|
|
||||||
{"TermsVersion", PERSISTENT},
|
|
||||||
{"TrainingVersion", PERSISTENT},
|
|
||||||
{"UbloxAvailable", PERSISTENT},
|
|
||||||
{"UpdateAvailable", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
|
||||||
{"UpdateFailedCount", CLEAR_ON_MANAGER_START},
|
|
||||||
{"UpdaterAvailableBranches", PERSISTENT},
|
|
||||||
{"UpdaterCurrentDescription", CLEAR_ON_MANAGER_START},
|
|
||||||
{"UpdaterCurrentReleaseNotes", CLEAR_ON_MANAGER_START},
|
|
||||||
{"UpdaterFetchAvailable", CLEAR_ON_MANAGER_START},
|
|
||||||
{"UpdaterNewDescription", CLEAR_ON_MANAGER_START},
|
|
||||||
{"UpdaterNewReleaseNotes", CLEAR_ON_MANAGER_START},
|
|
||||||
{"UpdaterState", CLEAR_ON_MANAGER_START},
|
|
||||||
{"UpdaterTargetBranch", CLEAR_ON_MANAGER_START},
|
|
||||||
{"UpdaterLastFetchTime", PERSISTENT},
|
|
||||||
{"Version", PERSISTENT},
|
|
||||||
|
|
||||||
// --- sunnypilot params --- //
|
|
||||||
{"ApiCache_DriveStats", PERSISTENT},
|
|
||||||
{"AutoLaneChangeBsmDelay", PERSISTENT},
|
|
||||||
{"AutoLaneChangeTimer", PERSISTENT},
|
|
||||||
{"BlinkerMinLateralControlSpeed", PERSISTENT | BACKUP},
|
|
||||||
{"BlinkerPauseLateralControl", PERSISTENT | BACKUP},
|
|
||||||
{"CarParamsSP", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
|
||||||
{"CarParamsSPCache", CLEAR_ON_MANAGER_START},
|
|
||||||
{"CarParamsSPPersistent", PERSISTENT},
|
|
||||||
{"CarPlatformBundle", PERSISTENT},
|
|
||||||
{"CustomAccIncrementsEnabled", PERSISTENT | BACKUP},
|
|
||||||
{"CustomAccLongPressIncrement", PERSISTENT | BACKUP},
|
|
||||||
{"CustomAccShortPressIncrement", PERSISTENT | BACKUP},
|
|
||||||
{"DeviceBootMode", PERSISTENT | BACKUP},
|
|
||||||
{"EnableGithubRunner", PERSISTENT | BACKUP},
|
|
||||||
{"InteractivityTimeout", PERSISTENT | BACKUP},
|
|
||||||
{"MaxTimeOffroad", PERSISTENT | BACKUP},
|
|
||||||
{"Brightness", PERSISTENT | BACKUP},
|
|
||||||
{"ModelRunnerTypeCache", CLEAR_ON_ONROAD_TRANSITION},
|
|
||||||
{"OffroadMode", CLEAR_ON_MANAGER_START},
|
|
||||||
{"QuietMode", PERSISTENT | BACKUP},
|
|
||||||
|
|
||||||
// MADS params
|
|
||||||
{"Mads", PERSISTENT | BACKUP},
|
|
||||||
{"MadsMainCruiseAllowed", PERSISTENT | BACKUP},
|
|
||||||
{"MadsSteeringMode", PERSISTENT | BACKUP},
|
|
||||||
{"MadsUnifiedEngagementMode", PERSISTENT | BACKUP},
|
|
||||||
|
|
||||||
// Model Manager params
|
|
||||||
{"ModelManager_ActiveBundle", PERSISTENT},
|
|
||||||
{"ModelManager_DownloadIndex", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
|
||||||
{"ModelManager_LastSyncTime", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
|
||||||
{"ModelManager_ModelsCache", PERSISTENT | BACKUP},
|
|
||||||
|
|
||||||
// Neural Network Lateral Control
|
|
||||||
{"NeuralNetworkLateralControl", PERSISTENT | BACKUP},
|
|
||||||
|
|
||||||
// sunnylink params
|
|
||||||
{"EnableSunnylinkUploader", PERSISTENT | BACKUP},
|
|
||||||
{"LastSunnylinkPingTime", CLEAR_ON_MANAGER_START},
|
|
||||||
{"SunnylinkCache_Roles", PERSISTENT},
|
|
||||||
{"SunnylinkCache_Users", PERSISTENT},
|
|
||||||
{"SunnylinkDongleId", PERSISTENT},
|
|
||||||
{"SunnylinkdPid", PERSISTENT},
|
|
||||||
{"SunnylinkEnabled", PERSISTENT},
|
|
||||||
|
|
||||||
// Backup Manager params
|
|
||||||
{"BackupManager_CreateBackup", PERSISTENT},
|
|
||||||
{"BackupManager_RestoreVersion", PERSISTENT},
|
|
||||||
|
|
||||||
// sunnypilot car specific params
|
|
||||||
{"HyundaiLongitudinalTuning", PERSISTENT},
|
|
||||||
|
|
||||||
{"DynamicExperimentalControl", PERSISTENT},
|
|
||||||
{"BlindSpot", PERSISTENT | BACKUP},
|
|
||||||
|
|
||||||
// model panel params
|
|
||||||
{"LagdToggle", PERSISTENT | BACKUP},
|
|
||||||
{"LagdToggleDesc", PERSISTENT},
|
|
||||||
{"LagdToggledelay", PERSISTENT | BACKUP},
|
|
||||||
|
|
||||||
// mapd
|
|
||||||
{"MapAdvisorySpeedLimit", CLEAR_ON_ONROAD_TRANSITION},
|
|
||||||
{"MapdVersion", PERSISTENT},
|
|
||||||
{"MapSpeedLimit", CLEAR_ON_ONROAD_TRANSITION},
|
|
||||||
{"NextMapSpeedLimit", CLEAR_ON_ONROAD_TRANSITION},
|
|
||||||
{"Offroad_OSMUpdateRequired", CLEAR_ON_MANAGER_START},
|
|
||||||
{"OsmDbUpdatesCheck", CLEAR_ON_MANAGER_START}, // mapd database update happens with device ON, reset on boot
|
|
||||||
{"OSMDownloadBounds", PERSISTENT},
|
|
||||||
{"OsmDownloadedDate", PERSISTENT},
|
|
||||||
{"OSMDownloadLocations", PERSISTENT},
|
|
||||||
{"OSMDownloadProgress", CLEAR_ON_MANAGER_START},
|
|
||||||
{"OsmLocal", PERSISTENT},
|
|
||||||
{"OsmLocationName", PERSISTENT},
|
|
||||||
{"OsmLocationTitle", PERSISTENT},
|
|
||||||
{"OsmLocationUrl", PERSISTENT},
|
|
||||||
{"OsmStateName", PERSISTENT},
|
|
||||||
{"OsmStateTitle", PERSISTENT},
|
|
||||||
{"OsmWayTest", PERSISTENT},
|
|
||||||
{"RoadName", CLEAR_ON_ONROAD_TRANSITION},
|
|
||||||
};
|
|
||||||
@@ -11,7 +11,6 @@ cdef extern from "common/params.h":
|
|||||||
CLEAR_ON_ONROAD_TRANSITION
|
CLEAR_ON_ONROAD_TRANSITION
|
||||||
CLEAR_ON_OFFROAD_TRANSITION
|
CLEAR_ON_OFFROAD_TRANSITION
|
||||||
DEVELOPMENT_ONLY
|
DEVELOPMENT_ONLY
|
||||||
BACKUP
|
|
||||||
ALL
|
ALL
|
||||||
|
|
||||||
cdef cppclass c_Params "Params":
|
cdef cppclass c_Params "Params":
|
||||||
@@ -26,7 +25,7 @@ cdef extern from "common/params.h":
|
|||||||
bool checkKey(string) nogil
|
bool checkKey(string) nogil
|
||||||
string getParamPath(string) nogil
|
string getParamPath(string) nogil
|
||||||
void clearAll(ParamKeyType)
|
void clearAll(ParamKeyType)
|
||||||
vector[string] allKeys(ParamKeyType)
|
vector[string] allKeys()
|
||||||
|
|
||||||
|
|
||||||
def ensure_bytes(v):
|
def ensure_bytes(v):
|
||||||
@@ -120,5 +119,5 @@ cdef class Params:
|
|||||||
cdef string key_bytes = ensure_bytes(key)
|
cdef string key_bytes = ensure_bytes(key)
|
||||||
return self.p.getParamPath(key_bytes).decode("utf-8")
|
return self.p.getParamPath(key_bytes).decode("utf-8")
|
||||||
|
|
||||||
def all_keys(self, type=ParamKeyType.ALL):
|
def all_keys(self):
|
||||||
return self.p.allKeys(type)
|
return self.p.allKeys()
|
||||||
|
|||||||
+9
-6
@@ -1,6 +1,9 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
from numbers import Number
|
from numbers import Number
|
||||||
|
|
||||||
|
from openpilot.common.numpy_fast import clip, interp
|
||||||
|
|
||||||
|
|
||||||
class PIDController:
|
class PIDController:
|
||||||
def __init__(self, k_p, k_i, k_f=0., k_d=0., pos_limit=1e308, neg_limit=-1e308, rate=100):
|
def __init__(self, k_p, k_i, k_f=0., k_d=0., pos_limit=1e308, neg_limit=-1e308, rate=100):
|
||||||
self._k_p = k_p
|
self._k_p = k_p
|
||||||
@@ -25,15 +28,15 @@ class PIDController:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def k_p(self):
|
def k_p(self):
|
||||||
return np.interp(self.speed, self._k_p[0], self._k_p[1])
|
return interp(self.speed, self._k_p[0], self._k_p[1])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def k_i(self):
|
def k_i(self):
|
||||||
return np.interp(self.speed, self._k_i[0], self._k_i[1])
|
return interp(self.speed, self._k_i[0], self._k_i[1])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def k_d(self):
|
def k_d(self):
|
||||||
return np.interp(self.speed, self._k_d[0], self._k_d[1])
|
return interp(self.speed, self._k_d[0], self._k_d[1])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def error_integral(self):
|
def error_integral(self):
|
||||||
@@ -61,10 +64,10 @@ class PIDController:
|
|||||||
|
|
||||||
# Clip i to prevent exceeding control limits
|
# Clip i to prevent exceeding control limits
|
||||||
control_no_i = self.p + self.d + self.f
|
control_no_i = self.p + self.d + self.f
|
||||||
control_no_i = np.clip(control_no_i, self.neg_limit, self.pos_limit)
|
control_no_i = clip(control_no_i, self.neg_limit, self.pos_limit)
|
||||||
self.i = np.clip(self.i, self.neg_limit - control_no_i, self.pos_limit - control_no_i)
|
self.i = clip(self.i, self.neg_limit - control_no_i, self.pos_limit - control_no_i)
|
||||||
|
|
||||||
control = self.p + self.i + self.d + self.f
|
control = self.p + self.i + self.d + self.f
|
||||||
|
|
||||||
self.control = np.clip(control, self.neg_limit, self.pos_limit)
|
self.control = clip(control, self.neg_limit, self.pos_limit)
|
||||||
return self.control
|
return self.control
|
||||||
|
|||||||
+12
-10
@@ -1,12 +1,11 @@
|
|||||||
"""Utilities for reading real time clocks and keeping soft real time constraints."""
|
"""Utilities for reading real time clocks and keeping soft real time constraints."""
|
||||||
import gc
|
import gc
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
|
from collections import deque
|
||||||
|
|
||||||
from setproctitle import getproctitle
|
from setproctitle import getproctitle
|
||||||
|
|
||||||
from openpilot.common.util import MovingAverage
|
|
||||||
from openpilot.system.hardware import PC
|
from openpilot.system.hardware import PC
|
||||||
|
|
||||||
|
|
||||||
@@ -28,15 +27,19 @@ class Priority:
|
|||||||
CTRL_HIGH = 53
|
CTRL_HIGH = 53
|
||||||
|
|
||||||
|
|
||||||
|
def set_realtime_priority(level: int) -> None:
|
||||||
|
if not PC:
|
||||||
|
os.sched_setscheduler(0, os.SCHED_FIFO, os.sched_param(level))
|
||||||
|
|
||||||
|
|
||||||
def set_core_affinity(cores: list[int]) -> None:
|
def set_core_affinity(cores: list[int]) -> None:
|
||||||
if sys.platform == 'linux' and not PC:
|
if not PC:
|
||||||
os.sched_setaffinity(0, cores)
|
os.sched_setaffinity(0, cores)
|
||||||
|
|
||||||
|
|
||||||
def config_realtime_process(cores: int | list[int], priority: int) -> None:
|
def config_realtime_process(cores: int | list[int], priority: int) -> None:
|
||||||
gc.disable()
|
gc.disable()
|
||||||
if sys.platform == 'linux' and not PC:
|
set_realtime_priority(priority)
|
||||||
os.sched_setscheduler(0, os.SCHED_FIFO, os.sched_param(priority))
|
|
||||||
c = cores if isinstance(cores, list) else [cores, ]
|
c = cores if isinstance(cores, list) else [cores, ]
|
||||||
set_core_affinity(c)
|
set_core_affinity(c)
|
||||||
|
|
||||||
@@ -49,12 +52,10 @@ class Ratekeeper:
|
|||||||
self._frame = 0
|
self._frame = 0
|
||||||
self._remaining = 0.0
|
self._remaining = 0.0
|
||||||
self._process_name = getproctitle()
|
self._process_name = getproctitle()
|
||||||
|
self._dts = deque([self._interval], maxlen=100)
|
||||||
self._last_monitor_time = -1.
|
self._last_monitor_time = -1.
|
||||||
self._next_frame_time = -1.
|
self._next_frame_time = -1.
|
||||||
|
|
||||||
self.avg_dt = MovingAverage(100)
|
|
||||||
self.avg_dt.add_value(self._interval)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def frame(self) -> int:
|
def frame(self) -> int:
|
||||||
return self._frame
|
return self._frame
|
||||||
@@ -65,8 +66,9 @@ class Ratekeeper:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def lagging(self) -> bool:
|
def lagging(self) -> bool:
|
||||||
|
avg_dt = sum(self._dts) / len(self._dts)
|
||||||
expected_dt = self._interval * (1 / 0.9)
|
expected_dt = self._interval * (1 / 0.9)
|
||||||
return self.avg_dt.get_average() > expected_dt
|
return avg_dt > expected_dt
|
||||||
|
|
||||||
# Maintain loop rate by calling this at the end of each loop
|
# Maintain loop rate by calling this at the end of each loop
|
||||||
def keep_time(self) -> bool:
|
def keep_time(self) -> bool:
|
||||||
@@ -83,7 +85,7 @@ class Ratekeeper:
|
|||||||
|
|
||||||
prev = self._last_monitor_time
|
prev = self._last_monitor_time
|
||||||
self._last_monitor_time = time.monotonic()
|
self._last_monitor_time = time.monotonic()
|
||||||
self.avg_dt.add_value(self._last_monitor_time - prev)
|
self._dts.append(self._last_monitor_time - prev)
|
||||||
|
|
||||||
lagged = False
|
lagged = False
|
||||||
remaining = self._next_frame_time - time.monotonic()
|
remaining = self._next_frame_time - time.monotonic()
|
||||||
|
|||||||
Executable → Regular
+2
-2
@@ -6,9 +6,9 @@ from openpilot.common.basedir import BASEDIR
|
|||||||
class Spinner:
|
class Spinner:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
try:
|
try:
|
||||||
self.spinner_proc = subprocess.Popen(["./spinner.py"],
|
self.spinner_proc = subprocess.Popen(["./spinner"],
|
||||||
stdin=subprocess.PIPE,
|
stdin=subprocess.PIPE,
|
||||||
cwd=os.path.join(BASEDIR, "system", "ui"),
|
cwd=os.path.join(BASEDIR, "selfdrive", "ui"),
|
||||||
close_fds=True)
|
close_fds=True)
|
||||||
except OSError:
|
except OSError:
|
||||||
self.spinner_proc = None
|
self.spinner_proc = None
|
||||||
|
|||||||
@@ -26,9 +26,6 @@ public:
|
|||||||
zmq_setsockopt(sock, ZMQ_LINGER, &timeout, sizeof(timeout));
|
zmq_setsockopt(sock, ZMQ_LINGER, &timeout, sizeof(timeout));
|
||||||
zmq_connect(sock, Path::swaglog_ipc().c_str());
|
zmq_connect(sock, Path::swaglog_ipc().c_str());
|
||||||
|
|
||||||
// workaround for https://github.com/dropbox/json11/issues/38
|
|
||||||
setlocale(LC_NUMERIC, "C");
|
|
||||||
|
|
||||||
print_level = CLOUDLOG_WARNING;
|
print_level = CLOUDLOG_WARNING;
|
||||||
if (const char* print_lvl = getenv("LOGPRINT")) {
|
if (const char* print_lvl = getenv("LOGPRINT")) {
|
||||||
if (strcmp(print_lvl, "debug") == 0) {
|
if (strcmp(print_lvl, "debug") == 0) {
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from openpilot.common.numpy_fast import interp
|
||||||
|
|
||||||
|
|
||||||
|
class TestInterp:
|
||||||
|
def test_correctness_controls(self):
|
||||||
|
_A_CRUISE_MIN_BP = np.asarray([0., 5., 10., 20., 40.])
|
||||||
|
_A_CRUISE_MIN_V = np.asarray([-1.0, -.8, -.67, -.5, -.30])
|
||||||
|
v_ego_arr = [-1, -1e-12, 0, 4, 5, 6, 7, 10, 11, 15.2, 20, 21, 39,
|
||||||
|
39.999999, 40, 41]
|
||||||
|
|
||||||
|
expected = np.interp(v_ego_arr, _A_CRUISE_MIN_BP, _A_CRUISE_MIN_V)
|
||||||
|
actual = interp(v_ego_arr, _A_CRUISE_MIN_BP, _A_CRUISE_MIN_V)
|
||||||
|
|
||||||
|
np.testing.assert_equal(actual, expected)
|
||||||
|
|
||||||
|
for v_ego in v_ego_arr:
|
||||||
|
expected = np.interp(v_ego, _A_CRUISE_MIN_BP, _A_CRUISE_MIN_V)
|
||||||
|
actual = interp(v_ego, _A_CRUISE_MIN_BP, _A_CRUISE_MIN_V)
|
||||||
|
np.testing.assert_equal(actual, expected)
|
||||||
@@ -24,6 +24,6 @@ class TestSimpleKalman:
|
|||||||
self.kf.set_x([[1.0], [1.0]])
|
self.kf.set_x([[1.0], [1.0]])
|
||||||
assert self.kf.x == [[1.0], [1.0]]
|
assert self.kf.x == [[1.0], [1.0]]
|
||||||
|
|
||||||
def test_update_returns_state(self):
|
def update_returns_state(self):
|
||||||
x = self.kf.update(100)
|
x = self.kf.update(100)
|
||||||
assert x == [i[0] for i in self.kf.x]
|
assert x == self.kf.x
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ from openpilot.common.basedir import BASEDIR
|
|||||||
class TextWindow:
|
class TextWindow:
|
||||||
def __init__(self, text):
|
def __init__(self, text):
|
||||||
try:
|
try:
|
||||||
self.text_proc = subprocess.Popen(["./text.py", text],
|
self.text_proc = subprocess.Popen(["./text", text],
|
||||||
stdin=subprocess.PIPE,
|
stdin=subprocess.PIPE,
|
||||||
cwd=os.path.join(BASEDIR, "system", "ui"),
|
cwd=os.path.join(BASEDIR, "selfdrive", "ui"),
|
||||||
close_fds=True)
|
close_fds=True)
|
||||||
except OSError:
|
except OSError:
|
||||||
self.text_proc = None
|
self.text_proc = None
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import datetime
|
import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
MIN_DATE = datetime.datetime(year=2025, month=2, day=21)
|
_MIN_DATE = datetime.datetime(year=2024, month=8, day=26)
|
||||||
|
|
||||||
def min_date():
|
def min_date():
|
||||||
# on systemd systems, the default time is the systemd build time
|
# on systemd systems, the default time is the systemd build time
|
||||||
systemd_path = Path("/lib/systemd/systemd")
|
systemd_path = Path("/lib/systemd/systemd")
|
||||||
if systemd_path.exists():
|
if systemd_path.exists():
|
||||||
d = datetime.datetime.fromtimestamp(systemd_path.stat().st_mtime)
|
d = datetime.datetime.fromtimestamp(systemd_path.stat().st_mtime)
|
||||||
return max(MIN_DATE, d + datetime.timedelta(days=1))
|
return d + datetime.timedelta(days=1)
|
||||||
return MIN_DATE
|
return _MIN_DATE
|
||||||
|
|
||||||
def system_time_valid():
|
def system_time_valid():
|
||||||
return datetime.datetime.now() > min_date()
|
return datetime.datetime.now() > min_date()
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from openpilot.common.transformations.orientation import rot_from_euler
|
from openpilot.common.transformations.orientation import rot_from_euler
|
||||||
from openpilot.common.transformations.camera import get_view_frame_from_calib_frame, view_frame_from_device_frame, _ar_ox_fisheye
|
from openpilot.common.transformations.camera import get_view_frame_from_calib_frame, view_frame_from_device_frame
|
||||||
|
|
||||||
# segnet
|
# segnet
|
||||||
SEGNET_SIZE = (512, 384)
|
SEGNET_SIZE = (512, 384)
|
||||||
@@ -39,13 +39,6 @@ sbigmodel_intrinsics = np.array([
|
|||||||
[0.0, sbigmodel_fl, 0.5 * (256 + MEDMODEL_CY)],
|
[0.0, sbigmodel_fl, 0.5 * (256 + MEDMODEL_CY)],
|
||||||
[0.0, 0.0, 1.0]])
|
[0.0, 0.0, 1.0]])
|
||||||
|
|
||||||
DM_INPUT_SIZE = (1440, 960)
|
|
||||||
dmonitoringmodel_fl = _ar_ox_fisheye.focal_length
|
|
||||||
dmonitoringmodel_intrinsics = np.array([
|
|
||||||
[dmonitoringmodel_fl, 0.0, DM_INPUT_SIZE[0]/2],
|
|
||||||
[0.0, dmonitoringmodel_fl, DM_INPUT_SIZE[1]/2 - (_ar_ox_fisheye.height - DM_INPUT_SIZE[1])/2],
|
|
||||||
[0.0, 0.0, 1.0]])
|
|
||||||
|
|
||||||
bigmodel_frame_from_calib_frame = np.dot(bigmodel_intrinsics,
|
bigmodel_frame_from_calib_frame = np.dot(bigmodel_intrinsics,
|
||||||
get_view_frame_from_calib_frame(0, 0, 0, 0))
|
get_view_frame_from_calib_frame(0, 0, 0, 0))
|
||||||
|
|
||||||
|
|||||||
@@ -255,28 +255,6 @@ bool ends_with(const std::string& s, const std::string& suffix) {
|
|||||||
strcmp(s.c_str() + (s.size() - suffix.size()), suffix.c_str()) == 0;
|
strcmp(s.c_str() + (s.size() - suffix.size()), suffix.c_str()) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string strip(const std::string &str) {
|
|
||||||
auto should_trim = [](unsigned char ch) {
|
|
||||||
return std::isspace(ch) || ch == '\0';
|
|
||||||
};
|
|
||||||
|
|
||||||
size_t start = 0;
|
|
||||||
while (start < str.size() && should_trim(static_cast<unsigned char>(str[start]))) {
|
|
||||||
start++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start == str.size()) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t end = str.size() - 1;
|
|
||||||
while (end > 0 && should_trim(static_cast<unsigned char>(str[end]))) {
|
|
||||||
end--;
|
|
||||||
}
|
|
||||||
|
|
||||||
return str.substr(start, end - start + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string check_output(const std::string& command) {
|
std::string check_output(const std::string& command) {
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
std::string result;
|
std::string result;
|
||||||
@@ -293,17 +271,4 @@ std::string check_output(const std::string& command) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool system_time_valid() {
|
|
||||||
// Default to August 26, 2024
|
|
||||||
tm min_tm = {.tm_year = 2024 - 1900, .tm_mon = 7, .tm_mday = 26};
|
|
||||||
time_t min_date = mktime(&min_tm);
|
|
||||||
|
|
||||||
struct stat st;
|
|
||||||
if (stat("/lib/systemd/systemd", &st) == 0) {
|
|
||||||
min_date = std::max(min_date, st.st_mtime + 86400); // Add 1 day (86400 seconds)
|
|
||||||
}
|
|
||||||
|
|
||||||
return time(nullptr) > min_date;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace util
|
} // namespace util
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ float getenv(const char* key, float default_val);
|
|||||||
std::string hexdump(const uint8_t* in, const size_t size);
|
std::string hexdump(const uint8_t* in, const size_t size);
|
||||||
bool starts_with(const std::string &s1, const std::string &s2);
|
bool starts_with(const std::string &s1, const std::string &s2);
|
||||||
bool ends_with(const std::string &s, const std::string &suffix);
|
bool ends_with(const std::string &s, const std::string &suffix);
|
||||||
std::string strip(const std::string &str);
|
|
||||||
|
|
||||||
// ***** random helpers *****
|
// ***** random helpers *****
|
||||||
int random_int(int min, int max);
|
int random_int(int min, int max);
|
||||||
@@ -96,8 +95,6 @@ bool create_directories(const std::string &dir, mode_t mode);
|
|||||||
|
|
||||||
std::string check_output(const std::string& command);
|
std::string check_output(const std::string& command);
|
||||||
|
|
||||||
bool system_time_valid();
|
|
||||||
|
|
||||||
inline void sleep_for(const int milliseconds) {
|
inline void sleep_for(const int milliseconds) {
|
||||||
if (milliseconds > 0) {
|
if (milliseconds > 0) {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
|
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
import os
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
def sudo_write(val: str, path: str) -> None:
|
|
||||||
try:
|
|
||||||
with open(path, 'w') as f:
|
|
||||||
f.write(str(val))
|
|
||||||
except PermissionError:
|
|
||||||
os.system(f"sudo chmod a+w {path}")
|
|
||||||
try:
|
|
||||||
with open(path, 'w') as f:
|
|
||||||
f.write(str(val))
|
|
||||||
except PermissionError:
|
|
||||||
# fallback for debugfs files
|
|
||||||
os.system(f"sudo su -c 'echo {val} > {path}'")
|
|
||||||
|
|
||||||
def sudo_read(path: str) -> str:
|
|
||||||
try:
|
|
||||||
return subprocess.check_output(f"sudo cat {path}", shell=True, encoding='utf8').strip()
|
|
||||||
except Exception:
|
|
||||||
return ""
|
|
||||||
|
|
||||||
class MovingAverage:
|
|
||||||
def __init__(self, window_size: int):
|
|
||||||
self.window_size: int = window_size
|
|
||||||
self.buffer: list[float] = [0.0] * window_size
|
|
||||||
self.index: int = 0
|
|
||||||
self.count: int = 0
|
|
||||||
self.sum: float = 0.0
|
|
||||||
|
|
||||||
def add_value(self, new_value: float):
|
|
||||||
# Update the sum: subtract the value being replaced and add the new value
|
|
||||||
self.sum -= self.buffer[self.index]
|
|
||||||
self.buffer[self.index] = new_value
|
|
||||||
self.sum += new_value
|
|
||||||
|
|
||||||
# Update the index in a circular manner
|
|
||||||
self.index = (self.index + 1) % self.window_size
|
|
||||||
|
|
||||||
# Track the number of added values (for partial windows)
|
|
||||||
self.count = min(self.count + 1, self.window_size)
|
|
||||||
|
|
||||||
def get_average(self) -> float:
|
|
||||||
if self.count == 0:
|
|
||||||
return float('nan')
|
|
||||||
return self.sum / self.count
|
|
||||||
+1
-1
@@ -1 +1 @@
|
|||||||
#define COMMA_VERSION "0.9.10"
|
#define COMMA_VERSION "0.9.8"
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
import os
|
|
||||||
import time
|
|
||||||
import struct
|
|
||||||
from openpilot.system.hardware.hw import Paths
|
|
||||||
|
|
||||||
WATCHDOG_FN = f"{Paths.shm_path()}/wd_"
|
|
||||||
_LAST_KICK = 0.0
|
|
||||||
|
|
||||||
def kick_watchdog():
|
|
||||||
global _LAST_KICK
|
|
||||||
current_time = time.monotonic()
|
|
||||||
|
|
||||||
if current_time - _LAST_KICK < 1.0:
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(f"{WATCHDOG_FN}{os.getpid()}", 'wb') as f:
|
|
||||||
f.write(struct.pack('<Q', int(current_time * 1e9)))
|
|
||||||
f.flush()
|
|
||||||
_LAST_KICK = current_time
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
+2
-4
@@ -14,11 +14,11 @@ collect_ignore = [
|
|||||||
"selfdrive/ui/tests/test_translations",
|
"selfdrive/ui/tests/test_translations",
|
||||||
"selfdrive/test/process_replay/test_processes.py",
|
"selfdrive/test/process_replay/test_processes.py",
|
||||||
"selfdrive/test/process_replay/test_regen.py",
|
"selfdrive/test/process_replay/test_regen.py",
|
||||||
|
"selfdrive/test/test_time_to_onroad.py",
|
||||||
]
|
]
|
||||||
collect_ignore_glob = [
|
collect_ignore_glob = [
|
||||||
"selfdrive/debug/*.py",
|
"selfdrive/debug/*.py",
|
||||||
"selfdrive/modeld/*.py",
|
"selfdrive/modeld/*.py",
|
||||||
"sunnypilot/modeld*/*.py",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -78,10 +78,8 @@ def openpilot_class_fixture():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
@pytest.fixture(scope="function")
|
||||||
def tici_setup_fixture(request, openpilot_function_fixture):
|
def tici_setup_fixture(openpilot_function_fixture):
|
||||||
"""Ensure a consistent state for tests on-device. Needs the openpilot function fixture to run first."""
|
"""Ensure a consistent state for tests on-device. Needs the openpilot function fixture to run first."""
|
||||||
if 'skip_tici_setup' in request.keywords:
|
|
||||||
return
|
|
||||||
HARDWARE.initialize_hardware()
|
HARDWARE.initialize_hardware()
|
||||||
HARDWARE.set_power_save(False)
|
HARDWARE.set_power_save(False)
|
||||||
os.system("pkill -9 -f athena")
|
os.system("pkill -9 -f athena")
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user