#pragma once #include #include namespace fgc { // Notification published after an image is captured and saved. struct CamEvent { std::string tower; // tower / FWT name std::string camera; // "RGB" / "ACR" / "NIR" int heading_decideg = 0; // yaw heading * 10 (one decimal as integer) int pitch_decideg = 0; // pitch elevation * 10 (one decimal as integer) long long timestamp_ms = 0; // Unix epoch ms; matches the image filename }; // The tower computer's health, on GGS/FWT//Health (retained): the CPU // guard's state and the readings behind it (ThermalGuard.h). A reading that is // unknown goes out as null. struct HealthReport { std::string tower; std::string state = "normal"; // normal / slowed / paused std::string reason; // why not normal, in plain words; "" when normal bool guard_on = true; // false after `thermal off` bool cpu_c_ok = false; double cpu_c = 0.0; bool cpu_mhz_ok = false; double cpu_mhz = 0.0; double cpu_busy_pct = -1.0; // -1 = unknown bool throttling = false; long long throttle_events_last_min = 0; bool enclosure_c_ok = false; double enclosure_c = 0.0; int save_count_last_min = 0; double save_ms_mean = 0.0; double save_ms_max = 0.0; long long held_s = 0; // the scan waiting for saving, seconds double interval_s = 0.0; // the time between pictures now long long timestamp_ms = 0; // Unix epoch ms }; // A console command that arrived over MQTT, on GGS/FWT//Command. It is // run by the same handleCommand() as a typed one, on the control thread. struct RemoteCommand { std::string id; // chosen by the sender, echoed in the reply; may be empty std::string cmd; // the command line, exactly as typed at the console long long received_ms = 0; bool retained = false; // a retained message: never run (it would re-run on reconnect) std::string error; // non-empty: the payload could not be read; reply, do not run }; // The tower's answer, on GGS/FWT//CommandReply. struct CommandReply { std::string id; std::string cmd; std::string level = "info"; // most severe line: info / warn / error std::vector lines; // what the command logged while it ran bool truncated = false; }; // What became of an outbound message. Dropped and Failed are separated because // they mean different things operationally: Dropped is "the link was down and we // discarded it silently", Failed is "the broker or library rejected it". // Inbound messages are always Ok. enum class Delivery { Ok, Dropped, Failed }; // One message that crossed the control channel, for the connectivity view. struct ChannelMessage { long long timestamp_ms = 0; bool outbound = true; // PUB (ours) vs RX (broker's) Delivery delivery = Delivery::Ok; std::string topic; std::string payload; }; // Cumulative channel counters since start-up. struct ChannelStats { long long published_ok = 0; long long published_dropped = 0; // attempted while disconnected: silently discarded long long published_failed = 0; // the broker/library rejected it long long received = 0; long long connects = 0; // successful (re)connections long long last_connect_ms = 0, last_loss_ms = 0; std::string last_status_payload; // what actually went out on StatusCode }; // Abstraction over the remote control/telemetry channel. Implemented by // MqttControlChannel (Eclipse Paho) and NullControlChannel (no broker; used // for development - publishes are dropped and recorded). class IControlChannel { public: virtual ~IControlChannel() = default; // Returns true once usable. NullControlChannel always succeeds. virtual bool connect() = 0; virtual void disconnect() = 0; virtual bool connected() const = 0; // The tower's mode (OperatingMode.h: 0 auto, 1 pan, 2 manual), on // StatusCode - on every change, and again on every reconnect. virtual void publishStatus(int code) = 0; virtual void publishCamEvent(const CamEvent& event) = 0; // The computer's health (HealthReport), retained. Default: dropped. virtual void publishHealth(const HealthReport& /*report*/) {} // Commands received since the last call, oldest first; clears them. And the // answer to one. Defaults: none / dropped, for a channel that takes no commands. virtual std::vector takeCommands() { return {}; } virtual void publishCommandReply(const CommandReply& /*reply*/) {} // Recent traffic and counters for the connectivity ('m') view. Default: none, // so an implementation that keeps no history needs no changes. virtual std::vector recentMessages() const { return {}; } virtual ChannelStats channelStats() const { return {}; } }; } // namespace fgc