-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Replace NeoPixelBus with TasmotaLED on ESP32x (#22556)
* Replace NeoPixelBus with TasmotaLED on ESP32x * update changelog
- Loading branch information
1 parent
8cb9345
commit db0287e
Showing
19 changed files
with
3,080 additions
and
1,250 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"name": "TasmotaLED", | ||
"version": "0.1", | ||
"keywords": [ | ||
"ws2816", "sk6812", "leds" | ||
], | ||
"description": "Lightweight implementation for adressable leds.", | ||
"repository": | ||
{ | ||
"type": "git", | ||
"url": "https://github.com/arendst/Tasmota/lib/lib_basic/TasmotaLED" | ||
}, | ||
"frameworks": "arduino", | ||
"platforms": [ | ||
"espressif32" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,237 @@ | ||
/* | ||
TasmotaLED.cpp - Lightweight implementation for adressable leds. | ||
Copyright (C) 2024 Stephan Hadinger | ||
This library is free software: you can redistribute it and/or modify | ||
it under the terms of the GNU General Public License as published by | ||
the Free Software Foundation, either version 3 of the License, or | ||
(at your option) any later version. | ||
This program is distributed in the hope that it will be useful, | ||
but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
GNU General Public License for more details. | ||
You should have received a copy of the GNU General Public License | ||
along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#include <Arduino.h> | ||
#ifdef ESP32 | ||
|
||
#include "TasmotaLEDPusher.h" | ||
#include "TasmotaLED.h" | ||
|
||
// DRAM_ATTR to force in IRAM because we use this in show loop | ||
static const DRAM_ATTR uint8_t TASMOTALED_CHANNEL_ORDERS[6][3] = { | ||
{1, 0, 2}, // GRB (0) | ||
{2, 0, 1}, // GBR (1) | ||
{0, 1, 2}, // RGB (2) | ||
{0, 2, 1}, // RBG (3) | ||
{2, 1, 0}, // BRG (4) | ||
{1, 2, 0} // BGR (5) | ||
}; | ||
|
||
static const TasmotaLED_Timing TasmotaLED_Timings[] = { | ||
// WS2812 | ||
// RmtBit0 0x00228010 RmtBit1 0x00128020 RmtReset 0x800207D0 | ||
{ | ||
.T0H = 400, | ||
.T0L = 850, | ||
.T1H = 800, | ||
.T1L = 450, | ||
.Reset = 80000 // it is 50000 for WS2812, but for compatibility with SK6812, we raise to 80000 | ||
}, | ||
// SK6812 | ||
// RmtBit0 0x0024800C RmtBit1 0x00188018 RmtReset 0x80020C80 | ||
{ | ||
.T0H = 300, | ||
.T0L = 900, | ||
.T1H = 600, | ||
.T1L = 600, | ||
.Reset = 80000 | ||
}, | ||
}; | ||
|
||
// enable AddLog | ||
extern void AddLog(uint32_t loglevel, PGM_P formatP, ...); | ||
enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE}; | ||
|
||
|
||
TasmotaLED::TasmotaLED(uint16_t type, uint16_t num_leds) : | ||
_type(type), | ||
_pixel_order((type >> 4) & 0x07), | ||
_w_before(type & 0x08), | ||
_timing((type >> 8) & 0xFF), | ||
_started(false), | ||
_dirty(true), | ||
_raw_format(false), | ||
_pixel_count(num_leds), | ||
_buf_work(nullptr), | ||
_buf_show(nullptr), | ||
_pixel_matrix(&TASMOTALED_CHANNEL_ORDERS[0]), | ||
_pusher(nullptr) | ||
{ | ||
if (_timing > (TasmotaLed_TimingEnd >> 8)) { | ||
_timing = 0; | ||
} | ||
switch (_type & 0x0F) { | ||
// case TasmotaLed_1_W: | ||
// _pixel_size = 1; | ||
// break; | ||
case TasmotaLed_4_WRGB: | ||
_pixel_size = 4; | ||
break; | ||
case TasmotaLed_3_RGB: | ||
default: // fallback | ||
_pixel_size = 3; | ||
break; | ||
} | ||
|
||
_pixel_matrix = &TASMOTALED_CHANNEL_ORDERS[_pixel_order]; | ||
|
||
_buf_work = new uint8_t[_pixel_count * _pixel_size]; | ||
memset(_buf_work, 0, _pixel_count * _pixel_size); | ||
_buf_show = new uint8_t[_pixel_count * _pixel_size]; | ||
memset(_buf_show, 0, _pixel_count * _pixel_size); | ||
// AddLog(LOG_LEVEL_DEBUG, "LED: type=0x%04X pixel_order=0x%02X _timing=%i ", _type, _pixel_order, _timing); | ||
} | ||
|
||
TasmotaLED::~TasmotaLED() { | ||
if (_pusher) { | ||
delete _pusher; | ||
_pusher = nullptr; | ||
} | ||
delete _buf_work; | ||
_buf_work = nullptr; | ||
delete _buf_show; | ||
_buf_show = nullptr; | ||
} | ||
|
||
// Color is passed as 0xWWRRGGBB and copied as WWRRGGBB in _buf_work | ||
void TasmotaLED::ClearTo(uint32_t wrgb, int32_t first, int32_t last) { | ||
// adjust first and last to be in range of 0 to _pixel_count-1 | ||
if (first <0) { first += _pixel_count; } | ||
if (last <0) { last += _pixel_count; } | ||
if (first < 0) { first = 0; } | ||
if (last >= _pixel_count) { last = _pixel_count - 1; } | ||
if (first > last) { return; } | ||
// adjust to pixel format | ||
uint8_t b0 = (wrgb >> 24) & 0xFF; | ||
uint8_t b1 = (wrgb >> 16) & 0xFF; | ||
uint8_t b2 = (wrgb >> 8) & 0xFF; | ||
uint8_t b3 = (wrgb ) & 0xFF; | ||
|
||
if ((b0 | b1 | b2 | b3) == 0) { | ||
// special version for clearing to black | ||
memset(_buf_work + first * _pixel_size, 0, (last - first + 1) * _pixel_size); | ||
} else { | ||
// fill sub-buffer with RRGGBB or WWRRGGBB (or raw) | ||
uint8_t *buf = _buf_work + first * _pixel_size; | ||
for (uint32_t i = first; i <= last; i++) { | ||
if (_pixel_size == 4) { *buf++ = b0;} | ||
*buf++ = b1; | ||
*buf++ = b2; | ||
*buf++ = b3; | ||
} | ||
} | ||
} | ||
|
||
void TasmotaLED::Show(void) { | ||
if (_pusher) { | ||
_dirty = false; // we don't use the _dirty attribute and always show | ||
|
||
// copy the input buffer to the work buffer in format to be understood by LED strip | ||
if (_raw_format) { | ||
memmove(_buf_show, _buf_work, _pixel_count * _pixel_size); // copy buffer in next buffer so we start with the current content | ||
} else { | ||
uint8_t *buf_from = _buf_work; | ||
uint8_t *buf_to = _buf_show; | ||
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++) { | ||
buf_to[(*_pixel_matrix)[0]] = buf_from[0]; // R | ||
buf_to[(*_pixel_matrix)[1]] = buf_from[1]; // G | ||
buf_to[(*_pixel_matrix)[2]] = buf_from[2]; // B | ||
buf_to += 3; | ||
buf_from += 3; | ||
} | ||
} else if (_pixel_size == 4) { | ||
for (uint32_t i = 0; i < _pixel_count; i++) { | ||
if (_w_before) { *buf_to++ = buf_from[3]; } | ||
buf_to[(*_pixel_matrix)[0]] = buf_from[0]; // R | ||
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; | ||
} | ||
} | ||
} | ||
_pusher->Push(_buf_show); // push to leds | ||
} | ||
} | ||
|
||
void TasmotaLED::SetPixelColor(int32_t index, uint32_t wrgb) { | ||
if (index < 0) { index += _pixel_count; } | ||
if ((index >= 0) && (index < _pixel_count)) { | ||
uint8_t *buf = _buf_work + index * _pixel_size; | ||
uint8_t b0 = (wrgb >> 24) & 0xFF; | ||
uint8_t b1 = (wrgb >> 16) & 0xFF; | ||
uint8_t b2 = (wrgb >> 8) & 0xFF; | ||
uint8_t b3 = (wrgb ) & 0xFF; | ||
|
||
if (_pixel_size == 4) { *buf++ = b0;} | ||
*buf++ = b1; | ||
*buf++ = b2; | ||
*buf++ = b3; | ||
_dirty = true; | ||
} | ||
} | ||
|
||
uint32_t TasmotaLED::GetPixelColor(int32_t index) { | ||
if (index < 0) { index += _pixel_count; } | ||
if ((index >= 0) && (index < _pixel_count)) { | ||
uint8_t *buf = _buf_work + index * _pixel_size; | ||
uint32_t wrgb = 0; | ||
if (_pixel_size == 4) { wrgb = (*buf++) << 24; } | ||
wrgb |= (*buf++) << 16; | ||
wrgb |= (*buf++) << 8; | ||
wrgb |= (*buf++); | ||
return wrgb; | ||
} else { | ||
return 0; | ||
} | ||
} | ||
|
||
void TasmotaLED::SetPusher(TasmotaLEDPusher *pusher) { | ||
if (_pusher) { | ||
delete _pusher; | ||
} | ||
_pusher = pusher; | ||
_started = false; | ||
} | ||
|
||
bool TasmotaLED::Begin(void) { | ||
if (_pusher) { | ||
if (_started) { | ||
return true; | ||
} else { | ||
const TasmotaLED_Timing * timing = &TasmotaLED_Timings[_timing]; | ||
// AddLog(LOG_LEVEL_DEBUG, "LED: T0H=%i T0L=%i T1H=%i T1L=%i Reset=%i", timing.T0H, timing.T0L, timing.T1H, timing.T1L, timing.Reset); | ||
return _pusher->Begin(_pixel_count, _pixel_size, timing); | ||
} | ||
} else { | ||
return false; | ||
} | ||
} | ||
|
||
bool TasmotaLED::CanShow(void) const { | ||
if (_pusher) { | ||
return _pusher->CanShow(); | ||
} | ||
return false; | ||
} | ||
|
||
#endif // ESP32 |
Oops, something went wrong.