106 lines
4.5 KiB
C++
106 lines
4.5 KiB
C++
#pragma once
|
|
|
|
#include <optional>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace fgc {
|
|
|
|
// The host half of the config handshake (hardware-config-plan.md section 6).
|
|
//
|
|
// Today the firmware carries a full parameter table and GUESSES when the host
|
|
// says nothing, so the same drivetrain value exists in two places and they can
|
|
// disagree. Instead the firmware declares what it needs and refuses to move
|
|
// until it has it:
|
|
//
|
|
// firmware -> BOOT build=abc123
|
|
// firmware -> NEED Y steps_per_rev global_scaler sw_mode enc_deviation ...
|
|
// host -> SET Y steps_per_rev 1210778
|
|
// host -> SET Y global_scaler 80
|
|
// ...
|
|
//
|
|
// This module is the pure part: read a NEED line, and work out which SET lines
|
|
// answer it. Sending them, and deciding what to do when some cannot be answered,
|
|
// belongs to the caller.
|
|
|
|
// A NEED line: the firmware naming the parameters it will not run without.
|
|
struct NeedRequest {
|
|
char axis = '?'; // 'Y' or 'P'
|
|
std::vector<std::string> keys;
|
|
};
|
|
|
|
// Returns nullopt for anything that is not a well-formed NEED line. A NEED with
|
|
// no keys is well-formed and means "this axis needs nothing" - which is how a
|
|
// firmware built for fewer axes than the rig has answers for the axis it lacks.
|
|
std::optional<NeedRequest> parseNeedLine(const std::string& line);
|
|
|
|
// Everything the host can answer for one axis. Each group carries its own
|
|
// "declared" flag because a value the host does not have must be reported as
|
|
// unanswered rather than sent as a zero - a zero here is a real setting, and a
|
|
// silently zeroed current or margin is a damaged rig.
|
|
struct AxisConfigSource {
|
|
// From [Motor.<axis>] milliamps, via TmcCurrent.h.
|
|
bool have_current = false;
|
|
int global_scaler = 0;
|
|
int run_irun = 0;
|
|
int homing_irun = 0;
|
|
|
|
// From [Motor] calibration and margins. Always known - they have defaults
|
|
// that predate hardware.ini and are already sent as CENTER / MARGIN.
|
|
long center_count = 0;
|
|
long soft_margin = 0;
|
|
|
|
// From [Motor.<axis>], the mechanism's own facts.
|
|
bool have_travel = false;
|
|
long steps_per_rev = 0; // expected full mechanical travel, in counts
|
|
bool have_deviation = false;
|
|
long enc_deviation = 0;
|
|
|
|
// Speeds, already converted from deg/s to VMAX by the caller (AxisSpeed.h).
|
|
// 0 means the conversion was refused - an uncalibrated scale - and the key
|
|
// goes unanswered rather than stopping the axis with a VMAX of zero.
|
|
long normal_vmax = 0;
|
|
long homing_vmax = 0;
|
|
long center_vmax = 0;
|
|
|
|
// Wiring facts: whether this axis has physical endstop switches on the TMC's
|
|
// REFL/REFR, and whether its encoder is aligned and usable.
|
|
bool have_wiring = false;
|
|
unsigned sw_mode = 0;
|
|
bool has_encoder = true;
|
|
|
|
// Optional: the encoder scale as the ENC_CONST register value (see
|
|
// encConstRegister). Never in a NEED line - the firmware has a default - so
|
|
// it is sent first, unasked, when declared.
|
|
bool have_enc_const = false;
|
|
long enc_const = 0;
|
|
};
|
|
|
|
struct FirmwareConfigPlan {
|
|
// Ready-to-send command lines, in the order the firmware asked for them.
|
|
std::vector<std::string> sets;
|
|
// Keys the host was asked for and has no value for. The firmware stays in
|
|
// NEEDCFG until they are answered, so this is a startup failure, not a
|
|
// warning to scroll past.
|
|
std::vector<std::string> unanswered;
|
|
// Keys that are not part of the vocabulary at all: a firmware newer than
|
|
// this host. Kept separate from `unanswered` because the fix is different -
|
|
// upgrade the host, rather than fill in hardware.ini.
|
|
std::vector<std::string> unknown;
|
|
|
|
bool complete() const { return unanswered.empty() && unknown.empty(); }
|
|
};
|
|
|
|
// Map one NEED request onto SET lines. `center` / `margin` are accepted as
|
|
// aliases for `center_count` / `soft_margin`, because those are the names the
|
|
// existing CENTER and MARGIN commands use and hand-typed sessions rely on them.
|
|
FirmwareConfigPlan planFirmwareConfig(const NeedRequest& need, const AxisConfigSource& src);
|
|
|
|
// Microsteps per encoder count as the TMC5160 holds it in decimal mode
|
|
// (ENCMODE bit 10): the whole part in the high 16 bits, the fraction in
|
|
// 1/10000ths in the low 16. 12.5 -> 0x000C1388. nullopt for anything that
|
|
// format cannot hold exactly: zero or less, 32768 or more, or a fifth decimal.
|
|
std::optional<long> encConstRegister(double microsteps_per_count);
|
|
|
|
} // namespace fgc
|