mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-06-27 05:12:06 +08:00
Compare commits
126 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7bf90d5372 | |||
| 41b5065499 | |||
| 334e06c04f | |||
| dcb3113c4b | |||
| 015aadd48c | |||
| 57fc4f79d1 | |||
| 7ec6a47c1e | |||
| 6234fbfd40 | |||
| 310a5b174c | |||
| 6e339f3315 | |||
| 7558108221 | |||
| b94946eaab | |||
| dfe283765f | |||
| 9eccd9ad1e | |||
| e23b61f0b6 | |||
| ae1e476431 | |||
| bbf0e11f71 | |||
| d3063e9a0a | |||
| ed222d04c9 | |||
| 2e9540d2b1 | |||
| be67d5a1d9 | |||
| facaee8b10 | |||
| 7a4169379d | |||
| 7c101a40c8 | |||
| c48600efbd | |||
| 0902527e27 | |||
| c7889a16be | |||
| d7d9c40242 | |||
| 84fdbb0eb4 | |||
| f3c4770f91 | |||
| 3dc80057f2 | |||
| e9246df02e | |||
| 070b1e68d1 | |||
| e19ecbf75c | |||
| fe24462949 | |||
| 8f73bcffe4 | |||
| 6c02d5c3f7 | |||
| 1f3c365f1a | |||
| 34d62836fe | |||
| c6e4241bad | |||
| 8f7bbe4ee3 | |||
| 75bf756893 | |||
| a22d6cd0d3 | |||
| 3d54c383ab | |||
| 1ec2c56b4e | |||
| c4edfa8b25 | |||
| 7aeabc37d0 | |||
| 5160bee543 | |||
| b33441213a | |||
| 43807746ff | |||
| 685dc5a80c | |||
| 1bc1d2e020 | |||
| 556060f793 | |||
| 24dfa0e1bf | |||
| 8f559d4f03 | |||
| e02a6e09fe | |||
| 049f6c1dd5 | |||
| adc347d12b | |||
| ce948f7362 | |||
| 4226ef5a66 | |||
| 8e14e400ef | |||
| adb9560870 | |||
| b737e8472f | |||
| 8f71d53eb0 | |||
| 7b5478a58e | |||
| 00c964abfb | |||
| eccdf8d880 | |||
| 29577a3346 | |||
| 81252f549c | |||
| 8ebfc99b93 | |||
| 5542bd57a4 | |||
| c287232374 | |||
| a923f25225 | |||
| 3c765a1f45 | |||
| a58853e70e | |||
| 957d39a5b6 | |||
| 78b6eaea7c | |||
| 794ee3c9b4 | |||
| 1bbace7dff | |||
| 83950c1b36 | |||
| 38318db4c6 | |||
| 1b921fa6f9 | |||
| fee1f29ce9 | |||
| 006482b3f4 | |||
| 7fc5040ed9 | |||
| 0f4ed56d51 | |||
| 8939e3a30b | |||
| 8d9a1fa436 | |||
| fc354ec8cf | |||
| 00c10f6851 | |||
| 5131c19232 | |||
| b0699ccf20 | |||
| df1789ccf5 | |||
| 7496dcee58 | |||
| e243663520 | |||
| 670cf27f8e | |||
| d90d5a403f | |||
| b206879e4d | |||
| c9a3a1a018 | |||
| bf21e10d81 | |||
| 293c3fc57f | |||
| 3ac9208364 | |||
| f8497d4af0 | |||
| d50732af94 | |||
| 01384affbb | |||
| c71c2ab651 | |||
| 3e7270a30e | |||
| 47c90317bf | |||
| 7dfc45f15f | |||
| 4576f7f154 | |||
| 612dbb32e1 | |||
| e123ac3d32 | |||
| c11e9a3bdd | |||
| 8c8ac3f28f | |||
| 847a5ce1f3 | |||
| 22d19f2fc4 | |||
| 863d86c10c | |||
| 55b94abfe4 | |||
| 354db5efd4 | |||
| 83714de075 | |||
| bcd0c67669 | |||
| 308d26ae14 | |||
| 360bb68547 | |||
| 3a1c9e0f01 | |||
| a4656bd939 | |||
| db32fbea20 |
@@ -1,3 +0,0 @@
|
||||
.Xauthority
|
||||
.env
|
||||
.host/
|
||||
@@ -1,18 +0,0 @@
|
||||
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 python3 -m ensurepip --upgrade
|
||||
RUN pip3 install ipython jupyter jupyterlab
|
||||
|
||||
RUN cd /tmp && \
|
||||
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" && \
|
||||
dpkg -i virtualgl.deb
|
||||
|
||||
RUN usermod -aG video batman
|
||||
|
||||
USER batman
|
||||
|
||||
RUN cd $HOME && \
|
||||
curl -O https://raw.githubusercontent.com/commaai/agnos-builder/master/userspace/home/.tmux.conf && \
|
||||
curl -O https://raw.githubusercontent.com/commaai/agnos-builder/master/userspace/home/.vimrc
|
||||
@@ -1,38 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
TARGET_USER=batman
|
||||
source .devcontainer/.host/.env
|
||||
|
||||
# override display flag for mac hosts
|
||||
if [[ $HOST_OS == darwin ]]; then
|
||||
echo "Setting up DISPLAY override for macOS..."
|
||||
cat <<EOF >> /home/$TARGET_USER/.bashrc
|
||||
source .devcontainer/.host/.env
|
||||
if [ -n "\$HOST_DISPLAY" ]; then
|
||||
DISPLAY_NUM=\$(echo "\$HOST_DISPLAY" | awk -F: '{print \$NF}')
|
||||
export DISPLAY=host.docker.internal:\$DISPLAY_NUM
|
||||
fi
|
||||
EOF
|
||||
fi
|
||||
|
||||
# setup virtualgl for mac hosts
|
||||
if [[ $HOST_OS == darwin ]]; then
|
||||
echo "Setting up virtualgl for macOS..."
|
||||
cat <<EOF >> /home/$TARGET_USER/.bashrc
|
||||
if [ -n "\$HOST_DISPLAY" ]; then
|
||||
export VGL_PORT=10000
|
||||
export VGL_CLIENT=host.docker.internal
|
||||
export VGL_COMPRESS=rgb
|
||||
export VGL_DISPLAY=:99
|
||||
export VGL_FPS=60
|
||||
# prevent vglrun from running exec
|
||||
alias exec=:; source vglrun :; unalias exec
|
||||
fi
|
||||
EOF
|
||||
fi
|
||||
|
||||
# These lines are temporary, to remain backwards compatible with old devcontainers
|
||||
# that were running as root and therefore had their caches written as root
|
||||
sudo chown -R $TARGET_USER: /tmp/scons_cache
|
||||
sudo chown -R $TARGET_USER: /tmp/comma_download_cache
|
||||
sudo chown -R $TARGET_USER: /home/batman/.comma
|
||||
@@ -1,15 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
source .devcontainer/.host/.env
|
||||
|
||||
# setup safe directories for submodules
|
||||
SUBMODULE_DIRS=$(git config --file .gitmodules --get-regexp path | awk '{ print $2 }')
|
||||
for DIR in $SUBMODULE_DIRS; do
|
||||
git config --global --add safe.directory "$PWD/$DIR"
|
||||
done
|
||||
|
||||
# virtual display for virtualgl
|
||||
if [[ "$HOST_OS" == "darwin" ]] && [[ -n "$HOST_DISPLAY" ]]; then
|
||||
echo "Starting virtual display at :99 ..."
|
||||
tmux new-session -d -s fakedisplay Xvfb :99 -screen 0 1920x1080x24
|
||||
fi
|
||||
@@ -1,53 +0,0 @@
|
||||
{
|
||||
"name": "openpilot devcontainer",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile"
|
||||
},
|
||||
"postCreateCommand": ".devcontainer/container_post_create.sh",
|
||||
"postStartCommand": ".devcontainer/container_post_start.sh",
|
||||
"initializeCommand": [".devcontainer/host_setup"],
|
||||
"privileged": true,
|
||||
"containerEnv": {
|
||||
"DISPLAY": "${localEnv:DISPLAY}",
|
||||
"PYTHONPATH": "${containerWorkspaceFolder}",
|
||||
"TERM": "xterm-256color",
|
||||
"force_color_prompt": "1"
|
||||
},
|
||||
"runArgs": [
|
||||
"--volume=/dev:/dev",
|
||||
"--volume=/tmp/.X11-unix:/tmp/.X11-unix",
|
||||
"--volume=${localWorkspaceFolder}/.devcontainer/.host/.Xauthority:/home/batman/.Xauthority",
|
||||
"--volume=${localEnv:HOME}/.comma:/home/batman/.comma",
|
||||
"--volume=${localEnv:HOME}/.azure:/home/batman/.azure",
|
||||
"--volume=/tmp/comma_download_cache:/tmp/comma_download_cache",
|
||||
"--shm-size=1G",
|
||||
"--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
|
||||
],
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/common-utils:2": {
|
||||
"installZsh": false,
|
||||
"installOhMyZsh": false,
|
||||
"upgradePackages": false,
|
||||
"username": "batman"
|
||||
},
|
||||
"ghcr.io/devcontainers-contrib/features/gh-cli:1": {},
|
||||
"ghcr.io/devcontainers/features/azure-cli:1": {}
|
||||
},
|
||||
"containerUser": "batman",
|
||||
"remoteUser": "batman",
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"ms-python.python",
|
||||
"ms-vscode.cpptools",
|
||||
"ms-toolsai.jupyter",
|
||||
"guyskk.language-cython",
|
||||
"lharri73.dbc"
|
||||
]
|
||||
}
|
||||
},
|
||||
"mounts": [
|
||||
"type=volume,source=scons_cache,target=/tmp/scons_cache"
|
||||
]
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# pull base image
|
||||
if [[ -z $USE_LOCAL_IMAGE ]]; then
|
||||
echo "Updating openpilot_base image if needed..."
|
||||
docker pull ghcr.io/commaai/openpilot-base:latest
|
||||
fi
|
||||
|
||||
# setup .host dir
|
||||
mkdir -p .devcontainer/.host
|
||||
|
||||
# setup links to Xauthority
|
||||
XAUTHORITY_LINK=".devcontainer/.host/.Xauthority"
|
||||
rm -f $XAUTHORITY_LINK
|
||||
if [[ -z $XAUTHORITY ]]; then
|
||||
echo "XAUTHORITY not set. Fallback to ~/.Xauthority ..."
|
||||
if ! [[ -f $HOME/.Xauthority ]]; then
|
||||
echo "~/.XAuthority file does not exist. GUI tools may not work properly."
|
||||
touch $XAUTHORITY_LINK # dummy file to satisfy container volume mount
|
||||
else
|
||||
ln -sf $HOME/.Xauthority $XAUTHORITY_LINK
|
||||
fi
|
||||
else
|
||||
ln -sf $XAUTHORITY $XAUTHORITY_LINK
|
||||
fi
|
||||
|
||||
# setup host env file
|
||||
HOST_INFO_FILE=".devcontainer/.host/.env"
|
||||
SYSTEM=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||
echo "HOST_OS=\"$SYSTEM\"" > $HOST_INFO_FILE
|
||||
echo "HOST_DISPLAY=\"$DISPLAY\"" >> $HOST_INFO_FILE
|
||||
|
||||
# run virtualgl if macos
|
||||
if [[ $SYSTEM == "darwin" ]]; then
|
||||
echo
|
||||
if [[ -f /opt/VirtualGL/bin/vglclient ]]; then
|
||||
echo "Starting VirtualGL client at port 10000..."
|
||||
VGL_LOG_FILE=".devcontainer/.host/.vgl/vglclient.log"
|
||||
mkdir -p "$(dirname $VGL_LOG_FILE)"
|
||||
/opt/VirtualGL/bin/vglclient -l "$VGL_LOG_FILE" -display "$DISPLAY" -port 10000 -detach
|
||||
else
|
||||
echo "VirtualGL not found. GUI tools may not work properly. Some GUI tools require OpenGL to work properly. To use them with XQuartz on mac, VirtualGL needs to be installed. To install it run:"
|
||||
echo
|
||||
echo " brew install --cask virtualgl"
|
||||
echo
|
||||
fi
|
||||
fi
|
||||
@@ -1,10 +0,0 @@
|
||||
:: pull base image
|
||||
IF NOT DEFINED USE_LOCAL_IMAGE ^
|
||||
echo "Updating openpilot_base image if needed..." && ^
|
||||
docker pull ghcr.io/commaai/openpilot-base:latest
|
||||
|
||||
:: setup .host dir
|
||||
mkdir .devcontainer\.host
|
||||
|
||||
:: setup host env file
|
||||
echo "" > .devcontainer\.host\.env
|
||||
@@ -8,7 +8,7 @@ assignees: ''
|
||||
|
||||
**Checklist**
|
||||
|
||||
- [ ] added entry to CAR in selfdrive/car/*/values.py and ran `selfdrive/opcar/docs.py` to generate new docs
|
||||
- [ ] added entry to CAR in selfdrive/car/*/values.py and ran `selfdrive/car/docs.py` to generate new docs
|
||||
- [ ] test route added to [routes.py](https://github.com/commaai/openpilot/blob/master/selfdrive/car/tests/routes.py)
|
||||
- [ ] route with openpilot:
|
||||
- [ ] route with stock system:
|
||||
|
||||
@@ -44,7 +44,7 @@ Explain how you tested this bug fix.
|
||||
|
||||
**Checklist**
|
||||
|
||||
- [ ] added entry to CAR in selfdrive/car/*/values.py and ran `selfdrive/opcar/docs.py` to generate new docs
|
||||
- [ ] added entry to CAR in selfdrive/car/*/values.py and ran `selfdrive/car/docs.py` to generate new docs
|
||||
- [ ] test route added to [routes.py](https://github.com/commaai/openpilot/blob/master/selfdrive/car/tests/routes.py)
|
||||
- [ ] route with openpilot:
|
||||
- [ ] route with stock system:
|
||||
|
||||
@@ -14,17 +14,25 @@ inputs:
|
||||
description: 'whether to save the cache'
|
||||
default: 'false'
|
||||
required: false
|
||||
outputs:
|
||||
cache-hit:
|
||||
description: 'cache hit occurred'
|
||||
value: ${{ (contains(runner.name, 'nsc') && steps.ns-cache.outputs.cache-hit) ||
|
||||
(!contains(runner.name, 'nsc') && inputs.save != 'false' && steps.gha-cache.outputs.cache-hit) ||
|
||||
(!contains(runner.name, 'nsc') && inputs.save == 'false' && steps.gha-cache-ro.outputs.cache-hit) }}
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: setup namespace cache
|
||||
id: ns-cache
|
||||
if: ${{ contains(runner.name, 'nsc') }}
|
||||
uses: namespacelabs/nscloud-cache-action@v1
|
||||
with:
|
||||
path: ${{ inputs.path }}
|
||||
|
||||
- name: setup github cache
|
||||
id: gha-cache
|
||||
if: ${{ !contains(runner.name, 'nsc') && inputs.save != 'false' }}
|
||||
uses: 'actions/cache@v4'
|
||||
with:
|
||||
@@ -33,6 +41,7 @@ runs:
|
||||
restore-keys: ${{ inputs.restore-keys }}
|
||||
|
||||
- name: setup github cache
|
||||
id: gha-cache-ro
|
||||
if: ${{ !contains(runner.name, 'nsc') && inputs.save == 'false' }}
|
||||
uses: 'actions/cache/restore@v4'
|
||||
with:
|
||||
|
||||
@@ -15,7 +15,3 @@ jobs:
|
||||
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 }}
|
||||
|
||||
@@ -19,8 +19,9 @@ jobs:
|
||||
docs:
|
||||
name: build docs
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 1
|
||||
steps:
|
||||
- uses: commaai/timeout@v1
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
git add .
|
||||
- name: update car docs
|
||||
run: |
|
||||
scons -j$(nproc) --minimal opendbc
|
||||
scons -j$(nproc) --minimal opendbc_repo
|
||||
PYTHONPATH=. python selfdrive/car/docs.py
|
||||
git add docs/CARS.md
|
||||
- name: Create Pull Request
|
||||
|
||||
@@ -32,9 +32,9 @@ env:
|
||||
jobs:
|
||||
build_release:
|
||||
name: build release
|
||||
runs-on: ${{ ((github.repository == 'commaai/openpilot') &&
|
||||
((github.event_name != 'pull_request') ||
|
||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-latest' }}
|
||||
runs-on:
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||
env:
|
||||
STRIPPED_DIR: /tmp/releasepilot
|
||||
steps:
|
||||
@@ -75,15 +75,9 @@ jobs:
|
||||
${{ env.RUN }} "scripts/lint/lint.sh --skip check_added_large_files"
|
||||
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: ${{ fromJson(
|
||||
((github.repository == 'commaai/openpilot') &&
|
||||
((github.event_name != 'pull_request') ||
|
||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && '["x86_64", "aarch64"]' || '["x86_64"]' ) }}
|
||||
runs-on: ${{ ((matrix.arch == 'aarch64') && 'namespace-profile-arm64-2x8') ||
|
||||
((matrix.arch == 'x86_64') && ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16') ||
|
||||
'ubuntu-latest'}}
|
||||
runs-on:
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -92,17 +86,14 @@ jobs:
|
||||
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot'
|
||||
run: |
|
||||
echo "PUSH_IMAGE=true" >> "$GITHUB_ENV"
|
||||
echo "TARGET_ARCHITECTURE=${{ matrix.arch }}" >> "$GITHUB_ENV"
|
||||
$DOCKER_LOGIN
|
||||
- uses: ./.github/workflows/setup-with-retry
|
||||
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
|
||||
timeout-minutes: 30
|
||||
|
||||
build_mac:
|
||||
name: build macOS
|
||||
runs-on: namespace-profile-macos-8x14
|
||||
runs-on: ${{ github.repository == 'commaai/openpilot' && 'namespace-profile-macos-8x14' || 'macos-latest' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -125,28 +116,11 @@ jobs:
|
||||
- name: Building openpilot
|
||||
run: . .venv/bin/activate && scons -j$(nproc)
|
||||
|
||||
docker_push_multiarch:
|
||||
name: docker push multiarch tag
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot'
|
||||
needs: [build]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: false
|
||||
- name: Setup docker
|
||||
run: |
|
||||
$DOCKER_LOGIN
|
||||
- name: Merge x64 and arm64 tags
|
||||
run: |
|
||||
export PUSH_IMAGE=true
|
||||
scripts/retry.sh selfdrive/test/docker_tag_multiarch.sh base x86_64 aarch64
|
||||
|
||||
static_analysis:
|
||||
name: static analysis
|
||||
runs-on: ${{ ((github.repository == 'commaai/openpilot') &&
|
||||
((github.event_name != 'pull_request') ||
|
||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||
runs-on:
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||
env:
|
||||
PYTHONWARNINGS: default
|
||||
steps:
|
||||
@@ -160,24 +134,16 @@ jobs:
|
||||
|
||||
unit_tests:
|
||||
name: unit tests
|
||||
runs-on: ${{ ((github.repository == 'commaai/openpilot') &&
|
||||
((github.event_name != 'pull_request') ||
|
||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-latest' }}
|
||||
runs-on:
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- uses: ./.github/workflows/setup-with-retry
|
||||
with:
|
||||
docker_hub_pat: ${{ secrets.DOCKER_HUB_PAT }}
|
||||
- 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: Setup cache
|
||||
uses: ./.github/workflows/auto-cache
|
||||
with:
|
||||
path: .ci_cache/comma_download_cache
|
||||
key: unit_tests_${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}
|
||||
- name: Run unit tests
|
||||
timeout-minutes: ${{ contains(runner.name, 'nsc') && 1 || 20 }}
|
||||
run: |
|
||||
@@ -195,27 +161,25 @@ jobs:
|
||||
|
||||
process_replay:
|
||||
name: process replay
|
||||
runs-on: ${{ ((github.repository == 'commaai/openpilot') &&
|
||||
((github.event_name != 'pull_request') ||
|
||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-latest' }}
|
||||
runs-on:
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- uses: ./.github/workflows/setup-with-retry
|
||||
with:
|
||||
docker_hub_pat: ${{ secrets.DOCKER_HUB_PAT }}
|
||||
- name: Cache test routes
|
||||
id: dependency-cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
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('selfdrive/test/process_replay/ref_commit', 'selfdrive/test/process_replay/test_processes.py') }}
|
||||
- name: Build openpilot
|
||||
run: |
|
||||
${{ env.RUN }} "scons -j$(nproc)"
|
||||
- name: Run replay
|
||||
timeout-minutes: ${{ contains(runner.name, 'nsc') && 1 || 20 }}
|
||||
timeout-minutes: ${{ contains(runner.name, 'nsc') && (steps.dependency-cache.outputs.cache-hit == 'true') && 1 || 20 }}
|
||||
run: |
|
||||
${{ env.RUN }} "coverage run selfdrive/test/process_replay/test_processes.py -j$(nproc) && \
|
||||
chmod -R 777 /tmp/comma_download_cache && \
|
||||
@@ -250,9 +214,9 @@ jobs:
|
||||
|
||||
test_cars:
|
||||
name: cars
|
||||
runs-on: ${{ ((github.repository == 'commaai/openpilot') &&
|
||||
((github.event_name != 'pull_request') ||
|
||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-latest' }}
|
||||
runs-on:
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -263,17 +227,17 @@ jobs:
|
||||
submodules: true
|
||||
- uses: ./.github/workflows/setup-with-retry
|
||||
- name: Cache test routes
|
||||
id: dependency-cache
|
||||
uses: ./.github/workflows/auto-cache
|
||||
id: routes-cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .ci_cache/comma_download_cache
|
||||
key: car_models-${{ hashFiles('selfdrive/car/tests/test_models.py', 'selfdrive/car/tests/routes.py') }}-${{ matrix.job }}
|
||||
- name: Build openpilot
|
||||
run: ${{ env.RUN }} "scons -j$(nproc)"
|
||||
- name: Test car models
|
||||
timeout-minutes: ${{ contains(runner.name, 'nsc') && 1 || 20 }}
|
||||
timeout-minutes: ${{ contains(runner.name, 'nsc') && (steps.routes-cache.outputs.cache-hit == 'true') && 1 || 20 }}
|
||||
run: |
|
||||
${{ env.RUN }} "FILEREADER_CACHE=1 MAX_EXAMPLES=1 $PYTEST selfdrive/car/tests/test_models.py && \
|
||||
${{ env.RUN }} "MAX_EXAMPLES=1 $PYTEST selfdrive/car/tests/test_models.py && \
|
||||
chmod -R 777 /tmp/comma_download_cache"
|
||||
env:
|
||||
NUM_JOBS: 4
|
||||
@@ -342,9 +306,9 @@ jobs:
|
||||
|
||||
simulator_driving:
|
||||
name: simulator driving
|
||||
runs-on: ${{ ((github.repository == 'commaai/openpilot') &&
|
||||
((github.event_name != 'pull_request') ||
|
||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||
runs-on:
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -363,9 +327,9 @@ jobs:
|
||||
create_ui_report:
|
||||
# This job name needs to be the same as UI_JOB_NAME in ui_preview.yaml
|
||||
name: Create UI Report
|
||||
runs-on: ${{ ((github.repository == 'commaai/openpilot') &&
|
||||
((github.event_name != 'pull_request') ||
|
||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||
runs-on:
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
|
||||
- ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-experiments:docker.builds.local-cache=separate' || 'ubuntu-24.04' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
||||
@@ -17,7 +17,6 @@ runs:
|
||||
uses: ./.github/workflows/setup
|
||||
continue-on-error: true
|
||||
with:
|
||||
docker_hub_pat: ${{ inputs.docker_hub_pat }}
|
||||
is_retried: true
|
||||
- if: steps.setup1.outcome == 'failure'
|
||||
shell: bash
|
||||
@@ -27,7 +26,6 @@ runs:
|
||||
uses: ./.github/workflows/setup
|
||||
continue-on-error: true
|
||||
with:
|
||||
docker_hub_pat: ${{ inputs.docker_hub_pat }}
|
||||
is_retried: true
|
||||
- if: steps.setup2.outcome == 'failure'
|
||||
shell: bash
|
||||
@@ -36,5 +34,4 @@ runs:
|
||||
if: steps.setup2.outcome == 'failure'
|
||||
uses: ./.github/workflows/setup
|
||||
with:
|
||||
docker_hub_pat: ${{ inputs.docker_hub_pat }}
|
||||
is_retried: true
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
name: 'openpilot env setup'
|
||||
|
||||
inputs:
|
||||
docker_hub_pat:
|
||||
description: 'Auth token for Docker Hub, required for BuildJet jobs'
|
||||
required: true
|
||||
default: ''
|
||||
is_retried:
|
||||
description: 'A mock param that asserts that we use the setup-with-retry instead of this action directly'
|
||||
required: false
|
||||
@@ -24,11 +20,9 @@ runs:
|
||||
name: No retries!
|
||||
run: |
|
||||
if [ "${{ github.run_attempt }}" -gt 1 ]; then
|
||||
echo -e "\033[31m"
|
||||
echo "##################################################"
|
||||
echo " Retries not allowed! Fix the flaky test! "
|
||||
echo "##################################################"
|
||||
echo -e "\033[0m"
|
||||
echo -e "\033[0;31m##################################################"
|
||||
echo -e "\033[0;31m Retries not allowed! Fix the flaky test! "
|
||||
echo -e "\033[0;31m##################################################\033[0m"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -36,19 +30,6 @@ runs:
|
||||
- shell: bash
|
||||
run: git lfs pull
|
||||
|
||||
# on BuildJet runners, must be logged into DockerHub to avoid rate limiting
|
||||
# https://buildjet.com/for-github-actions/docs/guides/docker
|
||||
- shell: bash
|
||||
if: ${{ contains(runner.name, 'buildjet') && inputs.docker_hub_pat == '' }}
|
||||
run: |
|
||||
echo "Need to set the Docker Hub PAT secret as an input to this action"
|
||||
exit 1
|
||||
- name: Login to Docker Hub
|
||||
if: contains(runner.name, 'buildjet')
|
||||
shell: bash
|
||||
run: |
|
||||
docker login -u adeebshihadeh -p ${{ inputs.docker_hub_pat }}
|
||||
|
||||
# build cache
|
||||
- id: date
|
||||
shell: bash
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
name: tools
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
workflow_call:
|
||||
inputs:
|
||||
run_number:
|
||||
default: '1'
|
||||
required: true
|
||||
type: string
|
||||
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 }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
BASE_IMAGE: openpilot-base
|
||||
DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
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
|
||||
|
||||
|
||||
jobs:
|
||||
devcontainer:
|
||||
name: devcontainer
|
||||
runs-on: ubuntu-latest
|
||||
if: false # we can re-enable once this is faster
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- uses: ./.github/workflows/setup-with-retry
|
||||
- name: Use local image for testing devcontainer with latest base image
|
||||
run: |
|
||||
echo "USE_LOCAL_IMAGE=true" >> "$GITHUB_ENV"
|
||||
- name: Setup Dev Container CLI
|
||||
run: npm install -g @devcontainers/cli
|
||||
- name: Build dev container image
|
||||
run: ./scripts/retry.sh devcontainer build --workspace-folder .
|
||||
- name: Run dev container
|
||||
run: |
|
||||
mkdir -p /tmp/devcontainer_scons_cache/
|
||||
cp -r $GITHUB_WORKSPACE/.ci_cache/scons_cache/. /tmp/devcontainer_scons_cache/
|
||||
devcontainer up --workspace-folder .
|
||||
- name: Test environment
|
||||
run: |
|
||||
devcontainer exec --workspace-folder . scons -j$(nproc) cereal/ common/
|
||||
devcontainer exec --workspace-folder . pip3 install pip-install-test
|
||||
devcontainer exec --workspace-folder . touch /home/batman/.comma/auth.json
|
||||
devcontainer exec --workspace-folder . sudo touch /root/test.txt
|
||||
@@ -68,17 +68,14 @@ RUN usermod -aG sudo $USER
|
||||
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
||||
USER $USER
|
||||
|
||||
COPY --chown=$USER pyproject.toml uv.lock /tmp/
|
||||
COPY --chown=$USER tools/install_python_dependencies.sh /tmp/tools/
|
||||
COPY --chown=$USER pyproject.toml uv.lock /home/$USER
|
||||
COPY --chown=$USER tools/install_python_dependencies.sh /home/$USER/tools/
|
||||
|
||||
ENV VIRTUAL_ENV=/home/$USER/.venv
|
||||
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
|
||||
RUN cd /tmp && \
|
||||
RUN cd /home/$USER && \
|
||||
tools/install_python_dependencies.sh && \
|
||||
mkdir -p $VIRTUAL_ENV && \
|
||||
cp -r /tmp/.venv/* $VIRTUAL_ENV && \
|
||||
rm -rf /tmp/* && \
|
||||
rm -rf /home/$USER/.cache
|
||||
rm -rf tools/ pyproject.toml uv.lock .cache
|
||||
|
||||
USER root
|
||||
RUN sudo git config --global --add safe.directory /tmp/openpilot
|
||||
|
||||
Vendored
+13
-4
@@ -79,6 +79,10 @@ def deviceStage(String stageName, String deviceType, List extra_env, def steps)
|
||||
return
|
||||
}
|
||||
|
||||
if (isReplay()) {
|
||||
error("REPLAYING TESTS IS NOT ALLOWED. FIX THEM INSTEAD.")
|
||||
}
|
||||
|
||||
def extra = extra_env.collect { "export ${it}" }.join('\n');
|
||||
def branch = env.BRANCH_NAME ?: 'master';
|
||||
def gitDiff = sh returnStdout: true, script: 'curl -s -H "Authorization: Bearer ${GITHUB_COMMENTS_TOKEN}" https://api.github.com/repos/commaai/openpilot/compare/master...${GIT_BRANCH} | jq .files[].filename || echo "/"', label: 'Getting changes'
|
||||
@@ -123,6 +127,11 @@ def hasPathChanged(String gitDiff, List<String> paths) {
|
||||
return false
|
||||
}
|
||||
|
||||
def isReplay() {
|
||||
def replayClass = "org.jenkinsci.plugins.workflow.cps.replay.ReplayCause"
|
||||
return currentBuild.rawBuild.getCauses().any{ cause -> cause.toString().contains(replayClass) }
|
||||
}
|
||||
|
||||
def setupCredentials() {
|
||||
withCredentials([
|
||||
string(credentialsId: 'azure_token', variable: 'AZURE_TOKEN'),
|
||||
@@ -207,8 +216,8 @@ node {
|
||||
step("build", "cd system/manager && ./build.py"),
|
||||
step("test pandad", "pytest selfdrive/pandad/tests/test_pandad.py", [diffPaths: ["panda", "selfdrive/pandad/"]]),
|
||||
step("test power draw", "pytest -s system/hardware/tici/tests/test_power_draw.py"),
|
||||
step("test encoder", "LD_LIBRARY_PATH=/usr/local/lib pytest system/loggerd/tests/test_encoder.py"),
|
||||
step("test pigeond", "pytest system/ubloxd/tests/test_pigeond.py"),
|
||||
step("test encoder", "LD_LIBRARY_PATH=/usr/local/lib pytest system/loggerd/tests/test_encoder.py", [diffPaths: ["system/loggerd/"]]),
|
||||
step("test pigeond", "pytest system/ubloxd/tests/test_pigeond.py", [diffPaths: ["system/ubloxd/"]]),
|
||||
step("test manager", "pytest system/manager/test/test_manager.py"),
|
||||
])
|
||||
},
|
||||
@@ -243,7 +252,7 @@ node {
|
||||
'replay': {
|
||||
deviceStage("model-replay", "tici-replay", ["UNSAFE=1"], [
|
||||
step("build", "cd system/manager && ./build.py", [diffPaths: ["selfdrive/modeld/", "tinygrad_repo", "selfdrive/test/process_replay/model_replay.py"]]),
|
||||
step("model replay", "selfdrive/test/process_replay/model_replay.py", [diffPaths: ["selfdrive/modeld/"]]),
|
||||
step("model replay", "selfdrive/test/process_replay/model_replay.py", [diffPaths: ["selfdrive/modeld/", "tinygrad_repo", "selfdrive/test/process_replay/model_replay.py"]]),
|
||||
])
|
||||
},
|
||||
'tizi': {
|
||||
@@ -253,7 +262,7 @@ node {
|
||||
step("test pandad spi", "pytest selfdrive/pandad/tests/test_pandad_spi.py"),
|
||||
step("test pandad", "pytest selfdrive/pandad/tests/test_pandad.py", [diffPaths: ["panda", "selfdrive/pandad/"]]),
|
||||
step("test amp", "pytest system/hardware/tici/tests/test_amplifier.py"),
|
||||
step("test qcomgpsd", "pytest system/qcomgpsd/tests/test_qcomgpsd.py"),
|
||||
step("test qcomgpsd", "pytest system/qcomgpsd/tests/test_qcomgpsd.py", [diffPaths: ["system/qcomgpsd/"]]),
|
||||
])
|
||||
},
|
||||
|
||||
|
||||
+2
-1
@@ -349,7 +349,7 @@ Export('common', 'gpucommon')
|
||||
env_swaglog = env.Clone()
|
||||
env_swaglog['CXXFLAGS'].append('-DSWAGLOG="\\"common/swaglog.h\\""')
|
||||
SConscript(['msgq_repo/SConscript'], exports={'env': env_swaglog})
|
||||
SConscript(['opendbc/can/SConscript'], exports={'env': env_swaglog})
|
||||
SConscript(['opendbc_repo/SConscript'], exports={'env': env_swaglog})
|
||||
|
||||
SConscript(['cereal/SConscript'])
|
||||
|
||||
@@ -366,6 +366,7 @@ SConscript(['rednose/SConscript'])
|
||||
|
||||
# Build system services
|
||||
SConscript([
|
||||
'system/ui/SConscript',
|
||||
'system/proclogd/SConscript',
|
||||
'system/ubloxd/SConscript',
|
||||
'system/loggerd/SConscript',
|
||||
|
||||
@@ -486,6 +486,9 @@ struct DeviceState @0xa4d8b5af2aa492eb {
|
||||
nvmeTempC @35 :List(Float32);
|
||||
modemTempC @36 :List(Float32);
|
||||
pmicTempC @39 :List(Float32);
|
||||
intakeTempC @46 :Float32;
|
||||
exhaustTempC @47 :Float32;
|
||||
caseTempC @48 :Float32;
|
||||
maxTempC @44 :Float32; # max of other temps, used to control fan
|
||||
thermalZones @38 :List(ThermalZone);
|
||||
thermalStatus @14 :ThermalStatus;
|
||||
|
||||
@@ -17,5 +17,5 @@ class TestServices:
|
||||
|
||||
def test_generated_header(self):
|
||||
with tempfile.NamedTemporaryFile(suffix=".h") as f:
|
||||
ret = os.system(f"python3 {services.__file__} > {f.name} && clang++ {f.name}")
|
||||
ret = os.system(f"python3 {services.__file__} > {f.name} && clang++ {f.name} -std=c++11")
|
||||
assert ret == 0, "generated services header is not valid C"
|
||||
|
||||
@@ -112,7 +112,6 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"DisablePowerDown", PERSISTENT},
|
||||
{"DisableUpdates", PERSISTENT},
|
||||
{"DisengageOnAccelerator", PERSISTENT},
|
||||
{"DmModelInitialized", CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"DongleId", PERSISTENT},
|
||||
{"DoReboot", CLEAR_ON_MANAGER_START},
|
||||
{"DoShutdown", CLEAR_ON_MANAGER_START},
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ public:
|
||||
if (prefix.empty()) {
|
||||
prefix = util::random_string(15);
|
||||
}
|
||||
msgq_path = "/dev/shm/" + prefix;
|
||||
msgq_path = Path::shm_path() + "/" + prefix;
|
||||
bool ret = util::create_directories(msgq_path, 0777);
|
||||
assert(ret);
|
||||
setenv("OPENPILOT_PREFIX", prefix.c_str(), 1);
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT
|
||||
class OpenpilotPrefix:
|
||||
def __init__(self, prefix: str = None, clean_dirs_on_exit: bool = True, shared_download_cache: bool = False):
|
||||
self.prefix = prefix if prefix else str(uuid.uuid4().hex[0:15])
|
||||
self.msgq_path = os.path.join('/dev/shm', self.prefix)
|
||||
self.msgq_path = os.path.join(Paths.shm_path(), self.prefix)
|
||||
self.clean_dirs_on_exit = clean_dirs_on_exit
|
||||
self.shared_download_cache = shared_download_cache
|
||||
|
||||
|
||||
+6
-2
@@ -48,13 +48,13 @@ class Ratekeeper:
|
||||
def __init__(self, rate: float, print_delay_threshold: float | None = 0.0) -> None:
|
||||
"""Rate in Hz for ratekeeping. print_delay_threshold must be nonnegative."""
|
||||
self._interval = 1. / rate
|
||||
self._next_frame_time = time.monotonic() + self._interval
|
||||
self._print_delay_threshold = print_delay_threshold
|
||||
self._frame = 0
|
||||
self._remaining = 0.0
|
||||
self._process_name = getproctitle()
|
||||
self._dts = deque([self._interval], maxlen=100)
|
||||
self._last_monitor_time = time.monotonic()
|
||||
self._last_monitor_time = -1.
|
||||
self._next_frame_time = -1.
|
||||
|
||||
@property
|
||||
def frame(self) -> int:
|
||||
@@ -79,6 +79,10 @@ class Ratekeeper:
|
||||
|
||||
# Monitors the cumulative lag, but does not enforce a rate
|
||||
def monitor_time(self) -> bool:
|
||||
if self._last_monitor_time < 0:
|
||||
self._next_frame_time = time.monotonic() + self._interval
|
||||
self._last_monitor_time = time.monotonic()
|
||||
|
||||
prev = self._last_monitor_time
|
||||
self._last_monitor_time = time.monotonic()
|
||||
self._dts.append(self._last_monitor_time - prev)
|
||||
|
||||
+2
-1
@@ -2,8 +2,9 @@
|
||||
|
||||
#include "common/watchdog.h"
|
||||
#include "common/util.h"
|
||||
#include "system/hardware/hw.h"
|
||||
|
||||
const std::string watchdog_fn_prefix = "/dev/shm/wd_"; // + <pid>
|
||||
const std::string watchdog_fn_prefix = Path::shm_path() + "/wd_"; // + <pid>
|
||||
|
||||
bool watchdog_kick(uint64_t ts) {
|
||||
static std::string fn = watchdog_fn_prefix + std::to_string(getpid());
|
||||
|
||||
+2
-2
@@ -167,7 +167,7 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Lexus|ES 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=ES 2017-18">Buy Here</a></sub></details>||
|
||||
|Lexus|ES 2019-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=ES 2019-24">Buy Here</a></sub></details>||
|
||||
|Lexus|ES Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=ES Hybrid 2017-18">Buy Here</a></sub></details>||
|
||||
|Lexus|ES Hybrid 2019-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=ES Hybrid 2019-24">Buy Here</a></sub></details>|<a href="https://youtu.be/BZ29osRVJeg?t=12" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Lexus|ES Hybrid 2019-25|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=ES Hybrid 2019-25">Buy Here</a></sub></details>|<a href="https://youtu.be/BZ29osRVJeg?t=12" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Lexus|GS F 2016|All|Stock|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=GS F 2016">Buy Here</a></sub></details>||
|
||||
|Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=IS 2017-19">Buy Here</a></sub></details>||
|
||||
|Lexus|IS 2022-23|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=IS 2022-23">Buy Here</a></sub></details>||
|
||||
@@ -188,7 +188,7 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Lincoln|Aviator Plug-in Hybrid 2020-24|Co-Pilot360 Plus|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lincoln&model=Aviator Plug-in Hybrid 2020-24">Buy Here</a></sub></details>||
|
||||
|MAN|eTGE 2020-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=MAN&model=eTGE 2020-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|MAN|TGE 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=MAN&model=TGE 2017-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Mazda|CX-5 2022-24|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Mazda connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Mazda&model=CX-5 2022-24">Buy Here</a></sub></details>||
|
||||
|Mazda|CX-5 2022-25|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Mazda connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Mazda&model=CX-5 2022-25">Buy Here</a></sub></details>||
|
||||
|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Mazda connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Mazda&model=CX-9 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/dA3duO4a0O4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Nissan B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Nissan&model=Altima 2019-20">Buy Here</a></sub></details>||
|
||||
|Nissan|Leaf 2018-23|ProPILOT Assist|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Nissan&model=Leaf 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/vaMbtAh_0cY" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ export OPENBLAS_NUM_THREADS=1
|
||||
export VECLIB_MAXIMUM_THREADS=1
|
||||
|
||||
if [ -z "$AGNOS_VERSION" ]; then
|
||||
export AGNOS_VERSION="11.2"
|
||||
export AGNOS_VERSION="11.3"
|
||||
fi
|
||||
|
||||
export STAGING_ROOT="/data/safe_staging"
|
||||
|
||||
+1
-1
Submodule msgq_repo updated: 3e17f865bb...434ed2312c
+1
-1
Submodule opendbc_repo updated: 7cb3d4c021...cc30feb6fb
+1
-1
Submodule panda updated: dec9223f97...c7cc2deaf0
+4
-1
@@ -31,6 +31,9 @@ dependencies = [
|
||||
# body / webrtcd
|
||||
"aiohttp",
|
||||
"aiortc",
|
||||
# aiortc does not put an upper bound on pyopenssl and is now incompatible
|
||||
# with the latest release
|
||||
"pyopenssl < 24.3.0",
|
||||
"pyaudio",
|
||||
|
||||
# panda
|
||||
@@ -98,7 +101,6 @@ dev = [
|
||||
"azure-identity",
|
||||
"azure-storage-blob",
|
||||
"dictdiffer",
|
||||
"flaky",
|
||||
"lru-dict",
|
||||
"matplotlib",
|
||||
"parameterized >=0.8, <0.9",
|
||||
@@ -239,6 +241,7 @@ exclude = [
|
||||
"cereal",
|
||||
"panda",
|
||||
"opendbc",
|
||||
"opendbc_repo",
|
||||
"rednose_repo",
|
||||
"tinygrad_repo",
|
||||
"teleoprtc",
|
||||
|
||||
@@ -32,7 +32,6 @@ blacklist = [
|
||||
|
||||
".git/",
|
||||
".github/",
|
||||
".devcontainer/",
|
||||
"Darwin/",
|
||||
".vscode",
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ for f in sorted(pyf):
|
||||
lns = len(src.split("\n"))
|
||||
tree = ast.parse(src)
|
||||
Analyzer().visit(tree)
|
||||
print("%5d %s %s" % (lns, f, xbit))
|
||||
print(f"{lns:5d} {f} {xbit}")
|
||||
if 'test' in f:
|
||||
testlns += lns
|
||||
elif f.startswith(('tools/', 'scripts/', 'selfdrive/debug')):
|
||||
@@ -47,8 +47,8 @@ for f in sorted(pyf):
|
||||
else:
|
||||
tlns += lns
|
||||
|
||||
print("%d lines of openpilot python" % tlns)
|
||||
print("%d lines of car ports" % carlns)
|
||||
print("%d lines of tools/scripts/debug" % scriptlns)
|
||||
print("%d lines of tests" % testlns)
|
||||
print(f"{tlns} lines of openpilot python")
|
||||
print(f"{carlns} lines of car ports")
|
||||
print(f"{scriptlns} lines of tools/scripts/debug")
|
||||
print(f"{testlns} lines of tests")
|
||||
#print(sorted(list(imps)))
|
||||
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
FAIL=0
|
||||
|
||||
if grep -n '#include "third_party/raylib/include/raylib\.h"' $@ | grep -v '^system/ui/raylib/raylib\.h'; then
|
||||
echo -e "Bad raylib include found! Use '#include \"system/ui/raylib/raylib.h\"' instead\n"
|
||||
FAIL=1
|
||||
fi
|
||||
|
||||
exit $FAIL
|
||||
@@ -53,6 +53,7 @@ function run_tests() {
|
||||
run "check_shebang_scripts_are_executable" python3 -m pre_commit_hooks.check_shebang_scripts_are_executable $ALL_FILES
|
||||
run "check_shebang_format" $DIR/check_shebang_format.sh $ALL_FILES
|
||||
run "check_nomerge_comments" $DIR/check_nomerge_comments.sh $ALL_FILES
|
||||
run "check_raylib_includes" $DIR/check_raylib_includes.sh $ALL_FILES
|
||||
|
||||
if [[ -z "$FAST" ]]; then
|
||||
run "mypy" mypy $PYTHON_FILES
|
||||
|
||||
+2
-2
@@ -16,9 +16,9 @@ def waste(core):
|
||||
j = 0
|
||||
while 1:
|
||||
if (i % 100) == 0:
|
||||
setproctitle("%3d: %8d" % (core, i))
|
||||
setproctitle(f"{core:3d}: {i:8d}")
|
||||
lt = time.monotonic()
|
||||
print("%3d: %8d %f %.2f" % (core, i, lt-st, j))
|
||||
print(f"{core:3d}: {i:8d} {lt-st:f} {j:.2f}")
|
||||
st = lt
|
||||
i += 1
|
||||
j = np.sum(np.matmul(m1, m2))
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f7565541b4e6213221174839b9b2b67397ced0b9807ea56413989fd37325b3b6
|
||||
size 4908
|
||||
@@ -17,7 +17,7 @@ class TestCarDocs:
|
||||
with open(CARS_MD_OUT) as f:
|
||||
current_cars_md = f.read()
|
||||
|
||||
assert generated_cars_md == current_cars_md, "Run selfdrive/opcar/docs.py to update the compatibility documentation"
|
||||
assert generated_cars_md == current_cars_md, "Run selfdrive/car/docs.py to update the compatibility documentation"
|
||||
|
||||
def test_docs_diff(self):
|
||||
dump_path = os.path.join(BASEDIR, "selfdrive", "car", "tests", "cars_dump")
|
||||
|
||||
@@ -394,7 +394,7 @@ class TestCarModelBase(unittest.TestCase):
|
||||
for msg in filter(lambda m: m.src in range(64), can.can):
|
||||
to_send = libpanda_py.make_CANPacket(msg.address, msg.src % 4, msg.dat)
|
||||
ret = self.safety.safety_rx_hook(to_send)
|
||||
self.assertEqual(1, ret, f"safety rx failed ({ret=}): {to_send}")
|
||||
self.assertEqual(1, ret, f"safety rx failed ({ret=}): {(msg.address, msg.src % 4)}")
|
||||
|
||||
# Skip first frame so CS_prev is properly initialized
|
||||
if idx == 0:
|
||||
|
||||
@@ -28,7 +28,7 @@ def can_printer(bus, max_msg, addr, ascii_decode):
|
||||
x = binascii.hexlify(msgs[_addr][-1]).decode('ascii')
|
||||
freq = len(msgs[_addr]) / (time.monotonic() - start)
|
||||
if max_msg is None or _addr < max_msg:
|
||||
dd += "%04X(%4d)(%6d)(%3dHz) %s %s\n" % (_addr, _addr, len(msgs[_addr]), freq, x.ljust(20), a)
|
||||
dd += f"{_addr:04X}({_addr:4d})({len(msgs[_addr]):6d})({freq:3}dHz) {x.ljust(20)} {a}\n"
|
||||
print(dd)
|
||||
lp = time.monotonic()
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ if __name__ == '__main__':
|
||||
start_t = time.process_time_ns()
|
||||
for msg in msgs:
|
||||
can_list = can_capnp_to_list([msg])
|
||||
for cp in tm.CI.can_parsers:
|
||||
for cp in tm.CI.can_parsers.values():
|
||||
if cp is not None:
|
||||
cp.update_strings(can_list)
|
||||
ets.append((time.process_time_ns() - start_t) * 1e-6)
|
||||
|
||||
@@ -8,6 +8,7 @@ from typing import cast
|
||||
|
||||
from cereal.services import SERVICE_LIST
|
||||
from openpilot.tools.lib.logreader import LogReader, ReadMode
|
||||
from openpilot.selfdrive.test.process_replay.migration import migrate_all
|
||||
|
||||
if __name__ == "__main__":
|
||||
cnt_events: Counter = Counter()
|
||||
@@ -20,7 +21,7 @@ if __name__ == "__main__":
|
||||
start_time = math.inf
|
||||
end_time = -math.inf
|
||||
ignition_off = None
|
||||
for msg in LogReader(sys.argv[1], ReadMode.QLOG):
|
||||
for msg in migrate_all(LogReader(sys.argv[1], ReadMode.QLOG)):
|
||||
t = (msg.logMonoTime - start_time) / 1e9
|
||||
end_time = max(end_time, msg.logMonoTime)
|
||||
start_time = min(start_time, msg.logMonoTime)
|
||||
|
||||
@@ -22,7 +22,7 @@ def get_fingerprint(lr):
|
||||
msgs[c.address] = len(c.dat)
|
||||
|
||||
# show CAN fingerprint
|
||||
fingerprint = ', '.join("%d: %d" % v for v in sorted(msgs.items()))
|
||||
fingerprint = ', '.join(f"{v[0]}: {v[1]}" for v in sorted(msgs.items()))
|
||||
print(f"\nfound {len(msgs)} messages. CAN fingerprint:\n")
|
||||
print(fingerprint)
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ while True:
|
||||
if c.src % 0x80 == 0 and c.address < 0x800 and c.address not in (0x7df, 0x7e0, 0x7e8):
|
||||
msgs[c.address] = len(c.dat)
|
||||
|
||||
fingerprint = ', '.join("%d: %d" % v for v in sorted(msgs.items()))
|
||||
fingerprint = ', '.join(f"{v[0]}: {v[1]}" for v in sorted(msgs.items()))
|
||||
|
||||
print(f"number of messages {len(msgs)}:")
|
||||
print(f"fingerprint {fingerprint}")
|
||||
|
||||
@@ -8,6 +8,7 @@ from enum import Enum
|
||||
from collections import defaultdict
|
||||
|
||||
from cereal import log, messaging
|
||||
from cereal.services import SERVICE_LIST
|
||||
from openpilot.common.transformations.orientation import rot_from_euler
|
||||
from openpilot.common.realtime import config_realtime_process
|
||||
from openpilot.common.params import Params
|
||||
@@ -23,8 +24,10 @@ MIN_STD_SANITY_CHECK = 1e-5 # m or rad
|
||||
MAX_FILTER_REWIND_TIME = 0.8 # s
|
||||
MAX_SENSOR_TIME_DIFF = 0.1 # s
|
||||
YAWRATE_CROSS_ERR_CHECK_FACTOR = 30
|
||||
INPUT_INVALID_THRESHOLD = 0.5
|
||||
INPUT_INVALID_DECAY = 0.9993 # ~10 secs to resume after a bad input
|
||||
INPUT_INVALID_THRESHOLD = 0.5 # 0 bad inputs ignored
|
||||
TIMING_INVALID_THRESHOLD = 2.5 # 2 bad timings ignored
|
||||
INPUT_INVALID_DECAY = 0.9993 # ~10 secs to resume after exceeding allowed bad inputs by one (at 100hz)
|
||||
TIMING_INVALID_DECAY = 0.9990 # ~2 secs to resume after exceeding allowed bad timings by one (at 100hz)
|
||||
POSENET_STD_INITIAL_VALUE = 10.0
|
||||
POSENET_STD_HIST_HALF = 20
|
||||
|
||||
@@ -265,10 +268,13 @@ def main():
|
||||
estimator = LocationEstimator(DEBUG)
|
||||
|
||||
filter_initialized = False
|
||||
critcal_services = ["accelerometer", "gyroscope", "liveCalibration", "cameraOdometry"]
|
||||
observation_timing_invalid = False
|
||||
critcal_services = ["accelerometer", "gyroscope", "cameraOdometry"]
|
||||
observation_timing_invalid = defaultdict(int)
|
||||
observation_input_invalid = defaultdict(int)
|
||||
|
||||
input_invalid_decay = {s: INPUT_INVALID_DECAY ** (100. / SERVICE_LIST[s].frequency) for s in critcal_services}
|
||||
timing_invalid_decay = {s: TIMING_INVALID_DECAY ** (100. / SERVICE_LIST[s].frequency) for s in critcal_services}
|
||||
|
||||
initial_pose = params.get("LocationFilterInitialState")
|
||||
if initial_pose is not None:
|
||||
initial_pose = json.loads(initial_pose)
|
||||
@@ -282,8 +288,6 @@ def main():
|
||||
acc_msgs, gyro_msgs = (messaging.drain_sock(sock) for sock in sensor_sockets)
|
||||
|
||||
if filter_initialized:
|
||||
observation_timing_invalid = False
|
||||
|
||||
msgs = []
|
||||
for msg in acc_msgs + gyro_msgs:
|
||||
t, valid, which, data = msg.logMonoTime, msg.valid, msg.which(), getattr(msg, msg.which())
|
||||
@@ -298,18 +302,23 @@ def main():
|
||||
if valid:
|
||||
t = log_mono_time * 1e-9
|
||||
res = estimator.handle_log(t, which, msg)
|
||||
if which not in critcal_services:
|
||||
continue
|
||||
|
||||
if res == HandleLogResult.TIMING_INVALID:
|
||||
observation_timing_invalid = True
|
||||
observation_timing_invalid[which] += 1
|
||||
elif res == HandleLogResult.INPUT_INVALID:
|
||||
observation_input_invalid[which] += 1
|
||||
else:
|
||||
observation_input_invalid[which] *= INPUT_INVALID_DECAY
|
||||
observation_input_invalid[which] *= input_invalid_decay[which]
|
||||
observation_timing_invalid[which] *= timing_invalid_decay[which]
|
||||
else:
|
||||
filter_initialized = sm.all_checks() and sensor_all_checks(acc_msgs, gyro_msgs, sensor_valid, sensor_recv_time, sensor_alive, SIMULATION)
|
||||
|
||||
if sm.updated["cameraOdometry"]:
|
||||
critical_service_inputs_valid = all(observation_input_invalid[s] < INPUT_INVALID_THRESHOLD for s in critcal_services)
|
||||
inputs_valid = sm.all_valid() and critical_service_inputs_valid and not observation_timing_invalid
|
||||
critical_service_timing_valid = all(observation_timing_invalid[s] < TIMING_INVALID_THRESHOLD for s in critcal_services)
|
||||
inputs_valid = sm.all_valid() and critical_service_inputs_valid and critical_service_timing_valid
|
||||
sensors_valid = sensor_all_checks(acc_msgs, gyro_msgs, sensor_valid, sensor_recv_time, sensor_alive, SIMULATION)
|
||||
|
||||
msg = estimator.get_msg(sensors_valid, inputs_valid, filter_initialized)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import pytest
|
||||
import numpy as np
|
||||
from collections import defaultdict
|
||||
from enum import Enum
|
||||
@@ -17,6 +16,7 @@ SELECT_COMPARE_FIELDS = {
|
||||
'sensors_flag': ['sensorsOK'],
|
||||
}
|
||||
JUNK_IDX = 100
|
||||
CONSISTENT_SPIKES_COUNT = 10
|
||||
|
||||
|
||||
class Scenario(Enum):
|
||||
@@ -25,6 +25,8 @@ class Scenario(Enum):
|
||||
GYRO_SPIKE_MIDWAY = 'gyro_spike_midway'
|
||||
ACCEL_OFF = 'accel_off'
|
||||
ACCEL_SPIKE_MIDWAY = 'accel_spike_midway'
|
||||
SENSOR_TIMING_SPIKE_MIDWAY = 'timing_spikes'
|
||||
SENSOR_TIMING_CONSISTENT_SPIKES = 'timing_consistent_spikes'
|
||||
|
||||
|
||||
def get_select_fields_data(logs):
|
||||
@@ -43,6 +45,17 @@ def get_select_fields_data(logs):
|
||||
return data
|
||||
|
||||
|
||||
def modify_logs_midway(logs, which, count, fn):
|
||||
non_which = [x for x in logs if x.which() != which]
|
||||
which = [x for x in logs if x.which() == which]
|
||||
temps = which[len(which) // 2:len(which) // 2 + count]
|
||||
for i, temp in enumerate(temps):
|
||||
temp = temp.as_builder()
|
||||
fn(temp)
|
||||
which[len(which) // 2 + i] = temp.as_reader()
|
||||
return sorted(non_which + which, key=lambda x: x.logMonoTime)
|
||||
|
||||
|
||||
def run_scenarios(scenario, logs):
|
||||
if scenario == Scenario.BASE:
|
||||
pass
|
||||
@@ -51,30 +64,28 @@ def run_scenarios(scenario, logs):
|
||||
logs = sorted([x for x in logs if x.which() != 'gyroscope'], key=lambda x: x.logMonoTime)
|
||||
|
||||
elif scenario == Scenario.GYRO_SPIKE_MIDWAY:
|
||||
non_gyro = [x for x in logs if x.which() not in 'gyroscope']
|
||||
gyro = [x for x in logs if x.which() in 'gyroscope']
|
||||
temp = gyro[len(gyro) // 2].as_builder()
|
||||
temp.gyroscope.gyroUncalibrated.v[0] += 3.0
|
||||
gyro[len(gyro) // 2] = temp.as_reader()
|
||||
logs = sorted(non_gyro + gyro, key=lambda x: x.logMonoTime)
|
||||
def gyro_spike(msg):
|
||||
msg.gyroscope.gyroUncalibrated.v[0] += 3.0
|
||||
logs = modify_logs_midway(logs, 'gyroscope', 1, gyro_spike)
|
||||
|
||||
elif scenario == Scenario.ACCEL_OFF:
|
||||
logs = sorted([x for x in logs if x.which() != 'accelerometer'], key=lambda x: x.logMonoTime)
|
||||
|
||||
elif scenario == Scenario.ACCEL_SPIKE_MIDWAY:
|
||||
non_accel = [x for x in logs if x.which() not in 'accelerometer']
|
||||
accel = [x for x in logs if x.which() in 'accelerometer']
|
||||
temp = accel[len(accel) // 2].as_builder()
|
||||
temp.accelerometer.acceleration.v[0] += 10.0
|
||||
accel[len(accel) // 2] = temp.as_reader()
|
||||
logs = sorted(non_accel + accel, key=lambda x: x.logMonoTime)
|
||||
def acc_spike(msg):
|
||||
msg.accelerometer.acceleration.v[0] += 10.0
|
||||
logs = modify_logs_midway(logs, 'accelerometer', 1, acc_spike)
|
||||
|
||||
elif scenario == Scenario.SENSOR_TIMING_SPIKE_MIDWAY or scenario == Scenario.SENSOR_TIMING_CONSISTENT_SPIKES:
|
||||
def timing_spike(msg):
|
||||
msg.accelerometer.timestamp -= int(0.150 * 1e9)
|
||||
count = 1 if scenario == Scenario.SENSOR_TIMING_SPIKE_MIDWAY else CONSISTENT_SPIKES_COUNT
|
||||
logs = modify_logs_midway(logs, 'accelerometer', count, timing_spike)
|
||||
|
||||
replayed_logs = replay_process_with_name(name='locationd', lr=logs)
|
||||
return get_select_fields_data(logs), get_select_fields_data(replayed_logs)
|
||||
|
||||
|
||||
@pytest.mark.xdist_group("test_locationd_scenarios")
|
||||
@pytest.mark.shared_download_cache
|
||||
class TestLocationdScenarios:
|
||||
"""
|
||||
Test locationd with different scenarios. In all these scenarios, we expect the following:
|
||||
@@ -122,7 +133,7 @@ class TestLocationdScenarios:
|
||||
assert np.allclose(orig_data['yaw_rate'], replayed_data['yaw_rate'], atol=np.radians(0.35))
|
||||
assert np.allclose(orig_data['roll'], replayed_data['roll'], atol=np.radians(0.55))
|
||||
assert np.diff(replayed_data['inputs_flag'])[499] == -1.0
|
||||
assert np.diff(replayed_data['inputs_flag'])[696] == 1.0
|
||||
assert np.diff(replayed_data['inputs_flag'])[704] == 1.0
|
||||
|
||||
def test_accel_off(self):
|
||||
"""
|
||||
@@ -146,3 +157,21 @@ class TestLocationdScenarios:
|
||||
orig_data, replayed_data = run_scenarios(Scenario.ACCEL_SPIKE_MIDWAY, self.logs)
|
||||
assert np.allclose(orig_data['yaw_rate'], replayed_data['yaw_rate'], atol=np.radians(0.35))
|
||||
assert np.allclose(orig_data['roll'], replayed_data['roll'], atol=np.radians(0.55))
|
||||
|
||||
def test_single_timing_spike(self):
|
||||
"""
|
||||
Test: timing of 150ms off for the single accelerometer message in the middle of the segment
|
||||
Expected Result: the message is ignored, and inputsOK is False for that time
|
||||
"""
|
||||
orig_data, replayed_data = run_scenarios(Scenario.SENSOR_TIMING_SPIKE_MIDWAY, self.logs)
|
||||
assert np.all(replayed_data['inputs_flag'] == orig_data['inputs_flag'])
|
||||
assert np.all(replayed_data['sensors_flag'] == orig_data['sensors_flag'])
|
||||
|
||||
def test_consistent_timing_spikes(self):
|
||||
"""
|
||||
Test: consistent timing spikes for N accelerometer messages in the middle of the segment
|
||||
Expected Result: inputsOK becomes False after N of bad measurements
|
||||
"""
|
||||
orig_data, replayed_data = run_scenarios(Scenario.SENSOR_TIMING_CONSISTENT_SPIKES, self.logs)
|
||||
assert np.diff(replayed_data['inputs_flag'])[500] == -1.0
|
||||
assert np.diff(replayed_data['inputs_flag'])[787] == 1.0
|
||||
|
||||
@@ -12,7 +12,6 @@ from cereal import messaging
|
||||
from cereal.messaging import PubMaster, SubMaster
|
||||
from msgq.visionipc import VisionIpcClient, VisionStreamType, VisionBuf
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.realtime import set_realtime_priority
|
||||
from openpilot.selfdrive.modeld.runners import ModelRunner, Runtime
|
||||
from openpilot.selfdrive.modeld.models.commonmodel_pyx import CLContext
|
||||
@@ -126,7 +125,6 @@ def main():
|
||||
cl_context = CLContext()
|
||||
model = ModelState(cl_context)
|
||||
cloudlog.warning("models loaded, dmonitoringmodeld starting")
|
||||
Params().put_bool("DmModelInitialized", True)
|
||||
|
||||
cloudlog.warning("connecting to driver stream")
|
||||
vipc_client = VisionIpcClient("camerad", VisionStreamType.VISION_STREAM_DRIVER, True, cl_context)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c829d824ebc73d15da82516592c07d9784369ccbf710698e919e06a702e70924
|
||||
size 50320138
|
||||
oid sha256:9dc64f5d1e7d6b67f1d4659a3483f03b4324b4c7b969a5ba90c4e37e62bf6fce
|
||||
size 50320584
|
||||
|
||||
@@ -145,6 +145,10 @@ void Panda::set_can_speed_kbps(uint16_t bus, uint16_t speed) {
|
||||
handle->control_write(0xde, bus, (speed * 10));
|
||||
}
|
||||
|
||||
void Panda::set_can_fd_auto(uint16_t bus, bool enabled) {
|
||||
handle->control_write(0xe8, bus, enabled);
|
||||
}
|
||||
|
||||
void Panda::set_data_speed_kbps(uint16_t bus, uint16_t speed) {
|
||||
handle->control_write(0xf9, bus, (speed * 10));
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ public:
|
||||
void enable_deepsleep();
|
||||
void send_heartbeat(bool engaged);
|
||||
void set_can_speed_kbps(uint16_t bus, uint16_t speed);
|
||||
void set_can_fd_auto(uint16_t bus, bool enabled);
|
||||
void set_data_speed_kbps(uint16_t bus, uint16_t speed);
|
||||
void set_canfd_non_iso(uint16_t bus, bool non_iso);
|
||||
void can_send(const capnp::List<cereal::CanData>::Reader &can_data_list);
|
||||
|
||||
@@ -67,6 +67,10 @@ Panda *connect(std::string serial="", uint32_t index=0) {
|
||||
}
|
||||
//panda->enable_deepsleep();
|
||||
|
||||
for (int i = 0; i < PANDA_BUS_CNT; i++) {
|
||||
panda->set_can_fd_auto(i, true);
|
||||
}
|
||||
|
||||
if (!panda->up_to_date() && !getenv("BOARDD_SKIP_FW_CHECK")) {
|
||||
throw std::runtime_error("Panda firmware out of date. Run pandad.py to update.");
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ int PandaSpiHandle::spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint1
|
||||
// due to full TX buffers
|
||||
nack_count += 1;
|
||||
if (nack_count > 3) {
|
||||
SPILOG(LOGE, "NACK sleep %d", nack_count);
|
||||
SPILOG(LOGD, "NACK sleep %d", nack_count);
|
||||
usleep(std::clamp(nack_count*10, 200, 2000));
|
||||
}
|
||||
}
|
||||
@@ -418,7 +418,7 @@ fail:
|
||||
}
|
||||
}
|
||||
|
||||
if (ret > 0) ret = -1;
|
||||
if (ret >= 0) ret = -1;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -6,6 +6,7 @@ import cereal.messaging as messaging
|
||||
from cereal import log
|
||||
from openpilot.common.gpio import gpio_set, gpio_init
|
||||
from panda import Panda, PandaDFU, PandaProtocolMismatch
|
||||
from openpilot.common.retry import retry
|
||||
from openpilot.system.manager.process_config import managed_processes
|
||||
from openpilot.system.hardware import HARDWARE
|
||||
from openpilot.system.hardware.tici.pins import GPIO
|
||||
@@ -51,6 +52,7 @@ class TestPandad:
|
||||
assert not Panda.wait_for_dfu(None, 3)
|
||||
assert not Panda.wait_for_panda(None, 3)
|
||||
|
||||
@retry(attempts=3)
|
||||
def _flash_bootstub_and_test(self, fn, expect_mismatch=False):
|
||||
self._go_to_dfu()
|
||||
pd = PandaDFU(None)
|
||||
|
||||
@@ -14,7 +14,7 @@ from openpilot.common.params import Params
|
||||
from openpilot.common.timeout import Timeout
|
||||
from openpilot.selfdrive.pandad import can_list_to_can_capnp
|
||||
from openpilot.system.hardware import TICI
|
||||
from openpilot.selfdrive.test.helpers import phone_only, with_processes
|
||||
from openpilot.selfdrive.test.helpers import with_processes
|
||||
|
||||
|
||||
@retry(attempts=3)
|
||||
@@ -72,7 +72,6 @@ class TestBoarddLoopback:
|
||||
os.environ['STARTED'] = '1'
|
||||
os.environ['BOARDD_LOOPBACK'] = '1'
|
||||
|
||||
@phone_only
|
||||
@with_processes(['pandad'])
|
||||
def test_loopback(self):
|
||||
num_pandas = 2 if TICI and "SINGLE_PANDA" not in os.environ else 1
|
||||
|
||||
@@ -7,7 +7,7 @@ import random
|
||||
import cereal.messaging as messaging
|
||||
from cereal.services import SERVICE_LIST
|
||||
from openpilot.system.hardware import HARDWARE
|
||||
from openpilot.selfdrive.test.helpers import phone_only, with_processes
|
||||
from openpilot.selfdrive.test.helpers import with_processes
|
||||
from openpilot.selfdrive.pandad.tests.test_pandad_loopback import setup_pandad, send_random_can_messages
|
||||
|
||||
JUNGLE_SPAM = "JUNGLE_SPAM" in os.environ
|
||||
@@ -23,7 +23,6 @@ class TestBoarddSpi:
|
||||
if not JUNGLE_SPAM:
|
||||
os.environ['BOARDD_LOOPBACK'] = '1'
|
||||
|
||||
@phone_only
|
||||
@with_processes(['pandad'])
|
||||
def test_spi_corruption(self, subtests):
|
||||
setup_pandad(1)
|
||||
|
||||
@@ -42,7 +42,7 @@ class TestAlerts:
|
||||
|
||||
for name, e in events.items():
|
||||
if not name.endswith("DEPRECATED"):
|
||||
fail_msg = "%s @%d not in EVENTS" % (name, e)
|
||||
fail_msg = f"{name} @{e} not in EVENTS"
|
||||
assert e in EVENTS.keys(), fail_msg
|
||||
|
||||
# ensure alert text doesn't exceed allowed width
|
||||
|
||||
@@ -10,7 +10,6 @@ from functools import wraps
|
||||
import cereal.messaging as messaging
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.system.manager.process_config import managed_processes
|
||||
from openpilot.system.hardware import PC
|
||||
from openpilot.system.version import training_version, terms_version
|
||||
|
||||
|
||||
@@ -29,14 +28,6 @@ def set_params_enabled():
|
||||
msg.liveCalibration.rpyCalib = [0.0, 0.0, 0.0]
|
||||
params.put("CalibrationParams", msg.to_bytes())
|
||||
|
||||
def phone_only(f):
|
||||
@wraps(f)
|
||||
def wrap(self, *args, **kwargs):
|
||||
if PC:
|
||||
pytest.skip("This test is not meant to run on PC")
|
||||
return f(self, *args, **kwargs)
|
||||
return wrap
|
||||
|
||||
def release_only(f):
|
||||
@wraps(f)
|
||||
def wrap(self, *args, **kwargs):
|
||||
|
||||
@@ -7,19 +7,20 @@ import tempfile
|
||||
from itertools import zip_longest
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
from openpilot.common.git import get_commit
|
||||
from openpilot.system.hardware import PC
|
||||
from openpilot.tools.lib.openpilotci import get_url
|
||||
from openpilot.selfdrive.test.process_replay.compare_logs import compare_logs, format_diff
|
||||
from openpilot.selfdrive.test.process_replay.process_replay import get_process_config, replay_process
|
||||
from openpilot.tools.lib.framereader import FrameReader
|
||||
from openpilot.tools.lib.framereader import FrameReader, NumpyFrameReader
|
||||
from openpilot.tools.lib.logreader import LogReader, save_log
|
||||
from openpilot.tools.lib.github_utils import GithubUtils
|
||||
|
||||
TEST_ROUTE = "2f4452b03ccb98f0|2022-12-03--13-45-30"
|
||||
SEGMENT = 6
|
||||
MAX_FRAMES = 100 if PC else 600
|
||||
MAX_FRAMES = 100 if PC else 400
|
||||
|
||||
NO_MODEL = "NO_MODEL" in os.environ
|
||||
SEND_EXTRA_INPUTS = bool(int(os.getenv("SEND_EXTRA_INPUTS", "0")))
|
||||
@@ -31,14 +32,14 @@ GITHUB = GithubUtils(API_TOKEN, DATA_TOKEN)
|
||||
|
||||
|
||||
def get_log_fn(test_route, ref="master"):
|
||||
return f"{test_route}_model_tici_{ref}.bz2"
|
||||
return f"{test_route}_model_tici_{ref}.zst"
|
||||
|
||||
def plot(proposed, master, title, tmp):
|
||||
proposed = list(proposed)
|
||||
master = list(master)
|
||||
fig, ax = plt.subplots()
|
||||
ax.plot(proposed, label='PROPOSED')
|
||||
ax.plot(master, label='MASTER')
|
||||
ax.plot(proposed, label='PROPOSED')
|
||||
plt.legend(loc='best')
|
||||
plt.title(title)
|
||||
plt.savefig(f'{tmp}/{title}.png')
|
||||
@@ -151,21 +152,44 @@ def model_replay(lr, frs):
|
||||
dmonitoringmodeld = get_process_config("dmonitoringmodeld")
|
||||
|
||||
modeld_msgs = replay_process(modeld, modeld_logs, frs)
|
||||
if isinstance(frs['roadCameraState'], NumpyFrameReader):
|
||||
del frs['roadCameraState'].frames
|
||||
del frs['wideRoadCameraState'].frames
|
||||
dmonitoringmodeld_msgs = replay_process(dmonitoringmodeld, dmodeld_logs, frs)
|
||||
return modeld_msgs + dmonitoringmodeld_msgs
|
||||
|
||||
|
||||
def get_frames():
|
||||
regen_cache = "--regen-cache" in sys.argv
|
||||
cache = "--cache" in sys.argv or not PC or regen_cache
|
||||
videos = ('fcamera.hevc', 'dcamera.hevc', 'ecamera.hevc')
|
||||
cams = ('roadCameraState', 'driverCameraState', 'wideRoadCameraState')
|
||||
|
||||
if cache:
|
||||
frames_cache = '/tmp/model_replay_cache' if PC else '/data/model_replay_cache'
|
||||
os.makedirs(frames_cache, exist_ok=True)
|
||||
|
||||
cache_size = 200
|
||||
for v in videos:
|
||||
if not all(os.path.isfile(f'{frames_cache}/{TEST_ROUTE}_{v}_{i}.npy') for i in range(MAX_FRAMES//cache_size)) or regen_cache:
|
||||
f = FrameReader(get_url(TEST_ROUTE, SEGMENT, v)).get(0, MAX_FRAMES + 1, pix_fmt="nv12")
|
||||
print(f'Caching {v}...')
|
||||
for i in range(MAX_FRAMES//cache_size):
|
||||
np.save(f'{frames_cache}/{TEST_ROUTE}_{v}_{i}', f[(i * cache_size) + 1:((i + 1) * cache_size) + 1])
|
||||
del f
|
||||
|
||||
return {c : NumpyFrameReader(f"{frames_cache}/{TEST_ROUTE}_{v}", 1928, 1208, cache_size) for c,v in zip(cams, videos, strict=True)}
|
||||
else:
|
||||
return {c : FrameReader(get_url(TEST_ROUTE, SEGMENT, v), readahead=True) for c,v in zip(cams, videos, strict=True)}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
update = "--update" in sys.argv or (os.getenv("GIT_BRANCH", "") == 'master')
|
||||
replay_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# load logs
|
||||
lr = list(LogReader(get_url(TEST_ROUTE, SEGMENT, "rlog.bz2")))
|
||||
frs = {
|
||||
'roadCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, "fcamera.hevc"), readahead=True),
|
||||
'driverCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, "dcamera.hevc"), readahead=True),
|
||||
'wideRoadCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, "ecamera.hevc"), readahead=True)
|
||||
}
|
||||
lr = list(LogReader(get_url(TEST_ROUTE, SEGMENT, "rlog.zst")))
|
||||
frs = get_frames()
|
||||
|
||||
log_msgs = []
|
||||
# run replays
|
||||
|
||||
@@ -5,13 +5,13 @@ import copy
|
||||
import json
|
||||
import heapq
|
||||
import signal
|
||||
import platform
|
||||
from collections import Counter, OrderedDict
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any
|
||||
from collections.abc import Callable, Iterable
|
||||
from tqdm import tqdm
|
||||
import capnp
|
||||
from openpilot.system.hardware.hw import Paths
|
||||
|
||||
import cereal.messaging as messaging
|
||||
from cereal import car
|
||||
@@ -780,8 +780,7 @@ def generate_params_config(lr=None, CP=None, fingerprint=None, custom_params=Non
|
||||
|
||||
def generate_environ_config(CP=None, fingerprint=None, log_dir=None) -> dict[str, Any]:
|
||||
environ_dict = {}
|
||||
if platform.system() != "Darwin":
|
||||
environ_dict["PARAMS_ROOT"] = "/dev/shm/params"
|
||||
environ_dict["PARAMS_ROOT"] = f"{Paths.shm_path()}/params"
|
||||
if log_dir is not None:
|
||||
environ_dict["LOG_ROOT"] = log_dir
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
2fc2e865ab77fd8145feab86d454f2111c5d9871
|
||||
255ceb08c75bc85379da5ec247e612be3716fb43
|
||||
|
||||
@@ -72,7 +72,7 @@ PROCS = {
|
||||
|
||||
PROCS.update({
|
||||
"tici": {
|
||||
"./pandad": 4.0,
|
||||
"./pandad": 5.0,
|
||||
"./ubloxd": 1.0,
|
||||
"system.ubloxd.pigeond": 6.0,
|
||||
},
|
||||
@@ -138,6 +138,7 @@ class TestOnroad:
|
||||
proc = None
|
||||
try:
|
||||
manager_path = os.path.join(BASEDIR, "system/manager/manager.py")
|
||||
cls.manager_st = time.monotonic()
|
||||
proc = subprocess.Popen(["python", manager_path])
|
||||
|
||||
sm = messaging.SubMaster(['carState'])
|
||||
@@ -202,6 +203,10 @@ class TestOnroad:
|
||||
with subtests.test(service=s):
|
||||
assert len(msgs) >= math.floor(SERVICE_LIST[s].frequency*int(TEST_DURATION*0.8))
|
||||
|
||||
def test_manager_starting_time(self):
|
||||
st = self.msgs['managerState'][0].logMonoTime / 1e9
|
||||
assert (st - self.manager_st) < 10, f"manager.py took {st - self.manager_st}s to publish the first 'managerState' msg"
|
||||
|
||||
def test_cloudlog_size(self):
|
||||
msgs = self.msgs['logMessage']
|
||||
|
||||
@@ -295,13 +300,18 @@ class TestOnroad:
|
||||
assert cpu_ok
|
||||
|
||||
def test_memory_usage(self):
|
||||
print("\n------------------------------------------------")
|
||||
print("--------------- Memory Usage -------------------")
|
||||
print("------------------------------------------------")
|
||||
offset = int(SERVICE_LIST['deviceState'].frequency * LOG_OFFSET)
|
||||
mems = [m.deviceState.memoryUsagePercent for m in self.msgs['deviceState'][offset:]]
|
||||
print("Memory usage: ", mems)
|
||||
|
||||
# check for big leaks. note that memory usage is
|
||||
# expected to go up while the MSGQ buffers fill up
|
||||
assert max(mems) - min(mems) <= 3.0
|
||||
assert np.average(mems) <= 65, "Average memory usage above 65%"
|
||||
assert np.max(np.diff(mems)) <= 4, "Max memory increase too high"
|
||||
assert np.average(np.diff(mems)) <= 1, "Average memory increase too high"
|
||||
|
||||
def test_gpu_usage(self):
|
||||
assert self.gpu_procs == {"weston", "ui", "camerad", "selfdrive.modeld.modeld", "selfdrive.modeld.dmonitoringmodeld"}
|
||||
|
||||
@@ -110,5 +110,3 @@ if GetOption('extras') and arch != "Darwin":
|
||||
# build watch3
|
||||
if arch in ['x86_64', 'aarch64', 'Darwin'] or GetOption('extras'):
|
||||
qt_env.Program("watch3", ["watch3.cc"], LIBS=qt_libs + ['common', 'msgq', 'visionipc'])
|
||||
|
||||
SConscript(['raylib/SConscript'])
|
||||
|
||||
@@ -124,6 +124,7 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) {
|
||||
// left: PrimeAdWidget
|
||||
QStackedWidget *left_widget = new QStackedWidget(this);
|
||||
QVBoxLayout *left_prime_layout = new QVBoxLayout();
|
||||
left_prime_layout->setContentsMargins(0, 0, 0, 0);
|
||||
QWidget *prime_user = new PrimeUserWidget();
|
||||
prime_user->setStyleSheet(R"(
|
||||
border-radius: 10px;
|
||||
|
||||
@@ -408,7 +408,7 @@ Setup::Setup(QWidget *parent) : QStackedWidget(parent) {
|
||||
std::stringstream buffer;
|
||||
buffer << std::ifstream("/sys/class/hwmon/hwmon1/in1_input").rdbuf();
|
||||
float voltage = (float)std::atoi(buffer.str().c_str()) / 1000.;
|
||||
if (voltage > 0 && voltage < 7) {
|
||||
if (voltage < 7) {
|
||||
addWidget(low_voltage());
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
_spinner
|
||||
@@ -1,17 +0,0 @@
|
||||
Import('env', 'arch', 'common')
|
||||
|
||||
raylib_env = env.Clone()
|
||||
raylib_util_lib = env.Library("raylib_util_lib", ['util.cc'], LIBS='raylib')
|
||||
linked_libs = ['raylib', raylib_util_lib, common]
|
||||
raylib_env['LIBPATH'] += [f'#third_party/raylib/{arch}/']
|
||||
|
||||
mac_frameworks = []
|
||||
if arch == "Darwin":
|
||||
mac_frameworks += ['OpenCL', 'CoreVideo', 'Cocoa', 'GLUT', 'CoreFoundation', 'OpenGL', 'IOKit']
|
||||
elif arch == 'larch64':
|
||||
linked_libs += []
|
||||
else:
|
||||
linked_libs += ['OpenCL', 'dl', 'pthread']
|
||||
|
||||
if arch != 'aarch64':
|
||||
raylib_env.Program("_spinner", ["spinner.cc"], LIBS=linked_libs, FRAMEWORKS=mac_frameworks)
|
||||
+49
-38
@@ -54,6 +54,7 @@ RETRY_DELAY = 10 # seconds
|
||||
MAX_RETRY_COUNT = 30 # Try for at most 5 minutes if upload fails immediately
|
||||
MAX_AGE = 31 * 24 * 3600 # seconds
|
||||
WS_FRAME_SIZE = 4096
|
||||
DEVICE_STATE_UPDATE_INTERVAL = 1.0 # in seconds
|
||||
|
||||
NetworkType = log.DeviceState.NetworkType
|
||||
|
||||
@@ -99,9 +100,9 @@ send_queue: Queue[str] = queue.Queue()
|
||||
upload_queue: Queue[UploadItem] = queue.Queue()
|
||||
low_priority_send_queue: Queue[str] = queue.Queue()
|
||||
log_recv_queue: Queue[str] = queue.Queue()
|
||||
cancelled_uploads: set[str] = set()
|
||||
|
||||
cur_upload_items: dict[int, UploadItem | None] = {}
|
||||
cur_upload_items_lock = threading.Lock()
|
||||
|
||||
|
||||
def strip_zst_extension(fn: str) -> str:
|
||||
@@ -129,8 +130,9 @@ class UploadQueueCache:
|
||||
@staticmethod
|
||||
def cache(upload_queue: Queue[UploadItem]) -> None:
|
||||
try:
|
||||
queue: list[UploadItem | None] = list(upload_queue.queue)
|
||||
items = [asdict(i) for i in queue if i is not None and (i.id not in cancelled_uploads)]
|
||||
with upload_queue.mutex:
|
||||
items = [asdict(item) for item in upload_queue.queue]
|
||||
|
||||
Params().put("AthenadUploadQueue", json.dumps(items))
|
||||
except Exception:
|
||||
cloudlog.exception("athena.UploadQueueCache.cache.exception")
|
||||
@@ -197,10 +199,12 @@ def retry_upload(tid: int, end_event: threading.Event, increase_count: bool = Tr
|
||||
progress=0,
|
||||
current=False
|
||||
)
|
||||
upload_queue.put_nowait(item)
|
||||
UploadQueueCache.cache(upload_queue)
|
||||
|
||||
cur_upload_items[tid] = None
|
||||
with cur_upload_items_lock:
|
||||
upload_queue.put_nowait(item)
|
||||
cur_upload_items[tid] = None
|
||||
|
||||
UploadQueueCache.cache(upload_queue)
|
||||
|
||||
for _ in range(RETRY_DELAY):
|
||||
time.sleep(1)
|
||||
@@ -211,15 +215,17 @@ def retry_upload(tid: int, end_event: threading.Event, increase_count: bool = Tr
|
||||
def cb(sm, item, tid, end_event: threading.Event, sz: int, cur: int) -> None:
|
||||
# Abort transfer if connection changed to metered after starting upload
|
||||
# or if athenad is shutting down to re-connect the websocket
|
||||
sm.update(0)
|
||||
metered = sm['deviceState'].networkMetered
|
||||
if metered and (not item.allow_cellular):
|
||||
raise AbortTransferException
|
||||
if not item.allow_cellular:
|
||||
if (time.monotonic() - sm.recv_time['deviceState']) > DEVICE_STATE_UPDATE_INTERVAL:
|
||||
sm.update(0)
|
||||
if sm['deviceState'].networkMetered:
|
||||
raise AbortTransferException
|
||||
|
||||
if end_event.is_set():
|
||||
raise AbortTransferException
|
||||
|
||||
cur_upload_items[tid] = replace(item, progress=cur / sz if sz else 1)
|
||||
with cur_upload_items_lock:
|
||||
cur_upload_items[tid] = replace(item, progress=cur / sz if sz else 1)
|
||||
|
||||
|
||||
def upload_handler(end_event: threading.Event) -> None:
|
||||
@@ -227,14 +233,10 @@ def upload_handler(end_event: threading.Event) -> None:
|
||||
tid = threading.get_ident()
|
||||
|
||||
while not end_event.is_set():
|
||||
cur_upload_items[tid] = None
|
||||
|
||||
try:
|
||||
cur_upload_items[tid] = item = replace(upload_queue.get(timeout=1), current=True)
|
||||
|
||||
if item.id in cancelled_uploads:
|
||||
cancelled_uploads.remove(item.id)
|
||||
continue
|
||||
with cur_upload_items_lock:
|
||||
cur_upload_items[tid] = None
|
||||
cur_upload_items[tid] = item = replace(upload_queue.get(timeout=1), current=True)
|
||||
|
||||
# Remove item if too old
|
||||
age = datetime.now() - datetime.fromtimestamp(item.created_at / 1000)
|
||||
@@ -258,13 +260,13 @@ def upload_handler(end_event: threading.Event) -> None:
|
||||
sz = -1
|
||||
|
||||
cloudlog.event("athena.upload_handler.upload_start", fn=fn, sz=sz, network_type=network_type, metered=metered, retry_count=item.retry_count)
|
||||
response = _do_upload(item, partial(cb, sm, item, tid, end_event))
|
||||
|
||||
if response.status_code not in (200, 201, 401, 403, 412):
|
||||
cloudlog.event("athena.upload_handler.retry", status_code=response.status_code, fn=fn, sz=sz, network_type=network_type, metered=metered)
|
||||
retry_upload(tid, end_event)
|
||||
else:
|
||||
cloudlog.event("athena.upload_handler.success", fn=fn, sz=sz, network_type=network_type, metered=metered)
|
||||
with _do_upload(item, partial(cb, sm, item, tid, end_event)) as response:
|
||||
if response.status_code not in (200, 201, 401, 403, 412):
|
||||
cloudlog.event("athena.upload_handler.retry", status_code=response.status_code, fn=fn, sz=sz, network_type=network_type, metered=metered)
|
||||
retry_upload(tid, end_event)
|
||||
else:
|
||||
cloudlog.event("athena.upload_handler.success", fn=fn, sz=sz, network_type=network_type, metered=metered)
|
||||
|
||||
UploadQueueCache.cache(upload_queue)
|
||||
except (requests.exceptions.Timeout, requests.exceptions.ConnectionError, requests.exceptions.SSLError):
|
||||
@@ -309,13 +311,16 @@ def getMessage(service: str, timeout: int = 1000) -> dict:
|
||||
raise Exception("invalid service")
|
||||
|
||||
socket = messaging.sub_sock(service, timeout=timeout)
|
||||
ret = messaging.recv_one(socket)
|
||||
try:
|
||||
ret = messaging.recv_one(socket)
|
||||
|
||||
if ret is None:
|
||||
raise TimeoutError
|
||||
if ret is None:
|
||||
raise TimeoutError
|
||||
|
||||
# this is because capnp._DynamicStructReader doesn't have typing information
|
||||
return cast(dict, ret.to_dict())
|
||||
# this is because capnp._DynamicStructReader doesn't have typing information
|
||||
return cast(dict, ret.to_dict())
|
||||
finally:
|
||||
del socket
|
||||
|
||||
|
||||
@dispatcher.add_method
|
||||
@@ -410,8 +415,10 @@ def uploadFilesToUrls(files_data: list[UploadFileDict]) -> UploadFilesToUrlRespo
|
||||
|
||||
@dispatcher.add_method
|
||||
def listUploadQueue() -> list[UploadItemDict]:
|
||||
items = list(upload_queue.queue) + list(cur_upload_items.values())
|
||||
return [asdict(i) for i in items if (i is not None) and (i.id not in cancelled_uploads)]
|
||||
with cur_upload_items_lock, upload_queue.mutex:
|
||||
items = list(upload_queue.queue) + [item for item in cur_upload_items.values() if item is not None]
|
||||
|
||||
return [asdict(item) for item in items]
|
||||
|
||||
|
||||
@dispatcher.add_method
|
||||
@@ -419,13 +426,14 @@ def cancelUpload(upload_id: str | list[str]) -> dict[str, int | str]:
|
||||
if not isinstance(upload_id, list):
|
||||
upload_id = [upload_id]
|
||||
|
||||
uploading_ids = {item.id for item in list(upload_queue.queue)}
|
||||
cancelled_ids = uploading_ids.intersection(upload_id)
|
||||
if len(cancelled_ids) == 0:
|
||||
return {"success": 0, "error": "not found"}
|
||||
with upload_queue.mutex:
|
||||
remaining_items = [item for item in upload_queue.queue if item.id not in upload_id]
|
||||
if len(remaining_items) == len(upload_queue.queue):
|
||||
return {"success": 0, "error": "not found"}
|
||||
|
||||
cancelled_uploads.update(cancelled_ids)
|
||||
return {"success": 1}
|
||||
upload_queue.queue.clear()
|
||||
upload_queue.queue.extend(remaining_items)
|
||||
return {"success": 1}
|
||||
|
||||
@dispatcher.add_method
|
||||
def setRouteViewed(route: str) -> dict[str, int | str]:
|
||||
@@ -626,8 +634,9 @@ def log_handler(end_event: threading.Event) -> None:
|
||||
|
||||
def stat_handler(end_event: threading.Event) -> None:
|
||||
STATS_DIR = Paths.stats_root()
|
||||
last_scan = 0.0
|
||||
|
||||
while not end_event.is_set():
|
||||
last_scan = 0.
|
||||
curr_scan = time.monotonic()
|
||||
try:
|
||||
if curr_scan - last_scan > 10:
|
||||
@@ -801,6 +810,8 @@ def main(exit_event: threading.Event = None):
|
||||
cur_upload_items.clear()
|
||||
|
||||
handle_long_poll(ws, exit_event)
|
||||
|
||||
ws.close()
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
break
|
||||
except (ConnectionError, TimeoutError, WebSocketException):
|
||||
|
||||
@@ -78,7 +78,6 @@ class TestAthenadMethods:
|
||||
|
||||
athenad.upload_queue = queue.Queue()
|
||||
athenad.cur_upload_items.clear()
|
||||
athenad.cancelled_uploads.clear()
|
||||
|
||||
for i in os.listdir(Paths.log_root()):
|
||||
p = os.path.join(Paths.log_root(), i)
|
||||
@@ -240,7 +239,7 @@ class TestAthenadMethods:
|
||||
@with_upload_handler
|
||||
def test_upload_handler_retry(self, mocker, host, status, retry):
|
||||
mock_put = mocker.patch('requests.put')
|
||||
mock_put.return_value.status_code = status
|
||||
mock_put.return_value.__enter__.return_value.status_code = status
|
||||
fn = self._create_file('qlog.zst')
|
||||
item = athenad.UploadItem(path=fn, url=f"{host}/qlog.zst", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True)
|
||||
|
||||
@@ -282,13 +281,10 @@ class TestAthenadMethods:
|
||||
athenad.upload_queue.put_nowait(item)
|
||||
dispatcher["cancelUpload"](item.id)
|
||||
|
||||
assert item.id in athenad.cancelled_uploads
|
||||
|
||||
self._wait_for_upload()
|
||||
time.sleep(0.1)
|
||||
|
||||
assert athenad.upload_queue.qsize() == 0
|
||||
assert len(athenad.cancelled_uploads) == 0
|
||||
|
||||
@with_upload_handler
|
||||
def test_cancel_expiry(self):
|
||||
@@ -331,7 +327,7 @@ class TestAthenadMethods:
|
||||
assert items[0] == asdict(item)
|
||||
assert not items[0]['current']
|
||||
|
||||
athenad.cancelled_uploads.add(item.id)
|
||||
dispatcher["cancelUpload"](item.id)
|
||||
items = dispatcher["listUploadQueue"]()
|
||||
assert len(items) == 0
|
||||
|
||||
@@ -343,7 +339,7 @@ class TestAthenadMethods:
|
||||
athenad.upload_queue.put_nowait(item2)
|
||||
|
||||
# Ensure canceled items are not persisted
|
||||
athenad.cancelled_uploads.add(item2.id)
|
||||
dispatcher["cancelUpload"](item2.id)
|
||||
|
||||
# serialize item
|
||||
athenad.UploadQueueCache.cache(athenad.upload_queue)
|
||||
|
||||
@@ -65,16 +65,19 @@ void CameraBuf::init(cl_device_id device_id, cl_context context, SpectraCamera *
|
||||
const SensorInfo *sensor = cam->sensor.get();
|
||||
|
||||
is_raw = cam->is_raw;
|
||||
camera_bufs_raw = std::make_unique<VisionBuf[]>(frame_buf_count);
|
||||
frame_metadata = std::make_unique<FrameMetadata[]>(frame_buf_count);
|
||||
|
||||
// RAW + final frames from ISP
|
||||
const int raw_frame_size = (sensor->frame_height + sensor->extra_height) * sensor->frame_stride;
|
||||
for (int i = 0; i < frame_buf_count; i++) {
|
||||
camera_bufs_raw[i].allocate(raw_frame_size);
|
||||
camera_bufs_raw[i].init_cl(device_id, context);
|
||||
// RAW frames from ISP
|
||||
if (is_raw) {
|
||||
camera_bufs_raw = std::make_unique<VisionBuf[]>(frame_buf_count);
|
||||
|
||||
const int raw_frame_size = (sensor->frame_height + sensor->extra_height) * sensor->frame_stride;
|
||||
for (int i = 0; i < frame_buf_count; i++) {
|
||||
camera_bufs_raw[i].allocate(raw_frame_size);
|
||||
camera_bufs_raw[i].init_cl(device_id, context);
|
||||
}
|
||||
LOGD("allocated %d CL buffers", frame_buf_count);
|
||||
}
|
||||
LOGD("allocated %d CL buffers", frame_buf_count);
|
||||
|
||||
out_img_width = sensor->frame_width;
|
||||
out_img_height = sensor->hdr_offset > 0 ? (sensor->frame_height - sensor->hdr_offset) / 2 : sensor->frame_height;
|
||||
@@ -83,8 +86,8 @@ void CameraBuf::init(cl_device_id device_id, cl_context context, SpectraCamera *
|
||||
// TODO: VENUS_BUFFER_SIZE should give the size, but it's too small. dependent on encoder settings?
|
||||
size_t nv12_size = (out_img_width <= 1344 ? 2900 : 2346)*cam->stride;
|
||||
|
||||
vipc_server->create_buffers_with_sizes(stream_type, YUV_BUFFER_COUNT, out_img_width, out_img_height, nv12_size, cam->stride, cam->uv_offset);
|
||||
LOGD("created %d YUV vipc buffers with size %dx%d", YUV_BUFFER_COUNT, cam->stride, cam->y_height);
|
||||
vipc_server->create_buffers_with_sizes(stream_type, VIPC_BUFFER_COUNT, out_img_width, out_img_height, nv12_size, cam->stride, cam->uv_offset);
|
||||
LOGD("created %d YUV vipc buffers with size %dx%d", VIPC_BUFFER_COUNT, cam->stride, cam->y_height);
|
||||
|
||||
imgproc = new ImgProc(device_id, context, this, sensor, cam->cc.camera_num, cam->stride, cam->uv_offset);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "common/util.h"
|
||||
|
||||
|
||||
const int YUV_BUFFER_COUNT = 20;
|
||||
const int VIPC_BUFFER_COUNT = 18;
|
||||
|
||||
typedef struct FrameMetadata {
|
||||
uint32_t frame_id;
|
||||
|
||||
@@ -69,10 +69,10 @@ public:
|
||||
};
|
||||
|
||||
void CameraState::init(VisionIpcServer *v, cl_device_id device_id, cl_context ctx) {
|
||||
if (!camera.enabled) return;
|
||||
|
||||
camera.camera_open(v, device_id, ctx);
|
||||
|
||||
if (!camera.enabled) return;
|
||||
|
||||
fl_pix = camera.cc.focal_len / camera.sensor->pixel_size_mm;
|
||||
set_exposure_rect();
|
||||
|
||||
@@ -140,14 +140,14 @@ void CameraState::set_camera_exposure(float grey_frac) {
|
||||
// Therefore we use the target EV from 3 frames ago, the grey fraction that was just measured was the result of that control action.
|
||||
// TODO: Lower latency to 2 frames, by using the histogram outputted by the sensor we can do AE before the debayering is complete
|
||||
|
||||
const float cur_ev_ = cur_ev[camera.buf.cur_frame_data.frame_id % 3];
|
||||
const auto &sensor = camera.sensor;
|
||||
const float cur_ev_ = cur_ev[camera.buf.cur_frame_data.frame_id % 3] * sensor->ev_scale;
|
||||
|
||||
// Scale target grey between 0.1 and 0.4 depending on lighting conditions
|
||||
float new_target_grey = std::clamp(0.4 - 0.3 * log2(1.0 + sensor->target_grey_factor*cur_ev_) / log2(6000.0), 0.1, 0.4);
|
||||
float target_grey = (1.0 - k_grey) * target_grey_fraction + k_grey * new_target_grey;
|
||||
|
||||
float desired_ev = std::clamp(cur_ev_ * target_grey / grey_frac, sensor->min_ev, sensor->max_ev);
|
||||
float desired_ev = std::clamp(cur_ev_ / sensor->ev_scale * target_grey / grey_frac, sensor->min_ev, sensor->max_ev);
|
||||
float k = (1.0 - k_ev) / 3.0;
|
||||
desired_ev = (k * cur_ev[0]) + (k * cur_ev[1]) + (k * cur_ev[2]) + (k_ev * desired_ev);
|
||||
|
||||
|
||||
@@ -242,6 +242,9 @@ SpectraCamera::SpectraCamera(SpectraMaster *master, const CameraConfig &config,
|
||||
cc(config),
|
||||
is_raw(raw) {
|
||||
mm.init(m->video0_fd);
|
||||
|
||||
ife_buf_depth = is_raw ? 4 : VIPC_BUFFER_COUNT;
|
||||
assert(ife_buf_depth < MAX_IFE_BUFS);
|
||||
}
|
||||
|
||||
SpectraCamera::~SpectraCamera() {
|
||||
@@ -261,12 +264,12 @@ int SpectraCamera::clear_req_queue() {
|
||||
}
|
||||
|
||||
void SpectraCamera::camera_open(VisionIpcServer *v, cl_device_id device_id, cl_context ctx) {
|
||||
if (!enabled) return;
|
||||
|
||||
if (!openSensor()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!enabled) return;
|
||||
|
||||
// size is driven by all the HW that handles frames,
|
||||
// the video encoder has certain alignment requirements in this case
|
||||
stride = VENUS_Y_STRIDE(COLOR_FMT_NV12, sensor->frame_width);
|
||||
@@ -288,14 +291,15 @@ void SpectraCamera::camera_open(VisionIpcServer *v, cl_device_id device_id, cl_c
|
||||
linkDevices();
|
||||
|
||||
LOGD("camera init %d", cc.camera_num);
|
||||
buf.init(device_id, ctx, this, v, FRAME_BUF_COUNT, cc.stream_type);
|
||||
buf.init(device_id, ctx, this, v, ife_buf_depth, cc.stream_type);
|
||||
camera_map_bufs();
|
||||
enqueue_req_multi(1, ife_buf_depth, 0);
|
||||
}
|
||||
|
||||
void SpectraCamera::enqueue_req_multi(uint64_t start, int n, bool dp) {
|
||||
for (uint64_t i = start; i < start + n; ++i) {
|
||||
request_ids[(i - 1) % FRAME_BUF_COUNT] = i;
|
||||
enqueue_buffer((i - 1) % FRAME_BUF_COUNT, dp);
|
||||
request_ids[(i - 1) % ife_buf_depth] = i;
|
||||
enqueue_buffer((i - 1) % ife_buf_depth, dp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -670,7 +674,7 @@ void SpectraCamera::enqueue_buffer(int i, bool dp) {
|
||||
int ret;
|
||||
uint64_t request_id = request_ids[i];
|
||||
|
||||
if (buf_handle_raw[i] && sync_objs[i]) {
|
||||
if (sync_objs[i]) {
|
||||
// wait
|
||||
struct cam_sync_wait sync_wait = {0};
|
||||
sync_wait.sync_obj = sync_objs[i];
|
||||
@@ -733,31 +737,31 @@ void SpectraCamera::enqueue_buffer(int i, bool dp) {
|
||||
|
||||
void SpectraCamera::camera_map_bufs() {
|
||||
int ret;
|
||||
for (int i = 0; i < FRAME_BUF_COUNT; i++) {
|
||||
for (int i = 0; i < ife_buf_depth; i++) {
|
||||
// configure ISP to put the image in place
|
||||
struct cam_mem_mgr_map_cmd mem_mgr_map_cmd = {0};
|
||||
mem_mgr_map_cmd.flags = CAM_MEM_FLAG_HW_READ_WRITE;
|
||||
mem_mgr_map_cmd.mmu_hdls[0] = m->device_iommu;
|
||||
mem_mgr_map_cmd.num_hdl = 1;
|
||||
//mem_mgr_map_cmd.mmu_hdls[1] = m->icp_device_iommu;
|
||||
//mem_mgr_map_cmd.num_hdl = 2;
|
||||
mem_mgr_map_cmd.num_hdl = 1;
|
||||
mem_mgr_map_cmd.flags = CAM_MEM_FLAG_HW_READ_WRITE;
|
||||
|
||||
// RAW bayer images
|
||||
mem_mgr_map_cmd.fd = buf.camera_bufs_raw[i].fd;
|
||||
ret = do_cam_control(m->video0_fd, CAM_REQ_MGR_MAP_BUF, &mem_mgr_map_cmd, sizeof(mem_mgr_map_cmd));
|
||||
assert(ret == 0);
|
||||
LOGD("map buf req: (fd: %d) 0x%x %d", buf.camera_bufs_raw[i].fd, mem_mgr_map_cmd.out.buf_handle, ret);
|
||||
buf_handle_raw[i] = mem_mgr_map_cmd.out.buf_handle;
|
||||
|
||||
// TODO: this needs to match camera bufs length
|
||||
// final processed images
|
||||
VisionBuf *vb = buf.vipc_server->get_buffer(buf.stream_type, i);
|
||||
mem_mgr_map_cmd.fd = vb->fd;
|
||||
ret = do_cam_control(m->video0_fd, CAM_REQ_MGR_MAP_BUF, &mem_mgr_map_cmd, sizeof(mem_mgr_map_cmd));
|
||||
LOGD("map buf req: (fd: %d) 0x%x %d", vb->fd, mem_mgr_map_cmd.out.buf_handle, ret);
|
||||
buf_handle_yuv[i] = mem_mgr_map_cmd.out.buf_handle;
|
||||
if (is_raw) {
|
||||
// RAW bayer images
|
||||
mem_mgr_map_cmd.fd = buf.camera_bufs_raw[i].fd;
|
||||
ret = do_cam_control(m->video0_fd, CAM_REQ_MGR_MAP_BUF, &mem_mgr_map_cmd, sizeof(mem_mgr_map_cmd));
|
||||
assert(ret == 0);
|
||||
LOGD("map buf req: (fd: %d) 0x%x %d", buf.camera_bufs_raw[i].fd, mem_mgr_map_cmd.out.buf_handle, ret);
|
||||
buf_handle_raw[i] = mem_mgr_map_cmd.out.buf_handle;
|
||||
} else {
|
||||
// final processed images
|
||||
VisionBuf *vb = buf.vipc_server->get_buffer(buf.stream_type, i);
|
||||
mem_mgr_map_cmd.fd = vb->fd;
|
||||
ret = do_cam_control(m->video0_fd, CAM_REQ_MGR_MAP_BUF, &mem_mgr_map_cmd, sizeof(mem_mgr_map_cmd));
|
||||
LOGD("map buf req: (fd: %d) 0x%x %d", vb->fd, mem_mgr_map_cmd.out.buf_handle, ret);
|
||||
buf_handle_yuv[i] = mem_mgr_map_cmd.out.buf_handle;
|
||||
}
|
||||
}
|
||||
enqueue_req_multi(1, FRAME_BUF_COUNT, 0);
|
||||
}
|
||||
|
||||
bool SpectraCamera::openSensor() {
|
||||
@@ -870,7 +874,7 @@ void SpectraCamera::configISP() {
|
||||
// allocate IFE memory, then configure it
|
||||
ife_cmd.init(m, 67984, 0x20,
|
||||
CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE,
|
||||
m->device_iommu, m->cdm_iommu, FRAME_BUF_COUNT);
|
||||
m->device_iommu, m->cdm_iommu, ife_buf_depth);
|
||||
if (!is_raw) {
|
||||
ife_gamma_lut.init(m, 64*sizeof(uint32_t), 0x20,
|
||||
CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE,
|
||||
@@ -925,7 +929,7 @@ void SpectraCamera::configICP() {
|
||||
|
||||
// BPS CMD buffer
|
||||
unsigned char striping_out[] = "\x00";
|
||||
bps_cmd.init(m, FRAME_BUF_COUNT*ALIGNED_SIZE(464, 0x20), 0x20,
|
||||
bps_cmd.init(m, ife_buf_depth*ALIGNED_SIZE(464, 0x20), 0x20,
|
||||
CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE | CAM_MEM_FLAG_HW_SHARED_ACCESS,
|
||||
m->icp_device_iommu);
|
||||
|
||||
@@ -1046,9 +1050,8 @@ void SpectraCamera::camera_close() {
|
||||
ret = device_control(csiphy_fd, CAM_RELEASE_DEV, session_handle, csiphy_dev_handle);
|
||||
LOGD("release csiphy: %d", ret);
|
||||
|
||||
for (int i = 0; i < FRAME_BUF_COUNT; i++) {
|
||||
release(m->video0_fd, buf_handle_yuv[i]);
|
||||
release(m->video0_fd, buf_handle_raw[i]);
|
||||
for (int i = 0; i < ife_buf_depth; i++) {
|
||||
release(m->video0_fd, is_raw ? buf_handle_raw[i] : buf_handle_yuv[i]);
|
||||
}
|
||||
LOGD("released buffers");
|
||||
}
|
||||
@@ -1071,13 +1074,13 @@ void SpectraCamera::handle_camera_event(const cam_req_mgr_message *event_data) {
|
||||
|
||||
if (real_id != 0) { // next ready
|
||||
if (real_id == 1) {idx_offset = main_id;}
|
||||
int buf_idx = (real_id - 1) % FRAME_BUF_COUNT;
|
||||
int buf_idx = (real_id - 1) % ife_buf_depth;
|
||||
|
||||
// check for skipped frames
|
||||
if (main_id > frame_id_last + 1 && !skipped) {
|
||||
LOGE("camera %d realign", cc.camera_num);
|
||||
clear_req_queue();
|
||||
enqueue_req_multi(real_id + 1, FRAME_BUF_COUNT - 1, 0);
|
||||
enqueue_req_multi(real_id + 1, ife_buf_depth - 1, 0);
|
||||
skipped = true;
|
||||
} else if (main_id == frame_id_last + 1) {
|
||||
skipped = false;
|
||||
@@ -1086,7 +1089,7 @@ void SpectraCamera::handle_camera_event(const cam_req_mgr_message *event_data) {
|
||||
// check for dropped requests
|
||||
if (real_id > request_id_last + 1) {
|
||||
LOGE("camera %d dropped requests %ld %ld", cc.camera_num, real_id, request_id_last);
|
||||
enqueue_req_multi(request_id_last + 1 + FRAME_BUF_COUNT, real_id - (request_id_last + 1), 0);
|
||||
enqueue_req_multi(request_id_last + 1 + ife_buf_depth, real_id - (request_id_last + 1), 0);
|
||||
}
|
||||
|
||||
// metas
|
||||
@@ -1099,12 +1102,12 @@ void SpectraCamera::handle_camera_event(const cam_req_mgr_message *event_data) {
|
||||
meta_data.timestamp_sof = timestamp; // this is timestamped in the kernel's SOF IRQ callback
|
||||
|
||||
// dispatch
|
||||
enqueue_req_multi(real_id + FRAME_BUF_COUNT, 1, 1);
|
||||
enqueue_req_multi(real_id + ife_buf_depth, 1, 1);
|
||||
} else { // not ready
|
||||
if (main_id > frame_id_last + 10) {
|
||||
LOGE("camera %d reset after half second of no response", cc.camera_num);
|
||||
clear_req_queue();
|
||||
enqueue_req_multi(request_id_last + 1, FRAME_BUF_COUNT, 0);
|
||||
enqueue_req_multi(request_id_last + 1, ife_buf_depth, 0);
|
||||
frame_id_last = main_id;
|
||||
skipped = true;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "system/camerad/cameras/camera_common.h"
|
||||
#include "system/camerad/sensors/sensor.h"
|
||||
|
||||
#define FRAME_BUF_COUNT 4
|
||||
#define MAX_IFE_BUFS 20
|
||||
|
||||
const int MIPI_SETTLE_CNT = 33; // Calculated by camera_freqs.py
|
||||
|
||||
@@ -116,6 +116,7 @@ public:
|
||||
|
||||
// *** state ***
|
||||
|
||||
int ife_buf_depth = -1;
|
||||
bool open = false;
|
||||
bool enabled = true;
|
||||
CameraConfig cc;
|
||||
@@ -151,11 +152,11 @@ public:
|
||||
SpectraBuf bps_iq;
|
||||
SpectraBuf bps_striping;
|
||||
|
||||
int buf_handle_yuv[FRAME_BUF_COUNT] = {};
|
||||
int buf_handle_raw[FRAME_BUF_COUNT] = {};
|
||||
int sync_objs[FRAME_BUF_COUNT] = {};
|
||||
int sync_objs_bps_out[FRAME_BUF_COUNT] = {};
|
||||
uint64_t request_ids[FRAME_BUF_COUNT] = {};
|
||||
int buf_handle_yuv[MAX_IFE_BUFS] = {};
|
||||
int buf_handle_raw[MAX_IFE_BUFS] = {};
|
||||
int sync_objs[MAX_IFE_BUFS] = {};
|
||||
int sync_objs_bps_out[MAX_IFE_BUFS] = {};
|
||||
uint64_t request_ids[MAX_IFE_BUFS] = {};
|
||||
uint64_t request_id_last = 0;
|
||||
uint64_t frame_id_last = 0;
|
||||
uint64_t idx_offset = 0;
|
||||
|
||||
@@ -43,27 +43,28 @@ OS04C10::OS04C10() {
|
||||
frame_data_type = 0x2c;
|
||||
mclk_frequency = 24000000; // Hz
|
||||
|
||||
ev_scale = 150.0;
|
||||
dc_gain_factor = 1;
|
||||
dc_gain_min_weight = 1; // always on is fine
|
||||
dc_gain_max_weight = 1;
|
||||
dc_gain_on_grey = 0.9;
|
||||
dc_gain_off_grey = 1.0;
|
||||
exposure_time_min = 2;
|
||||
exposure_time_max = 2400;
|
||||
exposure_time_max = 1684;
|
||||
analog_gain_min_idx = 0x0;
|
||||
analog_gain_rec_idx = 0x0; // 1x
|
||||
analog_gain_max_idx = 0x36;
|
||||
analog_gain_max_idx = 0x28;
|
||||
analog_gain_cost_delta = -1;
|
||||
analog_gain_cost_low = 0.4;
|
||||
analog_gain_cost_high = 6.4;
|
||||
for (int i = 0; i <= analog_gain_max_idx; i++) {
|
||||
sensor_analog_gains[i] = sensor_analog_gains_OS04C10[i];
|
||||
}
|
||||
min_ev = (exposure_time_min) * sensor_analog_gains[analog_gain_min_idx];
|
||||
min_ev = exposure_time_min * sensor_analog_gains[analog_gain_min_idx];
|
||||
max_ev = exposure_time_max * dc_gain_factor * sensor_analog_gains[analog_gain_max_idx];
|
||||
target_grey_factor = 0.01;
|
||||
|
||||
black_level = 64;
|
||||
black_level = 48;
|
||||
color_correct_matrix = {
|
||||
0x000000c2, 0x00000fe0, 0x00000fde,
|
||||
0x00000fa7, 0x000000d9, 0x00001000,
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
#define BIT_DEPTH 12
|
||||
#define PV_MAX10 1023
|
||||
#define PV_MAX12 4096
|
||||
#define PV_MAX12 4095
|
||||
#define PV_MAX16 65536 // gamma curve is calibrated to 16bit
|
||||
#define BLACK_LVL 64
|
||||
#define BLACK_LVL 48
|
||||
#define VIGNETTE_RSZ 2.2545f
|
||||
|
||||
float combine_dual_pvs(float lv, float sv, int expo_time) {
|
||||
|
||||
@@ -42,21 +42,21 @@ const struct i2c_random_wr_payload init_array_os04c10[] = {
|
||||
{0x3691, 0x0d},
|
||||
{0x3696, 0x4c},
|
||||
{0x3697, 0x4c},
|
||||
{0x3698, 0x40},
|
||||
{0x3698, 0x00},
|
||||
{0x3699, 0x80},
|
||||
{0x369a, 0x18},
|
||||
{0x369a, 0x80},
|
||||
{0x369b, 0x1f},
|
||||
{0x369c, 0x14},
|
||||
{0x369c, 0x1f},
|
||||
{0x369d, 0x80},
|
||||
{0x369e, 0x40},
|
||||
{0x369f, 0x21},
|
||||
{0x36a0, 0x12},
|
||||
{0x36a1, 0x5d},
|
||||
{0x36a1, 0xdd},
|
||||
{0x36a2, 0x66},
|
||||
{0x370a, 0x02},
|
||||
{0x370e, 0x0c},
|
||||
{0x370e, 0x00},
|
||||
{0x3710, 0x00},
|
||||
{0x3713, 0x00},
|
||||
{0x3713, 0x04},
|
||||
{0x3725, 0x02},
|
||||
{0x372a, 0x03},
|
||||
{0x3738, 0xce},
|
||||
@@ -81,11 +81,11 @@ const struct i2c_random_wr_payload init_array_os04c10[] = {
|
||||
{0x37ba, 0x03},
|
||||
{0x37bb, 0x00},
|
||||
{0x37bc, 0x04},
|
||||
{0x37be, 0x08},
|
||||
{0x37be, 0x26},
|
||||
{0x37c4, 0x11},
|
||||
{0x37c5, 0x80},
|
||||
{0x37c6, 0x14},
|
||||
{0x37c7, 0x08},
|
||||
{0x37c7, 0xa8},
|
||||
{0x37da, 0x11},
|
||||
{0x381f, 0x08},
|
||||
// {0x3829, 0x03},
|
||||
@@ -186,10 +186,10 @@ const struct i2c_random_wr_payload init_array_os04c10[] = {
|
||||
{0x3661, 0x04},
|
||||
{0x3664, 0x70},
|
||||
{0x3665, 0x00},
|
||||
{0x3681, 0xa6},
|
||||
{0x3682, 0x53},
|
||||
{0x3683, 0x2a},
|
||||
{0x3684, 0x15},
|
||||
{0x3681, 0x80},
|
||||
{0x3682, 0x40},
|
||||
{0x3683, 0x21},
|
||||
{0x3684, 0x12},
|
||||
{0x3700, 0x2a},
|
||||
{0x3701, 0x12},
|
||||
{0x3703, 0x28},
|
||||
@@ -198,7 +198,7 @@ const struct i2c_random_wr_payload init_array_os04c10[] = {
|
||||
{0x3709, 0x4a},
|
||||
{0x370b, 0x48},
|
||||
{0x370c, 0x01},
|
||||
{0x370f, 0x04},
|
||||
{0x370f, 0x00},
|
||||
{0x3714, 0x28},
|
||||
{0x3716, 0x04},
|
||||
{0x3719, 0x11},
|
||||
@@ -278,12 +278,12 @@ const struct i2c_random_wr_payload init_array_os04c10[] = {
|
||||
{0x3816, 0x03},
|
||||
{0x3817, 0x01},
|
||||
|
||||
{0x380c, 0x08}, {0x380d, 0x5c}, // HTS
|
||||
{0x380e, 0x09}, {0x380f, 0x38}, // VTS
|
||||
{0x380c, 0x0b}, {0x380d, 0xac}, // HTS
|
||||
{0x380e, 0x06}, {0x380f, 0x9c}, // VTS
|
||||
|
||||
{0x3820, 0xb3},
|
||||
{0x3821, 0x01},
|
||||
{0x3880, 0x25},
|
||||
{0x3880, 0x00},
|
||||
{0x3882, 0x20},
|
||||
{0x3c91, 0x0b},
|
||||
{0x3c94, 0x45},
|
||||
@@ -291,7 +291,7 @@ const struct i2c_random_wr_payload init_array_os04c10[] = {
|
||||
{0x3cae, 0x00},
|
||||
{0x4000, 0xf3},
|
||||
{0x4001, 0x60},
|
||||
{0x4003, 0x80},
|
||||
{0x4003, 0x40},
|
||||
{0x4300, 0xff},
|
||||
{0x4302, 0x0f},
|
||||
{0x4305, 0x83},
|
||||
@@ -307,7 +307,6 @@ const struct i2c_random_wr_payload init_array_os04c10[] = {
|
||||
// {0x0100, 0x01},
|
||||
// {0x320d, 0x00},
|
||||
// {0x3208, 0xa0},
|
||||
{0x3822, 0x14},
|
||||
|
||||
// initialize exposure
|
||||
{0x3503, 0x88},
|
||||
|
||||
@@ -43,6 +43,7 @@ public:
|
||||
float dc_gain_on_grey;
|
||||
float dc_gain_off_grey;
|
||||
|
||||
float ev_scale = 1.0;
|
||||
float sensor_analog_gains[ANALOG_GAIN_MAX_CNT];
|
||||
int analog_gain_min_idx;
|
||||
int analog_gain_max_idx;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import pytest
|
||||
import time
|
||||
import numpy as np
|
||||
from flaky import flaky
|
||||
from collections import defaultdict
|
||||
|
||||
import cereal.messaging as messaging
|
||||
from cereal import log
|
||||
from cereal.services import SERVICE_LIST
|
||||
from openpilot.common.retry import retry
|
||||
from openpilot.system.manager.process_config import managed_processes
|
||||
|
||||
TEST_TIMESPAN = 10
|
||||
@@ -17,44 +17,46 @@ FRAME_DELTA_TOLERANCE = {log.FrameData.ImageSensor.ar0231: 1.0,
|
||||
|
||||
CAMERAS = ('roadCameraState', 'driverCameraState', 'wideRoadCameraState')
|
||||
|
||||
# TODO: this shouldn't be needed
|
||||
@flaky(max_runs=3)
|
||||
@retry(attempts=3, delay=5.0)
|
||||
def setup_camerad(cls):
|
||||
# run camerad and record logs
|
||||
managed_processes['camerad'].start()
|
||||
time.sleep(3)
|
||||
socks = {c: messaging.sub_sock(c, conflate=False, timeout=100) for c in CAMERAS}
|
||||
|
||||
cls.logs = defaultdict(list)
|
||||
start_time = time.monotonic()
|
||||
while time.monotonic()- start_time < TEST_TIMESPAN:
|
||||
for cam, s in socks.items():
|
||||
cls.logs[cam] += messaging.drain_sock(s)
|
||||
time.sleep(0.2)
|
||||
managed_processes['camerad'].stop()
|
||||
|
||||
cls.log_by_frame_id = defaultdict(list)
|
||||
cls.sensor_type = None
|
||||
for cam, msgs in cls.logs.items():
|
||||
if cls.sensor_type is None:
|
||||
cls.sensor_type = getattr(msgs[0], msgs[0].which()).sensor.raw
|
||||
expected_frames = SERVICE_LIST[cam].frequency * TEST_TIMESPAN
|
||||
assert expected_frames*0.95 < len(msgs) < expected_frames*1.05, f"unexpected frame count {cam}: {expected_frames=}, got {len(msgs)}"
|
||||
|
||||
dts = np.abs(np.diff([getattr(m, m.which()).timestampSof/1e6 for m in msgs]) - 1000/SERVICE_LIST[cam].frequency)
|
||||
assert (dts < FRAME_DELTA_TOLERANCE[cls.sensor_type]).all(), f"{cam} dts(ms) out of spec: max diff {dts.max()}, 99 percentile {np.percentile(dts, 99)}"
|
||||
|
||||
for m in msgs:
|
||||
cls.log_by_frame_id[getattr(m, m.which()).frameId].append(m)
|
||||
|
||||
# strip beginning and end
|
||||
for _ in range(3):
|
||||
mn, mx = min(cls.log_by_frame_id.keys()), max(cls.log_by_frame_id.keys())
|
||||
del cls.log_by_frame_id[mn]
|
||||
del cls.log_by_frame_id[mx]
|
||||
|
||||
@pytest.mark.tici
|
||||
class TestCamerad:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
# run camerad and record logs
|
||||
managed_processes['camerad'].start()
|
||||
time.sleep(3)
|
||||
socks = {c: messaging.sub_sock(c, conflate=False, timeout=100) for c in CAMERAS}
|
||||
|
||||
cls.logs = defaultdict(list)
|
||||
start_time = time.monotonic()
|
||||
while time.monotonic()- start_time < TEST_TIMESPAN:
|
||||
for cam, s in socks.items():
|
||||
cls.logs[cam] += messaging.drain_sock(s)
|
||||
time.sleep(0.2)
|
||||
managed_processes['camerad'].stop()
|
||||
|
||||
cls.log_by_frame_id = defaultdict(list)
|
||||
cls.sensor_type = None
|
||||
for cam, msgs in cls.logs.items():
|
||||
if cls.sensor_type is None:
|
||||
cls.sensor_type = getattr(msgs[0], msgs[0].which()).sensor.raw
|
||||
expected_frames = SERVICE_LIST[cam].frequency * TEST_TIMESPAN
|
||||
assert expected_frames*0.95 < len(msgs) < expected_frames*1.05, f"unexpected frame count {cam}: {expected_frames=}, got {len(msgs)}"
|
||||
|
||||
dts = np.abs(np.diff([getattr(m, m.which()).timestampSof/1e6 for m in msgs]) - 1000/SERVICE_LIST[cam].frequency)
|
||||
assert (dts < FRAME_DELTA_TOLERANCE[cls.sensor_type]).all(), f"{cam} dts(ms) out of spec: max diff {dts.max()}, 99 percentile {np.percentile(dts, 99)}"
|
||||
|
||||
for m in msgs:
|
||||
cls.log_by_frame_id[getattr(m, m.which()).frameId].append(m)
|
||||
|
||||
# strip beginning and end
|
||||
for _ in range(3):
|
||||
mn, mx = min(cls.log_by_frame_id.keys()), max(cls.log_by_frame_id.keys())
|
||||
del cls.log_by_frame_id[mn]
|
||||
del cls.log_by_frame_id[mx]
|
||||
setup_camerad(cls)
|
||||
|
||||
def test_frame_skips(self):
|
||||
skips = {}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import time
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from openpilot.selfdrive.test.helpers import with_processes, phone_only
|
||||
from openpilot.selfdrive.test.helpers import with_processes
|
||||
from openpilot.system.camerad.snapshot.snapshot import get_snapshots
|
||||
|
||||
TEST_TIME = 45
|
||||
REPEAT = 5
|
||||
|
||||
@pytest.mark.tici
|
||||
class TestCamerad:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
@@ -28,7 +30,6 @@ class TestCamerad:
|
||||
print([i_median, i_mean])
|
||||
return med_ex[0] < i_median < med_ex[1] and mean_ex[0] < i_mean < mean_ex[1]
|
||||
|
||||
@phone_only
|
||||
@with_processes(['camerad'])
|
||||
def test_camera_operation(self):
|
||||
passed = 0
|
||||
|
||||
+46
-7
@@ -1,11 +1,54 @@
|
||||
import os
|
||||
from abc import abstractmethod, ABC
|
||||
from collections import namedtuple
|
||||
from dataclasses import dataclass, fields
|
||||
|
||||
from cereal import log
|
||||
|
||||
ThermalConfig = namedtuple('ThermalConfig', ['cpu', 'gpu', 'mem', 'bat', 'pmic'])
|
||||
NetworkType = log.DeviceState.NetworkType
|
||||
|
||||
@dataclass
|
||||
class ThermalZone:
|
||||
# a zone from /sys/class/thermal/thermal_zone*
|
||||
name: str # a.k.a type
|
||||
scale: float = 1000. # scale to get degrees in C
|
||||
zone_number = -1
|
||||
|
||||
def read(self) -> float:
|
||||
if self.zone_number < 0:
|
||||
for n in os.listdir("/sys/devices/virtual/thermal"):
|
||||
if not n.startswith("thermal_zone"):
|
||||
continue
|
||||
with open(os.path.join("/sys/devices/virtual/thermal", n, "type")) as f:
|
||||
if f.read().strip() == self.name:
|
||||
self.zone_number = int(n.removeprefix("thermal_zone"))
|
||||
break
|
||||
|
||||
try:
|
||||
with open(f"/sys/devices/virtual/thermal/thermal_zone{self.zone_number}/temp") as f:
|
||||
return int(f.read()) / self.scale
|
||||
except FileNotFoundError:
|
||||
return 0
|
||||
|
||||
@dataclass
|
||||
class ThermalConfig:
|
||||
cpu: list[ThermalZone] | None = None
|
||||
gpu: list[ThermalZone] | None = None
|
||||
pmic: list[ThermalZone] | None = None
|
||||
memory: ThermalZone | None = None
|
||||
intake: ThermalZone | None = None
|
||||
exhaust: ThermalZone | None = None
|
||||
case: ThermalZone | None = None
|
||||
|
||||
def get_msg(self):
|
||||
ret = {}
|
||||
for f in fields(ThermalConfig):
|
||||
v = getattr(self, f.name)
|
||||
if v is not None:
|
||||
if isinstance(v, list):
|
||||
ret[f.name + "TempC"] = [x.read() for x in v]
|
||||
else:
|
||||
ret[f.name + "TempC"] = v.read()
|
||||
return ret
|
||||
|
||||
class HardwareBase(ABC):
|
||||
@staticmethod
|
||||
@@ -84,9 +127,8 @@ class HardwareBase(ABC):
|
||||
def shutdown(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_thermal_config(self):
|
||||
pass
|
||||
return ThermalConfig()
|
||||
|
||||
@abstractmethod
|
||||
def set_screen_brightness(self, percentage):
|
||||
@@ -107,9 +149,6 @@ class HardwareBase(ABC):
|
||||
def get_modem_version(self):
|
||||
return None
|
||||
|
||||
def get_modem_nv(self):
|
||||
return None
|
||||
|
||||
@abstractmethod
|
||||
def get_modem_temperatures(self):
|
||||
pass
|
||||
|
||||
@@ -51,39 +51,6 @@ OFFROAD_DANGER_TEMP = 75
|
||||
|
||||
prev_offroad_states: dict[str, tuple[bool, str | None]] = {}
|
||||
|
||||
tz_by_type: dict[str, int] | None = None
|
||||
def populate_tz_by_type():
|
||||
global tz_by_type
|
||||
tz_by_type = {}
|
||||
for n in os.listdir("/sys/devices/virtual/thermal"):
|
||||
if not n.startswith("thermal_zone"):
|
||||
continue
|
||||
with open(os.path.join("/sys/devices/virtual/thermal", n, "type")) as f:
|
||||
tz_by_type[f.read().strip()] = int(n.removeprefix("thermal_zone"))
|
||||
|
||||
def read_tz(x):
|
||||
if x is None:
|
||||
return 0
|
||||
|
||||
if isinstance(x, str):
|
||||
if tz_by_type is None:
|
||||
populate_tz_by_type()
|
||||
x = tz_by_type[x]
|
||||
|
||||
try:
|
||||
with open(f"/sys/devices/virtual/thermal/thermal_zone{x}/temp") as f:
|
||||
return int(f.read())
|
||||
except FileNotFoundError:
|
||||
return 0
|
||||
|
||||
|
||||
def read_thermal(thermal_config):
|
||||
dat = messaging.new_message('deviceState', valid=True)
|
||||
dat.deviceState.cpuTempC = [read_tz(z) / thermal_config.cpu[1] for z in thermal_config.cpu[0]]
|
||||
dat.deviceState.gpuTempC = [read_tz(z) / thermal_config.gpu[1] for z in thermal_config.gpu[0]]
|
||||
dat.deviceState.memoryTempC = read_tz(thermal_config.mem[0]) / thermal_config.mem[1]
|
||||
dat.deviceState.pmicTempC = [read_tz(z) / thermal_config.pmic[1] for z in thermal_config.pmic[0]]
|
||||
return dat
|
||||
|
||||
|
||||
def set_offroad_alert_if_changed(offroad_alert: str, show_alert: bool, extra_text: str | None=None):
|
||||
@@ -99,7 +66,6 @@ def hw_state_thread(end_event, hw_queue):
|
||||
prev_hw_state = None
|
||||
|
||||
modem_version = None
|
||||
modem_nv = None
|
||||
modem_configured = False
|
||||
modem_restarted = False
|
||||
modem_missing_count = 0
|
||||
@@ -114,12 +80,11 @@ def hw_state_thread(end_event, hw_queue):
|
||||
modem_temps = prev_hw_state.modem_temps
|
||||
|
||||
# Log modem version once
|
||||
if AGNOS and ((modem_version is None) or (modem_nv is None)):
|
||||
if AGNOS and (modem_version is None):
|
||||
modem_version = HARDWARE.get_modem_version()
|
||||
modem_nv = HARDWARE.get_modem_nv()
|
||||
|
||||
if (modem_version is not None) and (modem_nv is not None):
|
||||
cloudlog.event("modem version", version=modem_version, nv=modem_nv)
|
||||
if modem_version is not None:
|
||||
cloudlog.event("modem version", version=modem_version)
|
||||
else:
|
||||
if not modem_restarted:
|
||||
# TODO: we may be able to remove this with a MM update
|
||||
@@ -234,7 +199,8 @@ def hardware_thread(end_event, hw_queue) -> None:
|
||||
if (sm.frame % round(SERVICE_LIST['pandaStates'].frequency * DT_HW) != 0) and not ign_edge:
|
||||
continue
|
||||
|
||||
msg = read_thermal(thermal_config)
|
||||
msg = messaging.new_message('deviceState', valid=True)
|
||||
msg.deviceState = thermal_config.get_msg()
|
||||
msg.deviceState.deviceType = HARDWARE.get_device_type()
|
||||
|
||||
try:
|
||||
@@ -264,13 +230,13 @@ def hardware_thread(end_event, hw_queue) -> None:
|
||||
# this subset is only used for offroad
|
||||
temp_sources = [
|
||||
msg.deviceState.memoryTempC,
|
||||
max(msg.deviceState.cpuTempC),
|
||||
max(msg.deviceState.gpuTempC),
|
||||
max(msg.deviceState.cpuTempC, default=0.),
|
||||
max(msg.deviceState.gpuTempC, default=0.),
|
||||
]
|
||||
offroad_comp_temp = offroad_temp_filter.update(max(temp_sources))
|
||||
|
||||
# this drives the thermal status while onroad
|
||||
temp_sources.append(max(msg.deviceState.pmicTempC))
|
||||
temp_sources.append(max(msg.deviceState.pmicTempC, default=0.))
|
||||
all_comp_temp = all_temp_filter.update(max(temp_sources))
|
||||
msg.deviceState.maxTempC = all_comp_temp
|
||||
|
||||
|
||||
@@ -47,4 +47,12 @@ namespace Path {
|
||||
}
|
||||
return "/tmp/comma_download_cache" + Path::openpilot_prefix() + "/";
|
||||
}
|
||||
|
||||
inline std::string shm_path() {
|
||||
#ifdef __APPLE__
|
||||
return"/tmp";
|
||||
#else
|
||||
return "/dev/shm";
|
||||
#endif
|
||||
}
|
||||
} // namespace Path
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import os
|
||||
import platform
|
||||
from pathlib import Path
|
||||
|
||||
from openpilot.system.hardware import PC
|
||||
@@ -56,3 +57,9 @@ class Paths:
|
||||
return Paths.comma_home()
|
||||
else:
|
||||
return "/tmp/.comma"
|
||||
|
||||
@staticmethod
|
||||
def shm_path() -> str:
|
||||
if PC and platform.system() == "Darwin":
|
||||
return "/tmp" # This is not really shared memory on macOS, but it's the closest we can get
|
||||
return "/dev/shm"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import random
|
||||
|
||||
from cereal import log
|
||||
from openpilot.system.hardware.base import HardwareBase, ThermalConfig
|
||||
from openpilot.system.hardware.base import HardwareBase
|
||||
|
||||
NetworkType = log.DeviceState.NetworkType
|
||||
NetworkStrength = log.DeviceState.NetworkStrength
|
||||
@@ -21,7 +21,7 @@ class Pc(HardwareBase):
|
||||
print("uninstall")
|
||||
|
||||
def get_imei(self, slot):
|
||||
return "%015d" % random.randint(0, 1 << 32)
|
||||
return f"{random.randint(0, 1 << 32):015d}"
|
||||
|
||||
def get_serial(self):
|
||||
return "cccccccc"
|
||||
@@ -53,9 +53,6 @@ class Pc(HardwareBase):
|
||||
def shutdown(self):
|
||||
print("SHUTDOWN!")
|
||||
|
||||
def get_thermal_config(self):
|
||||
return ThermalConfig(cpu=((None,), 1), gpu=((None,), 1), mem=(None, 1), bat=(None, 1), pmic=((None,), 1))
|
||||
|
||||
def set_screen_brightness(self, percentage):
|
||||
pass
|
||||
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
[
|
||||
{
|
||||
"name": "boot",
|
||||
"url": "https://commadist.azureedge.net/agnosupdate-staging/boot-184b9edb429167dcc97110134cdeffaa9739a758b3069e3ea7700e6559b79a0a.img.xz",
|
||||
"hash": "184b9edb429167dcc97110134cdeffaa9739a758b3069e3ea7700e6559b79a0a",
|
||||
"hash_raw": "184b9edb429167dcc97110134cdeffaa9739a758b3069e3ea7700e6559b79a0a",
|
||||
"size": 16414720,
|
||||
"url": "https://commadist.azureedge.net/agnosupdate/boot-45e107ad65e6cc9ee95dc139f9ed11d56ef7f5f0657f579498a4a48f0a2f7ea3.img.xz",
|
||||
"hash": "45e107ad65e6cc9ee95dc139f9ed11d56ef7f5f0657f579498a4a48f0a2f7ea3",
|
||||
"hash_raw": "45e107ad65e6cc9ee95dc139f9ed11d56ef7f5f0657f579498a4a48f0a2f7ea3",
|
||||
"size": 16418816,
|
||||
"sparse": false,
|
||||
"full_check": true,
|
||||
"has_ab": true
|
||||
},
|
||||
{
|
||||
"name": "system",
|
||||
"url": "https://commadist.azureedge.net/agnosupdate-staging/system-93a86656670d6d8d99ea401bd5735cd1060c2355d65f2c14de522c77a80c57ea.img.xz",
|
||||
"hash": "93a86656670d6d8d99ea401bd5735cd1060c2355d65f2c14de522c77a80c57ea",
|
||||
"hash_raw": "93a86656670d6d8d99ea401bd5735cd1060c2355d65f2c14de522c77a80c57ea",
|
||||
"url": "https://commadist.azureedge.net/agnosupdate/system-c0d738052c77f97b10bcea111479ddabd3fde2653d50533dd0fa2b17bb7881e9.img.xz",
|
||||
"hash": "c0d738052c77f97b10bcea111479ddabd3fde2653d50533dd0fa2b17bb7881e9",
|
||||
"hash_raw": "c0d738052c77f97b10bcea111479ddabd3fde2653d50533dd0fa2b17bb7881e9",
|
||||
"size": 4404019200,
|
||||
"sparse": false,
|
||||
"full_check": false,
|
||||
@@ -21,9 +21,9 @@
|
||||
},
|
||||
{
|
||||
"name": "xbl",
|
||||
"url": "https://commadist.azureedge.net/agnosupdate/xbl-446e37054b4c2f08bac3ee9d98256cdb93e876fb3343acfc8881124900f11050.img.xz",
|
||||
"hash": "446e37054b4c2f08bac3ee9d98256cdb93e876fb3343acfc8881124900f11050",
|
||||
"hash_raw": "446e37054b4c2f08bac3ee9d98256cdb93e876fb3343acfc8881124900f11050",
|
||||
"url": "https://commadist.azureedge.net/agnosupdate/xbl-bece486a68d9470c165e87955e451339cd86ada6ca2c7fde13c49144624ce030.img.xz",
|
||||
"hash": "bece486a68d9470c165e87955e451339cd86ada6ca2c7fde13c49144624ce030",
|
||||
"hash_raw": "bece486a68d9470c165e87955e451339cd86ada6ca2c7fde13c49144624ce030",
|
||||
"size": 3282256,
|
||||
"sparse": false,
|
||||
"full_check": true,
|
||||
@@ -41,9 +41,9 @@
|
||||
},
|
||||
{
|
||||
"name": "xbl_config",
|
||||
"url": "https://commadist.azureedge.net/agnosupdate/xbl_config-80f3e644529d30e260bb9b8b6c765d76a4ccd0a2d3104cc07acf93b0eabb8995.img.xz",
|
||||
"hash": "80f3e644529d30e260bb9b8b6c765d76a4ccd0a2d3104cc07acf93b0eabb8995",
|
||||
"hash_raw": "80f3e644529d30e260bb9b8b6c765d76a4ccd0a2d3104cc07acf93b0eabb8995",
|
||||
"url": "https://commadist.azureedge.net/agnosupdate/xbl_config-868b6f9aa98871dc50ef191a2d8f432578d1eca84f87d9185f8fb61242c3b66f.img.xz",
|
||||
"hash": "868b6f9aa98871dc50ef191a2d8f432578d1eca84f87d9185f8fb61242c3b66f",
|
||||
"hash_raw": "868b6f9aa98871dc50ef191a2d8f432578d1eca84f87d9185f8fb61242c3b66f",
|
||||
"size": 98124,
|
||||
"sparse": false,
|
||||
"full_check": true,
|
||||
@@ -51,9 +51,9 @@
|
||||
},
|
||||
{
|
||||
"name": "devcfg",
|
||||
"url": "https://commadist.azureedge.net/agnosupdate/devcfg-8ea8a9e779b0bd43af41ed367e3c781ba666012eebb4707ce58328b81219f9f8.img.xz",
|
||||
"hash": "8ea8a9e779b0bd43af41ed367e3c781ba666012eebb4707ce58328b81219f9f8",
|
||||
"hash_raw": "8ea8a9e779b0bd43af41ed367e3c781ba666012eebb4707ce58328b81219f9f8",
|
||||
"url": "https://commadist.azureedge.net/agnosupdate/devcfg-c27dc9ab628015ef265e1204ca736b2838ec179e9ecdd79e2ddb59d984b78df1.img.xz",
|
||||
"hash": "c27dc9ab628015ef265e1204ca736b2838ec179e9ecdd79e2ddb59d984b78df1",
|
||||
"hash_raw": "c27dc9ab628015ef265e1204ca736b2838ec179e9ecdd79e2ddb59d984b78df1",
|
||||
"size": 40336,
|
||||
"sparse": false,
|
||||
"full_check": true,
|
||||
@@ -61,9 +61,9 @@
|
||||
},
|
||||
{
|
||||
"name": "aop",
|
||||
"url": "https://commadist.azureedge.net/agnosupdate/aop-c1dbeefa20e742dde97eac76aaa00d1e6c2e2b01cfbd4c1242bd4e26c7d2aed4.img.xz",
|
||||
"hash": "c1dbeefa20e742dde97eac76aaa00d1e6c2e2b01cfbd4c1242bd4e26c7d2aed4",
|
||||
"hash_raw": "c1dbeefa20e742dde97eac76aaa00d1e6c2e2b01cfbd4c1242bd4e26c7d2aed4",
|
||||
"url": "https://commadist.azureedge.net/agnosupdate/aop-588bb60f0f8194d2df12f041e320a6dfeafae7209b312be3e4f6fe0744192837.img.xz",
|
||||
"hash": "588bb60f0f8194d2df12f041e320a6dfeafae7209b312be3e4f6fe0744192837",
|
||||
"hash_raw": "588bb60f0f8194d2df12f041e320a6dfeafae7209b312be3e4f6fe0744192837",
|
||||
"size": 184364,
|
||||
"sparse": false,
|
||||
"full_check": true,
|
||||
|
||||
@@ -10,7 +10,7 @@ from pathlib import Path
|
||||
|
||||
from cereal import log
|
||||
from openpilot.common.gpio import gpio_set, gpio_init, get_irqs_for_action
|
||||
from openpilot.system.hardware.base import HardwareBase, ThermalConfig
|
||||
from openpilot.system.hardware.base import HardwareBase, ThermalConfig, ThermalZone
|
||||
from openpilot.system.hardware.tici import iwlist
|
||||
from openpilot.system.hardware.tici.pins import GPIO
|
||||
from openpilot.system.hardware.tici.amplifier import Amplifier
|
||||
@@ -294,19 +294,6 @@ class Tici(HardwareBase):
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def get_modem_nv(self):
|
||||
timeout = 0.2 # Default timeout is too short
|
||||
files = (
|
||||
'/nv/item_files/modem/mmode/ue_usage_setting',
|
||||
'/nv/item_files/ims/IMS_enable',
|
||||
'/nv/item_files/modem/mmode/sms_only',
|
||||
)
|
||||
try:
|
||||
modem = self.get_modem()
|
||||
return { fn: str(modem.Command(f'AT+QNVFR="{fn}"', math.ceil(timeout), dbus_interface=MM_MODEM, timeout=timeout)) for fn in files}
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def get_modem_temperatures(self):
|
||||
timeout = 0.2 # Default timeout is too short
|
||||
try:
|
||||
@@ -336,12 +323,19 @@ class Tici(HardwareBase):
|
||||
os.system("sudo poweroff")
|
||||
|
||||
def get_thermal_config(self):
|
||||
return ThermalConfig(cpu=(["cpu%d-silver-usr" % i for i in range(4)] +
|
||||
["cpu%d-gold-usr" % i for i in range(4)], 1000),
|
||||
gpu=(("gpu0-usr", "gpu1-usr"), 1000),
|
||||
mem=("ddr-usr", 1000),
|
||||
bat=(None, 1),
|
||||
pmic=(("pm8998_tz", "pm8005_tz"), 1000))
|
||||
intake, exhaust, case = None, None, None
|
||||
if self.get_device_type() == "mici":
|
||||
case = ThermalZone("case")
|
||||
intake = ThermalZone("intake")
|
||||
exhaust = ThermalZone("exhaust")
|
||||
return ThermalConfig(cpu=[ThermalZone(f"cpu{i}-silver-usr") for i in range(4)] +
|
||||
[ThermalZone(f"cpu{i}-gold-usr") for i in range(4)],
|
||||
gpu=[ThermalZone("gpu0-usr"), ThermalZone("gpu1-usr")],
|
||||
memory=ThermalZone("ddr-usr"),
|
||||
pmic=[ThermalZone("pm8998_tz"), ThermalZone("pm8005_tz")],
|
||||
intake=intake,
|
||||
exhaust=exhaust,
|
||||
case=case)
|
||||
|
||||
def set_screen_brightness(self, percentage):
|
||||
try:
|
||||
@@ -465,7 +459,24 @@ class Tici(HardwareBase):
|
||||
manufacturer = None
|
||||
|
||||
cmds = []
|
||||
if manufacturer == 'Cavli Inc.':
|
||||
|
||||
if self.get_device_type() in ("tici", "tizi"):
|
||||
# clear out old blue prime initial APN
|
||||
os.system('mmcli -m any --3gpp-set-initial-eps-bearer-settings="apn="')
|
||||
|
||||
cmds += [
|
||||
# configure modem as data-centric
|
||||
'AT+QNVW=5280,0,"0102000000000000"',
|
||||
'AT+QNVFW="/nv/item_files/ims/IMS_enable",00',
|
||||
'AT+QNVFW="/nv/item_files/modem/mmode/ue_usage_setting",01',
|
||||
]
|
||||
if self.get_device_type() == "tizi":
|
||||
# SIM hot swap, not routed on tici
|
||||
cmds += [
|
||||
'AT+QSIMDET=1,0',
|
||||
'AT+QSIMSTAT=1',
|
||||
]
|
||||
elif manufacturer == 'Cavli Inc.':
|
||||
cmds += [
|
||||
'AT^SIMSWAP=1', # use SIM slot, instead of internal eSIM
|
||||
'AT$QCSIMSLEEP=0', # disable SIM sleep
|
||||
@@ -476,21 +487,17 @@ class Tici(HardwareBase):
|
||||
'AT$QCNETDEVCTL=3,1',
|
||||
]
|
||||
else:
|
||||
cmds += [
|
||||
# configure modem as data-centric
|
||||
'AT+QNVW=5280,0,"0102000000000000"',
|
||||
'AT+QNVFW="/nv/item_files/ims/IMS_enable",00',
|
||||
'AT+QNVFW="/nv/item_files/modem/mmode/ue_usage_setting",01',
|
||||
]
|
||||
if self.get_device_type() == "tizi":
|
||||
# this modem gets upset with too many AT commands
|
||||
if sim_id is None or len(sim_id) == 0:
|
||||
cmds += [
|
||||
# SIM hot swap
|
||||
'AT+QSIMDET=1,0',
|
||||
'AT+QSIMSTAT=1',
|
||||
# SIM sleep disable
|
||||
'AT$QCSIMSLEEP=0',
|
||||
'AT$QCSIMCFG=SimPowerSave,0',
|
||||
|
||||
# ethernet config
|
||||
'AT$QCPCFG=usbNet,1',
|
||||
]
|
||||
|
||||
# clear out old blue prime initial APN
|
||||
os.system('mmcli -m any --3gpp-set-initial-eps-bearer-settings="apn="')
|
||||
for cmd in cmds:
|
||||
try:
|
||||
modem.Command(cmd, math.ceil(TIMEOUT), dbus_interface=MM_MODEM, timeout=TIMEOUT)
|
||||
@@ -588,3 +595,4 @@ if __name__ == "__main__":
|
||||
t.configure_modem()
|
||||
t.initialize_hardware()
|
||||
t.set_power_save(False)
|
||||
print(t.get_sim_info())
|
||||
|
||||
@@ -7,8 +7,10 @@ class GPIO:
|
||||
UBLOX_RST_N = 32
|
||||
UBLOX_SAFEBOOT_N = 33
|
||||
GNSS_PWR_EN = 34 # SCHEMATIC LABEL: GPIO_UBLOX_PWR_EN
|
||||
|
||||
STM_RST_N = 124
|
||||
STM_BOOT0 = 134
|
||||
STM_PWR_EN_N = 41 # because STM32H7 RST doesn't generate a full power-on-reset
|
||||
|
||||
SIREN = 42
|
||||
SOM_ST_IO = 49
|
||||
|
||||
@@ -27,7 +27,7 @@ static kj::Array<capnp::word> build_boot_log() {
|
||||
|
||||
// Gather output of commands
|
||||
std::vector<std::string> bootlog_commands = {
|
||||
"[ -x \"$(command -v journalctl)\" ] && journalctl",
|
||||
"[ -x \"$(command -v journalctl)\" ] && journalctl -o short-monotonic",
|
||||
};
|
||||
|
||||
if (Hardware::TICI()) {
|
||||
|
||||
@@ -24,7 +24,11 @@ NetworkType = log.DeviceState.NetworkType
|
||||
UPLOAD_ATTR_NAME = 'user.upload'
|
||||
UPLOAD_ATTR_VALUE = b'1'
|
||||
|
||||
UPLOAD_QLOG_QCAM_MAX_SIZE = 5 * 1e6 # MB
|
||||
MAX_UPLOAD_SIZES = {
|
||||
"qlog": 25*1e6, # can't be too restrictive here since we use qlogs to find
|
||||
# bugs, including ones that can cause massive log sizes
|
||||
"qcam": 5*1e6,
|
||||
}
|
||||
LOG_COMPRESSION_LEVEL = 10 # little benefit up to level 15. level ~17 is a small step change
|
||||
|
||||
allow_sleep = bool(os.getenv("UPLOADER_SLEEP", "1"))
|
||||
@@ -170,7 +174,7 @@ class Uploader:
|
||||
if sz == 0:
|
||||
# tag files of 0 size as uploaded
|
||||
success = True
|
||||
elif name in self.immediate_priority and sz > UPLOAD_QLOG_QCAM_MAX_SIZE:
|
||||
elif name in MAX_UPLOAD_SIZES and sz > MAX_UPLOAD_SIZES[name]:
|
||||
cloudlog.event("uploader_too_large", key=key, fn=fn, sz=sz)
|
||||
success = True
|
||||
else:
|
||||
|
||||
@@ -17,7 +17,7 @@ from openpilot.system.manager.process_config import managed_processes
|
||||
from openpilot.system.athena.registration import register, UNREGISTERED_DONGLE_ID
|
||||
from openpilot.common.swaglog import cloudlog, add_file_handler
|
||||
from openpilot.system.version import get_build_metadata, terms_version, training_version
|
||||
|
||||
from openpilot.system.hardware.hw import Paths
|
||||
|
||||
|
||||
def manager_init() -> None:
|
||||
@@ -52,11 +52,11 @@ def manager_init() -> None:
|
||||
|
||||
# Create folders needed for msgq
|
||||
try:
|
||||
os.mkdir("/dev/shm")
|
||||
os.mkdir(Paths.shm_path())
|
||||
except FileExistsError:
|
||||
pass
|
||||
except PermissionError:
|
||||
print("WARNING: failed to make /dev/shm")
|
||||
print(f"WARNING: failed to make {Paths.shm_path()}")
|
||||
|
||||
# set version params
|
||||
params.put("Version", build_metadata.openpilot.version)
|
||||
|
||||
@@ -16,8 +16,9 @@ import openpilot.system.sentry as sentry
|
||||
from openpilot.common.basedir import BASEDIR
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
from openpilot.system.hardware.hw import Paths
|
||||
|
||||
WATCHDOG_FN = "/dev/shm/wd_"
|
||||
WATCHDOG_FN = f"{Paths.shm_path()}/wd_"
|
||||
ENABLE_WATCHDOG = os.getenv("NO_WATCHDOG") is None
|
||||
|
||||
|
||||
|
||||
@@ -89,7 +89,6 @@ procs = [
|
||||
PythonProcess("deleter", "system.loggerd.deleter", always_run),
|
||||
PythonProcess("dmonitoringd", "selfdrive.monitoring.dmonitoringd", driverview, enabled=(not PC or WEBCAM)),
|
||||
PythonProcess("qcomgpsd", "system.qcomgpsd.qcomgpsd", qcomgps, enabled=TICI),
|
||||
#PythonProcess("ugpsd", "system.ugpsd", only_onroad, enabled=TICI),
|
||||
PythonProcess("pandad", "selfdrive.pandad.pandad", always_run),
|
||||
PythonProcess("paramsd", "selfdrive.locationd.paramsd", only_onroad),
|
||||
NativeProcess("ubloxd", "system/ubloxd", ["./ubloxd"], ublox, enabled=TICI),
|
||||
|
||||
@@ -3,8 +3,6 @@ import pytest
|
||||
import signal
|
||||
import time
|
||||
|
||||
from parameterized import parameterized
|
||||
|
||||
from cereal import car
|
||||
from openpilot.common.params import Params
|
||||
import openpilot.system.manager.manager as manager
|
||||
@@ -37,14 +35,6 @@ class TestManager:
|
||||
# TODO: ensure there are blacklisted procs until we have a dedicated test
|
||||
assert len(BLACKLIST_PROCS), "No blacklisted procs to test not_run"
|
||||
|
||||
@parameterized.expand([(i,) for i in range(10)])
|
||||
def test_startup_time(self, index):
|
||||
start = time.monotonic()
|
||||
os.environ['PREPAREONLY'] = '1'
|
||||
manager.main()
|
||||
t = time.monotonic() - start
|
||||
assert t < MAX_STARTUP_TIME, f"startup took {t}s, expected <{MAX_STARTUP_TIME}s"
|
||||
|
||||
@pytest.mark.skip("this test is flaky the way it's currently written, should be moved to test_onroad")
|
||||
def test_clean_exit(self, subtests):
|
||||
"""
|
||||
|
||||
@@ -273,7 +273,7 @@ def main() -> NoReturn:
|
||||
|
||||
(pending_msgs, log_outer_length), inner_log_packet = unpack_from('<BH', payload), payload[calcsize('<BH'):]
|
||||
if pending_msgs > 0:
|
||||
cloudlog.debug("have %d pending messages" % pending_msgs)
|
||||
cloudlog.debug(f"have {pending_msgs} pending messages")
|
||||
assert log_outer_length == len(inner_log_packet)
|
||||
|
||||
(log_inner_length, log_type, log_time), log_payload = unpack_from('<HHQ', inner_log_packet), inner_log_packet[calcsize('<HHQ'):]
|
||||
@@ -283,7 +283,7 @@ def main() -> NoReturn:
|
||||
continue
|
||||
|
||||
if DEBUG:
|
||||
print("%.4f: got log: %x len %d" % (time.time(), log_type, len(log_payload)))
|
||||
print(f"{time.time():.4f}: got log: {log_type} len {len(log_payload)}")
|
||||
|
||||
if log_type == LOG_GNSS_OEMDRE_MEASUREMENT_REPORT:
|
||||
msg = messaging.new_message('qcomGnss', valid=True)
|
||||
|
||||
@@ -322,7 +322,7 @@ def parse_struct(ss):
|
||||
cnt = int(nam.split("[")[1].split("]")[0])
|
||||
st += st[-1]*(cnt-1)
|
||||
for i in range(cnt):
|
||||
nams.append("%s[%d]" % (nam.split("[")[0], i))
|
||||
nams.append(f'{nam.split("[")[0]}[{i}]')
|
||||
else:
|
||||
nams.append(nam)
|
||||
return st, nams
|
||||
|
||||
@@ -16,6 +16,7 @@ GOOD_SIGNAL = bool(int(os.getenv("GOOD_SIGNAL", '0')))
|
||||
class TestRawgpsd:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
os.environ['GPS_COLD_START'] = '1'
|
||||
os.system("sudo systemctl start systemd-resolved")
|
||||
os.system("sudo systemctl restart ModemManager lte")
|
||||
wait_for_modem()
|
||||
@@ -27,7 +28,6 @@ class TestRawgpsd:
|
||||
os.system("sudo systemctl restart ModemManager lte")
|
||||
|
||||
def setup_method(self):
|
||||
at_cmd("AT+QGPSDEL=0")
|
||||
self.sm = messaging.SubMaster(['qcomGnss', 'gpsLocation', 'gnssMeasurements'])
|
||||
|
||||
def teardown_method(self):
|
||||
|
||||
@@ -9,6 +9,7 @@ import urllib.parse
|
||||
from datetime import datetime, UTC
|
||||
|
||||
from cereal import messaging
|
||||
from openpilot.common.time import system_time_valid
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
from openpilot.system.hardware import TICI
|
||||
@@ -196,8 +197,8 @@ def initialize_pigeon(pigeon: TTYPigeon) -> bool:
|
||||
cloudlog.error(f"failed to restore almanac backup, status: {restore_status}")
|
||||
|
||||
# sending time to ublox
|
||||
t_now = datetime.now(UTC).replace(tzinfo=None)
|
||||
if t_now >= datetime(2021, 6, 1):
|
||||
if system_time_valid():
|
||||
t_now = datetime.now(UTC).replace(tzinfo=None)
|
||||
cloudlog.warning("Sending current time to ublox")
|
||||
|
||||
# UBX-MGA-INI-TIME_UTC
|
||||
|
||||
@@ -13,7 +13,7 @@ if __name__ == "__main__":
|
||||
cnos = []
|
||||
for m in ug.measurementReport.measurements:
|
||||
cnos.append(m.cno)
|
||||
print("Sats: %d Accuracy: %.2f m cnos" % (ug.measurementReport.numMeas, gle.horizontalAccuracy), sorted(cnos))
|
||||
print(f"Sats: {ug.measurementReport.numMeas} Accuracy: {gle.horizontalAccuracy:.2f} m cnos", sorted(cnos))
|
||||
except Exception:
|
||||
pass
|
||||
sm.update()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user