mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-07-07 14:32:06 +08:00
Merge branch 'upstream/openpilot/master' into sync-20240216
# Conflicts: # cereal # opendbc # panda # selfdrive/car/hyundai/interface.py # selfdrive/controls/controlsd.py # selfdrive/monitoring/dmonitoringd.py
This commit is contained in:
@@ -47,7 +47,7 @@ jobs:
|
||||
export PYTHONPATH=$TARGET_DIR
|
||||
cd $TARGET_DIR
|
||||
scons -j$(nproc)
|
||||
selfdrive/car/tests/test_car_interfaces.py
|
||||
pytest -n logical selfdrive/car/tests/test_car_interfaces.py
|
||||
- name: Push master-ci
|
||||
run: |
|
||||
unset TARGET_DIR
|
||||
|
||||
@@ -2,7 +2,7 @@ name: repo maintenance
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 12 * * 1" # every Monday at 12am UTC (4am PST)
|
||||
- cron: "0 14 * * 1" # every Monday at 2am UTC (6am PST)
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -11,6 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
container:
|
||||
image: ghcr.io/commaai/openpilot-base:latest
|
||||
if: github.repository == 'commaai/openpilot'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -36,6 +37,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
container:
|
||||
image: ghcr.io/commaai/openpilot-base:latest
|
||||
if: github.repository == 'commaai/openpilot'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: poetry lock
|
||||
|
||||
@@ -14,7 +14,6 @@ concurrency:
|
||||
env:
|
||||
PYTHONWARNINGS: error
|
||||
BASE_IMAGE: openpilot-base
|
||||
CL_BASE_IMAGE: openpilot-base-cl
|
||||
AZURE_TOKEN: ${{ secrets.AZURE_COMMADATACI_OPENPILOTCI_TOKEN }}
|
||||
|
||||
DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -22,11 +21,7 @@ env:
|
||||
|
||||
RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PRE_COMMIT_HOME=/tmp/pre-commit -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/pre-commit:/tmp/pre-commit -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c
|
||||
|
||||
BUILD_CL: selfdrive/test/docker_build.sh cl
|
||||
|
||||
RUN_CL: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PYTHONWARNINGS=error -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 $CL_BASE_IMAGE /bin/bash -c
|
||||
|
||||
PYTEST: pytest --continue-on-collection-errors --cov --cov-report=xml --cov-append --durations=0 --durations-min=5 --hypothesis-seed 0
|
||||
PYTEST: pytest --continue-on-collection-errors --cov --cov-report=xml --cov-append --durations=0 --durations-min=5 --hypothesis-seed 0 -n logical
|
||||
|
||||
jobs:
|
||||
build_release:
|
||||
@@ -106,11 +101,6 @@ jobs:
|
||||
- uses: ./.github/workflows/setup-with-retry
|
||||
with:
|
||||
docker_hub_pat: ${{ secrets.DOCKER_HUB_PAT }}
|
||||
- name: Build and push CL Docker image
|
||||
if: matrix.arch == 'x86_64'
|
||||
run: |
|
||||
unset TARGET_ARCHITECTURE
|
||||
eval "$BUILD_CL"
|
||||
|
||||
docker_push_multiarch:
|
||||
name: docker push multiarch tag
|
||||
@@ -182,7 +172,7 @@ jobs:
|
||||
run: |
|
||||
${{ env.RUN }} "source selfdrive/test/setup_xvfb.sh && \
|
||||
export MAPBOX_TOKEN='pk.eyJ1Ijoiam5ld2IiLCJhIjoiY2xxNW8zZXprMGw1ZzJwbzZneHd2NHljbSJ9.gV7VPRfbXFetD-1OVF0XZg' && \
|
||||
$PYTEST --timeout 60 -m 'not slow' -n $(nproc) && \
|
||||
$PYTEST --timeout 60 -m 'not slow' && \
|
||||
./selfdrive/ui/tests/create_test_translations.sh && \
|
||||
QT_QPA_PLATFORM=offscreen ./selfdrive/ui/tests/test_translations && \
|
||||
./selfdrive/ui/tests/test_translations.py"
|
||||
@@ -258,15 +248,13 @@ jobs:
|
||||
key: regen-${{ hashFiles('.github/workflows/selfdrive_tests.yaml', 'selfdrive/test/process_replay/test_regen.py') }}
|
||||
- name: Build base Docker image
|
||||
run: eval "$BUILD"
|
||||
- name: Build Docker image
|
||||
run: eval "$BUILD_CL"
|
||||
- name: Build openpilot
|
||||
run: |
|
||||
${{ env.RUN }} "scons -j$(nproc)"
|
||||
- name: Run regen
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
${{ env.RUN_CL }} "ONNXCPU=1 $PYTEST selfdrive/test/process_replay/test_regen.py && \
|
||||
${{ env.RUN }} "ONNXCPU=1 $PYTEST selfdrive/test/process_replay/test_regen.py && \
|
||||
chmod -R 777 /tmp/comma_download_cache"
|
||||
|
||||
test_modeld:
|
||||
@@ -279,9 +267,6 @@ jobs:
|
||||
- uses: ./.github/workflows/setup-with-retry
|
||||
- name: Build base Docker image
|
||||
run: eval "$BUILD"
|
||||
- name: Build Docker image
|
||||
# Sim docker is needed to get the OpenCL drivers
|
||||
run: eval "$BUILD_CL"
|
||||
- name: Build openpilot
|
||||
run: |
|
||||
${{ env.RUN }} "scons -j$(nproc)"
|
||||
@@ -289,14 +274,14 @@ jobs:
|
||||
- name: Run model replay with ONNX
|
||||
timeout-minutes: 4
|
||||
run: |
|
||||
${{ env.RUN_CL }} "unset PYTHONWARNINGS && \
|
||||
${{ env.RUN }} "unset PYTHONWARNINGS && \
|
||||
ONNXCPU=1 NO_NAV=1 coverage run selfdrive/test/process_replay/model_replay.py && \
|
||||
coverage combine && \
|
||||
coverage xml"
|
||||
- name: Run unit tests
|
||||
timeout-minutes: 4
|
||||
run: |
|
||||
${{ env.RUN_CL }} "unset PYTHONWARNINGS && \
|
||||
${{ env.RUN }} "unset PYTHONWARNINGS && \
|
||||
$PYTEST selfdrive/modeld"
|
||||
- name: "Upload coverage to Codecov"
|
||||
uses: codecov/codecov-action@v3
|
||||
@@ -328,7 +313,7 @@ jobs:
|
||||
- name: Build openpilot
|
||||
run: ${{ env.RUN }} "scons -j$(nproc)"
|
||||
- name: Test car models
|
||||
timeout-minutes: 25
|
||||
timeout-minutes: 10
|
||||
run: |
|
||||
${{ env.RUN }} "$PYTEST selfdrive/car/tests/test_models.py && \
|
||||
chmod -R 777 /tmp/comma_download_cache"
|
||||
|
||||
@@ -12,17 +12,12 @@ concurrency:
|
||||
|
||||
env:
|
||||
BASE_IMAGE: openpilot-base
|
||||
CL_BASE_IMAGE: openpilot-base-cl
|
||||
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 1G -v $GITHUB_WORKSPACE:/tmp/openpilot -w /tmp/openpilot -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c
|
||||
|
||||
BUILD_CL: selfdrive/test/docker_build.sh cl
|
||||
|
||||
RUN_CL: docker run --shm-size 1G -v $GITHUB_WORKSPACE:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $CL_BASE_IMAGE /bin/bash -c
|
||||
|
||||
|
||||
jobs:
|
||||
plotjuggler:
|
||||
@@ -52,8 +47,6 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
- uses: ./.github/workflows/setup-with-retry
|
||||
- name: Build base cl image
|
||||
run: eval "$BUILD_CL"
|
||||
- name: Setup to push to repo
|
||||
if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot'
|
||||
run: |
|
||||
@@ -104,6 +97,6 @@ jobs:
|
||||
timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 10 || 30) }} # allow more time when we missed the scons cache
|
||||
run: ${{ env.RUN }} "scons -j$(nproc)"
|
||||
- name: Test notebooks
|
||||
timeout-minutes: 2
|
||||
timeout-minutes: 3
|
||||
run: |
|
||||
${{ env.RUN }} "pip install nbmake && pytest --nbmake tools/car_porting/examples/"
|
||||
@@ -44,7 +44,7 @@ repos:
|
||||
- --explicit-package-bases
|
||||
exclude: '^(third_party/)|(cereal/)|(opendbc/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)|(xx/)'
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.1.14
|
||||
rev: v0.2.1
|
||||
hooks:
|
||||
- id: ruff
|
||||
exclude: '^(third_party/)|(cereal/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)'
|
||||
@@ -90,6 +90,6 @@ repos:
|
||||
args:
|
||||
- --lock
|
||||
- repo: https://github.com/python-jsonschema/check-jsonschema
|
||||
rev: 0.27.3
|
||||
rev: 0.28.0
|
||||
hooks:
|
||||
- id: check-github-workflows
|
||||
|
||||
@@ -22,6 +22,44 @@ RUN cd /tmp && \
|
||||
rm -rf arm/ && \
|
||||
rm -rf thumb/nofp thumb/v6* thumb/v8* thumb/v7+fp thumb/v7-r+fp.sp
|
||||
|
||||
# Add OpenCL
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
apt-utils \
|
||||
alien \
|
||||
unzip \
|
||||
tar \
|
||||
curl \
|
||||
xz-utils \
|
||||
dbus \
|
||||
gcc-arm-none-eabi \
|
||||
tmux \
|
||||
vim \
|
||||
lsb-core \
|
||||
libx11-6 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ARG INTEL_DRIVER=l_opencl_p_18.1.0.015.tgz
|
||||
ARG INTEL_DRIVER_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/vcp/15532
|
||||
RUN mkdir -p /tmp/opencl-driver-intel
|
||||
|
||||
RUN cd /tmp/opencl-driver-intel && \
|
||||
echo INTEL_DRIVER is $INTEL_DRIVER && \
|
||||
curl -O $INTEL_DRIVER_URL/$INTEL_DRIVER && \
|
||||
tar -xzf $INTEL_DRIVER && \
|
||||
for i in $(basename $INTEL_DRIVER .tgz)/rpm/*.rpm; do alien --to-deb $i; done && \
|
||||
dpkg -i *.deb && \
|
||||
rm -rf $INTEL_DRIVER $(basename $INTEL_DRIVER .tgz) *.deb && \
|
||||
mkdir -p /etc/OpenCL/vendors && \
|
||||
echo /opt/intel/opencl_compilers_and_libraries_18.1.0.015/linux/compiler/lib/intel64_lin/libintelocl.so > /etc/OpenCL/vendors/intel.icd && \
|
||||
cd / && \
|
||||
rm -rf /tmp/opencl-driver-intel
|
||||
|
||||
ENV NVIDIA_VISIBLE_DEVICES all
|
||||
ENV NVIDIA_DRIVER_CAPABILITIES graphics,utility,compute
|
||||
ENV QTWEBENGINE_DISABLE_SANDBOX 1
|
||||
|
||||
RUN dbus-uuidgen > /etc/machine-id
|
||||
|
||||
ARG USER=batman
|
||||
ARG USER_UID=1000
|
||||
RUN useradd -m -s /bin/bash -u $USER_UID $USER
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
FROM ghcr.io/commaai/openpilot-base:latest
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends\
|
||||
apt-utils \
|
||||
alien \
|
||||
unzip \
|
||||
tar \
|
||||
curl \
|
||||
xz-utils \
|
||||
dbus \
|
||||
gcc-arm-none-eabi \
|
||||
tmux \
|
||||
vim \
|
||||
lsb-core \
|
||||
libx11-6 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Intel OpenCL driver
|
||||
ARG INTEL_DRIVER=l_opencl_p_18.1.0.015.tgz
|
||||
ARG INTEL_DRIVER_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/vcp/15532
|
||||
RUN mkdir -p /tmp/opencl-driver-intel
|
||||
WORKDIR /tmp/opencl-driver-intel
|
||||
RUN echo INTEL_DRIVER is $INTEL_DRIVER && \
|
||||
curl -O $INTEL_DRIVER_URL/$INTEL_DRIVER && \
|
||||
tar -xzf $INTEL_DRIVER && \
|
||||
for i in $(basename $INTEL_DRIVER .tgz)/rpm/*.rpm; do alien --to-deb $i; done && \
|
||||
dpkg -i *.deb && \
|
||||
rm -rf $INTEL_DRIVER $(basename $INTEL_DRIVER .tgz) *.deb && \
|
||||
mkdir -p /etc/OpenCL/vendors && \
|
||||
echo /opt/intel/opencl_compilers_and_libraries_18.1.0.015/linux/compiler/lib/intel64_lin/libintelocl.so > /etc/OpenCL/vendors/intel.icd && \
|
||||
rm -rf /tmp/opencl-driver-intel
|
||||
ENV NVIDIA_VISIBLE_DEVICES all
|
||||
ENV NVIDIA_DRIVER_CAPABILITIES graphics,utility,compute
|
||||
ENV QTWEBENGINE_DISABLE_SANDBOX 1
|
||||
|
||||
RUN dbus-uuidgen > /etc/machine-id
|
||||
|
||||
Vendored
+13
-47
@@ -12,10 +12,12 @@ def retryWithDelay(int maxRetries, int delay, Closure body) {
|
||||
def device(String ip, String step_label, String cmd) {
|
||||
withCredentials([file(credentialsId: 'id_rsa', variable: 'key_file')]) {
|
||||
def ssh_cmd = """
|
||||
ssh -tt -o ConnectTimeout=30 -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -o BatchMode=yes -o StrictHostKeyChecking=no -i ${key_file} 'comma@${ip}' /usr/bin/bash <<'END'
|
||||
ssh -tt -o ConnectTimeout=5 -o ServerAliveInterval=5 -o ServerAliveCountMax=2 -o BatchMode=yes -o StrictHostKeyChecking=no -i ${key_file} 'comma@${ip}' /usr/bin/bash <<'END'
|
||||
|
||||
set -e
|
||||
|
||||
shopt -s huponexit # kill all child processes when the shell exits
|
||||
|
||||
export CI=1
|
||||
export PYTHONWARNINGS=error
|
||||
export LOGPRINT=debug
|
||||
@@ -78,17 +80,13 @@ def deviceStage(String stageName, String deviceType, List extra_env, def steps)
|
||||
def extra = extra_env.collect { "export ${it}" }.join('\n');
|
||||
def branch = env.BRANCH_NAME ?: 'master';
|
||||
|
||||
docker.image('ghcr.io/commaai/alpine-ssh').inside('--user=root') {
|
||||
lock(resource: "", label: deviceType, inversePrecedence: true, variable: 'device_ip', quantity: 1, resourceSelectStrategy: 'random') {
|
||||
lock(resource: "", label: deviceType, inversePrecedence: true, variable: 'device_ip', quantity: 1, resourceSelectStrategy: 'random') {
|
||||
docker.image('ghcr.io/commaai/alpine-ssh').inside('--user=root') {
|
||||
timeout(time: 20, unit: 'MINUTES') {
|
||||
retry (3) {
|
||||
device(device_ip, "git checkout", extra + "\n" + readFile("selfdrive/test/setup_device_ci.sh"))
|
||||
}
|
||||
steps.each { item ->
|
||||
if (branch != "master" && item.size() == 3 && !hasDirectoryChanged(item[2])) {
|
||||
println "Skipped '${item[0]}', no relevant changes were detected."
|
||||
return;
|
||||
}
|
||||
device(device_ip, item[0], item[1])
|
||||
}
|
||||
}
|
||||
@@ -106,7 +104,7 @@ def pcStage(String stageName, Closure body) {
|
||||
|
||||
checkout scm
|
||||
|
||||
def dockerArgs = "--user=batman -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/scons_cache:/tmp/scons_cache -e PYTHONPATH=${env.WORKSPACE}";
|
||||
def dockerArgs = "--user=batman -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/scons_cache:/tmp/scons_cache -e PYTHONPATH=${env.WORKSPACE} --cpus=8 --memory 16g -e PYTEST_ADDOPTS='-n8'";
|
||||
|
||||
def openpilot_base = retryWithDelay (3, 15) {
|
||||
return docker.build("openpilot-base:build-${env.GIT_COMMIT}", "-f Dockerfile.openpilot_base .")
|
||||
@@ -143,20 +141,6 @@ def setupCredentials() {
|
||||
}
|
||||
}
|
||||
|
||||
def hasDirectoryChanged(List<String> paths) {
|
||||
for (change in currentBuild.changeSets) {
|
||||
for (item in change.items) {
|
||||
for (affectedPath in item.affectedPaths) {
|
||||
for (path in paths) {
|
||||
if (affectedPath.startsWith(path)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
node {
|
||||
env.CI = "1"
|
||||
@@ -205,17 +189,17 @@ node {
|
||||
])
|
||||
},
|
||||
'HW + Unit Tests': {
|
||||
deviceStage("tici", "tici-common", ["UNSAFE=1"], [
|
||||
deviceStage("tici-hardware", "tici-common", ["UNSAFE=1"], [
|
||||
["build", "cd selfdrive/manager && ./build.py"],
|
||||
["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py", ["panda/", "selfdrive/boardd/"]],
|
||||
["test power draw", "./system/hardware/tici/tests/test_power_draw.py"],
|
||||
["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py"],
|
||||
["test power draw", "pytest -s system/hardware/tici/tests/test_power_draw.py"],
|
||||
["test encoder", "LD_LIBRARY_PATH=/usr/local/lib pytest system/loggerd/tests/test_encoder.py"],
|
||||
["test pigeond", "pytest system/sensord/tests/test_pigeond.py"],
|
||||
["test manager", "pytest selfdrive/manager/test/test_manager.py"],
|
||||
])
|
||||
},
|
||||
'loopback': {
|
||||
deviceStage("tici", "tici-loopback", ["UNSAFE=1"], [
|
||||
deviceStage("loopback", "tici-loopback", ["UNSAFE=1"], [
|
||||
["build openpilot", "cd selfdrive/manager && ./build.py"],
|
||||
["test boardd loopback", "pytest selfdrive/boardd/tests/test_boardd_loopback.py"],
|
||||
])
|
||||
@@ -243,7 +227,7 @@ node {
|
||||
])
|
||||
},
|
||||
'replay': {
|
||||
deviceStage("tici", "tici-replay", ["UNSAFE=1"], [
|
||||
deviceStage("model-replay", "tici-replay", ["UNSAFE=1"], [
|
||||
["build", "cd selfdrive/manager && ./build.py"],
|
||||
["model replay", "selfdrive/test/process_replay/model_replay.py"],
|
||||
])
|
||||
@@ -252,31 +236,13 @@ node {
|
||||
deviceStage("tizi", "tizi", ["UNSAFE=1"], [
|
||||
["build openpilot", "cd selfdrive/manager && ./build.py"],
|
||||
["test boardd loopback", "SINGLE_PANDA=1 pytest selfdrive/boardd/tests/test_boardd_loopback.py"],
|
||||
["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py", ["panda/", "selfdrive/boardd/"]],
|
||||
["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py"],
|
||||
["test amp", "pytest system/hardware/tici/tests/test_amplifier.py"],
|
||||
["test hw", "pytest system/hardware/tici/tests/test_hardware.py"],
|
||||
["test qcomgpsd", "pytest system/qcomgpsd/tests/test_qcomgpsd.py", ["system/qcomgpsd/"]],
|
||||
["test qcomgpsd", "pytest system/qcomgpsd/tests/test_qcomgpsd.py"],
|
||||
])
|
||||
},
|
||||
|
||||
// *** PC tests ***
|
||||
'PC tests': {
|
||||
pcStage("PC tests") {
|
||||
// tests that our build system's dependencies are configured properly,
|
||||
// needs a machine with lots of cores
|
||||
sh label: "test multi-threaded build",
|
||||
script: '''#!/bin/bash
|
||||
scons --no-cache --random -j$(nproc)'''
|
||||
}
|
||||
},
|
||||
'car tests': {
|
||||
pcStage("car tests") {
|
||||
sh label: "build", script: "selfdrive/manager/build.py"
|
||||
sh label: "run car tests", script: "cd selfdrive/car/tests && MAX_EXAMPLES=300 INTERNAL_SEG_CNT=300 FILEREADER_CACHE=1 \
|
||||
INTERNAL_SEG_LIST=selfdrive/car/tests/test_models_segs.txt pytest test_models.py test_car_interfaces.py"
|
||||
}
|
||||
},
|
||||
|
||||
)
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
+4
-1
@@ -1,4 +1,4 @@
|
||||
Version 0.9.6 (2024-02-XX)
|
||||
Version 0.9.6 (2024-02-22)
|
||||
========================
|
||||
* New driving model
|
||||
* Vision model trained on more data
|
||||
@@ -9,8 +9,11 @@ Version 0.9.6 (2024-02-XX)
|
||||
* AGNOS 9
|
||||
* comma body streaming and controls over WebRTC
|
||||
* Improved fuzzy fingerprinting for many makes and models
|
||||
* Chevrolet Equinox 2019-22 support thanks to JasonJShuler and nworb-cire!
|
||||
* Dodge Duranago 2020-21 support
|
||||
* Hyundai Staria 2023 support thanks to sunnyhaibin!
|
||||
* Kia Niro Plug-in Hybrid 2022 support thanks to sunnyhaibin!
|
||||
* Lexus LC 2024 support thanks to nelsonjchen!
|
||||
* Toyota RAV4 2023-24 support
|
||||
* Toyota RAV4 Hybrid 2023-24 support
|
||||
|
||||
|
||||
+1
-1
Submodule cereal updated: d6beb2482e...8e00786e2a
@@ -41,6 +41,15 @@ public:
|
||||
if (char* dongle_id = getenv("DONGLE_ID")) {
|
||||
ctx_j["dongle_id"] = dongle_id;
|
||||
}
|
||||
if (char* git_origin = getenv("GIT_ORIGIN")) {
|
||||
ctx_j["origin"] = git_origin;
|
||||
}
|
||||
if (char* git_branch = getenv("GIT_BRANCH")) {
|
||||
ctx_j["branch"] = git_branch;
|
||||
}
|
||||
if (char* git_commit = getenv("GIT_COMMIT")) {
|
||||
ctx_j["commit"] = git_commit;
|
||||
}
|
||||
if (char* daemon_name = getenv("MANAGER_DAEMON")) {
|
||||
ctx_j["daemon"] = daemon_name;
|
||||
}
|
||||
|
||||
+20
-3
@@ -1,10 +1,11 @@
|
||||
import gc
|
||||
import os
|
||||
import pytest
|
||||
import random
|
||||
|
||||
from openpilot.common.prefix import OpenpilotPrefix
|
||||
from openpilot.selfdrive.manager import manager
|
||||
from openpilot.system.hardware import TICI
|
||||
from openpilot.system.hardware import TICI, HARDWARE
|
||||
|
||||
|
||||
def pytest_sessionstart(session):
|
||||
@@ -45,6 +46,11 @@ def openpilot_function_fixture(request):
|
||||
# cleanup any started processes
|
||||
manager.manager_cleanup()
|
||||
|
||||
# some processes disable gc for performance, re-enable here
|
||||
if not gc.isenabled():
|
||||
gc.enable()
|
||||
gc.collect()
|
||||
|
||||
# If you use setUpClass, the environment variables won't be cleared properly,
|
||||
# so we need to hook both the function and class pytest fixtures
|
||||
@pytest.fixture(scope="class", autouse=True)
|
||||
@@ -57,12 +63,23 @@ def openpilot_class_fixture():
|
||||
os.environ.update(starting_env)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def tici_setup_fixture(openpilot_function_fixture):
|
||||
"""Ensure a consistent state for tests on-device. Needs the openpilot function fixture to run first."""
|
||||
HARDWARE.initialize_hardware()
|
||||
HARDWARE.set_power_save(False)
|
||||
os.system("pkill -9 -f athena")
|
||||
|
||||
|
||||
@pytest.hookimpl(tryfirst=True)
|
||||
def pytest_collection_modifyitems(config, items):
|
||||
skipper = pytest.mark.skip(reason="Skipping tici test on PC")
|
||||
for item in items:
|
||||
if not TICI and "tici" in item.keywords:
|
||||
item.add_marker(skipper)
|
||||
if "tici" in item.keywords:
|
||||
if not TICI:
|
||||
item.add_marker(skipper)
|
||||
else:
|
||||
item.fixturenames.append('tici_setup_fixture')
|
||||
|
||||
if "xdist_group_class_property" in item.keywords:
|
||||
class_property_name = item.get_closest_marker('xdist_group_class_property').args[0]
|
||||
|
||||
+8
-4
@@ -4,7 +4,7 @@
|
||||
|
||||
A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified.
|
||||
|
||||
# 275 Supported Cars
|
||||
# 279 Supported Cars
|
||||
|
||||
|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|<a href="##"><img width=2000></a>Hardware Needed<br> |Video|
|
||||
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||
@@ -23,6 +23,7 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Cadillac|Escalade ESV 2019[<sup>4</sup>](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-II connector<br>- 1 comma 3X<br>- 2 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=Cadillac&model=Escalade ESV 2019">Buy Here</a></sub></details>||
|
||||
|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<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=Chevrolet&model=Bolt EUV 2022-23">Buy Here</a></sub></details>|<a href="https://youtu.be/xvwzGMUA210" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<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=Chevrolet&model=Bolt EV 2022-23">Buy Here</a></sub></details>||
|
||||
|Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<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=Chevrolet&model=Equinox 2019-22">Buy Here</a></sub></details>||
|
||||
|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<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=Chevrolet&model=Silverado 1500 2020-21">Buy Here</a></sub></details>||
|
||||
|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<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=Chevrolet&model=Trailblazer 2021-22">Buy Here</a></sub></details>||
|
||||
|Chevrolet|Volt 2017-18[<sup>4</sup>](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-II connector<br>- 1 comma 3X<br>- 2 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=Chevrolet&model=Volt 2017-18">Buy Here</a></sub></details>|<a href="https://youtu.be/QeMCN_4TFfQ" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
@@ -33,6 +34,7 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Chrysler|Pacifica Hybrid 2018|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA 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=Chrysler&model=Pacifica Hybrid 2018">Buy Here</a></sub></details>||
|
||||
|Chrysler|Pacifica Hybrid 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA 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=Chrysler&model=Pacifica Hybrid 2019-23">Buy Here</a></sub></details>||
|
||||
|comma|body|All|openpilot|0 mph|0 mph|[](##)|[](##)|None||
|
||||
|Dodge|Durango 2020-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA 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=Dodge&model=Durango 2020-21">Buy Here</a></sub></details>||
|
||||
|Ford|Bronco Sport 2021-22|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Bronco Sport 2021-22">Buy Here</a></sub></details>||
|
||||
|Ford|Escape 2020-22|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|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=Ford&model=Escape 2020-22">Buy Here</a></sub></details>||
|
||||
|Ford|Explorer 2020-23|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|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=Ford&model=Explorer 2020-23">Buy Here</a></sub></details>||
|
||||
@@ -72,7 +74,7 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec 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=Honda&model=Odyssey 2018-20">Buy Here</a></sub></details>||
|
||||
|Honda|Passport 2019-23|All|openpilot|25 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec 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=Honda&model=Passport 2019-23">Buy Here</a></sub></details>||
|
||||
|Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec 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=Honda&model=Pilot 2016-22">Buy Here</a></sub></details>||
|
||||
|Honda|Ridgeline 2017-23|Honda Sensing|openpilot|25 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec 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=Honda&model=Ridgeline 2017-23">Buy Here</a></sub></details>||
|
||||
|Honda|Ridgeline 2017-24|Honda Sensing|openpilot|25 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec 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=Honda&model=Ridgeline 2017-24">Buy Here</a></sub></details>||
|
||||
|Hyundai|Azera 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K 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=Hyundai&model=Azera 2022">Buy Here</a></sub></details>||
|
||||
|Hyundai|Azera Hybrid 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C 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=Hyundai&model=Azera Hybrid 2019">Buy Here</a></sub></details>||
|
||||
|Hyundai|Azera Hybrid 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K 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=Hyundai&model=Azera Hybrid 2020">Buy Here</a></sub></details>||
|
||||
@@ -138,6 +140,7 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Kia|Niro Hybrid 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A 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=Kia&model=Niro Hybrid 2023">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Plug-in Hybrid 2018-19|All|Stock|10 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C 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=Kia&model=Niro Plug-in Hybrid 2018-19">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Plug-in Hybrid 2020|All|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai D 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=Kia&model=Niro Plug-in Hybrid 2020">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Plug-in Hybrid 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai D 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=Kia&model=Niro Plug-in Hybrid 2021">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Plug-in Hybrid 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F 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=Kia&model=Niro Plug-in Hybrid 2022">Buy Here</a></sub></details>||
|
||||
|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B 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=Kia&model=Optima 2017">Buy Here</a></sub></details>||
|
||||
|Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G 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=Kia&model=Optima 2019-20">Buy Here</a></sub></details>||
|
||||
@@ -161,6 +164,7 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|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>||
|
||||
|Lexus|LC 2024|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=LC 2024">Buy Here</a></sub></details>||
|
||||
|Lexus|NX 2018-19|All|openpilot available[<sup>2</sup>](#footnotes)|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=NX 2018-19">Buy Here</a></sub></details>||
|
||||
|Lexus|NX 2020-21|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=NX 2020-21">Buy Here</a></sub></details>||
|
||||
|Lexus|NX Hybrid 2018-19|All|openpilot available[<sup>2</sup>](#footnotes)|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=NX Hybrid 2018-19">Buy Here</a></sub></details>||
|
||||
@@ -267,8 +271,8 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<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=Volkswagen&model=Golf R 2015-19">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<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=Volkswagen&model=Golf SportsVan 2015-20">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|31 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<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=Volkswagen&model=Grand California 2019-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<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=Volkswagen&model=Jetta 2018-22">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<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=Volkswagen&model=Jetta GLI 2021-22">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Jetta 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<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=Volkswagen&model=Jetta 2018-24">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Jetta GLI 2021-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<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=Volkswagen&model=Jetta GLI 2021-24">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Passat 2015-22[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<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=Volkswagen&model=Passat 2015-22">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<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=Volkswagen&model=Passat Alltrack 2015-22">Buy Here</a></sub></details>||
|
||||
|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<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=Volkswagen&model=Passat GTE 2015-22">Buy Here</a></sub></details>||
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ export OPENBLAS_NUM_THREADS=1
|
||||
export VECLIB_MAXIMUM_THREADS=1
|
||||
|
||||
if [ -z "$AGNOS_VERSION" ]; then
|
||||
export AGNOS_VERSION="9.3"
|
||||
export AGNOS_VERSION="9.6"
|
||||
fi
|
||||
|
||||
export STAGING_ROOT="/data/safe_staging"
|
||||
|
||||
+1
-1
Submodule opendbc updated: aff840356a...4d004e78dd
+1
-1
Submodule panda updated: ea01b5148a...a48b419df4
Generated
+413
-393
File diff suppressed because it is too large
Load Diff
+5
-5
@@ -126,7 +126,7 @@ inputs = "*"
|
||||
Jinja2 = "*"
|
||||
lru-dict = "*"
|
||||
matplotlib = "*"
|
||||
metadrive-simulator = { version = "0.4.2.2", markers = "platform_machine != 'aarch64'" } # no linux/aarch64 wheels for certain dependencies
|
||||
metadrive-simulator = { version = "0.4.2.3", markers = "platform_machine != 'aarch64'" } # no linux/aarch64 wheels for certain dependencies
|
||||
mpld3 = "*"
|
||||
mypy = "*"
|
||||
myst-parser = "*"
|
||||
@@ -167,8 +167,8 @@ build-backend = "poetry.core.masonry.api"
|
||||
|
||||
# https://beta.ruff.rs/docs/configuration/#using-pyprojecttoml
|
||||
[tool.ruff]
|
||||
select = ["E", "F", "W", "PIE", "C4", "ISC", "RUF008", "RUF100", "A", "B", "TID251"]
|
||||
ignore = ["E741", "E402", "C408", "ISC003", "B027", "B024"]
|
||||
lint.select = ["E", "F", "W", "PIE", "C4", "ISC", "RUF008", "RUF100", "A", "B", "TID251"]
|
||||
lint.ignore = ["E741", "E402", "C408", "ISC003", "B027", "B024"]
|
||||
line-length = 160
|
||||
target-version="py311"
|
||||
exclude = [
|
||||
@@ -180,8 +180,8 @@ exclude = [
|
||||
"teleoprtc_repo",
|
||||
"third_party",
|
||||
]
|
||||
flake8-implicit-str-concat.allow-multiline=false
|
||||
[tool.ruff.flake8-tidy-imports.banned-api]
|
||||
lint.flake8-implicit-str-concat.allow-multiline=false
|
||||
[tool.ruff.lint.flake8-tidy-imports.banned-api]
|
||||
"selfdrive".msg = "Use openpilot.selfdrive"
|
||||
"common".msg = "Use openpilot.common"
|
||||
"system".msg = "Use openpilot.system"
|
||||
|
||||
@@ -95,7 +95,7 @@ selfdrive/car/ecu_addrs.py
|
||||
selfdrive/car/isotp_parallel_query.py
|
||||
selfdrive/car/tests/__init__.py
|
||||
selfdrive/car/tests/test_car_interfaces.py
|
||||
selfdrive/car/torque_data/*.toml
|
||||
selfdrive/car/torque_data/*
|
||||
|
||||
selfdrive/car/body/*.py
|
||||
selfdrive/car/chrysler/*.py
|
||||
|
||||
@@ -36,7 +36,7 @@ from openpilot.common.realtime import set_core_affinity
|
||||
from openpilot.system.hardware import HARDWARE, PC
|
||||
from openpilot.system.loggerd.xattr_cache import getxattr, setxattr
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
from openpilot.system.version import get_commit, get_origin, get_short_branch, get_version
|
||||
from openpilot.system.version import get_commit, get_normalized_origin, get_short_branch, get_version
|
||||
from openpilot.system.hardware.hw import Paths
|
||||
|
||||
|
||||
@@ -316,9 +316,9 @@ def getMessage(service: str, timeout: int = 1000) -> dict:
|
||||
def getVersion() -> Dict[str, str]:
|
||||
return {
|
||||
"version": get_version(),
|
||||
"remote": get_origin(''),
|
||||
"branch": get_short_branch(''),
|
||||
"commit": get_commit(default=''),
|
||||
"remote": get_normalized_origin(),
|
||||
"branch": get_short_branch(),
|
||||
"commit": get_commit(),
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ from multiprocessing import Process
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.selfdrive.manager.process import launcher
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
from openpilot.system.version import get_version, is_dirty
|
||||
from openpilot.system.hardware import HARDWARE
|
||||
from openpilot.system.version import get_version, get_normalized_origin, get_short_branch, get_commit, is_dirty
|
||||
|
||||
ATHENA_MGR_PID_PARAM = "AthenadPid"
|
||||
|
||||
@@ -14,7 +15,13 @@ ATHENA_MGR_PID_PARAM = "AthenadPid"
|
||||
def main():
|
||||
params = Params()
|
||||
dongle_id = params.get("DongleId").decode('utf-8')
|
||||
cloudlog.bind_global(dongle_id=dongle_id, version=get_version(), dirty=is_dirty())
|
||||
cloudlog.bind_global(dongle_id=dongle_id,
|
||||
version=get_version(),
|
||||
origin=get_normalized_origin(),
|
||||
branch=get_short_branch(),
|
||||
commit=get_commit(),
|
||||
dirty=is_dirty(),
|
||||
device=HARDWARE.get_device_type())
|
||||
|
||||
try:
|
||||
while 1:
|
||||
|
||||
@@ -32,7 +32,7 @@ class TestBoardd(unittest.TestCase):
|
||||
|
||||
with Timeout(90, "boardd didn't start"):
|
||||
sm = messaging.SubMaster(['pandaStates'])
|
||||
while sm.rcv_frame['pandaStates'] < 1 or len(sm['pandaStates']) == 0 or \
|
||||
while sm.recv_frame['pandaStates'] < 1 or len(sm['pandaStates']) == 0 or \
|
||||
any(ps.pandaType == log.PandaState.PandaType.unknown for ps in sm['pandaStates']):
|
||||
sm.update(1000)
|
||||
|
||||
|
||||
@@ -141,9 +141,10 @@ def fingerprint(logcan, sendcan, num_pandas):
|
||||
cached = True
|
||||
else:
|
||||
cloudlog.warning("Getting VIN & FW versions")
|
||||
# enable OBD multiplexing for Vin query, also allows time for sendcan subscriber to connect
|
||||
# enable OBD multiplexing for VIN query
|
||||
# NOTE: this takes ~0.1s and is relied on to allow sendcan subscriber to connect in time
|
||||
set_obd_multiplexing(params, True)
|
||||
# Vin query only reliably works through OBDII
|
||||
# VIN query only reliably works through OBDII
|
||||
vin_rx_addr, vin_rx_bus, vin = get_vin(logcan, sendcan, (0, 1))
|
||||
ecu_rx_addrs = get_present_ecus(logcan, sendcan, num_pandas=num_pandas)
|
||||
car_fw = get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, num_pandas=num_pandas)
|
||||
@@ -187,7 +188,7 @@ def fingerprint(logcan, sendcan, num_pandas):
|
||||
|
||||
cloudlog.event("fingerprinted", car_fingerprint=car_fingerprint, source=source, fuzzy=not exact_match, cached=cached,
|
||||
fw_count=len(car_fw), ecu_responses=list(ecu_rx_addrs), vin_rx_addr=vin_rx_addr, vin_rx_bus=vin_rx_bus,
|
||||
fingerprints=finger, fw_query_time=fw_query_time, error=True)
|
||||
fingerprints=repr(finger), fw_query_time=fw_query_time, error=True)
|
||||
return car_fingerprint, finger, vin, car_fw, source, exact_match
|
||||
|
||||
|
||||
@@ -195,7 +196,7 @@ def get_car(logcan, sendcan, experimental_long_allowed, num_pandas=1):
|
||||
candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(logcan, sendcan, num_pandas)
|
||||
|
||||
if candidate is None:
|
||||
cloudlog.event("car doesn't match any fingerprints", fingerprints=fingerprints, error=True)
|
||||
cloudlog.event("car doesn't match any fingerprints", fingerprints=repr(fingerprints), error=True)
|
||||
candidate = "mock"
|
||||
|
||||
CarInterface, CarController, CarState = interfaces[candidate]
|
||||
|
||||
@@ -67,6 +67,7 @@ FW_VERSIONS = {
|
||||
(Ecu.engine, 0x7e0, None): [
|
||||
b'68267018AO ',
|
||||
b'68267020AJ ',
|
||||
b'68303534AJ ',
|
||||
b'68340762AD ',
|
||||
b'68340764AD ',
|
||||
b'68352652AE ',
|
||||
@@ -299,6 +300,7 @@ FW_VERSIONS = {
|
||||
CAR.JEEP_GRAND_CHEROKEE_2019: {
|
||||
(Ecu.combinationMeter, 0x742, None): [
|
||||
b'68402703AB',
|
||||
b'68402704AB',
|
||||
b'68402708AB',
|
||||
b'68402971AD',
|
||||
b'68454144AD',
|
||||
@@ -326,6 +328,7 @@ FW_VERSIONS = {
|
||||
(Ecu.eps, 0x75a, None): [
|
||||
b'68417279AA',
|
||||
b'68417280AA',
|
||||
b'68417281AA',
|
||||
b'68453431AA',
|
||||
b'68453433AA',
|
||||
b'68453435AA',
|
||||
@@ -336,6 +339,7 @@ FW_VERSIONS = {
|
||||
(Ecu.engine, 0x7e0, None): [
|
||||
b'05035674AB ',
|
||||
b'68412635AG ',
|
||||
b'68412660AD ',
|
||||
b'68422860AB',
|
||||
b'68449435AE ',
|
||||
b'68496223AA ',
|
||||
@@ -346,6 +350,7 @@ FW_VERSIONS = {
|
||||
(Ecu.transmission, 0x7e1, None): [
|
||||
b'05035707AA',
|
||||
b'68419672AC',
|
||||
b'68419678AB',
|
||||
b'68423905AB',
|
||||
b'68449258AC',
|
||||
b'68495807AA',
|
||||
@@ -359,6 +364,7 @@ FW_VERSIONS = {
|
||||
b'68294051AG',
|
||||
b'68294051AI',
|
||||
b'68294052AG',
|
||||
b'68294052AH',
|
||||
b'68294063AG',
|
||||
b'68294063AH',
|
||||
b'68294063AI',
|
||||
@@ -474,14 +480,17 @@ FW_VERSIONS = {
|
||||
b'05149591AD ',
|
||||
b'05149591AE ',
|
||||
b'05149592AE ',
|
||||
b'05149599AE ',
|
||||
b'05149600AD ',
|
||||
b'05149605AE ',
|
||||
b'05149846AA ',
|
||||
b'05149848AA ',
|
||||
b'05149848AC ',
|
||||
b'05190341AD',
|
||||
b'68378695AJ ',
|
||||
b'68378696AJ ',
|
||||
b'68378701AI ',
|
||||
b'68378702AI ',
|
||||
b'68378710AL ',
|
||||
b'68378748AL ',
|
||||
b'68378758AM ',
|
||||
@@ -603,4 +612,34 @@ FW_VERSIONS = {
|
||||
b'M2421132MB',
|
||||
],
|
||||
},
|
||||
CAR.DODGE_DURANGO: {
|
||||
(Ecu.combinationMeter, 0x742, None): [
|
||||
b'68454261AD',
|
||||
b'68471535AE',
|
||||
],
|
||||
(Ecu.srs, 0x744, None): [
|
||||
b'68355362AB',
|
||||
b'68492238AD',
|
||||
],
|
||||
(Ecu.abs, 0x747, None): [
|
||||
b'68408639AD',
|
||||
b'68499978AB',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x753, None): [
|
||||
b'68440581AE',
|
||||
b'68456722AC',
|
||||
],
|
||||
(Ecu.eps, 0x75a, None): [
|
||||
b'68453435AA',
|
||||
b'68498477AA',
|
||||
],
|
||||
(Ecu.engine, 0x7e0, None): [
|
||||
b'05035786AE ',
|
||||
b'68449476AE ',
|
||||
],
|
||||
(Ecu.transmission, 0x7e1, None): [
|
||||
b'05035826AC',
|
||||
b'68449265AC',
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -28,13 +28,13 @@ class CarInterface(CarInterfaceBase):
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||
if candidate not in RAM_CARS:
|
||||
# Newer FW versions standard on the following platforms, or flashed by a dealer onto older platforms have a higher minimum steering speed.
|
||||
new_eps_platform = candidate in (CAR.PACIFICA_2019_HYBRID, CAR.PACIFICA_2020, CAR.JEEP_GRAND_CHEROKEE_2019)
|
||||
new_eps_platform = candidate in (CAR.PACIFICA_2019_HYBRID, CAR.PACIFICA_2020, CAR.JEEP_GRAND_CHEROKEE_2019, CAR.DODGE_DURANGO)
|
||||
new_eps_firmware = any(fw.ecu == 'eps' and fw.fwVersion[:4] >= b"6841" for fw in car_fw)
|
||||
if new_eps_platform or new_eps_firmware:
|
||||
ret.flags |= ChryslerFlags.HIGHER_MIN_STEERING_SPEED.value
|
||||
|
||||
# Chrysler
|
||||
if candidate in (CAR.PACIFICA_2017_HYBRID, CAR.PACIFICA_2018, CAR.PACIFICA_2018_HYBRID, CAR.PACIFICA_2019_HYBRID, CAR.PACIFICA_2020):
|
||||
if candidate in (CAR.PACIFICA_2017_HYBRID, CAR.PACIFICA_2018, CAR.PACIFICA_2018_HYBRID, CAR.PACIFICA_2019_HYBRID, CAR.PACIFICA_2020, CAR.DODGE_DURANGO):
|
||||
ret.mass = 2242.
|
||||
ret.wheelbase = 3.089
|
||||
ret.steerRatio = 16.2 # Pacifica Hybrid 2017
|
||||
@@ -80,6 +80,7 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
if ret.flags & ChryslerFlags.HIGHER_MIN_STEERING_SPEED:
|
||||
# TODO: allow these cars to steer down to 13 m/s if already engaged.
|
||||
# TODO: Durango 2020 may be able to steer to zero once above 38 kph
|
||||
ret.minSteerSpeed = 17.5 # m/s 17 on the way up, 13 on the way down once engaged.
|
||||
|
||||
ret.centerToFront = ret.wheelbase * 0.44
|
||||
|
||||
@@ -23,6 +23,9 @@ class CAR(StrEnum):
|
||||
PACIFICA_2018 = "CHRYSLER PACIFICA 2018"
|
||||
PACIFICA_2020 = "CHRYSLER PACIFICA 2020"
|
||||
|
||||
# Dodge
|
||||
DODGE_DURANGO = "DODGE DURANGO 2021"
|
||||
|
||||
# Jeep
|
||||
JEEP_GRAND_CHEROKEE = "JEEP GRAND CHEROKEE V6 2018" # includes 2017 Trailhawk
|
||||
JEEP_GRAND_CHEROKEE_2019 = "JEEP GRAND CHEROKEE 2019" # includes 2020 Trailhawk
|
||||
@@ -74,6 +77,7 @@ CAR_INFO: Dict[str, Optional[Union[ChryslerCarInfo, List[ChryslerCarInfo]]]] = {
|
||||
],
|
||||
CAR.JEEP_GRAND_CHEROKEE: ChryslerCarInfo("Jeep Grand Cherokee 2016-18", video_link="https://www.youtube.com/watch?v=eLR9o2JkuRk"),
|
||||
CAR.JEEP_GRAND_CHEROKEE_2019: ChryslerCarInfo("Jeep Grand Cherokee 2019-21", video_link="https://www.youtube.com/watch?v=jBe4lWnRSu4"),
|
||||
CAR.DODGE_DURANGO: ChryslerCarInfo("Dodge Durango 2020-21"),
|
||||
CAR.RAM_1500: ChryslerCarInfo("Ram 1500 2019-24", car_parts=CarParts.common([CarHarness.ram])),
|
||||
CAR.RAM_HD: [
|
||||
ChryslerCarInfo("Ram 2500 2020-24", car_parts=CarParts.common([CarHarness.ram])),
|
||||
@@ -128,6 +132,7 @@ DBC = {
|
||||
CAR.PACIFICA_2020: dbc_dict('chrysler_pacifica_2017_hybrid_generated', 'chrysler_pacifica_2017_hybrid_private_fusion'),
|
||||
CAR.PACIFICA_2018_HYBRID: dbc_dict('chrysler_pacifica_2017_hybrid_generated', 'chrysler_pacifica_2017_hybrid_private_fusion'),
|
||||
CAR.PACIFICA_2019_HYBRID: dbc_dict('chrysler_pacifica_2017_hybrid_generated', 'chrysler_pacifica_2017_hybrid_private_fusion'),
|
||||
CAR.DODGE_DURANGO: dbc_dict('chrysler_pacifica_2017_hybrid_generated', 'chrysler_pacifica_2017_hybrid_private_fusion'),
|
||||
CAR.JEEP_GRAND_CHEROKEE: dbc_dict('chrysler_pacifica_2017_hybrid_generated', 'chrysler_pacifica_2017_hybrid_private_fusion'),
|
||||
CAR.JEEP_GRAND_CHEROKEE_2019: dbc_dict('chrysler_pacifica_2017_hybrid_generated', 'chrysler_pacifica_2017_hybrid_private_fusion'),
|
||||
CAR.RAM_1500: dbc_dict('chrysler_ram_dt_generated', None),
|
||||
|
||||
@@ -54,7 +54,7 @@ class CarState(CarStateBase):
|
||||
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > CarControllerParams.STEER_DRIVER_ALLOWANCE, 5)
|
||||
ret.steerFaultTemporary = cp.vl["EPAS_INFO"]["EPAS_Failure"] == 1
|
||||
ret.steerFaultPermanent = cp.vl["EPAS_INFO"]["EPAS_Failure"] in (2, 3)
|
||||
# ret.espDisabled = False # TODO: find traction control signal
|
||||
ret.espDisabled = cp.vl["Cluster_Info1_FD1"]["DrvSlipCtlMde_D_Rq"] != 0 # 0 is default mode
|
||||
|
||||
if self.CP.carFingerprint in CANFD_CAR:
|
||||
# this signal is always 0 on non-CAN FD cars
|
||||
|
||||
@@ -24,6 +24,7 @@ FW_VERSIONS = {
|
||||
(Ecu.eps, 0x730, None): [
|
||||
b'LX6C-14D003-AF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||
b'LX6C-14D003-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||
b'LX6C-14D003-AK\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||
b'LX6C-14D003-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.abs, 0x760, None): [
|
||||
|
||||
@@ -119,6 +119,7 @@ FW_QUERY_CONFIG = FwQueryConfig(
|
||||
),
|
||||
],
|
||||
extra_ecus=[
|
||||
# We are unlikely to get a response from the PCM from behind the gateway
|
||||
(Ecu.engine, 0x7e0, None),
|
||||
(Ecu.shiftByWire, 0x732, None),
|
||||
],
|
||||
|
||||
@@ -14,7 +14,10 @@ EcuAddrSubAddr = Tuple[int, int, Optional[int]]
|
||||
LiveFwVersions = Dict[AddrType, Set[bytes]]
|
||||
OfflineFwVersions = Dict[str, Dict[EcuAddrSubAddr, List[bytes]]]
|
||||
|
||||
STANDARD_VIN_ADDRS = [0x7e0, 0x7e2, 0x18da10f1, 0x18da0ef1] # engine, VMCU, 29-bit engine, PGM-FI
|
||||
# A global list of addresses we will only ever consider for VIN responses
|
||||
# engine, hybrid controller, Ford abs, Hyundai CAN FD cluster, 29-bit engine, PGM-FI
|
||||
# TODO: move these to each brand's FW query config
|
||||
STANDARD_VIN_ADDRS = [0x7e0, 0x7e2, 0x760, 0x7c4, 0x18da10f1, 0x18da0ef1]
|
||||
|
||||
|
||||
def p16(val):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
from collections import defaultdict
|
||||
from typing import Any, DefaultDict, Dict, List, Optional, Set
|
||||
from typing import Any, DefaultDict, Dict, Iterator, List, Optional, Set, TypeVar
|
||||
from tqdm import tqdm
|
||||
import capnp
|
||||
|
||||
@@ -24,8 +24,10 @@ VERSIONS = get_interface_attr('FW_VERSIONS', ignore_none=True)
|
||||
MODEL_TO_BRAND = {c: b for b, e in VERSIONS.items() for c in e}
|
||||
REQUESTS = [(brand, config, r) for brand, config in FW_QUERY_CONFIGS.items() for r in config.requests]
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
def chunks(l, n=128):
|
||||
|
||||
def chunks(l: List[T], n: int = 128) -> Iterator[List[T]]:
|
||||
for i in range(0, len(l), n):
|
||||
yield l[i:i + n]
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
from openpilot.selfdrive.car.gm.values import CAR
|
||||
|
||||
# Trailblazer also matches as a SILVERADO, TODO: split with fw versions
|
||||
# FIXME: There are Equinox users with different message lengths, specifically 304 and 320
|
||||
|
||||
|
||||
FINGERPRINTS = {
|
||||
@@ -52,6 +53,9 @@ FINGERPRINTS = {
|
||||
}],
|
||||
CAR.EQUINOX: [{
|
||||
190: 6, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 8, 288: 5, 289: 8, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 413: 8, 451: 8, 452: 8, 453: 6, 455: 7, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 500: 6, 501: 8, 510: 8, 528: 5, 532: 6, 560: 8, 562: 8, 563: 5, 565: 5, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 789: 5, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 869: 4, 880: 6, 977: 8, 1001: 8, 1011: 6, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1271: 8, 1280: 4, 1296: 4, 1300: 8, 1611: 8, 1930: 7
|
||||
},
|
||||
{
|
||||
190: 6, 201: 8, 211: 2, 717: 5, 241: 6, 451: 8, 298: 8, 452: 8, 453: 6, 479: 3, 485: 8, 249: 8, 500: 6, 587: 8, 1611: 8, 289: 8, 481: 7, 193: 8, 197: 8, 209: 7, 455: 7, 489: 8, 309: 8, 413: 8, 501: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 311: 8, 510: 8, 528: 5, 532: 6, 715: 8, 560: 8, 562: 8, 707: 8, 789: 5, 869: 4, 880: 6, 761: 7, 840: 5, 842: 5, 844: 8, 313: 8, 381: 8, 386: 8, 810: 8, 322: 7, 384: 4, 800: 6, 1033: 7, 1034: 7, 1296: 4, 753: 5, 388: 8, 288: 5, 497: 8, 463: 3, 304: 3, 977: 8, 1001: 8, 1280: 4, 320: 4, 352: 5, 563: 5, 565: 5, 1221: 5, 1011: 6, 1017: 8, 1020: 8, 1249: 8, 1300: 8, 328: 1, 1217: 8, 1233: 8, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1930: 7, 1271: 8
|
||||
}],
|
||||
}
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ class CarInterface(CarInterfaceBase):
|
||||
# These cars have been put into dashcam only due to both a lack of users and test coverage.
|
||||
# These cars likely still work fine. Once a user confirms each car works and a test route is
|
||||
# added to selfdrive/car/tests/routes.py, we can remove it from this list.
|
||||
ret.dashcamOnly = candidate in {CAR.CADILLAC_ATS, CAR.HOLDEN_ASTRA, CAR.MALIBU, CAR.BUICK_REGAL, CAR.EQUINOX} or \
|
||||
ret.dashcamOnly = candidate in {CAR.CADILLAC_ATS, CAR.HOLDEN_ASTRA, CAR.MALIBU, CAR.BUICK_REGAL} or \
|
||||
(ret.networkLocation == NetworkLocation.gateway and ret.radarUnavailable)
|
||||
|
||||
# Start with a baseline tuning for all GM vehicles. Override tuning as needed in each model section below.
|
||||
|
||||
@@ -719,6 +719,7 @@ FW_VERSIONS = {
|
||||
b'36802-TLA-A040\x00\x00',
|
||||
b'36802-TLA-A050\x00\x00',
|
||||
b'36802-TLA-A060\x00\x00',
|
||||
b'36802-TLA-A070\x00\x00',
|
||||
b'36802-TMC-Q040\x00\x00',
|
||||
b'36802-TMC-Q070\x00\x00',
|
||||
b'36802-TNY-A030\x00\x00',
|
||||
@@ -873,6 +874,7 @@ FW_VERSIONS = {
|
||||
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
|
||||
b'37805-5MR-3050\x00\x00',
|
||||
b'37805-5MR-3250\x00\x00',
|
||||
b'37805-5MR-4070\x00\x00',
|
||||
b'37805-5MR-4080\x00\x00',
|
||||
b'37805-5MR-4180\x00\x00',
|
||||
b'37805-5MR-A240\x00\x00',
|
||||
@@ -918,6 +920,7 @@ FW_VERSIONS = {
|
||||
b'28102-5MX-A900\x00\x00',
|
||||
b'28102-5MX-A910\x00\x00',
|
||||
b'28102-5MX-C001\x00\x00',
|
||||
b'28102-5MX-C910\x00\x00',
|
||||
b'28102-5MX-D001\x00\x00',
|
||||
b'28102-5MX-D710\x00\x00',
|
||||
b'28102-5MX-K610\x00\x00',
|
||||
@@ -955,6 +958,7 @@ FW_VERSIONS = {
|
||||
b'78109-THR-C320\x00\x00',
|
||||
b'78109-THR-C330\x00\x00',
|
||||
b'78109-THR-CE20\x00\x00',
|
||||
b'78109-THR-CL10\x00\x00',
|
||||
b'78109-THR-DA20\x00\x00',
|
||||
b'78109-THR-DA30\x00\x00',
|
||||
b'78109-THR-DA40\x00\x00',
|
||||
@@ -1024,6 +1028,7 @@ FW_VERSIONS = {
|
||||
b'37805-RLV-F120\x00\x00',
|
||||
b'37805-RLV-L080\x00\x00',
|
||||
b'37805-RLV-L090\x00\x00',
|
||||
b'37805-RLV-L150\x00\x00',
|
||||
b'37805-RLV-L160\x00\x00',
|
||||
b'37805-RLV-L180\x00\x00',
|
||||
b'37805-RLV-L350\x00\x00',
|
||||
@@ -1244,6 +1249,7 @@ FW_VERSIONS = {
|
||||
b'39990-T6Z-A020\x00\x00',
|
||||
b'39990-T6Z-A030\x00\x00',
|
||||
b'39990-T6Z-A050\x00\x00',
|
||||
b'39990-T6Z-A110\x00\x00',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x18dab0f1, None): [
|
||||
b'36161-T6Z-A020\x00\x00',
|
||||
@@ -1251,6 +1257,7 @@ FW_VERSIONS = {
|
||||
b'36161-T6Z-A420\x00\x00',
|
||||
b'36161-T6Z-A520\x00\x00',
|
||||
b'36161-T6Z-A620\x00\x00',
|
||||
b'36161-T6Z-A720\x00\x00',
|
||||
b'36161-TJZ-A120\x00\x00',
|
||||
],
|
||||
(Ecu.gateway, 0x18daeff1, None): [
|
||||
@@ -1258,6 +1265,7 @@ FW_VERSIONS = {
|
||||
b'38897-T6Z-A110\x00\x00',
|
||||
],
|
||||
(Ecu.combinationMeter, 0x18da60f1, None): [
|
||||
b'78108-T6Z-AF10\x00\x00',
|
||||
b'78109-T6Z-A420\x00\x00',
|
||||
b'78109-T6Z-A510\x00\x00',
|
||||
b'78109-T6Z-A710\x00\x00',
|
||||
@@ -1275,6 +1283,7 @@ FW_VERSIONS = {
|
||||
b'57114-T6Z-A120\x00\x00',
|
||||
b'57114-T6Z-A130\x00\x00',
|
||||
b'57114-T6Z-A520\x00\x00',
|
||||
b'57114-T6Z-A610\x00\x00',
|
||||
b'57114-TJZ-A520\x00\x00',
|
||||
],
|
||||
},
|
||||
|
||||
@@ -159,7 +159,7 @@ CAR_INFO: Dict[str, Optional[Union[HondaCarInfo, List[HondaCarInfo]]]] = {
|
||||
HondaCarInfo("Honda Pilot 2016-22", min_steer_speed=12. * CV.MPH_TO_MS),
|
||||
HondaCarInfo("Honda Passport 2019-23", "All", min_steer_speed=12. * CV.MPH_TO_MS),
|
||||
],
|
||||
CAR.RIDGELINE: HondaCarInfo("Honda Ridgeline 2017-23", min_steer_speed=12. * CV.MPH_TO_MS),
|
||||
CAR.RIDGELINE: HondaCarInfo("Honda Ridgeline 2017-24", min_steer_speed=12. * CV.MPH_TO_MS),
|
||||
CAR.INSIGHT: HondaCarInfo("Honda Insight 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS),
|
||||
CAR.HONDA_E: HondaCarInfo("Honda e 2020", "All", min_steer_speed=3. * CV.MPH_TO_MS),
|
||||
CAR.CLARITY: HondaCarInfo("Honda Clarity 2018-22"),
|
||||
@@ -207,10 +207,19 @@ FW_QUERY_CONFIG = FwQueryConfig(
|
||||
[StdQueries.UDS_VERSION_REQUEST],
|
||||
[StdQueries.UDS_VERSION_RESPONSE],
|
||||
bus=1,
|
||||
logging=True,
|
||||
obd_multiplexing=False,
|
||||
),
|
||||
],
|
||||
# We lose these ECUs without the comma power on these cars.
|
||||
# Note that we still attempt to match with them when they are present
|
||||
non_essential_ecus={
|
||||
Ecu.programmedFuelInjection: [CAR.CIVIC_BOSCH, CAR.CRV_5G],
|
||||
Ecu.transmission: [CAR.CIVIC_BOSCH, CAR.CRV_5G],
|
||||
Ecu.vsa: [CAR.CIVIC_BOSCH, CAR.CRV_5G],
|
||||
Ecu.combinationMeter: [CAR.CIVIC_BOSCH, CAR.CRV_5G],
|
||||
Ecu.gateway: [CAR.CIVIC_BOSCH, CAR.CRV_5G],
|
||||
Ecu.electricBrakeBooster: [CAR.CIVIC_BOSCH, CAR.CRV_5G],
|
||||
},
|
||||
extra_ecus=[
|
||||
# The only other ECU on PT bus accessible by camera on radarless Civic
|
||||
(Ecu.unknown, 0x18DAB3F1, None),
|
||||
|
||||
@@ -914,12 +914,14 @@ FW_VERSIONS = {
|
||||
(Ecu.transmission, 0x7e1, None): [
|
||||
b'\xf1\x87VDGMD15352242DD3w\x87gxwvgv\x87wvw\x88wXwffVfffUfw\x88o\xff\x06J\xf1\x81E14\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcshcm49 E14\x00\x00\x00\x00\x00\x00\x00SHI0G50NB1tc5\xb7',
|
||||
b'\xf1\x87VDGMD15866192DD3x\x88x\x89wuFvvfUf\x88vWwgwwwvfVgx\x87o\xff\xbc^\xf1\x81E14\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcshcm49 E14\x00\x00\x00\x00\x00\x00\x00SHI0G50NB1tc5\xb7',
|
||||
b'\xf1\x87VDHMD16446682DD3WwwxxvGw\x88\x88\x87\x88\x88whxx\x87\x87\x87\x85fUfwu_\xffT\xf8\xf1\x81E14\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcshcm49 E14\x00\x00\x00\x00\x00\x00\x00SHI0G50NB1tc5\xb7',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00HI__ SCC F-CUP 1.00 1.01 96400-D2100 ',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00HI LKAS AT USA LHD 1.00 1.00 95895-D2020 160302',
|
||||
b'\xf1\x00HI LKAS AT USA LHD 1.00 1.00 95895-D2030 170208',
|
||||
],
|
||||
(Ecu.engine, 0x7e0, None): [
|
||||
b'\xf1\x810000000000\x00',
|
||||
@@ -971,6 +973,7 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00BD MDPS C 1.00 1.02 56310-XX000 4BD2C102',
|
||||
b'\xf1\x00BD MDPS C 1.00 1.08 56310/M6300 4BDDC108',
|
||||
b'\xf1\x00BD MDPS C 1.00 1.08 56310M6300\x00 4BDDC108',
|
||||
b'\xf1\x00BDm MDPS C A.01 1.01 56310M7800\x00 4BPMC101',
|
||||
b'\xf1\x00BDm MDPS C A.01 1.03 56310M7800\x00 4BPMC103',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
@@ -987,11 +990,13 @@ FW_VERSIONS = {
|
||||
b'\xf1\x81616F2051\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.abs, 0x7d1, None): [
|
||||
b'\xf1\x00\x00\x00\x00\x00\x00\x00',
|
||||
b'\xf1\x816VGRAH00018.ELF\xf1\x00\x00\x00\x00\x00\x00\x00',
|
||||
b'\xf1\x8758900-M7AB0 \xf1\x816VQRAD00127.ELF\xf1\x00\x00\x00\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.transmission, 0x7e1, None): [
|
||||
b'\xf1\x006V2B0_C2\x00\x006V2C6051\x00\x00CBD0N20NL1\x00\x00\x00\x00',
|
||||
b'\xf1\x006V2B0_C2\x00\x006V2C6051\x00\x00CBD0N20NL1\x90@\xc6\xae',
|
||||
b'\xf1\x816U2VC051\x00\x00\xf1\x006U2V0_C2\x00\x006U2VC051\x00\x00DBD0T16SS0\x00\x00\x00\x00',
|
||||
b"\xf1\x816U2VC051\x00\x00\xf1\x006U2V0_C2\x00\x006U2VC051\x00\x00DBD0T16SS0\xcf\x1e'\xc3",
|
||||
],
|
||||
@@ -1198,16 +1203,19 @@ FW_VERSIONS = {
|
||||
},
|
||||
CAR.KIA_NIRO_PHEV_2022: {
|
||||
(Ecu.engine, 0x7e0, None): [
|
||||
b'\xf1\x816H6G5051\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||
b'\xf1\x816H6G6051\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.transmission, 0x7e1, None): [
|
||||
b'\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PDE0G16NL3\x00\x00\x00\x00',
|
||||
b'\xf1\x816U3J9051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PDE0G16NL3\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.eps, 0x7d4, None): [
|
||||
b'\xf1\x00DE MDPS C 1.00 1.01 56310G5520\x00 4DEPC101',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00DEP MFC AT USA LHD 1.00 1.00 99211-G5500 210428',
|
||||
b'\xf1\x00DEP MFC AT USA LHD 1.00 1.06 99211-G5000 201028',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00DEhe SCC F-CUP 1.00 1.00 99110-G5600 ',
|
||||
@@ -1347,22 +1355,28 @@ FW_VERSIONS = {
|
||||
CAR.ELANTRA_GT_I30: {
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00PD LKAS AT KOR LHD 1.00 1.02 95740-G3000 A51',
|
||||
b'\xf1\x00PD LKAS AT USA LHD 1.00 1.02 95740-G3000 A51',
|
||||
b'\xf1\x00PD LKAS AT USA LHD 1.01 1.01 95740-G3100 A54',
|
||||
],
|
||||
(Ecu.transmission, 0x7e1, None): [
|
||||
b'\xf1\x006U2U0_C2\x00\x006U2T0051\x00\x00DPD0D16KS0u\xce\x1fk',
|
||||
b'\xf1\x006U2V0_C2\x00\x006U2V8051\x00\x00DPD0T16NS4\x00\x00\x00\x00',
|
||||
b'\xf1\x006U2V0_C2\x00\x006U2V8051\x00\x00DPD0T16NS4\xda\x7f\xd6\xa7',
|
||||
b'\xf1\x006U2V0_C2\x00\x006U2VA051\x00\x00DPD0H16NS0e\x0e\xcd\x8e',
|
||||
],
|
||||
(Ecu.eps, 0x7d4, None): [
|
||||
b'\xf1\x00PD MDPS C 1.00 1.00 56310G3300\x00 4PDDC100',
|
||||
b'\xf1\x00PD MDPS C 1.00 1.03 56310/G3300 4PDDC103',
|
||||
b'\xf1\x00PD MDPS C 1.00 1.04 56310/G3300 4PDDC104',
|
||||
],
|
||||
(Ecu.abs, 0x7d1, None): [
|
||||
b'\xf1\x00PD ESC \t 104\x18\t\x03 58920-G3350',
|
||||
b'\xf1\x00PD ESC \x0b 103\x17\x110 58920-G3350',
|
||||
b'\xf1\x00PD ESC \x0b 104\x18\t\x03 58920-G3350',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00PD__ SCC F-CUP 1.00 1.00 96400-G3300 ',
|
||||
b'\xf1\x00PD__ SCC F-CUP 1.01 1.00 96400-G3100 ',
|
||||
b'\xf1\x00PD__ SCC FNCUP 1.01 1.00 96400-G3000 ',
|
||||
],
|
||||
},
|
||||
@@ -1542,6 +1556,7 @@ FW_VERSIONS = {
|
||||
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.03 99211-GI010 220401',
|
||||
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.05 99211-GI010 220614',
|
||||
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.06 99211-GI010 230110',
|
||||
b'\xf1\x00NE1 MFC AT KOR LHD 1.00 1.00 99211-GI020 230719',
|
||||
],
|
||||
},
|
||||
CAR.IONIQ_6: {
|
||||
@@ -1555,6 +1570,7 @@ FW_VERSIONS = {
|
||||
},
|
||||
CAR.TUCSON_4TH_GEN: {
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
b'\xf1\x00NX4 FR_CMR AT EUR LHD 1.00 1.00 99211-N9220 14K',
|
||||
b'\xf1\x00NX4 FR_CMR AT EUR LHD 1.00 2.02 99211-N9000 14E',
|
||||
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9210 14G',
|
||||
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9220 14K',
|
||||
@@ -1567,6 +1583,7 @@ FW_VERSIONS = {
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00NX4__ 1.00 1.00 99110-N9100 ',
|
||||
b'\xf1\x00NX4__ 1.00 1.01 99110-N9000 ',
|
||||
b'\xf1\x00NX4__ 1.00 1.02 99110-N9000 ',
|
||||
b'\xf1\x00NX4__ 1.01 1.00 99110-N9100 ',
|
||||
],
|
||||
},
|
||||
@@ -1625,6 +1642,7 @@ FW_VERSIONS = {
|
||||
],
|
||||
(Ecu.fwdRadar, 0x7d0, None): [
|
||||
b'\xf1\x00MQ4_ SCC F-CUP 1.00 1.06 99110-P2000 ',
|
||||
b'\xf1\x00MQ4_ SCC FHCUP 1.00 1.00 99110-R5000 ',
|
||||
b'\xf1\x00MQ4_ SCC FHCUP 1.00 1.06 99110-P2000 ',
|
||||
b'\xf1\x00MQ4_ SCC FHCUP 1.00 1.08 99110-P2000 ',
|
||||
],
|
||||
|
||||
@@ -11,7 +11,6 @@ from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||
from openpilot.selfdrive.car.disable_ecu import disable_ecu
|
||||
|
||||
Ecu = car.CarParams.Ecu
|
||||
SafetyModel = car.CarParams.SafetyModel
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
EventName = car.CarEvent.EventName
|
||||
ENABLE_BUTTONS = (Buttons.RES_ACCEL, Buttons.SET_DECEL, Buttons.CANCEL)
|
||||
@@ -19,17 +18,6 @@ BUTTONS_DICT = {Buttons.RES_ACCEL: ButtonType.accelCruise, Buttons.SET_DECEL: Bu
|
||||
Buttons.GAP_DIST: ButtonType.gapAdjustCruise, Buttons.CANCEL: ButtonType.cancel}
|
||||
|
||||
|
||||
def set_safety_config_hyundai(candidate, CAN, can_fd=False):
|
||||
platform = SafetyModel.hyundaiCanfd if can_fd else \
|
||||
SafetyModel.hyundaiLegacy if candidate in LEGACY_SAFETY_MODE_CAR else \
|
||||
SafetyModel.hyundai
|
||||
cfgs = [get_safety_config(platform), ]
|
||||
if CAN.ECAN >= 4:
|
||||
cfgs.insert(0, get_safety_config(SafetyModel.noOutput))
|
||||
|
||||
return cfgs
|
||||
|
||||
|
||||
class CarInterface(CarInterfaceBase):
|
||||
@staticmethod
|
||||
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
@@ -55,6 +43,7 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
# detect HDA2 with ADAS Driving ECU
|
||||
if hda2:
|
||||
ret.flags |= HyundaiFlags.CANFD_HDA2.value
|
||||
if 0x110 in fingerprint[CAN.CAM]:
|
||||
ret.flags |= HyundaiFlags.CANFD_HDA2_ALT_STEERING.value
|
||||
else:
|
||||
@@ -314,22 +303,33 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.spFlags |= HyundaiFlagsSP.SP_NAV_MSG.value
|
||||
|
||||
# *** panda safety config ***
|
||||
ret.safetyConfigs = set_safety_config_hyundai(candidate, CAN, can_fd=(candidate in CANFD_CAR))
|
||||
|
||||
if hda2:
|
||||
ret.flags |= HyundaiFlags.CANFD_HDA2.value
|
||||
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_HDA2
|
||||
|
||||
if candidate in CANFD_CAR:
|
||||
if hda2 and ret.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING:
|
||||
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_HDA2_ALT_STEERING
|
||||
cfgs = [get_safety_config(car.CarParams.SafetyModel.hyundaiCanfd), ]
|
||||
if CAN.ECAN >= 4:
|
||||
cfgs.insert(0, get_safety_config(car.CarParams.SafetyModel.noOutput))
|
||||
ret.safetyConfigs = cfgs
|
||||
|
||||
if ret.flags & HyundaiFlags.CANFD_HDA2:
|
||||
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_HDA2
|
||||
if ret.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING:
|
||||
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_HDA2_ALT_STEERING
|
||||
if ret.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
||||
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_ALT_BUTTONS
|
||||
if ret.flags & HyundaiFlags.CANFD_CAMERA_SCC:
|
||||
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CAMERA_SCC
|
||||
else:
|
||||
if candidate in LEGACY_SAFETY_MODE_CAR:
|
||||
# these cars require a special panda safety mode due to missing counters and checksums in the messages
|
||||
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hyundaiLegacy)]
|
||||
else:
|
||||
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hyundai, 0)]
|
||||
|
||||
if candidate in CAMERA_SCC_CAR:
|
||||
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_HYUNDAI_CAMERA_SCC
|
||||
|
||||
if ret.spFlags & HyundaiFlagsSP.SP_ENHANCED_SCC:
|
||||
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_HYUNDAI_ESCC
|
||||
|
||||
if ret.flags & HyundaiFlags.CANFD_CAMERA_SCC or candidate in CAMERA_SCC_CAR:
|
||||
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CAMERA_SCC
|
||||
if ret.spFlags & HyundaiFlagsSP.SP_ENHANCED_SCC:
|
||||
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_HYUNDAI_ESCC
|
||||
if ret.openpilotLongitudinalControl:
|
||||
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_LONG
|
||||
if ret.flags & HyundaiFlags.HYBRID:
|
||||
|
||||
@@ -260,7 +260,10 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
|
||||
HyundaiCarInfo("Kia Niro Plug-in Hybrid 2018-19", "All", min_enable_speed=10. * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_c])),
|
||||
HyundaiCarInfo("Kia Niro Plug-in Hybrid 2020", "All", car_parts=CarParts.common([CarHarness.hyundai_d])),
|
||||
],
|
||||
CAR.KIA_NIRO_PHEV_2022: HyundaiCarInfo("Kia Niro Plug-in Hybrid 2022", "All", car_parts=CarParts.common([CarHarness.hyundai_f])),
|
||||
CAR.KIA_NIRO_PHEV_2022: [
|
||||
HyundaiCarInfo("Kia Niro Plug-in Hybrid 2021", "All", car_parts=CarParts.common([CarHarness.hyundai_d])),
|
||||
HyundaiCarInfo("Kia Niro Plug-in Hybrid 2022", "All", car_parts=CarParts.common([CarHarness.hyundai_f])),
|
||||
],
|
||||
CAR.KIA_NIRO_HEV_2021: [
|
||||
HyundaiCarInfo("Kia Niro Hybrid 2021", car_parts=CarParts.common([CarHarness.hyundai_d])),
|
||||
HyundaiCarInfo("Kia Niro Hybrid 2022", car_parts=CarParts.common([CarHarness.hyundai_f])),
|
||||
@@ -413,6 +416,9 @@ HYUNDAI_VERSION_REQUEST_MULTI = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]
|
||||
p16(uds.DATA_IDENTIFIER_TYPE.APPLICATION_SOFTWARE_IDENTIFICATION) + \
|
||||
p16(0xf100)
|
||||
|
||||
HYUNDAI_ECU_MANUFACTURING_DATE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \
|
||||
p16(uds.DATA_IDENTIFIER_TYPE.ECU_MANUFACTURING_DATE)
|
||||
|
||||
HYUNDAI_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40])
|
||||
|
||||
# Regex patterns for parsing platform code, FW date, and part number from FW versions
|
||||
@@ -431,6 +437,8 @@ PLATFORM_CODE_ECUS = [Ecu.fwdRadar, Ecu.fwdCamera, Ecu.eps]
|
||||
# TODO: there are date codes in the ABS firmware versions in hex
|
||||
DATE_FW_ECUS = [Ecu.fwdCamera]
|
||||
|
||||
ALL_HYUNDAI_ECUS = [Ecu.eps, Ecu.abs, Ecu.fwdRadar, Ecu.fwdCamera, Ecu.engine, Ecu.parkingAdas, Ecu.transmission, Ecu.adas, Ecu.hvac, Ecu.cornerRadar]
|
||||
|
||||
FW_QUERY_CONFIG = FwQueryConfig(
|
||||
requests=[
|
||||
# TODO: minimize shared whitelists for CAN and cornerRadar for CAN-FD
|
||||
@@ -464,13 +472,52 @@ FW_QUERY_CONFIG = FwQueryConfig(
|
||||
obd_multiplexing=False,
|
||||
),
|
||||
|
||||
# CAN-FD debugging queries
|
||||
# CAN & CAN FD query to understand the three digit date code
|
||||
# HDA2 cars usually use 6 digit date codes, so skip bus 1
|
||||
Request(
|
||||
[HYUNDAI_ECU_MANUFACTURING_DATE],
|
||||
[HYUNDAI_VERSION_RESPONSE],
|
||||
whitelist_ecus=[Ecu.fwdCamera],
|
||||
bus=0,
|
||||
auxiliary=True,
|
||||
logging=True,
|
||||
),
|
||||
|
||||
# CAN & CAN FD logging queries (from camera)
|
||||
Request(
|
||||
[HYUNDAI_VERSION_REQUEST_LONG],
|
||||
[HYUNDAI_VERSION_RESPONSE],
|
||||
whitelist_ecus=ALL_HYUNDAI_ECUS,
|
||||
bus=0,
|
||||
auxiliary=True,
|
||||
logging=True,
|
||||
),
|
||||
Request(
|
||||
[HYUNDAI_VERSION_REQUEST_MULTI],
|
||||
[HYUNDAI_VERSION_RESPONSE],
|
||||
whitelist_ecus=ALL_HYUNDAI_ECUS,
|
||||
bus=0,
|
||||
auxiliary=True,
|
||||
logging=True,
|
||||
),
|
||||
Request(
|
||||
[HYUNDAI_VERSION_REQUEST_LONG],
|
||||
[HYUNDAI_VERSION_RESPONSE],
|
||||
whitelist_ecus=ALL_HYUNDAI_ECUS,
|
||||
bus=1,
|
||||
auxiliary=True,
|
||||
obd_multiplexing=False,
|
||||
logging=True,
|
||||
),
|
||||
|
||||
# CAN-FD alt request logging queries
|
||||
Request(
|
||||
[HYUNDAI_VERSION_REQUEST_ALT],
|
||||
[HYUNDAI_VERSION_RESPONSE],
|
||||
whitelist_ecus=[Ecu.parkingAdas, Ecu.hvac],
|
||||
bus=0,
|
||||
auxiliary=True,
|
||||
logging=True,
|
||||
),
|
||||
Request(
|
||||
[HYUNDAI_VERSION_REQUEST_ALT],
|
||||
@@ -478,6 +525,7 @@ FW_QUERY_CONFIG = FwQueryConfig(
|
||||
whitelist_ecus=[Ecu.parkingAdas, Ecu.hvac],
|
||||
bus=1,
|
||||
auxiliary=True,
|
||||
logging=True,
|
||||
obd_multiplexing=False,
|
||||
),
|
||||
],
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import numpy as np
|
||||
import tomllib
|
||||
from abc import abstractmethod, ABC
|
||||
@@ -323,13 +322,14 @@ class RadarInterfaceBase(ABC):
|
||||
self.pts = {}
|
||||
self.delay = 0
|
||||
self.radar_ts = CP.radarTimeStep
|
||||
self.frame = 0
|
||||
self.no_radar_sleep = 'NO_RADAR_SLEEP' in os.environ
|
||||
|
||||
def update(self, can_strings):
|
||||
ret = car.RadarData.new_message()
|
||||
if not self.no_radar_sleep:
|
||||
time.sleep(self.radar_ts) # radard runs on RI updates
|
||||
return ret
|
||||
self.frame += 1
|
||||
if (self.frame % int(100 * self.radar_ts)) == 0:
|
||||
return car.RadarData.new_message()
|
||||
return None
|
||||
|
||||
|
||||
class CarStateBase(ABC):
|
||||
|
||||
@@ -5,11 +5,14 @@ from functools import partial
|
||||
import cereal.messaging as messaging
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
from openpilot.selfdrive.boardd.boardd import can_list_to_can_capnp
|
||||
from openpilot.selfdrive.car.fw_query_definitions import AddrType
|
||||
from panda.python.uds import CanClient, IsoTpMessage, FUNCTIONAL_ADDRS, get_rx_addr_for_tx_addr
|
||||
|
||||
|
||||
class IsoTpParallelQuery:
|
||||
def __init__(self, sendcan, logcan, bus, addrs, request, response, response_offset=0x8, functional_addrs=None, debug=False, response_pending_timeout=10):
|
||||
def __init__(self, sendcan: messaging.PubSocket, logcan: messaging.SubSocket, bus: int, addrs: list[int] | list[AddrType],
|
||||
request: list[bytes], response: list[bytes], response_offset: int = 0x8,
|
||||
functional_addrs: list[int] | None = None, debug: bool = False, response_pending_timeout: float = 10) -> None:
|
||||
self.sendcan = sendcan
|
||||
self.logcan = logcan
|
||||
self.bus = bus
|
||||
@@ -24,7 +27,7 @@ class IsoTpParallelQuery:
|
||||
assert tx_addr not in FUNCTIONAL_ADDRS, f"Functional address should be defined in functional_addrs: {hex(tx_addr)}"
|
||||
|
||||
self.msg_addrs = {tx_addr: get_rx_addr_for_tx_addr(tx_addr[0], rx_offset=response_offset) for tx_addr in real_addrs}
|
||||
self.msg_buffer = defaultdict(list)
|
||||
self.msg_buffer: dict[int, list[tuple[int, int, bytes, int]]] = defaultdict(list)
|
||||
|
||||
def rx(self):
|
||||
"""Drain can socket and sort messages into buffers based on address"""
|
||||
@@ -63,7 +66,7 @@ class IsoTpParallelQuery:
|
||||
messaging.drain_sock_raw(self.logcan)
|
||||
self.msg_buffer = defaultdict(list)
|
||||
|
||||
def _create_isotp_msg(self, tx_addr, sub_addr, rx_addr):
|
||||
def _create_isotp_msg(self, tx_addr: int, sub_addr: int | None, rx_addr: int):
|
||||
can_client = CanClient(self._can_tx, partial(self._can_rx, rx_addr, sub_addr=sub_addr), tx_addr, rx_addr,
|
||||
self.bus, sub_addr=sub_addr, debug=self.debug)
|
||||
|
||||
@@ -73,7 +76,7 @@ class IsoTpParallelQuery:
|
||||
# as well as reduces chances we process messages from previous queries
|
||||
return IsoTpMessage(can_client, timeout=0, separation_time=0.01, debug=self.debug, max_len=max_len)
|
||||
|
||||
def get_data(self, timeout, total_timeout=60.):
|
||||
def get_data(self, timeout: float, total_timeout: float = 60.) -> dict[AddrType, bytes]:
|
||||
self._drain_rx()
|
||||
|
||||
# Create message objects
|
||||
|
||||
@@ -32,7 +32,7 @@ class CarState(CarStateBase):
|
||||
|
||||
# Match panda speed reading
|
||||
speed_kph = cp.vl["ENGINE_DATA"]["SPEED"]
|
||||
ret.standstill = speed_kph < .1
|
||||
ret.standstill = speed_kph <= .1
|
||||
|
||||
can_gear = int(cp.vl["GEAR"]["GEAR"])
|
||||
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(can_gear, None))
|
||||
|
||||
@@ -22,7 +22,7 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
def _update(self, c):
|
||||
self.sm.update(0)
|
||||
gps_sock = 'gpsLocationExternal' if self.sm.rcv_frame['gpsLocationExternal'] > 1 else 'gpsLocation'
|
||||
gps_sock = 'gpsLocationExternal' if self.sm.recv_frame['gpsLocationExternal'] > 1 else 'gpsLocation'
|
||||
|
||||
ret = car.CarState.new_message()
|
||||
ret.vEgo = self.sm[gps_sock].speed
|
||||
|
||||
@@ -45,15 +45,28 @@ FW_VERSIONS = {
|
||||
},
|
||||
CAR.LEAF: {
|
||||
(Ecu.abs, 0x740, None): [
|
||||
b'476605SA1C',
|
||||
b'476605SC2D',
|
||||
b'476606WK7B',
|
||||
b'476606WK9B',
|
||||
],
|
||||
(Ecu.eps, 0x742, None): [
|
||||
b'5SA2A\x99A\x05\x02N123F\x15b\x00\x00\x00\x00\x00\x00\x00\x80',
|
||||
b'5SA2A\xb7A\x05\x02N123F\x15\xa2\x00\x00\x00\x00\x00\x00\x00\x80',
|
||||
b'5SN2A\xb7A\x05\x02N123F\x15\xa2\x00\x00\x00\x00\x00\x00\x00\x80',
|
||||
b'5SN2A\xb7A\x05\x02N126F\x15\xb2\x00\x00\x00\x00\x00\x00\x00\x80',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x707, None): [
|
||||
b'5SA0ADB\x04\x18\x00\x00\x00\x00\x00_*6\x04\x94a\x00\x00\x00\x80',
|
||||
b'5SA2ADB\x04\x18\x00\x00\x00\x00\x00_*6\x04\x94a\x00\x00\x00\x80',
|
||||
b'6WK2ADB\x04\x18\x00\x00\x00\x00\x00R;1\x18\x99\x10\x00\x00\x00\x80',
|
||||
b'6WK2BDB\x04\x18\x00\x00\x00\x00\x00R;1\x18\x99\x10\x00\x00\x00\x80',
|
||||
b'6WK2CDB\x04\x18\x00\x00\x00\x00\x00R=1\x18\x99\x10\x00\x00\x00\x80',
|
||||
],
|
||||
(Ecu.gateway, 0x18dad0f1, None): [
|
||||
b'284U25SA3C',
|
||||
b'284U25SP1C',
|
||||
b'284U26WK0A',
|
||||
b'284U26WK0C',
|
||||
],
|
||||
},
|
||||
|
||||
@@ -13,6 +13,15 @@ def create_steering_control(packer, apply_steer, steer_req):
|
||||
return packer.make_can_msg("ES_LKAS", 0, values)
|
||||
|
||||
|
||||
def create_steering_control_angle(packer, apply_steer, steer_req):
|
||||
values = {
|
||||
"LKAS_Output": apply_steer,
|
||||
"LKAS_Request": steer_req,
|
||||
"SET_3": 3
|
||||
}
|
||||
return packer.make_can_msg("ES_LKAS_ANGLE", 0, values)
|
||||
|
||||
|
||||
def create_steering_status(packer):
|
||||
return packer.make_can_msg("ES_LKAS_State", 0, {})
|
||||
|
||||
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR=$(dirname "$0")
|
||||
BASEDIR=$(realpath "$SCRIPT_DIR/../../../")
|
||||
cd $BASEDIR
|
||||
|
||||
MAX_EXAMPLES=300
|
||||
INTERNAL_SEG_CNT=300
|
||||
FILEREADER_CACHE=1
|
||||
INTERNAL_SEG_LIST=selfdrive/car/tests/test_models_segs.txt
|
||||
|
||||
cd selfdrive/car/tests && pytest test_models.py test_car_interfaces.py
|
||||
@@ -20,7 +20,6 @@ non_tested_cars = [
|
||||
GM.CADILLAC_ATS,
|
||||
GM.HOLDEN_ASTRA,
|
||||
GM.MALIBU,
|
||||
GM.EQUINOX,
|
||||
HYUNDAI.GENESIS_G90,
|
||||
HONDA.ODYSSEY_CHN,
|
||||
VOLKSWAGEN.CRAFTER_MK2, # need a route from an ACC-equipped Crafter
|
||||
@@ -46,6 +45,7 @@ routes = [
|
||||
CarTestRoute("3d84727705fecd04|2021-05-25--08-38-56", CHRYSLER.PACIFICA_2020),
|
||||
CarTestRoute("221c253375af4ee9|2022-06-15--18-38-24", CHRYSLER.RAM_1500),
|
||||
CarTestRoute("8fb5eabf914632ae|2022-08-04--17-28-53", CHRYSLER.RAM_HD, segment=6),
|
||||
CarTestRoute("3379c85aeedc8285|2023-12-07--17-49-39", CHRYSLER.DODGE_DURANGO),
|
||||
|
||||
CarTestRoute("54827bf84c38b14f|2023-01-25--14-14-11", FORD.BRONCO_SPORT_MK1),
|
||||
CarTestRoute("f8eaaccd2a90aef8|2023-05-04--15-10-09", FORD.ESCAPE_MK4),
|
||||
@@ -59,6 +59,7 @@ routes = [
|
||||
CarTestRoute("7cc2a8365b4dd8a9|2018-12-02--12-10-44", GM.ACADIA),
|
||||
CarTestRoute("aa20e335f61ba898|2019-02-05--16-59-04", GM.BUICK_REGAL),
|
||||
CarTestRoute("75a6bcb9b8b40373|2023-03-11--22-47-33", GM.BUICK_LACROSSE),
|
||||
CarTestRoute("e746f59bc96fd789|2024-01-31--22-25-58", GM.EQUINOX),
|
||||
CarTestRoute("ef8f2185104d862e|2023-02-09--18-37-13", GM.ESCALADE),
|
||||
CarTestRoute("46460f0da08e621e|2021-10-26--07-21-46", GM.ESCALADE_ESV),
|
||||
CarTestRoute("168f8b3be57f66ae|2023-09-12--21-44-42", GM.ESCALADE_ESV_2019),
|
||||
@@ -207,6 +208,7 @@ routes = [
|
||||
CarTestRoute("ec429c0f37564e3c|2020-02-01--17-28-12", TOYOTA.LEXUS_NX), # hybrid
|
||||
CarTestRoute("3fd5305f8b6ca765|2021-04-28--19-26-49", TOYOTA.LEXUS_NX_TSS2),
|
||||
CarTestRoute("09ae96064ed85a14|2022-06-09--12-22-31", TOYOTA.LEXUS_NX_TSS2), # hybrid
|
||||
CarTestRoute("4765fbbf59e3cd88|2024-02-06--17-45-32", TOYOTA.LEXUS_LC_TSS2),
|
||||
CarTestRoute("0a302ffddbb3e3d3|2020-02-08--16-19-08", TOYOTA.HIGHLANDER_TSS2),
|
||||
CarTestRoute("437e4d2402abf524|2021-05-25--07-58-50", TOYOTA.HIGHLANDER_TSS2), # hybrid
|
||||
CarTestRoute("3183cd9b021e89ce|2021-05-25--10-34-44", TOYOTA.HIGHLANDER),
|
||||
|
||||
@@ -14,6 +14,10 @@ from openpilot.selfdrive.car.car_helpers import interfaces
|
||||
from openpilot.selfdrive.car.fingerprints import all_known_cars
|
||||
from openpilot.selfdrive.car.fw_versions import FW_VERSIONS
|
||||
from openpilot.selfdrive.car.interfaces import get_interface_attr
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
|
||||
from openpilot.selfdrive.controls.lib.longcontrol import LongControl
|
||||
from openpilot.selfdrive.test.fuzzy_generation import DrawType, FuzzyGenerator
|
||||
|
||||
ALL_ECUS = list({ecu for ecus in FW_VERSIONS.values() for ecu in ecus.keys()})
|
||||
@@ -42,11 +46,6 @@ def get_fuzzy_car_interface_args(draw: DrawType) -> dict:
|
||||
|
||||
|
||||
class TestCarInterfaces(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
os.environ['NO_RADAR_SLEEP'] = '1'
|
||||
|
||||
# FIXME: Due to the lists used in carParams, Phase.target is very slow and will cause
|
||||
# many generated examples to overrun when max_examples > ~20, don't use it
|
||||
@parameterized.expand([(car,) for car in sorted(all_known_cars())])
|
||||
@@ -105,6 +104,17 @@ class TestCarInterfaces(unittest.TestCase):
|
||||
car_interface.apply(CC, now_nanos)
|
||||
now_nanos += DT_CTRL * 1e9 # 10ms
|
||||
|
||||
# Test controller initialization
|
||||
# TODO: wait until card refactor is merged to run controller a few times,
|
||||
# hypothesis also slows down significantly with just one more message draw
|
||||
LongControl(car_params)
|
||||
if car_params.steerControlType == car.CarParams.SteerControlType.angle:
|
||||
LatControlAngle(car_params, car_interface)
|
||||
elif car_params.lateralTuning.which() == 'pid':
|
||||
LatControlPID(car_params, car_interface)
|
||||
elif car_params.lateralTuning.which() == 'torque':
|
||||
LatControlTorque(car_params, car_interface)
|
||||
|
||||
# Test radar interface
|
||||
RadarInterface = importlib.import_module(f'selfdrive.car.{car_params.carName}.radar_interface').RadarInterface
|
||||
radar_interface = RadarInterface(car_params)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
import pytest
|
||||
import random
|
||||
import time
|
||||
import unittest
|
||||
@@ -226,7 +225,7 @@ class TestFwFingerprintTiming(unittest.TestCase):
|
||||
|
||||
def test_startup_timing(self):
|
||||
# Tests worse-case VIN query time and typical present ECU query time
|
||||
vin_ref_times = {'worst': 1.5, 'best': 0.5} # best assumes we go through all queries to get a match
|
||||
vin_ref_times = {'worst': 1.0, 'best': 0.5} # best assumes we go through all queries to get a match
|
||||
present_ecu_ref_time = 0.75
|
||||
|
||||
def fake_get_ecu_addrs(*_, timeout):
|
||||
@@ -252,9 +251,8 @@ class TestFwFingerprintTiming(unittest.TestCase):
|
||||
self._assert_timing(self.total_time / self.N, vin_ref_times[name])
|
||||
print(f'get_vin {name} case, query time={self.total_time / self.N} seconds')
|
||||
|
||||
@pytest.mark.timeout(60)
|
||||
def test_fw_query_timing(self):
|
||||
total_ref_time = 6.8
|
||||
total_ref_time = {1: 5.95, 2: 6.85}
|
||||
brand_ref_times = {
|
||||
1: {
|
||||
'gm': 0.5,
|
||||
@@ -262,7 +260,7 @@ class TestFwFingerprintTiming(unittest.TestCase):
|
||||
'chrysler': 0.3,
|
||||
'ford': 0.1,
|
||||
'honda': 0.55,
|
||||
'hyundai': 0.65,
|
||||
'hyundai': 1.05,
|
||||
'mazda': 0.1,
|
||||
'nissan': 0.8,
|
||||
'subaru': 0.45,
|
||||
@@ -272,28 +270,31 @@ class TestFwFingerprintTiming(unittest.TestCase):
|
||||
},
|
||||
2: {
|
||||
'ford': 0.2,
|
||||
'hyundai': 1.05,
|
||||
'hyundai': 1.85,
|
||||
}
|
||||
}
|
||||
|
||||
total_time = 0
|
||||
total_times = {1: 0.0, 2: 0.0}
|
||||
for num_pandas in (1, 2):
|
||||
for brand, config in FW_QUERY_CONFIGS.items():
|
||||
with self.subTest(brand=brand, num_pandas=num_pandas):
|
||||
multi_panda_requests = [r for r in config.requests if r.bus > 3]
|
||||
if not len(multi_panda_requests) and num_pandas > 1:
|
||||
raise unittest.SkipTest("No multi-panda FW queries")
|
||||
|
||||
avg_time = self._benchmark_brand(brand, num_pandas)
|
||||
total_time += avg_time
|
||||
total_times[num_pandas] += avg_time
|
||||
avg_time = round(avg_time, 2)
|
||||
self._assert_timing(avg_time, brand_ref_times[num_pandas][brand])
|
||||
|
||||
ref_time = brand_ref_times[num_pandas].get(brand)
|
||||
if ref_time is None:
|
||||
# ref time should be same as 1 panda if no aux queries
|
||||
ref_time = brand_ref_times[num_pandas - 1][brand]
|
||||
|
||||
self._assert_timing(avg_time, ref_time)
|
||||
print(f'{brand=}, {num_pandas=}, {len(config.requests)=}, avg FW query time={avg_time} seconds')
|
||||
|
||||
with self.subTest(brand='all_brands'):
|
||||
total_time = round(total_time, 2)
|
||||
self._assert_timing(total_time, total_ref_time)
|
||||
print(f'all brands, total FW query time={total_time} seconds')
|
||||
for num_pandas in (1, 2):
|
||||
with self.subTest(brand='all_brands', num_pandas=num_pandas):
|
||||
total_time = round(total_times[num_pandas], 2)
|
||||
self._assert_timing(total_time, total_ref_time[num_pandas])
|
||||
print(f'all brands, total FW query time={total_time} seconds')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -23,9 +23,8 @@ from openpilot.selfdrive.car.tests.routes import non_tested_cars, routes, CarTes
|
||||
from openpilot.selfdrive.controls.controlsd import Controls
|
||||
from openpilot.selfdrive.test.helpers import read_segment_list
|
||||
from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT
|
||||
from openpilot.tools.lib.comma_car_segments import get_url
|
||||
from openpilot.tools.lib.logreader import LogReader
|
||||
from openpilot.tools.lib.route import Route, SegmentName, RouteName
|
||||
from openpilot.tools.lib.logreader import LogReader, internal_source, openpilotci_source
|
||||
from openpilot.tools.lib.route import SegmentName
|
||||
|
||||
from panda.tests.libpanda import libpanda_py
|
||||
|
||||
@@ -37,7 +36,7 @@ NUM_JOBS = int(os.environ.get("NUM_JOBS", "1"))
|
||||
JOB_ID = int(os.environ.get("JOB_ID", "0"))
|
||||
INTERNAL_SEG_LIST = os.environ.get("INTERNAL_SEG_LIST", "")
|
||||
INTERNAL_SEG_CNT = int(os.environ.get("INTERNAL_SEG_CNT", "0"))
|
||||
MAX_EXAMPLES = int(os.environ.get("MAX_EXAMPLES", "50"))
|
||||
MAX_EXAMPLES = int(os.environ.get("MAX_EXAMPLES", "300"))
|
||||
CI = os.environ.get("CI", None) is not None
|
||||
|
||||
|
||||
@@ -75,14 +74,6 @@ class TestCarModelBase(unittest.TestCase):
|
||||
elm_frame: Optional[int]
|
||||
car_safety_mode_frame: Optional[int]
|
||||
|
||||
@classmethod
|
||||
def get_logreader(cls, seg):
|
||||
if len(INTERNAL_SEG_LIST):
|
||||
route_name = RouteName(cls.test_route.route)
|
||||
return LogReader(f"cd:/{route_name.dongle_id}/{route_name.time_str}/{seg}/rlog.bz2")
|
||||
else:
|
||||
return LogReader(get_url(cls.test_route.route, seg))
|
||||
|
||||
@classmethod
|
||||
def get_testing_data_from_logreader(cls, lr):
|
||||
car_fw = []
|
||||
@@ -133,22 +124,26 @@ class TestCarModelBase(unittest.TestCase):
|
||||
if cls.test_route.segment is not None:
|
||||
test_segs = (cls.test_route.segment,)
|
||||
|
||||
# Try the primary method first (CI or internal)
|
||||
is_internal = len(INTERNAL_SEG_LIST)
|
||||
|
||||
for seg in test_segs:
|
||||
segment_range = f"{cls.test_route.route}/{seg}"
|
||||
|
||||
try:
|
||||
lr = cls.get_logreader(seg)
|
||||
lr = LogReader(segment_range, default_source=internal_source if is_internal else openpilotci_source)
|
||||
return cls.get_testing_data_from_logreader(lr)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Route is not in CI bucket, assume either user has access (private), or it is public
|
||||
# test_route_on_ci_bucket will fail when running in CI
|
||||
if not len(INTERNAL_SEG_LIST):
|
||||
if not is_internal:
|
||||
cls.test_route_on_bucket = False
|
||||
|
||||
for seg in test_segs:
|
||||
segment_range = f"{cls.test_route.route}/{seg}"
|
||||
try:
|
||||
lr = LogReader(Route(cls.test_route.route).log_paths()[seg])
|
||||
lr = LogReader(segment_range)
|
||||
return cls.get_testing_data_from_logreader(lr)
|
||||
except Exception:
|
||||
pass
|
||||
@@ -239,7 +234,6 @@ class TestCarModelBase(unittest.TestCase):
|
||||
self.assertEqual(can_invalid_cnt, 0)
|
||||
|
||||
def test_radar_interface(self):
|
||||
os.environ['NO_RADAR_SLEEP'] = "1"
|
||||
RadarInterface = importlib.import_module(f'selfdrive.car.{self.CP.carName}.radar_interface').RadarInterface
|
||||
RI = RadarInterface(self.CP)
|
||||
assert RI
|
||||
|
||||
@@ -42,7 +42,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"CHEVROLET BOLT EUV 2022" = [2.0, 2.0, 0.05]
|
||||
"CHEVROLET SILVERADO 1500 2020" = [1.9, 1.9, 0.112]
|
||||
"CHEVROLET TRAILBLAZER 2021" = [1.33, 1.9, 0.16]
|
||||
"CHEVROLET EQUINOX 2019" = [2.0, 2.0, 0.05]
|
||||
"CHEVROLET EQUINOX 2019" = [2.5, 2.5, 0.05]
|
||||
"VOLKSWAGEN PASSAT NMS" = [2.5, 2.5, 0.1]
|
||||
"VOLKSWAGEN SHARAN 2ND GEN" = [2.5, 2.5, 0.1]
|
||||
"HYUNDAI SANTA CRUZ 1ST GEN" = [2.7, 2.7, 0.1]
|
||||
|
||||
@@ -5,12 +5,15 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"MAZDA CX-5 2022" = "MAZDA CX-9 2021"
|
||||
"MAZDA CX-9" = "MAZDA CX-9 2021"
|
||||
|
||||
"DODGE DURANGO 2021" = "CHRYSLER PACIFICA 2020"
|
||||
|
||||
"TOYOTA ALPHARD 2020" = "TOYOTA SIENNA 2018"
|
||||
"TOYOTA PRIUS v 2017" = "TOYOTA PRIUS 2017"
|
||||
"LEXUS IS 2018" = "LEXUS NX 2018"
|
||||
"LEXUS CT HYBRID 2018" = "LEXUS NX 2018"
|
||||
"LEXUS ES 2018" = "TOYOTA CAMRY 2018"
|
||||
"LEXUS RC 2020" = "LEXUS NX 2020"
|
||||
"LEXUS LC 2024" = "LEXUS NX 2020"
|
||||
|
||||
"KIA OPTIMA 4TH GEN" = "HYUNDAI SONATA 2020"
|
||||
"KIA OPTIMA 4TH GEN FACELIFT" = "HYUNDAI SONATA 2020"
|
||||
|
||||
@@ -59,10 +59,10 @@ class CarController:
|
||||
apply_steer = apply_meas_steer_torque_limits(new_steer, self.last_steer, CS.out.steeringTorqueEps, self.params)
|
||||
|
||||
# >100 degree/sec steering fault prevention
|
||||
self.steer_rate_counter, apply_steer_req = common_fault_avoidance(abs(CS.out.steeringRateDeg) >= MAX_STEER_RATE, CC.latActive,
|
||||
self.steer_rate_counter, apply_steer_req = common_fault_avoidance(abs(CS.out.steeringRateDeg) >= MAX_STEER_RATE, lat_active,
|
||||
self.steer_rate_counter, MAX_STEER_RATE_FRAMES)
|
||||
|
||||
if not CC.latActive:
|
||||
if not lat_active:
|
||||
apply_steer = 0
|
||||
|
||||
# *** steer angle ***
|
||||
|
||||
@@ -104,6 +104,9 @@ class CarState(CarStateBase):
|
||||
ret.leftBlinker = cp.vl["BLINKERS_STATE"]["TURN_SIGNALS"] == 1
|
||||
ret.rightBlinker = cp.vl["BLINKERS_STATE"]["TURN_SIGNALS"] == 2
|
||||
|
||||
if self.CP.carFingerprint != CAR.MIRAI:
|
||||
ret.engineRpm = cp.vl["ENGINE_RPM"]["RPM"]
|
||||
|
||||
ret.steeringTorque = cp.vl["STEER_TORQUE_SENSOR"]["STEER_TORQUE_DRIVER"]
|
||||
ret.steeringTorqueEps = cp.vl["STEER_TORQUE_SENSOR"]["STEER_TORQUE_EPS"] * self.eps_torque_scale
|
||||
# we could use the override bit from dbc, but it's triggered at too high torque values
|
||||
@@ -274,6 +277,9 @@ class CarState(CarStateBase):
|
||||
("STEER_TORQUE_SENSOR", 50),
|
||||
]
|
||||
|
||||
if CP.carFingerprint != CAR.MIRAI:
|
||||
messages.append(("ENGINE_RPM", 42))
|
||||
|
||||
if CP.carFingerprint in UNSUPPORTED_DSU_CAR:
|
||||
messages.append(("DSU_CRUISE", 5))
|
||||
messages.append(("PCM_CRUISE_ALT", 1))
|
||||
|
||||
@@ -38,6 +38,7 @@ FW_VERSIONS = {
|
||||
b'F152607180\x00\x00\x00\x00\x00\x00',
|
||||
b'F152641040\x00\x00\x00\x00\x00\x00',
|
||||
b'F152641050\x00\x00\x00\x00\x00\x00',
|
||||
b'F152641060\x00\x00\x00\x00\x00\x00',
|
||||
b'F152641061\x00\x00\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.dsu, 0x791, None): [
|
||||
@@ -55,10 +56,12 @@ FW_VERSIONS = {
|
||||
b'\x01896630725100\x00\x00\x00\x00',
|
||||
b'\x01896630725200\x00\x00\x00\x00',
|
||||
b'\x01896630725300\x00\x00\x00\x00',
|
||||
b'\x01896630725400\x00\x00\x00\x00',
|
||||
b'\x01896630735100\x00\x00\x00\x00',
|
||||
b'\x01896630738000\x00\x00\x00\x00',
|
||||
b'\x02896630724000\x00\x00\x00\x00897CF3302002\x00\x00\x00\x00',
|
||||
b'\x02896630728000\x00\x00\x00\x00897CF3302002\x00\x00\x00\x00',
|
||||
b'\x02896630734000\x00\x00\x00\x00897CF3305001\x00\x00\x00\x00',
|
||||
b'\x02896630737000\x00\x00\x00\x00897CF3305001\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x750, 0xf): [
|
||||
@@ -1361,16 +1364,19 @@ FW_VERSIONS = {
|
||||
b'\x018966378G3000\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.engine, 0x7e0, None): [
|
||||
b'\x0237881000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||
b'\x0237887000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||
b'\x02378A0000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||
b'\x02378F4000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.abs, 0x7b0, None): [
|
||||
b'\x01F152678221\x00\x00\x00\x00\x00\x00',
|
||||
b'F152678200\x00\x00\x00\x00\x00\x00',
|
||||
b'F152678210\x00\x00\x00\x00\x00\x00',
|
||||
b'F152678211\x00\x00\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.eps, 0x7a1, None): [
|
||||
b'8965B78110\x00\x00\x00\x00\x00\x00',
|
||||
b'8965B78120\x00\x00\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x750, 0xf): [
|
||||
@@ -1383,6 +1389,23 @@ FW_VERSIONS = {
|
||||
b'\x028646F7803100\x00\x00\x00\x008646G2601400\x00\x00\x00\x00',
|
||||
],
|
||||
},
|
||||
CAR.LEXUS_LC_TSS2: {
|
||||
(Ecu.engine, 0x7e0, None): [
|
||||
b'\x0131130000\x00\x00\x00\x00\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.abs, 0x7b0, None): [
|
||||
b'F152611390\x00\x00\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.eps, 0x7a1, None): [
|
||||
b'8965B11091\x00\x00\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x750, 0xf): [
|
||||
b'\x018821F6201400\x00\x00\x00\x00',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x750, 0x6d): [
|
||||
b'\x028646F1105200\x00\x00\x00\x008646G3304000\x00\x00\x00\x00',
|
||||
],
|
||||
},
|
||||
CAR.LEXUS_RC: {
|
||||
(Ecu.engine, 0x700, None): [
|
||||
b'\x01896632461100\x00\x00\x00\x00',
|
||||
@@ -1417,6 +1440,7 @@ FW_VERSIONS = {
|
||||
},
|
||||
CAR.LEXUS_RX: {
|
||||
(Ecu.engine, 0x700, None): [
|
||||
b'\x01896630E36100\x00\x00\x00\x00',
|
||||
b'\x01896630E36200\x00\x00\x00\x00',
|
||||
b'\x01896630E36300\x00\x00\x00\x00',
|
||||
b'\x01896630E37100\x00\x00\x00\x00',
|
||||
|
||||
@@ -182,6 +182,12 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.tireStiffnessFactor = 0.444 # not optimized yet
|
||||
ret.mass = 4070 * CV.LB_TO_KG
|
||||
|
||||
elif candidate == CAR.LEXUS_LC_TSS2:
|
||||
ret.wheelbase = 2.87
|
||||
ret.steerRatio = 13.0
|
||||
ret.tireStiffnessFactor = 0.444 # not optimized yet
|
||||
ret.mass = 4500 * CV.LB_TO_KG
|
||||
|
||||
elif candidate == CAR.PRIUS_TSS2:
|
||||
ret.wheelbase = 2.70002 # from toyota online sepc.
|
||||
ret.steerRatio = 13.4 # True steerRatio from older prius
|
||||
|
||||
@@ -81,6 +81,7 @@ class CAR(StrEnum):
|
||||
LEXUS_IS_TSS2 = "LEXUS IS 2023"
|
||||
LEXUS_NX = "LEXUS NX 2018"
|
||||
LEXUS_NX_TSS2 = "LEXUS NX 2020"
|
||||
LEXUS_LC_TSS2 = "LEXUS LC 2024"
|
||||
LEXUS_RC = "LEXUS RC 2020"
|
||||
LEXUS_RX = "LEXUS RX 2016"
|
||||
LEXUS_RX_TSS2 = "LEXUS RX 2020"
|
||||
@@ -206,6 +207,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = {
|
||||
ToyotaCarInfo("Lexus NX 2020-21"),
|
||||
ToyotaCarInfo("Lexus NX Hybrid 2020-21"),
|
||||
],
|
||||
CAR.LEXUS_LC_TSS2: ToyotaCarInfo("Lexus LC 2024"),
|
||||
CAR.LEXUS_RC: ToyotaCarInfo("Lexus RC 2018-20"),
|
||||
CAR.LEXUS_RX: [
|
||||
ToyotaCarInfo("Lexus RX 2016", "Lexus Safety System+"),
|
||||
@@ -444,6 +446,7 @@ DBC = {
|
||||
CAR.PRIUS: dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'),
|
||||
CAR.PRIUS_V: dbc_dict('toyota_new_mc_pt_generated', 'toyota_adas'),
|
||||
CAR.COROLLA: dbc_dict('toyota_new_mc_pt_generated', 'toyota_adas'),
|
||||
CAR.LEXUS_LC_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'),
|
||||
CAR.LEXUS_RC: dbc_dict('toyota_tnga_k_pt_generated', 'toyota_adas'),
|
||||
CAR.LEXUS_RX: dbc_dict('toyota_tnga_k_pt_generated', 'toyota_adas'),
|
||||
CAR.LEXUS_RX_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'),
|
||||
@@ -480,7 +483,8 @@ EPS_SCALE = defaultdict(lambda: 73, {CAR.PRIUS: 66, CAR.COROLLA: 88, CAR.LEXUS_I
|
||||
# Toyota/Lexus Safety Sense 2.0 and 2.5
|
||||
TSS2_CAR = {CAR.RAV4_TSS2, CAR.RAV4_TSS2_2022, CAR.RAV4_TSS2_2023, CAR.COROLLA_TSS2, CAR.LEXUS_ES_TSS2,
|
||||
CAR.LEXUS_RX_TSS2, CAR.HIGHLANDER_TSS2, CAR.PRIUS_TSS2, CAR.CAMRY_TSS2, CAR.LEXUS_IS_TSS2,
|
||||
CAR.MIRAI, CAR.LEXUS_NX_TSS2, CAR.ALPHARD_TSS2, CAR.AVALON_TSS2, CAR.CHR_TSS2}
|
||||
CAR.MIRAI, CAR.LEXUS_NX_TSS2, CAR.LEXUS_LC_TSS2, CAR.ALPHARD_TSS2, CAR.AVALON_TSS2,
|
||||
CAR.CHR_TSS2}
|
||||
|
||||
NO_DSU_CAR = TSS2_CAR | {CAR.CHR, CAR.CAMRY}
|
||||
|
||||
|
||||
+10
-4
@@ -15,7 +15,7 @@ def is_valid_vin(vin: str):
|
||||
return re.fullmatch(VIN_RE, vin) is not None
|
||||
|
||||
|
||||
def get_vin(logcan, sendcan, buses, timeout=0.1, retry=3, debug=False):
|
||||
def get_vin(logcan, sendcan, buses, timeout=0.1, retry=2, debug=False):
|
||||
for i in range(retry):
|
||||
for bus in buses:
|
||||
for request, response, valid_buses, vin_addrs, functional_addrs, rx_offset in (
|
||||
@@ -26,8 +26,14 @@ def get_vin(logcan, sendcan, buses, timeout=0.1, retry=3, debug=False):
|
||||
if bus not in valid_buses:
|
||||
continue
|
||||
|
||||
# When querying functional addresses, ideally we respond to everything that sends a first frame to avoid leaving the
|
||||
# ECU in a temporary bad state. Note that we may not cover all ECUs and response offsets. TODO: query physical addrs
|
||||
tx_addrs = vin_addrs
|
||||
if functional_addrs is not None:
|
||||
tx_addrs = [a for a in range(0x700, 0x800) if a != 0x7DF] + list(range(0x18DA00F1, 0x18DB00F1, 0x100))
|
||||
|
||||
try:
|
||||
query = IsoTpParallelQuery(sendcan, logcan, bus, vin_addrs, [request, ], [response, ], response_offset=rx_offset,
|
||||
query = IsoTpParallelQuery(sendcan, logcan, bus, tx_addrs, [request, ], [response, ], response_offset=rx_offset,
|
||||
functional_addrs=functional_addrs, debug=debug)
|
||||
results = query.get_data(timeout)
|
||||
|
||||
@@ -42,8 +48,8 @@ def get_vin(logcan, sendcan, buses, timeout=0.1, retry=3, debug=False):
|
||||
if vin.startswith(b'\x11'):
|
||||
vin = vin[1:18]
|
||||
|
||||
cloudlog.warning(f"got vin with {request=}")
|
||||
return get_rx_addr_for_tx_addr(addr), bus, vin.decode()
|
||||
cloudlog.error(f"got vin with {request=}")
|
||||
return get_rx_addr_for_tx_addr(addr, rx_offset=rx_offset), bus, vin.decode()
|
||||
except Exception:
|
||||
cloudlog.exception("VIN query exception")
|
||||
|
||||
|
||||
@@ -320,6 +320,7 @@ FW_VERSIONS = {
|
||||
b'\xf1\x8704E906024L \xf1\x895595',
|
||||
b'\xf1\x8704E906024L \xf1\x899970',
|
||||
b'\xf1\x8704E906027MS\xf1\x896223',
|
||||
b'\xf1\x8705E906013DB\xf1\x893361',
|
||||
b'\xf1\x875G0906259T \xf1\x890003',
|
||||
],
|
||||
(Ecu.transmission, 0x7e1, None): [
|
||||
@@ -327,6 +328,7 @@ FW_VERSIONS = {
|
||||
b'\xf1\x8709S927158BS\xf1\x893642',
|
||||
b'\xf1\x8709S927158BS\xf1\x893694',
|
||||
b'\xf1\x8709S927158CK\xf1\x893770',
|
||||
b'\xf1\x8709S927158JC\xf1\x894113',
|
||||
b'\xf1\x8709S927158R \xf1\x893552',
|
||||
b'\xf1\x8709S927158R \xf1\x893587',
|
||||
b'\xf1\x870GC300020N \xf1\x892803',
|
||||
@@ -340,9 +342,11 @@ FW_VERSIONS = {
|
||||
b'\xf1\x875Q0959655BR\xf1\x890403\xf1\x82\x1319170031313300314240011550159333463100',
|
||||
b'\xf1\x875Q0959655CB\xf1\x890421\xf1\x82\x1314171231313500314642021650169333613100',
|
||||
b'\xf1\x875Q0959655CB\xf1\x890421\xf1\x82\x1314171231313500314643021650169333613100',
|
||||
b'\xf1\x875Q0959655CB\xf1\x890421\xf1\x82\x1317171231313500314642023050309333613100',
|
||||
],
|
||||
(Ecu.eps, 0x712, None): [
|
||||
b'\xf1\x873Q0909144M \xf1\x895082\xf1\x82\x0571A10A11A1',
|
||||
b'\xf1\x875QM907144D \xf1\x891063\xf1\x82\x000_A1080_OM',
|
||||
b'\xf1\x875QM909144B \xf1\x891081\xf1\x82\x0521A10A01A1',
|
||||
b'\xf1\x875QM909144B \xf1\x891081\xf1\x82\x0521B00404A1',
|
||||
b'\xf1\x875QM909144C \xf1\x891082\xf1\x82\x0521A00642A1',
|
||||
@@ -350,6 +354,7 @@ FW_VERSIONS = {
|
||||
b'\xf1\x875QN909144B \xf1\x895082\xf1\x82\x0571A10A11A1',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x757, None): [
|
||||
b'\xf1\x872Q0907572AA\xf1\x890396',
|
||||
b'\xf1\x875Q0907572N \xf1\x890681',
|
||||
b'\xf1\x875Q0907572P \xf1\x890682',
|
||||
b'\xf1\x875Q0907572R \xf1\x890771',
|
||||
|
||||
@@ -223,8 +223,8 @@ CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = {
|
||||
VWCarInfo("Volkswagen Golf SportsVan 2015-20"),
|
||||
],
|
||||
CAR.JETTA_MK7: [
|
||||
VWCarInfo("Volkswagen Jetta 2018-22"),
|
||||
VWCarInfo("Volkswagen Jetta GLI 2021-22"),
|
||||
VWCarInfo("Volkswagen Jetta 2018-24"),
|
||||
VWCarInfo("Volkswagen Jetta GLI 2021-24"),
|
||||
],
|
||||
CAR.PASSAT_MK8: [
|
||||
VWCarInfo("Volkswagen Passat 2015-22", footnotes=[Footnote.PASSAT]),
|
||||
|
||||
@@ -60,7 +60,7 @@ class Controls:
|
||||
config_realtime_process(4, Priority.CTRL_HIGH)
|
||||
|
||||
# Ensure the current branch is cached, otherwise the first iteration of controlsd lags
|
||||
self.branch = get_short_branch("")
|
||||
self.branch = get_short_branch()
|
||||
|
||||
# Setup sockets
|
||||
self.pm = messaging.PubMaster(['sendcan', 'controlsState', 'carState',
|
||||
@@ -80,7 +80,8 @@ class Controls:
|
||||
'driverMonitoringState', 'longitudinalPlan', 'liveLocationKalman',
|
||||
'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters',
|
||||
'testJoystick', 'longitudinalPlanSP', 'modelV2SP'] + self.camera_packets + self.sensor_packets,
|
||||
ignore_alive=ignore, ignore_avg_freq=['radarState', 'testJoystick'], ignore_valid=['testJoystick', ])
|
||||
ignore_alive=ignore, ignore_avg_freq=ignore+['radarState', 'testJoystick'], ignore_valid=['testJoystick', ],
|
||||
frequency=int(1/DT_CTRL))
|
||||
|
||||
if CI is None:
|
||||
# wait for one pandaState and one CAN packet
|
||||
@@ -330,7 +331,7 @@ class Controls:
|
||||
num_events = len(self.events)
|
||||
|
||||
not_running = {p.name for p in self.sm['managerState'].processes if not p.running and p.shouldBeRunning}
|
||||
if self.sm.rcv_frame['managerState'] and (not_running - IGNORE_PROCESSES):
|
||||
if self.sm.recv_frame['managerState'] and (not_running - IGNORE_PROCESSES):
|
||||
self.events.add(EventName.processNotRunning)
|
||||
if not_running != self.not_running_prev:
|
||||
cloudlog.event("process_not_running", not_running=not_running, error=True)
|
||||
@@ -387,7 +388,7 @@ class Controls:
|
||||
self.events.add(EventName.paramsdTemporaryError)
|
||||
|
||||
# conservative HW alert. if the data or frequency are off, locationd will throw an error
|
||||
if any((self.sm.frame - self.sm.rcv_frame[s])*DT_CTRL > 10. for s in self.sensor_packets):
|
||||
if any((self.sm.frame - self.sm.recv_frame[s])*DT_CTRL > 10. for s in self.sensor_packets):
|
||||
self.events.add(EventName.sensorDataInvalid)
|
||||
|
||||
if not REPLAY:
|
||||
@@ -452,6 +453,17 @@ class Controls:
|
||||
self.set_initial_state()
|
||||
self.params.put_bool_nonblocking("ControlsReady", True)
|
||||
|
||||
cloudlog.event(
|
||||
"controlsd.initialized",
|
||||
dt=self.sm.frame*DT_CTRL,
|
||||
timeout=timed_out,
|
||||
canValid=CS.canValid,
|
||||
invalid=[s for s, valid in self.sm.valid.items() if not valid],
|
||||
not_alive=[s for s, alive in self.sm.alive.items() if not alive],
|
||||
not_freq_ok=[s for s, freq_ok in self.sm.freq_ok.items() if not freq_ok],
|
||||
error=True,
|
||||
)
|
||||
|
||||
# Check for CAN timeout
|
||||
if not can_strs:
|
||||
self.can_rcv_timeout_counter += 1
|
||||
@@ -610,7 +622,7 @@ class Controls:
|
||||
if not self.joystick_mode:
|
||||
# accel PID loop
|
||||
pid_accel_limits = self.CI.get_pid_accel_limits(self.CP, CS.vEgo, self.v_cruise_helper.v_cruise_kph * CV.KPH_TO_MS)
|
||||
t_since_plan = (self.sm.frame - self.sm.rcv_frame['longitudinalPlan']) * DT_CTRL
|
||||
t_since_plan = (self.sm.frame - self.sm.recv_frame['longitudinalPlan']) * DT_CTRL
|
||||
actuators.accel = self.LoC.update(CC.longActive, CS, long_plan, pid_accel_limits, t_since_plan)
|
||||
|
||||
# Steering PID loop and lateral MPC
|
||||
@@ -621,9 +633,9 @@ class Controls:
|
||||
self.sm['liveLocationKalman'])
|
||||
else:
|
||||
lac_log = log.ControlsState.LateralDebugState.new_message()
|
||||
if self.sm.rcv_frame['testJoystick'] > 0:
|
||||
if self.sm.recv_frame['testJoystick'] > 0:
|
||||
# reset joystick if it hasn't been received in a while
|
||||
should_reset_joystick = (self.sm.frame - self.sm.rcv_frame['testJoystick'])*DT_CTRL > 0.2
|
||||
should_reset_joystick = (self.sm.frame - self.sm.recv_frame['testJoystick'])*DT_CTRL > 0.2
|
||||
if not should_reset_joystick:
|
||||
joystick_axes = self.sm['testJoystick'].axes
|
||||
else:
|
||||
@@ -698,7 +710,7 @@ class Controls:
|
||||
|
||||
CC.cruiseControl.override = self.enabled and not CC.longActive and self.CP.openpilotLongitudinalControl
|
||||
CC.cruiseControl.cancel = CS.cruiseState.enabled and (not self.enabled or not self.CP.pcmCruise)
|
||||
if self.joystick_mode and self.sm.rcv_frame['testJoystick'] > 0 and self.sm['testJoystick'].buttons[0]:
|
||||
if self.joystick_mode and self.sm.recv_frame['testJoystick'] > 0 and self.sm['testJoystick'].buttons[0]:
|
||||
CC.cruiseControl.cancel = True
|
||||
|
||||
speeds = self.sm['longitudinalPlan'].speeds
|
||||
|
||||
@@ -224,7 +224,7 @@ def user_soft_disable_alert(alert_text_2: str) -> AlertCallbackType:
|
||||
return func
|
||||
|
||||
def startup_master_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
|
||||
branch = get_short_branch("") # Ensure get_short_branch is cached to avoid lags on startup
|
||||
branch = get_short_branch() # Ensure get_short_branch is cached to avoid lags on startup
|
||||
if "REPLAY" in os.environ:
|
||||
branch = "replay"
|
||||
|
||||
|
||||
@@ -29,11 +29,10 @@ def plannerd_thread():
|
||||
longitudinal_planner = LongitudinalPlanner(CP)
|
||||
pm = messaging.PubMaster(['longitudinalPlan', 'uiPlan', 'longitudinalPlanSP'])
|
||||
sm = messaging.SubMaster(['carControl', 'carState', 'controlsState', 'radarState', 'modelV2'],
|
||||
poll=['radarState', 'modelV2'], ignore_avg_freq=['radarState'])
|
||||
poll='modelV2', ignore_avg_freq=['radarState'])
|
||||
|
||||
while True:
|
||||
sm.update()
|
||||
|
||||
if sm.updated['modelV2']:
|
||||
longitudinal_planner.update(sm)
|
||||
longitudinal_planner.publish(sm, pm)
|
||||
|
||||
@@ -8,7 +8,7 @@ import capnp
|
||||
from cereal import messaging, log, car
|
||||
from openpilot.common.numpy_fast import interp
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.realtime import Ratekeeper, Priority, config_realtime_process
|
||||
from openpilot.common.realtime import DT_CTRL, Ratekeeper, Priority, config_realtime_process
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
|
||||
from openpilot.common.simple_kalman import KF1D
|
||||
@@ -201,6 +201,7 @@ class RadarD:
|
||||
|
||||
self.v_ego = 0.0
|
||||
self.v_ego_hist = deque([0.0], maxlen=delay+1)
|
||||
self.last_v_ego_frame = -1
|
||||
|
||||
self.radar_state: Optional[capnp._DynamicStructBuilder] = None
|
||||
self.radar_state_valid = False
|
||||
@@ -208,6 +209,7 @@ class RadarD:
|
||||
self.ready = False
|
||||
|
||||
def update(self, sm: messaging.SubMaster, rr: Optional[car.RadarData]):
|
||||
self.ready = sm.seen['modelV2']
|
||||
self.current_time = 1e-9*max(sm.logMonoTime.values())
|
||||
|
||||
radar_points = []
|
||||
@@ -216,11 +218,10 @@ class RadarD:
|
||||
radar_points = rr.points
|
||||
radar_errors = rr.errors
|
||||
|
||||
if sm.updated['carState']:
|
||||
if sm.recv_frame['carState'] != self.last_v_ego_frame:
|
||||
self.v_ego = sm['carState'].vEgo
|
||||
self.v_ego_hist.append(self.v_ego)
|
||||
if sm.updated['modelV2']:
|
||||
self.ready = True
|
||||
self.last_v_ego_frame = sm.recv_frame['carState']
|
||||
|
||||
ar_pts = {}
|
||||
for pt in radar_points:
|
||||
@@ -282,7 +283,7 @@ class RadarD:
|
||||
|
||||
|
||||
# fuses camera and radar data for best lead detection
|
||||
def radard_thread(sm: Optional[messaging.SubMaster] = None, pm: Optional[messaging.PubMaster] = None, can_sock: Optional[messaging.SubSocket] = None):
|
||||
def main():
|
||||
config_realtime_process(5, Priority.CTRL_LOW)
|
||||
|
||||
# wait for stats about the car to come in from controls
|
||||
@@ -296,12 +297,9 @@ def radard_thread(sm: Optional[messaging.SubMaster] = None, pm: Optional[messagi
|
||||
RadarInterface = importlib.import_module(f'selfdrive.car.{CP.carName}.radar_interface').RadarInterface
|
||||
|
||||
# *** setup messaging
|
||||
if can_sock is None:
|
||||
can_sock = messaging.sub_sock('can')
|
||||
if sm is None:
|
||||
sm = messaging.SubMaster(['modelV2', 'carState'], ignore_avg_freq=['modelV2', 'carState']) # Can't check average frequency, since radar determines timing
|
||||
if pm is None:
|
||||
pm = messaging.PubMaster(['radarState', 'liveTracks'])
|
||||
can_sock = messaging.sub_sock('can')
|
||||
sm = messaging.SubMaster(['modelV2', 'carState'], frequency=int(1./DT_CTRL))
|
||||
pm = messaging.PubMaster(['radarState', 'liveTracks'])
|
||||
|
||||
RI = RadarInterface(CP)
|
||||
|
||||
@@ -311,21 +309,15 @@ def radard_thread(sm: Optional[messaging.SubMaster] = None, pm: Optional[messagi
|
||||
while 1:
|
||||
can_strings = messaging.drain_sock_raw(can_sock, wait_for_one=True)
|
||||
rr = RI.update(can_strings)
|
||||
|
||||
sm.update(0)
|
||||
if rr is None:
|
||||
continue
|
||||
|
||||
sm.update(0)
|
||||
|
||||
RD.update(sm, rr)
|
||||
RD.publish(pm, -rk.remaining*1000.0)
|
||||
|
||||
rk.monitor_time()
|
||||
|
||||
|
||||
def main(sm: Optional[messaging.SubMaster] = None, pm: Optional[messaging.PubMaster] = None, can_sock: messaging.SubSocket = None):
|
||||
radard_thread(sm, pm, can_sock)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
+7
-19
@@ -1,14 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import json
|
||||
import codecs
|
||||
import cereal.messaging as messaging
|
||||
|
||||
from hexdump import hexdump
|
||||
from cereal import log
|
||||
from cereal.services import SERVICE_LIST
|
||||
from openpilot.tools.lib.live_logreader import raw_live_logreader
|
||||
|
||||
|
||||
codecs.register_error("strict", codecs.backslashreplace_errors)
|
||||
|
||||
@@ -22,32 +22,20 @@ if __name__ == "__main__":
|
||||
parser.add_argument('--no-print', action='store_true')
|
||||
parser.add_argument('--addr', default='127.0.0.1')
|
||||
parser.add_argument('--values', help='values to monitor (instead of entire event)')
|
||||
parser.add_argument("socket", type=str, nargs='*', help="socket names to dump. defaults to all services defined in cereal")
|
||||
parser.add_argument("socket", type=str, nargs='*', default=list(SERVICE_LIST.keys()), help="socket names to dump. defaults to all services defined in cereal")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.addr != "127.0.0.1":
|
||||
os.environ["ZMQ"] = "1"
|
||||
messaging.context = messaging.Context()
|
||||
|
||||
poller = messaging.Poller()
|
||||
|
||||
for m in args.socket if len(args.socket) > 0 else SERVICE_LIST:
|
||||
messaging.sub_sock(m, poller, addr=args.addr)
|
||||
lr = raw_live_logreader(args.socket, args.addr)
|
||||
|
||||
values = None
|
||||
if args.values:
|
||||
values = [s.strip().split(".") for s in args.values.split(",")]
|
||||
|
||||
while 1:
|
||||
polld = poller.poll(100)
|
||||
for sock in polld:
|
||||
msg = sock.receive()
|
||||
with log.Event.from_bytes(msg) as log_evt:
|
||||
evt = log_evt
|
||||
|
||||
for msg in lr:
|
||||
with log.Event.from_bytes(msg) as evt:
|
||||
if not args.no_print:
|
||||
if args.pipe:
|
||||
sys.stdout.write(msg)
|
||||
sys.stdout.write(str(msg))
|
||||
sys.stdout.flush()
|
||||
elif args.raw:
|
||||
hexdump(msg)
|
||||
|
||||
@@ -260,7 +260,7 @@ def main() -> NoReturn:
|
||||
set_realtime_priority(1)
|
||||
|
||||
pm = messaging.PubMaster(['liveCalibration'])
|
||||
sm = messaging.SubMaster(['cameraOdometry', 'carState', 'carParams'], poll=['cameraOdometry'])
|
||||
sm = messaging.SubMaster(['cameraOdometry', 'carState', 'carParams'], poll='cameraOdometry')
|
||||
|
||||
calibrator = Calibrator(param_put=True)
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ def main():
|
||||
REPLAY = bool(int(os.getenv("REPLAY", "0")))
|
||||
|
||||
pm = messaging.PubMaster(['liveParameters'])
|
||||
sm = messaging.SubMaster(['liveLocationKalman', 'carState'], poll=['liveLocationKalman'])
|
||||
sm = messaging.SubMaster(['liveLocationKalman', 'carState'], poll='liveLocationKalman')
|
||||
|
||||
params_reader = Params()
|
||||
# wait for stats about the car to come in from controls
|
||||
|
||||
@@ -218,7 +218,7 @@ def main(demo=False):
|
||||
config_realtime_process([0, 1, 2, 3], 5)
|
||||
|
||||
pm = messaging.PubMaster(['liveTorqueParameters'])
|
||||
sm = messaging.SubMaster(['carControl', 'carState', 'liveLocationKalman'], poll=['liveLocationKalman'])
|
||||
sm = messaging.SubMaster(['carControl', 'carState', 'liveLocationKalman'], poll='liveLocationKalman')
|
||||
|
||||
params = Params()
|
||||
with car.CarParams.from_bytes(params.get("CarParams", block=True)) as CP:
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import errno
|
||||
import fcntl
|
||||
import os
|
||||
import sys
|
||||
import fcntl
|
||||
import errno
|
||||
import signal
|
||||
import pathlib
|
||||
import shutil
|
||||
import signal
|
||||
import subprocess
|
||||
import tempfile
|
||||
import threading
|
||||
@@ -52,11 +53,13 @@ def write_onroad_params(started, params):
|
||||
def save_bootlog():
|
||||
# copy current params
|
||||
tmp = tempfile.mkdtemp()
|
||||
shutil.copytree(Params().get_param_path() + "/..", tmp, dirs_exist_ok=True)
|
||||
params_dirname = pathlib.Path(Params().get_param_path()).name
|
||||
params_dir = os.path.join(tmp, params_dirname)
|
||||
shutil.copytree(Params().get_param_path(), params_dir, dirs_exist_ok=True)
|
||||
|
||||
def fn(tmpdir):
|
||||
env = os.environ.copy()
|
||||
env['PARAMS_ROOT'] = tmpdir
|
||||
env['PARAMS_COPY_PATH'] = tmpdir
|
||||
subprocess.call("./bootlog", cwd=os.path.join(BASEDIR, "system/loggerd"), env=env)
|
||||
shutil.rmtree(tmpdir)
|
||||
t = threading.Thread(target=fn, args=(tmp, ))
|
||||
|
||||
@@ -125,9 +125,9 @@ def manager_init() -> None:
|
||||
params.put("Version", get_version())
|
||||
params.put("TermsVersion", terms_version)
|
||||
params.put("TrainingVersion", training_version)
|
||||
params.put("GitCommit", get_commit(default=""))
|
||||
params.put("GitBranch", get_short_branch(default=""))
|
||||
params.put("GitRemote", get_origin(default=""))
|
||||
params.put("GitCommit", get_commit())
|
||||
params.put("GitBranch", get_short_branch())
|
||||
params.put("GitRemote", get_origin())
|
||||
params.put_bool("IsTestedBranch", is_tested_branch())
|
||||
params.put_bool("IsReleaseBranch", is_release_branch())
|
||||
|
||||
@@ -139,6 +139,9 @@ def manager_init() -> None:
|
||||
serial = params.get("HardwareSerial")
|
||||
raise Exception(f"Registration failed for device {serial}")
|
||||
os.environ['DONGLE_ID'] = dongle_id # Needed for swaglog
|
||||
os.environ['GIT_ORIGIN'] = get_normalized_origin() # Needed for swaglog
|
||||
os.environ['GIT_BRANCH'] = get_short_branch() # Needed for swaglog
|
||||
os.environ['GIT_COMMIT'] = get_commit() # Needed for swaglog
|
||||
|
||||
if not is_dirty():
|
||||
os.environ['CLEAN'] = '1'
|
||||
@@ -184,7 +187,7 @@ def manager_thread() -> None:
|
||||
ignore.append("pandad")
|
||||
ignore += [x for x in os.getenv("BLOCK", "").split(",") if len(x) > 0]
|
||||
|
||||
sm = messaging.SubMaster(['deviceState', 'carParams'], poll=['deviceState'])
|
||||
sm = messaging.SubMaster(['deviceState', 'carParams'], poll='deviceState')
|
||||
pm = messaging.PubMaster(['managerState'])
|
||||
|
||||
write_onroad_params(False, params)
|
||||
@@ -193,7 +196,7 @@ def manager_thread() -> None:
|
||||
started_prev = False
|
||||
|
||||
while True:
|
||||
sm.update()
|
||||
sm.update(1000)
|
||||
|
||||
started = sm['deviceState'].started
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ import signal
|
||||
import time
|
||||
import unittest
|
||||
|
||||
from parameterized import parameterized
|
||||
|
||||
from cereal import car
|
||||
from openpilot.common.params import Params
|
||||
import openpilot.selfdrive.manager.manager as manager
|
||||
@@ -38,13 +40,13 @@ class TestManager(unittest.TestCase):
|
||||
# TODO: ensure there are blacklisted procs until we have a dedicated test
|
||||
self.assertTrue(len(BLACKLIST_PROCS), "No blacklisted procs to test not_run")
|
||||
|
||||
def test_startup_time(self):
|
||||
for _ in range(10):
|
||||
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"
|
||||
@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"
|
||||
|
||||
@unittest.skip("this test is flaky the way it's currently written, should be moved to test_onroad")
|
||||
def test_clean_exit(self):
|
||||
|
||||
@@ -16,7 +16,7 @@ def dmonitoringd_thread():
|
||||
|
||||
params = Params()
|
||||
pm = messaging.PubMaster(['driverMonitoringState', 'driverMonitoringStateSP'])
|
||||
sm = messaging.SubMaster(['driverStateV2', 'liveCalibration', 'carState', 'controlsState', 'modelV2'], poll=['driverStateV2'])
|
||||
sm = messaging.SubMaster(['driverStateV2', 'liveCalibration', 'carState', 'controlsState', 'modelV2'], poll='driverStateV2')
|
||||
|
||||
driver_status = DriverStatus(rhd_saved=params.get_bool("IsRhdDetected"))
|
||||
hands_on_wheel_status = HandsOnWheelStatus()
|
||||
@@ -50,7 +50,7 @@ def dmonitoringd_thread():
|
||||
# Get data from dmonitoringmodeld
|
||||
events = Events()
|
||||
|
||||
if sm.all_checks():
|
||||
if sm.all_checks() and len(sm['liveCalibration'].rpyCalib):
|
||||
driver_status.update_states(sm['driverStateV2'], sm['liveCalibration'].rpyCalib, sm['carState'].vEgo, sm['controlsState'].enabled)
|
||||
|
||||
# Block engaging after max number of distrations
|
||||
|
||||
@@ -4,6 +4,8 @@ import random
|
||||
import unittest
|
||||
import numpy as np
|
||||
|
||||
from parameterized import parameterized
|
||||
|
||||
import cereal.messaging as messaging
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.selfdrive.manager.process_config import managed_processes
|
||||
@@ -24,7 +26,7 @@ class TestNavd(unittest.TestCase):
|
||||
managed_processes['navd'].start()
|
||||
for _ in range(30):
|
||||
self.sm.update(1000)
|
||||
if all(f > 0 for f in self.sm.rcv_frame.values()):
|
||||
if all(f > 0 for f in self.sm.recv_frame.values()):
|
||||
break
|
||||
else:
|
||||
raise Exception("didn't get a route")
|
||||
@@ -50,11 +52,11 @@ class TestNavd(unittest.TestCase):
|
||||
}
|
||||
self._check_route(start, end)
|
||||
|
||||
def test_random(self):
|
||||
for _ in range(10):
|
||||
start = {"latitude": random.uniform(-90, 90), "longitude": random.uniform(-180, 180)}
|
||||
end = {"latitude": random.uniform(-90, 90), "longitude": random.uniform(-180, 180)}
|
||||
self._check_route(start, end, check_coords=False)
|
||||
@parameterized.expand([(i,) for i in range(10)])
|
||||
def test_random(self, index):
|
||||
start = {"latitude": random.uniform(-90, 90), "longitude": random.uniform(-180, 180)}
|
||||
end = {"latitude": random.uniform(-90, 90), "longitude": random.uniform(-180, 180)}
|
||||
self._check_route(start, end, check_coords=False)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ def set_tag(key: str, value: str) -> None:
|
||||
|
||||
def init(project: SentryProject) -> bool:
|
||||
# forks like to mess with this, so double check
|
||||
comma_remote = is_comma_remote() and "commaai" in get_origin(default="")
|
||||
comma_remote = is_comma_remote() and "commaai" in get_origin()
|
||||
if not comma_remote or not is_registered_device() or PC:
|
||||
return False
|
||||
|
||||
|
||||
@@ -7,9 +7,6 @@ elif [ "$1" = "sim" ]; then
|
||||
elif [ "$1" = "prebuilt" ]; then
|
||||
export DOCKER_IMAGE=openpilot-prebuilt
|
||||
export DOCKER_FILE=Dockerfile.openpilot
|
||||
elif [ "$1" = "cl" ]; then
|
||||
export DOCKER_IMAGE=openpilot-base-cl
|
||||
export DOCKER_FILE=Dockerfile.openpilot_base_cl
|
||||
else
|
||||
echo "Invalid docker build image: '$1'"
|
||||
exit 1
|
||||
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# Loop something forever until it fails, for verifying new tests
|
||||
|
||||
while true; do
|
||||
$@
|
||||
done
|
||||
@@ -762,7 +762,6 @@ def generate_environ_config(CP=None, fingerprint=None, log_dir=None) -> Dict[str
|
||||
if log_dir is not None:
|
||||
environ_dict["LOG_ROOT"] = log_dir
|
||||
|
||||
environ_dict["NO_RADAR_SLEEP"] = "1"
|
||||
environ_dict["REPLAY"] = "1"
|
||||
|
||||
# Regen or python process
|
||||
|
||||
@@ -1 +1 @@
|
||||
d9a3a0d4e806b49ec537233d30926bec70308485
|
||||
7d25b1f7d0bd3b506fa4e72ff893728894eb1a45
|
||||
@@ -58,7 +58,7 @@ segments = [
|
||||
("VOLKSWAGEN", "regen8BDFE7307A0|2023-10-30--23-19-36--0"),
|
||||
("MAZDA", "regen2E9F1A15FD5|2023-10-30--23-20-36--0"),
|
||||
("FORD", "regen6D39E54606E|2023-10-30--23-20-54--0"),
|
||||
]
|
||||
]
|
||||
|
||||
# dashcamOnly makes don't need to be tested until a full port is done
|
||||
excluded_interfaces = ["mock", "tesla"]
|
||||
@@ -107,7 +107,9 @@ def test_process(cfg, lr, segment, ref_log_path, new_log_path, ignore_fields=Non
|
||||
# check to make sure openpilot is engaged in the route
|
||||
if cfg.proc_name == "controlsd":
|
||||
if not check_openpilot_enabled(log_msgs):
|
||||
return f"Route did not enable at all or for long enough: {new_log_path}", log_msgs
|
||||
# FIXME: these segments should work, but the replay enabling logic is too brittle
|
||||
if segment not in ("regen6CA24BC3035|2023-10-30--23-14-28--0", "regen7D2D3F82D5B|2023-10-30--23-15-55--0"):
|
||||
return f"Route did not enable at all or for long enough: {new_log_path}", log_msgs
|
||||
|
||||
try:
|
||||
return compare_logs(ref_log_msgs, log_msgs, ignore_fields + cfg.ignore, ignore_msgs, cfg.tolerance), log_msgs
|
||||
@@ -160,7 +162,7 @@ if __name__ == "__main__":
|
||||
sys.exit(1)
|
||||
|
||||
cur_commit = get_commit()
|
||||
if cur_commit is None:
|
||||
if not cur_commit:
|
||||
raise Exception("Couldn't get current commit")
|
||||
|
||||
print(f"***** testing against commit {ref_commit} *****")
|
||||
|
||||
@@ -80,12 +80,10 @@ def profile(proc, func, car='toyota'):
|
||||
|
||||
if __name__ == '__main__':
|
||||
from openpilot.selfdrive.controls.controlsd import main as controlsd_thread
|
||||
from openpilot.selfdrive.controls.radard import radard_thread
|
||||
from openpilot.selfdrive.locationd.paramsd import main as paramsd_thread
|
||||
from openpilot.selfdrive.controls.plannerd import main as plannerd_thread
|
||||
|
||||
procs = {
|
||||
'radard': radard_thread,
|
||||
'controlsd': controlsd_thread,
|
||||
'paramsd': paramsd_thread,
|
||||
'plannerd': plannerd_thread,
|
||||
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR=$(dirname "$0")
|
||||
BASEDIR=$(realpath "$SCRIPT_DIR/../../")
|
||||
cd $BASEDIR
|
||||
|
||||
# tests that our build system's dependencies are configured properly,
|
||||
# needs a machine with lots of cores
|
||||
scons --clean
|
||||
scons --no-cache --random -j$(nproc)
|
||||
@@ -39,7 +39,7 @@ PROCS = {
|
||||
"./ui": 18.0,
|
||||
"selfdrive.locationd.paramsd": 9.0,
|
||||
"./sensord": 7.0,
|
||||
"selfdrive.controls.radard": 4.5,
|
||||
"selfdrive.controls.radard": 7.0,
|
||||
"selfdrive.modeld.modeld": 13.0,
|
||||
"selfdrive.modeld.dmonitoringmodeld": 8.0,
|
||||
"selfdrive.modeld.navmodeld": 1.0,
|
||||
@@ -57,7 +57,7 @@ PROCS = {
|
||||
"selfdrive.boardd.pandad": 0,
|
||||
"selfdrive.statsd": 0.4,
|
||||
"selfdrive.navd.navd": 0.4,
|
||||
"system.loggerd.uploader": (0.5, 10.0),
|
||||
"system.loggerd.uploader": (0.5, 15.0),
|
||||
"system.loggerd.deleter": 0.1,
|
||||
}
|
||||
|
||||
@@ -112,17 +112,11 @@ class TestOnroad(unittest.TestCase):
|
||||
|
||||
# setup env
|
||||
params = Params()
|
||||
if "CI" in os.environ:
|
||||
params.clear_all()
|
||||
params.remove("CurrentRoute")
|
||||
set_params_enabled()
|
||||
os.environ['TESTING_CLOSET'] = '1'
|
||||
if os.path.exists(Paths.log_root()):
|
||||
shutil.rmtree(Paths.log_root())
|
||||
os.system("rm /dev/shm/*")
|
||||
|
||||
# Make sure athena isn't running
|
||||
os.system("pkill -9 -f athena")
|
||||
|
||||
# start manager and run openpilot for a minute
|
||||
proc = None
|
||||
@@ -132,7 +126,7 @@ class TestOnroad(unittest.TestCase):
|
||||
|
||||
sm = messaging.SubMaster(['carState'])
|
||||
with Timeout(150, "controls didn't start"):
|
||||
while sm.rcv_frame['carState'] < 0:
|
||||
while sm.recv_frame['carState'] < 0:
|
||||
sm.update(1000)
|
||||
|
||||
# make sure we get at least two full segments
|
||||
@@ -429,4 +423,4 @@ class TestOnroad(unittest.TestCase):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
pytest.main()
|
||||
|
||||
@@ -29,12 +29,15 @@ def test_time_to_onroad():
|
||||
time.sleep(1)
|
||||
|
||||
# wait for engageability
|
||||
with Timeout(10, "timed out waiting for engageable"):
|
||||
while True:
|
||||
sm.update(1000)
|
||||
if sm['controlsState'].engageable:
|
||||
break
|
||||
time.sleep(1)
|
||||
try:
|
||||
with Timeout(10, "timed out waiting for engageable"):
|
||||
while True:
|
||||
sm.update(1000)
|
||||
if sm['controlsState'].engageable:
|
||||
break
|
||||
time.sleep(1)
|
||||
finally:
|
||||
print(f"onroad events: {sm['onroadEvents']}")
|
||||
print(f"engageable after {time.monotonic() - start_time:.2f}s")
|
||||
|
||||
# once we're enageable, must be for the next few seconds
|
||||
|
||||
@@ -166,7 +166,7 @@ def hw_state_thread(end_event, hw_queue):
|
||||
|
||||
def thermald_thread(end_event, hw_queue) -> None:
|
||||
pm = messaging.PubMaster(['deviceState'])
|
||||
sm = messaging.SubMaster(["peripheralState", "gpsLocationExternal", "controlsState", "pandaStates"], poll=["pandaStates"])
|
||||
sm = messaging.SubMaster(["peripheralState", "gpsLocationExternal", "controlsState", "pandaStates"], poll="pandaStates")
|
||||
|
||||
count = 0
|
||||
|
||||
@@ -233,7 +233,7 @@ def thermald_thread(end_event, hw_queue) -> None:
|
||||
if TICI:
|
||||
fan_controller = TiciFanController()
|
||||
|
||||
elif (time.monotonic() - sm.rcv_time['pandaStates']) > DISCONNECT_TIMEOUT:
|
||||
elif (time.monotonic() - sm.recv_time['pandaStates']) > DISCONNECT_TIMEOUT:
|
||||
if onroad_conditions["ignition"]:
|
||||
onroad_conditions["ignition"] = False
|
||||
cloudlog.error("panda timed out onroad")
|
||||
|
||||
@@ -124,7 +124,7 @@ def report_tombstone_apport(fn):
|
||||
clean_path = path.replace('/', '_')
|
||||
date = datetime.datetime.now().strftime("%Y-%m-%d--%H-%M-%S")
|
||||
|
||||
new_fn = f"{date}_{get_commit(default='nocommit')[:8]}_{safe_fn(clean_path)}"[:MAX_TOMBSTONE_FN_LEN]
|
||||
new_fn = f"{date}_{(get_commit() or 'nocommit')[:8]}_{safe_fn(clean_path)}"[:MAX_TOMBSTONE_FN_LEN]
|
||||
|
||||
crashlog_dir = os.path.join(Paths.log_root(), "crash")
|
||||
os.makedirs(crashlog_dir, exist_ok=True)
|
||||
|
||||
@@ -4,6 +4,7 @@ moc_*
|
||||
translations/main_test_en.*
|
||||
|
||||
ui
|
||||
mui
|
||||
watch3
|
||||
installer/installers/*
|
||||
qt/text
|
||||
|
||||
@@ -92,6 +92,9 @@ if GetOption('extras') and arch != "Darwin":
|
||||
# build updater UI
|
||||
qt_env.Program("qt/setup/updater", ["qt/setup/updater.cc", asset_obj], LIBS=qt_libs)
|
||||
|
||||
# build mui
|
||||
qt_env.Program("mui", ["mui.cc"], LIBS=qt_libs)
|
||||
|
||||
# build installers
|
||||
senv = qt_env.Clone()
|
||||
senv['LINKFLAGS'].append('-Wl,-strip-debug')
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
#include <QApplication>
|
||||
#include <QtWidgets>
|
||||
#include <QTimer>
|
||||
|
||||
#include "cereal/messaging/messaging.h"
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#include "selfdrive/ui/qt/qt_window.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
QApplication a(argc, argv);
|
||||
QWidget w;
|
||||
setMainWindow(&w);
|
||||
|
||||
w.setStyleSheet("background-color: black;");
|
||||
|
||||
// our beautiful UI
|
||||
QVBoxLayout *layout = new QVBoxLayout(&w);
|
||||
QLabel *label = new QLabel("〇");
|
||||
layout->addWidget(label, 0, Qt::AlignCenter);
|
||||
|
||||
QTimer timer;
|
||||
QObject::connect(&timer, &QTimer::timeout, [=]() {
|
||||
static SubMaster sm({"deviceState", "controlsState"});
|
||||
|
||||
bool onroad_prev = sm.allAliveAndValid({"deviceState"}) &&
|
||||
sm["deviceState"].getDeviceState().getStarted();
|
||||
sm.update(0);
|
||||
|
||||
bool onroad = sm.allAliveAndValid({"deviceState"}) &&
|
||||
sm["deviceState"].getDeviceState().getStarted();
|
||||
|
||||
if (onroad) {
|
||||
label->setText("〇");
|
||||
auto cs = sm["controlsState"].getControlsState();
|
||||
UIStatus status = cs.getEnabled() ? STATUS_ENGAGED : STATUS_DISENGAGED;
|
||||
label->setStyleSheet(QString("color: %1; font-size: 250px;").arg(bg_colors[status].name()));
|
||||
} else {
|
||||
label->setText("offroad");
|
||||
label->setStyleSheet("color: grey; font-size: 40px;");
|
||||
}
|
||||
|
||||
if ((onroad != onroad_prev) || sm.frame < 2) {
|
||||
Hardware::set_brightness(50);
|
||||
Hardware::set_display_power(onroad);
|
||||
}
|
||||
});
|
||||
timer.start(50);
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
@@ -199,7 +199,7 @@ OnboardingWindow::OnboardingWindow(QWidget *parent) : QStackedWidget(parent) {
|
||||
TermsPage* terms = new TermsPage(this);
|
||||
addWidget(terms);
|
||||
connect(terms, &TermsPage::acceptedTerms, [=]() {
|
||||
Params().put("HasAcceptedTerms", current_terms_version);
|
||||
params.put("HasAcceptedTerms", current_terms_version);
|
||||
accepted_terms = true;
|
||||
updateActiveScreen();
|
||||
});
|
||||
@@ -209,7 +209,7 @@ OnboardingWindow::OnboardingWindow(QWidget *parent) : QStackedWidget(parent) {
|
||||
addWidget(tr);
|
||||
connect(tr, &TrainingGuide::completedTraining, [=]() {
|
||||
training_done = true;
|
||||
Params().put("CompletedTrainingVersion", current_training_version);
|
||||
params.put("CompletedTrainingVersion", current_training_version);
|
||||
updateActiveScreen();
|
||||
});
|
||||
|
||||
|
||||
@@ -290,7 +290,7 @@ void AnnotatedCameraWidget::updateState(const UIState &s) {
|
||||
const auto nav_instruction = sm["navInstruction"].getNavInstruction();
|
||||
|
||||
// Handle older routes where vCruiseCluster is not set
|
||||
float v_cruise = cs.getVCruiseCluster() == 0.0 ? cs.getVCruise() : cs.getVCruiseCluster();
|
||||
float v_cruise = cs.getVCruiseCluster() == 0.0 ? cs.getVCruise() : cs.getVCruiseCluster();
|
||||
setSpeed = cs_alive ? v_cruise : SET_SPEED_NA;
|
||||
is_cruise_set = setSpeed > 0 && (int)setSpeed != SET_SPEED_NA;
|
||||
if (is_cruise_set && !s.scene.is_metric) {
|
||||
|
||||
@@ -42,7 +42,7 @@ sound_list: Dict[int, Tuple[str, Optional[int], float]] = {
|
||||
}
|
||||
|
||||
def check_controls_timeout_alert(sm):
|
||||
controls_missing = time.monotonic() - sm.rcv_time['controlsState']
|
||||
controls_missing = time.monotonic() - sm.recv_time['controlsState']
|
||||
|
||||
if controls_missing > CONTROLS_TIMEOUT:
|
||||
if sm['controlsState'].enabled and (controls_missing - CONTROLS_TIMEOUT) < 10:
|
||||
|
||||
+82
-82
@@ -413,96 +413,96 @@ def main() -> None:
|
||||
cloudlog.warning("updates are disabled by the DisableUpdates param")
|
||||
exit(0)
|
||||
|
||||
ov_lock_fd = open(LOCK_FILE, 'w')
|
||||
try:
|
||||
fcntl.flock(ov_lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
except OSError as e:
|
||||
raise RuntimeError("couldn't get overlay lock; is another instance running?") from e
|
||||
|
||||
# Set low io priority
|
||||
proc = psutil.Process()
|
||||
if psutil.LINUX:
|
||||
proc.ionice(psutil.IOPRIO_CLASS_BE, value=7)
|
||||
|
||||
# Check if we just performed an update
|
||||
if Path(os.path.join(STAGING_ROOT, "old_openpilot")).is_dir():
|
||||
cloudlog.event("update installed")
|
||||
|
||||
if not params.get("InstallDate"):
|
||||
t = datetime.datetime.utcnow().isoformat()
|
||||
params.put("InstallDate", t.encode('utf8'))
|
||||
|
||||
updater = Updater()
|
||||
update_failed_count = 0 # TODO: Load from param?
|
||||
wait_helper = WaitTimeHelper()
|
||||
|
||||
# invalidate old finalized update
|
||||
set_consistent_flag(False)
|
||||
|
||||
# set initial state
|
||||
params.put("UpdaterState", "idle")
|
||||
|
||||
# Run the update loop
|
||||
first_run = True
|
||||
while True:
|
||||
wait_helper.ready_event.clear()
|
||||
|
||||
# Attempt an update
|
||||
exception = None
|
||||
with open(LOCK_FILE, 'w') as ov_lock_fd:
|
||||
try:
|
||||
# TODO: reuse overlay from previous updated instance if it looks clean
|
||||
init_overlay()
|
||||
fcntl.flock(ov_lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
except OSError as e:
|
||||
raise RuntimeError("couldn't get overlay lock; is another instance running?") from e
|
||||
|
||||
# ensure we have some params written soon after startup
|
||||
updater.set_params(False, update_failed_count, exception)
|
||||
# Set low io priority
|
||||
proc = psutil.Process()
|
||||
if psutil.LINUX:
|
||||
proc.ionice(psutil.IOPRIO_CLASS_BE, value=7)
|
||||
|
||||
if not system_time_valid() or first_run:
|
||||
first_run = False
|
||||
wait_helper.sleep(60)
|
||||
continue
|
||||
# Check if we just performed an update
|
||||
if Path(os.path.join(STAGING_ROOT, "old_openpilot")).is_dir():
|
||||
cloudlog.event("update installed")
|
||||
|
||||
update_failed_count += 1
|
||||
if not params.get("InstallDate"):
|
||||
t = datetime.datetime.utcnow().isoformat()
|
||||
params.put("InstallDate", t.encode('utf8'))
|
||||
|
||||
# check for update
|
||||
params.put("UpdaterState", "checking...")
|
||||
updater.check_for_update()
|
||||
updater = Updater()
|
||||
update_failed_count = 0 # TODO: Load from param?
|
||||
wait_helper = WaitTimeHelper()
|
||||
|
||||
# download update
|
||||
last_fetch = read_time_from_param(params, "UpdaterLastFetchTime")
|
||||
timed_out = last_fetch is None or (datetime.datetime.utcnow() - last_fetch > datetime.timedelta(days=3))
|
||||
user_requested_fetch = wait_helper.user_request == UserRequest.FETCH
|
||||
if params.get_bool("NetworkMetered") and not timed_out and not user_requested_fetch:
|
||||
cloudlog.info("skipping fetch, connection metered")
|
||||
elif wait_helper.user_request == UserRequest.CHECK:
|
||||
cloudlog.info("skipping fetch, only checking")
|
||||
else:
|
||||
updater.fetch_update()
|
||||
write_time_to_param(params, "UpdaterLastFetchTime")
|
||||
update_failed_count = 0
|
||||
except subprocess.CalledProcessError as e:
|
||||
cloudlog.event(
|
||||
"update process failed",
|
||||
cmd=e.cmd,
|
||||
output=e.output,
|
||||
returncode=e.returncode
|
||||
)
|
||||
exception = f"command failed: {e.cmd}\n{e.output}"
|
||||
OVERLAY_INIT.unlink(missing_ok=True)
|
||||
except Exception as e:
|
||||
cloudlog.exception("uncaught updated exception, shouldn't happen")
|
||||
exception = str(e)
|
||||
OVERLAY_INIT.unlink(missing_ok=True)
|
||||
# invalidate old finalized update
|
||||
set_consistent_flag(False)
|
||||
|
||||
try:
|
||||
params.put("UpdaterState", "idle")
|
||||
update_successful = (update_failed_count == 0)
|
||||
updater.set_params(update_successful, update_failed_count, exception)
|
||||
except Exception:
|
||||
cloudlog.exception("uncaught updated exception while setting params, shouldn't happen")
|
||||
# set initial state
|
||||
params.put("UpdaterState", "idle")
|
||||
|
||||
# infrequent attempts if we successfully updated recently
|
||||
wait_helper.user_request = UserRequest.NONE
|
||||
wait_helper.sleep(5*60 if update_failed_count > 0 else 1.5*60*60)
|
||||
# Run the update loop
|
||||
first_run = True
|
||||
while True:
|
||||
wait_helper.ready_event.clear()
|
||||
|
||||
# Attempt an update
|
||||
exception = None
|
||||
try:
|
||||
# TODO: reuse overlay from previous updated instance if it looks clean
|
||||
init_overlay()
|
||||
|
||||
# ensure we have some params written soon after startup
|
||||
updater.set_params(False, update_failed_count, exception)
|
||||
|
||||
if not system_time_valid() or first_run:
|
||||
first_run = False
|
||||
wait_helper.sleep(60)
|
||||
continue
|
||||
|
||||
update_failed_count += 1
|
||||
|
||||
# check for update
|
||||
params.put("UpdaterState", "checking...")
|
||||
updater.check_for_update()
|
||||
|
||||
# download update
|
||||
last_fetch = read_time_from_param(params, "UpdaterLastFetchTime")
|
||||
timed_out = last_fetch is None or (datetime.datetime.utcnow() - last_fetch > datetime.timedelta(days=3))
|
||||
user_requested_fetch = wait_helper.user_request == UserRequest.FETCH
|
||||
if params.get_bool("NetworkMetered") and not timed_out and not user_requested_fetch:
|
||||
cloudlog.info("skipping fetch, connection metered")
|
||||
elif wait_helper.user_request == UserRequest.CHECK:
|
||||
cloudlog.info("skipping fetch, only checking")
|
||||
else:
|
||||
updater.fetch_update()
|
||||
write_time_to_param(params, "UpdaterLastFetchTime")
|
||||
update_failed_count = 0
|
||||
except subprocess.CalledProcessError as e:
|
||||
cloudlog.event(
|
||||
"update process failed",
|
||||
cmd=e.cmd,
|
||||
output=e.output,
|
||||
returncode=e.returncode
|
||||
)
|
||||
exception = f"command failed: {e.cmd}\n{e.output}"
|
||||
OVERLAY_INIT.unlink(missing_ok=True)
|
||||
except Exception as e:
|
||||
cloudlog.exception("uncaught updated exception, shouldn't happen")
|
||||
exception = str(e)
|
||||
OVERLAY_INIT.unlink(missing_ok=True)
|
||||
|
||||
try:
|
||||
params.put("UpdaterState", "idle")
|
||||
update_successful = (update_failed_count == 0)
|
||||
updater.set_params(update_successful, update_failed_count, exception)
|
||||
except Exception:
|
||||
cloudlog.exception("uncaught updated exception while setting params, shouldn't happen")
|
||||
|
||||
# infrequent attempts if we successfully updated recently
|
||||
wait_helper.user_request = UserRequest.NONE
|
||||
wait_helper.sleep(5*60 if update_failed_count > 0 else 1.5*60*60)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -606,6 +606,7 @@ void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num
|
||||
LOGD("start csiphy: %d", ret);
|
||||
ret = device_control(multi_cam_state->isp_fd, CAM_START_DEV, session_handle, isp_dev_handle);
|
||||
LOGD("start isp: %d", ret);
|
||||
assert(ret == 0);
|
||||
|
||||
// TODO: this is unneeded, should we be doing the start i2c in a different way?
|
||||
//ret = device_control(sensor_fd, CAM_START_DEV, session_handle, sensor_dev_handle);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
[
|
||||
{
|
||||
"name": "boot",
|
||||
"url": "https://commadist.azureedge.net/agnosupdate/boot-1cc21f31a7c09772fd759e6f2a614974bf4f2fc320c91a799ffadd11abc1f85f.img.xz",
|
||||
"hash": "1cc21f31a7c09772fd759e6f2a614974bf4f2fc320c91a799ffadd11abc1f85f",
|
||||
"hash_raw": "1cc21f31a7c09772fd759e6f2a614974bf4f2fc320c91a799ffadd11abc1f85f",
|
||||
"url": "https://commadist.azureedge.net/agnosupdate/boot-f0de74e139b8b99224738d4e72a5b1831758f20b09ff6bb28f3aaaae1c4c1ebe.img.xz",
|
||||
"hash": "f0de74e139b8b99224738d4e72a5b1831758f20b09ff6bb28f3aaaae1c4c1ebe",
|
||||
"hash_raw": "f0de74e139b8b99224738d4e72a5b1831758f20b09ff6bb28f3aaaae1c4c1ebe",
|
||||
"size": 15636480,
|
||||
"sparse": false,
|
||||
"full_check": true,
|
||||
@@ -61,17 +61,17 @@
|
||||
},
|
||||
{
|
||||
"name": "system",
|
||||
"url": "https://commadist.azureedge.net/agnosupdate/system-38402b90b65729f8a4feb729c8a862cdf306659a85f27431d3ff7e52d4027082.img.xz",
|
||||
"hash": "5dc1718e21c49e4fa910fbb3b2321381f497b38335a0cf3ca923157d589abe89",
|
||||
"hash_raw": "38402b90b65729f8a4feb729c8a862cdf306659a85f27431d3ff7e52d4027082",
|
||||
"url": "https://commadist.azureedge.net/agnosupdate/system-3bfb0f3a6bf677bdc8a6227f49ce3258025e1886dc81533e3fbacb356b5601db.img.xz",
|
||||
"hash": "10ac02f18c5f1cde5a888a3411d3701b929c3488753467e77aad6085db058eb9",
|
||||
"hash_raw": "3bfb0f3a6bf677bdc8a6227f49ce3258025e1886dc81533e3fbacb356b5601db",
|
||||
"size": 10737418240,
|
||||
"sparse": true,
|
||||
"full_check": false,
|
||||
"has_ab": true,
|
||||
"alt": {
|
||||
"hash": "1809e36d8e376e0a0c8348e3f684aba4100fe0382042c051efd0e946af1ce696",
|
||||
"url": "https://commadist.azureedge.net/agnosupdate/system-skip-chunks-38402b90b65729f8a4feb729c8a862cdf306659a85f27431d3ff7e52d4027082.img.xz",
|
||||
"size": 4077270244
|
||||
"hash": "a7db41b93b587f8f9c3f83a3313f186445c4bdf07283cd6a5421dfbc0286c9db",
|
||||
"url": "https://commadist.azureedge.net/agnosupdate/system-skip-chunks-3bfb0f3a6bf677bdc8a6227f49ce3258025e1886dc81533e3fbacb356b5601db.img.xz",
|
||||
"size": 4548131508
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -72,6 +72,7 @@ public:
|
||||
std::map<std::string, std::string> ret = {
|
||||
{"/BUILD", util::read_file("/BUILD")},
|
||||
{"lsblk", util::check_output("lsblk -o NAME,SIZE,STATE,VENDOR,MODEL,REV,SERIAL")},
|
||||
{"SOM ID", util::read_file("/sys/devices/platform/vendor/vendor:gpio-som-id/som_id")},
|
||||
};
|
||||
|
||||
std::string bs = util::check_output("abctl --boot_slot");
|
||||
|
||||
@@ -457,24 +457,37 @@ class Tici(HardwareBase):
|
||||
def configure_modem(self):
|
||||
sim_id = self.get_sim_info().get('sim_id', '')
|
||||
|
||||
# configure modem as data-centric
|
||||
cmds = [
|
||||
'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',
|
||||
]
|
||||
modem = self.get_modem()
|
||||
try:
|
||||
manufacturer = str(modem.Get(MM_MODEM, 'Manufacturer', dbus_interface=DBUS_PROPS, timeout=TIMEOUT))
|
||||
except Exception:
|
||||
manufacturer = None
|
||||
|
||||
cmds = []
|
||||
if manufacturer == 'Cavli Inc.':
|
||||
cmds += [
|
||||
# use sim slot
|
||||
'AT^SIMSWAP=1',
|
||||
|
||||
# configure ECM mode
|
||||
'AT$QCPCFG=usbNet,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',
|
||||
]
|
||||
|
||||
# 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)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# blue prime
|
||||
blue_prime = sim_id.startswith('8901410')
|
||||
initial_apn = "Broadband" if blue_prime else ""
|
||||
os.system(f'mmcli -m any --3gpp-set-initial-eps-bearer-settings="apn={initial_apn}"')
|
||||
|
||||
# eSIM prime
|
||||
if sim_id.startswith('8985235'):
|
||||
dest = "/etc/NetworkManager/system-connections/esim.nmconnection"
|
||||
|
||||
@@ -12,11 +12,6 @@ HARDWARE = Tici()
|
||||
@pytest.mark.tici
|
||||
class TestHardware(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
HARDWARE.initialize_hardware()
|
||||
HARDWARE.set_power_save(False)
|
||||
|
||||
def test_power_save_time(self):
|
||||
ts = []
|
||||
for _ in range(5):
|
||||
@@ -30,4 +25,4 @@ class TestHardware(unittest.TestCase):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
pytest.main()
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
from collections import defaultdict, deque
|
||||
import sys
|
||||
import pytest
|
||||
import unittest
|
||||
import time
|
||||
@@ -11,29 +13,32 @@ import cereal.messaging as messaging
|
||||
from cereal.services import SERVICE_LIST
|
||||
from openpilot.common.mock import mock_messages
|
||||
from openpilot.selfdrive.car.car_helpers import write_car_param
|
||||
from openpilot.system.hardware import HARDWARE
|
||||
from openpilot.system.hardware.tici.power_monitor import get_power
|
||||
from openpilot.selfdrive.manager.process_config import managed_processes
|
||||
from openpilot.selfdrive.manager.manager import manager_cleanup
|
||||
|
||||
SAMPLE_TIME = 8 # seconds to sample power
|
||||
SAMPLE_TIME = 8 # seconds to sample power
|
||||
MAX_WARMUP_TIME = 30 # seconds to wait for SAMPLE_TIME consecutive valid samples
|
||||
|
||||
@dataclass
|
||||
class Proc:
|
||||
name: str
|
||||
procs: List[str]
|
||||
power: float
|
||||
msgs: List[str]
|
||||
rtol: float = 0.05
|
||||
atol: float = 0.12
|
||||
warmup: float = 6.
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return '+'.join(self.procs)
|
||||
|
||||
|
||||
PROCS = [
|
||||
Proc('camerad', 2.1, msgs=['roadCameraState', 'wideRoadCameraState', 'driverCameraState']),
|
||||
Proc('modeld', 1.12, atol=0.2, msgs=['modelV2']),
|
||||
Proc('dmonitoringmodeld', 0.4, msgs=['driverStateV2']),
|
||||
Proc('encoderd', 0.23, msgs=[]),
|
||||
Proc('mapsd', 0.05, msgs=['mapRenderState']),
|
||||
Proc('navmodeld', 0.05, msgs=['navModel']),
|
||||
Proc(['camerad'], 2.1, msgs=['roadCameraState', 'wideRoadCameraState', 'driverCameraState']),
|
||||
Proc(['modeld'], 1.12, atol=0.2, msgs=['modelV2']),
|
||||
Proc(['dmonitoringmodeld'], 0.4, msgs=['driverStateV2']),
|
||||
Proc(['encoderd'], 0.23, msgs=[]),
|
||||
Proc(['mapsd', 'navmodeld'], 0.05, msgs=['mapRenderState', 'navModel']),
|
||||
]
|
||||
|
||||
|
||||
@@ -41,8 +46,6 @@ PROCS = [
|
||||
class TestPowerDraw(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
HARDWARE.initialize_hardware()
|
||||
HARDWARE.set_power_save(False)
|
||||
write_car_param()
|
||||
|
||||
# wait a bit for power save to disable
|
||||
@@ -51,41 +54,83 @@ class TestPowerDraw(unittest.TestCase):
|
||||
def tearDown(self):
|
||||
manager_cleanup()
|
||||
|
||||
def get_expected_messages(self, proc):
|
||||
return int(sum(SAMPLE_TIME * SERVICE_LIST[msg].frequency for msg in proc.msgs))
|
||||
|
||||
def valid_msg_count(self, proc, msg_counts):
|
||||
msgs_received = sum(msg_counts[msg] for msg in proc.msgs)
|
||||
msgs_expected = self.get_expected_messages(proc)
|
||||
return np.core.numeric.isclose(msgs_expected, msgs_received, rtol=.02, atol=2)
|
||||
|
||||
def valid_power_draw(self, proc, used):
|
||||
return np.core.numeric.isclose(used, proc.power, rtol=proc.rtol, atol=proc.atol)
|
||||
|
||||
def tabulate_msg_counts(self, msgs_and_power):
|
||||
msg_counts = defaultdict(lambda: 0)
|
||||
for _, counts in msgs_and_power:
|
||||
for msg, count in counts.items():
|
||||
msg_counts[msg] += count
|
||||
return msg_counts
|
||||
|
||||
def get_power_with_warmup_for_target(self, proc, prev):
|
||||
socks = {msg: messaging.sub_sock(msg) for msg in proc.msgs}
|
||||
for sock in socks.values():
|
||||
messaging.drain_sock_raw(sock)
|
||||
|
||||
msgs_and_power = deque([], maxlen=SAMPLE_TIME)
|
||||
|
||||
start_time = time.monotonic()
|
||||
|
||||
while (time.monotonic() - start_time) < MAX_WARMUP_TIME:
|
||||
power = get_power(1)
|
||||
iteration_msg_counts = {}
|
||||
for msg,sock in socks.items():
|
||||
iteration_msg_counts[msg] = len(messaging.drain_sock_raw(sock))
|
||||
msgs_and_power.append((power, iteration_msg_counts))
|
||||
|
||||
if len(msgs_and_power) < SAMPLE_TIME:
|
||||
continue
|
||||
|
||||
msg_counts = self.tabulate_msg_counts(msgs_and_power)
|
||||
now = np.mean([m[0] for m in msgs_and_power])
|
||||
|
||||
if self.valid_msg_count(proc, msg_counts) and self.valid_power_draw(proc, now - prev):
|
||||
break
|
||||
|
||||
return now, msg_counts, time.monotonic() - start_time - SAMPLE_TIME
|
||||
|
||||
@mock_messages(['liveLocationKalman'])
|
||||
def test_camera_procs(self):
|
||||
baseline = get_power()
|
||||
|
||||
prev = baseline
|
||||
used = {}
|
||||
warmup_time = {}
|
||||
msg_counts = {}
|
||||
for proc in PROCS:
|
||||
socks = {msg: messaging.sub_sock(msg) for msg in proc.msgs}
|
||||
managed_processes[proc.name].start()
|
||||
time.sleep(proc.warmup)
|
||||
for sock in socks.values():
|
||||
messaging.drain_sock_raw(sock)
|
||||
|
||||
now = get_power(SAMPLE_TIME)
|
||||
for proc in PROCS:
|
||||
for p in proc.procs:
|
||||
managed_processes[p].start()
|
||||
now, local_msg_counts, warmup_time[proc.name] = self.get_power_with_warmup_for_target(proc, prev)
|
||||
msg_counts.update(local_msg_counts)
|
||||
|
||||
used[proc.name] = now - prev
|
||||
prev = now
|
||||
for msg,sock in socks.items():
|
||||
msg_counts[msg] = len(messaging.drain_sock_raw(sock))
|
||||
|
||||
manager_cleanup()
|
||||
|
||||
tab = [['process', 'expected (W)', 'measured (W)', '# msgs expected', '# msgs received']]
|
||||
tab = [['process', 'expected (W)', 'measured (W)', '# msgs expected', '# msgs received', "warmup time (s)"]]
|
||||
for proc in PROCS:
|
||||
cur = used[proc.name]
|
||||
expected = proc.power
|
||||
msgs_received = sum(msg_counts[msg] for msg in proc.msgs)
|
||||
msgs_expected = int(sum(SAMPLE_TIME * SERVICE_LIST[msg].frequency for msg in proc.msgs))
|
||||
tab.append([proc.name, round(expected, 2), round(cur, 2), msgs_expected, msgs_received])
|
||||
tab.append([proc.name, round(expected, 2), round(cur, 2), self.get_expected_messages(proc), msgs_received, round(warmup_time[proc.name], 2)])
|
||||
with self.subTest(proc=proc.name):
|
||||
np.testing.assert_allclose(msgs_expected, msgs_received, rtol=.02, atol=2)
|
||||
np.testing.assert_allclose(cur, expected, rtol=proc.rtol, atol=proc.atol)
|
||||
self.assertTrue(self.valid_msg_count(proc, msg_counts), f"expected {self.get_expected_messages(proc)} msgs, got {msgs_received} msgs")
|
||||
self.assertTrue(self.valid_power_draw(proc, cur), f"expected {expected:.2f}W, got {cur:.2f}W")
|
||||
print(tabulate(tab))
|
||||
print(f"Baseline {baseline:.2f}W\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
pytest.main(sys.argv)
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
VideoEncoder::VideoEncoder(const EncoderInfo &encoder_info, int in_width, int in_height)
|
||||
: encoder_info(encoder_info), in_width(in_width), in_height(in_height) {
|
||||
|
||||
out_width = encoder_info.frame_width > 0 ? encoder_info.frame_width : in_width;
|
||||
out_height = encoder_info.frame_height > 0 ? encoder_info.frame_height : in_height;
|
||||
|
||||
pm.reset(new PubMaster({encoder_info.publish_name}));
|
||||
}
|
||||
|
||||
@@ -25,6 +29,8 @@ void VideoEncoder::publisher_publish(VideoEncoder *e, int segment_num, uint32_t
|
||||
edata.setFlags(flags);
|
||||
edata.setLen(dat.size());
|
||||
edat.setData(dat);
|
||||
edat.setWidth(out_width);
|
||||
edat.setHeight(out_height);
|
||||
if (flags & V4L2_BUF_FLAG_KEYFRAME) edat.setHeader(header);
|
||||
|
||||
uint32_t bytes_size = capnp::computeSerializedSizeInWords(msg) * sizeof(capnp::word);
|
||||
|
||||
@@ -22,10 +22,11 @@ public:
|
||||
virtual void encoder_open(const char* path) = 0;
|
||||
virtual void encoder_close() = 0;
|
||||
|
||||
static void publisher_publish(VideoEncoder *e, int segment_num, uint32_t idx, VisionIpcBufExtra &extra, unsigned int flags, kj::ArrayPtr<capnp::byte> header, kj::ArrayPtr<capnp::byte> dat);
|
||||
void publisher_publish(VideoEncoder *e, int segment_num, uint32_t idx, VisionIpcBufExtra &extra, unsigned int flags, kj::ArrayPtr<capnp::byte> header, kj::ArrayPtr<capnp::byte> dat);
|
||||
|
||||
protected:
|
||||
int in_width, in_height;
|
||||
int out_width, out_height;
|
||||
const EncoderInfo encoder_info;
|
||||
|
||||
private:
|
||||
|
||||
@@ -29,16 +29,16 @@ FfmpegEncoder::FfmpegEncoder(const EncoderInfo &encoder_info, int in_width, int
|
||||
frame = av_frame_alloc();
|
||||
assert(frame);
|
||||
frame->format = AV_PIX_FMT_YUV420P;
|
||||
frame->width = encoder_info.frame_width;
|
||||
frame->height = encoder_info.frame_height;
|
||||
frame->linesize[0] = encoder_info.frame_width;
|
||||
frame->linesize[1] = encoder_info.frame_width/2;
|
||||
frame->linesize[2] = encoder_info.frame_width/2;
|
||||
frame->width = out_width;
|
||||
frame->height = out_height;
|
||||
frame->linesize[0] = out_width;
|
||||
frame->linesize[1] = out_width/2;
|
||||
frame->linesize[2] = out_width/2;
|
||||
|
||||
convert_buf.resize(in_width * in_height * 3 / 2);
|
||||
|
||||
if (in_width != encoder_info.frame_width || in_height != encoder_info.frame_height) {
|
||||
downscale_buf.resize(encoder_info.frame_width * encoder_info.frame_height * 3 / 2);
|
||||
if (in_width != out_width || in_height != out_height) {
|
||||
downscale_buf.resize(out_width * out_height * 3 / 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user