fwt_software/include/fgc/HardwarePresence.h

93 lines
3.8 KiB
C++

#pragma once
#include "fgc/Config.h"
#include <string>
#include <vector>
namespace fgc {
// Reconciling what hardware.ini DECLARES against what the rig actually turned
// out to have.
//
// The program degrades gracefully everywhere - TestRunner skips the pitch and
// IMU leaves, CamEvent falls back to encoder pitch, CaptureScheduler sends the
// single-axis MOVE form. That is right for a rig that genuinely lacks them, and
// indistinguishable from a FAILURE on a rig that does not: a 2-axis tower whose
// pitch stops enumerating becomes a yaw-only tower, captures one elevation band,
// and reports itself healthy. Declaring the assembly is what lets startup tell
// those two apart.
// What this run actually found, from the sources that can answer: telemetry for
// the axes, the constructed sensor objects for the IMU and env sensor, camera
// enumeration for the cameras.
struct FoundHardware {
std::vector<std::string> axes; // yaw implied by any ST line, pitch by pitch_present
bool imu = false;
bool env = false;
std::vector<std::string> cameras; // by [Camera.<name>] block name, as configured
// How many of those the source actually opened. A camera can be configured
// and declared and still not be on the bus, which is the whole failure this
// section exists to catch - but the source reports a count, not which ones
// are missing, so the shortfall is named as a number. -1 = not asked.
int cameras_opened = -1;
// Telemetry never arrived, so the axis list is unknown rather than empty.
// Without this an unplugged MCU would report every declared axis as missing,
// which is true but useless - the one fault worth naming is the serial link.
bool axes_known = true;
};
enum class PresenceIssue {
MissingDeclared, // declared, not found - the failure this exists to catch
UndeclaredFound, // found, not declared - the file is stale
};
struct PresenceFinding {
PresenceIssue issue;
std::string subsystem; // "axis pitch", "imu", "env", "camera rgb"
std::string detail; // one operator-readable sentence, naming the fix
};
struct PresenceReport {
std::vector<PresenceFinding> findings;
// False when no hardware.ini was read, or it declared nothing comparable.
// Every tower is in this state until it is migrated, and it is what keeps
// this change invisible during the rollout.
bool reconciled = false;
bool anyMissing() const;
bool anyUndeclared() const;
std::vector<std::string> missing() const; // subsystem names, for the refusal line
};
// Pure comparison; says nothing about what to do about it.
PresenceReport reconcilePresence(const HardwareConfig& declared, const FoundHardware& found);
enum class PresenceAction {
Proceed, // nothing to reconcile, or everything matches
WarnOnly, // mismatches, but policy (or --degraded) says carry on
Refuse, // declared hardware is missing and this tower is strict
};
struct PresenceVerdict {
PresenceAction action = PresenceAction::Proceed;
std::string reason; // the line to log; empty when there is nothing to say
};
// `strict` is [Features] strict_presence, `degraded` is --degraded.
//
// Warn-only is the default deliberately: through the fleet rollout no tower may
// change behaviour on upgrade just by gaining a hardware.ini. A tower flips to
// strict once its file is known good, so the fleet-wide flip is a config change
// rather than a release.
PresenceVerdict presenceVerdict(const PresenceReport& report, bool strict, bool degraded);
// Every finding as one log-ready line, most serious first. Empty when there are
// none.
std::vector<std::string> formatPresence(const PresenceReport& report);
} // namespace fgc