# Gaugecontroller v2.0 Design **Date:** 2026-05-21 **Branch:** Stepper-Only **Scope:** Code quality / architecture — same features, better structure. No behaviour change. ## Goal Eliminate scattered magic constants and inconsistent parsing patterns. A developer adding or tuning a gauge should only need to edit one file. ## What is NOT changing - ISR logic, Q16 fixed-point stepping, trapezoidal velocity profile - Serial protocol commands and responses - Runtime `Gauge` struct fields (stay `float` for velocity, speed, accel) - LED code (absent on this branch; out of scope) --- ## Section 1: `gauge_config.h` Create `Gaugecontroller/gauge_config.h` alongside the sketch. ### New struct ```cpp struct GaugeConfig { // Hardware uint8_t dirPin; uint8_t stepPin; int8_t enablePin; // -1 = no enable pin bool dirInverted; bool stepActiveHigh; bool enableActiveLow; // Motion defaults (integers — cast to float in setup()) long minPos; long maxPos; long homingBackoffSteps; int maxSpeed; // steps/s int accel; // steps/s² int homingSpeed; // steps/s }; ``` ### Config table ```cpp constexpr GaugeConfig gaugeConfigs[] = { // dir step en dirInv stepHi enLow min max backoff speed accel homeSpd { 48, 49, -1, false, true, true, 0, 3780, 3800, 4000, 6000, 500 }, { 8, 9, -1, true, true, true, 0, 3780, 3800, 4000, 6000, 500 }, { 52, 53, -1, false, true, true, 0, 3780, 3800, 4000, 6000, 500 }, { 50, 51, -1, false, true, true, 0, 3780, 3800, 4000, 6000, 500 }, }; static const uint8_t GAUGE_COUNT = sizeof(gaugeConfigs) / sizeof(gaugeConfigs[0]); ``` Adding gauge 5 is one new table row. `GAUGE_COUNT` updates automatically. ### Changes to `Gaugecontroller.ino` - Remove `constexpr GaugePins gaugePins[]`, `struct GaugePins`, and the hardcoded `GAUGE_COUNT`. - Add `#include "gauge_config.h"`. - In `setup()`, initialise each `Gauge`'s motion defaults from `gaugeConfigs[i]`: ```cpp gauges[i].minPos = gaugeConfigs[i].minPos; gauges[i].maxPos = gaugeConfigs[i].maxPos; gauges[i].homingBackoffSteps = gaugeConfigs[i].homingBackoffSteps; gauges[i].maxSpeed = (float)gaugeConfigs[i].maxSpeed; gauges[i].accel = (float)gaugeConfigs[i].accel; gauges[i].homingSpeed = (float)gaugeConfigs[i].homingSpeed; ``` - All existing references to `gaugePins[i].dirPin` etc. become `gaugeConfigs[i].dirPin` etc. (field names are identical). - Remove the hardcoded default initialisers from the `Gauge` struct definition (`maxPos = 3780`, `homingBackoffSteps = 3800`, `maxSpeed = 4000.0f`, `accel = 6000.0f`, `homingSpeed = 500.0f`, `minPos = 0`). These fields become zero-initialised and are then set from `gaugeConfigs[i]` in `setup()`, eliminating the risk of the struct defaults and config table silently diverging. --- ## Section 2: Uniform `sscanf` parsing Three `parse*` functions currently use manual `indexOf`/`substring`. Convert them to `sscanf` to match the rest of the parser. ### `parseSpeed` ```cpp bool parseSpeed(const String& line) { int id; float speed; if (sscanf(line.c_str(), "SPEED %d %f", &id, &speed) == 2) { if (id < 0 || id >= GAUGE_COUNT) { sendReply("ERR BAD_ID"); return true; } if (speed <= 0.0f) { sendReply("ERR BAD_SPEED"); return true; } gauges[id].maxSpeed = speed; sendReply("OK"); return true; } return false; } ``` ### `parseAccel` ```cpp bool parseAccel(const String& line) { int id; float accel; if (sscanf(line.c_str(), "ACCEL %d %f", &id, &accel) == 2) { if (id < 0 || id >= GAUGE_COUNT) { sendReply("ERR BAD_ID"); return true; } if (accel <= 0.0f) { sendReply("ERR BAD_ACCEL"); return true; } gauges[id].accel = accel; sendReply("OK"); return true; } return false; } ``` ### `parseSweep` ```cpp bool parseSweep(const String& line) { int id; float accel, speed; if (sscanf(line.c_str(), "SWEEP %d %f %f", &id, &accel, &speed) == 3) { if (id < 0 || id >= GAUGE_COUNT) { sendReply("ERR BAD_ID"); return true; } Gauge& g = gauges[id]; if (accel <= 0.0f || speed <= 0.0f) { g.sweepEnabled = false; g.velocity = 0.0f; stopTimerStepping(id); sendReply("OK"); return true; } g.accel = accel; g.maxSpeed = speed; g.sweepEnabled = true; g.sweepTowardMax = true; atomicWriteLong(g.targetPos, g.maxPos); sendReply("OK"); return true; } return false; } ``` No change to accepted syntax, error codes, or response format. --- ## File inventory | File | Change | |---|---| | `Gaugecontroller/gauge_config.h` | New — all pin + motion defaults | | `Gaugecontroller/Gaugecontroller.ino` | Remove `GaugePins`, add include, update `setup()`, rewrite 3 parsers | ## Success criteria - Sketch compiles cleanly with `arduino-cli compile --fqbn arduino:avr:mega Gaugecontroller` - `GAUGE_COUNT` need not be edited when adding a gauge — only `gaugeConfigs[]` changes - No `indexOf`/`substring` remain in any `parse*` function - All existing protocol commands behave identically to v1