mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-06-22 01:32:07 +08:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 737a6c4236 | |||
| 86cd1b238d | |||
| 772e62127e | |||
| e7a3ea1b32 | |||
| 87af129090 | |||
| f6cf1336ef | |||
| 51046dd7fd | |||
| 2c85f29a0b | |||
| 68af0c4a17 |
@@ -29,11 +29,11 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
target: /^(?!master$).*/
|
target: /^(?!master-tici$).*/
|
||||||
exclude: /sunnypilot:.*/
|
exclude: /sunnypilot:.*/
|
||||||
change-to: ${{ github.base_ref }}
|
change-to: ${{ github.base_ref }}
|
||||||
already-exists-action: close_this
|
already-exists-action: close_this
|
||||||
already-exists-comment: "Your PR should be made against the `master` branch"
|
already-exists-comment: "Your PR should be made against the `master-tici` branch"
|
||||||
|
|
||||||
update-pr-labels:
|
update-pr-labels:
|
||||||
name: Update fork's PR Labels
|
name: Update fork's PR Labels
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
BASE_IMAGE: sunnypilot-base
|
BASE_IMAGE: sunnypilot-tici-base
|
||||||
DOCKER_REGISTRY: ghcr.io/sunnypilot
|
DOCKER_REGISTRY: ghcr.io/sunnypilot
|
||||||
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 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
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ name: cereal validation
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master-tici
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- 'cereal/**'
|
- 'cereal/**'
|
||||||
@@ -16,7 +16,7 @@ on:
|
|||||||
type: string
|
type: string
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: cereal-validation-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: cereal-validation-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master-tici' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix: ${{fromJSON(needs.setup.outputs.ci_runs)}}
|
matrix: ${{fromJSON(needs.setup.outputs.ci_runs)}}
|
||||||
uses: sunnypilot/sunnypilot/.github/workflows/ci_weekly_run.yaml@master
|
uses: sunnypilot/sunnypilot/.github/workflows/ci_weekly_run.yaml@master-tici
|
||||||
with:
|
with:
|
||||||
run_number: ${{ matrix.run_number }}
|
run_number: ${{ matrix.run_number }}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,6 @@ concurrency:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
selfdrive_tests:
|
selfdrive_tests:
|
||||||
uses: sunnypilot/sunnypilot/.github/workflows/selfdrive_tests.yaml@master
|
uses: sunnypilot/sunnypilot/.github/workflows/selfdrive_tests.yaml@master-tici
|
||||||
with:
|
with:
|
||||||
run_number: ${{ inputs.run_number }}
|
run_number: ${{ inputs.run_number }}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ runs:
|
|||||||
scons -j$(nproc) --cache-populate"
|
scons -j$(nproc) --cache-populate"
|
||||||
- name: Save scons cache
|
- name: Save scons cache
|
||||||
uses: actions/cache/save@v4
|
uses: actions/cache/save@v4
|
||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master-tici'
|
||||||
with:
|
with:
|
||||||
path: .ci_cache/scons_cache
|
path: .ci_cache/scons_cache
|
||||||
key: scons-${{ runner.arch }}-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
key: scons-${{ runner.arch }}-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ name: docs
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master-tici
|
||||||
pull_request:
|
pull_request:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
@@ -12,7 +12,7 @@ on:
|
|||||||
required: true
|
required: true
|
||||||
type: string
|
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: docs-tests-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master-tici' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -35,13 +35,13 @@ jobs:
|
|||||||
|
|
||||||
# Push to docs.comma.ai
|
# Push to docs.comma.ai
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
if: github.ref == 'refs/heads/master' && github.repository == 'sunnypilot/sunnypilot'
|
if: github.ref == 'refs/heads/master-tici' && github.repository == 'sunnypilot/sunnypilot'
|
||||||
with:
|
with:
|
||||||
path: openpilot-docs
|
path: openpilot-docs
|
||||||
ssh-key: ${{ secrets.OPENPILOT_DOCS_KEY }}
|
ssh-key: ${{ secrets.OPENPILOT_DOCS_KEY }}
|
||||||
repository: sunnypilot/sunnypilot-docs
|
repository: sunnypilot/sunnypilot-docs
|
||||||
- name: Push
|
- name: Push
|
||||||
if: github.ref == 'refs/heads/master' && github.repository == 'sunnypilot/sunnypilot'
|
if: github.ref == 'refs/heads/master-tici' && github.repository == 'sunnypilot/sunnypilot'
|
||||||
run: |
|
run: |
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ jobs:
|
|||||||
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@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc
|
||||||
with:
|
with:
|
||||||
ref: master
|
ref: master-tici
|
||||||
wait-interval: 30
|
wait-interval: 30
|
||||||
running-workflow-name: 'build prebuilt'
|
running-workflow-name: 'build prebuilt'
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
check-regexp: ^((?!.*(build master-ci).*).)*$
|
check-regexp: ^((?!.*(build __nightly).*).)*$
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ jobs:
|
|||||||
contents: write
|
contents: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
if: False
|
||||||
steps:
|
steps:
|
||||||
- uses: release-drafter/release-drafter@v6
|
- uses: release-drafter/release-drafter@v6
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
ImageOS: ubuntu24
|
ImageOS: ubuntu24
|
||||||
container:
|
container:
|
||||||
image: ghcr.io/sunnypilot/sunnypilot-base:latest
|
image: ghcr.io/sunnypilot/sunnypilot-tici-base:latest
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.repository == 'sunnypilot/sunnypilot'
|
if: github.repository == 'sunnypilot/sunnypilot'
|
||||||
permissions:
|
permissions:
|
||||||
@@ -25,7 +25,7 @@ jobs:
|
|||||||
if: ${{ github.event_name == 'schedule' }}
|
if: ${{ github.event_name == 'schedule' }}
|
||||||
uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc
|
uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc
|
||||||
with:
|
with:
|
||||||
ref: master
|
ref: master-tici
|
||||||
wait-interval: 30
|
wait-interval: 30
|
||||||
running-workflow-name: 'build __nightly'
|
running-workflow-name: 'build __nightly'
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
BASE_IMAGE: sunnypilot-base
|
BASE_IMAGE: sunnypilot-tici-base
|
||||||
BUILD: release/ci/docker_build_sp.sh base
|
BUILD: release/ci/docker_build_sp.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 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
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
title: "[bot] Update translations"
|
title: "[bot] Update translations"
|
||||||
body: "Automatic PR from repo-maintenance -> update_translations"
|
body: "Automatic PR from repo-maintenance -> update_translations"
|
||||||
branch: "update-translations"
|
branch: "update-translations"
|
||||||
base: "master"
|
base: "master-tici"
|
||||||
delete-branch: true
|
delete-branch: true
|
||||||
labels: bot
|
labels: bot
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ jobs:
|
|||||||
name: package_updates
|
name: package_updates
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: ghcr.io/sunnypilot/sunnypilot-base:latest
|
image: ghcr.io/sunnypilot/sunnypilot-tici-base:latest
|
||||||
if: github.repository == 'sunnypilot/sunnypilot'
|
if: github.repository == 'sunnypilot/sunnypilot'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -68,7 +68,7 @@ jobs:
|
|||||||
commit-message: Update Python packages
|
commit-message: Update Python packages
|
||||||
title: '[bot] Update Python packages'
|
title: '[bot] Update Python packages'
|
||||||
branch: auto-package-updates
|
branch: auto-package-updates
|
||||||
base: master
|
base: master-tici
|
||||||
delete-branch: true
|
delete-branch: true
|
||||||
body: 'Automatic PR from repo-maintenance -> package_updates'
|
body: 'Automatic PR from repo-maintenance -> package_updates'
|
||||||
labels: bot
|
labels: bot
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ name: selfdrive
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master-tici
|
||||||
pull_request:
|
pull_request:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
@@ -14,12 +14,12 @@ on:
|
|||||||
type: string
|
type: string
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: selfdrive-tests-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
|
group: selfdrive-tests-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master-tici' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
env:
|
env:
|
||||||
PYTHONWARNINGS: error
|
PYTHONWARNINGS: error
|
||||||
BASE_IMAGE: sunnypilot-base
|
BASE_IMAGE: sunnypilot-tici-base
|
||||||
AZURE_TOKEN: ${{ secrets.AZURE_COMMADATACI_OPENPILOTCI_TOKEN }}
|
AZURE_TOKEN: ${{ secrets.AZURE_COMMADATACI_OPENPILOTCI_TOKEN }}
|
||||||
|
|
||||||
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 }}
|
||||||
@@ -68,10 +68,10 @@ jobs:
|
|||||||
if: github.repository == 'sunnypilot/sunnypilot'
|
if: github.repository == 'sunnypilot/sunnypilot'
|
||||||
timeout-minutes: 3
|
timeout-minutes: 3
|
||||||
run: |
|
run: |
|
||||||
if [ "${{ github.ref }}" != "refs/heads/master" ]; then
|
if [ "${{ github.ref }}" != "refs/heads/master-tici" ]; then
|
||||||
git fetch origin master:refs/remotes/origin/master
|
git fetch origin master-tici:refs/remotes/origin/master-tici
|
||||||
|
|
||||||
SUBMODULE_PATHS=$(git diff origin/master HEAD --name-only | grep -E '^[^/]+$' | while read path; do
|
SUBMODULE_PATHS=$(git diff origin/master-tici HEAD --name-only | grep -E '^[^/]+$' | while read path; do
|
||||||
if git ls-files --stage "$path" | grep -q "^160000"; then
|
if git ls-files --stage "$path" | grep -q "^160000"; then
|
||||||
echo "$path"
|
echo "$path"
|
||||||
fi
|
fi
|
||||||
@@ -97,7 +97,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup docker push
|
- name: Setup docker push
|
||||||
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'sunnypilot/sunnypilot'
|
if: github.ref == 'refs/heads/master-tici' && github.event_name != 'pull_request' && github.repository == 'sunnypilot/sunnypilot'
|
||||||
run: |
|
run: |
|
||||||
echo "PUSH_IMAGE=true" >> "$GITHUB_ENV"
|
echo "PUSH_IMAGE=true" >> "$GITHUB_ENV"
|
||||||
$DOCKER_LOGIN
|
$DOCKER_LOGIN
|
||||||
@@ -129,7 +129,7 @@ jobs:
|
|||||||
PYTHONWARNINGS: default
|
PYTHONWARNINGS: default
|
||||||
- name: Save Homebrew cache
|
- name: Save Homebrew cache
|
||||||
uses: actions/cache/save@v4
|
uses: actions/cache/save@v4
|
||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master-tici'
|
||||||
with:
|
with:
|
||||||
path: ~/Library/Caches/Homebrew
|
path: ~/Library/Caches/Homebrew
|
||||||
key: brew-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
key: brew-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||||
@@ -146,7 +146,7 @@ jobs:
|
|||||||
run: . .venv/bin/activate && scons -j$(nproc)
|
run: . .venv/bin/activate && scons -j$(nproc)
|
||||||
- name: Save scons cache
|
- name: Save scons cache
|
||||||
uses: actions/cache/save@v4
|
uses: actions/cache/save@v4
|
||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master-tici'
|
||||||
with:
|
with:
|
||||||
path: /tmp/scons_cache
|
path: /tmp/scons_cache
|
||||||
key: scons-${{ runner.arch }}-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
key: scons-${{ runner.arch }}-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||||
@@ -305,5 +305,5 @@ jobs:
|
|||||||
- name: Upload Test Report
|
- name: Upload Test Report
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: report-${{ inputs.run_number || '1' }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master' || github.event.number }}
|
name: report-${{ inputs.run_number || '1' }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master-tici' && 'master-tici' || github.event.number }}
|
||||||
path: selfdrive/ui/tests/test_ui/report_1/screenshots
|
path: selfdrive/ui/tests/test_ui/report_1/screenshots
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ on:
|
|||||||
upstream_branch:
|
upstream_branch:
|
||||||
description: 'Upstream branch to build from'
|
description: 'Upstream branch to build from'
|
||||||
required: true
|
required: true
|
||||||
default: 'master'
|
default: 'master-tici'
|
||||||
type: string
|
type: string
|
||||||
custom_name:
|
custom_name:
|
||||||
description: 'Custom name for the model (no date, only name)'
|
description: 'Custom name for the model (no date, only name)'
|
||||||
@@ -35,7 +35,7 @@ on:
|
|||||||
upstream_branch:
|
upstream_branch:
|
||||||
description: 'Upstream branch to build from'
|
description: 'Upstream branch to build from'
|
||||||
required: true
|
required: true
|
||||||
default: 'master'
|
default: 'master-tici'
|
||||||
type: string
|
type: string
|
||||||
custom_name:
|
custom_name:
|
||||||
description: 'Custom name for the model (no date, only name)'
|
description: 'Custom name for the model (no date, only name)'
|
||||||
|
|||||||
@@ -8,14 +8,14 @@ env:
|
|||||||
PUBLIC_REPO_URL: "https://github.com/sunnypilot/sunnypilot"
|
PUBLIC_REPO_URL: "https://github.com/sunnypilot/sunnypilot"
|
||||||
|
|
||||||
# Branch configurations
|
# Branch configurations
|
||||||
STAGING_C3_SOURCE_BRANCH: ${{ vars.STAGING_C3_SOURCE_BRANCH || 'master' }} # vars are set on repo settings.
|
STAGING_C3_SOURCE_BRANCH: 'master-tici' # vars.STAGING_C3_SOURCE_BRANCH could be used, set on repo settings.
|
||||||
|
|
||||||
# Runtime configuration
|
# Runtime configuration
|
||||||
SOURCE_BRANCH: "${{ github.head_ref || github.ref_name }}"
|
SOURCE_BRANCH: "${{ github.head_ref || github.ref_name }}"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master, master-dev-c3-new ]
|
branches: [ master-tici ]
|
||||||
tags: [ 'release/*' ]
|
tags: [ 'release/*' ]
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [ labeled ]
|
types: [ labeled ]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
name: Build dev-c3-new
|
name: Build dev-c3-new
|
||||||
|
|
||||||
env:
|
env:
|
||||||
DEFAULT_SOURCE_BRANCH: "master"
|
DEFAULT_SOURCE_BRANCH: "master-tici"
|
||||||
DEFAULT_TARGET_BRANCH: "master-dev-c3-new"
|
DEFAULT_TARGET_BRANCH: "master-dev-c3-new"
|
||||||
PR_LABEL: "dev-c3"
|
PR_LABEL: "dev-c3"
|
||||||
LFS_URL: 'https://gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git/info/lfs'
|
LFS_URL: 'https://gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git/info/lfs'
|
||||||
@@ -10,17 +10,17 @@ env:
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master-tici
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [ labeled ]
|
types: [ labeled ]
|
||||||
branches:
|
branches:
|
||||||
- 'master'
|
- 'master-tici'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
source_branch:
|
source_branch:
|
||||||
description: 'Source branch to reset from'
|
description: 'Source branch to reset from'
|
||||||
required: true
|
required: true
|
||||||
default: 'master'
|
default: 'master-tici'
|
||||||
type: string
|
type: string
|
||||||
target_branch:
|
target_branch:
|
||||||
description: 'Target branch to reset and squash into'
|
description: 'Target branch to reset and squash into'
|
||||||
@@ -40,11 +40,7 @@ concurrency:
|
|||||||
jobs:
|
jobs:
|
||||||
reset-and-squash:
|
reset-and-squash:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: (
|
if: False
|
||||||
(github.event_name == 'workflow_dispatch')
|
|
||||||
|| (github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch))
|
|
||||||
|| (contains(github.event_name, 'pull_request') && ((github.event.action == 'labeled' && (github.event.label.name == 'dev-c3' || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, 'dev-c3'))))
|
|
||||||
)
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -2,19 +2,19 @@ name: "ui preview"
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master-tici
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [assigned, opened, synchronize, reopened, edited]
|
types: [assigned, opened, synchronize, reopened, edited]
|
||||||
branches:
|
branches:
|
||||||
- 'master'
|
- 'master-tici'
|
||||||
paths:
|
paths:
|
||||||
- 'selfdrive/ui/**'
|
- 'selfdrive/ui/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
UI_JOB_NAME: "Create UI Report"
|
UI_JOB_NAME: "Create UI Report"
|
||||||
REPORT_NAME: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master' || github.event.number }}
|
REPORT_NAME: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master-tici' && 'master-tici' || github.event.number }}
|
||||||
SHA: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.sha || github.event.pull_request.head.sha }}
|
SHA: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master-tici' && github.sha || github.event.pull_request.head.sha }}
|
||||||
BRANCH_NAME: "openpilot/pr-${{ github.event.number }}"
|
BRANCH_NAME: "openpilot/pr-${{ github.event.number }}"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -55,7 +55,7 @@ jobs:
|
|||||||
name: report-1-${{ env.REPORT_NAME }}
|
name: report-1-${{ env.REPORT_NAME }}
|
||||||
path: ${{ github.workspace }}/pr_ui
|
path: ${{ github.workspace }}/pr_ui
|
||||||
|
|
||||||
- name: Getting master ui
|
- name: Getting master-tici ui
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: sunnypilot/ci-artifacts
|
repository: sunnypilot/ci-artifacts
|
||||||
@@ -63,8 +63,8 @@ jobs:
|
|||||||
path: ${{ github.workspace }}/master_ui
|
path: ${{ github.workspace }}/master_ui
|
||||||
ref: openpilot_master_ui
|
ref: openpilot_master_ui
|
||||||
|
|
||||||
- name: Saving new master ui
|
- name: Saving new master-tici ui
|
||||||
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
if: github.ref == 'refs/heads/master-tici' && github.event_name == 'push'
|
||||||
working-directory: ${{ github.workspace }}/master_ui
|
working-directory: ${{ github.workspace }}/master_ui
|
||||||
run: |
|
run: |
|
||||||
git checkout --orphan=new_master_ui
|
git checkout --orphan=new_master_ui
|
||||||
@@ -93,9 +93,9 @@ jobs:
|
|||||||
|
|
||||||
for ((i=0; i<${#A[*]}; i=i+1));
|
for ((i=0; i<${#A[*]}; i=i+1));
|
||||||
do
|
do
|
||||||
# Check if the master file exists
|
# Check if the master-tici file exists
|
||||||
if [ ! -f "${{ github.workspace }}/master_ui/${A[$i]}.png" ]; then
|
if [ ! -f "${{ github.workspace }}/master_ui/${A[$i]}.png" ]; then
|
||||||
# This is a new file in PR UI that doesn't exist in master
|
# This is a new file in PR UI that doesn't exist in master-tici
|
||||||
DIFF="${DIFF}<details open>"
|
DIFF="${DIFF}<details open>"
|
||||||
DIFF="${DIFF}<summary>${A[$i]} : \$\${\\color{cyan}\\text{NEW}}\$\$</summary>"
|
DIFF="${DIFF}<summary>${A[$i]} : \$\${\\color{cyan}\\text{NEW}}\$\$</summary>"
|
||||||
DIFF="${DIFF}<table>"
|
DIFF="${DIFF}<table>"
|
||||||
@@ -118,7 +118,7 @@ jobs:
|
|||||||
DIFF="${DIFF}<table>"
|
DIFF="${DIFF}<table>"
|
||||||
|
|
||||||
DIFF="${DIFF}<tr>"
|
DIFF="${DIFF}<tr>"
|
||||||
DIFF="${DIFF} <td> master <img src=\"https://raw.githubusercontent.com/sunnypilot/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}_master_ref.png\"> </td>"
|
DIFF="${DIFF} <td> master-tici <img src=\"https://raw.githubusercontent.com/sunnypilot/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}_master_ref.png\"> </td>"
|
||||||
DIFF="${DIFF} <td> proposed <img src=\"https://raw.githubusercontent.com/sunnypilot/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}.png\"> </td>"
|
DIFF="${DIFF} <td> proposed <img src=\"https://raw.githubusercontent.com/sunnypilot/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}.png\"> </td>"
|
||||||
DIFF="${DIFF}</tr>"
|
DIFF="${DIFF}</tr>"
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM ghcr.io/sunnypilot/sunnypilot-base:latest
|
FROM ghcr.io/sunnypilot/sunnypilot-tici-base:latest
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ https://docs.sunnypilot.ai/ is your one stop shop for everything from features t
|
|||||||
Detailed instructions for [how to mount the device in a car](https://comma.ai/setup).
|
Detailed instructions for [how to mount the device in a car](https://comma.ai/setup).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
Please refer to [Recommended Branches](#-recommended-branches) to find your preferred/supported branch. This guide will assume you want to install the latest `staging-c3-new` branch.
|
Please refer to [Recommended Branches](#-recommended-branches) to find your preferred/supported branch. This guide will assume you want to install the latest `staging-tici` branch.
|
||||||
|
|
||||||
### If you want to use our newest branches (our rewrite)
|
### If you want to use our newest branches (our rewrite)
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
@@ -31,25 +31,24 @@ Please refer to [Recommended Branches](#-recommended-branches) to find your pref
|
|||||||
* sunnypilot not installed or you installed a version before 0.8.17?
|
* sunnypilot not installed or you installed a version before 0.8.17?
|
||||||
1. [Factory reset/uninstall](https://github.com/commaai/openpilot/wiki/FAQ#how-can-i-reset-the-device) the previous software if you have another software/fork installed.
|
1. [Factory reset/uninstall](https://github.com/commaai/openpilot/wiki/FAQ#how-can-i-reset-the-device) the previous software if you have another software/fork installed.
|
||||||
2. After factory reset/uninstall and upon reboot, select `Custom Software` when given the option.
|
2. After factory reset/uninstall and upon reboot, select `Custom Software` when given the option.
|
||||||
3. Input the installation URL per [Recommended Branches](#-recommended-branches). Example: ```https://staging-c3-new.sunnypilot.ai```.
|
3. Input the installation URL per [Recommended Branches](#-recommended-branches). Example: ```https://staging-tici.sunnypilot.ai```.
|
||||||
4. Complete the rest of the installation following the onscreen instructions.
|
4. Complete the rest of the installation following the onscreen instructions.
|
||||||
|
|
||||||
* sunnypilot already installed and you installed a version after 0.8.17?
|
* sunnypilot already installed and you installed a version after 0.8.17?
|
||||||
1. On the comma three, go to `Settings` ▶️ `Software`.
|
1. On the comma three, go to `Settings` ▶️ `Software`.
|
||||||
2. At the `Download` option, press `CHECK`. This will fetch the list of latest branches from sunnypilot.
|
2. At the `Download` option, press `CHECK`. This will fetch the list of latest branches from sunnypilot.
|
||||||
3. At the `Target Branch` option, press `SELECT` to open the Target Branch selector.
|
3. At the `Target Branch` option, press `SELECT` to open the Target Branch selector.
|
||||||
4. Scroll to select the desired branch per Recommended Branches (see below). Example: `staging-c3-new`
|
4. Scroll to select the desired branch per Recommended Branches (see below). Example: `staging-tici`
|
||||||
|
|
||||||
|
|
||||||
| Branch | Installation URL |
|
| Branch | Installation URL |
|
||||||
|:----------------:|:---------------------------------------------:|
|
|:---------------:|:---------------------------------------------:|
|
||||||
| `staging-c3-new` | `https://staging-c3-new.sunnypilot.ai` |
|
| `staging-tici` | `https://staging-tici.sunnypilot.ai` |
|
||||||
| `dev-c3-new` | `https://dev-c3-new.sunnypilot.ai` |
|
| `custom-branch` | `https://install.sunnypilot.ai/{branch_name}` |
|
||||||
| `custom-branch` | `https://install.sunnypilot.ai/{branch_name}` |
|
| `release-tici` | **Not yet available**. |
|
||||||
| `release-c3-new` | **Not yet available**. |
|
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> You can use sunnypilot/targetbranch as an install URL. Example: 'sunnypilot/staging-c3-new'.
|
> You can use sunnypilot/targetbranch as an install URL. Example: 'sunnypilot/staging-tici'.
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> Do you require further assistance with software installation? Join the [sunnypilot Discord server](https://discord.sunnypilot.com) and message us in the `#installation-help` channel.
|
> Do you require further assistance with software installation? Join the [sunnypilot Discord server](https://discord.sunnypilot.com) and message us in the `#installation-help` channel.
|
||||||
|
|||||||
+14
-1
@@ -202,7 +202,20 @@ struct CarControlSP @0xa5cd762cd951a455 {
|
|||||||
|
|
||||||
struct Param {
|
struct Param {
|
||||||
key @0 :Text;
|
key @0 :Text;
|
||||||
value @1 :Text;
|
type @2 :ParamType;
|
||||||
|
value @3 :Data;
|
||||||
|
|
||||||
|
valueDEPRECATED @1 :Text; # The data type change may cause issues with backwards compatibility.
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ParamType {
|
||||||
|
string @0;
|
||||||
|
bool @1;
|
||||||
|
int @2;
|
||||||
|
float @3;
|
||||||
|
time @4;
|
||||||
|
json @5;
|
||||||
|
bytes @6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -146,6 +146,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"CustomAccLongPressIncrement", {PERSISTENT | BACKUP, INT, "5"}},
|
{"CustomAccLongPressIncrement", {PERSISTENT | BACKUP, INT, "5"}},
|
||||||
{"CustomAccShortPressIncrement", {PERSISTENT | BACKUP, INT, "1"}},
|
{"CustomAccShortPressIncrement", {PERSISTENT | BACKUP, INT, "1"}},
|
||||||
{"DeviceBootMode", {PERSISTENT | BACKUP, INT, "0"}},
|
{"DeviceBootMode", {PERSISTENT | BACKUP, INT, "0"}},
|
||||||
|
{"DevUIInfo", {PERSISTENT | BACKUP, INT, "0"}},
|
||||||
{"EnableCopyparty", {PERSISTENT | BACKUP, BOOL}},
|
{"EnableCopyparty", {PERSISTENT | BACKUP, BOOL}},
|
||||||
{"EnableGithubRunner", {PERSISTENT | BACKUP, BOOL}},
|
{"EnableGithubRunner", {PERSISTENT | BACKUP, BOOL}},
|
||||||
{"GithubRunnerSufficientVoltage", {CLEAR_ON_MANAGER_START , BOOL}},
|
{"GithubRunnerSufficientVoltage", {CLEAR_ON_MANAGER_START , BOOL}},
|
||||||
|
|||||||
+1
-1
Submodule opendbc_repo updated: 42bbd450b9...1a1fd1af7f
@@ -31,13 +31,25 @@ while read hash submodule ref; do
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
git -C $submodule fetch --depth 100 origin master
|
# Check against master-tici for specific submodules, master for others
|
||||||
git -C $submodule branch -r --contains $hash | grep "origin/master"
|
if [ "$submodule" = "opendbc_repo" ] || [ "$submodule" = "panda" ]; then
|
||||||
if [ "$?" -eq 0 ]; then
|
git -C $submodule fetch --depth 100 origin master-tici
|
||||||
echo "$submodule ok"
|
remote_hash=$(git -C $submodule rev-parse FETCH_HEAD)
|
||||||
|
if git -C $submodule merge-base --is-ancestor $hash $remote_hash; then
|
||||||
|
echo "$submodule ok"
|
||||||
|
else
|
||||||
|
echo "$submodule: $hash is not on master-tici"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
echo "$submodule: $hash is not on master"
|
git -C $submodule fetch --depth 100 origin master
|
||||||
exit 1
|
git -C $submodule branch -r --contains $hash | grep "origin/master"
|
||||||
|
if [ "$?" -eq 0 ]; then
|
||||||
|
echo "$submodule ok"
|
||||||
|
else
|
||||||
|
echo "$submodule: $hash is not on master"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done <<< $(git submodule status --recursive)
|
done <<< $(git submodule status --recursive)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
if [ "$1" = "base" ]; then
|
if [ "$1" = "base" ]; then
|
||||||
export DOCKER_IMAGE=sunnypilot-base
|
export DOCKER_IMAGE=sunnypilot-tici-base
|
||||||
export DOCKER_FILE=Dockerfile.sunnypilot_base
|
export DOCKER_FILE=Dockerfile.sunnypilot_base
|
||||||
elif [ "$1" = "prebuilt" ]; then
|
elif [ "$1" = "prebuilt" ]; then
|
||||||
export DOCKER_IMAGE=sunnypilot-prebuilt
|
export DOCKER_IMAGE=sunnypilot-tici-prebuilt
|
||||||
export DOCKER_FILE=Dockerfile.sunnypilot
|
export DOCKER_FILE=Dockerfile.sunnypilot
|
||||||
else
|
else
|
||||||
echo "Invalid docker build image: '$1'"
|
echo "Invalid docker build image: '$1'"
|
||||||
|
|||||||
@@ -4,6 +4,9 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "selfdrive/ui/qt/util.h"
|
#include "selfdrive/ui/qt/util.h"
|
||||||
|
#ifdef SUNNYPILOT
|
||||||
|
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
void OnroadAlerts::updateState(const UIState &s) {
|
void OnroadAlerts::updateState(const UIState &s) {
|
||||||
Alert a = getAlert(*(s.sm), s.scene.started_frame);
|
Alert a = getAlert(*(s.sm), s.scene.started_frame);
|
||||||
@@ -73,6 +76,12 @@ void OnroadAlerts::paintEvent(QPaintEvent *event) {
|
|||||||
}
|
}
|
||||||
QRect r = QRect(0 + margin, height() - h + margin, width() - margin*2, h - margin*2);
|
QRect r = QRect(0 + margin, height() - h + margin, width() - margin*2, h - margin*2);
|
||||||
|
|
||||||
|
#ifdef SUNNYPILOT
|
||||||
|
const int dev_ui_info = uiStateSP()->scene.dev_ui_info;
|
||||||
|
const int adjustment = dev_ui_info > 1 && alert.size != cereal::SelfdriveState::AlertSize::FULL ? 30 : 0;
|
||||||
|
r = QRect(0 + margin, height() - h + margin - adjustment, width() - margin*2, h - margin*2);
|
||||||
|
#endif
|
||||||
|
|
||||||
QPainter p(this);
|
QPainter p(this);
|
||||||
|
|
||||||
// draw background + gradient
|
// draw background + gradient
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "selfdrive/ui/sunnypilot/qt/onroad/model.h"
|
#include "selfdrive/ui/sunnypilot/qt/onroad/model.h"
|
||||||
#define ExperimentalButton ExperimentalButtonSP
|
#define ExperimentalButton ExperimentalButtonSP
|
||||||
#define ModelRenderer ModelRendererSP
|
#define ModelRenderer ModelRendererSP
|
||||||
|
#define HudRenderer HudRendererSP
|
||||||
#else
|
#else
|
||||||
#include "selfdrive/ui/qt/onroad/buttons.h"
|
#include "selfdrive/ui/qt/onroad/buttons.h"
|
||||||
#include "selfdrive/ui/qt/onroad/hud.h"
|
#include "selfdrive/ui/qt/onroad/hud.h"
|
||||||
|
|||||||
@@ -73,6 +73,11 @@ void DriverMonitorRenderer::draw(QPainter &painter, const QRect &surface_rect) {
|
|||||||
float y = surface_rect.height() - offset;
|
float y = surface_rect.height() - offset;
|
||||||
float opacity = is_active ? 0.65f : 0.2f;
|
float opacity = is_active ? 0.65f : 0.2f;
|
||||||
|
|
||||||
|
#ifdef SUNNYPILOT
|
||||||
|
const int dev_ui_info = uiStateSP()->scene.dev_ui_info;
|
||||||
|
y -= dev_ui_info > 1 ? 50 : 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
drawIcon(painter, QPoint(x, y), dm_img, QColor(0, 0, 0, 70), opacity);
|
drawIcon(painter, QPoint(x, y), dm_img, QColor(0, 0, 0, 70), opacity);
|
||||||
|
|
||||||
QPointF keypoints[std::size(DEFAULT_FACE_KPTS_3D)];
|
QPointF keypoints[std::size(DEFAULT_FACE_KPTS_3D)];
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ qt_src = [
|
|||||||
"sunnypilot/qt/offroad/settings/visuals_panel.cc",
|
"sunnypilot/qt/offroad/settings/visuals_panel.cc",
|
||||||
"sunnypilot/qt/onroad/annotated_camera.cc",
|
"sunnypilot/qt/onroad/annotated_camera.cc",
|
||||||
"sunnypilot/qt/onroad/buttons.cc",
|
"sunnypilot/qt/onroad/buttons.cc",
|
||||||
|
"sunnypilot/qt/onroad/developer_ui/developer_ui.cc",
|
||||||
"sunnypilot/qt/onroad/hud.cc",
|
"sunnypilot/qt/onroad/hud.cc",
|
||||||
"sunnypilot/qt/onroad/model.cc",
|
"sunnypilot/qt/onroad/model.cc",
|
||||||
"sunnypilot/qt/onroad/onroad_home.cc",
|
"sunnypilot/qt/onroad/onroad_home.cc",
|
||||||
|
|||||||
@@ -72,6 +72,15 @@ VisualsPanel::VisualsPanel(QWidget *parent) : QWidget(parent) {
|
|||||||
list->addItem(chevron_info_settings);
|
list->addItem(chevron_info_settings);
|
||||||
param_watcher->addParam("ChevronInfo");
|
param_watcher->addParam("ChevronInfo");
|
||||||
|
|
||||||
|
// Visuals: Developer UI Info (Dev UI)
|
||||||
|
std::vector<QString> dev_ui_settings_texts{tr("Off"), tr("Right"), tr("Right &&\nBottom")};
|
||||||
|
dev_ui_settings = new ButtonParamControlSP(
|
||||||
|
"DevUIInfo", tr("Developer UI"), tr("Display real-time parameters and metrics from various sources."),
|
||||||
|
"",
|
||||||
|
dev_ui_settings_texts,
|
||||||
|
380);
|
||||||
|
list->addItem(dev_ui_settings);
|
||||||
|
|
||||||
sunnypilotScroller = new ScrollViewSP(list, this);
|
sunnypilotScroller = new ScrollViewSP(list, this);
|
||||||
vlayout->addWidget(sunnypilotScroller);
|
vlayout->addWidget(sunnypilotScroller);
|
||||||
|
|
||||||
@@ -90,4 +99,7 @@ void VisualsPanel::paramsRefresh() {
|
|||||||
if (chevron_info_settings) {
|
if (chevron_info_settings) {
|
||||||
chevron_info_settings->refresh();
|
chevron_info_settings->refresh();
|
||||||
}
|
}
|
||||||
|
if (dev_ui_settings) {
|
||||||
|
dev_ui_settings->refresh();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,4 +28,5 @@ protected:
|
|||||||
std::map<std::string, ParamControlSP*> toggles;
|
std::map<std::string, ParamControlSP*> toggles;
|
||||||
ParamWatcher * param_watcher;
|
ParamWatcher * param_watcher;
|
||||||
ButtonParamControlSP *chevron_info_settings;
|
ButtonParamControlSP *chevron_info_settings;
|
||||||
|
ButtonParamControlSP *dev_ui_settings;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,3 +14,8 @@ AnnotatedCameraWidgetSP::AnnotatedCameraWidgetSP(VisionStreamType type, QWidget
|
|||||||
void AnnotatedCameraWidgetSP::updateState(const UIState &s) {
|
void AnnotatedCameraWidgetSP::updateState(const UIState &s) {
|
||||||
AnnotatedCameraWidget::updateState(s);
|
AnnotatedCameraWidget::updateState(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnnotatedCameraWidgetSP::showEvent(QShowEvent *event) {
|
||||||
|
AnnotatedCameraWidget::showEvent(event);
|
||||||
|
ui_update_params_sp(uiState());
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,4 +15,7 @@ class AnnotatedCameraWidgetSP : public AnnotatedCameraWidget {
|
|||||||
public:
|
public:
|
||||||
explicit AnnotatedCameraWidgetSP(VisionStreamType type, QWidget *parent = nullptr);
|
explicit AnnotatedCameraWidgetSP(VisionStreamType type, QWidget *parent = nullptr);
|
||||||
void updateState(const UIState &s) override;
|
void updateState(const UIState &s) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void showEvent(QShowEvent *event) override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,227 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||||
|
*
|
||||||
|
* This file is part of sunnypilot and is licensed under the MIT License.
|
||||||
|
* See the LICENSE.md file in the root directory for more details.
|
||||||
|
*/
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "common/util.h"
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.h"
|
||||||
|
|
||||||
|
|
||||||
|
// Add Relative Distance to Primary Lead Car
|
||||||
|
// Unit: Meters
|
||||||
|
UiElement DeveloperUi::getDRel(bool lead_status, float lead_d_rel) {
|
||||||
|
QString value = lead_status ? QString::number(lead_d_rel, 'f', 0) : "-";
|
||||||
|
QColor color = QColor(255, 255, 255, 255);
|
||||||
|
|
||||||
|
if (lead_status) {
|
||||||
|
// Orange if close, Red if very close
|
||||||
|
if (lead_d_rel < 5) {
|
||||||
|
color = QColor(255, 0, 0, 255);
|
||||||
|
} else if (lead_d_rel < 15) {
|
||||||
|
color = QColor(255, 188, 0, 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return UiElement(value, "REL DIST", "m", color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Relative Velocity vs Primary Lead Car
|
||||||
|
// Unit: kph if metric, else mph
|
||||||
|
UiElement DeveloperUi::getVRel(bool lead_status, float lead_v_rel, bool is_metric, const QString &speed_unit) {
|
||||||
|
QString value = lead_status ? QString::number(lead_v_rel * (is_metric ? MS_TO_KPH : MS_TO_MPH), 'f', 0) : "-";
|
||||||
|
QColor color = QColor(255, 255, 255, 255);
|
||||||
|
|
||||||
|
if (lead_status) {
|
||||||
|
// Red if approaching faster than 10mph
|
||||||
|
// Orange if approaching (negative)
|
||||||
|
if (lead_v_rel < -4.4704) {
|
||||||
|
color = QColor(255, 0, 0, 255);
|
||||||
|
} else if (lead_v_rel < 0) {
|
||||||
|
color = QColor(255, 188, 0, 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return UiElement(value, "REL SPEED", speed_unit, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Real Steering Angle
|
||||||
|
// Unit: Degrees
|
||||||
|
UiElement DeveloperUi::getSteeringAngleDeg(float angle_steers, bool lat_active, bool steer_override) {
|
||||||
|
QString value = QString("%1%2%3").arg(QString::number(angle_steers, 'f', 1)).arg("°").arg("");
|
||||||
|
QColor color = lat_active ? (steer_override ? QColor(0x91, 0x9b, 0x95, 0xff) : QColor(0, 255, 0, 255)) : QColor(255, 255, 255, 255);
|
||||||
|
|
||||||
|
// Red if large steering angle
|
||||||
|
// Orange if moderate steering angle
|
||||||
|
if (std::fabs(angle_steers) > 180) {
|
||||||
|
color = QColor(255, 0, 0, 255);
|
||||||
|
} else if (std::fabs(angle_steers) > 90) {
|
||||||
|
color = QColor(255, 188, 0, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
return UiElement(value, "REAL STEER", "", color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Actual Lateral Acceleration (roll compensated) when using Torque
|
||||||
|
// Unit: m/s²
|
||||||
|
UiElement DeveloperUi::getActualLateralAccel(float curvature, float v_ego, float roll, bool lat_active, bool steer_override) {
|
||||||
|
double actualLateralAccel = (curvature * pow(v_ego, 2)) - (roll * 9.81);
|
||||||
|
|
||||||
|
QString value = QString::number(actualLateralAccel, 'f', 2);
|
||||||
|
QColor color = lat_active ? (steer_override ? QColor(0x91, 0x9b, 0x95, 0xff) : QColor(0, 255, 0, 255)) : QColor(255, 255, 255, 255);
|
||||||
|
|
||||||
|
return UiElement(value, "ACTUAL L.A.", "m/s²", color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Desired Steering Angle when using PID
|
||||||
|
// Unit: Degrees
|
||||||
|
UiElement DeveloperUi::getSteeringAngleDesiredDeg(bool lat_active, float steer_angle_desired, float angle_steers) {
|
||||||
|
QString value = lat_active ? QString("%1%2%3").arg(QString::number(steer_angle_desired, 'f', 1)).arg("°").arg("") : "-";
|
||||||
|
QColor color = QColor(255, 255, 255, 255);
|
||||||
|
|
||||||
|
if (lat_active) {
|
||||||
|
// Red if large steering angle
|
||||||
|
// Orange if moderate steering angle
|
||||||
|
if (std::fabs(angle_steers) > 180) {
|
||||||
|
color = QColor(255, 0, 0, 255);
|
||||||
|
} else if (std::fabs(angle_steers) > 90) {
|
||||||
|
color = QColor(255, 188, 0, 255);
|
||||||
|
} else {
|
||||||
|
color = QColor(0, 255, 0, 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return UiElement(value, "DESIRED STEER", "", color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Device Memory (RAM) Usage
|
||||||
|
// Unit: Percent
|
||||||
|
UiElement DeveloperUi::getMemoryUsagePercent(int memory_usage_percent) {
|
||||||
|
QString value = QString("%1%2").arg(QString::number(memory_usage_percent, 'd', 0)).arg("%");
|
||||||
|
QColor color = (memory_usage_percent > 85) ? QColor(255, 188, 0, 255) : QColor(255, 255, 255, 255);
|
||||||
|
|
||||||
|
return UiElement(value, "RAM", "", color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Vehicle Current Acceleration
|
||||||
|
// Unit: m/s²
|
||||||
|
UiElement DeveloperUi::getAEgo(float a_ego) {
|
||||||
|
QString value = QString::number(a_ego, 'f', 1);
|
||||||
|
QColor color = QColor(255, 255, 255, 255);
|
||||||
|
|
||||||
|
return UiElement(value, "ACC.", "m/s²", color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Relative Velocity to Primary Lead Car
|
||||||
|
// Unit: kph if metric, else mph
|
||||||
|
UiElement DeveloperUi::getVEgoLead(bool lead_status, float lead_v_rel, float v_ego, bool is_metric, const QString &speed_unit) {
|
||||||
|
QString value = lead_status ? QString::number((lead_v_rel + v_ego) * (is_metric ? MS_TO_KPH : MS_TO_MPH), 'f', 0) : "-";
|
||||||
|
QColor color = QColor(255, 255, 255, 255);
|
||||||
|
|
||||||
|
if (lead_status) {
|
||||||
|
// Red if approaching faster than 10mph
|
||||||
|
// Orange if approaching (negative)
|
||||||
|
if (lead_v_rel < -4.4704) {
|
||||||
|
color = QColor(255, 0, 0, 255);
|
||||||
|
} else if (lead_v_rel < 0) {
|
||||||
|
color = QColor(255, 188, 0, 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return UiElement(value, "L.S.", speed_unit, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Friction Coefficient Raw from torqued
|
||||||
|
// Unit: None
|
||||||
|
UiElement DeveloperUi::getFrictionCoefficientFiltered(float friction_coefficient_filtered, bool live_valid) {
|
||||||
|
QString value = QString::number(friction_coefficient_filtered, 'f', 3);
|
||||||
|
QColor color = live_valid ? QColor(0, 255, 0, 255) : QColor(255, 255, 255, 255);
|
||||||
|
|
||||||
|
return UiElement(value, "FRIC.", "", color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Lateral Acceleration Factor Raw from torqued
|
||||||
|
// Unit: m/s²
|
||||||
|
UiElement DeveloperUi::getLatAccelFactorFiltered(float lat_accel_factor_filtered, bool live_valid) {
|
||||||
|
QString value = QString::number(lat_accel_factor_filtered, 'f', 3);
|
||||||
|
QColor color = live_valid ? QColor(0, 255, 0, 255) : QColor(255, 255, 255, 255);
|
||||||
|
|
||||||
|
return UiElement(value, "L.A.", "m/s²", color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Steering Torque from Car EPS
|
||||||
|
// Unit: Newton Meters
|
||||||
|
UiElement DeveloperUi::getSteeringTorqueEps(float steering_torque_eps) {
|
||||||
|
QString value = QString::number(std::fabs(steering_torque_eps), 'f', 1);
|
||||||
|
QColor color = QColor(255, 255, 255, 255);
|
||||||
|
|
||||||
|
return UiElement(value, "E.T.", "N·dm", color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Bearing Degree and Direction from Car (Compass)
|
||||||
|
// Unit: Meters
|
||||||
|
UiElement DeveloperUi::getBearingDeg(float bearing_accuracy_deg, float bearing_deg) {
|
||||||
|
QString value = (bearing_accuracy_deg != 180.00) ? QString("%1%2%3").arg(QString::number(bearing_deg, 'd', 0)).arg("°").arg("") : "-";
|
||||||
|
QColor color = QColor(255, 255, 255, 255);
|
||||||
|
QString dir_value;
|
||||||
|
|
||||||
|
if (bearing_accuracy_deg != 180.00) {
|
||||||
|
if (((bearing_deg >= 337.5) && (bearing_deg <= 360)) || ((bearing_deg >= 0) && (bearing_deg <= 22.5))) {
|
||||||
|
dir_value = "N";
|
||||||
|
} else if ((bearing_deg > 22.5) && (bearing_deg < 67.5)) {
|
||||||
|
dir_value = "NE";
|
||||||
|
} else if ((bearing_deg >= 67.5) && (bearing_deg <= 112.5)) {
|
||||||
|
dir_value = "E";
|
||||||
|
} else if ((bearing_deg > 112.5) && (bearing_deg < 157.5)) {
|
||||||
|
dir_value = "SE";
|
||||||
|
} else if ((bearing_deg >= 157.5) && (bearing_deg <= 202.5)) {
|
||||||
|
dir_value = "S";
|
||||||
|
} else if ((bearing_deg > 202.5) && (bearing_deg < 247.5)) {
|
||||||
|
dir_value = "SW";
|
||||||
|
} else if ((bearing_deg >= 247.5) && (bearing_deg <= 292.5)) {
|
||||||
|
dir_value = "W";
|
||||||
|
} else if ((bearing_deg > 292.5) && (bearing_deg < 337.5)) {
|
||||||
|
dir_value = "NW";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dir_value = "OFF";
|
||||||
|
}
|
||||||
|
|
||||||
|
return UiElement(QString("%1 | %2").arg(dir_value).arg(value), "B.D.", "", color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Altitude of Current Location
|
||||||
|
// Unit: Meters
|
||||||
|
UiElement DeveloperUi::getAltitude(float gps_accuracy, float altitude) {
|
||||||
|
QString value = (gps_accuracy != 0.00) ? QString::number(altitude, 'f', 1) : "-";
|
||||||
|
QColor color = QColor(255, 255, 255, 255);
|
||||||
|
|
||||||
|
return UiElement(value, "ALT.", "m", color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Actuators Output
|
||||||
|
// Unit: Degree (angle) or m/s² (torque)
|
||||||
|
UiElement DeveloperUi::getActuatorsOutputLateral(cereal::CarParams::SteerControlType steerControlType,
|
||||||
|
cereal::CarControl::Actuators::Reader &actuators,
|
||||||
|
float desiredCurvature, float v_ego, float roll, bool lat_active, bool steer_override) {
|
||||||
|
QString label;
|
||||||
|
QString value;
|
||||||
|
QString unit;
|
||||||
|
|
||||||
|
if (steerControlType == cereal::CarParams::SteerControlType::ANGLE) {
|
||||||
|
label = "DESIRED STEER";
|
||||||
|
value = QString("%1%2%3").arg(QString::number(actuators.getSteeringAngleDeg(), 'f', 1)).arg("°").arg("");
|
||||||
|
} else {
|
||||||
|
label = "DESIRED L.A.";
|
||||||
|
double desiredLateralAccel = (desiredCurvature * pow(v_ego, 2)) - (roll * 9.81);
|
||||||
|
value = QString::number(desiredLateralAccel, 'f', 2);
|
||||||
|
unit = "m/s²";
|
||||||
|
}
|
||||||
|
|
||||||
|
value = lat_active ? value : "-";
|
||||||
|
QColor color = lat_active ? (steer_override ? QColor(0x91, 0x9b, 0x95, 0xff) : QColor(0, 255, 0, 255)) : QColor(255, 255, 255, 255);
|
||||||
|
|
||||||
|
return UiElement(value, label, unit, color);
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||||
|
*
|
||||||
|
* This file is part of sunnypilot and is licensed under the MIT License.
|
||||||
|
* See the LICENSE.md file in the root directory for more details.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "selfdrive/ui/qt/util.h"
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/onroad/developer_ui/ui_elements.h"
|
||||||
|
|
||||||
|
class DeveloperUi {
|
||||||
|
|
||||||
|
public:
|
||||||
|
static UiElement getDRel(bool lead_status, float lead_d_rel);
|
||||||
|
static UiElement getVRel(bool lead_status, float lead_v_rel, bool is_metric, const QString &speed_unit);
|
||||||
|
static UiElement getSteeringAngleDeg(float angle_steers, bool lat_active, bool steer_override);
|
||||||
|
static UiElement getActualLateralAccel(float curvature, float v_ego, float roll, bool lat_active, bool steer_override);
|
||||||
|
static UiElement getSteeringAngleDesiredDeg(bool lat_active, float steer_angle_desired, float angle_steers);
|
||||||
|
static UiElement getMemoryUsagePercent(int memory_usage_percent);
|
||||||
|
static UiElement getAEgo(float a_ego);
|
||||||
|
static UiElement getVEgoLead(bool lead_status, float lead_v_rel, float v_ego, bool is_metric, const QString &speed_unit);
|
||||||
|
static UiElement getFrictionCoefficientFiltered(float friction_coefficient_filtered, bool live_valid);
|
||||||
|
static UiElement getLatAccelFactorFiltered(float lat_accel_factor_filtered, bool live_valid);
|
||||||
|
static UiElement getSteeringTorqueEps(float steering_torque_eps);
|
||||||
|
static UiElement getBearingDeg(float bearing_accuracy_deg, float bearing_deg);
|
||||||
|
static UiElement getAltitude(float gps_accuracy, float altitude);
|
||||||
|
static UiElement getActuatorsOutputLateral(cereal::CarParams::SteerControlType steerControlType,
|
||||||
|
cereal::CarControl::Actuators::Reader &actuators,
|
||||||
|
float desiredCurvature, float v_ego, float roll, bool lat_active, bool steer_override);
|
||||||
|
};
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||||
|
*
|
||||||
|
* This file is part of sunnypilot and is licensed under the MIT License.
|
||||||
|
* See the LICENSE.md file in the root directory for more details.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
|
|
||||||
|
struct UiElement {
|
||||||
|
QString value{};
|
||||||
|
QString label{};
|
||||||
|
QString units{};
|
||||||
|
QColor color{};
|
||||||
|
|
||||||
|
explicit UiElement(const QString &value = "", const QString &label = "", const QString &units = "", const QColor &color = QColor(255, 255, 255, 255))
|
||||||
|
: value(value), label(label), units(units), color(color) {}
|
||||||
|
};
|
||||||
@@ -7,12 +7,202 @@
|
|||||||
|
|
||||||
#include "selfdrive/ui/sunnypilot/qt/onroad/hud.h"
|
#include "selfdrive/ui/sunnypilot/qt/onroad/hud.h"
|
||||||
|
|
||||||
|
#include "selfdrive/ui/qt/util.h"
|
||||||
|
|
||||||
|
|
||||||
HudRendererSP::HudRendererSP() {}
|
HudRendererSP::HudRendererSP() {}
|
||||||
|
|
||||||
void HudRendererSP::updateState(const UIState &s) {
|
void HudRendererSP::updateState(const UIState &s) {
|
||||||
HudRenderer::updateState(s);
|
HudRenderer::updateState(s);
|
||||||
|
|
||||||
|
const SubMaster &sm = *(s.sm);
|
||||||
|
const bool cs_alive = sm.alive("controlsState");
|
||||||
|
const auto cs = sm["controlsState"].getControlsState();
|
||||||
|
const auto car_state = sm["carState"].getCarState();
|
||||||
|
const auto car_control = sm["carControl"].getCarControl();
|
||||||
|
const auto radar_state = sm["radarState"].getRadarState();
|
||||||
|
const auto is_gps_location_external = sm.rcv_frame("gpsLocationExternal") > 1;
|
||||||
|
const auto gpsLocation = is_gps_location_external ? sm["gpsLocationExternal"].getGpsLocationExternal() : sm["gpsLocation"].getGpsLocation();
|
||||||
|
const auto ltp = sm["liveTorqueParameters"].getLiveTorqueParameters();
|
||||||
|
const auto car_params = sm["carParams"].getCarParams();
|
||||||
|
|
||||||
|
static int reverse_delay = 0;
|
||||||
|
bool reverse_allowed = false;
|
||||||
|
if (int(car_state.getGearShifter()) != 4) {
|
||||||
|
reverse_delay = 0;
|
||||||
|
reverse_allowed = false;
|
||||||
|
} else {
|
||||||
|
reverse_delay += 50;
|
||||||
|
if (reverse_delay >= 1000) {
|
||||||
|
reverse_allowed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reversing = reverse_allowed;
|
||||||
|
is_metric = s.scene.is_metric;
|
||||||
|
|
||||||
|
// Handle older routes where vEgoCluster is not set
|
||||||
|
v_ego_cluster_seen = v_ego_cluster_seen || car_state.getVEgoCluster() != 0.0;
|
||||||
|
float v_ego = v_ego_cluster_seen ? car_state.getVEgoCluster() : car_state.getVEgo();
|
||||||
|
speed = cs_alive ? std::max<float>(0.0, v_ego) : 0.0;
|
||||||
|
speed *= is_metric ? MS_TO_KPH : MS_TO_MPH;
|
||||||
|
|
||||||
|
latActive = car_control.getLatActive();
|
||||||
|
steerOverride = car_state.getSteeringPressed();
|
||||||
|
|
||||||
|
devUiInfo = s.scene.dev_ui_info;
|
||||||
|
|
||||||
|
speedUnit = is_metric ? tr("km/h") : tr("mph");
|
||||||
|
lead_d_rel = radar_state.getLeadOne().getDRel();
|
||||||
|
lead_v_rel = radar_state.getLeadOne().getVRel();
|
||||||
|
lead_status = radar_state.getLeadOne().getStatus();
|
||||||
|
steerControlType = car_params.getSteerControlType();
|
||||||
|
actuators = car_control.getActuators();
|
||||||
|
torqueLateral = steerControlType == cereal::CarParams::SteerControlType::TORQUE;
|
||||||
|
angleSteers = car_state.getSteeringAngleDeg();
|
||||||
|
desiredCurvature = cs.getDesiredCurvature();
|
||||||
|
curvature = cs.getCurvature();
|
||||||
|
roll = sm["liveParameters"].getLiveParameters().getRoll();
|
||||||
|
memoryUsagePercent = sm["deviceState"].getDeviceState().getMemoryUsagePercent();
|
||||||
|
gpsAccuracy = is_gps_location_external ? gpsLocation.getHorizontalAccuracy() : 1.0; // External reports accuracy, internal does not.
|
||||||
|
altitude = gpsLocation.getAltitude();
|
||||||
|
vEgo = car_state.getVEgo();
|
||||||
|
aEgo = car_state.getAEgo();
|
||||||
|
steeringTorqueEps = car_state.getSteeringTorqueEps();
|
||||||
|
bearingAccuracyDeg = gpsLocation.getBearingAccuracyDeg();
|
||||||
|
bearingDeg = gpsLocation.getBearingDeg();
|
||||||
|
torquedUseParams = ltp.getUseParams();
|
||||||
|
latAccelFactorFiltered = ltp.getLatAccelFactorFiltered();
|
||||||
|
frictionCoefficientFiltered = ltp.getFrictionCoefficientFiltered();
|
||||||
|
liveValid = ltp.getLiveValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HudRendererSP::draw(QPainter &p, const QRect &surface_rect) {
|
void HudRendererSP::draw(QPainter &p, const QRect &surface_rect) {
|
||||||
HudRenderer::draw(p, surface_rect);
|
HudRenderer::draw(p, surface_rect);
|
||||||
|
if (!reversing) {
|
||||||
|
// Bottom Dev UI
|
||||||
|
if (devUiInfo == 2) {
|
||||||
|
QRect rect_bottom(surface_rect.left(), surface_rect.bottom() - 60, surface_rect.width(), 61);
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(QColor(0, 0, 0, 100));
|
||||||
|
p.drawRect(rect_bottom);
|
||||||
|
drawBottomDevUI(p, rect_bottom.left(), rect_bottom.center().y());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right Dev UI
|
||||||
|
if (devUiInfo != 0) {
|
||||||
|
QRect rect_right(surface_rect.right() - (UI_BORDER_SIZE * 2), UI_BORDER_SIZE * 1.5, 184, 170);
|
||||||
|
drawRightDevUI(p, surface_rect.right() - 184 - UI_BORDER_SIZE * 2, UI_BORDER_SIZE * 2 + rect_right.height());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HudRendererSP::drawText(QPainter &p, int x, int y, const QString &text, QColor color) {
|
||||||
|
QRect real_rect = p.fontMetrics().boundingRect(text);
|
||||||
|
real_rect.moveCenter({x, y - real_rect.height() / 2});
|
||||||
|
p.setPen(color);
|
||||||
|
p.drawText(real_rect.x(), real_rect.bottom(), text);
|
||||||
|
}
|
||||||
|
|
||||||
|
int HudRendererSP::drawRightDevUIElement(QPainter &p, int x, int y, const QString &value, const QString &label, const QString &units, QColor &color) {
|
||||||
|
|
||||||
|
p.setFont(InterFont(28, QFont::Bold));
|
||||||
|
x += 92;
|
||||||
|
y += 80;
|
||||||
|
drawText(p, x, y, label);
|
||||||
|
|
||||||
|
p.setFont(InterFont(30 * 2, QFont::Bold));
|
||||||
|
y += 65;
|
||||||
|
drawText(p, x, y, value, color);
|
||||||
|
|
||||||
|
p.setFont(InterFont(28, QFont::Bold));
|
||||||
|
|
||||||
|
if (units.length() > 0) {
|
||||||
|
p.save();
|
||||||
|
x += 120;
|
||||||
|
y -= 25;
|
||||||
|
p.translate(x, y);
|
||||||
|
p.rotate(-90);
|
||||||
|
drawText(p, 0, 0, units);
|
||||||
|
p.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 130;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HudRendererSP::drawRightDevUI(QPainter &p, int x, int y) {
|
||||||
|
int rh = 5;
|
||||||
|
int ry = y;
|
||||||
|
|
||||||
|
UiElement dRelElement = DeveloperUi::getDRel(lead_status, lead_d_rel);
|
||||||
|
rh += drawRightDevUIElement(p, x, ry, dRelElement.value, dRelElement.label, dRelElement.units, dRelElement.color);
|
||||||
|
ry = y + rh;
|
||||||
|
|
||||||
|
UiElement vRelElement = DeveloperUi::getVRel(lead_status, lead_v_rel, is_metric, speedUnit);
|
||||||
|
rh += drawRightDevUIElement(p, x, ry, vRelElement.value, vRelElement.label, vRelElement.units, vRelElement.color);
|
||||||
|
ry = y + rh;
|
||||||
|
|
||||||
|
UiElement steeringAngleDegElement = DeveloperUi::getSteeringAngleDeg(angleSteers, latActive, steerOverride);
|
||||||
|
rh += drawRightDevUIElement(p, x, ry, steeringAngleDegElement.value, steeringAngleDegElement.label, steeringAngleDegElement.units, steeringAngleDegElement.color);
|
||||||
|
ry = y + rh;
|
||||||
|
|
||||||
|
UiElement actuatorsOutputLateralElement = DeveloperUi::getActuatorsOutputLateral(steerControlType, actuators, desiredCurvature, vEgo, roll, latActive, steerOverride);
|
||||||
|
rh += drawRightDevUIElement(p, x, ry, actuatorsOutputLateralElement.value, actuatorsOutputLateralElement.label, actuatorsOutputLateralElement.units, actuatorsOutputLateralElement.color);
|
||||||
|
ry = y + rh;
|
||||||
|
|
||||||
|
UiElement actualLateralAccelElement = DeveloperUi::getActualLateralAccel(curvature, vEgo, roll, latActive, steerOverride);
|
||||||
|
rh += drawRightDevUIElement(p, x, ry, actualLateralAccelElement.value, actualLateralAccelElement.label, actualLateralAccelElement.units, actualLateralAccelElement.color);
|
||||||
|
}
|
||||||
|
|
||||||
|
int HudRendererSP::drawBottomDevUIElement(QPainter &p, int x, int y, const QString &value, const QString &label, const QString &units, QColor &color) {
|
||||||
|
p.setFont(InterFont(38, QFont::Bold));
|
||||||
|
QFontMetrics fm(p.font());
|
||||||
|
QRect init_rect = fm.boundingRect(label + " ");
|
||||||
|
QRect real_rect = fm.boundingRect(init_rect, 0, label + " ");
|
||||||
|
real_rect.moveCenter({x, y});
|
||||||
|
|
||||||
|
QRect init_rect2 = fm.boundingRect(value);
|
||||||
|
QRect real_rect2 = fm.boundingRect(init_rect2, 0, value);
|
||||||
|
real_rect2.moveTop(real_rect.top());
|
||||||
|
real_rect2.moveLeft(real_rect.right() + 10);
|
||||||
|
|
||||||
|
QRect init_rect3 = fm.boundingRect(units);
|
||||||
|
QRect real_rect3 = fm.boundingRect(init_rect3, 0, units);
|
||||||
|
real_rect3.moveTop(real_rect.top());
|
||||||
|
real_rect3.moveLeft(real_rect2.right() + 10);
|
||||||
|
|
||||||
|
p.setPen(Qt::white);
|
||||||
|
p.drawText(real_rect, Qt::AlignLeft | Qt::AlignVCenter, label);
|
||||||
|
|
||||||
|
p.setPen(color);
|
||||||
|
p.drawText(real_rect2, Qt::AlignRight | Qt::AlignVCenter, value);
|
||||||
|
p.drawText(real_rect3, Qt::AlignLeft | Qt::AlignVCenter, units);
|
||||||
|
return 430;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HudRendererSP::drawBottomDevUI(QPainter &p, int x, int y) {
|
||||||
|
int rw = 90;
|
||||||
|
|
||||||
|
UiElement aEgoElement = DeveloperUi::getAEgo(aEgo);
|
||||||
|
rw += drawBottomDevUIElement(p, rw, y, aEgoElement.value, aEgoElement.label, aEgoElement.units, aEgoElement.color);
|
||||||
|
|
||||||
|
UiElement vEgoLeadElement = DeveloperUi::getVEgoLead(lead_status, lead_v_rel, vEgo, is_metric, speedUnit);
|
||||||
|
rw += drawBottomDevUIElement(p, rw, y, vEgoLeadElement.value, vEgoLeadElement.label, vEgoLeadElement.units, vEgoLeadElement.color);
|
||||||
|
|
||||||
|
if (torqueLateral && torquedUseParams) {
|
||||||
|
UiElement frictionCoefficientFilteredElement = DeveloperUi::getFrictionCoefficientFiltered(frictionCoefficientFiltered, liveValid);
|
||||||
|
rw += drawBottomDevUIElement(p, rw, y, frictionCoefficientFilteredElement.value, frictionCoefficientFilteredElement.label, frictionCoefficientFilteredElement.units, frictionCoefficientFilteredElement.color);
|
||||||
|
|
||||||
|
UiElement latAccelFactorFilteredElement = DeveloperUi::getLatAccelFactorFiltered(latAccelFactorFiltered, liveValid);
|
||||||
|
rw += drawBottomDevUIElement(p, rw, y, latAccelFactorFilteredElement.value, latAccelFactorFilteredElement.label, latAccelFactorFilteredElement.units, latAccelFactorFilteredElement.color);
|
||||||
|
} else {
|
||||||
|
UiElement steeringTorqueEpsElement = DeveloperUi::getSteeringTorqueEps(steeringTorqueEps);
|
||||||
|
rw += drawBottomDevUIElement(p, rw, y, steeringTorqueEpsElement.value, steeringTorqueEpsElement.label, steeringTorqueEpsElement.units, steeringTorqueEpsElement.color);
|
||||||
|
|
||||||
|
UiElement bearingDegElement = DeveloperUi::getBearingDeg(bearingAccuracyDeg, bearingDeg);
|
||||||
|
rw += drawBottomDevUIElement(p, rw, y, bearingDegElement.value, bearingDegElement.label, bearingDegElement.units, bearingDegElement.color);
|
||||||
|
}
|
||||||
|
|
||||||
|
UiElement altitudeElement = DeveloperUi::getAltitude(gpsAccuracy, altitude);
|
||||||
|
rw += drawBottomDevUIElement(p, rw, y, altitudeElement.value, altitudeElement.label, altitudeElement.units, altitudeElement.color);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QPainter>
|
|
||||||
|
|
||||||
#include "selfdrive/ui/qt/onroad/hud.h"
|
#include "selfdrive/ui/qt/onroad/hud.h"
|
||||||
|
#include "selfdrive/ui/sunnypilot/qt/onroad/developer_ui/developer_ui.h"
|
||||||
|
|
||||||
class HudRendererSP : public HudRenderer {
|
class HudRendererSP : public HudRenderer {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -18,4 +17,40 @@ public:
|
|||||||
HudRendererSP();
|
HudRendererSP();
|
||||||
void updateState(const UIState &s) override;
|
void updateState(const UIState &s) override;
|
||||||
void draw(QPainter &p, const QRect &surface_rect) override;
|
void draw(QPainter &p, const QRect &surface_rect) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Params params;
|
||||||
|
void drawText(QPainter &p, int x, int y, const QString &text, QColor color = Qt::white);
|
||||||
|
void drawRightDevUI(QPainter &p, int x, int y);
|
||||||
|
int drawRightDevUIElement(QPainter &p, int x, int y, const QString &value, const QString &label, const QString &units, QColor &color);
|
||||||
|
int drawBottomDevUIElement(QPainter &p, int x, int y, const QString &value, const QString &label, const QString &units, QColor &color);
|
||||||
|
void drawBottomDevUI(QPainter &p, int x, int y);
|
||||||
|
|
||||||
|
bool lead_status;
|
||||||
|
float lead_d_rel;
|
||||||
|
float lead_v_rel;
|
||||||
|
bool torqueLateral;
|
||||||
|
float angleSteers;
|
||||||
|
float desiredCurvature;
|
||||||
|
float curvature;
|
||||||
|
float roll;
|
||||||
|
int memoryUsagePercent;
|
||||||
|
int devUiInfo;
|
||||||
|
float gpsAccuracy;
|
||||||
|
float altitude;
|
||||||
|
float vEgo;
|
||||||
|
float aEgo;
|
||||||
|
float steeringTorqueEps;
|
||||||
|
float bearingAccuracyDeg;
|
||||||
|
float bearingDeg;
|
||||||
|
bool torquedUseParams;
|
||||||
|
float latAccelFactorFiltered;
|
||||||
|
float frictionCoefficientFiltered;
|
||||||
|
bool liveValid;
|
||||||
|
QString speedUnit;
|
||||||
|
bool latActive;
|
||||||
|
bool steerOverride;
|
||||||
|
bool reversing;
|
||||||
|
cereal::CarParams::SteerControlType steerControlType;
|
||||||
|
cereal::CarControl::Actuators::Reader actuators;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,13 +18,22 @@ UIStateSP::UIStateSP(QObject *parent) : UIState(parent) {
|
|||||||
"modelV2", "controlsState", "liveCalibration", "radarState", "deviceState",
|
"modelV2", "controlsState", "liveCalibration", "radarState", "deviceState",
|
||||||
"pandaStates", "carParams", "driverMonitoringState", "carState", "driverStateV2",
|
"pandaStates", "carParams", "driverMonitoringState", "carState", "driverStateV2",
|
||||||
"wideRoadCameraState", "managerState", "selfdriveState", "longitudinalPlan",
|
"wideRoadCameraState", "managerState", "selfdriveState", "longitudinalPlan",
|
||||||
"modelManagerSP", "selfdriveStateSP", "longitudinalPlanSP", "backupManagerSP"
|
"modelManagerSP", "selfdriveStateSP", "longitudinalPlanSP", "backupManagerSP",
|
||||||
|
"carControl", "gpsLocationExternal", "gpsLocation", "liveTorqueParameters",
|
||||||
|
"carStateSP", "liveParameters"
|
||||||
});
|
});
|
||||||
|
|
||||||
// update timer
|
// update timer
|
||||||
timer = new QTimer(this);
|
timer = new QTimer(this);
|
||||||
QObject::connect(timer, &QTimer::timeout, this, &UIStateSP::update);
|
QObject::connect(timer, &QTimer::timeout, this, &UIStateSP::update);
|
||||||
timer->start(1000 / UI_FREQ);
|
timer->start(1000 / UI_FREQ);
|
||||||
|
|
||||||
|
// Param watcher for UIScene param updates
|
||||||
|
param_watcher = new ParamWatcher(this);
|
||||||
|
connect(param_watcher, &ParamWatcher::paramChanged, [=](const QString ¶m_name, const QString ¶m_value) {
|
||||||
|
ui_update_params_sp(this);
|
||||||
|
});
|
||||||
|
param_watcher->addParam("DevUIInfo");
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method overrides completely the update method from the parent class intentionally.
|
// This method overrides completely the update method from the parent class intentionally.
|
||||||
@@ -39,6 +48,11 @@ void UIStateSP::update() {
|
|||||||
emit uiUpdate(*this);
|
emit uiUpdate(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ui_update_params_sp(UIStateSP *s) {
|
||||||
|
auto params = Params();
|
||||||
|
s->scene.dev_ui_info = std::atoi(params.get("DevUIInfo").c_str());
|
||||||
|
}
|
||||||
|
|
||||||
DeviceSP::DeviceSP(QObject *parent) : Device(parent) {
|
DeviceSP::DeviceSP(QObject *parent) : Device(parent) {
|
||||||
QObject::connect(uiStateSP(), &UIStateSP::uiUpdate, this, &DeviceSP::update);
|
QObject::connect(uiStateSP(), &UIStateSP::uiUpdate, this, &DeviceSP::update);
|
||||||
QObject::connect(this, &Device::displayPowerChanged, this, &DeviceSP::handleDisplayPowerChanged);
|
QObject::connect(this, &Device::displayPowerChanged, this, &DeviceSP::handleDisplayPowerChanged);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/models/role_model.h"
|
#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/models/role_model.h"
|
||||||
#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/models/sponsor_role_model.h"
|
#include "selfdrive/ui/sunnypilot/qt/network/sunnylink/models/sponsor_role_model.h"
|
||||||
#include "selfdrive/ui/ui.h"
|
#include "selfdrive/ui/ui.h"
|
||||||
|
#include "selfdrive/ui/qt/util.h"
|
||||||
|
|
||||||
class UIStateSP : public UIState {
|
class UIStateSP : public UIState {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -73,6 +74,7 @@ private slots:
|
|||||||
private:
|
private:
|
||||||
std::vector<RoleModel> sunnylinkRoles = {};
|
std::vector<RoleModel> sunnylinkRoles = {};
|
||||||
std::vector<UserModel> sunnylinkUsers = {};
|
std::vector<UserModel> sunnylinkUsers = {};
|
||||||
|
ParamWatcher *param_watcher;
|
||||||
};
|
};
|
||||||
|
|
||||||
UIStateSP *uiStateSP();
|
UIStateSP *uiStateSP();
|
||||||
@@ -92,3 +94,5 @@ private:
|
|||||||
|
|
||||||
DeviceSP *deviceSP();
|
DeviceSP *deviceSP();
|
||||||
inline DeviceSP *device() { return deviceSP(); }
|
inline DeviceSP *device() { return deviceSP(); }
|
||||||
|
|
||||||
|
void ui_update_params_sp(UIStateSP *s);
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||||
|
*
|
||||||
|
* This file is part of sunnypilot and is licensed under the MIT License.
|
||||||
|
* See the LICENSE.md file in the root directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef struct UISceneSP : UIScene {
|
||||||
|
int dev_ui_info = 0;
|
||||||
|
} UISceneSP;
|
||||||
@@ -66,6 +66,11 @@ typedef struct UIScene {
|
|||||||
uint64_t started_frame;
|
uint64_t started_frame;
|
||||||
} UIScene;
|
} UIScene;
|
||||||
|
|
||||||
|
#ifdef SUNNYPILOT
|
||||||
|
#include "sunnypilot/ui_scene.h"
|
||||||
|
#define UIScene UISceneSP
|
||||||
|
#endif
|
||||||
|
|
||||||
class UIState : public QObject {
|
class UIState : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ class ControlsExt:
|
|||||||
# MADS state
|
# MADS state
|
||||||
CC_SP.mads = sm['selfdriveStateSP'].mads
|
CC_SP.mads = sm['selfdriveStateSP'].mads
|
||||||
|
|
||||||
CC_SP.params = self.param_store.publish()
|
CC_SP.params = self.param_store.param_list
|
||||||
|
|
||||||
return CC_SP
|
return CC_SP
|
||||||
|
|
||||||
|
|||||||
@@ -4,39 +4,41 @@ Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
|||||||
This file is part of sunnypilot and is licensed under the MIT License.
|
This file is part of sunnypilot and is licensed under the MIT License.
|
||||||
See the LICENSE.md file in the root directory for more details.
|
See the LICENSE.md file in the root directory for more details.
|
||||||
"""
|
"""
|
||||||
import capnp
|
|
||||||
|
|
||||||
from cereal import custom
|
from cereal import custom
|
||||||
|
|
||||||
from opendbc.car import structs
|
from opendbc.car import structs
|
||||||
from openpilot.common.params import Params
|
from openpilot.common.params import Params
|
||||||
|
|
||||||
|
from sunnypilot.sunnylink.utils import get_param_as_byte
|
||||||
|
|
||||||
|
|
||||||
class ParamStore:
|
class ParamStore:
|
||||||
keys: list[str]
|
keys: list[str]
|
||||||
values: dict[str, str]
|
_params: dict[str, custom.CarControlSP.Param]
|
||||||
|
|
||||||
def __init__(self, CP: structs.CarParams):
|
def __init__(self, CP: structs.CarParams):
|
||||||
universal_params: list[str] = []
|
universal_params: list[str] = []
|
||||||
brand_params: list[str] = []
|
brand_params: list[str] = []
|
||||||
|
|
||||||
self.keys = universal_params + brand_params
|
self.keys = universal_params + brand_params
|
||||||
self.values = {}
|
self._params = {}
|
||||||
self.cached_params_list: list[capnp.lib.capnp._DynamicStructBuilder] | None = None
|
|
||||||
|
|
||||||
self.frame = 0
|
self.frame = 0
|
||||||
|
|
||||||
def update(self, params: Params) -> None:
|
def update(self, params: Params) -> None:
|
||||||
if self.frame % 300 == 0:
|
|
||||||
old_values = dict(self.values)
|
|
||||||
self.values = {k: params.get(k) or "0" for k in self.keys}
|
|
||||||
if old_values != self.values:
|
|
||||||
self.cached_params_list = None
|
|
||||||
|
|
||||||
self.frame += 1
|
self.frame += 1
|
||||||
|
if self.frame % 300 != 0:
|
||||||
|
return
|
||||||
|
|
||||||
def publish(self) -> list[capnp.lib.capnp._DynamicStructBuilder]:
|
for key in self.keys:
|
||||||
if self.cached_params_list is None:
|
param_type = params.get_type(key).name.lower() # Using string instead of number because its "loose" dependency, and could change by OP at anytime.
|
||||||
# TODO-SP: Why are we doing a list instead of a dictionary here?
|
|
||||||
self.cached_params_list = [custom.CarControlSP.Param(key=k, value=self.values[k]) for k in self.keys]
|
# Over engineering opportunity: It's possible this conversion is slow, we may check the value as params returns it for cache purposes. Not today.
|
||||||
return self.cached_params_list
|
param_value = get_param_as_byte(key, params)
|
||||||
|
if (existing_param := self._params.get(key)) is not None and existing_param.value == param_value:
|
||||||
|
continue
|
||||||
|
|
||||||
|
self._params[key] = custom.CarControlSP.Param(key=key, value=param_value, type=param_type)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def param_list(self) -> list[custom.CarControlSP.Param]:
|
||||||
|
return [v for k,v in self._params.items()]
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ from websocket import (ABNF, WebSocket, WebSocketException, WebSocketTimeoutExce
|
|||||||
|
|
||||||
import cereal.messaging as messaging
|
import cereal.messaging as messaging
|
||||||
from sunnypilot.sunnylink.api import SunnylinkApi
|
from sunnypilot.sunnylink.api import SunnylinkApi
|
||||||
from sunnypilot.sunnylink.utils import sunnylink_need_register, sunnylink_ready, get_param_as_byte
|
from sunnypilot.sunnylink.utils import sunnylink_need_register, sunnylink_ready, get_param_as_byte, save_param_from_base64_encoded_string
|
||||||
|
|
||||||
SUNNYLINK_ATHENA_HOST = os.getenv('SUNNYLINK_ATHENA_HOST', 'wss://ws.stg.api.sunnypilot.ai')
|
SUNNYLINK_ATHENA_HOST = os.getenv('SUNNYLINK_ATHENA_HOST', 'wss://ws.stg.api.sunnypilot.ai')
|
||||||
HANDLER_THREADS = int(os.getenv('HANDLER_THREADS', "4"))
|
HANDLER_THREADS = int(os.getenv('HANDLER_THREADS', "4"))
|
||||||
@@ -184,14 +184,18 @@ def getParams(params_keys: list[str], compression: bool = False) -> str | dict[s
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
param_keys_validated = [key for key in params_keys if key in getParamsAllKeys()]
|
param_keys_validated = [key for key in params_keys if key in getParamsAllKeys()]
|
||||||
params_dict: dict[str, list[dict[str, str | bool | int ]]] = {"params": [
|
params_dict: dict[str, list[dict[str, str | bool | int]]] = {"params": []}
|
||||||
{
|
for key in param_keys_validated:
|
||||||
|
value = get_param_as_byte(key)
|
||||||
|
if value is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
params_dict["params"].append({
|
||||||
"key": key,
|
"key": key,
|
||||||
"value": base64.b64encode(gzip.compress(get_param_as_byte(key)) if compression else get_param_as_byte(key)).decode('utf-8'),
|
"value": base64.b64encode(gzip.compress(value) if compression else value).decode('utf-8'),
|
||||||
"type": int(params.get_type(key).value),
|
"type": int(params.get_type(key).value),
|
||||||
"is_compressed": compression
|
"is_compressed": compression
|
||||||
} for key in param_keys_validated
|
})
|
||||||
]}
|
|
||||||
|
|
||||||
response = {str(param.get('key')): str(param.get('value')) for param in params_dict.get("params", [])}
|
response = {str(param.get('key')): str(param.get('value')) for param in params_dict.get("params", [])}
|
||||||
response |= {"params": json.dumps(params_dict.get("params", []))} # Upcoming for settings v1
|
response |= {"params": json.dumps(params_dict.get("params", []))} # Upcoming for settings v1
|
||||||
@@ -204,15 +208,9 @@ def getParams(params_keys: list[str], compression: bool = False) -> str | dict[s
|
|||||||
|
|
||||||
@dispatcher.add_method
|
@dispatcher.add_method
|
||||||
def saveParams(params_to_update: dict[str, str], compression: bool = False) -> None:
|
def saveParams(params_to_update: dict[str, str], compression: bool = False) -> None:
|
||||||
params = Params()
|
for key, value in params_to_update.items():
|
||||||
params_dict = {key: base64.b64decode(value) for key, value in params_to_update.items()}
|
|
||||||
|
|
||||||
if compression:
|
|
||||||
params_dict = {key: gzip.decompress(value) for key, value in params_dict.items()}
|
|
||||||
|
|
||||||
for key, value in params_dict.items():
|
|
||||||
try:
|
try:
|
||||||
params.put(key, value)
|
save_param_from_base64_encoded_string(key, value, compression)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
cloudlog.error(f"sunnylinkd.saveParams.exception {e}")
|
cloudlog.error(f"sunnylinkd.saveParams.exception {e}")
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ from enum import Enum
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from openpilot.common.git import get_branch
|
from openpilot.common.git import get_branch
|
||||||
from openpilot.common.params import Params, ParamKeyType, ParamKeyFlag
|
from openpilot.common.params import Params, ParamKeyFlag
|
||||||
from openpilot.common.realtime import Ratekeeper
|
from openpilot.common.realtime import Ratekeeper
|
||||||
from openpilot.common.swaglog import cloudlog
|
from openpilot.common.swaglog import cloudlog
|
||||||
from openpilot.system.version import get_version
|
from openpilot.system.version import get_version
|
||||||
@@ -20,7 +20,7 @@ from openpilot.system.version import get_version
|
|||||||
from cereal import messaging, custom
|
from cereal import messaging, custom
|
||||||
from sunnypilot.sunnylink.api import SunnylinkApi
|
from sunnypilot.sunnylink.api import SunnylinkApi
|
||||||
from sunnypilot.sunnylink.backups.utils import decrypt_compressed_data, encrypt_compress_data, SnakeCaseEncoder
|
from sunnypilot.sunnylink.backups.utils import decrypt_compressed_data, encrypt_compress_data, SnakeCaseEncoder
|
||||||
from sunnypilot.sunnylink.utils import get_param_as_byte
|
from sunnypilot.sunnylink.utils import get_param_as_byte, save_param_from_base64_encoded_string
|
||||||
|
|
||||||
|
|
||||||
class OperationType(Enum):
|
class OperationType(Enum):
|
||||||
@@ -173,8 +173,7 @@ class BackupManagerSP:
|
|||||||
self._update_progress(75.0, OperationType.RESTORE)
|
self._update_progress(75.0, OperationType.RESTORE)
|
||||||
|
|
||||||
# Apply configuration
|
# Apply configuration
|
||||||
all_values_encoded = self._get_metadata_value(backup_metadata, "all_values_encoded", "false")
|
self._apply_config(config_data)
|
||||||
self._apply_config(config_data, str(all_values_encoded).lower() == "true")
|
|
||||||
|
|
||||||
self.restore_status = custom.BackupManagerSP.Status.completed
|
self.restore_status = custom.BackupManagerSP.Status.completed
|
||||||
self._update_progress(100.0, OperationType.RESTORE)
|
self._update_progress(100.0, OperationType.RESTORE)
|
||||||
@@ -187,7 +186,7 @@ class BackupManagerSP:
|
|||||||
self._report_status()
|
self._report_status()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _apply_config(self, config_data: dict[str, str], all_values_encoded: bool = False) -> None:
|
def _apply_config(self, config_data: dict[str, str]) -> None:
|
||||||
"""Applies configuration data from a backup, but only for parameters marked as backupable."""
|
"""Applies configuration data from a backup, but only for parameters marked as backupable."""
|
||||||
backupable_params = [k.decode('utf-8') for k in self.params.all_keys(ParamKeyFlag.BACKUP)]
|
backupable_params = [k.decode('utf-8') for k in self.params.all_keys(ParamKeyFlag.BACKUP)]
|
||||||
backupable_set_lower = {p.lower() for p in backupable_params}
|
backupable_set_lower = {p.lower() for p in backupable_params}
|
||||||
@@ -199,26 +198,8 @@ class BackupManagerSP:
|
|||||||
if param.lower() in backupable_set_lower:
|
if param.lower() in backupable_set_lower:
|
||||||
# Find real param name (with correct casing)
|
# Find real param name (with correct casing)
|
||||||
real_param = next(p for p in backupable_params if p.lower() == param.lower())
|
real_param = next(p for p in backupable_params if p.lower() == param.lower())
|
||||||
param_type = self.params.get_type(real_param)
|
|
||||||
try:
|
try:
|
||||||
value = base64.b64decode(encoded_value) if all_values_encoded else encoded_value
|
save_param_from_base64_encoded_string(real_param, encoded_value)
|
||||||
|
|
||||||
if param_type != ParamKeyType.BYTES:
|
|
||||||
value = value.decode('utf-8') # type: ignore
|
|
||||||
|
|
||||||
if param_type == ParamKeyType.STRING:
|
|
||||||
value = value
|
|
||||||
elif param_type == ParamKeyType.BOOL:
|
|
||||||
value = value.lower() in ('true', '1', 'yes') # type: ignore
|
|
||||||
elif param_type == ParamKeyType.INT:
|
|
||||||
value = int(value) # type: ignore
|
|
||||||
elif param_type == ParamKeyType.FLOAT:
|
|
||||||
value = float(value) # type: ignore
|
|
||||||
elif param_type == ParamKeyType.TIME:
|
|
||||||
value = str(value)
|
|
||||||
elif param_type == ParamKeyType.JSON:
|
|
||||||
value = json.loads(value)
|
|
||||||
self.params.put(real_param, value)
|
|
||||||
restored_count += 1
|
restored_count += 1
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
cloudlog.error(f"Failed to restore param {param}: {str(e)}")
|
cloudlog.error(f"Failed to restore param {param}: {str(e)}")
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import base64
|
||||||
|
import gzip
|
||||||
import json
|
import json
|
||||||
from sunnypilot.sunnylink.api import SunnylinkApi, UNREGISTERED_SUNNYLINK_DONGLE_ID
|
from sunnypilot.sunnylink.api import SunnylinkApi, UNREGISTERED_SUNNYLINK_DONGLE_ID
|
||||||
from openpilot.common.params import Params, ParamKeyType
|
from openpilot.common.params import Params, ParamKeyType
|
||||||
@@ -58,13 +60,57 @@ def get_api_token():
|
|||||||
print(f"API Token: {token}")
|
print(f"API Token: {token}")
|
||||||
|
|
||||||
|
|
||||||
def get_param_as_byte(param_name: str) -> bytes:
|
def get_param_as_byte(param_name: str, params=None) -> bytes | None:
|
||||||
params = Params()
|
"""Get a parameter as bytes. Returns None if the parameter does not exist."""
|
||||||
|
params = params or Params() # Use existing Params instance if provided
|
||||||
param = params.get(param_name)
|
param = params.get(param_name)
|
||||||
param_type = params.get_type(param_name)
|
if param is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
param_type = params.get_type(param_name)
|
||||||
if param_type == ParamKeyType.BYTES:
|
if param_type == ParamKeyType.BYTES:
|
||||||
return bytes(param)
|
return bytes(param)
|
||||||
elif param_type == ParamKeyType.JSON:
|
elif param_type == ParamKeyType.JSON:
|
||||||
return json.dumps(param).encode('utf-8')
|
return json.dumps(param).encode('utf-8')
|
||||||
return str(param).encode('utf-8')
|
return str(param).encode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
def save_param_from_base64_encoded_string(param_name: str, base64_encoded_data: str, is_compressed=False) -> None:
|
||||||
|
"""Save a parameter from bytes. Overwrites the parameter if it already exists."""
|
||||||
|
params = Params()
|
||||||
|
# Find real param name (with correct casing)
|
||||||
|
param_type = params.get_type(param_name)
|
||||||
|
value = base64.b64decode(base64_encoded_data)
|
||||||
|
|
||||||
|
if is_compressed:
|
||||||
|
value = gzip.decompress(value)
|
||||||
|
|
||||||
|
# We convert to string anything that isn't bytes first. We later transform further.
|
||||||
|
param_value = _convert_param_to_type(value, param_type)
|
||||||
|
params.put(param_name, param_value)
|
||||||
|
|
||||||
|
|
||||||
|
def _convert_param_to_type(value: bytes, param_type: ParamKeyType) -> bytes | str | int | float | bool | dict | None:
|
||||||
|
"""
|
||||||
|
Convert a byte value to the specified param type. Used internally when getting a Param to convert it to the right type.
|
||||||
|
If this method looks familiar, it's because on SP we have a similar one in openpilot/sunnypilot/car/__init__.py.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# We convert to string anything that isn't bytes first. We later transform further.
|
||||||
|
if param_type != ParamKeyType.BYTES:
|
||||||
|
value = value.decode('utf-8') # type: ignore
|
||||||
|
|
||||||
|
if param_type == ParamKeyType.STRING:
|
||||||
|
value = value
|
||||||
|
elif param_type == ParamKeyType.BOOL:
|
||||||
|
value = value.lower() in ('true', '1', 'yes') # type: ignore
|
||||||
|
elif param_type == ParamKeyType.INT:
|
||||||
|
value = int(value) # type: ignore
|
||||||
|
elif param_type == ParamKeyType.FLOAT:
|
||||||
|
value = float(value) # type: ignore
|
||||||
|
elif param_type == ParamKeyType.TIME:
|
||||||
|
value = str(value) # type: ignore
|
||||||
|
elif param_type == ParamKeyType.JSON:
|
||||||
|
value = json.loads(value)
|
||||||
|
|
||||||
|
return value
|
||||||
|
|||||||
@@ -9,3 +9,5 @@ export VECLIB_MAXIMUM_THREADS=1
|
|||||||
if [ -z "$AGNOS_VERSION" ]; then
|
if [ -z "$AGNOS_VERSION" ]; then
|
||||||
export AGNOS_VERSION="12.8"
|
export AGNOS_VERSION="12.8"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
export STAGING_ROOT="/data/safe_staging"
|
||||||
|
|||||||
@@ -331,7 +331,7 @@ def hardware_thread(end_event, hw_queue) -> None:
|
|||||||
# - TIZI, or
|
# - TIZI, or
|
||||||
# - TICI and channel_type is "tici"
|
# - TICI and channel_type is "tici"
|
||||||
build_metadata = get_build_metadata()
|
build_metadata = get_build_metadata()
|
||||||
is_unsupported_combo = TICI and build_metadata.channel_type != "tici"
|
is_unsupported_combo = TICI and HARDWARE.get_device_type() == "tici" and build_metadata.channel_type != "tici"
|
||||||
startup_conditions["not_tici"] = not is_unsupported_combo
|
startup_conditions["not_tici"] = not is_unsupported_combo
|
||||||
onroad_conditions["not_tici"] = not is_unsupported_combo
|
onroad_conditions["not_tici"] = not is_unsupported_combo
|
||||||
set_offroad_alert("Offroad_TiciSupport", is_unsupported_combo, extra_text=build_metadata.channel)
|
set_offroad_alert("Offroad_TiciSupport", is_unsupported_combo, extra_text=build_metadata.channel)
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ from openpilot.common.swaglog import cloudlog
|
|||||||
from openpilot.common.git import get_commit, get_origin, get_branch, get_short_branch, get_commit_date
|
from openpilot.common.git import get_commit, get_origin, get_branch, get_short_branch, get_commit_date
|
||||||
|
|
||||||
RELEASE_SP_BRANCHES = ['release-c3']
|
RELEASE_SP_BRANCHES = ['release-c3']
|
||||||
TESTED_SP_BRANCHES = ['staging-c3', 'staging-c3-new']
|
TESTED_SP_BRANCHES = ['staging-c3', 'staging-c3-new', 'staging-tici']
|
||||||
MASTER_SP_BRANCHES = ['master']
|
MASTER_SP_BRANCHES = ['master']
|
||||||
RELEASE_BRANCHES = ['release3-staging', 'release3', 'release-tici', 'nightly'] + RELEASE_SP_BRANCHES
|
RELEASE_BRANCHES = ['release3-staging', 'release3', 'release-tici', 'nightly'] + RELEASE_SP_BRANCHES
|
||||||
TESTED_BRANCHES = RELEASE_BRANCHES + ['devel', 'devel-staging', 'nightly-dev'] + TESTED_SP_BRANCHES
|
TESTED_BRANCHES = RELEASE_BRANCHES + ['devel', 'devel-staging', 'nightly-dev'] + TESTED_SP_BRANCHES
|
||||||
|
|||||||
@@ -912,7 +912,7 @@ dependencies = [
|
|||||||
{ name = "yapf" },
|
{ name = "yapf" },
|
||||||
]
|
]
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://github.com/commaai/metadrive/releases/download/MetaDrive-minimal-0.4.2.4/metadrive_simulator-0.4.2.4-py3-none-any.whl", hash = "sha256:fbf0ea9be67e65cd45d38ff930e3d49f705dd76c9ddbd1e1482e3f87b61efcef" },
|
{ url = "https://github.com/commaai/metadrive/releases/download/MetaDrive-minimal-0.4.2.4/metadrive_simulator-0.4.2.4-py3-none-any.whl", hash = "sha256:d0afaf3b005e35e14b929d5491d2d5b64562d0c1cd5093ba969fb63908670dd4" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
|
|||||||
Reference in New Issue
Block a user