diff --git a/CLAUDE.md b/CLAUDE.md index edb7331..3f04eb2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -228,12 +228,14 @@ A single `session.log` in each session directory records major events: - **Codec**: H.264 AVC (hardware accelerated via `OMX.qcom.video.encoder.avc`) - **Resolution**: 1928x1208 (full camera resolution, no downscaling) -- **Bitrate**: 4 Mbps -- **Container**: MP4 (remuxed via libavformat) +- **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.mp4` -- **Standstill timeout**: suspends recording after 10 minutes of standstill, resumes when car moves -- **Storage**: ~90 MB per 3-minute segment, ~43 hours of footage in 78 GB free space +- **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**: starts recording on launch with 10-min idle timer; car in drive cancels timer; park/off restarts timer; ignition cycle = new trip +- **Graceful shutdown**: thermald sets `DashcamShutdown` param, dashcamd closes segment and acks within 15s +- **Storage**: ~56 MB per 3-minute segment at 2500 kbps - **Storage device**: WDC SDINDDH4-128G UFS 2.1 — automotive grade, ~384 TB write endurance, no concern for continuous writes ### Key Differences from Old Screen Recorder @@ -254,13 +256,13 @@ A single `session.log` in each session directory records major events: | `selfdrive/clearpilot/SConscript` | Build config for dashcamd | | `selfdrive/frogpilot/screenrecorder/omx_encoder.cc` | OMX encoder (added `encode_frame_nv12` method) | | `selfdrive/frogpilot/screenrecorder/omx_encoder.h` | Encoder header | -| `selfdrive/manager/process_config.py` | dashcamd registered as NativeProcess, encoderd disabled | -| `system/loggerd/deleter.py` | Storage rotation (9 GB threshold, oldest videos deleted first) | +| `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 - `DashcamDebug` — when `"1"`, dashcamd runs even without car connected (for bench testing) -- `IsDriverViewEnabled` — must be `"1"` to start camerad on bench (no car ignition) +- `DashcamShutdown` — set by thermald before power-off, dashcamd acks by clearing it ## Standstill Power Saving @@ -279,63 +281,88 @@ When `carState.standstill` is true: | `selfdrive/thermald/fan_controller.py` | Standstill-aware fan clamps | | `selfdrive/thermald/thermald.py` | Passes standstill to fan controller via carState | -## Debug Function Button (LFA/LKAS Steering Wheel Button) +## Display Modes (LFA/LKAS Debug Button) -The Hyundai Tucson's LFA (Lane Following Assist) steering wheel button is repurposed as a general-purpose UI control button. It has no driving function in ClearPilot since lateral control is disabled. +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) + +### 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 message: cruise_btns_msg_canfd["LFA_BTN"] - [selfdrive/car/hyundai/carstate.py:332-339] - -> Edge detection: lkas_enabled vs lkas_previously_enabled - -> create_button_events() -> ButtonEvent(type=FrogPilotButtonType.lkas) - [selfdrive/car/hyundai/interface.py:168] - -> controlsd.update_clearpilot_events(CS) - [selfdrive/controls/controlsd.py:1235-1239] - -> events.add(EventName.clpDebug) - -> controlsd.clearpilot_state_control(CC, CS) - [selfdrive/controls/controlsd.py:1241-1258] - -> Toggles ScreenDisaplayMode param (0=on, 1=off) in /dev/shm/params - -> UI reads ScreenDisaplayMode in drawHud() - [selfdrive/ui/qt/onroad.cc:390-403] - -> mode=1 and no alert: Hardware::set_display_power(false) - -> mode=0 or alert visible: Hardware::set_display_power(true) + -> 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) ``` -### Current Behavior - -- Each press toggles the display on/off instantly (debug alert suppressed) -- `ScreenDisaplayMode` is in-memory params (`/dev/shm/params`), resets on reboot -- `max_display_mode = 1` — currently only two states (on/off); can be extended for future modes - ### Key Files | File | Role | |------|------| -| `selfdrive/car/hyundai/carstate.py` | Reads LFA_BTN from CAN-FD | -| `selfdrive/car/hyundai/interface.py` | Creates ButtonEvent with FrogPilotButtonType.lkas | -| `selfdrive/controls/controlsd.py` | Fires clpDebug event, toggles ScreenDisaplayMode | -| `selfdrive/controls/lib/events.py` | clpDebug event definition (alert suppressed) | -| `selfdrive/ui/qt/onroad.cc` | Reads ScreenDisaplayMode, controls display power | +| `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 — `setAwake(s.scene.ignition || interactive_timeout > 0)` means ignition=true always keeps the screen awake. The FrogPilot `ScreenTimeoutOnroad` param (default 10s) has no effect because ignition being true short-circuits the timeout check. -- **Debug button (LFA)**: the only way to turn off the screen while driving. Toggles `ScreenDisaplayMode` param which is checked in `drawHud()` (onroad) and `updateState()` (park splash). Independent of the timeout system. +- **Ignition on (onroad)**: screen stays on unconditionally — ignition=true short-circuits the timeout check. +- **Debug button (LFA)**: cycles through display modes including screen off (state 3). Only state 3 calls `Hardware::set_display_power(false)`. -## Offroad UI +## Offroad UI (ClearPilot Menu) -The offroad home screen (`selfdrive/ui/qt/home.cc`) was replaced with a clean grid launcher. Stock FrogPilot widgets (date, version, update/alert notifications) were removed. +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. -- **Settings button**: opens the original comma/FrogPilot settings (backdoor to all original settings) -- **Dashcam button**: placeholder for future dashcam footage viewer -- Tapping the splash screen (ReadyWindow) goes directly to the grid launcher (no sidebar) -- Sidebar with metrics (TEMP, VEHICLE, CONNECT) is hidden but still accessible via settings path +### 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