diff --git a/Gaugecontroller_no_VFD/Gaugecontroller_no_VFD.ino b/Gaugecontroller_no_VFD/Gaugecontroller_no_VFD.ino index 7fb3189..6b3c895 100644 --- a/Gaugecontroller_no_VFD/Gaugecontroller_no_VFD.ino +++ b/Gaugecontroller_no_VFD/Gaugecontroller_no_VFD.ino @@ -6,11 +6,10 @@ static const uint8_t GAUGE_COUNT = 4; -// Backlight/status LEDs and indicator LEDs use separate data strips because -// their LED chipsets are not compatible on one chain. The command protocol +// Backlight/status LEDs use an addressable strip. Indicator LEDs are +// single-colour active-high outputs on per-gauge pins. The command protocol // still exposes one logical LED segment per gauge. static const uint8_t LED_DATA_PIN = 22; -static const uint8_t INDICATOR_LED_DATA_PIN = 36; static const uint8_t BREATHE_FRAME_MS = 16; static const uint8_t LED_SHOW_MIN_INTERVAL_MS = 16; static const uint8_t LED_SHOW_MOTION_INTERVAL_MS = 50; @@ -34,14 +33,16 @@ struct GaugePins { bool stepActiveHigh; bool enableActiveLow; const char* ledOrder; // one char per LED: 'G' = GRB, 'R' = RGB; length defines ledCount + int8_t indicatorRedPin; // logical LED index 3; -1 means not fitted + int8_t indicatorGreenPin; // logical LED index 4; -1 means not fitted }; constexpr GaugePins gaugePins[GAUGE_COUNT] = { - // dir, step, en, dirInv, stepHigh, enActiveLow, ledOrder - {48, 49, -1, false, true, true, "RRRGGRR"}, // Gauge 0 - {8, 9, -1, true, true, true, "GGGRRRR"}, // Gauge 1 - {52, 53, -1, false, true, true, "GGGRRRR"}, // Gauge 2 - {50, 51, -1, false, true, true, "GGGRRRR"}, // Gauge 3 + // dir, step, en, dirInv, stepHigh, enActiveLow, ledOrder, indRed, indGreen + {48, 49, -1, false, true, true, "RRRGGRR", 2, 3}, // Gauge 0 + {8, 9, -1, true, true, true, "GGGRRRR", 35, 36}, // Gauge 1 + {52, 53, -1, false, true, true, "GGGRRRR", 37, 38}, // Gauge 2 + {50, 51, -1, false, true, true, "GGGRRRR", 39, 40}, // Gauge 3 }; constexpr uint8_t cstrLen(const char* s) { @@ -149,21 +150,18 @@ bool rxOverflowed = false; CRGB logicalLeds[TOTAL_LEDS]; CRGB mainLeds[TOTAL_MAIN_LEDS]; -CRGB indicatorLeds[TOTAL_INDICATOR_LEDS]; CLEDController* mainLedController = nullptr; -CLEDController* indicatorLedController = nullptr; uint8_t gaugeLedOffset[GAUGE_COUNT]; uint8_t gaugeLedCount[GAUGE_COUNT]; uint8_t gaugeMainLedOffset[GAUGE_COUNT]; -uint8_t gaugeIndicatorLedOffset[GAUGE_COUNT]; uint8_t ledPhysicalIdx[TOTAL_LEDS]; +uint8_t ledGaugeIdx[TOTAL_LEDS]; +uint8_t ledLocalIdx[TOTAL_LEDS]; bool ledIsIndicator[TOTAL_LEDS]; bool ledRgSwap[TOTAL_LEDS]; BlinkState blinkState[TOTAL_LEDS]; bool mainLedsDirty = false; -bool indicatorLedsDirty = false; unsigned long lastLedShowMs = 0; -bool showIndicatorStripNext = false; // FastLED drives the shared strip as RGB. Each gauge's ledOrder string marks per-LED // type ('R' = RGB, 'G' = GRB); writes to GRB-ordered LEDs pre-swap R and G to compensate. @@ -180,12 +178,32 @@ inline CRGB encodeForStrip(uint8_t globalIdx, CRGB color) { return color; } +inline int8_t indicatorPinFor(uint8_t gaugeIdx, uint8_t localIdx) { + if (localIdx == 3) return gaugePins[gaugeIdx].indicatorRedPin; + if (localIdx == 4) return gaugePins[gaugeIdx].indicatorGreenPin; + return -1; +} + +inline bool indicatorIsOn(uint8_t localIdx, CRGB color) { + if (localIdx == 3) return color.r >= 128; + if (localIdx == 4) return color.g >= 128; + return false; +} + +inline void writeIndicatorLed(uint8_t globalIdx, CRGB color) { + uint8_t gaugeIdx = ledGaugeIdx[globalIdx]; + uint8_t localIdx = ledLocalIdx[globalIdx]; + int8_t pin = indicatorPinFor(gaugeIdx, localIdx); + if (pin >= 0) { + digitalWrite(pin, indicatorIsOn(localIdx, color) ? HIGH : LOW); + } +} + inline void writeLed(uint8_t globalIdx, CRGB color) { logicalLeds[globalIdx] = color; if (ledIsIndicator[globalIdx]) { - indicatorLeds[ledPhysicalIdx[globalIdx]] = encodeForStrip(globalIdx, color); - indicatorLedsDirty = true; + writeIndicatorLed(globalIdx, color); } else { mainLeds[ledPhysicalIdx[globalIdx]] = encodeForStrip(globalIdx, color); mainLedsDirty = true; @@ -211,7 +229,7 @@ uint32_t maxStepperRateQ16() { } void showDirtyLeds() { - if (!mainLedsDirty && !indicatorLedsDirty) return; + if (!mainLedsDirty) return; uint32_t maxStepRate = maxStepperRateQ16(); if (maxStepRate >= LED_SHOW_PAUSE_RATE_Q16) return; @@ -222,18 +240,9 @@ void showDirtyLeds() { : LED_SHOW_MIN_INTERVAL_MS; if (nowMs - lastLedShowMs < intervalMs) return; - if (showIndicatorStripNext && indicatorLedsDirty && indicatorLedController != nullptr) { - indicatorLedController->showLeds(255); - indicatorLedsDirty = false; - showIndicatorStripNext = false; - } else if (mainLedsDirty && mainLedController != nullptr) { + if (mainLedsDirty && mainLedController != nullptr) { mainLedController->showLeds(255); mainLedsDirty = false; - showIndicatorStripNext = true; - } else if (indicatorLedsDirty && indicatorLedController != nullptr) { - indicatorLedController->showLeds(255); - indicatorLedsDirty = false; - showIndicatorStripNext = false; } else { return; } @@ -1191,43 +1200,48 @@ void setup() { pinMode(gaugePins[i].enablePin, OUTPUT); setEnable(i, true); } + if (gaugePins[i].indicatorRedPin >= 0) { + pinMode(gaugePins[i].indicatorRedPin, OUTPUT); + digitalWrite(gaugePins[i].indicatorRedPin, LOW); + } + if (gaugePins[i].indicatorGreenPin >= 0) { + pinMode(gaugePins[i].indicatorGreenPin, OUTPUT); + digitalWrite(gaugePins[i].indicatorGreenPin, LOW); + } initStepperRuntime(i); setStepperLimits(i, gauges[i].minPos, gauges[i].maxPos); gauges[i].lastUpdateMicros = micros(); } - // Flatten the per-gauge LED counts into logical offsets and separate - // physical offsets for the main and indicator strips. + // Flatten the per-gauge LED counts into logical offsets and physical + // offsets for the addressable main strip. uint8_t ledOff = 0; uint8_t mainLedOff = 0; - uint8_t indicatorLedOff = 0; for (uint8_t i = 0; i < GAUGE_COUNT; i++) { gaugeLedCount[i] = cstrLen(gaugePins[i].ledOrder); gaugeLedOffset[i] = ledOff; gaugeMainLedOffset[i] = mainLedOff; - gaugeIndicatorLedOffset[i] = indicatorLedOff; for (uint8_t localIdx = 0; localIdx < gaugeLedCount[i]; localIdx++) { uint8_t globalIdx = ledOff + localIdx; bool indicator = isIndicatorLedIndex(localIdx); + ledGaugeIdx[globalIdx] = i; + ledLocalIdx[globalIdx] = localIdx; ledIsIndicator[globalIdx] = indicator; ledRgSwap[globalIdx] = gaugePins[i].ledOrder[localIdx] == 'G' || gaugePins[i].ledOrder[localIdx] == 'g'; ledPhysicalIdx[globalIdx] = indicator - ? indicatorLedOff + (localIdx - 3) + ? 0 : mainLedOff + localIdx - (localIdx > 4 ? 2 : 0); } ledOff += gaugeLedCount[i]; - indicatorLedOff += countIndicatorLedsForGauge(i); mainLedOff += gaugeLedCount[i] - countIndicatorLedsForGauge(i); } mainLedController = &FastLED.addLeds(mainLeds, TOTAL_MAIN_LEDS); - indicatorLedController = &FastLED.addLeds(indicatorLeds, TOTAL_INDICATOR_LEDS); FastLED.setBrightness(255); mainLedController->showLeds(255); - indicatorLedController->showLeds(255); setupStepperTimer(); requestHomeAll();