From 4a7551e358e997dfde01b11ea2e9fbf9c5eb3740 Mon Sep 17 00:00:00 2001 From: "Adrian A. Baumann" Date: Wed, 15 Apr 2026 21:53:01 +0200 Subject: [PATCH] Blinking added to Arduino --- CLAUDE.md | 3 +- Gaugecontroller/Gaugecontroller.ino | 79 ++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index e2c5422..b3e24f8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -90,8 +90,9 @@ Commands arrive as newline-terminated ASCII lines. Each `parse*` function in `pr | `HOME` | `HOME ` / `HOMEALL` | Run homing sequence | | `SWEEP` | `SWEEP ` | Start sweep (0/0 stops) | | `POS?` | `POS?` | Query all gauges: `POS ` | -| `LED` | `LED ` | Set one LED (0-based index within gauge segment) to RGB colour (0–255 each); `` may be a range `N-M` to set LEDs N through M in one command | +| `LED` | `LED ` | Set one LED (0-based index within gauge segment) to RGB colour (0–255 each); `` may be a range `N-M` to set LEDs N through M in one command; also stops any active blink on those LEDs | | `LED?` | `LED?` | Query all LEDs: one `LED ` line per LED, then `OK` | +| `BLINK` | `BLINK ` | Blink LED(s) using their current colour as the on-colour; `` may be a range `N-M`; `on_ms`/`off_ms` must both be > 0, or both 0 to stop blinking | | `PING` | `PING` | Responds `PONG` | All commands reply `OK` or `ERR BAD_ID` / `ERR BAD_CMD` etc. diff --git a/Gaugecontroller/Gaugecontroller.ino b/Gaugecontroller/Gaugecontroller.ino index bc21c94..ec41ad9 100644 --- a/Gaugecontroller/Gaugecontroller.ino +++ b/Gaugecontroller/Gaugecontroller.ino @@ -70,11 +70,21 @@ struct Gauge { bool sweepTowardMax = true; }; +struct BlinkState { + bool active = false; + uint32_t onMs = 500; + uint32_t offMs = 500; + CRGB onColor; + bool currentlyOn = false; + unsigned long lastToggleMs = 0; +}; + Gauge gauges[GAUGE_COUNT]; String rxLine; CRGB leds[TOTAL_LEDS]; uint8_t gaugeLedOffset[GAUGE_COUNT]; +BlinkState blinkState[TOTAL_LEDS]; void sendReply(const String& s) { CMD_PORT.println(s); @@ -531,8 +541,10 @@ bool parseLed(const String& line) { sendReply("ERR BAD_IDX"); return true; } CRGB color(constrain(r, 0, 255), constrain(g, 0, 255), constrain(b, 0, 255)); - for (int i = idxFirst; i <= idxLast; i++) + for (int i = idxFirst; i <= idxLast; i++) { + blinkState[gaugeLedOffset[id] + i].active = false; leds[gaugeLedOffset[id] + i] = color; + } FastLED.show(); sendReply("OK"); return true; @@ -540,6 +552,69 @@ bool parseLed(const String& line) { return false; } +bool parseBlink(const String& line) { + int id; + char idxToken[16]; + long onMs, offMs; + if (sscanf(line.c_str(), "BLINK %d %15s %ld %ld", &id, idxToken, &onMs, &offMs) == 4) { + if (id < 0 || id >= GAUGE_COUNT) { sendReply("ERR BAD_ID"); return true; } + char* dash = strchr(idxToken, '-'); + int idxFirst = atoi(idxToken); + int idxLast = dash ? atoi(dash + 1) : idxFirst; + if (idxFirst < 0 || idxLast >= gaugePins[id].ledCount || idxFirst > idxLast) { + sendReply("ERR BAD_IDX"); return true; + } + + if (onMs == 0 && offMs == 0) { + for (int i = idxFirst; i <= idxLast; i++) + blinkState[gaugeLedOffset[id] + i].active = false; + sendReply("OK"); + return true; + } + if (onMs <= 0 || offMs <= 0) { sendReply("ERR BAD_TIME"); return true; } + + unsigned long nowMs = millis(); + for (int i = idxFirst; i <= idxLast; i++) { + uint8_t globalIdx = gaugeLedOffset[id] + i; + BlinkState& bs = blinkState[globalIdx]; + bs.onColor = leds[globalIdx]; + bs.onMs = (uint32_t)onMs; + bs.offMs = (uint32_t)offMs; + bs.currentlyOn = true; + bs.lastToggleMs = nowMs; + bs.active = true; + leds[globalIdx] = bs.onColor; + } + FastLED.show(); + sendReply("OK"); + return true; + } + return false; +} + +void updateBlink() { + unsigned long nowMs = millis(); + bool changed = false; + + for (uint8_t i = 0; i < GAUGE_COUNT; i++) { + for (uint8_t j = 0; j < gaugePins[i].ledCount; j++) { + uint8_t globalIdx = gaugeLedOffset[i] + j; + BlinkState& bs = blinkState[globalIdx]; + if (!bs.active) continue; + + uint32_t period = bs.currentlyOn ? bs.onMs : bs.offMs; + if ((nowMs - bs.lastToggleMs) >= period) { + bs.currentlyOn = !bs.currentlyOn; + bs.lastToggleMs = nowMs; + leds[globalIdx] = bs.currentlyOn ? bs.onColor : CRGB::Black; + changed = true; + } + } + } + + if (changed) FastLED.show(); +} + void processLine(const String& line) { if (parseSet(line)) return; if (parseSpeed(line)) return; @@ -551,6 +626,7 @@ void processLine(const String& line) { if (parsePosQuery(line)) return; if (parseLedQuery(line)) return; if (parseLed(line)) return; + if (parseBlink(line)) return; if (parsePing(line)) return; sendReply("ERR BAD_CMD"); @@ -613,6 +689,7 @@ void setup() { void loop() { readCommands(); + updateBlink(); for (uint8_t i = 0; i < GAUGE_COUNT; i++) { updateGauge(i);