fwt_software/docs/modules-reference.md

12 KiB
Raw Blame History

Module Reference

Per-file reference for the refactored tree, plus the shared data structures.

Core (fgc_core — SDK-independent, unit-tested)

File Contents
include/fgc/Config.h, src/core/Config.cpp Typed AppConfig (General/Network/Serial/Camera/Paths/Features/Logging/UI/Motor/Scan/IMU) + ConfigLoader (INI parse, env overrides, validation)
include/fgc/Paths.h, src/core/Paths.cpp ~/$ENV expansion, executable dir, config search order, default output dir
include/fgc/Logger.h, src/core/Logger.cpp Leveled, thread-safe logger + per-category wire trace; LOG_TRACE..LOG_ERROR, LOG_TRACE_CAT
include/fgc/Geometry.h, src/core/Geometry.cpp Per-axis degrees↔encoder-counts affine map ([Motor] calibration)
include/fgc/ScanGrid.h, src/core/ScanGrid.cpp Capture waypoints (CSV or generated) + ping-pong cursor ([Scan])
include/fgc/TelemetryParser.h, src/core/TelemetryParser.cpp parseTelemetryLine (firmware ST line) → std::optional<MotorTelemetry>
include/fgc/CommandParser.h, src/core/CommandParser.cpp parseCommand whitespace tokenizer → Command
include/fgc/HelpText.h, src/core/HelpText.cpp Operator command catalog (helpCatalog) + renderHelp (console & TUI help)
include/fgc/DumpParser.h, src/core/DumpParser.cpp parseDump firmware DUMP block → DumpData (per-axis state + decoded TMC registers/flags); formatDump
include/fgc/DiagParser.h, src/core/DiagParser.cpp parseDiag firmware DG self-test stream → DiagResult (per-axis tests, PASS/FAIL); formatDiag
include/fgc/Calibration.h, src/core/Calibration.cpp linearFit (least-squares, R²) + circularMeanDeg for the IMU-referenced calibration
include/fgc/CalibrationRoutine.h, src/core/CalibrationRoutine.cpp gimbal calib worker thread: home-if-needed → pitch sweep at the first yaw position → pitch 0° → switch IMU to a no-mag XKF profile → IMU no-rotation + heading reset → yaw sweep, fitting degrees↔counts; tunable via CalibParams; exposes progress()/report()/takeResult()
include/fgc/MtiProtocol.h, src/core/MtiProtocol.cpp Xsens MTi binary protocol: MtiFramer (checksum framing), config-message builders, parseMTDataImuSample (temp/acc/gyr/mag/euler), config-readback query builders + applyImuConfigAck/finalizeImuConfigImuDeviceConfig (product/firmware/device-id/output mode+settings/sample rate/XKF scenario); orientation-control builders msgSetNoRotation (gyro-bias update) + msgResetOrientation (heading reset / store) + msgSetFilterProfile (select XKF profile) + pickNoMagProfile (choose a magnetometer-free profile from the available list)
include/fgc/sensors/Sht41Protocol.h, src/sensors/Sht41Protocol.cpp Sensirion SHT4x wire protocol, pure: command bytes, sht41Crc8 (poly 0x31/init 0xFF), decodeSht41Measurement (6-byte response → Sht41Reading, CRC-checked, raw→°C/%RH with RH clamped 0..100)
include/fgc/CaptureScheduler.h, src/core/CaptureScheduler.cpp Capture state machine over the interfaces; injectable clock; setGeometry adopts a recalibration
include/fgc/Application.h, src/core/Application.cpp Factory (real vs mock, headless vs TUI), wiring, control loop, gimbal … commands, background-result polling, buildSnapshot()
include/fgc/ui/UiSnapshot.h, src/ui/UiSnapshot.cpp Plain-data view model (incl. ImuView, EnvView, ActivityView, CalibResultView, DumpView) + pure formatting helpers (state label/colour, degrees, time-ago, pending-sensors)
include/fgc/ui/HeadlessUi.h, src/ui/HeadlessUi.cpp Default line console: stdin → command sink; logs via the default stdout/stderr writer
ini.c, ini.h Bundled third-party inih INI parser

Interfaces

File Interface Shared structs
include/fgc/IMotorController.h IMotorController MotorTelemetry
include/fgc/IControlChannel.h IControlChannel ControlCommand, CamEvent, EnvEvent
include/fgc/ICameraSource.h ICameraSource Frame
include/fgc/IImuSource.h IImuSource (incl. config(), refreshConfig(), noRotation(), headingReset(), setFilterProfile()) ImuSample (from MtiProtocol.h)
include/fgc/IEnvSensor.h IEnvSensor (connected(), sample(), name()) EnvSample
include/fgc/ui/IUserInterface.h IUserInterface UiSnapshot

Real implementations (SDK-gated)

File Implements Built when
src/serial/SerialMotorController.cpp IMotorController over Boost.Asio serial (pImpl) always
src/serial/MtiImuSource.cpp IImuSource over Boost.Asio serial: configures the MTi to Euler+calibrated, reads back its config (config()ImuDeviceConfig), then frames the MTData stream always
src/sensors/I2cBus.cpp Thin /dev/i2c-N wrapper (open/close, write, writeRead via I2C_SLAVE ioctl) always
src/sensors/Sht41EnvSensor.cpp IEnvSensor over I2C (pImpl): soft-reset, poll thread at [Env] period_ms, decode via Sht41Protocol, staleness = no valid sample within 2× the period always
src/mqtt/MqttControlChannel.cpp IControlChannel over Eclipse Paho WITH_MQTT
src/ui/TuiUi.cpp IUserInterface over FTXUI: panels, key bar, log pane WITH_TUI
src/camera/VimbaCameraSource.cpp ICameraSource over Vimba X (pImpl) WITH_VIMBA
src/camera/JpegXlEncoder.cpp libjxl encode-to-file always
src/camera/ImagePipeline.cpp frame → rotate → encode → write → CamEvent (worker thread) always

Mock / null implementations

File Implements
include/fgc/mock/MockMotorController.h Simulated sweeping gimbal (incl. canned DUMP)
include/fgc/mock/NullControlChannel.h No-op channel; auto-sweep
include/fgc/mock/MockCameraSource.h Synthetic gradient frames
include/fgc/mock/MockImuSource.h Synthetic IMU (sinusoidal orientation, gravity on accZ)
include/fgc/mock/MockEnvSensor.h Synthetic ambient sensor (slow sinusoidal temp/humidity, never stale); --mock-env

Entry point & scripts

File Role
main.cpp CLI parsing → AppConfig + RuntimeOptionsApplication::run()
scripts/run.sh Path-independent launcher
scripts/fire-gimbal-control.service systemd unit template

Data structures

MotorTelemetry / AxisTelemetry (IMotorController.h)

Per-axis yaw and pitch segments (pitch_present flag), each an AxisTelemetry: state (AxisState B/R/H/A/E), xactual, xenc (encoder counts), drv_status, sg/cs/pwm, and flags standstill/stall/overtemp/endstop_l/endstop_r, with moving()/ready() helpers. Parsed from the firmware ST Y:...[ P:...] line; degrees are derived via Geometry.

ControlCommand (IControlChannel.h)

control_code (0 = scan-grid sweep, 1 = directed to target_HDG) + target_heading, each with an *_available flag.

CamEvent (IControlChannel.h)

tower, camera (RGB/ACR/NIR), heading_decideg (yaw×10), pitch_decideg (pitch×10), timestamp_ms. Serialized to the CamEvent JSON payload (see mqtt-api.md).

EnvEvent (IControlChannel.h)

tower, temp_c, humidity_pct, timestamp_ms. Published once per fresh sample (deduplicated on timestamp_ms, not per control-loop tick) to the Env topic — see mqtt-api.md.

EnvSample (IEnvSensor.h)

One ambient reading: valid, temp_c (°C), humidity_pct (0..100), timestamp_ms (epoch ms). IEnvSensor::sample() returns nullopt rather than a stale sample once nothing valid has arrived within 2× the configured poll period, so a silently dead sensor reads as absent, not as a frozen value. Surfaced as EnvView in the TUI (i view) and as SensorsView::env in the compact panel.

Frame (ICameraSource.h)

Owned pixel buffer + width, height, channels (1 or 3), timestamp_ms, cam_id.

ImuSample (MtiProtocol.h)

One decoded Xsens MTi reading: temp_c (°C), acc[3] (m/s², incl. gravity), gyr[3] (rad/s), mag[3] (a.u., earth-normalized), roll_deg (180..180), pitch_deg (90..90), yaw_deg (0..360 heading — the MTi's native 180..180 is shifted by parseMTData), sample_counter. gimbal calib phase-unwraps the swept yaw (unwrapNear) so a sweep crossing 0/360 still fits a clean line.

ImuDeviceConfig (MtiProtocol.h)

The device configuration read back during the Config-state handshake (each has_* flag marks whether the device actually answered): product_code, device_id, firmware, output mode flags (temp/calibrated/orientation/aux/status), output settings (orientation_mode, timestamp_mode, per-channel acc/gyr/mag_enabled, data_format), period/sample_rate_hz, and the XKF scenario (scenario_type/version, resolved to scenario_label against available_profiles). Built by applyImuConfigAck (one ack frame at a time) + finalizeImuConfig (derive rate, resolve label). Surfaced read-only in the TUI's i view (IMU CONFIG section); the legacy "scenario" is the modern "filter profile" — same MIDs (0x62/0x64/0x65).

On-disk artifacts

Artifact Path Format
Captured images <output_dir>/<RGB|ACR|NIR>/<unix_ms>.jxl JPEG XL, rotated 90° CCW
Demo placeholder bin/x64/Release/test_smoke.jxl copied verbatim in demo mode
Diagnostics log <data_dir>/fire_gimbal_control/logs/diag_<ts>.log raw DG stream + parsed summary
Calibration log <data_dir>/fire_gimbal_control/logs/calib_<ts>.log per-axis samples + the least-squares fit

Diagnostics/calibration results are also surfaced live in the TUI (activity strip + gimbal g view) and applied to the running session's geometry; other state lives in memory.