docs: add Gaugecontroller v2.0 design spec

Describes the two-part refactor: gauge_config.h for centralised pin and
motion defaults, and uniform sscanf parsing across all parse* functions.
This commit is contained in:
2026-05-21 21:46:56 +02:00
parent e525dba0c4
commit 7c3068ff3a

View File

@@ -0,0 +1,162 @@
# 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