93 lines
3.8 KiB
C++
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
|