160 lines
6.1 KiB
C++
160 lines
6.1 KiB
C++
#pragma once
|
|
|
|
#include "fgc/Config.h" // TestProfile
|
|
#include "fgc/Geometry.h"
|
|
#include "fgc/TestReport.h"
|
|
|
|
#include <atomic>
|
|
#include <cstdint>
|
|
#include <mutex>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <thread>
|
|
|
|
namespace fgc {
|
|
|
|
class IMotorController;
|
|
class IImuSource;
|
|
class IEnvSensor;
|
|
class ICameraSource;
|
|
struct HardwareConfig;
|
|
struct DrivetrainConfig;
|
|
|
|
// Leaf-test selection bitmask. Subsystem masks are unions of their leaves.
|
|
enum TestLeaf : uint32_t {
|
|
T_GIMBAL_HOMING = 1u << 0,
|
|
T_GIMBAL_ENCODER = 1u << 1,
|
|
T_GIMBAL_FRICTION = 1u << 2,
|
|
T_GIMBAL_BACKLASH = 1u << 3,
|
|
T_GIMBAL_BALANCE = 1u << 4,
|
|
T_IMU_CONFIG = 1u << 5,
|
|
T_IMU_HEALTH = 1u << 6,
|
|
T_IMU_DRIFT = 1u << 7,
|
|
T_HOST_THERMAL = 1u << 8,
|
|
T_HOST_DISK = 1u << 9,
|
|
T_HOST_MEMORY = 1u << 10,
|
|
T_HOST_LOAD = 1u << 11,
|
|
// `test hardware`: is this rig the one hardware.ini says it is? These are
|
|
// preconditions rather than measurements - each either holds or does not, so
|
|
// they carry pass/fail metrics rather than values to trend.
|
|
T_HW_AXES = 1u << 12,
|
|
T_HW_MOTOR = 1u << 13,
|
|
T_HW_IMU = 1u << 14,
|
|
T_HW_ENV = 1u << 15,
|
|
T_HW_CAMERA = 1u << 16,
|
|
};
|
|
constexpr uint32_t T_GIMBAL_ALL = T_GIMBAL_HOMING | T_GIMBAL_ENCODER | T_GIMBAL_FRICTION |
|
|
T_GIMBAL_BACKLASH | T_GIMBAL_BALANCE;
|
|
constexpr uint32_t T_IMU_ALL = T_IMU_CONFIG | T_IMU_HEALTH | T_IMU_DRIFT;
|
|
constexpr uint32_t T_HOST_ALL = T_HOST_THERMAL | T_HOST_DISK | T_HOST_MEMORY | T_HOST_LOAD;
|
|
constexpr uint32_t T_HW_ALL = T_HW_AXES | T_HW_MOTOR | T_HW_IMU | T_HW_ENV | T_HW_CAMERA;
|
|
constexpr uint32_t T_ALL = T_GIMBAL_ALL | T_IMU_ALL | T_HOST_ALL | T_HW_ALL;
|
|
|
|
// Which leaf masks need real motor / IMU hardware (used by the caller to guard).
|
|
// Needs a HOMED gimbal, not merely a motor link: the caller refuses the whole
|
|
// run when it is not ready. The `test hardware` leaves are deliberately NOT
|
|
// here - they only read telemetry and DUMP, and they are the checks you want
|
|
// on a tower that has not been homed yet.
|
|
constexpr uint32_t T_NEEDS_MOTOR = T_GIMBAL_ALL;
|
|
constexpr uint32_t T_NEEDS_IMU = T_IMU_ALL;
|
|
|
|
// Resolve "subsystem [test]" tokens to a leaf mask. Empty subsystem => T_ALL;
|
|
// a subsystem with empty test => that subsystem's leaves. Returns false and sets
|
|
// `err` for an unknown subsystem/test token.
|
|
bool resolveTestSelection(const std::string& subsystem, const std::string& test,
|
|
uint32_t& mask, std::string& err);
|
|
|
|
// Everything the `test hardware` leaves need beyond the motor and IMU the runner
|
|
// already holds. Passed as one struct because the alternative is five more
|
|
// constructor parameters, and because every field is optional: a leaf whose
|
|
// input is absent reports "not run" rather than failing.
|
|
struct HardwareTestContext {
|
|
const HardwareConfig* declared = nullptr; // [Hardware], or null when undeclared
|
|
const DrivetrainConfig* drive = nullptr; // [Motor.<axis>], for the current echo
|
|
IEnvSensor* env = nullptr;
|
|
ICameraSource* camera = nullptr;
|
|
|
|
std::vector<std::string> configured_cameras; // [Camera.<name>] blocks in open order
|
|
std::string i2c_device; // [Env] i2c_device, for the adapter-class check
|
|
// The degree maps, so a declared deg/s can be turned back into the VMAX the
|
|
// firmware should be holding.
|
|
AxisMap geo_yaw;
|
|
AxisMap geo_pitch;
|
|
double r_sense_ohm = 0.0; // to recompute what CURRENT should have sent
|
|
|
|
// sysfs nodes, overridable so the checks are exercisable off a tower.
|
|
std::string usbfs_path = "/sys/module/usbcore/parameters/usbfs_memory_mb";
|
|
std::string lpm_path; // empty => discovered from the camera's USB port, or skipped
|
|
int usbfs_min_mb = 1000;
|
|
};
|
|
|
|
// Live progress for the activity strip (mirrors CalibProgress).
|
|
struct TestProgress {
|
|
bool running = false;
|
|
std::string section; // current leaf id
|
|
int step = 0;
|
|
int total = 0;
|
|
std::string phase;
|
|
};
|
|
|
|
// Runs the selected hardware self-tests on a worker thread, off the control
|
|
// loop. Mirrors PitchSetupRoutine's lifecycle: start()/cancel()/running(), live
|
|
// progress(), and takeReport() once finished. The motor/imu/Logger interfaces are
|
|
// thread-safe; the produced TestReport is handed back for the control thread to
|
|
// compare against the baseline, write to disk, and surface in the UI.
|
|
class TestRunner {
|
|
public:
|
|
TestRunner(IMotorController& motor, IImuSource* imu, Geometry geo,
|
|
uint32_t selection, TestProfile profile, std::string disk_path,
|
|
HardwareTestContext hw = {});
|
|
~TestRunner();
|
|
|
|
bool start();
|
|
void cancel();
|
|
bool running() const { return running_.load(); }
|
|
|
|
std::optional<TestReport> takeReport();
|
|
TestProgress progress() const;
|
|
|
|
private:
|
|
void run();
|
|
void setProgress(const std::string& section, int step, int total, const char* phase);
|
|
bool cancelled() const { return cancel_.load(); }
|
|
|
|
// Leaf modules — each appends one TestSection to `report_`.
|
|
void testHoming(TestReport& r);
|
|
void testEncoder(TestReport& r);
|
|
void testFriction(TestReport& r);
|
|
void testBacklash(TestReport& r);
|
|
void testBalance(TestReport& r);
|
|
void testImuConfig(TestReport& r);
|
|
void testImuHealth(TestReport& r);
|
|
void testImuDrift(TestReport& r);
|
|
void testHost(TestReport& r);
|
|
void testHwAxes(TestReport& r);
|
|
void testHwMotor(TestReport& r);
|
|
void testHwImu(TestReport& r);
|
|
void testHwEnv(TestReport& r);
|
|
void testHwCamera(TestReport& r);
|
|
|
|
IMotorController& motor_;
|
|
IImuSource* imu_;
|
|
Geometry geo_;
|
|
uint32_t selection_;
|
|
TestProfile profile_;
|
|
std::string disk_path_;
|
|
HardwareTestContext hw_;
|
|
|
|
std::thread thread_;
|
|
std::atomic<bool> running_{false};
|
|
std::atomic<bool> cancel_{false};
|
|
|
|
mutable std::mutex result_mutex_;
|
|
std::optional<TestReport> report_;
|
|
|
|
mutable std::mutex progress_mutex_;
|
|
TestProgress progress_;
|
|
};
|
|
|
|
} // namespace fgc
|