fwt_software/include/fgc/IControlChannel.h

134 lines
5.9 KiB
C++

#pragma once
#include <optional>
#include <string>
#include <vector>
namespace fgc {
// What a thermal camera's CamEvent carries beyond the common fields (see
// docs/mqtt-api.md). Temperatures are apparent (emissivity 1), in tenths of a
// degree Celsius; the hot spot is normalised 0..1 across the stored image.
struct ThermalEventFields {
int cal = 0; // calibration profile: says how to read the counts
int missed = 0; // GigE packets lost for this frame
bool stats_ok = false; // false: no valid pixel, the four below go out as null
int tmax_decic = 0;
int tmed_decic = 0;
double hotx = 0.0;
double hoty = 0.0;
};
// Notification published after an image is captured and saved.
struct CamEvent {
std::string tower; // tower / FWT name
std::string camera; // "RGB" / "TIR" / "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
std::optional<ThermalEventFields> thermal; // thermal cameras only
};
// The tower computer's health, on GGS/FWT/<tower>/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;
std::string cams_offline; // labels of cameras not delivering, comma-separated
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/<tower>/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/<tower>/CommandReply.
struct CommandReply {
std::string id;
std::string cmd;
std::string level = "info"; // most severe line: info / warn / error
std::vector<std::string> 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<RemoteCommand> 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<ChannelMessage> recentMessages() const { return {}; }
virtual ChannelStats channelStats() const { return {}; }
};
} // namespace fgc