#pragma once #include #include namespace fgc { // Remote control input (was struct mqtt_sub_data). The *_available flags mark // whether a fresh value arrived since the last poll(). struct ControlCommand { bool control_code_available = false; int control_code = 0; // 0 = automatic sweep, 1 = directed to target heading bool heading_available = false; std::string target_heading; // kept as string; the yaw target in degrees }; // 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 }; // 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 poll() yields a default). 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; virtual void publishStatus(int code) = 0; virtual void publishCamEvent(const CamEvent& event) = 0; // Latest control input; clears the *_available flags so each update is // acted on once. virtual ControlCommand poll() = 0; // 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