This commit is contained in:
2025-10-04 11:49:53 +02:00
parent 697e6fd11f
commit c65050cd44
3 changed files with 145 additions and 72 deletions
+117 -55
View File
@@ -1,113 +1,171 @@
#include "hardware_led.hpp" #include "hardware_led.hpp"
#include <Arduino.h> #include <Arduino.h>
#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) 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() { void HardwareLed::begin() {
_strip.begin(); m_strip.begin();
_strip.show(); // Turn off m_strip.show();
randomSeed(analogRead(0));
} }
void HardwareLed::end() { void HardwareLed::end() {
_strip.clear(); m_strip.clear();
_strip.show(); m_strip.show();
} }
void HardwareLed::update() { void HardwareLed::update() {
if (!_isActive) return; static unsigned long lastUpdate = 0;
unsigned long now = millis(); unsigned long now = millis();
if (_currentConfig.duration_ms > 0 && now - _startTime >= _currentConfig.duration_ms) { if (now - lastUpdate < 10) return; // Limit to ~100 FPS
_isActive = false; lastUpdate = now;
_strip.clear();
_strip.show(); 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; return;
} }
switch (_currentConfig.which_animation_params) { switch (m_currentConfig.which_animation_params) {
case hardware_LedConfig_static_params_tag: case hardware_LedConfig_static_params_tag:
applyStatic(_currentConfig.animation_params.static_params); applyStatic(m_currentConfig.animation_params.static_params);
break; break;
case hardware_LedConfig_pulse_params_tag: case hardware_LedConfig_pulse_params_tag:
applyPulse(_currentConfig.animation_params.pulse_params); applyPulse(m_currentConfig.animation_params.pulse_params);
break; break;
case hardware_LedConfig_fade_params_tag: case hardware_LedConfig_fade_params_tag:
applyFade(_currentConfig.animation_params.fade_params); applyFade(m_currentConfig.animation_params.fade_params);
break; break;
case hardware_LedConfig_flicker_params_tag: case hardware_LedConfig_flicker_params_tag:
applyFlicker(_currentConfig.animation_params.flicker_params); applyFlicker(m_currentConfig.animation_params.flicker_params);
break; break;
default: default:
LOG("Error: Unknown animation type");
break; break;
} }
} }
void HardwareLed::set(const hardware_LedConfig& config) { void HardwareLed::set(const hardware_LedConfig& config) {
_currentConfig = config; if (config.brightness > 255) {
_startTime = millis(); LOG("Error: Brightness exceeds 255");
_isActive = true; return;
_pulseState = 0; }
_lastPulseTime = _startTime; if (config.which_animation_params == hardware_LedConfig_fade_params_tag &&
_fadeIndex = 0; (config.animation_params.fade_params.colors_count == 0 ||
_lastFadeTime = _startTime; config.animation_params.fade_params.colors_count > 5)) {
if (_currentConfig.which_animation_params == 5 && _currentConfig.animation_params.fade_params.colors_count > 0) { LOG("Error: Invalid colors_count in FadeParams");
_fadeCurrentColor = _currentConfig.animation_params.fade_params.colors[0]; m_isActive = false;
_fadeTargetColor = _currentConfig.animation_params.fade_params.colors[0]; m_strip.clear();
_fadeProgress = 1.0f; m_strip.show();
_fadeStartTime = _startTime; 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(); update();
} }
void HardwareLed::applyStatic(const hardware_StaticParams& params) { 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) { void HardwareLed::applyPulse(const hardware_PulseParams& params) {
unsigned long now = millis(); 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); 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); setColor(params.color, pulseBrightness);
} }
void HardwareLed::applyFade(const hardware_FadeParams& params) { void HardwareLed::applyFade(const hardware_FadeParams& params) {
if (params.colors_count == 0) return; if (params.colors_count == 0 || params.colors_count > 5) {
unsigned long now = millis(); LOG("Error: Invalid colors_count in FadeParams");
if (_fadeProgress >= 1.0f) { return;
// Time to switch to next color
_fadeIndex = (_fadeIndex + 1) % params.colors_count;
_fadeCurrentColor = _fadeTargetColor;
_fadeTargetColor = params.colors[_fadeIndex];
_fadeProgress = 0.0f;
_fadeStartTime = now;
} }
_fadeProgress = (now - _fadeStartTime) / (float)params.speed_ms; unsigned long now = millis();
if (_fadeProgress > 1.0f) _fadeProgress = 1.0f; if (m_fadeProgress >= 1.0f) {
uint32_t interpolatedColor = lerpColor(_fadeCurrentColor, _fadeTargetColor, _fadeProgress); m_fadeIndex = (m_fadeIndex + 1) % params.colors_count;
setColor(interpolatedColor, _currentConfig.brightness); 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) { void HardwareLed::applyFlicker(const hardware_FlickerParams& params) {
// Simple random flicker based on intensity uint32_t intensity = min(params.intensity, 100U); // Clamp to 0-100
uint8_t threshold = map(params.intensity, 0, 100, 0, 255); uint8_t threshold = map(intensity, 0, 100, 0, 255);
if (random(255) < threshold) { bool showPixel = random(255) < threshold;
setColor(params.color, _currentConfig.brightness); if (showPixel != (m_strip.getPixelColor(0) != 0)) {
if (showPixel) {
setColor(params.color, m_currentConfig.brightness);
} else { } else {
_strip.clear(); m_strip.clear();
_strip.show(); m_strip.show();
}
} }
} }
void HardwareLed::setColor(uint32_t color, uint8_t brightness) { void HardwareLed::setColor(uint32_t color, uint8_t brightness) {
_strip.setBrightness(brightness); uint8_t r = (color >> 16) & 0xFF;
_strip.setPixelColor(0, color); uint8_t g = (color >> 8) & 0xFF;
_strip.show(); 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 r1 = (color1 >> 16) & 0xFF;
uint8_t g1 = (color1 >> 8) & 0xFF; uint8_t g1 = (color1 >> 8) & 0xFF;
uint8_t b1 = color1 & 0xFF; uint8_t b1 = color1 & 0xFF;
@@ -119,3 +177,7 @@ uint32_t HardwareLed::lerpColor(uint32_t color1, uint32_t color2, float t) {
uint8_t b = b1 + (b2 - b1) * t; uint8_t b = b1 + (b2 - b1) * t;
return (r << 16) | (g << 8) | b; return (r << 16) | (g << 8) | b;
} }
float HardwareLed::estimateCurrent_mA() const {
return m_strip.numPixels() * (m_currentConfig.brightness / 255.0f) * 60.0f;
}
+25 -15
View File
@@ -3,32 +3,42 @@
#include "hardware.pb.h" #include "hardware.pb.h"
#include <Adafruit_NeoPixel.h> #include <Adafruit_NeoPixel.h>
/**
* @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 { class HardwareLed {
public: public:
using AnimationCallback = void (*)();
HardwareLed(uint8_t pin, uint8_t numPixels = 1); HardwareLed(uint8_t pin, uint8_t numPixels = 1);
void begin(); void begin();
void end(); void end();
void update(); void update(); // Removed const
void set(const hardware_LedConfig& config); void set(const hardware_LedConfig& config);
void setAnimationCallback(AnimationCallback cb) { m_callback = cb; }
float estimateCurrent_mA() const;
private: private:
void applyStatic(const hardware_StaticParams& params); void applyStatic(const hardware_StaticParams& params);
void applyPulse(const hardware_PulseParams& 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 applyFlicker(const hardware_FlickerParams& params);
void setColor(uint32_t color, uint8_t brightness = 255); 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; Adafruit_NeoPixel m_strip;
hardware_LedConfig _currentConfig; hardware_LedConfig m_currentConfig = hardware_LedConfig_init_default;
unsigned long _startTime; unsigned long m_startTime;
uint8_t _pulseState; uint8_t m_pulseState;
unsigned long _lastPulseTime; unsigned long m_lastPulseTime;
uint8_t _fadeIndex; uint8_t m_fadeIndex;
unsigned long _lastFadeTime; unsigned long m_lastFadeTime;
uint32_t _fadeCurrentColor; uint32_t m_fadeCurrentColor;
uint32_t _fadeTargetColor; uint32_t m_fadeTargetColor;
float _fadeProgress; float m_fadeProgress;
unsigned long _fadeStartTime; unsigned long m_fadeStartTime;
bool _isActive; bool m_isActive;
AnimationCallback m_callback = nullptr;
}; };
+1
View File
@@ -18,6 +18,7 @@ board_build.filesystem = littlefs
lib_deps = lib_deps =
miguelbalboa/MFRC522@^1.4.12 miguelbalboa/MFRC522@^1.4.12
adafruit/Adafruit NeoPixel@^1.15.1 adafruit/Adafruit NeoPixel@^1.15.1
fastled/FastLED@^3.10.3
nanopb/Nanopb@^0.4.91 nanopb/Nanopb@^0.4.91
custom_nanopb_protos = custom_nanopb_protos =
+<proto/hardware.proto> +<proto/hardware.proto>