Architecture note

The Brightness carousel in Image adjustment currently routes to ExposureController → EXPOSURE_SET, which controls thermal sensor gain. Display backlight brightness is a separate hardware path managed by display-controller → DISPLAY_BRIGHTNESS_REQ. These two items need to be split into separate menu entries before wiring up the real services.

Integration map — stub → target service
flex_kneron_ui component
Artosyn service
ExposureController (stub) — brightness / contrast / sharpness
internal (VMF ISP params) thermal-parameters-controller N/A — CMOS sensor, not thermal
ZoomController (stub) — zoom level
view-controller permanent mode only — no viewport switching
RecordingController (stub) — record / snapshot
video-controller
AttitudeController (not yet impl) — pitch / roll
position-service currently internal — may migrate to external
InfobarWidget — battery level
custom battery_controller (×2 I²C) reference: Thor_LTV_gen2/battery_controller — Artosyn battery-service N/A (ADC-based)
InfobarWidget — stadiametric range
internal calculation peripheral-device-controller N/A — no hardware LRF / laser on Kneron
ReticleWidget — reticle type / color / position
internal / TBD general-device-controller almost N/A — CMOS device has different feature set
Brightness (display) — new menu item needed
display-controller ⚠ currently merged with sensor brightness — needs split
All controllers — persistent settings
settings-controller
ButtonServer (mock UDP) — physical button input
buttons-general-service
App lifecycle — startup readiness ping
atn-init
Menu open state → publish USER_ACTIVITY
inactivity_controller
Service catalog
High / fully applicable — 3 services
high
buttons-general-service
Listener IPC evdev
Reads Linux evdev input events for physical buttons (UP=103, DOWN=108, LEFT=105, RIGHT=106, SET=28, POWER=1, LPLRF=109), decodes short / long / release sequences, and publishes on the Listener IPC bus.
BUTTON_PRESSED BUTTON_LONG_PRESSED BUTTON_LONG_RELEASED
Replaces: the UDP ButtonServer mock in HOST_MOCK builds — on the real device all physical button events arrive here.
high
video-controller
Listener IPC Unix sockets
Captures MJPEG photos and H.264 video from Unix sockets (/run/jpeg.sock, /run/h264.sock), transcodes to JPEG/MP4, and implements RAV (recoil-activated video) ring-buffer recording.
RECORD_TOGGLE SNAPSHOT SHOW_VIDEO_WIDGET VIDEO_WIDGET_TIME RAV_ICON_VISIBILITY
Replaces: RecordingController stub — RECORD_TOGGLE and SNAPSHOT route here; recording state events come back for the infobar.
high
settings-controller
Listener IPC NVS / UBIFS
Persistent NVS storage using JSON/XML with CRC validation. Accepts value writes and commit commands, and broadcasts all settings on startup so services can restore their last state without extra reads.
SETTINGS_NVS_VALUE_SETUP SETTINGS_NVS_COMMIT SETTINGS_NVS_BROADCAST
Wires to: every carousel controller — values written via menu must persist across reboots through this service at /mnt/flash/settings.json (UBIFS).
Partial / adapt — 4 services (hardware layer changes needed)
partial
view-controller
Listener IPC
In TTM18 manages multiple viewport modes (clip-on, monocular, weapon scope, PIP) and digital zoom. On Kneron there is a single permanent viewport mode — no mode switching needed. Digital zoom and sensor crop/window management still apply.
ZOOM_LEVEL_REQ EXTENDED_CHANNEL_WINDOW_SET VIEWPORT_MODE_REQ PIP_MODE_REQ
Kneron: use in permanent-mode configuration for zoom and sensor crop/window management only. Viewport switching and PIP are unused. ZoomController stub connects here for ZOOM_LEVEL_REQ.
partial
display-controller
Listener IPC
Maps user-facing brightness levels to hardware backlight commands and persists via settings-controller. The Kneron device uses a different display than TTM18, so the hardware command layer needs a new driver. The IPC interface and level-to-percentage mapping logic are reusable.
DISPLAY_BRIGHTNESS_REQ DISPLAY_BRIGHTNESS_SETUP
Kneron: keep Listener IPC interface and settings-controller integration; replace hardware back-end with KL730 display driver sysfs/ioctl. Needs a new display driver before validation. See arch note re: sensor-vs-display brightness split.
internal / tbd
position-service
Listener IPC IMU I²C
Reads accelerometer + magnetometer, computes pitch / roll / yaw via sensor fusion and ellipsoid calibration, publishes angle values. Also detects recoil / shot trigger events. Currently: pitch/roll is implemented internally in flex_kneron_ui (AttitudeController stub). Whether to migrate to this external service depends on the KL730 board's IMU chip.
PITCH_ANGLE ROLL_ANGLE YAW_ANGLE SHOT_TRIGGER
Decision pending: if KL730 board has a compatible IMU (LSM303AGR or similar), migrate AttitudeController to subscribe here and remove internal IMU code. If the IMU chip differs significantly, keep internal implementation.
applicable
inactivity_controller
Listener IPC
Monitors buttons, IMU shake-n-wake, recording state, and USB connection to detect inactivity. Triggers SLEEP_MODE_ACTIVATION and auto-SHUTDOWN after configurable timeouts. Applicable on Kneron — auto-shutdown is useful even if sleep mode is disabled; the two timers are independently configurable.
SLEEP_MODE_ACTIVATION SHUTDOWN USER_ACTIVITY
Integration: flex_kneron_ui publishes USER_ACTIVITY while the menu is open — inhibits the inactivity timer. Recording and menu are fully independent: entering the menu must not touch recording state. The recording-inhibit signal is owned by video-controller, not the UI.
Custom implementation — 1 service (Artosyn N/A, use Thor_LTV_gen2 as reference)
custom impl
battery-service
Listener IPC I²C × 2
The Artosyn battery-service uses raw sysfs ADC + lookup tables — not applicable on Kneron. Kneron carries two smart battery packs, each with its own I²C gauge (addr 0x55 on separate buses). Reference implementation: Thor_LTV_gen2/battery_controller — reads SOC% with temperature compensation every 500 ms and publishes CHARGE_LEVEL + USB_CHARGING_ON via UDP. That architecture must be ported and extended for dual-pack support and Listener IPC output.
CHARGE_LEVEL USB_CHARGING_ON SHUTDOWN
Action: write atn-battery-controller based on Thor_LTV_gen2/battery_controller. Extend for two I²C packs; merge SOC% to a single infobar value; publish on Listener IPC bus so inactivity_controller can trigger auto-shutdown at low battery.
Reference only — 1 service
reference
atn-init
Listener IPC POSIX signals
PID-1 process manager: JSON-driven staged startup, watchdog with auto-restart, and coordinated shutdown. Uses a ping-based readiness protocol so the supervisor knows each service is alive before advancing to the next stage.
INIT_PING_CAST INIT_PING_REPLY INIT_READY_BROADCAST
Use as reference when designing the Kneron startup sequence. flex_kneron_ui should respond to INIT_PING_CAST with INIT_PING_REPLY to participate in supervised startup and auto-restart. Not yet wired.
Not applicable — 3 services (Kneron hardware incompatible)
not applicable
thermal-parameters-controller
Listener IPC
Manages Artosyn thermal sensor parameters — sensitivity, NUC, color palettes, high/low red thresholds — all thermal-specific concepts. The Artosyn codebase uses thermal_vin_service (ThermalPipeline) as the actual data source. Kneron uses a Sony IMX662 STARVIS 2 day/night CMOS sensor — no thermal core, no NUC, no palette selection. ISP parameters (brightness, contrast, sharpness) are set directly via VMF ISP API.
THERMAL_CONTRAST_REQ THERMAL_NUC_REQ COLOR_PALETTE_REQ
Kneron: ExposureController stub routes directly to VMF ISP control. Sensor pipeline is completely different — thermal service provides no applicable code or architecture.
not applicable
peripheral-device-controller
Listener IPC serial + GPIO
In TTM18 controls a hardware LRF (serial + GPIO) and laser pointer (GPIO). No hardware LRF or laser pointer on Kneron — ranging uses the stadiametric algorithm (pure software, no serial/GPIO). This service has no applicable hardware layer and is not a useful reference for stadiametric output.
LRF_DISTANCE LASER_POINTER_STATE
Kneron: stadiametric distance is computed internally and shown in InfobarWidget. No peripheral controller needed.
almost N/A
general-device-controller
Listener IPC
In TTM18 this is the central hub for: operation modes (thermal/fusion/NV), reticle selection, ballistics POI markers, grid overlays, LRF zeroing, weapon sight zeroing, ballistics trajectory, bad pixel correction (BPC), and firmware update. Almost all features are thermal- or ballistics-specific and do not exist on the Kneron CMOS day/night device. The only reusable pattern — *_REQ / *_COMMIT NVS persistence — is already covered by settings-controller.
OPERATION_MODE_REQ BPC_REQ BALLISTICS_POI_REQ FIRMWARE_UPDATE_REQ
Kneron: do not use this service. Reticle and device-level config go through settings-controller with internal controllers.