107 lines
5.0 KiB
C++
107 lines
5.0 KiB
C++
#pragma once
|
|
|
|
#include <map>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace fgc {
|
|
|
|
// Structured decode of a firmware DUMP block (the text between "DUMP BEGIN" and
|
|
// "DUMP END"). Mirrors firmware/tools/decode_dump.py, which is authoritative for
|
|
// the on-wire field names and the TMC status-register bit tables.
|
|
|
|
struct DumpAxis {
|
|
char axis = '?'; // 'Y' (yaw) / 'P' (pitch)
|
|
std::string state_name = "?"; // BOOT/RESET/HOMING/READY/ERROR
|
|
bool enabled = false;
|
|
bool has_encoder = false;
|
|
long lim_neg = 0;
|
|
long lim_pos = 0;
|
|
long soft_margin = 0; // counts kept clear of each hard limit
|
|
long center_count = 0; // count the firmware anchored the homed midpoint to
|
|
long hold_target = 0;
|
|
long speed = 0;
|
|
// Motor current, as the firmware believes it applied it. GLOBALSCALER and
|
|
// IHOLD_IRUN are write-only on the TMC5160, so this echo is the only way the
|
|
// host can confirm a CURRENT command landed.
|
|
//
|
|
// -1 means the field was absent, i.e. the firmware predates the command -
|
|
// which is a different thing from "applied a current of zero" and has to stay
|
|
// distinguishable, because one is a version skew and the other is a fault.
|
|
long global_scaler = -1;
|
|
long run_irun = -1;
|
|
long homing_irun = -1;
|
|
// The rest of what the host declares and the firmware is told. Same -1
|
|
// convention and the same reason: absent means a firmware that predates the
|
|
// config handshake, which is a version skew, not a value of zero.
|
|
long steps_per_rev = -1;
|
|
long enc_deviation = -1;
|
|
long homing_speed = -1;
|
|
long center_speed = -1;
|
|
long sw_mode = -1;
|
|
// Bitmask over the firmware's CfgKey: which required keys have arrived.
|
|
// -1 when absent.
|
|
long cfg_received = -1;
|
|
// Is the axis running the firmware's limp-home fallback rather than anything
|
|
// this host declared? USE DEFAULTS fills cfg_received with the whole required
|
|
// mask, so that field alone cannot tell the two apart - a bench board reads as
|
|
// fully configured. -1 when absent, i.e. a firmware predating the flag.
|
|
long limp_home = -1;
|
|
// The chip-select and enable pins the running image was BUILT with. -1 when
|
|
// absent, i.e. a firmware that predates the pin echo.
|
|
long cs_pin = -1;
|
|
long en_pin = -1;
|
|
// Encoder-tracking health accumulated by the firmware hold corrector.
|
|
long hold_corrections = 0; // # of hold resyncs since firmware boot/RESET
|
|
long hold_peak_dev = 0; // largest deviation seen while holding (counts)
|
|
long hold_cumulative_dev = 0; // sum of corrected deviations (counts)
|
|
int hsub = 0;
|
|
|
|
// Raw register hex strings as received, keyed by name (GCONF, DRV_STATUS...).
|
|
std::map<std::string, std::string> regs;
|
|
|
|
// Decoded status registers + their set-bit names.
|
|
unsigned drv_status = 0;
|
|
unsigned gstat = 0;
|
|
unsigned ramp_stat = 0;
|
|
int cs_actual = 0; // (DRV_STATUS >> 16) & 0x1F
|
|
int sg_result = 0; // DRV_STATUS & 0x3FF
|
|
std::vector<std::string> drv_flags;
|
|
std::vector<std::string> gstat_flags;
|
|
std::vector<std::string> ramp_flags;
|
|
};
|
|
|
|
struct DumpData {
|
|
bool valid = false;
|
|
std::string build;
|
|
long uptime_ms = 0;
|
|
// Why the MCU last restarted, as the firmware reported it.
|
|
//
|
|
// `mcusr` is the RAW value and means DIFFERENT THINGS per board: on AVR it is
|
|
// the MCUSR bitmask (bit 0 power-on, bit 1 external, ...); on RP2040 it is
|
|
// rp2040.getResetReason(), a plain enum where 3 is one value, not two bits.
|
|
// Decoding one as the other is silently wrong - it reported an RP2040 soft
|
|
// reset as "PORF (power-on), EXTRF (external)" on tower 121.
|
|
//
|
|
// So the firmware now NAMES it in the dump (`reset=<text>`), and that text is
|
|
// authoritative because only the board knows its own encoding. reset_flags is
|
|
// the legacy AVR bit decode, kept for firmware that predates the field.
|
|
unsigned mcusr = 0;
|
|
std::string reset_text; // empty => firmware did not name it
|
|
long free_ram = 0;
|
|
// SPI pins the image was built with - RP2040 only, where they are a choice.
|
|
// -1 when absent: a Leonardo, or firmware predating the echo.
|
|
long spi_sck = -1, spi_mosi = -1, spi_miso = -1;
|
|
std::vector<std::string> reset_flags;
|
|
std::vector<DumpAxis> axes;
|
|
};
|
|
|
|
// Parse a raw DUMP block. Returns {valid=false} for empty/malformed input (no
|
|
// "DUMP BEGIN .. DUMP END" pair).
|
|
DumpData parseDump(const std::string& block);
|
|
|
|
// Human-readable lines for a decoded dump (console-reusable pretty print).
|
|
std::vector<std::string> formatDump(const DumpData& d);
|
|
|
|
} // namespace fgc
|