136 lines
4.6 KiB
C++
136 lines
4.6 KiB
C++
#pragma once
|
|
|
|
#include "fgc/IMotorController.h" // AxisState
|
|
#include "fgc/Logger.h" // LogLevel
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace fgc {
|
|
|
|
// Plain-data view model handed from the control loop to a user interface. It is
|
|
// a pure snapshot: no references to the live motor/camera/channel objects, so
|
|
// the UI thread can copy and render it without touching (or racing) application
|
|
// logic. New subsystems become new structs here + a panel in the TUI.
|
|
|
|
// Colour intent, mapped to concrete terminal colours by the renderer.
|
|
enum class UiColor { Default, Dim, Green, Yellow, Red, Cyan };
|
|
|
|
// One gimbal axis.
|
|
struct AxisView {
|
|
std::string label; // "YAW" / "PITCH"
|
|
AxisState state = AxisState::Unknown;
|
|
double deg = 0.0; // heading/elevation, from xenc via Geometry
|
|
long xactual = 0;
|
|
long xenc = 0;
|
|
double target_deg = 0.0; // current scheduler target
|
|
int sg = 0; // SG_RESULT (live, from ST line)
|
|
int cs = 0; // CS_ACTUAL
|
|
int pwm = 0; // PWM_SCALE_SUM
|
|
unsigned drv_status = 0; // DRV_STATUS register
|
|
bool moving = false;
|
|
bool standstill = false;
|
|
bool stall = false;
|
|
bool overtemp = false;
|
|
bool endstop_l = false;
|
|
bool endstop_r = false;
|
|
};
|
|
|
|
struct GimbalView {
|
|
bool present = false; // motor link usable
|
|
AxisView yaw;
|
|
AxisView pitch;
|
|
bool pitch_present = false;
|
|
};
|
|
|
|
// One labelled sensor reading. `present=false` => render the dim "pending" form.
|
|
struct SensorField {
|
|
std::string label; // "Temp", "Humid", "Roll"...
|
|
std::string value; // formatted value, or placeholder when absent
|
|
std::string unit; // "°C", "%RH", "°"...
|
|
bool present = false;
|
|
};
|
|
|
|
// DHT11 (temperature/humidity) + Xsens MTi (orientation). Neither is integrated
|
|
// yet, so the MVP fills `fields` with pending placeholders; flip the *_present
|
|
// flags and populate values when the drivers land.
|
|
struct SensorsView {
|
|
bool dht_present = false;
|
|
bool imu_present = false;
|
|
std::vector<SensorField> fields;
|
|
};
|
|
|
|
struct CaptureView {
|
|
bool present = false;
|
|
bool active = false;
|
|
double image_rate = 0.0; // img/s
|
|
int camera_count = 0;
|
|
std::vector<std::string> labels;
|
|
// Last published capture (from ImagePipeline::lastEvent()).
|
|
bool has_last = false;
|
|
std::string last_label;
|
|
double last_heading_deg = 0.0;
|
|
double last_pitch_deg = 0.0;
|
|
long long last_ts_ms = 0;
|
|
};
|
|
|
|
struct ConnView {
|
|
bool mqtt_enabled = false;
|
|
bool mqtt_connected = false;
|
|
std::string broker;
|
|
std::string tower;
|
|
int control_code = 0; // 0 = auto-sweep, 1 = directed
|
|
std::string target_heading;
|
|
int last_status_code = 0;
|
|
};
|
|
|
|
struct HeaderView {
|
|
std::string tower;
|
|
std::string build;
|
|
long long uptime_ms = 0;
|
|
bool live = true; // LIVE vs MOCK
|
|
};
|
|
|
|
struct LogLine {
|
|
LogLevel level = LogLevel::Info;
|
|
std::string text; // formatted line (no trailing newline)
|
|
};
|
|
|
|
// Most recent firmware DUMP block (raw text), surfaced in the TUI help pane.
|
|
struct DumpView {
|
|
bool has = false;
|
|
std::string text;
|
|
};
|
|
|
|
struct UiSnapshot {
|
|
HeaderView header;
|
|
GimbalView gimbal;
|
|
SensorsView sensors;
|
|
CaptureView capture;
|
|
ConnView conn;
|
|
std::vector<LogLine> log;
|
|
DumpView dump;
|
|
};
|
|
|
|
// ---- Pure formatting helpers (unit-tested in tests/test_uisnapshot.cpp) ----
|
|
|
|
// Short state label for an axis state char (B/R/H/A/E -> these strings).
|
|
const char* axisStateLabel(AxisState s);
|
|
|
|
// Colour intent for an axis state (READY=green, HOMING=yellow, ERROR=red,
|
|
// BOOT/RESET=dim, Unknown=default).
|
|
UiColor axisStateColor(AxisState s);
|
|
|
|
// "12.3°" (one decimal, sign preserved).
|
|
std::string formatDegrees(double deg);
|
|
|
|
// Human "Ns ago" / "Nm ago" for an absolute ms timestamp relative to now_ms.
|
|
// Returns "—" when then_ms is 0 (never).
|
|
std::string formatTimeAgo(long long now_ms, long long then_ms);
|
|
|
|
// MVP placeholder: the Sensors panel fields shown before the DHT11/MTi drivers
|
|
// exist (all `present=false`). Centralised so the panel and tests agree.
|
|
SensorsView pendingSensorsView();
|
|
|
|
} // namespace fgc
|