21 Commits

Author SHA1 Message Date
brianhansonxyz 119d412c24 docs: park-mode power savings retro
Captures the design we tried on 2026-05-04, the bugs we hit, and
recommendations for v2. Force-pushed the failed attempt away from
origin/clearpilot so the commits aren't recoverable from the remote;
this document is the durable record of what was learned.

Key takeaways for v2:
- Throttle modeld/dmonitoringmodeld instead of killing them — the
  cold-spawn chain (modeld -> plannerd/frogpilot_process publishing
  longitudinalPlan/frogpilotPlan, plus locationd/sensord/etc. settling)
  is the root cause of the alert cascade.
- card.initialize() must run before park-mode is entered (it wires
  up CarController so controls_update actually generates CAN sends).
- NO_ENTRY alerts fire on engage attempt, not on engage success — any
  alert-suppression grace must key off CS.cruiseState.enabled rising
  edge, not just self.enabled.
- The fan-range widening piece (parked -> 0-100% fan range, no floor)
  is independently safe to land without the rest of the park-mode
  plumbing.
2026-05-04 20:10:57 -05:00
brianhansonxyz 0d1ceddad2 ui: restore ready_text.png splash sprite
ready.cc:75 loads /data/openpilot/selfdrive/clearpilot/theme/clearpilot/images/ready_text.png
to render the 'ready' text on the splash, but the asset never got copied
during the C++ UI port (b5a0b32). isNull() check meant it just silently drew
nothing. Copied verbatim from the broken tree.
2026-05-04 19:07:54 -05:00
brianhansonxyz 20ea43f317 nightrider: render lane-change UI (was hidden by disengaged-skip)
During a lane change controlsd writes no_lat_lane_change=true; OnroadWindow
forces edgeColor to STATUS_DISENGAGED so the bg color flips to the disengaged
hue. drawLaneLines's nightrider early-return ("hide all when disengaged")
was matching that and skipping the entire frame, so nightrider showed nothing
during the lane change.

Fixes:
- Hoist is_no_lat_lane_change above the early-return.
- Skip the early-return during lane change, so lane lines + road edges +
  blind-spot path still render in nightrider while the maneuver is active
  (matching how nightrider looks when normally engaged).
- In the outline-only track-polygon branch: when in lane change, draw the
  track as a 4 px outline of CHANGE_LANE_PATH_COLOR (the same yellow used
  to fill the polygon in normal mode) instead of the usual 3 px light-blue
  guide. Hollow shape, thicker stroke — matches Brian's spec.

Normal-mode rendering is unchanged.
2026-05-04 19:07:54 -05:00
brianhansonxyz f6516eb4cc CLAUDE.md: bring up to date with current state
Reorganized 'Current State' to enumerate what's actually active in the
tree now (boot/build infra, suppressed logging, gpsd, UI port, display
modes, speed_logicd, sound, dashcamd) instead of the brief summary of
just the early commits.

Trimmed 'Pending' to remove items that are now ported (UI, gpsd, sound,
speed_logic, display modes, dashcamd, memory-param scaffolding). Kept
the still-pending items: HDA2 driving-behavior tweaks, CarSpeedLimit
publisher, telemetry, bench mode, power/thermal, session logging.

Notes added:
- Memory-param keys currently registered (so the next port doesn't
  re-register existing keys by accident)
- camerad gating change to always_run (and the power tradeoff)
- Branch policy: clearpilot is the canonical/main branch; do not
  abandon it for another
- pkill _text by comm in the launch chain
- speed-limit widget shows 0 until carstate.py CAN-FD writes
  CarSpeedLimit
2026-05-03 23:19:41 -05:00
brianhansonxyz 8a7a776f9b port dashcamd: hardware-encoded MP4 dashcam
VisionIPC frames from camerad → OMX H.264 hardware encoder → 3-min MP4
segments + SRT GPS subtitles in /data/media/0/videos/<trip>/. Manages
its own trip lifecycle (WAITING/RECORDING/IDLE_TIMEOUT) and writes
DashcamState/DashcamFrames memory params for the UI's Status window.
Honors DashcamShutdown for graceful close before power-off.

Files added:
- selfdrive/clearpilot/dashcamd.cc + SConscript

Files modified:
- selfdrive/frogpilot/screenrecorder/omx_encoder.{cc,h}: ported broken's
  version, which adds encode_frame_nv12() (direct NV12 input from camerad,
  alongside the existing encode_frame_rgba used by the disabled screen
  recorder) and simplifies the libyuv conversion paths to NEON-only since
  this device is aarch64.
- selfdrive/SConscript: register selfdrive/clearpilot/SConscript so the
  dashcamd binary is part of the build.
- selfdrive/manager/process_config.py:
  - camerad gating driverview → always_run so dashcamd can record the
    moment ignition+drive arrives without waiting for camera startup.
  - Register dashcamd as NativeProcess gated always_run.
- system/loggerd/deleter.py:
  - MIN_BYTES 5 GB → 9 GB to leave headroom for dashcam footage.
  - delete_oldest_video(): trip-aware cleanup. Drops entire oldest trip
    dir first; if only the active trip remains, drops oldest segment
    inside it; cleans up legacy flat .mp4s too.
  - cleanup_log2(): keeps /data/log2 session logs under 4 GB total.
  - Hooked into deleter_thread: video first when out of bytes/percent;
    log2 quota check on the idle path. New code uses print(stderr) per
    the no-cloudlog rule.

Verified: built clean, manager started, dashcamd in WAITING state
(DashcamState=waiting, DashcamFrames=0), camerad running, no errors.
2026-05-03 23:14:23 -05:00
brianhansonxyz 3f5172b58b controlsd: 5-state ScreenDisplayMode machine + park->drive auto-wake
Replaces the 3-state cycle in clearpilot_state_control with broken's
5-state machine:
- Onroad (drive gear): 0→4, 1→2, 2→3, 3→4, 4→2 (auto modes never
  reached via the button — gpsd's day/night calc is the only path back)
- Not in drive: anything except 3 → 3 (screen off), state 3 → 0 (auto)

Also tracks park→drive edge to auto-wake from screen-off (mode 3 → 0)
when shifting into drive, regardless of how the screen got turned off.

Speed/cruise overlay state intentionally left out — owned by
speed_logicd, not controlsd.

events.py: remove clp_debug_notice + EventName.clpDebug binding
(no more "Clearpilot Debug Function Executed (N)" on-screen message).
The dead commented-out events.add(EventName.clpDebug) and stray print
of buttonEvents in controlsd are also cleaned up.
2026-05-03 23:06:57 -05:00
brianhansonxyz b5a0b3221c port C++ UI from broken: ready/splash, ClearPilot menu, onroad widgets, nightrider
Wholesale port of the 10 UI files (main.cc, ui.{cc,h}, onroad.{cc,h},
home.{cc,h}, window.{cc,h}, ready.{cc,h}, SConscript). sidebar.{cc,h}
unchanged.

Brings in:
- splash/ready screen rendered via Qt directly (replaces stock home)
- ready page shown when started but gear=park
- ClearPilot offroad menu (Home/Dashcam/Debug panels) replacing stock
- onroad UI: speed widget reading ClearpilotSpeedDisplay (gpsLocation
  via speed_logicd), speed-limit widget, cruise-vs-limit warning sign
- nightrider mode: camera suppressed, lane lines/path drawn as 2px
  outlines only (ScreenDisplayMode 1 or 4)
- screen power: ScreenDisplayMode 3 forces setAwake(false)
- ignition off blanks screen immediately (tap still wakes)
- Qt-based RPC widget-tree dump server at ipc:///tmp/clearpilot_ui_rpc
- crash handler in main.cc with stack trace

Deviation from broken (3 sites): no_lat_lane_change is read from
paramsMemory (controlsd writes it there in baseline) instead of broken's
custom cereal field frogpilotCarControl.noLatLaneChange. Keeps the
existing self-driving wiring intact.

SConscript drops screenrecorder.cc from qt_src (broken did the same;
omx_encoder.cc still built for dashcamd's future link).

Build clean. UI hasn't been launched yet — that comes after the
controlsd button-handler commit lands.

Translation .ts files are auto-regenerated by Qt's lupdate; included.
2026-05-03 23:03:42 -05:00
brianhansonxyz 41c154014a add speed_logic daemon: write speed + cruise warning display params
Standalone managed process (selfdrive.clearpilot.speed_logicd) that
ticks SpeedState at 2 Hz from cereal subscriptions. Decoupled from
controlsd so self-driving timing isn't affected.

Inputs:
- gpsLocation.speed + hasFix (vehicle speed)
- carState.cruiseState (cruise speed, enabled, standstill)
- CarSpeedLimit memory param (will be populated when carstate.py CAN-FD
  decode is ported; 0 until then — speed-limit + warning logic
  naturally short-circuits)
- IsMetric persistent param (read once at startup)

Outputs (memory params, gated on change to avoid 2 Hz tmpfs churn):
- ClearpilotSpeedDisplay, ClearpilotHasSpeed, ClearpilotSpeedUnit
- ClearpilotSpeedLimitDisplay, ClearpilotIsMetric
- ClearpilotCruiseWarning, ClearpilotCruiseWarningSpeed
- ClearpilotPlayDing (one-shot trigger consumed by soundd)

speed_logic.py copied verbatim from broken; speed_logicd.py is new
glue. Registered as PythonProcess gated on only_onroad.
2026-05-03 22:52:39 -05:00
brianhansonxyz 5d2fe5248b soundd: mix ClearPilot ding alongside alerts; add ding.wav
Adds the ding sound effect that fires on speed-limit changes / cruise-
warning transitions (writers will set ClearpilotPlayDing="1" in
/dev/shm/params; soundd polls at ~2Hz, clears the flag, plays once).

The ding plays at MAX_VOLUME independent of the alert volume map and
mixes into the same output stream. Single-shot — no looping. Loaded
once at startup; failure to load just disables the ding (rest of soundd
keeps working).

print-to-stderr, not cloudlog (CLAUDE.md rule).
2026-05-03 22:50:46 -05:00
brianhansonxyz f687d712e7 gpsd: re-add day/night auto display-mode switch
Restores the IsDaylight + ScreenDisplayMode auto-switch logic that was
stripped during the initial gpsd port (since the display-modes feature
hadn't been touched yet).

NOAA solar-position calc against the current GPS fix:
- First calc immediately when system clock is valid + GPS has fix
- Every 30s thereafter
- Writes IsDaylight memory param on change (twice/day, gated)
- ScreenDisplayMode 0 + sunset → 1 (auto-nightrider)
- ScreenDisplayMode 1 + sunrise → 0 (auto-normal)
- Manual modes 2/3/4 are never touched

Print-to-stderr instead of cloudlog per CLAUDE.md.
2026-05-03 22:47:28 -05:00
brianhansonxyz 837c14e081 register clearpilot memory params and seed defaults in manager_init
Scaffolding for the upcoming UI port. Registers the keys the new C++
UI and SpeedState daemon will read/write, and seeds /dev/shm/params
defaults at manager start so first-readers don't see missing keys
before writers spin up.

Keys registered: CarIsMetric, ClearpilotCruiseWarning,
ClearpilotCruiseWarningSpeed, ClearpilotHasSpeed, ClearpilotIsMetric,
ClearpilotPlayDing, ClearpilotShowHealthMetrics,
ClearpilotSpeedDisplay, ClearpilotSpeedLimitDisplay,
ClearpilotSpeedUnit, DashcamFrames, DashcamShutdown, DashcamState,
IsDaylight, ModelFps, ModelStandby, ModelStandbyTs,
ScreenRecorderDebug, ShutdownTouchReset, TelemetryEnabled, VpnEnabled.

PERSISTENT registration here is purely a no-op placeholder: the actual
storage is /dev/shm/params (tmpfs), which clears on every reboot
regardless. Bench-mode keys (Bench*, ClpUiState, LogDirInitialized)
not registered yet — they'll come with their respective features.
2026-05-03 22:45:04 -05:00
brianhansonxyz 3ebfc29d35 port clearpilot gpsd; decouple self-driving from GPS
Adds the AT-command-based GPS daemon for the Quectel EC25 modem (the
device has no u-blox chip and qcomgpsd's diag interface hangs on this
hardware). Trimmed from broken's version: dropped cloudlog calls and
the IsDaylight / ScreenDisplayMode auto-switching (those belong to the
display-modes feature, port later).

Used solely for system clock initialization, on-screen UI speed, and
per-segment dashcam GPS metadata.

Self-driving must NOT consume gpsLocation — feeding it to locationd's
kalman filter screws up the math. Patch locationd to skip GPS:
- locationd_thread() no longer subscribes to gpsLocation/gpsLocationExternal
- handle_msg's GPS branches commented (dead code without subscription)
- the "save LastGPSPosition once a minute when gpsOK" block commented
  (dead because gpsOK is now permanently false)

Result: liveLocationKalman.gpsOK = false for all self-driving consumers
(controlsd, paramsd, torqued, frogpilot_planner). They already handle
that case. Other liveLocationKalman fields still publish from the
camera-odometry + IMU + calibration kalman state.

system/clearpilot/__init__.py added so system.clearpilot.gpsd is a
valid Python module.
2026-05-03 22:29:07 -05:00
brianhansonxyz 54c566c68f kill stale text-error window by comm too, not just path
selfdrive/ui/text is a shell wrapper that execs ./_text. After exec,
the running process's argv has no path component, so
pkill -f 'selfdrive/ui/text' silently misses it. Add pkill -x _text
alongside the existing path-pattern kills in build_only.sh,
launch_openpilot.sh, and launch_chffrplus.sh.
2026-05-03 22:28:33 -05:00
brianhansonxyz f28ba340f2 disable segment + camera + boot data logging
We don't use comma's upload/replay pipeline, and the segment recorder
was silently filling /data with 30 MB rlog files per minute (the 64 GB
we just cleared). Disable the writers entirely.

- process_config.py: comment out loggerd, encoderd, stream_encoderd
- manager.py: skip save_bootlog() at manager init (was writing
  boot info to /data/media/0/realdata/boot/<bootid>/)

deleter still runs for cleanup of any leftover data; logmessaged still
runs (in-memory log routing IPC). uploader was already disabled in
baseline. No process consumes loggerd/encoderd output onroad, so this
is purely a sink removal.
2026-05-03 22:13:06 -05:00
brianhansonxyz 6ec4c7bdac controlsd: ScreenDisplayMode init uses put_int, not put_bool
Every other reference treats ScreenDisplayMode as an int (range 0-4).
The init line was using put_bool(0) which happened to write the same
"0" string and read back fine via get_int, but the type mismatch was
misleading.
2026-05-03 22:08:08 -05:00
brianhansonxyz b57f2d8d70 add CLAUDE.md documenting current state, snapshot locations, and port roadmap
Records: where the broken-but-feature-complete tree lives
(/data/openpilot-broken-2026-05-03 + tag pre-reset-2026-05-03), where
the baseline source still sits (/data/clearpilot-baseline), the
working-baseline-2 tag, and a categorized roadmap of features in the
broken tree that still need to be ported (driving behavior, onroad UI,
speed/cruise logic, dashcamd, gpsd, telemetry, bench mode, power/
thermal, memory params, session logging).

Carries forward the operational guardrails from the previous CLAUDE.md
(no cloudlog, chown to comma, samba/git/test workflow, params/cereal
gotchas, device specifics) so future sessions don't re-learn them.
2026-05-03 21:58:42 -05:00
brianhansonxyz b287fd094e make baseline build & launch cleanly
- onroad.cc: fix screenDisplayMode reference to nvg->screenDisplayMode
  (baseline had a stale reference to the variable after it moved into
  AnnotatedCameraWidget). Restores the original conditional intent.
- ui/SConscript + home.cc: drop QtWebEngine include/link entirely
  (no longer used by any active code).
- build.py: BUILD_ONLY env var spawns the failure TextWindow fully
  detached (own session, /dev/null stdio) so build_only.sh exits and
  caller can capture stderr; spinner binary update uses temp+os.replace
  so a running spinner doesn't ETXTBSY the build.
- build_only.sh: tee build output to /tmp/build.log and propagate
  build.py's exit code via PIPESTATUS.

Verified: build_only.sh completes cleanly, launch_openpilot.sh boots
the manager and spawns the standard process set.
2026-05-03 21:55:48 -05:00
brianhansonxyz 5624898a92 port startup-related changes from broken tree
Restores the boot/launch chain customizations on top of the freshly-reset
baseline. Driving-model and per-feature changes (dashcamd, telemetry, gpsd,
bench mode, manager wiring) are deliberately left out and will be ported
piecemeal.

Brought in:
- launch_openpilot.sh: kill stale instances, run on_start.sh, background
  vpn-monitor + nice-monitor, BENCH_MODE pass-through
- launch_chffrplus.sh: source build_preflight.sh, kill stale text-error UI
- build_only.sh, build_preflight.sh
- system/clearpilot/on_start.sh: SSH keys, ssh.service enable, git.hanson.xyz
  Host config, WiFi radio on, run provision.sh
- system/clearpilot/provision.sh + provision_wrapper.sh: connectivity wait,
  apt install (openvpn, curl, ccrypt, nodejs), Claude Code installer, git
  remote fix, fast-forward origin/clearpilot, /data/quick_boot
- system/clearpilot/vpn-monitor.sh + vpn.ovpn: OpenVPN tunnel auto-connect
- system/clearpilot/nice-monitor.sh: keep claude processes at nice 19
- system/clearpilot/dev: id_ed25519.{cpt,pub.cpt}, GithubSshKeys, encrypt.sh
  (DongleId-keyed instead of hardware-serial)
- system/clearpilot/tools/{decrypt,encrypt}: switch key source to DongleId
- system/clearpilot/startup_logo/{bg.jpg, generate_logo.sh, set_logo.sh}
- selfdrive/ui/qt/spinner{,.cc,.h}: new spinner with logo

Removed (baseline-only flow superseded by broken's on_start.sh+provision.sh):
- system/clearpilot/dev/on_start.sh
- system/clearpilot/dev/on_start_brian.sh.cpt
- system/clearpilot/dev/provision.sh
2026-05-03 21:07:14 -05:00
brianhansonxyz c2ab0fa662 reset to pre-modification baseline; restart feature work from clean state
Restoring the working tree to the pristine pre-Claude baseline previously
preserved at /data/clearpilot (now /data/clearpilot-baseline). The prior
modified-but-broken tree is snapshotted at /data/openpilot-broken-2026-05-03
and tagged here as pre-reset-2026-05-03 for reference.

From here, features (UI changes, dashcam, telemetry, GPS, display modes,
speed logic, standstill power saving, etc.) will be re-introduced one at
a time with proper testing.
2026-05-03 20:53:51 -05:00
brianhansonxyz f7e602c00b controlsd: re-wire UI hooks on top of restored baseline
Adds back the UI plumbing that the baseline controlsd doesn't have, so
the existing UI features keep working without changing driving logic:

- ScreenDisplayMode 5-state machine (auto-normal, auto-nightrider,
  manual normal, screen-off, manual nightrider) driven by the LFA
  debug button + gear edges. Replaces baseline's simple 0..2 cycle.
  Pure params write — no actuator effect.
- Speed/cruise-warning overlay tick at ~2Hz feeding SpeedState, which
  writes ClearpilotSpeedDisplay / ClearpilotSpeedLimitDisplay /
  ClearpilotCruiseWarning for the onroad UI. Reads gpsLocation,
  CarSpeedLimit, and CS.cruiseState — no actuator effect.
- frogpilot_variables.no_lat_lane_change is now populated alongside
  the existing Params write, so the perf-optimized carcontroller (which
  takes the bit as an argument instead of re-reading Params on the
  100Hz hot path) still sees the lane-change suppression signal.
- ScreenDisplayMode init switched from put_bool to put_int (UI reads
  it as int).
- gpsLocation added to SubMaster (ignore_alive/avg_freq/valid set,
  since gpsd is a ClearPilot addition not present everywhere).

No changes to controlsd's lateral or longitudinal control paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 08:44:52 -05:00
brianhansonxyz 47321e3867 restore driving logic to pre-variable-fps baseline
Wholesale revert of driving-relevant files to the snapshot in
/projects/openpilot/archive/clearpilot (HEAD 980f0aa). Goal: get
known-good driving behavior back, then re-introduce optimizations
slowly to track down a "feels like the wheel pulls right" regression.

Files restored from baseline:
- selfdrive/controls/controlsd.py
- selfdrive/controls/lib/events.py
- selfdrive/controls/lib/longitudinal_planner.py
- selfdrive/modeld/modeld.py
- selfdrive/modeld/dmonitoringmodeld.py
- selfdrive/locationd/calibrationd.py
- selfdrive/locationd/paramsd.py
- selfdrive/locationd/torqued.py
- selfdrive/car/interfaces.py
- selfdrive/car/hyundai/carstate.py (CAN-FD telemetry preserved as a
  commented block for future re-enable)
- selfdrive/monitoring/dmonitoringd.py
- selfdrive/frogpilot/controls/frogpilot_planner.py
- common/realtime.py

Intentionally NOT restored (kept as current):
- selfdrive/thermald/* (fan/power tuning kept)
- selfdrive/car/hyundai/carcontroller.py + hyundaicanfd.py (perf-only
  hoist of no_lat_lane_change Params read; behavior-equivalent)
- cereal/services.py, cereal/custom.capnp (additive only)
- selfdrive/manager/*, common/params.cc (heavy ClearPilot
  infrastructure: bench mode, log dir, dashcamd, gpsd, params)
- All selfdrive/ui/, selfdrive/clearpilot/, system/clearpilot/

UI features will be re-wired in a follow-up commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 08:40:02 -05:00
105 changed files with 995 additions and 7386 deletions
-2
View File
@@ -2,8 +2,6 @@ prebuilt
system/clearpilot/dev/on_start_brian.sh system/clearpilot/dev/on_start_brian.sh
system/clearpilot/dev/id_rsa system/clearpilot/dev/id_rsa
system/clearpilot/dev/id_rsa.pub system/clearpilot/dev/id_rsa.pub
system/clearpilot/dev/id_ed25519
system/clearpilot/dev/id_ed25519.pub
venv/ venv/
.venv/ .venv/
.ci_cache .ci_cache
-29
View File
@@ -1,29 +0,0 @@
# CAN-FD Issues to Investigate
## Cruise Control Desync on Hot Start
### Problem
When the car is already in cruise control mode before openpilot starts (or before controlsd initializes), pressing the cruise control button causes a desync:
1. Car has active cruise control when openpilot comes online
2. Driver presses cruise button — car interprets as "toggle off" (cruise was already on)
3. openpilot interprets it as "engage" (from its perspective, it hasn't seen a cruise enable transition)
4. Result: car disengages cruise, but openpilot thinks it just engaged lateral mode
### Proposed Fix
When controlsd first reads carState and discovers `cruiseState.enabled` is already true:
1. Set a flag `cruise_was_active_at_start = True`
2. While this flag is set, do NOT allow openpilot to transition to engaged state on button press
3. Only clear the flag after seeing `cruiseState.enabled` go to `False` at least once (a full stop of cruise, not just standstill/pause)
4. After the first full off cycle, normal engagement logic resumes
### Status
- Could not reproduce on 2026-04-14 — may require specific timing (openpilot restart while driving with cruise active)
- Need to capture telemetry data during reproduction to see exact signal sequence
- Key telemetry groups to watch: `cruise` (enabled, available, ACCMode, VSetDis), `buttons` (cruise_button)
### Relevant Code
- `selfdrive/controls/controlsd.py` — engagement state machine
- `selfdrive/car/hyundai/carstate.py` — CAN-FD cruise state parsing
- `selfdrive/car/interfaces.py` — pcm_enable / cruise state transitions
+169 -504
View File
@@ -2,27 +2,115 @@
## Project Overview ## Project Overview
ClearPilot is a custom fork of **FrogPilot** (itself a fork of comma.ai's openpilot), based on a 2024 release. It is purpose-built for Brian Hanson's **Hyundai Tucson** (HDA2 equipped). The vehicle's HDA2 system has specific quirks around how it synchronizes driving state with openpilot that require careful handling. ClearPilot is a custom fork of **FrogPilot** (itself a fork of comma.ai's openpilot), purpose-built for Brian Hanson's **Hyundai Tucson** (HDA2 equipped). The vehicle's HDA2 system has specific quirks around how it synchronizes driving state with openpilot that require careful handling.
### Key Customizations in This Fork The fork was previously in a state where many features were layered on top but the driving model behavior had regressed in ways that couldn't be traced. On **2026-05-03** the working tree was reset back to a known-clean baseline so features can be re-introduced one at a time with proper testing. Most non-driving-math features have since been ported back.
- **UI changes** to the onroad driving interface ## Current State
- **Lane change behavior**: brief disengage when turn signal is active during lane changes
- **Lateral control disabled**: the car's own radar cruise control handles lateral; openpilot handles longitudinal only
- **Driver monitoring timeouts**: modified safety timeouts for the driver monitoring system
- **Custom driving models**: `duck-amigo.thneed`, `farmville.onnx`, `wd-40.thneed` in `selfdrive/clearpilot/models/`
- **ClearPilot service**: Node.js service at `selfdrive/clearpilot/` with behavior scripts for lane change and longitudinal control
- **Native dashcamd**: C++ process capturing raw camera frames via VisionIPC with OMX H.264 hardware encoding
- **Standstill power saving**: model inference throttled to 1fps and fan quieted when car is stopped
- **ClearPilot menu**: sidebar settings panel replacing stock home screen (Home, Dashcam, Debug panels)
- **Status window**: live system stats (temp, fan, storage, RAM, WiFi, VPN, GPS, telemetry, dashcam status)
- **Debug button (LFA)**: steering wheel button repurposed for screen toggle and future UI actions
- **Telemetry system**: diff-based CSV logger via ZMQ IPC, toggleable from Debug panel
- **Bench mode**: `--bench` flag for onroad UI testing without car connected
- **GPS**: custom AT-command based GPS daemon (`system/clearpilot/gpsd.py`) replacing broken qcomgpsd diag interface
- **OpenVPN tunnel**: auto-connecting VPN to expose device on remote network for SSH access
See `GOALS.md` for feature roadmap. `build_only.sh` succeeds and `launch_openpilot.sh` boots the manager. The following customizations are active in this tree:
**Boot / build / device infra**
- launch chain (`launch_openpilot.sh`, `launch_chffrplus.sh`) with stale-process kill (including `_text` by comm), `on_start.sh` SSH/WiFi setup, OpenVPN auto-connect (`vpn-monitor.sh` + `vpn.ovpn`), `nice-monitor.sh`, `build_only.sh` + `build_preflight.sh`
- DongleId-keyed dev SSH identity (`system/clearpilot/dev/id_ed25519.{cpt,pub.cpt}` + `tools/{encrypt,decrypt}`)
- Custom startup logo (`bg.jpg`) + custom Qt spinner (`selfdrive/ui/qt/spinner{,.cc,.h}`) — `build.py` atomically swaps the prebuilt spinner binary after each successful build
- `BUILD_ONLY=1` env path in `build.py` spawns the failure TextWindow fully detached (own session, /dev/null stdio) so `build_only.sh` exits with a non-blocking error window
**Logging suppressed**
- `loggerd`, `encoderd`, `stream_encoderd` disabled in `process_config.py` — no `rlog`/`qlog` segments or `.hevc` files written to `/data/media/0/realdata/`
- `save_bootlog()` skipped in `manager_init()` — no boot logs
**GPS (Quectel modem replacement)**
- `system/clearpilot/gpsd.py` polls Quectel EC25 modem via `mmcli` AT commands at 2 Hz, publishes `gpsLocation`, sets system clock on first fix
- NOAA solar-position calc → `IsDaylight` memory param + auto `ScreenDisplayMode` 0↔1 switch (sunrise/sunset)
- **`locationd` patched to NOT subscribe to GPS** — `liveLocationKalman.gpsOK` stays false permanently. Self-driving sees GPS as not-present; downstream consumers (controlsd, paramsd, torqued, frogpilot_planner) handle that case naturally. GPS data is still published and used by speed_logicd / UI / dashcamd, just kept out of the kalman filter.
**UI (full C++ port)**
- New ready/splash screen rendered by Qt directly; shown when started but gear=park
- ClearPilot offroad menu (Home / Dashcam / Debug panels) replacing the stock home — Status window with live system stats (temp, fan, storage, RAM, WiFi, VPN, GPS, telemetry, dashcam)
- Onroad widgets: speed (from `gpsLocation` via `speed_logicd`), speed-limit, cruise-vs-limit warning sign
- Nightrider mode: camera suppressed, lane lines/path drawn as 2px outlines (`ScreenDisplayMode` 1 or 4)
- Display power: `ScreenDisplayMode` 3 → screen off; ignition off blanks immediately
- Qt RPC widget-tree dump server at `ipc:///tmp/clearpilot_ui_rpc`
- Crash handler in `main.cc` with stack-trace dump for SIGSEGV/SIGABRT
- `screenDisplayMode` is a member of `AnnotatedCameraWidget`, accessed from `OnroadWindow::updateState` as `nvg->screenDisplayMode`
- QtWebEngine dependency removed entirely
**Display modes (LFA debug button)**
- 5-state `ScreenDisplayMode` machine in `controlsd.clearpilot_state_control()`:
- Drive: 0→4, 1→2, 2→3, 3→4, 4→2 (button never goes back to auto)
- Not drive: anything except 3 → 3 (off), 3 → 0 (auto)
- Auto-wake from screen-off (mode 3 → 0) on park→drive edge
- "Clearpilot Debug Function Executed" alert removed (`clp_debug_notice` and its event registration deleted from `events.py`)
**Speed / cruise**
- `speed_logicd` standalone managed process (`selfdrive/clearpilot/speed_logicd.py` wrapping `speed_logic.SpeedState`) — subscribes to `gpsLocation` + `carState`, ticks at 2 Hz, writes `Clearpilot{Speed,SpeedLimit,CruiseWarning,...}Display` memory params
- Cruise-vs-limit warning thresholds: +10 over (limit ≥ 50), +7 over (26-49), +9 over (≤ 25); -5 under
- On warning transitions / speed-limit change: writes `ClearpilotPlayDing="1"` (consumed by soundd)
- Decoupled from `controlsd` so self-driving timing is unaffected
- **Note**: speed-limit widget shows 0 until `CarSpeedLimit` publisher in `hyundai/carstate.py` CAN-FD decode is ported (not done yet). Speed widget works.
**Sound**
- `soundd.py` mixes a single-shot ding alongside the alert stream (`MAX_VOLUME`, independent of alert volume map). Polls `ClearpilotPlayDing` at ~2 Hz, clears on read. `selfdrive/clearpilot/sounds/ding.wav` is the asset.
**Dashcam**
- `selfdrive/clearpilot/dashcamd` (native C++) — VisionIPC frames from camerad → OMX H.264 hardware encoder → 3-min MP4 segments + SRT GPS subtitle sidecars in `/data/media/0/videos/<trip>/`
- Trip lifecycle (WAITING → RECORDING → IDLE_TIMEOUT). 10-min idle close from drive→park; immediate close on ignition off; graceful close on `DashcamShutdown`
- Publishes `DashcamState` ("waiting"/"recording"/"stopped") and `DashcamFrames` (per-trip count) every 5 s
- `omx_encoder.cc` ports broken's version (adds `encode_frame_nv12()`, NEON-only libyuv paths)
- **`camerad` gating changed to `always_run`** so the dashcam can record the moment ignition+drive arrives without waiting for camera startup
- `system/loggerd/deleter.py` trip-aware cleanup: drops oldest entire trip dir first, falls back to oldest segment within active trip; also enforces 4 GB cap on `/data/log2`
## Where the Old Code Lives
| Location | What it is |
|---|---|
| `/data/openpilot/` | This repo. **Active.** |
| `/data/openpilot-broken-2026-05-03/` | Full snapshot (with `.git`) of the prior modified-but-broken tree. Reference for porting features. |
| `/data/clearpilot-baseline/` | The original baseline source we copied in. Kept for safety; do not modify. |
| `/data/openpilot-features-broken/` | Pre-existing snapshot from an earlier reset attempt — **unverified**, leave alone. |
| Tag | Commit | What |
|---|---|---|
| `pre-reset-2026-05-03` | `f7e602c` | Last commit of the pre-reset broken-but-feature-complete tree. |
| `working-baseline-2` | `b287fd0` | First commit after the reset where the bare baseline built and launched. |
Both tags are pushed to `origin/clearpilot`.
## Pending Feature Port Roadmap
Items still in `/data/openpilot-broken-2026-05-03/` that haven't been ported. Port in small, testable batches.
**Driving behavior (HDA2 specifics)** — these touch self-driving code and warrant extra scrutiny:
- Lateral disabled (car's radar cruise handles steering; openpilot longitudinal only)
- Brief disengage when turn signal is active during lane changes (note: `no_lat_lane_change` infrastructure already wired through `controlsd``paramsMemory` → UI/canfd, but the actual disengage trigger may need work)
- Driver-monitoring timeout adjustments
- Custom driving models — model files (`duck-amigo.thneed`, `farmville.onnx`, `wd-40.thneed`) live in `selfdrive/clearpilot/models/`; selection logic not ported
**Speed-limit publisher**
- `hyundai/carstate.py update_canfd()` writes `CarSpeedLimit` from CAN — until ported, the speed-limit widget shows 0 and cruise warnings never trigger
**Telemetry**
- `selfdrive/clearpilot/telemetry.py` (client) + `telemetryd.py` (collector) — diff-based CSV logger over ZMQ
- Toggleable via `TelemetryEnabled` memory param from Debug panel
- Auto-disabled if `/data` free < 5 GB; auto-disabled on every manager start
- Hyundai CAN-FD data logged from `update_canfd()` groups (car/cruise/speed_limit/buttons)
**Bench mode (UI testing without a car)**
- `--bench` flag → `BENCH_MODE=1` in `launch_openpilot.sh` (already wired) → enables `bench_onroad.py`, blocks real car processes
- `bench_cmd.py` for setting fake vehicle state via params; UI dump RPC wired (`bench_cmd dump`)
- Param keys (`Bench*`, `ClpUiState`) not yet registered
**Power/thermal**
- Standstill power saving: `modeld` and `dmonitoringmodeld` throttled to 1 fps when stopped
- Fan controller uses offroad clamps at standstill
- Park CPU savings + virtual battery shutdown fix
**Session logging**
- `/data/log2/current/` per-process stderr capture; aggregate `session.log` of major events
- Time-resolved log dir rename via GPS/NTP; 30-day rotation
- See `selfdrive/manager/process.py` and `manager.py` changes in the broken tree
- `LogDirInitialized` param not yet registered
## Working Rules ## Working Rules
@@ -41,12 +129,11 @@ This is self-driving software. All changes must be deliberate and well-understoo
**NEVER use `cloudlog`.** It's comma.ai's cloud telemetry pipeline, not ours — writes go to a publisher that's effectively a black hole for us (and the only thing it could do if ever reachable is bother the upstream FrogPilot developer). Our changes must always use **file logging** instead. **NEVER use `cloudlog`.** It's comma.ai's cloud telemetry pipeline, not ours — writes go to a publisher that's effectively a black hole for us (and the only thing it could do if ever reachable is bother the upstream FrogPilot developer). Our changes must always use **file logging** instead.
Use `print(..., file=sys.stderr, flush=True)`. `manager.py` redirects each managed process's stderr to `/data/log2/current/{process}.log`, so these lines land in the per-process log we already grep. Prefix custom log lines with `CLP ` so they're easy to filter out from upstream noise. Use `print(..., file=sys.stderr, flush=True)`. Once session-logging is re-ported, manager will redirect each managed process's stderr to `/data/log2/current/{process}.log`. Prefix custom log lines with `CLP ` so they're easy to filter from upstream noise.
Example:
```python ```python
import sys import sys
print(f"CLP frogpilotPlan valid=False: carState_freq_ok={sm.freq_ok['carState']}", file=sys.stderr, flush=True) print(f"CLP gpsd: ...", file=sys.stderr, flush=True)
``` ```
Do not use `cloudlog.warning`, `cloudlog.info`, `cloudlog.error`, `cloudlog.event`, or `cloudlog.exception` in any CLEARPILOT-added code. Existing upstream/FrogPilot `cloudlog` calls can stay untouched. Do not use `cloudlog.warning`, `cloudlog.info`, `cloudlog.error`, `cloudlog.event`, or `cloudlog.exception` in any CLEARPILOT-added code. Existing upstream/FrogPilot `cloudlog` calls can stay untouched.
@@ -62,8 +149,9 @@ chown -R comma:comma /data/openpilot
### Git ### Git
- Remote: `git@git.hanson.xyz:brianhansonxyz/clearpilot.git` - Remote: `git@git.hanson.xyz:brianhansonxyz/clearpilot.git`
- Branch: `clearpilot` - Branch: `clearpilot` — this is the canonical/main branch and is what fresh device flashes provision from. **Do not abandon it for another branch.**
- Large model files are tracked in git (intentional — this is a backup) - Large model files are tracked in git (intentional — this is a backup)
- The `clearpilot` branch was force-pushed on 2026-05-03 as part of the reset; the prior history is reachable via the `pre-reset-2026-05-03` tag.
### Samba Share ### Samba Share
@@ -76,526 +164,103 @@ chown -R comma:comma /data/openpilot
### Testing Changes ### Testing Changes
Always use `build_only.sh` to compile, then start the manager separately. Never compile individual targets with scons directly — always use the full build script. Always use full paths with `su - comma` — the login shell drops into `/home/comma` (volatile tmpfs), not `/data/openpilot`. **Always start the manager after a successful build** — don't wait for the user to ask. Use `build_only.sh` to compile, then start the manager separately. Never compile individual targets with scons directly — always use the full build script. Always start the manager after a successful build — don't wait for the user to ask.
```bash ```bash
# 1. Fix ownership (we edit as root, openpilot runs as comma) # 1. Fix ownership
chown -R comma:comma /data/openpilot chown -R comma:comma /data/openpilot
# 2. Build (kills running manager, removes prebuilt, compiles, exits) # 2. Build (kills running manager, removes prebuilt, compiles, exits)
# Shows progress spinner on screen. On failure, shows error on screen # build_only.sh tees output to /tmp/build.log and propagates the build's
# and prints to stderr. Does NOT start the manager. # exit code via PIPESTATUS. On failure: error text window stays on screen
# fully detached; the script exits non-zero and stderr has the compile error.
su - comma -c "bash /data/openpilot/build_only.sh" su - comma -c "bash /data/openpilot/build_only.sh"
# 3. If build succeeded ($? == 0), start openpilot # 3. If build succeeded ($? == 0), start openpilot
su - comma -c "bash /data/openpilot/launch_openpilot.sh" su - comma -c "bash /data/openpilot/launch_openpilot.sh"
# 4. Review the aggregate session log for errors # 4. Inspect logs
cat /data/log2/current/session.log
# 5. Check per-process stdout/stderr logs if needed
ls /data/log2/current/ ls /data/log2/current/
cat /data/log2/current/gpsd.log cat /data/log2/current/session.log
tail /tmp/build.log # last build's output
``` ```
### Changing a Service's Publish Rate
SubMaster's `freq_ok` check requires observed rate to fall within
`[0.8 × min_freq, 1.2 × max_freq]` of the value declared in
`cereal/services.py`. Publishing *faster* than declared fails the check
just as surely as publishing too slowly — it trips `all_freq_ok()`
`EventName.commIssue` → "TAKE CONTROL IMMEDIATELY / Communication Issue
Between Processes".
If you change how often a process publishes, you **must** update the rate
in `cereal/services.py` to match. Example (real bug we hit):
- Bumped thermald from 2Hz → 4Hz (DT_TRML 0.5→0.25) for faster fan control
- Bumped gpsd from 1Hz → 2Hz
- manager publishes `managerState` gated by `sm.update()` returning on
`deviceState`, so it picks up thermald's rate automatically
`services.py` still declared `deviceState` and `managerState` as 2Hz
(ceiling 2.4Hz) and `gpsLocation` as 1Hz (ceiling 1.2Hz), so controlsd
fired `commIssue` on every cycle the moment any of these arrived at the
new faster rate.
Fix: update the second tuple element (Hz) in `cereal/services.py` for the
affected service. Cereal will use the updated rate for all consumers.
### Adding New Params ### Adding New Params
The params system uses a C++ whitelist. Adding a new param name in `manager.py` alone will crash with `UnknownKeyName`. You must: The params system uses a C++ whitelist. Adding a new param name without registering it will crash with `UnknownKeyName`. To add one:
1. Register the key in `common/params.cc` (alphabetically, with `PERSISTENT` or `CLEAR_ON_*` flag) 1. Register the key in `common/params.cc` (alphabetically, with `PERSISTENT` or `CLEAR_ON_*` flag)
2. Add the default value in `selfdrive/manager/manager.py` in `manager_init()` 2. For memory params, add a default in `manager_init()`'s memory-params loop (after the persistent default loop)
3. Remove `prebuilt`, `common/params.o`, and `common/libcommon.a` to force rebuild 3. Remove `prebuilt`, `common/params.o`, and `common/libcommon.a` to force rebuild
### Memory Params (paramsMemory) ### Memory Params (paramsMemory)
ClearPilot uses memory params (`/dev/shm/params/d/`) for UI toggles that should reset on boot. Key rules: ClearPilot uses memory params (`/dev/shm/params/d/`) for transient state that should reset on boot. Conventions:
- **Registration**: Register the key in `common/params.cc` as `PERSISTENT` (same as FrogPilot pattern — the registration flag does NOT control which path the param lives at) - **Registration**: register in `common/params.cc` as `PERSISTENT` (the registration flag does NOT control which path the param lives at`/dev/shm` is tmpfs and clears on reboot regardless)
- **C++ access**: Use `Params{"/dev/shm/params"}` — stored as a class member `paramsMemory` in onroad.h. Do NOT use `Params("/dev/shm/params/d")` — the Params class appends `/d/` internally, so that would resolve to `/dev/shm/params/d/d/` - **C++ access**: `Params{"/dev/shm/params"}` (the Params class appends `/d/` internally — `Params("/dev/shm/params/d")` would resolve to `/dev/shm/params/d/d/`)
- **Python access**: Use `Params("/dev/shm/params")` - **Python access**: `Params("/dev/shm/params")`
- **Defaults**: Set in `manager_init()` via `Params("/dev/shm/params").put(key, value)` - **UI toggles**: use `ToggleControl` with manual `toggleFlipped` lambda, not `ParamControl` (which only handles persistent params)
- **UI toggles**: Use `ToggleControl` with manual `toggleFlipped` lambda that writes via `Params("/dev/shm/params")`. Do NOT use `ParamControl` for memory params — it reads/writes persistent params only - **IMPORTANT — method names differ between C++ and Python**: C++ uses camelCase (`putBool`, `getBool`, `getInt`), Python uses snake_case (`put_bool`, `get_bool`, `get_int`). This is a common source of silent failures.
- **Current memory params**: `TelemetryEnabled` (default "0"), `VpnEnabled` (default "1"), `ModelStandby` (default "0"), `ScreenDisplayMode`, `DashcamState` (default "stopped"), `DashcamFrames` (default "0"), `DashcamShutdown` (default "0")
- **IMPORTANT — method names differ between C++ and Python**: C++ uses camelCase (`putBool`, `getBool`, `getInt`), Python uses snake_case (`put_bool`, `get_bool`, `get_int`). This is a common source of silent failures — the wrong casing compiles/runs but doesn't work.
### Building Native (C++) Processes Currently registered memory-param keys (in `params.cc`): `ScreenDisplayMode`, `CPTLkasButtonAction`, `CarIsMetric`, `Clearpilot{CruiseWarning,CruiseWarningSpeed,HasSpeed,IsMetric,PlayDing,ShowHealthMetrics,SpeedDisplay,SpeedLimitDisplay,SpeedUnit}`, `Dashcam{Frames,Shutdown,State}`, `IsDaylight`, `ModelFps`, `ModelStandby`, `ModelStandbyTs`, `ScreenRecorderDebug`, `ShutdownTouchReset`, `TelemetryEnabled`, `VpnEnabled`, `no_lat_lane_change`. Bench-mode and `LogDirInitialized` keys not registered yet.
- SCons is the build system. Static libraries (`common`, `messaging`, `cereal`, `visionipc`) must be imported as SCons objects, not `-l` flags ### Changing a Service's Publish Rate
- The `--as-needed` linker flag can cause link order issues with static libs — disable it in your SConscript if needed
- OMX encoder object (`omx_encoder.o`) is compiled by the UI build — reference the pre-built `.o` file rather than recompiling (avoids "two environments" scons error)
- `prebuilt` is recreated after every successful build — always remove it before rebuilding
## Bench Mode (Onroad UI Testing) SubMaster's `freq_ok` check requires observed rate to fall within `[0.8 × min_freq, 1.2 × max_freq]` of the value declared in `cereal/services.py`. Publishing *faster* than declared trips `commIssue` just as surely as too slow. If you change how often a process publishes, update the rate in `cereal/services.py` to match.
Bench mode allows testing the onroad UI without a car connected. It runs a fake vehicle simulator (`bench_onroad.py`) as a managed process and disables real car processes (pandad, thermald, controlsd, etc.).
### Usage
**IMPORTANT**: Do NOT use `echo` to write bench params — `echo` appends a newline which causes param parsing to fail silently (e.g. gear stays in park). Always use the `bench_cmd.py` tool.
```bash
# 1. Build first
chown -R comma:comma /data/openpilot
su - comma -c "bash /data/openpilot/build_only.sh"
# 2. Start in bench mode
su - comma -c "bash /data/openpilot/launch_openpilot.sh --bench"
# 3. Wait for UI to be ready (polls RPC every 1s, up to 20s)
su - comma -c "PYTHONPATH=/data/openpilot python3 -m selfdrive.clearpilot.bench_cmd wait_ready"
# 4. Control vehicle state
su - comma -c "PYTHONPATH=/data/openpilot python3 -m selfdrive.clearpilot.bench_cmd gear D"
su - comma -c "PYTHONPATH=/data/openpilot python3 -m selfdrive.clearpilot.bench_cmd speed 20"
su - comma -c "PYTHONPATH=/data/openpilot python3 -m selfdrive.clearpilot.bench_cmd speedlimit 45"
su - comma -c "PYTHONPATH=/data/openpilot python3 -m selfdrive.clearpilot.bench_cmd cruise 55"
su - comma -c "PYTHONPATH=/data/openpilot python3 -m selfdrive.clearpilot.bench_cmd engaged 1"
# 5. Inspect UI widget tree (RPC call, instant response)
su - comma -c "PYTHONPATH=/data/openpilot python3 -m selfdrive.clearpilot.bench_cmd dump"
```
### Debugging Crashes
The UI has a SIGSEGV/SIGABRT crash handler (`selfdrive/ui/main.cc`) that prints a stack trace to stderr, captured in the per-process log:
```bash
# Check for crash traces (use /data/log2/current which is always the active session)
grep -A 30 "CRASH" /data/log2/current/ui.log
# Resolve addresses to source lines
addr2line -e /data/openpilot/selfdrive/ui/ui -f 0xADDRESS
# bench_cmd dump detects crash loops automatically:
# if UI process uptime < 5s, it reports "likely crash looping"
# Check per-process logs
ls /data/log2/current/
cat /data/log2/current/session.log
cat /data/log2/current/gpsd.log
```
### UI Introspection RPC
The UI process runs a ZMQ REP server at `ipc:///tmp/clearpilot_ui_rpc`. Send `"dump"` to get a recursive widget tree showing class name, visibility, geometry, and stacked layout current indices. This is the primary debugging tool for understanding what the UI is displaying.
- `bench_cmd dump` — queries the RPC and prints the widget tree
- `bench_cmd wait_ready` — polls the RPC every second until `ReadyWindow` is visible (up to 10s)
- `ui_dump.py` — standalone dump tool (same as `bench_cmd dump`)
### Architecture
- `launch_openpilot.sh --bench` sets `BENCH_MODE=1` env var
- `manager.py` reads `BENCH_MODE`, blocks real car processes, enables `bench_onroad` process
- `bench_onroad.py` publishes fake `pandaStates` (ignition=true), `carState`, `controlsState` — thermald reads the fake pandaStates to determine ignition and publishes `deviceState.started=true` on its own
- thermald and camerad run normally in bench mode (thermald manages CPU cores needed for camerad)
- Blocked processes in bench mode: pandad, controlsd, radard, plannerd, calibrationd, torqued, paramsd, locationd, sensord, ubloxd, pigeond, dmonitoringmodeld, dmonitoringd, modeld, soundd, loggerd, micd, dashcamd
### Key Files
| File | Role |
|------|------|
| `selfdrive/clearpilot/bench_onroad.py` | Fake vehicle state publisher |
| `selfdrive/clearpilot/bench_cmd.py` | Command tool for setting bench params and querying UI |
| `selfdrive/clearpilot/ui_dump.py` | Standalone UI widget tree dump |
| `selfdrive/manager/process_config.py` | Registers bench_onroad as managed process (enabled=BENCH_MODE) |
| `selfdrive/manager/manager.py` | Blocks conflicting processes in bench mode |
| `launch_openpilot.sh` | Accepts `--bench` flag, exports BENCH_MODE env var |
| `selfdrive/ui/qt/window.cc` | UI RPC server (`ipc:///tmp/clearpilot_ui_rpc`), widget tree dump |
### Resolved Issues
- **SIGSEGV in onroad view (fixed)**: `update_model()` in `ui.cc` dereferenced empty model position data when modeld wasn't running. Fixed by guarding against empty `plan_position.getX()`. The root cause was found using the crash handler + `addr2line`.
- **`showDriverView` overriding transitions (fixed)**: was forcing `slayout` to onroad/home every frame at 20Hz, overriding park/drive logic. Fixed to only act when not in started state.
- **Sidebar appearing during onroad transition (fixed)**: `MainWindow::closeSettings()` was re-enabling the sidebar. Fixed by not calling `closeSettings` during `offroadTransition`.
## Performance Profiling
Use `py-spy` to find CPU hotspots in any Python process. It's installed at `/home/comma/.local/bin/py-spy`. (If missing: `su - comma -c "/usr/local/pyenv/versions/3.11.4/bin/pip install py-spy"`.)
```bash
# Find the target pid
ps -eo pid,cmd | grep -E "selfdrive.controls.controlsd" | grep -v grep
# Record 10s of stacks at 200Hz, raw (folded) format
/home/comma/.local/bin/py-spy record -o /tmp/ctrl.txt --pid <PID> --duration 10 --rate 200 --format raw
# Aggregate: which line of step() is consuming the most samples
awk -F';' '{
for(i=1;i<=NF;i++) if ($i ~ /step \(selfdrive\/controls\/controlsd.py/) step_line=i;
if (step_line && step_line < NF) {
n=split($NF, parts, " "); count=parts[n];
caller = $(step_line+1);
sum[caller] += count;
}
step_line=0;
} END { for (c in sum) printf "%6d %s\n", sum[c], c }' /tmp/ctrl.txt | sort -rn | head -15
# Aggregate by a source file — shows hottest lines in that file
awk -F';' '{
for(i=1;i<=NF;i++) if ($i ~ /carstate\.py:/) {
match($i, /:[0-9]+/); ln = substr($i, RSTART+1, RLENGTH-1);
n=split($NF, parts, " "); count=parts[n];
sum[ln] += count;
}
} END { for (l in sum) printf "%5d line %s\n", sum[l], l }' /tmp/ctrl.txt | sort -rn | head -15
# Quick stack dump (single sample, no recording)
/home/comma/.local/bin/py-spy dump --pid <PID>
```
**Known performance trap — hot `Params` writes**: `Params.put()` does `mkstemp` + `fsync` + `flock` + `rename` + `fsync_dir`. At 100Hz even on tmpfs the `flock` contention is ruinous. Cache the last-written value and skip writes when unchanged. Found this pattern in `carstate.py` and `controlsd.py` — controlsd went from 69% → 28% CPU after gating writes.
## Session Logging
Per-process stderr and an aggregate event log are captured in `/data/log2/current/`.
### Log Directory
- `/data/log2/current/` is always the active session directory
- `init_log_dir()` is called once from `manager_init()` — creates a fresh `/data/log2/current/` real directory
- If a previous `current/` real directory exists (unresolved session), it's renamed using its mtime timestamp
- If a previous `current` symlink exists, it's removed
- Once system time is valid (GPS/NTP), the real directory is renamed to `/data/log2/YYYY-MM-DD-HH-MM-SS/` and `current` becomes a symlink to it
- `LogDirInitialized` param: `"0"` until time resolves, then `"1"`
- Open file handles survive the rename (same inode, same filesystem)
- Session directories older than 30 days are deleted on manager startup
### Per-Process Logs
- Every `PythonProcess` and `NativeProcess` has stderr redirected to `{name}.log` in the session directory
- `DaemonProcess` (athenad) redirects both stdout+stderr (existing behavior)
- Stderr is redirected via `os.dup2` inside the forked child process
### Aggregate Session Log (`session.log`)
A single `session.log` in each session directory records major events:
- Manager start/stop/crash
- Process starts, deaths (with exit codes), watchdog restarts
- Onroad/offroad transitions
### Key Files
| File | Role |
|------|------|
| `selfdrive/manager/process.py` | Log directory creation, stderr redirection, session_log logger |
| `selfdrive/manager/manager.py` | Log rotation cleanup, session event logging |
| `build_only.sh` | Build-only script (no manager start) |
## Dashcam (dashcamd)
### Architecture
`dashcamd` is a native C++ process that captures raw camera frames directly from `camerad` via VisionIPC and encodes to MP4 using the Qualcomm OMX H.264 hardware encoder. This replaces the earlier FrogPilot screen recorder approach (`QWidget::grab()` -> OMX).
- **Codec**: H.264 AVC (hardware accelerated via `OMX.qcom.video.encoder.avc`)
- **Resolution**: 1928x1208 (full camera resolution, no downscaling)
- **Bitrate**: 2500 kbps
- **Container**: MP4 (remuxed via libavformat) + SRT subtitle sidecar
- **Segment length**: 3 minutes per file
- **Save path**: `/data/media/0/videos/YYYYMMDD-HHMMSS/YYYYMMDD-HHMMSS.mp4` (trip directories)
- **GPS subtitles**: companion `.srt` file per segment with 1Hz entries (speed MPH, lat/lon, UTC timestamp)
- **Trip lifecycle**: waits in WAITING state until valid system time + GPS fix + car in drive; records until car parked 10 min or ignition off; then returns to WAITING
- **Graceful shutdown**: thermald sets `DashcamShutdown` param, dashcamd closes segment and acks within 15s
- **Storage**: ~56 MB per 3-minute segment at 2500 kbps (verified: actual bitrate ~2570 kbps)
- **Crash handler**: SIGSEGV/SIGABRT handler writes backtrace to `/tmp/dashcamd_crash.log`
- **Storage device**: WDC SDINDDH4-128G UFS 2.1 — automotive grade, ~384 TB write endurance, no concern for continuous writes
### OmxEncoder
The OMX encoder (`selfdrive/frogpilot/screenrecorder/omx_encoder.cc`) was ported from upstream FrogPilot with the following key properties:
- Each encoder instance calls `OMX_Init()` in constructor and `OMX_Deinit()` in destructor — manages its own OMX lifecycle
- Constructor takes 5 args: `(path, width, height, fps, bitrate)` — no h265/downscale params
- `encoder_close()` calls `av_write_trailer` + ffmpeg faststart remux (`-movflags +faststart`)
- Destructor has null guards and error handling on all OMX state transitions
- ClearPilot addition: `encode_frame_nv12()` for direct NV12 input (dashcamd), alongside original `encode_frame_rgba()` (screen recorder)
### Key Files
| File | Role |
|------|------|
| `selfdrive/clearpilot/dashcamd.cc` | Main dashcam process — VisionIPC -> OMX encoder |
| `selfdrive/clearpilot/SConscript` | Build config for dashcamd |
| `selfdrive/frogpilot/screenrecorder/omx_encoder.cc` | OMX encoder (upstream FrogPilot port + `encode_frame_nv12`) |
| `selfdrive/frogpilot/screenrecorder/omx_encoder.h` | Encoder header |
| `selfdrive/manager/process_config.py` | dashcamd registered as NativeProcess, camerad always_run, encoderd disabled |
| `system/loggerd/deleter.py` | Trip-aware storage rotation (oldest trip first, then segments within active trip) |
### Params
- `DashcamShutdown` (memory param) — set by thermald before power-off, dashcamd acks by clearing it
- `DashcamState` (memory param) — "stopped", "waiting", or "recording" — published every 5s
- `DashcamFrames` (memory param) — per-trip encoded frame count, resets each trip — published every 5s
## Standstill Power Saving
When `carState.standstill` is true:
- **modeld**: skips GPU inference on 19/20 frames (1fps vs 20fps), reports 0 frame drops to avoid triggering `modeldLagging` in controlsd. Runs full 20fps during calibration (`liveCalibration.calStatus != calibrated`)
- **dmonitoringmodeld**: same 1fps throttle, added `carState` subscription
- **Fan controller**: uses offroad clamps (0-30%) instead of onroad (30-100%) at standstill; thermal protection still active via feedforward if temp > 60°C
### Key Files
| File | Role |
|------|------|
| `selfdrive/modeld/modeld.py` | Standstill frame skip logic |
| `selfdrive/modeld/dmonitoringmodeld.py` | Standstill frame skip logic |
| `selfdrive/thermald/fan_controller.py` | Standstill-aware fan clamps |
| `selfdrive/thermald/thermald.py` | Passes standstill to fan controller via carState |
## Display Modes (LFA/LKAS Debug Button)
The Hyundai Tucson's LFA steering wheel button cycles through 5 display modes via `ScreenDisplayMode` param (`/dev/shm/params`, CLEAR_ON_MANAGER_START, default 0).
### Display States
| State | Name | Display | Camera | Path Drawing |
|-------|------|---------|--------|-------------|
| 0 | auto-normal | on | yes | filled (normal) |
| 1 | auto-nightrider | on | black | 2px outline only |
| 2 | normal (manual) | on | yes | filled (normal) |
| 3 | screen off | GPIO off | n/a | n/a |
| 4 | nightrider (manual) | on | black | 2px outline only |
### Auto Day/Night Switching
- `gpsd.py` computes `is_daylight(lat, lon, utc_dt)` using NOAA solar position algorithm
- First calculation immediately on GPS fix + valid clock, then every 30 seconds
- State 0 + sunset → auto-switch to 1; State 1 + sunrise → auto-switch to 0
- States 2/3/4 are never touched by auto logic
- `IsDaylight` param written to `/dev/shm/params` for reference
### Button Behavior
**Onroad (car in drive gear):** 0→4, 1→2, 2→3, 3→4, 4→2 (never back to auto via button)
**Not in drive (parked/off):** any except 3 → 3 (screen off), state 3 → 0 (auto-normal)
**Shift to drive from screen off:** auto-resets to mode 0 (auto-normal) via `controlsd`
**Shift to park from nightrider:** auto-switches to mode 3 (screen off) via `home.cc`
**Tap screen while screen off:** resets to mode 0 (auto-normal) via `window.cc` touch handler
### Nightrider Mode
- Camera feed suppressed (OpenGL clears to black instead of rendering camera texture)
- All HUD elements (speed, alerts, telemetry indicator) still visible
- Path/lane polygons drawn as 2px outlines only (no gradient fill)
- Lane lines, road edges, blind spot paths, adjacent paths all use outline rendering
### Signal Chain
```
Steering wheel LFA button press
-> CAN-FD: cruise_btns_msg_canfd["LFA_BTN"]
-> Edge detection → ButtonEvent(type=FrogPilotButtonType.lkas)
-> controlsd.clearpilot_state_control()
-> Reads ScreenDisplayMode, applies transition table based on driving_gear
-> Writes new ScreenDisplayMode to /dev/shm/params
-> UI reads ScreenDisplayMode in paintEvent() (for camera/nightrider)
and drawHud() (for display power on/off)
```
### Key Files
| File | Role |
|------|------|
| `selfdrive/controls/controlsd.py` | Button state machine, writes ScreenDisplayMode |
| `selfdrive/ui/qt/onroad.cc` | Nightrider rendering, display power control |
| `selfdrive/ui/qt/home.cc` | Display power for park/splash state |
| `system/clearpilot/gpsd.py` | Sunset/sunrise calc, auto day/night transitions |
| `selfdrive/clearpilot/bench_cmd.py` | `debugbutton` command simulates button press |
## Screen Timeout / Display Power
Display power is managed by `Device::updateWakefulness()` in `selfdrive/ui/ui.cc`.
- **Ignition off (offroad)**: screen blanks after `ScreenTimeout` seconds (default 120) of no touch. Tapping wakes it.
- **Ignition on (onroad)**: screen stays on unconditionally — ignition=true short-circuits the timeout check.
- **ScreenDisplayMode 3 override**: `updateWakefulness` checks `ScreenDisplayMode` first — if mode 3, calls `setAwake(false)` unconditionally, preventing ignition-on from overriding screen-off.
- **Debug button (LFA)**: cycles through display modes including screen off (state 3).
- **Park transition**: always shows splash screen; if coming from nightrider mode, auto-switches to screen off (mode 3) via `home.cc`.
- **Touch wake**: tapping screen while in mode 3 resets to mode 0 via `window.cc` event filter.
## Offroad UI (ClearPilot Menu)
The offroad home screen (`selfdrive/ui/qt/home.cc`) is a sidebar settings panel replacing the stock home screen. The original system settings are no longer accessible — the ClearPilot menu is the only settings interface.
### Panels
- **General**: Status window, Reset Calibration, Shutdown Timer, Reboot/Soft Reboot/Power Off
- **Network**: WiFi management, tethering, roaming, hidden networks (APN settings removed)
- **Dashcam**: placeholder for future dashcam footage viewer
- **Debug**: Telemetry logging toggle
### Navigation
- Tapping the splash screen (ReadyWindow) opens the ClearPilot menu
- "← Back" button returns to splash or onroad view
- Sidebar with stock metrics (TEMP, VEHICLE, CONNECT) is hidden
## Device: comma 3x ## Device: comma 3x
### Hardware - Qualcomm Snapdragon SoC (aarch64), serial `comma-3889765b`
- Qualcomm Snapdragon SoC (aarch64)
- Serial: comma-3889765b
- Storage: WDC SDINDDH4-128G, 128 GB UFS 2.1 - Storage: WDC SDINDDH4-128G, 128 GB UFS 2.1
- Connects to the car via comma panda (CAN bus interface) - Ubuntu 20.04.6 LTS on AGNOS 9.7
- Kernel 4.9.103+ (custom comma.ai PREEMPT build, vendor-patched Qualcomm)
- Python 3.11.4 via pyenv at `/usr/local/pyenv/versions/3.11.4/` (system python 3.8 — do not use)
- Display: Weston (Wayland) on tty1
- Hardware encoding: OMX (`OMX.qcom.video.encoder.avc` / `.hevc`); V4L2 VIDC exists but is not usable from ffmpeg subprocess
### Operating System ### Filesystem mount quirks
- **Ubuntu 20.04.6 LTS (Focal Fossa)** on aarch64 | Mount | Device | Type | Notes |
- **Kernel**: 4.9.103+ (custom comma.ai PREEMPT build, Feb 2024) — very old, vendor-patched Qualcomm kernel |---|---|---|---|
- **Python**: 3.11.4 via pyenv at `/usr/local/pyenv/versions/3.11.4/` (system python is 3.8, do not use) | `/` | /dev/sda7 | ext4 | rw |
- **AGNOS version**: 9.7 (comma's custom OS layer on top of Ubuntu) | `/data` | /dev/sda12 | ext4 | **persistent** — openpilot lives here |
- **Display server**: Weston (Wayland compositor) on tty1 | `/home` | overlay | overlayfs | **volatile** (upper on tmpfs) — changes lost on reboot |
- **SELinux**: mounted (enforcement status varies) | `/tmp` | tmpfs | tmpfs | volatile |
| `/persist` | /dev/sda2 | ext4 | persistent config/certs, noexec |
| `/dsp` | /dev/sde26 | ext4 | **read-only** Qualcomm DSP firmware |
| `/firmware` | /dev/sde4 | vfat | **read-only** firmware blobs |
### Users ### GPS
- `comma` (uid=1000) — the user openpilot runs as; member of root, sudo, disk, gpu, gpio groups The device has **no u-blox chip** (`/dev/ttyHS0` does not exist). GPS is the **Quectel EC25 LTE modem**'s built-in GPS, accessed via AT commands through `mmcli`. The original `qcomgpsd` is broken on this device because the diag interface hangs after setup. `system/clearpilot/gpsd.py` is the replacement; locationd is patched not to consume `gpsLocation` so the kalman filter isn't tainted.
- `root` — what we SSH in as; files must be chowned back to comma before running openpilot
### Filesystem / Mount Quirks ### Sidebar / Process Notes
| Mount | Device | Type | Notes | - `camerad` runs `always_run` (was `driverview`) — this is needed for dashcamd. Costs steady-state camera power even when ignition is off.
|-------------|-------------|---------|-------| - `loggerd`, `encoderd`, `stream_encoderd` are commented out in `process_config.py` — no segment or video logging
| `/` | /dev/sda7 | ext4 | Root filesystem, read-write | - `qcomgpsd` is commented out; `system.clearpilot.gpsd` is registered in its place (gated by `qcomgps` callback = `not ublox_available()`, which is always true on this device)
| `/data` | /dev/sda12 | ext4 | **Persistent**. Openpilot lives here. Survives reboots. | - `speed_logicd` is `only_onroad`; `dashcamd` is `always_run` (manages own trip lifecycle)
| `/home` | overlay | overlayfs | **VOLATILE** — upperdir on tmpfs, changes lost on reboot | - `uploader` already commented out in baseline
| `/tmp` | tmpfs | tmpfs | Volatile, 150 MB |
| `/var` | tmpfs | tmpfs | Volatile, 128 MB (fstab) / 1.5 GB (actual) |
| `/systemrw` | /dev/sda10 | ext4 | Writable system overlay, noexec |
| `/persist` | /dev/sda2 | ext4 | Persistent config/certs, noexec |
| `/cache` | /dev/sda11 | ext4 | Android-style cache partition |
| `/dsp` | /dev/sde26 | ext4 | **Read-only** Qualcomm DSP firmware |
| `/firmware` | /dev/sde4 | vfat | **Read-only** firmware blobs |
### Hardware Encoding
- **OMX**: `OMX.qcom.video.encoder.avc` (H.264) and `OMX.qcom.video.encoder.hevc` — used by dashcamd and screen recorder
- **V4L2**: Qualcomm VIDC at `/dev/v4l/by-path/platform-aa00000.qcom_vidc-video-index1` — used by encoderd (now disabled). Not accessible from ffmpeg due to permission/driver issues
- **ffmpeg**: v4.2.2, has `h264_v4l2m2m` and `h264_omx` listed but neither works from ffmpeg subprocess (OMX port issues, V4L2 device not found). Use OMX directly via the C++ encoder
### Fan Control
Software-controlled via `thermald` -> `fan_controller.py` -> panda USB -> PWM. Target temp 70°C, PI+feedforward controller. See Standstill Power Saving section for standstill-aware clamps.
## Boot Sequence ## Boot Sequence
``` ```
Power On Power On
-> systemd: comma.service (runs as comma user) systemd: comma.service (runs as comma user)
-> /usr/comma/comma.sh (waits for Weston, handles factory reset) /usr/comma/comma.sh (waits for Weston, handles factory reset)
-> /data/continue.sh (exec bridge to openpilot) /data/continue.sh
-> /data/openpilot/launch_openpilot.sh /data/openpilot/launch_openpilot.sh
-> Kills other instances of itself and manager.py → kill stale instances (launch_openpilot, launch_chffrplus, manager.py, ./ui, _text by comm)
-> Runs on_start.sh (logo, reverse SSH) → bash system/clearpilot/on_start.sh (SSH, WiFi, run provision.sh)
-> exec launch_chffrplus.sh → background system/clearpilot/vpn-monitor.sh
-> Sources launch_env.sh (thread counts, AGNOS_VERSION) → background system/clearpilot/nice-monitor.sh
-> Runs agnos_init (marks boot slot, GPU perms, checks OS update) → exec ./launch_chffrplus.sh
-> Sets PYTHONPATH, symlinks /data/pythonpath → source launch_env.sh
-> Runs build.py if no `prebuilt` marker → run agnos_init
-> Launches selfdrive/manager/manager.py → set PYTHONPATH
-> manager_init() sets default params → if no `prebuilt`: run build.py (spinner + scons)
-> ensure_running() loop starts all managed processes → exec selfdrive/manager/manager.py
→ manager_init() sets default params (persistent + memory)
→ ensure_running() loop starts managed processes
``` ```
## Openpilot Architecture
### Process Manager
`selfdrive/manager/manager.py` orchestrates all processes defined in `selfdrive/manager/process_config.py`.
### Always-Running Processes (offroad + onroad)
- `thermald` — thermal management and fan control
- `pandad` — panda CAN bus interface
- `ui` — Qt-based onroad/offroad UI
- `deleter` — storage cleanup (9 GB threshold)
- `statsd`, `timed`, `logmessaged`, `tombstoned` — telemetry/logging
- `manage_athenad` — comma cloud connectivity
- `fleet_manager`, `frogpilot_process` — FrogPilot additions
### Onroad-Only Processes (when driving)
- `controlsd` — main vehicle control loop
- `plannerd` — path planning
- `radard` — radar processing
- `modeld` — driving model inference (throttled to 1fps at standstill)
- `dmonitoringmodeld` — driver monitoring model (throttled to 1fps at standstill)
- `locationd`, `calibrationd`, `paramsd`, `torqued` — localization and calibration
- `sensord` — IMU/sensor data
- `soundd` — alert sounds
- `camerad` — camera capture
- `loggerd` — CAN/sensor log recording (video encoding disabled)
### ClearPilot Processes
- `dashcamd` — raw camera dashcam recording (always runs; manages its own trip lifecycle)
### GPS
- Device has **no u-blox chip** (`/dev/ttyHS0` does not exist) — `ubloxd`/`pigeond` never start
- GPS hardware is a **Quectel EC25 LTE modem** (USB, `lsusb: 2c7c:0125`) with built-in GPS
- GPS is accessed via AT commands through `mmcli`: `mmcli -m any --command='AT+QGPSLOC=2'`
- **`qcomgpsd`** (original openpilot process) uses the modem's diag interface which is broken on this device — the diag recv loop blocks forever after setup. Commented out.
- **`system/clearpilot/gpsd.py`** is the replacement — polls GPS via AT commands at 1Hz, publishes `gpsLocation` cereal messages
- GPS data flows: `gpsd``gpsLocation``locationd``liveLocationKalman``timed` (sets system clock)
- `locationd` checks `UbloxAvailable` param (false on this device) to subscribe to `gpsLocation` instead of `gpsLocationExternal`
- `mmcli` returns `response: '...'` wrapper — `at_cmd()` strips it before parsing (fixed)
- GPS antenna power must be enabled via GPIO: `gpio_set(GPIO.GNSS_PWR_EN, True)`
- System `/usr/sbin/gpsd` daemon may respawn and interfere — should be disabled or killed
### Telemetry
- **Client**: `selfdrive/clearpilot/telemetry.py``tlog(group, data)` sends JSON over ZMQ PUSH
- **Collector**: `selfdrive/clearpilot/telemetryd.py` — diffs against previous state, writes changed values to CSV
- **Toggle**: `TelemetryEnabled` memory param, controlled from Debug panel in ClearPilot menu
- **Auto-disable**: disabled on every manager start; disabled if `/data` free < 5GB
- **Hyundai CAN-FD data**: logged from `selfdrive/car/hyundai/carstate.py` `update_canfd()` — groups: `car`, `cruise`, `speed_limit`, `buttons`
- **GPS data**: logged directly by telemetryd via cereal `gpsLocation` subscription at 1Hz — group: `gps` (latitude, longitude, speed, altitude, bearing, accuracy)
- **CSV location**: `/data/log2/current/telemetry.csv` (or session directory)
- **Onroad overlay**: when telemetry enabled, status bar shows temp, fan %, model FPS, and STANDSTILL indicator
- **Speed limit**: processed by `selfdrive/clearpilot/speed_logic.py` (SpeedState class), converts m/s to display units, writes to memory params. Cruise warning signs appear when cruise set speed exceeds speed limit by threshold (10 mph if limit >= 50, 7 mph if < 50) or is 5+ mph under. Ding sound plays when warning sign appears or speed limit changes while visible (30s cooldown)
### Key Dependencies
- **Python 3.11** (via pyenv) with: numpy, casadi, onnx/onnxruntime, pycapnp, pyzmq, sentry-sdk, sympy, Cython
- **capnp (Cap'n Proto)** — IPC message serialization between all processes
- **ZeroMQ** — IPC transport layer
- **Qt 5** — UI framework (with WebEngine available but not used for rotation reasons)
- **OpenMAX (OMX)** — hardware video encoding
- **libavformat** — MP4 container muxing
- **libyuv** — color space conversion
- **SCons** — build system for native C++ components
-49
View File
@@ -1,49 +0,0 @@
# Dashcam Project
## Status
### Completed (2026-04-11)
- Disabled comma training data video encoding (`encoderd`) — CAN/sensor logs still recorded
- Re-enabled FrogPilot OMX screen recorder (H.264 MP4, 1440x720, 2Mbps, hardware encoded)
- Auto-start/stop recording tied to car ignition (`scene.started`)
- `ScreenRecorderDebug` param for bench testing without car connected
- Hidden all recorder UI elements — invisible to driver
- Videos saved to `/data/media/0/videos/YYYYMMDD-HHMMSS.mp4`, 3-minute segments
- Deleter updated: 9 GB free space threshold, rotates oldest videos first
- Cleaned up offroad UI: replaced stock home screen with grid launcher (Settings + Dashcam buttons)
### Next: Dashcam Footage Viewer
Build a native Qt widget accessible from the offroad home screen "Dashcam" button.
**Requirements:**
- List MP4 files from `/data/media/0/videos/` sorted newest first
- Tap a file to play it back using Qt Multimedia (`QMediaPlayer` + `QVideoWidget`)
- Only accessible when offroad (car in park or off)
- Back button to return to offroad home
- No rotation hacks needed — native Qt widget in existing UI tree handles rotation correctly
**Architecture:**
- New widget class (e.g. `DashcamViewer`) added to `selfdrive/ui/qt/`
- Wire into `HomeWindow`'s `QStackedLayout` alongside `home`, `onroad`, `ready`, `driver_view`
- Dashcam button in `OffroadHome` switches `slayout` to the viewer
- Viewer has a file list view and a playback view (sub-stacked layout)
- Back button returns to `OffroadHome`
- Build: add to `qt_src` list in `selfdrive/ui/SConscript`, link `Qt5Multimedia`
**Previous webview attempts (abandoned):**
- Brian tried QWebEngineView for browser-based playback but the WebEngine subprocess renders independently of Qt's widget tree
- Screen rotation (`view.rotate(90)`, Wayland `wl_surface_set_buffer_transform`) did not work for WebEngine content
- Native Qt widget approach avoids this problem entirely
## Key Files
| File | Role |
|------|------|
| `selfdrive/frogpilot/screenrecorder/screenrecorder.cc` | Recording logic, auto-start/stop |
| `selfdrive/frogpilot/screenrecorder/omx_encoder.cc` | OMX H.264 hardware encoder |
| `selfdrive/ui/qt/onroad.cc` | Timer driving frame capture |
| `selfdrive/ui/qt/home.cc` | Offroad home with Dashcam button |
| `system/loggerd/deleter.py` | Storage rotation |
| `/data/media/0/videos/` | Video output directory |
-46
View File
@@ -1,46 +0,0 @@
# ClearPilot — Feature Goals
Each goal below will be discussed in detail before implementation. Background and specifics to be provided by Brian when we get to each item.
## Dashcam
- [ ] **Dashcam viewer** — on-screen Qt widget for browsing and playing back recorded footage from the offroad home screen (Dashcam button already placed). See `DASHCAM_PROJECT.md` for architecture notes.
- [ ] **Dashcam uploader** — upload footage to a remote server or cloud storage
- [ ] **GPS + speed overlay on dashcam footage** — embed GPS coordinates and vehicle speed into the video stream or as metadata
- [ ] **Dashcam footage archive** — option to mark a trip's footage as archived (kept in storage but hidden from the main UI)
- [ ] **Suspend dashcam / route recording** — on-screen setting to pause recording for a trip and delete footage of the current trip so far (privacy mode)
## Driving Alerts & Safety
- [ ] **Chirp on speed change and over speed limit** — audible alert when speed limit changes or vehicle exceeds the limit
- [ ] **Warn on traffic standstill ahead** — alert when approaching cars ahead too quickly (closing distance warning)
- [ ] **On-screen current speed limit** — display the speed limit as reported by the car's CAN data
- [ ] **Fix on-screen speed value for MPH** — correct the speed display to use the proper value for MPH conversion
## Cruise Control & Driving State
- [ ] **Auto-set speed via CAN bus** — simulate pressing speed up/down buttons on CAN bus to automatically set cruise to the correct speed via UI interaction (stretch goal)
- [ ] **Fix engaged-while-braking state sync** — if openpilot is engaged while brakes are pressed, the system thinks it's active but the car isn't actually in cruise control, causing a sync error that should be recoverable
- [ ] **Fix resume-cruise lateral mode bug** — pressing resume cruise control (rather than enable) causes the car to enter a state where it thinks it's in always-on lateral mode and disables driver monitoring
- [ ] **Lateral assist in turn lanes** — keep lateral assist active when using turn signal in a turn lane (at low/turning speeds) as opposed to cruising speeds, where lateral currently disengages
## Driver Monitoring
- [ ] **Disable driver monitoring on demand** — add a technique to disable DM for 2 minutes via a button or gesture
- [ ] **Hands-on-wheel mode** — add a setting requiring the driver to keep hands on the wheel (configurable via settings)
## UI Modes & Display
- [ ] **Curves-only UI mode** — show only on-screen curve/path depictions without the camera feed (reduces visual clutter, saves processing)
- [ ] **Night mode auto-display-off** — turn off display if device starts at night (determine sunset for current location/datetime or use ambient light levels from car sensors)
- [ ] **Update boot/offroad splash logos** — replace the red pac-man ghost with a blue pac-man ghost for boot and offroad full-screen splash
- [ ] **Dashcam-only reboot mode** — on-screen option to reboot into a mode that provides no driver assist (reverts to stock OEM lane assist) but keeps dashcam running. For lending the car to friends who shouldn't use comma's driving features.
## Connectivity & Data
- [ ] **Offroad weather report screen** — weather display accessible from the offroad home grid (depends on internet connection)
- [ ] **Fix GPS tracking** — GPS tracking feature currently broken, processes commented out in process_config
## Vehicle-Specific (Hyundai Tucson HDA2)
- [ ] **Warn if panoramic roof is open** — if possible to intercept window/roof state from CAN bus, warn when the top roof is left open when the car is turned off
-1
View File
@@ -121,7 +121,6 @@ def objcopy(source, target, env, for_signature):
return '$OBJCOPY -O binary %s %s' % (source[0], target[0]) return '$OBJCOPY -O binary %s %s' % (source[0], target[0])
# Common autogenerated includes # Common autogenerated includes
os.makedirs("obj", exist_ok=True)
git_ver = get_version(BUILDER, BUILD_TYPE) git_ver = get_version(BUILDER, BUILD_TYPE)
with open("obj/gitversion.h", "w") as f: with open("obj/gitversion.h", "w") as f:
f.write(f'const uint8_t gitversion[8] = "{git_ver}";\n') f.write(f'const uint8_t gitversion[8] = "{git_ver}";\n')
+7 -2
View File
@@ -10,8 +10,11 @@ BASEDIR="/data/openpilot"
# Fix ownership — we edit as root, openpilot builds/runs as comma # Fix ownership — we edit as root, openpilot builds/runs as comma
sudo chown -R comma:comma "$BASEDIR" sudo chown -R comma:comma "$BASEDIR"
# Kill stale error displays and any running manager/launch/managed processes # Kill stale error displays and any running manager/launch/managed processes.
# `text` is a shell wrapper that execs `./_text` — after exec the process is named
# `_text` (no path), so we kill by exact comm in addition to the path pattern.
pkill -9 -f "selfdrive/ui/text" 2>/dev/null pkill -9 -f "selfdrive/ui/text" 2>/dev/null
pkill -9 -x _text 2>/dev/null
pkill -9 -f 'launch_openpilot.sh' 2>/dev/null pkill -9 -f 'launch_openpilot.sh' 2>/dev/null
pkill -9 -f 'launch_chffrplus.sh' 2>/dev/null pkill -9 -f 'launch_chffrplus.sh' 2>/dev/null
pkill -9 -f 'python.*manager.py' 2>/dev/null pkill -9 -f 'python.*manager.py' 2>/dev/null
@@ -35,4 +38,6 @@ source "$BASEDIR/build_preflight.sh"
cd "$BASEDIR/selfdrive/manager" cd "$BASEDIR/selfdrive/manager"
rm -f "$BASEDIR/prebuilt" rm -f "$BASEDIR/prebuilt"
BUILD_ONLY=1 exec ./build.py # Tee output to /tmp/build.log for inspection after the script exits
BUILD_ONLY=1 ./build.py 2>&1 | tee /tmp/build.log
exit "${PIPESTATUS[0]}"
-3
View File
@@ -12,9 +12,6 @@ struct FrogPilotCarControl @0x81c2f05a394cf4af {
alwaysOnLateral @0 :Bool; alwaysOnLateral @0 :Bool;
speedLimitChanged @1 :Bool; speedLimitChanged @1 :Bool;
trafficModeActive @2 :Bool; trafficModeActive @2 :Bool;
# CLEARPILOT: migrated from paramsMemory to avoid file-read syscalls in modeld/UI/carcontroller
latRequested @3 :Bool; # controlsd's request to enable lat before ramp-up delay
noLatLaneChange @4 :Bool; # lat is temporarily suppressed during a lane change
} }
struct FrogPilotCarState @0xaedffd8f31e7b55d { struct FrogPilotCarState @0xaedffd8f31e7b55d {
+3 -3
View File
@@ -30,7 +30,7 @@ services: dict[str, tuple] = {
"temperatureSensor": (True, 2., 200), "temperatureSensor": (True, 2., 200),
"temperatureSensor2": (True, 2., 200), "temperatureSensor2": (True, 2., 200),
"gpsNMEA": (True, 9.), "gpsNMEA": (True, 9.),
"deviceState": (True, 5., 1), # CLEARPILOT: 5Hz — thermald decimates pandaStates (10Hz) every 2 ticks "deviceState": (True, 2., 1),
"can": (True, 100., 1223), # decimation gives ~5 msgs in a full segment "can": (True, 100., 1223), # decimation gives ~5 msgs in a full segment
"controlsState": (True, 100., 10), "controlsState": (True, 100., 10),
"pandaStates": (True, 10., 1), "pandaStates": (True, 10., 1),
@@ -50,7 +50,7 @@ services: dict[str, tuple] = {
"longitudinalPlan": (True, 20., 5), "longitudinalPlan": (True, 20., 5),
"procLog": (True, 0.5, 15), "procLog": (True, 0.5, 15),
"gpsLocationExternal": (True, 10., 10), "gpsLocationExternal": (True, 10., 10),
"gpsLocation": (True, 2., 1), # CLEARPILOT: 2Hz (was 1Hz) — gpsd polls at 2Hz "gpsLocation": (True, 1., 1),
"ubloxGnss": (True, 10.), "ubloxGnss": (True, 10.),
"qcomGnss": (True, 2.), "qcomGnss": (True, 2.),
"gnssMeasurements": (True, 10., 10), "gnssMeasurements": (True, 10., 10),
@@ -70,7 +70,7 @@ services: dict[str, tuple] = {
"wideRoadEncodeIdx": (False, 20., 1), "wideRoadEncodeIdx": (False, 20., 1),
"wideRoadCameraState": (True, 20., 20), "wideRoadCameraState": (True, 20., 20),
"modelV2": (True, 20., 40), "modelV2": (True, 20., 40),
"managerState": (True, 5., 1), # CLEARPILOT: 5Hz — gated by deviceState arrival (see thermald) "managerState": (True, 2., 1),
"uploaderState": (True, 0., 1), "uploaderState": (True, 0., 1),
"navInstruction": (True, 1., 10), "navInstruction": (True, 1., 10),
"navRoute": (True, 0.), "navRoute": (True, 0.),
+28 -31
View File
@@ -109,9 +109,6 @@ std::unordered_map<std::string, uint32_t> keys = {
{"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"CurrentBootlog", PERSISTENT}, {"CurrentBootlog", PERSISTENT},
{"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"DashcamFrames", PERSISTENT},
{"DashcamState", PERSISTENT},
{"DashcamShutdown", CLEAR_ON_MANAGER_START},
{"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"DisablePowerDown", PERSISTENT}, {"DisablePowerDown", PERSISTENT},
{"DisableUpdates", PERSISTENT}, {"DisableUpdates", PERSISTENT},
@@ -161,7 +158,6 @@ std::unordered_map<std::string, uint32_t> keys = {
{"LastUpdateTime", PERSISTENT}, {"LastUpdateTime", PERSISTENT},
{"LiveParameters", PERSISTENT}, {"LiveParameters", PERSISTENT},
{"LiveTorqueParameters", PERSISTENT | DONT_LOG}, {"LiveTorqueParameters", PERSISTENT | DONT_LOG},
{"LogDirInitialized", CLEAR_ON_MANAGER_START},
{"LongitudinalPersonality", PERSISTENT}, {"LongitudinalPersonality", PERSISTENT},
{"NavDestination", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"NavDestination", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"NavDestinationWaypoints", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"NavDestinationWaypoints", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
@@ -193,18 +189,12 @@ std::unordered_map<std::string, uint32_t> keys = {
{"RecordFrontLock", PERSISTENT}, // for the internal fleet {"RecordFrontLock", PERSISTENT}, // for the internal fleet
{"ReplayControlsState", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"ReplayControlsState", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"RouteCount", PERSISTENT}, {"RouteCount", PERSISTENT},
{"ShutdownTouchReset", PERSISTENT},
{"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"SshEnabled", PERSISTENT}, {"SshEnabled", PERSISTENT},
{"TermsVersion", PERSISTENT}, {"TermsVersion", PERSISTENT},
{"TelemetryEnabled", PERSISTENT},
{"Timezone", PERSISTENT}, {"Timezone", PERSISTENT},
{"TrainingVersion", PERSISTENT}, {"TrainingVersion", PERSISTENT},
{"ModelFps", PERSISTENT},
{"ModelStandby", PERSISTENT},
{"ModelStandbyTs", PERSISTENT},
{"UbloxAvailable", PERSISTENT}, {"UbloxAvailable", PERSISTENT},
{"VpnEnabled", PERSISTENT},
{"UpdateAvailable", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"UpdateAvailable", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"UpdateFailedCount", CLEAR_ON_MANAGER_START}, {"UpdateFailedCount", CLEAR_ON_MANAGER_START},
{"UpdaterAvailableBranches", PERSISTENT}, {"UpdaterAvailableBranches", PERSISTENT},
@@ -220,13 +210,6 @@ std::unordered_map<std::string, uint32_t> keys = {
// FrogPilot parameters // FrogPilot parameters
{"AccelerationPath", PERSISTENT}, {"AccelerationPath", PERSISTENT},
{"BenchCruiseActive", CLEAR_ON_MANAGER_START},
{"BenchCruiseSpeed", CLEAR_ON_MANAGER_START},
{"ClpUiState", CLEAR_ON_MANAGER_START},
{"BenchEngaged", CLEAR_ON_MANAGER_START},
{"BenchGear", CLEAR_ON_MANAGER_START},
{"BenchSpeed", CLEAR_ON_MANAGER_START},
{"BenchSpeedLimit", CLEAR_ON_MANAGER_START},
{"AccelerationProfile", PERSISTENT}, {"AccelerationProfile", PERSISTENT},
{"AdjacentPath", PERSISTENT}, {"AdjacentPath", PERSISTENT},
{"AdjacentPathMetrics", PERSISTENT}, {"AdjacentPathMetrics", PERSISTENT},
@@ -249,27 +232,41 @@ std::unordered_map<std::string, uint32_t> keys = {
{"CarMake", PERSISTENT}, {"CarMake", PERSISTENT},
{"CarModel", PERSISTENT}, {"CarModel", PERSISTENT},
{"CarCruiseDisplayActual", PERSISTENT},
{"CarSpeedLimit", PERSISTENT}, {"CarSpeedLimit", PERSISTENT},
{"CarSpeedLimitWarning", PERSISTENT}, {"CarSpeedLimitWarning", PERSISTENT},
{"CarSpeedLimitLiteral", PERSISTENT}, {"CarSpeedLimitLiteral", PERSISTENT},
{"CarIsMetric", PERSISTENT},
{"ClearpilotSpeedDisplay", PERSISTENT},
{"ClearpilotSpeedLimitDisplay", PERSISTENT},
{"ClearpilotHasSpeed", PERSISTENT},
{"ClearpilotIsMetric", PERSISTENT},
{"ClearpilotSpeedUnit", PERSISTENT},
{"ClearpilotCruiseWarning", PERSISTENT},
{"ClearpilotCruiseWarningSpeed", PERSISTENT},
{"ClearpilotPlayDing", PERSISTENT},
// {"SpeedLimitLatDesired", PERSISTENT}, // {"SpeedLimitLatDesired", PERSISTENT},
// {"SpeedLimitVTSC", PERSISTENT}, // {"SpeedLimitVTSC", PERSISTENT},
{"CPTLkasButtonAction", PERSISTENT}, {"CPTLkasButtonAction", PERSISTENT},
{"IsDaylight", CLEAR_ON_MANAGER_START}, {"ScreenDisplayMode", PERSISTENT},
{"ScreenDisplayMode", CLEAR_ON_MANAGER_START},
// CLEARPILOT memory params (live at /dev/shm/params; tmpfs is volatile so
// these reset on reboot regardless of registration flag).
{"CarIsMetric", PERSISTENT},
{"ClearpilotCruiseWarning", PERSISTENT},
{"ClearpilotCruiseWarningSpeed", PERSISTENT},
{"ClearpilotHasSpeed", PERSISTENT},
{"ClearpilotIsMetric", PERSISTENT},
{"ClearpilotPlayDing", PERSISTENT},
{"ClearpilotShowHealthMetrics", PERSISTENT},
{"ClearpilotSpeedDisplay", PERSISTENT},
{"ClearpilotSpeedLimitDisplay", PERSISTENT},
{"ClearpilotSpeedUnit", PERSISTENT},
{"DashcamFrames", PERSISTENT},
{"DashcamShutdown", PERSISTENT},
{"DashcamState", PERSISTENT},
{"IsDaylight", PERSISTENT},
{"ModelFps", PERSISTENT},
{"ModelStandby", PERSISTENT},
{"ModelStandbyTs", PERSISTENT},
{"ScreenRecorderDebug", PERSISTENT},
{"ShutdownTouchReset", PERSISTENT},
{"TelemetryEnabled", PERSISTENT},
{"VpnEnabled", PERSISTENT},
{"RadarDist", PERSISTENT}, {"RadarDist", PERSISTENT},
{"ModelDist", PERSISTENT}, {"ModelDist", PERSISTENT},
@@ -290,7 +287,6 @@ std::unordered_map<std::string, uint32_t> keys = {
{"CEStopLights", PERSISTENT}, {"CEStopLights", PERSISTENT},
{"CEStopLightsLead", PERSISTENT}, {"CEStopLightsLead", PERSISTENT},
{"Compass", PERSISTENT}, {"Compass", PERSISTENT},
{"ClearpilotShowHealthMetrics", PERSISTENT},
{"ConditionalExperimental", PERSISTENT}, {"ConditionalExperimental", PERSISTENT},
{"CrosstrekTorque", PERSISTENT}, {"CrosstrekTorque", PERSISTENT},
{"CurrentHolidayTheme", PERSISTENT}, {"CurrentHolidayTheme", PERSISTENT},
@@ -444,7 +440,6 @@ std::unordered_map<std::string, uint32_t> keys = {
{"ScreenBrightnessOnroad", PERSISTENT}, {"ScreenBrightnessOnroad", PERSISTENT},
{"ScreenManagement", PERSISTENT}, {"ScreenManagement", PERSISTENT},
{"ScreenRecorder", PERSISTENT}, {"ScreenRecorder", PERSISTENT},
{"ScreenRecorderDebug", PERSISTENT},
{"ScreenTimeout", PERSISTENT}, {"ScreenTimeout", PERSISTENT},
{"ScreenTimeoutOnroad", PERSISTENT}, {"ScreenTimeoutOnroad", PERSISTENT},
{"SearchInput", PERSISTENT}, {"SearchInput", PERSISTENT},
@@ -508,6 +503,8 @@ std::unordered_map<std::string, uint32_t> keys = {
{"WheelIcon", PERSISTENT}, {"WheelIcon", PERSISTENT},
{"WheelSpeed", PERSISTENT}, {"WheelSpeed", PERSISTENT},
// Clearpilot
{"no_lat_lane_change", PERSISTENT},
}; };
} // namespace } // namespace
+1 -1
View File
@@ -12,7 +12,7 @@ from openpilot.system.hardware import PC
# time step for each process # time step for each process
DT_CTRL = 0.01 # controlsd DT_CTRL = 0.01 # controlsd
DT_MDL = 0.05 # model DT_MDL = 0.05 # model
DT_TRML = 0.25 # thermald and manager — 4 Hz DT_TRML = 0.5 # thermald and manager
DT_DMON = 0.05 # driver monitoring DT_DMON = 0.05 # driver monitoring
+358
View File
@@ -0,0 +1,358 @@
# Park-mode power savings — design notes & retro
## Goal
While ignition is on but the car is in **park**, reduce CPU/power draw by
shutting down processes that aren't needed for "watching the gear lever."
The constraint: the car's steering ECU must keep seeing the openpilot
heartbeat (LFA / LKAS / LKAS_ALT CAN-FD messages, every controlsd cycle)
or it drops out of tester mode and throws a steering fault on the next
shift to drive.
Behavior should approximate "ignition off" except:
- controlsd stays alive (it's the heartbeat source and the gear watcher)
- pandad / boardd / camerad / dashcamd / gpsd / ui / thermald keep running
- everything else (modeld, locationd, paramsd, torqued, calibrationd,
plannerd, radard, dmonitoringmodeld, dmonitoringd, soundd, sensord,
speed_logicd, frogpilot_process) gets paused
When the car shifts back to drive, all the paused processes spin up cold
and openpilot resumes normal operation.
## Status: reverted
We attempted this on **2026-05-04** (commits `5d18ad1``1e4e95c`,
force-pushed away). It built and launched fine on the bench but produced
a cascade of false alerts during the park→drive transition in the car —
"controlsd unresponsive", commIssue with longitudinalPlan/frogpilotPlan,
locationd temporaryError, sensorDataInvalid. Reverted to tag
`stable_5_4_26` (commit `0d1cedd`).
This document captures the design we tried and the problems we ran into
so the next attempt doesn't relearn the same mistakes.
## Design we tried
### 1. The flag
A new memory param `ParkMode` (registered in `common/params.cc`,
defaulted to `"0"` in `manager_init`'s memory-params loop). Lives at
`/dev/shm/params/d/ParkMode`. Written by controlsd, read by
process_config gating callbacks.
### 2. controlsd writes the flag and runs a minimal cycle in park
In `__init__`:
```python
self.park_mode = False
self.park_exit_frame = -1
self.startup_complete_frame = -1
self.PARK_GRACE_MAX_FRAMES = int(15.0 / DT_CTRL) # see "Park-grace cap" below
self.PARK_STARTUP_DELAY_FRAMES = int(10.0 / DT_CTRL) # see "Startup delay" below
self.last_engaged_frame = -1
self.last_engage_attempt_frame = -1
self.POST_ENGAGE_LAG_GRACE_FRAMES = int(3.0 / DT_CTRL)
```
In `step()` after `data_sample()`:
```python
self._update_park_mode(CS)
if self.park_mode or self._in_park_exit_grace():
self._park_mode_tick(CS)
self.CS_prev = CS
return
# ... normal flow
```
Helpers:
```python
def _park_mode_allowed(self):
# Don't allow park mode until init has completed AND we've run at
# least PARK_STARTUP_DELAY_FRAMES of normal step() after init.
if not self.initialized:
return False
if self.startup_complete_frame < 0:
self.startup_complete_frame = self.sm.frame
return (self.sm.frame - self.startup_complete_frame) >= self.PARK_STARTUP_DELAY_FRAMES
def _update_park_mode(self, CS):
if not self._park_mode_allowed():
return
in_park = CS.gearShifter == GearShifter.park
if in_park != self.park_mode:
self.park_mode = in_park
self.params_memory.put_bool("ParkMode", in_park)
if not in_park:
self.park_exit_frame = self.sm.frame
def _in_park_exit_grace(self):
if self.park_exit_frame < 0:
return False
if (self.sm.frame - self.park_exit_frame) >= self.PARK_GRACE_MAX_FRAMES:
return False
return not (self.sm.all_checks() and not self.card.can_rcv_timeout)
def _park_mode_tick(self, CS):
# Build a do-nothing CarControl; card.controls_update -> CI.apply ->
# CarController.update appends create_steering_messages()
# unconditionally, so the LFA/LKAS heartbeat keeps flowing.
CC = car.CarControl.new_message()
self.clearpilot_state_control(CC, CS)
self.card.controls_update(CC, self.frogpilot_variables)
```
Why every piece matters:
- **`_park_mode_allowed` (10 s startup delay)**: `card.initialize()` is
only called inside `data_sample`'s `if not self.initialized` branch.
That call wires `CarInterface` up so `controls_update` actually
produces CAN sends. If we entered park-mode before init completed,
the heartbeat was a silent no-op. The 10 s buffer also lets all
`only_onroad_active` processes complete their cold-spawn the very
first time, before manager starts pausing them.
- **`_in_park_exit_grace`**: when ParkMode flips off, the cold-spawn
chain takes time. Stay in keepalive-tick mode until SubMaster reports
everything healthy, with a hard cap as a safety net (we used 15 s,
saw it still wasn't enough — see "What broke" below).
- **`_park_mode_tick` calls `card.controls_update`**: don't call
`state_update` or `data_sample``step()` already did that. Just
publish the empty CC to push the heartbeat CAN messages.
### 3. Manager gating
In `selfdrive/manager/process_config.py`:
```python
def _park_mode() -> bool:
return Params("/dev/shm/params").get_bool("ParkMode")
def only_onroad_active(started, params, CP):
return started and not _park_mode()
def driverview_active(started, params, CP):
return driverview(started, params, CP) and not _park_mode()
def always_run_unless_parked(started, params, CP):
# Same as always_run, but pauses while ignition is on and parked.
# Preserves offroad behavior.
return not (started and _park_mode())
```
Re-gated:
- `only_onroad``only_onroad_active`: modeld, sensord, soundd,
locationd, calibrationd, torqued, paramsd, plannerd, radard,
speed_logicd
- `driverview``driverview_active`: dmonitoringmodeld, dmonitoringd
- `always_run``always_run_unless_parked`: frogpilot_process
`controlsd` stays plain `only_onroad` — it's the writer + heartbeat source.
`camerad`, `pandad`, `thermald`, `ui`, `dashcamd`, `gpsd`, `deleter`,
`fleet_manager`, `tombstoned`, `timed`, manager internals stay
`always_run` (or whatever they were).
### 4. Engage-attempt grace (separate from park-grace)
The state transition into engaged briefly bumps the controlsd loop time
over budget. `self.rk.lagging` flips True for a cycle, `update_events`
adds `EventName.controlsdLagging`, which has an `ET.NO_ENTRY` alert
("Controls Process Lagging: Reboot Your Device"). That alert fires
right as the user is taking their hands off the wheel after pressing
SET. Same goes for `commIssue` if any service is briefly stale.
Solution: track two engagement edges — the actual transition into
ENABLED (post-success) and the cruise.enabled rising edge (pre-success,
covers blocked attempts):
```python
# In __init__:
self.last_engaged_frame = -1
self.last_engage_attempt_frame = -1
# In update_events, BEFORE the lag/comm checks:
if CS.cruiseState.enabled and not self.CS_prev.cruiseState.enabled:
self.last_engage_attempt_frame = self.sm.frame
# At the engaged-state transition (state_transition):
enabled_prev = self.enabled
self.enabled = self.state in ENABLED_STATES
if self.enabled and not enabled_prev:
self.last_engaged_frame = self.sm.frame
# Gate logic in update_events:
in_engage_grace = (
(self.last_engaged_frame >= 0
and (self.sm.frame - self.last_engaged_frame) < self.POST_ENGAGE_LAG_GRACE_FRAMES)
or
(self.last_engage_attempt_frame >= 0
and (self.sm.frame - self.last_engage_attempt_frame) < self.POST_ENGAGE_LAG_GRACE_FRAMES)
)
if not REPLAY and self.rk.lagging and not in_engage_grace:
self.events.add(EventName.controlsdLagging)
# ... and similarly suppress commIssue when in_engage_grace
```
### 5. Fan range rules (port from broken tree)
Independent of park-mode plumbing. Widen the fan PID range when the car
is parked so the device can fully cool while the user can't hear road
noise.
`selfdrive/thermald/fan_controller.py`:
```python
def update(self, cur_temp, ignition, standstill=False, is_parked=True, cruise_engaged=False):
# neg_limit = -max_fan_pct, pos_limit = -min_fan_pct
if not ignition:
self.controller.neg_limit = -30
self.controller.pos_limit = 0
elif is_parked:
self.controller.neg_limit = -100
self.controller.pos_limit = 0 # 0-100% (full range)
elif cruise_engaged:
self.controller.neg_limit = -100
self.controller.pos_limit = -30 # 30-100%
elif standstill:
self.controller.neg_limit = -100
self.controller.pos_limit = -10 # 10-100%
else:
self.controller.neg_limit = -100
self.controller.pos_limit = -30 # 30-100%
```
`selfdrive/thermald/thermald.py`:
```python
# Add carState to the SubMaster service list
sm = messaging.SubMaster([..., "carState"], poll="pandaStates")
# At the fan_controller.update call site:
if sm.seen['carState']:
cs = sm['carState']
standstill = cs.standstill
is_parked = cs.gearShifter == car.CarState.GearShifter.park
else:
standstill = False
is_parked = True # default safe: assume parked, no fan floor
cruise_engaged = sm['controlsState'].enabled if sm.seen['controlsState'] else False
msg.deviceState.fanSpeedPercentDesired = fan_controller.update(
all_comp_temp, onroad_conditions["ignition"], standstill,
is_parked=is_parked, cruise_engaged=cruise_engaged)
```
This piece worked fine standalone — it's safe to land on its own without
the rest of the park-mode plumbing. (It does require the thermald
carState subscription to actually receive carState — which is fine in
normal operation.)
## What broke
### A. card.initialize() not called → silent CAN
First attempt entered park-mode immediately whenever `gearShifter ==
PARK`, including before controlsd had ever passed through its
`if not self.initialized` branch. Symptoms:
- UI stuck on splash even after shift to drive
- carState never published to cereal (tested by subscribing externally)
- presumably the steering ECU was getting no heartbeat, though we
hadn't yet tried to engage
Fix: `_park_mode_allowed` gate, requires `self.initialized` AND a 10 s
post-init buffer. **Critical.** Don't skip this in v2.
### B. Park-grace cap (8 s) too short
Cold-spawn chain length:
1. modeld load thneed weights, init GPU (~3-5 s)
2. modeld publishes modelV2
3. plannerd consumes modelV2, publishes longitudinalPlan
4. frogpilot_process consumes modelV2, publishes frogpilotPlan
5. paramsd, torqued, calibrationd estimators accumulate enough samples
to set valid=True
In testing this cumulatively exceeded 8 s. We bumped the cap to 15 s.
**Even 15 s wasn't enough in some test runs** — got commIssue alerts
with longitudinalPlan / frogpilotPlan still invalid past the cap.
Possible fixes for v2:
- Even longer cap (30 s)
- Or condition-only with no cap (live with the risk that a genuinely
broken service strands controlsd in keepalive forever)
- Or **a different approach**: don't actually pause modeld; throttle it
to 1 fps when stopped (this is what the broken tree's CLAUDE.md
pending-features list described as "modeld throttled to 1fps when
stopped"). Avoids the cold-spawn entirely.
### C. NO_ENTRY alerts fire on engage attempt, not engage success
`controlsdLagging` and `commIssue` both have `ET.NO_ENTRY`. NO_ENTRY
alerts fire when the user *tries* to engage but the event blocks them.
At that moment `self.enabled` hasn't flipped yet, so a grace keyed on
`last_engaged_frame` is inert.
Fix: also track `CS.cruiseState.enabled` rising edge as
`last_engage_attempt_frame`. See "Engage-attempt grace" above.
### D. Cascade of related alerts
After all the above were patched, in-car testing still produced
"locationd temporaryError" and "sensorDataInvalid" alerts after the
post-engage grace window expired. We didn't have time to chase these
down before reverting. Hypotheses:
- locationd's kalman filter needs more than ~15 s to converge after
cold spawn, especially without GPS feeding it (we explicitly skip
GPS in locationd).
- sensord might lose its IMU sample lock and need re-init when
killed/restarted.
These are an argument for the "throttle, don't kill" approach in v2.
### E. Sensor data invalid
`sensorDataInvalid` likely stems from sensord being killed and
restarted. The IMU init handshake takes time, and during that window
`accelerometer` / `gyroscope` services are alive but their data hasn't
stabilized — locationd reports invalid, controlsd alerts.
Same fix family as (D).
## Recommended approach for v2
The "kill processes" approach is architecturally clean but creates a
big cold-spawn cliff every time the user shifts to drive. The v2 plan
should probably look more like:
1. **Throttle, don't kill.** Send a "standby" memory param that modeld
reads and reduces its tick rate to 1 fps. dmonitoringmodeld likewise.
Plannerd/radard naturally adapt to slower modelV2 input. paramsd /
torqued / calibrationd / locationd keep accumulating slowly.
2. **Keep controlsd's main loop running normally** — no park_mode_tick.
The state machine already handles "not engaged" → no actuators →
passive. The heartbeat flows naturally because `state_control` /
`publish_logs` run every cycle.
3. **Apply the fan-range widening (Section 5 of "Design")** — that
piece is independently valuable and doesn't depend on the rest.
4. **Skip dashcamd touchpoints.** dashcamd is already gear-aware via
its own state machine and pauses recording in park naturally.
5. **Keep the `_park_mode_allowed` startup-delay gate concept** if any
form of conditional-shutdown is reintroduced — this guards against
`card.initialize()` being skipped.
### Files involved (for reference)
| File | Why |
|---|---|
| `common/params.cc` | register `ParkMode` (or `ModelStandby` etc.) |
| `selfdrive/manager/manager.py` | `manager_init` memory-param defaults |
| `selfdrive/manager/process_config.py` | gating helpers |
| `selfdrive/controls/controlsd.py` | the park branch and engage-grace |
| `selfdrive/thermald/fan_controller.py` | fan range rules |
| `selfdrive/thermald/thermald.py` | carState sub for fan rules |
| `selfdrive/modeld/modeld.py` (v2) | throttle on standby flag |
| `selfdrive/modeld/dmonitoringmodeld.py` (v2) | throttle on standby flag |
### Reference commits (force-pushed away from origin/clearpilot, but the
text of this document captures the substance)
- park-mode initial: bring up flag + gating + controlsd keepalive
- park-mode startup gate: 10 s post-init delay before allowing park
- engage-grace: 3 s suppression on engage edge for controlsdLagging
- engage-attempt grace + grace cap bump to 15 s
These were all on top of `stable_5_4_26` (`0d1cedd`).
+4 -1
View File
@@ -79,8 +79,11 @@ function launch {
agnos_init agnos_init
fi fi
# CLEARPILOT: kill stale error display from previous build/run # CLEARPILOT: kill stale error display from previous build/run.
# `text` is a wrapper that execs ./_text — running process is named _text
# with no path, so kill by exact comm too.
pkill -f "selfdrive/ui/text" 2>/dev/null pkill -f "selfdrive/ui/text" 2>/dev/null
pkill -x _text 2>/dev/null
# write tmux scrollback to a file # write tmux scrollback to a file
tmux capture-pane -pq -S-1000 > /tmp/launch_log tmux capture-pane -pq -S-1000 > /tmp/launch_log
+9
View File
@@ -13,8 +13,17 @@ pkill -9 -f 'selfdrive\.' 2>/dev/null
pkill -9 -f 'system\.' 2>/dev/null pkill -9 -f 'system\.' 2>/dev/null
pkill -9 -f './ui' 2>/dev/null pkill -9 -f './ui' 2>/dev/null
pkill -9 -f 'selfdrive/ui/text' 2>/dev/null pkill -9 -f 'selfdrive/ui/text' 2>/dev/null
# `text` is a shell wrapper that execs `./_text` — after exec the running
# process's argv has no path, so kill by exact comm too.
pkill -9 -x _text 2>/dev/null
sleep 1 sleep 1
# CLEARPILOT: ensure params persistence dir is owned by comma:comma. Editing
# the tree as root leaves files owned by root in /data/params/d_tmp/, and
# Params writes done as comma will then EACCES on rename. Reset on every
# launch so this never silently breaks again.
sudo chown -R comma:comma /data/params
bash /data/openpilot/system/clearpilot/on_start.sh bash /data/openpilot/system/clearpilot/on_start.sh
# CLEARPILOT: start VPN monitor (kills previous instances, runs as root) # CLEARPILOT: start VPN monitor (kills previous instances, runs as root)
+12 -1
View File
@@ -1,7 +1,17 @@
----- -----
- screen off on lkas - fix debug notice message
- screen mode 1 = no UI, screen mode 2 = off
- speed limit change chirp on cruise - speed limit change chirp on cruise
- fix always on detection, change message
-----
- Better debugger and data recorder
- Represent distance to lead car on primary UI
- Start testing for alert when stopped traffic and approaching > 31 mph
- or not enough time to slow at 31
- special experimental mode override?
----- -----
@@ -11,6 +21,7 @@
- better turning logic - better turning logic
- new settings UI - new settings UI
- experimental mode - experimental mode
- resume from stop
------------ ------------
-1
View File
@@ -166,7 +166,6 @@ Export('base_project_f4', 'base_project_h7', 'build_project')
# Common autogenerated includes # Common autogenerated includes
os.makedirs("board/obj", exist_ok=True)
with open("board/obj/gitversion.h", "w") as f: with open("board/obj/gitversion.h", "w") as f:
f.write(f'const uint8_t gitversion[] = "{get_version(BUILDER, BUILD_TYPE)}";\n') f.write(f'const uint8_t gitversion[] = "{get_version(BUILDER, BUILD_TYPE)}";\n')
+1 -3
View File
@@ -32,9 +32,7 @@ def main():
continue continue
cloudlog.info("starting athena daemon") cloudlog.info("starting athena daemon")
from openpilot.selfdrive.manager.process import _log_dir proc = Process(name='athenad', target=launcher, args=('selfdrive.athena.athenad', 'athenad'))
log_path = _log_dir + "/athenad.log"
proc = Process(name='athenad', target=launcher, args=('selfdrive.athena.athenad', 'athenad', log_path))
proc.start() proc.start()
proc.join() proc.join()
cloudlog.event("athenad exited", exitcode=proc.exitcode) cloudlog.event("athenad exited", exitcode=proc.exitcode)
+2 -4
View File
@@ -8,6 +8,7 @@ from openpilot.selfdrive.car.hyundai import hyundaicanfd, hyundaican
from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CANFD_CAR, CAR from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CANFD_CAR, CAR
from openpilot.selfdrive.car.interfaces import CarControllerBase from openpilot.selfdrive.car.interfaces import CarControllerBase
from openpilot.common.params import Params
VisualAlert = car.CarControl.HUDControl.VisualAlert VisualAlert = car.CarControl.HUDControl.VisualAlert
LongCtrlState = car.CarControl.Actuators.LongControlState LongCtrlState = car.CarControl.Actuators.LongControlState
@@ -56,7 +57,6 @@ class CarController(CarControllerBase):
self.car_fingerprint = CP.carFingerprint self.car_fingerprint = CP.carFingerprint
self.last_button_frame = 0 self.last_button_frame = 0
def update(self, CC, CS, now_nanos, frogpilot_variables): def update(self, CC, CS, now_nanos, frogpilot_variables):
actuators = CC.actuators actuators = CC.actuators
hud_control = CC.hudControl hud_control = CC.hudControl
@@ -112,9 +112,7 @@ class CarController(CarControllerBase):
hda2_long = hda2 and self.CP.openpilotLongitudinalControl hda2_long = hda2 and self.CP.openpilotLongitudinalControl
# steering control # steering control
# CLEARPILOT: no_lat_lane_change comes via frogpilot_variables (set by controlsd in-process) can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_steer))
no_lat_lane_change = int(getattr(frogpilot_variables, 'no_lat_lane_change', False))
can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_steer, no_lat_lane_change))
# prevent LFA from activating on HDA2 by sending "no lane lines detected" to ADAS ECU # prevent LFA from activating on HDA2 by sending "no lane lines detected" to ADAS ECU
if self.frame % 5 == 0 and hda2: if self.frame % 5 == 0 and hda2:
+7 -30
View File
@@ -13,7 +13,6 @@ from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CAN_GEARS, CAMERA_SCC_CAR, \ from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CAN_GEARS, CAMERA_SCC_CAR, \
CANFD_CAR, Buttons, CarControllerParams CANFD_CAR, Buttons, CarControllerParams
from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.interfaces import CarStateBase
from openpilot.selfdrive.clearpilot.telemetry import tlog
PREV_BUTTON_SAMPLES = 8 PREV_BUTTON_SAMPLES = 8
CLUSTER_SAMPLE_RATE = 20 # frames CLUSTER_SAMPLE_RATE = 20 # frames
@@ -48,10 +47,6 @@ class CarState(CarStateBase):
self.is_metric = False self.is_metric = False
self.buttons_counter = 0 self.buttons_counter = 0
# CLEARPILOT: cache to avoid per-cycle atomic writes to /dev/shm (eats CPU via fsync/flock)
self._prev_car_speed_limit = None
self._prev_car_is_metric = None
self.cruise_info = {} self.cruise_info = {}
# On some cars, CLU15->CF_Clu_VehicleSpeed can oscillate faster than the dash updates. Sample at 5 Hz # On some cars, CLU15->CF_Clu_VehicleSpeed can oscillate faster than the dash updates. Sample at 5 Hz
@@ -214,14 +209,9 @@ class CarState(CarStateBase):
self.lkas_previously_enabled = self.lkas_enabled self.lkas_previously_enabled = self.lkas_enabled
self.lkas_enabled = cp.vl["BCM_PO_11"]["LFA_Pressed"] self.lkas_enabled = cp.vl["BCM_PO_11"]["LFA_Pressed"]
# CLEARPILOT: gate on change — see same fix in update_canfd # self.params_memory.put_int("CarSpeedLimitLiteral", self.calculate_speed_limit(cp, cp_cam))
car_speed_limit = self.calculate_speed_limit(cp, cp_cam) * speed_conv self.params_memory.put_float("CarSpeedLimit", self.calculate_speed_limit(cp, cp_cam) * speed_conv)
if car_speed_limit != self._prev_car_speed_limit: self.params_memory.put_float("CarCruiseDisplayActual", cp_cruise.vl["SCC11"]["VSetDis"])
self.params_memory.put_float("CarSpeedLimit", car_speed_limit)
self._prev_car_speed_limit = car_speed_limit
if self.is_metric != self._prev_car_is_metric:
self.params_memory.put("CarIsMetric", "1" if self.is_metric else "0")
self._prev_car_is_metric = self.is_metric
return ret return ret
@@ -425,23 +415,10 @@ class CarState(CarStateBase):
# nonAdaptive = false, # nonAdaptive = false,
# speedCluster = 0 ) # speedCluster = 0 )
# CLEARPILOT: gate on change — these writes run 100Hz, each is an atomic fsync/flock transaction # print("Set limit")
car_speed_limit = self.calculate_speed_limit(cp, cp_cam) * speed_factor # print(self.calculate_speed_limit(cp, cp_cam))
if car_speed_limit != self._prev_car_speed_limit: # self.params_memory.put_float("CarSpeedLimitLiteral", self.calculate_speed_limit(cp, cp_cam))
self.params_memory.put_float("CarSpeedLimit", car_speed_limit) self.params_memory.put_float("CarSpeedLimit", self.calculate_speed_limit(cp, cp_cam) * speed_factor)
self._prev_car_speed_limit = car_speed_limit
if self.is_metric != self._prev_car_is_metric:
self.params_memory.put("CarIsMetric", "1" if self.is_metric else "0")
self._prev_car_is_metric = self.is_metric
# CLEARPILOT: telemetry logging — disabled, re-enable when needed
# speed_limit_bus = cp if self.CP.flags & HyundaiFlags.CANFD_HDA2 else cp_cam
# scc = cp_cam.vl["SCC_CONTROL"] if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp.vl["SCC_CONTROL"]
# cluster = speed_limit_bus.vl["CLUSTER_SPEED_LIMIT"]
# tlog("car", { ... })
# tlog("cruise", { ... })
# tlog("speed_limit", { ... })
# tlog("buttons", { ... })
return ret return ret
+9 -3
View File
@@ -2,6 +2,7 @@ from openpilot.common.numpy_fast import clip
from openpilot.selfdrive.car import CanBusBase from openpilot.selfdrive.car import CanBusBase
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags from openpilot.selfdrive.car.hyundai.values import HyundaiFlags
from openpilot.common.params import Params
class CanBus(CanBusBase): class CanBus(CanBusBase):
def __init__(self, CP, hda2=None, fingerprint=None) -> None: def __init__(self, CP, hda2=None, fingerprint=None) -> None:
@@ -35,9 +36,12 @@ class CanBus(CanBusBase):
return self._cam return self._cam
def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_steer, no_lat_lane_change=0): def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_steer):
# CLEARPILOT: no_lat_lane_change is passed in by the caller so we can hoist
# the Params read out of the 100Hz hot path (was ~5% of carcontroller time) # Im sure there is a better way to do this
params_memory = Params("/dev/shm/params")
no_lat_lane_change = params_memory.get_int("no_lat_lane_change", 1)
ret = [] ret = []
values = { values = {
@@ -126,6 +130,8 @@ def create_buttons(packer, CP, CAN, cnt, btn):
def create_buttons_alt(packer, CP, CAN, cnt, btn, template): def create_buttons_alt(packer, CP, CAN, cnt, btn, template):
return return
params_memory = Params("/dev/shm/params")
CarCruiseDisplayActual = params_memory.get_float("CarCruiseDisplayActual")
values = { values = {
"COUNTER": cnt, "COUNTER": cnt,
-9
View File
@@ -484,19 +484,10 @@ class CarInterfaceBase(ABC):
self.silent_steer_warning = True self.silent_steer_warning = True
events.add(EventName.steerTempUnavailableSilent) events.add(EventName.steerTempUnavailableSilent)
else: else:
# CLEARPILOT: log once per instance of this warning
if not getattr(self, '_steer_fault_logged', False):
import sys
print(f"CLP steerTempUnavailable: steerFaultTemporary={cs_out.steerFaultTemporary} "
f"steeringPressed={cs_out.steeringPressed} standstill={cs_out.standstill} "
f"steering_unpressed={self.steering_unpressed} steeringAngleDeg={cs_out.steeringAngleDeg:.1f} "
f"steeringTorque={cs_out.steeringTorque:.1f} vEgo={cs_out.vEgo:.2f}", file=sys.stderr)
self._steer_fault_logged = True
events.add(EventName.steerTempUnavailable) events.add(EventName.steerTempUnavailable)
else: else:
self.no_steer_warning = False self.no_steer_warning = False
self.silent_steer_warning = False self.silent_steer_warning = False
self._steer_fault_logged = False
if cs_out.steerFaultPermanent: if cs_out.steerFaultPermanent:
events.add(EventName.steerUnavailable) events.add(EventName.steerUnavailable)
-147
View File
@@ -1,147 +0,0 @@
#!/usr/bin/env python3
"""
ClearPilot bench command tool. Sets bench params and queries UI state.
Usage:
python3 -m selfdrive.clearpilot.bench_cmd gear D
python3 -m selfdrive.clearpilot.bench_cmd speed 20
python3 -m selfdrive.clearpilot.bench_cmd speedlimit 45
python3 -m selfdrive.clearpilot.bench_cmd cruise 55
python3 -m selfdrive.clearpilot.bench_cmd cruiseactive 0|1|2 (0=disabled, 1=active, 2=paused)
python3 -m selfdrive.clearpilot.bench_cmd engaged 1
python3 -m selfdrive.clearpilot.bench_cmd ding (trigger speed limit ding sound)
python3 -m selfdrive.clearpilot.bench_cmd debugbutton (simulate LKAS debug button press)
python3 -m selfdrive.clearpilot.bench_cmd dump
python3 -m selfdrive.clearpilot.bench_cmd wait_ready
"""
import os
import subprocess
import sys
import time
import zmq
from openpilot.common.params import Params
def check_ui_process():
"""Check if UI process is running and healthy. Returns error string or None if OK."""
try:
result = subprocess.run(["pgrep", "-a", "-f", "./ui"], capture_output=True, text=True)
if result.returncode != 0:
return "ERROR: UI process not running"
# Get the PID and check its uptime
for line in result.stdout.strip().split("\n"):
parts = line.split(None, 1)
if len(parts) >= 2 and "./ui" in parts[1]:
pid = parts[0]
try:
stat = os.stat(f"/proc/{pid}")
uptime = time.time() - stat.st_mtime
if uptime < 5:
return f"ERROR: UI process (pid {pid}) uptime {uptime:.1f}s — likely crash looping. Check: tail /data/log2/$(ls -t /data/log2/ | head -1)/session.log"
except FileNotFoundError:
return "ERROR: UI process disappeared"
except Exception:
pass
return None
def ui_dump():
ctx = zmq.Context()
sock = ctx.socket(zmq.REQ)
sock.setsockopt(zmq.RCVTIMEO, 2000)
sock.connect("ipc:///tmp/clearpilot_ui_rpc")
sock.send_string("dump")
try:
return sock.recv_string()
except zmq.Again:
return None
finally:
sock.close()
ctx.term()
def wait_ready(timeout=20):
"""Wait until the UI shows ReadyWindow, up to timeout seconds."""
start = time.time()
while time.time() - start < timeout:
dump = ui_dump()
if dump and "ReadyWindow" in dump:
# Check it's actually visible
for line in dump.split("\n"):
if "ReadyWindow" in line and "vis=Y" in line:
print("UI ready (ReadyWindow visible)")
return True
time.sleep(1)
print(f"ERROR: UI not ready after {timeout}s")
if dump:
print(dump)
return False
def main():
if len(sys.argv) < 2:
print(__doc__)
return
cmd = sys.argv[1].lower()
params = Params("/dev/shm/params")
param_map = {
"gear": "BenchGear",
"speed": "BenchSpeed",
"speedlimit": "BenchSpeedLimit",
"cruise": "BenchCruiseSpeed",
"cruiseactive": "BenchCruiseActive",
"engaged": "BenchEngaged",
}
if cmd == "dump":
ui_status = check_ui_process()
if ui_status:
print(ui_status)
else:
result = ui_dump()
if result:
print(result)
else:
print("ERROR: UI not responding")
elif cmd == "wait_ready":
wait_ready()
elif cmd == "ding":
params.put("ClearpilotPlayDing", "1")
print("Ding triggered")
elif cmd == "debugbutton":
# Simulate LKAS debug button — same state machine as controlsd.clearpilot_state_control()
current = params.get_int("ScreenDisplayMode")
gear = (params.get("BenchGear") or b"P").decode().strip().upper()
in_drive = gear in ("D", "S", "L")
if in_drive:
transitions = {0: 4, 1: 2, 2: 3, 3: 4, 4: 2}
new_mode = transitions.get(current, 0)
else:
new_mode = 0 if current == 3 else 3
params.put_int("ScreenDisplayMode", new_mode)
mode_names = {0: "auto-normal", 1: "auto-nightrider", 2: "normal", 3: "screen-off", 4: "nightrider"}
print(f"ScreenDisplayMode: {current} ({mode_names.get(current, '?')}) → {new_mode} ({mode_names.get(new_mode, '?')})"
f" [gear={gear}, in_drive={in_drive}]")
elif cmd in param_map:
if len(sys.argv) < 3:
print(f"Usage: bench_cmd {cmd} <value>")
return
value = sys.argv[2]
params.put(param_map[cmd], value)
print(f"{param_map[cmd]} = {value}")
else:
print(f"Unknown command: {cmd}")
print(__doc__)
if __name__ == "__main__":
main()
-137
View File
@@ -1,137 +0,0 @@
#!/usr/bin/env python3
"""
ClearPilot bench onroad simulator.
Publishes fake messages to make the UI go onroad and display
configurable vehicle state. Control values via params in /dev/shm/params:
BenchSpeed - vehicle speed in mph (default: 0)
BenchSpeedLimit - speed limit in mph (default: 0, 0=hidden)
BenchCruiseSpeed - cruise set speed in mph (default: 0, 0=not set)
BenchCruiseActive - 0=disabled, 1=active, 2=paused/standstill (default: 0)
BenchGear - P, D, R, N (default: P)
BenchEngaged - 0 or 1, cruise engaged (default: 0)
Usage:
su - comma -c "PYTHONPATH=/data/openpilot python3 -m selfdrive.clearpilot.bench_onroad"
To stop: Ctrl+C or kill the process. UI returns to offroad.
"""
import time
import cereal.messaging as messaging
from cereal import log, car
from openpilot.common.params import Params
from openpilot.common.conversions import Conversions as CV
from openpilot.selfdrive.clearpilot.speed_logic import SpeedState
def main():
params = Params()
params_mem = Params("/dev/shm/params")
# Set defaults
params_mem.put("BenchSpeed", "0")
params_mem.put("BenchSpeedLimit", "0")
params_mem.put("BenchCruiseSpeed", "0")
params_mem.put("BenchCruiseActive", "0")
params_mem.put("BenchGear", "P")
params_mem.put("BenchEngaged", "0")
# ClearPilot speed processing
speed_state = SpeedState()
# thermald handles deviceState (reads our fake pandaStates for ignition)
pm = messaging.PubMaster([
"pandaStates", "carState", "controlsState",
"driverMonitoringState", "liveCalibration",
])
print("Bench onroad simulator started")
print("Set values in /dev/shm/params/d/Bench*")
print(" BenchSpeed=0 BenchSpeedLimit=0 BenchCruiseSpeed=0 BenchGear=P BenchEngaged=0")
gear_map = {
"P": car.CarState.GearShifter.park,
"D": car.CarState.GearShifter.drive,
"R": car.CarState.GearShifter.reverse,
"N": car.CarState.GearShifter.neutral,
}
frame = 0
try:
while True:
# Read bench params
speed_mph = float((params_mem.get("BenchSpeed", encoding="utf-8") or "0").strip())
speed_limit_mph = float((params_mem.get("BenchSpeedLimit", encoding="utf-8") or "0").strip())
cruise_mph = float((params_mem.get("BenchCruiseSpeed", encoding="utf-8") or "0").strip())
gear_str = (params_mem.get("BenchGear", encoding="utf-8") or "P").strip().upper()
cruise_active_str = (params_mem.get("BenchCruiseActive", encoding="utf-8") or "0").strip()
engaged = (params_mem.get("BenchEngaged", encoding="utf-8") or "0").strip() == "1"
speed_ms = speed_mph * CV.MPH_TO_MS
speed_limit_ms = speed_limit_mph * CV.MPH_TO_MS
cruise_ms = cruise_mph * CV.MPH_TO_MS
gear = gear_map.get(gear_str, car.CarState.GearShifter.park)
# Cruise state: 0=disabled, 1=active, 2=paused
cruise_active = cruise_active_str == "1"
cruise_standstill = cruise_active_str == "2"
# ClearPilot speed processing (~2 Hz at 10 Hz loop)
if frame % 5 == 0:
has_speed = speed_mph > 0
speed_state.update(speed_ms, has_speed, speed_limit_ms, is_metric=False,
cruise_speed_ms=cruise_ms, cruise_active=cruise_active or cruise_standstill,
cruise_standstill=cruise_standstill)
# pandaStates — 10 Hz (thermald reads ignition from this)
if frame % 1 == 0:
dat = messaging.new_message("pandaStates", 1)
dat.pandaStates[0].ignitionLine = True
dat.pandaStates[0].pandaType = log.PandaState.PandaType.tres
pm.send("pandaStates", dat)
# carState — 10 Hz
dat = messaging.new_message("carState")
cs = dat.carState
cs.vEgo = speed_ms
cs.vEgoCluster = speed_ms
cs.gearShifter = gear
cs.standstill = speed_ms < 0.1
cs.cruiseState.available = True
cs.cruiseState.enabled = engaged
cs.cruiseState.speed = cruise_mph * CV.MPH_TO_MS if cruise_mph > 0 else 0
pm.send("carState", dat)
# controlsState — 10 Hz
dat = messaging.new_message("controlsState")
ctl = dat.controlsState
ctl.vCruise = cruise_mph * 1.60934 if cruise_mph > 0 else 255 # km/h or 255=not set
ctl.vCruiseCluster = ctl.vCruise
ctl.enabled = engaged
ctl.active = engaged
pm.send("controlsState", dat)
# driverMonitoringState — low freq
if frame % 10 == 0:
dat = messaging.new_message("driverMonitoringState")
dat.driverMonitoringState.isActiveMode = True
pm.send("driverMonitoringState", dat)
# liveCalibration — low freq
if frame % 50 == 0:
dat = messaging.new_message("liveCalibration")
dat.liveCalibration.calStatus = log.LiveCalibrationData.Status.calibrated
dat.liveCalibration.rpyCalib = [0.0, 0.0, 0.0]
pm.send("liveCalibration", dat)
frame += 1
time.sleep(0.1) # 10 Hz base loop
except KeyboardInterrupt:
print("\nBench simulator stopped")
if __name__ == "__main__":
main()
Binary file not shown.
-121
View File
@@ -1,121 +0,0 @@
#!/usr/bin/env python3
"""
CLEARPILOT dashcamd — records raw camera footage to MP4 using hardware H.264 encoder.
Connects directly to camerad via VisionIPC, receives NV12 frames, and pipes them
to ffmpeg's h264_v4l2m2m encoder. Produces 3-minute MP4 segments in /data/media/0/videos/.
This replaces the FrogPilot screen recorder approach (QWidget::grab -> OMX) with a
direct camera capture that works regardless of UI state (screen off, alternate modes, etc).
"""
import os
import time
import subprocess
import signal
from pathlib import Path
from datetime import datetime
from cereal.visionipc import VisionIpcClient, VisionStreamType
from openpilot.common.params import Params
from openpilot.common.swaglog import cloudlog
from openpilot.selfdrive import sentry
PROCESS_NAME = "selfdrive.clearpilot.dashcamd"
VIDEOS_DIR = "/data/media/0/videos"
SEGMENT_SECONDS = 180 # 3 minutes
CAMERA_FPS = 20
FRAMES_PER_SEGMENT = SEGMENT_SECONDS * CAMERA_FPS
def make_filename():
return datetime.now().strftime("%Y%m%d-%H%M%S") + ".mp4"
def open_encoder(width, height, filepath):
"""Start an ffmpeg subprocess that accepts raw NV12 on stdin and writes MP4."""
cmd = [
"ffmpeg", "-y", "-nostdin", "-loglevel", "error",
"-f", "rawvideo",
"-pix_fmt", "nv12",
"-s", f"{width}x{height}",
"-r", str(CAMERA_FPS),
"-i", "pipe:0",
"-c:v", "h264_v4l2m2m",
"-b:v", "4M",
"-f", "mp4",
"-movflags", "+faststart",
filepath,
]
return subprocess.Popen(cmd, stdin=subprocess.PIPE)
def main():
sentry.set_tag("daemon", PROCESS_NAME)
cloudlog.bind(daemon=PROCESS_NAME)
os.makedirs(VIDEOS_DIR, exist_ok=True)
params = Params()
# Connect to camerad road stream
cloudlog.info("dashcamd: connecting to camerad road stream")
vipc = VisionIpcClient("camerad", VisionStreamType.VISION_STREAM_ROAD, False)
while not vipc.connect(False):
time.sleep(0.1)
width, height = vipc.width, vipc.height
# NV12 frame: Y plane (w*h) + UV plane (w*h/2)
frame_size = width * height * 3 // 2
cloudlog.info(f"dashcamd: connected, {width}x{height}, frame_size={frame_size}")
frame_count = 0
encoder = None
lock_path = None
try:
while True:
buf = vipc.recv()
if buf is None:
continue
# Start new segment if needed
if encoder is None or frame_count >= FRAMES_PER_SEGMENT:
# Close previous segment
if encoder is not None:
encoder.stdin.close()
encoder.wait()
if lock_path and os.path.exists(lock_path):
os.remove(lock_path)
cloudlog.info(f"dashcamd: closed segment, {frame_count} frames")
# Open new segment
filename = make_filename()
filepath = os.path.join(VIDEOS_DIR, filename)
lock_path = filepath + ".lock"
Path(lock_path).touch()
cloudlog.info(f"dashcamd: opening segment {filename}")
encoder = open_encoder(width, height, filepath)
frame_count = 0
# Write raw NV12 frame to ffmpeg stdin
try:
encoder.stdin.write(buf.data[:frame_size])
frame_count += 1
except BrokenPipeError:
cloudlog.error("dashcamd: encoder pipe broken, restarting segment")
encoder = None
except (KeyboardInterrupt, SystemExit):
pass
finally:
if encoder is not None:
encoder.stdin.close()
encoder.wait()
if lock_path and os.path.exists(lock_path):
os.remove(lock_path)
cloudlog.info("dashcamd: stopped")
if __name__ == "__main__":
main()
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env python3
"""
ClearPilot speed/cruise daemon.
Subscribes to gpsLocation (for vehicle speed display) and carState (for
cruise state), reads CarSpeedLimit from /dev/shm/params, and ticks
SpeedState at ~2 Hz. SpeedState writes the display params the onroad UI
reads, and asserts ClearpilotPlayDing="1" on speed-limit warning
transitions (soundd consumes that flag).
Decoupled from controlsd so self-driving timing isn't affected.
"""
import sys
import cereal.messaging as messaging
from openpilot.common.params import Params
from openpilot.common.realtime import Ratekeeper
from openpilot.selfdrive.clearpilot.speed_logic import SpeedState
def main():
print("CLP speed_logicd: starting", file=sys.stderr, flush=True)
params = Params()
params_memory = Params("/dev/shm/params")
speed_state = SpeedState()
is_metric = params.get_bool("IsMetric")
sm = messaging.SubMaster(['gpsLocation', 'carState'])
rk = Ratekeeper(2.0, print_delay_threshold=None)
while True:
sm.update(0)
gps = sm['gpsLocation']
has_gps = sm.valid['gpsLocation'] and gps.hasFix
speed_ms = float(gps.speed) if has_gps else 0.0
cs = sm['carState']
cruise_speed_ms = float(cs.cruiseState.speed)
cruise_active = bool(cs.cruiseState.enabled)
cruise_standstill = bool(cs.cruiseState.standstill)
# CarSpeedLimit is published by hyundai/carstate.py CAN-FD decode (when
# ported). Until then it's 0 / empty and the speed-limit + warning logic
# naturally short-circuits.
try:
speed_limit_ms = float(params_memory.get("CarSpeedLimit") or 0.0)
except (TypeError, ValueError):
speed_limit_ms = 0.0
speed_state.update(speed_ms, has_gps, speed_limit_ms, is_metric,
cruise_speed_ms, cruise_active, cruise_standstill)
rk.keep_time()
if __name__ == "__main__":
main()
-53
View File
@@ -1,53 +0,0 @@
"""
ClearPilot telemetry client library.
Usage from any process:
from openpilot.selfdrive.clearpilot.telemetry import tlog
tlog("canbus", {"speed": 45.2, "speed_limit": 60})
Sends JSON packets over ZMQ PUSH to telemetryd, which diffs and writes CSV.
Only sends when TelemetryEnabled memory param is set — zero cost when disabled.
"""
import json
import os
import time
import zmq
TELEMETRY_SOCK = "ipc:///tmp/clearpilot_telemetry"
_PARAM_PATH = "/dev/shm/params/d/TelemetryEnabled"
_ctx = None
_sock = None
_last_check = 0
_enabled = False
def tlog(group: str, data: dict):
"""Log a telemetry packet. Only changed values will be written to CSV by telemetryd."""
global _ctx, _sock, _last_check, _enabled
# Check param at most once per second to avoid filesystem overhead
now = time.monotonic()
if now - _last_check > 1.0:
_last_check = now
try:
with open(_PARAM_PATH, 'r') as f:
_enabled = f.read().strip() == "1"
except (FileNotFoundError, IOError):
_enabled = False
if not _enabled:
return
if _sock is None:
_ctx = zmq.Context.instance()
_sock = _ctx.socket(zmq.PUSH)
_sock.setsockopt(zmq.LINGER, 0)
_sock.setsockopt(zmq.SNDHWM, 100)
_sock.connect(TELEMETRY_SOCK)
msg = json.dumps({"ts": time.time(), "group": group, "data": data})
try:
_sock.send_string(msg, zmq.NOBLOCK)
except zmq.Again:
pass # drop if collector isn't running or queue full
-147
View File
@@ -1,147 +0,0 @@
#!/usr/bin/env python3
"""
ClearPilot telemetry collector.
Receives telemetry packets from any process via ZMQ, diffs against previous
state per group, and writes only changed values to CSV.
Controlled by TelemetryEnabled param — when toggled on, the first packet
from each group writes all values (full dump). When toggled off, stops writing.
CSV format: timestamp,group,key,value
"""
import csv
import json
import os
import shutil
import time
import zmq
import cereal.messaging as messaging
from openpilot.common.params import Params
from openpilot.selfdrive.clearpilot.telemetry import TELEMETRY_SOCK
from openpilot.selfdrive.manager.process import _log_dir, session_log
MIN_DISK_FREE_GB = 5
DISK_CHECK_INTERVAL = 10 # seconds
def main():
params = Params("/dev/shm/params")
ctx = zmq.Context.instance()
sock = ctx.socket(zmq.PULL)
sock.setsockopt(zmq.RCVHWM, 1000)
sock.bind(TELEMETRY_SOCK)
# GPS subscriber for location telemetry
sm = messaging.SubMaster(['gpsLocation'])
last_gps_log = 0
csv_path = os.path.join(_log_dir, "telemetry.csv")
state: dict[str, dict] = {} # group -> {key: last_value}
was_enabled = False
writer = None
f = None
last_disk_check = 0
while True:
# Check enable state every iteration (cheap param read)
enabled = params.get("TelemetryEnabled") == b"1"
# Check disk space every 10 seconds while enabled
if enabled and (time.monotonic() - last_disk_check) > DISK_CHECK_INTERVAL:
last_disk_check = time.monotonic()
disk = shutil.disk_usage("/data")
free_gb = disk.free / (1024 ** 3)
if free_gb < MIN_DISK_FREE_GB:
session_log.warning("telemetry disabled: disk free %.1f GB < %d GB", free_gb, MIN_DISK_FREE_GB)
params.put("TelemetryEnabled", "0")
enabled = False
# Toggled on: open CSV, clear state so first packet is a full dump
if enabled and not was_enabled:
f = open(csv_path, "a", newline="")
writer = csv.writer(f)
if os.path.getsize(csv_path) == 0:
writer.writerow(["timestamp", "group", "key", "value"])
state.clear() # force full dump on first packet per group
f.flush()
# Toggled off: close file
if not enabled and was_enabled:
if f:
f.close()
f = None
writer = None
was_enabled = enabled
# GPS telemetry at most 1Hz — fed through the same diff logic
if enabled and writer is not None:
sm.update(0)
now = time.monotonic()
if sm.updated['gpsLocation'] and (now - last_gps_log) >= 1.0:
gps = sm['gpsLocation']
gps_data = {
"latitude": f"{gps.latitude:.7f}",
"longitude": f"{gps.longitude:.7f}",
"speed": f"{gps.speed:.2f}",
"altitude": f"{gps.altitude:.1f}",
"bearing": f"{gps.bearingDeg:.1f}",
"accuracy": f"{gps.accuracy:.1f}",
}
ts = time.time()
if "gps" not in state:
state["gps"] = {}
prev_gps = state["gps"]
gps_changed = False
for key, value in gps_data.items():
if key not in prev_gps or prev_gps[key] != value:
writer.writerow([f"{ts:.6f}", "gps", key, value])
prev_gps[key] = value
gps_changed = True
if gps_changed:
f.flush()
last_gps_log = now
# Always drain the socket (even when disabled) to avoid backpressure
try:
raw = sock.recv_string(zmq.NOBLOCK)
except zmq.Again:
time.sleep(0.01)
continue
except zmq.ZMQError:
time.sleep(0.01)
continue
if not enabled or writer is None:
continue
try:
pkt = json.loads(raw)
except json.JSONDecodeError:
continue
ts = pkt.get("ts", 0)
group = pkt.get("group", "")
data = pkt.get("data", {})
if group not in state:
state[group] = {}
prev = state[group]
changed = False
for key, value in data.items():
str_val = str(value)
if key not in prev or prev[key] != str_val:
writer.writerow([f"{ts:.6f}", group, key, str_val])
prev[key] = str_val
changed = True
if changed:
f.flush()
if __name__ == "__main__":
main()
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 53 KiB

-12
View File
@@ -1,12 +0,0 @@
#!/usr/bin/env python3
"""Query the UI process for its current widget tree. Usage: python3 -m selfdrive.clearpilot.ui_dump"""
import zmq
ctx = zmq.Context()
sock = ctx.socket(zmq.REQ)
sock.setsockopt(zmq.RCVTIMEO, 2000)
sock.connect("ipc:///tmp/clearpilot_ui_rpc")
sock.send_string("dump")
try:
print(sock.recv_string())
except zmq.Again:
print("ERROR: UI not responding (timeout)")
+76 -223
View File
@@ -37,8 +37,6 @@ from openpilot.system.version import get_short_branch
from openpilot.selfdrive.frogpilot.controls.lib.frogpilot_functions import CRUISING_SPEED, PROBABILITY, MovingAverageCalculator from openpilot.selfdrive.frogpilot.controls.lib.frogpilot_functions import CRUISING_SPEED, PROBABILITY, MovingAverageCalculator
from openpilot.selfdrive.frogpilot.controls.lib.model_manager import RADARLESS_MODELS from openpilot.selfdrive.frogpilot.controls.lib.model_manager import RADARLESS_MODELS
from openpilot.selfdrive.clearpilot.telemetry import tlog
from openpilot.selfdrive.clearpilot.speed_logic import SpeedState
from openpilot.selfdrive.frogpilot.controls.lib.speed_limit_controller import SpeedLimitController from openpilot.selfdrive.frogpilot.controls.lib.speed_limit_controller import SpeedLimitController
SOFT_DISABLE_TIME = 3 # seconds SOFT_DISABLE_TIME = 3 # seconds
@@ -49,7 +47,7 @@ CAMERA_OFFSET = 0.04
REPLAY = "REPLAY" in os.environ REPLAY = "REPLAY" in os.environ
SIMULATION = "SIMULATION" in os.environ SIMULATION = "SIMULATION" in os.environ
TESTING_CLOSET = "TESTING_CLOSET" in os.environ TESTING_CLOSET = "TESTING_CLOSET" in os.environ
IGNORE_PROCESSES = {"loggerd", "encoderd", "statsd", "telemetryd", "dashcamd"} IGNORE_PROCESSES = {"loggerd", "encoderd", "statsd"}
ThermalStatus = log.DeviceState.ThermalStatus ThermalStatus = log.DeviceState.ThermalStatus
State = log.ControlsState.OpenpilotState State = log.ControlsState.OpenpilotState
@@ -80,10 +78,8 @@ class Controls:
self.params_memory.put_bool("CPTLkasButtonAction", False) self.params_memory.put_bool("CPTLkasButtonAction", False)
self.params_memory.put_int("ScreenDisplayMode", 0) self.params_memory.put_int("ScreenDisplayMode", 0)
# CLEARPILOT: edge tracking for park→drive auto-wake of screen
# ClearPilot speed processing self.was_driving_gear = False
self.speed_state = SpeedState()
self.speed_state_frame = 0
self.radarless_model = self.params.get("Model", encoding='utf-8') in RADARLESS_MODELS self.radarless_model = self.params.get("Model", encoding='utf-8') in RADARLESS_MODELS
@@ -113,9 +109,8 @@ class Controls:
self.sm = messaging.SubMaster(['deviceState', 'pandaStates', 'peripheralState', 'modelV2', 'liveCalibration', self.sm = messaging.SubMaster(['deviceState', 'pandaStates', 'peripheralState', 'modelV2', 'liveCalibration',
'carOutput', 'driverMonitoringState', 'longitudinalPlan', 'liveLocationKalman', 'carOutput', 'driverMonitoringState', 'longitudinalPlan', 'liveLocationKalman',
'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters', 'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters',
'testJoystick', 'frogpilotPlan', 'gpsLocation'] + self.camera_packets + self.sensor_packets, 'testJoystick', 'frogpilotPlan'] + self.camera_packets + self.sensor_packets,
ignore_alive=ignore+['gpsLocation'], ignore_avg_freq=ignore+['radarState', 'testJoystick', 'gpsLocation'], ignore_alive=ignore, ignore_avg_freq=ignore+['radarState', 'testJoystick'], ignore_valid=['testJoystick', ],
ignore_valid=['testJoystick', 'gpsLocation'],
frequency=int(1/DT_CTRL)) frequency=int(1/DT_CTRL))
self.joystick_mode = self.params.get_bool("JoystickDebugMode") self.joystick_mode = self.params.get_bool("JoystickDebugMode")
@@ -170,26 +165,6 @@ class Controls:
self.current_alert_types = [ET.PERMANENT] self.current_alert_types = [ET.PERMANENT]
self.logged_comm_issue = None self.logged_comm_issue = None
self.not_running_prev = None self.not_running_prev = None
self.lat_requested_ts = 0 # CLEARPILOT: timestamp when lat was first requested (ramp-up delay + comm issue suppression)
self.prev_lat_requested = False
# CLEARPILOT: gate frogpilotCarControl send on change (3 static bools, was publishing 100Hz)
self._prev_fpcc = (None, None, None, None, None)
self._last_fpcc_send_frame = 0
# CLEARPILOT: hysteresis counters for transient-filter on cascade alerts. A blip
# under 50ms (5 cycles at 100Hz) is typical of MSGQ conflate + slow-polling-consumer
# freq-measurement artifacts — not a real comm issue. Persistent failure still
# alerts after 50ms, well inside a driver's reaction window.
self._hyst_commissue = 0
self._hyst_locationd_tmp = 0
self._hyst_paramsd_tmp = 0
self._hyst_posenet = 0
self.HYST_CYCLES = 5
# CLEARPILOT: parked-cycle skip — in park+ignition-on, run the full step() only
# every 10th cycle. CAN parse + CAN TX still happen every cycle; outer logic
# (events, state machine, PID/MPC, publishing) runs at 10Hz. Cached message
# bytes are re-published on skipped cycles so downstream freq_ok stays OK.
self._cached_controlsState_bytes = None
self._cached_carControl_bytes = None
self.steer_limited = False self.steer_limited = False
self.desired_curvature = 0.0 self.desired_curvature = 0.0
self.experimental_mode = False self.experimental_mode = False
@@ -224,8 +199,6 @@ class Controls:
self.always_on_lateral_main = self.always_on_lateral and self.params.get_bool("AlwaysOnLateralMain") self.always_on_lateral_main = self.always_on_lateral and self.params.get_bool("AlwaysOnLateralMain")
self.drive_added = False self.drive_added = False
self.driving_gear = False
self.was_driving_gear = False
self.fcw_random_event_triggered = False self.fcw_random_event_triggered = False
self.holiday_theme_alerted = False self.holiday_theme_alerted = False
self.onroad_distance_pressed = False self.onroad_distance_pressed = False
@@ -264,51 +237,27 @@ class Controls:
CS = self.data_sample() CS = self.data_sample()
cloudlog.timestamp("Data sampled") cloudlog.timestamp("Data sampled")
# CLEARPILOT: handle debug-button press + display-mode transitions on every self.update_events(CS)
# cycle — button edge events only live in the cycle's CS.buttonEvents and self.update_frogpilot_events(CS)
# would otherwise be dropped on skipped cycles. self.update_clearpilot_events(CS)
self.handle_screen_mode(CS)
# CLEARPILOT: in park, only run the full step() every 10th cycle. data_sample cloudlog.timestamp("Events updated")
# above still runs (CAN parse, button detection). Below, card.controls_update
# still runs (CAN TX heartbeat, counters increment). The skipped outer logic
# (events, state machine, PID/MPC, publishing) causes at most ~100ms lag on
# button→state transitions, which is fine in park. Cached message bytes are
# re-sent so downstream consumers see steady 100Hz.
parked = CS.gearShifter == car.CarState.GearShifter.park
full_cycle = (not parked) or (self.sm.frame % 10 == 0) or (self._cached_controlsState_bytes is None)
if full_cycle: if not self.CP.passive and self.initialized:
self.update_events(CS) # Update control state
self.update_frogpilot_events(CS) self.state_transition(CS)
self.update_clearpilot_events(CS)
cloudlog.timestamp("Events updated") # Compute actuators (runs PID loops and lateral MPC)
CC, lac_log = self.state_control(CS)
CC = self.clearpilot_state_control(CC, CS)
if not self.CP.passive and self.initialized: # Publish data
# Update control state self.publish_logs(CS, start_time, CC, lac_log)
self.state_transition(CS)
# Compute actuators (runs PID loops and lateral MPC) self.CS_prev = CS
CC, lac_log = self.state_control(CS)
CC = self.clearpilot_state_control(CC, CS)
# Publish data (also sends CAN TX via card.controls_update inside)
self.publish_logs(CS, start_time, CC, lac_log)
self.CS_prev = CS
# Update FrogPilot variables
self.update_frogpilot_variables(CS)
else:
# CAN TX heartbeat: keep counters incrementing and CAN frames flowing to the car
if not self.CP.passive and self.initialized:
self.card.controls_update(self.CC, self.frogpilot_variables)
# Re-publish cached messages so downstream freq_ok checks don't trip
self.pm.send('controlsState', self._cached_controlsState_bytes)
self.pm.send('carControl', self._cached_carControl_bytes)
self.CS_prev = CS
# Update FrogPilot variables
self.update_frogpilot_variables(CS)
def data_sample(self): def data_sample(self):
"""Receive data from sockets and update carState""" """Receive data from sockets and update carState"""
@@ -494,24 +443,6 @@ class Controls:
# All events here should at least have NO_ENTRY and SOFT_DISABLE. # All events here should at least have NO_ENTRY and SOFT_DISABLE.
num_events = len(self.events) num_events = len(self.events)
# CLEARPILOT: compute model standby suppression early — used by multiple checks below
try:
standby_ts = float(self.params_memory.get("ModelStandbyTs") or "0")
except (ValueError, TypeError):
standby_ts = 0
now = time.monotonic()
model_suppress = (now - standby_ts) < 2.0
# CLEARPILOT: suppress commIssue/location/params errors for 2s after lat was requested
# Model FPS jumps from 4 to 20 on engage, causing transient freq check failures
# lat_requested_ts is set in state_control on the False->True transition of LatRequested
# CLEARPILOT: 2s window — long enough to cover the modeld rate transition burst
# without hiding real comms issues. Extending this further risks masking a genuine
# fault that demands immediate driver takeover.
lat_engage_suppress = (now - self.lat_requested_ts) < 2.0
# CLEARPILOT: expose suppress flags + standby_ts for the debug dumper in step()
not_running = {p.name for p in self.sm['managerState'].processes if not p.running and p.shouldBeRunning} not_running = {p.name for p in self.sm['managerState'].processes if not p.running and p.shouldBeRunning}
if self.sm.recv_frame['managerState'] and (not_running - IGNORE_PROCESSES): if self.sm.recv_frame['managerState'] and (not_running - IGNORE_PROCESSES):
self.events.add(EventName.processNotRunning) self.events.add(EventName.processNotRunning)
@@ -524,17 +455,10 @@ class Controls:
self.events.add(EventName.cameraMalfunction) self.events.add(EventName.cameraMalfunction)
elif not self.sm.all_freq_ok(self.camera_packets): elif not self.sm.all_freq_ok(self.camera_packets):
self.events.add(EventName.cameraFrameRate) self.events.add(EventName.cameraFrameRate)
# CLEARPILOT: alert only when avg cycle time exceeds 20ms (≈50Hz effective). if not REPLAY and self.rk.lagging:
# Stock rk.lagging fires at 11.1ms (90% of 10ms) which the Hyundai CAN load
# routinely crosses while driving — that's normal, not a fault. 50Hz control is
# still plenty responsive. `rk.lagging` is still used defensively elsewhere
# (lines ~479, 492) to skip secondary checks when slightly overloaded.
avg_dt = sum(self.rk._dts) / len(self.rk._dts)
alert_lagging = avg_dt > 0.020
if not REPLAY and alert_lagging and not model_suppress and not lat_engage_suppress:
self.events.add(EventName.controlsdLagging) self.events.add(EventName.controlsdLagging)
if not self.radarless_model: if not self.radarless_model:
if not model_suppress and (len(self.sm['radarState'].radarErrors) or (not self.rk.lagging and not self.sm.all_checks(['radarState']))): if len(self.sm['radarState'].radarErrors) or (not self.rk.lagging and not self.sm.all_checks(['radarState'])):
self.events.add(EventName.radarFault) self.events.add(EventName.radarFault)
if not self.sm.valid['pandaStates']: if not self.sm.valid['pandaStates']:
self.events.add(EventName.usbError) self.events.add(EventName.usbError)
@@ -546,60 +470,34 @@ class Controls:
# generic catch-all. ideally, a more specific event should be added above instead # generic catch-all. ideally, a more specific event should be added above instead
has_disable_events = self.events.contains(ET.NO_ENTRY) and (self.events.contains(ET.SOFT_DISABLE) or self.events.contains(ET.IMMEDIATE_DISABLE)) has_disable_events = self.events.contains(ET.NO_ENTRY) and (self.events.contains(ET.SOFT_DISABLE) or self.events.contains(ET.IMMEDIATE_DISABLE))
no_system_errors = (not has_disable_events) or (len(self.events) == num_events) no_system_errors = (not has_disable_events) or (len(self.events) == num_events)
# CLEARPILOT: commIssue fires ONLY when messages actually aren't flowing. If all if (not self.sm.all_checks() or self.card.can_rcv_timeout) and no_system_errors:
# subscribers are alive and CAN isn't timing out, comms are fine — any `valid=False` if not self.sm.all_alive():
# is an upstream self-declaration that cascades from the MSGQ conflate + self.events.add(EventName.commIssue)
# slow-polling-consumer freq_ok measurement artifact. The car drives correctly elif not self.sm.all_freq_ok():
# during these cascades (content is still usable), so we stop raising the banner. self.events.add(EventName.commIssueAvgFreq)
# Genuine comms failures — missing messages or CAN RX timeout — still fire. else: # invalid or can_rcv_timeout.
comms_really_broken = (not self.sm.all_alive()) or self.card.can_rcv_timeout self.events.add(EventName.commIssue)
commissue_cond = comms_really_broken and no_system_errors and not model_suppress and not lat_engage_suppress
if commissue_cond:
self._hyst_commissue += 1
else:
self._hyst_commissue = 0
if self._hyst_commissue >= self.HYST_CYCLES:
self.events.add(EventName.commIssue)
if commissue_cond:
# Log ONCE per entry into comms-really-broken state — no hyst counter so it doesn't
# spam every cycle (hyst changes every cycle and would make logs dict always differ).
logs = { logs = {
'invalid': [s for s, valid in self.sm.valid.items() if not valid], 'invalid': [s for s, valid in self.sm.valid.items() if not valid],
'not_alive': [s for s, alive in self.sm.alive.items() if not alive], 'not_alive': [s for s, alive in self.sm.alive.items() if not alive],
'not_freq_ok': [s for s, freq_ok in self.sm.freq_ok.items() if not freq_ok],
'can_rcv_timeout': self.card.can_rcv_timeout, 'can_rcv_timeout': self.card.can_rcv_timeout,
} }
if logs != self.logged_comm_issue: if logs != self.logged_comm_issue:
import sys, json cloudlog.event("commIssue", error=True, **logs)
print("CLP commIssue " + json.dumps(logs), file=sys.stderr, flush=True)
self.logged_comm_issue = logs self.logged_comm_issue = logs
else: else:
self.logged_comm_issue = None self.logged_comm_issue = None
if not (self.CP.notCar and self.joystick_mode): if not (self.CP.notCar and self.joystick_mode):
# CLEARPILOT: suppress locationd/paramsd "temporary error" when we're in the if not self.sm['liveLocationKalman'].posenetOK:
# freq-only cascade (same root as the commIssue suppression above). These events self.events.add(EventName.posenetInvalid)
# cascade from upstream freq_ok artifacts — locationd's filterInitialized latches
# False if calibrationd tips invalid due to freq, which cascades here.
# Real failures still fire commIssue above via alive/valid/can_rcv_timeout gate.
freq_only_cascade = (not self.sm.all_checks()) and not comms_really_broken
# deviceFalling is real-physics (shock sensor), no hysteresis, no cascade suppression.
if not self.sm['liveLocationKalman'].deviceStable: if not self.sm['liveLocationKalman'].deviceStable:
self.events.add(EventName.deviceFalling) self.events.add(EventName.deviceFalling)
if not self.sm['liveLocationKalman'].inputsOK:
posenet_bad = not self.sm['liveLocationKalman'].posenetOK and not model_suppress and not lat_engage_suppress and not freq_only_cascade
self._hyst_posenet = self._hyst_posenet + 1 if posenet_bad else 0
if self._hyst_posenet >= self.HYST_CYCLES:
self.events.add(EventName.posenetInvalid)
locd_bad = not self.sm['liveLocationKalman'].inputsOK and not model_suppress and not lat_engage_suppress and not freq_only_cascade
self._hyst_locationd_tmp = self._hyst_locationd_tmp + 1 if locd_bad else 0
if self._hyst_locationd_tmp >= self.HYST_CYCLES:
self.events.add(EventName.locationdTemporaryError) self.events.add(EventName.locationdTemporaryError)
if not self.sm['liveParameters'].valid and not TESTING_CLOSET and (not SIMULATION or REPLAY):
paramsd_bad = not self.sm['liveParameters'].valid and not TESTING_CLOSET and (not SIMULATION or REPLAY) and not model_suppress and not lat_engage_suppress and not freq_only_cascade
self._hyst_paramsd_tmp = self._hyst_paramsd_tmp + 1 if paramsd_bad else 0
if self._hyst_paramsd_tmp >= self.HYST_CYCLES:
self.events.add(EventName.paramsdTemporaryError) self.events.add(EventName.paramsdTemporaryError)
# conservative HW alert. if the data or frequency are off, locationd will throw an error # conservative HW alert. if the data or frequency are off, locationd will throw an error
@@ -613,8 +511,16 @@ class Controls:
if self.cruise_mismatch_counter > int(6. / DT_CTRL): if self.cruise_mismatch_counter > int(6. / DT_CTRL):
self.events.add(EventName.cruiseMismatch) self.events.add(EventName.cruiseMismatch)
# CLEARPILOT: FCW disabled — car's own radar AEB works better and triggers reliably. # Check for FCW
# The comma FCW was producing false positives and adds nothing over the stock system. stock_long_is_braking = self.enabled and not self.CP.openpilotLongitudinalControl and CS.aEgo < -1.25
model_fcw = self.sm['modelV2'].meta.hardBrakePredicted and not CS.brakePressed and not stock_long_is_braking
planner_fcw = self.sm['longitudinalPlan'].fcw and self.enabled
if planner_fcw or model_fcw:
self.events.add(EventName.fcw)
# self.fcw_random_event_triggered = True
# elif self.fcw_random_event_triggered and self.random_events:
# self.events.add(EventName.yourFrogTriedToKillMe)
# self.fcw_random_event_triggered = False
for m in messaging.drain_sock(self.log_sock, wait_for_one=False): for m in messaging.drain_sock(self.log_sock, wait_for_one=False):
try: try:
@@ -637,7 +543,7 @@ class Controls:
self.distance_traveled = 0 self.distance_traveled = 0
self.distance_traveled += CS.vEgo * DT_CTRL self.distance_traveled += CS.vEgo * DT_CTRL
if self.sm['modelV2'].frameDropPerc > 20 and not model_suppress: if self.sm['modelV2'].frameDropPerc > 20:
self.events.add(EventName.modeldLagging) self.events.add(EventName.modeldLagging)
@@ -724,14 +630,6 @@ class Controls:
# Check if openpilot is engaged and actuators are enabled # Check if openpilot is engaged and actuators are enabled
self.enabled = self.state in ENABLED_STATES self.enabled = self.state in ENABLED_STATES
self.active = self.state in ACTIVE_STATES self.active = self.state in ACTIVE_STATES
# CLEARPILOT: engagement telemetry disabled — was running at 100Hz, causing CPU load
# tlog("engage", {
# "state": self.state.name if hasattr(self.state, 'name') else str(self.state),
# "enabled": self.enabled, "active": self.active,
# "cruise_enabled": CS.cruiseState.enabled, "cruise_available": CS.cruiseState.available,
# "brakePressed": CS.brakePressed,
# })
if self.active: if self.active:
self.current_alert_types.append(ET.WARNING) self.current_alert_types.append(ET.WARNING)
@@ -762,19 +660,8 @@ class Controls:
# Check which actuators can be enabled # Check which actuators can be enabled
standstill = CS.vEgo <= max(self.CP.minSteerSpeed, MIN_LATERAL_CONTROL_SPEED) or CS.standstill standstill = CS.vEgo <= max(self.CP.minSteerSpeed, MIN_LATERAL_CONTROL_SPEED) or CS.standstill
# CLEARPILOT: lat_requested ignores momentary MDPS faults so modeld doesn't drop rate during CC.latActive = (self.active or self.FPCC.alwaysOnLateral) and self.speed_check and not CS.steerFaultTemporary and not CS.steerFaultPermanent and \
# brief steerFaultTemporary blips (stale predictions on recovery caused a fault feedback loop). (not standstill or self.joystick_mode)
# lat_engaged gates the actual steering command and still respects the fault.
lat_requested = (self.active or self.FPCC.alwaysOnLateral) and self.speed_check and \
(not standstill or self.joystick_mode)
lat_engaged = lat_requested and not CS.steerFaultTemporary and not CS.steerFaultPermanent
now_ts = time.monotonic()
if lat_requested and not self.prev_lat_requested:
self.lat_requested_ts = now_ts
self.prev_lat_requested = lat_requested
self.FPCC.latRequested = lat_requested
CC.latActive = lat_engaged and (now_ts - self.lat_requested_ts) >= 0.25
CC.longActive = self.enabled and not self.events.contains(ET.OVERRIDE_LONGITUDINAL) and self.CP.openpilotLongitudinalControl CC.longActive = self.enabled and not self.events.contains(ET.OVERRIDE_LONGITUDINAL) and self.CP.openpilotLongitudinalControl
actuators = CC.actuators actuators = CC.actuators
@@ -789,13 +676,11 @@ class Controls:
CC.leftBlinker = model_v2.meta.laneChangeDirection == LaneChangeDirection.left CC.leftBlinker = model_v2.meta.laneChangeDirection == LaneChangeDirection.left
CC.rightBlinker = model_v2.meta.laneChangeDirection == LaneChangeDirection.right CC.rightBlinker = model_v2.meta.laneChangeDirection == LaneChangeDirection.right
no_lat_lane_change = model_v2.meta.laneChangeState == LaneChangeState.laneChangeStarting and clearpilot_disable_lat_on_lane_change if model_v2.meta.laneChangeState == LaneChangeState.laneChangeStarting and clearpilot_disable_lat_on_lane_change:
if no_lat_lane_change:
CC.latActive = False CC.latActive = False
# CLEARPILOT: noLatLaneChange now lives on frogpilotCarControl (see update_frogpilot_variables). self.params_memory.put_bool("no_lat_lane_change", True)
# Also mirrored to frogpilot_variables so in-process carcontroller reads it without IPC. else:
self.FPCC.noLatLaneChange = no_lat_lane_change self.params_memory.put_bool("no_lat_lane_change", False)
self.frogpilot_variables.no_lat_lane_change = no_lat_lane_change
if CS.leftBlinker or CS.rightBlinker: if CS.leftBlinker or CS.rightBlinker:
self.last_blinker_frame = self.sm.frame self.last_blinker_frame = self.sm.frame
@@ -1031,8 +916,6 @@ class Controls:
controlsState.lateralControlState.torqueState = lac_log controlsState.lateralControlState.torqueState = lac_log
self.pm.send('controlsState', dat) self.pm.send('controlsState', dat)
# CLEARPILOT: cache for re-publication on parked-skip cycles
self._cached_controlsState_bytes = dat.to_bytes()
# onroadEvents - logged every second or on change # onroadEvents - logged every second or on change
if (self.sm.frame % int(1. / DT_CTRL) == 0) or (self.events.names != self.events_prev): if (self.sm.frame % int(1. / DT_CTRL) == 0) or (self.events.names != self.events_prev):
@@ -1047,7 +930,6 @@ class Controls:
cc_send.valid = CS.canValid cc_send.valid = CS.canValid
cc_send.carControl = CC cc_send.carControl = CC
self.pm.send('carControl', cc_send) self.pm.send('carControl', cc_send)
self._cached_carControl_bytes = cc_send.to_bytes()
# copy CarControl to pass to CarInterface on the next iteration # copy CarControl to pass to CarInterface on the next iteration
self.CC = CC self.CC = CC
@@ -1078,11 +960,6 @@ class Controls:
while True: while True:
self.step() self.step()
self.rk.monitor_time() self.rk.monitor_time()
# CLEARPILOT: accumulated debt from startup/blocking calls never recovers.
# Reset the rate keeper when catastrophically behind — prevents a one-time
# ~8s fingerprinting stall from poisoning the lag metric for the whole session.
if self.rk.remaining < -1.0:
self.rk._next_frame_time = time.monotonic() + self.rk._interval
except SystemExit: except SystemExit:
e.set() e.set()
t.join() t.join()
@@ -1153,11 +1030,13 @@ class Controls:
elif self.sm['modelV2'].meta.turnDirection == Desire.turnRight: elif self.sm['modelV2'].meta.turnDirection == Desire.turnRight:
self.events.add(EventName.turningRight) self.events.add(EventName.turningRight)
# CLEARPILOT: check crash file once per second, not every cycle (stat syscall at 100Hz hurts) if os.path.isfile(os.path.join(sentry.CRASHES_DIR, 'error.txt')) and self.crashed_timer < 10:
if self.sm.frame % 100 == 0:
self._crashed_file_exists = os.path.isfile(os.path.join(sentry.CRASHES_DIR, 'error.txt'))
if getattr(self, '_crashed_file_exists', False) and self.crashed_timer < 10:
self.events.add(EventName.openpilotCrashed) self.events.add(EventName.openpilotCrashed)
# if self.random_events and not self.openpilot_crashed_triggered:
# self.events.add(EventName.openpilotCrashedRandomEvents)
# self.openpilot_crashed_triggered = True
self.crashed_timer += DT_CTRL self.crashed_timer += DT_CTRL
# if self.speed_limit_alert or self.speed_limit_confirmation: # if self.speed_limit_alert or self.speed_limit_confirmation:
@@ -1280,18 +1159,10 @@ class Controls:
self.FPCC.trafficModeActive = self.frogpilot_variables.traffic_mode and self.params_memory.get_bool("TrafficModeActive") self.FPCC.trafficModeActive = self.frogpilot_variables.traffic_mode and self.params_memory.get_bool("TrafficModeActive")
# CLEARPILOT: send only when any field changes, with 1Hz keepalive fpcc_send = messaging.new_message('frogpilotCarControl')
# Saves ~7ms/sec of capnp+zmq work (was sending 100Hz despite static contents) fpcc_send.valid = CS.canValid
# latRequested and noLatLaneChange are edge-triggered too (rare flips) fpcc_send.frogpilotCarControl = self.FPCC
fpcc_tuple = (self.FPCC.alwaysOnLateral, self.FPCC.speedLimitChanged, self.FPCC.trafficModeActive, self.pm.send('frogpilotCarControl', fpcc_send)
self.FPCC.latRequested, self.FPCC.noLatLaneChange)
if fpcc_tuple != self._prev_fpcc or (self.sm.frame - self._last_fpcc_send_frame) >= 100:
fpcc_send = messaging.new_message('frogpilotCarControl')
fpcc_send.valid = CS.canValid
fpcc_send.frogpilotCarControl = self.FPCC
self.pm.send('frogpilotCarControl', fpcc_send)
self._prev_fpcc = fpcc_tuple
self._last_fpcc_send_frame = self.sm.frame
if self.params_memory.get_bool("FrogPilotTogglesUpdated"): if self.params_memory.get_bool("FrogPilotTogglesUpdated"):
self.update_frogpilot_params() self.update_frogpilot_params()
@@ -1366,51 +1237,33 @@ class Controls:
def update_clearpilot_events(self, CS): def update_clearpilot_events(self, CS):
if (len(CS.buttonEvents) > 0): if (len(CS.buttonEvents) > 0):
print (CS.buttonEvents) print (CS.buttonEvents)
if any(be.pressed and be.type == FrogPilotButtonType.lkas for be in CS.buttonEvents):
self.events.add(EventName.clpDebug)
def handle_screen_mode(self, CS): def clearpilot_state_control(self, CC, CS):
"""CLEARPILOT: tracks driving_gear, auto-resets display, and cycles # CLEARPILOT: pure UI plumbing — does not modify CC/actuators. Maintains
ScreenDisplayMode on debug-button presses. Must run every cycle so button # ScreenDisplayMode (5-state machine driven by the LFA/debug button + gear
edge events aren't lost during parked-skip mode (edges happen in carstate # edges). Speed/cruise overlay state is owned by speed_logicd, not here.
edge detection and only appear in that one cycle's CS.buttonEvents).""" driving_gear = CS.gearShifter not in (GearShifter.neutral, GearShifter.park,
self.driving_gear = CS.gearShifter not in (GearShifter.neutral, GearShifter.park, GearShifter.reverse, GearShifter.unknown) GearShifter.reverse, GearShifter.unknown)
# auto-reset display when shifting into drive from screen-off # Auto-wake screen when shifting into drive from screen-off
if self.driving_gear and not self.was_driving_gear: if driving_gear and not self.was_driving_gear:
if self.params_memory.get_int("ScreenDisplayMode") == 3: if self.params_memory.get_int("ScreenDisplayMode") == 3:
self.params_memory.put_int("ScreenDisplayMode", 0) self.params_memory.put_int("ScreenDisplayMode", 0)
self.was_driving_gear = self.driving_gear self.was_driving_gear = driving_gear
# LFA/debug button cycles ScreenDisplayMode. Onroad and offroad use
# different transition tables.
if any(be.pressed and be.type == FrogPilotButtonType.lkas for be in CS.buttonEvents): if any(be.pressed and be.type == FrogPilotButtonType.lkas for be in CS.buttonEvents):
current = self.params_memory.get_int("ScreenDisplayMode") current = self.params_memory.get_int("ScreenDisplayMode")
if driving_gear:
if self.driving_gear:
# Onroad: 0→4, 1→2, 2→3, 3→4, 4→2 (never back to auto via button) # Onroad: 0→4, 1→2, 2→3, 3→4, 4→2 (never back to auto via button)
transitions = {0: 4, 1: 2, 2: 3, 3: 4, 4: 2} transitions = {0: 4, 1: 2, 2: 3, 3: 4, 4: 2}
new_mode = transitions.get(current, 0) new_mode = transitions.get(current, 0)
else: else:
# Not in drive: any except 3 → 3, state 3 → 0 # Not in drive: anything except 3 → 3 (screen off), state 3 → 0 (auto)
new_mode = 0 if current == 3 else 3 new_mode = 0 if current == 3 else 3
self.params_memory.put_int("ScreenDisplayMode", new_mode) self.params_memory.put_int("ScreenDisplayMode", new_mode)
def clearpilot_state_control(self, CC, CS):
# ClearPilot speed processing (~2 Hz at 100 Hz loop)
self.speed_state_frame += 1
if self.speed_state_frame % 50 == 0:
gps = self.sm['gpsLocation']
has_gps = self.sm.valid['gpsLocation'] and gps.hasFix
speed_ms = gps.speed if has_gps else 0.0
speed_limit_ms = self.params_memory.get_float("CarSpeedLimit")
is_metric = (self.params_memory.get("CarIsMetric", encoding="utf-8") or "0") == "1"
cruise_speed_ms = CS.cruiseState.speed
cruise_active = CS.cruiseState.enabled
cruise_standstill = CS.cruiseState.standstill
self.speed_state.update(speed_ms, has_gps, speed_limit_ms, is_metric,
cruise_speed_ms, cruise_active, cruise_standstill)
return CC return CC
def main(): def main():
-14
View File
@@ -262,16 +262,6 @@ def calibration_incomplete_alert(CP: car.CarParams, CS: car.CarState, sm: messag
AlertStatus.normal, AlertSize.mid, AlertStatus.normal, AlertSize.mid,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2) Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2)
def clp_debug_notice(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
if not hasattr(clp_debug_notice, "counter"):
clp_debug_notice.counter = 0
clp_debug_notice.counter += 1
return Alert(
f"Clearpilot Debug Function Executed ({clp_debug_notice.counter})",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 3.0)
def no_gps_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: def no_gps_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
# Clearpilot todo: # Clearpilot todo:
@@ -778,10 +768,6 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
ET.SOFT_DISABLE: soft_disable_alert("Sensor Data Invalid"), ET.SOFT_DISABLE: soft_disable_alert("Sensor Data Invalid"),
}, },
# CLEARPILOT: alert suppressed — event still fires for screen toggle and future actions
EventName.clpDebug: {
},
EventName.noGps: { EventName.noGps: {
ET.PERMANENT: no_gps_alert, ET.PERMANENT: no_gps_alert,
}, },
+2 -33
View File
@@ -143,10 +143,6 @@ class LongitudinalPlanner:
self.params = Params() self.params = Params()
self.params_memory = Params("/dev/shm/params") self.params_memory = Params("/dev/shm/params")
# CLEARPILOT: track model FPS for dynamic dt adjustment
self.model_fps = 20
self._dbg_prev_valid = True # CLEARPILOT: diagnostic logging on valid transitions
self.radarless_model = self.params.get("Model", encoding='utf-8') in RADARLESS_MODELS self.radarless_model = self.params.get("Model", encoding='utf-8') in RADARLESS_MODELS
self.release = get_short_branch() == "clearpilot" self.release = get_short_branch() == "clearpilot"
@@ -177,19 +173,6 @@ class LongitudinalPlanner:
return x, v, a, j return x, v, a, j
def update(self, sm): def update(self, sm):
# CLEARPILOT: read actual model FPS and adjust dt accordingly
model_fps_raw = self.params_memory.get("ModelFps")
if model_fps_raw is not None:
try:
fps = int(model_fps_raw)
if fps > 0 and fps != self.model_fps:
self.model_fps = fps
self.dt = 1.0 / fps
self.v_desired_filter.dt = self.dt
self.v_desired_filter.update_alpha(2.0) # rc=2.0, same as __init__
except (ValueError, ZeroDivisionError):
pass
self.mpc.mode = 'blended' if sm['controlsState'].experimentalMode else 'acc' self.mpc.mode = 'blended' if sm['controlsState'].experimentalMode else 'acc'
v_ego = sm['carState'].vEgo v_ego = sm['carState'].vEgo
@@ -256,10 +239,7 @@ class LongitudinalPlanner:
self.j_desired_trajectory = np.interp(ModelConstants.T_IDXS[:CONTROL_N], T_IDXS_MPC[:-1], self.mpc.j_solution) self.j_desired_trajectory = np.interp(ModelConstants.T_IDXS[:CONTROL_N], T_IDXS_MPC[:-1], self.mpc.j_solution)
# TODO counter is only needed because radar is glitchy, remove once radar is gone # TODO counter is only needed because radar is glitchy, remove once radar is gone
# CLEARPILOT: scale crash_cnt threshold by FPS — at 20fps need 3 frames (0.15s), self.fcw = self.mpc.crash_cnt > 2 and not sm['carState'].standstill
# at 4fps need 1 frame (0.25s already exceeds 0.15s window)
fcw_threshold = max(0, int(0.15 * self.model_fps) - 1) # 20fps->2, 4fps->0
self.fcw = self.mpc.crash_cnt > fcw_threshold and not sm['carState'].standstill
if self.fcw: if self.fcw:
cloudlog.info("FCW triggered") cloudlog.info("FCW triggered")
@@ -278,18 +258,7 @@ class LongitudinalPlanner:
def publish(self, sm, pm): def publish(self, sm, pm):
plan_send = messaging.new_message('longitudinalPlan') plan_send = messaging.new_message('longitudinalPlan')
valid = sm.all_checks(service_list=['carState', 'controlsState']) plan_send.valid = sm.all_checks(service_list=['carState', 'controlsState'])
# CLEARPILOT: log on transition into invalid — stderr goes to our plannerd.log
if valid != self._dbg_prev_valid and not valid:
import sys
print(
"CLP longitudinalPlan valid=False: "
f"carState(a={sm.alive['carState']},v={sm.valid['carState']},f={sm.freq_ok['carState']}) "
f"controlsState(a={sm.alive['controlsState']},v={sm.valid['controlsState']},f={sm.freq_ok['controlsState']})",
file=sys.stderr, flush=True
)
self._dbg_prev_valid = valid
plan_send.valid = valid
longitudinalPlan = plan_send.longitudinalPlan longitudinalPlan = plan_send.longitudinalPlan
longitudinalPlan.modelMonoTime = sm.logMonoTime['modelV2'] longitudinalPlan.modelMonoTime = sm.logMonoTime['modelV2']
@@ -58,9 +58,6 @@ class FrogPilotPlanner:
self.params = Params() self.params = Params()
self.params_memory = Params("/dev/shm/params") self.params_memory = Params("/dev/shm/params")
# CLEARPILOT: track valid transitions so we only log when it flips, not every cycle
self._dbg_prev_valid = True
self.cem = ConditionalExperimentalMode() self.cem = ConditionalExperimentalMode()
self.lead_one = Lead() self.lead_one = Lead()
self.mtsc = MapTurnSpeedController() self.mtsc = MapTurnSpeedController()
@@ -245,18 +242,7 @@ class FrogPilotPlanner:
def publish(self, sm, pm): def publish(self, sm, pm):
frogpilot_plan_send = messaging.new_message('frogpilotPlan') frogpilot_plan_send = messaging.new_message('frogpilotPlan')
valid = sm.all_checks(service_list=['carState', 'controlsState']) frogpilot_plan_send.valid = sm.all_checks(service_list=['carState', 'controlsState'])
# CLEARPILOT: log on transition into invalid — stderr goes to our plannerd.log
if valid != self._dbg_prev_valid and not valid:
import sys
print(
"CLP frogpilotPlan valid=False: "
f"carState(a={sm.alive['carState']},v={sm.valid['carState']},f={sm.freq_ok['carState']}) "
f"controlsState(a={sm.alive['controlsState']},v={sm.valid['controlsState']},f={sm.freq_ok['controlsState']})",
file=sys.stderr, flush=True
)
self._dbg_prev_valid = valid
frogpilot_plan_send.valid = valid
frogpilotPlan = frogpilot_plan_send.frogpilotPlan frogpilotPlan = frogpilot_plan_send.frogpilotPlan
frogpilotPlan.accelerationJerk = A_CHANGE_COST * (float(self.jerk) if self.lead_one.status else 1) frogpilotPlan.accelerationJerk = A_CHANGE_COST * (float(self.jerk) if self.lead_one.status else 1)
@@ -27,7 +27,7 @@ ScreenRecorder::ScreenRecorder(QWidget *parent) : QPushButton(parent), image_que
void ScreenRecorder::initializeEncoder() { void ScreenRecorder::initializeEncoder() {
const std::string path = "/data/media/0/videos"; const std::string path = "/data/media/0/videos";
encoder = std::make_unique<OmxEncoder>(path.c_str(), recording_width, recording_height, 60, 2 * 1024 * 1024); encoder = std::make_unique<OmxEncoder>(path.c_str(), recording_width, recording_height, 60, 2 * 1024 * 1024, false, false);
} }
ScreenRecorder::~ScreenRecorder() { ScreenRecorder::~ScreenRecorder() {
@@ -132,20 +132,13 @@ void ScreenRecorder::stop() {
} }
void ScreenRecorder::update_screen() { void ScreenRecorder::update_screen() {
bool car_on = uiState()->scene.started || uiState()->scene.screen_recorder_debug; if (!uiState()->scene.started) {
if (!car_on) {
if (recording) { if (recording) {
stop(); stop();
} }
return; return;
} }
if (!recording) return;
// CLEARPILOT: auto-start recording when car is on (or debug flag set)
if (!recording) {
start();
return;
}
if (milliseconds() - started > 1000 * 60 * 3) { if (milliseconds() - started > 1000 * 60 * 3) {
stop(); stop();
+1 -8
View File
@@ -284,14 +284,7 @@ def main() -> NoReturn:
# 4Hz driven by cameraOdometry # 4Hz driven by cameraOdometry
if sm.frame % 5 == 0: if sm.frame % 5 == 0:
# CLEARPILOT: publish valid based on calibration status, not upstream sm.all_checks(). calibrator.send_data(pm, sm.all_checks())
# Original openpilot gated valid on fresh inputs, but that caused a cascade:
# upstream freq glitches → liveCalibration.valid=False → locationd stays
# uninitialized → paramsd fed garbage → bogus steerRatio/stiffnessFactor → erratic
# steering. "valid" semantically means "calibration data is trustworthy"; that's a
# question about calibration convergence, not input freshness.
cal_valid = calibrator.cal_status == log.LiveCalibrationData.Status.calibrated
calibrator.send_data(pm, cal_valid)
if __name__ == "__main__": if __name__ == "__main__":
+25 -24
View File
@@ -594,10 +594,15 @@ void Localizer::handle_msg(const cereal::Event::Reader& log) {
this->handle_sensor(t, log.getAccelerometer()); this->handle_sensor(t, log.getAccelerometer());
} else if (log.isGyroscope()) { } else if (log.isGyroscope()) {
this->handle_sensor(t, log.getGyroscope()); this->handle_sensor(t, log.getGyroscope());
} else if (log.isGpsLocation()) { // CLEARPILOT: GPS branches removed — locationd no longer subscribes to
this->handle_gps(t, log.getGpsLocation(), GPS_QUECTEL_SENSOR_TIME_OFFSET); // gpsLocation/gpsLocationExternal, so these would be dead code regardless.
} else if (log.isGpsLocationExternal()) { // Self-driving treats GPS as not present: gpsOK stays false (last_gps_msg
this->handle_gps(t, log.getGpsLocationExternal(), GPS_UBLOX_SENSOR_TIME_OFFSET); // never updates), and other liveLocationKalman fields stay at the kalman
// filter's IMU+camera-odometry-only state.
// } else if (log.isGpsLocation()) {
// this->handle_gps(t, log.getGpsLocation(), GPS_QUECTEL_SENSOR_TIME_OFFSET);
// } else if (log.isGpsLocationExternal()) {
// this->handle_gps(t, log.getGpsLocationExternal(), GPS_UBLOX_SENSOR_TIME_OFFSET);
//} else if (log.isGnssMeasurements()) { //} else if (log.isGnssMeasurements()) {
// this->handle_gnss(t, log.getGnssMeasurements()); // this->handle_gnss(t, log.getGnssMeasurements());
} else if (log.isCarState()) { } else if (log.isCarState()) {
@@ -676,22 +681,16 @@ void Localizer::configure_gnss_source(const LocalizerGnssSource &source) {
} }
int Localizer::locationd_thread() { int Localizer::locationd_thread() {
Params params; // CLEARPILOT: do not subscribe to GPS. Our gpsd publishes gpsLocation for
LocalizerGnssSource source; // UI/clock/dashcam, but feeding it to the kalman filter screws up the
const char* gps_location_socket; // self-driving math. liveLocationKalman.gpsOK stays false; downstream
if (params.getBool("UbloxAvailable")) { // self-driving consumers (controlsd, paramsd, torqued, frogpilot_planner)
source = LocalizerGnssSource::UBLOX; // already handle that case.
gps_location_socket = "gpsLocationExternal"; this->configure_gnss_source(LocalizerGnssSource::QCOM);
} else { const std::initializer_list<const char *> service_list = {"cameraOdometry", "liveCalibration",
source = LocalizerGnssSource::QCOM;
gps_location_socket = "gpsLocation";
}
this->configure_gnss_source(source);
const std::initializer_list<const char *> service_list = {gps_location_socket, "cameraOdometry", "liveCalibration",
"carState", "accelerometer", "gyroscope"}; "carState", "accelerometer", "gyroscope"};
SubMaster sm(service_list, {}, nullptr, {gps_location_socket}); SubMaster sm(service_list, {}, nullptr, {});
PubMaster pm({"liveLocationKalman"}); PubMaster pm({"liveLocationKalman"});
uint64_t cnt = 0; uint64_t cnt = 0;
@@ -730,12 +729,14 @@ int Localizer::locationd_thread() {
kj::ArrayPtr<capnp::byte> bytes = this->get_message_bytes(msg_builder, inputsOK, sensorsOK, gpsOK, filterInitialized); kj::ArrayPtr<capnp::byte> bytes = this->get_message_bytes(msg_builder, inputsOK, sensorsOK, gpsOK, filterInitialized);
pm.send("liveLocationKalman", bytes.begin(), bytes.size()); pm.send("liveLocationKalman", bytes.begin(), bytes.size());
if (cnt % 1200 == 0 && gpsOK) { // once a minute // CLEARPILOT: dead code now that gpsOK is permanently false (we don't
VectorXd posGeo = this->get_position_geodetic(); // subscribe to gpsLocation). Was: write LastGPSPosition once a minute.
std::string lastGPSPosJSON = util::string_format( // if (cnt % 1200 == 0 && gpsOK) {
"{\"latitude\": %.15f, \"longitude\": %.15f, \"altitude\": %.15f}", posGeo(0), posGeo(1), posGeo(2)); // VectorXd posGeo = this->get_position_geodetic();
params.putNonBlocking("LastGPSPosition", lastGPSPosJSON); // std::string lastGPSPosJSON = util::string_format(
} // "{\"latitude\": %.15f, \"longitude\": %.15f, \"altitude\": %.15f}", posGeo(0), posGeo(1), posGeo(2));
// params.putNonBlocking("LastGPSPosition", lastGPSPosJSON);
// }
cnt++; cnt++;
} }
} }
+1 -10
View File
@@ -187,7 +187,6 @@ def main():
avg_offset_valid = True avg_offset_valid = True
total_offset_valid = True total_offset_valid = True
roll_valid = True roll_valid = True
dbg_prev_valid = True # CLEARPILOT: track valid transitions
while True: while True:
sm.update() sm.update()
@@ -257,15 +256,7 @@ def main():
liveParameters.filterState.std = P.tolist() liveParameters.filterState.std = P.tolist()
liveParameters.filterState.valid = True liveParameters.filterState.valid = True
lp_valid = sm.all_checks() msg.valid = sm.all_checks()
# CLEARPILOT: on transition to invalid, log per-subscriber state to paramsd.log
if lp_valid != dbg_prev_valid and not lp_valid:
import sys
bad = [s for s in sm.alive if not (sm.alive[s] and sm.valid[s] and sm.freq_ok.get(s, True))]
details = [f"{s}(a={sm.alive[s]},v={sm.valid[s]},f={sm.freq_ok[s]})" for s in bad]
print(f"CLP liveParameters valid=False: {' '.join(details)}", file=sys.stderr, flush=True)
dbg_prev_valid = lp_valid
msg.valid = lp_valid
if sm.frame % 1200 == 0: # once a minute if sm.frame % 1200 == 0: # once a minute
params = { params = {
+1 -11
View File
@@ -226,8 +226,6 @@ def main(demo=False):
with car.CarParams.from_bytes(params.get("CarParams", block=True)) as CP: with car.CarParams.from_bytes(params.get("CarParams", block=True)) as CP:
estimator = TorqueEstimator(CP) estimator = TorqueEstimator(CP)
dbg_prev_valid = True # CLEARPILOT: track valid transitions
while True: while True:
sm.update() sm.update()
if sm.all_checks(): if sm.all_checks():
@@ -238,15 +236,7 @@ def main(demo=False):
# 4Hz driven by liveLocationKalman # 4Hz driven by liveLocationKalman
if sm.frame % 5 == 0: if sm.frame % 5 == 0:
tq_valid = sm.all_checks() pm.send('liveTorqueParameters', estimator.get_msg(valid=sm.all_checks()))
# CLEARPILOT: log per-sub detail on transition to invalid — goes to torqued.log
if tq_valid != dbg_prev_valid and not tq_valid:
import sys
bad = [s for s in sm.alive if not (sm.alive[s] and sm.valid[s] and sm.freq_ok.get(s, True))]
details = [f"{s}(a={sm.alive[s]},v={sm.valid[s]},f={sm.freq_ok[s]})" for s in bad]
print(f"CLP liveTorqueParameters valid=False: {' '.join(details)}", file=sys.stderr, flush=True)
dbg_prev_valid = tq_valid
pm.send('liveTorqueParameters', estimator.get_msg(valid=tq_valid))
# Cache points every 60 seconds while onroad # Cache points every 60 seconds while onroad
if sm.frame % 240 == 0: if sm.frame % 240 == 0:
+23 -6
View File
@@ -56,12 +56,19 @@ def build(spinner: Spinner, dirty: bool = False, minimal: bool = False) -> None:
if scons.returncode == 0: if scons.returncode == 0:
Path('/data/openpilot/prebuilt').touch() Path('/data/openpilot/prebuilt').touch()
# CLEARPILOT: update prebuilt spinner if the new build is newer # CLEARPILOT: update prebuilt spinner if the new build is newer.
# Write to a temp path then os.replace so we can swap a binary that's
# currently executing (the in-process spinner holds the old one open).
new_spinner = Path(BASEDIR) / "selfdrive/ui/_spinner" new_spinner = Path(BASEDIR) / "selfdrive/ui/_spinner"
old_spinner = Path(BASEDIR) / "selfdrive/ui/qt/spinner" old_spinner = Path(BASEDIR) / "selfdrive/ui/qt/spinner"
if new_spinner.exists() and (not old_spinner.exists() or new_spinner.stat().st_mtime > old_spinner.stat().st_mtime): if new_spinner.exists() and (not old_spinner.exists() or new_spinner.stat().st_mtime > old_spinner.stat().st_mtime):
import shutil import shutil
shutil.copy2(str(new_spinner), str(old_spinner)) try:
tmp_spinner = old_spinner.with_name(old_spinner.name + ".new")
shutil.copy2(str(new_spinner), str(tmp_spinner))
os.replace(str(tmp_spinner), str(old_spinner))
except OSError as e:
print(f"CLP failed to update prebuilt spinner: {e}", file=sys.stderr)
break break
@@ -78,13 +85,23 @@ def build(spinner: Spinner, dirty: bool = False, minimal: bool = False) -> None:
# Show TextWindow # Show TextWindow
spinner.close() spinner.close()
if not os.getenv("CI"): if not os.getenv("CI"):
# CLEARPILOT: BUILD_ONLY mode shows error on screen but doesn't block msg = "openpilot failed to build\n \n" + error_s
t = TextWindow("openpilot failed to build\n \n" + error_s)
if os.getenv("BUILD_ONLY"): if os.getenv("BUILD_ONLY"):
# CLEARPILOT: BUILD_ONLY mode — spawn the text window fully detached
# (own session, /dev/null stdio) so it stays on screen after this
# script exits and doesn't hold our stdout/stderr pipes open.
print(error_s, file=sys.stderr) print(error_s, file=sys.stderr)
devnull = open(os.devnull, 'r+b')
subprocess.Popen(
["./text", msg],
cwd=os.path.join(BASEDIR, "selfdrive", "ui"),
stdin=devnull, stdout=devnull, stderr=devnull,
start_new_session=True,
close_fds=True,
)
else: else:
t.wait_for_exit() with TextWindow(msg) as t:
t.close() t.wait_for_exit()
exit(1) exit(1)
# enforce max cache size # enforce max cache size
+29 -63
View File
@@ -16,7 +16,7 @@ from openpilot.common.text_window import TextWindow
from openpilot.common.time import system_time_valid from openpilot.common.time import system_time_valid
from openpilot.system.hardware import HARDWARE, PC from openpilot.system.hardware import HARDWARE, PC
from openpilot.selfdrive.manager.helpers import unblock_stdout, write_onroad_params, save_bootlog from openpilot.selfdrive.manager.helpers import unblock_stdout, write_onroad_params, save_bootlog
from openpilot.selfdrive.manager.process import ensure_running, init_log_dir, update_log_dir_timestamp, session_log from openpilot.selfdrive.manager.process import ensure_running
from openpilot.selfdrive.manager.process_config import managed_processes from openpilot.selfdrive.manager.process_config import managed_processes
from openpilot.selfdrive.athena.registration import register, UNREGISTERED_DONGLE_ID from openpilot.selfdrive.athena.registration import register, UNREGISTERED_DONGLE_ID
from openpilot.common.swaglog import cloudlog, add_file_handler from openpilot.common.swaglog import cloudlog, add_file_handler
@@ -51,58 +51,16 @@ def frogpilot_boot_functions(frogpilot_functions):
except Exception as e: except Exception as e:
print(f"An unexpected error occurred: {e}") print(f"An unexpected error occurred: {e}")
def cleanup_old_logs(max_age_days=30):
"""CLEARPILOT: delete session log directories older than max_age_days."""
import shutil
log_base = "/data/log2"
if not os.path.exists(log_base):
return
cutoff = time.time() - (max_age_days * 86400)
for entry in os.listdir(log_base):
if entry == "current":
continue
path = os.path.join(log_base, entry)
if os.path.isdir(path):
if os.path.getmtime(path) < cutoff:
try:
shutil.rmtree(path)
except OSError:
pass
def manager_init(frogpilot_functions) -> None: def manager_init(frogpilot_functions) -> None:
init_log_dir()
cleanup_old_logs()
frogpilot_boot = threading.Thread(target=frogpilot_boot_functions, args=(frogpilot_functions,)) frogpilot_boot = threading.Thread(target=frogpilot_boot_functions, args=(frogpilot_functions,))
frogpilot_boot.start() frogpilot_boot.start()
save_bootlog() # CLEARPILOT: skip writing boot logs to /data/media/0/realdata/boot/
# save_bootlog()
params = Params() params = Params()
params_storage = Params("/persist/params") params_storage = Params("/persist/params")
params.clear_all(ParamKeyType.CLEAR_ON_MANAGER_START) params.clear_all(ParamKeyType.CLEAR_ON_MANAGER_START)
# CLEARPILOT: always start with telemetry disabled, VPN enabled (memory params)
params_memory = Params("/dev/shm/params")
params_memory.put("TelemetryEnabled", "0")
params_memory.put("VpnEnabled", "1")
params_memory.put("DashcamFrames", "0")
params_memory.put("DashcamState", "stopped")
params_memory.put("DashcamShutdown", "0")
params_memory.put("ModelFps", "20")
params_memory.put("ModelStandby", "0")
params_memory.put("ShutdownTouchReset", "0")
params_memory.put("ModelStandbyTs", "0")
params_memory.put("CarIsMetric", "0")
params_memory.put("ClearpilotSpeedDisplay", "")
params_memory.put("ClearpilotSpeedLimitDisplay", "0")
params_memory.put("ClearpilotHasSpeed", "0")
params_memory.put("ClearpilotIsMetric", "0")
params_memory.put("ClearpilotSpeedUnit", "mph")
params_memory.put("ClearpilotCruiseWarning", "")
params_memory.put("ClearpilotCruiseWarningSpeed", "")
params_memory.put("ClearpilotPlayDing", "0")
params.clear_all(ParamKeyType.CLEAR_ON_ONROAD_TRANSITION) params.clear_all(ParamKeyType.CLEAR_ON_ONROAD_TRANSITION)
params.clear_all(ParamKeyType.CLEAR_ON_OFFROAD_TRANSITION) params.clear_all(ParamKeyType.CLEAR_ON_OFFROAD_TRANSITION)
if is_release_branch(): if is_release_branch():
@@ -178,7 +136,6 @@ def manager_init(frogpilot_functions) -> None:
("DisableOpenpilotLongitudinal", "0"), ("DisableOpenpilotLongitudinal", "0"),
("DisableVTSCSmoothing", "0"), ("DisableVTSCSmoothing", "0"),
("DisengageVolume", "100"), ("DisengageVolume", "100"),
("TelemetryEnabled", "0"),
("DragonPilotTune", "0"), ("DragonPilotTune", "0"),
("DriverCamera", "0"), ("DriverCamera", "0"),
("DynamicPathWidth", "0"), ("DynamicPathWidth", "0"),
@@ -273,7 +230,6 @@ def manager_init(frogpilot_functions) -> None:
("ScreenBrightnessOnroad", "101"), ("ScreenBrightnessOnroad", "101"),
("ScreenManagement", "1"), ("ScreenManagement", "1"),
("ScreenRecorder", "1"), ("ScreenRecorder", "1"),
("ScreenRecorderDebug", "1"),
("ScreenTimeout", "30"), ("ScreenTimeout", "30"),
("ScreenTimeoutOnroad", "30"), ("ScreenTimeoutOnroad", "30"),
("SearchInput", "0"), ("SearchInput", "0"),
@@ -345,6 +301,32 @@ def manager_init(frogpilot_functions) -> None:
else: else:
params_storage.put(k, params.get(k)) params_storage.put(k, params.get(k))
# CLEARPILOT memory-param defaults. /dev/shm/params is on tmpfs so these
# reset on every boot anyway; we still set them so first-readers don't see
# missing keys before the writer process has spun up.
params_memory = Params("/dev/shm/params")
for k, v in [
("CarIsMetric", "0"),
("ClearpilotCruiseWarning", ""),
("ClearpilotCruiseWarningSpeed", ""),
("ClearpilotHasSpeed", "0"),
("ClearpilotIsMetric", "0"),
("ClearpilotPlayDing", "0"),
("ClearpilotSpeedDisplay", ""),
("ClearpilotSpeedLimitDisplay", "0"),
("ClearpilotSpeedUnit", "mph"),
("DashcamFrames", "0"),
("DashcamShutdown", "0"),
("DashcamState", "stopped"),
("ModelFps", "20"),
("ModelStandby", "0"),
("ModelStandbyTs", "0"),
("ShutdownTouchReset", "0"),
("TelemetryEnabled", "0"),
("VpnEnabled", "1"),
]:
params_memory.put(k, v)
# Create folders needed for msgq # Create folders needed for msgq
try: try:
os.mkdir("/dev/shm") os.mkdir("/dev/shm")
@@ -410,7 +392,6 @@ def manager_thread(frogpilot_functions) -> None:
cloudlog.bind(daemon="manager") cloudlog.bind(daemon="manager")
cloudlog.info("manager start") cloudlog.info("manager start")
cloudlog.info({"environ": os.environ}) cloudlog.info({"environ": os.environ})
session_log.info("manager starting")
params = Params() params = Params()
params_memory = Params("/dev/shm/params") params_memory = Params("/dev/shm/params")
@@ -420,14 +401,6 @@ def manager_thread(frogpilot_functions) -> None:
ignore += ["manage_athenad", "uploader"] ignore += ["manage_athenad", "uploader"]
if os.getenv("NOBOARD") is not None: if os.getenv("NOBOARD") is not None:
ignore.append("pandad") ignore.append("pandad")
# CLEARPILOT: bench mode — disable real car processes, enable bench simulator
if os.getenv("BENCH_MODE") is not None:
ignore += ["pandad", "controlsd", "radard", "plannerd",
"calibrationd", "torqued", "paramsd", "locationd", "sensord",
"ubloxd", "pigeond", "dmonitoringmodeld", "dmonitoringd",
"modeld", "soundd", "loggerd", "micd",
"dashcamd"]
session_log.info("bench mode enabled")
ignore += [x for x in os.getenv("BLOCK", "").split(",") if len(x) > 0] ignore += [x for x in os.getenv("BLOCK", "").split(",") if len(x) > 0]
sm = messaging.SubMaster(['deviceState', 'carParams'], poll='deviceState') sm = messaging.SubMaster(['deviceState', 'carParams'], poll='deviceState')
@@ -449,7 +422,6 @@ def manager_thread(frogpilot_functions) -> None:
if started and not started_prev: if started and not started_prev:
params.clear_all(ParamKeyType.CLEAR_ON_ONROAD_TRANSITION) params.clear_all(ParamKeyType.CLEAR_ON_ONROAD_TRANSITION)
session_log.info("onroad transition")
if openpilot_crashed: if openpilot_crashed:
os.remove(os.path.join(sentry.CRASHES_DIR, 'error.txt')) os.remove(os.path.join(sentry.CRASHES_DIR, 'error.txt'))
@@ -457,7 +429,6 @@ def manager_thread(frogpilot_functions) -> None:
elif not started and started_prev: elif not started and started_prev:
params.clear_all(ParamKeyType.CLEAR_ON_OFFROAD_TRANSITION) params.clear_all(ParamKeyType.CLEAR_ON_OFFROAD_TRANSITION)
params_memory.clear_all(ParamKeyType.CLEAR_ON_OFFROAD_TRANSITION) params_memory.clear_all(ParamKeyType.CLEAR_ON_OFFROAD_TRANSITION)
session_log.info("offroad transition")
# update onroad params, which drives boardd's safety setter thread # update onroad params, which drives boardd's safety setter thread
if started != started_prev: if started != started_prev:
@@ -467,9 +438,6 @@ def manager_thread(frogpilot_functions) -> None:
ensure_running(managed_processes.values(), started, params=params, CP=sm['carParams'], not_run=ignore) ensure_running(managed_processes.values(), started, params=params, CP=sm['carParams'], not_run=ignore)
# CLEARPILOT: rename log directory once system time is valid
update_log_dir_timestamp()
running = ' '.join("{}{}\u001b[0m".format("\u001b[32m" if p.proc.is_alive() else "\u001b[31m", p.name) running = ' '.join("{}{}\u001b[0m".format("\u001b[32m" if p.proc.is_alive() else "\u001b[31m", p.name)
for p in managed_processes.values() if p.proc) for p in managed_processes.values() if p.proc)
print(running) print(running)
@@ -487,7 +455,6 @@ def manager_thread(frogpilot_functions) -> None:
shutdown = True shutdown = True
params.put("LastManagerExitReason", f"{param} {datetime.datetime.now()}") params.put("LastManagerExitReason", f"{param} {datetime.datetime.now()}")
cloudlog.warning(f"Shutting down manager - {param} set") cloudlog.warning(f"Shutting down manager - {param} set")
session_log.info("manager shutting down: %s", param)
if shutdown: if shutdown:
break break
@@ -539,7 +506,6 @@ if __name__ == "__main__":
except Exception: except Exception:
add_file_handler(cloudlog) add_file_handler(cloudlog)
cloudlog.exception("Manager failed to start") cloudlog.exception("Manager failed to start")
session_log.critical("manager failed to start: %s", traceback.format_exc())
try: try:
managed_processes['ui'].stop() managed_processes['ui'].stop()
+7 -130
View File
@@ -2,7 +2,6 @@ import importlib
import os import os
import signal import signal
import struct import struct
import sys
import datetime import datetime
import time import time
import subprocess import subprocess
@@ -18,117 +17,17 @@ import openpilot.selfdrive.sentry as sentry
from openpilot.common.basedir import BASEDIR from openpilot.common.basedir import BASEDIR
from openpilot.common.params import Params from openpilot.common.params import Params
from openpilot.common.swaglog import cloudlog from openpilot.common.swaglog import cloudlog
from openpilot.common.time import system_time_valid
WATCHDOG_FN = "/dev/shm/wd_" WATCHDOG_FN = "/dev/shm/wd_"
ENABLE_WATCHDOG = os.getenv("NO_WATCHDOG") is None ENABLE_WATCHDOG = os.getenv("NO_WATCHDOG") is None
# CLEARPILOT: logging directory and session log timestamp = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
# init_log_dir() must be called once from manager_init() before any process starts. _log_dir = f"/data/log2/{timestamp}"
# Until then, _log_dir and session_log are usable but write to a NullHandler. os.makedirs(_log_dir, exist_ok=True)
import logging
_log_dir = "/data/log2/current"
_time_resolved = False
_session_handler = None
session_log = logging.getLogger("clearpilot.session")
session_log.setLevel(logging.DEBUG)
session_log.addHandler(logging.NullHandler())
def init_log_dir():
"""Create /data/log2/current as a real directory for this session.
Called once from manager_init(). Previous current (if a real dir) is
renamed to a timestamp or boot-monotonic name before we create a fresh one."""
global _log_dir, _time_resolved, _session_handler
log_base = "/data/log2"
current = os.path.join(log_base, "current")
os.makedirs(log_base, exist_ok=True)
# If 'current' is a symlink, just remove the symlink
if os.path.islink(current):
os.unlink(current)
# If 'current' is a real directory (leftover from previous session that
# never got time-resolved), rename it out of the way
elif os.path.isdir(current):
# Use mtime of session.log (or the dir itself) for the rename
session_file = os.path.join(current, "session.log")
mtime = os.path.getmtime(session_file) if os.path.exists(session_file) else os.path.getmtime(current)
ts = datetime.datetime.fromtimestamp(mtime).strftime('%Y-%m-%d-%H-%M-%S')
dest = os.path.join(log_base, ts)
# Avoid collision
if os.path.exists(dest):
dest = dest + f"-{int(time.monotonic())}"
try:
os.rename(current, dest)
except OSError:
pass
os.makedirs(current, exist_ok=True)
_log_dir = current
_time_resolved = False
# Set up session log file handler
_session_handler = logging.FileHandler(os.path.join(_log_dir, "session.log"))
_session_handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s"))
# Remove NullHandler and add file handler
session_log.handlers.clear()
session_log.addHandler(_session_handler)
session_log.info("session started, log dir: %s", _log_dir)
def update_log_dir_timestamp():
"""Rename /data/log2/current to a real timestamp and replace with a symlink
once system time is valid."""
global _log_dir, _time_resolved, _session_handler
if _time_resolved:
return
if not system_time_valid():
return
log_base = "/data/log2"
current = os.path.join(log_base, "current")
ts_name = datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S')
new_dir = os.path.join(log_base, ts_name)
try:
os.rename(current, new_dir)
# Create symlink: current -> YYYY-MM-DD-HH-MM-SS
os.symlink(ts_name, current)
_log_dir = new_dir
_time_resolved = True
# Re-point session log handler (open files follow the inode, but
# new opens should go through the symlink — update handler for clarity)
session_log.removeHandler(_session_handler)
_session_handler.close()
_session_handler = logging.FileHandler(os.path.join(_log_dir, "session.log"))
_session_handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s"))
session_log.addHandler(_session_handler)
session_log.info("log directory renamed to %s", _log_dir)
# Signal via param that the directory has been time-resolved
try:
from openpilot.common.params import Params
Params().put("LogDirInitialized", "1")
except Exception:
pass
except OSError:
pass
def launcher(proc: str, name: str, log_path: str) -> None: def launcher(proc: str, name: str) -> None:
# CLEARPILOT: redirect stderr to per-process log file
try:
log_file = open(log_path, 'a')
os.dup2(log_file.fileno(), sys.stderr.fileno())
os.dup2(log_file.fileno(), sys.stdout.fileno())
except Exception as e:
print(f"CLEARPILOT: stderr redirect failed for {name}: {e}", file=sys.stderr)
try: try:
# import the process # import the process
mod = importlib.import_module(proc) mod = importlib.import_module(proc)
@@ -154,17 +53,9 @@ def launcher(proc: str, name: str, log_path: str) -> None:
raise raise
def nativelauncher(pargs: list[str], cwd: str, name: str, log_path: str) -> None: def nativelauncher(pargs: list[str], cwd: str, name: str) -> None:
os.environ['MANAGER_DAEMON'] = name os.environ['MANAGER_DAEMON'] = name
# CLEARPILOT: redirect stderr and stdout to per-process log file
try:
log_file = open(log_path, 'a')
os.dup2(log_file.fileno(), sys.stderr.fileno())
os.dup2(log_file.fileno(), sys.stdout.fileno())
except Exception as e:
print(f"CLEARPILOT: stderr redirect failed for {name}: {e}", file=sys.stderr)
# exec the process # exec the process
os.chdir(cwd) os.chdir(cwd)
os.execvp(pargs[0], pargs) os.execvp(pargs[0], pargs)
@@ -219,7 +110,6 @@ class ManagerProcess(ABC):
if dt > self.watchdog_max_dt: if dt > self.watchdog_max_dt:
if (self.watchdog_seen or self.always_watchdog and self.proc.exitcode is not None) and ENABLE_WATCHDOG: if (self.watchdog_seen or self.always_watchdog and self.proc.exitcode is not None) and ENABLE_WATCHDOG:
cloudlog.error(f"Watchdog timeout for {self.name} (exitcode {self.proc.exitcode}) restarting ({started=})") cloudlog.error(f"Watchdog timeout for {self.name} (exitcode {self.proc.exitcode}) restarting ({started=})")
session_log.warning("watchdog timeout for %s (exitcode %s), restarting", self.name, self.proc.exitcode)
self.restart() self.restart()
else: else:
self.watchdog_seen = True self.watchdog_seen = True
@@ -249,10 +139,6 @@ class ManagerProcess(ABC):
ret = self.proc.exitcode ret = self.proc.exitcode
cloudlog.info(f"{self.name} is dead with {ret}") cloudlog.info(f"{self.name} is dead with {ret}")
if ret is not None and ret != 0:
session_log.error("process %s died with exit code %s", self.name, ret)
elif ret == 0:
session_log.info("process %s stopped (exit 0)", self.name)
if self.proc.exitcode is not None: if self.proc.exitcode is not None:
self.shutting_down = False self.shutting_down = False
@@ -312,13 +198,9 @@ class NativeProcess(ManagerProcess):
global _log_dir global _log_dir
log_path = _log_dir+"/"+self.name+".log" log_path = _log_dir+"/"+self.name+".log"
# CLEARPILOT: ensure log file exists even if child redirect fails
open(log_path, 'a').close()
cwd = os.path.join(BASEDIR, self.cwd) cwd = os.path.join(BASEDIR, self.cwd)
cloudlog.info(f"starting process {self.name}") cloudlog.info(f"starting process {self.name}")
session_log.info("starting %s", self.name) self.proc = Process(name=self.name, target=self.launcher, args=(self.cmdline, cwd, self.name))
self.proc = Process(name=self.name, target=self.launcher, args=(self.cmdline, cwd, self.name, log_path))
self.proc.start() self.proc.start()
self.watchdog_seen = False self.watchdog_seen = False
self.shutting_down = False self.shutting_down = False
@@ -349,12 +231,8 @@ class PythonProcess(ManagerProcess):
global _log_dir global _log_dir
log_path = _log_dir+"/"+self.name+".log" log_path = _log_dir+"/"+self.name+".log"
# CLEARPILOT: ensure log file exists even if child redirect fails
open(log_path, 'a').close()
cloudlog.info(f"starting python {self.module}") cloudlog.info(f"starting python {self.module}")
session_log.info("starting %s", self.name) self.proc = Process(name=self.name, target=self.launcher, args=(self.module, self.name))
self.proc = Process(name=self.name, target=self.launcher, args=(self.module, self.name, log_path))
self.proc.start() self.proc.start()
self.watchdog_seen = False self.watchdog_seen = False
self.shutting_down = False self.shutting_down = False
@@ -398,7 +276,6 @@ class DaemonProcess(ManagerProcess):
pass pass
cloudlog.info(f"starting daemon {self.name}") cloudlog.info(f"starting daemon {self.name}")
session_log.info("starting daemon %s", self.name)
proc = subprocess.Popen(['python', '-m', self.module], proc = subprocess.Popen(['python', '-m', self.module],
stdin=open('/dev/null'), stdin=open('/dev/null'),
stdout=open(log_path, 'a'), stdout=open(log_path, 'a'),
+16 -13
View File
@@ -7,7 +7,6 @@ from openpilot.selfdrive.manager.process import PythonProcess, NativeProcess, Da
WEBCAM = os.getenv("USE_WEBCAM") is not None WEBCAM = os.getenv("USE_WEBCAM") is not None
BENCH_MODE = os.getenv("BENCH_MODE") is not None
def driverview(started: bool, params: Params, CP: car.CarParams) -> bool: def driverview(started: bool, params: Params, CP: car.CarParams) -> bool:
return started or params.get_bool("IsDriverViewEnabled") return started or params.get_bool("IsDriverViewEnabled")
@@ -52,13 +51,11 @@ def allow_uploads(started, params, CP: car.CarParams) -> bool:
allow_uploads = not (params.get_bool("DeviceManagement") and params.get_bool("NoUploads")) allow_uploads = not (params.get_bool("DeviceManagement") and params.get_bool("NoUploads"))
return allow_uploads return allow_uploads
# ClearPilot functions
def dashcam_should_run(started, params, CP: car.CarParams) -> bool:
return True # CLEARPILOT: dashcamd manages its own trip lifecycle
procs = [ procs = [
DaemonProcess("manage_athenad", "selfdrive.athena.manage_athenad", "AthenadPid"), DaemonProcess("manage_athenad", "selfdrive.athena.manage_athenad", "AthenadPid"),
# CLEARPILOT: camerad runs always (was driverview) so dashcamd can record
# the moment ignition+drive-gear arrives without waiting for camera startup.
NativeProcess("camerad", "system/camerad", ["./camerad"], always_run), NativeProcess("camerad", "system/camerad", ["./camerad"], always_run),
NativeProcess("logcatd", "system/logcatd", ["./logcatd"], allow_logging), NativeProcess("logcatd", "system/logcatd", ["./logcatd"], allow_logging),
NativeProcess("proclogd", "system/proclogd", ["./proclogd"], allow_logging), NativeProcess("proclogd", "system/proclogd", ["./proclogd"], allow_logging),
@@ -67,10 +64,12 @@ procs = [
PythonProcess("timed", "system.timed", always_run, enabled=not PC), PythonProcess("timed", "system.timed", always_run, enabled=not PC),
PythonProcess("dmonitoringmodeld", "selfdrive.modeld.dmonitoringmodeld", driverview, enabled=(not PC or WEBCAM)), PythonProcess("dmonitoringmodeld", "selfdrive.modeld.dmonitoringmodeld", driverview, enabled=(not PC or WEBCAM)),
# CLEARPILOT: disabled video encoding (camera .hevc files) — CAN/sensor logs still recorded via loggerd # CLEARPILOT: disabled segment + camera logging — no rlog/qlog or .hevc
# files written to /data/media/0/realdata. We don't use comma's upload/
# replay pipeline. Keep deleter running for any leftover cleanup.
# NativeProcess("encoderd", "system/loggerd", ["./encoderd"], allow_logging), # NativeProcess("encoderd", "system/loggerd", ["./encoderd"], allow_logging),
# NativeProcess("stream_encoderd", "system/loggerd", ["./encoderd", "--stream"], notcar), # NativeProcess("stream_encoderd", "system/loggerd", ["./encoderd", "--stream"], notcar),
NativeProcess("loggerd", "system/loggerd", ["./loggerd"], allow_logging), # NativeProcess("loggerd", "system/loggerd", ["./loggerd"], allow_logging),
NativeProcess("modeld", "selfdrive/modeld", ["./modeld"], only_onroad), NativeProcess("modeld", "selfdrive/modeld", ["./modeld"], only_onroad),
#NativeProcess("mapsd", "selfdrive/navd", ["./mapsd"], only_onroad), #NativeProcess("mapsd", "selfdrive/navd", ["./mapsd"], only_onroad),
#PythonProcess("navmodeld", "selfdrive.modeld.navmodeld", only_onroad), #PythonProcess("navmodeld", "selfdrive.modeld.navmodeld", only_onroad),
@@ -84,8 +83,17 @@ procs = [
PythonProcess("controlsd", "selfdrive.controls.controlsd", only_onroad), PythonProcess("controlsd", "selfdrive.controls.controlsd", only_onroad),
PythonProcess("deleter", "system.loggerd.deleter", always_run), PythonProcess("deleter", "system.loggerd.deleter", always_run),
PythonProcess("dmonitoringd", "selfdrive.monitoring.dmonitoringd", driverview, enabled=(not PC or WEBCAM)), PythonProcess("dmonitoringd", "selfdrive.monitoring.dmonitoringd", driverview, enabled=(not PC or WEBCAM)),
# PythonProcess("qcomgpsd", "system.qcomgpsd.qcomgpsd", qcomgps, enabled=TICI), # PythonProcess("qcomgpsd", "system.qcomgpsd.qcomgpsd", qcomgps, enabled=TICI), # Fixme
# CLEARPILOT: replacement for qcomgpsd (whose diag interface is broken on this device).
# Uses Quectel modem AT commands via mmcli. Self-driving does NOT consume this; locationd
# is patched to skip gpsLocation. Used only for system clock + UI speed + dashcam metadata.
PythonProcess("gpsd", "system.clearpilot.gpsd", qcomgps, enabled=TICI), PythonProcess("gpsd", "system.clearpilot.gpsd", qcomgps, enabled=TICI),
# CLEARPILOT: speed/cruise overlay daemon. Reads gpsLocation + carState, writes display
# params for the onroad UI; asserts ClearpilotPlayDing on speed-limit warning transitions.
PythonProcess("speed_logicd", "selfdrive.clearpilot.speed_logicd", only_onroad),
# CLEARPILOT: dashcam — VisionIPC frames → OMX H.264 → 3-min MP4 segments + SRT
# GPS subtitles in /data/media/0/videos/. Manages its own trip lifecycle.
NativeProcess("dashcamd", "selfdrive/clearpilot", ["./dashcamd"], always_run),
# PythonProcess("ugpsd", "system.ugpsd", only_onroad, enabled=TICI), # PythonProcess("ugpsd", "system.ugpsd", only_onroad, enabled=TICI),
#PythonProcess("navd", "selfdrive.navd.navd", only_onroad), #PythonProcess("navd", "selfdrive.navd.navd", only_onroad),
PythonProcess("pandad", "selfdrive.boardd.pandad", always_run), PythonProcess("pandad", "selfdrive.boardd.pandad", always_run),
@@ -108,11 +116,6 @@ procs = [
# FrogPilot processes # FrogPilot processes
PythonProcess("fleet_manager", "selfdrive.frogpilot.fleetmanager.fleet_manager", always_run), PythonProcess("fleet_manager", "selfdrive.frogpilot.fleetmanager.fleet_manager", always_run),
PythonProcess("frogpilot_process", "selfdrive.frogpilot.frogpilot_process", always_run), PythonProcess("frogpilot_process", "selfdrive.frogpilot.frogpilot_process", always_run),
# ClearPilot processes
NativeProcess("dashcamd", "selfdrive/clearpilot", ["./dashcamd"], dashcam_should_run),
PythonProcess("telemetryd", "selfdrive.clearpilot.telemetryd", always_run),
PythonProcess("bench_onroad", "selfdrive.clearpilot.bench_onroad", always_run, enabled=BENCH_MODE),
] ]
managed_processes = {p.name: p for p in procs} managed_processes = {p.name: p for p in procs}
+2 -14
View File
@@ -128,14 +128,10 @@ def main():
assert vipc_client.is_connected() assert vipc_client.is_connected()
cloudlog.warning(f"connected with buffer size: {vipc_client.buffer_len}") cloudlog.warning(f"connected with buffer size: {vipc_client.buffer_len}")
sm = SubMaster(["liveCalibration", "carState"]) sm = SubMaster(["liveCalibration"])
pm = PubMaster(["driverStateV2"]) pm = PubMaster(["driverStateV2"])
calib = np.zeros(CALIB_LEN, dtype=np.float32) calib = np.zeros(CALIB_LEN, dtype=np.float32)
# CLEARPILOT: cache last model output so we can republish (not re-infer) at standstill.
# Saves ~7% CPU; downstream dmonitoringd sees a steady 10Hz stream with known-good
# last readings (driver can't become distracted relative to a stopped car).
last_model_output = None
# last = 0 # last = 0
while True: while True:
@@ -147,16 +143,8 @@ def main():
if sm.updated["liveCalibration"]: if sm.updated["liveCalibration"]:
calib[:] = np.array(sm["liveCalibration"].rpyCalib) calib[:] = np.array(sm["liveCalibration"].rpyCalib)
standstill = sm["carState"].standstill
t1 = time.perf_counter() t1 = time.perf_counter()
if standstill and last_model_output is not None: model_output, dsp_execution_time = model.run(buf, calib)
# CLEARPILOT: reuse last inference at standstill
model_output = last_model_output
dsp_execution_time = 0.0
else:
model_output, dsp_execution_time = model.run(buf, calib)
last_model_output = model_output
t2 = time.perf_counter() t2 = time.perf_counter()
pm.send("driverStateV2", get_driverstate_packet(model_output, vipc_client.frame_id, vipc_client.timestamp_sof, t2 - t1, dsp_execution_time)) pm.send("driverStateV2", get_driverstate_packet(model_output, vipc_client.frame_id, vipc_client.timestamp_sof, t2 - t1, dsp_execution_time))
+2 -36
View File
@@ -134,15 +134,11 @@ def main(demo=False):
setproctitle(PROCESS_NAME) setproctitle(PROCESS_NAME)
config_realtime_process(7, 54) config_realtime_process(7, 54)
import time as _time
cloudlog.warning("setting up CL context") cloudlog.warning("setting up CL context")
_t0 = _time.monotonic()
cl_context = CLContext() cl_context = CLContext()
_t1 = _time.monotonic() cloudlog.warning("CL context ready; loading model")
cloudlog.warning("CL context ready in %.3fs; loading model", _t1 - _t0)
model = ModelState(cl_context) model = ModelState(cl_context)
_t2 = _time.monotonic() cloudlog.warning("models loaded, modeld starting")
cloudlog.warning("model loaded in %.3fs (total init %.3fs), modeld starting", _t2 - _t1, _t2 - _t0)
# visionipc clients # visionipc clients
while True: while True:
@@ -183,9 +179,6 @@ def main(demo=False):
model_transform_main = np.zeros((3, 3), dtype=np.float32) model_transform_main = np.zeros((3, 3), dtype=np.float32)
model_transform_extra = np.zeros((3, 3), dtype=np.float32) model_transform_extra = np.zeros((3, 3), dtype=np.float32)
live_calib_seen = False live_calib_seen = False
model_standby = False
last_standby_ts_write = 0
params_memory = Params("/dev/shm/params")
nav_features = np.zeros(ModelConstants.NAV_FEATURE_LEN, dtype=np.float32) nav_features = np.zeros(ModelConstants.NAV_FEATURE_LEN, dtype=np.float32)
nav_instructions = np.zeros(ModelConstants.NAV_INSTRUCTION_LEN, dtype=np.float32) nav_instructions = np.zeros(ModelConstants.NAV_INSTRUCTION_LEN, dtype=np.float32)
buf_main, buf_extra = None, None buf_main, buf_extra = None, None
@@ -240,33 +233,6 @@ def main(demo=False):
meta_extra = meta_main meta_extra = meta_main
sm.update(0) sm.update(0)
# CLEARPILOT: two-state modeld — 0fps only when parked (ignition-on means
# engine running in park; ignition-off stops modeld at the manager level).
# Standstill in drive (red light) keeps running so lateral stays responsive
# and liveCalibration/paramsd observations continue.
parked = sm['carState'].gearShifter == car.CarState.GearShifter.park
should_standby = parked
if should_standby and not model_standby:
params_memory.put_bool("ModelStandby", True)
params_memory.put("ModelFps", "0")
model_standby = True
cloudlog.warning("modeld: standby ON")
elif not should_standby and model_standby:
params_memory.put_bool("ModelStandby", False)
params_memory.put("ModelFps", "20")
model_standby = False
run_count = 0
frame_dropped_filter.x = 0.
cloudlog.warning("modeld: standby OFF")
if model_standby:
now = _time.monotonic()
if now - last_standby_ts_write > 1.0:
params_memory.put("ModelStandbyTs", str(now))
last_standby_ts_write = now
last_vipc_frame_id = meta_main.frame_id
continue
desire = DH.desire desire = DH.desire
is_rhd = sm["driverMonitoringState"].isRHD is_rhd = sm["driverMonitoringState"].isRHD
frame_id = sm["roadCameraState"].frameId frame_id = sm["roadCameraState"].frameId
+2 -22
View File
@@ -21,7 +21,6 @@ def dmonitoringd_thread():
v_cruise_last = 0 v_cruise_last = 0
driver_engaged = False driver_engaged = False
dbg_prev_valid = True # CLEARPILOT: track valid transitions
# 10Hz <- dmonitoringmodeld # 10Hz <- dmonitoringmodeld
while True: while True:
@@ -44,18 +43,7 @@ def dmonitoringd_thread():
# Get data from dmonitoringmodeld # Get data from dmonitoringmodeld
events = Events() events = Events()
# CLEARPILOT: narrow update_states gate. The original sm.all_checks() also if sm.all_checks() and len(sm['liveCalibration'].rpyCalib):
# required modelV2 fresh (stops at standstill in two-state modeld) and
# liveCalibration.valid (calibrationd cascades its own freq_ok to valid, which
# flaps). Both made DM freeze pose → face_detected stuck False → awareness
# decayed to 0 within 6s of engagement. Narrow the gate to the subs
# update_states actually reads, and only to alive+valid (skip freq_ok and
# skip liveCalibration.valid). rpyCalib presence is sufficient to know
# calibration has produced output.
if (sm.alive['driverStateV2'] and sm.valid['driverStateV2'] and
sm.alive['carState'] and sm.valid['carState'] and
sm.alive['controlsState'] and sm.valid['controlsState'] and
sm.alive['liveCalibration'] and len(sm['liveCalibration'].rpyCalib) > 0):
driver_status.update_states(sm['driverStateV2'], sm['liveCalibration'].rpyCalib, sm['carState'].vEgo, sm['controlsState'].enabled) driver_status.update_states(sm['driverStateV2'], sm['liveCalibration'].rpyCalib, sm['carState'].vEgo, sm['controlsState'].enabled)
# Block engaging after max number of distrations # Block engaging after max number of distrations
@@ -66,16 +54,8 @@ def dmonitoringd_thread():
# Update events from driver state # Update events from driver state
driver_status.update_events(events, driver_engaged, sm['controlsState'].enabled, sm['carState'].standstill) driver_status.update_events(events, driver_engaged, sm['controlsState'].enabled, sm['carState'].standstill)
# CLEARPILOT: log on transition to invalid so we can see which sub caused the cascade
dm_valid = sm.all_checks()
if dm_valid != dbg_prev_valid and not dm_valid:
import sys
bad = [s for s in sm.alive if not (sm.alive[s] and sm.valid[s] and sm.freq_ok.get(s, True))]
details = [f"{s}(a={sm.alive[s]},v={sm.valid[s]},f={sm.freq_ok[s]})" for s in bad]
print(f"CLP driverMonitoringState valid=False: {' '.join(details)}", file=sys.stderr, flush=True)
dbg_prev_valid = dm_valid
# build driverMonitoringState packet # build driverMonitoringState packet
dat = messaging.new_message('driverMonitoringState', valid=dm_valid) dat = messaging.new_message('driverMonitoringState', valid=sm.all_checks())
dat.driverMonitoringState = { dat.driverMonitoringState = {
"events": events.to_msg(), "events": events.to_msg(),
"faceDetected": driver_status.face_detected, "faceDetected": driver_status.face_detected,
+4 -24
View File
@@ -6,11 +6,9 @@ from openpilot.common.numpy_fast import interp
from openpilot.common.swaglog import cloudlog from openpilot.common.swaglog import cloudlog
from openpilot.selfdrive.controls.lib.pid import PIDController from openpilot.selfdrive.controls.lib.pid import PIDController
class BaseFanController(ABC): class BaseFanController(ABC):
@abstractmethod @abstractmethod
def update(self, cur_temp: float, ignition: bool, standstill: bool = False, def update(self, cur_temp: float, ignition: bool) -> int:
is_parked: bool = True, cruise_engaged: bool = False) -> int:
pass pass
@@ -22,27 +20,9 @@ class TiciFanController(BaseFanController):
self.last_ignition = False self.last_ignition = False
self.controller = PIDController(k_p=0, k_i=4e-3, k_f=1, rate=(1 / DT_TRML)) self.controller = PIDController(k_p=0, k_i=4e-3, k_f=1, rate=(1 / DT_TRML))
def update(self, cur_temp: float, ignition: bool, standstill: bool = False, def update(self, cur_temp: float, ignition: bool) -> int:
is_parked: bool = True, cruise_engaged: bool = False) -> int: self.controller.neg_limit = -(100 if ignition else 30)
# CLEARPILOT fan range rules: self.controller.pos_limit = -(30 if ignition else 0)
# parked → 0-100% (full, no floor)
# in drive + cruise engaged (any speed, inc standstill) → 30-100%
# in drive + cruise off + standstill → 10-100%
# in drive + cruise off + moving → 30-100%
# In the PID output, neg_limit is how negative it can go (= max fan as %),
# pos_limit is how positive (= negative of min fan %).
if is_parked:
self.controller.neg_limit = -100
self.controller.pos_limit = 0
elif cruise_engaged:
self.controller.neg_limit = -100
self.controller.pos_limit = -30
elif standstill:
self.controller.neg_limit = -100
self.controller.pos_limit = -10
else:
self.controller.neg_limit = -100
self.controller.pos_limit = -30
if ignition != self.last_ignition: if ignition != self.last_ignition:
self.controller.reset() self.controller.reset()
+7 -10
View File
@@ -36,9 +36,12 @@ class PowerMonitoring:
# Reset capacity if it's low # Reset capacity if it's low
self.car_battery_capacity_uWh = max((CAR_BATTERY_CAPACITY_uWh / 10), int(car_battery_capacity_uWh)) self.car_battery_capacity_uWh = max((CAR_BATTERY_CAPACITY_uWh / 10), int(car_battery_capacity_uWh))
# CLEARPILOT: hardcoded 30 minute shutdown timer (not user-configurable) # FrogPilot variables
self.device_shutdown_time = 1800 device_management = self.params.get_bool("DeviceManagement")
self.low_voltage_shutdown = VBATT_PAUSE_CHARGING device_shutdown_setting = self.params.get_int("DeviceShutdown") if device_management else 33
# If the toggle is set for < 1 hour, configure by 15 minute increments
self.device_shutdown_time = (device_shutdown_setting - 3) * 3600 if device_shutdown_setting >= 4 else device_shutdown_setting * (60 * 15)
self.low_voltage_shutdown = self.params.get_float("LowVoltageShutdown") if device_management else VBATT_PAUSE_CHARGING
# Calculation tick # Calculation tick
def calculate(self, voltage: int | None, ignition: bool): def calculate(self, voltage: int | None, ignition: bool):
@@ -122,13 +125,7 @@ class PowerMonitoring:
offroad_time > VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S) offroad_time > VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S)
should_shutdown |= offroad_time > self.device_shutdown_time should_shutdown |= offroad_time > self.device_shutdown_time
should_shutdown |= low_voltage_shutdown should_shutdown |= low_voltage_shutdown
# CLEARPILOT: removed `car_battery_capacity_uWh <= 0` trigger. That's a virtual should_shutdown |= (self.car_battery_capacity_uWh <= 0)
# capacity counter floor-limited to 3e6 µWh on boot which drains in ~12 min at
# typical device power. With a short drive that doesn't fully recharge (charges
# at 45W, cap 30e6 µWh = 36 min to full), a quick store stop could trip shutdown
# well before the intended 30-min idle timer. The real protection we want here
# is the car battery voltage check (kept above) — the virtual counter is now
# retained only for telemetry.
should_shutdown &= not ignition should_shutdown &= not ignition
should_shutdown &= (not self.params.get_bool("DisablePowerDown")) should_shutdown &= (not self.params.get_bool("DisablePowerDown"))
should_shutdown &= in_car should_shutdown &= in_car
+3 -33
View File
@@ -10,7 +10,7 @@ from pathlib import Path
import psutil import psutil
import cereal.messaging as messaging import cereal.messaging as messaging
from cereal import car, log from cereal import log
from cereal.services import SERVICE_LIST from cereal.services import SERVICE_LIST
from openpilot.common.dict_helpers import strip_deprecated_keys from openpilot.common.dict_helpers import strip_deprecated_keys
from openpilot.common.filter_simple import FirstOrderFilter from openpilot.common.filter_simple import FirstOrderFilter
@@ -164,7 +164,7 @@ def hw_state_thread(end_event, hw_queue):
def thermald_thread(end_event, hw_queue) -> None: def thermald_thread(end_event, hw_queue) -> None:
pm = messaging.PubMaster(['deviceState', 'frogpilotDeviceState']) pm = messaging.PubMaster(['deviceState', 'frogpilotDeviceState'])
sm = messaging.SubMaster(["peripheralState", "gpsLocationExternal", "controlsState", "pandaStates", "carState"], poll="pandaStates") sm = messaging.SubMaster(["peripheralState", "gpsLocationExternal", "controlsState", "pandaStates"], poll="pandaStates")
count = 0 count = 0
@@ -197,9 +197,7 @@ def thermald_thread(end_event, hw_queue) -> None:
engaged_prev = False engaged_prev = False
params = Params() params = Params()
params_memory = Params("/dev/shm/params")
power_monitor = PowerMonitoring() power_monitor = PowerMonitoring()
last_touch_reset = "0" # CLEARPILOT: track last seen touch reset value
HARDWARE.initialize_hardware() HARDWARE.initialize_hardware()
thermal_config = HARDWARE.get_thermal_config() thermal_config = HARDWARE.get_thermal_config()
@@ -292,18 +290,7 @@ def thermald_thread(end_event, hw_queue) -> None:
msg.deviceState.maxTempC = all_comp_temp msg.deviceState.maxTempC = all_comp_temp
if fan_controller is not None: if fan_controller is not None:
# CLEARPILOT: fan rules based on gear (parked vs drive) and cruise-engaged state msg.deviceState.fanSpeedPercentDesired = fan_controller.update(all_comp_temp, onroad_conditions["ignition"])
if sm.seen['carState']:
cs = sm['carState']
standstill = cs.standstill
is_parked = cs.gearShifter == car.CarState.GearShifter.park
else:
standstill = False
is_parked = True # default safe: assume parked, no fan floor
cruise_engaged = sm['controlsState'].enabled if sm.seen['controlsState'] else False
msg.deviceState.fanSpeedPercentDesired = fan_controller.update(
all_comp_temp, onroad_conditions["ignition"], standstill,
is_parked=is_parked, cruise_engaged=cruise_engaged)
is_offroad_for_5_min = (started_ts is None) and ((not started_seen) or (off_ts is None) or (time.monotonic() - off_ts > 60 * 5)) is_offroad_for_5_min = (started_ts is None) and ((not started_seen) or (off_ts is None) or (time.monotonic() - off_ts > 60 * 5))
if is_offroad_for_5_min and offroad_comp_temp > OFFROAD_DANGER_TEMP: if is_offroad_for_5_min and offroad_comp_temp > OFFROAD_DANGER_TEMP:
@@ -421,26 +408,9 @@ def thermald_thread(end_event, hw_queue) -> None:
statlog.sample("som_power_draw", som_power_draw) statlog.sample("som_power_draw", som_power_draw)
msg.deviceState.somPowerDrawW = som_power_draw msg.deviceState.somPowerDrawW = som_power_draw
# CLEARPILOT: screen tap resets shutdown timer (off_ts) while offroad
touch_reset = params_memory.get("ShutdownTouchReset")
if touch_reset is not None and touch_reset != last_touch_reset and off_ts is not None:
off_ts = time.monotonic()
cloudlog.info("shutdown timer reset by screen touch")
last_touch_reset = touch_reset
# Check if we need to shut down # Check if we need to shut down
if power_monitor.should_shutdown(onroad_conditions["ignition"], in_car, off_ts, started_seen): if power_monitor.should_shutdown(onroad_conditions["ignition"], in_car, off_ts, started_seen):
cloudlog.warning(f"shutting device down, offroad since {off_ts}") cloudlog.warning(f"shutting device down, offroad since {off_ts}")
# CLEARPILOT: signal dashcamd to close recording gracefully before power-off
params_memory.put_bool("DashcamShutdown", True)
deadline = time.monotonic() + 15.0
while time.monotonic() < deadline:
if not params_memory.get_bool("DashcamShutdown"):
cloudlog.info("dashcamd shutdown ack received")
break
time.sleep(0.5)
else:
cloudlog.warning("dashcamd shutdown ack timeout, proceeding")
params.put_bool("DoShutdown", True) params.put_bool("DoShutdown", True)
msg.deviceState.started = started_ts is not None msg.deviceState.started = started_ts is not None
+23 -11
View File
@@ -79,8 +79,8 @@ void OnroadWindow::updateState(const UIState &s) {
nvg->update(); // CLEARPILOT: force repaint every frame for HUD elements nvg->update(); // CLEARPILOT: force repaint every frame for HUD elements
QColor bgColor = bg_colors[s.status]; QColor bgColor = bg_colors[s.status];
// CLEARPILOT: read from frogpilotCarControl cereal message (was paramsMemory) // CLEARPILOT: read from paramsMemory; controlsd writes "no_lat_lane_change".
if ((*s.sm)["frogpilotCarControl"].getFrogpilotCarControl().getNoLatLaneChange()) { if (paramsMemory.getBool("no_lat_lane_change")) {
bgColor = bg_colors[STATUS_DISENGAGED]; bgColor = bg_colors[STATUS_DISENGAGED];
} }
@@ -851,8 +851,15 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) {
// CLEARPILOT: nightrider mode — outline only, no fill // CLEARPILOT: nightrider mode — outline only, no fill
bool outlineOnly = nightriderMode; bool outlineOnly = nightriderMode;
// CLEARPILOT: in nightrider mode, hide all lines when not engaged // CLEARPILOT: read here so the nightrider hide-when-disengaged check below
if (outlineOnly && edgeColor == bg_colors[STATUS_DISENGAGED]) { // can let lane-change frames through (controlsd forces edgeColor to
// STATUS_DISENGAGED while no_lat_lane_change is true).
bool is_no_lat_lane_change = paramsMemory.getBool("no_lat_lane_change");
// CLEARPILOT: in nightrider mode, hide all lines when not engaged — except
// during a lane change, where we still want lane lines + road edges drawn
// alongside the yellow lane-change outline.
if (outlineOnly && edgeColor == bg_colors[STATUS_DISENGAGED] && !is_no_lat_lane_change) {
painter.restore(); painter.restore();
return; return;
} }
@@ -893,8 +900,7 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) {
// paint center lane path // paint center lane path
// QColor bg_colors[CHANGE_LANE_PATH_COLOR]; // QColor bg_colors[CHANGE_LANE_PATH_COLOR];
// CLEARPILOT: read from frogpilotCarControl cereal message (was paramsMemory) // is_no_lat_lane_change was read at the top of this function.
bool is_no_lat_lane_change = sm["frogpilotCarControl"].getFrogpilotCarControl().getNoLatLaneChange();
QColor center_lane_color; QColor center_lane_color;
@@ -955,11 +961,17 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) {
} }
if (outlineOnly) { if (outlineOnly) {
// CLEARPILOT: in nightrider, the tire path outline is light blue at 3px. // CLEARPILOT: in nightrider, the tire path is rendered as an outline.
// Uses a fixed light-blue instead of center_lane_color (which is status-tinted) so // - Normal: light blue 3px (status-neutral guide)
// the path reads as a neutral guide, not as engagement/status feedback. // - Lane change: 4px outline of CHANGE_LANE_PATH_COLOR (the same yellow
QColor lightBlue(153, 204, 255, 220); // #99CCFF light blue, mostly opaque // used to fill the polygon in normal mode), so the nightrider lane
painter.setPen(QPen(lightBlue, 3)); // change reads as the same visual cue, just hollow.
if (is_no_lat_lane_change) {
painter.setPen(QPen(bg_colors[CHANGE_LANE_PATH_COLOR], 4));
} else {
QColor lightBlue(153, 204, 255, 220); // #99CCFF light blue, mostly opaque
painter.setPen(QPen(lightBlue, 3));
}
painter.setBrush(Qt::NoBrush); painter.setBrush(Qt::NoBrush);
} else { } else {
painter.setPen(Qt::NoPen); painter.setPen(Qt::NoPen);
Binary file not shown.
+14 -12
View File
@@ -93,7 +93,8 @@ class Soundd:
self.spl_filter_weighted = FirstOrderFilter(0, 2.5, FILTER_DT, initialized=False) self.spl_filter_weighted = FirstOrderFilter(0, 2.5, FILTER_DT, initialized=False)
# ClearPilot ding (plays independently of alerts) # CLEARPILOT ding (plays independently of alerts; triggered by writers
# setting ClearpilotPlayDing="1" in /dev/shm/params).
self.ding_sound = None self.ding_sound = None
self.ding_frame = 0 self.ding_frame = 0
self.ding_playing = False self.ding_playing = False
@@ -101,6 +102,7 @@ class Soundd:
self._load_ding() self._load_ding()
def _load_ding(self): def _load_ding(self):
import sys
ding_path = BASEDIR + "/selfdrive/clearpilot/sounds/ding.wav" ding_path = BASEDIR + "/selfdrive/clearpilot/sounds/ding.wav"
try: try:
wavefile = wave.open(ding_path, 'r') wavefile = wave.open(ding_path, 'r')
@@ -109,9 +111,9 @@ class Soundd:
assert wavefile.getframerate() == SAMPLE_RATE assert wavefile.getframerate() == SAMPLE_RATE
length = wavefile.getnframes() length = wavefile.getnframes()
self.ding_sound = np.frombuffer(wavefile.readframes(length), dtype=np.int16).astype(np.float32) / (2**16/2) self.ding_sound = np.frombuffer(wavefile.readframes(length), dtype=np.int16).astype(np.float32) / (2**16/2)
cloudlog.info(f"ClearPilot ding loaded: {length} frames") print(f"CLP soundd: ClearPilot ding loaded: {length} frames", file=sys.stderr, flush=True)
except Exception as e: except Exception as e:
cloudlog.error(f"Failed to load ding sound: {e}") print(f"CLP soundd: failed to load ding sound: {e}", file=sys.stderr, flush=True)
self.ding_sound = None self.ding_sound = None
def load_sounds(self): def load_sounds(self):
@@ -160,7 +162,7 @@ class Soundd:
ret = ret * self.current_volume ret = ret * self.current_volume
# Mix in ClearPilot ding (independent of alerts, always max volume) # CLEARPILOT: mix in ding (independent of alerts, always max volume)
if self.ding_playing and self.ding_sound is not None: if self.ding_playing and self.ding_sound is not None:
ding_remaining = len(self.ding_sound) - self.ding_frame ding_remaining = len(self.ding_sound) - self.ding_frame
if ding_remaining > 0: if ding_remaining > 0:
@@ -231,14 +233,6 @@ class Soundd:
self.get_audible_alert(sm) self.get_audible_alert(sm)
# ClearPilot: check for ding trigger at ~2Hz
self.ding_check_counter += 1
if self.ding_check_counter % 10 == 0 and self.ding_sound is not None:
if self.params_memory.get("ClearpilotPlayDing") == b"1":
self.params_memory.put("ClearpilotPlayDing", "0")
self.ding_playing = True
self.ding_frame = 0
rk.keep_time() rk.keep_time()
assert stream.active assert stream.active
@@ -247,6 +241,14 @@ class Soundd:
if self.params_memory.get_bool("FrogPilotTogglesUpdated"): if self.params_memory.get_bool("FrogPilotTogglesUpdated"):
self.update_frogpilot_params() self.update_frogpilot_params()
# CLEARPILOT: poll ClearpilotPlayDing at ~2Hz; clear it on read.
self.ding_check_counter += 1
if self.ding_check_counter % 10 == 0 and self.ding_sound is not None:
if self.params_memory.get("ClearpilotPlayDing") == b"1":
self.params_memory.put("ClearpilotPlayDing", "0")
self.ding_playing = True
self.ding_frame = 0
def update_frogpilot_params(self): def update_frogpilot_params(self):
self.alert_volume_control = self.params.get_bool("AlertVolumeControl") self.alert_volume_control = self.params.get_bool("AlertVolumeControl")
-5
View File
@@ -1,10 +1,5 @@
#!/bin/sh #!/bin/sh
# CLEARPILOT: prefer freshly built _spinner over prebuilt qt/spinner
if [ -f ./_spinner ]; then
exec ./_spinner "$1"
fi
if [ -f /TICI ] && [ ! -f qt/spinner ]; then if [ -f /TICI ] && [ ! -f qt/spinner ]; then
cp qt/spinner_larch64 qt/spinner cp qt/spinner_larch64 qt/spinner
fi fi
+3 -2
View File
@@ -118,8 +118,9 @@ void update_model(UIState *s,
} }
// update path // update path
// CLEARPILOT: read from frogpilotCarControl cereal message (was paramsMemory) // CLEARPILOT: read from paramsMemory; controlsd writes "no_lat_lane_change"
bool no_lat_lane_change = (*s->sm)["frogpilotCarControl"].getFrogpilotCarControl().getNoLatLaneChange(); // there. (Broken used a custom cereal field; we keep the param-based wiring.)
bool no_lat_lane_change = paramsMemory.getBool("no_lat_lane_change");
float path; float path;
if (no_lat_lane_change) { if (no_lat_lane_change) {
path = (float)LANE_CHANGE_NO_LAT_PATH_WIDTH / 20; // Release: better calc for EU users path = (float)LANE_CHANGE_NO_LAT_PATH_WIDTH / 20; // Release: better calc for EU users
+2 -12
View File
@@ -7,27 +7,17 @@
#include "system/hardware/hw.h" #include "system/hardware/hw.h"
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
fprintf(stderr, "camerad: starting\n");
if (Hardware::PC()) { if (Hardware::PC()) {
fprintf(stderr, "camerad: exiting, not meant to run on PC\n"); printf("exiting, camerad is not meant to run on PC\n");
return 0; return 0;
} }
int ret; int ret;
fprintf(stderr, "camerad: setting realtime priority 53\n");
ret = util::set_realtime_priority(53); ret = util::set_realtime_priority(53);
fprintf(stderr, "camerad: set_realtime_priority ret=%d\n", ret);
assert(ret == 0); assert(ret == 0);
fprintf(stderr, "camerad: setting core affinity to cpu6\n");
ret = util::set_core_affinity({6}); ret = util::set_core_affinity({6});
bool isOffroad = Params().getBool("IsOffroad"); assert(ret == 0 || Params().getBool("IsOffroad")); // failure ok while offroad due to offlining cores
fprintf(stderr, "camerad: set_core_affinity ret=%d, IsOffroad=%d\n", ret, isOffroad);
assert(ret == 0 || isOffroad); // failure ok while offroad due to offlining cores
fprintf(stderr, "camerad: starting camerad_thread\n");
camerad_thread(); camerad_thread();
fprintf(stderr, "camerad: camerad_thread returned\n");
return 0; return 0;
} }
+33 -30
View File
@@ -1,13 +1,22 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
ClearPilot GPS daemon — reads GPS from Quectel EC25 modem via AT commands ClearPilot GPS daemon — reads GPS from Quectel EC25 modem via AT commands
and publishes gpsLocation messages for locationd/timed. and publishes gpsLocation messages.
Replaces qcomgpsd which uses the diag interface (broken on this device). Replaces qcomgpsd (which uses the diag interface broken on this device).
Used solely for: setting system clock on first fix, an on-screen UI
speed indicator, per-segment GPS metadata for the dashcam, and driving
the auto day/night display-mode switch (ScreenDisplayMode 0 ↔ 1) via
NOAA solar-position calc against the current fix.
Self-driving code does NOT consume this output — locationd is patched
to not subscribe to gpsLocation, so liveLocationKalman.gpsOK stays false.
""" """
import math import math
import os import os
import subprocess import subprocess
import sys
import time import time
import datetime import datetime
@@ -15,7 +24,6 @@ from cereal import log
import cereal.messaging as messaging import cereal.messaging as messaging
from openpilot.common.gpio import gpio_init, gpio_set from openpilot.common.gpio import gpio_init, gpio_set
from openpilot.common.params import Params from openpilot.common.params import Params
from openpilot.common.swaglog import cloudlog
from openpilot.common.time import system_time_valid from openpilot.common.time import system_time_valid
from openpilot.system.hardware.tici.pins import GPIO from openpilot.system.hardware.tici.pins import GPIO
@@ -84,8 +92,7 @@ def at_cmd(cmd: str) -> str:
f"mmcli -m any --timeout 10 --command='{cmd}'", f"mmcli -m any --timeout 10 --command='{cmd}'",
shell=True, encoding='utf8', stderr=subprocess.DEVNULL shell=True, encoding='utf8', stderr=subprocess.DEVNULL
).strip() ).strip()
# mmcli wraps AT responses: response: '+QGPSLOC: ...' # mmcli wraps AT responses: response: '+QGPSLOC: ...' — strip the wrapper
# Strip the wrapper to get just the AT response
if result.startswith("response: '") and result.endswith("'"): if result.startswith("response: '") and result.endswith("'"):
result = result[len("response: '"):-1] result = result[len("response: '"):-1]
return result return result
@@ -94,7 +101,7 @@ def at_cmd(cmd: str) -> str:
def wait_for_modem(): def wait_for_modem():
cloudlog.warning("gpsd: waiting for modem") print("CLP gpsd: waiting for modem", file=sys.stderr, flush=True)
while True: while True:
ret = subprocess.call( ret = subprocess.call(
"mmcli -m any --timeout 10 --command='AT+QGPS?'", "mmcli -m any --timeout 10 --command='AT+QGPS?'",
@@ -125,12 +132,10 @@ def parse_qgpsloc(response: str):
fix = int(fields[5]) # 2=2D, 3=3D fix = int(fields[5]) # 2=2D, 3=3D
cog = float(fields[6]) # course over ground cog = float(fields[6]) # course over ground
spkm = float(fields[7]) # speed km/h spkm = float(fields[7]) # speed km/h
spkn = float(fields[8]) # speed knots
date = fields[9] # DDMMYY date = fields[9] # DDMMYY
nsat = int(fields[10]) nsat = int(fields[10])
# Build unix timestamp from UTC + date # Build unix timestamp from UTC + date
# utc: "HHMMSS.S", date: "DDMMYY"
hh, mm = int(utc[0:2]), int(utc[2:4]) hh, mm = int(utc[0:2]), int(utc[2:4])
ss = float(utc[4:]) ss = float(utc[4:])
dd, mo, yy = int(date[0:2]), int(date[2:4]), 2000 + int(date[4:6]) dd, mo, yy = int(date[0:2]), int(date[2:4]), 2000 + int(date[4:6])
@@ -141,52 +146,51 @@ def parse_qgpsloc(response: str):
"latitude": lat, "latitude": lat,
"longitude": lon, "longitude": lon,
"altitude": alt, "altitude": alt,
"speed": spkm / 3.6, # convert km/h to m/s "speed": spkm / 3.6, # km/h -> m/s
"bearing": cog, "bearing": cog,
"accuracy": hdop * 5, # rough conversion from HDOP to meters "accuracy": hdop * 5, # rough HDOP -> meters
"timestamp_ms": dt.timestamp() * 1e3, "timestamp_ms": dt.timestamp() * 1e3,
"satellites": nsat, "satellites": nsat,
"fix": fix, "fix": fix,
} }
except (ValueError, IndexError) as e: except (ValueError, IndexError) as e:
cloudlog.error(f"gpsd: parse error: {e}") print(f"CLP gpsd: parse error: {e}", file=sys.stderr, flush=True)
return None return None
def main(): def main():
import sys print("CLP gpsd: starting", file=sys.stderr, flush=True)
print("gpsd: starting", file=sys.stderr, flush=True)
# Kill system gpsd which may respawn and interfere with modem access # Kill system gpsd which may respawn and interfere with modem access
subprocess.run("pkill -f /usr/sbin/gpsd", shell=True, subprocess.run("pkill -f /usr/sbin/gpsd", shell=True,
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
wait_for_modem() wait_for_modem()
print("gpsd: modem ready", file=sys.stderr, flush=True) print("CLP gpsd: modem ready", file=sys.stderr, flush=True)
# Enable GPS antenna power # Enable GPS antenna power
gpio_init(GPIO.GNSS_PWR_EN, True) gpio_init(GPIO.GNSS_PWR_EN, True)
gpio_set(GPIO.GNSS_PWR_EN, True) gpio_set(GPIO.GNSS_PWR_EN, True)
print("gpsd: GPIO power enabled", file=sys.stderr, flush=True) print("CLP gpsd: GPIO power enabled", file=sys.stderr, flush=True)
# Don't restart GPS if already running (preserve existing fix) # Don't restart GPS if already running (preserve existing fix)
resp = at_cmd("AT+QGPS?") resp = at_cmd("AT+QGPS?")
print(f"gpsd: QGPS status: {resp}", file=sys.stderr, flush=True) print(f"CLP gpsd: QGPS status: {resp}", file=sys.stderr, flush=True)
if "QGPS: 1" not in resp: if "QGPS: 1" not in resp:
at_cmd('AT+QGPSCFG="dpoenable",0') at_cmd('AT+QGPSCFG="dpoenable",0')
at_cmd('AT+QGPSCFG="outport","none"') at_cmd('AT+QGPSCFG="outport","none"')
at_cmd("AT+QGPS=1") at_cmd("AT+QGPS=1")
print("gpsd: GPS started fresh", file=sys.stderr, flush=True) print("CLP gpsd: GPS started fresh", file=sys.stderr, flush=True)
else: else:
print("gpsd: GPS already running, keeping fix", file=sys.stderr, flush=True) print("CLP gpsd: GPS already running, keeping fix", file=sys.stderr, flush=True)
pm = messaging.PubMaster(["gpsLocation"]) pm = messaging.PubMaster(["gpsLocation"])
clock_set = system_time_valid() clock_set = system_time_valid()
params_memory = Params("/dev/shm/params") params_memory = Params("/dev/shm/params")
last_daylight_check = 0.0 last_daylight_check = 0.0
daylight_computed = False daylight_computed = False
prev_daylight = None # CLEARPILOT: gate IsDaylight write on change prev_daylight = None # gate IsDaylight write on change (twice/day, no point rewriting every 30s)
print("gpsd: entering main loop", file=sys.stderr, flush=True) print("CLP gpsd: entering main loop", file=sys.stderr, flush=True)
while True: while True:
resp = at_cmd("AT+QGPSLOC=2") resp = at_cmd("AT+QGPSLOC=2")
@@ -201,10 +205,9 @@ def main():
capture_output=True) capture_output=True)
if ret.returncode == 0: if ret.returncode == 0:
clock_set = True clock_set = True
cloudlog.warning("gpsd: system clock set from GPS: %s", gps_dt) print(f"CLP gpsd: system clock set from GPS: {gps_dt}", file=sys.stderr, flush=True)
print(f"gpsd: system clock set from GPS: {gps_dt}", file=sys.stderr, flush=True)
else: else:
cloudlog.error("gpsd: failed to set clock: %s", ret.stderr.decode().strip()) print(f"CLP gpsd: failed to set clock: {ret.stderr.decode().strip()}", file=sys.stderr, flush=True)
msg = messaging.new_message("gpsLocation", valid=True) msg = messaging.new_message("gpsLocation", valid=True)
gps = msg.gpsLocation gps = msg.gpsLocation
@@ -224,7 +227,8 @@ def main():
gps.speedAccuracy = 1.0 gps.speedAccuracy = 1.0
pm.send("gpsLocation", msg) pm.send("gpsLocation", msg)
# CLEARPILOT: daylight calculation for auto display mode switching # Daylight calc + auto display-mode switch (only touches modes 0 and 1).
# First calc happens immediately once clock is set; thereafter every 30s.
if clock_set: if clock_set:
now_mono = time.monotonic() now_mono = time.monotonic()
interval = 1.0 if not daylight_computed else 30.0 interval = 1.0 if not daylight_computed else 30.0
@@ -232,24 +236,23 @@ def main():
last_daylight_check = now_mono last_daylight_check = now_mono
utc_now = datetime.datetime.utcfromtimestamp(fix["timestamp_ms"] / 1000) utc_now = datetime.datetime.utcfromtimestamp(fix["timestamp_ms"] / 1000)
daylight = is_daylight(fix["latitude"], fix["longitude"], utc_now) daylight = is_daylight(fix["latitude"], fix["longitude"], utc_now)
# CLEARPILOT: gate on change — daylight flips twice a day, don't rewrite every 30s
if daylight != prev_daylight: if daylight != prev_daylight:
params_memory.put_bool("IsDaylight", daylight) params_memory.put_bool("IsDaylight", daylight)
prev_daylight = daylight prev_daylight = daylight
if not daylight_computed: if not daylight_computed:
daylight_computed = True daylight_computed = True
cloudlog.warning("gpsd: initial daylight calc: %s", "day" if daylight else "night") print(f"CLP gpsd: initial daylight calc: {'day' if daylight else 'night'}",
print(f"gpsd: initial daylight calc: {'day' if daylight else 'night'}", file=sys.stderr, flush=True) file=sys.stderr, flush=True)
# Auto-transition: only touch states 0 and 1 # Auto-transition: only touch states 0 and 1 (manual modes 2/3/4 stay)
current_mode = params_memory.get_int("ScreenDisplayMode") current_mode = params_memory.get_int("ScreenDisplayMode")
if current_mode == 0 and not daylight: if current_mode == 0 and not daylight:
params_memory.put_int("ScreenDisplayMode", 1) params_memory.put_int("ScreenDisplayMode", 1)
cloudlog.warning("gpsd: auto-switch to nightrider (sunset)") print("CLP gpsd: auto-switch to nightrider (sunset)", file=sys.stderr, flush=True)
elif current_mode == 1 and daylight: elif current_mode == 1 and daylight:
params_memory.put_int("ScreenDisplayMode", 0) params_memory.put_int("ScreenDisplayMode", 0)
cloudlog.warning("gpsd: auto-switch to normal (sunrise)") print("CLP gpsd: auto-switch to normal (sunrise)", file=sys.stderr, flush=True)
time.sleep(0.5) # 2 Hz polling time.sleep(0.5) # 2 Hz polling
+4
View File
@@ -50,6 +50,7 @@ public:
} }
static void reboot() { std::system("sudo reboot"); } static void reboot() { std::system("sudo reboot"); }
static void soft_reboot() { static void soft_reboot() {
const std::vector<std::string> commands = { const std::vector<std::string> commands = {
"rm -f /tmp/safe_staging_overlay.lock", "rm -f /tmp/safe_staging_overlay.lock",
@@ -67,7 +68,9 @@ public:
} }
} }
} }
static void poweroff() { std::system("sudo poweroff"); } static void poweroff() { std::system("sudo poweroff"); }
static void set_brightness(int percent) { static void set_brightness(int percent) {
std::string max = util::read_file("/sys/class/backlight/panel0-backlight/max_brightness"); std::string max = util::read_file("/sys/class/backlight/panel0-backlight/max_brightness");
@@ -77,6 +80,7 @@ public:
brightness_control.close(); brightness_control.close();
} }
} }
static void set_display_power(bool on) { static void set_display_power(bool on) {
std::ofstream bl_power_control("/sys/class/backlight/panel0-backlight/bl_power"); std::ofstream bl_power_control("/sys/class/backlight/panel0-backlight/bl_power");
if (bl_power_control.is_open()) { if (bl_power_control.is_open()) {
+35 -30
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os import os
import shutil import shutil
import sys
import threading import threading
from openpilot.system.hardware.hw import Paths from openpilot.system.hardware.hw import Paths
from openpilot.common.swaglog import cloudlog from openpilot.common.swaglog import cloudlog
@@ -8,14 +9,16 @@ from openpilot.system.loggerd.config import get_available_bytes, get_available_p
from openpilot.system.loggerd.uploader import listdir_by_creation from openpilot.system.loggerd.uploader import listdir_by_creation
from openpilot.system.loggerd.xattr_cache import getxattr from openpilot.system.loggerd.xattr_cache import getxattr
# CLEARPILOT: increased from 5 GB to 9 GB to reserve space for screen recordings # CLEARPILOT: bumped from 5 GB to 9 GB so dashcam footage has headroom
MIN_BYTES = 9 * 1024 * 1024 * 1024 MIN_BYTES = 9 * 1024 * 1024 * 1024
MIN_PERCENT = 10 MIN_PERCENT = 10
DELETE_LAST = ['boot', 'crash'] DELETE_LAST = ['boot', 'crash']
# CLEARPILOT: screen recorder video directory # CLEARPILOT: dashcam footage directory (trip dirs YYYYMMDD-HHMMSS/ with .mp4 segments)
VIDEOS_DIR = '/data/media/0/videos' VIDEOS_DIR = '/data/media/0/videos'
# CLEARPILOT: max total size for /data/log2 session logs
LOG2_MAX_BYTES = 4 * 1024 * 1024 * 1024
PRESERVE_ATTR_NAME = 'user.preserve' PRESERVE_ATTR_NAME = 'user.preserve'
PRESERVE_ATTR_VALUE = b'1' PRESERVE_ATTR_VALUE = b'1'
@@ -49,15 +52,16 @@ def get_preserved_segments(dirs_by_creation: list[str]) -> list[str]:
def delete_oldest_video(): def delete_oldest_video():
"""CLEARPILOT: delete oldest dashcam footage when disk space is low. """CLEARPILOT: prune dashcam footage when disk space is low.
Trip directories are /data/media/0/videos/YYYYMMDD-HHMMSS/ containing .mp4 segments. Trip directories are /data/media/0/videos/YYYYMMDD-HHMMSS/ containing .mp4
Deletes entire oldest trip directory first. If only one trip remains (active), segments. Deletes entire oldest trip directory first. If only one trip
deletes individual segments oldest-first within it. Also cleans up legacy flat .mp4 files.""" remains (the active one), deletes individual segments oldest-first within
it. Also cleans up legacy flat .mp4 files.
Returns True if something was deleted."""
try: try:
if not os.path.isdir(VIDEOS_DIR): if not os.path.isdir(VIDEOS_DIR):
return False return False
# Collect legacy flat mp4 files and trip directories
legacy_files = [] legacy_files = []
trip_dirs = [] trip_dirs = []
for entry in os.listdir(VIDEOS_DIR): for entry in os.listdir(VIDEOS_DIR):
@@ -67,71 +71,72 @@ def delete_oldest_video():
elif os.path.isdir(path): elif os.path.isdir(path):
trip_dirs.append(entry) trip_dirs.append(entry)
# Delete legacy flat files first (oldest by name)
if legacy_files: if legacy_files:
legacy_files.sort() legacy_files.sort()
delete_path = os.path.join(VIDEOS_DIR, legacy_files[0]) delete_path = os.path.join(VIDEOS_DIR, legacy_files[0])
cloudlog.info(f"deleting legacy video {delete_path}") print(f"CLP deleter: deleting legacy video {delete_path}", file=sys.stderr, flush=True)
os.remove(delete_path) os.remove(delete_path)
return True return True
if not trip_dirs: if not trip_dirs:
return False return False
trip_dirs.sort() # sorted by timestamp name = chronological order trip_dirs.sort() # timestamp names = chronological order
# If more than one trip, delete the oldest entire trip directory
if len(trip_dirs) > 1: if len(trip_dirs) > 1:
delete_path = os.path.join(VIDEOS_DIR, trip_dirs[0]) delete_path = os.path.join(VIDEOS_DIR, trip_dirs[0])
cloudlog.info(f"deleting trip {delete_path}") print(f"CLP deleter: deleting trip {delete_path}", file=sys.stderr, flush=True)
shutil.rmtree(delete_path) shutil.rmtree(delete_path)
return True return True
# Only one trip left (likely active) — delete oldest segment within it # Only one trip left (likely active) — drop its oldest segment
trip_path = os.path.join(VIDEOS_DIR, trip_dirs[0]) trip_path = os.path.join(VIDEOS_DIR, trip_dirs[0])
segments = sorted(f for f in os.listdir(trip_path) if f.endswith('.mp4')) segments = sorted(f for f in os.listdir(trip_path) if f.endswith('.mp4'))
if not segments: if not segments:
return False return False
delete_path = os.path.join(trip_path, segments[0]) delete_path = os.path.join(trip_path, segments[0])
cloudlog.info(f"deleting segment {delete_path}") print(f"CLP deleter: deleting segment {delete_path}", file=sys.stderr, flush=True)
os.remove(delete_path) os.remove(delete_path)
return True return True
except OSError: except OSError as e:
cloudlog.exception(f"issue deleting video from {VIDEOS_DIR}") print(f"CLP deleter: issue deleting video from {VIDEOS_DIR}: {e}", file=sys.stderr, flush=True)
return False return False
# CLEARPILOT: max total size for /data/log2 session logs
LOG2_MAX_BYTES = 4 * 1024 * 1024 * 1024
def cleanup_log2(): def cleanup_log2():
"""Delete oldest session log directories until /data/log2 is under LOG2_MAX_BYTES.""" """CLEARPILOT: keep /data/log2 session logs under LOG2_MAX_BYTES total.
Deletes oldest dated session directories first (the 'current' symlink/dir
is preserved). Runs even when disk space is fine."""
log_base = "/data/log2" log_base = "/data/log2"
if not os.path.isdir(log_base): if not os.path.isdir(log_base):
return return
# Get all session dirs sorted oldest first (by name = timestamp)
dirs = [] dirs = []
for entry in sorted(os.listdir(log_base)): for entry in sorted(os.listdir(log_base)):
if entry == "current": if entry == "current":
continue continue
path = os.path.join(log_base, entry) path = os.path.join(log_base, entry)
if os.path.isdir(path) and not os.path.islink(path): if os.path.isdir(path) and not os.path.islink(path):
size = sum(f.stat().st_size for f in os.scandir(path) if f.is_file()) try:
size = sum(f.stat().st_size for f in os.scandir(path) if f.is_file())
except OSError:
size = 0
dirs.append((entry, path, size)) dirs.append((entry, path, size))
total = sum(s for _, _, s in dirs) total = sum(s for _, _, s in dirs)
# Also count current session
current = os.path.join(log_base, "current") current = os.path.join(log_base, "current")
if os.path.isdir(current): if os.path.isdir(current):
total += sum(f.stat().st_size for f in os.scandir(current) if f.is_file()) try:
# Delete oldest until under quota total += sum(f.stat().st_size for f in os.scandir(current) if f.is_file())
except OSError:
pass
while total > LOG2_MAX_BYTES and dirs: while total > LOG2_MAX_BYTES and dirs:
entry, path, size = dirs.pop(0) entry, path, size = dirs.pop(0)
try: try:
cloudlog.info(f"deleting log session {path} ({size // 1024 // 1024} MB)") print(f"CLP deleter: deleting log session {path} ({size // 1024 // 1024} MB)",
file=sys.stderr, flush=True)
shutil.rmtree(path) shutil.rmtree(path)
total -= size total -= size
except OSError: except OSError as e:
cloudlog.exception(f"issue deleting log {path}") print(f"CLP deleter: issue deleting log {path}: {e}", file=sys.stderr, flush=True)
def deleter_thread(exit_event): def deleter_thread(exit_event):
@@ -140,7 +145,7 @@ def deleter_thread(exit_event):
out_of_percent = get_available_percent(default=MIN_PERCENT + 1) < MIN_PERCENT out_of_percent = get_available_percent(default=MIN_PERCENT + 1) < MIN_PERCENT
if out_of_percent or out_of_bytes: if out_of_percent or out_of_bytes:
# CLEARPILOT: try deleting oldest video first, then fall back to log segments # CLEARPILOT: drop oldest dashcam footage first, fall back to log segments
if delete_oldest_video(): if delete_oldest_video():
exit_event.wait(.1) exit_event.wait(.1)
continue continue
@@ -168,7 +173,7 @@ def deleter_thread(exit_event):
cloudlog.exception(f"issue deleting {delete_path}") cloudlog.exception(f"issue deleting {delete_path}")
exit_event.wait(.1) exit_event.wait(.1)
else: else:
# CLEARPILOT: enforce log2 size quota even when disk space is fine # CLEARPILOT: keep /data/log2 quota even when disk space is fine
cleanup_log2() cleanup_log2()
exit_event.wait(30) exit_event.wait(30)
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
libqpOASES_e.so.3.1
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
libqpOASES_e.so.3.1
+1
View File
@@ -0,0 +1 @@
../include
-32
View File
@@ -1,32 +0,0 @@
/*
* Copyright 2011 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_H_
#define INCLUDE_LIBYUV_H_
#include "libyuv/basic_types.h"
#include "libyuv/compare.h"
#include "libyuv/convert.h"
#include "libyuv/convert_argb.h"
#include "libyuv/convert_from.h"
#include "libyuv/convert_from_argb.h"
#include "libyuv/cpu_id.h"
#include "libyuv/mjpeg_decoder.h"
#include "libyuv/planar_functions.h"
#include "libyuv/rotate.h"
#include "libyuv/rotate_argb.h"
#include "libyuv/row.h"
#include "libyuv/scale.h"
#include "libyuv/scale_argb.h"
#include "libyuv/scale_row.h"
#include "libyuv/version.h"
#include "libyuv/video_common.h"
#endif // INCLUDE_LIBYUV_H_
-118
View File
@@ -1,118 +0,0 @@
/*
* Copyright 2011 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_BASIC_TYPES_H_
#define INCLUDE_LIBYUV_BASIC_TYPES_H_
#include <stddef.h> // for NULL, size_t
#if defined(_MSC_VER) && (_MSC_VER < 1600)
#include <sys/types.h> // for uintptr_t on x86
#else
#include <stdint.h> // for uintptr_t
#endif
#ifndef GG_LONGLONG
#ifndef INT_TYPES_DEFINED
#define INT_TYPES_DEFINED
#ifdef COMPILER_MSVC
typedef unsigned __int64 uint64;
typedef __int64 int64;
#ifndef INT64_C
#define INT64_C(x) x ## I64
#endif
#ifndef UINT64_C
#define UINT64_C(x) x ## UI64
#endif
#define INT64_F "I64"
#else // COMPILER_MSVC
#if defined(__LP64__) && !defined(__OpenBSD__) && !defined(__APPLE__)
typedef unsigned long uint64; // NOLINT
typedef long int64; // NOLINT
#ifndef INT64_C
#define INT64_C(x) x ## L
#endif
#ifndef UINT64_C
#define UINT64_C(x) x ## UL
#endif
#define INT64_F "l"
#else // defined(__LP64__) && !defined(__OpenBSD__) && !defined(__APPLE__)
typedef unsigned long long uint64; // NOLINT
typedef long long int64; // NOLINT
#ifndef INT64_C
#define INT64_C(x) x ## LL
#endif
#ifndef UINT64_C
#define UINT64_C(x) x ## ULL
#endif
#define INT64_F "ll"
#endif // __LP64__
#endif // COMPILER_MSVC
typedef unsigned int uint32;
typedef int int32;
typedef unsigned short uint16; // NOLINT
typedef short int16; // NOLINT
typedef unsigned char uint8;
typedef signed char int8;
#endif // INT_TYPES_DEFINED
#endif // GG_LONGLONG
// Detect compiler is for x86 or x64.
#if defined(__x86_64__) || defined(_M_X64) || \
defined(__i386__) || defined(_M_IX86)
#define CPU_X86 1
#endif
// Detect compiler is for ARM.
#if defined(__arm__) || defined(_M_ARM)
#define CPU_ARM 1
#endif
#ifndef ALIGNP
#ifdef __cplusplus
#define ALIGNP(p, t) \
(reinterpret_cast<uint8*>(((reinterpret_cast<uintptr_t>(p) + \
((t) - 1)) & ~((t) - 1))))
#else
#define ALIGNP(p, t) \
((uint8*)((((uintptr_t)(p) + ((t) - 1)) & ~((t) - 1)))) /* NOLINT */
#endif
#endif
#if !defined(LIBYUV_API)
#if defined(_WIN32) || defined(__CYGWIN__)
#if defined(LIBYUV_BUILDING_SHARED_LIBRARY)
#define LIBYUV_API __declspec(dllexport)
#elif defined(LIBYUV_USING_SHARED_LIBRARY)
#define LIBYUV_API __declspec(dllimport)
#else
#define LIBYUV_API
#endif // LIBYUV_BUILDING_SHARED_LIBRARY
#elif defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__APPLE__) && \
(defined(LIBYUV_BUILDING_SHARED_LIBRARY) || \
defined(LIBYUV_USING_SHARED_LIBRARY))
#define LIBYUV_API __attribute__ ((visibility ("default")))
#else
#define LIBYUV_API
#endif // __GNUC__
#endif // LIBYUV_API
#define LIBYUV_BOOL int
#define LIBYUV_FALSE 0
#define LIBYUV_TRUE 1
// Visual C x86 or GCC little endian.
#if defined(__x86_64__) || defined(_M_X64) || \
defined(__i386__) || defined(_M_IX86) || \
defined(__arm__) || defined(_M_ARM) || \
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define LIBYUV_LITTLE_ENDIAN
#endif
#endif // INCLUDE_LIBYUV_BASIC_TYPES_H_
-78
View File
@@ -1,78 +0,0 @@
/*
* Copyright 2011 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_COMPARE_H_
#define INCLUDE_LIBYUV_COMPARE_H_
#include "libyuv/basic_types.h"
#ifdef __cplusplus
namespace libyuv {
extern "C" {
#endif
// Compute a hash for specified memory. Seed of 5381 recommended.
LIBYUV_API
uint32 HashDjb2(const uint8* src, uint64 count, uint32 seed);
// Scan an opaque argb image and return fourcc based on alpha offset.
// Returns FOURCC_ARGB, FOURCC_BGRA, or 0 if unknown.
LIBYUV_API
uint32 ARGBDetect(const uint8* argb, int stride_argb, int width, int height);
// Sum Square Error - used to compute Mean Square Error or PSNR.
LIBYUV_API
uint64 ComputeSumSquareError(const uint8* src_a,
const uint8* src_b, int count);
LIBYUV_API
uint64 ComputeSumSquareErrorPlane(const uint8* src_a, int stride_a,
const uint8* src_b, int stride_b,
int width, int height);
static const int kMaxPsnr = 128;
LIBYUV_API
double SumSquareErrorToPsnr(uint64 sse, uint64 count);
LIBYUV_API
double CalcFramePsnr(const uint8* src_a, int stride_a,
const uint8* src_b, int stride_b,
int width, int height);
LIBYUV_API
double I420Psnr(const uint8* src_y_a, int stride_y_a,
const uint8* src_u_a, int stride_u_a,
const uint8* src_v_a, int stride_v_a,
const uint8* src_y_b, int stride_y_b,
const uint8* src_u_b, int stride_u_b,
const uint8* src_v_b, int stride_v_b,
int width, int height);
LIBYUV_API
double CalcFrameSsim(const uint8* src_a, int stride_a,
const uint8* src_b, int stride_b,
int width, int height);
LIBYUV_API
double I420Ssim(const uint8* src_y_a, int stride_y_a,
const uint8* src_u_a, int stride_u_a,
const uint8* src_v_a, int stride_v_a,
const uint8* src_y_b, int stride_y_b,
const uint8* src_u_b, int stride_u_b,
const uint8* src_v_b, int stride_v_b,
int width, int height);
#ifdef __cplusplus
} // extern "C"
} // namespace libyuv
#endif
#endif // INCLUDE_LIBYUV_COMPARE_H_
-84
View File
@@ -1,84 +0,0 @@
/*
* Copyright 2013 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_COMPARE_ROW_H_
#define INCLUDE_LIBYUV_COMPARE_ROW_H_
#include "libyuv/basic_types.h"
#ifdef __cplusplus
namespace libyuv {
extern "C" {
#endif
#if defined(__pnacl__) || defined(__CLR_VER) || \
(defined(__i386__) && !defined(__SSE2__))
#define LIBYUV_DISABLE_X86
#endif
// MemorySanitizer does not support assembly code yet. http://crbug.com/344505
#if defined(__has_feature)
#if __has_feature(memory_sanitizer)
#define LIBYUV_DISABLE_X86
#endif
#endif
// Visual C 2012 required for AVX2.
#if defined(_M_IX86) && !defined(__clang__) && \
defined(_MSC_VER) && _MSC_VER >= 1700
#define VISUALC_HAS_AVX2 1
#endif // VisualStudio >= 2012
// clang >= 3.4.0 required for AVX2.
#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__))
#if (__clang_major__ > 3) || (__clang_major__ == 3 && (__clang_minor__ >= 4))
#define CLANG_HAS_AVX2 1
#endif // clang >= 3.4
#endif // __clang__
#if !defined(LIBYUV_DISABLE_X86) && \
defined(_M_IX86) && (defined(VISUALC_HAS_AVX2) || defined(CLANG_HAS_AVX2))
#define HAS_HASHDJB2_AVX2
#endif
// The following are available for Visual C and GCC:
#if !defined(LIBYUV_DISABLE_X86) && \
(defined(__x86_64__) || (defined(__i386__) || defined(_M_IX86)))
#define HAS_HASHDJB2_SSE41
#define HAS_SUMSQUAREERROR_SSE2
#endif
// The following are available for Visual C and clangcl 32 bit:
#if !defined(LIBYUV_DISABLE_X86) && defined(_M_IX86) && \
(defined(VISUALC_HAS_AVX2) || defined(CLANG_HAS_AVX2))
#define HAS_HASHDJB2_AVX2
#define HAS_SUMSQUAREERROR_AVX2
#endif
// The following are available for Neon:
#if !defined(LIBYUV_DISABLE_NEON) && \
(defined(__ARM_NEON__) || defined(LIBYUV_NEON) || defined(__aarch64__))
#define HAS_SUMSQUAREERROR_NEON
#endif
uint32 SumSquareError_C(const uint8* src_a, const uint8* src_b, int count);
uint32 SumSquareError_SSE2(const uint8* src_a, const uint8* src_b, int count);
uint32 SumSquareError_AVX2(const uint8* src_a, const uint8* src_b, int count);
uint32 SumSquareError_NEON(const uint8* src_a, const uint8* src_b, int count);
uint32 HashDjb2_C(const uint8* src, int count, uint32 seed);
uint32 HashDjb2_SSE41(const uint8* src, int count, uint32 seed);
uint32 HashDjb2_AVX2(const uint8* src, int count, uint32 seed);
#ifdef __cplusplus
} // extern "C"
} // namespace libyuv
#endif
#endif // INCLUDE_LIBYUV_COMPARE_ROW_H_
-259
View File
@@ -1,259 +0,0 @@
/*
* Copyright 2011 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_CONVERT_H_
#define INCLUDE_LIBYUV_CONVERT_H_
#include "libyuv/basic_types.h"
#include "libyuv/rotate.h" // For enum RotationMode.
// TODO(fbarchard): fix WebRTC source to include following libyuv headers:
#include "libyuv/convert_argb.h" // For WebRTC I420ToARGB. b/620
#include "libyuv/convert_from.h" // For WebRTC ConvertFromI420. b/620
#include "libyuv/planar_functions.h" // For WebRTC I420Rect, CopyPlane. b/618
#ifdef __cplusplus
namespace libyuv {
extern "C" {
#endif
// Convert I444 to I420.
LIBYUV_API
int I444ToI420(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Convert I422 to I420.
LIBYUV_API
int I422ToI420(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Convert I411 to I420.
LIBYUV_API
int I411ToI420(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Copy I420 to I420.
#define I420ToI420 I420Copy
LIBYUV_API
int I420Copy(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Convert I400 (grey) to I420.
LIBYUV_API
int I400ToI420(const uint8* src_y, int src_stride_y,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
#define J400ToJ420 I400ToI420
// Convert NV12 to I420.
LIBYUV_API
int NV12ToI420(const uint8* src_y, int src_stride_y,
const uint8* src_uv, int src_stride_uv,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Convert NV21 to I420.
LIBYUV_API
int NV21ToI420(const uint8* src_y, int src_stride_y,
const uint8* src_vu, int src_stride_vu,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Convert YUY2 to I420.
LIBYUV_API
int YUY2ToI420(const uint8* src_yuy2, int src_stride_yuy2,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Convert UYVY to I420.
LIBYUV_API
int UYVYToI420(const uint8* src_uyvy, int src_stride_uyvy,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Convert M420 to I420.
LIBYUV_API
int M420ToI420(const uint8* src_m420, int src_stride_m420,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Convert Android420 to I420.
LIBYUV_API
int Android420ToI420(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
int pixel_stride_uv,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// ARGB little endian (bgra in memory) to I420.
LIBYUV_API
int ARGBToI420(const uint8* src_frame, int src_stride_frame,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// BGRA little endian (argb in memory) to I420.
LIBYUV_API
int BGRAToI420(const uint8* src_frame, int src_stride_frame,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// ABGR little endian (rgba in memory) to I420.
LIBYUV_API
int ABGRToI420(const uint8* src_frame, int src_stride_frame,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// RGBA little endian (abgr in memory) to I420.
LIBYUV_API
int RGBAToI420(const uint8* src_frame, int src_stride_frame,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// RGB little endian (bgr in memory) to I420.
LIBYUV_API
int RGB24ToI420(const uint8* src_frame, int src_stride_frame,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// RGB big endian (rgb in memory) to I420.
LIBYUV_API
int RAWToI420(const uint8* src_frame, int src_stride_frame,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// RGB16 (RGBP fourcc) little endian to I420.
LIBYUV_API
int RGB565ToI420(const uint8* src_frame, int src_stride_frame,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// RGB15 (RGBO fourcc) little endian to I420.
LIBYUV_API
int ARGB1555ToI420(const uint8* src_frame, int src_stride_frame,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// RGB12 (R444 fourcc) little endian to I420.
LIBYUV_API
int ARGB4444ToI420(const uint8* src_frame, int src_stride_frame,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
#ifdef HAVE_JPEG
// src_width/height provided by capture.
// dst_width/height for clipping determine final size.
LIBYUV_API
int MJPGToI420(const uint8* sample, size_t sample_size,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int src_width, int src_height,
int dst_width, int dst_height);
// Query size of MJPG in pixels.
LIBYUV_API
int MJPGSize(const uint8* sample, size_t sample_size,
int* width, int* height);
#endif
// Convert camera sample to I420 with cropping, rotation and vertical flip.
// "src_size" is needed to parse MJPG.
// "dst_stride_y" number of bytes in a row of the dst_y plane.
// Normally this would be the same as dst_width, with recommended alignment
// to 16 bytes for better efficiency.
// If rotation of 90 or 270 is used, stride is affected. The caller should
// allocate the I420 buffer according to rotation.
// "dst_stride_u" number of bytes in a row of the dst_u plane.
// Normally this would be the same as (dst_width + 1) / 2, with
// recommended alignment to 16 bytes for better efficiency.
// If rotation of 90 or 270 is used, stride is affected.
// "crop_x" and "crop_y" are starting position for cropping.
// To center, crop_x = (src_width - dst_width) / 2
// crop_y = (src_height - dst_height) / 2
// "src_width" / "src_height" is size of src_frame in pixels.
// "src_height" can be negative indicating a vertically flipped image source.
// "crop_width" / "crop_height" is the size to crop the src to.
// Must be less than or equal to src_width/src_height
// Cropping parameters are pre-rotation.
// "rotation" can be 0, 90, 180 or 270.
// "format" is a fourcc. ie 'I420', 'YUY2'
// Returns 0 for successful; -1 for invalid parameter. Non-zero for failure.
LIBYUV_API
int ConvertToI420(const uint8* src_frame, size_t src_size,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int crop_x, int crop_y,
int src_width, int src_height,
int crop_width, int crop_height,
enum RotationMode rotation,
uint32 format);
#ifdef __cplusplus
} // extern "C"
} // namespace libyuv
#endif
#endif // INCLUDE_LIBYUV_CONVERT_H_
-319
View File
@@ -1,319 +0,0 @@
/*
* Copyright 2012 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_CONVERT_ARGB_H_
#define INCLUDE_LIBYUV_CONVERT_ARGB_H_
#include "libyuv/basic_types.h"
#include "libyuv/rotate.h" // For enum RotationMode.
// TODO(fbarchard): This set of functions should exactly match convert.h
// TODO(fbarchard): Add tests. Create random content of right size and convert
// with C vs Opt and or to I420 and compare.
// TODO(fbarchard): Some of these functions lack parameter setting.
#ifdef __cplusplus
namespace libyuv {
extern "C" {
#endif
// Alias.
#define ARGBToARGB ARGBCopy
// Copy ARGB to ARGB.
LIBYUV_API
int ARGBCopy(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Convert I420 to ARGB.
LIBYUV_API
int I420ToARGB(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Duplicate prototype for function in convert_from.h for remoting.
LIBYUV_API
int I420ToABGR(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Convert I422 to ARGB.
LIBYUV_API
int I422ToARGB(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Convert I444 to ARGB.
LIBYUV_API
int I444ToARGB(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Convert J444 to ARGB.
LIBYUV_API
int J444ToARGB(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Convert I444 to ABGR.
LIBYUV_API
int I444ToABGR(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_abgr, int dst_stride_abgr,
int width, int height);
// Convert I411 to ARGB.
LIBYUV_API
int I411ToARGB(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Convert I420 with Alpha to preattenuated ARGB.
LIBYUV_API
int I420AlphaToARGB(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
const uint8* src_a, int src_stride_a,
uint8* dst_argb, int dst_stride_argb,
int width, int height, int attenuate);
// Convert I420 with Alpha to preattenuated ABGR.
LIBYUV_API
int I420AlphaToABGR(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
const uint8* src_a, int src_stride_a,
uint8* dst_abgr, int dst_stride_abgr,
int width, int height, int attenuate);
// Convert I400 (grey) to ARGB. Reverse of ARGBToI400.
LIBYUV_API
int I400ToARGB(const uint8* src_y, int src_stride_y,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Convert J400 (jpeg grey) to ARGB.
LIBYUV_API
int J400ToARGB(const uint8* src_y, int src_stride_y,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Alias.
#define YToARGB I400ToARGB
// Convert NV12 to ARGB.
LIBYUV_API
int NV12ToARGB(const uint8* src_y, int src_stride_y,
const uint8* src_uv, int src_stride_uv,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Convert NV21 to ARGB.
LIBYUV_API
int NV21ToARGB(const uint8* src_y, int src_stride_y,
const uint8* src_vu, int src_stride_vu,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Convert M420 to ARGB.
LIBYUV_API
int M420ToARGB(const uint8* src_m420, int src_stride_m420,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Convert YUY2 to ARGB.
LIBYUV_API
int YUY2ToARGB(const uint8* src_yuy2, int src_stride_yuy2,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Convert UYVY to ARGB.
LIBYUV_API
int UYVYToARGB(const uint8* src_uyvy, int src_stride_uyvy,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Convert J420 to ARGB.
LIBYUV_API
int J420ToARGB(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Convert J422 to ARGB.
LIBYUV_API
int J422ToARGB(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Convert J420 to ABGR.
LIBYUV_API
int J420ToABGR(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_abgr, int dst_stride_abgr,
int width, int height);
// Convert J422 to ABGR.
LIBYUV_API
int J422ToABGR(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_abgr, int dst_stride_abgr,
int width, int height);
// Convert H420 to ARGB.
LIBYUV_API
int H420ToARGB(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Convert H422 to ARGB.
LIBYUV_API
int H422ToARGB(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Convert H420 to ABGR.
LIBYUV_API
int H420ToABGR(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_abgr, int dst_stride_abgr,
int width, int height);
// Convert H422 to ABGR.
LIBYUV_API
int H422ToABGR(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_abgr, int dst_stride_abgr,
int width, int height);
// BGRA little endian (argb in memory) to ARGB.
LIBYUV_API
int BGRAToARGB(const uint8* src_frame, int src_stride_frame,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// ABGR little endian (rgba in memory) to ARGB.
LIBYUV_API
int ABGRToARGB(const uint8* src_frame, int src_stride_frame,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// RGBA little endian (abgr in memory) to ARGB.
LIBYUV_API
int RGBAToARGB(const uint8* src_frame, int src_stride_frame,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Deprecated function name.
#define BG24ToARGB RGB24ToARGB
// RGB little endian (bgr in memory) to ARGB.
LIBYUV_API
int RGB24ToARGB(const uint8* src_frame, int src_stride_frame,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// RGB big endian (rgb in memory) to ARGB.
LIBYUV_API
int RAWToARGB(const uint8* src_frame, int src_stride_frame,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// RGB16 (RGBP fourcc) little endian to ARGB.
LIBYUV_API
int RGB565ToARGB(const uint8* src_frame, int src_stride_frame,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// RGB15 (RGBO fourcc) little endian to ARGB.
LIBYUV_API
int ARGB1555ToARGB(const uint8* src_frame, int src_stride_frame,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// RGB12 (R444 fourcc) little endian to ARGB.
LIBYUV_API
int ARGB4444ToARGB(const uint8* src_frame, int src_stride_frame,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
#ifdef HAVE_JPEG
// src_width/height provided by capture
// dst_width/height for clipping determine final size.
LIBYUV_API
int MJPGToARGB(const uint8* sample, size_t sample_size,
uint8* dst_argb, int dst_stride_argb,
int src_width, int src_height,
int dst_width, int dst_height);
#endif
// Convert camera sample to ARGB with cropping, rotation and vertical flip.
// "src_size" is needed to parse MJPG.
// "dst_stride_argb" number of bytes in a row of the dst_argb plane.
// Normally this would be the same as dst_width, with recommended alignment
// to 16 bytes for better efficiency.
// If rotation of 90 or 270 is used, stride is affected. The caller should
// allocate the I420 buffer according to rotation.
// "dst_stride_u" number of bytes in a row of the dst_u plane.
// Normally this would be the same as (dst_width + 1) / 2, with
// recommended alignment to 16 bytes for better efficiency.
// If rotation of 90 or 270 is used, stride is affected.
// "crop_x" and "crop_y" are starting position for cropping.
// To center, crop_x = (src_width - dst_width) / 2
// crop_y = (src_height - dst_height) / 2
// "src_width" / "src_height" is size of src_frame in pixels.
// "src_height" can be negative indicating a vertically flipped image source.
// "crop_width" / "crop_height" is the size to crop the src to.
// Must be less than or equal to src_width/src_height
// Cropping parameters are pre-rotation.
// "rotation" can be 0, 90, 180 or 270.
// "format" is a fourcc. ie 'I420', 'YUY2'
// Returns 0 for successful; -1 for invalid parameter. Non-zero for failure.
LIBYUV_API
int ConvertToARGB(const uint8* src_frame, size_t src_size,
uint8* dst_argb, int dst_stride_argb,
int crop_x, int crop_y,
int src_width, int src_height,
int crop_width, int crop_height,
enum RotationMode rotation,
uint32 format);
#ifdef __cplusplus
} // extern "C"
} // namespace libyuv
#endif
#endif // INCLUDE_LIBYUV_CONVERT_ARGB_H_
-179
View File
@@ -1,179 +0,0 @@
/*
* Copyright 2011 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_CONVERT_FROM_H_
#define INCLUDE_LIBYUV_CONVERT_FROM_H_
#include "libyuv/basic_types.h"
#include "libyuv/rotate.h"
#ifdef __cplusplus
namespace libyuv {
extern "C" {
#endif
// See Also convert.h for conversions from formats to I420.
// I420Copy in convert to I420ToI420.
LIBYUV_API
int I420ToI422(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
LIBYUV_API
int I420ToI444(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
LIBYUV_API
int I420ToI411(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Copy to I400. Source can be I420, I422, I444, I400, NV12 or NV21.
LIBYUV_API
int I400Copy(const uint8* src_y, int src_stride_y,
uint8* dst_y, int dst_stride_y,
int width, int height);
LIBYUV_API
int I420ToNV12(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_y, int dst_stride_y,
uint8* dst_uv, int dst_stride_uv,
int width, int height);
LIBYUV_API
int I420ToNV21(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_y, int dst_stride_y,
uint8* dst_vu, int dst_stride_vu,
int width, int height);
LIBYUV_API
int I420ToYUY2(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_frame, int dst_stride_frame,
int width, int height);
LIBYUV_API
int I420ToUYVY(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_frame, int dst_stride_frame,
int width, int height);
LIBYUV_API
int I420ToARGB(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
LIBYUV_API
int I420ToBGRA(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
LIBYUV_API
int I420ToABGR(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
LIBYUV_API
int I420ToRGBA(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_rgba, int dst_stride_rgba,
int width, int height);
LIBYUV_API
int I420ToRGB24(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_frame, int dst_stride_frame,
int width, int height);
LIBYUV_API
int I420ToRAW(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_frame, int dst_stride_frame,
int width, int height);
LIBYUV_API
int I420ToRGB565(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_frame, int dst_stride_frame,
int width, int height);
// Convert I420 To RGB565 with 4x4 dither matrix (16 bytes).
// Values in dither matrix from 0 to 7 recommended.
// The order of the dither matrix is first byte is upper left.
LIBYUV_API
int I420ToRGB565Dither(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_frame, int dst_stride_frame,
const uint8* dither4x4, int width, int height);
LIBYUV_API
int I420ToARGB1555(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_frame, int dst_stride_frame,
int width, int height);
LIBYUV_API
int I420ToARGB4444(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_frame, int dst_stride_frame,
int width, int height);
// Convert I420 to specified format.
// "dst_sample_stride" is bytes in a row for the destination. Pass 0 if the
// buffer has contiguous rows. Can be negative. A multiple of 16 is optimal.
LIBYUV_API
int ConvertFromI420(const uint8* y, int y_stride,
const uint8* u, int u_stride,
const uint8* v, int v_stride,
uint8* dst_sample, int dst_sample_stride,
int width, int height,
uint32 format);
#ifdef __cplusplus
} // extern "C"
} // namespace libyuv
#endif
#endif // INCLUDE_LIBYUV_CONVERT_FROM_H_
@@ -1,190 +0,0 @@
/*
* Copyright 2012 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_CONVERT_FROM_ARGB_H_
#define INCLUDE_LIBYUV_CONVERT_FROM_ARGB_H_
#include "libyuv/basic_types.h"
#ifdef __cplusplus
namespace libyuv {
extern "C" {
#endif
// Copy ARGB to ARGB.
#define ARGBToARGB ARGBCopy
LIBYUV_API
int ARGBCopy(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Convert ARGB To BGRA.
LIBYUV_API
int ARGBToBGRA(const uint8* src_argb, int src_stride_argb,
uint8* dst_bgra, int dst_stride_bgra,
int width, int height);
// Convert ARGB To ABGR.
LIBYUV_API
int ARGBToABGR(const uint8* src_argb, int src_stride_argb,
uint8* dst_abgr, int dst_stride_abgr,
int width, int height);
// Convert ARGB To RGBA.
LIBYUV_API
int ARGBToRGBA(const uint8* src_argb, int src_stride_argb,
uint8* dst_rgba, int dst_stride_rgba,
int width, int height);
// Convert ARGB To RGB24.
LIBYUV_API
int ARGBToRGB24(const uint8* src_argb, int src_stride_argb,
uint8* dst_rgb24, int dst_stride_rgb24,
int width, int height);
// Convert ARGB To RAW.
LIBYUV_API
int ARGBToRAW(const uint8* src_argb, int src_stride_argb,
uint8* dst_rgb, int dst_stride_rgb,
int width, int height);
// Convert ARGB To RGB565.
LIBYUV_API
int ARGBToRGB565(const uint8* src_argb, int src_stride_argb,
uint8* dst_rgb565, int dst_stride_rgb565,
int width, int height);
// Convert ARGB To RGB565 with 4x4 dither matrix (16 bytes).
// Values in dither matrix from 0 to 7 recommended.
// The order of the dither matrix is first byte is upper left.
// TODO(fbarchard): Consider pointer to 2d array for dither4x4.
// const uint8(*dither)[4][4];
LIBYUV_API
int ARGBToRGB565Dither(const uint8* src_argb, int src_stride_argb,
uint8* dst_rgb565, int dst_stride_rgb565,
const uint8* dither4x4, int width, int height);
// Convert ARGB To ARGB1555.
LIBYUV_API
int ARGBToARGB1555(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb1555, int dst_stride_argb1555,
int width, int height);
// Convert ARGB To ARGB4444.
LIBYUV_API
int ARGBToARGB4444(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb4444, int dst_stride_argb4444,
int width, int height);
// Convert ARGB To I444.
LIBYUV_API
int ARGBToI444(const uint8* src_argb, int src_stride_argb,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Convert ARGB To I422.
LIBYUV_API
int ARGBToI422(const uint8* src_argb, int src_stride_argb,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Convert ARGB To I420. (also in convert.h)
LIBYUV_API
int ARGBToI420(const uint8* src_argb, int src_stride_argb,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Convert ARGB to J420. (JPeg full range I420).
LIBYUV_API
int ARGBToJ420(const uint8* src_argb, int src_stride_argb,
uint8* dst_yj, int dst_stride_yj,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Convert ARGB to J422.
LIBYUV_API
int ARGBToJ422(const uint8* src_argb, int src_stride_argb,
uint8* dst_yj, int dst_stride_yj,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Convert ARGB To I411.
LIBYUV_API
int ARGBToI411(const uint8* src_argb, int src_stride_argb,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Convert ARGB to J400. (JPeg full range).
LIBYUV_API
int ARGBToJ400(const uint8* src_argb, int src_stride_argb,
uint8* dst_yj, int dst_stride_yj,
int width, int height);
// Convert ARGB to I400.
LIBYUV_API
int ARGBToI400(const uint8* src_argb, int src_stride_argb,
uint8* dst_y, int dst_stride_y,
int width, int height);
// Convert ARGB to G. (Reverse of J400toARGB, which replicates G back to ARGB)
LIBYUV_API
int ARGBToG(const uint8* src_argb, int src_stride_argb,
uint8* dst_g, int dst_stride_g,
int width, int height);
// Convert ARGB To NV12.
LIBYUV_API
int ARGBToNV12(const uint8* src_argb, int src_stride_argb,
uint8* dst_y, int dst_stride_y,
uint8* dst_uv, int dst_stride_uv,
int width, int height);
// Convert ARGB To NV21.
LIBYUV_API
int ARGBToNV21(const uint8* src_argb, int src_stride_argb,
uint8* dst_y, int dst_stride_y,
uint8* dst_vu, int dst_stride_vu,
int width, int height);
// Convert ARGB To NV21.
LIBYUV_API
int ARGBToNV21(const uint8* src_argb, int src_stride_argb,
uint8* dst_y, int dst_stride_y,
uint8* dst_vu, int dst_stride_vu,
int width, int height);
// Convert ARGB To YUY2.
LIBYUV_API
int ARGBToYUY2(const uint8* src_argb, int src_stride_argb,
uint8* dst_yuy2, int dst_stride_yuy2,
int width, int height);
// Convert ARGB To UYVY.
LIBYUV_API
int ARGBToUYVY(const uint8* src_argb, int src_stride_argb,
uint8* dst_uyvy, int dst_stride_uyvy,
int width, int height);
#ifdef __cplusplus
} // extern "C"
} // namespace libyuv
#endif
#endif // INCLUDE_LIBYUV_CONVERT_FROM_ARGB_H_
-81
View File
@@ -1,81 +0,0 @@
/*
* Copyright 2011 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_CPU_ID_H_
#define INCLUDE_LIBYUV_CPU_ID_H_
#include "libyuv/basic_types.h"
#ifdef __cplusplus
namespace libyuv {
extern "C" {
#endif
// Internal flag to indicate cpuid requires initialization.
static const int kCpuInitialized = 0x1;
// These flags are only valid on ARM processors.
static const int kCpuHasARM = 0x2;
static const int kCpuHasNEON = 0x4;
// 0x8 reserved for future ARM flag.
// These flags are only valid on x86 processors.
static const int kCpuHasX86 = 0x10;
static const int kCpuHasSSE2 = 0x20;
static const int kCpuHasSSSE3 = 0x40;
static const int kCpuHasSSE41 = 0x80;
static const int kCpuHasSSE42 = 0x100;
static const int kCpuHasAVX = 0x200;
static const int kCpuHasAVX2 = 0x400;
static const int kCpuHasERMS = 0x800;
static const int kCpuHasFMA3 = 0x1000;
static const int kCpuHasAVX3 = 0x2000;
// 0x2000, 0x4000, 0x8000 reserved for future X86 flags.
// These flags are only valid on MIPS processors.
static const int kCpuHasMIPS = 0x10000;
static const int kCpuHasDSPR2 = 0x20000;
static const int kCpuHasMSA = 0x40000;
// Internal function used to auto-init.
LIBYUV_API
int InitCpuFlags(void);
// Internal function for parsing /proc/cpuinfo.
LIBYUV_API
int ArmCpuCaps(const char* cpuinfo_name);
// Detect CPU has SSE2 etc.
// Test_flag parameter should be one of kCpuHas constants above.
// returns non-zero if instruction set is detected
static __inline int TestCpuFlag(int test_flag) {
LIBYUV_API extern int cpu_info_;
return (!cpu_info_ ? InitCpuFlags() : cpu_info_) & test_flag;
}
// For testing, allow CPU flags to be disabled.
// ie MaskCpuFlags(~kCpuHasSSSE3) to disable SSSE3.
// MaskCpuFlags(-1) to enable all cpu specific optimizations.
// MaskCpuFlags(1) to disable all cpu specific optimizations.
LIBYUV_API
void MaskCpuFlags(int enable_flags);
// Low level cpuid for X86. Returns zeros on other CPUs.
// eax is the info type that you want.
// ecx is typically the cpu number, and should normally be zero.
LIBYUV_API
void CpuId(uint32 eax, uint32 ecx, uint32* cpu_info);
#ifdef __cplusplus
} // extern "C"
} // namespace libyuv
#endif
#endif // INCLUDE_LIBYUV_CPU_ID_H_
-76
View File
@@ -1,76 +0,0 @@
/*
* Copyright 2016 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_MACROS_MSA_H_
#define INCLUDE_LIBYUV_MACROS_MSA_H_
#if !defined(LIBYUV_DISABLE_MSA) && defined(__mips_msa)
#include <stdint.h>
#include <msa.h>
#define LD_B(RTYPE, psrc) *((RTYPE*)(psrc)) /* NOLINT */
#define LD_UB(...) LD_B(v16u8, __VA_ARGS__)
#define ST_B(RTYPE, in, pdst) *((RTYPE*)(pdst)) = (in) /* NOLINT */
#define ST_UB(...) ST_B(v16u8, __VA_ARGS__)
/* Description : Load two vectors with 16 'byte' sized elements
Arguments : Inputs - psrc, stride
Outputs - out0, out1
Return Type - as per RTYPE
Details : Load 16 byte elements in 'out0' from (psrc)
Load 16 byte elements in 'out1' from (psrc + stride)
*/
#define LD_B2(RTYPE, psrc, stride, out0, out1) { \
out0 = LD_B(RTYPE, (psrc)); \
out1 = LD_B(RTYPE, (psrc) + stride); \
}
#define LD_UB2(...) LD_B2(v16u8, __VA_ARGS__)
#define LD_B4(RTYPE, psrc, stride, out0, out1, out2, out3) { \
LD_B2(RTYPE, (psrc), stride, out0, out1); \
LD_B2(RTYPE, (psrc) + 2 * stride , stride, out2, out3); \
}
#define LD_UB4(...) LD_B4(v16u8, __VA_ARGS__)
/* Description : Store two vectors with stride each having 16 'byte' sized
elements
Arguments : Inputs - in0, in1, pdst, stride
Details : Store 16 byte elements from 'in0' to (pdst)
Store 16 byte elements from 'in1' to (pdst + stride)
*/
#define ST_B2(RTYPE, in0, in1, pdst, stride) { \
ST_B(RTYPE, in0, (pdst)); \
ST_B(RTYPE, in1, (pdst) + stride); \
}
#define ST_UB2(...) ST_B2(v16u8, __VA_ARGS__)
#
#define ST_B4(RTYPE, in0, in1, in2, in3, pdst, stride) { \
ST_B2(RTYPE, in0, in1, (pdst), stride); \
ST_B2(RTYPE, in2, in3, (pdst) + 2 * stride, stride); \
}
#define ST_UB4(...) ST_B4(v16u8, __VA_ARGS__)
#
/* Description : Shuffle byte vector elements as per mask vector
Arguments : Inputs - in0, in1, in2, in3, mask0, mask1
Outputs - out0, out1
Return Type - as per RTYPE
Details : Byte elements from 'in0' & 'in1' are copied selectively to
'out0' as per control vector 'mask0'
*/
#define VSHF_B2(RTYPE, in0, in1, in2, in3, mask0, mask1, out0, out1) { \
out0 = (RTYPE) __msa_vshf_b((v16i8) mask0, (v16i8) in1, (v16i8) in0); \
out1 = (RTYPE) __msa_vshf_b((v16i8) mask1, (v16i8) in3, (v16i8) in2); \
}
#define VSHF_B2_UB(...) VSHF_B2(v16u8, __VA_ARGS__)
#endif /* !defined(LIBYUV_DISABLE_MSA) && defined(__mips_msa) */
#endif // INCLUDE_LIBYUV_MACROS_MSA_H_
-192
View File
@@ -1,192 +0,0 @@
/*
* Copyright 2012 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_MJPEG_DECODER_H_
#define INCLUDE_LIBYUV_MJPEG_DECODER_H_
#include "libyuv/basic_types.h"
#ifdef __cplusplus
// NOTE: For a simplified public API use convert.h MJPGToI420().
struct jpeg_common_struct;
struct jpeg_decompress_struct;
struct jpeg_source_mgr;
namespace libyuv {
#ifdef __cplusplus
extern "C" {
#endif
LIBYUV_BOOL ValidateJpeg(const uint8* sample, size_t sample_size);
#ifdef __cplusplus
} // extern "C"
#endif
static const uint32 kUnknownDataSize = 0xFFFFFFFF;
enum JpegSubsamplingType {
kJpegYuv420,
kJpegYuv422,
kJpegYuv411,
kJpegYuv444,
kJpegYuv400,
kJpegUnknown
};
struct Buffer {
const uint8* data;
int len;
};
struct BufferVector {
Buffer* buffers;
int len;
int pos;
};
struct SetJmpErrorMgr;
// MJPEG ("Motion JPEG") is a pseudo-standard video codec where the frames are
// simply independent JPEG images with a fixed huffman table (which is omitted).
// It is rarely used in video transmission, but is common as a camera capture
// format, especially in Logitech devices. This class implements a decoder for
// MJPEG frames.
//
// See http://tools.ietf.org/html/rfc2435
class LIBYUV_API MJpegDecoder {
public:
typedef void (*CallbackFunction)(void* opaque,
const uint8* const* data,
const int* strides,
int rows);
static const int kColorSpaceUnknown;
static const int kColorSpaceGrayscale;
static const int kColorSpaceRgb;
static const int kColorSpaceYCbCr;
static const int kColorSpaceCMYK;
static const int kColorSpaceYCCK;
MJpegDecoder();
~MJpegDecoder();
// Loads a new frame, reads its headers, and determines the uncompressed
// image format.
// Returns LIBYUV_TRUE if image looks valid and format is supported.
// If return value is LIBYUV_TRUE, then the values for all the following
// getters are populated.
// src_len is the size of the compressed mjpeg frame in bytes.
LIBYUV_BOOL LoadFrame(const uint8* src, size_t src_len);
// Returns width of the last loaded frame in pixels.
int GetWidth();
// Returns height of the last loaded frame in pixels.
int GetHeight();
// Returns format of the last loaded frame. The return value is one of the
// kColorSpace* constants.
int GetColorSpace();
// Number of color components in the color space.
int GetNumComponents();
// Sample factors of the n-th component.
int GetHorizSampFactor(int component);
int GetVertSampFactor(int component);
int GetHorizSubSampFactor(int component);
int GetVertSubSampFactor(int component);
// Public for testability.
int GetImageScanlinesPerImcuRow();
// Public for testability.
int GetComponentScanlinesPerImcuRow(int component);
// Width of a component in bytes.
int GetComponentWidth(int component);
// Height of a component.
int GetComponentHeight(int component);
// Width of a component in bytes with padding for DCTSIZE. Public for testing.
int GetComponentStride(int component);
// Size of a component in bytes.
int GetComponentSize(int component);
// Call this after LoadFrame() if you decide you don't want to decode it
// after all.
LIBYUV_BOOL UnloadFrame();
// Decodes the entire image into a one-buffer-per-color-component format.
// dst_width must match exactly. dst_height must be <= to image height; if
// less, the image is cropped. "planes" must have size equal to at least
// GetNumComponents() and they must point to non-overlapping buffers of size
// at least GetComponentSize(i). The pointers in planes are incremented
// to point to after the end of the written data.
// TODO(fbarchard): Add dst_x, dst_y to allow specific rect to be decoded.
LIBYUV_BOOL DecodeToBuffers(uint8** planes, int dst_width, int dst_height);
// Decodes the entire image and passes the data via repeated calls to a
// callback function. Each call will get the data for a whole number of
// image scanlines.
// TODO(fbarchard): Add dst_x, dst_y to allow specific rect to be decoded.
LIBYUV_BOOL DecodeToCallback(CallbackFunction fn, void* opaque,
int dst_width, int dst_height);
// The helper function which recognizes the jpeg sub-sampling type.
static JpegSubsamplingType JpegSubsamplingTypeHelper(
int* subsample_x, int* subsample_y, int number_of_components);
private:
void AllocOutputBuffers(int num_outbufs);
void DestroyOutputBuffers();
LIBYUV_BOOL StartDecode();
LIBYUV_BOOL FinishDecode();
void SetScanlinePointers(uint8** data);
LIBYUV_BOOL DecodeImcuRow();
int GetComponentScanlinePadding(int component);
// A buffer holding the input data for a frame.
Buffer buf_;
BufferVector buf_vec_;
jpeg_decompress_struct* decompress_struct_;
jpeg_source_mgr* source_mgr_;
SetJmpErrorMgr* error_mgr_;
// LIBYUV_TRUE iff at least one component has scanline padding. (i.e.,
// GetComponentScanlinePadding() != 0.)
LIBYUV_BOOL has_scanline_padding_;
// Temporaries used to point to scanline outputs.
int num_outbufs_; // Outermost size of all arrays below.
uint8*** scanlines_;
int* scanlines_sizes_;
// Temporary buffer used for decoding when we can't decode directly to the
// output buffers. Large enough for just one iMCU row.
uint8** databuf_;
int* databuf_strides_;
};
} // namespace libyuv
#endif // __cplusplus
#endif // INCLUDE_LIBYUV_MJPEG_DECODER_H_
@@ -1,529 +0,0 @@
/*
* Copyright 2011 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_PLANAR_FUNCTIONS_H_
#define INCLUDE_LIBYUV_PLANAR_FUNCTIONS_H_
#include "libyuv/basic_types.h"
// TODO(fbarchard): Remove the following headers includes.
#include "libyuv/convert.h"
#include "libyuv/convert_argb.h"
#ifdef __cplusplus
namespace libyuv {
extern "C" {
#endif
// Copy a plane of data.
LIBYUV_API
void CopyPlane(const uint8* src_y, int src_stride_y,
uint8* dst_y, int dst_stride_y,
int width, int height);
LIBYUV_API
void CopyPlane_16(const uint16* src_y, int src_stride_y,
uint16* dst_y, int dst_stride_y,
int width, int height);
// Set a plane of data to a 32 bit value.
LIBYUV_API
void SetPlane(uint8* dst_y, int dst_stride_y,
int width, int height,
uint32 value);
// Split interleaved UV plane into separate U and V planes.
LIBYUV_API
void SplitUVPlane(const uint8* src_uv, int src_stride_uv,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Merge separate U and V planes into one interleaved UV plane.
LIBYUV_API
void MergeUVPlane(const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_uv, int dst_stride_uv,
int width, int height);
// Copy I400. Supports inverting.
LIBYUV_API
int I400ToI400(const uint8* src_y, int src_stride_y,
uint8* dst_y, int dst_stride_y,
int width, int height);
#define J400ToJ400 I400ToI400
// Copy I422 to I422.
#define I422ToI422 I422Copy
LIBYUV_API
int I422Copy(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Copy I444 to I444.
#define I444ToI444 I444Copy
LIBYUV_API
int I444Copy(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Convert YUY2 to I422.
LIBYUV_API
int YUY2ToI422(const uint8* src_yuy2, int src_stride_yuy2,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Convert UYVY to I422.
LIBYUV_API
int UYVYToI422(const uint8* src_uyvy, int src_stride_uyvy,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
LIBYUV_API
int YUY2ToNV12(const uint8* src_yuy2, int src_stride_yuy2,
uint8* dst_y, int dst_stride_y,
uint8* dst_uv, int dst_stride_uv,
int width, int height);
LIBYUV_API
int UYVYToNV12(const uint8* src_uyvy, int src_stride_uyvy,
uint8* dst_y, int dst_stride_y,
uint8* dst_uv, int dst_stride_uv,
int width, int height);
// Convert I420 to I400. (calls CopyPlane ignoring u/v).
LIBYUV_API
int I420ToI400(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_y, int dst_stride_y,
int width, int height);
// Alias
#define J420ToJ400 I420ToI400
#define I420ToI420Mirror I420Mirror
// I420 mirror.
LIBYUV_API
int I420Mirror(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Alias
#define I400ToI400Mirror I400Mirror
// I400 mirror. A single plane is mirrored horizontally.
// Pass negative height to achieve 180 degree rotation.
LIBYUV_API
int I400Mirror(const uint8* src_y, int src_stride_y,
uint8* dst_y, int dst_stride_y,
int width, int height);
// Alias
#define ARGBToARGBMirror ARGBMirror
// ARGB mirror.
LIBYUV_API
int ARGBMirror(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Convert NV12 to RGB565.
LIBYUV_API
int NV12ToRGB565(const uint8* src_y, int src_stride_y,
const uint8* src_uv, int src_stride_uv,
uint8* dst_rgb565, int dst_stride_rgb565,
int width, int height);
// I422ToARGB is in convert_argb.h
// Convert I422 to BGRA.
LIBYUV_API
int I422ToBGRA(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_bgra, int dst_stride_bgra,
int width, int height);
// Convert I422 to ABGR.
LIBYUV_API
int I422ToABGR(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_abgr, int dst_stride_abgr,
int width, int height);
// Convert I422 to RGBA.
LIBYUV_API
int I422ToRGBA(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_rgba, int dst_stride_rgba,
int width, int height);
// Alias
#define RGB24ToRAW RAWToRGB24
LIBYUV_API
int RAWToRGB24(const uint8* src_raw, int src_stride_raw,
uint8* dst_rgb24, int dst_stride_rgb24,
int width, int height);
// Draw a rectangle into I420.
LIBYUV_API
int I420Rect(uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int x, int y, int width, int height,
int value_y, int value_u, int value_v);
// Draw a rectangle into ARGB.
LIBYUV_API
int ARGBRect(uint8* dst_argb, int dst_stride_argb,
int x, int y, int width, int height, uint32 value);
// Convert ARGB to gray scale ARGB.
LIBYUV_API
int ARGBGrayTo(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Make a rectangle of ARGB gray scale.
LIBYUV_API
int ARGBGray(uint8* dst_argb, int dst_stride_argb,
int x, int y, int width, int height);
// Make a rectangle of ARGB Sepia tone.
LIBYUV_API
int ARGBSepia(uint8* dst_argb, int dst_stride_argb,
int x, int y, int width, int height);
// Apply a matrix rotation to each ARGB pixel.
// matrix_argb is 4 signed ARGB values. -128 to 127 representing -2 to 2.
// The first 4 coefficients apply to B, G, R, A and produce B of the output.
// The next 4 coefficients apply to B, G, R, A and produce G of the output.
// The next 4 coefficients apply to B, G, R, A and produce R of the output.
// The last 4 coefficients apply to B, G, R, A and produce A of the output.
LIBYUV_API
int ARGBColorMatrix(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb, int dst_stride_argb,
const int8* matrix_argb,
int width, int height);
// Deprecated. Use ARGBColorMatrix instead.
// Apply a matrix rotation to each ARGB pixel.
// matrix_argb is 3 signed ARGB values. -128 to 127 representing -1 to 1.
// The first 4 coefficients apply to B, G, R, A and produce B of the output.
// The next 4 coefficients apply to B, G, R, A and produce G of the output.
// The last 4 coefficients apply to B, G, R, A and produce R of the output.
LIBYUV_API
int RGBColorMatrix(uint8* dst_argb, int dst_stride_argb,
const int8* matrix_rgb,
int x, int y, int width, int height);
// Apply a color table each ARGB pixel.
// Table contains 256 ARGB values.
LIBYUV_API
int ARGBColorTable(uint8* dst_argb, int dst_stride_argb,
const uint8* table_argb,
int x, int y, int width, int height);
// Apply a color table each ARGB pixel but preserve destination alpha.
// Table contains 256 ARGB values.
LIBYUV_API
int RGBColorTable(uint8* dst_argb, int dst_stride_argb,
const uint8* table_argb,
int x, int y, int width, int height);
// Apply a luma/color table each ARGB pixel but preserve destination alpha.
// Table contains 32768 values indexed by [Y][C] where 7 it 7 bit luma from
// RGB (YJ style) and C is an 8 bit color component (R, G or B).
LIBYUV_API
int ARGBLumaColorTable(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb, int dst_stride_argb,
const uint8* luma_rgb_table,
int width, int height);
// Apply a 3 term polynomial to ARGB values.
// poly points to a 4x4 matrix. The first row is constants. The 2nd row is
// coefficients for b, g, r and a. The 3rd row is coefficients for b squared,
// g squared, r squared and a squared. The 4rd row is coefficients for b to
// the 3, g to the 3, r to the 3 and a to the 3. The values are summed and
// result clamped to 0 to 255.
// A polynomial approximation can be dirived using software such as 'R'.
LIBYUV_API
int ARGBPolynomial(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb, int dst_stride_argb,
const float* poly,
int width, int height);
// Convert plane of 16 bit shorts to half floats.
// Source values are multiplied by scale before storing as half float.
LIBYUV_API
int HalfFloatPlane(const uint16* src_y, int src_stride_y,
uint16* dst_y, int dst_stride_y,
float scale,
int width, int height);
// Quantize a rectangle of ARGB. Alpha unaffected.
// scale is a 16 bit fractional fixed point scaler between 0 and 65535.
// interval_size should be a value between 1 and 255.
// interval_offset should be a value between 0 and 255.
LIBYUV_API
int ARGBQuantize(uint8* dst_argb, int dst_stride_argb,
int scale, int interval_size, int interval_offset,
int x, int y, int width, int height);
// Copy ARGB to ARGB.
LIBYUV_API
int ARGBCopy(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Copy Alpha channel of ARGB to alpha of ARGB.
LIBYUV_API
int ARGBCopyAlpha(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Extract the alpha channel from ARGB.
LIBYUV_API
int ARGBExtractAlpha(const uint8* src_argb, int src_stride_argb,
uint8* dst_a, int dst_stride_a,
int width, int height);
// Copy Y channel to Alpha of ARGB.
LIBYUV_API
int ARGBCopyYToAlpha(const uint8* src_y, int src_stride_y,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
typedef void (*ARGBBlendRow)(const uint8* src_argb0, const uint8* src_argb1,
uint8* dst_argb, int width);
// Get function to Alpha Blend ARGB pixels and store to destination.
LIBYUV_API
ARGBBlendRow GetARGBBlend();
// Alpha Blend ARGB images and store to destination.
// Source is pre-multiplied by alpha using ARGBAttenuate.
// Alpha of destination is set to 255.
LIBYUV_API
int ARGBBlend(const uint8* src_argb0, int src_stride_argb0,
const uint8* src_argb1, int src_stride_argb1,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Alpha Blend plane and store to destination.
// Source is not pre-multiplied by alpha.
LIBYUV_API
int BlendPlane(const uint8* src_y0, int src_stride_y0,
const uint8* src_y1, int src_stride_y1,
const uint8* alpha, int alpha_stride,
uint8* dst_y, int dst_stride_y,
int width, int height);
// Alpha Blend YUV images and store to destination.
// Source is not pre-multiplied by alpha.
// Alpha is full width x height and subsampled to half size to apply to UV.
LIBYUV_API
int I420Blend(const uint8* src_y0, int src_stride_y0,
const uint8* src_u0, int src_stride_u0,
const uint8* src_v0, int src_stride_v0,
const uint8* src_y1, int src_stride_y1,
const uint8* src_u1, int src_stride_u1,
const uint8* src_v1, int src_stride_v1,
const uint8* alpha, int alpha_stride,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height);
// Multiply ARGB image by ARGB image. Shifted down by 8. Saturates to 255.
LIBYUV_API
int ARGBMultiply(const uint8* src_argb0, int src_stride_argb0,
const uint8* src_argb1, int src_stride_argb1,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Add ARGB image with ARGB image. Saturates to 255.
LIBYUV_API
int ARGBAdd(const uint8* src_argb0, int src_stride_argb0,
const uint8* src_argb1, int src_stride_argb1,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Subtract ARGB image (argb1) from ARGB image (argb0). Saturates to 0.
LIBYUV_API
int ARGBSubtract(const uint8* src_argb0, int src_stride_argb0,
const uint8* src_argb1, int src_stride_argb1,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Convert I422 to YUY2.
LIBYUV_API
int I422ToYUY2(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_frame, int dst_stride_frame,
int width, int height);
// Convert I422 to UYVY.
LIBYUV_API
int I422ToUYVY(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_frame, int dst_stride_frame,
int width, int height);
// Convert unattentuated ARGB to preattenuated ARGB.
LIBYUV_API
int ARGBAttenuate(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Convert preattentuated ARGB to unattenuated ARGB.
LIBYUV_API
int ARGBUnattenuate(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Internal function - do not call directly.
// Computes table of cumulative sum for image where the value is the sum
// of all values above and to the left of the entry. Used by ARGBBlur.
LIBYUV_API
int ARGBComputeCumulativeSum(const uint8* src_argb, int src_stride_argb,
int32* dst_cumsum, int dst_stride32_cumsum,
int width, int height);
// Blur ARGB image.
// dst_cumsum table of width * (height + 1) * 16 bytes aligned to
// 16 byte boundary.
// dst_stride32_cumsum is number of ints in a row (width * 4).
// radius is number of pixels around the center. e.g. 1 = 3x3. 2=5x5.
// Blur is optimized for radius of 5 (11x11) or less.
LIBYUV_API
int ARGBBlur(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb, int dst_stride_argb,
int32* dst_cumsum, int dst_stride32_cumsum,
int width, int height, int radius);
// Multiply ARGB image by ARGB value.
LIBYUV_API
int ARGBShade(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb, int dst_stride_argb,
int width, int height, uint32 value);
// Interpolate between two images using specified amount of interpolation
// (0 to 255) and store to destination.
// 'interpolation' is specified as 8 bit fraction where 0 means 100% src0
// and 255 means 1% src0 and 99% src1.
LIBYUV_API
int InterpolatePlane(const uint8* src0, int src_stride0,
const uint8* src1, int src_stride1,
uint8* dst, int dst_stride,
int width, int height, int interpolation);
// Interpolate between two ARGB images using specified amount of interpolation
// Internally calls InterpolatePlane with width * 4 (bpp).
LIBYUV_API
int ARGBInterpolate(const uint8* src_argb0, int src_stride_argb0,
const uint8* src_argb1, int src_stride_argb1,
uint8* dst_argb, int dst_stride_argb,
int width, int height, int interpolation);
// Interpolate between two YUV images using specified amount of interpolation
// Internally calls InterpolatePlane on each plane where the U and V planes
// are half width and half height.
LIBYUV_API
int I420Interpolate(const uint8* src0_y, int src0_stride_y,
const uint8* src0_u, int src0_stride_u,
const uint8* src0_v, int src0_stride_v,
const uint8* src1_y, int src1_stride_y,
const uint8* src1_u, int src1_stride_u,
const uint8* src1_v, int src1_stride_v,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height, int interpolation);
#if defined(__pnacl__) || defined(__CLR_VER) || \
(defined(__i386__) && !defined(__SSE2__))
#define LIBYUV_DISABLE_X86
#endif
// MemorySanitizer does not support assembly code yet. http://crbug.com/344505
#if defined(__has_feature)
#if __has_feature(memory_sanitizer)
#define LIBYUV_DISABLE_X86
#endif
#endif
// The following are available on all x86 platforms:
#if !defined(LIBYUV_DISABLE_X86) && \
(defined(_M_IX86) || defined(__x86_64__) || defined(__i386__))
#define HAS_ARGBAFFINEROW_SSE2
#endif
// Row function for copying pixels from a source with a slope to a row
// of destination. Useful for scaling, rotation, mirror, texture mapping.
LIBYUV_API
void ARGBAffineRow_C(const uint8* src_argb, int src_argb_stride,
uint8* dst_argb, const float* uv_dudv, int width);
LIBYUV_API
void ARGBAffineRow_SSE2(const uint8* src_argb, int src_argb_stride,
uint8* dst_argb, const float* uv_dudv, int width);
// Shuffle ARGB channel order. e.g. BGRA to ARGB.
// shuffler is 16 bytes and must be aligned.
LIBYUV_API
int ARGBShuffle(const uint8* src_bgra, int src_stride_bgra,
uint8* dst_argb, int dst_stride_argb,
const uint8* shuffler, int width, int height);
// Sobel ARGB effect with planar output.
LIBYUV_API
int ARGBSobelToPlane(const uint8* src_argb, int src_stride_argb,
uint8* dst_y, int dst_stride_y,
int width, int height);
// Sobel ARGB effect.
LIBYUV_API
int ARGBSobel(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
// Sobel ARGB effect w/ Sobel X, Sobel, Sobel Y in ARGB.
LIBYUV_API
int ARGBSobelXY(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb, int dst_stride_argb,
int width, int height);
#ifdef __cplusplus
} // extern "C"
} // namespace libyuv
#endif
#endif // INCLUDE_LIBYUV_PLANAR_FUNCTIONS_H_
-117
View File
@@ -1,117 +0,0 @@
/*
* Copyright 2011 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_ROTATE_H_
#define INCLUDE_LIBYUV_ROTATE_H_
#include "libyuv/basic_types.h"
#ifdef __cplusplus
namespace libyuv {
extern "C" {
#endif
// Supported rotation.
typedef enum RotationMode {
kRotate0 = 0, // No rotation.
kRotate90 = 90, // Rotate 90 degrees clockwise.
kRotate180 = 180, // Rotate 180 degrees.
kRotate270 = 270, // Rotate 270 degrees clockwise.
// Deprecated.
kRotateNone = 0,
kRotateClockwise = 90,
kRotateCounterClockwise = 270,
} RotationModeEnum;
// Rotate I420 frame.
LIBYUV_API
int I420Rotate(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int src_width, int src_height, enum RotationMode mode);
// Rotate NV12 input and store in I420.
LIBYUV_API
int NV12ToI420Rotate(const uint8* src_y, int src_stride_y,
const uint8* src_uv, int src_stride_uv,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int src_width, int src_height, enum RotationMode mode);
// Rotate a plane by 0, 90, 180, or 270.
LIBYUV_API
int RotatePlane(const uint8* src, int src_stride,
uint8* dst, int dst_stride,
int src_width, int src_height, enum RotationMode mode);
// Rotate planes by 90, 180, 270. Deprecated.
LIBYUV_API
void RotatePlane90(const uint8* src, int src_stride,
uint8* dst, int dst_stride,
int width, int height);
LIBYUV_API
void RotatePlane180(const uint8* src, int src_stride,
uint8* dst, int dst_stride,
int width, int height);
LIBYUV_API
void RotatePlane270(const uint8* src, int src_stride,
uint8* dst, int dst_stride,
int width, int height);
LIBYUV_API
void RotateUV90(const uint8* src, int src_stride,
uint8* dst_a, int dst_stride_a,
uint8* dst_b, int dst_stride_b,
int width, int height);
// Rotations for when U and V are interleaved.
// These functions take one input pointer and
// split the data into two buffers while
// rotating them. Deprecated.
LIBYUV_API
void RotateUV180(const uint8* src, int src_stride,
uint8* dst_a, int dst_stride_a,
uint8* dst_b, int dst_stride_b,
int width, int height);
LIBYUV_API
void RotateUV270(const uint8* src, int src_stride,
uint8* dst_a, int dst_stride_a,
uint8* dst_b, int dst_stride_b,
int width, int height);
// The 90 and 270 functions are based on transposes.
// Doing a transpose with reversing the read/write
// order will result in a rotation by +- 90 degrees.
// Deprecated.
LIBYUV_API
void TransposePlane(const uint8* src, int src_stride,
uint8* dst, int dst_stride,
int width, int height);
LIBYUV_API
void TransposeUV(const uint8* src, int src_stride,
uint8* dst_a, int dst_stride_a,
uint8* dst_b, int dst_stride_b,
int width, int height);
#ifdef __cplusplus
} // extern "C"
} // namespace libyuv
#endif
#endif // INCLUDE_LIBYUV_ROTATE_H_
-33
View File
@@ -1,33 +0,0 @@
/*
* Copyright 2012 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_ROTATE_ARGB_H_
#define INCLUDE_LIBYUV_ROTATE_ARGB_H_
#include "libyuv/basic_types.h"
#include "libyuv/rotate.h" // For RotationMode.
#ifdef __cplusplus
namespace libyuv {
extern "C" {
#endif
// Rotate ARGB frame
LIBYUV_API
int ARGBRotate(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb, int dst_stride_argb,
int src_width, int src_height, enum RotationMode mode);
#ifdef __cplusplus
} // extern "C"
} // namespace libyuv
#endif
#endif // INCLUDE_LIBYUV_ROTATE_ARGB_H_
-121
View File
@@ -1,121 +0,0 @@
/*
* Copyright 2013 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_ROTATE_ROW_H_
#define INCLUDE_LIBYUV_ROTATE_ROW_H_
#include "libyuv/basic_types.h"
#ifdef __cplusplus
namespace libyuv {
extern "C" {
#endif
#if defined(__pnacl__) || defined(__CLR_VER) || \
(defined(__i386__) && !defined(__SSE2__))
#define LIBYUV_DISABLE_X86
#endif
// MemorySanitizer does not support assembly code yet. http://crbug.com/344505
#if defined(__has_feature)
#if __has_feature(memory_sanitizer)
#define LIBYUV_DISABLE_X86
#endif
#endif
// The following are available for Visual C and clangcl 32 bit:
#if !defined(LIBYUV_DISABLE_X86) && defined(_M_IX86)
#define HAS_TRANSPOSEWX8_SSSE3
#define HAS_TRANSPOSEUVWX8_SSE2
#endif
// The following are available for GCC 32 or 64 bit but not NaCL for 64 bit:
#if !defined(LIBYUV_DISABLE_X86) && \
(defined(__i386__) || (defined(__x86_64__) && !defined(__native_client__)))
#define HAS_TRANSPOSEWX8_SSSE3
#endif
// The following are available for 64 bit GCC but not NaCL:
#if !defined(LIBYUV_DISABLE_X86) && !defined(__native_client__) && \
defined(__x86_64__)
#define HAS_TRANSPOSEWX8_FAST_SSSE3
#define HAS_TRANSPOSEUVWX8_SSE2
#endif
#if !defined(LIBYUV_DISABLE_NEON) && !defined(__native_client__) && \
(defined(__ARM_NEON__) || defined(LIBYUV_NEON) || defined(__aarch64__))
#define HAS_TRANSPOSEWX8_NEON
#define HAS_TRANSPOSEUVWX8_NEON
#endif
#if !defined(LIBYUV_DISABLE_MIPS) && !defined(__native_client__) && \
defined(__mips__) && \
defined(__mips_dsp) && (__mips_dsp_rev >= 2)
#define HAS_TRANSPOSEWX8_DSPR2
#define HAS_TRANSPOSEUVWX8_DSPR2
#endif // defined(__mips__)
void TransposeWxH_C(const uint8* src, int src_stride,
uint8* dst, int dst_stride, int width, int height);
void TransposeWx8_C(const uint8* src, int src_stride,
uint8* dst, int dst_stride, int width);
void TransposeWx8_NEON(const uint8* src, int src_stride,
uint8* dst, int dst_stride, int width);
void TransposeWx8_SSSE3(const uint8* src, int src_stride,
uint8* dst, int dst_stride, int width);
void TransposeWx8_Fast_SSSE3(const uint8* src, int src_stride,
uint8* dst, int dst_stride, int width);
void TransposeWx8_DSPR2(const uint8* src, int src_stride,
uint8* dst, int dst_stride, int width);
void TransposeWx8_Fast_DSPR2(const uint8* src, int src_stride,
uint8* dst, int dst_stride, int width);
void TransposeWx8_Any_NEON(const uint8* src, int src_stride,
uint8* dst, int dst_stride, int width);
void TransposeWx8_Any_SSSE3(const uint8* src, int src_stride,
uint8* dst, int dst_stride, int width);
void TransposeWx8_Fast_Any_SSSE3(const uint8* src, int src_stride,
uint8* dst, int dst_stride, int width);
void TransposeWx8_Any_DSPR2(const uint8* src, int src_stride,
uint8* dst, int dst_stride, int width);
void TransposeUVWxH_C(const uint8* src, int src_stride,
uint8* dst_a, int dst_stride_a,
uint8* dst_b, int dst_stride_b,
int width, int height);
void TransposeUVWx8_C(const uint8* src, int src_stride,
uint8* dst_a, int dst_stride_a,
uint8* dst_b, int dst_stride_b, int width);
void TransposeUVWx8_SSE2(const uint8* src, int src_stride,
uint8* dst_a, int dst_stride_a,
uint8* dst_b, int dst_stride_b, int width);
void TransposeUVWx8_NEON(const uint8* src, int src_stride,
uint8* dst_a, int dst_stride_a,
uint8* dst_b, int dst_stride_b, int width);
void TransposeUVWx8_DSPR2(const uint8* src, int src_stride,
uint8* dst_a, int dst_stride_a,
uint8* dst_b, int dst_stride_b, int width);
void TransposeUVWx8_Any_SSE2(const uint8* src, int src_stride,
uint8* dst_a, int dst_stride_a,
uint8* dst_b, int dst_stride_b, int width);
void TransposeUVWx8_Any_NEON(const uint8* src, int src_stride,
uint8* dst_a, int dst_stride_a,
uint8* dst_b, int dst_stride_b, int width);
void TransposeUVWx8_Any_DSPR2(const uint8* src, int src_stride,
uint8* dst_a, int dst_stride_a,
uint8* dst_b, int dst_stride_b, int width);
#ifdef __cplusplus
} // extern "C"
} // namespace libyuv
#endif
#endif // INCLUDE_LIBYUV_ROTATE_ROW_H_
File diff suppressed because it is too large Load Diff
-103
View File
@@ -1,103 +0,0 @@
/*
* Copyright 2011 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_SCALE_H_
#define INCLUDE_LIBYUV_SCALE_H_
#include "libyuv/basic_types.h"
#ifdef __cplusplus
namespace libyuv {
extern "C" {
#endif
// Supported filtering.
typedef enum FilterMode {
kFilterNone = 0, // Point sample; Fastest.
kFilterLinear = 1, // Filter horizontally only.
kFilterBilinear = 2, // Faster than box, but lower quality scaling down.
kFilterBox = 3 // Highest quality.
} FilterModeEnum;
// Scale a YUV plane.
LIBYUV_API
void ScalePlane(const uint8* src, int src_stride,
int src_width, int src_height,
uint8* dst, int dst_stride,
int dst_width, int dst_height,
enum FilterMode filtering);
LIBYUV_API
void ScalePlane_16(const uint16* src, int src_stride,
int src_width, int src_height,
uint16* dst, int dst_stride,
int dst_width, int dst_height,
enum FilterMode filtering);
// Scales a YUV 4:2:0 image from the src width and height to the
// dst width and height.
// If filtering is kFilterNone, a simple nearest-neighbor algorithm is
// used. This produces basic (blocky) quality at the fastest speed.
// If filtering is kFilterBilinear, interpolation is used to produce a better
// quality image, at the expense of speed.
// If filtering is kFilterBox, averaging is used to produce ever better
// quality image, at further expense of speed.
// Returns 0 if successful.
LIBYUV_API
int I420Scale(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
int src_width, int src_height,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int dst_width, int dst_height,
enum FilterMode filtering);
LIBYUV_API
int I420Scale_16(const uint16* src_y, int src_stride_y,
const uint16* src_u, int src_stride_u,
const uint16* src_v, int src_stride_v,
int src_width, int src_height,
uint16* dst_y, int dst_stride_y,
uint16* dst_u, int dst_stride_u,
uint16* dst_v, int dst_stride_v,
int dst_width, int dst_height,
enum FilterMode filtering);
#ifdef __cplusplus
// Legacy API. Deprecated.
LIBYUV_API
int Scale(const uint8* src_y, const uint8* src_u, const uint8* src_v,
int src_stride_y, int src_stride_u, int src_stride_v,
int src_width, int src_height,
uint8* dst_y, uint8* dst_u, uint8* dst_v,
int dst_stride_y, int dst_stride_u, int dst_stride_v,
int dst_width, int dst_height,
LIBYUV_BOOL interpolate);
// Legacy API. Deprecated.
LIBYUV_API
int ScaleOffset(const uint8* src_i420, int src_width, int src_height,
uint8* dst_i420, int dst_width, int dst_height, int dst_yoffset,
LIBYUV_BOOL interpolate);
// For testing, allow disabling of specialized scalers.
LIBYUV_API
void SetUseReferenceImpl(LIBYUV_BOOL use);
#endif // __cplusplus
#ifdef __cplusplus
} // extern "C"
} // namespace libyuv
#endif
#endif // INCLUDE_LIBYUV_SCALE_H_
-56
View File
@@ -1,56 +0,0 @@
/*
* Copyright 2012 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_SCALE_ARGB_H_
#define INCLUDE_LIBYUV_SCALE_ARGB_H_
#include "libyuv/basic_types.h"
#include "libyuv/scale.h" // For FilterMode
#ifdef __cplusplus
namespace libyuv {
extern "C" {
#endif
LIBYUV_API
int ARGBScale(const uint8* src_argb, int src_stride_argb,
int src_width, int src_height,
uint8* dst_argb, int dst_stride_argb,
int dst_width, int dst_height,
enum FilterMode filtering);
// Clipped scale takes destination rectangle coordinates for clip values.
LIBYUV_API
int ARGBScaleClip(const uint8* src_argb, int src_stride_argb,
int src_width, int src_height,
uint8* dst_argb, int dst_stride_argb,
int dst_width, int dst_height,
int clip_x, int clip_y, int clip_width, int clip_height,
enum FilterMode filtering);
// Scale with YUV conversion to ARGB and clipping.
LIBYUV_API
int YUVToARGBScaleClip(const uint8* src_y, int src_stride_y,
const uint8* src_u, int src_stride_u,
const uint8* src_v, int src_stride_v,
uint32 src_fourcc,
int src_width, int src_height,
uint8* dst_argb, int dst_stride_argb,
uint32 dst_fourcc,
int dst_width, int dst_height,
int clip_x, int clip_y, int clip_width, int clip_height,
enum FilterMode filtering);
#ifdef __cplusplus
} // extern "C"
} // namespace libyuv
#endif
#endif // INCLUDE_LIBYUV_SCALE_ARGB_H_
-503
View File
@@ -1,503 +0,0 @@
/*
* Copyright 2013 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_SCALE_ROW_H_
#define INCLUDE_LIBYUV_SCALE_ROW_H_
#include "libyuv/basic_types.h"
#include "libyuv/scale.h"
#ifdef __cplusplus
namespace libyuv {
extern "C" {
#endif
#if defined(__pnacl__) || defined(__CLR_VER) || \
(defined(__i386__) && !defined(__SSE2__))
#define LIBYUV_DISABLE_X86
#endif
// MemorySanitizer does not support assembly code yet. http://crbug.com/344505
#if defined(__has_feature)
#if __has_feature(memory_sanitizer)
#define LIBYUV_DISABLE_X86
#endif
#endif
// GCC >= 4.7.0 required for AVX2.
#if defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))
#if (__GNUC__ > 4) || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 7))
#define GCC_HAS_AVX2 1
#endif // GNUC >= 4.7
#endif // __GNUC__
// clang >= 3.4.0 required for AVX2.
#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__))
#if (__clang_major__ > 3) || (__clang_major__ == 3 && (__clang_minor__ >= 4))
#define CLANG_HAS_AVX2 1
#endif // clang >= 3.4
#endif // __clang__
// Visual C 2012 required for AVX2.
#if defined(_M_IX86) && !defined(__clang__) && \
defined(_MSC_VER) && _MSC_VER >= 1700
#define VISUALC_HAS_AVX2 1
#endif // VisualStudio >= 2012
// The following are available on all x86 platforms:
#if !defined(LIBYUV_DISABLE_X86) && \
(defined(_M_IX86) || defined(__x86_64__) || defined(__i386__))
#define HAS_FIXEDDIV1_X86
#define HAS_FIXEDDIV_X86
#define HAS_SCALEARGBCOLS_SSE2
#define HAS_SCALEARGBCOLSUP2_SSE2
#define HAS_SCALEARGBFILTERCOLS_SSSE3
#define HAS_SCALEARGBROWDOWN2_SSE2
#define HAS_SCALEARGBROWDOWNEVEN_SSE2
#define HAS_SCALECOLSUP2_SSE2
#define HAS_SCALEFILTERCOLS_SSSE3
#define HAS_SCALEROWDOWN2_SSSE3
#define HAS_SCALEROWDOWN34_SSSE3
#define HAS_SCALEROWDOWN38_SSSE3
#define HAS_SCALEROWDOWN4_SSSE3
#define HAS_SCALEADDROW_SSE2
#endif
// The following are available on all x86 platforms, but
// require VS2012, clang 3.4 or gcc 4.7.
// The code supports NaCL but requires a new compiler and validator.
#if !defined(LIBYUV_DISABLE_X86) && (defined(VISUALC_HAS_AVX2) || \
defined(CLANG_HAS_AVX2) || defined(GCC_HAS_AVX2))
#define HAS_SCALEADDROW_AVX2
#define HAS_SCALEROWDOWN2_AVX2
#define HAS_SCALEROWDOWN4_AVX2
#endif
// The following are available on Neon platforms:
#if !defined(LIBYUV_DISABLE_NEON) && !defined(__native_client__) && \
(defined(__ARM_NEON__) || defined(LIBYUV_NEON) || defined(__aarch64__))
#define HAS_SCALEARGBCOLS_NEON
#define HAS_SCALEARGBROWDOWN2_NEON
#define HAS_SCALEARGBROWDOWNEVEN_NEON
#define HAS_SCALEFILTERCOLS_NEON
#define HAS_SCALEROWDOWN2_NEON
#define HAS_SCALEROWDOWN34_NEON
#define HAS_SCALEROWDOWN38_NEON
#define HAS_SCALEROWDOWN4_NEON
#define HAS_SCALEARGBFILTERCOLS_NEON
#endif
// The following are available on Mips platforms:
#if !defined(LIBYUV_DISABLE_MIPS) && !defined(__native_client__) && \
defined(__mips__) && defined(__mips_dsp) && (__mips_dsp_rev >= 2)
#define HAS_SCALEROWDOWN2_DSPR2
#define HAS_SCALEROWDOWN4_DSPR2
#define HAS_SCALEROWDOWN34_DSPR2
#define HAS_SCALEROWDOWN38_DSPR2
#endif
// Scale ARGB vertically with bilinear interpolation.
void ScalePlaneVertical(int src_height,
int dst_width, int dst_height,
int src_stride, int dst_stride,
const uint8* src_argb, uint8* dst_argb,
int x, int y, int dy,
int bpp, enum FilterMode filtering);
void ScalePlaneVertical_16(int src_height,
int dst_width, int dst_height,
int src_stride, int dst_stride,
const uint16* src_argb, uint16* dst_argb,
int x, int y, int dy,
int wpp, enum FilterMode filtering);
// Simplify the filtering based on scale factors.
enum FilterMode ScaleFilterReduce(int src_width, int src_height,
int dst_width, int dst_height,
enum FilterMode filtering);
// Divide num by div and return as 16.16 fixed point result.
int FixedDiv_C(int num, int div);
int FixedDiv_X86(int num, int div);
// Divide num - 1 by div - 1 and return as 16.16 fixed point result.
int FixedDiv1_C(int num, int div);
int FixedDiv1_X86(int num, int div);
#ifdef HAS_FIXEDDIV_X86
#define FixedDiv FixedDiv_X86
#define FixedDiv1 FixedDiv1_X86
#else
#define FixedDiv FixedDiv_C
#define FixedDiv1 FixedDiv1_C
#endif
// Compute slope values for stepping.
void ScaleSlope(int src_width, int src_height,
int dst_width, int dst_height,
enum FilterMode filtering,
int* x, int* y, int* dx, int* dy);
void ScaleRowDown2_C(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown2_16_C(const uint16* src_ptr, ptrdiff_t src_stride,
uint16* dst, int dst_width);
void ScaleRowDown2Linear_C(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown2Linear_16_C(const uint16* src_ptr, ptrdiff_t src_stride,
uint16* dst, int dst_width);
void ScaleRowDown2Box_C(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown2Box_Odd_C(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown2Box_16_C(const uint16* src_ptr, ptrdiff_t src_stride,
uint16* dst, int dst_width);
void ScaleRowDown4_C(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown4_16_C(const uint16* src_ptr, ptrdiff_t src_stride,
uint16* dst, int dst_width);
void ScaleRowDown4Box_C(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown4Box_16_C(const uint16* src_ptr, ptrdiff_t src_stride,
uint16* dst, int dst_width);
void ScaleRowDown34_C(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown34_16_C(const uint16* src_ptr, ptrdiff_t src_stride,
uint16* dst, int dst_width);
void ScaleRowDown34_0_Box_C(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* d, int dst_width);
void ScaleRowDown34_0_Box_16_C(const uint16* src_ptr, ptrdiff_t src_stride,
uint16* d, int dst_width);
void ScaleRowDown34_1_Box_C(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* d, int dst_width);
void ScaleRowDown34_1_Box_16_C(const uint16* src_ptr, ptrdiff_t src_stride,
uint16* d, int dst_width);
void ScaleCols_C(uint8* dst_ptr, const uint8* src_ptr,
int dst_width, int x, int dx);
void ScaleCols_16_C(uint16* dst_ptr, const uint16* src_ptr,
int dst_width, int x, int dx);
void ScaleColsUp2_C(uint8* dst_ptr, const uint8* src_ptr,
int dst_width, int, int);
void ScaleColsUp2_16_C(uint16* dst_ptr, const uint16* src_ptr,
int dst_width, int, int);
void ScaleFilterCols_C(uint8* dst_ptr, const uint8* src_ptr,
int dst_width, int x, int dx);
void ScaleFilterCols_16_C(uint16* dst_ptr, const uint16* src_ptr,
int dst_width, int x, int dx);
void ScaleFilterCols64_C(uint8* dst_ptr, const uint8* src_ptr,
int dst_width, int x, int dx);
void ScaleFilterCols64_16_C(uint16* dst_ptr, const uint16* src_ptr,
int dst_width, int x, int dx);
void ScaleRowDown38_C(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown38_16_C(const uint16* src_ptr, ptrdiff_t src_stride,
uint16* dst, int dst_width);
void ScaleRowDown38_3_Box_C(const uint8* src_ptr,
ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown38_3_Box_16_C(const uint16* src_ptr,
ptrdiff_t src_stride,
uint16* dst_ptr, int dst_width);
void ScaleRowDown38_2_Box_C(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown38_2_Box_16_C(const uint16* src_ptr, ptrdiff_t src_stride,
uint16* dst_ptr, int dst_width);
void ScaleAddRow_C(const uint8* src_ptr, uint16* dst_ptr, int src_width);
void ScaleAddRow_16_C(const uint16* src_ptr, uint32* dst_ptr, int src_width);
void ScaleARGBRowDown2_C(const uint8* src_argb,
ptrdiff_t src_stride,
uint8* dst_argb, int dst_width);
void ScaleARGBRowDown2Linear_C(const uint8* src_argb,
ptrdiff_t src_stride,
uint8* dst_argb, int dst_width);
void ScaleARGBRowDown2Box_C(const uint8* src_argb, ptrdiff_t src_stride,
uint8* dst_argb, int dst_width);
void ScaleARGBRowDownEven_C(const uint8* src_argb, ptrdiff_t src_stride,
int src_stepx,
uint8* dst_argb, int dst_width);
void ScaleARGBRowDownEvenBox_C(const uint8* src_argb,
ptrdiff_t src_stride,
int src_stepx,
uint8* dst_argb, int dst_width);
void ScaleARGBCols_C(uint8* dst_argb, const uint8* src_argb,
int dst_width, int x, int dx);
void ScaleARGBCols64_C(uint8* dst_argb, const uint8* src_argb,
int dst_width, int x, int dx);
void ScaleARGBColsUp2_C(uint8* dst_argb, const uint8* src_argb,
int dst_width, int, int);
void ScaleARGBFilterCols_C(uint8* dst_argb, const uint8* src_argb,
int dst_width, int x, int dx);
void ScaleARGBFilterCols64_C(uint8* dst_argb, const uint8* src_argb,
int dst_width, int x, int dx);
// Specialized scalers for x86.
void ScaleRowDown2_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown2Linear_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown2Box_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown2_AVX2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown2Linear_AVX2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown2Box_AVX2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown4_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown4Box_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown4_AVX2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown4Box_AVX2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown34_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown34_1_Box_SSSE3(const uint8* src_ptr,
ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown34_0_Box_SSSE3(const uint8* src_ptr,
ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown38_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown38_3_Box_SSSE3(const uint8* src_ptr,
ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown38_2_Box_SSSE3(const uint8* src_ptr,
ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown2_Any_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown2Linear_Any_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown2Box_Any_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown2Box_Odd_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown2_Any_AVX2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown2Linear_Any_AVX2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown2Box_Any_AVX2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown2Box_Odd_AVX2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown4_Any_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown4Box_Any_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown4_Any_AVX2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown4Box_Any_AVX2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown34_Any_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown34_1_Box_Any_SSSE3(const uint8* src_ptr,
ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown34_0_Box_Any_SSSE3(const uint8* src_ptr,
ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown38_Any_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown38_3_Box_Any_SSSE3(const uint8* src_ptr,
ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown38_2_Box_Any_SSSE3(const uint8* src_ptr,
ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleAddRow_SSE2(const uint8* src_ptr, uint16* dst_ptr, int src_width);
void ScaleAddRow_AVX2(const uint8* src_ptr, uint16* dst_ptr, int src_width);
void ScaleAddRow_Any_SSE2(const uint8* src_ptr, uint16* dst_ptr, int src_width);
void ScaleAddRow_Any_AVX2(const uint8* src_ptr, uint16* dst_ptr, int src_width);
void ScaleFilterCols_SSSE3(uint8* dst_ptr, const uint8* src_ptr,
int dst_width, int x, int dx);
void ScaleColsUp2_SSE2(uint8* dst_ptr, const uint8* src_ptr,
int dst_width, int x, int dx);
// ARGB Column functions
void ScaleARGBCols_SSE2(uint8* dst_argb, const uint8* src_argb,
int dst_width, int x, int dx);
void ScaleARGBFilterCols_SSSE3(uint8* dst_argb, const uint8* src_argb,
int dst_width, int x, int dx);
void ScaleARGBColsUp2_SSE2(uint8* dst_argb, const uint8* src_argb,
int dst_width, int x, int dx);
void ScaleARGBFilterCols_NEON(uint8* dst_argb, const uint8* src_argb,
int dst_width, int x, int dx);
void ScaleARGBCols_NEON(uint8* dst_argb, const uint8* src_argb,
int dst_width, int x, int dx);
void ScaleARGBFilterCols_Any_NEON(uint8* dst_argb, const uint8* src_argb,
int dst_width, int x, int dx);
void ScaleARGBCols_Any_NEON(uint8* dst_argb, const uint8* src_argb,
int dst_width, int x, int dx);
// ARGB Row functions
void ScaleARGBRowDown2_SSE2(const uint8* src_argb, ptrdiff_t src_stride,
uint8* dst_argb, int dst_width);
void ScaleARGBRowDown2Linear_SSE2(const uint8* src_argb, ptrdiff_t src_stride,
uint8* dst_argb, int dst_width);
void ScaleARGBRowDown2Box_SSE2(const uint8* src_argb, ptrdiff_t src_stride,
uint8* dst_argb, int dst_width);
void ScaleARGBRowDown2_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleARGBRowDown2Linear_NEON(const uint8* src_argb, ptrdiff_t src_stride,
uint8* dst_argb, int dst_width);
void ScaleARGBRowDown2Box_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleARGBRowDown2_Any_SSE2(const uint8* src_argb, ptrdiff_t src_stride,
uint8* dst_argb, int dst_width);
void ScaleARGBRowDown2Linear_Any_SSE2(const uint8* src_argb,
ptrdiff_t src_stride,
uint8* dst_argb, int dst_width);
void ScaleARGBRowDown2Box_Any_SSE2(const uint8* src_argb, ptrdiff_t src_stride,
uint8* dst_argb, int dst_width);
void ScaleARGBRowDown2_Any_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleARGBRowDown2Linear_Any_NEON(const uint8* src_argb,
ptrdiff_t src_stride,
uint8* dst_argb, int dst_width);
void ScaleARGBRowDown2Box_Any_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleARGBRowDownEven_SSE2(const uint8* src_argb, ptrdiff_t src_stride,
int src_stepx, uint8* dst_argb, int dst_width);
void ScaleARGBRowDownEvenBox_SSE2(const uint8* src_argb, ptrdiff_t src_stride,
int src_stepx,
uint8* dst_argb, int dst_width);
void ScaleARGBRowDownEven_NEON(const uint8* src_argb, ptrdiff_t src_stride,
int src_stepx,
uint8* dst_argb, int dst_width);
void ScaleARGBRowDownEvenBox_NEON(const uint8* src_argb, ptrdiff_t src_stride,
int src_stepx,
uint8* dst_argb, int dst_width);
void ScaleARGBRowDownEven_Any_SSE2(const uint8* src_argb, ptrdiff_t src_stride,
int src_stepx,
uint8* dst_argb, int dst_width);
void ScaleARGBRowDownEvenBox_Any_SSE2(const uint8* src_argb,
ptrdiff_t src_stride,
int src_stepx,
uint8* dst_argb, int dst_width);
void ScaleARGBRowDownEven_Any_NEON(const uint8* src_argb, ptrdiff_t src_stride,
int src_stepx,
uint8* dst_argb, int dst_width);
void ScaleARGBRowDownEvenBox_Any_NEON(const uint8* src_argb,
ptrdiff_t src_stride,
int src_stepx,
uint8* dst_argb, int dst_width);
// ScaleRowDown2Box also used by planar functions
// NEON downscalers with interpolation.
// Note - not static due to reuse in convert for 444 to 420.
void ScaleRowDown2_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown2Linear_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown2Box_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown4_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown4Box_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
// Down scale from 4 to 3 pixels. Use the neon multilane read/write
// to load up the every 4th pixel into a 4 different registers.
// Point samples 32 pixels to 24 pixels.
void ScaleRowDown34_NEON(const uint8* src_ptr,
ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown34_0_Box_NEON(const uint8* src_ptr,
ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown34_1_Box_NEON(const uint8* src_ptr,
ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
// 32 -> 12
void ScaleRowDown38_NEON(const uint8* src_ptr,
ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
// 32x3 -> 12x1
void ScaleRowDown38_3_Box_NEON(const uint8* src_ptr,
ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
// 32x2 -> 12x1
void ScaleRowDown38_2_Box_NEON(const uint8* src_ptr,
ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown2_Any_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown2Linear_Any_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown2Box_Any_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown2Box_Odd_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown4_Any_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown4Box_Any_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown34_Any_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown34_0_Box_Any_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown34_1_Box_Any_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
// 32 -> 12
void ScaleRowDown38_Any_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
// 32x3 -> 12x1
void ScaleRowDown38_3_Box_Any_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
// 32x2 -> 12x1
void ScaleRowDown38_2_Box_Any_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleAddRow_NEON(const uint8* src_ptr, uint16* dst_ptr, int src_width);
void ScaleAddRow_Any_NEON(const uint8* src_ptr, uint16* dst_ptr, int src_width);
void ScaleFilterCols_NEON(uint8* dst_ptr, const uint8* src_ptr,
int dst_width, int x, int dx);
void ScaleFilterCols_Any_NEON(uint8* dst_ptr, const uint8* src_ptr,
int dst_width, int x, int dx);
void ScaleRowDown2_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown2Box_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown4_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown4Box_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown34_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown34_0_Box_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* d, int dst_width);
void ScaleRowDown34_1_Box_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* d, int dst_width);
void ScaleRowDown38_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst, int dst_width);
void ScaleRowDown38_2_Box_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
void ScaleRowDown38_3_Box_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
uint8* dst_ptr, int dst_width);
#ifdef __cplusplus
} // extern "C"
} // namespace libyuv
#endif
#endif // INCLUDE_LIBYUV_SCALE_ROW_H_
-16
View File
@@ -1,16 +0,0 @@
/*
* Copyright 2012 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_VERSION_H_
#define INCLUDE_LIBYUV_VERSION_H_
#define LIBYUV_VERSION 1622
#endif // INCLUDE_LIBYUV_VERSION_H_
-184
View File
@@ -1,184 +0,0 @@
/*
* Copyright 2011 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Common definitions for video, including fourcc and VideoFormat.
#ifndef INCLUDE_LIBYUV_VIDEO_COMMON_H_
#define INCLUDE_LIBYUV_VIDEO_COMMON_H_
#include "libyuv/basic_types.h"
#ifdef __cplusplus
namespace libyuv {
extern "C" {
#endif
//////////////////////////////////////////////////////////////////////////////
// Definition of FourCC codes
//////////////////////////////////////////////////////////////////////////////
// Convert four characters to a FourCC code.
// Needs to be a macro otherwise the OS X compiler complains when the kFormat*
// constants are used in a switch.
#ifdef __cplusplus
#define FOURCC(a, b, c, d) ( \
(static_cast<uint32>(a)) | (static_cast<uint32>(b) << 8) | \
(static_cast<uint32>(c) << 16) | (static_cast<uint32>(d) << 24))
#else
#define FOURCC(a, b, c, d) ( \
((uint32)(a)) | ((uint32)(b) << 8) | /* NOLINT */ \
((uint32)(c) << 16) | ((uint32)(d) << 24)) /* NOLINT */
#endif
// Some pages discussing FourCC codes:
// http://www.fourcc.org/yuv.php
// http://v4l2spec.bytesex.org/spec/book1.htm
// http://developer.apple.com/quicktime/icefloe/dispatch020.html
// http://msdn.microsoft.com/library/windows/desktop/dd206750.aspx#nv12
// http://people.xiph.org/~xiphmont/containers/nut/nut4cc.txt
// FourCC codes grouped according to implementation efficiency.
// Primary formats should convert in 1 efficient step.
// Secondary formats are converted in 2 steps.
// Auxilliary formats call primary converters.
enum FourCC {
// 9 Primary YUV formats: 5 planar, 2 biplanar, 2 packed.
FOURCC_I420 = FOURCC('I', '4', '2', '0'),
FOURCC_I422 = FOURCC('I', '4', '2', '2'),
FOURCC_I444 = FOURCC('I', '4', '4', '4'),
FOURCC_I411 = FOURCC('I', '4', '1', '1'),
FOURCC_I400 = FOURCC('I', '4', '0', '0'),
FOURCC_NV21 = FOURCC('N', 'V', '2', '1'),
FOURCC_NV12 = FOURCC('N', 'V', '1', '2'),
FOURCC_YUY2 = FOURCC('Y', 'U', 'Y', '2'),
FOURCC_UYVY = FOURCC('U', 'Y', 'V', 'Y'),
// 2 Secondary YUV formats: row biplanar.
FOURCC_M420 = FOURCC('M', '4', '2', '0'),
FOURCC_Q420 = FOURCC('Q', '4', '2', '0'), // deprecated.
// 9 Primary RGB formats: 4 32 bpp, 2 24 bpp, 3 16 bpp.
FOURCC_ARGB = FOURCC('A', 'R', 'G', 'B'),
FOURCC_BGRA = FOURCC('B', 'G', 'R', 'A'),
FOURCC_ABGR = FOURCC('A', 'B', 'G', 'R'),
FOURCC_24BG = FOURCC('2', '4', 'B', 'G'),
FOURCC_RAW = FOURCC('r', 'a', 'w', ' '),
FOURCC_RGBA = FOURCC('R', 'G', 'B', 'A'),
FOURCC_RGBP = FOURCC('R', 'G', 'B', 'P'), // rgb565 LE.
FOURCC_RGBO = FOURCC('R', 'G', 'B', 'O'), // argb1555 LE.
FOURCC_R444 = FOURCC('R', '4', '4', '4'), // argb4444 LE.
// 4 Secondary RGB formats: 4 Bayer Patterns. deprecated.
FOURCC_RGGB = FOURCC('R', 'G', 'G', 'B'),
FOURCC_BGGR = FOURCC('B', 'G', 'G', 'R'),
FOURCC_GRBG = FOURCC('G', 'R', 'B', 'G'),
FOURCC_GBRG = FOURCC('G', 'B', 'R', 'G'),
// 1 Primary Compressed YUV format.
FOURCC_MJPG = FOURCC('M', 'J', 'P', 'G'),
// 5 Auxiliary YUV variations: 3 with U and V planes are swapped, 1 Alias.
FOURCC_YV12 = FOURCC('Y', 'V', '1', '2'),
FOURCC_YV16 = FOURCC('Y', 'V', '1', '6'),
FOURCC_YV24 = FOURCC('Y', 'V', '2', '4'),
FOURCC_YU12 = FOURCC('Y', 'U', '1', '2'), // Linux version of I420.
FOURCC_J420 = FOURCC('J', '4', '2', '0'),
FOURCC_J400 = FOURCC('J', '4', '0', '0'), // unofficial fourcc
FOURCC_H420 = FOURCC('H', '4', '2', '0'), // unofficial fourcc
// 14 Auxiliary aliases. CanonicalFourCC() maps these to canonical fourcc.
FOURCC_IYUV = FOURCC('I', 'Y', 'U', 'V'), // Alias for I420.
FOURCC_YU16 = FOURCC('Y', 'U', '1', '6'), // Alias for I422.
FOURCC_YU24 = FOURCC('Y', 'U', '2', '4'), // Alias for I444.
FOURCC_YUYV = FOURCC('Y', 'U', 'Y', 'V'), // Alias for YUY2.
FOURCC_YUVS = FOURCC('y', 'u', 'v', 's'), // Alias for YUY2 on Mac.
FOURCC_HDYC = FOURCC('H', 'D', 'Y', 'C'), // Alias for UYVY.
FOURCC_2VUY = FOURCC('2', 'v', 'u', 'y'), // Alias for UYVY on Mac.
FOURCC_JPEG = FOURCC('J', 'P', 'E', 'G'), // Alias for MJPG.
FOURCC_DMB1 = FOURCC('d', 'm', 'b', '1'), // Alias for MJPG on Mac.
FOURCC_BA81 = FOURCC('B', 'A', '8', '1'), // Alias for BGGR.
FOURCC_RGB3 = FOURCC('R', 'G', 'B', '3'), // Alias for RAW.
FOURCC_BGR3 = FOURCC('B', 'G', 'R', '3'), // Alias for 24BG.
FOURCC_CM32 = FOURCC(0, 0, 0, 32), // Alias for BGRA kCMPixelFormat_32ARGB
FOURCC_CM24 = FOURCC(0, 0, 0, 24), // Alias for RAW kCMPixelFormat_24RGB
FOURCC_L555 = FOURCC('L', '5', '5', '5'), // Alias for RGBO.
FOURCC_L565 = FOURCC('L', '5', '6', '5'), // Alias for RGBP.
FOURCC_5551 = FOURCC('5', '5', '5', '1'), // Alias for RGBO.
// 1 Auxiliary compressed YUV format set aside for capturer.
FOURCC_H264 = FOURCC('H', '2', '6', '4'),
// Match any fourcc.
FOURCC_ANY = -1,
};
enum FourCCBpp {
// Canonical fourcc codes used in our code.
FOURCC_BPP_I420 = 12,
FOURCC_BPP_I422 = 16,
FOURCC_BPP_I444 = 24,
FOURCC_BPP_I411 = 12,
FOURCC_BPP_I400 = 8,
FOURCC_BPP_NV21 = 12,
FOURCC_BPP_NV12 = 12,
FOURCC_BPP_YUY2 = 16,
FOURCC_BPP_UYVY = 16,
FOURCC_BPP_M420 = 12,
FOURCC_BPP_Q420 = 12,
FOURCC_BPP_ARGB = 32,
FOURCC_BPP_BGRA = 32,
FOURCC_BPP_ABGR = 32,
FOURCC_BPP_RGBA = 32,
FOURCC_BPP_24BG = 24,
FOURCC_BPP_RAW = 24,
FOURCC_BPP_RGBP = 16,
FOURCC_BPP_RGBO = 16,
FOURCC_BPP_R444 = 16,
FOURCC_BPP_RGGB = 8,
FOURCC_BPP_BGGR = 8,
FOURCC_BPP_GRBG = 8,
FOURCC_BPP_GBRG = 8,
FOURCC_BPP_YV12 = 12,
FOURCC_BPP_YV16 = 16,
FOURCC_BPP_YV24 = 24,
FOURCC_BPP_YU12 = 12,
FOURCC_BPP_J420 = 12,
FOURCC_BPP_J400 = 8,
FOURCC_BPP_H420 = 12,
FOURCC_BPP_MJPG = 0, // 0 means unknown.
FOURCC_BPP_H264 = 0,
FOURCC_BPP_IYUV = 12,
FOURCC_BPP_YU16 = 16,
FOURCC_BPP_YU24 = 24,
FOURCC_BPP_YUYV = 16,
FOURCC_BPP_YUVS = 16,
FOURCC_BPP_HDYC = 16,
FOURCC_BPP_2VUY = 16,
FOURCC_BPP_JPEG = 1,
FOURCC_BPP_DMB1 = 1,
FOURCC_BPP_BA81 = 8,
FOURCC_BPP_RGB3 = 24,
FOURCC_BPP_BGR3 = 24,
FOURCC_BPP_CM32 = 32,
FOURCC_BPP_CM24 = 24,
// Match any fourcc.
FOURCC_BPP_ANY = 0, // 0 means unknown.
};
// Converts fourcc aliases into canonical ones.
LIBYUV_API uint32 CanonicalFourCC(uint32 fourcc);
#ifdef __cplusplus
} // extern "C"
} // namespace libyuv
#endif
#endif // INCLUDE_LIBYUV_VIDEO_COMMON_H_
+1
View File
@@ -0,0 +1 @@
larch64/
@@ -1 +0,0 @@
#include "export_core.hpp"
@@ -1 +0,0 @@
#include "layer_parameter.hpp"
@@ -1 +0,0 @@
#include "map.hpp"
@@ -1 +0,0 @@
#include "qmaplibre"
@@ -1 +0,0 @@
#include "settings.hpp"
@@ -1 +0,0 @@
#include "source_parameter.hpp"
@@ -1 +0,0 @@
#include "style_parameter.hpp"
@@ -1 +0,0 @@
#include "types.hpp"
@@ -1 +0,0 @@
#include "utils.hpp"

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