Merge branch 'upstream/openpilot/master' into sync-20250215

# Conflicts:
#	common/params.cc
#	opendbc_repo
#	panda
#	selfdrive/car/tests/test_models.py
#	selfdrive/modeld/fill_model_msg.py
#	selfdrive/test/process_replay/process_replay.py
#	selfdrive/test/process_replay/ref_commit
#	selfdrive/ui/qt/offroad/developer_panel.cc
#	selfdrive/ui/tests/test_ui/run.py
#	selfdrive/ui/translations/main_ar.ts
#	selfdrive/ui/translations/main_de.ts
#	selfdrive/ui/translations/main_es.ts
#	selfdrive/ui/translations/main_fr.ts
#	selfdrive/ui/translations/main_ja.ts
#	selfdrive/ui/translations/main_ko.ts
#	selfdrive/ui/translations/main_pt-BR.ts
#	selfdrive/ui/translations/main_th.ts
#	selfdrive/ui/translations/main_tr.ts
#	selfdrive/ui/translations/main_zh-CHS.ts
#	selfdrive/ui/translations/main_zh-CHT.ts
#	system/athena/athenad.py
This commit is contained in:
Jason Wen
2025-02-15 20:19:43 -05:00
141 changed files with 2619 additions and 1336 deletions
+1 -1
View File
@@ -322,7 +322,7 @@ jobs:
run: |
${{ env.RUN }} "source selfdrive/test/setup_xvfb.sh && \
source selfdrive/test/setup_vsound.sh && \
CI=1 pytest tools/sim/tests/test_metadrive_bridge.py"
CI=1 pytest -s tools/sim/tests/test_metadrive_bridge.py"
create_ui_report:
# This job name needs to be the same as UI_JOB_NAME in ui_preview.yaml
Vendored
+2 -2
View File
@@ -103,7 +103,7 @@ def deviceStage(String stageName, String deviceType, List extra_env, def steps)
def diffPaths = args.diffPaths ?: []
def cmdTimeout = args.timeout ?: 9999
if (branch != "master" && diffPaths && !hasPathChanged(gitDiff, diffPaths)) {
if (branch != "master" && !branch.contains("__jenkins_loop_") && diffPaths && !hasPathChanged(gitDiff, diffPaths)) {
println "Skipping ${name}: no changes in ${diffPaths}."
return
} else {
@@ -170,7 +170,7 @@ node {
'testing-closet*', 'hotfix-*']
def excludeRegex = excludeBranches.join('|').replaceAll('\\*', '.*')
if (env.BRANCH_NAME != 'master') {
if (env.BRANCH_NAME != 'master' && !env.BRANCH_NAME.contains('__jenkins_loop_')) {
properties([
disableConcurrentBuilds(abortPrevious: true)
])
+13 -14
View File
@@ -1,23 +1,22 @@
Version 0.9.9 (2025-03-30)
Version 0.9.8 (2025-02-27)
========================
* New driving model
* Model now gates applying positive acceleration in Chill mode
* New driving monitoring model
* Reduced false positives related to passengers
* Image processing pipeline moved to the ISP
* More GPU time for bigger driving models
* Power draw reduced 0.5W, which means your device runs cooler
* Added toggle to enable driver monitoring even when openpilot is not engaged
* FIREHOSE mode
* Allows you to maximize your training data uploads to improve the models
* Enable openpilot longitudinal control for Ford Q3 vehicles
* New Toyota TSS2 longitudinal tune
* Coming soon
* Rivian support
* F-150 & Mach-E support
* Tesla Model 3 support
Version 0.9.8 (2025-01-30)
========================
* New driving monitoring model
* Reduced false positives related to passengers
* Image processing pipeline moved to the ISP
* More GPU time for driving models
* Power draw reduced 0.5W, which means your device runs cooler
* Added toggle to enable driver monitoring even when openpilot is not engaged
* Enable openpilot longitudinal control for Ford Q3 vehicles
* New Toyota TSS2 longitudinal tune
* Coming soon
* New driving model with gas gating
* Training data upload mode
Version 0.9.7 (2024-06-13)
========================
+1 -2
View File
@@ -361,7 +361,7 @@ SConscript(['opendbc_repo/SConscript'], exports={'env': env_swaglog})
SConscript(['cereal/SConscript'])
Import('socketmaster', 'msgq')
messaging = [socketmaster, msgq, 'zmq', 'capnp', 'kj',]
messaging = [socketmaster, msgq, 'capnp', 'kj',]
Export('messaging')
@@ -373,7 +373,6 @@ SConscript(['rednose/SConscript'])
# Build system services
SConscript([
'system/ui/SConscript',
'system/proclogd/SConscript',
'system/ubloxd/SConscript',
'system/loggerd/SConscript',
+4 -4
View File
@@ -29,7 +29,7 @@ _services: dict[str, tuple] = {
"pandaStates": (True, 10., 1),
"peripheralState": (True, 2., 1),
"radarState": (True, 20., 5),
"roadEncodeIdx": (False, 20., 1),
"roadEncodeIdx": (False, 20., 20),
"liveTracks": (True, 20.),
"sendcan": (True, 100., 139),
"logMessage": (True, 0.),
@@ -53,15 +53,15 @@ _services: dict[str, tuple] = {
"livePose": (True, 20., 4),
"liveParameters": (True, 20., 5),
"cameraOdometry": (True, 20., 10),
"thumbnail": (True, 0.2, 1),
"thumbnail": (True, 1 / 60., 1),
"onroadEvents": (True, 1., 1),
"carParams": (True, 0.02, 1),
"roadCameraState": (True, 20., 20),
"driverCameraState": (True, 20., 20),
"driverEncodeIdx": (False, 20., 1),
"driverEncodeIdx": (False, 20., 20),
"driverStateV2": (True, 20., 10),
"driverMonitoringState": (True, 20., 10),
"wideRoadEncodeIdx": (False, 20., 1),
"wideRoadEncodeIdx": (False, 20., 20),
"wideRoadCameraState": (True, 20., 20),
"drivingModelData": (True, 20., 10),
"modelV2": (True, 20.),
+21
View File
@@ -1,6 +1,10 @@
import io
import os
import tempfile
import contextlib
import zstandard as zstd
LOG_COMPRESSION_LEVEL = 10 # little benefit up to level 15. level ~17 is a small step change
class CallbackReader:
@@ -35,3 +39,20 @@ def atomic_write_in_dir(path: str, mode: str = 'w', buffering: int = -1, encodin
yield tmp_file
tmp_file_name = tmp_file.name
os.replace(tmp_file_name, path)
def get_upload_stream(filepath: str, should_compress: bool) -> tuple[io.BufferedIOBase, int]:
if not should_compress:
file_size = os.path.getsize(filepath)
file_stream = open(filepath, "rb")
return file_stream, file_size
# Compress the file on the fly
compressed_stream = io.BytesIO()
compressor = zstd.ZstdCompressor(level=LOG_COMPRESSION_LEVEL)
with open(filepath, "rb") as f:
compressor.copy_stream(f, compressed_stream)
compressed_size = compressed_stream.tell()
compressed_stream.seek(0)
return compressed_stream, compressed_size
+1 -1
View File
@@ -1 +1 @@
#define DEFAULT_MODEL "Notre Dame (Default)"
#define DEFAULT_MODEL "Not Too Shabby (Default)"
+1
View File
@@ -120,6 +120,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"ExperimentalLongitudinalEnabled", PERSISTENT | DEVELOPMENT_ONLY | BACKUP},
{"ExperimentalMode", PERSISTENT | BACKUP},
{"ExperimentalModeConfirmed", PERSISTENT | BACKUP},
{"FirehoseMode", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"FirmwareQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"ForcePowerDown", PERSISTENT},
{"GitBranch", PERSISTENT},
+2 -6
View File
@@ -27,11 +27,6 @@ class Priority:
CTRL_HIGH = 53
def set_realtime_priority(level: int) -> None:
if not PC:
os.sched_setscheduler(0, os.SCHED_FIFO, os.sched_param(level))
def set_core_affinity(cores: list[int]) -> None:
if not PC:
os.sched_setaffinity(0, cores)
@@ -39,7 +34,8 @@ def set_core_affinity(cores: list[int]) -> None:
def config_realtime_process(cores: int | list[int], priority: int) -> None:
gc.disable()
set_realtime_priority(priority)
if not PC:
os.sched_setscheduler(0, os.SCHED_FIFO, os.sched_param(priority))
c = cores if isinstance(cores, list) else [cores, ]
set_core_affinity(c)
+1 -1
View File
@@ -184,7 +184,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Lexus|RX Hybrid 2016|Lexus Safety System+|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<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=RX Hybrid 2016">Buy Here</a></sub></details>||
|Lexus|RX Hybrid 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<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=RX Hybrid 2017-19">Buy Here</a></sub></details>||
|Lexus|RX Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<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=RX Hybrid 2020-22">Buy Here</a></sub></details>||
|Lexus|UX Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<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=UX Hybrid 2019-23">Buy Here</a></sub></details>||
|Lexus|UX Hybrid 2019-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<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=UX Hybrid 2019-24">Buy Here</a></sub></details>||
|Lincoln|Aviator 2020-24|Co-Pilot360 Plus|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lincoln&model=Aviator 2020-24">Buy Here</a></sub></details>||
|Lincoln|Aviator Plug-in Hybrid 2020-24|Co-Pilot360 Plus|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lincoln&model=Aviator Plug-in Hybrid 2020-24">Buy Here</a></sub></details>||
|MAN|eTGE 2020-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=MAN&model=eTGE 2020-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
+1 -1
View File
@@ -7,7 +7,7 @@ export OPENBLAS_NUM_THREADS=1
export VECLIB_MAXIMUM_THREADS=1
if [ -z "$AGNOS_VERSION" ]; then
export AGNOS_VERSION="11.6"
export AGNOS_VERSION="11.8"
fi
export STAGING_ROOT="/data/safe_staging"
+1 -1
Submodule panda updated: 4ca963345a...44a9806bfb
+1
View File
@@ -111,6 +111,7 @@ dev = [
"tabulate",
"types-requests",
"types-tabulate",
"raylib",
]
tools = [
+145
View File
@@ -0,0 +1,145 @@
#!/usr/bin/env bash
set -e
YELLOW='\033[0;33m'
GREEN='\033[0;32m'
UNDERLINE='\033[4m'
BOLD='\033[1m'
NC='\033[0m'
BRANCH="master"
RUNS="20"
COOKIE_JAR=/tmp/cookies
CRUMB=$(curl -s --cookie-jar $COOKIE_JAR 'https://jenkins.comma.life/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)')
function loop() {
JENKINS_BRANCH="__jenkins_loop_${BRANCH}"
API_ROUTE="https://jenkins.comma.life/job/openpilot/job/$JENKINS_BRANCH"
for run in $(seq 1 $((RUNS / 2))); do
N=2
TEST_BUILDS=()
# Try to find previous builds
ALL_BUILDS=( $(curl -s $API_ROUTE/api/json | jq .builds.[].number 2> /dev/null || :) )
# No builds. Create branch
if [[ ${#ALL_BUILDS[@]} -eq 0 ]]; then
TEMP_DIR=$(mktemp -d)
GIT_LFS_SKIP_SMUDGE=1 git clone --quiet -b $BRANCH --depth=1 --no-tags git@github.com:commaai/openpilot $TEMP_DIR
git -C $TEMP_DIR checkout --quiet -b $JENKINS_BRANCH
echo "TESTING" >> $TEMP_DIR/testing_jenkins
git -C $TEMP_DIR add testing_jenkins
git -C $TEMP_DIR commit --quiet -m "testing"
git -C $TEMP_DIR push --quiet -f origin $JENKINS_BRANCH
rm -rf $TEMP_DIR
FIRST_BUILD=1
echo ''
echo 'waiting on Jenkins...'
echo ''
sleep 90
else
# Found some builds. Wait for them to end if they are still running
for i in ${ALL_BUILDS[@]}; do
running=$(curl -s $API_ROUTE/$i/api/json/ | jq .inProgress)
if [[ $running == "false" ]]; then
continue
fi
TEST_BUILDS=( ${ALL_BUILDS[@]} )
N=${#TEST_BUILDS[@]}
break
done
fi
# No running builds found
if [[ ${#TEST_BUILDS[@]} -eq 0 ]]; then
FIRST_BUILD=$(curl -s $API_ROUTE/api/json | jq .nextBuildNumber)
LAST_BUILD=$((FIRST_BUILD+N-1))
TEST_BUILDS=( $(seq $FIRST_BUILD $LAST_BUILD) )
# Start N new builds
for i in ${TEST_BUILDS[@]};
do
echo "Starting build $i"
curl -s --output /dev/null --cookie $COOKIE_JAR -H "$CRUMB" -X POST $API_ROUTE/build?delay=0sec
sleep 5
done
echo ""
fi
# Wait for all builds to end
while true; do
sleep 30
count=0
for i in ${TEST_BUILDS[@]};
do
RES=$(curl -s -w "\n%{http_code}" --cookie $COOKIE_JAR -H "$CRUMB" $API_ROUTE/$i/api/json)
HTTP_CODE=$(tail -n1 <<< "$RES")
JSON=$(sed '$ d' <<< "$RES")
if [[ $HTTP_CODE == "200" ]]; then
STILL_RUNNING=$(echo $JSON | jq .inProgress)
if [[ $STILL_RUNNING == "true" ]]; then
echo -e "Build $i: ${YELLOW}still running${NC}"
continue
else
count=$((count+1))
echo -e "Build $i: ${GREEN}done${NC}"
fi
else
echo "No status for build $i"
fi
done
echo "See live results: ${API_ROUTE}/buildTimeTrend"
echo ""
if [[ $count -ge $N ]]; then
break
fi
done
done
}
function usage() {
echo ""
echo "Run the Jenkins tests multiple times on a specific branch"
echo ""
echo -e "${BOLD}${UNDERLINE}Options:${NC}"
echo -e " ${BOLD}-n, --n${NC}"
echo -e " Specify how many runs to do (default to ${BOLD}20${NC})"
echo -e " ${BOLD}-b, --branch${NC}"
echo -e " Specify which branch to run the tests against (default to ${BOLD}master${NC})"
echo ""
}
function _looper() {
if [[ $# -eq 0 ]]; then
usage
exit 0
fi
# parse Options
while [[ $# -gt 0 ]]; do
case $1 in
-n | --n ) shift 1; RUNS="$1"; shift 1 ;;
-b | --b | --branch | -branch ) shift 1; BRANCH="$1"; shift 1 ;;
* ) usage; exit 0 ;;
esac
done
echo ""
echo -e "You are about to start $RUNS Jenkins builds against the $BRANCH branch."
echo -e "If you expect this to run overnight, ${UNDERLINE}${BOLD}unplug the cold reboot power switch${NC} from the testing closet before."
echo ""
read -p "Press (y/Y) to confirm: " choice
if [[ "$choice" == "y" || "$choice" == "Y" ]]; then
loop
fi
}
_looper $@
-1
View File
@@ -53,7 +53,6 @@ function run_tests() {
run "check_shebang_scripts_are_executable" python3 -m pre_commit_hooks.check_shebang_scripts_are_executable $ALL_FILES
run "check_shebang_format" $DIR/check_shebang_format.sh $ALL_FILES
run "check_nomerge_comments" $DIR/check_nomerge_comments.sh $ALL_FILES
run "check_raylib_includes" $DIR/check_raylib_includes.sh $ALL_FILES
if [[ -z "$FAST" ]]; then
run "mypy" mypy $PYTHON_FILES
+7 -16
View File
@@ -45,9 +45,6 @@ class CarSpecificEvents:
if self.CP.brand in ('body', 'mock'):
events = Events()
elif self.CP.brand in ('subaru', 'mazda'):
events = self.create_common_events(CS, CS_prev)
elif self.CP.brand == 'ford':
events = self.create_common_events(CS, CS_prev, extra_gears=[GearShifter.manumatic])
@@ -102,13 +99,9 @@ class CarSpecificEvents:
events.add(EventName.manualRestart)
elif self.CP.brand == 'gm':
# The ECM allows enabling on falling edge of set, but only rising edge of resume
events = self.create_common_events(CS, CS_prev, extra_gears=[GearShifter.sport, GearShifter.low,
GearShifter.eco, GearShifter.manumatic],
pcm_enable=self.CP.pcmCruise, enable_buttons=(ButtonType.decelCruise,))
if not self.CP.pcmCruise:
if any(b.type == ButtonType.accelCruise and b.pressed for b in CS.buttonEvents):
events.add(EventName.buttonEnable)
pcm_enable=self.CP.pcmCruise)
# Enabling at a standstill with brake is allowed
# TODO: verify 17 Volt can enable for the first time at a stop and allow for all GMs
@@ -122,8 +115,7 @@ class CarSpecificEvents:
elif self.CP.brand == 'volkswagen':
events = self.create_common_events(CS, CS_prev, extra_gears=[GearShifter.eco, GearShifter.sport, GearShifter.manumatic],
pcm_enable=self.CP.pcmCruise,
enable_buttons=(ButtonType.setCruise, ButtonType.resumeCruise))
pcm_enable=self.CP.pcmCruise)
# Low speed steer alert hysteresis logic
if (self.CP.minSteerSpeed - 1e-3) > VWCarControllerParams.DEFAULT_MIN_STEER_SPEED and CS.vEgo < (self.CP.minSteerSpeed + 1.):
@@ -160,12 +152,12 @@ class CarSpecificEvents:
events.add(EventName.belowSteerSpeed)
else:
raise ValueError(f"Unsupported car: {self.CP.brand}")
events = self.create_common_events(CS, CS_prev)
return events
def create_common_events(self, CS: structs.CarState, CS_prev: car.CarState, extra_gears=None, pcm_enable=True,
allow_enable=True, allow_button_cancel=True, enable_buttons=(ButtonType.accelCruise, ButtonType.decelCruise)):
allow_enable=True, allow_button_cancel=True):
events = Events()
if CS.doorOpen:
@@ -209,12 +201,11 @@ class CarSpecificEvents:
events.add(EventName.invalidLkasSetting)
if CS.lowSpeedAlert:
events.add(EventName.belowSteerSpeed)
if CS.buttonEnable:
events.add(EventName.buttonEnable)
# Handle button presses
# Handle cancel button presses
for b in CS.buttonEvents:
# Enable OP long on falling edge of enable buttons (defaults to accelCruise and decelCruise, overridable per-port)
if not self.CP.pcmCruise and (b.type in enable_buttons and not b.pressed):
events.add(EventName.buttonEnable)
# Disable on rising and falling edge of cancel for both stock and OP long
# TODO: only check the cancel button with openpilot longitudinal on all brands to match panda safety
if b.type == ButtonType.cancel and (allow_button_cancel or not self.CP.pcmCruise):
+3 -3
View File
@@ -8,17 +8,17 @@ import cereal.messaging as messaging
from cereal import car, log, custom
from panda import ALTERNATIVE_EXPERIENCE
from openpilot.common.params import Params
from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper
from openpilot.common.swaglog import cloudlog, ForwardingHandler
from opendbc.car import DT_CTRL, carlog, structs
from opendbc.car import DT_CTRL, structs
from opendbc.car.can_definitions import CanData, CanRecvCallable, CanSendCallable
from opendbc.car.carlog import carlog
from opendbc.car.fw_versions import ObdCallback
from opendbc.car.car_helpers import get_car, get_radar_interface
from opendbc.car.interfaces import CarInterfaceBase, RadarInterfaceBase
from opendbc.safety import ALTERNATIVE_EXPERIENCE
from openpilot.selfdrive.pandad import can_capnp_to_list, can_list_to_can_capnp
from openpilot.selfdrive.car.cruise import VCruiseHelper
from openpilot.selfdrive.car.car_specific import MockCarState
+10 -22
View File
@@ -1,3 +1,4 @@
import time
import capnp
import copy
import os
@@ -10,17 +11,15 @@ import hypothesis.strategies as st
from hypothesis import Phase, given, settings
from parameterized import parameterized_class
from cereal import messaging, log, car
from openpilot.common.basedir import BASEDIR
from openpilot.common.params import Params
from opendbc.car import DT_CTRL, gen_empty_fingerprint, structs
from opendbc.car.fingerprints import all_known_cars, MIGRATION
from opendbc.car.can_definitions import CanData
from opendbc.car.car_helpers import FRAME_FINGERPRINT, interfaces
from opendbc.car.fingerprints import all_known_cars, MIGRATION
from opendbc.car.honda.values import CAR as HONDA, HondaFlags
from opendbc.car.values import Platform
from opendbc.car.structs import car
from opendbc.car.tests.routes import non_tested_cars, routes, CarTestRoute
from openpilot.selfdrive.selfdrived.events import ET
from openpilot.selfdrive.selfdrived.selfdrived import SelfdriveD
from opendbc.car.values import Platform
from openpilot.common.basedir import BASEDIR
from openpilot.selfdrive.pandad import can_capnp_to_list
from openpilot.selfdrive.test.helpers import read_segment_list
from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT
@@ -30,8 +29,6 @@ from openpilot.tools.lib.route import SegmentName
from panda.tests.libpanda import libpanda_py
EventName = log.OnroadEvent.EventName
PandaType = log.PandaState.PandaType
SafetyModel = car.CarParams.SafetyModel
NUM_JOBS = int(os.environ.get("NUM_JOBS", "1"))
@@ -174,8 +171,6 @@ class TestCarModelBase(unittest.TestCase):
self.CI = self.CarInterface(self.CP.copy(), copy.deepcopy(self.CP_SP), self.CarController, self.CarState)
assert self.CI
Params().put_bool("OpenpilotEnabledToggle", self.openpilot_enabled)
# TODO: check safetyModel is in release panda build
self.safety = libpanda_py.libpanda
@@ -344,10 +339,8 @@ class TestCarModelBase(unittest.TestCase):
to_send = libpanda_py.make_CANPacket(address, bus, dat)
self.safety.safety_rx_hook(to_send)
can = messaging.new_message('can', 1)
can.can = [log.CanData(address=address, dat=dat, src=bus)]
CS = self.CI.update(can_capnp_to_list((can.to_bytes(),)))
can = [(int(time.monotonic() * 1e9), [CanData(address=address, dat=dat, src=bus)])]
CS = self.CI.update(can)
if self.safety.get_gas_pressed_prev() != prev_panda_gas:
self.assertEqual(CS.gasPressed, self.safety.get_gas_pressed_prev())
@@ -392,8 +385,6 @@ class TestCarModelBase(unittest.TestCase):
controls_allowed_prev = False
CS_prev = car.CarState.new_message()
checks = defaultdict(int)
selfdrived = SelfdriveD(CP=self.CP, CP_SP=self.CP_SP)
selfdrived.initialized = True
for idx, can in enumerate(self.can_msgs):
CS = self.CI.update(can_capnp_to_list((can.as_builder().to_bytes(), ))).as_reader()
for msg in filter(lambda m: m.src in range(64), can.can):
@@ -437,11 +428,8 @@ class TestCarModelBase(unittest.TestCase):
if not self.CP.notCar:
checks['cruiseState'] += CS.cruiseState.enabled != self.safety.get_cruise_engaged_prev()
else:
# Check for enable events on rising edge of controls allowed
selfdrived.update_events(CS)
selfdrived.CS_prev = CS
button_enable = (selfdrived.events.contains(ET.ENABLE) and
EventName.pedalPressed not in selfdrived.events.names)
# Check for user button enable on rising edge of controls allowed
button_enable = CS.buttonEnable and (not CS.brakePressed or CS.standstill)
mismatch = button_enable != (self.safety.get_controls_allowed() and not controls_allowed_prev)
checks['controlsAllowed'] += mismatch
controls_allowed_prev = self.safety.get_controls_allowed()
@@ -3,7 +3,7 @@ import os
import time
import numpy as np
from cereal import log
from opendbc.car.interfaces import ACCEL_MIN
from opendbc.car.interfaces import ACCEL_MIN, ACCEL_MAX
from openpilot.common.realtime import DT_MDL
from openpilot.common.swaglog import cloudlog
# WARNING: imports outside of constants will not trigger a rebuild
@@ -55,6 +55,8 @@ FCW_IDXS = T_IDXS < 5.0
T_DIFFS = np.diff(T_IDXS, prepend=[0.])
COMFORT_BRAKE = 2.5
STOP_DISTANCE = 6.0
CRUISE_MIN_ACCEL = -1.2
CRUISE_MAX_ACCEL = 1.6
def get_jerk_factor(personality=log.LongitudinalPersonality.standard):
if personality==log.LongitudinalPersonality.relaxed:
@@ -281,7 +283,7 @@ class LongitudinalMpc:
elif self.mode == 'blended':
a_change_cost = 40.0 if prev_accel_constraint else 0
cost_weights = [0., 0.1, 0.2, 5.0, a_change_cost, 1.0]
constraint_cost_weights = [LIMIT_COST, LIMIT_COST, LIMIT_COST, 50.0]
constraint_cost_weights = [LIMIT_COST, LIMIT_COST, LIMIT_COST, DANGER_ZONE_COST]
else:
raise NotImplementedError(f'Planner mode {self.mode} not recognized in planner cost set')
self.set_cost_weights(cost_weights, constraint_cost_weights)
@@ -325,12 +327,6 @@ class LongitudinalMpc:
lead_xv = self.extrapolate_lead(x_lead, v_lead, a_lead, a_lead_tau)
return lead_xv
def set_accel_limits(self, min_a, max_a):
# TODO this sets a max accel limit, but the minimum limit is only for cruise decel
# needs refactor
self.cruise_min_a = min_a
self.max_a = max_a
def update(self, radarstate, v_cruise, x, v, a, j, personality=log.LongitudinalPersonality.standard):
t_follow = get_T_FOLLOW(personality)
v_ego = self.x0[1]
@@ -346,8 +342,7 @@ class LongitudinalMpc:
lead_1_obstacle = lead_xv_1[:,0] + get_stopped_equivalence_factor(lead_xv_1[:,1])
self.params[:,0] = ACCEL_MIN
# negative accel constraint causes problems because negative speed is not allowed
self.params[:,1] = max(0.0, self.max_a)
self.params[:,1] = ACCEL_MAX
# Update in ACC mode or ACC/e2e blend
if self.mode == 'acc':
@@ -355,9 +350,9 @@ class LongitudinalMpc:
# Fake an obstacle for cruise, this ensures smooth acceleration to set speed
# when the leads are no factor.
v_lower = v_ego + (T_IDXS * self.cruise_min_a * 1.05)
v_lower = v_ego + (T_IDXS * CRUISE_MIN_ACCEL * 1.05)
# TODO does this make sense when max_a is negative?
v_upper = v_ego + (T_IDXS * self.max_a * 1.05)
v_upper = v_ego + (T_IDXS * CRUISE_MAX_ACCEL * 1.05)
v_cruise_clipped = np.clip(v_cruise * np.ones(N+1),
v_lower,
v_upper)
+21 -18
View File
@@ -18,7 +18,6 @@ from openpilot.common.swaglog import cloudlog
from openpilot.sunnypilot.selfdrive.controls.lib.longitudinal_planner import LongitudinalPlannerSP
LON_MPC_STEP = 0.2 # first step is 0.2s
A_CRUISE_MIN = -1.2
A_CRUISE_MAX_VALS = [1.6, 1.2, 0.8, 0.6]
A_CRUISE_MAX_BP = [0., 10.0, 25., 40.]
CONTROL_N_T_IDX = ModelConstants.T_IDXS[:CONTROL_N]
@@ -79,7 +78,10 @@ class LongitudinalPlanner(LongitudinalPlannerSP):
self.a_desired = init_a
self.v_desired_filter = FirstOrderFilter(init_v, 2.0, self.dt)
self.prev_accel_clip = [ACCEL_MIN, ACCEL_MAX]
self.v_model_error = 0.0
self.output_a_target = 0.0
self.output_should_stop = False
self.v_desired_trajectory = np.zeros(CONTROL_N)
self.a_desired_trajectory = np.zeros(CONTROL_N)
@@ -134,17 +136,16 @@ class LongitudinalPlanner(LongitudinalPlannerSP):
prev_accel_constraint = not (reset_state or sm['carState'].standstill)
if self.mpc.mode == 'acc':
accel_limits = [A_CRUISE_MIN, get_max_accel(v_ego)]
accel_clip = [ACCEL_MIN, get_max_accel(v_ego)]
steer_angle_without_offset = sm['carState'].steeringAngleDeg - sm['liveParameters'].angleOffsetDeg
accel_limits_turns = limit_accel_in_turns(v_ego, steer_angle_without_offset, accel_limits, self.CP)
accel_clip = limit_accel_in_turns(v_ego, steer_angle_without_offset, accel_clip, self.CP)
else:
accel_limits = [ACCEL_MIN, ACCEL_MAX]
accel_limits_turns = [ACCEL_MIN, ACCEL_MAX]
accel_clip = [ACCEL_MIN, ACCEL_MAX]
if reset_state:
self.v_desired_filter.x = v_ego
# Clip aEgo to cruise limits to prevent large accelerations when becoming active
self.a_desired = np.clip(sm['carState'].aEgo, accel_limits[0], accel_limits[1])
self.a_desired = np.clip(sm['carState'].aEgo, accel_clip[0], accel_clip[1])
# Prevent divergence, smooth in current v_ego
self.v_desired_filter.x = max(0.0, self.v_desired_filter.update(v_ego))
@@ -155,18 +156,14 @@ class LongitudinalPlanner(LongitudinalPlannerSP):
self.allow_throttle = throttle_prob > ALLOW_THROTTLE_THRESHOLD or v_ego <= MIN_ALLOW_THROTTLE_SPEED
if not self.allow_throttle:
clipped_accel_coast = max(accel_coast, accel_limits_turns[0])
clipped_accel_coast_interp = np.interp(v_ego, [MIN_ALLOW_THROTTLE_SPEED, MIN_ALLOW_THROTTLE_SPEED*2], [accel_limits_turns[1], clipped_accel_coast])
accel_limits_turns[1] = min(accel_limits_turns[1], clipped_accel_coast_interp)
clipped_accel_coast = max(accel_coast, accel_clip[0])
clipped_accel_coast_interp = np.interp(v_ego, [MIN_ALLOW_THROTTLE_SPEED, MIN_ALLOW_THROTTLE_SPEED*2], [accel_clip[1], clipped_accel_coast])
accel_clip[1] = min(accel_clip[1], clipped_accel_coast_interp)
if force_slow_decel:
v_cruise = 0.0
# clip limits, cannot init MPC outside of bounds
accel_limits_turns[0] = min(accel_limits_turns[0], self.a_desired + 0.05)
accel_limits_turns[1] = max(accel_limits_turns[1], self.a_desired - 0.05)
self.mpc.set_weights(prev_accel_constraint, personality=sm['selfdriveState'].personality)
self.mpc.set_accel_limits(accel_limits_turns[0], accel_limits_turns[1])
self.mpc.set_cur_state(self.v_desired_filter.x, self.a_desired)
self.mpc.update(sm['radarState'], v_cruise, x, v, a, j, personality=sm['selfdriveState'].personality)
@@ -184,6 +181,15 @@ class LongitudinalPlanner(LongitudinalPlannerSP):
self.a_desired = float(np.interp(self.dt, CONTROL_N_T_IDX, self.a_desired_trajectory))
self.v_desired_filter.x = self.v_desired_filter.x + self.dt * (self.a_desired + a_prev) / 2.0
action_t = self.CP.longitudinalActuatorDelay + DT_MDL
output_a_target, self.output_should_stop = get_accel_from_plan(self.v_desired_trajectory, self.a_desired_trajectory,
action_t=action_t, vEgoStopping=self.CP.vEgoStopping)
for idx in range(2):
accel_clip[idx] = np.clip(accel_clip[idx], self.prev_accel_clip[idx] - 0.05, self.prev_accel_clip[idx] + 0.05)
self.output_a_target = np.clip(output_a_target, accel_clip[0], accel_clip[1])
self.prev_accel_clip = accel_clip
def publish(self, sm, pm):
plan_send = messaging.new_message('longitudinalPlan')
@@ -202,11 +208,8 @@ class LongitudinalPlanner(LongitudinalPlannerSP):
longitudinalPlan.longitudinalPlanSource = self.mpc.source
longitudinalPlan.fcw = self.fcw
action_t = self.CP.longitudinalActuatorDelay + DT_MDL
a_target, should_stop = get_accel_from_plan(longitudinalPlan.speeds, longitudinalPlan.accels,
action_t=action_t, vEgoStopping=self.CP.vEgoStopping)
longitudinalPlan.aTarget = float(a_target)
longitudinalPlan.shouldStop = bool(should_stop)
longitudinalPlan.aTarget = float(self.output_a_target)
longitudinalPlan.shouldStop = bool(self.output_should_stop)
longitudinalPlan.allowBrake = True
longitudinalPlan.allowThrottle = bool(self.allow_throttle)
+1 -1
View File
@@ -11,5 +11,5 @@ if __name__ == "__main__":
time.sleep(1)
# honda bosch radar disable
disabled = disable_ecu(*can_callbacks, bus=1, addr=0x18DAB0F1, com_cont_req=b'\x28\x83\x03', timeout=0.5, debug=False)
disabled = disable_ecu(*can_callbacks, bus=1, addr=0x18DAB0F1, com_cont_req=b'\x28\x83\x03', timeout=0.5)
print(f"disabled: {disabled}")
+5 -1
View File
@@ -2,6 +2,7 @@
import argparse
import time
import cereal.messaging as messaging
from opendbc.car.carlog import carlog
from opendbc.car.ecu_addrs import get_all_ecu_addrs
from openpilot.common.params import Params
from openpilot.selfdrive.car.card import can_comm_callbacks, obd_callback
@@ -15,6 +16,9 @@ if __name__ == "__main__":
parser.add_argument('--timeout', type=float, default=1.0)
args = parser.parse_args()
if args.debug:
carlog.setLevel('DEBUG')
logcan = messaging.sub_sock('can')
sendcan = messaging.pub_sock('sendcan')
can_callbacks = can_comm_callbacks(logcan, sendcan)
@@ -29,7 +33,7 @@ if __name__ == "__main__":
obd_callback(params)(not args.no_obd)
print("Getting ECU addresses ...")
ecu_addrs = get_all_ecu_addrs(*can_callbacks, args.bus, args.timeout, debug=args.debug)
ecu_addrs = get_all_ecu_addrs(*can_callbacks, args.bus, args.timeout)
print()
print("Found ECUs on rx addresses:")
+6 -2
View File
@@ -3,6 +3,7 @@ import time
import argparse
import cereal.messaging as messaging
from cereal import car
from opendbc.car.carlog import carlog
from opendbc.car.fw_versions import get_fw_versions, match_fw_to_car
from opendbc.car.vin import get_vin
from openpilot.common.params import Params
@@ -18,6 +19,9 @@ if __name__ == "__main__":
parser.add_argument('--brand', help='Only query addresses/with requests for this brand')
args = parser.parse_args()
if args.debug:
carlog.setLevel('DEBUG')
logcan = messaging.sub_sock('can')
pandaStates_sock = messaging.sub_sock('pandaStates')
sendcan = messaging.pub_sock('sendcan')
@@ -46,13 +50,13 @@ if __name__ == "__main__":
t = time.time()
print("Getting vin...")
set_obd_multiplexing(True)
vin_rx_addr, vin_rx_bus, vin = get_vin(*can_callbacks, (0, 1), debug=args.debug)
vin_rx_addr, vin_rx_bus, vin = get_vin(*can_callbacks, (0, 1))
print(f'RX: {hex(vin_rx_addr)}, BUS: {vin_rx_bus}, VIN: {vin}')
print(f"Getting VIN took {time.time() - t:.3f} s")
print()
t = time.time()
fw_vers = get_fw_versions(*can_callbacks, set_obd_multiplexing, query_brand=args.brand, extra=extra, num_pandas=num_pandas, debug=args.debug, progress=True)
fw_vers = get_fw_versions(*can_callbacks, set_obd_multiplexing, query_brand=args.brand, extra=extra, num_pandas=num_pandas, progress=True)
_, candidates = match_fw_to_car(fw_vers, vin)
print()
+5 -1
View File
@@ -2,6 +2,7 @@
import argparse
import time
import cereal.messaging as messaging
from opendbc.car.carlog import carlog
from opendbc.car.vin import get_vin
from openpilot.selfdrive.car.card import can_comm_callbacks
@@ -13,10 +14,13 @@ if __name__ == "__main__":
parser.add_argument('--retry', type=int, default=5)
args = parser.parse_args()
if args.debug:
carlog.setLevel('DEBUG')
sendcan = messaging.pub_sock('sendcan')
logcan = messaging.sub_sock('can')
can_callbacks = can_comm_callbacks(logcan, sendcan)
time.sleep(1)
vin_rx_addr, vin_rx_bus, vin = get_vin(*can_callbacks, (args.bus,), args.timeout, args.retry, debug=args.debug)
vin_rx_addr, vin_rx_bus, vin = get_vin(*can_callbacks, (args.bus,), args.timeout, args.retry)
print(f'RX: {hex(vin_rx_addr)}, BUS: {vin_rx_bus}, VIN: {vin}')
+7 -2
View File
@@ -2,7 +2,9 @@
import sys
import argparse
from subprocess import check_output, CalledProcessError
from opendbc.car.carlog import carlog
from opendbc.car.uds import UdsClient, MessageTimeoutError, SESSION_TYPE, DTC_GROUP_TYPE
from opendbc.safety import Safety
from panda import Panda
parser = argparse.ArgumentParser(description="clear DTC status")
@@ -11,6 +13,9 @@ parser.add_argument("--bus", type=int, default=0)
parser.add_argument('--debug', action='store_true')
args = parser.parse_args()
if args.debug:
carlog.setLevel('DEBUG')
try:
check_output(["pidof", "pandad"])
print("pandad is running, please kill openpilot before running this script! (aborted)")
@@ -20,8 +25,8 @@ except CalledProcessError as e:
raise e
panda = Panda()
panda.set_safety_mode(Panda.SAFETY_ELM327)
uds_client = UdsClient(panda, args.addr, bus=args.bus, debug=args.debug)
panda.set_safety_mode(Safety.SAFETY_ELM327)
uds_client = UdsClient(panda, args.addr, bus=args.bus)
print("extended diagnostic session ...")
try:
uds_client.diagnostic_session_control(SESSION_TYPE.EXTENDED_DIAGNOSTIC)
@@ -16,7 +16,9 @@ import argparse
from typing import NamedTuple
from subprocess import check_output, CalledProcessError
from opendbc.car.carlog import carlog
from opendbc.car.uds import UdsClient, SESSION_TYPE, DATA_IDENTIFIER_TYPE
from opendbc.safety import Safety
from panda.python import Panda
class ConfigValues(NamedTuple):
@@ -78,6 +80,9 @@ if __name__ == "__main__":
parser.add_argument('--bus', type=int, default=0, help='can bus to use (default: 0)')
args = parser.parse_args()
if args.debug:
carlog.setLevel('DEBUG')
try:
check_output(["pidof", "pandad"])
print("pandad is running, please kill openpilot before running this script! (aborted)")
@@ -92,8 +97,8 @@ if __name__ == "__main__":
sys.exit(0)
panda = Panda()
panda.set_safety_mode(Panda.SAFETY_ELM327)
uds_client = UdsClient(panda, 0x7D0, bus=args.bus, debug=args.debug)
panda.set_safety_mode(Safety.SAFETY_ELM327)
uds_client = UdsClient(panda, 0x7D0, bus=args.bus)
print("\n[START DIAGNOSTIC SESSION]")
session_type : SESSION_TYPE = 0x07 # type: ignore
+1 -1
View File
@@ -6,7 +6,7 @@ from collections import defaultdict
import matplotlib.pyplot as plt
from cereal.services import SERVICE_LIST
from openpilot.system.loggerd.uploader import LOG_COMPRESSION_LEVEL
from openpilot.common.file_helpers import LOG_COMPRESSION_LEVEL
from openpilot.tools.lib.logreader import LogReader
from tqdm import tqdm
+7 -2
View File
@@ -2,7 +2,9 @@
import sys
import argparse
from subprocess import check_output, CalledProcessError
from opendbc.car.carlog import carlog
from opendbc.car.uds import UdsClient, SESSION_TYPE, DTC_REPORT_TYPE, DTC_STATUS_MASK_TYPE, get_dtc_num_as_str, get_dtc_status_names
from opendbc.safety import Safety
from panda import Panda
parser = argparse.ArgumentParser(description="read DTC status")
@@ -11,6 +13,9 @@ parser.add_argument("--bus", type=int, default=0)
parser.add_argument('--debug', action='store_true')
args = parser.parse_args()
if args.debug:
carlog.setLevel('DEBUG')
try:
check_output(["pidof", "pandad"])
print("pandad is running, please kill openpilot before running this script! (aborted)")
@@ -20,8 +25,8 @@ except CalledProcessError as e:
raise e
panda = Panda()
panda.set_safety_mode(Panda.SAFETY_ELM327)
uds_client = UdsClient(panda, args.addr, bus=args.bus, debug=args.debug)
panda.set_safety_mode(Safety.SAFETY_ELM327)
uds_client = UdsClient(panda, args.addr, bus=args.bus)
print("extended diagnostic session ...")
uds_client.diagnostic_session_control(SESSION_TYPE.EXTENDED_DIAGNOSTIC)
print("read diagnostic codes ...")
+7 -2
View File
@@ -3,8 +3,10 @@
import argparse
import struct
from enum import IntEnum
from opendbc.car.carlog import carlog
from opendbc.car.uds import UdsClient, MessageTimeoutError, NegativeResponseError, SESSION_TYPE,\
DATA_IDENTIFIER_TYPE, ACCESS_TYPE
from opendbc.safety import Safety
from panda import Panda
from datetime import date
@@ -33,10 +35,13 @@ if __name__ == "__main__":
parser.add_argument("action", choices={"show", "enable", "disable"}, help="show or modify current EPS HCA config")
args = parser.parse_args()
if args.debug:
carlog.setLevel('DEBUG')
panda = Panda()
panda.set_safety_mode(Panda.SAFETY_ELM327)
panda.set_safety_mode(Safety.SAFETY_ELM327)
bus = 1 if panda.has_obd() else 0
uds_client = UdsClient(panda, MQB_EPS_CAN_ADDR, MQB_EPS_CAN_ADDR + RX_OFFSET, bus, timeout=0.2, debug=args.debug)
uds_client = UdsClient(panda, MQB_EPS_CAN_ADDR, MQB_EPS_CAN_ADDR + RX_OFFSET, bus, timeout=0.2)
try:
uds_client.diagnostic_session_control(SESSION_TYPE.EXTENDED_DIAGNOSTIC)
+2 -4
View File
@@ -6,7 +6,6 @@ While the roll calibration is a real value that can be estimated, here we assume
and the image input into the neural network is not corrected for roll.
'''
import gc
import os
import capnp
import numpy as np
@@ -16,7 +15,7 @@ from cereal import log
import cereal.messaging as messaging
from openpilot.common.conversions import Conversions as CV
from openpilot.common.params import Params
from openpilot.common.realtime import set_realtime_priority
from openpilot.common.realtime import config_realtime_process
from openpilot.common.transformations.orientation import rot_from_euler, euler_from_rot
from openpilot.common.swaglog import cloudlog
@@ -256,8 +255,7 @@ class Calibrator:
def main() -> NoReturn:
gc.disable()
set_realtime_priority(1)
config_realtime_process([0, 1, 2, 3], 5)
pm = messaging.PubMaster(['liveCalibration'])
sm = messaging.SubMaster(['cameraOdometry', 'carState', 'carParams'], poll='cameraOdometry')
+7 -7
View File
@@ -12,6 +12,7 @@ from cereal.services import SERVICE_LIST
from openpilot.common.transformations.orientation import rot_from_euler
from openpilot.common.realtime import config_realtime_process
from openpilot.common.params import Params
from openpilot.common.swaglog import cloudlog
from openpilot.selfdrive.locationd.helpers import rotate_std
from openpilot.selfdrive.locationd.models.pose_kf import PoseKalman, States
from openpilot.selfdrive.locationd.models.constants import ObservationKind, GENERATED_DIR
@@ -78,20 +79,20 @@ class LocationEstimator:
# sensor time and log time should be close
sensor_time_invalid = abs(sensor_time - t) > MAX_SENSOR_TIME_DIFF
if sensor_time_invalid:
print("Sensor reading ignored, sensor timestamp more than 100ms off from log time")
cloudlog.warning("Sensor reading ignored, sensor timestamp more than 100ms off from log time")
return not sensor_time_invalid
def _validate_timestamp(self, t: float):
kf_t = self.kf.t
invalid = not np.isnan(kf_t) and (kf_t - t) > MAX_FILTER_REWIND_TIME
if invalid:
print("Observation timestamp is older than the max rewind threshold of the filter")
cloudlog.warning("Observation timestamp is older than the max rewind threshold of the filter")
return not invalid
def _finite_check(self, t: float, new_x: np.ndarray, new_P: np.ndarray):
all_finite = np.isfinite(new_x).all() and np.isfinite(new_P).all()
if not all_finite:
print("Non-finite values detected, kalman reset")
cloudlog.error("Non-finite values detected, kalman reset")
self.reset(t)
def handle_log(self, t: float, which: str, msg: capnp._DynamicStructReader) -> HandleLogResult:
@@ -308,13 +309,12 @@ def main():
continue
if res == HandleLogResult.TIMING_INVALID:
print(f"Observation {which} ignored due to failed timing check")
cloudlog.warning(f"Observation {which} ignored due to failed timing check")
observation_input_invalid[which] += 1
print(observation_input_invalid[which])
elif res == HandleLogResult.INPUT_INVALID:
print(f"Observation {which} ignored due to failed sanity check")
cloudlog.warning(f"Observation {which} ignored due to failed sanity check")
observation_input_invalid[which] += 1
else:
elif res == HandleLogResult.SUCCESS:
observation_input_invalid[which] *= input_invalid_decay[which]
else:
filter_initialized = sm.all_checks() and sensor_all_checks(acc_msgs, gyro_msgs, sensor_valid, sensor_recv_time, sensor_alive, SIMULATION)
+10 -10
View File
@@ -31,7 +31,6 @@ class ModelConstants:
DISENGAGE_WIDTH = 5
POSE_WIDTH = 6
WIDE_FROM_DEVICE_WIDTH = 3
SIM_POSE_WIDTH = 6
LEAD_WIDTH = 4
LANE_LINES_WIDTH = 2
ROAD_EDGES_WIDTH = 2
@@ -72,13 +71,14 @@ class Plan:
class Meta:
ENGAGED = slice(0, 1)
# next 2, 4, 6, 8, 10 seconds
GAS_DISENGAGE = slice(1, 36, 7)
BRAKE_DISENGAGE = slice(2, 36, 7)
STEER_OVERRIDE = slice(3, 36, 7)
HARD_BRAKE_3 = slice(4, 36, 7)
HARD_BRAKE_4 = slice(5, 36, 7)
HARD_BRAKE_5 = slice(6, 36, 7)
GAS_PRESS = slice(7, 36, 7)
GAS_DISENGAGE = slice(1, 31, 6)
BRAKE_DISENGAGE = slice(2, 31, 6)
STEER_OVERRIDE = slice(3, 31, 6)
HARD_BRAKE_3 = slice(4, 31, 6)
HARD_BRAKE_4 = slice(5, 31, 6)
HARD_BRAKE_5 = slice(6, 31, 6)
# next 0, 2, 4, 6, 8, 10 seconds
LEFT_BLINKER = slice(36, 48, 2)
RIGHT_BLINKER = slice(37, 48, 2)
GAS_PRESS = slice(31, 55, 4)
BRAKE_PRESS = slice(32, 55, 4)
LEFT_BLINKER = slice(33, 55, 4)
RIGHT_BLINKER = slice(34, 55, 4)
+2 -4
View File
@@ -8,7 +8,6 @@ if TICI:
os.environ['QCOM'] = '1'
else:
from openpilot.selfdrive.modeld.runners.ort_helpers import make_onnx_cpu_runner
import gc
import math
import time
import pickle
@@ -21,7 +20,7 @@ from cereal import messaging
from cereal.messaging import PubMaster, SubMaster
from msgq.visionipc import VisionIpcClient, VisionStreamType, VisionBuf
from openpilot.common.swaglog import cloudlog
from openpilot.common.realtime import set_realtime_priority
from openpilot.common.realtime import config_realtime_process
from openpilot.common.transformations.model import dmonitoringmodel_intrinsics, DM_INPUT_SIZE
from openpilot.common.transformations.camera import _ar_ox_fisheye, _os_fisheye
from openpilot.selfdrive.modeld.models.commonmodel_pyx import CLContext, MonitoringModelFrame
@@ -140,9 +139,8 @@ def get_driverstate_packet(model_output: np.ndarray, frame_id: int, location_ts:
def main():
gc.disable()
setproctitle(PROCESS_NAME)
set_realtime_priority(1)
config_realtime_process([0, 1, 2, 3], 5)
sentry.set_tag("daemon", PROCESS_NAME)
cloudlog.bind(daemon=PROCESS_NAME)
+4 -4
View File
@@ -112,10 +112,10 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
# temporal pose
temporal_pose = modelV2.temporalPose
temporal_pose.trans = net_output_data['plan'][0,0,Plan.VELOCITY].tolist()
temporal_pose.transStd = net_output_data['plan_stds'][0,0,Plan.VELOCITY].tolist()
temporal_pose.rot = net_output_data['plan'][0,0,Plan.ORIENTATION_RATE].tolist()
temporal_pose.rotStd = net_output_data['plan_stds'][0,0,Plan.ORIENTATION_RATE].tolist()
temporal_pose.trans = net_output_data['sim_pose'][0,:ModelConstants.POSE_WIDTH//2].tolist()
temporal_pose.transStd = net_output_data['sim_pose_stds'][0,:ModelConstants.POSE_WIDTH//2].tolist()
temporal_pose.rot = net_output_data['sim_pose'][0,ModelConstants.POSE_WIDTH//2:].tolist()
temporal_pose.rotStd = net_output_data['sim_pose_stds'][0,ModelConstants.POSE_WIDTH//2:].tolist()
# poly path
fill_xyz_poly(driving_model_data.path, ModelConstants.POLY_PATH_DEGREE, *net_output_data['plan'][0,:,Plan.POSITION].T)
+2 -2
View File
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:39786068cae1ed8c0dc34ef80c281dfcc67ed18a50e06b90765c49bcfdbf7db4
size 51453312
oid sha256:d21daa542227ecc5972da45df4e26f018ba113c0461f270e367d57e3ad89221a
size 51461700
+1
View File
@@ -91,6 +91,7 @@ class Parser:
self.parse_mdn('road_edges', outs, in_N=0, out_N=0, out_shape=(ModelConstants.NUM_ROAD_EDGES,ModelConstants.IDX_N,ModelConstants.LANE_LINES_WIDTH))
self.parse_mdn('pose', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,))
self.parse_mdn('road_transform', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,))
self.parse_mdn('sim_pose', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,))
self.parse_mdn('wide_from_device_euler', outs, in_N=0, out_N=0, out_shape=(ModelConstants.WIDE_FROM_DEVICE_WIDTH,))
self.parse_mdn('lead', outs, in_N=ModelConstants.LEAD_MHP_N, out_N=ModelConstants.LEAD_MHP_SELECTION,
out_shape=(ModelConstants.LEAD_TRAJ_LEN,ModelConstants.LEAD_WIDTH))
+2 -5
View File
@@ -1,15 +1,12 @@
#!/usr/bin/env python3
import gc
import cereal.messaging as messaging
from openpilot.common.params import Params
from openpilot.common.realtime import set_realtime_priority
from openpilot.common.realtime import config_realtime_process
from openpilot.selfdrive.monitoring.helpers import DriverMonitoring
def dmonitoringd_thread():
gc.disable()
set_realtime_priority(2)
config_realtime_process([0, 1, 2, 3], 5)
params = Params()
pm = messaging.PubMaster(['driverMonitoringState'])
-7
View File
@@ -2,10 +2,3 @@
from openpilot.selfdrive.pandad.pandad_api_impl import can_list_to_can_capnp, can_capnp_to_list
assert can_list_to_can_capnp
assert can_capnp_to_list
def can_capnp_to_can_list(can, src_filter=None):
ret = []
for msg in can:
if src_filter is None or msg.src in src_filter:
ret.append((msg.address, msg.dat, msg.src))
return ret
+1 -2
View File
@@ -1,8 +1,7 @@
#include "cereal/messaging/messaging.h"
#include "selfdrive/pandad/panda.h"
#include "opendbc/can/common.h"
void can_list_to_can_capnp_cpp(const std::vector<can_frame> &can_list, std::string &out, bool sendcan, bool valid) {
void can_list_to_can_capnp_cpp(const std::vector<CanFrame> &can_list, std::string &out, bool sendcan, bool valid) {
MessageBuilder msg;
auto event = msg.initEvent(valid);
+3 -9
View File
@@ -6,12 +6,6 @@ from libcpp.string cimport string
from libcpp cimport bool
from libc.stdint cimport uint8_t, uint32_t, uint64_t
cdef extern from "panda.h":
cdef struct can_frame:
long address
string dat
long src
cdef extern from "opendbc/can/common.h":
cdef struct CanFrame:
long src
@@ -23,12 +17,12 @@ cdef extern from "opendbc/can/common.h":
vector[CanFrame] frames
cdef extern from "can_list_to_can_capnp.cc":
void can_list_to_can_capnp_cpp(const vector[can_frame] &can_list, string &out, bool sendcan, bool valid)
void can_list_to_can_capnp_cpp(const vector[CanFrame] &can_list, string &out, bool sendcan, bool valid)
void can_capnp_to_can_list_cpp(const vector[string] &strings, vector[CanData] &can_data, bool sendcan)
def can_list_to_can_capnp(can_msgs, msgtype='can', valid=True):
cdef can_frame *f
cdef vector[can_frame] can_list
cdef CanFrame *f
cdef vector[CanFrame] can_list
can_list.reserve(len(can_msgs))
for can_msg in can_msgs:
+2 -3
View File
@@ -7,7 +7,7 @@ import cereal.messaging as messaging
from cereal import car, log, custom
from msgq.visionipc import VisionIpcClient, VisionStreamType
from panda import ALTERNATIVE_EXPERIENCE
from opendbc.safety import ALTERNATIVE_EXPERIENCE
from openpilot.common.params import Params
@@ -31,7 +31,6 @@ from openpilot.sunnypilot.selfdrive.selfdrived.events import EventsSP
REPLAY = "REPLAY" in os.environ
SIMULATION = "SIMULATION" in os.environ
TESTING_CLOSET = "TESTING_CLOSET" in os.environ
IGNORE_PROCESSES = {"loggerd", "encoderd", "statsd"}
LONGITUDINAL_PERSONALITY_MAP = {v: k for k, v in log.LongitudinalPersonality.schema.enumerants.items()}
ThermalStatus = log.DeviceState.ThermalStatus
@@ -284,7 +283,7 @@ class SelfdriveD(CruiseHelper):
if not_running != self.not_running_prev:
cloudlog.event("process_not_running", not_running=not_running, error=True)
self.not_running_prev = not_running
if self.sm.recv_frame['managerState'] and (not_running - IGNORE_PROCESSES):
if self.sm.recv_frame['managerState'] and not_running:
self.events.add(EventName.processNotRunning)
else:
if not SIMULATION and not self.rk.lagging:
@@ -66,7 +66,7 @@ class Maneuver:
print("Crashed!!!!")
valid = False
if self.ensure_start and log['v_rel'] > 0 and log['speeds'][-1] <= 0.1:
if self.ensure_start and log['v_rel'] > 0 and log['acceleration'] < 1e-3:
print('LongitudinalPlanner not starting!')
valid = False
@@ -30,8 +30,8 @@ class Plant:
self.distance = 0.
self.speed = speed
self.should_stop = False
self.acceleration = 0.0
self.speeds = []
# lead car
self.lead_relevancy = lead_relevancy
@@ -134,9 +134,9 @@ class Plant:
'liveParameters': lp.liveParameters,
'modelV2': model.modelV2}
self.planner.update(sm)
self.speed = self.planner.v_desired_filter.x
self.acceleration = self.planner.a_desired
self.speeds = self.planner.v_desired_trajectory.tolist()
self.acceleration = self.planner.output_a_target
self.speed = self.speed + self.acceleration * self.ts
self.should_stop = self.planner.output_should_stop
fcw = self.planner.fcw
self.distance_lead = self.distance_lead + v_lead * self.ts
@@ -168,7 +168,7 @@ class Plant:
"distance": self.distance,
"speed": self.speed,
"acceleration": self.acceleration,
"speeds": self.speeds,
"should_stop": self.should_stop,
"distance_lead": self.distance_lead,
"fcw": fcw,
}
@@ -150,10 +150,7 @@ def create_maneuvers(kwargs):
enabled=False,
**kwargs,
),
]
if not kwargs['e2e']:
# allow_throttle won't trigger with e2e
maneuvers.append(Maneuver(
Maneuver(
"slow to 5m/s with allow_throttle = False and pitch = +0.1",
duration=30.,
initial_speed=20.,
@@ -164,7 +161,7 @@ def create_maneuvers(kwargs):
breakpoints=[0.0, 2., 2.01],
ensure_slowdown=True,
**kwargs,
))
)]
if not kwargs['force_decel']:
# controls relies on planner commanding to move for stock-ACC resume spamming
maneuvers.append(Maneuver(
+8 -8
View File
@@ -6,15 +6,15 @@ import traceback
from cereal import messaging, car, log
from opendbc.car.fingerprints import MIGRATION
from opendbc.car.toyota.values import EPS_SCALE
from opendbc.car.ford.values import CAR as FORD, FordFlags
from opendbc.car.toyota.values import EPS_SCALE, ToyotaSafetyFlags
from opendbc.car.ford.values import CAR as FORD, FordFlags, FordSafetyFlags
from opendbc.car.hyundai.values import HyundaiSafetyFlags
from openpilot.selfdrive.modeld.constants import ModelConstants
from openpilot.selfdrive.modeld.fill_model_msg import fill_xyz_poly, fill_lane_line_meta
from openpilot.selfdrive.test.process_replay.vision_meta import meta_from_encode_index
from openpilot.selfdrive.controls.lib.longitudinal_planner import get_accel_from_plan
from openpilot.system.manager.process_config import managed_processes
from openpilot.tools.lib.logreader import LogIterable
from panda import Panda
MessageWithIndex = tuple[int, capnp.lib.capnp._DynamicStructReader]
MigrationOps = tuple[list[tuple[int, capnp.lib.capnp._DynamicStructReader]], list[capnp.lib.capnp._DynamicStructReader], list[int]]
@@ -269,19 +269,19 @@ def migrate_carOutput(msgs):
def migrate_pandaStates(msgs):
# TODO: safety param migration should be handled automatically
safety_param_migration = {
"TOYOTA_PRIUS": EPS_SCALE["TOYOTA_PRIUS"] | Panda.FLAG_TOYOTA_STOCK_LONGITUDINAL,
"TOYOTA_RAV4": EPS_SCALE["TOYOTA_RAV4"] | Panda.FLAG_TOYOTA_ALT_BRAKE,
"KIA_EV6": Panda.FLAG_HYUNDAI_EV_GAS | Panda.FLAG_HYUNDAI_CANFD_HDA2,
"TOYOTA_PRIUS": EPS_SCALE["TOYOTA_PRIUS"] | ToyotaSafetyFlags.FLAG_TOYOTA_STOCK_LONGITUDINAL,
"TOYOTA_RAV4": EPS_SCALE["TOYOTA_RAV4"] | ToyotaSafetyFlags.FLAG_TOYOTA_ALT_BRAKE,
"KIA_EV6": HyundaiSafetyFlags.FLAG_HYUNDAI_EV_GAS | HyundaiSafetyFlags.FLAG_HYUNDAI_CANFD_HDA2,
}
# TODO: get new Ford route
safety_param_migration |= {car: Panda.FLAG_FORD_LONG_CONTROL for car in (set(FORD) - FORD.with_flags(FordFlags.CANFD))}
safety_param_migration |= {car: FordSafetyFlags.FLAG_FORD_LONG_CONTROL for car in (set(FORD) - FORD.with_flags(FordFlags.CANFD))}
# Migrate safety param base on carParams
CP = next((m.carParams for _, m in msgs if m.which() == 'carParams'), None)
assert CP is not None, "carParams message not found"
fingerprint = MIGRATION.get(CP.carFingerprint, CP.carFingerprint)
if fingerprint in safety_param_migration:
safety_param = safety_param_migration[fingerprint]
safety_param = safety_param_migration[fingerprint].value
elif len(CP.safetyConfigs):
safety_param = CP.safetyConfigs[0].safetyParam
if CP.safetyConfigs[0].safetyParamDEPRECATED != 0:
+15 -12
View File
@@ -33,7 +33,7 @@ GITHUB = GithubUtils(API_TOKEN, DATA_TOKEN)
EXEC_TIMINGS = [
# model, instant max, average max
("modelV2", 0.03, 0.025),
("modelV2", 0.035, 0.025),
("driverStateV2", 0.02, 0.015),
]
@@ -57,21 +57,24 @@ def get_event(logs, event):
def zl(array, fill):
return zip_longest(array, [], fillvalue=fill)
def get_idx_if_non_empty(l, idx=None):
return l if idx is None else (l[idx] if len(l) > 0 else None)
def generate_report(proposed, master, tmp, commit):
ModelV2_Plots = zl([
(lambda x: x.velocity.x[0], "velocity.x"),
(lambda x: x.action.desiredCurvature, "desiredCurvature"),
(lambda x: x.leadsV3[0].x[0], "leadsV3.x"),
(lambda x: x.laneLines[1].y[0], "laneLines.y"),
#(lambda x: x.meta.disengagePredictions.gasPressProbs[1], "gasPressProbs")
(lambda x: get_idx_if_non_empty(x.velocity.x, 0), "velocity.x"),
(lambda x: get_idx_if_non_empty(x.action.desiredCurvature), "desiredCurvature"),
(lambda x: get_idx_if_non_empty(x.leadsV3[0].x, 0), "leadsV3.x"),
(lambda x: get_idx_if_non_empty(x.laneLines[1].y, 0), "laneLines.y"),
(lambda x: get_idx_if_non_empty(x.meta.disengagePredictions.gasPressProbs, 1), "gasPressProbs")
], "modelV2")
DriverStateV2_Plots = zl([
(lambda x: x.wheelOnRightProb, "wheelOnRightProb"),
(lambda x: x.leftDriverData.faceProb, "leftDriverData.faceProb"),
(lambda x: x.leftDriverData.faceOrientation[0], "leftDriverData.faceOrientation0"),
(lambda x: x.leftDriverData.leftBlinkProb, "leftDriverData.leftBlinkProb"),
(lambda x: x.leftDriverData.notReadyProb[0], "leftDriverData.notReadyProb0"),
(lambda x: x.rightDriverData.faceProb, "rightDriverData.faceProb"),
(lambda x: get_idx_if_non_empty(x.wheelOnRightProb), "wheelOnRightProb"),
(lambda x: get_idx_if_non_empty(x.leftDriverData.faceProb), "leftDriverData.faceProb"),
(lambda x: get_idx_if_non_empty(x.leftDriverData.faceOrientation, 0), "leftDriverData.faceOrientation0"),
(lambda x: get_idx_if_non_empty(x.leftDriverData.leftBlinkProb), "leftDriverData.leftBlinkProb"),
(lambda x: get_idx_if_non_empty(x.leftDriverData.notReadyProb, 0), "leftDriverData.notReadyProb0"),
(lambda x: get_idx_if_non_empty(x.rightDriverData.faceProb), "rightDriverData.faceProb"),
], "driverStateV2")
return [plot(map(v[0], get_event(proposed, event)), \
@@ -18,11 +18,11 @@ from cereal import car
from cereal.services import SERVICE_LIST
from msgq.visionipc import VisionIpcServer, get_endpoint_name as vipc_get_endpoint_name
from opendbc.car.car_helpers import get_car, interfaces
from opendbc.safety import ALTERNATIVE_EXPERIENCE
from openpilot.common.params import Params
from openpilot.common.prefix import OpenpilotPrefix
from openpilot.common.timeout import Timeout
from openpilot.common.realtime import DT_CTRL
from panda.python import ALTERNATIVE_EXPERIENCE
from openpilot.selfdrive.car.card import can_comm_callbacks, convert_to_capnp
from openpilot.system.manager.process_config import managed_processes
from openpilot.selfdrive.test.process_replay.vision_meta import meta_from_camera_state, available_streams
+27 -45
View File
@@ -8,7 +8,6 @@ import shutil
import subprocess
import time
import numpy as np
import zstandard as zstd
from collections import Counter, defaultdict
from pathlib import Path
from tabulate import tabulate
@@ -23,7 +22,6 @@ from openpilot.selfdrive.selfdrived.events import EVENTS, ET
from openpilot.selfdrive.test.helpers import set_params_enabled, release_only
from openpilot.system.hardware import HARDWARE
from openpilot.system.hardware.hw import Paths
from openpilot.system.loggerd.uploader import LOG_COMPRESSION_LEVEL
from openpilot.tools.lib.logreader import LogReader
"""
@@ -36,7 +34,7 @@ CPU usage budget
TEST_DURATION = 25
LOG_OFFSET = 8
MAX_TOTAL_CPU = 275. # total for all 8 cores
MAX_TOTAL_CPU = 280. # total for all 8 cores
PROCS = {
# Baseline CPU usage by process
"selfdrive.controls.controlsd": 16.0,
@@ -44,7 +42,7 @@ PROCS = {
"selfdrive.car.card": 26.0,
"./loggerd": 14.0,
"./encoderd": 17.0,
"./camerad": 14.5,
"./camerad": 10.0,
"selfdrive.controls.plannerd": 9.0,
"./ui": 18.0,
"selfdrive.locationd.paramsd": 9.0,
@@ -101,12 +99,12 @@ TIMINGS = {
"wideRoadCameraState": [1.5, 0.35],
}
LOGS_SIZE_RATE = {
"qlog": 0.0083,
"rlog": 0.135,
"qcamera.ts": 0.03828,
LOGS_SIZE = { # MB per segment
"qlog.zst": 0.5,
"rlog.zst": 8.1,
"qcamera.ts": 2.3,
}
LOGS_SIZE_RATE.update(dict.fromkeys(['ecamera.hevc', 'fcamera.hevc'], 1.2740))
LOGS_SIZE.update(dict.fromkeys(['ecamera.hevc', 'fcamera.hevc', 'dcamera.hevc'], 76.5))
def cputime_total(ct):
@@ -119,15 +117,16 @@ class TestOnroad:
@classmethod
def setup_class(cls):
if "DEBUG" in os.environ:
segs = filter(lambda x: os.path.exists(os.path.join(x, "rlog")), Path(Paths.log_root()).iterdir())
segs = filter(lambda x: os.path.exists(os.path.join(x, "rlog.zst")), Path(Paths.log_root()).iterdir())
segs = sorted(segs, key=lambda x: x.stat().st_mtime)
print(segs[-3])
cls.lr = list(LogReader(os.path.join(segs[-3], "rlog")))
cls.lr = list(LogReader(os.path.join(segs[-3], "rlog.zst")))
return
# setup env
params = Params()
params.remove("CurrentRoute")
params.put_bool("RecordFront", True)
set_params_enabled()
os.environ['REPLAY'] = '1'
os.environ['TESTING_CLOSET'] = '1'
@@ -173,18 +172,15 @@ class TestOnroad:
if proc.wait(60) is None:
proc.kill()
cls.lrs = [list(LogReader(os.path.join(str(s), "rlog"))) for s in cls.segments]
cls.lrs = [list(LogReader(os.path.join(str(s), "rlog.zst"))) for s in cls.segments]
cls.lr = list(LogReader(os.path.join(str(cls.segments[0]), "rlog")))
cls.lr = list(LogReader(os.path.join(str(cls.segments[0]), "rlog.zst")))
cls.log_path = cls.segments[0]
cls.log_sizes = {}
for f in cls.log_path.iterdir():
assert f.is_file()
cls.log_sizes[f] = f.stat().st_size / 1e6
if f.name in ("qlog", "rlog"):
with open(f, 'rb') as ff:
cls.log_sizes[f] = len(zstd.compress(ff.read(), LOG_COMPRESSION_LEVEL)) / 1e6
cls.msgs = defaultdict(list)
for m in cls.lr:
@@ -217,12 +213,14 @@ class TestOnroad:
big_logs = [f for f, n in cnt.most_common(3) if n / sum(cnt.values()) > 30.]
assert len(big_logs) == 0, f"Log spam: {big_logs}"
def test_log_sizes(self):
def test_log_sizes(self, subtests):
# TODO: this isn't super stable between different devices
for f, sz in self.log_sizes.items():
rate = LOGS_SIZE_RATE[f.name]
minn = rate * TEST_DURATION * 0.8
maxx = rate * TEST_DURATION * 1.2
assert minn < sz < maxx
rate = LOGS_SIZE[f.name]/60.
minn = rate * TEST_DURATION * 0.5
maxx = rate * TEST_DURATION * 1.5
with subtests.test(file=f.name):
assert minn < sz < maxx
def test_ui_timings(self):
result = "\n"
@@ -316,37 +314,21 @@ class TestOnroad:
def test_gpu_usage(self):
assert self.gpu_procs == {"weston", "ui", "camerad", "selfdrive.modeld.modeld", "selfdrive.modeld.dmonitoringmodeld"}
def test_camera_processing_time(self):
def test_camera_frame_timings(self, subtests):
result = "\n"
result += "------------------------------------------------\n"
result += "-------------- ImgProc Timing ------------------\n"
result += "------------------------------------------------\n"
ts = []
for s in ['roadCameraState', 'driverCameraState', 'wideCameraState']:
ts.extend(getattr(m, s).processingTime for m in self.msgs[s])
assert min(ts) < 0.025, f"high execution time: {min(ts)}"
result += f"execution time: min {min(ts):.5f}s\n"
result += f"execution time: max {max(ts):.5f}s\n"
result += f"execution time: mean {np.mean(ts):.5f}s\n"
result += "------------------------------------------------\n"
print(result)
@pytest.mark.skip("TODO: enable once timings are fixed")
def test_camera_frame_timings(self):
result = "\n"
result += "------------------------------------------------\n"
result += "----------------- SoF Timing ------------------\n"
result += "----------------- SOF Timing ------------------\n"
result += "------------------------------------------------\n"
for name in ['roadCameraState', 'wideRoadCameraState', 'driverCameraState']:
ts = [getattr(m, m.which()).timestampSof for m in self.lr if name in m.which()]
d_ms = np.diff(ts) / 1e6
d50 = np.abs(d_ms-50)
assert max(d50) < 1.0, f"high sof delta vs 50ms: {max(d50)}"
result += f"{name} sof delta vs 50ms: min {min(d50):.5f}s\n"
result += f"{name} sof delta vs 50ms: max {max(d50):.5f}s\n"
result += f"{name} sof delta vs 50ms: mean {d50.mean():.5f}s\n"
result += "------------------------------------------------\n"
result += f"{name} sof delta vs 50ms: min {min(d50):.2f}ms\n"
result += f"{name} sof delta vs 50ms: max {max(d50):.2f}ms\n"
result += f"{name} sof delta vs 50ms: mean {d50.mean():.2f}ms\n"
with subtests.test(camera=name):
assert max(d50) < 5.0, f"high SOF delta vs 50ms: {max(d50)}"
result += "------------------------------------------------\n"
print(result)
def test_mpc_execution_timings(self):
+1 -4
View File
@@ -1,9 +1,5 @@
#include <QDebug>
#include <QProcess>
#include "selfdrive/ui/qt/offroad/developer_panel.h"
#include "selfdrive/ui/qt/widgets/ssh_keys.h"
#include "common/util.h"
#ifdef SUNNYPILOT
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
@@ -114,6 +110,7 @@ void DeveloperPanel::updateToggles(bool _offroad) {
experimentalLongitudinalToggle->setVisible(false);
hyundaiRadarTracksToggle->setVisible(false);
}
experimentalLongitudinalToggle->refresh();
offroad = _offroad;
}
+1 -1
View File
@@ -20,7 +20,7 @@ private:
ParamControl* experimentalLongitudinalToggle;
ParamControl* hyundaiRadarTracksToggle;
bool is_release;
bool offroad;
bool offroad = false;
private slots:
void updateToggles(bool _offroad);
+14
View File
@@ -42,6 +42,20 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
tr("When enabled, pressing the accelerator pedal will disengage openpilot."),
"../assets/offroad/icon_disengage_on_accelerator.svg",
},
{
"FirehoseMode",
tr("FIREHOSE Mode"),
tr("Enable <b>FIREHOSE Mode</b> to get your driving data in the training set.<br><br>"
"Follow these steps to get your device ready:<br>"
" 1. Bring your device inside and connect to a good USB-C adapter<br>"
" 2. Connect to Wi-Fi<br>"
" 3. Enable this toggle<br>"
" 4. Leave it connected for at least 30 minutes<br>"
"<br>"
"This toggle turns off once you restart your device. Repeat once a week for maximum effectiveness."
""),
"../assets/offroad/icon_warning.png",
},
{
"IsLdwEnabled",
tr("Enable Lane Departure Warnings"),
View File
+8
View File
@@ -1553,6 +1553,14 @@ This may take up to a minute.</source>
<source>Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>FIREHOSE Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable &lt;b&gt;FIREHOSE Mode&lt;/b&gt; to get your driving data in the training set.&lt;br&gt;&lt;br&gt;Follow these steps to get your device ready:&lt;br&gt; 1. Bring your device inside and connect to a good USB-C adapter&lt;br&gt; 2. Connect to Wi-Fi&lt;br&gt; 3. Enable this toggle&lt;br&gt; 4. Leave it connected for at least 30 minutes&lt;br&gt;&lt;br&gt;This toggle turns off once you restart your device. Repeat once a week for maximum effectiveness.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Updater</name>
+8
View File
@@ -1537,6 +1537,14 @@ This may take up to a minute.</source>
<source>Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>FIREHOSE Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable &lt;b&gt;FIREHOSE Mode&lt;/b&gt; to get your driving data in the training set.&lt;br&gt;&lt;br&gt;Follow these steps to get your device ready:&lt;br&gt; 1. Bring your device inside and connect to a good USB-C adapter&lt;br&gt; 2. Connect to Wi-Fi&lt;br&gt; 3. Enable this toggle&lt;br&gt; 4. Leave it connected for at least 30 minutes&lt;br&gt;&lt;br&gt;This toggle turns off once you restart your device. Repeat once a week for maximum effectiveness.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Updater</name>
+8
View File
@@ -1537,6 +1537,14 @@ Esto puede tardar un minuto.</translation>
<source>Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>FIREHOSE Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable &lt;b&gt;FIREHOSE Mode&lt;/b&gt; to get your driving data in the training set.&lt;br&gt;&lt;br&gt;Follow these steps to get your device ready:&lt;br&gt; 1. Bring your device inside and connect to a good USB-C adapter&lt;br&gt; 2. Connect to Wi-Fi&lt;br&gt; 3. Enable this toggle&lt;br&gt; 4. Leave it connected for at least 30 minutes&lt;br&gt;&lt;br&gt;This toggle turns off once you restart your device. Repeat once a week for maximum effectiveness.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Updater</name>
+8
View File
@@ -1537,6 +1537,14 @@ Cela peut prendre jusqu&apos;à une minute.</translation>
<source>Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>FIREHOSE Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable &lt;b&gt;FIREHOSE Mode&lt;/b&gt; to get your driving data in the training set.&lt;br&gt;&lt;br&gt;Follow these steps to get your device ready:&lt;br&gt; 1. Bring your device inside and connect to a good USB-C adapter&lt;br&gt; 2. Connect to Wi-Fi&lt;br&gt; 3. Enable this toggle&lt;br&gt; 4. Leave it connected for at least 30 minutes&lt;br&gt;&lt;br&gt;This toggle turns off once you restart your device. Repeat once a week for maximum effectiveness.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Updater</name>
+8
View File
@@ -1533,6 +1533,14 @@ This may take up to a minute.</source>
<source>Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>FIREHOSE Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable &lt;b&gt;FIREHOSE Mode&lt;/b&gt; to get your driving data in the training set.&lt;br&gt;&lt;br&gt;Follow these steps to get your device ready:&lt;br&gt; 1. Bring your device inside and connect to a good USB-C adapter&lt;br&gt; 2. Connect to Wi-Fi&lt;br&gt; 3. Enable this toggle&lt;br&gt; 4. Leave it connected for at least 30 minutes&lt;br&gt;&lt;br&gt;This toggle turns off once you restart your device. Repeat once a week for maximum effectiveness.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Updater</name>
+8
View File
@@ -1533,6 +1533,14 @@ This may take up to a minute.</source>
<source>Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>FIREHOSE Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable &lt;b&gt;FIREHOSE Mode&lt;/b&gt; to get your driving data in the training set.&lt;br&gt;&lt;br&gt;Follow these steps to get your device ready:&lt;br&gt; 1. Bring your device inside and connect to a good USB-C adapter&lt;br&gt; 2. Connect to Wi-Fi&lt;br&gt; 3. Enable this toggle&lt;br&gt; 4. Leave it connected for at least 30 minutes&lt;br&gt;&lt;br&gt;This toggle turns off once you restart your device. Repeat once a week for maximum effectiveness.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Updater</name>
+8
View File
@@ -1537,6 +1537,14 @@ Isso pode levar até um minuto.</translation>
<source>Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>FIREHOSE Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable &lt;b&gt;FIREHOSE Mode&lt;/b&gt; to get your driving data in the training set.&lt;br&gt;&lt;br&gt;Follow these steps to get your device ready:&lt;br&gt; 1. Bring your device inside and connect to a good USB-C adapter&lt;br&gt; 2. Connect to Wi-Fi&lt;br&gt; 3. Enable this toggle&lt;br&gt; 4. Leave it connected for at least 30 minutes&lt;br&gt;&lt;br&gt;This toggle turns off once you restart your device. Repeat once a week for maximum effectiveness.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Updater</name>
+8
View File
@@ -1533,6 +1533,14 @@ This may take up to a minute.</source>
<source>Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>FIREHOSE Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable &lt;b&gt;FIREHOSE Mode&lt;/b&gt; to get your driving data in the training set.&lt;br&gt;&lt;br&gt;Follow these steps to get your device ready:&lt;br&gt; 1. Bring your device inside and connect to a good USB-C adapter&lt;br&gt; 2. Connect to Wi-Fi&lt;br&gt; 3. Enable this toggle&lt;br&gt; 4. Leave it connected for at least 30 minutes&lt;br&gt;&lt;br&gt;This toggle turns off once you restart your device. Repeat once a week for maximum effectiveness.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Updater</name>
+8
View File
@@ -1531,6 +1531,14 @@ This may take up to a minute.</source>
<source>Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>FIREHOSE Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable &lt;b&gt;FIREHOSE Mode&lt;/b&gt; to get your driving data in the training set.&lt;br&gt;&lt;br&gt;Follow these steps to get your device ready:&lt;br&gt; 1. Bring your device inside and connect to a good USB-C adapter&lt;br&gt; 2. Connect to Wi-Fi&lt;br&gt; 3. Enable this toggle&lt;br&gt; 4. Leave it connected for at least 30 minutes&lt;br&gt;&lt;br&gt;This toggle turns off once you restart your device. Repeat once a week for maximum effectiveness.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Updater</name>
+8
View File
@@ -1533,6 +1533,14 @@ This may take up to a minute.</source>
<source>Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>FIREHOSE Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable &lt;b&gt;FIREHOSE Mode&lt;/b&gt; to get your driving data in the training set.&lt;br&gt;&lt;br&gt;Follow these steps to get your device ready:&lt;br&gt; 1. Bring your device inside and connect to a good USB-C adapter&lt;br&gt; 2. Connect to Wi-Fi&lt;br&gt; 3. Enable this toggle&lt;br&gt; 4. Leave it connected for at least 30 minutes&lt;br&gt;&lt;br&gt;This toggle turns off once you restart your device. Repeat once a week for maximum effectiveness.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Updater</name>
+8
View File
@@ -1533,6 +1533,14 @@ This may take up to a minute.</source>
<source>Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>FIREHOSE Mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable &lt;b&gt;FIREHOSE Mode&lt;/b&gt; to get your driving data in the training set.&lt;br&gt;&lt;br&gt;Follow these steps to get your device ready:&lt;br&gt; 1. Bring your device inside and connect to a good USB-C adapter&lt;br&gt; 2. Connect to Wi-Fi&lt;br&gt; 3. Enable this toggle&lt;br&gt; 4. Leave it connected for at least 30 minutes&lt;br&gt;&lt;br&gt;This toggle turns off once you restart your device. Repeat once a week for maximum effectiveness.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Updater</name>
+3 -3
View File
@@ -24,10 +24,10 @@ THE SOFTWARE.
Last updated: July 29, 2024
"""
from panda import Panda, ALTERNATIVE_EXPERIENCE
from openpilot.common.params import Params
from opendbc.safety import ALTERNATIVE_EXPERIENCE
from opendbc.car.hyundai.values import HyundaiSafetyFlags
from opendbc.sunnypilot.car.hyundai.values import HyundaiFlagsSP
@@ -55,7 +55,7 @@ class MadsParams:
hyundai_cruise_main_toggleable = True
if hyundai_cruise_main_toggleable:
CP_SP.flags |= HyundaiFlagsSP.LONGITUDINAL_MAIN_CRUISE_TOGGLEABLE.value
CP.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_LONG_MAIN_CRUISE_TOGGLEABLE
CP.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.FLAG_HYUNDAI_LONG_MAIN_CRUISE_TOGGLEABLE.value
# MADS is currently not supported in Tesla due to lack of consistent states to engage controls
# TODO-SP: To enable MADS for Tesla, identify consistent signals for MADS toggling
+1 -1
View File
@@ -1 +1 @@
39786068cae1ed8c0dc34ef80c281dfcc67ed18a50e06b90765c49bcfdbf7db4
d21daa542227ecc5972da45df4e26f018ba113c0461f270e367d57e3ad89221a
+18 -14
View File
@@ -15,7 +15,6 @@ import tempfile
import threading
import time
import gzip
import zstandard as zstd
from dataclasses import asdict, dataclass, replace
from datetime import datetime
from functools import partial
@@ -32,11 +31,10 @@ import cereal.messaging as messaging
from cereal import log
from cereal.services import SERVICE_LIST
from openpilot.common.api import Api
from openpilot.common.file_helpers import CallbackReader
from openpilot.common.file_helpers import CallbackReader, get_upload_stream
from openpilot.common.params import Params
from openpilot.common.realtime import set_core_affinity
from openpilot.system.hardware import HARDWARE, PC
from openpilot.system.loggerd.uploader import LOG_COMPRESSION_LEVEL
from openpilot.system.loggerd.xattr_cache import getxattr, setxattr
from openpilot.common.swaglog import cloudlog
from openpilot.system.version import get_build_metadata
@@ -147,6 +145,9 @@ def handle_long_poll(ws: WebSocket, exit_event: threading.Event | None) -> None:
threading.Thread(target=ws_recv, args=(ws, end_event), name='ws_recv'),
threading.Thread(target=ws_send, args=(ws, end_event), name='ws_send'),
threading.Thread(target=upload_handler, args=(end_event,), name='upload_handler'),
threading.Thread(target=upload_handler, args=(end_event,), name='upload_handler2'),
threading.Thread(target=upload_handler, args=(end_event,), name='upload_handler3'),
threading.Thread(target=upload_handler, args=(end_event,), name='upload_handler4'),
threading.Thread(target=log_handler, args=(end_event,), name='log_handler'),
threading.Thread(target=stat_handler, args=(end_event,), name='stat_handler'),
] + [
@@ -293,17 +294,17 @@ def _do_upload(upload_item: UploadItem, callback: Callable = None) -> requests.R
path = strip_zst_extension(path)
compress = True
with open(path, "rb") as f:
content = f.read()
if compress:
cloudlog.event("athena.upload_handler.compress", fn=path, fn_orig=upload_item.path)
content = zstd.compress(content, LOG_COMPRESSION_LEVEL)
with io.BytesIO(content) as data:
return requests.put(upload_item.url,
data=CallbackReader(data, callback, len(content)) if callback else data,
headers={**upload_item.headers, 'Content-Length': str(len(content))},
timeout=30)
stream = None
try:
stream, content_length = get_upload_stream(path, compress)
response = requests.put(upload_item.url,
data=CallbackReader(stream, callback, content_length) if callback else stream,
headers={**upload_item.headers, 'Content-Length': str(content_length)},
timeout=30)
return response
finally:
if stream:
stream.close()
# security: user should be able to request any message from their car
@@ -522,6 +523,9 @@ def getSshAuthorizedKeys() -> str:
def getGithubUsername() -> str:
return Params().get("GithubUsername", encoding='utf8') or ''
@dispatcher.add_method
def getFirehoseMode() -> bool:
return Params().get_bool("FirehoseMode") or False
@dispatcher.add_method
def getSimInfo():
+1 -1
View File
@@ -138,7 +138,7 @@ class TestAthenadMethods:
route = '2021-03-29--13-32-47'
segments = [0, 1, 2, 3, 11]
filenames = ['qlog', 'qcamera.ts', 'rlog', 'fcamera.hevc', 'ecamera.hevc', 'dcamera.hevc']
filenames = ['qlog.zst', 'qcamera.ts', 'rlog.zst', 'fcamera.hevc', 'ecamera.hevc', 'dcamera.hevc']
files = [f'{route}--{s}/{f}' for s in segments for f in filenames]
for file in files:
self._create_file(file)
+1 -1
View File
@@ -1,6 +1,6 @@
Import('env', 'arch', 'messaging', 'common', 'gpucommon', 'visionipc')
libs = ['pthread', common, 'jpeg', 'OpenCL', messaging, visionipc, gpucommon]
libs = ['pthread', common, 'OpenCL', messaging, visionipc, gpucommon]
if arch != "Darwin":
camera_obj = env.Object(['cameras/camera_qcom2.cc', 'cameras/camera_common.cc', 'cameras/spectra.cc',
File diff suppressed because one or more lines are too long
+2 -93
View File
@@ -3,8 +3,6 @@
#include <cassert>
#include <string>
#include <jpeglib.h>
#include "common/clutil.h"
#include "common/swaglog.h"
@@ -64,11 +62,11 @@ void CameraBuf::init(cl_device_id device_id, cl_context context, SpectraCamera *
const SensorInfo *sensor = cam->sensor.get();
is_raw = cam->is_raw;
is_raw = cam->output_type == ISP_RAW_OUTPUT;
frame_metadata = std::make_unique<FrameMetadata[]>(frame_buf_count);
// RAW frames from ISP
if (is_raw) {
if (cam->output_type != ISP_IFE_PROCESSED) {
camera_bufs_raw = std::make_unique<VisionBuf[]>(frame_buf_count);
const int raw_frame_size = (sensor->frame_height + sensor->extra_height) * sensor->frame_stride;
@@ -150,95 +148,6 @@ kj::Array<uint8_t> get_raw_frame_image(const CameraBuf *b) {
return kj::mv(frame_image);
}
static kj::Array<capnp::byte> yuv420_to_jpeg(const CameraBuf *b, int thumbnail_width, int thumbnail_height) {
int downscale = b->cur_yuv_buf->width / thumbnail_width;
assert(downscale * thumbnail_height == b->cur_yuv_buf->height);
int in_stride = b->cur_yuv_buf->stride;
// make the buffer big enough. jpeg_write_raw_data requires 16-pixels aligned height to be used.
std::unique_ptr<uint8_t[]> buf(new uint8_t[(thumbnail_width * ((thumbnail_height + 15) & ~15) * 3) / 2]);
uint8_t *y_plane = buf.get();
uint8_t *u_plane = y_plane + thumbnail_width * thumbnail_height;
uint8_t *v_plane = u_plane + (thumbnail_width * thumbnail_height) / 4;
{
// subsampled conversion from nv12 to yuv
for (int hy = 0; hy < thumbnail_height/2; hy++) {
for (int hx = 0; hx < thumbnail_width/2; hx++) {
int ix = hx * downscale + (downscale-1)/2;
int iy = hy * downscale + (downscale-1)/2;
y_plane[(hy*2 + 0)*thumbnail_width + (hx*2 + 0)] = b->cur_yuv_buf->y[(iy*2 + 0) * in_stride + ix*2 + 0];
y_plane[(hy*2 + 0)*thumbnail_width + (hx*2 + 1)] = b->cur_yuv_buf->y[(iy*2 + 0) * in_stride + ix*2 + 1];
y_plane[(hy*2 + 1)*thumbnail_width + (hx*2 + 0)] = b->cur_yuv_buf->y[(iy*2 + 1) * in_stride + ix*2 + 0];
y_plane[(hy*2 + 1)*thumbnail_width + (hx*2 + 1)] = b->cur_yuv_buf->y[(iy*2 + 1) * in_stride + ix*2 + 1];
u_plane[hy*thumbnail_width/2 + hx] = b->cur_yuv_buf->uv[iy*in_stride + ix*2 + 0];
v_plane[hy*thumbnail_width/2 + hx] = b->cur_yuv_buf->uv[iy*in_stride + ix*2 + 1];
}
}
}
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
uint8_t *thumbnail_buffer = nullptr;
size_t thumbnail_len = 0;
jpeg_mem_dest(&cinfo, &thumbnail_buffer, &thumbnail_len);
cinfo.image_width = thumbnail_width;
cinfo.image_height = thumbnail_height;
cinfo.input_components = 3;
jpeg_set_defaults(&cinfo);
jpeg_set_colorspace(&cinfo, JCS_YCbCr);
// configure sampling factors for yuv420.
cinfo.comp_info[0].h_samp_factor = 2; // Y
cinfo.comp_info[0].v_samp_factor = 2;
cinfo.comp_info[1].h_samp_factor = 1; // U
cinfo.comp_info[1].v_samp_factor = 1;
cinfo.comp_info[2].h_samp_factor = 1; // V
cinfo.comp_info[2].v_samp_factor = 1;
cinfo.raw_data_in = TRUE;
jpeg_set_quality(&cinfo, 50, TRUE);
jpeg_start_compress(&cinfo, TRUE);
JSAMPROW y[16], u[8], v[8];
JSAMPARRAY planes[3]{y, u, v};
for (int line = 0; line < cinfo.image_height; line += 16) {
for (int i = 0; i < 16; ++i) {
y[i] = y_plane + (line + i) * cinfo.image_width;
if (i % 2 == 0) {
int offset = (cinfo.image_width / 2) * ((i + line) / 2);
u[i / 2] = u_plane + offset;
v[i / 2] = v_plane + offset;
}
}
jpeg_write_raw_data(&cinfo, planes, 16);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
kj::Array<capnp::byte> dat = kj::heapArray<capnp::byte>(thumbnail_buffer, thumbnail_len);
free(thumbnail_buffer);
return dat;
}
void publish_thumbnail(PubMaster *pm, const CameraBuf *b) {
auto thumbnail = yuv420_to_jpeg(b, b->out_img_width / 4, b->out_img_height / 4);
if (thumbnail.size() == 0) return;
MessageBuilder msg;
auto thumbnaild = msg.initEvent().initThumbnail();
thumbnaild.setFrameId(b->cur_frame_data.frame_id);
thumbnaild.setTimestampEof(b->cur_frame_data.timestamp_eof);
thumbnaild.setThumbnail(thumbnail);
pm->send("thumbnail", msg);
}
float set_exposure_target(const CameraBuf *b, Rect ae_xywh, int x_skip, int y_skip) {
int lum_med;
uint32_t lum_binning[256] = {0};
-1
View File
@@ -52,5 +52,4 @@ public:
void camerad_thread();
kj::Array<uint8_t> get_raw_frame_image(const CameraBuf *b);
float set_exposure_target(const CameraBuf *b, Rect ae_xywh, int x_skip, int y_skip);
void publish_thumbnail(PubMaster *pm, const CameraBuf *b);
int open_v4l_by_name_and_index(const char name[], int index = 0, int flags = O_RDWR | O_NONBLOCK);
+3 -12
View File
@@ -55,7 +55,7 @@ public:
float fl_pix = 0;
CameraState(SpectraMaster *master, const CameraConfig &config) : camera(master, config, true /*config.stream_type == VISION_STREAM_ROAD*/) {};
CameraState(SpectraMaster *master, const CameraConfig &config) : camera(master, config, config.stream_type == VISION_STREAM_DRIVER ? ISP_BPS_PROCESSED : ISP_IFE_PROCESSED) {};
~CameraState();
void init(VisionIpcServer *v, cl_device_id device_id, cl_context ctx);
void update_exposure_score(float desired_ev, int exp_t, int exp_g_idx, float exp_gain);
@@ -231,9 +231,7 @@ void CameraState::set_camera_exposure(float grey_frac) {
void CameraState::run() {
util::set_thread_name(camera.cc.publish_name);
std::vector<const char*> pubs = {camera.cc.publish_name};
if (camera.cc.stream_type == VISION_STREAM_ROAD) pubs.push_back("thumbnail");
PubMaster pm(pubs);
PubMaster pm(std::vector{camera.cc.publish_name});
for (uint32_t cnt = 0; !do_exit; ++cnt) {
// Acquire the buffer; continue if acquisition fails
@@ -263,17 +261,10 @@ void CameraState::run() {
framed.setImage(get_raw_frame_image(&camera.buf));
}
// Process camera registers and set camera exposure
if (camera.is_raw) {
camera.sensor->processRegisters((uint8_t *)camera.buf.cur_camera_buf->addr, framed);
}
set_camera_exposure(set_exposure_target(&camera.buf, ae_xywh, 2, camera.cc.stream_type != VISION_STREAM_DRIVER ? 2 : 4));
// Send the message
pm.send(camera.cc.publish_name, msg);
if (camera.cc.stream_type == VISION_STREAM_ROAD && cnt % 100 == 3) {
publish_thumbnail(&pm, &camera.buf); // this takes 10ms???
}
}
}
@@ -292,7 +283,7 @@ void camerad_thread() {
// *** per-cam init ***
std::vector<std::unique_ptr<CameraState>> cams;
for (const auto &config : {WIDE_ROAD_CAMERA_CONFIG, DRIVER_CAMERA_CONFIG, ROAD_CAMERA_CONFIG}) {
for (const auto &config : {WIDE_ROAD_CAMERA_CONFIG, ROAD_CAMERA_CONFIG, DRIVER_CAMERA_CONFIG}) {
auto cam = std::make_unique<CameraState>(&m, config);
cam->init(&v, device_id, ctx);
cams.emplace_back(std::move(cam));
@@ -16,6 +16,7 @@ struct CameraConfig {
cereal::FrameData::Builder (cereal::Event::Builder::*init_camera_state)();
bool enabled;
uint32_t phy;
bool vignetting_correction;
};
// NOTE: to be able to disable road and wide road, we still have to configure the sensor over i2c
@@ -28,6 +29,7 @@ const CameraConfig WIDE_ROAD_CAMERA_CONFIG = {
.init_camera_state = &cereal::Event::Builder::initWideRoadCameraState,
.enabled = !getenv("DISABLE_WIDE_ROAD"),
.phy = CAM_ISP_IFE_IN_RES_PHY_0,
.vignetting_correction = false,
};
const CameraConfig ROAD_CAMERA_CONFIG = {
@@ -38,6 +40,7 @@ const CameraConfig ROAD_CAMERA_CONFIG = {
.init_camera_state = &cereal::Event::Builder::initRoadCameraState,
.enabled = !getenv("DISABLE_ROAD"),
.phy = CAM_ISP_IFE_IN_RES_PHY_1,
.vignetting_correction = true,
};
const CameraConfig DRIVER_CAMERA_CONFIG = {
@@ -48,4 +51,5 @@ const CameraConfig DRIVER_CAMERA_CONFIG = {
.init_camera_state = &cereal::Event::Builder::initDriverCameraState,
.enabled = !getenv("DISABLE_DRIVER"),
.phy = CAM_ISP_IFE_IN_RES_PHY_2,
.vignetting_correction = false,
};
+57 -53
View File
@@ -2,13 +2,46 @@
#include "cdm.h"
#include "system/camerad/cameras/tici.h"
#include "system/camerad/cameras/hw.h"
#include "system/camerad/sensors/sensor.h"
int build_update(uint8_t *dst, const SensorInfo *s, std::vector<uint32_t> &patches, int camera_num) {
int build_common_ife_bps(uint8_t *dst, const CameraConfig cam, const SensorInfo *s, std::vector<uint32_t> &patches, bool ife) {
uint8_t *start = dst;
/*
Common between IFE and BPS.
*/
// IFE -> BPS addresses
/*
std::map<uint32_t, uint32_t> addrs = {
{0xf30, 0x3468},
};
*/
// YUV
dst += write_cont(dst, ife ? 0xf30 : 0x3468, {
0x00680208,
0x00000108,
0x00400000,
0x03ff0000,
0x01c01ed8,
0x00001f68,
0x02000000,
0x03ff0000,
0x1fb81e88,
0x000001c0,
0x02000000,
0x03ff0000,
});
return dst - start;
}
int build_update(uint8_t *dst, const CameraConfig cam, const SensorInfo *s, std::vector<uint32_t> &patches) {
uint8_t *start = dst;
// init sequence
dst += write_random(dst, {
0x2c, 0xffffffff,
0x30, 0xffffffff,
@@ -17,6 +50,7 @@ int build_update(uint8_t *dst, const SensorInfo *s, std::vector<uint32_t> &patch
0x3c, 0xffffffff,
});
// demux cfg
dst += write_cont(dst, 0x560, {
0x00000001,
0x04440444,
@@ -35,36 +69,29 @@ int build_update(uint8_t *dst, const SensorInfo *s, std::vector<uint32_t> &patch
0x00000000,
});
// module config/enables (e.g. enable debayer, white balance, etc.)
dst += write_cont(dst, 0x40, {
0x00000c06 | ((uint32_t)(camera_num == 1) << 8),
0x00000c06 | ((uint32_t)(cam.vignetting_correction) << 8),
});
dst += write_cont(dst, 0x48, {
(1 << 3) | (1 << 1),
});
dst += write_cont(dst, 0x4c, {
0x00000019,
});
dst += write_cont(dst, 0xe0c, {
0x00000e00,
});
dst += write_cont(dst, 0xe2c, {
0x00000e00,
});
dst += write_cont(dst, 0x44, {
0x00000000,
});
dst += write_cont(dst, 0xaac, {
dst += write_cont(dst, 0x48, {
(1 << 3) | (1 << 1),
});
dst += write_cont(dst, 0x4c, {
0x00000019,
});
dst += write_cont(dst, 0xf00, {
0x00000000,
});
dst += write_cont(dst, 0xf00, {
0x00000000,
// cropping
dst += write_cont(dst, 0xe0c, {
0x00000e00,
});
dst += write_cont(dst, 0xe2c, {
0x00000e00,
});
// black level scale + offset
@@ -78,11 +105,11 @@ int build_update(uint8_t *dst, const SensorInfo *s, std::vector<uint32_t> &patch
}
int build_initial_config(uint8_t *dst, const SensorInfo *s, std::vector<uint32_t> &patches, int camera_num) {
int build_initial_config(uint8_t *dst, const CameraConfig cam, const SensorInfo *s, std::vector<uint32_t> &patches) {
uint8_t *start = dst;
// start with the every frame config
dst += build_update(dst, s, patches, camera_num);
dst += build_update(dst, cam, s, patches);
uint64_t addr;
@@ -115,15 +142,6 @@ int build_initial_config(uint8_t *dst, const SensorInfo *s, std::vector<uint32_t
// TODO: this is DMI64 in the dump, does that matter?
dst += write_dmi(dst, &addr, s->linearization_lut.size()*sizeof(uint32_t), 0xc24, 9);
patches.push_back(addr - (uint64_t)start);
/* TODO
cdm_dmi_cmd_t 248
.length = 287
.reserved = 33
.cmd = 11
.addr = 0
.DMIAddr = 3108
.DMISel = 9
*/
// vignetting correction
dst += write_cont(dst, 0x6bc, {
@@ -164,23 +182,7 @@ int build_initial_config(uint8_t *dst, const SensorInfo *s, std::vector<uint32_t
dst += write_dmi(dst, &addr, s->gamma_lut_rgb.size()*sizeof(uint32_t), 0xc24, 30); // R
patches.push_back(addr - (uint64_t)start);
// YUV
dst += write_cont(dst, 0xf30, {
0x00680208,
0x00000108,
0x00400000,
0x03ff0000,
0x01c01ed8,
0x00001f68,
0x02000000,
0x03ff0000,
0x1fb81e88,
0x000001c0,
0x02000000,
0x03ff0000,
});
// TODO: remove this
// output size/scaling
dst += write_cont(dst, 0xa3c, {
0x00000003,
((s->frame_width - 1) << 16) | (s->frame_width - 1),
@@ -226,6 +228,8 @@ int build_initial_config(uint8_t *dst, const SensorInfo *s, std::vector<uint32_t
0x00000017,
});
dst += build_common_ife_bps(dst, cam, s, patches, true);
return dst - start;
}
+377 -75
View File
@@ -17,10 +17,9 @@
#include "common/swaglog.h"
#include "system/camerad/cameras/ife.h"
#include "system/camerad/cameras/spectra.h"
#include "system/camerad/cameras/bps_blobs.h"
#include "third_party/linux/include/msm_media_info.h"
// For debugging:
// echo "4294967295" > /sys/module/cam_debug_util/parameters/debug_mdl
// ************** low level camera helpers ****************
@@ -194,11 +193,11 @@ void SpectraMaster::init() {
// looks like there's only one of these
isp_fd = open_v4l_by_name_and_index("cam-isp");
assert(isp_fd >= 0);
LOGD("opened isp");
LOGD("opened isp %d", (int)isp_fd);
icp_fd = open_v4l_by_name_and_index("cam-icp");
assert(icp_fd >= 0);
LOGD("opened icp");
LOGD("opened icp %d", (int)icp_fd);
// query ISP for MMU handles
LOG("-- Query for MMU handles");
@@ -234,14 +233,14 @@ void SpectraMaster::init() {
// *** SpectraCamera ***
SpectraCamera::SpectraCamera(SpectraMaster *master, const CameraConfig &config, bool raw)
SpectraCamera::SpectraCamera(SpectraMaster *master, const CameraConfig &config, SpectraOutputType out)
: m(master),
enabled(config.enabled),
cc(config),
is_raw(raw) {
output_type(out) {
mm.init(m->video0_fd);
ife_buf_depth = is_raw ? 4 : VIPC_BUFFER_COUNT;
ife_buf_depth = (out != ISP_IFE_PROCESSED) ? 4 : VIPC_BUFFER_COUNT;
assert(ife_buf_depth < MAX_IFE_BUFS);
}
@@ -257,11 +256,22 @@ int SpectraCamera::clear_req_queue() {
req_mgr_flush_request.link_hdl = link_handle;
req_mgr_flush_request.flush_type = CAM_REQ_MGR_FLUSH_TYPE_ALL;
int ret = do_cam_control(m->video0_fd, CAM_REQ_MGR_FLUSH_REQ, &req_mgr_flush_request, sizeof(req_mgr_flush_request));
// LOGD("flushed all req: %d", ret);
LOGD("flushed all req: %d", ret);
if (icp_dev_handle) {
struct cam_flush_dev_cmd cmd = {
.session_handle = session_handle,
.dev_handle = icp_dev_handle,
.flush_type = CAM_FLUSH_TYPE_ALL,
};
int err = do_cam_control(m->icp_fd, CAM_FLUSH_REQ, &cmd, sizeof(cmd));
assert(err == 0);
}
for (int i = 0; i < MAX_IFE_BUFS; ++i) {
destroySyncObjectAt(i);
}
return ret;
}
@@ -279,7 +289,7 @@ void SpectraCamera::camera_open(VisionIpcServer *v, cl_device_id device_id, cl_c
uv_height = VENUS_UV_SCANLINES(COLOR_FMT_NV12, sensor->frame_height);
uv_offset = stride*y_height;
yuv_size = uv_offset + stride*uv_height;
if (!is_raw) {
if (output_type != ISP_RAW_OUTPUT) {
uv_offset = ALIGNED_SIZE(uv_offset, 0x1000);
yuv_size = uv_offset + ALIGNED_SIZE(stride*uv_height, 0x1000);
}
@@ -288,7 +298,7 @@ void SpectraCamera::camera_open(VisionIpcServer *v, cl_device_id device_id, cl_c
open = true;
configISP();
//configICP(); // needs the new AGNOS kernel
if (output_type == ISP_BPS_PROCESSED) configICP();
configCSIPHY();
linkDevices();
@@ -300,8 +310,9 @@ void SpectraCamera::camera_open(VisionIpcServer *v, cl_device_id device_id, cl_c
void SpectraCamera::enqueue_req_multi(uint64_t start, int n, bool dp) {
for (uint64_t i = start; i < start + n; ++i) {
request_ids[(i - 1) % ife_buf_depth] = i;
enqueue_buffer((i - 1) % ife_buf_depth, dp);
uint64_t idx = (i - 1) % ife_buf_depth;
request_ids[idx] = i;
enqueue_buffer(idx, dp);
}
}
@@ -454,22 +465,245 @@ int SpectraCamera::sensors_init() {
return ret;
}
void add_patch(struct cam_packet *pkt, int32_t dst_hdl, uint32_t dst_offset, int32_t src_hdl, uint32_t src_offset) {
void *ptr = (char*)&pkt->payload + pkt->patch_offset;
struct cam_patch_desc *p = (struct cam_patch_desc *)((unsigned char*)ptr + sizeof(struct cam_patch_desc)*pkt->num_patches);
p->dst_buf_hdl = dst_hdl;
p->src_buf_hdl = src_hdl;
p->dst_offset = dst_offset;
p->src_offset = src_offset;
pkt->num_patches++;
};
void SpectraCamera::config_bps(int idx, int request_id) {
/*
Handles per-frame BPS config.
* BPS = Bayer Processing Segment
*/
(void)idx;
(void)request_id;
}
void add_patch(void *ptr, int n, int32_t dst_hdl, uint32_t dst_offset, int32_t src_hdl, uint32_t src_offset) {
struct cam_patch_desc *p = (struct cam_patch_desc *)((unsigned char*)ptr + sizeof(struct cam_patch_desc)*n);
p->dst_buf_hdl = dst_hdl;
p->src_buf_hdl = src_hdl;
p->dst_offset = dst_offset;
p->src_offset = src_offset;
};
int size = sizeof(struct cam_packet) + sizeof(struct cam_cmd_buf_desc)*2 + sizeof(struct cam_buf_io_cfg)*2;
size += sizeof(struct cam_patch_desc)*9;
uint32_t cam_packet_handle = 0;
auto pkt = mm.alloc<struct cam_packet>(size, &cam_packet_handle);
pkt->header.op_code = CSLDeviceTypeBPS | CAM_ICP_OPCODE_BPS_UPDATE;
pkt->header.request_id = request_id;
pkt->header.size = size;
typedef struct {
struct {
uint32_t ptr[2];
uint32_t unknown[2];
} frames[9];
uint32_t unknown1;
uint32_t unknown2;
uint32_t unknown3;
uint32_t unknown4;
uint32_t cdm_addr;
uint32_t cdm_size;
uint32_t settings_addr;
uint32_t striping_addr;
uint32_t cdm_addr2;
uint32_t req_id;
uint64_t handle;
} bps_tmp;
typedef struct {
uint32_t a;
uint32_t n;
unsigned base : 32;
unsigned unused : 12;
unsigned length : 20;
uint32_t p;
uint32_t u;
uint32_t h;
uint32_t b;
} cdm_tmp;
// *** cmd buf ***
std::vector<uint32_t> patches;
struct cam_cmd_buf_desc *buf_desc = (struct cam_cmd_buf_desc *)&pkt->payload;
{
pkt->num_cmd_buf = 2;
pkt->kmd_cmd_buf_index = -1;
pkt->kmd_cmd_buf_offset = 0;
buf_desc[0].meta_data = 0;
buf_desc[0].mem_handle = bps_cmd.handle;
buf_desc[0].type = CAM_CMD_BUF_FW;
buf_desc[0].offset = bps_cmd.aligned_size()*idx;
buf_desc[0].length = sizeof(bps_tmp) + sizeof(cdm_tmp);
buf_desc[0].size = buf_desc[0].length;
// rest gets patched in
bps_tmp *fp = (bps_tmp *)((unsigned char *)bps_cmd.ptr + buf_desc[0].offset);
memset(fp, 0, buf_desc[0].length);
fp->handle = (uint64_t)icp_dev_handle;
fp->cdm_size = bps_cdm_striping_bl.size; // this comes from the striping lib create call
fp->req_id = 0; // why always 0?
cdm_tmp *pa = (cdm_tmp *)((unsigned char *)fp + sizeof(bps_tmp));
pa->a = 0;
pa->n = 1;
pa->p = 20; // GENERIC
pa->u = 0;
pa->h = 0;
pa->b = 0;
pa->unused = 0;
pa->base = 0; // this gets patched
int cdm_len = 0;
if (bps_lin_reg.size() == 0) {
for (int i = 0; i < 4; i++) {
bps_lin_reg.push_back(((sensor->linearization_pts[i] & 0xffff) << 0x10) | (sensor->linearization_pts[i] >> 0x10));
}
}
if (bps_ccm_reg.size() == 0) {
for (int i = 0; i < 3; i++) {
bps_ccm_reg.push_back(sensor->color_correct_matrix[i] | (sensor->color_correct_matrix[i+3] << 0x10));
bps_ccm_reg.push_back(sensor->color_correct_matrix[i+6]);
}
}
// white balance
cdm_len += write_cont((unsigned char *)bps_cdm_program_array.ptr + cdm_len, 0x2868, {
0x04000400,
0x00000400,
0x00000000,
0x00000000,
});
// debayer
cdm_len += write_cont((unsigned char *)bps_cdm_program_array.ptr + cdm_len, 0x2878, {
0x00000080,
0x00800066,
});
// linearization, EN=0
cdm_len += write_cont((unsigned char *)bps_cdm_program_array.ptr + cdm_len, 0x1868, bps_lin_reg);
cdm_len += write_cont((unsigned char *)bps_cdm_program_array.ptr + cdm_len, 0x1878, bps_lin_reg);
cdm_len += write_cont((unsigned char *)bps_cdm_program_array.ptr + cdm_len, 0x1888, bps_lin_reg);
cdm_len += write_cont((unsigned char *)bps_cdm_program_array.ptr + cdm_len, 0x1898, bps_lin_reg);
/*
uint8_t *start = (unsigned char *)bps_cdm_program_array.ptr + cdm_len;
uint64_t addr;
cdm_len += write_dmi((unsigned char *)bps_cdm_program_array.ptr + cdm_len, &addr, sensor->linearization_lut.size()*sizeof(uint32_t), 0x1808, 1);
patches.push_back(addr - (uint64_t)start);
*/
// color correction
cdm_len += write_cont((unsigned char *)bps_cdm_program_array.ptr + cdm_len, 0x2e68, bps_ccm_reg);
cdm_len += build_common_ife_bps((unsigned char *)bps_cdm_program_array.ptr + cdm_len, cc, sensor.get(), patches, false);
pa->length = cdm_len - 1;
// *** second command ***
// parsed by cam_icp_packet_generic_blob_handler
struct isp_packet {
uint32_t header;
struct cam_icp_clk_bw_request clk;
} __attribute__((packed)) tmp;
tmp.header = CAM_ICP_CMD_GENERIC_BLOB_CLK;
tmp.header |= (sizeof(cam_icp_clk_bw_request)) << 8;
tmp.clk.budget_ns = 0x1fca058;
tmp.clk.frame_cycles = 2329024; // comes from the striping lib
tmp.clk.rt_flag = 0x0;
tmp.clk.uncompressed_bw = 0x38512180;
tmp.clk.compressed_bw = 0x38512180;
buf_desc[1].size = sizeof(tmp);
buf_desc[1].offset = 0;
buf_desc[1].length = buf_desc[1].size - buf_desc[1].offset;
buf_desc[1].type = CAM_CMD_BUF_GENERIC;
buf_desc[1].meta_data = CAM_ICP_CMD_META_GENERIC_BLOB;
auto buf2 = mm.alloc<uint32_t>(buf_desc[1].size, (uint32_t*)&buf_desc[1].mem_handle);
memcpy(buf2.get(), &tmp, sizeof(tmp));
}
// *** io config ***
pkt->num_io_configs = 2;
pkt->io_configs_offset = sizeof(struct cam_cmd_buf_desc)*pkt->num_cmd_buf;
struct cam_buf_io_cfg *io_cfg = (struct cam_buf_io_cfg *)((char*)&pkt->payload + pkt->io_configs_offset);
{
// input frame
io_cfg[0].offsets[0] = 0;
io_cfg[0].mem_handle[0] = buf_handle_raw[idx];
io_cfg[0].planes[0] = (struct cam_plane_cfg){
.width = sensor->frame_width,
.height = sensor->frame_height + sensor->extra_height,
.plane_stride = sensor->frame_stride,
.slice_height = sensor->frame_height + sensor->extra_height,
};
io_cfg[0].format = sensor->mipi_format;
io_cfg[0].color_space = CAM_COLOR_SPACE_BASE;
io_cfg[0].color_pattern = 0x5;
io_cfg[0].bpp = (sensor->mipi_format == CAM_FORMAT_MIPI_RAW_10 ? 0xa : 0xc);
io_cfg[0].resource_type = CAM_ICP_BPS_INPUT_IMAGE;
io_cfg[0].fence = sync_objs_ife[idx];
io_cfg[0].direction = CAM_BUF_INPUT;
io_cfg[0].subsample_pattern = 0x1;
io_cfg[0].framedrop_pattern = 0x1;
// output frame
io_cfg[1].mem_handle[0] = buf_handle_yuv[idx];
io_cfg[1].mem_handle[1] = buf_handle_yuv[idx];
io_cfg[1].planes[0] = (struct cam_plane_cfg){
.width = sensor->frame_width,
.height = sensor->frame_height,
.plane_stride = stride,
.slice_height = y_height,
};
io_cfg[1].planes[1] = (struct cam_plane_cfg){
.width = sensor->frame_width,
.height = sensor->frame_height/2,
.plane_stride = stride,
.slice_height = uv_height,
};
io_cfg[1].offsets[1] = ALIGNED_SIZE(io_cfg[1].planes[0].plane_stride*io_cfg[1].planes[0].slice_height, 0x1000);
assert(io_cfg[1].offsets[1] == uv_offset);
io_cfg[1].format = CAM_FORMAT_NV12; // TODO: why is this 21 in the dump? should be 12
io_cfg[1].color_space = CAM_COLOR_SPACE_BT601_FULL;
io_cfg[1].resource_type = CAM_ICP_BPS_OUTPUT_IMAGE_FULL;
io_cfg[1].fence = sync_objs_bps[idx];
io_cfg[1].direction = CAM_BUF_OUTPUT;
io_cfg[1].subsample_pattern = 0x1;
io_cfg[1].framedrop_pattern = 0x1;
}
// *** patches ***
{
assert(patches.size() == 0 | patches.size() == 1);
pkt->patch_offset = sizeof(struct cam_cmd_buf_desc)*pkt->num_cmd_buf + sizeof(struct cam_buf_io_cfg)*pkt->num_io_configs;
if (patches.size() > 0) {
add_patch(pkt.get(), bps_cmd.handle, patches[0], bps_linearization_lut.handle, 0);
}
// input frame
add_patch(pkt.get(), bps_cmd.handle, buf_desc[0].offset + offsetof(bps_tmp, frames[0].ptr[0]), buf_handle_raw[idx], 0);
// output frame
add_patch(pkt.get(), bps_cmd.handle, buf_desc[0].offset + offsetof(bps_tmp, frames[1].ptr[0]), buf_handle_yuv[idx], 0);
add_patch(pkt.get(), bps_cmd.handle, buf_desc[0].offset + offsetof(bps_tmp, frames[1].ptr[1]), buf_handle_yuv[idx], io_cfg[1].offsets[1]);
// rest of buffers
add_patch(pkt.get(), bps_cmd.handle, buf_desc[0].offset + offsetof(bps_tmp, settings_addr), bps_iq.handle, 0);
add_patch(pkt.get(), bps_cmd.handle, buf_desc[0].offset + offsetof(bps_tmp, cdm_addr2), bps_cmd.handle, sizeof(bps_tmp));
add_patch(pkt.get(), bps_cmd.handle, buf_desc[0].offset + 0xc8, bps_cdm_program_array.handle, 0);
add_patch(pkt.get(), bps_cmd.handle, buf_desc[0].offset + offsetof(bps_tmp, striping_addr), bps_striping.handle, 0);
add_patch(pkt.get(), bps_cmd.handle, buf_desc[0].offset + offsetof(bps_tmp, cdm_addr), bps_cdm_striping_bl.handle, 0);
}
int ret = device_config(m->icp_fd, session_handle, icp_dev_handle, cam_packet_handle);
assert(ret == 0);
}
void SpectraCamera::config_ife(int idx, int request_id, bool init) {
/*
@@ -509,11 +743,12 @@ void SpectraCamera::config_ife(int idx, int request_id, bool init) {
buf_desc[0].offset = ife_cmd.aligned_size()*idx;
// stream of IFE register writes
bool is_raw = output_type != ISP_IFE_PROCESSED;
if (!is_raw) {
if (init) {
buf_desc[0].length = build_initial_config((unsigned char*)ife_cmd.ptr + buf_desc[0].offset, sensor.get(), patches, cc.camera_num);
buf_desc[0].length = build_initial_config((unsigned char*)ife_cmd.ptr + buf_desc[0].offset, cc, sensor.get(), patches);
} else {
buf_desc[0].length = build_update((unsigned char*)ife_cmd.ptr + buf_desc[0].offset, sensor.get(), patches, cc.camera_num);
buf_desc[0].length = build_update((unsigned char*)ife_cmd.ptr + buf_desc[0].offset, cc, sensor.get(), patches);
}
}
@@ -597,8 +832,7 @@ void SpectraCamera::config_ife(int idx, int request_id, bool init) {
pkt->io_configs_offset = sizeof(struct cam_cmd_buf_desc)*pkt->num_cmd_buf;
struct cam_buf_io_cfg *io_cfg = (struct cam_buf_io_cfg *)((char*)&pkt->payload + pkt->io_configs_offset);
if (is_raw) {
if (output_type != ISP_IFE_PROCESSED) {
io_cfg[0].mem_handle[0] = buf_handle_raw[idx];
io_cfg[0].planes[0] = (struct cam_plane_cfg){
.width = sensor->frame_width,
@@ -611,7 +845,7 @@ void SpectraCamera::config_ife(int idx, int request_id, bool init) {
io_cfg[0].color_pattern = 0x5;
io_cfg[0].bpp = (sensor->mipi_format == CAM_FORMAT_MIPI_RAW_10 ? 0xa : 0xc);
io_cfg[0].resource_type = CAM_ISP_IFE_OUT_RES_RDI_0;
io_cfg[0].fence = sync_objs[idx];
io_cfg[0].fence = sync_objs_ife[idx];
io_cfg[0].direction = CAM_BUF_OUTPUT;
io_cfg[0].subsample_pattern = 0x1;
io_cfg[0].framedrop_pattern = 0x1;
@@ -636,7 +870,7 @@ void SpectraCamera::config_ife(int idx, int request_id, bool init) {
io_cfg[0].color_pattern = 0x0;
io_cfg[0].bpp = 0;
io_cfg[0].resource_type = CAM_ISP_IFE_OUT_RES_FULL;
io_cfg[0].fence = sync_objs[idx];
io_cfg[0].fence = sync_objs_ife[idx];
io_cfg[0].direction = CAM_BUF_OUTPUT;
io_cfg[0].subsample_pattern = 0x1;
io_cfg[0].framedrop_pattern = 0x1;
@@ -649,21 +883,18 @@ void SpectraCamera::config_ife(int idx, int request_id, bool init) {
// order here corresponds to the one in build_initial_config
assert(patches.size() == 6 || patches.size() == 0);
pkt->num_patches = patches.size();
pkt->patch_offset = sizeof(struct cam_cmd_buf_desc)*pkt->num_cmd_buf + sizeof(struct cam_buf_io_cfg)*pkt->num_io_configs;
if (pkt->num_patches > 0) {
void *p = (char*)&pkt->payload + pkt->patch_offset;
if (patches.size() > 0) {
// linearization LUT
add_patch(p, 0, ife_cmd.handle, patches[0], ife_linearization_lut.handle, 0);
add_patch(pkt.get(), ife_cmd.handle, patches[0], ife_linearization_lut.handle, 0);
// vignetting correction LUTs
add_patch(p, 1, ife_cmd.handle, patches[1], ife_vignetting_lut.handle, 0);
add_patch(p, 2, ife_cmd.handle, patches[2], ife_vignetting_lut.handle, ife_vignetting_lut.size);
add_patch(pkt.get(), ife_cmd.handle, patches[1], ife_vignetting_lut.handle, 0);
add_patch(pkt.get(), ife_cmd.handle, patches[2], ife_vignetting_lut.handle, ife_vignetting_lut.size);
// gamma LUTs
for (int i = 0; i < 3; i++) {
add_patch(p, i+3, ife_cmd.handle, patches[i+3], ife_gamma_lut.handle, ife_gamma_lut.size*i);
add_patch(pkt.get(), ife_cmd.handle, patches[i+3], ife_gamma_lut.handle, ife_gamma_lut.size*i);
}
}
}
@@ -676,23 +907,46 @@ void SpectraCamera::enqueue_buffer(int i, bool dp) {
int ret;
uint64_t request_id = request_ids[i];
if (sync_objs[i]) {
// SOF has come in, wait until readout is complete
// Before queuing up a new frame, wait for the
// previous one in this slot (index) to come in.
if (sync_objs_ife[i]) {
// TODO: write a test to stress test w/ a low timeout and check camera frame ids match
struct cam_sync_wait sync_wait = {0};
sync_wait.sync_obj = sync_objs[i];
// *** Wait for IFE ***
// in RAW_OUTPUT mode, this is just the frame readout from the sensor
// in IFE_PROCESSED mode, this is both frame readout and image processing (~1ms)
sync_wait.sync_obj = sync_objs_ife[i];
sync_wait.timeout_ms = 100;
ret = do_sync_control(m->cam_sync_fd, CAM_SYNC_WAIT, &sync_wait, sizeof(sync_wait));
if (ret != 0) {
// TODO: handle frame drop cleanly
// when this happens, it messes up future frames
LOGE("failed to wait for sync: %d %d", ret, sync_wait.sync_obj);
LOGE("failed to wait for IFE sync: %d %d", ret, sync_wait.sync_obj);
}
buf.frame_metadata[i].timestamp_end_of_isp = (uint64_t)nanos_since_boot();
// *** Wait for BPS ***
if (ret == 0 && sync_objs_bps[i]) {
sync_wait.sync_obj = sync_objs_bps[i];
sync_wait.timeout_ms = 50; // typically 7ms
ret = do_sync_control(m->cam_sync_fd, CAM_SYNC_WAIT, &sync_wait, sizeof(sync_wait));
if (ret != 0) {
LOGE("failed to wait for BPS sync: %d %d", ret, sync_wait.sync_obj);
}
}
// in IFE_PROCESSED mode, we can't know the true EOF, so recover it with sensor readout time
buf.frame_metadata[i].timestamp_eof = buf.frame_metadata[i].timestamp_sof + sensor->readout_time_ns;
if (dp) {
buf.frame_metadata[i].timestamp_end_of_isp = (uint64_t)nanos_since_boot();
// all good, hand off frame
if (dp && ret == 0) {
buf.queue(i);
}
if (ret != 0) {
clear_req_queue();
}
destroySyncObjectAt(i);
}
@@ -703,14 +957,14 @@ void SpectraCamera::enqueue_buffer(int i, bool dp) {
if (ret != 0) {
LOGE("failed to create fence: %d %d", ret, sync_create.sync_obj);
}
sync_objs[i] = sync_create.sync_obj;
sync_objs_ife[i] = sync_create.sync_obj;
if (icp_dev_handle > 0) {
ret = do_cam_control(m->cam_sync_fd, CAM_SYNC_CREATE, &sync_create, sizeof(sync_create));
if (ret != 0) {
LOGE("failed to create fence: %d %d", ret, sync_create.sync_obj);
}
sync_objs_bps_out[i] = sync_create.sync_obj;
sync_objs_bps[i] = sync_create.sync_obj;
}
// schedule request with camera request manager
@@ -728,7 +982,7 @@ void SpectraCamera::enqueue_buffer(int i, bool dp) {
// submit request to IFE and BPS
config_ife(i, request_id);
config_bps(i, request_id);
if (output_type == ISP_BPS_PROCESSED) config_bps(i, request_id);
}
void SpectraCamera::destroySyncObjectAt(int index) {
@@ -744,14 +998,14 @@ void SpectraCamera::destroySyncObjectAt(int index) {
sync_obj = 0; // Reset the sync object to 0
};
destroy_sync_obj(m->cam_sync_fd, sync_objs[index]);
destroy_sync_obj(m->cam_sync_fd, sync_objs_bps_out[index]);
destroy_sync_obj(m->cam_sync_fd, sync_objs_ife[index]);
destroy_sync_obj(m->cam_sync_fd, sync_objs_bps[index]);
}
void SpectraCamera::camera_map_bufs() {
int ret;
for (int i = 0; i < ife_buf_depth; i++) {
// configure ISP to put the image in place
// map our VisionIPC bufs into ISP memory
struct cam_mem_mgr_map_cmd mem_mgr_map_cmd = {0};
mem_mgr_map_cmd.flags = CAM_MEM_FLAG_HW_READ_WRITE;
mem_mgr_map_cmd.mmu_hdls[0] = m->device_iommu;
@@ -761,14 +1015,16 @@ void SpectraCamera::camera_map_bufs() {
mem_mgr_map_cmd.mmu_hdls[1] = m->icp_device_iommu;
}
if (is_raw) {
if (output_type != ISP_IFE_PROCESSED) {
// RAW bayer images
mem_mgr_map_cmd.fd = buf.camera_bufs_raw[i].fd;
ret = do_cam_control(m->video0_fd, CAM_REQ_MGR_MAP_BUF, &mem_mgr_map_cmd, sizeof(mem_mgr_map_cmd));
assert(ret == 0);
LOGD("map buf req: (fd: %d) 0x%x %d", buf.camera_bufs_raw[i].fd, mem_mgr_map_cmd.out.buf_handle, ret);
buf_handle_raw[i] = mem_mgr_map_cmd.out.buf_handle;
} else {
}
if (output_type != ISP_RAW_OUTPUT) {
// final processed images
VisionBuf *vb = buf.vipc_server->get_buffer(buf.stream_type, i);
mem_mgr_map_cmd.fd = vb->fd;
@@ -865,7 +1121,7 @@ void SpectraCamera::configISP() {
},
};
if (is_raw) {
if (output_type != ISP_IFE_PROCESSED) {
in_port_info.line_start = 0;
in_port_info.line_stop = sensor->frame_height + sensor->extra_height - 1;
in_port_info.height = sensor->frame_height + sensor->extra_height;
@@ -890,7 +1146,7 @@ void SpectraCamera::configISP() {
ife_cmd.init(m, 67984, 0x20,
CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE,
m->device_iommu, m->cdm_iommu, ife_buf_depth);
if (!is_raw) {
if (output_type == ISP_IFE_PROCESSED) {
assert(sensor->gamma_lut_rgb.size() == 64);
ife_gamma_lut.init(m, sensor->gamma_lut_rgb.size()*sizeof(uint32_t), 0x20,
CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE,
@@ -920,11 +1176,19 @@ void SpectraCamera::configICP() {
Configures both the ICP and BPS.
*/
int cfg_handle;
uint32_t cfg_size = sizeof(bps_cfg[0]) / sizeof(bps_cfg[0][0]);
void *cfg = alloc_w_mmu_hdl(m->video0_fd, cfg_size, (uint32_t*)&cfg_handle, 0x1,
CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_HW_SHARED_ACCESS,
m->icp_device_iommu);
memcpy(cfg, bps_cfg[sensor->num()], cfg_size);
struct cam_icp_acquire_dev_info icp_info = {
.scratch_mem_size = 0x0,
.dev_type = 0x1, // BPS
.io_config_cmd_size = 0,
.io_config_cmd_handle = 0,
.dev_type = CAM_ICP_RES_TYPE_BPS,
.io_config_cmd_size = cfg_size,
.io_config_cmd_handle = cfg_handle,
.secure_mode = 0,
.num_out_res = 1,
.in_res = (struct cam_icp_res_info){
@@ -945,26 +1209,45 @@ void SpectraCamera::configICP() {
icp_dev_handle = *h;
LOGD("acquire icp dev");
// BPS CMD buffer
unsigned char striping_out[] = "\x00";
bps_cmd.init(m, ife_buf_depth*ALIGNED_SIZE(464, 0x20), 0x20,
release(m->video0_fd, cfg_handle);
// BPS has a lot of buffers to init
bps_cmd.init(m, 464, 0x20,
CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE | CAM_MEM_FLAG_HW_SHARED_ACCESS,
m->icp_device_iommu);
m->icp_device_iommu, 0, ife_buf_depth);
bps_iq.init(m, 560, 0x20,
// BPSIQSettings struct
uint32_t settings_size = sizeof(bps_settings[0]) / sizeof(bps_settings[0][0]);
bps_iq.init(m, settings_size, 0x20,
CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE | CAM_MEM_FLAG_HW_SHARED_ACCESS,
m->icp_device_iommu);
bps_cdm_program_array.init(m, 0x40, 0x20,
CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE | CAM_MEM_FLAG_HW_SHARED_ACCESS,
m->icp_device_iommu);
bps_striping.init(m, sizeof(striping_out), 0x20,
CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE | CAM_MEM_FLAG_HW_SHARED_ACCESS,
m->icp_device_iommu);
memcpy(bps_striping.ptr, striping_out, sizeof(striping_out));
memcpy(bps_iq.ptr, bps_settings[sensor->num()], settings_size);
bps_cdm_striping_bl.init(m, 65216, 0x20,
// for cdm register writes, just make it bigger than you need
bps_cdm_program_array.init(m, 0x1000, 0x20,
CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE | CAM_MEM_FLAG_HW_SHARED_ACCESS,
m->icp_device_iommu);
// striping lib output
uint32_t striping_size = sizeof(bps_striping_output[0]) / sizeof(bps_striping_output[0][0]);
bps_striping.init(m, striping_size, 0x20,
CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE | CAM_MEM_FLAG_HW_SHARED_ACCESS,
m->icp_device_iommu);
memcpy(bps_striping.ptr, bps_striping_output[sensor->num()], striping_size);
// used internally by the BPS, we just allocate it.
// size comes from the BPSStripingLib
bps_cdm_striping_bl.init(m, 0xa100, 0x20,
CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE | CAM_MEM_FLAG_HW_SHARED_ACCESS,
m->icp_device_iommu);
// LUTs
/*
bps_linearization_lut.init(m, sensor->linearization_lut.size()*sizeof(uint32_t), 0x20,
CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE | CAM_MEM_FLAG_HW_SHARED_ACCESS,
m->icp_device_iommu);
memcpy(bps_linearization_lut.ptr, sensor->linearization_lut.data(), bps_linearization_lut.size);
*/
}
void SpectraCamera::configCSIPHY() {
@@ -1015,6 +1298,7 @@ void SpectraCamera::linkDevices() {
req_mgr_link_info.dev_hdls[0] = isp_dev_handle;
req_mgr_link_info.dev_hdls[1] = sensor_dev_handle;
int ret = do_cam_control(m->video0_fd, CAM_REQ_MGR_LINK, &req_mgr_link_info, sizeof(req_mgr_link_info));
assert(ret == 0);
link_handle = req_mgr_link_info.link_hdl;
LOGD("link: %d session: 0x%X isp: 0x%X sensors: 0x%X link: 0x%X", ret, session_handle, isp_dev_handle, sensor_dev_handle, link_handle);
@@ -1028,9 +1312,15 @@ void SpectraCamera::linkDevices() {
ret = device_control(csiphy_fd, CAM_START_DEV, session_handle, csiphy_dev_handle);
LOGD("start csiphy: %d", ret);
assert(ret == 0);
ret = device_control(m->isp_fd, CAM_START_DEV, session_handle, isp_dev_handle);
LOGD("start isp: %d", ret);
assert(ret == 0);
if (output_type == ISP_BPS_PROCESSED) {
ret = device_control(m->icp_fd, CAM_START_DEV, session_handle, icp_dev_handle);
LOGD("start icp: %d", ret);
assert(ret == 0);
}
}
void SpectraCamera::camera_close() {
@@ -1041,8 +1331,13 @@ void SpectraCamera::camera_close() {
// LOGD("stop sensor: %d", ret);
int ret = device_control(m->isp_fd, CAM_STOP_DEV, session_handle, isp_dev_handle);
LOGD("stop isp: %d", ret);
if (output_type == ISP_BPS_PROCESSED) {
ret = device_control(m->icp_fd, CAM_STOP_DEV, session_handle, icp_dev_handle);
LOGD("stop icp: %d", ret);
}
ret = device_control(csiphy_fd, CAM_STOP_DEV, session_handle, csiphy_dev_handle);
LOGD("stop csiphy: %d", ret);
// link control stop
LOG("-- Stop link control");
struct cam_req_mgr_link_control req_mgr_link_control = {0};
@@ -1063,17 +1358,22 @@ void SpectraCamera::camera_close() {
// release devices
LOGD("-- Release devices");
if (icp_dev_handle > 0) {
ret = device_control(m->isp_fd, CAM_RELEASE_DEV, session_handle, isp_dev_handle);
LOGD("release isp: %d", ret);
if (output_type == ISP_BPS_PROCESSED) {
ret = device_control(m->icp_fd, CAM_RELEASE_DEV, session_handle, icp_dev_handle);
LOGD("release icp: %d", ret);
}
ret = device_control(m->isp_fd, CAM_RELEASE_DEV, session_handle, isp_dev_handle);
LOGD("release isp: %d", ret);
ret = device_control(csiphy_fd, CAM_RELEASE_DEV, session_handle, csiphy_dev_handle);
LOGD("release csiphy: %d", ret);
for (int i = 0; i < ife_buf_depth; i++) {
release(m->video0_fd, is_raw ? buf_handle_raw[i] : buf_handle_yuv[i]);
if (buf_handle_raw[i]) {
release(m->video0_fd, buf_handle_raw[i]);
}
if (buf_handle_yuv[i]) {
release(m->video0_fd, buf_handle_yuv[i]);
}
}
LOGD("released buffers");
}
@@ -1095,7 +1395,9 @@ void SpectraCamera::handle_camera_event(const cam_req_mgr_message *event_data) {
uint64_t real_id = event_data->u.frame_msg.request_id;
if (real_id != 0) { // next ready
if (real_id == 1) {idx_offset = main_id;}
if (real_id == 1) {
idx_offset = main_id;
}
int buf_idx = (real_id - 1) % ife_buf_depth;
// check for skipped frames
+14 -5
View File
@@ -9,7 +9,7 @@
#include "media/cam_req_mgr.h"
#include "common/util.h"
#include "system/camerad/cameras/tici.h"
#include "system/camerad/cameras/hw.h"
#include "system/camerad/cameras/camera_common.h"
#include "system/camerad/sensors/sensor.h"
@@ -29,6 +29,12 @@ const int MIPI_SETTLE_CNT = 33; // Calculated by camera_freqs.py
#define OpcodesIFEInitialConfig 0x0
#define OpcodesIFEUpdate 0x1
typedef enum {
ISP_RAW_OUTPUT, // raw frame from sensor
ISP_IFE_PROCESSED, // fully processed image through the IFE
ISP_BPS_PROCESSED, // fully processed image through the BPS
} SpectraOutputType;
std::optional<int32_t> device_acquire(int fd, int32_t session_handle, void *data, uint32_t num_resources=1);
int device_config(int fd, int32_t session_handle, int32_t dev_handle, uint64_t packet_handle);
int device_control(int fd, int op_code, int session_handle, int dev_handle);
@@ -103,7 +109,7 @@ public:
class SpectraCamera {
public:
SpectraCamera(SpectraMaster *master, const CameraConfig &config, bool raw);
SpectraCamera(SpectraMaster *master, const CameraConfig &config, SpectraOutputType out);
~SpectraCamera();
void camera_open(VisionIpcServer *v, cl_device_id device_id, cl_context ctx);
@@ -166,18 +172,21 @@ public:
SpectraBuf bps_cdm_striping_bl;
SpectraBuf bps_iq;
SpectraBuf bps_striping;
SpectraBuf bps_linearization_lut;
std::vector<uint32_t> bps_lin_reg;
std::vector<uint32_t> bps_ccm_reg;
int buf_handle_yuv[MAX_IFE_BUFS] = {};
int buf_handle_raw[MAX_IFE_BUFS] = {};
int sync_objs[MAX_IFE_BUFS] = {};
int sync_objs_bps_out[MAX_IFE_BUFS] = {};
int sync_objs_ife[MAX_IFE_BUFS] = {};
int sync_objs_bps[MAX_IFE_BUFS] = {};
uint64_t request_ids[MAX_IFE_BUFS] = {};
uint64_t request_id_last = 0;
uint64_t frame_id_last = 0;
uint64_t idx_offset = 0;
bool skipped = true;
bool is_raw;
SpectraOutputType output_type;
CameraBuf buf;
MemoryManager mm;
-86
View File
@@ -1,7 +1,6 @@
#include <cassert>
#include <cmath>
#include "common/swaglog.h"
#include "system/camerad/sensors/sensor.h"
namespace {
@@ -16,64 +15,6 @@ const float sensor_analog_gains_AR0231[] = {
5.0 / 4.0, 6.0 / 4.0, 6.0 / 3.0, 7.0 / 3.0, // 8, 9, 10, 11
7.0 / 2.0, 8.0 / 2.0, 8.0 / 1.0}; // 12, 13, 14, 15 = bypass
std::map<uint16_t, std::pair<int, int>> ar0231_build_register_lut(const AR0231 *s, uint8_t *data) {
// This function builds a lookup table from register address, to a pair of indices in the
// buffer where to read this address. The buffer contains padding bytes,
// as well as markers to indicate the type of the next byte.
//
// 0xAA is used to indicate the MSB of the address, 0xA5 for the LSB of the address.
// Every byte of data (MSB and LSB) is preceded by 0x5A. Specifying an address is optional
// for contiguous ranges. See page 27-29 of the AR0231 Developer guide for more information.
int max_i[] = {1828 / 2 * 3, 1500 / 2 * 3};
auto get_next_idx = [](int cur_idx) {
return (cur_idx % 3 == 1) ? cur_idx + 2 : cur_idx + 1; // Every third byte is padding
};
std::map<uint16_t, std::pair<int, int>> registers;
for (int register_row = 0; register_row < 2; register_row++) {
uint8_t *registers_raw = data + s->frame_stride * register_row;
assert(registers_raw[0] == 0x0a); // Start of line
int value_tag_count = 0;
int first_val_idx = 0;
uint16_t cur_addr = 0;
for (int i = 1; i <= max_i[register_row]; i = get_next_idx(get_next_idx(i))) {
int val_idx = get_next_idx(i);
uint8_t tag = registers_raw[i];
uint16_t val = registers_raw[val_idx];
if (tag == 0xAA) { // Register MSB tag
cur_addr = val << 8;
} else if (tag == 0xA5) { // Register LSB tag
cur_addr |= val;
cur_addr -= 2; // Next value tag will increment address again
} else if (tag == 0x5A) { // Value tag
// First tag
if (value_tag_count % 2 == 0) {
cur_addr += 2;
first_val_idx = val_idx;
} else {
registers[cur_addr] = std::make_pair(first_val_idx + s->frame_stride * register_row, val_idx + s->frame_stride * register_row);
}
value_tag_count++;
}
}
}
return registers;
}
float ar0231_parse_temp_sensor(uint16_t calib1, uint16_t calib2, uint16_t data_reg) {
// See AR0231 Developer Guide - page 36
float slope = (125.0 - 55.0) / ((float)calib1 - (float)calib2);
float t0 = 55.0 - slope * (float)calib2;
return t0 + slope * (float)data_reg;
}
} // namespace
AR0231::AR0231() {
@@ -169,33 +110,6 @@ AR0231::AR0231() {
};
}
void AR0231::processRegisters(uint8_t *cur_buf, cereal::FrameData::Builder &framed) const {
const uint8_t expected_preamble[] = {0x0a, 0xaa, 0x55, 0x20, 0xa5, 0x55};
uint8_t *data = cur_buf + registers_offset;
if (memcmp(data, expected_preamble, std::size(expected_preamble)) != 0) {
LOGE("unexpected register data found");
return;
}
if (ar0231_register_lut.empty()) {
ar0231_register_lut = ar0231_build_register_lut(this, data);
}
std::map<uint16_t, uint16_t> registers;
for (uint16_t addr : {0x2000, 0x2002, 0x20b0, 0x20b2, 0x30c6, 0x30c8, 0x30ca, 0x30cc}) {
auto offset = ar0231_register_lut[addr];
registers[addr] = ((uint16_t)data[offset.first] << 8) | data[offset.second];
}
uint32_t frame_id = ((uint32_t)registers[0x2000] << 16) | registers[0x2002];
framed.setFrameIdSensor(frame_id);
float temp_0 = ar0231_parse_temp_sensor(registers[0x30c6], registers[0x30c8], registers[0x20b0]);
float temp_1 = ar0231_parse_temp_sensor(registers[0x30ca], registers[0x30cc], registers[0x20b2]);
framed.setTemperaturesC({temp_0, temp_1});
}
std::vector<i2c_random_wr_payload> AR0231::getExposureRegisters(int exposure_time, int new_exp_g, bool dc_gain_enabled) const {
uint16_t analog_gain_reg = 0xFF00 | (new_exp_g << 4) | new_exp_g;
return {
+4 -2
View File
@@ -22,7 +22,6 @@ public:
virtual std::vector<i2c_random_wr_payload> getExposureRegisters(int exposure_time, int new_exp_g, bool dc_gain_enabled) const { return {}; }
virtual float getExposureScore(float desired_ev, int exp_t, int exp_g_idx, float exp_gain, int gain_idx) const {return 0; }
virtual int getSlaveAddress(int port) const { assert(0); }
virtual void processRegisters(uint8_t *cur_buf, cereal::FrameData::Builder &framed) const {}
cereal::FrameData::ImageSensor image_sensor = cereal::FrameData::ImageSensor::UNKNOWN;
float pixel_size_mm;
@@ -82,6 +81,10 @@ public:
std::vector<uint32_t> linearization_lut; // length 36
std::vector<uint32_t> linearization_pts; // length 4
std::vector<uint32_t> vignetting_lut; // length 221
const int num() const {
return static_cast<int>(image_sensor);
};
};
class AR0231 : public SensorInfo {
@@ -90,7 +93,6 @@ public:
std::vector<i2c_random_wr_payload> getExposureRegisters(int exposure_time, int new_exp_g, bool dc_gain_enabled) const override;
float getExposureScore(float desired_ev, int exp_t, int exp_g_idx, float exp_gain, int gain_idx) const override;
int getSlaveAddress(int port) const override;
void processRegisters(uint8_t *cur_buf, cereal::FrameData::Builder &framed) const override;
private:
mutable std::map<uint16_t, std::pair<int, int>> ar0231_register_lut;
+1 -1
View File
@@ -5,7 +5,7 @@ set -e
# no CCI and UTIL, very spammy
echo 0xfffdbfff | sudo tee /sys/module/cam_debug_util/parameters/debug_mdl
echo 0 | sudo tee /sys/module/cam_debug_util/parameters/debug_mdl
#echo 0 | sudo tee /sys/module/cam_debug_util/parameters/debug_mdl
sudo dmesg -C
scons -u -j8 --minimal .
+51 -39
View File
@@ -1,24 +1,4 @@
[
{
"name": "boot",
"url": "https://commadist.azureedge.net/agnosupdate/boot-5679a04c7cb08ab2f6bdb26b7f807d2a5819d2055151a9d3c89e65c7f24a85d8.img.xz",
"hash": "5679a04c7cb08ab2f6bdb26b7f807d2a5819d2055151a9d3c89e65c7f24a85d8",
"hash_raw": "5679a04c7cb08ab2f6bdb26b7f807d2a5819d2055151a9d3c89e65c7f24a85d8",
"size": 16422912,
"sparse": false,
"full_check": true,
"has_ab": true
},
{
"name": "system",
"url": "https://commadist.azureedge.net/agnosupdate/system-5a11d6b2588ddb562b69cf2c27d7a8feae2ef0693f73a01cf6536b2cd9a09a29.img.xz",
"hash": "5a11d6b2588ddb562b69cf2c27d7a8feae2ef0693f73a01cf6536b2cd9a09a29",
"hash_raw": "5a11d6b2588ddb562b69cf2c27d7a8feae2ef0693f73a01cf6536b2cd9a09a29",
"size": 4404019200,
"sparse": false,
"full_check": false,
"has_ab": true
},
{
"name": "xbl",
"url": "https://commadist.azureedge.net/agnosupdate/xbl-468f1ad6ab55e198647ff9191f91bd2918db9c0a3e27bae5673b4c5575c1254c.img.xz",
@@ -27,17 +7,8 @@
"size": 3282256,
"sparse": false,
"full_check": true,
"has_ab": true
},
{
"name": "abl",
"url": "https://commadist.azureedge.net/agnosupdate/abl-32a2174b5f764e95dfc54cf358ba01752943b1b3b90e626149c3da7d5f1830b6.img.xz",
"hash": "32a2174b5f764e95dfc54cf358ba01752943b1b3b90e626149c3da7d5f1830b6",
"hash_raw": "32a2174b5f764e95dfc54cf358ba01752943b1b3b90e626149c3da7d5f1830b6",
"size": 274432,
"sparse": false,
"full_check": true,
"has_ab": true
"has_ab": true,
"ondevice_hash": "d35a86e7b8ddd9279b513a6f27da1521aa0f89fb93987ea74d57d0f0bbbbd247"
},
{
"name": "xbl_config",
@@ -47,17 +18,19 @@
"size": 98124,
"sparse": false,
"full_check": true,
"has_ab": true
"has_ab": true,
"ondevice_hash": "623f1568072ee2d687ba8449a3d894c1c83dc4131b2e79eff35696885f70a419"
},
{
"name": "devcfg",
"url": "https://commadist.azureedge.net/agnosupdate/devcfg-225b24ea7b1d2fee7f7d2da21386920ddacac2e33e9e938168436292f4eae180.img.xz",
"hash": "225b24ea7b1d2fee7f7d2da21386920ddacac2e33e9e938168436292f4eae180",
"hash_raw": "225b24ea7b1d2fee7f7d2da21386920ddacac2e33e9e938168436292f4eae180",
"size": 40336,
"name": "abl",
"url": "https://commadist.azureedge.net/agnosupdate/abl-32a2174b5f764e95dfc54cf358ba01752943b1b3b90e626149c3da7d5f1830b6.img.xz",
"hash": "32a2174b5f764e95dfc54cf358ba01752943b1b3b90e626149c3da7d5f1830b6",
"hash_raw": "32a2174b5f764e95dfc54cf358ba01752943b1b3b90e626149c3da7d5f1830b6",
"size": 274432,
"sparse": false,
"full_check": true,
"has_ab": true
"has_ab": true,
"ondevice_hash": "32a2174b5f764e95dfc54cf358ba01752943b1b3b90e626149c3da7d5f1830b6"
},
{
"name": "aop",
@@ -67,6 +40,45 @@
"size": 184364,
"sparse": false,
"full_check": true,
"has_ab": true
"has_ab": true,
"ondevice_hash": "bf74feca486f650589f6b7c90eab73274e35a68b5e00bfc1de0ed5f5484d4b3d"
},
{
"name": "devcfg",
"url": "https://commadist.azureedge.net/agnosupdate/devcfg-225b24ea7b1d2fee7f7d2da21386920ddacac2e33e9e938168436292f4eae180.img.xz",
"hash": "225b24ea7b1d2fee7f7d2da21386920ddacac2e33e9e938168436292f4eae180",
"hash_raw": "225b24ea7b1d2fee7f7d2da21386920ddacac2e33e9e938168436292f4eae180",
"size": 40336,
"sparse": false,
"full_check": true,
"has_ab": true,
"ondevice_hash": "70f682b59ca0fe2f197d1486bd8be7b9b7e560798ad40ddef83b9f0a2f497938"
},
{
"name": "boot",
"url": "https://commadist.azureedge.net/agnosupdate/boot-c7cba1ce64bf85384241fa063971855c5ffcb4d90a0d07bed4733d46b94d4170.img.xz",
"hash": "c7cba1ce64bf85384241fa063971855c5ffcb4d90a0d07bed4733d46b94d4170",
"hash_raw": "c7cba1ce64bf85384241fa063971855c5ffcb4d90a0d07bed4733d46b94d4170",
"size": 18475008,
"sparse": false,
"full_check": true,
"has_ab": true,
"ondevice_hash": "6a9a71bf01f2013f35bda9594cefe3cb4a3835402a6cb0e95306fe4decf261c5"
},
{
"name": "system",
"url": "https://commadist.azureedge.net/agnosupdate/system-cd03486f6c7333dee21f59af771f9992ea90a9a04271c1506a663d658f391625.img.xz",
"hash": "990ff7005a5bee8e759c96ddba23f1258f043fb038cf74083bf7d2d9c9a29e39",
"hash_raw": "cd03486f6c7333dee21f59af771f9992ea90a9a04271c1506a663d658f391625",
"size": 4404019200,
"sparse": true,
"full_check": false,
"has_ab": true,
"ondevice_hash": "d922fffe1b5f02898465a2d6625294abb70d22643ebf2d6a94f5d7512291d1a4",
"alt": {
"hash": "cd03486f6c7333dee21f59af771f9992ea90a9a04271c1506a663d658f391625",
"url": "https://commadist.azureedge.net/agnosupdate/system-cd03486f6c7333dee21f59af771f9992ea90a9a04271c1506a663d658f391625.img",
"size": 4404019200
}
}
]
+400
View File
@@ -0,0 +1,400 @@
[
{
"name": "gpt_main_0",
"url": "https://commadist.azureedge.net/agnosupdate/gpt_main_0-8928a31fd9ee20f8703649f89833eba9b55e84b6415e67799c777b163c95a0bd.img.xz",
"hash": "8928a31fd9ee20f8703649f89833eba9b55e84b6415e67799c777b163c95a0bd",
"hash_raw": "8928a31fd9ee20f8703649f89833eba9b55e84b6415e67799c777b163c95a0bd",
"size": 24576,
"sparse": false,
"full_check": true,
"has_ab": false,
"ondevice_hash": "8928a31fd9ee20f8703649f89833eba9b55e84b6415e67799c777b163c95a0bd",
"gpt": {
"lun": 0,
"start_sector": 0,
"num_sectors": 6
}
},
{
"name": "gpt_main_1",
"url": "https://commadist.azureedge.net/agnosupdate/gpt_main_1-fe8ef7653db588d7420a625920ca06927dfcb0ed8aff3e3a1c74a52a24398ba6.img.xz",
"hash": "fe8ef7653db588d7420a625920ca06927dfcb0ed8aff3e3a1c74a52a24398ba6",
"hash_raw": "fe8ef7653db588d7420a625920ca06927dfcb0ed8aff3e3a1c74a52a24398ba6",
"size": 24576,
"sparse": false,
"full_check": true,
"has_ab": false,
"ondevice_hash": "fe8ef7653db588d7420a625920ca06927dfcb0ed8aff3e3a1c74a52a24398ba6",
"gpt": {
"lun": 1,
"start_sector": 0,
"num_sectors": 6
}
},
{
"name": "gpt_main_2",
"url": "https://commadist.azureedge.net/agnosupdate/gpt_main_2-5ccfc7240c8cbfa2f1a018a2e376cf274a6baf858c9bfe71951d8e28cab53c21.img.xz",
"hash": "5ccfc7240c8cbfa2f1a018a2e376cf274a6baf858c9bfe71951d8e28cab53c21",
"hash_raw": "5ccfc7240c8cbfa2f1a018a2e376cf274a6baf858c9bfe71951d8e28cab53c21",
"size": 24576,
"sparse": false,
"full_check": true,
"has_ab": false,
"ondevice_hash": "5ccfc7240c8cbfa2f1a018a2e376cf274a6baf858c9bfe71951d8e28cab53c21",
"gpt": {
"lun": 2,
"start_sector": 0,
"num_sectors": 6
}
},
{
"name": "gpt_main_3",
"url": "https://commadist.azureedge.net/agnosupdate/gpt_main_3-c707979fa21e89519328f4f30c2b21c9c453401ca8303f914c1873d410a95159.img.xz",
"hash": "c707979fa21e89519328f4f30c2b21c9c453401ca8303f914c1873d410a95159",
"hash_raw": "c707979fa21e89519328f4f30c2b21c9c453401ca8303f914c1873d410a95159",
"size": 24576,
"sparse": false,
"full_check": true,
"has_ab": false,
"ondevice_hash": "c707979fa21e89519328f4f30c2b21c9c453401ca8303f914c1873d410a95159",
"gpt": {
"lun": 3,
"start_sector": 0,
"num_sectors": 6
}
},
{
"name": "gpt_main_4",
"url": "https://commadist.azureedge.net/agnosupdate/gpt_main_4-e9405dcd785dbe79412184e1894a9c51ab7deb33bb612166c4c42a3d2bf42a0e.img.xz",
"hash": "e9405dcd785dbe79412184e1894a9c51ab7deb33bb612166c4c42a3d2bf42a0e",
"hash_raw": "e9405dcd785dbe79412184e1894a9c51ab7deb33bb612166c4c42a3d2bf42a0e",
"size": 24576,
"sparse": false,
"full_check": true,
"has_ab": false,
"ondevice_hash": "e9405dcd785dbe79412184e1894a9c51ab7deb33bb612166c4c42a3d2bf42a0e",
"gpt": {
"lun": 4,
"start_sector": 0,
"num_sectors": 6
}
},
{
"name": "gpt_main_5",
"url": "https://commadist.azureedge.net/agnosupdate/gpt_main_5-21ae965f05b2fa8d02e04f1eb74718f9779864f6eacdeb859757d6435e8ccce3.img.xz",
"hash": "21ae965f05b2fa8d02e04f1eb74718f9779864f6eacdeb859757d6435e8ccce3",
"hash_raw": "21ae965f05b2fa8d02e04f1eb74718f9779864f6eacdeb859757d6435e8ccce3",
"size": 24576,
"sparse": false,
"full_check": true,
"has_ab": false,
"ondevice_hash": "21ae965f05b2fa8d02e04f1eb74718f9779864f6eacdeb859757d6435e8ccce3",
"gpt": {
"lun": 5,
"start_sector": 0,
"num_sectors": 6
}
},
{
"name": "persist",
"url": "https://commadist.azureedge.net/agnosupdate/persist-9814b07851292f510f3794b767489f38ab379a99f0ea75dc620ad2d3a496d54d.img.xz",
"hash": "9814b07851292f510f3794b767489f38ab379a99f0ea75dc620ad2d3a496d54d",
"hash_raw": "9814b07851292f510f3794b767489f38ab379a99f0ea75dc620ad2d3a496d54d",
"size": 33554432,
"sparse": false,
"full_check": true,
"has_ab": false,
"ondevice_hash": "9814b07851292f510f3794b767489f38ab379a99f0ea75dc620ad2d3a496d54d"
},
{
"name": "systemrw",
"url": "https://commadist.azureedge.net/agnosupdate/systemrw-8ce150ca38ef64a0885fc2fe816e5b63bae8adb4df5d809c5b318e6996366c7e.img.xz",
"hash": "8ce150ca38ef64a0885fc2fe816e5b63bae8adb4df5d809c5b318e6996366c7e",
"hash_raw": "8ce150ca38ef64a0885fc2fe816e5b63bae8adb4df5d809c5b318e6996366c7e",
"size": 16777216,
"sparse": false,
"full_check": true,
"has_ab": false,
"ondevice_hash": "8ce150ca38ef64a0885fc2fe816e5b63bae8adb4df5d809c5b318e6996366c7e"
},
{
"name": "cache",
"url": "https://commadist.azureedge.net/agnosupdate/cache-ebfbaaa2f96dc4e5fea4f126364e5bf5b3b44c12cbc753b62fdd8baab82f70b4.img.xz",
"hash": "ebfbaaa2f96dc4e5fea4f126364e5bf5b3b44c12cbc753b62fdd8baab82f70b4",
"hash_raw": "ebfbaaa2f96dc4e5fea4f126364e5bf5b3b44c12cbc753b62fdd8baab82f70b4",
"size": 134217728,
"sparse": false,
"full_check": true,
"has_ab": false,
"ondevice_hash": "ebfbaaa2f96dc4e5fea4f126364e5bf5b3b44c12cbc753b62fdd8baab82f70b4"
},
{
"name": "xbl",
"url": "https://commadist.azureedge.net/agnosupdate/xbl-468f1ad6ab55e198647ff9191f91bd2918db9c0a3e27bae5673b4c5575c1254c.img.xz",
"hash": "468f1ad6ab55e198647ff9191f91bd2918db9c0a3e27bae5673b4c5575c1254c",
"hash_raw": "468f1ad6ab55e198647ff9191f91bd2918db9c0a3e27bae5673b4c5575c1254c",
"size": 3282256,
"sparse": false,
"full_check": true,
"has_ab": true,
"ondevice_hash": "d35a86e7b8ddd9279b513a6f27da1521aa0f89fb93987ea74d57d0f0bbbbd247"
},
{
"name": "xbl_config",
"url": "https://commadist.azureedge.net/agnosupdate/xbl_config-92b675dc2862ed15c732d91d9eb307d7e852e349217db8bee8f8829db543686b.img.xz",
"hash": "92b675dc2862ed15c732d91d9eb307d7e852e349217db8bee8f8829db543686b",
"hash_raw": "92b675dc2862ed15c732d91d9eb307d7e852e349217db8bee8f8829db543686b",
"size": 98124,
"sparse": false,
"full_check": true,
"has_ab": true,
"ondevice_hash": "623f1568072ee2d687ba8449a3d894c1c83dc4131b2e79eff35696885f70a419"
},
{
"name": "abl",
"url": "https://commadist.azureedge.net/agnosupdate/abl-32a2174b5f764e95dfc54cf358ba01752943b1b3b90e626149c3da7d5f1830b6.img.xz",
"hash": "32a2174b5f764e95dfc54cf358ba01752943b1b3b90e626149c3da7d5f1830b6",
"hash_raw": "32a2174b5f764e95dfc54cf358ba01752943b1b3b90e626149c3da7d5f1830b6",
"size": 274432,
"sparse": false,
"full_check": true,
"has_ab": true,
"ondevice_hash": "32a2174b5f764e95dfc54cf358ba01752943b1b3b90e626149c3da7d5f1830b6"
},
{
"name": "aop",
"url": "https://commadist.azureedge.net/agnosupdate/aop-f0fcf7611d0890a72984f15a516dd37fa532dfcb70d428a8406838cf74ce23d5.img.xz",
"hash": "f0fcf7611d0890a72984f15a516dd37fa532dfcb70d428a8406838cf74ce23d5",
"hash_raw": "f0fcf7611d0890a72984f15a516dd37fa532dfcb70d428a8406838cf74ce23d5",
"size": 184364,
"sparse": false,
"full_check": true,
"has_ab": true,
"ondevice_hash": "bf74feca486f650589f6b7c90eab73274e35a68b5e00bfc1de0ed5f5484d4b3d"
},
{
"name": "bluetooth",
"url": "https://commadist.azureedge.net/agnosupdate/bluetooth-9bb766d2d2ce0cc4491664b3010fe1ef62f8ffc1e362d55f78e48c4141f75533.img.xz",
"hash": "9bb766d2d2ce0cc4491664b3010fe1ef62f8ffc1e362d55f78e48c4141f75533",
"hash_raw": "9bb766d2d2ce0cc4491664b3010fe1ef62f8ffc1e362d55f78e48c4141f75533",
"size": 1048576,
"sparse": false,
"full_check": true,
"has_ab": true,
"ondevice_hash": "9bb766d2d2ce0cc4491664b3010fe1ef62f8ffc1e362d55f78e48c4141f75533"
},
{
"name": "cmnlib64",
"url": "https://commadist.azureedge.net/agnosupdate/cmnlib64-1a876bd151bb9635f18719c4a17f953079de6e11d3eaec800968fc75669e0dc3.img.xz",
"hash": "1a876bd151bb9635f18719c4a17f953079de6e11d3eaec800968fc75669e0dc3",
"hash_raw": "1a876bd151bb9635f18719c4a17f953079de6e11d3eaec800968fc75669e0dc3",
"size": 524288,
"sparse": false,
"full_check": true,
"has_ab": true,
"ondevice_hash": "1a876bd151bb9635f18719c4a17f953079de6e11d3eaec800968fc75669e0dc3"
},
{
"name": "cmnlib",
"url": "https://commadist.azureedge.net/agnosupdate/cmnlib-63df823e8a5fae01d66cb2b8c20f0d2ddb5c5f2425e5d0992a64676273ba1c82.img.xz",
"hash": "63df823e8a5fae01d66cb2b8c20f0d2ddb5c5f2425e5d0992a64676273ba1c82",
"hash_raw": "63df823e8a5fae01d66cb2b8c20f0d2ddb5c5f2425e5d0992a64676273ba1c82",
"size": 524288,
"sparse": false,
"full_check": true,
"has_ab": true,
"ondevice_hash": "63df823e8a5fae01d66cb2b8c20f0d2ddb5c5f2425e5d0992a64676273ba1c82"
},
{
"name": "devcfg",
"url": "https://commadist.azureedge.net/agnosupdate/devcfg-225b24ea7b1d2fee7f7d2da21386920ddacac2e33e9e938168436292f4eae180.img.xz",
"hash": "225b24ea7b1d2fee7f7d2da21386920ddacac2e33e9e938168436292f4eae180",
"hash_raw": "225b24ea7b1d2fee7f7d2da21386920ddacac2e33e9e938168436292f4eae180",
"size": 40336,
"sparse": false,
"full_check": true,
"has_ab": true,
"ondevice_hash": "70f682b59ca0fe2f197d1486bd8be7b9b7e560798ad40ddef83b9f0a2f497938"
},
{
"name": "devinfo",
"url": "https://commadist.azureedge.net/agnosupdate/devinfo-143869c499a7e878fbeab756e9c53074195770cc41d6d0d10e45c043141389a3.img.xz",
"hash": "143869c499a7e878fbeab756e9c53074195770cc41d6d0d10e45c043141389a3",
"hash_raw": "143869c499a7e878fbeab756e9c53074195770cc41d6d0d10e45c043141389a3",
"size": 4096,
"sparse": false,
"full_check": true,
"has_ab": false,
"ondevice_hash": "143869c499a7e878fbeab756e9c53074195770cc41d6d0d10e45c043141389a3"
},
{
"name": "dsp",
"url": "https://commadist.azureedge.net/agnosupdate/dsp-4b15fbd2f45581f1553f33f01649e450b24aa19d5deff2ac7dcb16a534d9c248.img.xz",
"hash": "4b15fbd2f45581f1553f33f01649e450b24aa19d5deff2ac7dcb16a534d9c248",
"hash_raw": "4b15fbd2f45581f1553f33f01649e450b24aa19d5deff2ac7dcb16a534d9c248",
"size": 33554432,
"sparse": false,
"full_check": true,
"has_ab": true,
"ondevice_hash": "4b15fbd2f45581f1553f33f01649e450b24aa19d5deff2ac7dcb16a534d9c248"
},
{
"name": "hyp",
"url": "https://commadist.azureedge.net/agnosupdate/hyp-ff5ece6a4e3d2b4d898c77ffe193fc8bbc8acebe78263996ecf52373d8088927.img.xz",
"hash": "ff5ece6a4e3d2b4d898c77ffe193fc8bbc8acebe78263996ecf52373d8088927",
"hash_raw": "ff5ece6a4e3d2b4d898c77ffe193fc8bbc8acebe78263996ecf52373d8088927",
"size": 524288,
"sparse": false,
"full_check": true,
"has_ab": true,
"ondevice_hash": "ff5ece6a4e3d2b4d898c77ffe193fc8bbc8acebe78263996ecf52373d8088927"
},
{
"name": "keymaster",
"url": "https://commadist.azureedge.net/agnosupdate/keymaster-5c968c76f29b9a4d66fbe57e639bac6b7a2c83b1758e25abbaf5d276b8a6af04.img.xz",
"hash": "5c968c76f29b9a4d66fbe57e639bac6b7a2c83b1758e25abbaf5d276b8a6af04",
"hash_raw": "5c968c76f29b9a4d66fbe57e639bac6b7a2c83b1758e25abbaf5d276b8a6af04",
"size": 524288,
"sparse": false,
"full_check": true,
"has_ab": true,
"ondevice_hash": "5c968c76f29b9a4d66fbe57e639bac6b7a2c83b1758e25abbaf5d276b8a6af04"
},
{
"name": "limits",
"url": "https://commadist.azureedge.net/agnosupdate/limits-94951a0f7aa55fb6cb975535ce4ebbfe6d695f04cb5424677b01c10dfa2e94e1.img.xz",
"hash": "94951a0f7aa55fb6cb975535ce4ebbfe6d695f04cb5424677b01c10dfa2e94e1",
"hash_raw": "94951a0f7aa55fb6cb975535ce4ebbfe6d695f04cb5424677b01c10dfa2e94e1",
"size": 4096,
"sparse": false,
"full_check": true,
"has_ab": false,
"ondevice_hash": "94951a0f7aa55fb6cb975535ce4ebbfe6d695f04cb5424677b01c10dfa2e94e1"
},
{
"name": "logfs",
"url": "https://commadist.azureedge.net/agnosupdate/logfs-b8b5ac87f3d954404fc7ecbdd9ee3b5b0cf5691e5006e6ec55db4c899ff61220.img.xz",
"hash": "b8b5ac87f3d954404fc7ecbdd9ee3b5b0cf5691e5006e6ec55db4c899ff61220",
"hash_raw": "b8b5ac87f3d954404fc7ecbdd9ee3b5b0cf5691e5006e6ec55db4c899ff61220",
"size": 8388608,
"sparse": false,
"full_check": true,
"has_ab": false,
"ondevice_hash": "b8b5ac87f3d954404fc7ecbdd9ee3b5b0cf5691e5006e6ec55db4c899ff61220"
},
{
"name": "modem",
"url": "https://commadist.azureedge.net/agnosupdate/modem-a3d014f0896d77a2df7e5a80a70f43a51a047b9d03cfc675b6f0e31a6ecc4994.img.xz",
"hash": "a3d014f0896d77a2df7e5a80a70f43a51a047b9d03cfc675b6f0e31a6ecc4994",
"hash_raw": "a3d014f0896d77a2df7e5a80a70f43a51a047b9d03cfc675b6f0e31a6ecc4994",
"size": 125829120,
"sparse": false,
"full_check": true,
"has_ab": true,
"ondevice_hash": "a3d014f0896d77a2df7e5a80a70f43a51a047b9d03cfc675b6f0e31a6ecc4994"
},
{
"name": "qupfw",
"url": "https://commadist.azureedge.net/agnosupdate/qupfw-64cc7c29d5d69b04267452b8b4ddba9f4809e68f476fc162ca283f58537afe4a.img.xz",
"hash": "64cc7c29d5d69b04267452b8b4ddba9f4809e68f476fc162ca283f58537afe4a",
"hash_raw": "64cc7c29d5d69b04267452b8b4ddba9f4809e68f476fc162ca283f58537afe4a",
"size": 65536,
"sparse": false,
"full_check": true,
"has_ab": true,
"ondevice_hash": "64cc7c29d5d69b04267452b8b4ddba9f4809e68f476fc162ca283f58537afe4a"
},
{
"name": "splash",
"url": "https://commadist.azureedge.net/agnosupdate/splash-5c61260048f22ede6e6343fabb27f6ff73f9271f4751a01aaf7abf097afc1f08.img.xz",
"hash": "5c61260048f22ede6e6343fabb27f6ff73f9271f4751a01aaf7abf097afc1f08",
"hash_raw": "5c61260048f22ede6e6343fabb27f6ff73f9271f4751a01aaf7abf097afc1f08",
"size": 34226176,
"sparse": false,
"full_check": true,
"has_ab": false,
"ondevice_hash": "5c61260048f22ede6e6343fabb27f6ff73f9271f4751a01aaf7abf097afc1f08"
},
{
"name": "storsec",
"url": "https://commadist.azureedge.net/agnosupdate/storsec-4494d86f68b125fbf2c004c824b1c6dbe71e61a65d2a1cc7db13c553edcb3fce.img.xz",
"hash": "4494d86f68b125fbf2c004c824b1c6dbe71e61a65d2a1cc7db13c553edcb3fce",
"hash_raw": "4494d86f68b125fbf2c004c824b1c6dbe71e61a65d2a1cc7db13c553edcb3fce",
"size": 131072,
"sparse": false,
"full_check": true,
"has_ab": true,
"ondevice_hash": "4494d86f68b125fbf2c004c824b1c6dbe71e61a65d2a1cc7db13c553edcb3fce"
},
{
"name": "tz",
"url": "https://commadist.azureedge.net/agnosupdate/tz-e9443bf187641661bfa6c96702b9ab0156e72fb7482500f8799ba9ee2503cb16.img.xz",
"hash": "e9443bf187641661bfa6c96702b9ab0156e72fb7482500f8799ba9ee2503cb16",
"hash_raw": "e9443bf187641661bfa6c96702b9ab0156e72fb7482500f8799ba9ee2503cb16",
"size": 2097152,
"sparse": false,
"full_check": true,
"has_ab": true,
"ondevice_hash": "e9443bf187641661bfa6c96702b9ab0156e72fb7482500f8799ba9ee2503cb16"
},
{
"name": "boot",
"url": "https://commadist.azureedge.net/agnosupdate/boot-c7cba1ce64bf85384241fa063971855c5ffcb4d90a0d07bed4733d46b94d4170.img.xz",
"hash": "c7cba1ce64bf85384241fa063971855c5ffcb4d90a0d07bed4733d46b94d4170",
"hash_raw": "c7cba1ce64bf85384241fa063971855c5ffcb4d90a0d07bed4733d46b94d4170",
"size": 18475008,
"sparse": false,
"full_check": true,
"has_ab": true,
"ondevice_hash": "6a9a71bf01f2013f35bda9594cefe3cb4a3835402a6cb0e95306fe4decf261c5"
},
{
"name": "system",
"url": "https://commadist.azureedge.net/agnosupdate/system-cd03486f6c7333dee21f59af771f9992ea90a9a04271c1506a663d658f391625.img.xz",
"hash": "990ff7005a5bee8e759c96ddba23f1258f043fb038cf74083bf7d2d9c9a29e39",
"hash_raw": "cd03486f6c7333dee21f59af771f9992ea90a9a04271c1506a663d658f391625",
"size": 4404019200,
"sparse": true,
"full_check": false,
"has_ab": true,
"ondevice_hash": "d922fffe1b5f02898465a2d6625294abb70d22643ebf2d6a94f5d7512291d1a4",
"alt": {
"hash": "cd03486f6c7333dee21f59af771f9992ea90a9a04271c1506a663d658f391625",
"url": "https://commadist.azureedge.net/agnosupdate/system-cd03486f6c7333dee21f59af771f9992ea90a9a04271c1506a663d658f391625.img",
"size": 4404019200
}
},
{
"name": "userdata_90",
"url": "https://commadist.azureedge.net/agnosupdate/userdata_90-554a22697b356cb150c2c803b4cb1de79403849e9be451c844d218d38b5bc236.img.xz",
"hash": "4f0a862e3aff4980e697ece63afaef6f9869d013ac2ca4c45193e41089ee4f5c",
"hash_raw": "554a22697b356cb150c2c803b4cb1de79403849e9be451c844d218d38b5bc236",
"size": 96636764160,
"sparse": true,
"full_check": true,
"has_ab": false,
"ondevice_hash": "5d780092d51c569e6b8a28ab73f4029bcc3517698f496af5801f863c9865060f"
},
{
"name": "userdata_89",
"url": "https://commadist.azureedge.net/agnosupdate/userdata_89-6045b9a3f1ae6e0ee09b95da039b697ab8d8447cdd0796fa31afa9c7d324ee80.img.xz",
"hash": "ba49fef48573e9befdfb6334181753855cb83d3e1d8c6d4d83d510ea0141ec3f",
"hash_raw": "6045b9a3f1ae6e0ee09b95da039b697ab8d8447cdd0796fa31afa9c7d324ee80",
"size": 95563022336,
"sparse": true,
"full_check": true,
"has_ab": false,
"ondevice_hash": "19b63b184063c25ff2fc9f1c8d1c919c140c3e1295ebac6cb66e64c5cb609abe"
},
{
"name": "userdata_30",
"url": "https://commadist.azureedge.net/agnosupdate/userdata_30-498358c1e5347dc3f8c369523bd77b94ef73d6c6729b40f376209d0d32b356fe.img.xz",
"hash": "828d0911713af02de7fae4c583a2274783e344939f296c7c016866a8cf2cb63f",
"hash_raw": "498358c1e5347dc3f8c369523bd77b94ef73d6c6729b40f376209d0d32b356fe",
"size": 32212254720,
"sparse": true,
"full_check": true,
"has_ab": false,
"ondevice_hash": "4beb60ffceff88b05daa014db50cb2f4e9acec3ed7ae1b89a8d3c84cfc3c1c92"
}
]
+6 -6
View File
@@ -76,7 +76,7 @@ def sudo_write(val, path):
def sudo_read(path: str) -> str:
try:
return subprocess.check_output(f"sudo cat {path}", shell=True, encoding='utf8')
return subprocess.check_output(f"sudo cat {path}", shell=True, encoding='utf8').strip()
except Exception:
return ""
@@ -371,7 +371,7 @@ class Tici(HardwareBase):
# *** CPU config ***
# offline big cluster, leave core 4 online for pandad
# offline big cluster
for i in range(4, 8):
val = '0' if powersave_enabled else '1'
sudo_write(val, f'/sys/devices/system/cpu/cpu{i}/online')
@@ -384,13 +384,13 @@ class Tici(HardwareBase):
# *** IRQ config ***
# GPU
affine_irq(5, "kgsl-3d0")
# GPU, modeld core
affine_irq(7, "kgsl-3d0")
# camerad core
camera_irqs = ("cci", "cpas_camnoc", "cpas-cdm", "csid", "ife", "csid-lite", "ife-lite")
camera_irqs = ("a5", "cci", "cpas_camnoc", "cpas-cdm", "csid", "ife", "csid-lite", "ife-lite")
for n in camera_irqs:
affine_irq(5, n)
affine_irq(6, n)
def get_gpu_usage_percent(self):
try:
@@ -31,7 +31,7 @@ class Proc:
PROCS = [
Proc(['camerad'], 2.1, msgs=['roadCameraState', 'wideRoadCameraState', 'driverCameraState']),
Proc(['camerad'], 1.75, msgs=['roadCameraState', 'wideRoadCameraState', 'driverCameraState']),
Proc(['modeld'], 1.12, atol=0.2, msgs=['modelV2']),
Proc(['dmonitoringmodeld'], 0.6, msgs=['driverStateV2']),
Proc(['encoderd'], 0.23, msgs=[]),
+5 -5
View File
@@ -1,10 +1,10 @@
Import('env', 'arch', 'messaging', 'common', 'visionipc')
libs = [common, messaging, visionipc,
'z', 'avformat', 'avcodec', 'swscale',
'avutil', 'yuv', 'OpenCL', 'pthread']
'avformat', 'avcodec', 'avutil',
'yuv', 'OpenCL', 'pthread', 'zstd']
src = ['logger.cc', 'video_writer.cc', 'encoder/encoder.cc', 'encoder/v4l_encoder.cc']
src = ['logger.cc', 'zstd_writer.cc', 'video_writer.cc', 'encoder/encoder.cc', 'encoder/v4l_encoder.cc', 'encoder/jpeg_encoder.cc']
if arch != "larch64":
src += ['encoder/ffmpeg_encoder.cc']
@@ -19,8 +19,8 @@ logger_lib = env.Library('logger', src)
libs.insert(0, logger_lib)
env.Program('loggerd', ['loggerd.cc'], LIBS=libs)
env.Program('encoderd', ['encoderd.cc'], LIBS=libs)
env.Program('encoderd', ['encoderd.cc'], LIBS=libs + ["jpeg"])
env.Program('bootlog.cc', LIBS=libs)
if GetOption('extras'):
env.Program('tests/test_logger', ['tests/test_runner.cc', 'tests/test_logger.cc'], LIBS=libs + ['curl', 'crypto'])
env.Program('tests/test_logger', ['tests/test_runner.cc', 'tests/test_logger.cc', 'tests/test_zstd_writer.cc'], LIBS=libs + ['curl', 'crypto'])
+3 -2
View File
@@ -5,6 +5,7 @@
#include "common/params.h"
#include "common/swaglog.h"
#include "system/loggerd/logger.h"
#include "system/loggerd/zstd_writer.h"
static kj::Array<capnp::word> build_boot_log() {
@@ -50,14 +51,14 @@ static kj::Array<capnp::word> build_boot_log() {
int main(int argc, char** argv) {
const std::string id = logger_get_identifier("BootCount");
const std::string path = Path::log_root() + "/boot/" + id;
const std::string path = Path::log_root() + "/boot/" + id + ".zst";
LOGW("bootlog to %s", path.c_str());
// Open bootlog
bool r = util::create_directories(Path::log_root() + "/boot/", 0775);
assert(r);
RawFile file(path.c_str());
ZstdFileWriter file(path, LOG_COMPRESSION_LEVEL);
// Write initdata
file.write(logger_build_init_data().asBytes());
// Write bootlog
+1 -17
View File
@@ -6,12 +6,7 @@ VideoEncoder::VideoEncoder(const EncoderInfo &encoder_info, int in_width, int in
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;
std::vector pubs = {encoder_info.publish_name};
if (encoder_info.thumbnail_name != NULL) {
pubs.push_back(encoder_info.thumbnail_name);
}
pm.reset(new PubMaster(pubs));
pm.reset(new PubMaster(std::vector{encoder_info.publish_name}));
}
void VideoEncoder::publisher_publish(int segment_num, uint32_t idx, VisionIpcBufExtra &extra,
@@ -45,15 +40,4 @@ void VideoEncoder::publisher_publish(int segment_num, uint32_t idx, VisionIpcBuf
kj::ArrayOutputStream output_stream(kj::ArrayPtr<capnp::byte>(msg_cache.data(), bytes_size));
capnp::writeMessage(output_stream, msg);
pm->send(encoder_info.publish_name, msg_cache.data(), bytes_size);
// Publish keyframe thumbnail
if ((flags & V4L2_BUF_FLAG_KEYFRAME) && encoder_info.thumbnail_name != NULL) {
MessageBuilder tm;
auto thumbnail = tm.initEvent().initThumbnail();
thumbnail.setFrameId(extra.frame_id);
thumbnail.setTimestampEof(extra.timestamp_eof);
thumbnail.setThumbnail(dat);
thumbnail.setEncoding(cereal::Thumbnail::Encoding::KEYFRAME);
pm->send(encoder_info.thumbnail_name, tm);
}
}
-2
View File
@@ -30,8 +30,6 @@ public:
void publisher_publish(int segment_num, uint32_t idx, VisionIpcBufExtra &extra, unsigned int flags, kj::ArrayPtr<capnp::byte> header, kj::ArrayPtr<capnp::byte> dat);
protected:
void publish_thumbnail(uint32_t frame_id, uint64_t timestamp_eof, kj::ArrayPtr<capnp::byte> dat);
int in_width, in_height;
int out_width, out_height;
const EncoderInfo encoder_info;
+4 -1
View File
@@ -48,7 +48,10 @@ FfmpegEncoder::~FfmpegEncoder() {
}
void FfmpegEncoder::encoder_open(const char* path) {
const AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_FFVHUFF);
auto codec_id = encoder_info.encode_type == cereal::EncodeIndex::Type::QCAMERA_H264
? AV_CODEC_ID_H264
: AV_CODEC_ID_FFVHUFF;
const AVCodec *codec = avcodec_find_encoder(codec_id);
this->codec_ctx = avcodec_alloc_context3(codec);
assert(this->codec_ctx);
+105
View File
@@ -0,0 +1,105 @@
#include "system/loggerd/encoder/jpeg_encoder.h"
#include <cassert>
#include <cstring>
JpegEncoder::JpegEncoder(const std::string &pusblish_name, int width, int height)
: publish_name(pusblish_name), thumbnail_width(width), thumbnail_height(height) {
yuv_buffer.resize((thumbnail_width * ((thumbnail_height + 15) & ~15) * 3) / 2);
pm = std::make_unique<PubMaster>(std::vector{pusblish_name.c_str()});
}
JpegEncoder::~JpegEncoder() {
if (out_buffer) {
free(out_buffer);
}
}
void JpegEncoder::pushThumbnail(VisionBuf *buf, const VisionIpcBufExtra &extra) {
generateThumbnail(buf->y, buf->uv, buf->width, buf->height, buf->stride);
MessageBuilder msg;
auto thumbnaild = msg.initEvent().initThumbnail();
thumbnaild.setFrameId(extra.frame_id);
thumbnaild.setTimestampEof(extra.timestamp_eof);
thumbnaild.setThumbnail({out_buffer, out_size});
pm->send(publish_name.c_str(), msg);
}
void JpegEncoder::generateThumbnail(const uint8_t *y_addr, const uint8_t *uv_addr, int width, int height, int stride) {
int downscale = width / thumbnail_width;
assert(downscale * thumbnail_height == height);
// make the buffer big enough. jpeg_write_raw_data requires 16-pixels aligned height to be used.
uint8_t *y_plane = yuv_buffer.data();
uint8_t *u_plane = y_plane + thumbnail_width * thumbnail_height;
uint8_t *v_plane = u_plane + (thumbnail_width * thumbnail_height) / 4;
{
// subsampled conversion from nv12 to yuv
for (int hy = 0; hy < thumbnail_height / 2; hy++) {
for (int hx = 0; hx < thumbnail_width / 2; hx++) {
int ix = hx * downscale + (downscale - 1) / 2;
int iy = hy * downscale + (downscale - 1) / 2;
y_plane[(hy * 2 + 0) * thumbnail_width + (hx * 2 + 0)] = y_addr[(iy * 2 + 0) * stride + ix * 2 + 0];
y_plane[(hy * 2 + 0) * thumbnail_width + (hx * 2 + 1)] = y_addr[(iy * 2 + 0) * stride + ix * 2 + 1];
y_plane[(hy * 2 + 1) * thumbnail_width + (hx * 2 + 0)] = y_addr[(iy * 2 + 1) * stride + ix * 2 + 0];
y_plane[(hy * 2 + 1) * thumbnail_width + (hx * 2 + 1)] = y_addr[(iy * 2 + 1) * stride + ix * 2 + 1];
u_plane[hy * thumbnail_width / 2 + hx] = uv_addr[iy * stride + ix * 2 + 0];
v_plane[hy * thumbnail_width / 2 + hx] = uv_addr[iy * stride + ix * 2 + 1];
}
}
}
compressToJpeg(y_plane, u_plane, v_plane);
}
void JpegEncoder::compressToJpeg(uint8_t *y_plane, uint8_t *u_plane, uint8_t *v_plane) {
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
if (out_buffer) {
free(out_buffer);
out_buffer = nullptr;
out_size = 0;
}
jpeg_mem_dest(&cinfo, &out_buffer, &out_size);
cinfo.image_width = thumbnail_width;
cinfo.image_height = thumbnail_height;
cinfo.input_components = 3;
jpeg_set_defaults(&cinfo);
jpeg_set_colorspace(&cinfo, JCS_YCbCr);
// configure sampling factors for yuv420.
cinfo.comp_info[0].h_samp_factor = 2; // Y
cinfo.comp_info[0].v_samp_factor = 2;
cinfo.comp_info[1].h_samp_factor = 1; // U
cinfo.comp_info[1].v_samp_factor = 1;
cinfo.comp_info[2].h_samp_factor = 1; // V
cinfo.comp_info[2].v_samp_factor = 1;
cinfo.raw_data_in = TRUE;
jpeg_set_quality(&cinfo, 50, TRUE);
jpeg_start_compress(&cinfo, TRUE);
JSAMPROW y[16], u[8], v[8];
JSAMPARRAY planes[3]{y, u, v};
for (int line = 0; line < cinfo.image_height; line += 16) {
for (int i = 0; i < 16; ++i) {
y[i] = y_plane + (line + i) * cinfo.image_width;
if (i % 2 == 0) {
int offset = (cinfo.image_width / 2) * ((i + line) / 2);
u[i / 2] = u_plane + offset;
v[i / 2] = v_plane + offset;
}
}
jpeg_write_raw_data(&cinfo, planes, 16);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
}
+32
View File
@@ -0,0 +1,32 @@
#pragma once
#include <cstdio>
#include <cstdlib>
#include <cstddef>
#include <cstdint>
#include <jpeglib.h>
#include <vector>
#include <memory>
#include "cereal/messaging/messaging.h"
#include "msgq/visionipc/visionbuf.h"
class JpegEncoder {
public:
JpegEncoder(const std::string &pusblish_name, int width, int height);
~JpegEncoder();
void pushThumbnail(VisionBuf *buf, const VisionIpcBufExtra &extra);
private:
void generateThumbnail(const uint8_t *y, const uint8_t *uv, int width, int height, int stride);
void compressToJpeg(uint8_t *y_plane, uint8_t *u_plane, uint8_t *v_plane);
int thumbnail_width;
int thumbnail_height;
std::string publish_name;
std::vector<uint8_t> yuv_buffer;
std::unique_ptr<PubMaster> pm;
// JPEG output buffer
unsigned char* out_buffer = nullptr;
unsigned long out_size = 0;
};
+1 -1
View File
@@ -155,7 +155,7 @@ void V4LEncoder::dequeue_handler(V4LEncoder *e) {
V4LEncoder::V4LEncoder(const EncoderInfo &encoder_info, int in_width, int in_height)
: VideoEncoder(encoder_info, in_width, in_height) {
fd = open("/dev/v4l/by-path/platform-aa00000.qcom_vidc-video-index1", O_RDWR|O_NONBLOCK);
fd = HANDLE_EINTR(open("/dev/v4l/by-path/platform-aa00000.qcom_vidc-video-index1", O_RDWR|O_NONBLOCK));
assert(fd >= 0);
struct v4l2_capability cap;
+12
View File
@@ -1,6 +1,7 @@
#include <cassert>
#include "system/loggerd/loggerd.h"
#include "system/loggerd/encoder/jpeg_encoder.h"
#ifdef QCOM2
#include "system/loggerd/encoder/v4l_encoder.h"
@@ -50,6 +51,8 @@ void encoder_thread(EncoderdState *s, const LogCameraInfo &cam_info) {
std::vector<std::unique_ptr<Encoder>> encoders;
VisionIpcClient vipc_client = VisionIpcClient("camerad", cam_info.stream_type, false);
std::unique_ptr<JpegEncoder> jpeg_encoder;
int cur_seg = 0;
while (!do_exit) {
if (!vipc_client.connect(false)) {
@@ -67,6 +70,11 @@ void encoder_thread(EncoderdState *s, const LogCameraInfo &cam_info) {
auto &e = encoders.emplace_back(new Encoder(encoder_info, buf_info.width, buf_info.height));
e->encoder_open(nullptr);
}
// Only one thumbnail can be generated per camera stream
if (auto thumbnail_name = cam_info.encoder_infos[0].thumbnail_name) {
jpeg_encoder = std::make_unique<JpegEncoder>(thumbnail_name, buf_info.width / 4, buf_info.height / 4);
}
}
bool lagging = false;
@@ -108,6 +116,10 @@ void encoder_thread(EncoderdState *s, const LogCameraInfo &cam_info) {
LOGE("Failed to encode frame. frame_id: %d", extra.frame_id);
}
}
if (jpeg_encoder && (extra.frame_id % 1200 == 100)) {
jpeg_encoder->pushThumbnail(buf, extra);
}
}
}
}
+39 -4
View File
@@ -113,6 +113,42 @@ std::string logger_get_identifier(std::string key) {
return util::string_format("%08x--%s", cnt, ss.str().c_str());
}
std::string zstd_decompress(const std::string &in) {
ZSTD_DCtx *dctx = ZSTD_createDCtx();
assert(dctx != nullptr);
// Initialize input and output buffers
ZSTD_inBuffer input = {in.data(), in.size(), 0};
// Estimate and reserve memory for decompressed data
size_t estimatedDecompressedSize = ZSTD_getFrameContentSize(in.data(), in.size());
if (estimatedDecompressedSize == ZSTD_CONTENTSIZE_ERROR || estimatedDecompressedSize == ZSTD_CONTENTSIZE_UNKNOWN) {
estimatedDecompressedSize = in.size() * 2; // Use a fallback size
}
std::string decompressedData;
decompressedData.reserve(estimatedDecompressedSize);
const size_t bufferSize = ZSTD_DStreamOutSize(); // Recommended output buffer size
std::string outputBuffer(bufferSize, '\0');
while (input.pos < input.size) {
ZSTD_outBuffer output = {outputBuffer.data(), bufferSize, 0};
size_t result = ZSTD_decompressStream(dctx, &output, &input);
if (ZSTD_isError(result)) {
break;
}
decompressedData.append(outputBuffer.data(), output.pos);
}
ZSTD_freeDCtx(dctx);
decompressedData.shrink_to_fit();
return decompressedData;
}
static void log_sentinel(LoggerState *log, SentinelType type, int exit_signal = 0) {
MessageBuilder msg;
auto sen = msg.initEvent().initSentinel();
@@ -144,12 +180,11 @@ bool LoggerState::next() {
bool ret = util::create_directories(segment_path, 0775);
assert(ret == true);
const std::string rlog_path = segment_path + "/rlog";
lock_file = rlog_path + ".lock";
lock_file = segment_path + "/rlog.lock";
std::ofstream{lock_file};
rlog.reset(new RawFile(rlog_path));
qlog.reset(new RawFile(segment_path + "/qlog"));
rlog.reset(new ZstdFileWriter(segment_path + "/rlog.zst", LOG_COMPRESSION_LEVEL));
qlog.reset(new ZstdFileWriter(segment_path + "/qlog.zst", LOG_COMPRESSION_LEVEL));
// log init data & sentinel type.
write(init_data.asBytes(), true);
+4 -22
View File
@@ -7,31 +7,12 @@
#include "cereal/messaging/messaging.h"
#include "common/util.h"
#include "system/hardware/hw.h"
#include "system/loggerd/zstd_writer.h"
class RawFile {
public:
RawFile(const std::string &path) {
file = util::safe_fopen(path.c_str(), "wb");
assert(file != nullptr);
}
~RawFile() {
util::safe_fflush(file);
int err = fclose(file);
assert(err == 0);
}
inline void write(void* data, size_t size) {
int written = util::safe_fwrite(data, 1, size, file);
assert(written == size);
}
inline void write(kj::ArrayPtr<capnp::byte> array) { write(array.begin(), array.size()); }
private:
FILE* file = nullptr;
};
constexpr int LOG_COMPRESSION_LEVEL = 10;
typedef cereal::Sentinel::SentinelType SentinelType;
class LoggerState {
public:
LoggerState(const std::string& log_root = Path::log_root());
@@ -48,8 +29,9 @@ protected:
int part = -1, exit_signal = 0;
std::string route_path, route_name, segment_path, lock_file;
kj::Array<capnp::word> init_data;
std::unique_ptr<RawFile> rlog, qlog;
std::unique_ptr<ZstdFileWriter> rlog, qlog;
};
kj::Array<capnp::word> logger_build_init_data();
std::string logger_get_identifier(std::string key);
std::string zstd_decompress(const std::string &in);
+1
View File
@@ -56,6 +56,7 @@ public:
const EncoderInfo main_road_encoder_info = {
.publish_name = "roadEncodeData",
.thumbnail_name = "thumbnail",
.filename = "fcamera.hevc",
INIT_ENCODE_FUNCTIONS(RoadEncode),
};
+1 -1
View File
@@ -106,7 +106,7 @@ class TestEncoder:
# Check encodeIdx
if encode_idx_name is not None:
rlog_path = f"{route_prefix_path}--{i}/rlog"
rlog_path = f"{route_prefix_path}--{i}/rlog.zst"
msgs = [m for m in LogReader(rlog_path) if m.which() == encode_idx_name]
encode_msgs = [getattr(m, encode_idx_name) for m in msgs]
+3 -2
View File
@@ -9,12 +9,13 @@ void verify_segment(const std::string &route_path, int segment, int max_segment,
SentinelType end_sentinel = segment == max_segment - 1 ? SentinelType::END_OF_ROUTE : SentinelType::END_OF_SEGMENT;
REQUIRE(!util::file_exists(segment_path + "/rlog.lock"));
for (const char *fn : {"/rlog", "/qlog"}) {
for (const char *fn : {"/rlog.zst", "/qlog.zst"}) {
const std::string log_file = segment_path + fn;
std::string log = util::read_file(log_file);
REQUIRE(!log.empty());
std::string decompressed_log = zstd_decompress(log);
int event_cnt = 0, i = 0;
kj::ArrayPtr<const capnp::word> words((capnp::word *)log.data(), log.size() / sizeof(capnp::word));
kj::ArrayPtr<const capnp::word> words((capnp::word *)decompressed_log.data(), decompressed_log.size() / sizeof(capnp::word));
while (words.size() > 0) {
try {
capnp::FlatArrayMessageReader reader(words);
+3 -3
View File
@@ -142,7 +142,7 @@ class TestLoggerd:
Params().put("RecordFront", "1")
d = DEVICE_CAMERAS[("tici", "ar0231")]
expected_files = {"rlog", "qlog", "qcamera.ts", "fcamera.hevc", "dcamera.hevc", "ecamera.hevc"}
expected_files = {"rlog.zst", "qlog.zst", "qcamera.ts", "fcamera.hevc", "dcamera.hevc", "ecamera.hevc"}
streams = [(VisionStreamType.VISION_STREAM_ROAD, (d.fcam.width, d.fcam.height, 2048*2346, 2048, 2048*1216), "roadCameraState"),
(VisionStreamType.VISION_STREAM_DRIVER, (d.dcam.width, d.dcam.height, 2048*2346, 2048, 2048*1216), "driverCameraState"),
(VisionStreamType.VISION_STREAM_WIDE_ROAD, (d.ecam.width, d.ecam.height, 2048*2346, 2048, 2048*1216), "wideRoadCameraState")]
@@ -229,7 +229,7 @@ class TestLoggerd:
random.sample(no_qlog_services, random.randint(2, min(10, len(no_qlog_services))))
sent_msgs = self._publish_random_messages(services)
qlog_path = os.path.join(self._get_latest_log_dir(), "qlog")
qlog_path = os.path.join(self._get_latest_log_dir(), "qlog.zst")
lr = list(LogReader(qlog_path))
# check initData and sentinel
@@ -255,7 +255,7 @@ class TestLoggerd:
services = random.sample(CEREAL_SERVICES, random.randint(5, 10))
sent_msgs = self._publish_random_messages(services)
lr = list(LogReader(os.path.join(self._get_latest_log_dir(), "rlog")))
lr = list(LogReader(os.path.join(self._get_latest_log_dir(), "rlog.zst")))
# check initData and sentinel
self._check_init_data(lr)

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