Compare commits

..

3 Commits

Author SHA1 Message Date
DevTekVE 5d754169a6 Updating ESCC guide to use relay box 2024-07-29 12:31:45 +02:00
DevTekVE 0bbe217642 images didn't push 2024-03-21 19:13:03 +01:00
DevTekVE a36dc616ac Very very very first iteration, with very first ever made board 2024-03-21 19:11:31 +01:00
1076 changed files with 32748 additions and 80210 deletions
+3 -6
View File
@@ -1,16 +1,13 @@
FROM ghcr.io/commaai/openpilot-base:latest FROM ghcr.io/commaai/openpilot-base:latest
RUN apt update && apt install -y vim net-tools usbutils htop ripgrep tmux wget mesa-utils xvfb libxtst6 libxv1 libglu1-mesa gdb bash-completion RUN apt update && apt install -y vim net-tools usbutils htop ripgrep tmux wget mesa-utils xvfb libxtst6 libxv1 libglu1-mesa libegl1-mesa
RUN python3 -m ensurepip --upgrade RUN pip install ipython jupyter jupyterlab
RUN pip3 install ipython jupyter jupyterlab
RUN cd /tmp && \ RUN cd /tmp && \
ARCH=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/) && \ ARCH=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/) && \
curl -L -o virtualgl.deb "https://github.com/VirtualGL/virtualgl/releases/download/3.1.1/virtualgl_3.1.1_$ARCH.deb" && \ curl -L -o virtualgl.deb "https://downloads.sourceforge.net/project/virtualgl/3.1/virtualgl_3.1_$ARCH.deb" && \
dpkg -i virtualgl.deb dpkg -i virtualgl.deb
RUN usermod -aG video batman
USER batman USER batman
RUN cd $HOME && \ RUN cd $HOME && \
+4 -10
View File
@@ -14,12 +14,11 @@
"force_color_prompt": "1" "force_color_prompt": "1"
}, },
"runArgs": [ "runArgs": [
"--volume=/dev:/dev",
"--volume=/tmp/.X11-unix:/tmp/.X11-unix", "--volume=/tmp/.X11-unix:/tmp/.X11-unix",
"--volume=${localWorkspaceFolder}/.devcontainer/.host/.Xauthority:/home/batman/.Xauthority", "--volume=${localWorkspaceFolder}/.devcontainer/.host/.Xauthority:/home/batman/.Xauthority",
"--volume=${localEnv:HOME}/.comma:/home/batman/.comma", "--volume=${localEnv:HOME}/.comma:/home/batman/.comma",
"--volume=${localEnv:HOME}/.azure:/home/batman/.azure",
"--volume=/tmp/comma_download_cache:/tmp/comma_download_cache", "--volume=/tmp/comma_download_cache:/tmp/comma_download_cache",
"--volume=/tmp/devcontainer_scons_cache:/tmp/scons_cache",
"--shm-size=1G", "--shm-size=1G",
"--add-host=host.docker.internal:host-gateway", // required to use host.docker.internal on linux "--add-host=host.docker.internal:host-gateway", // required to use host.docker.internal on linux
"--publish=0.0.0.0:8070-8079:8070-8079" // body ZMQ services "--publish=0.0.0.0:8070-8079:8070-8079" // body ZMQ services
@@ -30,9 +29,7 @@
"installOhMyZsh": false, "installOhMyZsh": false,
"upgradePackages": false, "upgradePackages": false,
"username": "batman" "username": "batman"
}, }
"ghcr.io/devcontainers-contrib/features/gh-cli:1": {},
"ghcr.io/devcontainers/features/azure-cli:1": {}
}, },
"containerUser": "batman", "containerUser": "batman",
"remoteUser": "batman", "remoteUser": "batman",
@@ -46,8 +43,5 @@
"lharri73.dbc" "lharri73.dbc"
] ]
} }
}, }
"mounts": [ }
"type=volume,source=scons_cache,target=/tmp/scons_cache"
]
}
+1 -1
View File
@@ -24,7 +24,7 @@ body:
id: os-version id: os-version
attributes: attributes:
label: OS Version label: OS Version
placeholder: Ubuntu 24.04 placeholder: Ubuntu 20.04
validations: validations:
required: true required: true
+1 -1
View File
@@ -8,7 +8,7 @@ assignees: ''
**Checklist** **Checklist**
- [ ] added entry to CAR in selfdrive/car/*/values.py and ran `selfdrive/car/docs.py` to generate new docs - [ ] added entry to CarInfo 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) - [ ] test route added to [routes.py](https://github.com/commaai/openpilot/blob/master/selfdrive/car/tests/routes.py)
- [ ] route with openpilot: - [ ] route with openpilot:
- [ ] route with stock system: - [ ] route with stock system:
+1 -1
View File
@@ -44,7 +44,7 @@ subaru:
tesla: tesla:
- changed-files: - changed-files:
- any-glob-to-all-files: 'selfdrive/car/tesla/*' - any-glob-to-all-files: 'selfdrive/car/telsa/*'
toyota: toyota:
- changed-files: - changed-files:
+1 -1
View File
@@ -44,7 +44,7 @@ Explain how you tested this bug fix.
**Checklist** **Checklist**
- [ ] added entry to CAR in selfdrive/car/*/values.py and ran `selfdrive/car/docs.py` to generate new docs - [ ] added entry to CarInfo 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) - [ ] test route added to [routes.py](https://github.com/commaai/openpilot/blob/master/selfdrive/car/tests/routes.py)
- [ ] route with openpilot: - [ ] route with openpilot:
- [ ] route with stock system: - [ ] route with stock system:
+4 -4
View File
@@ -19,14 +19,14 @@ runs:
using: "composite" using: "composite"
steps: steps:
- name: setup namespace cache - name: setup namespace cache
if: ${{ contains(runner.name, 'nsc') }} if: ${{ contains(runner.name, 'nsc') }}
uses: namespacelabs/nscloud-cache-action@v1 uses: namespacelabs/nscloud-cache-action@v1
with: with:
path: ${{ inputs.path }} path: ${{ inputs.path }}
- name: setup github cache - name: setup github cache
if: ${{ !contains(runner.name, 'nsc') && inputs.save != 'false' }} if: ${{ !contains(runner.name, 'nsc') && inputs.save != 'false' }}
uses: 'actions/cache@v4' uses: 'actions/cache@v3'
with: with:
path: ${{ inputs.path }} path: ${{ inputs.path }}
key: ${{ inputs.key }} key: ${{ inputs.key }}
@@ -34,7 +34,7 @@ runs:
- name: setup github cache - name: setup github cache
if: ${{ !contains(runner.name, 'nsc') && inputs.save == 'false' }} if: ${{ !contains(runner.name, 'nsc') && inputs.save == 'false' }}
uses: 'actions/cache/restore@v4' uses: 'actions/cache/restore@v3'
with: with:
path: ${{ inputs.path }} path: ${{ inputs.path }}
key: ${{ inputs.key }} key: ${{ inputs.key }}
@@ -46,4 +46,4 @@ runs:
run: | run: |
mkdir -p ${{ inputs.path }} mkdir -p ${{ inputs.path }}
sudo chmod -R 777 ${{ inputs.path }} sudo chmod -R 777 ${{ inputs.path }}
sudo chown -R $USER ${{ inputs.path }} sudo chown -R $USER ${{ inputs.path }}
+178 -24
View File
@@ -5,7 +5,7 @@ on:
jobs: jobs:
labeler: labeler:
name: review name: apply labels
permissions: permissions:
contents: read contents: read
pull-requests: write pull-requests: write
@@ -14,17 +14,17 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: false submodules: false
# Label PRs
- uses: actions/labeler@v5.0.0 - uses: actions/labeler@v5.0.0
with: with:
dot: true dot: true
configuration-path: .github/labeler.yaml configuration-path: .github/labeler.yaml
# Check PR target branch pr_branch_check:
- name: check branch name: check branch
uses: Vankka/pr-target-branch-action@def32ec9d93514138d6ac0132ee62e120a72aed5 runs-on: ubuntu-latest
if: github.repository == 'commaai/openpilot' if: github.repository == 'commaai/openpilot'
steps:
- uses: Vankka/pr-target-branch-action@69ab6dd5c221de3548b3b6c4d102c1f4913d3baa
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
@@ -34,20 +34,174 @@ jobs:
already-exists-action: close_this already-exists-action: close_this
already-exists-comment: "Your PR should be made against the `master` branch" already-exists-comment: "Your PR should be made against the `master` branch"
# Welcome comment check-pr-template:
- name: comment runs-on: ubuntu-latest
uses: thollander/actions-comment-pull-request@fabd468d3a1a0b97feee5f6b9e499eab0dd903f6 permissions:
if: github.event.pull_request.head.repo.full_name != 'commaai/openpilot' contents: read
with: issues: write
message: | pull-requests: write
<!-- _(run_id **${{ github.run_id }}**)_ --> actions: read
Thanks for contributing to openpilot! In order for us to review your PR as quickly as possible, check the following: if: github.event.pull_request.head.repo.full_name != 'commaai/openpilot'
* Convert your PR to a draft unless it's ready to review steps:
* Read the [contributing docs](https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md) - uses: actions/github-script@v7
* Before marking as "ready for review", ensure: with:
* the goal is clearly stated in the description script: |
* all the tests are passing // Comment to add to the PR if no template has been used
* the change is [something we merge](https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md#what-gets-merged) const NO_TEMPLATE_MESSAGE =
* include a route or your device' dongle ID if relevant "It looks like you didn't use one of the Pull Request templates. Please check [the contributing docs](https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md). \
comment_tag: run_id Also make sure that you didn't modify any of the checkboxes or headings within the template.";
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} // body data for future requests
const body_data = {
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
};
// Utility function to extract all headings
const extractHeadings = (markdown) => {
const headingRegex = /^(#{1,6})\s+(.+)$/gm;
const boldTextRegex = /^(?:\*\*|__)(.+?)(?:\*\*|__)\s*$/gm;
const headings = [];
let headingMatch;
while ((headingMatch = headingRegex.exec(markdown))) {
headings.push(headingMatch[2].trim());
}
let boldMatch;
while ((boldMatch = boldTextRegex.exec(markdown))) {
headings.push(boldMatch[1].trim());
}
return headings;
};
// Utility function to extract all check box descriptions
const extractCheckBoxTexts = (markdown) => {
const checkboxRegex = /^\s*-\s*\[( |x)\]\s+(.+)$/gm;
const checkboxes = [];
let match;
while ((match = checkboxRegex.exec(markdown))) {
checkboxes.push(match[2].trim());
}
return checkboxes;
};
// Utility function to check if a list is a subset of another list
isSubset = (subset, superset) => {
return subset.every((item) => superset.includes(item));
};
// Utility function to check if a list of checkboxes is a subset of another list of checkboxes
isCheckboxSubset = (templateCheckBoxTexts, prTextCheckBoxTexts) => {
// Check if each template checkbox text is a substring of at least one PR checkbox text
// (user should be allowed to add additional text)
return templateCheckBoxTexts.every((item) => prTextCheckBoxTexts.some((element) => element.includes(item)))
}
// Get filenames of all currently checked-in PR templates
const template_contents = await github.rest.repos.getContent({
owner: context.repo.owner,
repo: context.repo.repo,
path: ".github/PULL_REQUEST_TEMPLATE",
});
var template_filenames = [];
for (const content of template_contents.data) {
template_filenames.push(content.path);
}
console.debug("Received template filenames: " + template_filenames);
// Retrieve templates
var templates = [];
for (const template_filename of template_filenames) {
const template_response = await github.rest.repos.getContent({
owner: context.repo.owner,
repo: context.repo.repo,
path: template_filename,
});
// Convert Base64 content back
const decoded_template = atob(template_response.data.content);
const headings = extractHeadings(decoded_template);
const checkboxes = extractCheckBoxTexts(decoded_template);
if (!headings.length && !checkboxes.length) {
console.warn(
"Invalid template! Contains neither headings nor checkboxes, ignoring it: \n" +
decoded_template
);
} else {
templates.push({ headings: headings, checkboxes: checkboxes });
}
}
// Retrieve the PR Body
const pull_request = await github.rest.issues.get({
...body_data,
});
const pull_request_text = pull_request.data.body;
console.debug("Received Pull Request body: \n" + pull_request_text);
/* Check if the PR Body matches one of the templates
A template is defined by all headings and checkboxes it contains
We extract all Headings and Checkboxes from the PR text and check if any of the templates is a subset of that
*/
const pr_headings = extractHeadings(pull_request_text);
const pr_checkboxes = extractCheckBoxTexts(pull_request_text);
console.debug("Found Headings in PR body:\n" + pr_headings);
console.debug("Found Checkboxes in PR body:\n" + pr_checkboxes);
var template_found = false;
// Iterate over each template to check if it applies
for (const template of templates) {
console.log(
"Checking for headings: [" +
template.headings +
"] and checkboxes: [" +
template.checkboxes + "]"
);
if (
isCheckboxSubset(template.checkboxes, pr_checkboxes) &&
isSubset(template.headings, pr_headings)
) {
console.debug("Found matching template!");
template_found = true;
}
}
// List comments from previous runs
var existing_comments = [];
const comments = await github.rest.issues.listComments({
...body_data,
});
for (const comment of comments.data) {
if (comment.body === NO_TEMPLATE_MESSAGE) {
existing_comments.push(comment);
}
}
// Add a comment to the PR that it is not using a the template (but only if this comment does not exist already)
if (!template_found) {
var comment_already_sent = false;
// Add an 'in-bot-review' label since this PR doesn't have the template
github.rest.issues.addLabels({
...body_data,
labels: ["in-bot-review"],
});
if (existing_comments.length < 1) {
github.rest.issues.createComment({
...body_data,
body: NO_TEMPLATE_MESSAGE,
});
}
} else {
// If template has been found, delete any old comment about missing template
for (const existing_comment of existing_comments) {
github.rest.issues.deleteComment({
...body_data,
comment_id: existing_comment.id,
});
}
// Remove the 'in-bot-review' label after the review is done and the PR has passed
github.rest.issues.removeLabel({
...body_data,
name: "in-bot-review",
}).catch((error) => {
console.log("Label 'in-bot-review' not found, ignoring");
});
}
+2 -2
View File
@@ -7,12 +7,12 @@ on:
env: env:
BASE_IMAGE: openpilot-base BASE_IMAGE: openpilot-base
DOCKER_REGISTRY: ghcr.io/commaai DOCKER_REGISTRY: ghcr.io/commaai
RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -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 $DOCKER_REGISTRY/$BASE_IMAGE:latest /bin/bash -c RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -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 $DOCKER_REGISTRY/$BASE_IMAGE:latest /bin/bash -c
jobs: jobs:
badges: badges:
name: create badges name: create badges
runs-on: ubuntu-latest runs-on: ubuntu-20.04
if: github.repository == 'commaai/openpilot' if: github.repository == 'commaai/openpilot'
permissions: permissions:
contents: write contents: write
-101
View File
@@ -1,101 +0,0 @@
name: weekly CI test report
on:
schedule:
- cron: '37 9 * * 1' # 9:37AM UTC -> 2:37AM PST every monday
workflow_dispatch:
inputs:
ci_runs:
description: 'The amount of runs to trigger in CI test report'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CI_RUNS: ${{ github.event.inputs.ci_runs || '50' }}
jobs:
setup:
if: github.repository == 'commaai/openpilot'
runs-on: ubuntu-latest
outputs:
ci_runs: ${{ steps.ci_runs_setup.outputs.matrix }}
steps:
- id: ci_runs_setup
name: CI_RUNS=${{ env.CI_RUNS }}
run: |
matrix=$(python3 -c "import json; print(json.dumps({ 'run_number' : list(range(${{ env.CI_RUNS }})) }))")
echo "matrix=$matrix" >> $GITHUB_OUTPUT
ci_matrix_run:
needs: [ setup ]
strategy:
fail-fast: false
matrix: ${{fromJSON(needs.setup.outputs.ci_runs)}}
uses: commaai/openpilot/.github/workflows/ci_weekly_run.yaml@master
with:
run_number: ${{ matrix.run_number }}
report:
needs: [ci_matrix_run]
runs-on: ubuntu-latest
if: always()
steps:
- name: Get job results
uses: actions/github-script@v7
id: get-job-results
with:
script: |
const jobs = await github
.paginate("GET /repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt}/jobs", {
owner: "commaai",
repo: "${{ github.event.repository.name }}",
run_id: "${{ github.run_id }}",
attempt: "${{ github.run_attempt }}",
})
var report = {}
jobs.slice(1, jobs.length-1).forEach(job => {
if (job.conclusion === "skipped") return;
const jobName = job.name.split(" / ")[2];
const runRegex = /\((.*?)\)/;
const run = job.name.match(runRegex)[1];
report[jobName] = report[jobName] || { successes: [], failures: [], cancelled: [] };
switch (job.conclusion) {
case "success":
report[jobName].successes.push({ "run_number": run, "link": job.html_url}); break;
case "failure":
report[jobName].failures.push({ "run_number": run, "link": job.html_url }); break;
case "cancelled":
report[jobName].cancelled.push({ "run_number": run, "link": job.html_url }); break;
}
});
return JSON.stringify({"jobs": report});
- name: Add job results to summary
env:
JOB_RESULTS: ${{ fromJSON(steps.get-job-results.outputs.result) }}
run: |
cat <<EOF >> template.html
<table>
<thead>
<tr>
<th></th>
<th>Job</th>
<th>✅ Passing</th>
<th>❌ Failure Details</th>
</tr>
</thead>
<tbody>
{% for key in jobs.keys() %}<tr>
<td>{% for i in range(5) %}{% if i+1 <= (5 * jobs[key]["successes"]|length // ${{ env.CI_RUNS }}) %}🟩{% else %}🟥{% endif %}{% endfor%}</td>
<td>{{ key }}</td>
<td>{{ 100 * jobs[key]["successes"]|length // ${{ env.CI_RUNS }} }}%</td>
<td>{% if jobs[key]["failures"]|length > 0 %}<details>{% for failure in jobs[key]["failures"] %}<a href="{{ failure['link'] }}">Log for run #{{ failure['run_number'] }}</a><br>{% endfor %}</details>{% else %}{% endif %}</td>
</td>
</tr>{% endfor %}
</table>
EOF
pip install jinja2-cli
echo $JOB_RESULTS | jinja2 template.html > report.html
echo "# CI Test Report - ${{ env.CI_RUNS }} Runs" >> $GITHUB_STEP_SUMMARY
cat report.html >> $GITHUB_STEP_SUMMARY
-21
View File
@@ -1,21 +0,0 @@
name: weekly CI test run
on:
workflow_call:
inputs:
run_number:
required: true
type: string
concurrency:
group: ci-run-${{ inputs.run_number }}-${{ github.ref }}
cancel-in-progress: true
jobs:
selfdrive_tests:
uses: commaai/openpilot/.github/workflows/selfdrive_tests.yaml@master
with:
run_number: ${{ inputs.run_number }}
tools_tests:
uses: commaai/openpilot/.github/workflows/tools_tests.yaml@master
with:
run_number: ${{ inputs.run_number }}
-97
View File
@@ -1,97 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ "master", "*-c3", "master*" ]
pull_request:
branches: [ "master", "*-c3", "master*" ]
schedule:
- cron: '39 7 * * 2'
jobs:
analyze:
name: Analyze (${{ matrix.language }})
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
permissions:
# required for all workflows
security-events: write
# required to fetch internal or private CodeQL packs
packages: read
# only required for workflows in private repositories
actions: read
contents: read
strategy:
fail-fast: false
matrix:
include:
- language: c-cpp
build-mode: autobuild
- language: javascript-typescript
build-mode: none
- language: python
build-mode: none
# CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- if: matrix.build-mode == 'manual'
shell: bash
run: |
echo 'If you are using a "manual" build mode for one or more of the' \
'languages you are analyzing, replace this with the commands to build' \
'your code, for example:'
echo ' make bootstrap'
echo ' make release'
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
@@ -14,7 +14,7 @@ runs:
${{ env.RUN }} "rm -rf /tmp/scons_cache/* && \ ${{ env.RUN }} "rm -rf /tmp/scons_cache/* && \
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@v3
if: github.ref == 'refs/heads/master' if: github.ref == 'refs/heads/master'
with: with:
path: .ci_cache/scons_cache path: .ci_cache/scons_cache
+20 -20
View File
@@ -5,34 +5,35 @@ on:
branches: branches:
- master - master
pull_request: pull_request:
workflow_call:
inputs:
run_number:
default: '1'
required: true
type: string
concurrency: concurrency:
group: docs-tests-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }} group: ${{ 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:
BASE_IMAGE: openpilot-base
BUILD: selfdrive/test/docker_build.sh base
RUN: docker run --shm-size 1G -v $GITHUB_WORKSPACE:/tmp/openpilot -w /tmp/openpilot -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:
docs: docs:
name: build docs name: build docs
runs-on: ubuntu-latest runs-on: ubuntu-20.04
timeout-minutes: 1 timeout-minutes: 45
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: true submodules: true
- uses: ./.github/workflows/setup-with-retry
# Build - name: Build openpilot
run: |
${{ env.RUN }} "scons -j$(nproc)"
- name: Build docs - name: Build docs
run: | run: |
# TODO: can we install just the "docs" dependency group without the normal deps? ${{ env.RUN }} "apt update && apt install -y doxygen && cd docs && make -j$(nproc) html"
pip install mkdocs
mkdocs build
# Push to docs.comma.ai
- uses: actions/checkout@v4 - uses: actions/checkout@v4
if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot' if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot'
with: with:
@@ -47,17 +48,16 @@ jobs:
source release/identity.sh source release/identity.sh
cd openpilot-docs cd openpilot-docs
git checkout --orphan tmp git checkout --orphan tmp
git rm -rf . git rm -rf .
# copy over docs cp -r ../build/docs/html/ docs/
cp -r ../docs_site/ docs/ cp -r ../docs/README.md .
# GitHub pages config
touch docs/.nojekyll touch docs/.nojekyll
echo -n docs.comma.ai > docs/CNAME echo -n docs.comma.ai > docs/CNAME
git add -f . git add -f .
git commit -m "build docs" git commit -m "build docs"
# docs live in different repo to not bloat openpilot's full clone size # docs live in different repo to not bloat openpilot's full clone size
-45
View File
@@ -1,45 +0,0 @@
name: jenkins scan
on:
issue_comment:
types: [created, edited]
jobs:
# TODO: gc old branches in a separate job in this workflow
scan-comments:
runs-on: ubuntu-latest
if: ${{ github.event.issue.pull_request }}
steps:
- name: Check for trigger phrase
id: check_comment
uses: actions/github-script@v7
with:
script: |
const triggerPhrase = "trigger-jenkins";
const comment = context.payload.comment.body;
const commenter = context.payload.comment.user.login;
const { data: permissions } = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: commenter
});
const hasWriteAccess = permissions.permission === 'write' || permissions.permission === 'admin';
return (hasWriteAccess && comment.includes(triggerPhrase));
result-encoding: json
- name: Checkout repository
if: steps.check_comment.outputs.result == 'true'
uses: actions/checkout@v4
with:
ref: refs/pull/${{ github.event.issue.number }}/head
- name: Push to tmp-jenkins branch
if: steps.check_comment.outputs.result == 'true'
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git checkout -b tmp-jenkins-${{ github.event.issue.number }}
GIT_LFS_SKIP_PUSH=1 git push -f origin tmp-jenkins-${{ github.event.issue.number }}
-46
View File
@@ -1,46 +0,0 @@
name: Mirror to GitLab
on:
push:
delete:
workflow_dispatch: # This enables manual triggering
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Wait for other instances of this workflow to conclude
uses: softprops/turnstyle@8db075d65b19bf94e6e8687b504db69938dc3c65
with:
same-branch-only: 'true'
abort-after-seconds: 300
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Checkout Repository
uses: actions/checkout@v3
with:
ref: ${{ github.ref }}
fetch-depth: 0 # Fetch full history
- 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
# Note: If you have issues with "push rejected missing LFS" or something make sure you disabled LFS on the GITLAB repo if you intend to use a different LFS repo other than the target repo.
- name: Sync and commit changes
id: sync-and-commit
run: |
# Add GitLab remote
git remote add gitlab git@gitlab.com:sunnypilot/sunnyhaibin/sunnypilot-github-mirror.git
git push -u --force gitlab ${{ github.ref }}
+2 -2
View File
@@ -11,7 +11,7 @@ env:
jobs: jobs:
build_prebuilt: build_prebuilt:
name: build prebuilt name: build prebuilt
runs-on: ubuntu-latest runs-on: ubuntu-20.04
if: github.repository == 'commaai/openpilot' if: github.repository == 'commaai/openpilot'
env: env:
PUSH_IMAGE: true PUSH_IMAGE: true
@@ -22,7 +22,7 @@ jobs:
steps: steps:
- name: Wait for green check mark - name: Wait for green check mark
if: ${{ github.event_name != 'workflow_dispatch' }} if: ${{ github.event_name != 'workflow_dispatch' }}
uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc uses: lewagon/wait-on-check-action@595dabb3acf442d47e29c9ec9ba44db0c6bdd18f
with: with:
ref: master ref: master
wait-interval: 30 wait-interval: 30
+2 -2
View File
@@ -12,7 +12,7 @@ jobs:
ImageOS: ubuntu20 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-20.04
if: github.repository == 'commaai/openpilot' if: github.repository == 'commaai/openpilot'
permissions: permissions:
checks: read checks: read
@@ -24,7 +24,7 @@ jobs:
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 != 'workflow_dispatch' }} if: ${{ github.event_name != 'workflow_dispatch' }}
uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc uses: lewagon/wait-on-check-action@595dabb3acf442d47e29c9ec9ba44db0c6bdd18f
with: with:
ref: master ref: master
wait-interval: 30 wait-interval: 30
+13 -12
View File
@@ -8,7 +8,7 @@ on:
jobs: jobs:
bump_submodules: bump_submodules:
name: bump_submodules name: bump_submodules
runs-on: ubuntu-latest runs-on: ubuntu-20.04
container: container:
image: ghcr.io/commaai/openpilot-base:latest image: ghcr.io/commaai/openpilot-base:latest
if: github.repository == 'commaai/openpilot' if: github.repository == 'commaai/openpilot'
@@ -22,9 +22,8 @@ jobs:
git -c submodule."tinygrad".update=none submodule update --remote git -c submodule."tinygrad".update=none submodule update --remote
git add . git add .
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@9153d834b60caba6d51c9b9510b087acf9f33f83 uses: peter-evans/create-pull-request@5b4a9f6a9e2af26e5f02351490b90d01eb8ec1e5
with: with:
author: Vehicle Researcher <user@comma.ai>
token: ${{ secrets.ACTIONS_CREATE_PR_PAT }} token: ${{ secrets.ACTIONS_CREATE_PR_PAT }}
commit-message: bump submodules commit-message: bump submodules
title: '[bot] Bump submodules' title: '[bot] Bump submodules'
@@ -35,24 +34,26 @@ jobs:
labels: bot labels: bot
package_updates: package_updates:
name: package_updates name: package_updates
runs-on: ubuntu-latest runs-on: ubuntu-20.04
container: container:
image: ghcr.io/commaai/openpilot-base:latest image: ghcr.io/commaai/openpilot-base:latest
if: github.repository == 'commaai/openpilot' if: github.repository == 'commaai/openpilot'
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: uv lock - name: poetry lock
run: | run: |
python3 -m ensurepip --upgrade pip install poetry
pip3 install uv poetry lock
uv lock --upgrade - name: pre-commit autoupdate
run: |
git config --global --add safe.directory '*'
pre-commit autoupdate
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@9153d834b60caba6d51c9b9510b087acf9f33f83 uses: peter-evans/create-pull-request@5b4a9f6a9e2af26e5f02351490b90d01eb8ec1e5
with: with:
author: Vehicle Researcher <user@comma.ai>
token: ${{ secrets.ACTIONS_CREATE_PR_PAT }} token: ${{ secrets.ACTIONS_CREATE_PR_PAT }}
commit-message: Update Python packages commit-message: Update Python packages and pre-commit hooks
title: '[bot] Update Python packages' title: '[bot] Update Python packages and pre-commit hooks'
branch: auto-package-updates branch: auto-package-updates
base: master base: master
delete-branch: true delete-branch: true
+132 -87
View File
@@ -6,15 +6,9 @@ on:
- master - master
pull_request: pull_request:
workflow_dispatch: workflow_dispatch:
workflow_call:
inputs:
run_number:
default: '1'
required: true
type: string
concurrency: concurrency:
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 }} group: ${{ 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:
@@ -25,16 +19,14 @@ env:
DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
BUILD: selfdrive/test/docker_build.sh 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 RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PRE_COMMIT_HOME=/tmp/pre-commit -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/pre-commit:/tmp/pre-commit -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
PYTEST: pytest --continue-on-collection-errors --cov --cov-report=xml --cov-append --durations=0 --durations-min=5 --hypothesis-seed 0 -n logical PYTEST: pytest --continue-on-collection-errors --cov --cov-report=xml --cov-append --durations=0 --durations-min=5 --hypothesis-seed 0 -n logical
jobs: jobs:
build_release: build_release:
name: build release name: build release
runs-on: ${{ ((github.repository == 'commaai/openpilot') && runs-on: ubuntu-20.04
((github.event_name != 'pull_request') ||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-latest' }}
env: env:
STRIPPED_DIR: /tmp/releasepilot STRIPPED_DIR: /tmp/releasepilot
steps: steps:
@@ -45,6 +37,7 @@ jobs:
- name: Build devel - name: Build devel
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-pre-commit
- uses: ./.github/workflows/setup-with-retry - uses: ./.github/workflows/setup-with-retry
- name: Check submodules - name: Check submodules
if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot' if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot'
@@ -54,35 +47,53 @@ jobs:
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: |
cd $STRIPPED_DIR cd $STRIPPED_DIR
${{ env.RUN }} "python system/manager/build.py" ${{ env.RUN }} "python selfdrive/manager/build.py"
- name: Run tests - name: Run tests
timeout-minutes: 3 timeout-minutes: 3
run: | run: |
cd $STRIPPED_DIR cd $STRIPPED_DIR
${{ env.RUN }} "release/check-dirty.sh && \ ${{ env.RUN }} "release/check-dirty.sh && \
MAX_EXAMPLES=5 $PYTEST -m 'not slow' selfdrive/car" MAX_EXAMPLES=5 $PYTEST selfdrive/car"
- name: static analysis - name: pre-commit
timeout-minutes: 1 timeout-minutes: 3
run: | run: |
cd $GITHUB_WORKSPACE cd $GITHUB_WORKSPACE
cp .pre-commit-config.yaml $STRIPPED_DIR
cp pyproject.toml $STRIPPED_DIR cp pyproject.toml $STRIPPED_DIR
cp poetry.lock $STRIPPED_DIR
cd $STRIPPED_DIR cd $STRIPPED_DIR
${{ env.RUN }} "scripts/lint.sh" ${{ env.RUN }} "unset PYTHONWARNINGS && SKIP=check-added-large-files pre-commit run --all && chmod -R 777 /tmp/pre-commit"
build: build:
strategy: strategy:
matrix: matrix:
arch: ${{ fromJson( arch: ${{ fromJson(
((github.repository == 'commaai/openpilot') && ((github.repository == 'commaai/openpilot') &&
((github.event_name != 'pull_request') || ((github.event_name != 'pull_request') ||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && '["x86_64", "aarch64"]' || '["x86_64"]' ) }} (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && '["x86_64", "aarch64"]' || '["x86_64"]' ) }}
runs-on: ${{ (matrix.arch == 'aarch64') && 'namespace-profile-arm64-2x8' || 'ubuntu-latest' }} runs-on: ${{ (matrix.arch == 'aarch64') && 'namespace-profile-arm64-2x8' || 'ubuntu-20.04' }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: true submodules: true
- name: Setup docker push - uses: ./.github/workflows/setup-with-retry
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' with:
docker_hub_pat: ${{ secrets.DOCKER_HUB_PAT }}
- uses: ./.github/workflows/compile-openpilot
timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 15 || 30) }} # allow more time when we missed the scons cache
docker_push:
name: docker push
strategy:
matrix:
arch: ${{ fromJson( (github.repository == 'commaai/openpilot') && '["x86_64", "aarch64"]' || '["x86_64"]' ) }}
runs-on: ${{ (matrix.arch == 'aarch64') && 'namespace-profile-arm64-2x8' || 'ubuntu-20.04' }}
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot'
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Setup to push to repo
run: | run: |
echo "PUSH_IMAGE=true" >> "$GITHUB_ENV" echo "PUSH_IMAGE=true" >> "$GITHUB_ENV"
echo "TARGET_ARCHITECTURE=${{ matrix.arch }}" >> "$GITHUB_ENV" echo "TARGET_ARCHITECTURE=${{ matrix.arch }}" >> "$GITHUB_ENV"
@@ -90,39 +101,12 @@ jobs:
- uses: ./.github/workflows/setup-with-retry - uses: ./.github/workflows/setup-with-retry
with: with:
docker_hub_pat: ${{ secrets.DOCKER_HUB_PAT }} docker_hub_pat: ${{ secrets.DOCKER_HUB_PAT }}
- uses: ./.github/workflows/compile-openpilot
timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 15 || 30) }} # allow more time when we missed the scons cache
build_mac:
name: build macOS
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- run: git lfs pull
- name: Install dependencies
run: ./tools/mac_setup.sh
env:
# package install has DeprecationWarnings
PYTHONWARNINGS: default
- run: echo "CACHE_COMMIT_DATE=$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M')" >> $GITHUB_ENV
- name: Getting scons cache
uses: 'actions/cache@v4'
with:
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
run: . .venv/bin/activate && scons -j$(nproc)
docker_push_multiarch: docker_push_multiarch:
name: docker push multiarch tag name: docker push multiarch tag
runs-on: ubuntu-latest runs-on: ubuntu-20.04
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot'
needs: [build] needs: [docker_push]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
@@ -138,8 +122,21 @@ jobs:
static_analysis: static_analysis:
name: static analysis name: static analysis
runs-on: ${{ ((github.repository == 'commaai/openpilot') && runs-on: ${{ ((github.repository == 'commaai/openpilot') &&
((github.event_name != 'pull_request') || ((github.event_name != 'pull_request') ||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-latest' }} (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-20.04' }}
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/workflows/setup-pre-commit
- uses: ./.github/workflows/setup-with-retry
- name: pre-commit
timeout-minutes: 4
run: ${{ env.RUN }} "unset PYTHONWARNINGS && pre-commit run --all && chmod -R 777 /tmp/pre-commit"
valgrind:
name: valgrind
runs-on: ubuntu-20.04
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
@@ -147,15 +144,19 @@ jobs:
- uses: ./.github/workflows/setup-with-retry - uses: ./.github/workflows/setup-with-retry
- name: Build openpilot - name: Build openpilot
run: ${{ env.RUN }} "scons -j$(nproc)" run: ${{ env.RUN }} "scons -j$(nproc)"
- name: static analysis - name: Run valgrind
timeout-minutes: 1 timeout-minutes: 1
run: ${{ env.RUN }} "scripts/lint.sh" run: |
${{ env.RUN }} "python selfdrive/test/test_valgrind_replay.py"
- name: Print logs
if: always()
run: cat selfdrive/test/valgrind_logs.txt
unit_tests: unit_tests:
name: unit tests name: unit tests
runs-on: ${{ ((github.repository == 'commaai/openpilot') && runs-on: ${{ ((github.repository == 'commaai/openpilot') &&
((github.event_name != 'pull_request') || ((github.event_name != 'pull_request') ||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-latest' }} (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-20.04' }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
@@ -174,9 +175,9 @@ jobs:
$PYTEST --timeout 60 -m 'not slow' && \ $PYTEST --timeout 60 -m 'not slow' && \
./selfdrive/ui/tests/create_test_translations.sh && \ ./selfdrive/ui/tests/create_test_translations.sh && \
QT_QPA_PLATFORM=offscreen ./selfdrive/ui/tests/test_translations && \ QT_QPA_PLATFORM=offscreen ./selfdrive/ui/tests/test_translations && \
pytest ./selfdrive/ui/tests/test_translations.py" ./selfdrive/ui/tests/test_translations.py"
- name: "Upload coverage to Codecov" - name: "Upload coverage to Codecov"
uses: codecov/codecov-action@v4 uses: codecov/codecov-action@v3
with: with:
name: ${{ github.job }} name: ${{ github.job }}
env: env:
@@ -185,8 +186,8 @@ jobs:
process_replay: process_replay:
name: process replay name: process replay
runs-on: ${{ ((github.repository == 'commaai/openpilot') && runs-on: ${{ ((github.repository == 'commaai/openpilot') &&
((github.event_name != 'pull_request') || ((github.event_name != 'pull_request') ||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-latest' }} (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-20.04' }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
@@ -196,10 +197,10 @@ jobs:
docker_hub_pat: ${{ secrets.DOCKER_HUB_PAT }} docker_hub_pat: ${{ secrets.DOCKER_HUB_PAT }}
- name: Cache test routes - name: Cache test routes
id: dependency-cache id: dependency-cache
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: .ci_cache/comma_download_cache path: .ci_cache/comma_download_cache
key: proc-replay-${{ hashFiles('.github/workflows/selfdrive_tests.yaml', 'selfdrive/test/process_replay/ref_commit', 'selfdrive/test/process_replay/test_regen.py') }} key: proc-replay-${{ hashFiles('.github/workflows/selfdrive_tests.yaml', 'selfdrive/test/process_replay/ref_commit') }}
- name: Build openpilot - name: Build openpilot
run: | run: |
${{ env.RUN }} "scons -j$(nproc)" ${{ env.RUN }} "scons -j$(nproc)"
@@ -214,7 +215,7 @@ jobs:
id: print-diff id: print-diff
if: always() if: always()
run: cat selfdrive/test/process_replay/diff.txt run: cat selfdrive/test/process_replay/diff.txt
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v3
if: always() if: always()
continue-on-error: true continue-on-error: true
with: with:
@@ -224,20 +225,66 @@ jobs:
if: ${{ failure() && steps.print-diff.outcome == 'success' && github.repository == 'commaai/openpilot' && env.AZURE_TOKEN != '' }} if: ${{ failure() && steps.print-diff.outcome == 'success' && github.repository == 'commaai/openpilot' && env.AZURE_TOKEN != '' }}
run: | run: |
${{ env.RUN }} "unset PYTHONWARNINGS && AZURE_TOKEN='$AZURE_TOKEN' python selfdrive/test/process_replay/test_processes.py -j$(nproc) --upload-only" ${{ env.RUN }} "unset PYTHONWARNINGS && AZURE_TOKEN='$AZURE_TOKEN' python selfdrive/test/process_replay/test_processes.py -j$(nproc) --upload-only"
- name: "Upload coverage to Codecov"
uses: codecov/codecov-action@v3
with:
name: ${{ github.job }}
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
regen:
name: regen
runs-on: 'ubuntu-20.04'
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/workflows/setup-with-retry
- name: Cache test routes
id: dependency-cache
uses: actions/cache@v3
with:
path: .ci_cache/comma_download_cache
key: regen-${{ hashFiles('.github/workflows/selfdrive_tests.yaml', 'selfdrive/test/process_replay/test_regen.py') }}
- name: Build base Docker image
run: eval "$BUILD"
- name: Build openpilot
run: |
${{ env.RUN }} "scons -j$(nproc)"
- name: Run regen
timeout-minutes: 30
run: |
${{ env.RUN }} "ONNXCPU=1 $PYTEST selfdrive/test/process_replay/test_regen.py && \
chmod -R 777 /tmp/comma_download_cache"
test_modeld:
name: model tests
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/workflows/setup-with-retry
- name: Build base Docker image
run: eval "$BUILD"
- name: Build openpilot
run: |
${{ env.RUN }} "scons -j$(nproc)"
# PYTHONWARNINGS triggers a SyntaxError in onnxruntime # PYTHONWARNINGS triggers a SyntaxError in onnxruntime
- name: Run model replay with ONNX - name: Run model replay with ONNX
timeout-minutes: 4 timeout-minutes: 4
run: | run: |
${{ env.RUN }} "unset PYTHONWARNINGS && \ ${{ env.RUN }} "unset PYTHONWARNINGS && \
ONNXCPU=1 NO_NAV=1 coverage run selfdrive/test/process_replay/model_replay.py && \ ONNXCPU=1 NO_NAV=1 coverage run selfdrive/test/process_replay/model_replay.py && \
coverage combine && coverage xml" coverage combine && \
- name: Run regen coverage xml"
- name: Run unit tests
timeout-minutes: 4 timeout-minutes: 4
run: | run: |
${{ env.RUN }} "ONNXCPU=1 $PYTEST selfdrive/test/process_replay/test_regen.py && \ ${{ env.RUN }} "unset PYTHONWARNINGS && \
chmod -R 777 /tmp/comma_download_cache" $PYTEST selfdrive/modeld"
- name: "Upload coverage to Codecov" - name: "Upload coverage to Codecov"
uses: codecov/codecov-action@v4 uses: codecov/codecov-action@v3
with: with:
name: ${{ github.job }} name: ${{ github.job }}
env: env:
@@ -246,12 +293,12 @@ jobs:
test_cars: test_cars:
name: cars name: cars
runs-on: ${{ ((github.repository == 'commaai/openpilot') && runs-on: ${{ ((github.repository == 'commaai/openpilot') &&
((github.event_name != 'pull_request') || ((github.event_name != 'pull_request') ||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-latest' }} (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-20.04' }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
job: [0, 1] job: [0, 1, 2, 3, 4]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
@@ -266,15 +313,15 @@ jobs:
- 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: 20 timeout-minutes: 10
run: | run: |
${{ env.RUN }} "$PYTEST selfdrive/car/tests/test_models.py && \ ${{ env.RUN }} "$PYTEST selfdrive/car/tests/test_models.py && \
chmod -R 777 /tmp/comma_download_cache" chmod -R 777 /tmp/comma_download_cache"
env: env:
NUM_JOBS: 2 NUM_JOBS: 5
JOB_ID: ${{ matrix.job }} JOB_ID: ${{ matrix.job }}
- name: "Upload coverage to Codecov" - name: "Upload coverage to Codecov"
uses: codecov/codecov-action@v4 uses: codecov/codecov-action@v3
with: with:
name: ${{ github.job }}-${{ matrix.job }} name: ${{ github.job }}-${{ matrix.job }}
env: env:
@@ -282,7 +329,7 @@ jobs:
car_docs_diff: car_docs_diff:
name: PR comments name: PR comments
runs-on: ubuntu-latest runs-on: ubuntu-20.04
if: github.event_name == 'pull_request' if: github.event_name == 'pull_request'
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -293,7 +340,7 @@ jobs:
- uses: ./.github/workflows/setup-with-retry - uses: ./.github/workflows/setup-with-retry
- name: Get base car info - name: Get base car info
run: | run: |
${{ env.RUN }} "scons -j$(nproc) && python selfdrive/debug/dump_car_docs.py --path /tmp/openpilot_cache/base_car_docs" ${{ env.RUN }} "scons -j$(nproc) && python selfdrive/debug/dump_car_info.py --path /tmp/openpilot_cache/base_car_info"
sudo chown -R $USER:$USER ${{ github.workspace }} sudo chown -R $USER:$USER ${{ github.workspace }}
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
@@ -305,19 +352,19 @@ jobs:
run: | run: |
cd current cd current
${{ env.RUN }} "scons -j$(nproc)" ${{ env.RUN }} "scons -j$(nproc)"
output=$(${{ env.RUN }} "python selfdrive/debug/print_docs_diff.py --path /tmp/openpilot_cache/base_car_docs") output=$(${{ env.RUN }} "python selfdrive/debug/print_docs_diff.py --path /tmp/openpilot_cache/base_car_info")
output="${output//$'\n'/'%0A'}" output="${output//$'\n'/'%0A'}"
echo "::set-output name=diff::$output" echo "::set-output name=diff::$output"
- name: Find comment - name: Find comment
if: ${{ env.AZURE_TOKEN != '' }} if: ${{ env.AZURE_TOKEN != '' }}
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e uses: peter-evans/find-comment@1769778a0c5bd330272d749d12c036d65e70d39d
id: fc id: fc
with: with:
issue-number: ${{ github.event.pull_request.number }} issue-number: ${{ github.event.pull_request.number }}
body-includes: This PR makes changes to body-includes: This PR makes changes to
- name: Update comment - name: Update comment
if: ${{ steps.save_diff.outputs.diff != '' && env.AZURE_TOKEN != '' }} if: ${{ steps.save_diff.outputs.diff != '' && env.AZURE_TOKEN != '' }}
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 uses: peter-evans/create-or-update-comment@b95e16d2859ad843a14218d1028da5b2c4cbc4b4
with: with:
comment-id: ${{ steps.fc.outputs.comment-id }} comment-id: ${{ steps.fc.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }} issue-number: ${{ github.event.pull_request.number }}
@@ -325,7 +372,7 @@ jobs:
edit-mode: replace edit-mode: replace
- name: Delete comment - name: Delete comment
if: ${{ steps.fc.outputs.comment-id != '' && steps.save_diff.outputs.diff == '' && env.AZURE_TOKEN != '' }} if: ${{ steps.fc.outputs.comment-id != '' && steps.save_diff.outputs.diff == '' && env.AZURE_TOKEN != '' }}
uses: actions/github-script@v7 uses: actions/github-script@v6
with: with:
script: | script: |
github.rest.issues.deleteComment({ github.rest.issues.deleteComment({
@@ -335,10 +382,8 @@ jobs:
}) })
create_ui_report: create_ui_report:
# 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: ubuntu-latest runs-on: ubuntu-20.04
if: github.event_name == 'pull_request'
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
@@ -350,10 +395,10 @@ jobs:
run: > run: >
${{ env.RUN }} "PYTHONWARNINGS=ignore && ${{ env.RUN }} "PYTHONWARNINGS=ignore &&
source selfdrive/test/setup_xvfb.sh && source selfdrive/test/setup_xvfb.sh &&
export MAPBOX_TOKEN='pk.eyJ1Ijoiam5ld2IiLCJhIjoiY2xxNW8zZXprMGw1ZzJwbzZneHd2NHljbSJ9.gV7VPRfbXFetD-1OVF0XZg' && export MAPBOX_TOKEN='pk.eyJ1Ijoiam5ld2IiLCJhIjoiY2xxNW8zZXprMGw1ZzJwbzZneHd2NHljbSJ9.gV7VPRfbXFetD-1OVF0XZg' &&
python selfdrive/ui/tests/test_ui/run.py" python selfdrive/ui/tests/test_ui/run.py"
- name: Upload Test Report - name: Upload Test Report
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v2
with: with:
name: report-${{ github.event.number }} name: report
path: selfdrive/ui/tests/test_ui/report_1/screenshots path: selfdrive/ui/tests/test_ui/report
@@ -0,0 +1,12 @@
name: 'set up pre-commit environment'
runs:
using: "composite"
steps:
- uses: ./.github/workflows/auto-cache
with:
path: .ci_cache/pre-commit
key: pre-commit-${{ hashFiles('**/.pre-commit-config.yaml') }}
restore-keys: |
pre-commit-
save: ${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' }}
+1 -1
View File
@@ -60,4 +60,4 @@ runs:
find . -type f -not -executable -not -perm 644 -exec chmod 644 {} \; find . -type f -not -executable -not -perm 644 -exec chmod 644 {} \;
# build our docker image # build our docker image
- shell: bash - shell: bash
run: eval ${{ env.BUILD }} run: eval ${{ env.BUILD }}
+5 -6
View File
@@ -5,23 +5,22 @@ on:
workflow_dispatch: workflow_dispatch:
env: env:
DAYS_BEFORE_PR_CLOSE: 2 DAYS_BEFORE_PR_CLOSE: 7
DAYS_BEFORE_PR_STALE: 9 DAYS_BEFORE_PR_STALE: 30
jobs: jobs:
stale: stale:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/stale@v9 - uses: actions/stale@v8
with: with:
exempt-all-milestones: true exempt-milestones: true
# pull request config # pull request config
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
delete-branch: ${{ github.event.pull_request.head.repo.full_name == 'commaai/openpilot' }} # 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,car port,car" # if wip or it needs testing from the community, don't mark as stale exempt-pr-labels: "ignore stale,needs testing,car port" # 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 }}
+45 -46
View File
@@ -5,14 +5,9 @@ on:
branches: branches:
- master - master
pull_request: pull_request:
workflow_call:
inputs:
run_number:
default: '1'
required: true
type: string
concurrency: concurrency:
group: tools-tests-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }} group: ${{ 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:
@@ -21,59 +16,45 @@ env:
BUILD: selfdrive/test/docker_build.sh base BUILD: selfdrive/test/docker_build.sh base
RUN: docker run --shm-size 2G -v $GITHUB_WORKSPACE:/tmp/openpilot -w /tmp/openpilot -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 RUN: docker run --shm-size 1G -v $GITHUB_WORKSPACE:/tmp/openpilot -w /tmp/openpilot -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:
simulator_driving: plotjuggler:
name: simulator driving name: plotjuggler
runs-on: ubuntu-latest runs-on: ubuntu-20.04
timeout-minutes: 20 timeout-minutes: 45
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: true submodules: true
- uses: ./.github/workflows/setup-with-retry - uses: ./.github/workflows/setup-with-retry
- name: Build openpilot - name: Build openpilot
timeout-minutes: 5
run: ${{ env.RUN }} "scons -j$(nproc) cereal/ common/ --minimal"
- name: Test PlotJuggler
timeout-minutes: 2
run: | run: |
${{ env.RUN }} "scons -j$(nproc)" ${{ env.RUN }} "pytest tools/plotjuggler/"
- name: Run bridge test
run: |
${{ env.RUN }} "export MAPBOX_TOKEN='pk.eyJ1Ijoiam5ld2IiLCJhIjoiY2xxNW8zZXprMGw1ZzJwbzZneHd2NHljbSJ9.gV7VPRfbXFetD-1OVF0XZg' && \
source selfdrive/test/setup_xvfb.sh && \
source selfdrive/test/setup_vsound.sh && \
CI=1 pytest tools/sim/tests/test_metadrive_bridge.py"
test_compatibility: simulator:
name: test 20.04 + 3.11 name: simulator
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
if: github.repository == 'commaai/openpilot'
timeout-minutes: 45
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: true submodules: true
- name: Installing ubuntu dependencies - uses: ./.github/workflows/setup-with-retry
run: INSTALL_EXTRA_PACKAGES=no tools/install_ubuntu_dependencies.sh - name: Setup to push to repo
- name: Installing python if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot'
uses: actions/setup-python@v5 run: |
with: echo "PUSH_IMAGE=true" >> "$GITHUB_ENV"
python-version: '3.11.4' $DOCKER_LOGIN
- name: Installing pip - name: Build and push sim image
run: pip install pip==24.0 run: |
- name: Installing uv selfdrive/test/docker_build.sh sim
run: pip install uv
- name: git LFS
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
uses: 'actions/cache@v4'
with:
path: /tmp/scons_cache
key: scons-${{ runner.arch }}-ubuntu2004-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
restore-keys: |
scons-${{ runner.arch }}-ubuntu2004-${{ env.CACHE_COMMIT_DATE }}
scons-${{ runner.arch }}-ubuntu2004
- name: Building openpilot
run: uv run scons -u -j$(nproc)
devcontainer: devcontainer:
name: devcontainer name: devcontainer
@@ -89,7 +70,7 @@ jobs:
- name: Setup Dev Container CLI - name: Setup Dev Container CLI
run: npm install -g @devcontainers/cli run: npm install -g @devcontainers/cli
- name: Build dev container image - name: Build dev container image
run: ./scripts/retry.sh devcontainer build --workspace-folder . run: devcontainer build --workspace-folder .
- name: Run dev container - name: Run dev container
run: | run: |
mkdir -p /tmp/devcontainer_scons_cache/ mkdir -p /tmp/devcontainer_scons_cache/
@@ -98,6 +79,24 @@ jobs:
- name: Test environment - name: Test environment
run: | run: |
devcontainer exec --workspace-folder . scons -j$(nproc) cereal/ common/ devcontainer exec --workspace-folder . scons -j$(nproc) cereal/ common/
devcontainer exec --workspace-folder . pip3 install pip-install-test devcontainer exec --workspace-folder . pip install pip-install-test
devcontainer exec --workspace-folder . touch /home/batman/.comma/auth.json devcontainer exec --workspace-folder . touch /home/batman/.comma/auth.json
devcontainer exec --workspace-folder . sudo touch /root/test.txt devcontainer exec --workspace-folder . sudo touch /root/test.txt
notebooks:
name: notebooks
runs-on: ubuntu-20.04
if: github.repository == 'commaai/openpilot'
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/workflows/setup-with-retry
- name: Build openpilot
timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 10 || 30) }} # allow more time when we missed the scons cache
run: ${{ env.RUN }} "scons -j$(nproc)"
- name: Test notebooks
timeout-minutes: 3
run: |
${{ env.RUN }} "pip install nbmake && pytest --nbmake tools/car_porting/examples/"
-91
View File
@@ -1,91 +0,0 @@
name: "ui preview"
on:
pull_request_target:
types: [assigned, opened, synchronize, reopened, edited]
branches:
- 'master'
paths:
- 'selfdrive/ui/**'
env:
UI_JOB_NAME: "Create UI Report"
jobs:
preview:
if: github.repository == 'commaai/openpilot'
name: preview
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
pull-requests: write
actions: read
steps:
- name: Waiting for ui test to start
run: sleep 30
- name: Wait for ui report
uses: lewagon/wait-on-check-action@v1.3.4
with:
ref: ${{ github.event.pull_request.head.sha }}
check-name: ${{ env.UI_JOB_NAME }}
repo-token: ${{ secrets.GITHUB_TOKEN }}
allowed-conclusions: success
wait-interval: 20
- name: Get workflow run ID
id: get_run_id
run: |
echo "run_id=$(curl https://api.github.com/repos/${{ github.repository }}/commits/${{ github.event.pull_request.head.sha }}/check-runs | jq -r '.check_runs[] | select(.name == "${{ env.UI_JOB_NAME }}") | .html_url | capture("(?<number>[0-9]+)") | .number')" >> $GITHUB_OUTPUT
- name: Checkout ci-artifacts
uses: actions/checkout@v4
with:
repository: commaai/ci-artifacts
ssh-key: ${{ secrets.CI_ARTIFACTS_DEPLOY_KEY }}
path: ${{ github.workspace }}/ci-artifacts
ref: master
- name: Download artifact
id: download-artifact
uses: dawidd6/action-download-artifact@v6
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
run_id: ${{ steps.get_run_id.outputs.run_id }}
search_artifacts: true
name: report-${{ github.event.number }}
path: ${{ github.workspace }}/ci-artifacts
- name: Push Screenshots
working-directory: ${{ github.workspace }}/ci-artifacts
run: |
git checkout -b openpilot/pr-${{ github.event.number }}
git config user.name "GitHub Actions Bot"
git config user.email "<>"
git add ${{ github.workspace }}/ci-artifacts/*
git commit -m "screenshots for PR #${{ github.event.number }}"
git push origin openpilot/pr-${{ github.event.number }} --force
- name: Comment Screenshots on PR
uses: thollander/actions-comment-pull-request@v2
with:
message: |
<!-- _(run_id_screenshots **${{ github.run_id }}**)_ -->
## UI Screenshots
<table>
<tr>
<td><img src="https://raw.githubusercontent.com/commaai/ci-artifacts/openpilot/pr-${{ github.event.number }}/homescreen.png"></td>
<td><img src="https://raw.githubusercontent.com/commaai/ci-artifacts/openpilot/pr-${{ github.event.number }}/onroad.png"></td>
</tr>
<tr>
<td><img src="https://raw.githubusercontent.com/commaai/ci-artifacts/openpilot/pr-${{ github.event.number }}/onroad_map.png"></td>
<td><img src="https://raw.githubusercontent.com/commaai/ci-artifacts/openpilot/pr-${{ github.event.number }}/onroad_sidebar.png"></td>
</tr>
<tr>
<td><img src="https://raw.githubusercontent.com/commaai/ci-artifacts/openpilot/pr-${{ github.event.number }}/settings_network.png"></td>
<td><img src="https://raw.githubusercontent.com/commaai/ci-artifacts/openpilot/pr-${{ github.event.number }}/settings_device.png"></td>
</tr>
</table>
comment_tag: run_id_screenshots
pr_number: ${{ github.event.number }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+6 -25
View File
@@ -14,8 +14,6 @@ model2.png
a.out a.out
.hypothesis .hypothesis
/docs_site/
*.dylib *.dylib
*.DSYM *.DSYM
*.d *.d
@@ -42,10 +40,8 @@ compile_commands.json
compare_runtime*.html compare_runtime*.html
persist persist
selfdrive/pandad/pandad board/obj/
cereal/services.h selfdrive/boardd/boardd
cereal/gen
cereal/messaging/bridge
selfdrive/logcatd/logcatd selfdrive/logcatd/logcatd
selfdrive/mapd/default_speeds_by_region.json selfdrive/mapd/default_speeds_by_region.json
system/proclogd/proclogd system/proclogd/proclogd
@@ -60,8 +56,12 @@ selfdrive/modeld/_navmodeld
selfdrive/modeld/_dmonitoringmodeld selfdrive/modeld/_dmonitoringmodeld
/src/ /src/
one
notebooks notebooks
xx
yy
hyperthneed hyperthneed
panda_jungle
provisioning provisioning
.coverage* .coverage*
@@ -87,22 +87,3 @@ build/
poetry.toml poetry.toml
Pipfile Pipfile
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide
-240
View File
@@ -1,240 +0,0 @@
variables:
BUILD_DIR: "/data/openpilot"
OUTPUT_DIR: "${CI_PROJECT_DIR}/output"
CI_DIR: "${CI_PROJECT_DIR}/release/ci"
VERSION: 'echo $(date "+%Y.%m.%d")'
GIT_SUBMODULE_STRATEGY: recursive
GIT_DISCOVERY_ACROSS_FILESYSTEM: 1
DEV_C3_SOURCE_BRANCH: "master-dev-c3"
GIT_CONFIG_USER_EMAIL: "gitlab@pipeline.com"
GIT_CONFIG_USER_NAME: "Gitlab Pipeline"
PUBLIC_REPO_URL: "https://github.com/sunnyhaibin/sunnypilot"
BASE_BUILD_NUMER: 3000
EXTRA_VERSION_IDENTIFIER: "${CI_PIPELINE_IID}"
NEW_BRANCH: ${CI_COMMIT_REF_NAME}-prebuilt
stages:
- build
- sanity
- publish
- notify
default:
retry: 2
tags:
- sunnypilot
- x86
.default_before_script: &default_before_script
- 'if [ "$EXTRA_VERSION_IDENTIFIER" = "$CI_PIPELINE_IID" ]; then export EXTRA_VERSION_IDENTIFIER=$((CI_PIPELINE_IID + BASE_BUILD_NUMER)); fi'
- 'export VERSION=$(eval $VERSION)-${EXTRA_VERSION_IDENTIFIER}'
- 'mkdir -p "${BUILD_DIR}/"'
- 'git config --global user.email "${GIT_CONFIG_USER_EMAIL}"'
- 'git config --global user.name "${GIT_CONFIG_USER_NAME}"'
workflow: # If running on any branch other than main.
rules:
# We are an MR, but it's a draft, we won't proceed with anything.
- if: '$CI_MERGE_REQUEST_TITLE =~ /^wip:/i || $CI_MERGE_REQUEST_TITLE =~ /^draft:/i'
when: never
# Below are the rules when a commit is done (code has been added to the branch)
# Commit to master-dev-c3
- if: $CI_COMMIT_REF_NAME == $DEV_C3_SOURCE_BRANCH
variables:
EXTRA_VERSION_IDENTIFIER: "${CI_PIPELINE_IID}"
NEW_BRANCH: "dev-c3"
AUTO_BUILD: true
when: always
#commit made to main (master)
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
variables:
NEW_BRANCH: "staging-c3"
VERSION: 'cat common/version.h | grep COMMA_VERSION | sed -e "s/[^0-9|.]//g"'
EXTRA_VERSION_IDENTIFIER: "staging"
AUTO_PUBLISH: true
AUTO_BUILD: true
when: always
# if tag
- if: $CI_COMMIT_TAG
variables:
NEW_BRANCH: "release-c3"
VERSION: 'cat common/version.h | grep COMMA_VERSION | sed -e "s/[^0-9|.]//g"'
EXTRA_VERSION_IDENTIFIER: "release"
AUTO_BUILD: true
- when: always
build:
stage: build
cache:
key: "${CI_COMMIT_REF_SLUG}"
paths:
- "${CI_DIR}/scons_cache"
before_script:
- find $BUILD_DIR/ -mindepth 1 -delete
- *default_before_script
- "echo Starting build stage..."
- "echo BUILD_DIR: ${BUILD_DIR}"
- "echo CI_DIR: ${CI_DIR}"
- "echo VERSION: ${VERSION}"
- "echo CI_COMMIT_REF_NAME: ${CI_COMMIT_REF_NAME}"
- git config --global --add safe.directory ${CI_PROJECT_DIR}
script:
- export PYTHONPATH="$BUILD_DIR"
- "echo Building Panda..."
- scons -j$(nproc) cache_dir=${CI_DIR}/scons_cache ${CI_PROJECT_DIR}/panda
- mkdir -p ${BUILD_DIR}
- ls -la ${BUILD_DIR}
- "echo Building Rest..."
- ./release/release_files.py | sort | uniq | rsync -vrRl --files-from=- . $BUILD_DIR/
# - cp -pR --parents $(cat release/files_common release/files_tici | sort | uniq) $BUILD_DIR/ 2> >(grep -v 'warning:' >&2)
- cd $BUILD_DIR
- sed -i '/from .board.jungle import PandaJungle, PandaJungleDFU/s/^/#/' panda/__init__.py # comment panda jungle when prebuilt
- scons -j$(nproc) cache_dir=${CI_DIR}/scons_cache --minimal
- touch ${BUILD_DIR}/prebuilt
- sudo rm -rf ${OUTPUT_DIR}
- mkdir -p ${OUTPUT_DIR}
# We first include the paths we want to keep, even if we later will be excluding the other things on those paths
- rsync -avm
--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='*.A'
--exclude='*.o'
--exclude='*.O'
--exclude='*.os'
--exclude='*.OS'
--exclude='*.pyc'
--exclude='*.PYC'
--exclude='moc_*'
--exclude='MOC_*'
--exclude='*.cc'
--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='**/.git/'
--exclude='**/SConstruct'
--exclude='**/SConscript'
--delete-excluded
--chown=comma:comma
${BUILD_DIR}/ ${OUTPUT_DIR}/
after_script:
# cleanup build dir after doing work
- find $BUILD_DIR/ -mindepth 1 -delete
artifacts:
paths:
- ${OUTPUT_DIR}/
tags: [ 'sunnypilot', 'tici' ]
rules:
- if: $AUTO_BUILD
when: always
- when: manual
.publish_base: &publish_base
image: alpine
variables:
GIT_SUBMODULE_STRATEGY: normal
stage: publish
needs:
- job: build
artifacts: true
before_script:
- 'apk update && apk upgrade'
- 'apk add git bash openssh'
- 'eval $(ssh-agent -s)'
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
- 'mkdir -p ~/.ssh/'
- 'chmod 700 ~/.ssh'
- export HOST=$(echo ${GIT_ORIGIN} | cut -d'@' -f2 | cut -d':' -f1)
- echo fetching ssh pub keys for ${HOST}
- 'ssh-keyscan -H ${HOST} >> ~/.ssh/known_hosts' # Adding gitlab to trusted
- 'chmod 644 ~/.ssh/known_hosts'
- *default_before_script
script:
- echo "${GIT_ORIGIN}"
- echo "Calling to publish [${CI_DIR}/publish.sh ${CI_PROJECT_DIR} ${OUTPUT_DIR} ${NEW_BRANCH} ${VERSION} ${GIT_ORIGIN}]"
- git config --global --add safe.directory ${OUTPUT_DIR}
- $CI_DIR/publish.sh "${CI_PROJECT_DIR}" "${OUTPUT_DIR}" "${NEW_BRANCH}" "${VERSION}" "${GIT_ORIGIN}" "-${EXTRA_VERSION_IDENTIFIER}"
allow_failure: false
publish to private gitlab prebuilt:
extends: ".publish_base"
variables:
GIT_ORIGIN: git@gitlab.com:sunnypilot/public/sunnypilot-prebuilts.git
rules:
- if: $AUTO_BUILD
when: on_success
- if: $CI_MERGE_REQUEST_IID
when: on_success
- when: manual
publish to public github prebuilt:
extends: ".publish_base"
variables:
GIT_ORIGIN: git@github.com:sunnyhaibin/sunnypilot.git
GIT_CONFIG_USER_EMAIL: "jason.wen@sunnypilot.ai"
GIT_CONFIG_USER_NAME: "Jason Wen"
rules:
- if: $AUTO_PUBLISH
when: on_success
- when: manual
.notify_discord: &notify_discord
image: alpine
stage: notify
needs: ["build"]
variables:
DISCORD_HOOK: "${DISCORD_MANUAL_BUILD_WEBHOOK_URL}" # Default hook if not overriden by children
before_script:
- 'apk add curl jq envsubst'
script:
- echo using [${TEMPLATE}]
- cat release/ci/${TEMPLATE} | envsubst | tee payload.json
- 'curl -X POST -H "Content-Type: application/json" -d "$(cat payload.json)" ${DISCORD_HOOK} | jq .'
rules:
- if: $NEW_BRANCH
when: on_success
- when: never
allow_failure: true
notify pending action:
extends: ".notify_discord"
variables:
TEMPLATE: "discord_template_notify_dev_private.json"
before_script:
- !reference [".notify_discord", "before_script"]
- export AVATAR_URL=$(curl -s -X GET "https://gitlab.com/api/v4/avatar?email=${GITLAB_USER_EMAIL}" | jq -r '.avatar_url')
notify new dev build:
extends: ".notify_discord"
stage: notify
needs: ["publish to public github prebuilt"] # This notify shall only happen after a publish to github public
variables:
TEMPLATE: "discord_template_notify_dev_public.json"
before_script:
- !reference [".notify_discord", "before_script"]
- export EXTRA_VERSION_IDENTIFIER=$((CI_PIPELINE_IID + BASE_BUILD_NUMER))
rules:
- if: $NEW_BRANCH == "dev-c3"
variables:
DISCORD_HOOK: "${DISCORD_NEW_BUILD_WEBHOOK_URL}" # Overriding hook because we know we are dev-c3
- !reference [".notify_discord", "rules"]
+12 -9
View File
@@ -1,18 +1,21 @@
[submodule "panda"] [submodule "panda"]
path = panda path = panda
url = https://github.com/sunnyhaibin/panda.git url = ../../sunnyhaibin/panda.git
[submodule "opendbc"] [submodule "opendbc"]
path = opendbc_repo path = opendbc
url = https://github.com/sunnypilot/opendbc.git url = ../../sunnyhaibin/opendbc.git
[submodule "msgq"] [submodule "cereal"]
path = msgq_repo path = cereal
url = https://github.com/sunnypilot/msgq.git url = ../../sunnyhaibin/cereal.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 "body"]
path = body
url = ../../commaai/body.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/geohot/tinygrad.git
-25
View File
@@ -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="Poetry SCons Build Debug" defaultType="TOOL">
<configuration id="b93ec964-16e5-4962-a12e-3ed360ce8f02" name="Poetry SCons Build Debug">
<build type="TOOL">
<tool actionId="Tool_External Tools_Poetry SCons Build Debug" />
</build>
<clean type="TOOL">
<tool actionId="Tool_External Tools_Poetry SCons Clean" />
</clean>
</configuration>
</target>
<target id="edd8ad9d-183b-467c-a355-0d9a0ecab026" name="Poetry SCons Build Release" defaultType="TOOL">
<configuration id="09523339-5ce3-4223-ab9e-904f38ad7752" name="Poetry SCons Build Release">
<build type="TOOL">
<tool actionId="Tool_External Tools_Poetry SCons Build Release" />
</build>
<clean type="TOOL">
<tool actionId="Tool_External Tools_Poetry SCons Clean" />
</clean>
</configuration>
</target>
</component>
</project>
-23
View File
@@ -1,23 +0,0 @@
<toolSet name="External Tools">
<tool name="Poetry 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 &quot;source .venv/bin/activate &amp;&amp; scons -u -j$(nproc) --compile_db --ccflags=\&quot;-fno-inline\&quot;&quot;" />
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
</exec>
</tool>
<tool name="Poetry 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 &quot;source .venv/bin/activate &amp;&amp; scons -c&quot; " />
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
</exec>
</tool>
<tool name="Poetry 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 &quot;source .venv/bin/activate &amp;&amp; scons -u -j$(nproc) --compile_db&quot; " />
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
</exec>
</tool>
</toolSet>
-41
View File
@@ -1,41 +0,0 @@
[importlinter]
root_packages =
openpilot
[importlinter:contract:1]
name = Forbid imports from openpilot.selfdrive.car to openpilot.system
type = forbidden
source_modules =
openpilot.selfdrive.car
forbidden_modules =
openpilot.system
openpilot.body
openpilot.docs
openpilot.msgq
openpilot.panda
openpilot.rednose
openpilot.release
openpilot.teleoprtc
openpilot.tinygrad
ignore_imports =
openpilot.selfdrive.car.card -> openpilot.common.realtime
openpilot.selfdrive.car.card -> openpilot.selfdrive.controls.lib.events
openpilot.selfdrive.car.interfaces -> openpilot.selfdrive.controls.lib.events
openpilot.selfdrive.car.tests.test_models -> openpilot.tools.lib.logreader
openpilot.selfdrive.car.tests.test_models -> openpilot.selfdrive.car.card
openpilot.selfdrive.car.tests.test_models -> openpilot.tools.lib.route
openpilot.selfdrive.car.tests.test_models -> openpilot.system.hardware.hw
openpilot.selfdrive.car.tests.test_models -> openpilot.selfdrive.test.helpers
openpilot.selfdrive.car.isotp_parallel_query -> openpilot.common.swaglog
openpilot.selfdrive.car.fw_versions -> openpilot.common.swaglog
openpilot.selfdrive.car.disable_ecu -> openpilot.common.swaglog
openpilot.selfdrive.car.vin -> openpilot.common.swaglog
openpilot.selfdrive.car.ecu_addrs -> openpilot.common.swaglog
openpilot.selfdrive.car.car_helpers -> openpilot.common.swaglog
openpilot.selfdrive.car.car_helpers -> openpilot.system.version
openpilot.selfdrive.car.interfaces -> openpilot.selfdrive.controls.lib.drive_helpers
openpilot.selfdrive.car.tests.test_car_interfaces -> openpilot.selfdrive.controls.lib.latcontrol_angle
openpilot.selfdrive.car.tests.test_car_interfaces -> openpilot.selfdrive.controls.lib.longcontrol
openpilot.selfdrive.car.tests.test_car_interfaces -> openpilot.selfdrive.controls.lib.latcontrol_torque
openpilot.selfdrive.car.tests.test_car_interfaces -> openpilot.selfdrive.controls.lib.latcontrol_pid
unmatched_ignore_imports_alerting = warn
+2 -2
View File
@@ -1,4 +1,4 @@
[lfs] [lfs]
url = https://gitlab.com/sunnypilot/public/sunnypilot-lfs.git/info/lfs url = https://gitlab.com/commaai/openpilot-lfs.git/info/lfs
pushurl = ssh://git@gitlab.com/sunnypilot/public/sunnypilot-lfs.git pushurl = ssh://git@gitlab.com/commaai/openpilot-lfs.git
locksverify = false locksverify = false
-4
View File
@@ -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
+103
View File
@@ -0,0 +1,103 @@
exclude: '^(tinygrad_repo)'
repos:
- repo: meta
hooks:
- id: check-hooks-apply
- id: check-useless-excludes
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: check-ast
exclude: '^(third_party)/'
- id: check-json
exclude: '.devcontainer/devcontainer.json|.vscode/' # these support JSON with comments
- id: check-toml
- id: check-xml
- id: check-yaml
- id: check-merge-conflict
- id: check-symlinks
- id: check-executables-have-shebangs
- id: check-shebang-scripts-are-executable
- id: check-added-large-files
exclude: '(docs/CARS.md)|(poetry.lock)|(third_party/acados/include/blasfeo/include/blasfeo_d_kernel.h)'
args:
- --maxkb=120
- --enforce-all
- repo: https://github.com/codespell-project/codespell
rev: v2.2.6
hooks:
- id: codespell
exclude: '^(third_party/)|(body/)|(cereal/)|(panda/)|(opendbc/)|(rednose/)|(rednose_repo/)|(teleoprtc/)|(teleoprtc_repo/)|(selfdrive/ui/translations/.*.ts)|(poetry.lock)'
args:
# if you've got a short variable name that's getting flagged, add it here
- -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints
- --builtins clear,rare,informal,usage,code,names,en-GB_to_en-US
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.2.2
hooks:
- id: ruff
exclude: '^(third_party/)|(cereal/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)'
- repo: local
hooks:
- id: mypy
name: mypy
entry: mypy
language: system
types: [python]
args:
- --local-partial-types
- --explicit-package-bases
exclude: '^(third_party/)|(cereal/)|(opendbc/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)|(xx/)'
- repo: local
hooks:
- id: cppcheck
name: cppcheck
entry: cppcheck
language: system
types: [c++]
exclude: '^(third_party/)|(cereal/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(tools/)|(selfdrive/modeld/thneed/debug/)|(selfdrive/modeld/test/)|(selfdrive/camerad/test/)|(installer/)'
args:
- --error-exitcode=1
- --language=c++
- --quiet
- --force
- -j8
- repo: https://github.com/cpplint/cpplint
rev: 1.6.1
hooks:
- id: cpplint
exclude: '^(third_party/)|(cereal/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(generated/)'
args:
- --quiet
- --counting=total
- --linelength=240
# https://google.github.io/styleguide/cppguide.html
# relevant rules are whitelisted, see all options with: cpplint --filter=
- --filter=-build,-legal,-readability,-runtime,-whitespace,+build/include_subdir,+build/forward_decl,+build/include_what_you_use,+build/deprecated,+whitespace/comma,+whitespace/line_length,+whitespace/empty_if_body,+whitespace/empty_loop_body,+whitespace/empty_conditional_body,+whitespace/forcolon,+whitespace/parens,+whitespace/semicolon,+whitespace/tab,+readability/braces
- repo: https://github.com/MarcoGorelli/cython-lint
rev: v0.16.0
hooks:
- id: cython-lint
exclude: '^(third_party/)|(cereal/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(generated/)'
args:
- --max-line-length=240
- --ignore=E111, E302, E305
- repo: local
hooks:
- id: test_translations
name: test translations
entry: selfdrive/ui/tests/test_translations.py
language: script
pass_filenames: false
files: 'selfdrive/ui/translations/*'
- repo: https://github.com/python-poetry/poetry
rev: '1.8.0'
hooks:
- id: poetry-check
name: validate poetry lock
args:
- --lock
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.28.0
hooks:
- id: check-github-workflows
+1
View File
@@ -0,0 +1 @@
3.11.4
-10
View File
@@ -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="openpilot-special" TARGET_NAME="Poetry SCons Build Debug" CONFIG_NAME="Poetry 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>
-10
View File
@@ -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="openpilot-special" TARGET_NAME="Poetry SCons Build Release" CONFIG_NAME="Poetry 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>
+2 -13
View File
@@ -12,16 +12,5 @@
"**/.git": true, "**/.git": true,
"**/.venv": true, "**/.venv": true,
"**/__pycache__": true "**/__pycache__": true
}, }
"python.analysis.exclude": [ }
"**/.git",
"**/.venv",
"**/__pycache__",
// exclude directories that should be using the symlinked version
"common/**",
"selfdrive/**",
"system/**",
"third_party/**",
"tools/**",
]
}
+3 -133
View File
@@ -1,145 +1,15 @@
sunnypilot - 0.9.8.0 (2024-xx-xx) sunnypilot - 0.9.7.0 (2024-xx-xx)
========================
* Always on driver monitoring toggle
************************
* UPDATED: Synced with commaai's openpilot
* master commit 4ef757c (July 06, 2024)
* NEW❗: Default Driving Model: Notre Dame (July 01, 2024)
* NEW❗: Longitudinal: Acceleration Personality thanks to kegman, rav4kumar, and arne1282!
* Select from three distinct acceleration personalities: Eco, Normal, and Sport
* Acceleration personalities are integrated directly into the model's acceleration matrix and can be activated in real-time!
* NEW❗: Longitudinal: Dynamic Personality thanks to rav4kumar!
* Dynamically adjusts following distance and reaction based on your "Driving Personality" setting
* Personalities adapt in real-time to your speed and the distance to the lead car
* Provides a more responsive and tailored driving experience compared to predefined settings
* UPDATED: Driving Personality: Updated mode names
* Aggressive, Moderate, Standard, Relaxed
* NEW❗: Hyundai CAN: Enable Cruise Main by Default
* Set CRUISE MAIN to ON by default when the car starts, without engaging MADS
* This feature only applies when "openpilot Longitudinal Control (Alpha)" is enabled under the "Toggles" menu
* NEW❗: Toyota - Enhanced Blind Spot Monitor (BSM) thanks to arne182, rav4kumar, and eFiniLan!
* Enables Blind Spot Monitor (BSM) signals parsing in sunnypilot using the factory Blind Spot Monitor (BSM)
* sunnypilot will use debugging CAN messages to receive unfiltered BSM signals, allowing detection of more objects
* Supported platforms
* RAV4 TSS1, equipped with factory Blind Spot Monitoring (BSM)
* Lexus LSS1, equipped with factory Blind Spot Monitoring (BSM)
* Toyota TSS1/1.5, equipped with factory Blind Spot Monitoring (BSM)
* Prius TSS2, equipped with factory Blind Spot Monitoring (BSM)
* NOTE: Only enable this feature if your Toyota/Lexus vehicle has factory Blind Spot Monitor equipped, and mentioned in the supported platforms list
* UPDATED: Toyota: TSS2 longitudinal: Custom Tuning
* Re-tuned and tested by the community (July 1, 2024)
* UPDATED: Driving Model Selector v5
* NEW❗: Driving Model additions
* Notre Dame (July 01, 2024) - NDv3
* UPDATED: Neural Network Lateral Control (NNLC)
* NEW❗: Remove Lateral Jerk Response (Alpha)
* FIXED: Hotfix for "lazy" steering performance in tighter curves thanks to twilsonco!
* UPDATED: Toyota: Continued support for Smart DSU (SDSU) and Radar CAN Filter
* In response to the official deprecation of support for Smart DSU (SDSU) and Radar CAN Filter in the upstream ([commaai/openpilot#32777](https://github.com/commaai/openpilot/pull/32777)), sunnypilot will continue maintaining software support for Smart DSU (SDSU) and Radar CAN Filter
* UPDATED: Continued support for Mapbox navigation
* In response to the official temporary deprecation of support for Mapbox navigation in the upstream ([commaai/openpilot#32773](https://github.com/commaai/openpilot/pull/32773)), sunnypilot will continue maintaining software support for Mapbox navigation
* NEW❗: Toyota - Automatic Brake Hold (AHB) thanks to AlexandreSato!
* When you stop the vehicle completely by depressing the brake pedal, sunnypilot will activate Auto Brake Hold
* NOTE: Only for Toyota/Lexus vehicles with TSS2/LSS2
* NEW❗: Toyota - Automatic Door Locking and Unlocking thanks to AlexandreSato, cydia2020, and dragonpilot-community!
* Auto Lock by Speed: All doors are automatically locked when vehicle speed is approximately 6 mph (10 km/h) or higher
* Auto Unlock by Shift to P: All doors are automatically unlocked when shifting the shift lever to P
* FIXED: Driving Personality:
* Maniac mode now correctly enforced when selected
* FIXED: Experimental Model Distance Button Hold
* Experimental Model toggle with distance button hold no longer changes Personality
* Personality setting remains consistent when switching between Chill and Experimental Mode
* UI Updates
* Display Metrics Below Chevron
* NEW❗: Time to Lead Car
* Displays the time to reach the position previously occupied by the lead car
* NEW❗: Display Distance, Speed, and Time to Lead Car simultaneously
* Ford F-150 2022-23 support
* Ford F-150 Lightning 2021-23 support
* Ford Mustang Mach-E 2021-23 support
* Hyundai Kona Electric Non-SCC 2019 support thanks to NikitaNekrasov!
* Kia Ceed Plug-in Hybrid Non-SCC 2022 support thanks to TerminatorNL!
sunnypilot - 0.9.7.1 (2024-06-13)
======================== ========================
* New driving model * New driving model
* Inputs the past curvature for smoother and more accurate lateral control * Support for many hybrid Ford models
* Simplified neural network architecture in the model's last layers
* Minor fixes to desire augmentation and weight decay
* New driver monitoring model
* Improved end-to-end bit for phone detection
* Adjust driving personality with the follow distance button
* Support for hybrid variants of supported Ford models
* Fingerprinting without the OBD-II port on all cars
* Improved fuzzy fingerprinting for Ford and Volkswagen
************************ ************************
* UPDATED: Synced with commaai's openpilot * UPDATED: Synced with commaai's openpilot
* master commit f8cb04e (June 10, 2024) * master commit 56e343b (February 27, 2024)
* NEW❗: sunnylink (Alpha early access)
* NEW❗: Config/Settings Backup
* Remotely back up and restore sunnypilot settings easily
* Device registration with sunnylink ensures a secure, integrated experience across services
* AES encryption derived from the device's RSA private key is used for utmost security
* Settings are encrypted on-device, transmitted securely via HTTPS, and stored encrypted on sunnylink
* Prevents loss of settings after device resets, offering peace of mind through end-to-end encryption
* Early alpha access to all current and previous GitHub Sponsors and Patreon supporters
* GitHub account pairing from device settings scanning QR code
* Pairing your account will allow you to access features via our API (still WIP but accessible if you dig a little on our code 😉)
* Allow inheritance of your sponsorship status, allowing you to get extra features and early access whenever applicable
* NEW❗: iOS Siri Shortcuts Navigation support thanks to twilsonco and mike86437! * NEW❗: iOS Siri Shortcuts Navigation support thanks to twilsonco and mike86437!
* iOS and macOS Shortcuts to quickly set navigation destinations from your iOS device * iOS and macOS Shortcuts to quickly set navigation destinations from your iOS device
* comma Prime support * comma Prime support
* Personal Mapbox/Amap/Google Maps token support * Personal Mapbox/Amap/Google Maps token support
* Instructions on how to set up your iOS Siri Shortcuts: https://routinehub.co/shortcut/17677/ * Instructions on how to set up your iOS Siri Shortcuts: https://routinehub.co/shortcut/17677/
* NEW❗: Forced Offroad mode
* Force sunnypilot in the offroad state even when the car is on
* When Forced Offroad mode is on, allows changing offroad-only settings even when the car is turned on
* To engage/disengage Force Offroad, go to Settings -> Device panel
* NEW❗: Ford CAN-FD longitudinal
* NEW❗: Parse speed limit sign recognition from camera for certain supported platforms
* UPDATED: Auto Lane Change Timer -> Auto Lane Change by Blinker
* NEW❗: New "Off" option to disable lane change by blinker
* UPDATED: Pause Lateral Below Speed with Blinker
* NEW❗: Customizable Pause Lateral Speed
* Pause lateral actuation with blinker when traveling below the desired speed selected. Default is 20 MPH or 32 km/h.
* UPDATED: Hyundai CAN Longitudinal
* Auto-enable radar tracks on platforms with applicable Mando radar
* UPDATED: Hyundai CAN-FD Radar-based SCC
* Longitudinal support for CAN-FD Radar-based SCC cars
* UPDATED: Hyundai CAN-FD Camera-based SCC
* NEW❗: Parse lead info for camera-based SCC platforms with longitudinal support
* Improve lead tracking when using openpilot longitudinal
* RE-ENABLED: Map-based Turn Speed Control (M-TSC) for supported platforms
* openpilot Longitudinal Control available cars
* Custom Stock Longitudinal Control available cars
* UPDATED: Continued support for comma Pedal
* In response to the official deprecation of support for comma Pedal in the upstream, sunnypilot will continue maintaining software support for comma Pedal
* UPDATED: Driving Model Selector v4
* NEW❗: Driving Model additions
* North Dakota (April 29, 2024) - NDv2
* WD40 (April 09, 2024) - WD40
* Duck Amigo (March 18, 2024) - DA
* Recertified Herbalist (March 01, 2024) - CHLR
* Legacy Driving Models with Navigate on openpilot (NoO) support
* Includes Duck Amigo and all preceding models
* UPDATED: Bumping mapd by [@pfeiferj](https://github.com/pfeiferj) to version [v1.9.0](https://github.com/pfeiferj/mapd/releases/tag/v1.9.0) thanks to pfeiferj!
* UPDATED: Reset Mapbox Access Token -> Reset Access Tokens for Map Services
* Reset self-service access tokens for Mapbox, Amap, and Google Maps
* UPDATED: Upstream native support for Gap Adjust Cruise
* UPDATED: Neural Network Lateral Control (NNLC)
* Due to upstream changes with platform simplifications, most platforms will match and fallback to combined platform model
* This will be updated when the new mapping of platforms are restructured (thanks @twilsonco 😉)
* UI Updates
* Display Metrics Below Chevron
* NEW❗: Metrics is now being displayed below the chevron instead of above
* NEW❗: Display both Distance and Speed simultaneously
* NEW❗: View sunnylink connectivity status on the left sidebar!
sunnypilot - 0.9.6.2 (2024-05-29)
========================
* REMOVED: Screen Recorder
* Screen Recorder is removed due to unnecessary resource usage
* An improved version will be available in the near future. Stay tuned!
sunnypilot - 0.9.6.1 (2024-02-27) sunnypilot - 0.9.6.1 (2024-02-27)
======================== ========================
+16 -1
View File
@@ -8,6 +8,21 @@ ENV PYTHONPATH ${OPENPILOT_PATH}:${PYTHONPATH}
RUN mkdir -p ${OPENPILOT_PATH} RUN mkdir -p ${OPENPILOT_PATH}
WORKDIR ${OPENPILOT_PATH} WORKDIR ${OPENPILOT_PATH}
COPY . ${OPENPILOT_PATH}/ COPY SConstruct ${OPENPILOT_PATH}
COPY ./openpilot ${OPENPILOT_PATH}/openpilot
COPY ./third_party ${OPENPILOT_PATH}/third_party
COPY ./site_scons ${OPENPILOT_PATH}/site_scons
COPY ./rednose ${OPENPILOT_PATH}/rednose
COPY ./rednose_repo/site_scons ${OPENPILOT_PATH}/rednose_repo/site_scons
COPY ./tools ${OPENPILOT_PATH}/tools
COPY ./release ${OPENPILOT_PATH}/release
COPY ./common ${OPENPILOT_PATH}/common
COPY ./opendbc ${OPENPILOT_PATH}/opendbc
COPY ./cereal ${OPENPILOT_PATH}/cereal
COPY ./panda ${OPENPILOT_PATH}/panda
COPY ./selfdrive ${OPENPILOT_PATH}/selfdrive
COPY ./system ${OPENPILOT_PATH}/system
COPY ./body ${OPENPILOT_PATH}/body
RUN scons --cache-readonly -j$(nproc) RUN scons --cache-readonly -j$(nproc)
+33 -31
View File
@@ -1,4 +1,4 @@
FROM ubuntu:24.04 FROM ubuntu:20.04
ENV PYTHONUNBUFFERED 1 ENV PYTHONUNBUFFERED 1
@@ -13,10 +13,14 @@ 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 INSTALL_EXTRA_PACKAGES=no /tmp/tools/install_ubuntu_dependencies.sh && \ RUN cd /tmp && \
rm -rf /var/lib/apt/lists/* /tmp/* && \ tools/install_ubuntu_dependencies.sh && \
cd /usr/lib/gcc/arm-none-eabi/* && \ rm -rf /var/lib/apt/lists/* && \
rm -rf arm/ thumb/nofp thumb/v6* thumb/v8* thumb/v7+fp thumb/v7-r+fp.sp rm -rf /tmp/* && \
# remove unused architectures from gcc for panda
cd /usr/lib/gcc/arm-none-eabi/9.2.1 && \
rm -rf arm/ && \
rm -rf thumb/nofp thumb/v6* thumb/v8* thumb/v7+fp thumb/v7-r+fp.sp
# Add OpenCL # Add OpenCL
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
@@ -30,28 +34,23 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
gcc-arm-none-eabi \ gcc-arm-none-eabi \
tmux \ tmux \
vim \ vim \
lsb-core \
libx11-6 \ libx11-6 \
wget \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
RUN mkdir -p /tmp/opencl-driver-intel && \ ARG INTEL_DRIVER=l_opencl_p_18.1.0.015.tgz
cd /tmp/opencl-driver-intel && \ ARG INTEL_DRIVER_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/vcp/15532
wget https://github.com/intel/llvm/releases/download/2024-WW14/oclcpuexp-2024.17.3.0.09_rel.tar.gz && \ RUN mkdir -p /tmp/opencl-driver-intel
wget https://github.com/oneapi-src/oneTBB/releases/download/v2021.12.0/oneapi-tbb-2021.12.0-lin.tgz && \
mkdir -p /opt/intel/oclcpuexp_2024.17.3.0.09_rel && \ RUN cd /tmp/opencl-driver-intel && \
cd /opt/intel/oclcpuexp_2024.17.3.0.09_rel && \ echo INTEL_DRIVER is $INTEL_DRIVER && \
tar -zxvf /tmp/opencl-driver-intel/oclcpuexp-2024.17.3.0.09_rel.tar.gz && \ curl -O $INTEL_DRIVER_URL/$INTEL_DRIVER && \
tar -xzf $INTEL_DRIVER && \
for i in $(basename $INTEL_DRIVER .tgz)/rpm/*.rpm; do alien --to-deb $i; done && \
dpkg -i *.deb && \
rm -rf $INTEL_DRIVER $(basename $INTEL_DRIVER .tgz) *.deb && \
mkdir -p /etc/OpenCL/vendors && \ mkdir -p /etc/OpenCL/vendors && \
echo /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64/libintelocl.so > /etc/OpenCL/vendors/intel_expcpu.icd && \ echo /opt/intel/opencl_compilers_and_libraries_18.1.0.015/linux/compiler/lib/intel64_lin/libintelocl.so > /etc/OpenCL/vendors/intel.icd && \
cd /opt/intel && \
tar -zxvf /tmp/opencl-driver-intel/oneapi-tbb-2021.12.0-lin.tgz && \
ln -s /opt/intel/oneapi-tbb-2021.12.0/lib/intel64/gcc4.8/libtbb.so /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 && \
ln -s /opt/intel/oneapi-tbb-2021.12.0/lib/intel64/gcc4.8/libtbbmalloc.so /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 && \
ln -s /opt/intel/oneapi-tbb-2021.12.0/lib/intel64/gcc4.8/libtbb.so.12 /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 && \
ln -s /opt/intel/oneapi-tbb-2021.12.0/lib/intel64/gcc4.8/libtbbmalloc.so.2 /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 && \
mkdir -p /etc/ld.so.conf.d && \
echo /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 > /etc/ld.so.conf.d/libintelopenclexp.conf && \
ldconfig -f /etc/ld.so.conf.d/libintelopenclexp.conf && \
cd / && \ cd / && \
rm -rf /tmp/opencl-driver-intel rm -rf /tmp/opencl-driver-intel
@@ -62,23 +61,26 @@ ENV QTWEBENGINE_DISABLE_SANDBOX 1
RUN dbus-uuidgen > /etc/machine-id RUN dbus-uuidgen > /etc/machine-id
ARG USER=batman ARG USER=batman
ARG USER_UID=1001 ARG USER_UID=1000
RUN useradd -m -s /bin/bash -u $USER_UID $USER RUN useradd -m -s /bin/bash -u $USER_UID $USER
RUN usermod -aG sudo $USER RUN usermod -aG sudo $USER
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
USER $USER USER $USER
COPY --chown=$USER pyproject.toml uv.lock /tmp/ ENV POETRY_VIRTUALENVS_CREATE=false
ENV PYENV_VERSION=3.11.4
ENV PYENV_ROOT="/home/$USER/pyenv"
ENV PATH="$PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH"
COPY --chown=$USER pyproject.toml poetry.lock .python-version /tmp/
COPY --chown=$USER tools/install_python_dependencies.sh /tmp/tools/ COPY --chown=$USER tools/install_python_dependencies.sh /tmp/tools/
ENV VIRTUAL_ENV=/home/$USER/.venv
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
RUN cd /tmp && \ RUN cd /tmp && \
tools/install_python_dependencies.sh && \ tools/install_python_dependencies.sh && \
mkdir -p $VIRTUAL_ENV && \
cp -r /tmp/.venv/* $VIRTUAL_ENV && \
rm -rf /tmp/* && \ rm -rf /tmp/* && \
rm -rf /home/$USER/.cache rm -rf /home/$USER/.cache && \
find /home/$USER/pyenv -type d -name ".git" | xargs rm -rf && \
rm -rf /home/$USER/pyenv/versions/3.11.4/lib/python3.11/test
USER root USER root
RUN sudo git config --global --add safe.directory /tmp/openpilot RUN sudo git config --global --add safe.directory /tmp/openpilot
-77
View File
@@ -1,77 +0,0 @@
# How Tos
This page is a repository of useful how-tos as a supplement for additional information.
Table of Contents
=======================
* [Radar Tracks](#Radar-Tracks)
* [Enable Radar Tracks](#-Enable-Radar-Tracks)
* [Enable Mapbox Navigation](#-Enable-Mapbox-Navigation)
---
<details><summary><h3>📡 Radar Tracks</h3></summary>
Radar tracks can now be enabled manually on applicable cars through SSH thanks to [@greghogan](https://github.com/greghogan) and [@pd0wm](https://github.com/pd0wm).
Some Hyundai radars can be reconfigured to output (debug) radar points on bus 1.
Reconfiguration is done over UDS by reading/writing to 0x0142 using the Read/Write Data By Identifier
endpoints (0x22 & 0x2E). This script checks your radar firmware version against a list of known
firmware versions. If you want to try on a new radar, make sure to note the default config value
in case it is different from the other radars and you need to revert the changes.
After changing the config the car should not show any faults when openpilot is not running.
These config changes are persistent across car reboots. You need to run this script again
to go back to the default values.
**USE AT YOUR OWN RISK!** Stock system safety features, like AEB and FCW, might be affected by these changes.
**How radar points can be used along with vision:**
* Current OP long policy is identify with vision first, if vision sees a vehicle match it to a radar point. If vision sees nothing you get a false negative and no lead car detection. (Source: [Hubblesphere#7894 from comma.ai community Discord](https://discord.com/channels/469524606043160576/872899198738104330/872913890793635872))
### 🚨 Enable Radar Tracks
***(EXPERIMENTAL, as of January 1st, 2022)***
***(Only applicable to some Hyundai, Kia, and Genesis cars, as of January 1st, 2022)***
*(Base on version 0.8.12 [`devel`](https://github.com/commaai/openpilot/tree/devel))*
**USE AT YOUR OWN RISK!** Stock system safety features, like AEB and FCW, might be affected by these changes.
1. Ensure the car is at the `OFF` ignition position.
2. Connect your compatible comma device (EON, C2, C3) to the car. comma device power should be ON.
3. Use a laptop or applicable device to connect to your comma device via SSH. (Tips: Instructions to SSH in [HERE](https://github.com/commaai/openpilot/wiki/SSH))
4. In the SSH terminal after successfully connected to your comma device, execute the following commands:
1. `pkill -f openpilot`
2. `python /data/openpilot/selfdrive/debug/hyundai_enable_radar_points.py`
3. Follow the instructions in the script:
* `Power on the vehicle keeping the engine off (press start button twice) then type OK to continue`.
* If successful, the following message should appear: `[DONE]. Restart your vehicle and ensure there are no faults`.
* If the script did not run successfully, reach out to the community in [Sunnyhaibin's Openpilot Discord Server](https://discord.gg/wRW3meAgtx) or `#hyundai-kia-genesis channel` on [commaai community Discord Server](https://discord.comma.ai) for assistance.
4. Reboot your comma device:
1. C3: `sudo reboot`
2. C2 or EON: `reboot`
5. Once your comma device is rebooted, start your car with engine on (with or without comma device connected). Ensure that there are no faults from the car. If there are faults, reach out to the community in [Sunnyhaibin's Openpilot Discord Server](https://discord.gg/wRW3meAgtx) or `#hyundai-kia-genesis channel` on [commaai community Discord Server](https://discord.comma.ai) for assistance.
6. Go for a quick drive and drive behind a lead car with varied follow distance. Then, come back and allow the drive to upload its `rlogs` in [comma Connect](https://connect.comma.ai).
7. With all `rlogs` uploaded, open the drive in Cabana from [comma Connect](https://connect.comma.ai). Load DBC -> `hyundai_kia_mando_front_radar.dbc`, then search `RADAR_TRACK_50x` (`x` could be anything), open any of them, and look at `LONG_DIST`.
8. If the radar tracks data is relevant with the lead car you drove behind, you are done! Your car now have radar tracks enabled.
</details>
<details><summary><h3>🗺 Enable Mapbox Navigation</h3></summary>
1) Create a free mapbox account. Account will ask for a credit card for verification. You will not be charged for the free tier.
2) On the Dashboard, you will see a section called Access Tokens. Click `Create a Token`. Name it whatever you like. Set the scopes to allow everything for both Public and Secret. Copy both of these keys. **YOU WON'T BE ABLE TO ACCESS THE SECRET KEY AFTER THIS WINDOW.**
3) Once rebooted, connect your C3 to a network with internet access and find the C3s IP address.
4) In a browser, navigate to that IP with **port 8082** (i.e 192.168.1.69:8082). You should be greeted with the Comma logo and a public key input field.
5) Paste your Public token (pk.xx), click enter, paste your Secret key (sk.xx), click enter. You can now search for places. This page will be available at your devicess IP address/port 8082 to search for destinations.
6) To set Home and Work addresses, search for a place, select Home/Work from the dropdown and click Navigate. For non-Home/Work destinations, select Recent Places.<br>*At this time, it is not possible to search directly on the C3.*
**TIPS:**
- If your C3 is showing a black screen that says “Map Loading”, performing a reboot via the UI should fix it.
- If your phone can create a Hotspot, you are able to connect the C3 to your phone hotspot and use your phone browser to search for places.
- In the Navigation panel on the C3, you can select Home, Work, and from a list of Recent Places you have navigated to without needing a browser (assuming the C3 is connected to the internet.)
**IMPORTANT NOTE:** Your C3 will require an active internet connection to download map data, generate driving directions, and ETA. Once map data and directions are downloaded, it *is* possible to use it offline, however nothing will update (such as new driving direction after a missed turn, updated ETA, map data further into your drive etc.)
***NAVIGATION NOTE:** At this time, mapbox does not support alphanumeric addresses (i.e W123N1234 Main St). There is currently no known workaround for this.*
</details>
Vendored
+17 -19
View File
@@ -40,7 +40,6 @@ if [ -f /TICI ]; then
rm -rf /tmp/tmp* rm -rf /tmp/tmp*
rm -rf ~/.commacache rm -rf ~/.commacache
rm -rf /dev/shm/* rm -rf /dev/shm/*
rm -rf /dev/tmp/tmp*
if ! systemctl is-active --quiet systemd-resolved; then if ! systemctl is-active --quiet systemd-resolved; then
echo "restarting resolved" echo "restarting resolved"
@@ -83,7 +82,7 @@ def deviceStage(String stageName, String deviceType, List extra_env, def steps)
lock(resource: "", label: deviceType, inversePrecedence: true, variable: 'device_ip', quantity: 1, resourceSelectStrategy: 'random') { lock(resource: "", label: deviceType, inversePrecedence: true, variable: 'device_ip', quantity: 1, resourceSelectStrategy: 'random') {
docker.image('ghcr.io/commaai/alpine-ssh').inside('--user=root') { docker.image('ghcr.io/commaai/alpine-ssh').inside('--user=root') {
timeout(time: 35, unit: 'MINUTES') { timeout(time: 20, unit: 'MINUTES') {
retry (3) { retry (3) {
device(device_ip, "git checkout", extra + "\n" + readFile("selfdrive/test/setup_device_ci.sh")) device(device_ip, "git checkout", extra + "\n" + readFile("selfdrive/test/setup_device_ci.sh"))
} }
@@ -183,7 +182,7 @@ node {
deviceStage("onroad", "tici-needs-can", [], [ deviceStage("onroad", "tici-needs-can", [], [
// TODO: ideally, this test runs in master-ci, but it takes 5+m to build it // 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"], //["build master-ci", "cd $SOURCE_DIR/release && TARGET_DIR=$TEST_DIR $SOURCE_DIR/scripts/retry.sh ./build_devel.sh"],
["build openpilot", "cd system/manager && ./build.py"], ["build openpilot", "cd selfdrive/manager && ./build.py"],
["check dirty", "release/check-dirty.sh"], ["check dirty", "release/check-dirty.sh"],
["onroad tests", "pytest selfdrive/test/test_onroad.py -s"], ["onroad tests", "pytest selfdrive/test/test_onroad.py -s"],
["time to onroad", "pytest selfdrive/test/test_time_to_onroad.py"], ["time to onroad", "pytest selfdrive/test/test_time_to_onroad.py"],
@@ -191,54 +190,53 @@ node {
}, },
'HW + Unit Tests': { 'HW + Unit Tests': {
deviceStage("tici-hardware", "tici-common", ["UNSAFE=1"], [ deviceStage("tici-hardware", "tici-common", ["UNSAFE=1"], [
["build", "cd system/manager && ./build.py"], ["build", "cd selfdrive/manager && ./build.py"],
["test pandad", "pytest selfdrive/pandad/tests/test_pandad.py"], ["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py"],
["test power draw", "pytest -s system/hardware/tici/tests/test_power_draw.py"], ["test power draw", "pytest -s system/hardware/tici/tests/test_power_draw.py"],
["test encoder", "LD_LIBRARY_PATH=/usr/local/lib pytest system/loggerd/tests/test_encoder.py"], ["test encoder", "LD_LIBRARY_PATH=/usr/local/lib pytest system/loggerd/tests/test_encoder.py"],
["test pigeond", "pytest system/ubloxd/tests/test_pigeond.py"], ["test pigeond", "pytest system/sensord/tests/test_pigeond.py"],
["test manager", "pytest system/manager/test/test_manager.py"], ["test manager", "pytest selfdrive/manager/test/test_manager.py"],
]) ])
}, },
'loopback': { 'loopback': {
deviceStage("loopback", "tici-loopback", ["UNSAFE=1"], [ deviceStage("loopback", "tici-loopback", ["UNSAFE=1"], [
["build openpilot", "cd system/manager && ./build.py"], ["build openpilot", "cd selfdrive/manager && ./build.py"],
["test pandad loopback", "pytest selfdrive/pandad/tests/test_pandad_loopback.py"], ["test boardd loopback", "pytest selfdrive/boardd/tests/test_boardd_loopback.py"],
]) ])
}, },
'camerad': { 'camerad': {
deviceStage("AR0231", "tici-ar0231", ["UNSAFE=1"], [ deviceStage("AR0231", "tici-ar0231", ["UNSAFE=1"], [
["build", "cd system/manager && ./build.py"], ["build", "cd selfdrive/manager && ./build.py"],
["test camerad", "pytest system/camerad/test/test_camerad.py"], ["test camerad", "pytest system/camerad/test/test_camerad.py"],
["test exposure", "pytest system/camerad/test/test_exposure.py"], ["test exposure", "pytest system/camerad/test/test_exposure.py"],
]) ])
deviceStage("OX03C10", "tici-ox03c10", ["UNSAFE=1"], [ deviceStage("OX03C10", "tici-ox03c10", ["UNSAFE=1"], [
["build", "cd system/manager && ./build.py"], ["build", "cd selfdrive/manager && ./build.py"],
["test camerad", "pytest system/camerad/test/test_camerad.py"], ["test camerad", "pytest system/camerad/test/test_camerad.py"],
["test exposure", "pytest system/camerad/test/test_exposure.py"], ["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"], [
["build", "cd system/manager && ./build.py"], ["build", "cd selfdrive/manager && ./build.py"],
["test sensord", "pytest system/sensord/tests/test_sensord.py"], ["test sensord", "pytest system/sensord/tests/test_sensord.py"],
]) ])
deviceStage("BMX + LSM", "tici-bmx-lsm", ["UNSAFE=1"], [ deviceStage("BMX + LSM", "tici-bmx-lsm", ["UNSAFE=1"], [
["build", "cd system/manager && ./build.py"], ["build", "cd selfdrive/manager && ./build.py"],
["test sensord", "pytest system/sensord/tests/test_sensord.py"], ["test sensord", "pytest system/sensord/tests/test_sensord.py"],
]) ])
}, },
'replay': { 'replay': {
deviceStage("model-replay", "tici-replay", ["UNSAFE=1"], [ deviceStage("model-replay", "tici-replay", ["UNSAFE=1"], [
["build", "cd system/manager && ./build.py"], ["build", "cd selfdrive/manager && ./build.py"],
["model replay", "selfdrive/test/process_replay/model_replay.py"], ["model replay", "selfdrive/test/process_replay/model_replay.py"],
]) ])
}, },
'tizi': { 'tizi': {
deviceStage("tizi", "tizi", ["UNSAFE=1"], [ deviceStage("tizi", "tizi", ["UNSAFE=1"], [
["build openpilot", "cd system/manager && ./build.py"], ["build openpilot", "cd selfdrive/manager && ./build.py"],
["test pandad loopback", "SINGLE_PANDA=1 pytest selfdrive/pandad/tests/test_pandad_loopback.py"], ["test boardd loopback", "SINGLE_PANDA=1 pytest selfdrive/boardd/tests/test_boardd_loopback.py"],
["test pandad spi", "pytest selfdrive/pandad/tests/test_pandad_spi.py"], ["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py"],
["test pandad", "pytest selfdrive/pandad/tests/test_pandad.py"],
["test amp", "pytest system/hardware/tici/tests/test_amplifier.py"], ["test amp", "pytest system/hardware/tici/tests/test_amplifier.py"],
["test hw", "pytest system/hardware/tici/tests/test_hardware.py"], ["test hw", "pytest system/hardware/tici/tests/test_hardware.py"],
["test qcomgpsd", "pytest system/qcomgpsd/tests/test_qcomgpsd.py"], ["test qcomgpsd", "pytest system/qcomgpsd/tests/test_qcomgpsd.py"],
@@ -251,4 +249,4 @@ node {
currentBuild.result = 'FAILED' currentBuild.result = 'FAILED'
throw e throw e
} }
} }
-21
View File
@@ -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
+11 -11
View File
@@ -170,16 +170,16 @@ After running the command to install the desired branch, your comma device shoul
* Speed Limit Control (SLC) - Set speed limit based on map data or car interface (if applicable) * Speed Limit Control (SLC) - Set speed limit based on map data or car interface (if applicable)
* HKG only: Highway Driving Assist (HDA) status integration - Use cars native speed sign detection to set desired speed (on applicable HKG cars only) * HKG only: Highway Driving Assist (HDA) status integration - Use cars native speed sign detection to set desired speed (on applicable HKG cars only)
- [**Gap Adjust Cruise (GAC)**](#gap-adjust-cruise) - Allow `GAP`/`INTERVAL`/`DISTANCE` button on the steering wheel or on-screen button to adjust the follow distance from the lead car. See table below for options - [**Gap Adjust Cruise (GAC)**](#gap-adjust-cruise) - Allow `GAP`/`INTERVAL`/`DISTANCE` button on the steering wheel or on-screen button to adjust the follow distance from the lead car. See table below for options
- [**Quiet Drive 🤫**](#-quiet-drive) - Toggle to mute all notification sounds (excluding driver safety warnings) - [**Quiet Drive 🤫**](#-quiet-drive) - Toggle to mute all notification sounds (excluding driver safety warnings)
- [**Auto Lane Change Timer**](#Auto-Lane-Change-Timer) - Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set - [**Auto Lane Change Timer**](#Auto-Lane-Change-Timer) - Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set
- [**Force Car Recognition (FCR)**](#Force-Car-Recognition-) - Use a selector to force your car to be recognized by sunnypilot - [**Force Car Recognition (FCR)**](#Force-Car-Recognition-) - Use a selector to force your car to be recognized by sunnypilot
- [**Fix sunnypilot No Offroad**](#Fix-sunnypilot-No-Offroad) - Enforce sunnypilot to go offroad and turns off after shutting down the car. This feature fixes non-official devices running sunnypilot without comma power - [**Fix sunnypilot No Offroad**](#Fix-sunnypilot-No-Offroad) - Enforce sunnypilot to go offroad and turns off after shutting down the car. This feature fixes non-official devices running sunnypilot without comma power
- [**Enable ACC+MADS with RES+/SET-**](#Enable-ACC+MADS-with-RES+/SET-) - Engage both ACC and MADS with a single press of RES+ or SET- button - [**Enable ACC+MADS with RES+/SET-**](#Enable-ACC+MADS-with-RES+/SET-) - Engage both ACC and MADS with a single press of RES+ or SET- button
- [**Offline OSM Maps**](#Offline-OSM-Maps) - OSM database can now be downloaded locally for offline use[^2]. This enables offline SLC, V-TSC and M-TSC. Currently available for US South, US West, US Northeast, Florida, Taiwan, South Africa and New Zealand - [**Offline OSM Maps**](#Offline-OSM-Maps) - OSM database can now be downloaded locally for offline use[^2]. This enables offline SLC, V-TSC and M-TSC. Currently available for US South, US West, US Northeast, Florida, Taiwan, South Africa and New Zealand
- [**Various Live Tuning**](#Various-Live-Tuning) - Ability to tailor your driving experience on the fly: - [**Various Live Tuning**](#Various-Live-Tuning) - Ability to tailor your driving experience on the fly:
* Enforce Torque Lateral Control - Use the newest [torque controller](https://blog.comma.ai/0815release/#torque-controller) for all vehicles. * Enforce Torque Lateral Control - Use the newest [torque controller](https://blog.comma.ai/0815release/#torque-controller) for all vehicles.
* Torque Lateral Control Live Tune - Ability to adjust the torque controllers `FRICTION` and `LAT_ACCEL_FACTOR` values to suit your vehicle. * Torque Lateral Control Live Tune - Ability to adjust the torque controllers `FRICTION` and `LAT_ACCEL_FACTOR` values to suit your vehicle.
* Torque Lateral Controller Self-Tune - Enable automatic turning for the Torque controller. * Torque Lateral Controller Self-Tune - Enable automatic turning for the Torque controller.
### Visual Enhancements ### Visual Enhancements
* **M.A.D.S Status Icon** - Dedicated icon to display M.A.D.S. engagement status * **M.A.D.S Status Icon** - Dedicated icon to display M.A.D.S. engagement status
@@ -223,7 +223,7 @@ The goal of Modified Assistive Driving Safety (MADS) is to enhance the user driv
* `SET-` button enables ACC/SCC * `SET-` button enables ACC/SCC
* `CANCEL` button only disables ACC/SCC * `CANCEL` button only disables ACC/SCC
* `CRUISE (MAIN)` must be `ON` to use ACC/SCC * `CRUISE (MAIN)` must be `ON` to use ACC/SCC
* `CRUISE (MAIN)` button disables ACC/SCC completely when `OFF` **(strictly enforced in panda safety code)** * `CRUISE (MAIN)` button disables sunnypilot completely when `OFF` **(strictly enforced in panda safety code)**
### Disengage Lateral ALC on Brake Press Mode toggle ### Disengage Lateral ALC on Brake Press Mode toggle
Dedicated toggle to handle Lateral state on brake pedal press and release: Dedicated toggle to handle Lateral state on brake pedal press and release:
+5 -20
View File
@@ -1,19 +1,7 @@
Version 0.9.8 (2024-XX-XX) Version 0.9.7 (2024-XX-XX)
========================
* Added toggle to enable driver monitoring even when openpilot is not engaged
Version 0.9.7 (2024-06-13)
======================== ========================
* New driving model * New driving model
* Inputs the past curvature for smoother and more accurate lateral control * Support for many hybrid Ford models
* Simplified neural network architecture in the model's last layers
* Minor fixes to desire augmentation and weight decay
* New driver monitoring model
* Improved end-to-end bit for phone detection
* Adjust driving personality with the follow distance button
* Support for hybrid variants of supported Ford models
* Fingerprinting without the OBD-II port on all cars
* Improved fuzzy fingerprinting for Ford and Volkswagen
Version 0.9.6 (2024-02-27) Version 0.9.6 (2024-02-27)
======================== ========================
@@ -23,9 +11,6 @@ Version 0.9.6 (2024-02-27)
* Directly outputs curvature for lateral control * Directly outputs curvature for lateral control
* New driver monitoring model * New driver monitoring model
* Trained on larger dataset * Trained on larger dataset
* Model path UI
* Shows where driving model wants to be
* Shows what model is seeing more clearly, but more jittery
* AGNOS 9 * AGNOS 9
* comma body streaming and controls over WebRTC * comma body streaming and controls over WebRTC
* Improved fuzzy fingerprinting for many makes and models * Improved fuzzy fingerprinting for many makes and models
@@ -643,7 +628,7 @@ Version 0.5.13 (2019-05-31)
* Reduce CPU utilization by 20% and improve stability * Reduce CPU utilization by 20% and improve stability
* Temporarily remove mapd functionalities to improve stability * Temporarily remove mapd functionalities to improve stability
* Add openpilot record-only mode for unsupported cars * Add openpilot record-only mode for unsupported cars
* Synchronize controlsd to pandad to reduce latency * Synchronize controlsd to boardd to reduce latency
* Remove panda support for Subaru giraffe * Remove panda support for Subaru giraffe
Version 0.5.12 (2019-05-16) Version 0.5.12 (2019-05-16)
@@ -979,7 +964,7 @@ Version 0.2.8 (2017-02-27)
Version 0.2.7 (2017-02-08) Version 0.2.7 (2017-02-08)
=========================== ===========================
* Better performance and pictures at night * Better performance and pictures at night
* Fix ptr alignment issue in pandad * Fix ptr alignment issue in boardd
* Fix brake error light, fix crash if too cold * Fix brake error light, fix crash if too cold
Version 0.2.6 (2017-01-31) Version 0.2.6 (2017-01-31)
@@ -1011,7 +996,7 @@ Version 0.2.2 (2017-01-10)
Version 0.2.1 (2016-12-14) Version 0.2.1 (2016-12-14)
=========================== ===========================
* Performance improvements, removal of more numpy * Performance improvements, removal of more numpy
* Fix pandad process priority * Fix boardd process priority
* Make counter timer reset on use of steering wheel * Make counter timer reset on use of steering wheel
Version 0.2 (2016-12-12) Version 0.2 (2016-12-12)
+23 -36
View File
@@ -14,8 +14,6 @@ SCons.Warnings.warningAsException(True)
TICI = os.path.isfile('/TICI') TICI = os.path.isfile('/TICI')
AGNOS = TICI AGNOS = TICI
UBUNTU_FOCAL = int(subprocess.check_output('[ -f /etc/os-release ] && . /etc/os-release && [ "$ID" = "ubuntu" ] && [ "$VERSION_ID" = "20.04" ] && echo 1 || echo 0', shell=True, encoding='utf-8').rstrip())
Export('UBUNTU_FOCAL')
Decider('MD5-timestamp') Decider('MD5-timestamp')
@@ -69,15 +67,9 @@ AddOption('--pc-thneed',
AddOption('--minimal', AddOption('--minimal',
action='store_false', action='store_false',
dest='extras', dest='extras',
default=os.path.exists(File('#.lfsconfig').abspath), # minimal by default on release branch (where there's no LFS) default=os.path.islink(Dir('#rednose/').abspath), # minimal by default on release branch (where rednose is not a link)
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 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
@@ -110,6 +102,7 @@ if arch == "larch64":
libpath = [ libpath = [
"/usr/local/lib", "/usr/local/lib",
"/usr/lib",
"/system/vendor/lib64", "/system/vendor/lib64",
f"#third_party/acados/{arch}/lib", f"#third_party/acados/{arch}/lib",
] ]
@@ -177,12 +170,9 @@ if arch != "Darwin":
ldflags += ["-Wl,--as-needed", "-Wl,--no-undefined"] ldflags += ["-Wl,--as-needed", "-Wl,--no-undefined"]
# Enable swaglog include in submodules # Enable swaglog include in submodules
cflags += ['-DSWAGLOG="\\"common/swaglog.h\\""']
cxxflags += ['-DSWAGLOG="\\"common/swaglog.h\\""'] cxxflags += ['-DSWAGLOG="\\"common/swaglog.h\\""']
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(' ')
@@ -203,7 +193,6 @@ env = Environment(
"-Wno-c99-designator", "-Wno-c99-designator",
"-Wno-reorder-init-list", "-Wno-reorder-init-list",
"-Wno-error=unused-but-set-variable", "-Wno-error=unused-but-set-variable",
"-Wno-vla-cxx-extension",
] + cflags + ccflags, ] + cflags + ccflags,
CPPPATH=cpppath + [ CPPPATH=cpppath + [
@@ -216,9 +205,9 @@ env = Environment(
"#third_party/json11", "#third_party/json11",
"#third_party/linux/include", "#third_party/linux/include",
"#third_party/snpe/include", "#third_party/snpe/include",
"#third_party/qrcode",
"#third_party", "#third_party",
"#cereal", "#cereal",
"#msgq",
"#opendbc/can", "#opendbc/can",
"#third_party/maplibre-native-qt/include", "#third_party/maplibre-native-qt/include",
f"#third_party/maplibre-native-qt/{arch}/include" f"#third_party/maplibre-native-qt/{arch}/include"
@@ -233,9 +222,10 @@ env = Environment(
CFLAGS=["-std=gnu11"] + cflags, CFLAGS=["-std=gnu11"] + cflags,
CXXFLAGS=["-std=c++1z"] + cxxflags, CXXFLAGS=["-std=c++1z"] + cxxflags,
LIBPATH=libpath + [ LIBPATH=libpath + [
"#msgq_repo", "#cereal",
"#third_party", "#third_party",
"#selfdrive/pandad", "#opendbc/can",
"#selfdrive/boardd",
"#common", "#common",
"#rednose/helpers", "#rednose/helpers",
], ],
@@ -243,7 +233,7 @@ env = Environment(
COMPILATIONDB_USE_ABSPATH=True, COMPILATIONDB_USE_ABSPATH=True,
REDNOSE_ROOT="#", REDNOSE_ROOT="#",
tools=["default", "cython", "compilation_db", "rednose_filter"], tools=["default", "cython", "compilation_db", "rednose_filter"],
toolpath=["#site_scons/site_tools", "#rednose_repo/site_scons/site_tools"], toolpath=["#rednose_repo/site_scons/site_tools"],
) )
if arch == "Darwin": if arch == "Darwin":
@@ -255,8 +245,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)
@@ -283,8 +272,7 @@ if arch == "Darwin":
else: else:
envCython["LINKFLAGS"] = ["-pthread", "-shared"] envCython["LINKFLAGS"] = ["-pthread", "-shared"]
np_version = SCons.Script.Value(np.__version__) Export('envCython')
Export('envCython', 'np_version')
# Qt build environment # Qt build environment
qt_env = env.Clone() qt_env = env.Clone()
@@ -328,7 +316,7 @@ try:
except SCons.Errors.UserError: except SCons.Errors.UserError:
qt_env.Tool('qt') qt_env.Tool('qt')
qt_env['CPPPATH'] += qt_dirs + ["#third_party/qrcode"] qt_env['CPPPATH'] += qt_dirs# + ["#selfdrive/ui/qt/"]
qt_flags = [ qt_flags = [
"-D_REENTRANT", "-D_REENTRANT",
"-DQT_NO_DEBUG", "-DQT_NO_DEBUG",
@@ -367,16 +355,12 @@ gpucommon = [_gpucommon]
Export('common', 'gpucommon') Export('common', 'gpucommon')
# Build messaging (cereal + msgq + socketmaster + their dependencies) # Build cereal and messaging
SConscript(['msgq_repo/SConscript'])
SConscript(['cereal/SConscript']) SConscript(['cereal/SConscript'])
Import('socketmaster', 'msgq')
messaging = [socketmaster, msgq, 'zmq', 'capnp', 'kj',]
Export('messaging')
# Build other submodules # Build other submodules
SConscript([ SConscript([
'body/board/SConscript',
'opendbc/can/SConscript', 'opendbc/can/SConscript',
'panda/SConscript', 'panda/SConscript',
]) ])
@@ -392,22 +376,25 @@ SConscript([
]) ])
if arch != "Darwin": if arch != "Darwin":
SConscript([ SConscript([
'system/camerad/SConscript',
'system/sensord/SConscript', 'system/sensord/SConscript',
'system/logcatd/SConscript', 'system/logcatd/SConscript',
]) ])
if arch == "larch64":
SConscript(['system/camerad/SConscript'])
# Build openpilot # Build openpilot
SConscript(['third_party/SConscript']) SConscript(['third_party/SConscript'])
SConscript(['selfdrive/SConscript']) SConscript(['selfdrive/boardd/SConscript'])
SConscript(['selfdrive/controls/lib/lateral_mpc_lib/SConscript'])
SConscript(['selfdrive/controls/lib/longitudinal_mpc_lib/SConscript'])
SConscript(['selfdrive/locationd/SConscript'])
SConscript(['selfdrive/navd/SConscript'])
SConscript(['selfdrive/modeld/SConscript'])
SConscript(['selfdrive/ui/SConscript'])
if Dir('#tools/cabana/').exists() and GetOption('extras'): if arch in ['x86_64', 'aarch64', 'Darwin'] and Dir('#tools/cabana/').exists() and GetOption('extras'):
SConscript(['tools/replay/SConscript']) SConscript(['tools/replay/SConscript'])
if arch != "larch64": SConscript(['tools/cabana/SConscript'])
SConscript(['tools/cabana/SConscript'])
external_sconscript = GetOption('external_sconscript') external_sconscript = GetOption('external_sconscript')
if external_sconscript: if external_sconscript:
Submodule
+1
Submodule body added at 61ace31efa
Submodule
+1
Submodule cereal added at d4c43a0865
-51
View File
@@ -1,51 +0,0 @@
# What is cereal?
cereal is the messaging system for openpilot. It uses [msgq](https://github.com/commaai/msgq) as a pub/sub backend, and [Cap'n proto](https://capnproto.org/capnp-tool.html) for serialization of the structs.
## Messaging Spec
You'll find the message types in [log.capnp](log.capnp). It uses [Cap'n proto](https://capnproto.org/capnp-tool.html) and defines one struct called `Event`.
All `Events` have a `logMonoTime` and a `valid`. Then a big union defines the packet type.
### Best Practices
- **All fields must describe quantities in SI units**, unless otherwise specified in the field name.
- In the context of the message they are in, field names should be completely unambiguous.
- All values should be easy to plot and be human-readable with minimal parsing.
### Maintaining backwards-compatibility
When making changes to the messaging spec you want to maintain backwards-compatibility, such that old logs can
be parsed with a new version of cereal. Adding structs and adding members to structs is generally safe, most other
things are not. Read more details [here](https://capnproto.org/language.html).
### Custom forks
Forks of [openpilot](https://github.com/commaai/openpilot) might want to add things to the messaging
spec, however this could conflict with future changes made in mainline cereal/openpilot. Rebasing against mainline openpilot
then means breaking backwards-compatibility with all old logs of your fork. So we added reserved events in
[custom.capnp](custom.capnp) that we will leave empty in mainline cereal/openpilot. **If you only modify those, you can ensure your
fork will remain backwards-compatible with all versions of mainline openpilot and your fork.**
Example
---
```python
import cereal.messaging as messaging
# in subscriber
sm = messaging.SubMaster(['sensorEvents'])
while 1:
sm.update()
print(sm['sensorEvents'])
```
```python
# in publisher
pm = messaging.PubMaster(['sensorEvents'])
dat = messaging.new_message('sensorEvents', size=1)
dat.sensorEvents[0] = {"gyro": {"v": [0.1, -0.1, 0.1]}}
pm.send('sensorEvents', dat)
```
-31
View File
@@ -1,31 +0,0 @@
Import('env', 'envCython', 'arch', 'common', 'msgq')
import shutil
cereal_dir = Dir('.')
gen_dir = Dir('gen')
other_dir = Dir('#msgq')
# Build cereal
schema_files = ['log.capnp', 'car.capnp', 'legacy.capnp', 'custom.capnp']
env.Command(["gen/c/include/c++.capnp.h"], [], "mkdir -p " + gen_dir.path + "/c/include && touch $TARGETS")
env.Command([f'gen/cpp/{s}.c++' for s in schema_files] + [f'gen/cpp/{s}.h' for s in schema_files],
schema_files,
f"capnpc --src-prefix={cereal_dir.path} $SOURCES -o c++:{gen_dir.path}/cpp/")
# TODO: remove non shared cereal and messaging
cereal_objects = env.SharedObject([f'gen/cpp/{s}.c++' for s in schema_files])
cereal = env.Library('cereal', cereal_objects)
env.SharedLibrary('cereal_shared', cereal_objects)
# Build messaging
services_h = env.Command(['services.h'], ['services.py'], 'python3 ' + cereal_dir.path + '/services.py > $TARGET')
env.Program('messaging/bridge', ['messaging/bridge.cc'], LIBS=[msgq, 'zmq', common])
socketmaster = env.SharedObject(['messaging/socketmaster.cc'])
socketmaster = env.Library('socketmaster', socketmaster)
Export('cereal', 'socketmaster')
-9
View File
@@ -1,9 +0,0 @@
import os
import capnp
CEREAL_PATH = os.path.dirname(os.path.abspath(__file__))
capnp.remove_import_hook()
log = capnp.load(os.path.join(CEREAL_PATH, "log.capnp"))
car = capnp.load(os.path.join(CEREAL_PATH, "car.capnp"))
custom = capnp.load(os.path.join(CEREAL_PATH, "custom.capnp"))
-761
View File
@@ -1,761 +0,0 @@
using Cxx = import "./include/c++.capnp";
$Cxx.namespace("cereal");
@0x8e2af1e708af8b8d;
# ******* events causing controls state machine transition *******
struct CarEvent @0x9b1657f34caf3ad3 {
name @0 :EventName;
# event types
enable @1 :Bool;
noEntry @2 :Bool;
warning @3 :Bool; # alerts presented only when enabled or soft disabling
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 @0xbaa8c5d505f727de {
canError @0;
steerUnavailable @1;
wrongGear @4;
doorOpen @5;
seatbeltNotLatched @6;
espDisabled @7;
wrongCarMode @8;
steerTempUnavailable @9;
reverseGear @10;
buttonCancel @11;
buttonEnable @12;
pedalPressed @13; # exits active state
preEnableStandstill @73; # added during pre-enable state with brake
gasPressedOverride @108; # added when user is pressing gas with no disengage on gas
steerOverride @114;
cruiseDisabled @14;
speedTooLow @17;
outOfSpace @18;
overheat @19;
calibrationIncomplete @20;
calibrationInvalid @21;
calibrationRecalibrating @117;
controlsMismatch @22;
pcmEnable @23;
pcmDisable @24;
radarFault @26;
brakeHold @28;
parkBrake @29;
manualRestart @30;
lowSpeedLockout @31;
joystickDebug @34;
steerTempUnavailableSilent @35;
resumeRequired @36;
preDriverDistracted @37;
promptDriverDistracted @38;
driverDistracted @39;
preDriverUnresponsive @43;
promptDriverUnresponsive @44;
driverUnresponsive @45;
belowSteerSpeed @46;
lowBattery @48;
accFaulted @51;
sensorDataInvalid @52;
commIssue @53;
commIssueAvgFreq @109;
tooDistracted @54;
posenetInvalid @55;
soundsUnavailable @56;
preLaneChangeLeft @57;
preLaneChangeRight @58;
laneChange @59;
lowMemory @63;
stockAeb @64;
ldw @65;
carUnrecognized @66;
invalidLkasSetting @69;
speedTooHigh @70;
laneChangeBlocked @71;
relayMalfunction @72;
stockFcw @74;
startup @75;
startupNoCar @76;
startupNoControl @77;
startupMaster @78;
startupNoFw @104;
fcw @79;
steerSaturated @80;
belowEngageSpeed @84;
noGps @85;
wrongCruiseMode @87;
modeldLagging @89;
deviceFalling @90;
fanMalfunction @91;
cameraMalfunction @92;
cameraFrameRate @110;
processNotRunning @95;
dashcamMode @96;
controlsInitializing @98;
usbError @99;
roadCameraError @100;
driverCameraError @101;
wideRoadCameraError @102;
highCpuUsage @105;
cruiseMismatch @106;
lkasDisabled @107;
canBusMissing @111;
controlsdLagging @112;
resumeBlocked @113;
steerTimeLimit @115;
vehicleSensorsInvalid @116;
locationdTemporaryError @103;
locationdPermanentError @118;
paramsdTemporaryError @50;
paramsdPermanentError @119;
actuatorsApiUnavailable @120;
espActive @121;
manualSteeringRequired @122;
manualLongitudinalRequired @123;
silentPedalPressed @124;
silentButtonEnable @125;
silentBrakeHold @126;
silentWrongGear @127;
spReverseGear @128;
preKeepHandsOnWheel @129;
promptKeepHandsOnWheel @130;
keepHandsOnWheel @131;
speedLimitActive @132;
speedLimitValueChange @133;
e2eLongStop @134;
e2eLongStart @135;
controlsMismatchLong @136;
cruiseEngageBlocked @137;
laneChangeRoadEdge @138;
speedLimitPreActive @139;
speedLimitConfirmed @140;
torqueNNLoad @141;
hyundaiRadarTracksAvailable @142;
spAutoBrakeHold @143;
radarCanErrorDEPRECATED @15;
communityFeatureDisallowedDEPRECATED @62;
radarCommIssueDEPRECATED @67;
driverMonitorLowAccDEPRECATED @68;
gasUnavailableDEPRECATED @3;
dataNeededDEPRECATED @16;
modelCommIssueDEPRECATED @27;
ipasOverrideDEPRECATED @33;
geofenceDEPRECATED @40;
driverMonitorOnDEPRECATED @41;
driverMonitorOffDEPRECATED @42;
calibrationProgressDEPRECATED @47;
invalidGiraffeHondaDEPRECATED @49;
invalidGiraffeToyotaDEPRECATED @60;
internetConnectivityNeededDEPRECATED @61;
whitePandaUnsupportedDEPRECATED @81;
commIssueWarningDEPRECATED @83;
focusRecoverActiveDEPRECATED @86;
neosUpdateRequiredDEPRECATED @88;
modelLagWarningDEPRECATED @93;
startupOneplusDEPRECATED @82;
startupFuzzyFingerprintDEPRECATED @97;
noTargetDEPRECATED @25;
brakeUnavailableDEPRECATED @2;
plannerErrorDEPRECATED @32;
gpsMalfunctionDEPRECATED @94;
}
}
# ******* main car state @ 100hz *******
# all speeds in m/s
struct CarState {
events @13 :List(CarEvent);
# CAN health
canValid @26 :Bool; # invalid counter/checksums
canTimeout @40 :Bool; # CAN bus dropped out
canErrorCounter @48 :UInt32;
# car speed
vEgo @1 :Float32; # best estimate of speed
aEgo @16 :Float32; # best estimate of acceleration
vEgoRaw @17 :Float32; # unfiltered speed from CAN sensors
vEgoCluster @44 :Float32; # best estimate of speed shown on car's instrument cluster, used for UI
yawRate @22 :Float32; # best estimate of yaw rate
standstill @18 :Bool;
wheelSpeeds @2 :WheelSpeeds;
# gas pedal, 0.0-1.0
gas @3 :Float32; # this is user pedal only
gasPressed @4 :Bool; # this is user pedal only
engineRpm @46 :Float32;
# brake pedal, 0.0-1.0
brake @5 :Float32; # this is user pedal only
brakePressed @6 :Bool; # this is user pedal only
regenBraking @45 :Bool; # this is user pedal only
parkingBrake @39 :Bool;
brakeHoldActive @38 :Bool;
# steering wheel
steeringAngleDeg @7 :Float32;
steeringAngleOffsetDeg @37 :Float32; # Offset betweens sensors in case there multiple
steeringRateDeg @15 :Float32;
steeringTorque @8 :Float32; # TODO: standardize units
steeringTorqueEps @27 :Float32; # TODO: standardize units
steeringPressed @9 :Bool; # if the user is using the steering wheel
steerFaultTemporary @35 :Bool; # temporary EPS fault
steerFaultPermanent @36 :Bool; # permanent EPS fault
stockAeb @30 :Bool;
stockFcw @31 :Bool;
espDisabled @32 :Bool;
accFaulted @42 :Bool;
carFaultedNonCritical @47 :Bool; # some ECU is faulted, but car remains controllable
espActive @51 :Bool;
# cruise state
cruiseState @10 :CruiseState;
# gear
gearShifter @14 :GearShifter;
# button presses
buttonEvents @11 :List(ButtonEvent);
leftBlinker @20 :Bool;
rightBlinker @21 :Bool;
genericToggle @23 :Bool;
# lock info
doorOpen @24 :Bool;
seatbeltUnlatched @25 :Bool;
# clutch (manual transmission only)
clutchPressed @28 :Bool;
madsEnabled @52 :Bool;
leftBlinkerOn @53 :Bool;
rightBlinkerOn @54 :Bool;
disengageByBrake @55 :Bool;
belowLaneChangeSpeed @56 :Bool;
accEnabled @57 :Bool;
latActive @58 :Bool;
gapAdjustCruiseTr @59 :Int32;
endToEndLong @60 :Bool;
customStockLong @61 :CustomStockLong;
struct CustomStockLong {
cruiseButton @0 :Int16;
finalSpeedKph @1 :Float32;
vCruiseKphPrevDEPRECATED @2 :Float32;
targetSpeed @3 :Float32;
vSetDis @4 :Float32;
speedDiff @5 :Float32;
buttonType @6 :Int16;
}
# blindspot sensors
leftBlindspot @33 :Bool; # Is there something blocking the left lane change
rightBlindspot @34 :Bool; # Is there something blocking the right lane change
fuelGauge @41 :Float32; # battery or fuel tank level from 0.0 to 1.0
charging @43 :Bool;
# process meta
cumLagMs @50 :Float32;
struct WheelSpeeds {
# optional wheel speeds
fl @0 :Float32;
fr @1 :Float32;
rl @2 :Float32;
rr @3 :Float32;
}
struct CruiseState {
enabled @0 :Bool;
speed @1 :Float32;
speedCluster @6 :Float32; # Set speed as shown on instrument cluster
available @2 :Bool;
speedOffset @3 :Float32;
standstill @4 :Bool;
nonAdaptive @5 :Bool;
speedLimit @7 :Float32;
}
enum GearShifter {
unknown @0;
park @1;
drive @2;
neutral @3;
reverse @4;
sport @5;
low @6;
brake @7;
eco @8;
manumatic @9;
}
# send on change
struct ButtonEvent {
pressed @0 :Bool;
type @1 :Type;
enum Type {
unknown @0;
leftBlinker @1;
rightBlinker @2;
accelCruise @3;
decelCruise @4;
cancel @5;
altButton1 @6;
altButton2 @7;
altButton3 @8;
setCruise @9;
resumeCruise @10;
gapAdjustCruise @11;
}
}
# deprecated
errorsDEPRECATED @0 :List(CarEvent.EventName);
brakeLightsDEPRECATED @19 :Bool;
steeringRateLimitedDEPRECATED @29 :Bool;
canMonoTimesDEPRECATED @12: List(UInt64);
canRcvTimeoutDEPRECATED @49 :Bool;
}
# ******* radar state @ 20hz *******
struct RadarData @0x888ad6581cf0aacb {
errors @0 :List(Error);
points @1 :List(RadarPoint);
enum Error {
canError @0;
fault @1;
wrongConfig @2;
}
# similar to LiveTracks
# is one timestamp valid for all? I think so
struct RadarPoint {
trackId @0 :UInt64; # no trackId reuse
# these 3 are the minimum required
dRel @1 :Float32; # m from the front bumper of the car
yRel @2 :Float32; # m
vRel @3 :Float32; # m/s
# these are optional and valid if they are not NaN
aRel @4 :Float32; # m/s^2
yvRel @5 :Float32; # m/s
# some radars flag measurements VS estimates
measured @6 :Bool;
}
# deprecated
canMonoTimesDEPRECATED @2 :List(UInt64);
}
# ******* car controls @ 100hz *******
struct CarControl {
# must be true for any actuator commands to work
enabled @0 :Bool;
latActive @11: Bool;
longActive @12: Bool;
vCruise @17 :Float32; # actual set speed
# Actuator commands as computed by controlsd
actuators @6 :Actuators;
# moved to CarOutput
actuatorsOutputDEPRECATED @10 :Actuators;
leftBlinker @15: Bool;
rightBlinker @16: Bool;
orientationNED @13 :List(Float32);
angularVelocity @14 :List(Float32);
cruiseControl @4 :CruiseControl;
hudControl @5 :HUDControl;
struct Actuators {
# range from 0.0 - 1.0
gas @0: Float32;
brake @1: Float32;
# range from -1.0 - 1.0
steer @2: Float32;
# value sent over can to the car
steerOutputCan @8: Float32;
steeringAngleDeg @3: Float32;
curvature @7: Float32;
speed @6: Float32; # m/s
accel @4: Float32; # m/s^2
longControlState @5: LongControlState;
enum LongControlState @0xe40f3a917d908282{
off @0;
pid @1;
stopping @2;
starting @3;
}
}
struct CruiseControl {
cancel @0: Bool;
resume @1: Bool;
override @4: Bool;
speedOverrideDEPRECATED @2: Float32;
accelOverrideDEPRECATED @3: Float32;
}
struct HUDControl {
speedVisible @0: Bool;
setSpeed @1: Float32;
lanesVisible @2: Bool;
leadVisible @3: Bool;
visualAlert @4: VisualAlert;
audibleAlert @5: AudibleAlert;
rightLaneVisible @6: Bool;
leftLaneVisible @7: Bool;
rightLaneDepart @8: Bool;
leftLaneDepart @9: Bool;
leadDistanceBars @10: Int8; # 1-3: 1 is closest, 3 is farthest. some ports may utilize 2-4 bars instead
enum VisualAlert {
# these are the choices from the Honda
# map as good as you can for your car
none @0;
fcw @1;
steerRequired @2;
brakePressed @3;
wrongGear @4;
seatbeltUnbuckled @5;
speedTooHigh @6;
ldw @7;
}
enum AudibleAlert {
none @0;
engage @1;
disengage @2;
refuse @3;
warningSoft @4;
warningImmediate @5;
prompt @6;
promptRepeat @7;
promptDistracted @8;
promptStarting @9;
promptSingleLow @10;
promptSingleHigh @11;
}
}
gasDEPRECATED @1 :Float32;
brakeDEPRECATED @2 :Float32;
steeringTorqueDEPRECATED @3 :Float32;
activeDEPRECATED @7 :Bool;
rollDEPRECATED @8 :Float32;
pitchDEPRECATED @9 :Float32;
}
struct CarOutput {
# Any car specific rate limits or quirks applied by
# the CarController are reflected in actuatorsOutput
# and matches what is sent to the car
actuatorsOutput @0 :CarControl.Actuators;
}
# ****** car param ******
struct CarParams {
carName @0 :Text;
carFingerprint @1 :Text;
fuzzyFingerprint @55 :Bool;
notCar @66 :Bool; # flag for non-car robotics platforms
pcmCruise @3 :Bool; # is openpilot's state tied to the PCM's cruise state?
enableDsu @5 :Bool; # driving support unit
enableBsm @56 :Bool; # blind spot monitoring
flags @64 :UInt32; # flags for car specific quirks
experimentalLongitudinalAvailable @71 :Bool;
pcmCruiseSpeed @74 :Bool; # is openpilot's state tied to the PCM's cruise speed?
customStockLongAvailable @75 :Bool;
spFlags @76 :UInt32; # flags for car specific quirks in sunnypilot
minEnableSpeed @7 :Float32;
minSteerSpeed @8 :Float32;
safetyConfigs @62 :List(SafetyConfig);
alternativeExperience @65 :Int16; # panda flag for features like no disengage on gas
# Car docs fields
maxLateralAccel @68 :Float32;
autoResumeSng @69 :Bool; # describes whether car can resume from a stop automatically
# things about the car in the manual
mass @17 :Float32; # [kg] curb weight: all fluids no cargo
wheelbase @18 :Float32; # [m] distance from rear axle to front axle
centerToFront @19 :Float32; # [m] distance from center of mass to front axle
steerRatio @20 :Float32; # [] ratio of steering wheel angle to front wheel angle
steerRatioRear @21 :Float32; # [] ratio of steering wheel angle to rear wheel angle (usually 0)
# things we can derive
rotationalInertia @22 :Float32; # [kg*m2] body rotational inertia
tireStiffnessFactor @72 :Float32; # scaling factor used in calculating tireStiffness[Front,Rear]
tireStiffnessFront @23 :Float32; # [N/rad] front tire coeff of stiff
tireStiffnessRear @24 :Float32; # [N/rad] rear tire coeff of stiff
longitudinalTuning @25 :LongitudinalPIDTuning;
lateralParams @48 :LateralParams;
lateralTuning :union {
pid @26 :LateralPIDTuning;
indiDEPRECATED @27 :LateralINDITuning;
lqrDEPRECATED @40 :LateralLQRTuning;
torque @67 :LateralTorqueTuning;
}
steerLimitAlert @28 :Bool;
steerLimitTimer @47 :Float32; # time before steerLimitAlert is issued
vEgoStopping @29 :Float32; # Speed at which the car goes into stopping state
vEgoStarting @59 :Float32; # Speed at which the car goes into starting state
stoppingControl @31 :Bool; # Does the car allow full control even at lows speeds when stopping
steerControlType @34 :SteerControlType;
radarUnavailable @35 :Bool; # True when radar objects aren't visible on CAN or aren't parsed out
stopAccel @60 :Float32; # Required acceleration to keep vehicle stationary
stoppingDecelRate @52 :Float32; # m/s^2/s while trying to stop
startAccel @32 :Float32; # Required acceleration to get car moving
startingState @70 :Bool; # Does this car make use of special starting state
steerActuatorDelay @36 :Float32; # Steering wheel actuator delay in seconds
longitudinalActuatorDelay @58 :Float32; # Gas/Brake actuator delay in seconds
openpilotLongitudinalControl @37 :Bool; # is openpilot doing the longitudinal control?
carVin @38 :Text; # VIN number queried during fingerprinting
dashcamOnly @41: Bool;
passive @73: Bool; # is openpilot in control?
transmissionType @43 :TransmissionType;
carFw @44 :List(CarFw);
radarTimeStep @45: Float32 = 0.05; # time delta between radar updates, 20Hz is very standard
fingerprintSource @49: FingerprintSource;
networkLocation @50 :NetworkLocation; # Where Panda/C2 is integrated into the car's CAN network
wheelSpeedFactor @63 :Float32; # Multiplier on wheels speeds to computer actual speeds
struct SafetyConfig {
safetyModel @0 :SafetyModel;
safetyParam @3 :UInt16;
safetyParamDEPRECATED @1 :Int16;
safetyParam2DEPRECATED @2 :UInt32;
}
struct LateralParams {
torqueBP @0 :List(Int32);
torqueV @1 :List(Int32);
}
struct LateralPIDTuning {
kpBP @0 :List(Float32);
kpV @1 :List(Float32);
kiBP @2 :List(Float32);
kiV @3 :List(Float32);
kf @4 :Float32;
}
struct LateralTorqueTuning {
useSteeringAngle @0 :Bool;
kp @1 :Float32;
ki @2 :Float32;
friction @3 :Float32;
kf @4 :Float32;
steeringAngleDeadzoneDeg @5 :Float32;
latAccelFactor @6 :Float32;
latAccelOffset @7 :Float32;
nnModelName @8 :Text;
nnModelFuzzyMatch @9 :Bool;
}
struct LongitudinalPIDTuning {
kpBP @0 :List(Float32);
kpV @1 :List(Float32);
kiBP @2 :List(Float32);
kiV @3 :List(Float32);
kf @6 :Float32;
deadzoneBPDEPRECATED @4 :List(Float32);
deadzoneVDEPRECATED @5 :List(Float32);
}
struct LateralINDITuning {
outerLoopGainBP @4 :List(Float32);
outerLoopGainV @5 :List(Float32);
innerLoopGainBP @6 :List(Float32);
innerLoopGainV @7 :List(Float32);
timeConstantBP @8 :List(Float32);
timeConstantV @9 :List(Float32);
actuatorEffectivenessBP @10 :List(Float32);
actuatorEffectivenessV @11 :List(Float32);
outerLoopGainDEPRECATED @0 :Float32;
innerLoopGainDEPRECATED @1 :Float32;
timeConstantDEPRECATED @2 :Float32;
actuatorEffectivenessDEPRECATED @3 :Float32;
}
struct LateralLQRTuning {
scale @0 :Float32;
ki @1 :Float32;
dcGain @2 :Float32;
# State space system
a @3 :List(Float32);
b @4 :List(Float32);
c @5 :List(Float32);
k @6 :List(Float32); # LQR gain
l @7 :List(Float32); # Kalman gain
}
enum SafetyModel {
silent @0;
hondaNidec @1;
toyota @2;
elm327 @3;
gm @4;
hondaBoschGiraffe @5;
ford @6;
cadillac @7;
hyundai @8;
chrysler @9;
tesla @10;
subaru @11;
gmPassive @12;
mazda @13;
nissan @14;
volkswagen @15;
toyotaIpas @16;
allOutput @17;
gmAscm @18;
noOutput @19; # like silent but without silent CAN TXs
hondaBosch @20;
volkswagenPq @21;
subaruPreglobal @22; # pre-Global platform
hyundaiLegacy @23;
hyundaiCommunity @24;
volkswagenMlb @25;
hongqi @26;
body @27;
hyundaiCanfd @28;
volkswagenMqbEvo @29;
chryslerCusw @30;
psa @31;
}
enum SteerControlType {
torque @0;
angle @1;
curvatureDEPRECATED @2;
}
enum TransmissionType {
unknown @0;
automatic @1; # Traditional auto, including DSG
manual @2; # True "stick shift" only
direct @3; # Electric vehicle or other direct drive
cvt @4;
}
struct CarFw {
ecu @0 :Ecu;
fwVersion @1 :Data;
address @2 :UInt32;
subAddress @3 :UInt8;
responseAddress @4 :UInt32;
request @5 :List(Data);
brand @6 :Text;
bus @7 :UInt8;
logging @8 :Bool;
obdMultiplexing @9 :Bool;
}
enum Ecu {
eps @0;
abs @1;
fwdRadar @2;
fwdCamera @3;
engine @4;
unknown @5;
transmission @8; # Transmission Control Module
hybrid @18; # hybrid control unit, e.g. Chrysler's HCP, Honda's IMA Control Unit, Toyota's hybrid control computer
srs @9; # airbag
gateway @10; # can gateway
hud @11; # heads up display
combinationMeter @12; # instrument cluster
electricBrakeBooster @15;
shiftByWire @16;
adas @19;
cornerRadar @21;
hvac @20;
parkingAdas @7; # parking assist system ECU, e.g. Toyota's IPAS, Hyundai's RSPA, etc.
epb @22; # electronic parking brake
telematics @23;
body @24; # body control module
# Toyota only
dsu @6;
# Honda only
vsa @13; # Vehicle Stability Assist
programmedFuelInjection @14;
debug @17;
}
enum FingerprintSource {
can @0;
fw @1;
fixed @2;
}
enum NetworkLocation {
fwdCamera @0; # Standard/default integration at LKAS camera
gateway @1; # Integration at vehicle's CAN gateway
}
enableGasInterceptorDEPRECATED @2 :Bool;
enableCameraDEPRECATED @4 :Bool;
enableApgsDEPRECATED @6 :Bool;
steerRateCostDEPRECATED @33 :Float32;
isPandaBlackDEPRECATED @39 :Bool;
hasStockCameraDEPRECATED @57 :Bool;
safetyParamDEPRECATED @10 :Int16;
safetyModelDEPRECATED @9 :SafetyModel;
safetyModelPassiveDEPRECATED @42 :SafetyModel = silent;
minSpeedCanDEPRECATED @51 :Float32;
communityFeatureDEPRECATED @46: Bool;
startingAccelRateDEPRECATED @53 :Float32;
steerMaxBPDEPRECATED @11 :List(Float32);
steerMaxVDEPRECATED @12 :List(Float32);
gasMaxBPDEPRECATED @13 :List(Float32);
gasMaxVDEPRECATED @14 :List(Float32);
brakeMaxBPDEPRECATED @15 :List(Float32);
brakeMaxVDEPRECATED @16 :List(Float32);
directAccelControlDEPRECATED @30 :Bool;
maxSteeringAngleDegDEPRECATED @54 :Float32;
longitudinalActuatorDelayLowerBoundDEPRECATEDDEPRECATED @61 :Float32;
}
-222
View File
@@ -1,222 +0,0 @@
using Cxx = import "./include/c++.capnp";
$Cxx.namespace("cereal");
using Car = import "car.capnp";
@0xb526ba661d550a59;
# custom.capnp: a home for empty structs reserved for custom forks
# These structs are guaranteed to remain reserved and empty in mainline
# cereal, so use these if you want custom events in your fork.
# you can rename the struct, but don't change the identifier
enum LongitudinalPersonalitySP {
aggressive @0;
moderate @1;
standard @2;
relaxed @3;
overtake @4;
}
enum AccelerationPersonality {
sport @0;
normal @1;
eco @2;
stock @3;
}
enum ModelGeneration {
default @0;
one @1;
two @2;
three @3;
four @4;
five @5;
}
enum MpcSource {
acc @0;
blended @1;
}
struct ControlsStateSP @0x81c2f05a394cf4af {
lateralState @0 :Text;
personality @8 :LongitudinalPersonalitySP;
dynamicPersonality @9 :Bool;
accelPersonality @10 :AccelerationPersonality;
overtakingAccelerationAssist @11 :Bool;
lateralControlState :union {
indiState @1 :LateralINDIState;
pidState @2 :LateralPIDState;
angleState @3 :LateralAngleState;
debugState @4 :LateralDebugState;
torqueState @5 :LateralTorqueState;
curvatureState @6 :LateralCurvatureState;
lqrStateDEPRECATED @7 :LateralLQRState;
}
struct LateralINDIState {
}
struct LateralPIDState {
}
struct LateralAngleState {
}
struct LateralDebugState {
}
struct LateralTorqueState {
nnLog @0 :List(Float32);
}
struct LateralCurvatureState {
}
struct LateralLQRState {
}
}
struct LongitudinalPlanSP @0xaedffd8f31e7b55d {
visionTurnControllerState @0 :VisionTurnControllerState;
visionTurnSpeed @1 :Float32;
visionCurrentLatAcc @16 :Float32;
visionMaxPredLatAcc @17 :Float32;
speedLimitControlState @2 :SpeedLimitControlState;
speedLimit @3 :Float32;
speedLimitOffset @4 :Float32;
distToSpeedLimit @5 :Float32;
isMapSpeedLimit @6 :Bool;
speedLimitPercOffset @11 :Bool;
speedLimitValueOffset @12 :Float32;
desiredTF @13 :Float32;
notSpeedLimit @14 :Int16;
e2eX @15 :List(Float32);
e2eBlendedDEPRECATED @18 :Text;
e2eStatus @22 :Bool;
mpcSource @23 :MpcSource;
dynamicExperimentalControl @24 :Bool;
distToTurn @7 :Float32;
turnSpeed @8 :Float32;
turnSpeedControlState @9 :SpeedLimitControlState;
turnSign @10 :Int16;
events @19 :List(Car.CarEvent);
longitudinalPlanSource @20 :LongitudinalPlanSource;
personalityDEPRECATED @21 :LongitudinalPersonalitySP;
enum SpeedLimitControlState {
inactive @0; # No speed limit set or not enabled by parameter.
tempInactive @1; # User wants to ignore speed limit until it changes.
adapting @2; # Reducing speed to match new speed limit.
active @3; # Cruising at speed limit.
preActive @4;
}
enum VisionTurnControllerState {
disabled @0; # No predicted substantial turn on vision range or feature disabled.
entering @1; # A substantial turn is predicted ahead, adapting speed to turn comfort levels.
turning @2; # Actively turning. Managing acceleration to provide a roll on turn feeling.
leaving @3; # Road ahead straightens. Start to allow positive acceleration.
}
enum LongitudinalPlanSource {
cruise @0;
lead0 @1;
lead1 @2;
lead2 @3;
e2e @4;
turn @5;
limit @6;
turnlimit @7;
}
}
struct LateralPlanSP @0xf35cc4560bbf6ec2 {
laneWidth @0 :Float32;
lProb @1 :Float32;
rProb @2 :Float32;
dProb @3 :Float32;
dynamicLaneProfile @4 :Int8;
standstillElapsed @5 :Float32;
dynamicLaneProfileStatus @9 :Bool;
dPathWLinesXDEPRECATED @6 :List(Float32);
dPathWLinesYDEPRECATED @7 :List(Float32);
laneChangePrevDEPRECATED @8 :Bool;
laneChangeEdgeBlockDEPRECATED @10 :Bool;
}
struct DriverMonitoringStateSP @0xda96579883444c35 {
handsOnWheelState @0 :HandsOnWheelState;
notModified @1 :Float32;
enum HandsOnWheelState {
none @0; # hand on wheel monitoring inactive
ok @1; # driver has hands on steering wheel
minor @2; # hands off steering wheel for acceptable period
warning @3; # hands off steering wheel for warning period
critical @4; # # hands off steering wheel for critical period
terminal @5; # # hands off steering wheel for terminal period
}
}
struct LiveMapDataSP @0x80ae746ee2596b11 {
speedLimitValid @0 :Bool;
speedLimit @1 :Float32;
speedLimitAheadValid @2 :Bool;
speedLimitAhead @3 :Float32;
speedLimitAheadDistance @4 :Float32;
turnSpeedLimitValid @5 :Bool;
turnSpeedLimit @6 :Float32;
turnSpeedLimitEndDistance @7 :Float32;
turnSpeedLimitSign @8 :Int16;
turnSpeedLimitsAhead @9 :List(Float32);
turnSpeedLimitsAheadDistances @10 :List(Float32);
turnSpeedLimitsAheadSigns @11 :List(Int16);
lastGpsTimestamp @12 :Int64; # Milliseconds since January 1, 1970.
currentRoadName @13 :Text;
lastGpsLatitude @14 :Float64;
lastGpsLongitude @15 :Float64;
lastGpsSpeed @16 :Float32;
lastGpsBearingDeg @17 :Float32;
lastGpsAccuracy @18 :Float32;
lastGpsBearingAccuracyDeg @19 :Float32;
dataType @20 :DataType;
enum DataType {
default @0;
offline @1;
online @2;
}
}
struct E2eLongStateSP @0xa5cd762cd951a455 {
status @0 :UInt16;
}
struct ModelDataV2SP @0xf98d843bfd7004a3 {
laneChangePrev @0 :Bool;
laneChangeEdgeBlock @1 :Bool;
customModel @2 :Bool;
modelGeneration @3 :ModelGeneration;
modelCapabilities @4 :UInt32;
}
struct CustomReserved7 @0xb86e6369214c01c8 {
}
struct CustomReserved8 @0xf416ec09499d9d19 {
}
struct CustomReserved9 @0xa1680744031fdb2d {
}
-26
View File
@@ -1,26 +0,0 @@
# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
# Licensed under the MIT License:
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
@0xbdf87d7bb8304e81;
$namespace("capnp::annotations");
annotation namespace(file): Text;
annotation name(field, enumerant, struct, enum, interface, method, param, group, union): Text;
-574
View File
@@ -1,574 +0,0 @@
using Cxx = import "./include/c++.capnp";
$Cxx.namespace("cereal");
@0x80ef1ec4889c2a63;
# legacy.capnp: a home for deprecated structs
struct LogRotate @0x9811e1f38f62f2d1 {
segmentNum @0 :Int32;
path @1 :Text;
}
struct LiveUI @0xc08240f996aefced {
rearViewCam @0 :Bool;
alertText1 @1 :Text;
alertText2 @2 :Text;
awarenessStatus @3 :Float32;
}
struct UiLayoutState @0x88dcce08ad29dda0 {
activeApp @0 :App;
sidebarCollapsed @1 :Bool;
mapEnabled @2 :Bool;
mockEngaged @3 :Bool;
enum App @0x9917470acf94d285 {
home @0;
music @1;
nav @2;
settings @3;
none @4;
}
}
struct OrbslamCorrection @0x8afd33dc9b35e1aa {
correctionMonoTime @0 :UInt64;
prePositionECEF @1 :List(Float64);
postPositionECEF @2 :List(Float64);
prePoseQuatECEF @3 :List(Float32);
postPoseQuatECEF @4 :List(Float32);
numInliers @5 :UInt32;
}
struct EthernetPacket @0xa99a9d5b33cf5859 {
pkt @0 :Data;
ts @1 :Float32;
}
struct CellInfo @0xcff7566681c277ce {
timestamp @0 :UInt64;
repr @1 :Text; # android toString() for now
}
struct WifiScan @0xd4df5a192382ba0b {
bssid @0 :Text;
ssid @1 :Text;
capabilities @2 :Text;
frequency @3 :Int32;
level @4 :Int32;
timestamp @5 :Int64;
centerFreq0 @6 :Int32;
centerFreq1 @7 :Int32;
channelWidth @8 :ChannelWidth;
operatorFriendlyName @9 :Text;
venueName @10 :Text;
is80211mcResponder @11 :Bool;
passpoint @12 :Bool;
distanceCm @13 :Int32;
distanceSdCm @14 :Int32;
enum ChannelWidth @0xcb6a279f015f6b51 {
w20Mhz @0;
w40Mhz @1;
w80Mhz @2;
w160Mhz @3;
w80Plus80Mhz @4;
}
}
struct LiveEventData @0x94b7baa90c5c321e {
name @0 :Text;
value @1 :Int32;
}
struct ModelData @0xb8aad62cffef28a9 {
frameId @0 :UInt32;
frameAge @12 :UInt32;
frameDropPerc @13 :Float32;
timestampEof @9 :UInt64;
modelExecutionTime @14 :Float32;
gpuExecutionTime @16 :Float32;
rawPred @15 :Data;
path @1 :PathData;
leftLane @2 :PathData;
rightLane @3 :PathData;
lead @4 :LeadData;
freePath @6 :List(Float32);
settings @5 :ModelSettings;
leadFuture @7 :LeadData;
speed @8 :List(Float32);
meta @10 :MetaData;
longitudinal @11 :LongitudinalData;
struct PathData @0x8817eeea389e9f08 {
points @0 :List(Float32);
prob @1 :Float32;
std @2 :Float32;
stds @3 :List(Float32);
poly @4 :List(Float32);
validLen @5 :Float32;
}
struct LeadData @0xd1c9bef96d26fa91 {
dist @0 :Float32;
prob @1 :Float32;
std @2 :Float32;
relVel @3 :Float32;
relVelStd @4 :Float32;
relY @5 :Float32;
relYStd @6 :Float32;
relA @7 :Float32;
relAStd @8 :Float32;
}
struct ModelSettings @0xa26e3710efd3e914 {
bigBoxX @0 :UInt16;
bigBoxY @1 :UInt16;
bigBoxWidth @2 :UInt16;
bigBoxHeight @3 :UInt16;
boxProjection @4 :List(Float32);
yuvCorrection @5 :List(Float32);
inputTransform @6 :List(Float32);
}
struct MetaData @0x9744f25fb60f2bf8 {
engagedProb @0 :Float32;
desirePrediction @1 :List(Float32);
brakeDisengageProb @2 :Float32;
gasDisengageProb @3 :Float32;
steerOverrideProb @4 :Float32;
desireState @5 :List(Float32);
}
struct LongitudinalData @0xf98f999c6a071122 {
distances @2 :List(Float32);
speeds @0 :List(Float32);
accelerations @1 :List(Float32);
}
}
struct ECEFPoint @0xc25bbbd524983447 {
x @0 :Float64;
y @1 :Float64;
z @2 :Float64;
}
struct ECEFPointDEPRECATED @0xe10e21168db0c7f7 {
x @0 :Float32;
y @1 :Float32;
z @2 :Float32;
}
struct GPSPlannerPoints @0xab54c59699f8f9f3 {
curPosDEPRECATED @0 :ECEFPointDEPRECATED;
pointsDEPRECATED @1 :List(ECEFPointDEPRECATED);
curPos @6 :ECEFPoint;
points @7 :List(ECEFPoint);
valid @2 :Bool;
trackName @3 :Text;
speedLimit @4 :Float32;
accelTarget @5 :Float32;
}
struct GPSPlannerPlan @0xf5ad1d90cdc1dd6b {
valid @0 :Bool;
poly @1 :List(Float32);
trackName @2 :Text;
speed @3 :Float32;
acceleration @4 :Float32;
pointsDEPRECATED @5 :List(ECEFPointDEPRECATED);
points @6 :List(ECEFPoint);
xLookahead @7 :Float32;
}
struct UiNavigationEvent @0x90c8426c3eaddd3b {
type @0: Type;
status @1: Status;
distanceTo @2: Float32;
endRoadPointDEPRECATED @3: ECEFPointDEPRECATED;
endRoadPoint @4: ECEFPoint;
enum Type @0xe8db07dcf8fcea05 {
none @0;
laneChangeLeft @1;
laneChangeRight @2;
mergeLeft @3;
mergeRight @4;
turnLeft @5;
turnRight @6;
}
enum Status @0xb9aa88c75ef99a1f {
none @0;
passive @1;
approaching @2;
active @3;
}
}
struct LiveLocationData @0xb99b2bc7a57e8128 {
status @0 :UInt8;
# 3D fix
lat @1 :Float64;
lon @2 :Float64;
alt @3 :Float32; # m
# speed
speed @4 :Float32; # m/s
# NED velocity components
vNED @5 :List(Float32);
# roll, pitch, heading (x,y,z)
roll @6 :Float32; # WRT to center of earth?
pitch @7 :Float32; # WRT to center of earth?
heading @8 :Float32; # WRT to north?
# what are these?
wanderAngle @9 :Float32;
trackAngle @10 :Float32;
# car frame -- https://upload.wikimedia.org/wikipedia/commons/f/f5/RPY_angles_of_cars.png
# gyro, in car frame, deg/s
gyro @11 :List(Float32);
# accel, in car frame, m/s^2
accel @12 :List(Float32);
accuracy @13 :Accuracy;
source @14 :SensorSource;
# if we are fixing a location in the past
fixMonoTime @15 :UInt64;
gpsWeek @16 :Int32;
timeOfWeek @17 :Float64;
positionECEF @18 :List(Float64);
poseQuatECEF @19 :List(Float32);
pitchCalibration @20 :Float32;
yawCalibration @21 :Float32;
imuFrame @22 :List(Float32);
struct Accuracy @0x943dc4625473b03f {
pNEDError @0 :List(Float32);
vNEDError @1 :List(Float32);
rollError @2 :Float32;
pitchError @3 :Float32;
headingError @4 :Float32;
ellipsoidSemiMajorError @5 :Float32;
ellipsoidSemiMinorError @6 :Float32;
ellipsoidOrientationError @7 :Float32;
}
enum SensorSource @0xc871d3cc252af657 {
applanix @0;
kalman @1;
orbslam @2;
timing @3;
dummy @4;
}
}
struct OrbOdometry @0xd7700859ed1f5b76 {
# timing first
startMonoTime @0 :UInt64;
endMonoTime @1 :UInt64;
# fundamental matrix and error
f @2: List(Float64);
err @3: Float64;
# number of inlier points
inliers @4: Int32;
# for debug only
# indexed by endMonoTime features
# value is startMonoTime feature match
# -1 if no match
matches @5: List(Int16);
}
struct OrbFeatures @0xcd60164a8a0159ef {
timestampEof @0 :UInt64;
# transposed arrays of normalized image coordinates
# len(xs) == len(ys) == len(descriptors) * 32
xs @1 :List(Float32);
ys @2 :List(Float32);
descriptors @3 :Data;
octaves @4 :List(Int8);
# match index to last OrbFeatures
# -1 if no match
timestampLastEof @5 :UInt64;
matches @6: List(Int16);
}
struct OrbFeaturesSummary @0xd500d30c5803fa4f {
timestampEof @0 :UInt64;
timestampLastEof @1 :UInt64;
featureCount @2 :UInt16;
matchCount @3 :UInt16;
computeNs @4 :UInt64;
}
struct OrbKeyFrame @0xc8233c0345e27e24 {
# this is a globally unique id for the KeyFrame
id @0: UInt64;
# this is the location of the KeyFrame
pos @1: ECEFPoint;
# these are the features in the world
# len(dpos) == len(descriptors) * 32
dpos @2 :List(ECEFPoint);
descriptors @3 :Data;
}
struct KalmanOdometry @0x92e21bb7ea38793a {
trans @0 :List(Float32); # m/s in device frame
rot @1 :List(Float32); # rad/s in device frame
transStd @2 :List(Float32); # std m/s in device frame
rotStd @3 :List(Float32); # std rad/s in device frame
}
struct OrbObservation @0x9b326d4e436afec7 {
observationMonoTime @0 :UInt64;
normalizedCoordinates @1 :List(Float32);
locationECEF @2 :List(Float64);
matchDistance @3: UInt32;
}
struct CalibrationFeatures @0x8fdfadb254ea867a {
frameId @0 :UInt32;
p0 @1 :List(Float32);
p1 @2 :List(Float32);
status @3 :List(Int8);
}
struct NavStatus @0xbd8822120928120c {
isNavigating @0 :Bool;
currentAddress @1 :Address;
struct Address @0xce7cd672cacc7814 {
title @0 :Text;
lat @1 :Float64;
lng @2 :Float64;
house @3 :Text;
address @4 :Text;
street @5 :Text;
city @6 :Text;
state @7 :Text;
country @8 :Text;
}
}
struct NavUpdate @0xdb98be6565516acb {
isNavigating @0 :Bool;
curSegment @1 :Int32;
segments @2 :List(Segment);
struct LatLng @0x9eaef9187cadbb9b {
lat @0 :Float64;
lng @1 :Float64;
}
struct Segment @0xa5b39b4fc4d7da3f {
from @0 :LatLng;
to @1 :LatLng;
updateTime @2 :Int32;
distance @3 :Int32;
crossTime @4 :Int32;
exitNo @5 :Int32;
instruction @6 :Instruction;
parts @7 :List(LatLng);
enum Instruction @0xc5417a637451246f {
turnLeft @0;
turnRight @1;
keepLeft @2;
keepRight @3;
straight @4;
roundaboutExitNumber @5;
roundaboutExit @6;
roundaboutTurnLeft @7;
unkn8 @8;
roundaboutStraight @9;
unkn10 @10;
roundaboutTurnRight @11;
unkn12 @12;
roundaboutUturn @13;
unkn14 @14;
arrive @15;
exitLeft @16;
exitRight @17;
unkn18 @18;
uturn @19;
# ...
}
}
}
struct TrafficEvent @0xacfa74a094e62626 {
type @0 :Type;
distance @1 :Float32;
action @2 :Action;
resuming @3 :Bool;
enum Type @0xd85d75253435bf4b {
stopSign @0;
lightRed @1;
lightYellow @2;
lightGreen @3;
stopLight @4;
}
enum Action @0xa6f6ce72165ccb49 {
none @0;
yield @1;
stop @2;
resumeReady @3;
}
}
struct AndroidGnss @0xdfdf30d03fc485bd {
union {
measurements @0 :Measurements;
navigationMessage @1 :NavigationMessage;
}
struct Measurements @0xa20710d4f428d6cd {
clock @0 :Clock;
measurements @1 :List(Measurement);
struct Clock @0xa0e27b453a38f450 {
timeNanos @0 :Int64;
hardwareClockDiscontinuityCount @1 :Int32;
hasTimeUncertaintyNanos @2 :Bool;
timeUncertaintyNanos @3 :Float64;
hasLeapSecond @4 :Bool;
leapSecond @5 :Int32;
hasFullBiasNanos @6 :Bool;
fullBiasNanos @7 :Int64;
hasBiasNanos @8 :Bool;
biasNanos @9 :Float64;
hasBiasUncertaintyNanos @10 :Bool;
biasUncertaintyNanos @11 :Float64;
hasDriftNanosPerSecond @12 :Bool;
driftNanosPerSecond @13 :Float64;
hasDriftUncertaintyNanosPerSecond @14 :Bool;
driftUncertaintyNanosPerSecond @15 :Float64;
}
struct Measurement @0xd949bf717d77614d {
svId @0 :Int32;
constellation @1 :Constellation;
timeOffsetNanos @2 :Float64;
state @3 :Int32;
receivedSvTimeNanos @4 :Int64;
receivedSvTimeUncertaintyNanos @5 :Int64;
cn0DbHz @6 :Float64;
pseudorangeRateMetersPerSecond @7 :Float64;
pseudorangeRateUncertaintyMetersPerSecond @8 :Float64;
accumulatedDeltaRangeState @9 :Int32;
accumulatedDeltaRangeMeters @10 :Float64;
accumulatedDeltaRangeUncertaintyMeters @11 :Float64;
hasCarrierFrequencyHz @12 :Bool;
carrierFrequencyHz @13 :Float32;
hasCarrierCycles @14 :Bool;
carrierCycles @15 :Int64;
hasCarrierPhase @16 :Bool;
carrierPhase @17 :Float64;
hasCarrierPhaseUncertainty @18 :Bool;
carrierPhaseUncertainty @19 :Float64;
hasSnrInDb @20 :Bool;
snrInDb @21 :Float64;
multipathIndicator @22 :MultipathIndicator;
enum Constellation @0x9ef1f3ff0deb5ffb {
unknown @0;
gps @1;
sbas @2;
glonass @3;
qzss @4;
beidou @5;
galileo @6;
}
enum State @0xcbb9490adce12d72 {
unknown @0;
codeLock @1;
bitSync @2;
subframeSync @3;
towDecoded @4;
msecAmbiguous @5;
symbolSync @6;
gloStringSync @7;
gloTodDecoded @8;
bdsD2BitSync @9;
bdsD2SubframeSync @10;
galE1bcCodeLock @11;
galE1c2ndCodeLock @12;
galE1bPageSync @13;
sbasSync @14;
}
enum MultipathIndicator @0xc04e7b6231d4caa8 {
unknown @0;
detected @1;
notDetected @2;
}
}
}
struct NavigationMessage @0xe2517b083095fd4e {
type @0 :Int32;
svId @1 :Int32;
messageId @2 :Int32;
submessageId @3 :Int32;
data @4 :Data;
status @5 :Status;
enum Status @0xec1ff7996b35366f {
unknown @0;
parityPassed @1;
parityRebuilt @2;
}
}
}
struct LidarPts @0xe3d6685d4e9d8f7a {
r @0 :List(UInt16); # uint16 m*500.0
theta @1 :List(UInt16); # uint16 deg*100.0
reflect @2 :List(UInt8); # uint8 0-255
# For storing out of file.
idx @3 :UInt64;
# For storing in file
pkt @4 :Data;
}
-2437
View File
File diff suppressed because it is too large Load Diff
-49
View File
@@ -1,49 +0,0 @@
using Cxx = import "./include/c++.capnp";
$Cxx.namespace("cereal");
@0xa086df597ef5d7a0;
# Geometry
struct Point {
x @0: Float64;
y @1: Float64;
z @2: Float64;
}
struct PolyLine {
points @0: List(Point);
}
# Map features
struct Lane {
id @0 :Text;
leftBoundary @1 :LaneBoundary;
rightBoundary @2 :LaneBoundary;
leftAdjacentId @3 :Text;
rightAdjacentId @4 :Text;
inboundIds @5 :List(Text);
outboundIds @6 :List(Text);
struct LaneBoundary {
polyLine @0 :PolyLine;
startHeading @1 :Float32; # WRT north
}
}
# Map tiles
struct TileSummary {
version @0 :Text;
updatedAt @1 :UInt64; # Millis since epoch
level @2 :UInt8;
x @3 :UInt16;
y @4 :UInt16;
}
struct MapTile {
summary @0 :TileSummary;
lanes @1 :List(Lane);
}
-257
View File
@@ -1,257 +0,0 @@
# must be built with scons
from msgq.ipc_pyx import Context, Poller, SubSocket, PubSocket, SocketEventHandle, toggle_fake_events, \
set_fake_prefix, get_fake_prefix, delete_fake_prefix, wait_for_one_event
from msgq.ipc_pyx import MultiplePublishersError, IpcError
from msgq import fake_event_handle, pub_sock, sub_sock, drain_sock_raw
import msgq
import os
import capnp
import time
from typing import Optional, List, Union, Dict, Deque
from collections import deque
from cereal import log
from cereal.services import SERVICE_LIST
NO_TRAVERSAL_LIMIT = 2**64-1
def reset_context():
msgq.context = Context()
def log_from_bytes(dat: bytes, struct: capnp.lib.capnp._StructModule = log.Event) -> capnp.lib.capnp._DynamicStructReader:
with struct.from_bytes(dat, traversal_limit_in_words=NO_TRAVERSAL_LIMIT) as msg:
return msg
def new_message(service: Optional[str], size: Optional[int] = None, **kwargs) -> capnp.lib.capnp._DynamicStructBuilder:
args = {
'valid': False,
'logMonoTime': int(time.monotonic() * 1e9),
**kwargs
}
dat = log.Event.new_message(**args)
if service is not None:
if size is None:
dat.init(service)
else:
dat.init(service, size)
return dat
def drain_sock(sock: SubSocket, wait_for_one: bool = False) -> List[capnp.lib.capnp._DynamicStructReader]:
"""Receive all message currently available on the queue"""
msgs = drain_sock_raw(sock, wait_for_one=wait_for_one)
return [log_from_bytes(m) for m in msgs]
# TODO: print when we drop packets?
def recv_sock(sock: SubSocket, wait: bool = False) -> Optional[capnp.lib.capnp._DynamicStructReader]:
"""Same as drain sock, but only returns latest message. Consider using conflate instead."""
dat = None
while 1:
if wait and dat is None:
recv = sock.receive()
else:
recv = sock.receive(non_blocking=True)
if recv is None: # Timeout hit
break
dat = recv
if dat is not None:
dat = log_from_bytes(dat)
return dat
def recv_one(sock: SubSocket) -> Optional[capnp.lib.capnp._DynamicStructReader]:
dat = sock.receive()
if dat is not None:
dat = log_from_bytes(dat)
return dat
def recv_one_or_none(sock: SubSocket) -> Optional[capnp.lib.capnp._DynamicStructReader]:
dat = sock.receive(non_blocking=True)
if dat is not None:
dat = log_from_bytes(dat)
return dat
def recv_one_retry(sock: SubSocket) -> capnp.lib.capnp._DynamicStructReader:
"""Keep receiving until we get a message"""
while True:
dat = sock.receive()
if dat is not None:
return log_from_bytes(dat)
class SubMaster:
def __init__(self, services: List[str], poll: Optional[str] = None,
ignore_alive: Optional[List[str]] = None, ignore_avg_freq: Optional[List[str]] = None,
ignore_valid: Optional[List[str]] = None, addr: str = "127.0.0.1", frequency: Optional[float] = None):
self.frame = -1
self.seen = {s: False for s in services}
self.updated = {s: False for s in services}
self.recv_time = {s: 0. for s in services}
self.recv_frame = {s: 0 for s in services}
self.alive = {s: False for s in services}
self.freq_ok = {s: False for s in services}
self.recv_dts: Dict[str, Deque[float]] = {}
self.sock = {}
self.data = {}
self.valid = {}
self.logMonoTime = {}
self.max_freq = {}
self.min_freq = {}
self.poller = Poller()
polled_services = set([poll, ] if poll is not None else services)
self.non_polled_services = set(services) - polled_services
self.ignore_average_freq = [] if ignore_avg_freq is None else ignore_avg_freq
self.ignore_alive = [] if ignore_alive is None else ignore_alive
self.ignore_valid = [] if ignore_valid is None else ignore_valid
self.simulation = bool(int(os.getenv("SIMULATION", "0")))
# if freq and poll aren't specified, assume the max to be conservative
assert frequency is None or poll is None, "Do not specify 'frequency' - frequency of the polled service will be used."
self.update_freq = frequency or max([SERVICE_LIST[s].frequency for s in polled_services])
for s in services:
p = self.poller if s not in self.non_polled_services else None
self.sock[s] = sub_sock(s, poller=p, addr=addr, conflate=True)
try:
data = new_message(s)
except capnp.lib.capnp.KjException:
data = new_message(s, 0) # lists
self.data[s] = getattr(data.as_reader(), s)
self.logMonoTime[s] = 0
self.valid[s] = True # FIXME: this should default to False
freq = max(min([SERVICE_LIST[s].frequency, self.update_freq]), 1.)
if s == poll:
max_freq = freq
min_freq = freq
else:
max_freq = min(freq, self.update_freq)
if SERVICE_LIST[s].frequency >= 2*self.update_freq:
min_freq = self.update_freq
elif self.update_freq >= 2*SERVICE_LIST[s].frequency:
min_freq = freq
else:
min_freq = min(freq, freq / 2.)
self.max_freq[s] = max_freq*1.2
self.min_freq[s] = min_freq*0.8
self.recv_dts[s] = deque(maxlen=int(10*freq))
def __getitem__(self, s: str) -> capnp.lib.capnp._DynamicStructReader:
return self.data[s]
def _check_avg_freq(self, s: str) -> bool:
return SERVICE_LIST[s].frequency > 0.99 and (s not in self.ignore_average_freq) and (s not in self.ignore_alive)
def update(self, timeout: int = 100) -> None:
msgs = []
for sock in self.poller.poll(timeout):
msgs.append(recv_one_or_none(sock))
# non-blocking receive for non-polled sockets
for s in self.non_polled_services:
msgs.append(recv_one_or_none(self.sock[s]))
self.update_msgs(time.monotonic(), msgs)
def update_msgs(self, cur_time: float, msgs: List[capnp.lib.capnp._DynamicStructReader]) -> None:
self.frame += 1
self.updated = dict.fromkeys(self.updated, False)
for msg in msgs:
if msg is None:
continue
s = msg.which()
self.seen[s] = True
self.updated[s] = True
if self.recv_time[s] > 1e-5:
self.recv_dts[s].append(cur_time - self.recv_time[s])
self.recv_time[s] = cur_time
self.recv_frame[s] = self.frame
self.data[s] = getattr(msg, s)
self.logMonoTime[s] = msg.logMonoTime
self.valid[s] = msg.valid
for s in self.data:
if SERVICE_LIST[s].frequency > 1e-5 and not self.simulation:
# alive if delay is within 10x the expected frequency
self.alive[s] = (cur_time - self.recv_time[s]) < (10. / SERVICE_LIST[s].frequency)
# check average frequency; slow to fall, quick to recover
dts = self.recv_dts[s]
assert dts.maxlen is not None
recent_dts = list(dts)[-int(dts.maxlen / 10):]
try:
avg_freq = 1 / (sum(dts) / len(dts))
avg_freq_recent = 1 / (sum(recent_dts) / len(recent_dts))
except ZeroDivisionError:
avg_freq = 0
avg_freq_recent = 0
avg_freq_ok = self.min_freq[s] <= avg_freq <= self.max_freq[s]
recent_freq_ok = self.min_freq[s] <= avg_freq_recent <= self.max_freq[s]
self.freq_ok[s] = avg_freq_ok or recent_freq_ok
else:
self.freq_ok[s] = True
if self.simulation:
self.alive[s] = self.seen[s] # alive is defined as seen when simulation flag set
else:
self.alive[s] = True
def all_alive(self, service_list: Optional[List[str]] = None) -> bool:
if service_list is None:
service_list = list(self.sock.keys())
return all(self.alive[s] for s in service_list if s not in self.ignore_alive)
def all_freq_ok(self, service_list: Optional[List[str]] = None) -> bool:
if service_list is None:
service_list = list(self.sock.keys())
return all(self.freq_ok[s] for s in service_list if self._check_avg_freq(s))
def all_valid(self, service_list: Optional[List[str]] = None) -> bool:
if service_list is None:
service_list = list(self.sock.keys())
return all(self.valid[s] for s in service_list if s not in self.ignore_valid)
def all_checks(self, service_list: Optional[List[str]] = None) -> bool:
return self.all_alive(service_list) and self.all_freq_ok(service_list) and self.all_valid(service_list)
class PubMaster:
def __init__(self, services: List[str]):
self.sock = {}
for s in services:
self.sock[s] = pub_sock(s)
def send(self, s: str, dat: Union[bytes, capnp.lib.capnp._DynamicStructBuilder]) -> None:
if not isinstance(dat, bytes):
dat = dat.to_bytes()
self.sock[s].send(dat)
def wait_for_readers_to_update(self, s: str, timeout: int, dt: float = 0.05) -> bool:
for _ in range(int(timeout*(1./dt))):
if self.sock[s].all_readers_updated():
return True
time.sleep(dt)
return False
def all_readers_updated(self, s: str) -> bool:
return self.sock[s].all_readers_updated() # type: ignore
-92
View File
@@ -1,92 +0,0 @@
#include <algorithm>
#include <cassert>
#include <csignal>
#include <iostream>
#include <map>
#include <string>
typedef void (*sighandler_t)(int sig);
#include "cereal/services.h"
#include "msgq/impl_msgq.h"
#include "msgq/impl_zmq.h"
std::atomic<bool> do_exit = false;
static void set_do_exit(int sig) {
do_exit = true;
}
void sigpipe_handler(int sig) {
assert(sig == SIGPIPE);
std::cout << "SIGPIPE received" << std::endl;
}
static std::vector<std::string> get_services(std::string whitelist_str, bool zmq_to_msgq) {
std::vector<std::string> service_list;
for (const auto& it : services) {
std::string name = it.second.name;
bool in_whitelist = whitelist_str.find(name) != std::string::npos;
if (name == "plusFrame" || name == "uiLayoutState" || (zmq_to_msgq && !in_whitelist)) {
continue;
}
service_list.push_back(name);
}
return service_list;
}
int main(int argc, char** argv) {
signal(SIGPIPE, (sighandler_t)sigpipe_handler);
signal(SIGINT, (sighandler_t)set_do_exit);
signal(SIGTERM, (sighandler_t)set_do_exit);
bool zmq_to_msgq = argc > 2;
std::string ip = zmq_to_msgq ? argv[1] : "127.0.0.1";
std::string whitelist_str = zmq_to_msgq ? std::string(argv[2]) : "";
Poller *poller;
Context *pub_context;
Context *sub_context;
if (zmq_to_msgq) { // republishes zmq debugging messages as msgq
poller = new ZMQPoller();
pub_context = new MSGQContext();
sub_context = new ZMQContext();
} else {
poller = new MSGQPoller();
pub_context = new ZMQContext();
sub_context = new MSGQContext();
}
std::map<SubSocket*, PubSocket*> sub2pub;
for (auto endpoint : get_services(whitelist_str, zmq_to_msgq)) {
PubSocket * pub_sock;
SubSocket * sub_sock;
if (zmq_to_msgq) {
pub_sock = new MSGQPubSocket();
sub_sock = new ZMQSubSocket();
} else {
pub_sock = new ZMQPubSocket();
sub_sock = new MSGQSubSocket();
}
pub_sock->connect(pub_context, endpoint);
sub_sock->connect(sub_context, endpoint, ip, false);
poller->registerSocket(sub_sock);
sub2pub[sub_sock] = pub_sock;
}
while (!do_exit) {
for (auto sub_sock : poller->poll(100)) {
Message * msg = sub_sock->receive();
if (msg == NULL) continue;
int ret;
do {
ret = sub2pub[sub_sock]->sendMessage(msg);
} while (ret == -1 && errno == EINTR && !do_exit);
assert(ret >= 0 || do_exit);
delete msg;
if (do_exit) break;
}
}
return 0;
}
-102
View File
@@ -1,102 +0,0 @@
#pragma once
#include <cstddef>
#include <map>
#include <string>
#include <vector>
#include <utility>
#include <capnp/serialize.h>
#include "cereal/gen/cpp/log.capnp.h"
#include "common/timing.h"
#include "msgq/ipc.h"
class SubMaster {
public:
SubMaster(const std::vector<const char *> &service_list, const std::vector<const char *> &poll = {},
const char *address = nullptr, const std::vector<const char *> &ignore_alive = {});
void update(int timeout = 1000);
void update_msgs(uint64_t current_time, const std::vector<std::pair<std::string, cereal::Event::Reader>> &messages);
inline bool allAlive(const std::vector<const char *> &service_list = {}) { return all_(service_list, false, true); }
inline bool allValid(const std::vector<const char *> &service_list = {}) { return all_(service_list, true, false); }
inline bool allAliveAndValid(const std::vector<const char *> &service_list = {}) { return all_(service_list, true, true); }
void drain();
~SubMaster();
uint64_t frame = 0;
bool updated(const char *name) const;
bool alive(const char *name) const;
bool valid(const char *name) const;
uint64_t rcv_frame(const char *name) const;
uint64_t rcv_time(const char *name) const;
cereal::Event::Reader &operator[](const char *name) const;
private:
bool all_(const std::vector<const char *> &service_list, bool valid, bool alive);
Poller *poller_ = nullptr;
struct SubMessage;
std::map<SubSocket *, SubMessage *> messages_;
std::map<std::string, SubMessage *> services_;
};
class MessageBuilder : public capnp::MallocMessageBuilder {
public:
MessageBuilder() = default;
cereal::Event::Builder initEvent(bool valid = true) {
cereal::Event::Builder event = initRoot<cereal::Event>();
event.setLogMonoTime(nanos_since_boot());
event.setValid(valid);
return event;
}
kj::ArrayPtr<capnp::byte> toBytes() {
heapArray_ = capnp::messageToFlatArray(*this);
return heapArray_.asBytes();
}
size_t getSerializedSize() {
return capnp::computeSerializedSizeInWords(*this) * sizeof(capnp::word);
}
int serializeToBuffer(unsigned char *buffer, size_t buffer_size) {
size_t serialized_size = getSerializedSize();
if (serialized_size > buffer_size) { return -1; }
kj::ArrayOutputStream out(kj::ArrayPtr<capnp::byte>(buffer, buffer_size));
capnp::writeMessage(out, *this);
return serialized_size;
}
private:
kj::Array<capnp::word> heapArray_;
};
class PubMaster {
public:
PubMaster(const std::vector<const char *> &service_list);
inline int send(const char *name, capnp::byte *data, size_t size) { return sockets_.at(name)->send((char *)data, size); }
int send(const char *name, MessageBuilder &msg);
~PubMaster();
private:
std::map<std::string, PubSocket *> sockets_;
};
class AlignedBuffer {
public:
kj::ArrayPtr<const capnp::word> align(const char *data, const size_t size) {
words_size = size / sizeof(capnp::word) + 1;
if (aligned_buf.size() < words_size) {
aligned_buf = kj::heapArray<capnp::word>(words_size < 512 ? 512 : words_size);
}
memcpy(aligned_buf.begin(), data, size);
return aligned_buf.slice(0, words_size);
}
inline kj::ArrayPtr<const capnp::word> align(Message *m) {
return align(m->getData(), m->getSize());
}
private:
kj::Array<capnp::word> aligned_buf;
size_t words_size;
};
-203
View File
@@ -1,203 +0,0 @@
#include <assert.h>
#include <stdlib.h>
#include <string>
#include <mutex>
#include "cereal/services.h"
#include "cereal/messaging/messaging.h"
const bool SIMULATION = (getenv("SIMULATION") != nullptr) && (std::string(getenv("SIMULATION")) == "1");
static inline bool inList(const std::vector<const char *> &list, const char *value) {
for (auto &v : list) {
if (strcmp(value, v) == 0) return true;
}
return false;
}
class MessageContext {
public:
MessageContext() : ctx_(nullptr) {}
~MessageContext() { delete ctx_; }
inline Context *context() {
std::call_once(init_flag, [=]() { ctx_ = Context::create(); });
return ctx_;
}
private:
Context *ctx_;
std::once_flag init_flag;
};
MessageContext message_context;
struct SubMaster::SubMessage {
std::string name;
SubSocket *socket = nullptr;
int freq = 0;
bool updated = false, alive = false, valid = true, ignore_alive;
uint64_t rcv_time = 0, rcv_frame = 0;
void *allocated_msg_reader = nullptr;
bool is_polled = false;
capnp::FlatArrayMessageReader *msg_reader = nullptr;
AlignedBuffer aligned_buf;
cereal::Event::Reader event;
};
SubMaster::SubMaster(const std::vector<const char *> &service_list, const std::vector<const char *> &poll,
const char *address, const std::vector<const char *> &ignore_alive) {
poller_ = Poller::create();
for (auto name : service_list) {
assert(services.count(std::string(name)) > 0);
service serv = services.at(std::string(name));
SubSocket *socket = SubSocket::create(message_context.context(), name, address ? address : "127.0.0.1", true);
assert(socket != 0);
bool is_polled = inList(poll, name) || poll.empty();
if (is_polled) poller_->registerSocket(socket);
SubMessage *m = new SubMessage{
.name = name,
.socket = socket,
.freq = serv.frequency,
.ignore_alive = inList(ignore_alive, name),
.allocated_msg_reader = malloc(sizeof(capnp::FlatArrayMessageReader)),
.is_polled = is_polled};
m->msg_reader = new (m->allocated_msg_reader) capnp::FlatArrayMessageReader({});
messages_[socket] = m;
services_[name] = m;
}
}
void SubMaster::update(int timeout) {
for (auto &kv : messages_) kv.second->updated = false;
auto sockets = poller_->poll(timeout);
// add non-polled sockets for non-blocking receive
for (auto &kv : messages_) {
SubMessage *m = kv.second;
SubSocket *s = kv.first;
if (!m->is_polled) sockets.push_back(s);
}
uint64_t current_time = nanos_since_boot();
std::vector<std::pair<std::string, cereal::Event::Reader>> messages;
for (auto s : sockets) {
Message *msg = s->receive(true);
if (msg == nullptr) continue;
SubMessage *m = messages_.at(s);
m->msg_reader->~FlatArrayMessageReader();
capnp::ReaderOptions options;
options.traversalLimitInWords = kj::maxValue; // Don't limit
m->msg_reader = new (m->allocated_msg_reader) capnp::FlatArrayMessageReader(m->aligned_buf.align(msg), options);
delete msg;
messages.push_back({m->name, m->msg_reader->getRoot<cereal::Event>()});
}
update_msgs(current_time, messages);
}
void SubMaster::update_msgs(uint64_t current_time, const std::vector<std::pair<std::string, cereal::Event::Reader>> &messages){
if (++frame == UINT64_MAX) frame = 1;
for (auto &kv : messages) {
auto m_find = services_.find(kv.first);
if (m_find == services_.end()){
continue;
}
SubMessage *m = m_find->second;
m->event = kv.second;
m->updated = true;
m->rcv_time = current_time;
m->rcv_frame = frame;
m->valid = m->event.getValid();
if (SIMULATION) m->alive = true;
}
if (!SIMULATION) {
for (auto &kv : messages_) {
SubMessage *m = kv.second;
m->alive = (m->freq <= (1e-5) || ((current_time - m->rcv_time) * (1e-9)) < (10.0 / m->freq));
}
}
}
bool SubMaster::all_(const std::vector<const char *> &service_list, bool valid, bool alive) {
int found = 0;
for (auto &kv : messages_) {
SubMessage *m = kv.second;
if (service_list.size() == 0 || inList(service_list, m->name.c_str())) {
found += (!valid || m->valid) && (!alive || (m->alive || m->ignore_alive));
}
}
return service_list.size() == 0 ? found == messages_.size() : found == service_list.size();
}
void SubMaster::drain() {
while (true) {
auto polls = poller_->poll(0);
if (polls.size() == 0)
break;
for (auto sock : polls) {
Message *msg = sock->receive(true);
delete msg;
}
}
}
bool SubMaster::updated(const char *name) const {
return services_.at(name)->updated;
}
bool SubMaster::alive(const char *name) const {
return services_.at(name)->alive;
}
bool SubMaster::valid(const char *name) const {
return services_.at(name)->valid;
}
uint64_t SubMaster::rcv_frame(const char *name) const {
return services_.at(name)->rcv_frame;
}
uint64_t SubMaster::rcv_time(const char *name) const {
return services_.at(name)->rcv_time;
}
cereal::Event::Reader &SubMaster::operator[](const char *name) const {
return services_.at(name)->event;
}
SubMaster::~SubMaster() {
delete poller_;
for (auto &kv : messages_) {
SubMessage *m = kv.second;
m->msg_reader->~FlatArrayMessageReader();
free(m->allocated_msg_reader);
delete m->socket;
delete m;
}
}
PubMaster::PubMaster(const std::vector<const char *> &service_list) {
for (auto name : service_list) {
assert(services.count(name) > 0);
PubSocket *socket = PubSocket::create(message_context.context(), name);
assert(socket);
sockets_[name] = socket;
}
}
int PubMaster::send(const char *name, MessageBuilder &msg) {
auto bytes = msg.toBytes();
return send(name, bytes.begin(), bytes.size());
}
PubMaster::~PubMaster() {
for (auto s : sockets_) delete s.second;
}
-185
View File
@@ -1,185 +0,0 @@
import os
import capnp
import multiprocessing
import numbers
import random
import threading
import time
from parameterized import parameterized
import pytest
from cereal import log, car
import cereal.messaging as messaging
from cereal.services import SERVICE_LIST
events = [evt for evt in log.Event.schema.union_fields if evt in SERVICE_LIST.keys()]
def random_sock():
return random.choice(events)
def random_socks(num_socks=10):
return list({random_sock() for _ in range(num_socks)})
def random_bytes(length=1000):
return bytes([random.randrange(0xFF) for _ in range(length)])
def zmq_sleep(t=1):
if "ZMQ" in os.environ:
time.sleep(t)
# TODO: this should take any capnp struct and returrn a msg with random populated data
def random_carstate():
fields = ["vEgo", "aEgo", "gas", "steeringAngleDeg"]
msg = messaging.new_message("carState")
cs = msg.carState
for f in fields:
setattr(cs, f, random.random() * 10)
return msg
# TODO: this should compare any capnp structs
def assert_carstate(cs1, cs2):
for f in car.CarState.schema.non_union_fields:
# TODO: check all types
val1, val2 = getattr(cs1, f), getattr(cs2, f)
if isinstance(val1, numbers.Number):
assert val1 == val2, f"{f}: sent '{val1}' vs recvd '{val2}'"
def delayed_send(delay, sock, dat):
def send_func():
sock.send(dat)
threading.Timer(delay, send_func).start()
class TestMessaging:
def setUp(self):
# TODO: ZMQ tests are too slow; all sleeps will need to be
# replaced with logic to block on the necessary condition
if "ZMQ" in os.environ:
pytest.skip()
# ZMQ pub socket takes too long to die
# sleep to prevent multiple publishers error between tests
zmq_sleep()
@parameterized.expand(events)
def test_new_message(self, evt):
try:
msg = messaging.new_message(evt)
except capnp.lib.capnp.KjException:
msg = messaging.new_message(evt, random.randrange(200))
assert (time.monotonic() - msg.logMonoTime) < 0.1
assert not msg.valid
assert evt == msg.which()
@parameterized.expand(events)
def test_pub_sock(self, evt):
messaging.pub_sock(evt)
@parameterized.expand(events)
def test_sub_sock(self, evt):
messaging.sub_sock(evt)
@parameterized.expand([
(messaging.drain_sock, capnp._DynamicStructReader),
(messaging.drain_sock_raw, bytes),
])
def test_drain_sock(self, func, expected_type):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sub_sock = messaging.sub_sock(sock, timeout=1000)
zmq_sleep()
# no wait and no msgs in queue
msgs = func(sub_sock)
assert isinstance(msgs, list)
assert len(msgs) == 0
# no wait but msgs are queued up
num_msgs = random.randrange(3, 10)
for _ in range(num_msgs):
pub_sock.send(messaging.new_message(sock).to_bytes())
time.sleep(0.1)
msgs = func(sub_sock)
assert isinstance(msgs, list)
assert all(isinstance(msg, expected_type) for msg in msgs)
assert len(msgs) == num_msgs
def test_recv_sock(self):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sub_sock = messaging.sub_sock(sock, timeout=100)
zmq_sleep()
# no wait and no msg in queue, socket should timeout
recvd = messaging.recv_sock(sub_sock)
assert recvd is None
# no wait and one msg in queue
msg = random_carstate()
pub_sock.send(msg.to_bytes())
time.sleep(0.01)
recvd = messaging.recv_sock(sub_sock)
assert isinstance(recvd, capnp._DynamicStructReader)
# https://github.com/python/mypy/issues/13038
assert_carstate(msg.carState, recvd.carState)
def test_recv_one(self):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sub_sock = messaging.sub_sock(sock, timeout=1000)
zmq_sleep()
# no msg in queue, socket should timeout
recvd = messaging.recv_one(sub_sock)
assert recvd is None
# one msg in queue
msg = random_carstate()
pub_sock.send(msg.to_bytes())
recvd = messaging.recv_one(sub_sock)
assert isinstance(recvd, capnp._DynamicStructReader)
assert_carstate(msg.carState, recvd.carState)
@pytest.mark.xfail(condition="ZMQ" in os.environ, reason='ZMQ detected')
def test_recv_one_or_none(self):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sub_sock = messaging.sub_sock(sock)
zmq_sleep()
# no msg in queue, socket shouldn't block
recvd = messaging.recv_one_or_none(sub_sock)
assert recvd is None
# one msg in queue
msg = random_carstate()
pub_sock.send(msg.to_bytes())
recvd = messaging.recv_one_or_none(sub_sock)
assert isinstance(recvd, capnp._DynamicStructReader)
assert_carstate(msg.carState, recvd.carState)
def test_recv_one_retry(self):
sock = "carState"
sock_timeout = 0.1
pub_sock = messaging.pub_sock(sock)
sub_sock = messaging.sub_sock(sock, timeout=round(sock_timeout*1000))
zmq_sleep()
# this test doesn't work with ZMQ since multiprocessing interrupts it
if "ZMQ" not in os.environ:
# wait 15 socket timeouts and make sure it's still retrying
p = multiprocessing.Process(target=messaging.recv_one_retry, args=(sub_sock,))
p.start()
time.sleep(sock_timeout*15)
assert p.is_alive()
p.terminate()
# wait 15 socket timeouts before sending
msg = random_carstate()
delayed_send(sock_timeout*15, pub_sock, msg.to_bytes())
start_time = time.monotonic()
recvd = messaging.recv_one_retry(sub_sock)
assert (time.monotonic() - start_time) >= sock_timeout*15
assert isinstance(recvd, capnp._DynamicStructReader)
assert_carstate(msg.carState, recvd.carState)
@@ -1,157 +0,0 @@
import random
import time
from typing import Sized, cast
import cereal.messaging as messaging
from cereal.messaging.tests.test_messaging import events, random_sock, random_socks, \
random_bytes, random_carstate, assert_carstate, \
zmq_sleep
class TestSubMaster:
def setup_method(self):
# ZMQ pub socket takes too long to die
# sleep to prevent multiple publishers error between tests
zmq_sleep(3)
def test_init(self):
sm = messaging.SubMaster(events)
for p in [sm.updated, sm.recv_time, sm.recv_frame, sm.alive,
sm.sock, sm.data, sm.logMonoTime, sm.valid]:
assert len(cast(Sized, p)) == len(events)
def test_init_state(self):
socks = random_socks()
sm = messaging.SubMaster(socks)
assert sm.frame == -1
assert not any(sm.updated.values())
assert not any(sm.alive.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(t == 0 for t in sm.logMonoTime.values())
for p in [sm.updated, sm.recv_time, sm.recv_frame, sm.alive,
sm.sock, sm.data, sm.logMonoTime, sm.valid]:
assert len(cast(Sized, p)) == len(socks)
def test_getitem(self):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sm = messaging.SubMaster([sock,])
zmq_sleep()
msg = random_carstate()
pub_sock.send(msg.to_bytes())
sm.update(1000)
assert_carstate(msg.carState, sm[sock])
# TODO: break this test up to individually test SubMaster.update and SubMaster.update_msgs
def test_update(self):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sm = messaging.SubMaster([sock,])
zmq_sleep()
for i in range(10):
msg = messaging.new_message(sock)
pub_sock.send(msg.to_bytes())
sm.update(1000)
assert sm.frame == i
assert all(sm.updated.values())
def test_update_timeout(self):
sock = random_sock()
sm = messaging.SubMaster([sock,])
for _ in range(5):
timeout = random.randrange(1000, 5000)
start_time = time.monotonic()
sm.update(timeout)
t = time.monotonic() - start_time
assert t >= timeout/1000.
assert t < 5
assert not any(sm.updated.values())
def test_avg_frequency_checks(self):
for poll in (True, False):
sm = messaging.SubMaster(["modelV2", "carParams", "carState", "cameraOdometry", "liveCalibration"],
poll=("modelV2" if poll else None),
frequency=(20. if not poll else None))
checks = {
"carState": (20, 20),
"modelV2": (20, 20 if poll else 10),
"cameraOdometry": (20, 10),
"liveCalibration": (4, 4),
"carParams": (None, None),
}
for service, (max_freq, min_freq) in checks.items():
if max_freq is not None:
assert sm._check_avg_freq(service)
assert sm.max_freq[service] == max_freq*1.2
assert sm.min_freq[service] == min_freq*0.8
else:
assert not sm._check_avg_freq(service)
def test_alive(self):
pass
def test_ignore_alive(self):
pass
def test_valid(self):
pass
# SubMaster should always conflate
def test_conflate(self):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sm = messaging.SubMaster([sock,])
n = 10
for i in range(n+1):
msg = messaging.new_message(sock)
msg.carState.vEgo = i
pub_sock.send(msg.to_bytes())
time.sleep(0.01)
sm.update(1000)
assert sm[sock].vEgo == n
class TestPubMaster:
def setup_method(self):
# ZMQ pub socket takes too long to die
# sleep to prevent multiple publishers error between tests
zmq_sleep(3)
def test_init(self):
messaging.PubMaster(events)
def test_send(self):
socks = random_socks()
pm = messaging.PubMaster(socks)
sub_socks = {s: messaging.sub_sock(s, conflate=True, timeout=1000) for s in socks}
zmq_sleep()
# PubMaster accepts either a capnp msg builder or bytes
for capnp in [True, False]:
for i in range(100):
sock = socks[i % len(socks)]
if capnp:
try:
msg = messaging.new_message(sock)
except Exception:
msg = messaging.new_message(sock, random.randrange(50))
else:
msg = random_bytes()
pm.send(sock, msg)
recvd = sub_socks[sock].receive()
if capnp:
msg.clear_write_flag()
msg = msg.to_bytes()
assert msg == recvd, i
-21
View File
@@ -1,21 +0,0 @@
import os
import tempfile
from typing import Dict
from parameterized import parameterized
import cereal.services as services
from cereal.services import SERVICE_LIST
class TestServices:
@parameterized.expand(SERVICE_LIST.keys())
def test_services(self, s):
service = SERVICE_LIST[s]
assert service.frequency <= 104
assert service.decimation != 0
def test_generated_header(self):
with tempfile.NamedTemporaryFile(suffix=".h") as f:
ret = os.system(f"python3 {services.__file__} > {f.name} && clang++ {f.name}")
assert ret == 0, "generated services header is not valid C"
-131
View File
@@ -1,131 +0,0 @@
#!/usr/bin/env python3
from typing import Optional
class Service:
def __init__(self, should_log: bool, frequency: float, decimation: Optional[int] = None):
self.should_log = should_log
self.frequency = frequency
self.decimation = decimation
_services: dict[str, tuple] = {
# service: (should_log, frequency, qlog decimation (optional))
# note: the "EncodeIdx" packets will still be in the log
"gyroscope": (True, 104., 104),
"gyroscope2": (True, 100., 100),
"accelerometer": (True, 104., 104),
"accelerometer2": (True, 100., 100),
"magnetometer": (True, 25.),
"lightSensor": (True, 100., 100),
"temperatureSensor": (True, 2., 200),
"temperatureSensor2": (True, 2., 200),
"gpsNMEA": (True, 9.),
"deviceState": (True, 2., 1),
"can": (True, 100., 2053), # decimation gives ~3 msgs in a full segment
"controlsState": (True, 100., 10),
"pandaStates": (True, 10., 1),
"peripheralState": (True, 2., 1),
"radarState": (True, 20., 5),
"roadEncodeIdx": (False, 20., 1),
"liveTracks": (True, 20.),
"sendcan": (True, 100., 139),
"logMessage": (True, 0.),
"errorLogMessage": (True, 0., 1),
"liveCalibration": (True, 4., 4),
"liveTorqueParameters": (True, 4., 1),
"androidLog": (True, 0.),
"carState": (True, 100., 10),
"carControl": (True, 100., 10),
"carOutput": (True, 100., 10),
"longitudinalPlan": (True, 20., 10),
"procLog": (True, 0.5, 15),
"gpsLocationExternal": (True, 10., 10),
"gpsLocation": (True, 1., 1),
"ubloxGnss": (True, 10.),
"qcomGnss": (True, 2.),
"gnssMeasurements": (True, 10., 10),
"clocks": (True, 0.1, 1),
"ubloxRaw": (True, 20.),
"livePose": (True, 20., 4),
"liveLocationKalman": (True, 20.),
"liveParameters": (True, 20., 5),
"cameraOdometry": (True, 20., 10),
"lateralPlanDEPRECATED": (True, 20., 5),
"thumbnail": (True, 0.2, 1),
"onroadEvents": (True, 1., 1),
"carParams": (True, 0.02, 1),
"roadCameraState": (True, 20., 20),
"driverCameraState": (True, 20., 20),
"driverEncodeIdx": (False, 20., 1),
"driverStateV2": (True, 20., 10),
"driverMonitoringState": (True, 20., 10),
"wideRoadEncodeIdx": (False, 20., 1),
"wideRoadCameraState": (True, 20., 20),
"drivingModelData": (True, 20., 10),
"modelV2": (True, 20.),
"managerState": (True, 2., 1),
"uploaderState": (True, 0., 1),
"navInstruction": (True, 1., 10),
"navRoute": (True, 0.),
"navThumbnail": (True, 0.),
"navModelDEPRECATED": (True, 2., 4.),
"mapRenderState": (True, 2., 1.),
"uiPlanDEPRECATED": (True, 20., 40.),
"qRoadEncodeIdx": (False, 20.),
"userFlag": (True, 0., 1),
"microphone": (True, 10., 10),
"controlsStateSP": (True, 100., 10),
"longitudinalPlanSP": (True, 20., 5),
"lateralPlanSPDEPRECATED": (True, 20., 5),
"driverMonitoringStateSP": (True, 20., 10),
"liveMapDataSP": (True, 0.),
"e2eLongStateSP": (True, 0.),
"modelV2SP": (True, 20., 40),
# debug
"uiDebug": (True, 0., 1),
"testJoystick": (True, 0.),
"roadEncodeData": (False, 20.),
"driverEncodeData": (False, 20.),
"wideRoadEncodeData": (False, 20.),
"qRoadEncodeData": (False, 20.),
"livestreamWideRoadEncodeIdx": (False, 20.),
"livestreamRoadEncodeIdx": (False, 20.),
"livestreamDriverEncodeIdx": (False, 20.),
"livestreamWideRoadEncodeData": (False, 20.),
"livestreamRoadEncodeData": (False, 20.),
"livestreamDriverEncodeData": (False, 20.),
"customReservedRawData0": (True, 0.),
"customReservedRawData1": (True, 0.),
"customReservedRawData2": (True, 0.),
}
SERVICE_LIST = {name: Service(*vals) for
idx, (name, vals) in enumerate(_services.items())}
def build_header():
h = ""
h += "/* THIS IS AN AUTOGENERATED FILE, PLEASE EDIT services.py */\n"
h += "#ifndef __SERVICES_H\n"
h += "#define __SERVICES_H\n"
h += "#include <map>\n"
h += "#include <string>\n"
h += "struct service { std::string name; bool should_log; int frequency; int decimation; };\n"
h += "static std::map<std::string, service> services = {\n"
for k, v in SERVICE_LIST.items():
should_log = "true" if v.should_log else "false"
decimation = -1 if v.decimation is None else v.decimation
h += ' { "%s", {"%s", %s, %d, %d}},\n' % \
(k, k, should_log, v.frequency, decimation)
h += "};\n"
h += "#endif\n"
return h
if __name__ == "__main__":
print(build_header())
+36 -17
View File
@@ -1,27 +1,46 @@
from .comma_connect import CommaConnectApi import jwt
from .sunnylink import SunnylinkApi import os
import requests
from datetime import datetime, timedelta
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, use_sunnylink=False): def __init__(self, dongle_id):
if use_sunnylink: self.dongle_id = dongle_id
self.service = SunnylinkApi(dongle_id) with open(Paths.persist_root()+'/comma/id_rsa') as f:
else: self.private_key = f.read()
self.service = CommaConnectApi(dongle_id)
def request(self, method, endpoint, **params):
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.utcnow()
payload = {
'identity': self.dongle_id,
'nbf': now,
'iat': now,
'exp': now + timedelta(hours=expiry_hours)
}
token = jwt.encode(payload, self.private_key, algorithm='RS256')
if isinstance(token, bytes):
token = token.decode('utf8')
return token
def api_get(endpoint, method='GET', timeout=None, access_token=None, use_sunnylink=False, **params): def api_get(endpoint, method='GET', timeout=None, access_token=None, **params):
return CommaConnectApi(None).api_get(endpoint, method, timeout, access_token, **params) if not use_sunnylink else \ headers = {}
SunnylinkApi(None).api_get(endpoint, method, timeout, access_token, **params) 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)
-56
View File
@@ -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(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, **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, self.api_host + "/" + endpoint, timeout=timeout, headers=headers, params=params)
-11
View File
@@ -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-"
-155
View File
@@ -1,155 +0,0 @@
import os
import time
import jwt
import json
from pathlib import Path
from datetime import datetime, timedelta
from openpilot.common.params import Params
from openpilot.system.hardware import HARDWARE
from openpilot.system.hardware.hw import Paths
from openpilot.common.api.base import BaseApi
API_HOST = os.getenv('SUNNYLINK_API_HOST', 'https://stg.api.sunnypilot.ai')
UNREGISTERED_SUNNYLINK_DONGLE_ID = "UnregisteredDevice"
MAX_RETRIES = 6
CRASH_LOG_DIR = '/data/community/crashes'
class SunnylinkApi(BaseApi):
def __init__(self, dongle_id):
super().__init__(dongle_id, API_HOST)
self.user_agent = "sunnypilot-"
self.spinner = None
self.params = Params()
def api_get(self, endpoint, method='GET', timeout=10, access_token=None, **kwargs):
if not self.params.get_bool("SunnylinkEnabled"):
return None
return super().api_get(endpoint, method, timeout, access_token, **kwargs)
def resume_queued(self, timeout=10, **kwargs):
sunnylinkId, commaId = self._resolve_dongle_ids()
return self.api_get(f"ws/{sunnylinkId}/resume_queued", "POST", timeout, access_token=self.get_token(), **kwargs)
def get_token(self, expiry_hours=1):
# Add your additional data here
additional_data = {}
return super()._get_token(expiry_hours, **additional_data)
def _status_update(self, message):
print(message)
if self.spinner:
self.spinner.update(message)
time.sleep(0.5)
def _resolve_dongle_ids(self):
sunnylink_dongle_id = self.params.get("SunnylinkDongleId", encoding='utf-8')
comma_dongle_id = self.dongle_id or self.params.get("DongleId", encoding='utf-8')
return sunnylink_dongle_id, comma_dongle_id
def _resolve_imeis(self):
imei1, imei2 = None, None
imei_try = 0
while imei1 is None and imei2 is None and imei_try < MAX_RETRIES:
try:
imei1, imei2 = self.params.get("IMEI", encoding='utf8') or HARDWARE.get_imei(0), HARDWARE.get_imei(1)
except Exception:
self._status_update(f"Error getting imei, trying again... [{imei_try+1}/{MAX_RETRIES}]")
time.sleep(1)
imei_try += 1
return imei1, imei2
def _resolve_serial(self):
serial = self.params.get("HardwareSerial", encoding='utf8') or HARDWARE.get_serial()
return serial
def register_device(self, spinner=None, timeout=60, verbose=False):
self.spinner = spinner
sunnylink_dongle_id, comma_dongle_id = self._resolve_dongle_ids()
if comma_dongle_id is None:
self._status_update("Comma dongle ID not found, deferring sunnylink's registration to comma's registration process.")
return None
imei1, imei2 = self._resolve_imeis()
serial = self._resolve_serial()
if sunnylink_dongle_id not in (None, UNREGISTERED_SUNNYLINK_DONGLE_ID):
return sunnylink_dongle_id
privkey_path = Path(Paths.persist_root()+"/comma/id_rsa")
pubkey_path = Path(Paths.persist_root()+"/comma/id_rsa.pub")
start_time = time.monotonic()
successful_registration = False
if not pubkey_path.is_file():
sunnylink_dongle_id = UNREGISTERED_SUNNYLINK_DONGLE_ID
self._status_update("Public key not found, setting dongle ID to unregistered.")
else:
Params().put("LastSunnylinkPingTime", "0") # Reset the last ping time to 0 if we are trying to register
with pubkey_path.open() as f1, privkey_path.open() as f2:
public_key = f1.read()
private_key = f2.read()
backoff = 1
while True:
register_token = jwt.encode({'register': True, 'exp': datetime.utcnow() + timedelta(hours=1)}, private_key, algorithm='RS256')
try:
if verbose or time.monotonic() - start_time < timeout / 2:
self._status_update("Registering device to sunnylink...")
elif time.monotonic() - start_time >= timeout / 2:
self._status_update("Still registering device to sunnylink...")
resp = self.api_get("v2/pilotauth/", method='POST', timeout=15, imei=imei1, imei2=imei2, serial=serial, comma_dongle_id=comma_dongle_id, public_key=public_key, register_token=register_token)
if resp is None:
raise Exception("Unable to register device, request was None")
if resp.status_code in (409, 412):
timeout = time.monotonic() - start_time # Don't retry if the public key is already in use
key_in_use = "Public key is already in use, is your key unique? Contact your vendor for a new key."
unsafe_key = "Public key is known to not be unique and it's unsafe. Contact your vendor for a new key."
error_message = key_in_use if resp.status_code == 409 else unsafe_key
raise Exception(error_message)
if resp.status_code != 200:
raise Exception(f"Failed to register with sunnylink. Status code: {resp.status_code}\nData\n:{resp.text}")
dongleauth = json.loads(resp.text)
sunnylink_dongle_id = dongleauth["device_id"]
if sunnylink_dongle_id:
self._status_update("Device registered successfully.")
successful_registration = True
break
except Exception as e:
if verbose:
self._status_update(f"Waiting {backoff}s before retry, Exception occurred during registration: [{str(e)}]")
if not os.path.exists(CRASH_LOG_DIR):
os.makedirs(CRASH_LOG_DIR)
with open(f'{CRASH_LOG_DIR}/error.txt', 'a') as f:
f.write(f"[{datetime.now()}] sunnylink: {str(e)}\n")
backoff = min(backoff * 2, 60)
time.sleep(backoff)
if time.monotonic() - start_time > timeout:
self._status_update(f"Giving up on sunnylink's registration after {timeout}s. Will retry on next boot.")
time.sleep(3)
break
self.params.put("SunnylinkDongleId", sunnylink_dongle_id or UNREGISTERED_SUNNYLINK_DONGLE_ID)
# Set the last ping time to the current time since we were just talking to the API
last_ping = int(time.monotonic() * 1e9) if successful_registration else start_time
Params().put("LastSunnylinkPingTime", str(last_ping))
# Disable sunnylink if registration was not successful
if not successful_registration:
Params().put_bool("SunnylinkEnabled", False)
self.spinner = None
return sunnylink_dongle_id
-42
View File
@@ -1,42 +0,0 @@
from functools import cache
import subprocess
from openpilot.common.run import run_cmd, run_cmd_default
@cache
def get_commit(cwd: str = None, branch: str = "HEAD") -> str:
return run_cmd_default(["git", "rev-parse", branch], cwd=cwd)
@cache
def get_commit_date(cwd: str = None, commit: str = "HEAD") -> str:
return run_cmd_default(["git", "show", "--no-patch", "--format='%ct %ci'", commit], cwd=cwd)
@cache
def get_short_branch(cwd: str = None) -> str:
return run_cmd_default(["git", "rev-parse", "--abbrev-ref", "HEAD"], cwd=cwd)
@cache
def get_branch(cwd: str = None) -> str:
return run_cmd_default(["git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"], cwd=cwd)
@cache
def get_origin(cwd: str = None) -> str:
try:
local_branch = run_cmd(["git", "name-rev", "--name-only", "HEAD"], cwd=cwd)
tracking_remote = run_cmd(["git", "config", "branch." + local_branch + ".remote"], cwd=cwd)
return run_cmd(["git", "config", "remote." + tracking_remote + ".url"], cwd=cwd)
except subprocess.CalledProcessError: # Not on a branch, fallback
return run_cmd_default(["git", "config", "--get", "remote.origin.url"], cwd=cwd)
@cache
def get_normalized_origin(cwd: str = None) -> str:
return get_origin(cwd) \
.replace("git@", "", 1) \
.replace(".git", "", 1) \
.replace("https://", "", 1) \
.replace(":", "/", 1)
+2 -2
View File
@@ -1,5 +1,5 @@
import os import os
from functools import cache from functools import lru_cache
def gpio_init(pin: int, output: bool) -> None: def gpio_init(pin: int, output: bool) -> None:
try: try:
@@ -35,7 +35,7 @@ def gpio_export(pin: int) -> None:
except Exception: except Exception:
print(f"Failed to export gpio {pin}") print(f"Failed to export gpio {pin}")
@cache @lru_cache(maxsize=None)
def get_irq_action(irq: int) -> list[str]: def get_irq_action(irq: int) -> list[str]:
try: try:
with open(f"/sys/kernel/irq/{irq}/actions") as f: with open(f"/sys/kernel/irq/{irq}/actions") as f:
-45
View File
@@ -1,45 +0,0 @@
HTML_REPLACEMENTS = [
(r'&', r'&amp;'),
(r'"', r'&quot;'),
]
def parse_markdown(text: str, tab_length: int = 2) -> str:
lines = text.split("\n")
output: list[str] = []
list_level = 0
def end_outstanding_lists(level: int, end_level: int) -> int:
while level > end_level:
level -= 1
output.append("</ul>")
if level > 0:
output.append("</li>")
return end_level
for i, line in enumerate(lines):
if i + 1 < len(lines) and lines[i + 1].startswith("==="): # heading
output.append(f"<h1>{line}</h1>")
elif line.startswith("==="):
pass
elif line.lstrip().startswith("* "): # list
line_level = 1 + line.count(" " * tab_length, 0, line.index("*"))
if list_level >= line_level:
list_level = end_outstanding_lists(list_level, line_level)
else:
list_level += 1
if list_level > 1:
output[-1] = output[-1].replace("</li>", "")
output.append("<ul>")
output.append(f"<li>{line.replace('*', '', 1).lstrip()}</li>")
else:
list_level = end_outstanding_lists(list_level, 0)
if len(line) > 0:
output.append(line)
end_outstanding_lists(list_level, 0)
output_str = "\n".join(output) + "\n"
for (fr, to) in HTML_REPLACEMENTS:
output_str = output_str.replace(fr, to)
return output_str
-1
View File
@@ -1 +0,0 @@
#define CURRENT_MODEL "Notre Dame (July 1, 2024)"
+110 -177
View File
@@ -24,8 +24,8 @@ int fsync_dir(const std::string &path) {
int result = -1; int result = -1;
int fd = HANDLE_EINTR(open(path.c_str(), O_RDONLY, 0755)); int fd = HANDLE_EINTR(open(path.c_str(), O_RDONLY, 0755));
if (fd >= 0) { if (fd >= 0) {
result = HANDLE_EINTR(fsync(fd)); result = fsync(fd);
HANDLE_EINTR(close(fd)); close(fd);
} }
return result; return result;
} }
@@ -89,7 +89,6 @@ private:
std::unordered_map<std::string, uint32_t> keys = { std::unordered_map<std::string, uint32_t> keys = {
{"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG}, {"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG},
{"AlwaysOnDM", PERSISTENT},
{"ApiCache_Device", PERSISTENT}, {"ApiCache_Device", PERSISTENT},
{"ApiCache_NavDestinations", PERSISTENT}, {"ApiCache_NavDestinations", PERSISTENT},
{"AssistNowToken", PERSISTENT}, {"AssistNowToken", PERSISTENT},
@@ -111,46 +110,45 @@ std::unordered_map<std::string, uint32_t> keys = {
{"CurrentBootlog", PERSISTENT}, {"CurrentBootlog", PERSISTENT},
{"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"DisablePowerDown", PERSISTENT | BACKUP}, {"DisablePowerDown", PERSISTENT},
{"DisableUpdates", PERSISTENT | BACKUP}, {"DisableUpdates", PERSISTENT},
{"DisengageOnAccelerator", PERSISTENT | BACKUP}, {"DisengageOnAccelerator", PERSISTENT},
{"DmModelInitialized", CLEAR_ON_ONROAD_TRANSITION}, {"DmModelInitialized", CLEAR_ON_ONROAD_TRANSITION},
{"DongleId", PERSISTENT}, {"DongleId", PERSISTENT},
{"DoReboot", CLEAR_ON_MANAGER_START}, {"DoReboot", CLEAR_ON_MANAGER_START},
{"DoShutdown", CLEAR_ON_MANAGER_START}, {"DoShutdown", CLEAR_ON_MANAGER_START},
{"DoUninstall", CLEAR_ON_MANAGER_START}, {"DoUninstall", CLEAR_ON_MANAGER_START},
{"ExperimentalLongitudinalEnabled", PERSISTENT | DEVELOPMENT_ONLY | BACKUP}, {"ExperimentalLongitudinalEnabled", PERSISTENT | DEVELOPMENT_ONLY},
{"ExperimentalMode", PERSISTENT | BACKUP}, {"ExperimentalMode", PERSISTENT},
{"ExperimentalModeConfirmed", PERSISTENT | BACKUP}, {"ExperimentalModeConfirmed", PERSISTENT},
{"FirmwareQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"FirmwareQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"ForcePowerDown", PERSISTENT}, {"ForcePowerDown", PERSISTENT},
{"GitBranch", PERSISTENT}, {"GitBranch", PERSISTENT},
{"GitCommit", PERSISTENT}, {"GitCommit", PERSISTENT},
{"GitCommitDate", PERSISTENT}, {"GitCommitDate", PERSISTENT},
{"GitDiff", PERSISTENT}, {"GitDiff", PERSISTENT},
{"GithubSshKeys", PERSISTENT | BACKUP}, {"GithubSshKeys", PERSISTENT},
{"GithubUsername", PERSISTENT | BACKUP}, {"GithubUsername", PERSISTENT},
{"GitRemote", PERSISTENT}, {"GitRemote", PERSISTENT},
{"GsmApn", PERSISTENT | BACKUP}, {"GsmApn", PERSISTENT},
{"GsmMetered", PERSISTENT | BACKUP}, {"GsmMetered", PERSISTENT},
{"GsmRoaming", PERSISTENT | BACKUP}, {"GsmRoaming", PERSISTENT},
{"HardwareSerial", PERSISTENT}, {"HardwareSerial", PERSISTENT},
{"HasAcceptedTerms", PERSISTENT}, {"HasAcceptedTerms", PERSISTENT},
{"IMEI", PERSISTENT}, {"IMEI", PERSISTENT},
{"InstallDate", PERSISTENT}, {"InstallDate", PERSISTENT},
{"IsDriverViewEnabled", CLEAR_ON_MANAGER_START}, {"IsDriverViewEnabled", CLEAR_ON_MANAGER_START},
{"IsEngaged", PERSISTENT}, {"IsEngaged", PERSISTENT},
{"IsLdwEnabled", PERSISTENT | BACKUP}, {"IsLdwEnabled", PERSISTENT},
{"IsMetric", PERSISTENT | BACKUP}, {"IsMetric", PERSISTENT},
{"IsOffroad", CLEAR_ON_MANAGER_START}, {"IsOffroad", CLEAR_ON_MANAGER_START},
{"IsOnroad", PERSISTENT}, {"IsOnroad", PERSISTENT},
{"IsRhdDetected", PERSISTENT}, {"IsRhdDetected", PERSISTENT},
{"IsReleaseBranch", CLEAR_ON_MANAGER_START}, {"IsReleaseBranch", CLEAR_ON_MANAGER_START},
{"IsReleaseSPBranch", CLEAR_ON_MANAGER_START},
{"IsTakingSnapshot", CLEAR_ON_MANAGER_START}, {"IsTakingSnapshot", CLEAR_ON_MANAGER_START},
{"IsTestedBranch", CLEAR_ON_MANAGER_START}, {"IsTestedBranch", CLEAR_ON_MANAGER_START},
{"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"LanguageSetting", PERSISTENT | BACKUP}, {"LanguageSetting", PERSISTENT},
{"LastAthenaPingTime", CLEAR_ON_MANAGER_START}, {"LastAthenaPingTime", CLEAR_ON_MANAGER_START},
{"LastGPSPosition", PERSISTENT}, {"LastGPSPosition", PERSISTENT},
{"LastManagerExitReason", CLEAR_ON_MANAGER_START}, {"LastManagerExitReason", CLEAR_ON_MANAGER_START},
@@ -160,12 +158,12 @@ std::unordered_map<std::string, uint32_t> keys = {
{"LastUpdateTime", PERSISTENT}, {"LastUpdateTime", PERSISTENT},
{"LiveParameters", PERSISTENT}, {"LiveParameters", PERSISTENT},
{"LiveTorqueParameters", PERSISTENT | DONT_LOG}, {"LiveTorqueParameters", PERSISTENT | DONT_LOG},
{"LongitudinalPersonality", PERSISTENT | BACKUP}, {"LongitudinalPersonality", PERSISTENT},
{"NavDestination", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"NavDestination", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"NavDestinationWaypoints", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"NavDestinationWaypoints", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"NavPastDestinations", PERSISTENT}, {"NavPastDestinations", PERSISTENT},
{"NavSettingLeftSide", PERSISTENT | BACKUP}, {"NavSettingLeftSide", PERSISTENT},
{"NavSettingTime24h", PERSISTENT | BACKUP}, {"NavSettingTime24h", PERSISTENT},
{"NetworkMetered", PERSISTENT}, {"NetworkMetered", PERSISTENT},
{"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"ObdMultiplexingEnabled", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"ObdMultiplexingEnabled", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
@@ -173,6 +171,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"Offroad_CarUnrecognized", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"Offroad_CarUnrecognized", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"Offroad_ConnectivityNeeded", CLEAR_ON_MANAGER_START}, {"Offroad_ConnectivityNeeded", CLEAR_ON_MANAGER_START},
{"Offroad_ConnectivityNeededPrompt", CLEAR_ON_MANAGER_START}, {"Offroad_ConnectivityNeededPrompt", CLEAR_ON_MANAGER_START},
{"Offroad_InvalidTime", CLEAR_ON_MANAGER_START},
{"Offroad_IsTakingSnapshot", CLEAR_ON_MANAGER_START}, {"Offroad_IsTakingSnapshot", CLEAR_ON_MANAGER_START},
{"Offroad_NeosUpdate", CLEAR_ON_MANAGER_START}, {"Offroad_NeosUpdate", CLEAR_ON_MANAGER_START},
{"Offroad_NoFirmware", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"Offroad_NoFirmware", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
@@ -181,19 +180,18 @@ std::unordered_map<std::string, uint32_t> keys = {
{"Offroad_TemperatureTooHigh", CLEAR_ON_MANAGER_START}, {"Offroad_TemperatureTooHigh", CLEAR_ON_MANAGER_START},
{"Offroad_UnofficialHardware", CLEAR_ON_MANAGER_START}, {"Offroad_UnofficialHardware", CLEAR_ON_MANAGER_START},
{"Offroad_UpdateFailed", CLEAR_ON_MANAGER_START}, {"Offroad_UpdateFailed", CLEAR_ON_MANAGER_START},
{"Offroad_OSMUpdateRequired", CLEAR_ON_MANAGER_START}, {"OpenpilotEnabledToggle", PERSISTENT},
{"OpenpilotEnabledToggle", PERSISTENT | BACKUP},
{"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"PandaSomResetTriggered", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"PandaSomResetTriggered", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"PandaSignatures", CLEAR_ON_MANAGER_START}, {"PandaSignatures", CLEAR_ON_MANAGER_START},
{"PrimeType", PERSISTENT}, {"PrimeType", PERSISTENT},
{"RecordFront", PERSISTENT | BACKUP}, {"RecordFront", PERSISTENT},
{"RecordFrontLock", PERSISTENT}, // for the internal fleet {"RecordFrontLock", PERSISTENT}, // for the internal fleet
{"ReplayControlsState", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"ReplayControlsState", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"RouteCount", PERSISTENT},
{"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"SshEnabled", PERSISTENT | BACKUP}, {"SshEnabled", PERSISTENT},
{"TermsVersion", PERSISTENT}, {"TermsVersion", PERSISTENT},
{"Timezone", PERSISTENT},
{"TrainingVersion", PERSISTENT}, {"TrainingVersion", PERSISTENT},
{"UbloxAvailable", PERSISTENT}, {"UbloxAvailable", PERSISTENT},
{"UpdateAvailable", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"UpdateAvailable", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
@@ -208,164 +206,101 @@ std::unordered_map<std::string, uint32_t> keys = {
{"UpdaterTargetBranch", CLEAR_ON_MANAGER_START}, {"UpdaterTargetBranch", CLEAR_ON_MANAGER_START},
{"UpdaterLastFetchTime", PERSISTENT}, {"UpdaterLastFetchTime", PERSISTENT},
{"Version", PERSISTENT}, {"Version", PERSISTENT},
{"VisionRadarToggle", PERSISTENT},
{"AccelPersonality", PERSISTENT | BACKUP}, {"AccMadsCombo", PERSISTENT},
{"AccMadsCombo", PERSISTENT | BACKUP}, {"AmapKey1", PERSISTENT},
{"AmapKey1", PERSISTENT | BACKUP}, {"AmapKey2", PERSISTENT},
{"AmapKey2", PERSISTENT | BACKUP}, {"AutoLaneChangeTimer", PERSISTENT},
{"ApiCache_DriveStats", PERSISTENT | BACKUP}, {"AutoLaneChangeBsmDelay", PERSISTENT},
{"AutoLaneChangeTimer", PERSISTENT | BACKUP}, {"BelowSpeedPause", PERSISTENT},
{"AutoLaneChangeBsmDelay", PERSISTENT | BACKUP}, {"BrakeLights", PERSISTENT},
{"BelowSpeedPause", PERSISTENT | BACKUP}, {"BrightnessControl", PERSISTENT},
{"BrakeLights", PERSISTENT | BACKUP}, {"ButtonAutoHide", PERSISTENT},
{"BrightnessControl", PERSISTENT | BACKUP}, {"CameraControl", PERSISTENT},
{"ButtonAutoHide", PERSISTENT | BACKUP}, {"CameraControlToggle", PERSISTENT},
{"CameraControl", PERSISTENT | BACKUP}, {"CameraOffset", PERSISTENT},
{"CameraControlToggle", PERSISTENT | BACKUP}, {"CarModel", PERSISTENT},
{"CameraOffset", PERSISTENT | BACKUP}, {"CarModelText", PERSISTENT},
{"CarModel", PERSISTENT | BACKUP}, {"ChevronInfo", PERSISTENT},
{"CarModelText", PERSISTENT | BACKUP}, {"CustomBootScreen", PERSISTENT},
{"ChevronInfo", PERSISTENT | BACKUP}, {"CustomMapboxTokenPk", PERSISTENT},
{"CustomBootScreen", PERSISTENT | BACKUP}, {"CustomMapboxTokenSk", PERSISTENT},
{"CustomDrivingModel", PERSISTENT}, {"CustomOffsets", PERSISTENT},
{"CustomMapboxTokenPk", PERSISTENT | BACKUP}, {"CustomStockLong", PERSISTENT},
{"CustomMapboxTokenSk", PERSISTENT | BACKUP}, {"CustomTorqueLateral", PERSISTENT},
{"CustomOffsets", PERSISTENT | BACKUP}, {"DevUI", PERSISTENT},
{"CustomStockLong", PERSISTENT | BACKUP}, {"DevUIInfo", PERSISTENT},
{"CustomStockLongPlanner", PERSISTENT | BACKUP}, {"DisableOnroadUploads", PERSISTENT},
{"CustomTorqueLateral", PERSISTENT | BACKUP}, {"DisengageLateralOnBrake", PERSISTENT},
{"DevUIInfo", PERSISTENT | BACKUP}, {"DynamicExperimentalControl", PERSISTENT},
{"DisableOnroadUploads", PERSISTENT | BACKUP}, {"DynamicExperimentalControlToggle", PERSISTENT},
{"DisengageLateralOnBrake", PERSISTENT | BACKUP}, {"DynamicLaneProfile", PERSISTENT},
{"DrivingModelGeneration", PERSISTENT}, {"DynamicLaneProfileToggle", PERSISTENT},
{"DrivingModelMetadataText", PERSISTENT}, {"EnableAmap", PERSISTENT},
{"DrivingModelName", PERSISTENT}, {"EnableDebugSnapshot", PERSISTENT},
{"DrivingModelText", PERSISTENT}, {"EnableGmap", PERSISTENT},
{"DrivingModelUrl", PERSISTENT}, {"EnableMads", PERSISTENT},
{"DynamicExperimentalControl", PERSISTENT | BACKUP}, {"EndToEndLongAlertLead", PERSISTENT},
{"DynamicLaneProfile", PERSISTENT | BACKUP}, {"EndToEndLongAlertLight", PERSISTENT},
{"DynamicPersonality", PERSISTENT | BACKUP}, {"EndToEndLongAlertUI", PERSISTENT},
{"EnableAmap", PERSISTENT | BACKUP}, {"EndToEndLongToggle", PERSISTENT},
{"EnableGmap", PERSISTENT | BACKUP}, {"EnforceTorqueLateral", PERSISTENT},
{"EnableMads", PERSISTENT | BACKUP}, {"EnhancedScc", PERSISTENT},
{"EnableSlc", PERSISTENT | BACKUP},
{"EndToEndLongAlertLead", PERSISTENT | BACKUP},
{"EndToEndLongAlertLight", PERSISTENT | BACKUP},
{"EndToEndLongAlertUI", PERSISTENT | BACKUP},
{"EndToEndLongToggle", PERSISTENT | BACKUP},
{"EnforceTorqueLateral", PERSISTENT | BACKUP},
{"EnhancedScc", PERSISTENT | BACKUP},
{"FeatureStatus", PERSISTENT | BACKUP},
{"FleetManagerPin", PERSISTENT}, {"FleetManagerPin", PERSISTENT},
{"ForceOffroad", CLEAR_ON_MANAGER_START}, {"GapAdjustCruise", PERSISTENT},
{"GmapKey", PERSISTENT | BACKUP}, {"GapAdjustCruiseMax", PERSISTENT},
{"HandsOnWheelMonitoring", PERSISTENT | BACKUP}, {"GapAdjustCruiseMin", PERSISTENT},
{"HasAcceptedTermsSP", PERSISTENT}, {"GapAdjustCruiseMode", PERSISTENT},
{"HideVEgoUi", PERSISTENT | BACKUP}, {"GapAdjustCruiseTr", PERSISTENT},
{"HyundaiCruiseMainDefault", PERSISTENT | BACKUP}, {"GmapKey", PERSISTENT},
{"HkgCustomLongTuning", PERSISTENT | BACKUP}, {"HandsOnWheelMonitoring", PERSISTENT},
{"HkgSmoothStop", PERSISTENT | BACKUP}, {"HideVEgoUi", PERSISTENT},
{"HyundaiCruiseMainDefault", PERSISTENT | BACKUP}, {"HkgSmoothStop", PERSISTENT},
{"HotspotOnBoot", PERSISTENT}, {"HotspotOnBoot", PERSISTENT},
{"HotspotOnBootConfirmed", PERSISTENT}, {"LastCarModel", PERSISTENT},
{"HyundaiRadarTracksAvailable", PERSISTENT},
{"HyundaiRadarTracksAvailableCache", PERSISTENT},
{"HyundaiRadarTracksAvailablePersistent", PERSISTENT},
{"LastCarModel", PERSISTENT | BACKUP},
{"LastSpeedLimitSignTap", PERSISTENT}, {"LastSpeedLimitSignTap", PERSISTENT},
{"LastSunnylinkPingTime", CLEAR_ON_MANAGER_START}, {"LiveTorque", PERSISTENT},
{"LiveTorque", PERSISTENT | BACKUP}, {"LkasToggle", PERSISTENT},
{"LiveTorqueRelaxed", PERSISTENT | BACKUP}, {"MadsCruiseMain", PERSISTENT},
{"LkasToggle", PERSISTENT | BACKUP}, {"MadsIconToggle", PERSISTENT},
{"MadsCruiseMain", PERSISTENT | BACKUP}, {"MapboxFullScreen", PERSISTENT},
{"MadsIconToggle", PERSISTENT | BACKUP}, {"MaxTimeOffroad", PERSISTENT},
{"MapboxFullScreen", PERSISTENT | BACKUP}, {"OnroadScreenOff", PERSISTENT},
{"MapTargetVelocities", PERSISTENT}, {"OnroadScreenOffBrightness", PERSISTENT},
{"Map3DBuildings", PERSISTENT | BACKUP}, {"OnroadScreenOffEvent", PERSISTENT},
{"MaxTimeOffroad", PERSISTENT | BACKUP}, {"OsmDbUpdatesCheck", PERSISTENT},
{"NavModelText", PERSISTENT | BACKUP},
{"NavModelUrl", PERSISTENT | BACKUP},
{"NNFF", PERSISTENT | BACKUP},
{"NNFFCarModel", PERSISTENT | BACKUP},
{"NNFFNoLateralJerk", PERSISTENT | BACKUP},
{"OnroadScreenOff", PERSISTENT | BACKUP},
{"OnroadScreenOffBrightness", PERSISTENT | BACKUP},
{"OnroadScreenOffEvent", PERSISTENT | BACKUP},
{"OnroadSettings", PERSISTENT | BACKUP},
{"OsmLocal", PERSISTENT}, {"OsmLocal", PERSISTENT},
{"OsmLocalDb", PERSISTENT},
{"OsmLocationName", PERSISTENT}, {"OsmLocationName", PERSISTENT},
{"OsmLocationTitle", PERSISTENT}, {"OsmLocationTitle", PERSISTENT},
{"OsmLocationUrl", PERSISTENT}, {"OsmLocationUrl", PERSISTENT},
{"OsmWayTest", PERSISTENT}, {"OsmWayTest", PERSISTENT},
{"OsmDownloadedDate", PERSISTENT}, {"PathOffset", PERSISTENT},
{"OvertakingAccelerationAssist", PERSISTENT}, {"QuietDrive", PERSISTENT},
{"PathOffset", PERSISTENT | BACKUP}, {"RoadEdge", PERSISTENT},
{"PauseLateralSpeed", PERSISTENT | BACKUP}, {"ReverseAccChange", PERSISTENT},
{"PCMVCruiseOverride", PERSISTENT | BACKUP}, {"ReverseDmCam", PERSISTENT},
{"PCMVCruiseOverrideSpeed", PERSISTENT | BACKUP}, {"ScreenRecorder", PERSISTENT},
{"QuietDrive", PERSISTENT | BACKUP}, {"ShowDebugUI", PERSISTENT},
{"RoadEdge", PERSISTENT | BACKUP}, {"SidebarTemperature", PERSISTENT},
{"ReverseAccChange", PERSISTENT | BACKUP}, {"SidebarTemperatureOptions", PERSISTENT},
{"ReverseDmCam", PERSISTENT | BACKUP}, {"SpeedLimitControl", PERSISTENT},
{"ScreenRecorder", PERSISTENT | BACKUP}, {"SpeedLimitPercOffset", PERSISTENT},
{"ShowDebugUI", PERSISTENT | BACKUP}, {"SpeedLimitValueOffset", PERSISTENT},
{"SidebarTemperatureOptions", PERSISTENT | BACKUP}, {"SpeedLimitOffsetType", PERSISTENT},
{"SpeedLimitControlPolicy", PERSISTENT | BACKUP}, {"StandStillTimer", PERSISTENT},
{"SpeedLimitEngageType", PERSISTENT | BACKUP}, {"StockLongToyota", PERSISTENT},
{"SpeedLimitValueOffset", PERSISTENT | BACKUP}, {"TorqueDeadzoneDeg", PERSISTENT},
{"SpeedLimitOffsetType", PERSISTENT | BACKUP}, {"TorqueFriction", PERSISTENT},
{"SpeedLimitWarningFlash", PERSISTENT | BACKUP}, {"TorqueMaxLatAccel", PERSISTENT},
{"SpeedLimitWarningType", PERSISTENT | BACKUP}, {"ToyotaTSS2Long", PERSISTENT},
{"SpeedLimitWarningValueOffset", PERSISTENT | BACKUP}, {"TrueVEgoUi", PERSISTENT},
{"SpeedLimitWarningOffsetType", PERSISTENT | BACKUP}, {"TurnSpeedControl", PERSISTENT},
{"StandStillTimer", PERSISTENT | BACKUP}, {"TurnVisionControl", PERSISTENT},
{"StockLongToyota", PERSISTENT | BACKUP}, {"VisionCurveLaneless", PERSISTENT},
{"SubaruManualParkingBrakeSng", PERSISTENT | BACKUP}, {"VwAccType", PERSISTENT},
{"SunnylinkDongleId", PERSISTENT},
{"SunnylinkEnabled", PERSISTENT},
{"SunnylinkdPid", PERSISTENT},
{"TermsVersionSunnypilot", PERSISTENT},
{"TorqueDeadzoneDeg", PERSISTENT | BACKUP},
{"TorqueFriction", PERSISTENT | BACKUP},
{"TorqueLateralJerk", PERSISTENT | BACKUP},
{"TorqueMaxLatAccel", PERSISTENT | BACKUP},
{"TorquedOverride", PERSISTENT | BACKUP},
{"ToyotaAutoHold", PERSISTENT | BACKUP},
{"ToyotaAutoLockBySpeed", PERSISTENT | BACKUP},
{"ToyotaAutoUnlockByShifter", PERSISTENT | BACKUP},
{"ToyotaDriveMode", PERSISTENT | BACKUP},
{"ToyotaEnhancedBsm", PERSISTENT | BACKUP},
{"ToyotaSnG", PERSISTENT | BACKUP},
{"ToyotaTSS2Long", PERSISTENT | BACKUP},
{"TrueVEgoUi", PERSISTENT | BACKUP},
{"TurnSpeedControl", PERSISTENT | BACKUP},
{"TurnVisionControl", PERSISTENT | BACKUP},
{"DriverCameraHardwareMissing", PERSISTENT},
{"VisionCurveLaneless", PERSISTENT | BACKUP},
{"VwAccType", PERSISTENT | BACKUP},
{"VwCCOnly", PERSISTENT | BACKUP},
{"Offroad_ForceStatus", CLEAR_ON_MANAGER_START},
{"Offroad_SupersededUpdate", PERSISTENT}, {"Offroad_SupersededUpdate", PERSISTENT},
{"SunnylinkCache_Users", PERSISTENT},
{"SunnylinkCache_Roles", PERSISTENT},
{"EnableGitlabRunner", PERSISTENT | BACKUP},
{"EnableSunnylinkUploader", PERSISTENT | BACKUP},
// PFEIFER - MAPD {{
{"MapdVersion", PERSISTENT},
{"RoadName", CLEAR_ON_ONROAD_TRANSITION},
{"MapSpeedLimit", CLEAR_ON_ONROAD_TRANSITION},
{"MapAdvisorySpeedLimit", CLEAR_ON_ONROAD_TRANSITION},
{"NextMapSpeedLimit", CLEAR_ON_ONROAD_TRANSITION},
{"OSMDownloadBounds", PERSISTENT},
{"OSMDownloadLocations", PERSISTENT},
{"OsmDownloadedDate", PERSISTENT},
{"OsmStateTitle", PERSISTENT},
{"OsmStateName", PERSISTENT},
{"OSMDownloadProgress", CLEAR_ON_MANAGER_START},
{"OsmDbUpdatesCheck", CLEAR_ON_MANAGER_START}, // mapd database update happens with device ON, reset on boot
// }} PFEIFER - MAPD
}; };
} // namespace } // namespace
@@ -432,9 +367,7 @@ int Params::put(const char* key, const char* value, size_t value_size) {
} while (false); } while (false);
close(tmp_fd); close(tmp_fd);
if (result != 0) { ::unlink(tmp_path.c_str());
::unlink(tmp_path.c_str());
}
return result; return result;
} }
-1
View File
@@ -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
}; };
-6
View File
@@ -3,7 +3,6 @@
from libcpp cimport bool from libcpp cimport bool
from libcpp.string cimport string from libcpp.string cimport string
from libcpp.vector cimport vector from libcpp.vector cimport vector
from libcpp.map cimport map
cdef extern from "common/params.h": cdef extern from "common/params.h":
cpdef enum ParamKeyType: cpdef enum ParamKeyType:
@@ -12,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":
@@ -28,7 +26,6 @@ cdef extern from "common/params.h":
string getParamPath(string) nogil string getParamPath(string) nogil
void clearAll(ParamKeyType) void clearAll(ParamKeyType)
vector[string] allKeys() vector[string] allKeys()
map[string, string] readAll()
def ensure_bytes(v): def ensure_bytes(v):
@@ -119,6 +116,3 @@ cdef class Params:
def all_keys(self): def all_keys(self):
return self.p.allKeys() return self.p.allKeys()
def read_all(self):
return self.p.readAll()
-5
View File
@@ -5,7 +5,6 @@
#include "common/params.h" #include "common/params.h"
#include "common/util.h" #include "common/util.h"
#include "system/hardware/hw.h"
class OpenpilotPrefix { class OpenpilotPrefix {
public: public:
@@ -26,10 +25,6 @@ public:
system(util::string_format("rm %s -rf", real_path.c_str()).c_str()); system(util::string_format("rm %s -rf", real_path.c_str()).c_str());
unlink(param_path.c_str()); unlink(param_path.c_str());
} }
if (getenv("COMMA_CACHE") == nullptr) {
system(util::string_format("rm %s -rf", Path::download_cache_root().c_str()).c_str());
}
system(util::string_format("rm %s -rf", Path::comma_home().c_str()).c_str());
system(util::string_format("rm %s -rf", msgq_path.c_str()).c_str()); system(util::string_format("rm %s -rf", msgq_path.c_str()).c_str());
unsetenv("OPENPILOT_PREFIX"); unsetenv("OPENPILOT_PREFIX");
} }
+1 -3
View File
@@ -4,7 +4,6 @@ import uuid
from openpilot.common.params import Params from openpilot.common.params import Params
from openpilot.system.hardware import PC
from openpilot.system.hardware.hw import Paths from openpilot.system.hardware.hw import Paths
from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT
@@ -46,8 +45,7 @@ class OpenpilotPrefix:
shutil.rmtree(os.path.realpath(symlink_path), ignore_errors=True) shutil.rmtree(os.path.realpath(symlink_path), ignore_errors=True)
os.remove(symlink_path) os.remove(symlink_path)
shutil.rmtree(self.msgq_path, ignore_errors=True) shutil.rmtree(self.msgq_path, ignore_errors=True)
if PC: shutil.rmtree(Paths.log_root(), ignore_errors=True)
shutil.rmtree(Paths.log_root(), ignore_errors=True)
if not os.environ.get("COMMA_CACHE", False): if not os.environ.get("COMMA_CACHE", False):
shutil.rmtree(Paths.download_cache_root(), ignore_errors=True) shutil.rmtree(Paths.download_cache_root(), ignore_errors=True)
shutil.rmtree(Paths.comma_home(), ignore_errors=True) shutil.rmtree(Paths.comma_home(), ignore_errors=True)
+1 -1
View File
@@ -9,7 +9,7 @@ public:
~RateKeeper() {} ~RateKeeper() {}
bool keepTime(); bool keepTime();
bool monitorTime(); bool monitorTime();
inline uint64_t frame() const { return frame_; } inline double frame() const { return frame_; }
inline double remaining() const { return remaining_; } inline double remaining() const { return remaining_; }
private: private:
+5 -15
View File
@@ -2,11 +2,9 @@
import gc import gc
import os import os
import time import time
import threading
import psutil
from collections import deque from collections import deque
from openpilot.common.threadname import getthreadname from setproctitle import getproctitle
from openpilot.system.hardware import PC from openpilot.system.hardware import PC
@@ -14,7 +12,7 @@ from openpilot.system.hardware import PC
# time step for each process # time step for each process
DT_CTRL = 0.01 # controlsd DT_CTRL = 0.01 # controlsd
DT_MDL = 0.05 # model DT_MDL = 0.05 # model
DT_HW = 0.5 # hardwared and manager DT_TRML = 0.5 # thermald and manager
DT_DMON = 0.05 # driver monitoring DT_DMON = 0.05 # driver monitoring
@@ -25,7 +23,7 @@ class Priority:
CTRL_LOW = 51 # plannerd & radard CTRL_LOW = 51 # plannerd & radard
# CORE 3 # CORE 3
# - pandad = 55 # - boardd = 55
CTRL_HIGH = 53 CTRL_HIGH = 53
@@ -46,14 +44,6 @@ def config_realtime_process(cores: int | list[int], priority: int) -> None:
set_core_affinity(c) set_core_affinity(c)
def set_thread_affinity(thread: threading.Thread, cores: list[int]) -> None:
try:
process = psutil.Process(thread.ident)
process.cpu_affinity(cores)
except Exception as e:
print(f"Error setting thread affinity: {e}")
class Ratekeeper: class Ratekeeper:
def __init__(self, rate: float, print_delay_threshold: float | None = 0.0) -> None: def __init__(self, rate: float, print_delay_threshold: float | None = 0.0) -> None:
"""Rate in Hz for ratekeeping. print_delay_threshold must be nonnegative.""" """Rate in Hz for ratekeeping. print_delay_threshold must be nonnegative."""
@@ -62,7 +52,7 @@ class Ratekeeper:
self._print_delay_threshold = print_delay_threshold self._print_delay_threshold = print_delay_threshold
self._frame = 0 self._frame = 0
self._remaining = 0.0 self._remaining = 0.0
self._thread_name = getthreadname() self._process_name = getproctitle()
self._dts = deque([self._interval], maxlen=100) self._dts = deque([self._interval], maxlen=100)
self._last_monitor_time = time.monotonic() self._last_monitor_time = time.monotonic()
@@ -97,7 +87,7 @@ class Ratekeeper:
remaining = self._next_frame_time - time.monotonic() remaining = self._next_frame_time - time.monotonic()
self._next_frame_time += self._interval self._next_frame_time += self._interval
if self._print_delay_threshold is not None and remaining < -self._print_delay_threshold: if self._print_delay_threshold is not None and remaining < -self._print_delay_threshold:
print(f"{self._thread_name} lagging by {-remaining * 1000:.2f} ms") print(f"{self._process_name} lagging by {-remaining * 1000:.2f} ms")
lagged = True lagged = True
self._frame += 1 self._frame += 1
self._remaining = remaining self._remaining = remaining
-13
View File
@@ -1,13 +0,0 @@
import subprocess
def run_cmd(cmd: list[str], cwd=None, env=None) -> str:
return subprocess.check_output(cmd, encoding='utf8', cwd=cwd, env=env).strip()
def run_cmd_default(cmd: list[str], default: str = "", cwd=None, env=None) -> str:
try:
return run_cmd(cmd, cwd=cwd, env=env)
except subprocess.CalledProcessError:
return default
+1 -1
View File
@@ -3,7 +3,7 @@ import subprocess
from openpilot.common.basedir import BASEDIR from openpilot.common.basedir import BASEDIR
class Spinner: class Spinner():
def __init__(self): def __init__(self):
try: try:
self.spinner_proc = subprocess.Popen(["./spinner"], self.spinner_proc = subprocess.Popen(["./spinner"],
+2 -2
View File
@@ -1,6 +1,6 @@
import numpy as np import numpy as np
class RunningStat: class RunningStat():
# tracks realtime mean and standard deviation without storing any data # tracks realtime mean and standard deviation without storing any data
def __init__(self, priors=None, max_trackable=-1): def __init__(self, priors=None, max_trackable=-1):
self.max_trackable = max_trackable self.max_trackable = max_trackable
@@ -51,7 +51,7 @@ class RunningStat:
def params_to_save(self): def params_to_save(self):
return [self.M, self.S, self.n] return [self.M, self.S, self.n]
class RunningStatFilter: class RunningStatFilter():
def __init__(self, raw_priors=None, filtered_priors=None, max_trackable=-1): def __init__(self, raw_priors=None, filtered_priors=None, max_trackable=-1):
self.raw_stat = RunningStat(raw_priors, -1) self.raw_stat = RunningStat(raw_priors, -1)
self.filtered_stat = RunningStat(filtered_priors, max_trackable) self.filtered_stat = RunningStat(filtered_priors, max_trackable)
+7 -2
View File
@@ -1,10 +1,11 @@
import os import os
import unittest
from uuid import uuid4 from uuid import uuid4
from openpilot.common.file_helpers import atomic_write_in_dir from openpilot.common.file_helpers import atomic_write_in_dir
class TestFileHelpers: class TestFileHelpers(unittest.TestCase):
def run_atomic_write_func(self, atomic_write_func): def run_atomic_write_func(self, atomic_write_func):
path = f"/tmp/tmp{uuid4()}" path = f"/tmp/tmp{uuid4()}"
with atomic_write_func(path) as f: with atomic_write_func(path) as f:
@@ -12,8 +13,12 @@ class TestFileHelpers:
assert not os.path.exists(path) assert not os.path.exists(path)
with open(path) as f: with open(path) as f:
assert f.read() == "test" self.assertEqual(f.read(), "test")
os.remove(path) os.remove(path)
def test_atomic_write_in_dir(self): def test_atomic_write_in_dir(self):
self.run_atomic_write_func(atomic_write_in_dir) self.run_atomic_write_func(atomic_write_in_dir)
if __name__ == "__main__":
unittest.main()
-15
View File
@@ -1,15 +0,0 @@
import os
from openpilot.common.basedir import BASEDIR
from openpilot.common.markdown import parse_markdown
class TestMarkdown:
def test_all_release_notes(self):
with open(os.path.join(BASEDIR, "RELEASES.md")) as f:
release_notes = f.read().split("\n\n")
assert len(release_notes) > 10
for rn in release_notes:
md = parse_markdown(rn)
assert len(md) > 0
+6 -1
View File
@@ -1,9 +1,10 @@
import numpy as np import numpy as np
import unittest
from openpilot.common.numpy_fast import interp from openpilot.common.numpy_fast import interp
class TestInterp: class InterpTest(unittest.TestCase):
def test_correctness_controls(self): def test_correctness_controls(self):
_A_CRUISE_MIN_BP = np.asarray([0., 5., 10., 20., 40.]) _A_CRUISE_MIN_BP = np.asarray([0., 5., 10., 20., 40.])
_A_CRUISE_MIN_V = np.asarray([-1.0, -.8, -.67, -.5, -.30]) _A_CRUISE_MIN_V = np.asarray([-1.0, -.8, -.67, -.5, -.30])
@@ -19,3 +20,7 @@ class TestInterp:
expected = np.interp(v_ego, _A_CRUISE_MIN_BP, _A_CRUISE_MIN_V) 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) actual = interp(v_ego, _A_CRUISE_MIN_BP, _A_CRUISE_MIN_V)
np.testing.assert_equal(actual, expected) np.testing.assert_equal(actual, expected)
if __name__ == "__main__":
unittest.main()
+16 -12
View File
@@ -1,13 +1,13 @@
import pytest
import os import os
import threading import threading
import time import time
import uuid import uuid
import unittest
from openpilot.common.params import Params, ParamKeyType, UnknownKeyName from openpilot.common.params import Params, ParamKeyType, UnknownKeyName
class TestParams: class TestParams(unittest.TestCase):
def setup_method(self): def setUp(self):
self.params = Params() self.params = Params()
def test_params_put_and_get(self): def test_params_put_and_get(self):
@@ -49,16 +49,16 @@ class TestParams:
assert self.params.get("CarParams", True) == b"test" assert self.params.get("CarParams", True) == b"test"
def test_params_unknown_key_fails(self): def test_params_unknown_key_fails(self):
with pytest.raises(UnknownKeyName): with self.assertRaises(UnknownKeyName):
self.params.get("swag") self.params.get("swag")
with pytest.raises(UnknownKeyName): with self.assertRaises(UnknownKeyName):
self.params.get_bool("swag") self.params.get_bool("swag")
with pytest.raises(UnknownKeyName): with self.assertRaises(UnknownKeyName):
self.params.put("swag", "abc") self.params.put("swag", "abc")
with pytest.raises(UnknownKeyName): with self.assertRaises(UnknownKeyName):
self.params.put_bool("swag", True) self.params.put_bool("swag", True)
def test_remove_not_there(self): def test_remove_not_there(self):
@@ -68,19 +68,19 @@ class TestParams:
def test_get_bool(self): def test_get_bool(self):
self.params.remove("IsMetric") self.params.remove("IsMetric")
assert not self.params.get_bool("IsMetric") self.assertFalse(self.params.get_bool("IsMetric"))
self.params.put_bool("IsMetric", True) self.params.put_bool("IsMetric", True)
assert self.params.get_bool("IsMetric") self.assertTrue(self.params.get_bool("IsMetric"))
self.params.put_bool("IsMetric", False) self.params.put_bool("IsMetric", False)
assert not self.params.get_bool("IsMetric") self.assertFalse(self.params.get_bool("IsMetric"))
self.params.put("IsMetric", "1") self.params.put("IsMetric", "1")
assert self.params.get_bool("IsMetric") self.assertTrue(self.params.get_bool("IsMetric"))
self.params.put("IsMetric", "0") self.params.put("IsMetric", "0")
assert not self.params.get_bool("IsMetric") self.assertFalse(self.params.get_bool("IsMetric"))
def test_put_non_blocking_with_get_block(self): def test_put_non_blocking_with_get_block(self):
q = Params() q = Params()
@@ -107,3 +107,7 @@ class TestParams:
assert len(keys) > 20 assert len(keys) > 20
assert len(keys) == len(set(keys)) assert len(keys) == len(set(keys))
assert b"CarParams" in keys assert b"CarParams" in keys
if __name__ == "__main__":
unittest.main()
+10 -4
View File
@@ -1,8 +1,10 @@
import unittest
from openpilot.common.simple_kalman import KF1D from openpilot.common.simple_kalman import KF1D
class TestSimpleKalman: class TestSimpleKalman(unittest.TestCase):
def setup_method(self): def setUp(self):
dt = 0.01 dt = 0.01
x0_0 = 0.0 x0_0 = 0.0
x1_0 = 0.0 x1_0 = 0.0
@@ -22,8 +24,12 @@ class TestSimpleKalman:
def test_getter_setter(self): def test_getter_setter(self):
self.kf.set_x([[1.0], [1.0]]) self.kf.set_x([[1.0], [1.0]])
assert self.kf.x == [[1.0], [1.0]] self.assertEqual(self.kf.x, [[1.0], [1.0]])
def update_returns_state(self): def update_returns_state(self):
x = self.kf.update(100) x = self.kf.update(100)
assert x == self.kf.x self.assertEqual(x, self.kf.x)
if __name__ == "__main__":
unittest.main()
-8
View File
@@ -1,8 +0,0 @@
from openpilot.common.threadname import setthreadname, getthreadname, LINUX
class TestThreadName:
def test_set_get_threadname(self):
if LINUX:
name = 'TESTING'
setthreadname(name)
assert name == getthreadname()
-19
View File
@@ -1,19 +0,0 @@
import ctypes
import os
LINUX = os.name == 'posix' and os.uname().sysname == 'Linux'
if LINUX:
libc = ctypes.CDLL('libc.so.6')
def setthreadname(name: str) -> None:
if LINUX:
name = name[-15:] + '\0'
libc.prctl(15, str.encode(name), 0, 0, 0)
def getthreadname() -> str:
if LINUX:
name = ctypes.create_string_buffer(16)
libc.prctl(16, name)
return name.value.decode('utf-8')
return ""
+2 -11
View File
@@ -1,15 +1,6 @@
import datetime import datetime
from pathlib import Path
_MIN_DATE = datetime.datetime(year=2024, month=3, day=30) MIN_DATE = datetime.datetime(year=2024, month=1, day=28)
def min_date():
# on systemd systems, the default time is the systemd build time
systemd_path = Path("/lib/systemd/systemd")
if systemd_path.exists():
d = datetime.datetime.fromtimestamp(systemd_path.stat().st_mtime)
return d + datetime.timedelta(days=1)
return _MIN_DATE
def system_time_valid(): def system_time_valid():
return datetime.datetime.now() > min_date() return datetime.datetime.now() > MIN_DATE
+39 -58
View File
@@ -1,74 +1,55 @@
import itertools
import numpy as np import numpy as np
from dataclasses import dataclass
import openpilot.common.transformations.orientation as orient import openpilot.common.transformations.orientation as orient
## -- hardcoded hardware params -- ## -- hardcoded hardware params --
@dataclass(frozen=True) eon_f_focal_length = 910.0
class CameraConfig: eon_d_focal_length = 650.0
width: int tici_f_focal_length = 2648.0
height: int tici_e_focal_length = tici_d_focal_length = 567.0 # probably wrong? magnification is not consistent across frame
focal_length: float
@property eon_f_frame_size = (1164, 874)
def size(self): eon_d_frame_size = (816, 612)
return (self.width, self.height) tici_f_frame_size = tici_e_frame_size = tici_d_frame_size = (1928, 1208)
@property # aka 'K' aka camera_frame_from_view_frame
def intrinsics(self): eon_fcam_intrinsics = np.array([
# aka 'K' aka camera_frame_from_view_frame [eon_f_focal_length, 0.0, float(eon_f_frame_size[0])/2],
return np.array([ [0.0, eon_f_focal_length, float(eon_f_frame_size[1])/2],
[self.focal_length, 0.0, float(self.width)/2], [0.0, 0.0, 1.0]])
[0.0, self.focal_length, float(self.height)/2], eon_intrinsics = eon_fcam_intrinsics # xx
[0.0, 0.0, 1.0]
])
@property eon_dcam_intrinsics = np.array([
def intrinsics_inv(self): [eon_d_focal_length, 0.0, float(eon_d_frame_size[0])/2],
# aka 'K_inv' aka view_frame_from_camera_frame [0.0, eon_d_focal_length, float(eon_d_frame_size[1])/2],
return np.linalg.inv(self.intrinsics) [0.0, 0.0, 1.0]])
@dataclass(frozen=True) tici_fcam_intrinsics = np.array([
class _NoneCameraConfig(CameraConfig): [tici_f_focal_length, 0.0, float(tici_f_frame_size[0])/2],
width: int = 0 [0.0, tici_f_focal_length, float(tici_f_frame_size[1])/2],
height: int = 0 [0.0, 0.0, 1.0]])
focal_length: float = 0
@dataclass(frozen=True) tici_dcam_intrinsics = np.array([
class DeviceCameraConfig: [tici_d_focal_length, 0.0, float(tici_d_frame_size[0])/2],
fcam: CameraConfig [0.0, tici_d_focal_length, float(tici_d_frame_size[1])/2],
dcam: CameraConfig [0.0, 0.0, 1.0]])
ecam: CameraConfig
def all_cams(self): tici_ecam_intrinsics = tici_dcam_intrinsics
for cam in ['fcam', 'dcam', 'ecam']:
if not isinstance(getattr(self, cam), _NoneCameraConfig):
yield cam, getattr(self, cam)
_ar_ox_fisheye = CameraConfig(1928, 1208, 567.0) # focal length probably wrong? magnification is not consistent across frame # aka 'K_inv' aka view_frame_from_camera_frame
_os_fisheye = CameraConfig(2688 // 2, 1520 // 2, 567.0 / 4 * 3) eon_fcam_intrinsics_inv = np.linalg.inv(eon_fcam_intrinsics)
_ar_ox_config = DeviceCameraConfig(CameraConfig(1928, 1208, 2648.0), _ar_ox_fisheye, _ar_ox_fisheye) eon_intrinsics_inv = eon_fcam_intrinsics_inv # xx
_os_config = DeviceCameraConfig(CameraConfig(2688 // 2, 1520 // 2, 1522.0 * 3 / 4), _os_fisheye, _os_fisheye)
_neo_config = DeviceCameraConfig(CameraConfig(1164, 874, 910.0), CameraConfig(816, 612, 650.0), _NoneCameraConfig())
DEVICE_CAMERAS = { tici_fcam_intrinsics_inv = np.linalg.inv(tici_fcam_intrinsics)
# A "device camera" is defined by a device type and sensor tici_ecam_intrinsics_inv = np.linalg.inv(tici_ecam_intrinsics)
# sensor type was never set on eon/neo/two
("neo", "unknown"): _neo_config,
# unknown here is AR0231, field was added with OX03C10 support
("tici", "unknown"): _ar_ox_config,
# before deviceState.deviceType was set, assume tici AR config FULL_FRAME_SIZE = tici_f_frame_size
("unknown", "ar0231"): _ar_ox_config, FOCAL = tici_f_focal_length
("unknown", "ox03c10"): _ar_ox_config, fcam_intrinsics = tici_fcam_intrinsics
W, H = FULL_FRAME_SIZE[0], FULL_FRAME_SIZE[1]
# simulator (emulates a tici)
("pc", "unknown"): _ar_ox_config,
}
prods = itertools.product(('tici', 'tizi', 'mici'), (('ar0231', _ar_ox_config), ('ox03c10', _ar_ox_config), ('os04c10', _os_config)))
DEVICE_CAMERAS.update({(d, c[0]): c[1] for d, c in prods})
# device/mesh : x->forward, y-> right, z->down # device/mesh : x->forward, y-> right, z->down
# view : x->right, y->down, z->forward # view : x->right, y->down, z->forward
@@ -112,7 +93,7 @@ def roll_from_ke(m):
-(m[0, 0] - m[0, 1] * m[2, 0] / m[2, 1])) -(m[0, 0] - m[0, 1] * m[2, 0] / m[2, 1]))
def normalize(img_pts, intrinsics): def normalize(img_pts, intrinsics=fcam_intrinsics):
# normalizes image coordinates # normalizes image coordinates
# accepts single pt or array of pts # accepts single pt or array of pts
intrinsics_inv = np.linalg.inv(intrinsics) intrinsics_inv = np.linalg.inv(intrinsics)
@@ -125,7 +106,7 @@ def normalize(img_pts, intrinsics):
return img_pts_normalized[:, :2].reshape(input_shape) return img_pts_normalized[:, :2].reshape(input_shape)
def denormalize(img_pts, intrinsics, width=np.inf, height=np.inf): def denormalize(img_pts, intrinsics=fcam_intrinsics, width=np.inf, height=np.inf):
# denormalizes image coordinates # denormalizes image coordinates
# accepts single pt or array of pts # accepts single pt or array of pts
img_pts = np.array(img_pts) img_pts = np.array(img_pts)
@@ -142,7 +123,7 @@ def denormalize(img_pts, intrinsics, width=np.inf, height=np.inf):
return img_pts_denormalized[:, :2].reshape(input_shape) return img_pts_denormalized[:, :2].reshape(input_shape)
def get_calib_from_vp(vp, intrinsics): def get_calib_from_vp(vp, intrinsics=fcam_intrinsics):
vp_norm = normalize(vp, intrinsics) vp_norm = normalize(vp, intrinsics)
yaw_calib = np.arctan(vp_norm[0]) yaw_calib = np.arctan(vp_norm[0])
pitch_calib = -np.arctan(vp_norm[1]*np.cos(yaw_calib)) pitch_calib = -np.arctan(vp_norm[1]*np.cos(yaw_calib))
+18 -3
View File
@@ -1,11 +1,19 @@
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 from openpilot.common.transformations.camera import (
FULL_FRAME_SIZE, get_view_frame_from_calib_frame, view_frame_from_device_frame,
eon_fcam_intrinsics, tici_ecam_intrinsics, tici_fcam_intrinsics)
# segnet # segnet
SEGNET_SIZE = (512, 384) SEGNET_SIZE = (512, 384)
def get_segnet_frame_from_camera_frame(segnet_size=SEGNET_SIZE, full_frame_size=FULL_FRAME_SIZE):
return np.array([[float(segnet_size[0]) / full_frame_size[0], 0.0],
[0.0, float(segnet_size[1]) / full_frame_size[1]]])
segnet_frame_from_camera_frame = get_segnet_frame_from_camera_frame() # xx
# MED model # MED model
MEDMODEL_INPUT_SIZE = (512, 256) MEDMODEL_INPUT_SIZE = (512, 256)
MEDMODEL_YUV_SIZE = (MEDMODEL_INPUT_SIZE[0], MEDMODEL_INPUT_SIZE[1] * 3 // 2) MEDMODEL_YUV_SIZE = (MEDMODEL_INPUT_SIZE[0], MEDMODEL_INPUT_SIZE[1] * 3 // 2)
@@ -55,9 +63,16 @@ calib_from_medmodel = np.linalg.inv(medmodel_frame_from_calib_frame[:, :3])
calib_from_sbigmodel = np.linalg.inv(sbigmodel_frame_from_calib_frame[:, :3]) calib_from_sbigmodel = np.linalg.inv(sbigmodel_frame_from_calib_frame[:, :3])
# This function is verified to give similar results to xx.uncommon.utils.transform_img # This function is verified to give similar results to xx.uncommon.utils.transform_img
def get_warp_matrix(device_from_calib_euler: np.ndarray, intrinsics: np.ndarray, bigmodel_frame: bool = False) -> np.ndarray: def get_warp_matrix(device_from_calib_euler: np.ndarray, wide_camera: bool = False, bigmodel_frame: bool = False, tici: bool = True) -> np.ndarray:
if tici and wide_camera:
cam_intrinsics = tici_ecam_intrinsics
elif tici:
cam_intrinsics = tici_fcam_intrinsics
else:
cam_intrinsics = eon_fcam_intrinsics
calib_from_model = calib_from_sbigmodel if bigmodel_frame else calib_from_medmodel calib_from_model = calib_from_sbigmodel if bigmodel_frame else calib_from_medmodel
device_from_calib = rot_from_euler(device_from_calib_euler) device_from_calib = rot_from_euler(device_from_calib_euler)
camera_from_calib = intrinsics @ view_frame_from_device_frame @ device_from_calib camera_from_calib = cam_intrinsics @ view_frame_from_device_frame @ device_from_calib
warp_matrix: np.ndarray = camera_from_calib @ calib_from_model warp_matrix: np.ndarray = camera_from_calib @ calib_from_model
return warp_matrix return warp_matrix
+10 -5
View File
@@ -1,4 +1,7 @@
#!/usr/bin/env python3
import numpy as np import numpy as np
import unittest
import openpilot.common.transformations.coordinates as coord import openpilot.common.transformations.coordinates as coord
@@ -41,7 +44,7 @@ ned_offsets_batch = np.array([[ 53.88103168, 43.83445935, -46.27488057],
[ 78.56272609, 18.53100158, -43.25290759]]) [ 78.56272609, 18.53100158, -43.25290759]])
class TestNED: class TestNED(unittest.TestCase):
def test_small_distances(self): def test_small_distances(self):
start_geodetic = np.array([33.8042184, -117.888593, 0.0]) start_geodetic = np.array([33.8042184, -117.888593, 0.0])
local_coord = coord.LocalCoord.from_geodetic(start_geodetic) local_coord = coord.LocalCoord.from_geodetic(start_geodetic)
@@ -51,13 +54,13 @@ class TestNED:
west_geodetic = start_geodetic + [0, -0.0005, 0] west_geodetic = start_geodetic + [0, -0.0005, 0]
west_ned = local_coord.geodetic2ned(west_geodetic) west_ned = local_coord.geodetic2ned(west_geodetic)
assert np.abs(west_ned[0]) < 1e-3 self.assertLess(np.abs(west_ned[0]), 1e-3)
assert west_ned[1] < 0 self.assertLess(west_ned[1], 0)
southwest_geodetic = start_geodetic + [-0.0005, -0.002, 0] southwest_geodetic = start_geodetic + [-0.0005, -0.002, 0]
southwest_ned = local_coord.geodetic2ned(southwest_geodetic) southwest_ned = local_coord.geodetic2ned(southwest_geodetic)
assert southwest_ned[0] < 0 self.assertLess(southwest_ned[0], 0)
assert southwest_ned[1] < 0 self.assertLess(southwest_ned[1], 0)
def test_ecef_geodetic(self): def test_ecef_geodetic(self):
# testing single # testing single
@@ -102,3 +105,5 @@ class TestNED:
np.testing.assert_allclose(converter.ned2ecef(ned_offsets_batch), np.testing.assert_allclose(converter.ned2ecef(ned_offsets_batch),
ecef_positions_offset_batch, ecef_positions_offset_batch,
rtol=1e-9, atol=1e-7) rtol=1e-9, atol=1e-7)
if __name__ == "__main__":
unittest.main()
+8 -1
View File
@@ -1,4 +1,7 @@
#!/usr/bin/env python3
import numpy as np import numpy as np
import unittest
from openpilot.common.transformations.orientation import euler2quat, quat2euler, euler2rot, rot2euler, \ from openpilot.common.transformations.orientation import euler2quat, quat2euler, euler2rot, rot2euler, \
rot2quat, quat2rot, \ rot2quat, quat2rot, \
@@ -29,7 +32,7 @@ ned_eulers = np.array([[ 0.46806039, -0.4881889 , 1.65697808],
[ 2.50450101, 0.36304151, 0.33136365]]) [ 2.50450101, 0.36304151, 0.33136365]])
class TestOrientation: class TestOrientation(unittest.TestCase):
def test_quat_euler(self): def test_quat_euler(self):
for i, eul in enumerate(eulers): for i, eul in enumerate(eulers):
np.testing.assert_allclose(quats[i], euler2quat(eul), rtol=1e-7) np.testing.assert_allclose(quats[i], euler2quat(eul), rtol=1e-7)
@@ -59,3 +62,7 @@ class TestOrientation:
np.testing.assert_allclose(ned_eulers[i], ned_euler_from_ecef(ecef_positions[i], eulers[i]), rtol=1e-7) np.testing.assert_allclose(ned_eulers[i], ned_euler_from_ecef(ecef_positions[i], eulers[i]), rtol=1e-7)
#np.testing.assert_allclose(eulers[i], ecef_euler_from_ned(ecef_positions[i], ned_eulers[i]), rtol=1e-7) #np.testing.assert_allclose(eulers[i], ecef_euler_from_ned(ecef_positions[i], ned_eulers[i]), rtol=1e-7)
# np.testing.assert_allclose(ned_eulers, ned_euler_from_ecef(ecef_positions, eulers), rtol=1e-7) # np.testing.assert_allclose(ned_eulers, ned_euler_from_ecef(ecef_positions, eulers), rtol=1e-7)
if __name__ == "__main__":
unittest.main()
+24 -3
View File
@@ -246,13 +246,18 @@ std::string random_string(std::string::size_type length) {
return s; return s;
} }
std::string dir_name(std::string const &path) {
size_t pos = path.find_last_of("/");
if (pos == std::string::npos) return "";
return path.substr(0, pos);
}
bool starts_with(const std::string &s1, const std::string &s2) { bool starts_with(const std::string &s1, const std::string &s2) {
return strncmp(s1.c_str(), s2.c_str(), s2.size()) == 0; return strncmp(s1.c_str(), s2.c_str(), s2.size()) == 0;
} }
bool ends_with(const std::string& s, const std::string& suffix) { bool ends_with(const std::string &s1, const std::string &s2) {
return s.size() >= suffix.size() && return strcmp(s1.c_str() + (s1.size() - s2.size()), s2.c_str()) == 0;
strcmp(s.c_str() + (s.size() - suffix.size()), suffix.c_str()) == 0;
} }
std::string check_output(const std::string& command) { std::string check_output(const std::string& command) {
@@ -271,4 +276,20 @@ std::string check_output(const std::string& command) {
return result; return result;
} }
struct tm get_time() {
time_t rawtime;
time(&rawtime);
struct tm sys_time;
gmtime_r(&rawtime, &sys_time);
return sys_time;
}
bool time_valid(struct tm sys_time) {
int year = 1900 + sys_time.tm_year;
int month = 1 + sys_time.tm_mon;
return (year > 2023) || (year == 2023 && month >= 6);
}
} // namespace util } // namespace util
+7 -8
View File
@@ -8,6 +8,7 @@
#include <atomic> #include <atomic>
#include <chrono> #include <chrono>
#include <csignal> #include <csignal>
#include <ctime>
#include <map> #include <map>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
@@ -44,6 +45,10 @@ int set_realtime_priority(int level);
int set_core_affinity(std::vector<int> cores); int set_core_affinity(std::vector<int> cores);
int set_file_descriptor_limit(uint64_t limit); int set_file_descriptor_limit(uint64_t limit);
// ***** Time helpers *****
struct tm get_time();
bool time_valid(struct tm sys_time);
// ***** math helpers ***** // ***** math helpers *****
// map x from [a1, a2] to [b1, b2] // map x from [a1, a2] to [b1, b2]
@@ -70,8 +75,9 @@ int getenv(const char* key, int default_val);
float getenv(const char* key, float default_val); 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);
std::string dir_name(std::string const& path);
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 &s1, const std::string &s2);
// ***** random helpers ***** // ***** random helpers *****
int random_int(int min, int max); int random_int(int min, int max);
@@ -173,10 +179,3 @@ void update_max_atomic(std::atomic<T>& max, T const& value) {
T prev = max; T prev = max;
while (prev < value && !max.compare_exchange_weak(prev, value)) {} while (prev < value && !max.compare_exchange_weak(prev, value)) {}
} }
typedef struct Rect {
int x;
int y;
int w;
int h;
} Rect;
-11
View File
@@ -1,11 +0,0 @@
class Freezable:
_frozen: bool = False
def freeze(self):
if not self._frozen:
self._frozen = True
def __setattr__(self, *args, **kwargs):
if self._frozen:
raise Exception("cannot modify frozen object")
super().__setattr__(*args, **kwargs)
+1 -1
View File
@@ -1 +1 @@
#define COMMA_VERSION "0.9.8.0" #define COMMA_VERSION "0.9.7.0"

Some files were not shown because too many files have changed in this diff Show More