From c65050cd44585761be6d50c90397508d73e04475 Mon Sep 17 00:00:00 2001 From: Jean Jacques Avril Date: Sat, 4 Oct 2025 11:49:53 +0200 Subject: [PATCH] wip --- lib/hardware/hardware_led.cpp | 174 +++++++++++++++++++++++----------- lib/hardware/hardware_led.hpp | 42 ++++---- platformio.ini | 1 + 3 files changed, 145 insertions(+), 72 deletions(-) diff --git a/lib/hardware/hardware_led.cpp b/lib/hardware/hardware_led.cpp index f33d04b..a5a6335 100644 --- a/lib/hardware/hardware_led.cpp +++ b/lib/hardware/hardware_led.cpp @@ -1,113 +1,171 @@ #include "hardware_led.hpp" #include +#define DEBUG_LED +#ifdef DEBUG_LED +#define LOG(msg) Serial.println(msg) +#else +#define LOG(msg) +#endif + HardwareLed::HardwareLed(uint8_t pin, uint8_t numPixels) - : _strip(numPixels, pin, NEO_GRB + NEO_KHZ800), _isActive(false) {} + : m_strip(numPixels > 0 ? numPixels : 1, pin, NEO_GRB + NEO_KHZ800), + m_currentConfig(hardware_LedConfig_init_default), + m_isActive(false), + m_startTime(0), + m_pulseState(0), + m_lastPulseTime(0), + m_fadeIndex(0), + m_lastFadeTime(0), + m_fadeCurrentColor(0), + m_fadeTargetColor(0), + m_fadeProgress(0.0f), + m_fadeStartTime(0) {} void HardwareLed::begin() { - _strip.begin(); - _strip.show(); // Turn off + m_strip.begin(); + m_strip.show(); + randomSeed(analogRead(0)); } void HardwareLed::end() { - _strip.clear(); - _strip.show(); + m_strip.clear(); + m_strip.show(); } void HardwareLed::update() { - if (!_isActive) return; - + static unsigned long lastUpdate = 0; unsigned long now = millis(); - if (_currentConfig.duration_ms > 0 && now - _startTime >= _currentConfig.duration_ms) { - _isActive = false; - _strip.clear(); - _strip.show(); + if (now - lastUpdate < 10) return; // Limit to ~100 FPS + lastUpdate = now; + + if (!m_isActive) return; + + // Safe against millis() overflow due to unsigned arithmetic + if (m_currentConfig.duration_ms > 0 && (now - m_startTime) >= m_currentConfig.duration_ms) { + m_isActive = false; + m_strip.clear(); + m_strip.show(); + if (m_callback) m_callback(); return; } - switch (_currentConfig.which_animation_params) { + switch (m_currentConfig.which_animation_params) { case hardware_LedConfig_static_params_tag: - applyStatic(_currentConfig.animation_params.static_params); + applyStatic(m_currentConfig.animation_params.static_params); break; case hardware_LedConfig_pulse_params_tag: - applyPulse(_currentConfig.animation_params.pulse_params); + applyPulse(m_currentConfig.animation_params.pulse_params); break; case hardware_LedConfig_fade_params_tag: - applyFade(_currentConfig.animation_params.fade_params); + applyFade(m_currentConfig.animation_params.fade_params); break; case hardware_LedConfig_flicker_params_tag: - applyFlicker(_currentConfig.animation_params.flicker_params); + applyFlicker(m_currentConfig.animation_params.flicker_params); break; default: + LOG("Error: Unknown animation type"); break; } } void HardwareLed::set(const hardware_LedConfig& config) { - _currentConfig = config; - _startTime = millis(); - _isActive = true; - _pulseState = 0; - _lastPulseTime = _startTime; - _fadeIndex = 0; - _lastFadeTime = _startTime; - if (_currentConfig.which_animation_params == 5 && _currentConfig.animation_params.fade_params.colors_count > 0) { - _fadeCurrentColor = _currentConfig.animation_params.fade_params.colors[0]; - _fadeTargetColor = _currentConfig.animation_params.fade_params.colors[0]; - _fadeProgress = 1.0f; - _fadeStartTime = _startTime; + if (config.brightness > 255) { + LOG("Error: Brightness exceeds 255"); + return; + } + if (config.which_animation_params == hardware_LedConfig_fade_params_tag && + (config.animation_params.fade_params.colors_count == 0 || + config.animation_params.fade_params.colors_count > 5)) { + LOG("Error: Invalid colors_count in FadeParams"); + m_isActive = false; + m_strip.clear(); + m_strip.show(); + return; + } + if (config.which_animation_params == hardware_LedConfig_pulse_params_tag && + config.animation_params.pulse_params.speed_ms == 0) { + LOG("Error: Pulse speed_ms cannot be zero"); + return; + } + m_currentConfig = config; + m_startTime = millis(); + m_isActive = true; + m_pulseState = 0; + m_lastPulseTime = m_startTime; + m_fadeIndex = 0; + m_lastFadeTime = m_startTime; + if (config.which_animation_params == hardware_LedConfig_fade_params_tag && + config.animation_params.fade_params.colors_count > 0) { + m_fadeCurrentColor = config.animation_params.fade_params.colors[0]; + m_fadeTargetColor = config.animation_params.fade_params.colors[0]; + m_fadeProgress = 1.0f; + m_fadeStartTime = m_startTime; } - // Immediately apply initial state update(); } void HardwareLed::applyStatic(const hardware_StaticParams& params) { - setColor(params.color, _currentConfig.brightness); + setColor(params.color, m_currentConfig.brightness); } void HardwareLed::applyPulse(const hardware_PulseParams& params) { unsigned long now = millis(); - float phase = fmod((now - _startTime) / (float)params.speed_ms, 1.0f); + float speed_ms = max(params.speed_ms, 1U); // Prevent division by zero + float phase = fmod((now - m_startTime) / (float)speed_ms, 1.0f); float brightnessFactor = 0.5f + 0.5f * sin(2 * PI * phase); - uint8_t pulseBrightness = _currentConfig.brightness * brightnessFactor; + uint8_t pulseBrightness = m_currentConfig.brightness * brightnessFactor; setColor(params.color, pulseBrightness); } void HardwareLed::applyFade(const hardware_FadeParams& params) { - if (params.colors_count == 0) return; - unsigned long now = millis(); - if (_fadeProgress >= 1.0f) { - // Time to switch to next color - _fadeIndex = (_fadeIndex + 1) % params.colors_count; - _fadeCurrentColor = _fadeTargetColor; - _fadeTargetColor = params.colors[_fadeIndex]; - _fadeProgress = 0.0f; - _fadeStartTime = now; + if (params.colors_count == 0 || params.colors_count > 5) { + LOG("Error: Invalid colors_count in FadeParams"); + return; } - _fadeProgress = (now - _fadeStartTime) / (float)params.speed_ms; - if (_fadeProgress > 1.0f) _fadeProgress = 1.0f; - uint32_t interpolatedColor = lerpColor(_fadeCurrentColor, _fadeTargetColor, _fadeProgress); - setColor(interpolatedColor, _currentConfig.brightness); + unsigned long now = millis(); + if (m_fadeProgress >= 1.0f) { + m_fadeIndex = (m_fadeIndex + 1) % params.colors_count; + m_fadeCurrentColor = m_fadeTargetColor; + m_fadeTargetColor = params.colors[m_fadeIndex]; + m_fadeProgress = 0.0f; + m_fadeStartTime = now; + } + float speed_ms = max(params.speed_ms, 1U); // Prevent division by zero + m_fadeProgress = (now - m_fadeStartTime) / (float)speed_ms; + if (m_fadeProgress > 1.0f) m_fadeProgress = 1.0f; + uint32_t interpolatedColor = lerpColor(m_fadeCurrentColor, m_fadeTargetColor, m_fadeProgress); + setColor(interpolatedColor, m_currentConfig.brightness); } void HardwareLed::applyFlicker(const hardware_FlickerParams& params) { - // Simple random flicker based on intensity - uint8_t threshold = map(params.intensity, 0, 100, 0, 255); - if (random(255) < threshold) { - setColor(params.color, _currentConfig.brightness); - } else { - _strip.clear(); - _strip.show(); + uint32_t intensity = min(params.intensity, 100U); // Clamp to 0-100 + uint8_t threshold = map(intensity, 0, 100, 0, 255); + bool showPixel = random(255) < threshold; + if (showPixel != (m_strip.getPixelColor(0) != 0)) { + if (showPixel) { + setColor(params.color, m_currentConfig.brightness); + } else { + m_strip.clear(); + m_strip.show(); + } } } void HardwareLed::setColor(uint32_t color, uint8_t brightness) { - _strip.setBrightness(brightness); - _strip.setPixelColor(0, color); - _strip.show(); + uint8_t r = (color >> 16) & 0xFF; + uint8_t g = (color >> 8) & 0xFF; + uint8_t b = color & 0xFF; + r = (r * brightness) / 255; + g = (g * brightness) / 255; + b = (b * brightness) / 255; + for (uint16_t i = 0; i < m_strip.numPixels(); i++) { + m_strip.setPixelColor(i, r, g, b); + } + m_strip.show(); } -uint32_t HardwareLed::lerpColor(uint32_t color1, uint32_t color2, float t) { +uint32_t HardwareLed::lerpColor(uint32_t color1, uint32_t color2, float t) const { uint8_t r1 = (color1 >> 16) & 0xFF; uint8_t g1 = (color1 >> 8) & 0xFF; uint8_t b1 = color1 & 0xFF; @@ -118,4 +176,8 @@ uint32_t HardwareLed::lerpColor(uint32_t color1, uint32_t color2, float t) { uint8_t g = g1 + (g2 - g1) * t; uint8_t b = b1 + (b2 - b1) * t; return (r << 16) | (g << 8) | b; +} + +float HardwareLed::estimateCurrent_mA() const { + return m_strip.numPixels() * (m_currentConfig.brightness / 255.0f) * 60.0f; } \ No newline at end of file diff --git a/lib/hardware/hardware_led.hpp b/lib/hardware/hardware_led.hpp index 28649f6..e055949 100644 --- a/lib/hardware/hardware_led.hpp +++ b/lib/hardware/hardware_led.hpp @@ -3,32 +3,42 @@ #include "hardware.pb.h" #include +/** + * @class HardwareLed + * @brief Manages an LED strip on ESP8266 using Adafruit NeoPixel library. + * Supports animations defined by hardware_LedConfig (static, pulse, fade, flicker). + */ class HardwareLed { public: + using AnimationCallback = void (*)(); + HardwareLed(uint8_t pin, uint8_t numPixels = 1); void begin(); void end(); - void update(); + void update(); // Removed const void set(const hardware_LedConfig& config); + void setAnimationCallback(AnimationCallback cb) { m_callback = cb; } + float estimateCurrent_mA() const; private: void applyStatic(const hardware_StaticParams& params); void applyPulse(const hardware_PulseParams& params); - void applyFade(const hardware_FadeParams& params); + void applyFade(const hardware_FadeParams& params); // Removed const void applyFlicker(const hardware_FlickerParams& params); void setColor(uint32_t color, uint8_t brightness = 255); - uint32_t lerpColor(uint32_t color1, uint32_t color2, float t); + uint32_t lerpColor(uint32_t color1, uint32_t color2, float t) const; - Adafruit_NeoPixel _strip; - hardware_LedConfig _currentConfig; - unsigned long _startTime; - uint8_t _pulseState; - unsigned long _lastPulseTime; - uint8_t _fadeIndex; - unsigned long _lastFadeTime; - uint32_t _fadeCurrentColor; - uint32_t _fadeTargetColor; - float _fadeProgress; - unsigned long _fadeStartTime; - bool _isActive; -}; + Adafruit_NeoPixel m_strip; + hardware_LedConfig m_currentConfig = hardware_LedConfig_init_default; + unsigned long m_startTime; + uint8_t m_pulseState; + unsigned long m_lastPulseTime; + uint8_t m_fadeIndex; + unsigned long m_lastFadeTime; + uint32_t m_fadeCurrentColor; + uint32_t m_fadeTargetColor; + float m_fadeProgress; + unsigned long m_fadeStartTime; + bool m_isActive; + AnimationCallback m_callback = nullptr; +}; \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 895464d..caac4be 100644 --- a/platformio.ini +++ b/platformio.ini @@ -18,6 +18,7 @@ board_build.filesystem = littlefs lib_deps = miguelbalboa/MFRC522@^1.4.12 adafruit/Adafruit NeoPixel@^1.15.1 + fastled/FastLED@^3.10.3 nanopb/Nanopb@^0.4.91 custom_nanopb_protos = +