WS2812 and Berry animation support for reverse-order LED strip (#24138)

This commit is contained in:
s-hadinger 2025-11-18 23:05:02 +01:00 committed by GitHub
parent 9340e218bd
commit 4676db2ede
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 32 additions and 17 deletions

View File

@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file.
## [15.1.0.2]
### Added
- WS2812 and Berry animation support for reverse-order LED strip
### Breaking Changed

View File

@ -57,10 +57,10 @@ TasmotaLED is designed with the following principles:
┌─────────────────────────────────────────────────────────────┐
│ TasmotaLED Class │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ _buf_work │ │ _buf_show │ │ Pixel Format │ │
│ │ (editable) │─▶│ (internal) │ │ Conversion │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ │ _buf_work │ │ _buf_show │ │ Pixel Format │
│ │ (editable) │─▶│ (internal) │ │ Conversion │
│ └──────────────┘ └──────────────┘ └──────────────┘
└────────────────────┬────────────────────────────────────────┘
@ -116,6 +116,7 @@ TasmotaLED uses a dual-buffer system:
│ - _type: uint16_t │
│ - _pixel_order: uint8_t │
│ - _w_before: bool │
│ - _pixel_reverse: bool │
│ - _timing: uint8_t │
│ - _started: bool │
│ - _dirty: bool │
@ -144,6 +145,7 @@ TasmotaLED uses a dual-buffer system:
│ + GetType(): uint8_t │
│ + IsDirty(): bool │
│ + Dirty(): void │
│ + SetPixelReverse(bool): void │
│ + SetRawFormat(raw): void │
└─────────────────────────────────────────────────────────────┘
@ -171,18 +173,18 @@ TasmotaLED uses a dual-buffer system:
┌─────────────────┼─────────────────┐
│ │ │
┌─────────┴──────────┐ ┌────┴────────┐ ┌─────┴──────────┐
│ TasmotaLEDPusherRMT│ │TasmotaLED │ │ TasmotaLED │
│ │ │PusherSPI │ │PusherI2S │
├────────────────────┤ ├─────────────┤ ├────────────────┤
┌─────────┴──────────┐ ┌────┴────────┐ ┌─────┴──────────┐
│ TasmotaLEDPusherRMT│ │TasmotaLED │ │ TasmotaLED │
│ │ │PusherSPI │ │PusherI2S │
├────────────────────┤ ├─────────────┤ ├────────────────┤
│ - _pin: int8_t │ │- _pin: int8_t│ │(Future) │
│ - _channel: handle │ │- _spi_strip │ │ │
│ - _led_encoder │ │- _with_dma │ │ │
│ - _tx_config │ │ │ │ │
├────────────────────┤ ├─────────────┤ ├────────────────┤
│ - _channel: handle │ │- _spi_strip │ │ │
│ - _led_encoder │ │- _with_dma │ │ │
│ - _tx_config │ │ │ │ │
├────────────────────┤ ├─────────────┤ ├────────────────┤
│ + Push(): bool │ │+ Push(): bool│ │ │
│ + CanShow(): bool │ │+ CanShow() │ │ │
└────────────────────┘ └─────────────┘ └────────────────┘
│ + CanShow(): bool │ │+ CanShow() │ │ │
└────────────────────┘ └─────────────┘ └────────────────┘
```

View File

@ -63,6 +63,7 @@ enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_D
TasmotaLED::TasmotaLED(uint16_t type, uint16_t num_leds) :
_type(type),
_pixel_reverse(false),
_timing((type >> 8) & 0xFF),
_started(false),
_dirty(true),
@ -175,6 +176,11 @@ void TasmotaLED::Show(void) {
} else {
uint8_t *buf_from = _buf_work;
uint8_t *buf_to = _buf_show;
int32_t pixel_incr = _pixel_size; // will be set to negative if reverse
if (_pixel_reverse) {
buf_from += (_pixel_count - 1) * _pixel_size;
pixel_incr = -pixel_incr;
}
if (_pixel_size == 3) {
// copying with swapping 512 pixels (1536 bytes) takes 124 microseconds to copy, so it's negligeable
for (uint32_t i = 0; i < _pixel_count; i++) {
@ -182,7 +188,7 @@ void TasmotaLED::Show(void) {
buf_to[(*_pixel_matrix)[1]] = buf_from[1]; // G
buf_to[(*_pixel_matrix)[2]] = buf_from[2]; // B
buf_to += 3;
buf_from += 3;
buf_from += pixel_incr;
}
} else if (_pixel_size == 4) {
for (uint32_t i = 0; i < _pixel_count; i++) {
@ -191,8 +197,8 @@ void TasmotaLED::Show(void) {
buf_to[(*_pixel_matrix)[1]] = buf_from[1]; // G
buf_to[(*_pixel_matrix)[2]] = buf_from[2]; // B
if (!_w_before) { *buf_to++ = buf_from[3]; }
buf_to += 3; // one increment already happened
buf_from += 4;
buf_to += 4; // one increment already happened
buf_from += pixel_incr;
}
}
}

View File

@ -96,6 +96,8 @@ public:
void SetPixelSubType(uint8_t type); // change only Pixel order and pixel size
void _adjustSubType(void);
inline void SetPixelReverse(bool reverse) { _pixel_reverse = reverse; }
bool Begin(void);
void SetPusher(TasmotaLEDPusher *pusher); // needs to be called before `Begin()`, sets the hardware implementation
void Show(void); // pushes the pixels to the LED strip
@ -118,6 +120,7 @@ protected:
uint16_t _type; // the composite type
uint8_t _pixel_order; // permutation between RGB and position of W
bool _w_before; // true if W channel comes first (4 channels only)
bool _pixel_reverse; // display LED strip in reverse order
uint8_t _timing; // timing code for strip, 0=WS2812, 1=SK6812...
bool _started; // true if the hardware implementation is configured
bool _dirty; // for NeoPixelBus compatibility, but ignored by `Push()`

View File

@ -636,6 +636,7 @@ bool Ws2812InitStrip(void)
}
uint16_t led_type = Ws2812SettingsToLedType();
strip = new TasmotaLED(led_type, Settings->light_pixels);
strip->SetPixelReverse(Settings->light_pixels_reverse);
strip->SetPusher(pusher);
strip->Begin();
@ -651,6 +652,7 @@ bool Ws2812ChangePixelCount(void)
return true;
}
strip->SetPixelCount(Settings->light_pixels);
strip->SetPixelReverse(Settings->light_pixels_reverse);
Ws2812Clear();
return true;
}
@ -662,6 +664,7 @@ bool Ws2812ChangePixelType(bool clear)
}
uint16_t led_type = Ws2812SettingsToLedType();
strip->SetPixelSubType(led_type & 0xFF); // just submit the lower part
strip->SetPixelReverse(Settings->light_pixels_reverse);
if (clear) {
Ws2812Clear();
} else {