Fan control rework (thermald → 4Hz):
- DT_TRML 0.5s → 0.25s (thermald loop + fan PID now at 4Hz)
- New clamp rules based on (gear, cruise_engaged, standstill):
parked → 0-100%
in drive + cruise engaged (any speed) → 30-100%
in drive + cruise off + standstill → 10-100%
in drive + cruise off + moving → 30-100%
- thermald now reads gearShifter (via carState) and controlsState.enabled,
passes them to fan_controller.update()
- Removed BENCH_MODE special case — new rules cover bench automatically
- Removed ignition-based branches — gear is the correct signal
System health overlay:
- Subscribed UI to peripheralState so we can read fanSpeedRpm
- Added FAN row: actual fan% (RPM / 65) to sit alongside LAG/DROP/TEMP/CPU/MEM.
Shows the real fan output vs. what the PID is asking for.
Migrate hot signals from paramsMemory to cereal (frogpilotCarControl):
- Added latRequested @3 and noLatLaneChange @4 to FrogPilotCarControl schema
- controlsd sets FPCC.latRequested / FPCC.noLatLaneChange (send-on-change
already gates the IPC)
- modeld reads from sm['frogpilotCarControl'] (added to its subscribers)
instead of paramsMemory (saves ~20 file-read syscalls/sec)
- carcontroller reads from frogpilot_variables (set in-process by controlsd)
instead of paramsMemory (saves ~100 file-read syscalls/sec in 100Hz path).
Dropped carcontroller's now-unused Params instance and import.
- UI (ui.cc, onroad.cc) reads from sm['frogpilotCarControl'].noLatLaneChange
- Removed LatRequested and no_lat_lane_change param registrations + defaults
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously ran unpinned (affinity mask 0xff) across all 8 cores. When it
landed on core 4 (controlsd) or 5 (plannerd/radard) or 7 (modeld), its
70MB/s frame copies and MP4 muxing caused cache/memory-bandwidth
contention with the RT-pinned processes. SCHED_FIFO prevented direct
preemption but not the cache thrash.
OMX offloads actual H.264 work to hardware so the main thread is
lightweight — fine on the little cluster.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
dashcamd now waits for valid system time + GPS fix + drive gear before
starting a trip. Returns to waiting state on 10-min park timeout or
ignition off. Publishes DashcamState and per-trip DashcamFrames to
memory params. Status window shows stopped/waiting/recording states.
Updated CLAUDE.md with current display mode behavior, OmxEncoder port
details, speed limit warning thresholds, and dashcam param docs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- OMX_Init/OMX_Deinit managed per encoder instance lifecycle
- Proper error handling in constructor, encoder_open, encoder_close
- Null guards on done_out.pop() and handle in destructor
- Codec config written directly to codecpar (no codec_ctx)
- ffmpeg faststart remux on segment close
- Crash handler in dashcamd for diagnostics
- DashcamFrames param for live frame count in status window
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Reset OMX subsystem (Deinit/Init) on dashcamd startup to clear stale
encoder state from previous unclean exits
- Validate OMX output buffers before memcpy to prevent segfault
- Validate VisionBuf frame data before encoding
- Add dashcam row to status window showing recording state and disk usage
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- modeld: enter standby when latActive=false (not just standstill),
exception for lane changes (no_lat_lane_change). Fix Python capnp
property access (.latActive not getLatActive())
- controlsd: move model_suppress computation early, suppress radarFault,
posenetInvalid, locationdTemporaryError, paramsdTemporaryError during
model standby + 2s grace period. All cascade from modeld not publishing
- dashcamd: always_run (manages own trip lifecycle), wait for valid frame
dimensions before encoding (fix SIGSEGV on early start)
- Fan: driving range 15-100% (was 30-100%)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Each MP4 segment gets a companion .srt file with 1Hz entries containing
speed (MPH), lat/lon coordinates, and UTC timestamp from gpsLocation
cereal messages. Falls back to "No GPS" when fix is unavailable.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dashcam recording now organized by trip in /data/media/0/videos/YYYYMMDD-HHMMSS/.
Starts recording immediately on launch (with 10-min idle timer), transitions to
continuous recording when drive gear detected. New trip on every ignition cycle.
Graceful shutdown via DashcamShutdown param with 15s ack timeout in thermald.
- Bitrate reduced to 2500 kbps (was 4 Mbps)
- Trip state machine: IDLE → RECORDING ↔ IDLE_TIMEOUT → TRIP_ENDED
- Deleter: trip-aware deletion (oldest trip first, then segments within active trip)
- camerad changed to always_run (was driverview) so dashcam works offroad
- DashcamShutdown param for graceful close before device power-off
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New dashcamd: connects to camerad via VisionIPC, feeds raw NV12
frames directly to OMX H.264 encoder. Full 1928x1208 resolution,
4Mbps, 3-minute MP4 segments. Works regardless of UI state.
- Added encode_frame_nv12() to OmxEncoder — skips RGBA->NV12 conversion
- Suspends recording after 10 minutes of standstill
- Disabled old screen recorder timer in onroad.cc
- Suppress debug button alert (clpDebug event still fires for screen toggle)
- launch_openpilot.sh self-cleans other instances before starting
- Register DashcamDebug param in params.cc and manager.py
- Add dashcamd to build system (SConscript) and process_config
- Updated CLAUDE.md with all session changes
- Added GOALS.md feature roadmap
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>