Merge pull request #4484 from blazoncek/parallel-I2S

WWA strip support & parallel I2S for S2/S3 (bumping outputs from 5/4 to 12)
This commit is contained in:
Blaž Kristan 2025-02-13 19:10:37 +01:00 committed by GitHub
commit a0c55c6406
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 813 additions and 673 deletions

1
.gitignore vendored
View File

@ -15,6 +15,7 @@ wled-update.sh
/build_output/ /build_output/
/node_modules/ /node_modules/
/logs/
/wled00/extLibs /wled00/extLibs
/wled00/LittleFS /wled00/LittleFS

View File

@ -138,7 +138,7 @@ lib_compat_mode = strict
lib_deps = lib_deps =
fastled/FastLED @ 3.6.0 fastled/FastLED @ 3.6.0
IRremoteESP8266 @ 2.8.2 IRremoteESP8266 @ 2.8.2
makuna/NeoPixelBus @ 2.8.0 makuna/NeoPixelBus @ 2.8.3
#https://github.com/makuna/NeoPixelBus.git#CoreShaderBeta #https://github.com/makuna/NeoPixelBus.git#CoreShaderBeta
https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.4.0 https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.4.0
# for I2C interface # for I2C interface

View File

@ -1,3 +1,4 @@
#pragma once
/* /*
WS2812FX.h - Library for WS2812 LED effects. WS2812FX.h - Library for WS2812 LED effects.
Harm Aldick - 2016 Harm Aldick - 2016
@ -8,12 +9,15 @@
Adapted from code originally licensed under the MIT license Adapted from code originally licensed under the MIT license
Modified for WLED Modified for WLED
Segment class/struct (c) 2022 Blaz Kristan (@blazoncek)
*/ */
#ifndef WS2812FX_h #ifndef WS2812FX_h
#define WS2812FX_h #define WS2812FX_h
#include <vector> #include <vector>
#include "wled.h"
#include "const.h" #include "const.h"
#include "bus_manager.h" #include "bus_manager.h"
@ -74,16 +78,13 @@ extern byte realtimeMode; // used in getMappedPixelIndex()
#define MAX_NUM_SEGMENTS 16 #define MAX_NUM_SEGMENTS 16
/* How much data bytes all segments combined may allocate */ /* How much data bytes all segments combined may allocate */
#define MAX_SEGMENT_DATA 5120 #define MAX_SEGMENT_DATA 5120
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
#define MAX_NUM_SEGMENTS 20
#define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*512) // 10k by default (S2 is short on free RAM)
#else #else
#ifndef MAX_NUM_SEGMENTS #define MAX_NUM_SEGMENTS 32 // warning: going beyond 32 may consume too much RAM for stable operation
#define MAX_NUM_SEGMENTS 32
#endif
#if defined(ARDUINO_ARCH_ESP32S2)
#define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*768) // 24k by default (S2 is short on free RAM)
#else
#define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*1280) // 40k by default #define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*1280) // 40k by default
#endif #endif
#endif
/* How much data bytes each segment should max allocate to leave enough space for other segments, /* How much data bytes each segment should max allocate to leave enough space for other segments,
assuming each segment uses the same amount of data. 256 for ESP8266, 640 for ESP32. */ assuming each segment uses the same amount of data. 256 for ESP8266, 640 for ESP32. */
@ -571,6 +572,8 @@ typedef struct Segment {
inline uint16_t groupLength() const { return grouping + spacing; } inline uint16_t groupLength() const { return grouping + spacing; }
inline uint8_t getLightCapabilities() const { return _capabilities; } inline uint8_t getLightCapabilities() const { return _capabilities; }
inline void deactivate() { setGeometry(0,0); } inline void deactivate() { setGeometry(0,0); }
inline Segment &clearName() { if (name) free(name); name = nullptr; return *this; }
inline Segment &setName(const String &name) { return setName(name.c_str()); }
inline static unsigned getUsedSegmentData() { return Segment::_usedSegmentData; } inline static unsigned getUsedSegmentData() { return Segment::_usedSegmentData; }
inline static void addUsedSegmentData(int len) { Segment::_usedSegmentData += len; } inline static void addUsedSegmentData(int len) { Segment::_usedSegmentData += len; }
@ -593,6 +596,7 @@ typedef struct Segment {
Segment &setOption(uint8_t n, bool val); Segment &setOption(uint8_t n, bool val);
Segment &setMode(uint8_t fx, bool loadDefaults = false); Segment &setMode(uint8_t fx, bool loadDefaults = false);
Segment &setPalette(uint8_t pal); Segment &setPalette(uint8_t pal);
Segment &setName(const char* name);
uint8_t differs(const Segment& b) const; uint8_t differs(const Segment& b) const;
void refreshLightCapabilities(); void refreshLightCapabilities();

View File

@ -649,6 +649,20 @@ Segment &Segment::setPalette(uint8_t pal) {
return *this; return *this;
} }
Segment &Segment::setName(const char *newName) {
if (newName) {
const int newLen = min(strlen(newName), (size_t)WLED_MAX_SEGNAME_LEN);
if (newLen) {
if (name) name = static_cast<char*>(realloc(name, newLen+1));
else name = static_cast<char*>(malloc(newLen+1));
if (name) strlcpy(name, newName, newLen+1);
name[newLen] = 0;
return *this;
}
}
return clearName();
}
// 2D matrix // 2D matrix
unsigned Segment::virtualWidth() const { unsigned Segment::virtualWidth() const {
unsigned groupLen = groupLength(); unsigned groupLen = groupLength();
@ -1311,6 +1325,34 @@ void WS2812FX::finalizeInit() {
_hasWhiteChannel = _isOffRefreshRequired = false; _hasWhiteChannel = _isOffRefreshRequired = false;
unsigned digitalCount = 0;
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
// determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT)
unsigned maxLedsOnBus = 0;
for (const auto &bus : busConfigs) {
if (Bus::isDigital(bus.type) && !Bus::is2Pin(bus.type)) {
digitalCount++;
if (bus.count > maxLedsOnBus) maxLedsOnBus = bus.count;
}
}
DEBUG_PRINTF_P(PSTR("Maximum LEDs on a bus: %u\nDigital buses: %u\n"), maxLedsOnBus, digitalCount);
// we may remove 300 LEDs per bus limit when NeoPixelBus is updated beyond 2.9.0
if (maxLedsOnBus <= 300 && useParallelI2S) BusManager::useParallelOutput(); // must call before creating buses
else useParallelI2S = false; // enforce single I2S
#endif
// create buses/outputs
unsigned mem = 0;
digitalCount = 0;
for (const auto &bus : busConfigs) {
mem += bus.memUsage(Bus::isDigital(bus.type) && !Bus::is2Pin(bus.type) ? digitalCount++ : 0); // includes global buffer
if (mem <= MAX_LED_MEMORY) {
if (BusManager::add(bus) == -1) break;
} else DEBUG_PRINTF_P(PSTR("Out of LED memory! Bus %d (%d) #%u not created."), (int)bus.type, (int)bus.count, digitalCount);
}
busConfigs.clear();
busConfigs.shrink_to_fit();
//if busses failed to load, add default (fresh install, FS issue, ...) //if busses failed to load, add default (fresh install, FS issue, ...)
if (BusManager::getNumBusses() == 0) { if (BusManager::getNumBusses() == 0) {
DEBUG_PRINTLN(F("No busses, init default")); DEBUG_PRINTLN(F("No busses, init default"));
@ -1326,6 +1368,7 @@ void WS2812FX::finalizeInit() {
unsigned prevLen = 0; unsigned prevLen = 0;
unsigned pinsIndex = 0; unsigned pinsIndex = 0;
digitalCount = 0;
for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
uint8_t defPin[OUTPUT_MAX_PINS]; uint8_t defPin[OUTPUT_MAX_PINS];
// if we have less types than requested outputs and they do not align, use last known type to set current type // if we have less types than requested outputs and they do not align, use last known type to set current type
@ -1390,9 +1433,11 @@ void WS2812FX::finalizeInit() {
if (Bus::isPWM(dataType) || Bus::isOnOff(dataType)) count = 1; if (Bus::isPWM(dataType) || Bus::isOnOff(dataType)) count = 1;
prevLen += count; prevLen += count;
BusConfig defCfg = BusConfig(dataType, defPin, start, count, DEFAULT_LED_COLOR_ORDER, false, 0, RGBW_MODE_MANUAL_ONLY, 0, useGlobalLedBuffer); BusConfig defCfg = BusConfig(dataType, defPin, start, count, DEFAULT_LED_COLOR_ORDER, false, 0, RGBW_MODE_MANUAL_ONLY, 0, useGlobalLedBuffer);
mem += defCfg.memUsage(Bus::isDigital(dataType) && !Bus::is2Pin(dataType) ? digitalCount++ : 0);
if (BusManager::add(defCfg) == -1) break; if (BusManager::add(defCfg) == -1) break;
} }
} }
DEBUG_PRINTF_P(PSTR("LED buffer size: %uB/%uB\n"), mem, BusManager::memUsage());
_length = 0; _length = 0;
for (int i=0; i<BusManager::getNumBusses(); i++) { for (int i=0; i<BusManager::getNumBusses(); i++) {
@ -1409,6 +1454,7 @@ void WS2812FX::finalizeInit() {
// This must be done after all buses have been created, as some kinds (parallel I2S) interact // This must be done after all buses have been created, as some kinds (parallel I2S) interact
bus->begin(); bus->begin();
} }
DEBUG_PRINTF_P(PSTR("Heap after buses: %d\n"), ESP.getFreeHeap());
Segment::maxWidth = _length; Segment::maxWidth = _length;
Segment::maxHeight = 1; Segment::maxHeight = 1;

View File

@ -21,10 +21,12 @@
#endif #endif
#include "const.h" #include "const.h"
#include "pin_manager.h" #include "pin_manager.h"
#include "bus_wrapper.h"
#include "bus_manager.h" #include "bus_manager.h"
#include "bus_wrapper.h"
#include <bits/unique_ptr.h>
extern bool cctICused; extern bool cctICused;
extern bool useParallelI2S;
//colors.cpp //colors.cpp
uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb); uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
@ -32,28 +34,6 @@ uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
//udp.cpp //udp.cpp
uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, const uint8_t* buffer, uint8_t bri=255, bool isRGBW=false); uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, const uint8_t* buffer, uint8_t bri=255, bool isRGBW=false);
// enable additional debug output
#if defined(WLED_DEBUG_HOST)
#include "net_debug.h"
#define DEBUGOUT NetDebug
#else
#define DEBUGOUT Serial
#endif
#ifdef WLED_DEBUG
#ifndef ESP8266
#include <rom/rtc.h>
#endif
#define DEBUG_PRINT(x) DEBUGOUT.print(x)
#define DEBUG_PRINTLN(x) DEBUGOUT.println(x)
#define DEBUG_PRINTF(x...) DEBUGOUT.printf(x)
#define DEBUG_PRINTF_P(x...) DEBUGOUT.printf_P(x)
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x)
#define DEBUG_PRINTF(x...)
#define DEBUG_PRINTF_P(x...)
#endif
//color mangling macros //color mangling macros
#define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b)))) #define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b))))
@ -66,6 +46,7 @@ uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, const
bool ColorOrderMap::add(uint16_t start, uint16_t len, uint8_t colorOrder) { bool ColorOrderMap::add(uint16_t start, uint16_t len, uint8_t colorOrder) {
if (count() >= WLED_MAX_COLOR_ORDER_MAPPINGS || len == 0 || (colorOrder & 0x0F) > COL_ORDER_MAX) return false; // upper nibble contains W swap information if (count() >= WLED_MAX_COLOR_ORDER_MAPPINGS || len == 0 || (colorOrder & 0x0F) > COL_ORDER_MAX) return false; // upper nibble contains W swap information
_mappings.push_back({start,len,colorOrder}); _mappings.push_back({start,len,colorOrder});
DEBUGBUS_PRINTF_P(PSTR("Bus: Add COM (%d,%d,%d)\n"), (int)start, (int)len, (int)colorOrder);
return true; return true;
} }
@ -119,10 +100,14 @@ uint32_t Bus::autoWhiteCalc(uint32_t c) const {
} }
uint8_t *Bus::allocateData(size_t size) { uint8_t *Bus::allocateData(size_t size) {
if (_data) free(_data); // should not happen, but for safety freeData(); // should not happen, but for safety
return _data = (uint8_t *)(size>0 ? calloc(size, sizeof(uint8_t)) : nullptr); return _data = (uint8_t *)(size>0 ? calloc(size, sizeof(uint8_t)) : nullptr);
} }
void Bus::freeData() {
if (_data) free(_data);
_data = nullptr;
}
BusDigital::BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com) BusDigital::BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com)
: Bus(bc.type, bc.start, bc.autoWhite, bc.count, bc.reversed, (bc.refreshReq || bc.type == TYPE_TM1814)) : Bus(bc.type, bc.start, bc.autoWhite, bc.count, bc.reversed, (bc.refreshReq || bc.type == TYPE_TM1814))
@ -132,30 +117,41 @@ BusDigital::BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com
, _milliAmpsMax(bc.milliAmpsMax) , _milliAmpsMax(bc.milliAmpsMax)
, _colorOrderMap(com) , _colorOrderMap(com)
{ {
if (!isDigital(bc.type) || !bc.count) return; DEBUGBUS_PRINTLN(F("Bus: Creating digital bus."));
if (!PinManager::allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return; if (!isDigital(bc.type) || !bc.count) { DEBUGBUS_PRINTLN(F("Not digial or empty bus!")); return; }
if (!PinManager::allocatePin(bc.pins[0], true, PinOwner::BusDigital)) { DEBUGBUS_PRINTLN(F("Pin 0 allocated!")); return; }
_frequencykHz = 0U; _frequencykHz = 0U;
_pins[0] = bc.pins[0]; _pins[0] = bc.pins[0];
if (is2Pin(bc.type)) { if (is2Pin(bc.type)) {
if (!PinManager::allocatePin(bc.pins[1], true, PinOwner::BusDigital)) { if (!PinManager::allocatePin(bc.pins[1], true, PinOwner::BusDigital)) {
cleanup(); cleanup();
DEBUGBUS_PRINTLN(F("Pin 1 allocated!"));
return; return;
} }
_pins[1] = bc.pins[1]; _pins[1] = bc.pins[1];
_frequencykHz = bc.frequency ? bc.frequency : 2000U; // 2MHz clock if undefined _frequencykHz = bc.frequency ? bc.frequency : 2000U; // 2MHz clock if undefined
} }
_iType = PolyBus::getI(bc.type, _pins, nr); _iType = PolyBus::getI(bc.type, _pins, nr);
if (_iType == I_NONE) return; if (_iType == I_NONE) { DEBUGBUS_PRINTLN(F("Incorrect iType!")); return; }
_hasRgb = hasRGB(bc.type); _hasRgb = hasRGB(bc.type);
_hasWhite = hasWhite(bc.type); _hasWhite = hasWhite(bc.type);
_hasCCT = hasCCT(bc.type); _hasCCT = hasCCT(bc.type);
if (bc.doubleBuffer && !allocateData(bc.count * Bus::getNumberOfChannels(bc.type))) return; if (bc.doubleBuffer && !allocateData(bc.count * Bus::getNumberOfChannels(bc.type))) { DEBUGBUS_PRINTLN(F("Buffer allocation failed!")); return; }
//_buffering = bc.doubleBuffer; //_buffering = bc.doubleBuffer;
uint16_t lenToCreate = bc.count; uint16_t lenToCreate = bc.count;
if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(bc.count); // only needs a third of "RGB" LEDs for NeoPixelBus if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(bc.count); // only needs a third of "RGB" LEDs for NeoPixelBus
_busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr); _busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr);
_valid = (_busPtr != nullptr); _valid = (_busPtr != nullptr);
DEBUG_PRINTF_P(PSTR("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u). mA=%d/%d\n"), _valid?"S":"Uns", nr, bc.count, bc.type, _pins[0], is2Pin(bc.type)?_pins[1]:255, _iType, _milliAmpsPerLed, _milliAmpsMax); DEBUGBUS_PRINTF_P(PSTR("Bus: %successfully inited #%u (len:%u, type:%u (RGB:%d, W:%d, CCT:%d), pins:%u,%u [itype:%u] mA=%d/%d)\n"),
_valid?"S":"Uns",
(int)nr,
(int)bc.count,
(int)bc.type,
(int)_hasRgb, (int)_hasWhite, (int)_hasCCT,
(unsigned)_pins[0], is2Pin(bc.type)?(unsigned)_pins[1]:255U,
(unsigned)_iType,
(int)_milliAmpsPerLed, (int)_milliAmpsMax
);
} }
//DISCLAIMER //DISCLAIMER
@ -166,7 +162,7 @@ BusDigital::BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com
//I am NOT to be held liable for burned down garages or houses! //I am NOT to be held liable for burned down garages or houses!
// To disable brightness limiter we either set output max current to 0 or single LED current to 0 // To disable brightness limiter we either set output max current to 0 or single LED current to 0
uint8_t BusDigital::estimateCurrentAndLimitBri() { uint8_t BusDigital::estimateCurrentAndLimitBri() const {
bool useWackyWS2815PowerModel = false; bool useWackyWS2815PowerModel = false;
byte actualMilliampsPerLed = _milliAmpsPerLed; byte actualMilliampsPerLed = _milliAmpsPerLed;
@ -179,7 +175,7 @@ uint8_t BusDigital::estimateCurrentAndLimitBri() {
actualMilliampsPerLed = 12; // from testing an actual strip actualMilliampsPerLed = 12; // from testing an actual strip
} }
size_t powerBudget = (_milliAmpsMax - MA_FOR_ESP/BusManager::getNumBusses()); //80/120mA for ESP power unsigned powerBudget = (_milliAmpsMax - MA_FOR_ESP/BusManager::getNumBusses()); //80/120mA for ESP power
if (powerBudget > getLength()) { //each LED uses about 1mA in standby, exclude that from power budget if (powerBudget > getLength()) { //each LED uses about 1mA in standby, exclude that from power budget
powerBudget -= getLength(); powerBudget -= getLength();
} else { } else {
@ -204,26 +200,25 @@ uint8_t BusDigital::estimateCurrentAndLimitBri() {
} }
// powerSum has all the values of channels summed (max would be getLength()*765 as white is excluded) so convert to milliAmps // powerSum has all the values of channels summed (max would be getLength()*765 as white is excluded) so convert to milliAmps
busPowerSum = (busPowerSum * actualMilliampsPerLed) / 765; BusDigital::_milliAmpsTotal = (busPowerSum * actualMilliampsPerLed * _bri) / (765*255);
_milliAmpsTotal = busPowerSum * _bri / 255;
uint8_t newBri = _bri; uint8_t newBri = _bri;
if (busPowerSum * _bri / 255 > powerBudget) { //scale brightness down to stay in current limit if (BusDigital::_milliAmpsTotal > powerBudget) {
float scale = (float)(powerBudget * 255) / (float)(busPowerSum * _bri); //scale brightness down to stay in current limit
if (scale >= 1.0f) return _bri; unsigned scaleB = powerBudget * 255 / BusDigital::_milliAmpsTotal;
_milliAmpsTotal = ceilf((float)_milliAmpsTotal * scale); newBri = (_bri * scaleB) / 256 + 1;
uint8_t scaleB = min((int)(scale * 255), 255); BusDigital::_milliAmpsTotal = powerBudget;
newBri = unsigned(_bri * scaleB) / 256 + 1; //_milliAmpsTotal = (busPowerSum * actualMilliampsPerLed * newBri) / (765*255);
} }
return newBri; return newBri;
} }
void BusDigital::show() { void BusDigital::show() {
_milliAmpsTotal = 0; BusDigital::_milliAmpsTotal = 0;
if (!_valid) return; if (!_valid) return;
uint8_t cctWW = 0, cctCW = 0; uint8_t cctWW = 0, cctCW = 0;
unsigned newBri = estimateCurrentAndLimitBri(); // will fill _milliAmpsTotal unsigned newBri = estimateCurrentAndLimitBri(); // will fill _milliAmpsTotal (TODO: could use PolyBus::CalcTotalMilliAmpere())
if (newBri < _bri) PolyBus::setBrightness(_busPtr, _iType, newBri); // limit brightness to stay within current limits if (newBri < _bri) PolyBus::setBrightness(_busPtr, _iType, newBri); // limit brightness to stay within current limits
if (_data) { if (_data) {
@ -249,6 +244,7 @@ void BusDigital::show() {
// TODO: there is an issue if CCT is calculated from RGB value (_cct==-1), we cannot do that with double buffer // TODO: there is an issue if CCT is calculated from RGB value (_cct==-1), we cannot do that with double buffer
Bus::_cct = _data[offset+channels-1]; Bus::_cct = _data[offset+channels-1];
Bus::calculateCCT(c, cctWW, cctCW); Bus::calculateCCT(c, cctWW, cctCW);
if (_type == TYPE_WS2812_WWA) c = RGBW32(cctWW, cctCW, 0, W(c)); // may need swapping
} }
unsigned pix = i; unsigned pix = i;
if (_reversed) pix = _len - pix -1; if (_reversed) pix = _len - pix -1;
@ -334,8 +330,8 @@ void IRAM_ATTR BusDigital::setPixelColor(unsigned pix, uint32_t c) {
uint8_t cctWW = 0, cctCW = 0; uint8_t cctWW = 0, cctCW = 0;
Bus::calculateCCT(c, cctWW, cctCW); Bus::calculateCCT(c, cctWW, cctCW);
wwcw = (cctCW<<8) | cctWW; wwcw = (cctCW<<8) | cctWW;
if (_type == TYPE_WS2812_WWA) c = RGBW32(cctWW, cctCW, 0, W(c)); // may need swapping
} }
PolyBus::setPixelColor(_busPtr, _iType, pix, c, co, wwcw); PolyBus::setPixelColor(_busPtr, _iType, pix, c, co, wwcw);
} }
} }
@ -367,16 +363,24 @@ uint32_t IRAM_ATTR BusDigital::getPixelColor(unsigned pix) const {
case 2: c = RGBW32(b, b, b, b); break; case 2: c = RGBW32(b, b, b, b); break;
} }
} }
if (_type == TYPE_WS2812_WWA) {
uint8_t w = R(c) | G(c);
c = RGBW32(w, w, 0, w);
}
return c; return c;
} }
} }
uint8_t BusDigital::getPins(uint8_t* pinArray) const { unsigned BusDigital::getPins(uint8_t* pinArray) const {
unsigned numPins = is2Pin(_type) + 1; unsigned numPins = is2Pin(_type) + 1;
if (pinArray) for (unsigned i = 0; i < numPins; i++) pinArray[i] = _pins[i]; if (pinArray) for (unsigned i = 0; i < numPins; i++) pinArray[i] = _pins[i];
return numPins; return numPins;
} }
unsigned BusDigital::getBusSize() const {
return sizeof(BusDigital) + (isOk() ? PolyBus::getDataSize(_busPtr, _iType) + (_data ? _len * getNumberOfChannels() : 0) : 0);
}
void BusDigital::setColorOrder(uint8_t colorOrder) { void BusDigital::setColorOrder(uint8_t colorOrder) {
// upper nibble contains W swap information // upper nibble contains W swap information
if ((colorOrder & 0x0F) > 5) return; if ((colorOrder & 0x0F) > 5) return;
@ -399,8 +403,8 @@ std::vector<LEDType> BusDigital::getLEDTypes() {
{TYPE_WS2805, "D", PSTR("WS2805 RGBCW")}, {TYPE_WS2805, "D", PSTR("WS2805 RGBCW")},
{TYPE_SM16825, "D", PSTR("SM16825 RGBCW")}, {TYPE_SM16825, "D", PSTR("SM16825 RGBCW")},
{TYPE_WS2812_1CH_X3, "D", PSTR("WS2811 White")}, {TYPE_WS2812_1CH_X3, "D", PSTR("WS2811 White")},
//{TYPE_WS2812_2CH_X3, "D", PSTR("WS2811 CCT")}, // not implemented //{TYPE_WS2812_2CH_X3, "D", PSTR("WS281x CCT")}, // not implemented
//{TYPE_WS2812_WWA, "D", PSTR("WS2811 WWA")}, // not implemented {TYPE_WS2812_WWA, "D", PSTR("WS281x WWA")}, // amber ignored
{TYPE_WS2801, "2P", PSTR("WS2801")}, {TYPE_WS2801, "2P", PSTR("WS2801")},
{TYPE_APA102, "2P", PSTR("APA102")}, {TYPE_APA102, "2P", PSTR("APA102")},
{TYPE_LPD8806, "2P", PSTR("LPD8806")}, {TYPE_LPD8806, "2P", PSTR("LPD8806")},
@ -415,12 +419,13 @@ void BusDigital::begin() {
} }
void BusDigital::cleanup() { void BusDigital::cleanup() {
DEBUG_PRINTLN(F("Digital Cleanup.")); DEBUGBUS_PRINTLN(F("Digital Cleanup."));
PolyBus::cleanup(_busPtr, _iType); PolyBus::cleanup(_busPtr, _iType);
_iType = I_NONE; _iType = I_NONE;
_valid = false; _valid = false;
_busPtr = nullptr; _busPtr = nullptr;
if (_data != nullptr) freeData(); freeData();
//PinManager::deallocateMultiplePins(_pins, 2, PinOwner::BusDigital);
PinManager::deallocatePin(_pins[1], PinOwner::BusDigital); PinManager::deallocatePin(_pins[1], PinOwner::BusDigital);
PinManager::deallocatePin(_pins[0], PinOwner::BusDigital); PinManager::deallocatePin(_pins[0], PinOwner::BusDigital);
} }
@ -492,9 +497,9 @@ BusPwm::BusPwm(const BusConfig &bc)
_hasRgb = hasRGB(bc.type); _hasRgb = hasRGB(bc.type);
_hasWhite = hasWhite(bc.type); _hasWhite = hasWhite(bc.type);
_hasCCT = hasCCT(bc.type); _hasCCT = hasCCT(bc.type);
_data = _pwmdata; // avoid malloc() and use stack _data = _pwmdata; // avoid malloc() and use already allocated memory
_valid = true; _valid = true;
DEBUG_PRINTF_P(PSTR("%successfully inited PWM strip with type %u, frequency %u, bit depth %u and pins %u,%u,%u,%u,%u\n"), _valid?"S":"Uns", bc.type, _frequency, _depth, _pins[0], _pins[1], _pins[2], _pins[3], _pins[4]); DEBUGBUS_PRINTF_P(PSTR("%successfully inited PWM strip with type %u, frequency %u, bit depth %u and pins %u,%u,%u,%u,%u\n"), _valid?"S":"Uns", bc.type, _frequency, _depth, _pins[0], _pins[1], _pins[2], _pins[3], _pins[4]);
} }
void BusPwm::setPixelColor(unsigned pix, uint32_t c) { void BusPwm::setPixelColor(unsigned pix, uint32_t c) {
@ -623,7 +628,7 @@ void BusPwm::show() {
} }
} }
uint8_t BusPwm::getPins(uint8_t* pinArray) const { unsigned BusPwm::getPins(uint8_t* pinArray) const {
if (!_valid) return 0; if (!_valid) return 0;
unsigned numPins = numPWMPins(_type); unsigned numPins = numPWMPins(_type);
if (pinArray) for (unsigned i = 0; i < numPins; i++) pinArray[i] = _pins[i]; if (pinArray) for (unsigned i = 0; i < numPins; i++) pinArray[i] = _pins[i];
@ -676,7 +681,7 @@ BusOnOff::BusOnOff(const BusConfig &bc)
_hasCCT = false; _hasCCT = false;
_data = &_onoffdata; // avoid malloc() and use stack _data = &_onoffdata; // avoid malloc() and use stack
_valid = true; _valid = true;
DEBUG_PRINTF_P(PSTR("%successfully inited On/Off strip with pin %u\n"), _valid?"S":"Uns", _pin); DEBUGBUS_PRINTF_P(PSTR("%successfully inited On/Off strip with pin %u\n"), _valid?"S":"Uns", _pin);
} }
void BusOnOff::setPixelColor(unsigned pix, uint32_t c) { void BusOnOff::setPixelColor(unsigned pix, uint32_t c) {
@ -699,7 +704,7 @@ void BusOnOff::show() {
digitalWrite(_pin, _reversed ? !(bool)_data[0] : (bool)_data[0]); digitalWrite(_pin, _reversed ? !(bool)_data[0] : (bool)_data[0]);
} }
uint8_t BusOnOff::getPins(uint8_t* pinArray) const { unsigned BusOnOff::getPins(uint8_t* pinArray) const {
if (!_valid) return 0; if (!_valid) return 0;
if (pinArray) pinArray[0] = _pin; if (pinArray) pinArray[0] = _pin;
return 1; return 1;
@ -736,7 +741,7 @@ BusNetwork::BusNetwork(const BusConfig &bc)
_UDPchannels = _hasWhite + 3; _UDPchannels = _hasWhite + 3;
_client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]); _client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]);
_valid = (allocateData(_len * _UDPchannels) != nullptr); _valid = (allocateData(_len * _UDPchannels) != nullptr);
DEBUG_PRINTF_P(PSTR("%successfully inited virtual strip with type %u and IP %u.%u.%u.%u\n"), _valid?"S":"Uns", bc.type, bc.pins[0], bc.pins[1], bc.pins[2], bc.pins[3]); DEBUGBUS_PRINTF_P(PSTR("%successfully inited virtual strip with type %u and IP %u.%u.%u.%u\n"), _valid?"S":"Uns", bc.type, bc.pins[0], bc.pins[1], bc.pins[2], bc.pins[3]);
} }
void BusNetwork::setPixelColor(unsigned pix, uint32_t c) { void BusNetwork::setPixelColor(unsigned pix, uint32_t c) {
@ -763,7 +768,7 @@ void BusNetwork::show() {
_broadcastLock = false; _broadcastLock = false;
} }
uint8_t BusNetwork::getPins(uint8_t* pinArray) const { unsigned BusNetwork::getPins(uint8_t* pinArray) const {
if (pinArray) for (unsigned i = 0; i < 4; i++) pinArray[i] = _client[i]; if (pinArray) for (unsigned i = 0; i < 4; i++) pinArray[i] = _client[i];
return 4; return 4;
} }
@ -784,6 +789,7 @@ std::vector<LEDType> BusNetwork::getLEDTypes() {
} }
void BusNetwork::cleanup() { void BusNetwork::cleanup() {
DEBUGBUS_PRINTLN(F("Virtual Cleanup."));
_type = I_NONE; _type = I_NONE;
_valid = false; _valid = false;
freeData(); freeData();
@ -791,43 +797,66 @@ void BusNetwork::cleanup() {
//utility to get the approx. memory usage of a given BusConfig //utility to get the approx. memory usage of a given BusConfig
uint32_t BusManager::memUsage(const BusConfig &bc) { unsigned BusConfig::memUsage(unsigned nr) const {
if (Bus::isOnOff(bc.type) || Bus::isPWM(bc.type)) return OUTPUT_MAX_PINS; if (Bus::isVirtual(type)) {
return sizeof(BusNetwork) + (count * Bus::getNumberOfChannels(type));
unsigned len = bc.count + bc.skipAmount; } else if (Bus::isDigital(type)) {
unsigned channels = Bus::getNumberOfChannels(bc.type); return sizeof(BusDigital) + PolyBus::memUsage(count + skipAmount, PolyBus::getI(type, pins, nr)) + doubleBuffer * (count + skipAmount) * Bus::getNumberOfChannels(type);
unsigned multiplier = 1; } else if (Bus::isOnOff(type)) {
if (Bus::isDigital(bc.type)) { // digital types return sizeof(BusOnOff);
if (Bus::is16bit(bc.type)) len *= 2; // 16-bit LEDs } else {
#ifdef ESP8266 return sizeof(BusPwm);
if (bc.pins[0] == 3) { //8266 DMA uses 5x the mem
multiplier = 5;
} }
#else //ESP32 RMT uses double buffer, parallel I2S uses 8x buffer (3 times) }
multiplier = PolyBus::isParallelI2S1Output() ? 24 : 2;
unsigned BusManager::memUsage() {
// when ESP32, S2 & S3 use parallel I2S only the largest bus determines the total memory requirements for back buffers
// front buffers are always allocated per bus
unsigned size = 0;
unsigned maxI2S = 0;
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(ESP8266)
unsigned digitalCount = 0;
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
#define MAX_RMT 4
#else
#define MAX_RMT 8
#endif #endif
#endif
for (const auto &bus : busses) {
unsigned busSize = bus->getBusSize();
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(ESP8266)
if (bus->isDigital() && !bus->is2Pin()) digitalCount++;
if (PolyBus::isParallelI2S1Output() && digitalCount > MAX_RMT) {
unsigned i2sCommonSize = 3 * bus->getLength() * bus->getNumberOfChannels() * (bus->is16bit()+1);
if (i2sCommonSize > maxI2S) maxI2S = i2sCommonSize;
busSize -= i2sCommonSize;
} }
return (len * multiplier + bc.doubleBuffer * (bc.count + bc.skipAmount)) * channels; #endif
size += busSize;
} }
return size + maxI2S;
uint32_t BusManager::memUsage(unsigned maxChannels, unsigned maxCount, unsigned minBuses) {
//ESP32 RMT uses double buffer, parallel I2S uses 8x buffer (3 times)
unsigned multiplier = PolyBus::isParallelI2S1Output() ? 3 : 2;
return (maxChannels * maxCount * minBuses * multiplier);
} }
int BusManager::add(const BusConfig &bc) { int BusManager::add(const BusConfig &bc) {
DEBUGBUS_PRINTF_P(PSTR("Bus: Adding bus (%d - %d >= %d)\n"), getNumBusses(), getNumVirtualBusses(), WLED_MAX_BUSSES);
if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1; if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1;
unsigned numDigital = 0;
for (const auto &bus : busses) if (bus->isDigital() && !bus->is2Pin()) numDigital++;
if (Bus::isVirtual(bc.type)) { if (Bus::isVirtual(bc.type)) {
busses[numBusses] = new BusNetwork(bc); //busses.push_back(std::make_unique<BusNetwork>(bc)); // when C++ >11
busses.push_back(new BusNetwork(bc));
} else if (Bus::isDigital(bc.type)) { } else if (Bus::isDigital(bc.type)) {
busses[numBusses] = new BusDigital(bc, numBusses, colorOrderMap); //busses.push_back(std::make_unique<BusDigital>(bc, numDigital, colorOrderMap));
busses.push_back(new BusDigital(bc, numDigital, colorOrderMap));
} else if (Bus::isOnOff(bc.type)) { } else if (Bus::isOnOff(bc.type)) {
busses[numBusses] = new BusOnOff(bc); //busses.push_back(std::make_unique<BusOnOff>(bc));
busses.push_back(new BusOnOff(bc));
} else { } else {
busses[numBusses] = new BusPwm(bc); //busses.push_back(std::make_unique<BusPwm>(bc));
busses.push_back(new BusPwm(bc));
} }
return numBusses++; return busses.size();
} }
// credit @willmmiles // credit @willmmiles
@ -856,18 +885,21 @@ String BusManager::getLEDTypesJSONString() {
} }
void BusManager::useParallelOutput() { void BusManager::useParallelOutput() {
_parallelOutputs = 8; // hardcoded since we use NPB I2S x8 methods DEBUGBUS_PRINTLN(F("Bus: Enabling parallel I2S."));
PolyBus::setParallelI2S1Output(); PolyBus::setParallelI2S1Output();
} }
bool BusManager::hasParallelOutput() {
return PolyBus::isParallelI2S1Output();
}
//do not call this method from system context (network callback) //do not call this method from system context (network callback)
void BusManager::removeAll() { void BusManager::removeAll() {
DEBUG_PRINTLN(F("Removing all.")); DEBUGBUS_PRINTLN(F("Removing all."));
//prevents crashes due to deleting busses while in use. //prevents crashes due to deleting busses while in use.
while (!canAllShow()) yield(); while (!canAllShow()) yield();
for (unsigned i = 0; i < numBusses; i++) delete busses[i]; for (auto &bus : busses) delete bus; // needed when not using std::unique_ptr C++ >11
numBusses = 0; busses.clear();
_parallelOutputs = 1;
PolyBus::setParallelI2S1Output(false); PolyBus::setParallelI2S1Output(false);
} }
@ -878,7 +910,9 @@ void BusManager::removeAll() {
void BusManager::esp32RMTInvertIdle() { void BusManager::esp32RMTInvertIdle() {
bool idle_out; bool idle_out;
unsigned rmt = 0; unsigned rmt = 0;
for (unsigned u = 0; u < numBusses(); u++) { unsigned u = 0;
for (auto &bus : busses) {
if (bus->getLength()==0 || !bus->isDigital() || bus->is2Pin()) continue;
#if defined(CONFIG_IDF_TARGET_ESP32C3) // 2 RMT, only has 1 I2S but NPB does not support it ATM #if defined(CONFIG_IDF_TARGET_ESP32C3) // 2 RMT, only has 1 I2S but NPB does not support it ATM
if (u > 1) return; if (u > 1) return;
rmt = u; rmt = u;
@ -889,11 +923,11 @@ void BusManager::esp32RMTInvertIdle() {
if (u > 3) return; if (u > 3) return;
rmt = u; rmt = u;
#else #else
if (u < _parallelOutputs) continue; unsigned numI2S = !PolyBus::isParallelI2S1Output(); // if using parallel I2S, RMT is used 1st
if (u >= _parallelOutputs + 8) return; // only 8 RMT channels if (numI2S > u) continue;
rmt = u - _parallelOutputs; if (u > 7 + numI2S) return;
rmt = u - numI2S;
#endif #endif
if (busses[u]->getLength()==0 || !busses[u]->isDigital() || busses[u]->is2Pin()) continue;
//assumes that bus number to rmt channel mapping stays 1:1 //assumes that bus number to rmt channel mapping stays 1:1
rmt_channel_t ch = static_cast<rmt_channel_t>(rmt); rmt_channel_t ch = static_cast<rmt_channel_t>(rmt);
rmt_idle_level_t lvl; rmt_idle_level_t lvl;
@ -902,6 +936,7 @@ void BusManager::esp32RMTInvertIdle() {
else if (lvl == RMT_IDLE_LEVEL_LOW) lvl = RMT_IDLE_LEVEL_HIGH; else if (lvl == RMT_IDLE_LEVEL_LOW) lvl = RMT_IDLE_LEVEL_HIGH;
else continue; else continue;
rmt_set_idle_level(ch, idle_out, lvl); rmt_set_idle_level(ch, idle_out, lvl);
u++
} }
} }
#endif #endif
@ -910,12 +945,12 @@ void BusManager::on() {
#ifdef ESP8266 #ifdef ESP8266
//Fix for turning off onboard LED breaking bus //Fix for turning off onboard LED breaking bus
if (PinManager::getPinOwner(LED_BUILTIN) == PinOwner::BusDigital) { if (PinManager::getPinOwner(LED_BUILTIN) == PinOwner::BusDigital) {
for (unsigned i = 0; i < numBusses; i++) { for (auto &bus : busses) {
uint8_t pins[2] = {255,255}; uint8_t pins[2] = {255,255};
if (busses[i]->isDigital() && busses[i]->getPins(pins)) { if (bus->isDigital() && bus->getPins(pins)) {
if (pins[0] == LED_BUILTIN || pins[1] == LED_BUILTIN) { if (pins[0] == LED_BUILTIN || pins[1] == LED_BUILTIN) {
BusDigital *bus = static_cast<BusDigital*>(busses[i]); BusDigital *b = static_cast<BusDigital*>(bus);
bus->begin(); b->begin();
break; break;
} }
} }
@ -932,7 +967,7 @@ void BusManager::off() {
// turn off built-in LED if strip is turned off // turn off built-in LED if strip is turned off
// this will break digital bus so will need to be re-initialised on On // this will break digital bus so will need to be re-initialised on On
if (PinManager::getPinOwner(LED_BUILTIN) == PinOwner::BusDigital) { if (PinManager::getPinOwner(LED_BUILTIN) == PinOwner::BusDigital) {
for (unsigned i = 0; i < numBusses; i++) if (busses[i]->isOffRefreshRequired()) return; for (const auto &bus : busses) if (bus->isOffRefreshRequired()) return;
pinMode(LED_BUILTIN, OUTPUT); pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH); digitalWrite(LED_BUILTIN, HIGH);
} }
@ -944,30 +979,26 @@ void BusManager::off() {
void BusManager::show() { void BusManager::show() {
_milliAmpsUsed = 0; _milliAmpsUsed = 0;
for (unsigned i = 0; i < numBusses; i++) { for (auto &bus : busses) {
busses[i]->show(); bus->show();
_milliAmpsUsed += busses[i]->getUsedCurrent(); _milliAmpsUsed += bus->getUsedCurrent();
} }
} }
void BusManager::setStatusPixel(uint32_t c) { void BusManager::setStatusPixel(uint32_t c) {
for (unsigned i = 0; i < numBusses; i++) { for (auto &bus : busses) bus->setStatusPixel(c);
busses[i]->setStatusPixel(c);
}
} }
void IRAM_ATTR BusManager::setPixelColor(unsigned pix, uint32_t c) { void IRAM_ATTR BusManager::setPixelColor(unsigned pix, uint32_t c) {
for (unsigned i = 0; i < numBusses; i++) { for (auto &bus : busses) {
unsigned bstart = busses[i]->getStart(); unsigned bstart = bus->getStart();
if (pix < bstart || pix >= bstart + busses[i]->getLength()) continue; if (pix < bstart || pix >= bstart + bus->getLength()) continue;
busses[i]->setPixelColor(pix - bstart, c); bus->setPixelColor(pix - bstart, c);
} }
} }
void BusManager::setBrightness(uint8_t b) { void BusManager::setBrightness(uint8_t b) {
for (unsigned i = 0; i < numBusses; i++) { for (auto &bus : busses) bus->setBrightness(b);
busses[i]->setBrightness(b);
}
} }
void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) { void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) {
@ -980,34 +1011,32 @@ void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) {
} }
uint32_t BusManager::getPixelColor(unsigned pix) { uint32_t BusManager::getPixelColor(unsigned pix) {
for (unsigned i = 0; i < numBusses; i++) { for (auto &bus : busses) {
unsigned bstart = busses[i]->getStart(); unsigned bstart = bus->getStart();
if (!busses[i]->containsPixel(pix)) continue; if (!bus->containsPixel(pix)) continue;
return busses[i]->getPixelColor(pix - bstart); return bus->getPixelColor(pix - bstart);
} }
return 0; return 0;
} }
bool BusManager::canAllShow() { bool BusManager::canAllShow() {
for (unsigned i = 0; i < numBusses; i++) { for (const auto &bus : busses) if (!bus->canShow()) return false;
if (!busses[i]->canShow()) return false;
}
return true; return true;
} }
Bus* BusManager::getBus(uint8_t busNr) { Bus* BusManager::getBus(uint8_t busNr) {
if (busNr >= numBusses) return nullptr; if (busNr >= busses.size()) return nullptr;
return busses[busNr]; return busses[busNr];
} }
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit()) //semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
uint16_t BusManager::getTotalLength() { uint16_t BusManager::getTotalLength() {
unsigned len = 0; unsigned len = 0;
for (unsigned i=0; i<numBusses; i++) len += busses[i]->getLength(); for (const auto &bus : busses) len += bus->getLength();
return len; return len;
} }
bool PolyBus::useParallelI2S = false; bool PolyBus::_useParallelI2S = false;
// Bus static member definition // Bus static member definition
int16_t Bus::_cct = -1; int16_t Bus::_cct = -1;
@ -1016,9 +1045,8 @@ uint8_t Bus::_gAWM = 255;
uint16_t BusDigital::_milliAmpsTotal = 0; uint16_t BusDigital::_milliAmpsTotal = 0;
uint8_t BusManager::numBusses = 0; //std::vector<std::unique_ptr<Bus>> BusManager::busses;
Bus* BusManager::busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES]; std::vector<Bus*> BusManager::busses;
ColorOrderMap BusManager::colorOrderMap = {}; ColorOrderMap BusManager::colorOrderMap = {};
uint16_t BusManager::_milliAmpsUsed = 0; uint16_t BusManager::_milliAmpsUsed = 0;
uint16_t BusManager::_milliAmpsMax = ABL_MILLIAMPS_DEFAULT; uint16_t BusManager::_milliAmpsMax = ABL_MILLIAMPS_DEFAULT;
uint8_t BusManager::_parallelOutputs = 1;

View File

@ -1,3 +1,4 @@
#pragma once
#ifndef BusManager_h #ifndef BusManager_h
#define BusManager_h #define BusManager_h
@ -8,6 +9,30 @@
#include "const.h" #include "const.h"
#include "pin_manager.h" #include "pin_manager.h"
#include <vector> #include <vector>
#include <memory>
// enable additional debug output
#if defined(WLED_DEBUG_HOST)
#include "net_debug.h"
#define DEBUGOUT NetDebug
#else
#define DEBUGOUT Serial
#endif
#ifdef WLED_DEBUG_BUS
#ifndef ESP8266
#include <rom/rtc.h>
#endif
#define DEBUGBUS_PRINT(x) DEBUGOUT.print(x)
#define DEBUGBUS_PRINTLN(x) DEBUGOUT.println(x)
#define DEBUGBUS_PRINTF(x...) DEBUGOUT.printf(x)
#define DEBUGBUS_PRINTF_P(x...) DEBUGOUT.printf_P(x)
#else
#define DEBUGBUS_PRINT(x)
#define DEBUGBUS_PRINTLN(x)
#define DEBUGBUS_PRINTF(x...)
#define DEBUGBUS_PRINTF_P(x...)
#endif
//colors.cpp //colors.cpp
uint16_t approximateKelvinFromRGB(uint32_t rgb); uint16_t approximateKelvinFromRGB(uint32_t rgb);
@ -78,7 +103,7 @@ class Bus {
_autoWhiteMode = Bus::hasWhite(type) ? aw : RGBW_MODE_MANUAL_ONLY; _autoWhiteMode = Bus::hasWhite(type) ? aw : RGBW_MODE_MANUAL_ONLY;
}; };
virtual ~Bus() {} //throw the bus under the bus virtual ~Bus() {} //throw the bus under the bus (derived class needs to freeData())
virtual void begin() {}; virtual void begin() {};
virtual void show() = 0; virtual void show() = 0;
@ -88,14 +113,15 @@ class Bus {
virtual void setBrightness(uint8_t b) { _bri = b; }; virtual void setBrightness(uint8_t b) { _bri = b; };
virtual void setColorOrder(uint8_t co) {} virtual void setColorOrder(uint8_t co) {}
virtual uint32_t getPixelColor(unsigned pix) const { return 0; } virtual uint32_t getPixelColor(unsigned pix) const { return 0; }
virtual uint8_t getPins(uint8_t* pinArray = nullptr) const { return 0; } virtual unsigned getPins(uint8_t* pinArray = nullptr) const { return 0; }
virtual uint16_t getLength() const { return isOk() ? _len : 0; } virtual uint16_t getLength() const { return isOk() ? _len : 0; }
virtual uint8_t getColorOrder() const { return COL_ORDER_RGB; } virtual uint8_t getColorOrder() const { return COL_ORDER_RGB; }
virtual uint8_t skippedLeds() const { return 0; } virtual unsigned skippedLeds() const { return 0; }
virtual uint16_t getFrequency() const { return 0U; } virtual uint16_t getFrequency() const { return 0U; }
virtual uint16_t getLEDCurrent() const { return 0; } virtual uint16_t getLEDCurrent() const { return 0; }
virtual uint16_t getUsedCurrent() const { return 0; } virtual uint16_t getUsedCurrent() const { return 0; }
virtual uint16_t getMaxCurrent() const { return 0; } virtual uint16_t getMaxCurrent() const { return 0; }
virtual unsigned getBusSize() const { return sizeof(Bus); }
inline bool hasRGB() const { return _hasRgb; } inline bool hasRGB() const { return _hasRgb; }
inline bool hasWhite() const { return _hasWhite; } inline bool hasWhite() const { return _hasWhite; }
@ -111,7 +137,7 @@ class Bus {
inline void setStart(uint16_t start) { _start = start; } inline void setStart(uint16_t start) { _start = start; }
inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; } inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; }
inline uint8_t getAutoWhiteMode() const { return _autoWhiteMode; } inline uint8_t getAutoWhiteMode() const { return _autoWhiteMode; }
inline uint32_t getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); } inline unsigned getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); }
inline uint16_t getStart() const { return _start; } inline uint16_t getStart() const { return _start; }
inline uint8_t getType() const { return _type; } inline uint8_t getType() const { return _type; }
inline bool isOk() const { return _valid; } inline bool isOk() const { return _valid; }
@ -120,8 +146,8 @@ class Bus {
inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start + _len; } inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start + _len; }
static inline std::vector<LEDType> getLEDTypes() { return {{TYPE_NONE, "", PSTR("None")}}; } // not used. just for reference for derived classes static inline std::vector<LEDType> getLEDTypes() { return {{TYPE_NONE, "", PSTR("None")}}; } // not used. just for reference for derived classes
static constexpr uint32_t getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK static constexpr unsigned getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK
static constexpr uint32_t getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); } static constexpr unsigned getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); }
static constexpr bool hasRGB(uint8_t type) { static constexpr bool hasRGB(uint8_t type) {
return !((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_ANALOG_1CH || type == TYPE_ANALOG_2CH || type == TYPE_ONOFF); return !((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_ANALOG_1CH || type == TYPE_ANALOG_2CH || type == TYPE_ONOFF);
} }
@ -192,7 +218,7 @@ class Bus {
uint32_t autoWhiteCalc(uint32_t c) const; uint32_t autoWhiteCalc(uint32_t c) const;
uint8_t *allocateData(size_t size = 1); uint8_t *allocateData(size_t size = 1);
void freeData() { if (_data != nullptr) free(_data); _data = nullptr; } void freeData();
}; };
@ -209,12 +235,13 @@ class BusDigital : public Bus {
void setColorOrder(uint8_t colorOrder) override; void setColorOrder(uint8_t colorOrder) override;
[[gnu::hot]] uint32_t getPixelColor(unsigned pix) const override; [[gnu::hot]] uint32_t getPixelColor(unsigned pix) const override;
uint8_t getColorOrder() const override { return _colorOrder; } uint8_t getColorOrder() const override { return _colorOrder; }
uint8_t getPins(uint8_t* pinArray = nullptr) const override; unsigned getPins(uint8_t* pinArray = nullptr) const override;
uint8_t skippedLeds() const override { return _skip; } unsigned skippedLeds() const override { return _skip; }
uint16_t getFrequency() const override { return _frequencykHz; } uint16_t getFrequency() const override { return _frequencykHz; }
uint16_t getLEDCurrent() const override { return _milliAmpsPerLed; } uint16_t getLEDCurrent() const override { return _milliAmpsPerLed; }
uint16_t getUsedCurrent() const override { return _milliAmpsTotal; } uint16_t getUsedCurrent() const override { return _milliAmpsTotal; }
uint16_t getMaxCurrent() const override { return _milliAmpsMax; } uint16_t getMaxCurrent() const override { return _milliAmpsMax; }
unsigned getBusSize() const override;
void begin() override; void begin() override;
void cleanup(); void cleanup();
@ -244,7 +271,7 @@ class BusDigital : public Bus {
return c; return c;
} }
uint8_t estimateCurrentAndLimitBri(); uint8_t estimateCurrentAndLimitBri() const;
}; };
@ -255,10 +282,11 @@ class BusPwm : public Bus {
void setPixelColor(unsigned pix, uint32_t c) override; void setPixelColor(unsigned pix, uint32_t c) override;
uint32_t getPixelColor(unsigned pix) const override; //does no index check uint32_t getPixelColor(unsigned pix) const override; //does no index check
uint8_t getPins(uint8_t* pinArray = nullptr) const override; unsigned getPins(uint8_t* pinArray = nullptr) const override;
uint16_t getFrequency() const override { return _frequency; } uint16_t getFrequency() const override { return _frequency; }
unsigned getBusSize() const override { return sizeof(BusPwm); }
void show() override; void show() override;
void cleanup() { deallocatePins(); } inline void cleanup() { deallocatePins(); _data = nullptr; }
static std::vector<LEDType> getLEDTypes(); static std::vector<LEDType> getLEDTypes();
@ -282,9 +310,10 @@ class BusOnOff : public Bus {
void setPixelColor(unsigned pix, uint32_t c) override; void setPixelColor(unsigned pix, uint32_t c) override;
uint32_t getPixelColor(unsigned pix) const override; uint32_t getPixelColor(unsigned pix) const override;
uint8_t getPins(uint8_t* pinArray) const override; unsigned getPins(uint8_t* pinArray) const override;
unsigned getBusSize() const override { return sizeof(BusOnOff); }
void show() override; void show() override;
void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); } inline void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); _data = nullptr; }
static std::vector<LEDType> getLEDTypes(); static std::vector<LEDType> getLEDTypes();
@ -300,9 +329,10 @@ class BusNetwork : public Bus {
~BusNetwork() { cleanup(); } ~BusNetwork() { cleanup(); }
bool canShow() const override { return !_broadcastLock; } // this should be a return value from UDP routine if it is still sending data out bool canShow() const override { return !_broadcastLock; } // this should be a return value from UDP routine if it is still sending data out
void setPixelColor(unsigned pix, uint32_t c) override; [[gnu::hot]] void setPixelColor(unsigned pix, uint32_t c) override;
uint32_t getPixelColor(unsigned pix) const override; [[gnu::hot]] uint32_t getPixelColor(unsigned pix) const override;
uint8_t getPins(uint8_t* pinArray = nullptr) const override; unsigned getPins(uint8_t* pinArray = nullptr) const override;
unsigned getBusSize() const override { return sizeof(BusNetwork) + (isOk() ? _len * _UDPchannels : 0); }
void show() override; void show() override;
void cleanup(); void cleanup();
@ -348,6 +378,16 @@ struct BusConfig {
type = busType & 0x7F; // bit 7 may be/is hacked to include refresh info (1=refresh in off state, 0=no refresh) type = busType & 0x7F; // bit 7 may be/is hacked to include refresh info (1=refresh in off state, 0=no refresh)
size_t nPins = Bus::getNumberOfPins(type); size_t nPins = Bus::getNumberOfPins(type);
for (size_t i = 0; i < nPins; i++) pins[i] = ppins[i]; for (size_t i = 0; i < nPins; i++) pins[i] = ppins[i];
DEBUGBUS_PRINTF_P(PSTR("Bus: Config (%d-%d, type:%d, CO:%d, rev:%d, skip:%d, AW:%d kHz:%d, mA:%d/%d)\n"),
(int)start, (int)(start+len),
(int)type,
(int)colorOrder,
(int)reversed,
(int)skipAmount,
(int)autoWhite,
(int)frequency,
(int)milliAmpsPerLed, (int)milliAmpsMax
);
} }
//validates start and length and extends total if needed //validates start and length and extends total if needed
@ -361,6 +401,8 @@ struct BusConfig {
if (start + count > total) total = start + count; if (start + count > total) total = start + count;
return true; return true;
} }
unsigned memUsage(unsigned nr = 0) const;
}; };
@ -378,14 +420,13 @@ class BusManager {
public: public:
BusManager() {}; BusManager() {};
//utility to get the approx. memory usage of a given BusConfig static unsigned memUsage();
static uint32_t memUsage(const BusConfig &bc);
static uint32_t memUsage(unsigned channels, unsigned count, unsigned buses = 1);
static uint16_t currentMilliamps() { return _milliAmpsUsed + MA_FOR_ESP; } static uint16_t currentMilliamps() { return _milliAmpsUsed + MA_FOR_ESP; }
static uint16_t ablMilliampsMax() { return _milliAmpsMax; } static uint16_t ablMilliampsMax() { return _milliAmpsMax; }
static int add(const BusConfig &bc); static int add(const BusConfig &bc);
static void useParallelOutput(); // workaround for inaccessible PolyBus static void useParallelOutput(); // workaround for inaccessible PolyBus
static bool hasParallelOutput(); // workaround for inaccessible PolyBus
//do not call this method from system context (network callback) //do not call this method from system context (network callback)
static void removeAll(); static void removeAll();
@ -409,25 +450,24 @@ class BusManager {
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit()) //semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
static uint16_t getTotalLength(); static uint16_t getTotalLength();
static inline uint8_t getNumBusses() { return numBusses; } static inline uint8_t getNumBusses() { return busses.size(); }
static String getLEDTypesJSONString(); static String getLEDTypesJSONString();
static inline ColorOrderMap& getColorOrderMap() { return colorOrderMap; } static inline ColorOrderMap& getColorOrderMap() { return colorOrderMap; }
private: private:
static uint8_t numBusses; //static std::vector<std::unique_ptr<Bus>> busses; // we'd need C++ >11
static Bus* busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES]; static std::vector<Bus*> busses;
static ColorOrderMap colorOrderMap; static ColorOrderMap colorOrderMap;
static uint16_t _milliAmpsUsed; static uint16_t _milliAmpsUsed;
static uint16_t _milliAmpsMax; static uint16_t _milliAmpsMax;
static uint8_t _parallelOutputs;
#ifdef ESP32_DATA_IDLE_HIGH #ifdef ESP32_DATA_IDLE_HIGH
static void esp32RMTInvertIdle() ; static void esp32RMTInvertIdle() ;
#endif #endif
static uint8_t getNumVirtualBusses() { static uint8_t getNumVirtualBusses() {
int j = 0; int j = 0;
for (int i=0; i<numBusses; i++) if (busses[i]->isVirtual()) j++; for (const auto &bus : busses) j += bus->isVirtual();
return j; return j;
} }
}; };

View File

@ -1,23 +1,9 @@
#pragma once
#ifndef BusWrapper_h #ifndef BusWrapper_h
#define BusWrapper_h #define BusWrapper_h
//#define NPB_CONF_4STEP_CADENCE
#include "NeoPixelBusLg.h" #include "NeoPixelBusLg.h"
#include "bus_manager.h"
// temporary - these defines should actually be set in platformio.ini
// C3: I2S0 and I2S1 methods not supported (has one I2S bus)
// S2: I2S1 methods not supported (has one I2S bus)
// S3: I2S0 and I2S1 methods not supported yet (has two I2S buses)
// https://github.com/Makuna/NeoPixelBus/blob/b32f719e95ef3c35c46da5c99538017ef925c026/src/internal/Esp32_i2s.h#L4
// https://github.com/Makuna/NeoPixelBus/blob/b32f719e95ef3c35c46da5c99538017ef925c026/src/internal/NeoEsp32RmtMethod.h#L857
#if !defined(WLED_NO_I2S0_PIXELBUS) && (defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3))
#define WLED_NO_I2S0_PIXELBUS
#endif
#if !defined(WLED_NO_I2S1_PIXELBUS) && (defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2))
#define WLED_NO_I2S1_PIXELBUS
#endif
// temporary end
//Hardware SPI Pins //Hardware SPI Pins
#define P_8266_HS_MOSI 13 #define P_8266_HS_MOSI 13
@ -55,110 +41,98 @@
#define I_8266_DM_TM2_3 19 #define I_8266_DM_TM2_3 19
#define I_8266_BB_TM2_3 20 #define I_8266_BB_TM2_3 20
//UCS8903 (RGB) //UCS8903 (RGB)
#define I_8266_U0_UCS_3 49 #define I_8266_U0_UCS_3 21
#define I_8266_U1_UCS_3 50 #define I_8266_U1_UCS_3 22
#define I_8266_DM_UCS_3 51 #define I_8266_DM_UCS_3 23
#define I_8266_BB_UCS_3 52 #define I_8266_BB_UCS_3 24
//UCS8904 (RGBW) //UCS8904 (RGBW)
#define I_8266_U0_UCS_4 53 #define I_8266_U0_UCS_4 25
#define I_8266_U1_UCS_4 54 #define I_8266_U1_UCS_4 26
#define I_8266_DM_UCS_4 55 #define I_8266_DM_UCS_4 27
#define I_8266_BB_UCS_4 56 #define I_8266_BB_UCS_4 28
//FW1906 GRBCW //FW1906 GRBCW
#define I_8266_U0_FW6_5 66 #define I_8266_U0_FW6_5 29
#define I_8266_U1_FW6_5 67 #define I_8266_U1_FW6_5 30
#define I_8266_DM_FW6_5 68 #define I_8266_DM_FW6_5 31
#define I_8266_BB_FW6_5 69 #define I_8266_BB_FW6_5 32
//ESP8266 APA106 //ESP8266 APA106
#define I_8266_U0_APA106_3 81 #define I_8266_U0_APA106_3 33
#define I_8266_U1_APA106_3 82 #define I_8266_U1_APA106_3 34
#define I_8266_DM_APA106_3 83 #define I_8266_DM_APA106_3 35
#define I_8266_BB_APA106_3 84 #define I_8266_BB_APA106_3 36
//WS2805 (RGBCW) //WS2805 (RGBCW)
#define I_8266_U0_2805_5 89 #define I_8266_U0_2805_5 37
#define I_8266_U1_2805_5 90 #define I_8266_U1_2805_5 38
#define I_8266_DM_2805_5 91 #define I_8266_DM_2805_5 39
#define I_8266_BB_2805_5 92 #define I_8266_BB_2805_5 40
//TM1914 (RGB) //TM1914 (RGB)
#define I_8266_U0_TM1914_3 99 #define I_8266_U0_TM1914_3 41
#define I_8266_U1_TM1914_3 100 #define I_8266_U1_TM1914_3 42
#define I_8266_DM_TM1914_3 101 #define I_8266_DM_TM1914_3 43
#define I_8266_BB_TM1914_3 102 #define I_8266_BB_TM1914_3 44
//SM16825 (RGBCW) //SM16825 (RGBCW)
#define I_8266_U0_SM16825_5 103 #define I_8266_U0_SM16825_5 45
#define I_8266_U1_SM16825_5 104 #define I_8266_U1_SM16825_5 46
#define I_8266_DM_SM16825_5 105 #define I_8266_DM_SM16825_5 47
#define I_8266_BB_SM16825_5 106 #define I_8266_BB_SM16825_5 48
/*** ESP32 Neopixel methods ***/ /*** ESP32 Neopixel methods ***/
//RGB //RGB
#define I_32_RN_NEO_3 21 #define I_32_RN_NEO_3 1
#define I_32_I0_NEO_3 22 #define I_32_I2_NEO_3 2
#define I_32_I1_NEO_3 23
//RGBW //RGBW
#define I_32_RN_NEO_4 25 #define I_32_RN_NEO_4 5
#define I_32_I0_NEO_4 26 #define I_32_I2_NEO_4 6
#define I_32_I1_NEO_4 27
//400Kbps //400Kbps
#define I_32_RN_400_3 29 #define I_32_RN_400_3 9
#define I_32_I0_400_3 30 #define I_32_I2_400_3 10
#define I_32_I1_400_3 31
//TM1814 (RGBW) //TM1814 (RGBW)
#define I_32_RN_TM1_4 33 #define I_32_RN_TM1_4 13
#define I_32_I0_TM1_4 34 #define I_32_I2_TM1_4 14
#define I_32_I1_TM1_4 35
//TM1829 (RGB) //TM1829 (RGB)
#define I_32_RN_TM2_3 36 #define I_32_RN_TM2_3 17
#define I_32_I0_TM2_3 37 #define I_32_I2_TM2_3 18
#define I_32_I1_TM2_3 38
//UCS8903 (RGB) //UCS8903 (RGB)
#define I_32_RN_UCS_3 57 #define I_32_RN_UCS_3 21
#define I_32_I0_UCS_3 58 #define I_32_I2_UCS_3 22
#define I_32_I1_UCS_3 59
//UCS8904 (RGBW) //UCS8904 (RGBW)
#define I_32_RN_UCS_4 60 #define I_32_RN_UCS_4 25
#define I_32_I0_UCS_4 61 #define I_32_I2_UCS_4 26
#define I_32_I1_UCS_4 62
//FW1906 GRBCW //FW1906 GRBCW
#define I_32_RN_FW6_5 63 #define I_32_RN_FW6_5 29
#define I_32_I0_FW6_5 64 #define I_32_I2_FW6_5 30
#define I_32_I1_FW6_5 65
//APA106 //APA106
#define I_32_RN_APA106_3 85 #define I_32_RN_APA106_3 33
#define I_32_I0_APA106_3 86 #define I_32_I2_APA106_3 34
#define I_32_I1_APA106_3 87
//WS2805 (RGBCW) //WS2805 (RGBCW)
#define I_32_RN_2805_5 93 #define I_32_RN_2805_5 37
#define I_32_I0_2805_5 94 #define I_32_I2_2805_5 38
#define I_32_I1_2805_5 95
//TM1914 (RGB) //TM1914 (RGB)
#define I_32_RN_TM1914_3 96 #define I_32_RN_TM1914_3 41
#define I_32_I0_TM1914_3 97 #define I_32_I2_TM1914_3 42
#define I_32_I1_TM1914_3 98
//SM16825 (RGBCW) //SM16825 (RGBCW)
#define I_32_RN_SM16825_5 107 #define I_32_RN_SM16825_5 45
#define I_32_I0_SM16825_5 108 #define I_32_I2_SM16825_5 46
#define I_32_I1_SM16825_5 109
//APA102 //APA102
#define I_HS_DOT_3 39 //hardware SPI #define I_HS_DOT_3 101 //hardware SPI
#define I_SS_DOT_3 40 //soft SPI #define I_SS_DOT_3 102 //soft SPI
//LPD8806 //LPD8806
#define I_HS_LPD_3 41 #define I_HS_LPD_3 103
#define I_SS_LPD_3 42 #define I_SS_LPD_3 104
//WS2801 //WS2801
#define I_HS_WS1_3 43 #define I_HS_WS1_3 105
#define I_SS_WS1_3 44 #define I_SS_WS1_3 106
//P9813 //P9813
#define I_HS_P98_3 45 #define I_HS_P98_3 107
#define I_SS_P98_3 46 #define I_SS_P98_3 108
//LPD6803 //LPD6803
#define I_HS_LPO_3 47 #define I_HS_LPO_3 109
#define I_SS_LPO_3 48 #define I_SS_LPO_3 110
// In the following NeoGammaNullMethod can be replaced with NeoGammaWLEDMethod to perform Gamma correction implicitly // In the following NeoGammaNullMethod can be replaced with NeoGammaWLEDMethod to perform Gamma correction implicitly
@ -230,66 +204,95 @@
/*** ESP32 Neopixel methods ***/ /*** ESP32 Neopixel methods ***/
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
// C3: I2S0 and I2S1 methods not supported (has one I2S bus)
// S2: I2S0 methods supported (single & parallel), I2S1 methods not supported (has one I2S bus)
// S3: I2S0 methods not supported, I2S1 supports LCD parallel methods (has two I2S buses)
// https://github.com/Makuna/NeoPixelBus/blob/b32f719e95ef3c35c46da5c99538017ef925c026/src/internal/Esp32_i2s.h#L4
// https://github.com/Makuna/NeoPixelBus/blob/b32f719e95ef3c35c46da5c99538017ef925c026/src/internal/NeoEsp32RmtMethod.h#L857
#if defined(CONFIG_IDF_TARGET_ESP32S3)
// S3 will always use LCD parallel output
typedef X8Ws2812xMethod X1Ws2812xMethod;
typedef X8Sk6812Method X1Sk6812Method;
typedef X8400KbpsMethod X1400KbpsMethod;
typedef X8800KbpsMethod X1800KbpsMethod;
typedef X8Tm1814Method X1Tm1814Method;
typedef X8Tm1829Method X1Tm1829Method;
typedef X8Apa106Method X1Apa106Method;
typedef X8Ws2805Method X1Ws2805Method;
typedef X8Tm1914Method X1Tm1914Method;
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
// S2 will use I2S0
typedef NeoEsp32I2s0Ws2812xMethod X1Ws2812xMethod;
typedef NeoEsp32I2s0Sk6812Method X1Sk6812Method;
typedef NeoEsp32I2s0400KbpsMethod X1400KbpsMethod;
typedef NeoEsp32I2s0800KbpsMethod X1800KbpsMethod;
typedef NeoEsp32I2s0Tm1814Method X1Tm1814Method;
typedef NeoEsp32I2s0Tm1829Method X1Tm1829Method;
typedef NeoEsp32I2s0Apa106Method X1Apa106Method;
typedef NeoEsp32I2s0Ws2805Method X1Ws2805Method;
typedef NeoEsp32I2s0Tm1914Method X1Tm1914Method;
#elif !defined(CONFIG_IDF_TARGET_ESP32C3)
// regular ESP32 will use I2S1
typedef NeoEsp32I2s1Ws2812xMethod X1Ws2812xMethod;
typedef NeoEsp32I2s1Sk6812Method X1Sk6812Method;
typedef NeoEsp32I2s1400KbpsMethod X1400KbpsMethod;
typedef NeoEsp32I2s1800KbpsMethod X1800KbpsMethod;
typedef NeoEsp32I2s1Tm1814Method X1Tm1814Method;
typedef NeoEsp32I2s1Tm1829Method X1Tm1829Method;
typedef NeoEsp32I2s1Apa106Method X1Apa106Method;
typedef NeoEsp32I2s1Ws2805Method X1Ws2805Method;
typedef NeoEsp32I2s1Tm1914Method X1Tm1914Method;
#endif
//RGB //RGB
#define B_32_RN_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod> #define B_32_RN_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod> // ESP32, S2, S3, C3
#define B_32_I0_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s0Ws2812xMethod, NeoGammaNullMethod> //#define B_32_IN_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2sNWs2812xMethod, NeoGammaNullMethod> // ESP32 (dynamic I2S selection)
#define B_32_I1_NEO_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1Ws2812xMethod, NeoGammaNullMethod> #define B_32_I2_NEO_3 NeoPixelBusLg<NeoGrbFeature, X1Ws2812xMethod, NeoGammaNullMethod> // ESP32, S2, S3 (automatic I2S selection, see typedef above)
#define B_32_I1_NEO_3P NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1X8Ws2812xMethod, NeoGammaNullMethod> // parallel I2S #define B_32_IP_NEO_3 NeoPixelBusLg<NeoGrbFeature, X8Ws2812xMethod, NeoGammaNullMethod> // parallel I2S (ESP32, S2, S3)
//RGBW //RGBW
#define B_32_RN_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32RmtNSk6812Method, NeoGammaNullMethod> #define B_32_RN_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32RmtNSk6812Method, NeoGammaNullMethod>
#define B_32_I0_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32I2s0Sk6812Method, NeoGammaNullMethod> #define B_32_I2_NEO_4 NeoPixelBusLg<NeoGrbwFeature, X1Sk6812Method, NeoGammaNullMethod>
#define B_32_I1_NEO_4 NeoPixelBusLg<NeoGrbwFeature, NeoEsp32I2s1Sk6812Method, NeoGammaNullMethod> #define B_32_IP_NEO_4 NeoPixelBusLg<NeoGrbwFeature, X8Sk6812Method, NeoGammaNullMethod> // parallel I2S
#define B_32_I1_NEO_4P NeoPixelBusLg<NeoGrbwFeature, NeoEsp32I2s1X8Sk6812Method, NeoGammaNullMethod> // parallel I2S
//400Kbps //400Kbps
#define B_32_RN_400_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32RmtN400KbpsMethod, NeoGammaNullMethod> #define B_32_RN_400_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32RmtN400KbpsMethod, NeoGammaNullMethod>
#define B_32_I0_400_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s0400KbpsMethod, NeoGammaNullMethod> #define B_32_I2_400_3 NeoPixelBusLg<NeoGrbFeature, X1400KbpsMethod, NeoGammaNullMethod>
#define B_32_I1_400_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1400KbpsMethod, NeoGammaNullMethod> #define B_32_IP_400_3 NeoPixelBusLg<NeoGrbFeature, X8400KbpsMethod, NeoGammaNullMethod> // parallel I2S
#define B_32_I1_400_3P NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1X8400KbpsMethod, NeoGammaNullMethod> // parallel I2S
//TM1814 (RGBW) //TM1814 (RGBW)
#define B_32_RN_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, NeoEsp32RmtNTm1814Method, NeoGammaNullMethod> #define B_32_RN_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, NeoEsp32RmtNTm1814Method, NeoGammaNullMethod>
#define B_32_I0_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, NeoEsp32I2s0Tm1814Method, NeoGammaNullMethod> #define B_32_I2_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, X1Tm1814Method, NeoGammaNullMethod>
#define B_32_I1_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, NeoEsp32I2s1Tm1814Method, NeoGammaNullMethod> #define B_32_IP_TM1_4 NeoPixelBusLg<NeoWrgbTm1814Feature, X8Tm1814Method, NeoGammaNullMethod> // parallel I2S
#define B_32_I1_TM1_4P NeoPixelBusLg<NeoWrgbTm1814Feature, NeoEsp32I2s1X8Tm1814Method, NeoGammaNullMethod> // parallel I2S
//TM1829 (RGB) //TM1829 (RGB)
#define B_32_RN_TM2_3 NeoPixelBusLg<NeoBrgFeature, NeoEsp32RmtNTm1829Method, NeoGammaNullMethod> #define B_32_RN_TM2_3 NeoPixelBusLg<NeoBrgFeature, NeoEsp32RmtNTm1829Method, NeoGammaNullMethod>
#define B_32_I0_TM2_3 NeoPixelBusLg<NeoBrgFeature, NeoEsp32I2s0Tm1829Method, NeoGammaNullMethod> #define B_32_I2_TM2_3 NeoPixelBusLg<NeoBrgFeature, X1Tm1829Method, NeoGammaNullMethod>
#define B_32_I1_TM2_3 NeoPixelBusLg<NeoBrgFeature, NeoEsp32I2s1Tm1829Method, NeoGammaNullMethod> #define B_32_IP_TM2_3 NeoPixelBusLg<NeoBrgFeature, X8Tm1829Method, NeoGammaNullMethod> // parallel I2S
#define B_32_I1_TM2_3P NeoPixelBusLg<NeoBrgFeature, NeoEsp32I2s1X8Tm1829Method, NeoGammaNullMethod> // parallel I2S
//UCS8903 //UCS8903
#define B_32_RN_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod> #define B_32_RN_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod>
#define B_32_I0_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, NeoEsp32I2s0800KbpsMethod, NeoGammaNullMethod> #define B_32_I2_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, X1800KbpsMethod, NeoGammaNullMethod>
#define B_32_I1_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, NeoEsp32I2s1800KbpsMethod, NeoGammaNullMethod> #define B_32_IP_UCS_3 NeoPixelBusLg<NeoRgbUcs8903Feature, X8800KbpsMethod, NeoGammaNullMethod> // parallel I2S
#define B_32_I1_UCS_3P NeoPixelBusLg<NeoRgbUcs8903Feature, NeoEsp32I2s1X8800KbpsMethod, NeoGammaNullMethod> // parallel I2S
//UCS8904 //UCS8904
#define B_32_RN_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod> #define B_32_RN_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod>
#define B_32_I0_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, NeoEsp32I2s0800KbpsMethod, NeoGammaNullMethod> #define B_32_I2_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, X1800KbpsMethod, NeoGammaNullMethod>
#define B_32_I1_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, NeoEsp32I2s1800KbpsMethod, NeoGammaNullMethod> #define B_32_IP_UCS_4 NeoPixelBusLg<NeoRgbwUcs8904Feature, X8800KbpsMethod, NeoGammaNullMethod>// parallel I2S
#define B_32_I1_UCS_4P NeoPixelBusLg<NeoRgbwUcs8904Feature, NeoEsp32I2s1X8800KbpsMethod, NeoGammaNullMethod>// parallel I2S
//APA106 //APA106
#define B_32_RN_APA106_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32RmtNApa106Method, NeoGammaNullMethod> #define B_32_RN_APA106_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32RmtNApa106Method, NeoGammaNullMethod>
#define B_32_I0_APA106_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s0Apa106Method, NeoGammaNullMethod> #define B_32_I2_APA106_3 NeoPixelBusLg<NeoGrbFeature, X1Apa106Method, NeoGammaNullMethod>
#define B_32_I1_APA106_3 NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1Apa106Method, NeoGammaNullMethod> #define B_32_IP_APA106_3 NeoPixelBusLg<NeoGrbFeature, X8Apa106Method, NeoGammaNullMethod> // parallel I2S
#define B_32_I1_APA106_3P NeoPixelBusLg<NeoGrbFeature, NeoEsp32I2s1X8Apa106Method, NeoGammaNullMethod> // parallel I2S
//FW1906 GRBCW //FW1906 GRBCW
#define B_32_RN_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod> #define B_32_RN_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod>
#define B_32_I0_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp32I2s0800KbpsMethod, NeoGammaNullMethod> #define B_32_I2_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, X1800KbpsMethod, NeoGammaNullMethod>
#define B_32_I1_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp32I2s1800KbpsMethod, NeoGammaNullMethod> #define B_32_IP_FW6_5 NeoPixelBusLg<NeoGrbcwxFeature, X8800KbpsMethod, NeoGammaNullMethod> // parallel I2S
#define B_32_I1_FW6_5P NeoPixelBusLg<NeoGrbcwxFeature, NeoEsp32I2s1X8800KbpsMethod, NeoGammaNullMethod> // parallel I2S
//WS2805 RGBWC //WS2805 RGBWC
#define B_32_RN_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp32RmtNWs2805Method, NeoGammaNullMethod> #define B_32_RN_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp32RmtNWs2805Method, NeoGammaNullMethod>
#define B_32_I0_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp32I2s0Ws2805Method, NeoGammaNullMethod> #define B_32_I2_2805_5 NeoPixelBusLg<NeoGrbwwFeature, X1Ws2805Method, NeoGammaNullMethod>
#define B_32_I1_2805_5 NeoPixelBusLg<NeoGrbwwFeature, NeoEsp32I2s1Ws2805Method, NeoGammaNullMethod> #define B_32_IP_2805_5 NeoPixelBusLg<NeoGrbwwFeature, X8Ws2805Method, NeoGammaNullMethod> // parallel I2S
#define B_32_I1_2805_5P NeoPixelBusLg<NeoGrbwwFeature, NeoEsp32I2s1X8Ws2805Method, NeoGammaNullMethod> // parallel I2S
//TM1914 (RGB) //TM1914 (RGB)
#define B_32_RN_TM1914_3 NeoPixelBusLg<NeoGrbTm1914Feature, NeoEsp32RmtNTm1914Method, NeoGammaNullMethod> #define B_32_RN_TM1914_3 NeoPixelBusLg<NeoGrbTm1914Feature, NeoEsp32RmtNTm1914Method, NeoGammaNullMethod>
#define B_32_I0_TM1914_3 NeoPixelBusLg<NeoGrbTm1914Feature, NeoEsp32I2s0Tm1914Method, NeoGammaNullMethod> #define B_32_I2_TM1914_3 NeoPixelBusLg<NeoGrbTm1914Feature, X1Tm1914Method, NeoGammaNullMethod>
#define B_32_I1_TM1914_3 NeoPixelBusLg<NeoGrbTm1914Feature, NeoEsp32I2s1Tm1914Method, NeoGammaNullMethod> #define B_32_IP_TM1914_3 NeoPixelBusLg<NeoGrbTm1914Feature, X8Tm1914Method, NeoGammaNullMethod> // parallel I2S
#define B_32_I1_TM1914_3P NeoPixelBusLg<NeoGrbTm1914Feature, NeoEsp32I2s1X8Tm1914Method, NeoGammaNullMethod> // parallel I2S
//Sm16825 (RGBWC) //Sm16825 (RGBWC)
#define B_32_RN_SM16825_5 NeoPixelBusLg<NeoRgbcwSm16825eFeature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod> #define B_32_RN_SM16825_5 NeoPixelBusLg<NeoRgbcwSm16825eFeature, NeoEsp32RmtNWs2812xMethod, NeoGammaNullMethod>
#define B_32_I0_SM16825_5 NeoPixelBusLg<NeoRgbcwSm16825eFeature, NeoEsp32I2s0Ws2812xMethod, NeoGammaNullMethod> #define B_32_I2_SM16825_5 NeoPixelBusLg<NeoRgbcwSm16825eFeature, X1Ws2812xMethod, NeoGammaNullMethod>
#define B_32_I1_SM16825_5 NeoPixelBusLg<NeoRgbcwSm16825eFeature, NeoEsp32I2s1Ws2812xMethod, NeoGammaNullMethod> #define B_32_IP_SM16825_5 NeoPixelBusLg<NeoRgbcwSm16825eFeature, X8Ws2812xMethod, NeoGammaNullMethod> // parallel I2S
#define B_32_I1_SM16825_5P NeoPixelBusLg<NeoRgbcwSm16825eFeature, NeoEsp32I2s1X8Ws2812xMethod, NeoGammaNullMethod> // parallel I2S
#endif #endif
//APA102 //APA102
@ -328,11 +331,11 @@
//handles pointer type conversion for all possible bus types //handles pointer type conversion for all possible bus types
class PolyBus { class PolyBus {
private: private:
static bool useParallelI2S; static bool _useParallelI2S;
public: public:
static inline void setParallelI2S1Output(bool b = true) { useParallelI2S = b; } static inline void setParallelI2S1Output(bool b = true) { _useParallelI2S = b; }
static inline bool isParallelI2S1Output(void) { return useParallelI2S; } static inline bool isParallelI2S1Output(void) { return _useParallelI2S; }
// initialize SPI bus speed for DotStar methods // initialize SPI bus speed for DotStar methods
template <class T> template <class T>
@ -436,34 +439,19 @@ class PolyBus {
case I_32_RN_TM1914_3: beginTM1914<B_32_RN_TM1914_3*>(busPtr); break; case I_32_RN_TM1914_3: beginTM1914<B_32_RN_TM1914_3*>(busPtr); break;
case I_32_RN_SM16825_5: (static_cast<B_32_RN_SM16825_5*>(busPtr))->Begin(); break; case I_32_RN_SM16825_5: (static_cast<B_32_RN_SM16825_5*>(busPtr))->Begin(); break;
// I2S1 bus or parellel buses // I2S1 bus or parellel buses
#ifndef WLED_NO_I2S1_PIXELBUS #ifndef CONFIG_IDF_TARGET_ESP32C3
case I_32_I1_NEO_3: if (useParallelI2S) (static_cast<B_32_I1_NEO_3P*>(busPtr))->Begin(); else (static_cast<B_32_I1_NEO_3*>(busPtr))->Begin(); break; case I_32_I2_NEO_3: if (_useParallelI2S) (static_cast<B_32_IP_NEO_3*>(busPtr))->Begin(); else (static_cast<B_32_I2_NEO_3*>(busPtr))->Begin(); break;
case I_32_I1_NEO_4: if (useParallelI2S) (static_cast<B_32_I1_NEO_4P*>(busPtr))->Begin(); else (static_cast<B_32_I1_NEO_4*>(busPtr))->Begin(); break; case I_32_I2_NEO_4: if (_useParallelI2S) (static_cast<B_32_IP_NEO_4*>(busPtr))->Begin(); else (static_cast<B_32_I2_NEO_4*>(busPtr))->Begin(); break;
case I_32_I1_400_3: if (useParallelI2S) (static_cast<B_32_I1_400_3P*>(busPtr))->Begin(); else (static_cast<B_32_I1_400_3*>(busPtr))->Begin(); break; case I_32_I2_400_3: if (_useParallelI2S) (static_cast<B_32_IP_400_3*>(busPtr))->Begin(); else (static_cast<B_32_I2_400_3*>(busPtr))->Begin(); break;
case I_32_I1_TM1_4: if (useParallelI2S) beginTM1814<B_32_I1_TM1_4P*>(busPtr); else beginTM1814<B_32_I1_TM1_4*>(busPtr); break; case I_32_I2_TM1_4: if (_useParallelI2S) beginTM1814<B_32_IP_TM1_4*>(busPtr); else beginTM1814<B_32_I2_TM1_4*>(busPtr); break;
case I_32_I1_TM2_3: if (useParallelI2S) (static_cast<B_32_I1_TM2_3P*>(busPtr))->Begin(); else (static_cast<B_32_I1_TM2_3*>(busPtr))->Begin(); break; case I_32_I2_TM2_3: if (_useParallelI2S) (static_cast<B_32_IP_TM2_3*>(busPtr))->Begin(); else (static_cast<B_32_I2_TM2_3*>(busPtr))->Begin(); break;
case I_32_I1_UCS_3: if (useParallelI2S) (static_cast<B_32_I1_UCS_3P*>(busPtr))->Begin(); else (static_cast<B_32_I1_UCS_3*>(busPtr))->Begin(); break; case I_32_I2_UCS_3: if (_useParallelI2S) (static_cast<B_32_IP_UCS_3*>(busPtr))->Begin(); else (static_cast<B_32_I2_UCS_3*>(busPtr))->Begin(); break;
case I_32_I1_UCS_4: if (useParallelI2S) (static_cast<B_32_I1_UCS_4P*>(busPtr))->Begin(); else (static_cast<B_32_I1_UCS_4*>(busPtr))->Begin(); break; case I_32_I2_UCS_4: if (_useParallelI2S) (static_cast<B_32_IP_UCS_4*>(busPtr))->Begin(); else (static_cast<B_32_I2_UCS_4*>(busPtr))->Begin(); break;
case I_32_I1_FW6_5: if (useParallelI2S) (static_cast<B_32_I1_FW6_5P*>(busPtr))->Begin(); else (static_cast<B_32_I1_FW6_5*>(busPtr))->Begin(); break; case I_32_I2_FW6_5: if (_useParallelI2S) (static_cast<B_32_IP_FW6_5*>(busPtr))->Begin(); else (static_cast<B_32_I2_FW6_5*>(busPtr))->Begin(); break;
case I_32_I1_APA106_3: if (useParallelI2S) (static_cast<B_32_I1_APA106_3P*>(busPtr))->Begin(); else (static_cast<B_32_I1_APA106_3*>(busPtr))->Begin(); break; case I_32_I2_APA106_3: if (_useParallelI2S) (static_cast<B_32_IP_APA106_3*>(busPtr))->Begin(); else (static_cast<B_32_I2_APA106_3*>(busPtr))->Begin(); break;
case I_32_I1_2805_5: if (useParallelI2S) (static_cast<B_32_I1_2805_5P*>(busPtr))->Begin(); else (static_cast<B_32_I1_2805_5*>(busPtr))->Begin(); break; case I_32_I2_2805_5: if (_useParallelI2S) (static_cast<B_32_IP_2805_5*>(busPtr))->Begin(); else (static_cast<B_32_I2_2805_5*>(busPtr))->Begin(); break;
case I_32_I1_TM1914_3: if (useParallelI2S) beginTM1914<B_32_I1_TM1914_3P*>(busPtr); else beginTM1914<B_32_I1_TM1914_3*>(busPtr); break; case I_32_I2_TM1914_3: if (_useParallelI2S) beginTM1914<B_32_IP_TM1914_3*>(busPtr); else beginTM1914<B_32_I2_TM1914_3*>(busPtr); break;
case I_32_I1_SM16825_5: if (useParallelI2S) (static_cast<B_32_I1_SM16825_5P*>(busPtr))->Begin(); else (static_cast<B_32_I1_SM16825_5*>(busPtr))->Begin(); break; case I_32_I2_SM16825_5: if (_useParallelI2S) (static_cast<B_32_IP_SM16825_5*>(busPtr))->Begin(); else (static_cast<B_32_I2_SM16825_5*>(busPtr))->Begin(); break;
#endif
// I2S0 bus
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->Begin(); break;
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->Begin(); break;
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->Begin(); break;
case I_32_I0_TM1_4: beginTM1814<B_32_I0_TM1_4*>(busPtr); break;
case I_32_I0_TM2_3: (static_cast<B_32_I0_TM2_3*>(busPtr))->Begin(); break;
case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->Begin(); break;
case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->Begin(); break;
case I_32_I0_FW6_5: (static_cast<B_32_I0_FW6_5*>(busPtr))->Begin(); break;
case I_32_I0_APA106_3: (static_cast<B_32_I0_APA106_3*>(busPtr))->Begin(); break;
case I_32_I0_2805_5: (static_cast<B_32_I0_2805_5*>(busPtr))->Begin(); break;
case I_32_I0_TM1914_3: beginTM1914<B_32_I0_TM1914_3*>(busPtr); break;
case I_32_I0_SM16825_5: (static_cast<B_32_I0_SM16825_5*>(busPtr))->Begin(); break;
#endif #endif
// ESP32 can (and should, to avoid inadvertantly driving the chip select signal) specify the pins used for SPI, but only in begin() // ESP32 can (and should, to avoid inadvertantly driving the chip select signal) specify the pins used for SPI, but only in begin()
case I_HS_DOT_3: beginDotStar<B_HS_DOT_3*>(busPtr, pins[1], -1, pins[0], -1, clock_kHz); break; case I_HS_DOT_3: beginDotStar<B_HS_DOT_3*>(busPtr, pins[1], -1, pins[0], -1, clock_kHz); break;
@ -484,8 +472,8 @@ class PolyBus {
#if defined(ARDUINO_ARCH_ESP32) && !(defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3)) #if defined(ARDUINO_ARCH_ESP32) && !(defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3))
// NOTE: "channel" is only used on ESP32 (and its variants) for RMT channel allocation // NOTE: "channel" is only used on ESP32 (and its variants) for RMT channel allocation
// since 0.15.0-b3 I2S1 is favoured for classic ESP32 and moved to position 0 (channel 0) so we need to subtract 1 for correct RMT allocation // since 0.15.0-b3 I2S1 is favoured for classic ESP32 and moved to position 0 (channel 0) so we need to subtract 1 for correct RMT allocation
if (useParallelI2S && channel > 7) channel -= 8; // accommodate parallel I2S1 which is used 1st on classic ESP32 if (!_useParallelI2S && channel > 0) channel--; // accommodate I2S1 which is used as 1st bus on classic ESP32
else if (channel > 0) channel--; // accommodate I2S1 which is used as 1st bus on classic ESP32 // if user selected parallel I2S, RMT is used 1st (8 channels) followed by parallel I2S (8 channels)
#endif #endif
void* busPtr = nullptr; void* busPtr = nullptr;
switch (busType) { switch (busType) {
@ -555,34 +543,19 @@ class PolyBus {
case I_32_RN_TM1914_3: busPtr = new B_32_RN_TM1914_3(len, pins[0], (NeoBusChannel)channel); break; case I_32_RN_TM1914_3: busPtr = new B_32_RN_TM1914_3(len, pins[0], (NeoBusChannel)channel); break;
case I_32_RN_SM16825_5: busPtr = new B_32_RN_SM16825_5(len, pins[0], (NeoBusChannel)channel); break; case I_32_RN_SM16825_5: busPtr = new B_32_RN_SM16825_5(len, pins[0], (NeoBusChannel)channel); break;
// I2S1 bus or paralell buses // I2S1 bus or paralell buses
#ifndef WLED_NO_I2S1_PIXELBUS #ifndef CONFIG_IDF_TARGET_ESP32C3
case I_32_I1_NEO_3: if (useParallelI2S) busPtr = new B_32_I1_NEO_3P(len, pins[0]); else busPtr = new B_32_I1_NEO_3(len, pins[0]); break; case I_32_I2_NEO_3: if (_useParallelI2S) busPtr = new B_32_IP_NEO_3(len, pins[0]); else busPtr = new B_32_I2_NEO_3(len, pins[0]); break;
case I_32_I1_NEO_4: if (useParallelI2S) busPtr = new B_32_I1_NEO_4P(len, pins[0]); else busPtr = new B_32_I1_NEO_4(len, pins[0]); break; case I_32_I2_NEO_4: if (_useParallelI2S) busPtr = new B_32_IP_NEO_4(len, pins[0]); else busPtr = new B_32_I2_NEO_4(len, pins[0]); break;
case I_32_I1_400_3: if (useParallelI2S) busPtr = new B_32_I1_400_3P(len, pins[0]); else busPtr = new B_32_I1_400_3(len, pins[0]); break; case I_32_I2_400_3: if (_useParallelI2S) busPtr = new B_32_IP_400_3(len, pins[0]); else busPtr = new B_32_I2_400_3(len, pins[0]); break;
case I_32_I1_TM1_4: if (useParallelI2S) busPtr = new B_32_I1_TM1_4P(len, pins[0]); else busPtr = new B_32_I1_TM1_4(len, pins[0]); break; case I_32_I2_TM1_4: if (_useParallelI2S) busPtr = new B_32_IP_TM1_4(len, pins[0]); else busPtr = new B_32_I2_TM1_4(len, pins[0]); break;
case I_32_I1_TM2_3: if (useParallelI2S) busPtr = new B_32_I1_TM2_3P(len, pins[0]); else busPtr = new B_32_I1_TM2_3(len, pins[0]); break; case I_32_I2_TM2_3: if (_useParallelI2S) busPtr = new B_32_IP_TM2_3(len, pins[0]); else busPtr = new B_32_I2_TM2_3(len, pins[0]); break;
case I_32_I1_UCS_3: if (useParallelI2S) busPtr = new B_32_I1_UCS_3P(len, pins[0]); else busPtr = new B_32_I1_UCS_3(len, pins[0]); break; case I_32_I2_UCS_3: if (_useParallelI2S) busPtr = new B_32_IP_UCS_3(len, pins[0]); else busPtr = new B_32_I2_UCS_3(len, pins[0]); break;
case I_32_I1_UCS_4: if (useParallelI2S) busPtr = new B_32_I1_UCS_4P(len, pins[0]); else busPtr = new B_32_I1_UCS_4(len, pins[0]); break; case I_32_I2_UCS_4: if (_useParallelI2S) busPtr = new B_32_IP_UCS_4(len, pins[0]); else busPtr = new B_32_I2_UCS_4(len, pins[0]); break;
case I_32_I1_APA106_3: if (useParallelI2S) busPtr = new B_32_I1_APA106_3P(len, pins[0]); else busPtr = new B_32_I1_APA106_3(len, pins[0]); break; case I_32_I2_APA106_3: if (_useParallelI2S) busPtr = new B_32_IP_APA106_3(len, pins[0]); else busPtr = new B_32_I2_APA106_3(len, pins[0]); break;
case I_32_I1_FW6_5: if (useParallelI2S) busPtr = new B_32_I1_FW6_5P(len, pins[0]); else busPtr = new B_32_I1_FW6_5(len, pins[0]); break; case I_32_I2_FW6_5: if (_useParallelI2S) busPtr = new B_32_IP_FW6_5(len, pins[0]); else busPtr = new B_32_I2_FW6_5(len, pins[0]); break;
case I_32_I1_2805_5: if (useParallelI2S) busPtr = new B_32_I1_2805_5P(len, pins[0]); else busPtr = new B_32_I1_2805_5(len, pins[0]); break; case I_32_I2_2805_5: if (_useParallelI2S) busPtr = new B_32_IP_2805_5(len, pins[0]); else busPtr = new B_32_I2_2805_5(len, pins[0]); break;
case I_32_I1_TM1914_3: if (useParallelI2S) busPtr = new B_32_I1_TM1914_3P(len, pins[0]); else busPtr = new B_32_I1_TM1914_3(len, pins[0]); break; case I_32_I2_TM1914_3: if (_useParallelI2S) busPtr = new B_32_IP_TM1914_3(len, pins[0]); else busPtr = new B_32_I2_TM1914_3(len, pins[0]); break;
case I_32_I1_SM16825_5: if (useParallelI2S) busPtr = new B_32_I1_SM16825_5P(len, pins[0]); else busPtr = new B_32_I1_SM16825_5(len, pins[0]); break; case I_32_I2_SM16825_5: if (_useParallelI2S) busPtr = new B_32_IP_SM16825_5(len, pins[0]); else busPtr = new B_32_I2_SM16825_5(len, pins[0]); break;
#endif
// I2S0 bus
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_NEO_3: busPtr = new B_32_I0_NEO_3(len, pins[0]); break;
case I_32_I0_NEO_4: busPtr = new B_32_I0_NEO_4(len, pins[0]); break;
case I_32_I0_400_3: busPtr = new B_32_I0_400_3(len, pins[0]); break;
case I_32_I0_TM1_4: busPtr = new B_32_I0_TM1_4(len, pins[0]); break;
case I_32_I0_TM2_3: busPtr = new B_32_I0_TM2_3(len, pins[0]); break;
case I_32_I0_UCS_3: busPtr = new B_32_I0_UCS_3(len, pins[0]); break;
case I_32_I0_UCS_4: busPtr = new B_32_I0_UCS_4(len, pins[0]); break;
case I_32_I0_APA106_3: busPtr = new B_32_I0_APA106_3(len, pins[0]); break;
case I_32_I0_FW6_5: busPtr = new B_32_I0_FW6_5(len, pins[0]); break;
case I_32_I0_2805_5: busPtr = new B_32_I0_2805_5(len, pins[0]); break;
case I_32_I0_TM1914_3: busPtr = new B_32_I0_TM1914_3(len, pins[0]); break;
case I_32_I0_SM16825_5: busPtr = new B_32_I0_SM16825_5(len, pins[0]); break;
#endif #endif
#endif #endif
// for 2-wire: pins[1] is clk, pins[0] is dat. begin expects (len, clk, dat) // for 2-wire: pins[1] is clk, pins[0] is dat. begin expects (len, clk, dat)
@ -669,34 +642,19 @@ class PolyBus {
case I_32_RN_TM1914_3: (static_cast<B_32_RN_TM1914_3*>(busPtr))->Show(consistent); break; case I_32_RN_TM1914_3: (static_cast<B_32_RN_TM1914_3*>(busPtr))->Show(consistent); break;
case I_32_RN_SM16825_5: (static_cast<B_32_RN_SM16825_5*>(busPtr))->Show(consistent); break; case I_32_RN_SM16825_5: (static_cast<B_32_RN_SM16825_5*>(busPtr))->Show(consistent); break;
// I2S1 bus or paralell buses // I2S1 bus or paralell buses
#ifndef WLED_NO_I2S1_PIXELBUS #ifndef CONFIG_IDF_TARGET_ESP32C3
case I_32_I1_NEO_3: if (useParallelI2S) (static_cast<B_32_I1_NEO_3P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_NEO_3*>(busPtr))->Show(consistent); break; case I_32_I2_NEO_3: if (_useParallelI2S) (static_cast<B_32_IP_NEO_3*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_NEO_3*>(busPtr))->Show(consistent); break;
case I_32_I1_NEO_4: if (useParallelI2S) (static_cast<B_32_I1_NEO_4P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_NEO_4*>(busPtr))->Show(consistent); break; case I_32_I2_NEO_4: if (_useParallelI2S) (static_cast<B_32_IP_NEO_4*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_NEO_4*>(busPtr))->Show(consistent); break;
case I_32_I1_400_3: if (useParallelI2S) (static_cast<B_32_I1_400_3P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_400_3*>(busPtr))->Show(consistent); break; case I_32_I2_400_3: if (_useParallelI2S) (static_cast<B_32_IP_400_3*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_400_3*>(busPtr))->Show(consistent); break;
case I_32_I1_TM1_4: if (useParallelI2S) (static_cast<B_32_I1_TM1_4P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_TM1_4*>(busPtr))->Show(consistent); break; case I_32_I2_TM1_4: if (_useParallelI2S) (static_cast<B_32_IP_TM1_4*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_TM1_4*>(busPtr))->Show(consistent); break;
case I_32_I1_TM2_3: if (useParallelI2S) (static_cast<B_32_I1_TM2_3P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_TM2_3*>(busPtr))->Show(consistent); break; case I_32_I2_TM2_3: if (_useParallelI2S) (static_cast<B_32_IP_TM2_3*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_TM2_3*>(busPtr))->Show(consistent); break;
case I_32_I1_UCS_3: if (useParallelI2S) (static_cast<B_32_I1_UCS_3P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_UCS_3*>(busPtr))->Show(consistent); break; case I_32_I2_UCS_3: if (_useParallelI2S) (static_cast<B_32_IP_UCS_3*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_UCS_3*>(busPtr))->Show(consistent); break;
case I_32_I1_UCS_4: if (useParallelI2S) (static_cast<B_32_I1_UCS_4P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_UCS_4*>(busPtr))->Show(consistent); break; case I_32_I2_UCS_4: if (_useParallelI2S) (static_cast<B_32_IP_UCS_4*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_UCS_4*>(busPtr))->Show(consistent); break;
case I_32_I1_APA106_3: if (useParallelI2S) (static_cast<B_32_I1_APA106_3P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_APA106_3*>(busPtr))->Show(consistent); break; case I_32_I2_APA106_3: if (_useParallelI2S) (static_cast<B_32_IP_APA106_3*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_APA106_3*>(busPtr))->Show(consistent); break;
case I_32_I1_FW6_5: if (useParallelI2S) (static_cast<B_32_I1_FW6_5P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_FW6_5*>(busPtr))->Show(consistent); break; case I_32_I2_FW6_5: if (_useParallelI2S) (static_cast<B_32_IP_FW6_5*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_FW6_5*>(busPtr))->Show(consistent); break;
case I_32_I1_2805_5: if (useParallelI2S) (static_cast<B_32_I1_2805_5P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_2805_5*>(busPtr))->Show(consistent); break; case I_32_I2_2805_5: if (_useParallelI2S) (static_cast<B_32_IP_2805_5*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_2805_5*>(busPtr))->Show(consistent); break;
case I_32_I1_TM1914_3: if (useParallelI2S) (static_cast<B_32_I1_TM1914_3P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_TM1914_3*>(busPtr))->Show(consistent); break; case I_32_I2_TM1914_3: if (_useParallelI2S) (static_cast<B_32_IP_TM1914_3*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_TM1914_3*>(busPtr))->Show(consistent); break;
case I_32_I1_SM16825_5: if (useParallelI2S) (static_cast<B_32_I1_SM16825_5P*>(busPtr))->Show(consistent); else (static_cast<B_32_I1_SM16825_5*>(busPtr))->Show(consistent); break; case I_32_I2_SM16825_5: if (_useParallelI2S) (static_cast<B_32_IP_SM16825_5*>(busPtr))->Show(consistent); else (static_cast<B_32_I2_SM16825_5*>(busPtr))->Show(consistent); break;
#endif
// I2S0 bus
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->Show(consistent); break;
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->Show(consistent); break;
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->Show(consistent); break;
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->Show(consistent); break;
case I_32_I0_TM2_3: (static_cast<B_32_I0_TM2_3*>(busPtr))->Show(consistent); break;
case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->Show(consistent); break;
case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->Show(consistent); break;
case I_32_I0_APA106_3: (static_cast<B_32_I0_APA106_3*>(busPtr))->Show(consistent); break;
case I_32_I0_FW6_5: (static_cast<B_32_I0_FW6_5*>(busPtr))->Show(consistent); break;
case I_32_I0_2805_5: (static_cast<B_32_I0_2805_5*>(busPtr))->Show(consistent); break;
case I_32_I0_TM1914_3: (static_cast<B_32_I0_TM1914_3*>(busPtr))->Show(consistent); break;
case I_32_I0_SM16825_5: (static_cast<B_32_I0_SM16825_5*>(busPtr))->Show(consistent); break;
#endif #endif
#endif #endif
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->Show(consistent); break; case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->Show(consistent); break;
@ -743,6 +701,7 @@ class PolyBus {
case I_8266_U0_UCS_4: return (static_cast<B_8266_U0_UCS_4*>(busPtr))->CanShow(); break; case I_8266_U0_UCS_4: return (static_cast<B_8266_U0_UCS_4*>(busPtr))->CanShow(); break;
case I_8266_U1_UCS_4: return (static_cast<B_8266_U1_UCS_4*>(busPtr))->CanShow(); break; case I_8266_U1_UCS_4: return (static_cast<B_8266_U1_UCS_4*>(busPtr))->CanShow(); break;
case I_8266_DM_UCS_4: return (static_cast<B_8266_DM_UCS_4*>(busPtr))->CanShow(); break; case I_8266_DM_UCS_4: return (static_cast<B_8266_DM_UCS_4*>(busPtr))->CanShow(); break;
case I_8266_BB_UCS_4: return (static_cast<B_8266_BB_UCS_4*>(busPtr))->CanShow(); break;
case I_8266_U0_APA106_3: return (static_cast<B_8266_U0_APA106_3*>(busPtr))->CanShow(); break; case I_8266_U0_APA106_3: return (static_cast<B_8266_U0_APA106_3*>(busPtr))->CanShow(); break;
case I_8266_U1_APA106_3: return (static_cast<B_8266_U1_APA106_3*>(busPtr))->CanShow(); break; case I_8266_U1_APA106_3: return (static_cast<B_8266_U1_APA106_3*>(busPtr))->CanShow(); break;
case I_8266_DM_APA106_3: return (static_cast<B_8266_DM_APA106_3*>(busPtr))->CanShow(); break; case I_8266_DM_APA106_3: return (static_cast<B_8266_DM_APA106_3*>(busPtr))->CanShow(); break;
@ -779,34 +738,19 @@ class PolyBus {
case I_32_RN_TM1914_3: return (static_cast<B_32_RN_TM1914_3*>(busPtr))->CanShow(); break; case I_32_RN_TM1914_3: return (static_cast<B_32_RN_TM1914_3*>(busPtr))->CanShow(); break;
case I_32_RN_SM16825_5: return (static_cast<B_32_RN_SM16825_5*>(busPtr))->CanShow(); break; case I_32_RN_SM16825_5: return (static_cast<B_32_RN_SM16825_5*>(busPtr))->CanShow(); break;
// I2S1 bus or paralell buses // I2S1 bus or paralell buses
#ifndef WLED_NO_I2S1_PIXELBUS #ifndef CONFIG_IDF_TARGET_ESP32C3
case I_32_I1_NEO_3: if (useParallelI2S) return (static_cast<B_32_I1_NEO_3P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_NEO_3*>(busPtr))->CanShow(); break; case I_32_I2_NEO_3: if (_useParallelI2S) return (static_cast<B_32_IP_NEO_3*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_NEO_3*>(busPtr))->CanShow(); break;
case I_32_I1_NEO_4: if (useParallelI2S) return (static_cast<B_32_I1_NEO_4P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_NEO_4*>(busPtr))->CanShow(); break; case I_32_I2_NEO_4: if (_useParallelI2S) return (static_cast<B_32_IP_NEO_4*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_NEO_4*>(busPtr))->CanShow(); break;
case I_32_I1_400_3: if (useParallelI2S) return (static_cast<B_32_I1_400_3P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_400_3*>(busPtr))->CanShow(); break; case I_32_I2_400_3: if (_useParallelI2S) return (static_cast<B_32_IP_400_3*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_400_3*>(busPtr))->CanShow(); break;
case I_32_I1_TM1_4: if (useParallelI2S) return (static_cast<B_32_I1_TM1_4P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_TM1_4*>(busPtr))->CanShow(); break; case I_32_I2_TM1_4: if (_useParallelI2S) return (static_cast<B_32_IP_TM1_4*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_TM1_4*>(busPtr))->CanShow(); break;
case I_32_I1_TM2_3: if (useParallelI2S) return (static_cast<B_32_I1_TM2_3P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_TM2_3*>(busPtr))->CanShow(); break; case I_32_I2_TM2_3: if (_useParallelI2S) return (static_cast<B_32_IP_TM2_3*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_TM2_3*>(busPtr))->CanShow(); break;
case I_32_I1_UCS_3: if (useParallelI2S) return (static_cast<B_32_I1_UCS_3P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_UCS_3*>(busPtr))->CanShow(); break; case I_32_I2_UCS_3: if (_useParallelI2S) return (static_cast<B_32_IP_UCS_3*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_UCS_3*>(busPtr))->CanShow(); break;
case I_32_I1_UCS_4: if (useParallelI2S) return (static_cast<B_32_I1_UCS_4P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_UCS_4*>(busPtr))->CanShow(); break; case I_32_I2_UCS_4: if (_useParallelI2S) return (static_cast<B_32_IP_UCS_4*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_UCS_4*>(busPtr))->CanShow(); break;
case I_32_I1_APA106_3: if (useParallelI2S) return (static_cast<B_32_I1_APA106_3P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_APA106_3*>(busPtr))->CanShow(); break; case I_32_I2_APA106_3: if (_useParallelI2S) return (static_cast<B_32_IP_APA106_3*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_APA106_3*>(busPtr))->CanShow(); break;
case I_32_I1_FW6_5: if (useParallelI2S) return (static_cast<B_32_I1_FW6_5P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_FW6_5*>(busPtr))->CanShow(); break; case I_32_I2_FW6_5: if (_useParallelI2S) return (static_cast<B_32_IP_FW6_5*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_FW6_5*>(busPtr))->CanShow(); break;
case I_32_I1_2805_5: if (useParallelI2S) return (static_cast<B_32_I1_2805_5P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_2805_5*>(busPtr))->CanShow(); break; case I_32_I2_2805_5: if (_useParallelI2S) return (static_cast<B_32_IP_2805_5*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_2805_5*>(busPtr))->CanShow(); break;
case I_32_I1_TM1914_3: if (useParallelI2S) return (static_cast<B_32_I1_TM1914_3P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_TM1914_3*>(busPtr))->CanShow(); break; case I_32_I2_TM1914_3: if (_useParallelI2S) return (static_cast<B_32_IP_TM1914_3*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_TM1914_3*>(busPtr))->CanShow(); break;
case I_32_I1_SM16825_5: if (useParallelI2S) return (static_cast<B_32_I1_SM16825_5P*>(busPtr))->CanShow(); else return (static_cast<B_32_I1_SM16825_5*>(busPtr))->CanShow(); break; case I_32_I2_SM16825_5: if (_useParallelI2S) return (static_cast<B_32_IP_SM16825_5*>(busPtr))->CanShow(); else return (static_cast<B_32_I2_SM16825_5*>(busPtr))->CanShow(); break;
#endif
// I2S0 bus
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_NEO_3: return (static_cast<B_32_I0_NEO_3*>(busPtr))->CanShow(); break;
case I_32_I0_NEO_4: return (static_cast<B_32_I0_NEO_4*>(busPtr))->CanShow(); break;
case I_32_I0_400_3: return (static_cast<B_32_I0_400_3*>(busPtr))->CanShow(); break;
case I_32_I0_TM1_4: return (static_cast<B_32_I0_TM1_4*>(busPtr))->CanShow(); break;
case I_32_I0_TM2_3: return (static_cast<B_32_I0_TM2_3*>(busPtr))->CanShow(); break;
case I_32_I0_UCS_3: return (static_cast<B_32_I0_UCS_3*>(busPtr))->CanShow(); break;
case I_32_I0_UCS_4: return (static_cast<B_32_I0_UCS_4*>(busPtr))->CanShow(); break;
case I_32_I0_APA106_3: return (static_cast<B_32_I0_APA106_3*>(busPtr))->CanShow(); break;
case I_32_I0_FW6_5: return (static_cast<B_32_I0_FW6_5*>(busPtr))->CanShow(); break;
case I_32_I0_2805_5: return (static_cast<B_32_I0_2805_5*>(busPtr))->CanShow(); break;
case I_32_I0_TM1914_3: return (static_cast<B_32_I0_TM1914_3*>(busPtr))->CanShow(); break;
case I_32_I0_SM16825_5: return (static_cast<B_32_I0_SM16825_5*>(busPtr))->CanShow(); break;
#endif #endif
#endif #endif
case I_HS_DOT_3: return (static_cast<B_HS_DOT_3*>(busPtr))->CanShow(); break; case I_HS_DOT_3: return (static_cast<B_HS_DOT_3*>(busPtr))->CanShow(); break;
@ -823,7 +767,7 @@ class PolyBus {
return true; return true;
} }
static void setPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint32_t c, uint8_t co, uint16_t wwcw = 0) { [[gnu::hot]] static void setPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint32_t c, uint8_t co, uint16_t wwcw = 0) {
uint8_t r = c >> 16; uint8_t r = c >> 16;
uint8_t g = c >> 8; uint8_t g = c >> 8;
uint8_t b = c >> 0; uint8_t b = c >> 0;
@ -916,34 +860,19 @@ class PolyBus {
case I_32_RN_TM1914_3: (static_cast<B_32_RN_TM1914_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; case I_32_RN_TM1914_3: (static_cast<B_32_RN_TM1914_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
case I_32_RN_SM16825_5: (static_cast<B_32_RN_SM16825_5*>(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); break; case I_32_RN_SM16825_5: (static_cast<B_32_RN_SM16825_5*>(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); break;
// I2S1 bus or paralell buses // I2S1 bus or paralell buses
#ifndef WLED_NO_I2S1_PIXELBUS #ifndef CONFIG_IDF_TARGET_ESP32C3
case I_32_I1_NEO_3: if (useParallelI2S) (static_cast<B_32_I1_NEO_3P*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I1_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; case I_32_I2_NEO_3: if (_useParallelI2S) (static_cast<B_32_IP_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I2_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
case I_32_I1_NEO_4: if (useParallelI2S) (static_cast<B_32_I1_NEO_4P*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I1_NEO_4*>(busPtr))->SetPixelColor(pix, col); break; case I_32_I2_NEO_4: if (_useParallelI2S) (static_cast<B_32_IP_NEO_4*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I2_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_I1_400_3: if (useParallelI2S) (static_cast<B_32_I1_400_3P*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I1_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; case I_32_I2_400_3: if (_useParallelI2S) (static_cast<B_32_IP_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I2_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
case I_32_I1_TM1_4: if (useParallelI2S) (static_cast<B_32_I1_TM1_4P*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I1_TM1_4*>(busPtr))->SetPixelColor(pix, col); break; case I_32_I2_TM1_4: if (_useParallelI2S) (static_cast<B_32_IP_TM1_4*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I2_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_I1_TM2_3: if (useParallelI2S) (static_cast<B_32_I1_TM2_3P*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I1_TM2_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; case I_32_I2_TM2_3: if (_useParallelI2S) (static_cast<B_32_IP_TM2_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I2_TM2_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
case I_32_I1_UCS_3: if (useParallelI2S) (static_cast<B_32_I1_UCS_3P*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I1_UCS_3*>(busPtr))->SetPixelColor(pix, Rgb48Color(RgbColor(col))); break; case I_32_I2_UCS_3: if (_useParallelI2S) (static_cast<B_32_IP_UCS_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I2_UCS_3*>(busPtr))->SetPixelColor(pix, Rgb48Color(RgbColor(col))); break;
case I_32_I1_UCS_4: if (useParallelI2S) (static_cast<B_32_I1_UCS_4P*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I1_UCS_4*>(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break; case I_32_I2_UCS_4: if (_useParallelI2S) (static_cast<B_32_IP_UCS_4*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I2_UCS_4*>(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break;
case I_32_I1_APA106_3: if (useParallelI2S) (static_cast<B_32_I1_APA106_3P*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I1_APA106_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; case I_32_I2_APA106_3: if (_useParallelI2S) (static_cast<B_32_IP_APA106_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I2_APA106_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
case I_32_I1_FW6_5: if (useParallelI2S) (static_cast<B_32_I1_FW6_5P*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); else (static_cast<B_32_I1_FW6_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; case I_32_I2_FW6_5: if (_useParallelI2S) (static_cast<B_32_IP_FW6_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); else (static_cast<B_32_I2_FW6_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break;
case I_32_I1_2805_5: if (useParallelI2S) (static_cast<B_32_I1_2805_5P*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); else (static_cast<B_32_I1_2805_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; case I_32_I2_2805_5: if (_useParallelI2S) (static_cast<B_32_IP_2805_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); else (static_cast<B_32_I2_2805_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break;
case I_32_I1_TM1914_3: if (useParallelI2S) (static_cast<B_32_I1_TM1914_3P*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I1_TM1914_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; case I_32_I2_TM1914_3: if (_useParallelI2S) (static_cast<B_32_IP_TM1914_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast<B_32_I2_TM1914_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
case I_32_I1_SM16825_5: if (useParallelI2S) (static_cast<B_32_I1_SM16825_5P*>(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); else (static_cast<B_32_I1_SM16825_5*>(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); break; case I_32_I2_SM16825_5: if (_useParallelI2S) (static_cast<B_32_IP_SM16825_5*>(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); else (static_cast<B_32_I2_SM16825_5*>(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); break;
#endif
// I2S0 bus
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->SetPixelColor(pix, col); break;
case I_32_I0_TM2_3: (static_cast<B_32_I0_TM2_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->SetPixelColor(pix, Rgb48Color(RgbColor(col))); break;
case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break;
case I_32_I0_APA106_3: (static_cast<B_32_I0_APA106_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
case I_32_I0_FW6_5: (static_cast<B_32_I0_FW6_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break;
case I_32_I0_2805_5: (static_cast<B_32_I0_2805_5*>(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break;
case I_32_I0_TM1914_3: (static_cast<B_32_I0_TM1914_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
case I_32_I0_SM16825_5: (static_cast<B_32_I0_SM16825_5*>(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); break;
#endif #endif
#endif #endif
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
@ -1027,34 +956,19 @@ class PolyBus {
case I_32_RN_TM1914_3: (static_cast<B_32_RN_TM1914_3*>(busPtr))->SetLuminance(b); break; case I_32_RN_TM1914_3: (static_cast<B_32_RN_TM1914_3*>(busPtr))->SetLuminance(b); break;
case I_32_RN_SM16825_5: (static_cast<B_32_RN_SM16825_5*>(busPtr))->SetLuminance(b); break; case I_32_RN_SM16825_5: (static_cast<B_32_RN_SM16825_5*>(busPtr))->SetLuminance(b); break;
// I2S1 bus or paralell buses // I2S1 bus or paralell buses
#ifndef WLED_NO_I2S1_PIXELBUS #ifndef CONFIG_IDF_TARGET_ESP32C3
case I_32_I1_NEO_3: if (useParallelI2S) (static_cast<B_32_I1_NEO_3P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_NEO_3*>(busPtr))->SetLuminance(b); break; case I_32_I2_NEO_3: if (_useParallelI2S) (static_cast<B_32_IP_NEO_3*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_NEO_3*>(busPtr))->SetLuminance(b); break;
case I_32_I1_NEO_4: if (useParallelI2S) (static_cast<B_32_I1_NEO_4P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_NEO_4*>(busPtr))->SetLuminance(b); break; case I_32_I2_NEO_4: if (_useParallelI2S) (static_cast<B_32_IP_NEO_4*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_NEO_4*>(busPtr))->SetLuminance(b); break;
case I_32_I1_400_3: if (useParallelI2S) (static_cast<B_32_I1_400_3P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_400_3*>(busPtr))->SetLuminance(b); break; case I_32_I2_400_3: if (_useParallelI2S) (static_cast<B_32_IP_400_3*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_400_3*>(busPtr))->SetLuminance(b); break;
case I_32_I1_TM1_4: if (useParallelI2S) (static_cast<B_32_I1_TM1_4P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_TM1_4*>(busPtr))->SetLuminance(b); break; case I_32_I2_TM1_4: if (_useParallelI2S) (static_cast<B_32_IP_TM1_4*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_TM1_4*>(busPtr))->SetLuminance(b); break;
case I_32_I1_TM2_3: if (useParallelI2S) (static_cast<B_32_I1_TM2_3P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_TM2_3*>(busPtr))->SetLuminance(b); break; case I_32_I2_TM2_3: if (_useParallelI2S) (static_cast<B_32_IP_TM2_3*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_TM2_3*>(busPtr))->SetLuminance(b); break;
case I_32_I1_UCS_3: if (useParallelI2S) (static_cast<B_32_I1_UCS_3P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_UCS_3*>(busPtr))->SetLuminance(b); break; case I_32_I2_UCS_3: if (_useParallelI2S) (static_cast<B_32_IP_UCS_3*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_UCS_3*>(busPtr))->SetLuminance(b); break;
case I_32_I1_UCS_4: if (useParallelI2S) (static_cast<B_32_I1_UCS_4P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_UCS_4*>(busPtr))->SetLuminance(b); break; case I_32_I2_UCS_4: if (_useParallelI2S) (static_cast<B_32_IP_UCS_4*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_UCS_4*>(busPtr))->SetLuminance(b); break;
case I_32_I1_APA106_3: if (useParallelI2S) (static_cast<B_32_I1_APA106_3P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_APA106_3*>(busPtr))->SetLuminance(b); break; case I_32_I2_APA106_3: if (_useParallelI2S) (static_cast<B_32_IP_APA106_3*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_APA106_3*>(busPtr))->SetLuminance(b); break;
case I_32_I1_FW6_5: if (useParallelI2S) (static_cast<B_32_I1_FW6_5P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_FW6_5*>(busPtr))->SetLuminance(b); break; case I_32_I2_FW6_5: if (_useParallelI2S) (static_cast<B_32_IP_FW6_5*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_FW6_5*>(busPtr))->SetLuminance(b); break;
case I_32_I1_2805_5: if (useParallelI2S) (static_cast<B_32_I1_2805_5P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_2805_5*>(busPtr))->SetLuminance(b); break; case I_32_I2_2805_5: if (_useParallelI2S) (static_cast<B_32_IP_2805_5*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_2805_5*>(busPtr))->SetLuminance(b); break;
case I_32_I1_TM1914_3: if (useParallelI2S) (static_cast<B_32_I1_TM1914_3P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_TM1914_3*>(busPtr))->SetLuminance(b); break; case I_32_I2_TM1914_3: if (_useParallelI2S) (static_cast<B_32_IP_TM1914_3*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_TM1914_3*>(busPtr))->SetLuminance(b); break;
case I_32_I1_SM16825_5: if (useParallelI2S) (static_cast<B_32_I1_SM16825_5P*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I1_SM16825_5*>(busPtr))->SetLuminance(b); break; case I_32_I2_SM16825_5: if (_useParallelI2S) (static_cast<B_32_IP_SM16825_5*>(busPtr))->SetLuminance(b); else (static_cast<B_32_I2_SM16825_5*>(busPtr))->SetLuminance(b); break;
#endif
// I2S0 bus
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->SetLuminance(b); break;
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->SetLuminance(b); break;
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->SetLuminance(b); break;
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->SetLuminance(b); break;
case I_32_I0_TM2_3: (static_cast<B_32_I0_TM2_3*>(busPtr))->SetLuminance(b); break;
case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->SetLuminance(b); break;
case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->SetLuminance(b); break;
case I_32_I0_APA106_3: (static_cast<B_32_I0_APA106_3*>(busPtr))->SetLuminance(b); break;
case I_32_I0_FW6_5: (static_cast<B_32_I0_FW6_5*>(busPtr))->SetLuminance(b); break;
case I_32_I0_2805_5: (static_cast<B_32_I0_2805_5*>(busPtr))->SetLuminance(b); break;
case I_32_I0_TM1914_3: (static_cast<B_32_I0_TM1914_3*>(busPtr))->SetLuminance(b); break;
case I_32_I0_SM16825_5: (static_cast<B_32_I0_SM16825_5*>(busPtr))->SetLuminance(b); break;
#endif #endif
#endif #endif
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetLuminance(b); break; case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->SetLuminance(b); break;
@ -1070,7 +984,7 @@ class PolyBus {
} }
} }
static uint32_t getPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint8_t co) { [[gnu::hot]] static uint32_t getPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint8_t co) {
RgbwColor col(0,0,0,0); RgbwColor col(0,0,0,0);
switch (busType) { switch (busType) {
case I_NONE: break; case I_NONE: break;
@ -1139,34 +1053,19 @@ class PolyBus {
case I_32_RN_TM1914_3: col = (static_cast<B_32_RN_TM1914_3*>(busPtr))->GetPixelColor(pix); break; case I_32_RN_TM1914_3: col = (static_cast<B_32_RN_TM1914_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_RN_SM16825_5: { Rgbww80Color c = (static_cast<B_32_RN_SM16825_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,max(c.WW,c.CW)/257); } break; // will not return original W case I_32_RN_SM16825_5: { Rgbww80Color c = (static_cast<B_32_RN_SM16825_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,max(c.WW,c.CW)/257); } break; // will not return original W
// I2S1 bus or paralell buses // I2S1 bus or paralell buses
#ifndef WLED_NO_I2S1_PIXELBUS #ifndef CONFIG_IDF_TARGET_ESP32C3
case I_32_I1_NEO_3: col = (useParallelI2S) ? (static_cast<B_32_I1_NEO_3P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_NEO_3*>(busPtr))->GetPixelColor(pix); break; case I_32_I2_NEO_3: col = (_useParallelI2S) ? (static_cast<B_32_IP_NEO_3*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_NEO_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_I1_NEO_4: col = (useParallelI2S) ? (static_cast<B_32_I1_NEO_4P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_NEO_4*>(busPtr))->GetPixelColor(pix); break; case I_32_I2_NEO_4: col = (_useParallelI2S) ? (static_cast<B_32_IP_NEO_4*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_NEO_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_I1_400_3: col = (useParallelI2S) ? (static_cast<B_32_I1_400_3P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_400_3*>(busPtr))->GetPixelColor(pix); break; case I_32_I2_400_3: col = (_useParallelI2S) ? (static_cast<B_32_IP_400_3*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_400_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_I1_TM1_4: col = (useParallelI2S) ? (static_cast<B_32_I1_TM1_4P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_TM1_4*>(busPtr))->GetPixelColor(pix); break; case I_32_I2_TM1_4: col = (_useParallelI2S) ? (static_cast<B_32_IP_TM1_4*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_TM1_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_I1_TM2_3: col = (useParallelI2S) ? (static_cast<B_32_I1_TM2_3P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_TM2_3*>(busPtr))->GetPixelColor(pix); break; case I_32_I2_TM2_3: col = (_useParallelI2S) ? (static_cast<B_32_IP_TM2_3*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_TM2_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_I1_UCS_3: { Rgb48Color c = (useParallelI2S) ? (static_cast<B_32_I1_UCS_3P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_UCS_3*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,0); } break; case I_32_I2_UCS_3: { Rgb48Color c = (_useParallelI2S) ? (static_cast<B_32_IP_UCS_3*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_UCS_3*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,0); } break;
case I_32_I1_UCS_4: { Rgbw64Color c = (useParallelI2S) ? (static_cast<B_32_I1_UCS_4P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_UCS_4*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,c.W/257); } break; case I_32_I2_UCS_4: { Rgbw64Color c = (_useParallelI2S) ? (static_cast<B_32_IP_UCS_4*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_UCS_4*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,c.W/257); } break;
case I_32_I1_APA106_3: col = (useParallelI2S) ? (static_cast<B_32_I1_APA106_3P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_APA106_3*>(busPtr))->GetPixelColor(pix); break; case I_32_I2_APA106_3: col = (_useParallelI2S) ? (static_cast<B_32_IP_APA106_3*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_APA106_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_I1_FW6_5: { RgbwwColor c = (useParallelI2S) ? (static_cast<B_32_I1_FW6_5P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_FW6_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W case I_32_I2_FW6_5: { RgbwwColor c = (_useParallelI2S) ? (static_cast<B_32_IP_FW6_5*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_FW6_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W
case I_32_I1_2805_5: { RgbwwColor c = (useParallelI2S) ? (static_cast<B_32_I1_2805_5P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_2805_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W case I_32_I2_2805_5: { RgbwwColor c = (_useParallelI2S) ? (static_cast<B_32_IP_2805_5*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_2805_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W
case I_32_I1_TM1914_3: col = (useParallelI2S) ? (static_cast<B_32_I1_TM1914_3P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_TM1914_3*>(busPtr))->GetPixelColor(pix); break; case I_32_I2_TM1914_3: col = (_useParallelI2S) ? (static_cast<B_32_IP_TM1914_3*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_TM1914_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_I1_SM16825_5: { Rgbww80Color c = (useParallelI2S) ? (static_cast<B_32_I1_SM16825_5P*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I1_SM16825_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,max(c.WW,c.CW)/257); } break; // will not return original W case I_32_I2_SM16825_5: { Rgbww80Color c = (_useParallelI2S) ? (static_cast<B_32_IP_SM16825_5*>(busPtr))->GetPixelColor(pix) : (static_cast<B_32_I2_SM16825_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,max(c.WW,c.CW)/257); } break; // will not return original W
#endif
// I2S0 bus
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_NEO_3: col = (static_cast<B_32_I0_NEO_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_I0_NEO_4: col = (static_cast<B_32_I0_NEO_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_I0_400_3: col = (static_cast<B_32_I0_400_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_I0_TM1_4: col = (static_cast<B_32_I0_TM1_4*>(busPtr))->GetPixelColor(pix); break;
case I_32_I0_TM2_3: col = (static_cast<B_32_I0_TM2_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_I0_UCS_3: { Rgb48Color c = (static_cast<B_32_I0_UCS_3*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,0); } break;
case I_32_I0_UCS_4: { Rgbw64Color c = (static_cast<B_32_I0_UCS_4*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,c.W/257); } break;
case I_32_I0_APA106_3: col = (static_cast<B_32_I0_APA106_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_I0_FW6_5: { RgbwwColor c = (static_cast<B_32_I0_FW6_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W
case I_32_I0_2805_5: { RgbwwColor c = (static_cast<B_32_I0_2805_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W
case I_32_I0_TM1914_3: col = (static_cast<B_32_I0_TM1914_3*>(busPtr))->GetPixelColor(pix); break;
case I_32_I0_SM16825_5: { Rgbww80Color c = (static_cast<B_32_I0_SM16825_5*>(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,max(c.WW,c.CW)/257); } break; // will not return original W
#endif #endif
#endif #endif
case I_HS_DOT_3: col = (static_cast<B_HS_DOT_3*>(busPtr))->GetPixelColor(pix); break; case I_HS_DOT_3: col = (static_cast<B_HS_DOT_3*>(busPtr))->GetPixelColor(pix); break;
@ -1269,34 +1168,19 @@ class PolyBus {
case I_32_RN_TM1914_3: delete (static_cast<B_32_RN_TM1914_3*>(busPtr)); break; case I_32_RN_TM1914_3: delete (static_cast<B_32_RN_TM1914_3*>(busPtr)); break;
case I_32_RN_SM16825_5: delete (static_cast<B_32_RN_SM16825_5*>(busPtr)); break; case I_32_RN_SM16825_5: delete (static_cast<B_32_RN_SM16825_5*>(busPtr)); break;
// I2S1 bus or paralell buses // I2S1 bus or paralell buses
#ifndef WLED_NO_I2S1_PIXELBUS #ifndef CONFIG_IDF_TARGET_ESP32C3
case I_32_I1_NEO_3: if (useParallelI2S) delete (static_cast<B_32_I1_NEO_3P*>(busPtr)); else delete (static_cast<B_32_I1_NEO_3*>(busPtr)); break; case I_32_I2_NEO_3: if (_useParallelI2S) delete (static_cast<B_32_IP_NEO_3*>(busPtr)); else delete (static_cast<B_32_I2_NEO_3*>(busPtr)); break;
case I_32_I1_NEO_4: if (useParallelI2S) delete (static_cast<B_32_I1_NEO_4P*>(busPtr)); else delete (static_cast<B_32_I1_NEO_4*>(busPtr)); break; case I_32_I2_NEO_4: if (_useParallelI2S) delete (static_cast<B_32_IP_NEO_4*>(busPtr)); else delete (static_cast<B_32_I2_NEO_4*>(busPtr)); break;
case I_32_I1_400_3: if (useParallelI2S) delete (static_cast<B_32_I1_400_3P*>(busPtr)); else delete (static_cast<B_32_I1_400_3*>(busPtr)); break; case I_32_I2_400_3: if (_useParallelI2S) delete (static_cast<B_32_IP_400_3*>(busPtr)); else delete (static_cast<B_32_I2_400_3*>(busPtr)); break;
case I_32_I1_TM1_4: if (useParallelI2S) delete (static_cast<B_32_I1_TM1_4P*>(busPtr)); else delete (static_cast<B_32_I1_TM1_4*>(busPtr)); break; case I_32_I2_TM1_4: if (_useParallelI2S) delete (static_cast<B_32_IP_TM1_4*>(busPtr)); else delete (static_cast<B_32_I2_TM1_4*>(busPtr)); break;
case I_32_I1_TM2_3: if (useParallelI2S) delete (static_cast<B_32_I1_TM2_3P*>(busPtr)); else delete (static_cast<B_32_I1_TM2_3*>(busPtr)); break; case I_32_I2_TM2_3: if (_useParallelI2S) delete (static_cast<B_32_IP_TM2_3*>(busPtr)); else delete (static_cast<B_32_I2_TM2_3*>(busPtr)); break;
case I_32_I1_UCS_3: if (useParallelI2S) delete (static_cast<B_32_I1_UCS_3P*>(busPtr)); else delete (static_cast<B_32_I1_UCS_3*>(busPtr)); break; case I_32_I2_UCS_3: if (_useParallelI2S) delete (static_cast<B_32_IP_UCS_3*>(busPtr)); else delete (static_cast<B_32_I2_UCS_3*>(busPtr)); break;
case I_32_I1_UCS_4: if (useParallelI2S) delete (static_cast<B_32_I1_UCS_4P*>(busPtr)); else delete (static_cast<B_32_I1_UCS_4*>(busPtr)); break; case I_32_I2_UCS_4: if (_useParallelI2S) delete (static_cast<B_32_IP_UCS_4*>(busPtr)); else delete (static_cast<B_32_I2_UCS_4*>(busPtr)); break;
case I_32_I1_APA106_3: if (useParallelI2S) delete (static_cast<B_32_I1_APA106_3P*>(busPtr)); else delete (static_cast<B_32_I1_APA106_3*>(busPtr)); break; case I_32_I2_APA106_3: if (_useParallelI2S) delete (static_cast<B_32_IP_APA106_3*>(busPtr)); else delete (static_cast<B_32_I2_APA106_3*>(busPtr)); break;
case I_32_I1_FW6_5: if (useParallelI2S) delete (static_cast<B_32_I1_FW6_5P*>(busPtr)); else delete (static_cast<B_32_I1_FW6_5*>(busPtr)); break; case I_32_I2_FW6_5: if (_useParallelI2S) delete (static_cast<B_32_IP_FW6_5*>(busPtr)); else delete (static_cast<B_32_I2_FW6_5*>(busPtr)); break;
case I_32_I1_2805_5: if (useParallelI2S) delete (static_cast<B_32_I1_2805_5P*>(busPtr)); else delete (static_cast<B_32_I1_2805_5*>(busPtr)); break; case I_32_I2_2805_5: if (_useParallelI2S) delete (static_cast<B_32_IP_2805_5*>(busPtr)); else delete (static_cast<B_32_I2_2805_5*>(busPtr)); break;
case I_32_I1_TM1914_3: if (useParallelI2S) delete (static_cast<B_32_I1_TM1914_3P*>(busPtr)); else delete (static_cast<B_32_I1_TM1914_3*>(busPtr)); break; case I_32_I2_TM1914_3: if (_useParallelI2S) delete (static_cast<B_32_IP_TM1914_3*>(busPtr)); else delete (static_cast<B_32_I2_TM1914_3*>(busPtr)); break;
case I_32_I1_SM16825_5: if (useParallelI2S) delete (static_cast<B_32_I1_SM16825_5P*>(busPtr)); else delete (static_cast<B_32_I1_SM16825_5*>(busPtr)); break; case I_32_I2_SM16825_5: if (_useParallelI2S) delete (static_cast<B_32_IP_SM16825_5*>(busPtr)); else delete (static_cast<B_32_I2_SM16825_5*>(busPtr)); break;
#endif
// I2S0 bus
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_NEO_3: delete (static_cast<B_32_I0_NEO_3*>(busPtr)); break;
case I_32_I0_NEO_4: delete (static_cast<B_32_I0_NEO_4*>(busPtr)); break;
case I_32_I0_400_3: delete (static_cast<B_32_I0_400_3*>(busPtr)); break;
case I_32_I0_TM1_4: delete (static_cast<B_32_I0_TM1_4*>(busPtr)); break;
case I_32_I0_TM2_3: delete (static_cast<B_32_I0_TM2_3*>(busPtr)); break;
case I_32_I0_UCS_3: delete (static_cast<B_32_I0_UCS_3*>(busPtr)); break;
case I_32_I0_UCS_4: delete (static_cast<B_32_I0_UCS_4*>(busPtr)); break;
case I_32_I0_APA106_3: delete (static_cast<B_32_I0_APA106_3*>(busPtr)); break;
case I_32_I0_FW6_5: delete (static_cast<B_32_I0_FW6_5*>(busPtr)); break;
case I_32_I0_2805_5: delete (static_cast<B_32_I0_2805_5*>(busPtr)); break;
case I_32_I0_TM1914_3: delete (static_cast<B_32_I0_TM1914_3*>(busPtr)); break;
case I_32_I0_SM16825_5: delete (static_cast<B_32_I0_SM16825_5*>(busPtr)); break;
#endif #endif
#endif #endif
case I_HS_DOT_3: delete (static_cast<B_HS_DOT_3*>(busPtr)); break; case I_HS_DOT_3: delete (static_cast<B_HS_DOT_3*>(busPtr)); break;
@ -1312,8 +1196,178 @@ class PolyBus {
} }
} }
static unsigned getDataSize(void* busPtr, uint8_t busType) {
unsigned size = 0;
switch (busType) {
case I_NONE: break;
#ifdef ESP8266
case I_8266_U0_NEO_3: size = (static_cast<B_8266_U0_NEO_3*>(busPtr))->PixelsSize()*2; break;
case I_8266_U1_NEO_3: size = (static_cast<B_8266_U1_NEO_3*>(busPtr))->PixelsSize()*2; break;
case I_8266_DM_NEO_3: size = (static_cast<B_8266_DM_NEO_3*>(busPtr))->PixelsSize()*5; break;
case I_8266_BB_NEO_3: size = (static_cast<B_8266_BB_NEO_3*>(busPtr))->PixelsSize()*2; break;
case I_8266_U0_NEO_4: size = (static_cast<B_8266_U0_NEO_4*>(busPtr))->PixelsSize()*2; break;
case I_8266_U1_NEO_4: size = (static_cast<B_8266_U1_NEO_4*>(busPtr))->PixelsSize()*2; break;
case I_8266_DM_NEO_4: size = (static_cast<B_8266_DM_NEO_4*>(busPtr))->PixelsSize()*5; break;
case I_8266_BB_NEO_4: size = (static_cast<B_8266_BB_NEO_4*>(busPtr))->PixelsSize()*2; break;
case I_8266_U0_400_3: size = (static_cast<B_8266_U0_400_3*>(busPtr))->PixelsSize()*2; break;
case I_8266_U1_400_3: size = (static_cast<B_8266_U1_400_3*>(busPtr))->PixelsSize()*2; break;
case I_8266_DM_400_3: size = (static_cast<B_8266_DM_400_3*>(busPtr))->PixelsSize()*5; break;
case I_8266_BB_400_3: size = (static_cast<B_8266_BB_400_3*>(busPtr))->PixelsSize()*2; break;
case I_8266_U0_TM1_4: size = (static_cast<B_8266_U0_TM1_4*>(busPtr))->PixelsSize()*2; break;
case I_8266_U1_TM1_4: size = (static_cast<B_8266_U1_TM1_4*>(busPtr))->PixelsSize()*2; break;
case I_8266_DM_TM1_4: size = (static_cast<B_8266_DM_TM1_4*>(busPtr))->PixelsSize()*5; break;
case I_8266_BB_TM1_4: size = (static_cast<B_8266_BB_TM1_4*>(busPtr))->PixelsSize()*2; break;
case I_8266_U0_TM2_3: size = (static_cast<B_8266_U0_TM2_3*>(busPtr))->PixelsSize()*2; break;
case I_8266_U1_TM2_3: size = (static_cast<B_8266_U1_TM2_3*>(busPtr))->PixelsSize()*2; break;
case I_8266_DM_TM2_3: size = (static_cast<B_8266_DM_TM2_3*>(busPtr))->PixelsSize()*5; break;
case I_8266_BB_TM2_3: size = (static_cast<B_8266_BB_TM2_3*>(busPtr))->PixelsSize()*2; break;
case I_8266_U0_UCS_3: size = (static_cast<B_8266_U0_UCS_3*>(busPtr))->PixelsSize()*2; break;
case I_8266_U1_UCS_3: size = (static_cast<B_8266_U1_UCS_3*>(busPtr))->PixelsSize()*2; break;
case I_8266_DM_UCS_3: size = (static_cast<B_8266_DM_UCS_3*>(busPtr))->PixelsSize()*5; break;
case I_8266_BB_UCS_3: size = (static_cast<B_8266_BB_UCS_3*>(busPtr))->PixelsSize()*2; break;
case I_8266_U0_UCS_4: size = (static_cast<B_8266_U0_UCS_4*>(busPtr))->PixelsSize()*2; break;
case I_8266_U1_UCS_4: size = (static_cast<B_8266_U1_UCS_4*>(busPtr))->PixelsSize()*2; break;
case I_8266_DM_UCS_4: size = (static_cast<B_8266_DM_UCS_4*>(busPtr))->PixelsSize()*5; break;
case I_8266_BB_UCS_4: size = (static_cast<B_8266_BB_UCS_4*>(busPtr))->PixelsSize()*2; break;
case I_8266_U0_APA106_3: size = (static_cast<B_8266_U0_APA106_3*>(busPtr))->PixelsSize()*2; break;
case I_8266_U1_APA106_3: size = (static_cast<B_8266_U1_APA106_3*>(busPtr))->PixelsSize()*2; break;
case I_8266_DM_APA106_3: size = (static_cast<B_8266_DM_APA106_3*>(busPtr))->PixelsSize()*5; break;
case I_8266_BB_APA106_3: size = (static_cast<B_8266_BB_APA106_3*>(busPtr))->PixelsSize()*2; break;
case I_8266_U0_FW6_5: size = (static_cast<B_8266_U0_FW6_5*>(busPtr))->PixelsSize()*2; break;
case I_8266_U1_FW6_5: size = (static_cast<B_8266_U1_FW6_5*>(busPtr))->PixelsSize()*2; break;
case I_8266_DM_FW6_5: size = (static_cast<B_8266_DM_FW6_5*>(busPtr))->PixelsSize()*5; break;
case I_8266_BB_FW6_5: size = (static_cast<B_8266_BB_FW6_5*>(busPtr))->PixelsSize()*2; break;
case I_8266_U0_2805_5: size = (static_cast<B_8266_U0_2805_5*>(busPtr))->PixelsSize()*2; break;
case I_8266_U1_2805_5: size = (static_cast<B_8266_U1_2805_5*>(busPtr))->PixelsSize()*2; break;
case I_8266_DM_2805_5: size = (static_cast<B_8266_DM_2805_5*>(busPtr))->PixelsSize()*5; break;
case I_8266_BB_2805_5: size = (static_cast<B_8266_BB_2805_5*>(busPtr))->PixelsSize()*2; break;
case I_8266_U0_TM1914_3: size = (static_cast<B_8266_U0_TM1914_3*>(busPtr))->PixelsSize()*2; break;
case I_8266_U1_TM1914_3: size = (static_cast<B_8266_U1_TM1914_3*>(busPtr))->PixelsSize()*2; break;
case I_8266_DM_TM1914_3: size = (static_cast<B_8266_DM_TM1914_3*>(busPtr))->PixelsSize()*5; break;
case I_8266_BB_TM1914_3: size = (static_cast<B_8266_BB_TM1914_3*>(busPtr))->PixelsSize()*2; break;
case I_8266_U0_SM16825_5: size = (static_cast<B_8266_U0_SM16825_5*>(busPtr))->PixelsSize()*2; break;
case I_8266_U1_SM16825_5: size = (static_cast<B_8266_U1_SM16825_5*>(busPtr))->PixelsSize()*2; break;
case I_8266_DM_SM16825_5: size = (static_cast<B_8266_DM_SM16825_5*>(busPtr))->PixelsSize()*5; break;
case I_8266_BB_SM16825_5: size = (static_cast<B_8266_BB_SM16825_5*>(busPtr))->PixelsSize()*2; break;
#endif
#ifdef ARDUINO_ARCH_ESP32
// RMT buses (front + back + small system managed RMT)
case I_32_RN_NEO_3: size = (static_cast<B_32_RN_NEO_3*>(busPtr))->PixelsSize()*2; break;
case I_32_RN_NEO_4: size = (static_cast<B_32_RN_NEO_4*>(busPtr))->PixelsSize()*2; break;
case I_32_RN_400_3: size = (static_cast<B_32_RN_400_3*>(busPtr))->PixelsSize()*2; break;
case I_32_RN_TM1_4: size = (static_cast<B_32_RN_TM1_4*>(busPtr))->PixelsSize()*2; break;
case I_32_RN_TM2_3: size = (static_cast<B_32_RN_TM2_3*>(busPtr))->PixelsSize()*2; break;
case I_32_RN_UCS_3: size = (static_cast<B_32_RN_UCS_3*>(busPtr))->PixelsSize()*2; break;
case I_32_RN_UCS_4: size = (static_cast<B_32_RN_UCS_4*>(busPtr))->PixelsSize()*2; break;
case I_32_RN_APA106_3: size = (static_cast<B_32_RN_APA106_3*>(busPtr))->PixelsSize()*2; break;
case I_32_RN_FW6_5: size = (static_cast<B_32_RN_FW6_5*>(busPtr))->PixelsSize()*2; break;
case I_32_RN_2805_5: size = (static_cast<B_32_RN_2805_5*>(busPtr))->PixelsSize()*2; break;
case I_32_RN_TM1914_3: size = (static_cast<B_32_RN_TM1914_3*>(busPtr))->PixelsSize()*2; break;
case I_32_RN_SM16825_5: size = (static_cast<B_32_RN_SM16825_5*>(busPtr))->PixelsSize()*2; break;
// I2S1 bus or paralell buses (front + DMA; DMA = front * cadence, aligned to 4 bytes)
#ifndef CONFIG_IDF_TARGET_ESP32C3
case I_32_I2_NEO_3: size = (_useParallelI2S) ? (static_cast<B_32_IP_NEO_3*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_NEO_3*>(busPtr))->PixelsSize()*4; break;
case I_32_I2_NEO_4: size = (_useParallelI2S) ? (static_cast<B_32_IP_NEO_4*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_NEO_4*>(busPtr))->PixelsSize()*4; break;
case I_32_I2_400_3: size = (_useParallelI2S) ? (static_cast<B_32_IP_400_3*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_400_3*>(busPtr))->PixelsSize()*4; break;
case I_32_I2_TM1_4: size = (_useParallelI2S) ? (static_cast<B_32_IP_TM1_4*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_TM1_4*>(busPtr))->PixelsSize()*4; break;
case I_32_I2_TM2_3: size = (_useParallelI2S) ? (static_cast<B_32_IP_TM2_3*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_TM2_3*>(busPtr))->PixelsSize()*4; break;
case I_32_I2_UCS_3: size = (_useParallelI2S) ? (static_cast<B_32_IP_UCS_3*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_UCS_3*>(busPtr))->PixelsSize()*4; break;
case I_32_I2_UCS_4: size = (_useParallelI2S) ? (static_cast<B_32_IP_UCS_4*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_UCS_4*>(busPtr))->PixelsSize()*4; break;
case I_32_I2_APA106_3: size = (_useParallelI2S) ? (static_cast<B_32_IP_APA106_3*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_APA106_3*>(busPtr))->PixelsSize()*4; break;
case I_32_I2_FW6_5: size = (_useParallelI2S) ? (static_cast<B_32_IP_FW6_5*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_FW6_5*>(busPtr))->PixelsSize()*4; break;
case I_32_I2_2805_5: size = (_useParallelI2S) ? (static_cast<B_32_IP_2805_5*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_2805_5*>(busPtr))->PixelsSize()*4; break;
case I_32_I2_TM1914_3: size = (_useParallelI2S) ? (static_cast<B_32_IP_TM1914_3*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_TM1914_3*>(busPtr))->PixelsSize()*4; break;
case I_32_I2_SM16825_5: size = (_useParallelI2S) ? (static_cast<B_32_IP_SM16825_5*>(busPtr))->PixelsSize()*4 : (static_cast<B_32_I2_SM16825_5*>(busPtr))->PixelsSize()*4; break;
#endif
#endif
case I_HS_DOT_3: size = (static_cast<B_HS_DOT_3*>(busPtr))->PixelsSize()*2; break;
case I_SS_DOT_3: size = (static_cast<B_SS_DOT_3*>(busPtr))->PixelsSize()*2; break;
case I_HS_LPD_3: size = (static_cast<B_HS_LPD_3*>(busPtr))->PixelsSize()*2; break;
case I_SS_LPD_3: size = (static_cast<B_SS_LPD_3*>(busPtr))->PixelsSize()*2; break;
case I_HS_LPO_3: size = (static_cast<B_HS_LPO_3*>(busPtr))->PixelsSize()*2; break;
case I_SS_LPO_3: size = (static_cast<B_SS_LPO_3*>(busPtr))->PixelsSize()*2; break;
case I_HS_WS1_3: size = (static_cast<B_HS_WS1_3*>(busPtr))->PixelsSize()*2; break;
case I_SS_WS1_3: size = (static_cast<B_SS_WS1_3*>(busPtr))->PixelsSize()*2; break;
case I_HS_P98_3: size = (static_cast<B_HS_P98_3*>(busPtr))->PixelsSize()*2; break;
case I_SS_P98_3: size = (static_cast<B_SS_P98_3*>(busPtr))->PixelsSize()*2; break;
}
return size;
}
static unsigned memUsage(unsigned count, unsigned busType) {
unsigned size = count*3; // let's assume 3 channels, we will add count or 2*count below for 4 channels or 5 channels
switch (busType) {
case I_NONE: size = 0; break;
#ifdef ESP8266
// UART methods have front + back buffers + small UART
case I_8266_U0_NEO_4: size = (size + count)*2; break; // 4 channels
case I_8266_U1_NEO_4: size = (size + count)*2; break; // 4 channels
case I_8266_BB_NEO_4: size = (size + count)*2; break; // 4 channels
case I_8266_U0_TM1_4: size = (size + count)*2; break; // 4 channels
case I_8266_U1_TM1_4: size = (size + count)*2; break; // 4 channels
case I_8266_BB_TM1_4: size = (size + count)*2; break; // 4 channels
case I_8266_U0_UCS_3: size *= 4; break; // 16 bit
case I_8266_U1_UCS_3: size *= 4; break; // 16 bit
case I_8266_BB_UCS_3: size *= 4; break; // 16 bit
case I_8266_U0_UCS_4: size = (size + count)*2*2; break; // 16 bit 4 channels
case I_8266_U1_UCS_4: size = (size + count)*2*2; break; // 16 bit 4 channels
case I_8266_BB_UCS_4: size = (size + count)*2*2; break; // 16 bit 4 channels
case I_8266_U0_FW6_5: size = (size + 2*count)*2; break; // 5 channels
case I_8266_U1_FW6_5: size = (size + 2*count)*2; break; // 5channels
case I_8266_BB_FW6_5: size = (size + 2*count)*2; break; // 5 channels
case I_8266_U0_2805_5: size = (size + 2*count)*2; break; // 5 channels
case I_8266_U1_2805_5: size = (size + 2*count)*2; break; // 5 channels
case I_8266_BB_2805_5: size = (size + 2*count)*2; break; // 5 channels
case I_8266_U0_SM16825_5: size = (size + 2*count)*2*2; break; // 16 bit 5 channels
case I_8266_U1_SM16825_5: size = (size + 2*count)*2*2; break; // 16 bit 5 channels
case I_8266_BB_SM16825_5: size = (size + 2*count)*2*2; break; // 16 bit 5 channels
// DMA methods have front + DMA buffer = ((1+(3+1)) * channels)
case I_8266_DM_NEO_3: size *= 5; break;
case I_8266_DM_NEO_4: size = (size + count)*5; break;
case I_8266_DM_400_3: size *= 5; break;
case I_8266_DM_TM1_4: size = (size + count)*5; break;
case I_8266_DM_TM2_3: size *= 5; break;
case I_8266_DM_UCS_3: size *= 2*5; break;
case I_8266_DM_UCS_4: size = (size + count)*2*5; break;
case I_8266_DM_APA106_3: size *= 5; break;
case I_8266_DM_FW6_5: size = (size + 2*count)*5; break;
case I_8266_DM_2805_5: size = (size + 2*count)*5; break;
case I_8266_DM_TM1914_3: size *= 5; break;
case I_8266_DM_SM16825_5: size = (size + 2*count)*2*5; break;
#endif
#ifdef ARDUINO_ARCH_ESP32
// RMT buses (1x front and 1x back buffer)
case I_32_RN_NEO_4: size = (size + count)*2; break;
case I_32_RN_TM1_4: size = (size + count)*2; break;
case I_32_RN_UCS_3: size *= 2*2; break;
case I_32_RN_UCS_4: size = (size + count)*2*2; break;
case I_32_RN_FW6_5: size = (size + 2*count)*2; break;
case I_32_RN_2805_5: size = (size + 2*count)*2; break;
case I_32_RN_SM16825_5: size = (size + 2*count)*2*2; break;
// I2S1 bus or paralell buses (individual 1x front and 1 DMA (3x or 4x pixel count) or common back DMA buffers)
#ifndef CONFIG_IDF_TARGET_ESP32C3
case I_32_I2_NEO_3: size *= 4; break;
case I_32_I2_NEO_4: size = (size + count)*4; break;
case I_32_I2_400_3: size *= 4; break;
case I_32_I2_TM1_4: size = (size + count)*4; break;
case I_32_I2_TM2_3: size *= 4; break;
case I_32_I2_UCS_3: size *= 2*4; break;
case I_32_I2_UCS_4: size = (size + count)*2*4; break;
case I_32_I2_APA106_3: size *= 4; break;
case I_32_I2_FW6_5: size = (size + 2*count)*4; break;
case I_32_I2_2805_5: size = (size + 2*count)*4; break;
case I_32_I2_TM1914_3: size *= 4; break;
case I_32_I2_SM16825_5: size = (size + 2*count)*2*4; break;
#endif
#endif
// everything else uses 2 buffers
default: size *= 2; break;
}
return size;
}
//gives back the internal type index (I_XX_XXX_X above) for the input //gives back the internal type index (I_XX_XXX_X above) for the input
static uint8_t getI(uint8_t busType, uint8_t* pins, uint8_t num = 0) { static uint8_t getI(uint8_t busType, const uint8_t* pins, uint8_t num = 0) {
if (!Bus::isDigital(busType)) return I_NONE; if (!Bus::isDigital(busType)) return I_NONE;
if (Bus::is2Pin(busType)) { //SPI LED chips if (Bus::is2Pin(busType)) { //SPI LED chips
bool isHSPI = false; bool isHSPI = false;
@ -1372,26 +1426,33 @@ class PolyBus {
uint8_t offset = 0; // 0 = RMT (num 1-8), 1 = I2S0 (used by Audioreactive), 2 = I2S1 uint8_t offset = 0; // 0 = RMT (num 1-8), 1 = I2S0 (used by Audioreactive), 2 = I2S1
#if defined(CONFIG_IDF_TARGET_ESP32S2) #if defined(CONFIG_IDF_TARGET_ESP32S2)
// ESP32-S2 only has 4 RMT channels // ESP32-S2 only has 4 RMT channels
if (_useParallelI2S) {
if (num > 11) return I_NONE;
if (num > 3) offset = 1; // use x8 parallel I2S0 channels (use last to allow Audioreactive)
} else {
if (num > 4) return I_NONE; if (num > 4) return I_NONE;
if (num > 3) offset = 1; // only one I2S (use last to allow Audioreactive) if (num > 3) offset = 1; // only one I2S0 (use last to allow Audioreactive)
}
#elif defined(CONFIG_IDF_TARGET_ESP32C3) #elif defined(CONFIG_IDF_TARGET_ESP32C3)
// On ESP32-C3 only the first 2 RMT channels are usable for transmitting // On ESP32-C3 only the first 2 RMT channels are usable for transmitting
if (num > 1) return I_NONE; if (num > 1) return I_NONE;
//if (num > 1) offset = 1; // I2S not supported yet (only 1 I2S) //if (num > 1) offset = 1; // I2S not supported yet (only 1 I2S)
#elif defined(CONFIG_IDF_TARGET_ESP32S3) #elif defined(CONFIG_IDF_TARGET_ESP32S3)
// On ESP32-S3 only the first 4 RMT channels are usable for transmitting // On ESP32-S3 only the first 4 RMT channels are usable for transmitting
if (num > 3) return I_NONE; if (_useParallelI2S) {
//if (num > 3) offset = num -4; // I2S not supported yet if (num > 11) return I_NONE;
if (num > 3) offset = 1; // use x8 parallel I2S LCD channels
} else {
if (num > 3) return I_NONE; // do not use single I2S (as it is not supported)
}
#else #else
// standard ESP32 has 8 RMT and 2 I2S channels // standard ESP32 has 8 RMT and x1/x8 I2S1 channels
if (useParallelI2S) { if (_useParallelI2S) {
if (num > 16) return I_NONE; if (num > 15) return I_NONE;
if (num < 8) offset = 2; // prefer 8 parallel I2S1 channels if (num > 7) offset = 1; // 8 RMT followed by 8 I2S
if (num == 16) offset = 1;
} else { } else {
if (num > 9) return I_NONE; if (num > 9) return I_NONE;
if (num > 8) offset = 1; if (num == 0) offset = 1; // prefer I2S1 for 1st bus (less flickering but more RAM needed)
if (num == 0) offset = 2; // prefer I2S1 for 1st bus (less flickering but more RAM needed)
} }
#endif #endif
switch (busType) { switch (busType) {

View File

@ -118,6 +118,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
Bus::setCCTBlend(cctBlending); Bus::setCCTBlend(cctBlending);
strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS
CJSON(useGlobalLedBuffer, hw_led[F("ld")]); CJSON(useGlobalLedBuffer, hw_led[F("ld")]);
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
CJSON(useParallelI2S, hw_led[F("prl")]);
#endif
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D
// 2D Matrix Settings // 2D Matrix Settings
@ -162,34 +165,6 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
DEBUG_PRINTF_P(PSTR("Heap before buses: %d\n"), ESP.getFreeHeap()); DEBUG_PRINTF_P(PSTR("Heap before buses: %d\n"), ESP.getFreeHeap());
int s = 0; // bus iterator int s = 0; // bus iterator
if (fromFS) BusManager::removeAll(); // can't safely manipulate busses directly in network callback if (fromFS) BusManager::removeAll(); // can't safely manipulate busses directly in network callback
unsigned mem = 0;
// determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT)
bool useParallel = false;
#if defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH_ESP32S2) && !defined(ARDUINO_ARCH_ESP32S3) && !defined(ARDUINO_ARCH_ESP32C3)
unsigned digitalCount = 0;
unsigned maxLedsOnBus = 0;
unsigned maxChannels = 0;
for (JsonObject elm : ins) {
unsigned type = elm["type"] | TYPE_WS2812_RGB;
unsigned len = elm["len"] | DEFAULT_LED_COUNT;
if (!Bus::isDigital(type)) continue;
if (!Bus::is2Pin(type)) {
digitalCount++;
unsigned channels = Bus::getNumberOfChannels(type);
if (len > maxLedsOnBus) maxLedsOnBus = len;
if (channels > maxChannels) maxChannels = channels;
}
}
DEBUG_PRINTF_P(PSTR("Maximum LEDs on a bus: %u\nDigital buses: %u\n"), maxLedsOnBus, digitalCount);
// we may remove 300 LEDs per bus limit when NeoPixelBus is updated beyond 2.9.0
if (maxLedsOnBus <= 300 && digitalCount > 5) {
DEBUG_PRINTLN(F("Switching to parallel I2S."));
useParallel = true;
BusManager::useParallelOutput();
mem = BusManager::memUsage(maxChannels, maxLedsOnBus, 8); // use alternate memory calculation
}
#endif
for (JsonObject elm : ins) { for (JsonObject elm : ins) {
if (s >= WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES) break; if (s >= WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES) break;
@ -220,24 +195,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
maMax = 0; maMax = 0;
} }
ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh
if (fromFS) {
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax); busConfigs.push_back(std::move(BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax)));
if (useParallel && s < 8) {
// if for some unexplained reason the above pre-calculation was wrong, update
unsigned memT = BusManager::memUsage(bc); // includes x8 memory allocation for parallel I2S
if (memT > mem) mem = memT; // if we have unequal LED count use the largest
} else
mem += BusManager::memUsage(bc); // includes global buffer
if (mem <= MAX_LED_MEMORY) if (BusManager::add(bc) == -1) break; // finalization will be done in WLED::beginStrip()
} else {
if (busConfigs[s] != nullptr) delete busConfigs[s];
busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax);
doInitBusses = true; // finalization done in beginStrip() doInitBusses = true; // finalization done in beginStrip()
}
s++; s++;
} }
DEBUG_PRINTF_P(PSTR("LED buffer size: %uB\n"), mem);
DEBUG_PRINTF_P(PSTR("Heap after buses: %d\n"), ESP.getFreeHeap());
} }
if (hw_led["rev"]) BusManager::getBus(0)->setReversed(true); //set 0.11 global reversed setting for first bus if (hw_led["rev"]) BusManager::getBus(0)->setReversed(true); //set 0.11 global reversed setting for first bus
@ -828,6 +790,9 @@ void serializeConfig() {
hw_led["fps"] = strip.getTargetFps(); hw_led["fps"] = strip.getTargetFps();
hw_led[F("rgbwm")] = Bus::getGlobalAWMode(); // global auto white mode override hw_led[F("rgbwm")] = Bus::getGlobalAWMode(); // global auto white mode override
hw_led[F("ld")] = useGlobalLedBuffer; hw_led[F("ld")] = useGlobalLedBuffer;
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
hw_led[F("prl")] = BusManager::hasParallelOutput();
#endif
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D
// 2D Matrix Settings // 2D Matrix Settings
@ -852,8 +817,19 @@ void serializeConfig() {
JsonArray hw_led_ins = hw_led.createNestedArray("ins"); JsonArray hw_led_ins = hw_led.createNestedArray("ins");
for (size_t s = 0; s < BusManager::getNumBusses(); s++) { for (size_t s = 0; s < BusManager::getNumBusses(); s++) {
DEBUG_PRINTF_P(PSTR("Cfg: Saving bus #%u\n"), s);
Bus *bus = BusManager::getBus(s); Bus *bus = BusManager::getBus(s);
if (!bus || bus->getLength()==0) break; if (!bus || bus->getLength()==0) break;
DEBUG_PRINTF_P(PSTR(" (%d-%d, type:%d, CO:%d, rev:%d, skip:%d, AW:%d kHz:%d, mA:%d/%d)\n"),
(int)bus->getStart(), (int)(bus->getStart()+bus->getLength()),
(int)(bus->getType() & 0x7F),
(int)bus->getColorOrder(),
(int)bus->isReversed(),
(int)bus->skippedLeds(),
(int)bus->getAutoWhiteMode(),
(int)bus->getFrequency(),
(int)bus->getLEDCurrent(), (int)bus->getMaxCurrent()
);
JsonObject ins = hw_led_ins.createNestedObject(); JsonObject ins = hw_led_ins.createNestedObject();
ins["start"] = bus->getStart(); ins["start"] = bus->getStart();
ins["len"] = bus->getLength(); ins["len"] = bus->getLength();

View File

@ -37,7 +37,7 @@
#endif #endif
#ifndef WLED_MAX_USERMODS #ifndef WLED_MAX_USERMODS
#ifdef ESP8266 #if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32S2)
#define WLED_MAX_USERMODS 4 #define WLED_MAX_USERMODS 4
#else #else
#define WLED_MAX_USERMODS 6 #define WLED_MAX_USERMODS 6
@ -49,31 +49,31 @@
#define WLED_MAX_DIGITAL_CHANNELS 3 #define WLED_MAX_DIGITAL_CHANNELS 3
#define WLED_MAX_ANALOG_CHANNELS 5 #define WLED_MAX_ANALOG_CHANNELS 5
#define WLED_MAX_BUSSES 4 // will allow 3 digital & 1 analog RGB #define WLED_MAX_BUSSES 4 // will allow 3 digital & 1 analog RGB
#define WLED_MIN_VIRTUAL_BUSSES 2 #define WLED_MIN_VIRTUAL_BUSSES 3
#else #else
#define WLED_MAX_ANALOG_CHANNELS (LEDC_CHANNEL_MAX*LEDC_SPEED_MODE_MAX) #define WLED_MAX_ANALOG_CHANNELS (LEDC_CHANNEL_MAX*LEDC_SPEED_MODE_MAX)
#if defined(CONFIG_IDF_TARGET_ESP32C3) // 2 RMT, 6 LEDC, only has 1 I2S but NPB does not support it ATM #if defined(CONFIG_IDF_TARGET_ESP32C3) // 2 RMT, 6 LEDC, only has 1 I2S but NPB does not support it ATM
#define WLED_MAX_BUSSES 6 // will allow 2 digital & 2 analog RGB or 6 PWM white #define WLED_MAX_BUSSES 6 // will allow 2 digital & 2 analog RGB or 6 PWM white
#define WLED_MAX_DIGITAL_CHANNELS 2 #define WLED_MAX_DIGITAL_CHANNELS 2
//#define WLED_MAX_ANALOG_CHANNELS 6 //#define WLED_MAX_ANALOG_CHANNELS 6
#define WLED_MIN_VIRTUAL_BUSSES 3 #define WLED_MIN_VIRTUAL_BUSSES 4
#elif defined(CONFIG_IDF_TARGET_ESP32S2) // 4 RMT, 8 LEDC, only has 1 I2S bus, supported in NPB #elif defined(CONFIG_IDF_TARGET_ESP32S2) // 4 RMT, 8 LEDC, only has 1 I2S bus, supported in NPB
// the 5th bus (I2S) will prevent Audioreactive usermod from functioning (it is last used though) // the 5th bus (I2S) will prevent Audioreactive usermod from functioning (it is last used though)
#define WLED_MAX_BUSSES 7 // will allow 5 digital & 2 analog RGB #define WLED_MAX_BUSSES 14 // will allow 12 digital & 2 analog RGB
#define WLED_MAX_DIGITAL_CHANNELS 5 #define WLED_MAX_DIGITAL_CHANNELS 12 // x4 RMT + x1/x8 I2S0
//#define WLED_MAX_ANALOG_CHANNELS 8
#define WLED_MIN_VIRTUAL_BUSSES 3
#elif defined(CONFIG_IDF_TARGET_ESP32S3) // 4 RMT, 8 LEDC, has 2 I2S but NPB does not support them ATM
#define WLED_MAX_BUSSES 6 // will allow 4 digital & 2 analog RGB
#define WLED_MAX_DIGITAL_CHANNELS 4
//#define WLED_MAX_ANALOG_CHANNELS 8 //#define WLED_MAX_ANALOG_CHANNELS 8
#define WLED_MIN_VIRTUAL_BUSSES 4 #define WLED_MIN_VIRTUAL_BUSSES 4
#elif defined(CONFIG_IDF_TARGET_ESP32S3) // 4 RMT, 8 LEDC, has 2 I2S but NPB supports parallel x8 LCD on I2S1
#define WLED_MAX_BUSSES 14 // will allow 12 digital & 2 analog RGB
#define WLED_MAX_DIGITAL_CHANNELS 12 // x4 RMT + x8 I2S-LCD
//#define WLED_MAX_ANALOG_CHANNELS 8
#define WLED_MIN_VIRTUAL_BUSSES 6
#else #else
// the last digital bus (I2S0) will prevent Audioreactive usermod from functioning // the last digital bus (I2S0) will prevent Audioreactive usermod from functioning
#define WLED_MAX_BUSSES 20 // will allow 17 digital & 3 analog RGB #define WLED_MAX_BUSSES 19 // will allow 16 digital & 3 analog RGB
#define WLED_MAX_DIGITAL_CHANNELS 17 #define WLED_MAX_DIGITAL_CHANNELS 16 // x1/x8 I2S1 + x8 RMT
//#define WLED_MAX_ANALOG_CHANNELS 16 //#define WLED_MAX_ANALOG_CHANNELS 16
#define WLED_MIN_VIRTUAL_BUSSES 4 #define WLED_MIN_VIRTUAL_BUSSES 6
#endif #endif
#endif #endif
#else #else
@ -115,7 +115,7 @@
#endif #endif
#endif #endif
#ifdef ESP8266 #if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32S2)
#define WLED_MAX_COLOR_ORDER_MAPPINGS 5 #define WLED_MAX_COLOR_ORDER_MAPPINGS 5
#else #else
#define WLED_MAX_COLOR_ORDER_MAPPINGS 10 #define WLED_MAX_COLOR_ORDER_MAPPINGS 10
@ -125,7 +125,7 @@
#undef WLED_MAX_LEDMAPS #undef WLED_MAX_LEDMAPS
#endif #endif
#ifndef WLED_MAX_LEDMAPS #ifndef WLED_MAX_LEDMAPS
#ifdef ESP8266 #if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32S2)
#define WLED_MAX_LEDMAPS 10 #define WLED_MAX_LEDMAPS 10
#else #else
#define WLED_MAX_LEDMAPS 16 #define WLED_MAX_LEDMAPS 16
@ -477,6 +477,8 @@
#ifndef MAX_LEDS #ifndef MAX_LEDS
#ifdef ESP8266 #ifdef ESP8266
#define MAX_LEDS 1664 //can't rely on memory limit to limit this to 1600 LEDs #define MAX_LEDS 1664 //can't rely on memory limit to limit this to 1600 LEDs
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
#define MAX_LEDS 2048 //due to memory constraints
#else #else
#define MAX_LEDS 8192 #define MAX_LEDS 8192
#endif #endif
@ -486,7 +488,9 @@
#ifdef ESP8266 #ifdef ESP8266
#define MAX_LED_MEMORY 4000 #define MAX_LED_MEMORY 4000
#else #else
#if defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32C3) #if defined(ARDUINO_ARCH_ESP32S2)
#define MAX_LED_MEMORY 16000
#elif defined(ARDUINO_ARCH_ESP32C3)
#define MAX_LED_MEMORY 32000 #define MAX_LED_MEMORY 32000
#else #else
#define MAX_LED_MEMORY 64000 #define MAX_LED_MEMORY 64000

View File

@ -42,10 +42,10 @@
if (loc) d.Sf.action = getURL('/settings/leds'); if (loc) d.Sf.action = getURL('/settings/leds');
} }
function bLimits(b,v,p,m,l,o=5,d=2,a=6) { function bLimits(b,v,p,m,l,o=5,d=2,a=6) {
oMaxB = maxB = b; // maxB - max buses (can be changed if using ESP32 parallel I2S) oMaxB = maxB = b; // maxB - max buses (can be changed if using ESP32 parallel I2S): 19 - ESP32, 14 - S3/S2, 6 - C3, 4 - 8266
maxD = d; // maxD - max digital channels (can be changed if using ESP32 parallel I2S) maxD = d; // maxD - max digital channels (can be changed if using ESP32 parallel I2S): 16 - ESP32, 12 - S3/S2, 2 - C3, 3 - 8266
maxA = a; // maxA - max analog channels maxA = a; // maxA - max analog channels: 16 - ESP32, 8 - S3/S2, 6 - C3, 5 - 8266
maxV = v; // maxV - min virtual buses maxV = v; // maxV - min virtual buses: 4 - ESP32/S3, 3 - S2/C3, 2 - ESP8266
maxPB = p; // maxPB - max LEDs per bus maxPB = p; // maxPB - max LEDs per bus
maxM = m; // maxM - max LED memory maxM = m; // maxM - max LED memory
maxL = l; // maxL - max LEDs (will serve to determine ESP >1664 == ESP32) maxL = l; // maxL - max LEDs (will serve to determine ESP >1664 == ESP32)
@ -250,6 +250,7 @@
} }
// enable/disable LED fields // enable/disable LED fields
let dC = 0; // count of digital buses (for parallel I2S)
let LTs = d.Sf.querySelectorAll("#mLC select[name^=LT]"); let LTs = d.Sf.querySelectorAll("#mLC select[name^=LT]");
LTs.forEach((s,i)=>{ LTs.forEach((s,i)=>{
if (i < LTs.length-1) s.disabled = true; // prevent changing type (as we can't update options) if (i < LTs.length-1) s.disabled = true; // prevent changing type (as we can't update options)
@ -257,6 +258,7 @@
var n = s.name.substring(2); var n = s.name.substring(2);
var t = parseInt(s.value); var t = parseInt(s.value);
memu += getMem(t, n); // calc memory memu += getMem(t, n); // calc memory
dC += (isDig(t) && !isD2P(t));
setPinConfig(n,t); setPinConfig(n,t);
gId("abl"+n).style.display = (!abl || !isDig(t)) ? "none" : "inline"; // show/hide individual ABL settings gId("abl"+n).style.display = (!abl || !isDig(t)) ? "none" : "inline"; // show/hide individual ABL settings
if (change) { // did we change LED type? if (change) { // did we change LED type?
@ -295,7 +297,6 @@
// do we have a led count field // do we have a led count field
if (nm=="LC") { if (nm=="LC") {
let c = parseInt(LC.value,10); //get LED count let c = parseInt(LC.value,10); //get LED count
if (c > 300 && i < 8) maxB = oMaxB - Math.max(maxD-7,0); //TODO: hard limit for buses when using ESP32 parallel I2S
if (!customStarts || !startsDirty[n]) gId("ls"+n).value = sLC; //update start value if (!customStarts || !startsDirty[n]) gId("ls"+n).value = sLC; //update start value
gId("ls"+n).disabled = !customStarts; //enable/disable field editing gId("ls"+n).disabled = !customStarts; //enable/disable field editing
if (c) { if (c) {
@ -350,6 +351,17 @@
else LC.style.color = d.ro_gpio.some((e)=>e==parseInt(LC.value)) ? "orange" : "#fff"; else LC.style.color = d.ro_gpio.some((e)=>e==parseInt(LC.value)) ? "orange" : "#fff";
} }
}); });
const S2 = (oMaxB == 14) && (maxV == 4);
const S3 = (oMaxB == 14) && (maxV == 6);
if (oMaxB == 19 || S2 || S3) { // TODO: crude ESP32 & S2/S3 detection
if (maxLC > 300 || dC <= 2) {
d.Sf["PR"].checked = false;
gId("prl").classList.add("hide");
} else
gId("prl").classList.remove("hide");
maxD = (S2 || S3 ? 4 : 8) + (d.Sf["PR"].checked ? 8 : S2); // TODO: use bLimits() : 4/8RMT + (x1/x8 parallel) I2S1
maxB = oMaxB - (d.Sf["PR"].checked ? 0 : 7 + S3); // S2 (maxV==3) does support single I2S
}
// distribute ABL current if not using PPL // distribute ABL current if not using PPL
enPPL(sDI); enPPL(sDI);
@ -470,14 +482,13 @@ mA/LED: <select name="LAsel${s}" onchange="enLA(this,'${s}');UI();">
} }
} }
}); });
enLA(d.Sf["LAsel"+s],s); // update LED mA
// disable inappropriate LED types // disable inappropriate LED types
let sel = d.getElementsByName("LT"+s)[0] let sel = d.getElementsByName("LT"+s)[0]
if (i >= maxB || digitalB >= maxD) disable(sel,'option[data-type="D"]'); // NOTE: see isDig() if (i >= maxB || digitalB >= maxD) disable(sel,'option[data-type="D"]'); // NOTE: see isDig()
if (i >= maxB || twopinB >= 1) disable(sel,'option[data-type="2P"]'); // NOTE: see isD2P() if (i >= maxB || twopinB >= 1) disable(sel,'option[data-type="2P"]'); // NOTE: see isD2P()
disable(sel,`option[data-type^="${'A'.repeat(maxA-analogB+1)}"]`); // NOTE: see isPWM() disable(sel,`option[data-type^="${'A'.repeat(maxA-analogB+1)}"]`); // NOTE: see isPWM()
sel.selectedIndex = sel.querySelector('option:not(:disabled)').index; sel.selectedIndex = sel.querySelector('option:not(:disabled)').index;
// initialize current limiter
enLA(d.Sf["LAsel"+s],s);
} }
if (n==-1) { if (n==-1) {
o[--i].remove();--i; o[--i].remove();--i;
@ -789,6 +800,7 @@ Swap: <select id="xw${s}" name="XW${s}">
Use less than <span id="wreason">800 LEDs per output</span> for the best experience!<br> Use less than <span id="wreason">800 LEDs per output</span> for the best experience!<br>
</div> </div>
<hr class="sml"> <hr class="sml">
<div id="prl" class="hide">Use parallel I2S: <input type="checkbox" name="PR"><br></div>
Make a segment for each output: <input type="checkbox" name="MS"><br> Make a segment for each output: <input type="checkbox" name="MS"><br>
Custom bus start indices: <input type="checkbox" onchange="tglSi(this.checked)" id="si"><br> Custom bus start indices: <input type="checkbox" onchange="tglSi(this.checked)" id="si"><br>
Use global LED buffer: <input type="checkbox" name="LD" onchange="UI()"><br> Use global LED buffer: <input type="checkbox" name="LD" onchange="UI()"><br>

View File

@ -1,3 +1,4 @@
#pragma once
#ifndef WLED_FCN_DECLARE_H #ifndef WLED_FCN_DECLARE_H
#define WLED_FCN_DECLARE_H #define WLED_FCN_DECLARE_H

View File

@ -134,11 +134,13 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
strip.correctWB = request->hasArg(F("CCT")); strip.correctWB = request->hasArg(F("CCT"));
strip.cctFromRgb = request->hasArg(F("CR")); strip.cctFromRgb = request->hasArg(F("CR"));
cctICused = request->hasArg(F("IC")); cctICused = request->hasArg(F("IC"));
uint8_t cctBlending = request->arg(F("CB")).toInt(); Bus::setCCTBlend(request->arg(F("CB")).toInt());
Bus::setCCTBlend(cctBlending);
Bus::setGlobalAWMode(request->arg(F("AW")).toInt()); Bus::setGlobalAWMode(request->arg(F("AW")).toInt());
strip.setTargetFps(request->arg(F("FR")).toInt()); strip.setTargetFps(request->arg(F("FR")).toInt());
useGlobalLedBuffer = request->hasArg(F("LD")); useGlobalLedBuffer = request->hasArg(F("LD"));
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
useParallelI2S = request->hasArg(F("PR"));
#endif
bool busesChanged = false; bool busesChanged = false;
for (int s = 0; s < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; s++) { for (int s = 0; s < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; s++) {
@ -208,8 +210,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
type |= request->hasArg(rf) << 7; // off refresh override type |= request->hasArg(rf) << 7; // off refresh override
// actual finalization is done in WLED::loop() (removing old busses and adding new) // actual finalization is done in WLED::loop() (removing old busses and adding new)
// this may happen even before this loop is finished so we do "doInitBusses" after the loop // this may happen even before this loop is finished so we do "doInitBusses" after the loop
if (busConfigs[s] != nullptr) delete busConfigs[s]; busConfigs.push_back(std::move(BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freq, useGlobalLedBuffer, maPerLed, maMax)));
busConfigs[s] = new(std::nothrow) BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freq, useGlobalLedBuffer, maPerLed, maMax);
busesChanged = true; busesChanged = true;
} }
//doInitBusses = busesChanged; // we will do that below to ensure all input data is processed //doInitBusses = busesChanged; // we will do that below to ensure all input data is processed

View File

@ -185,46 +185,7 @@ void WLED::loop()
DEBUG_PRINTLN(F("Re-init busses.")); DEBUG_PRINTLN(F("Re-init busses."));
bool aligned = strip.checkSegmentAlignment(); //see if old segments match old bus(ses) bool aligned = strip.checkSegmentAlignment(); //see if old segments match old bus(ses)
BusManager::removeAll(); BusManager::removeAll();
unsigned mem = 0; strip.finalizeInit(); // will create buses and also load default ledmap if present
// determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT)
bool useParallel = false;
#if defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH_ESP32S2) && !defined(ARDUINO_ARCH_ESP32S3) && !defined(ARDUINO_ARCH_ESP32C3)
unsigned digitalCount = 0;
unsigned maxLedsOnBus = 0;
unsigned maxChannels = 0;
for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
if (busConfigs[i] == nullptr) break;
if (!Bus::isDigital(busConfigs[i]->type)) continue;
if (!Bus::is2Pin(busConfigs[i]->type)) {
digitalCount++;
unsigned channels = Bus::getNumberOfChannels(busConfigs[i]->type);
if (busConfigs[i]->count > maxLedsOnBus) maxLedsOnBus = busConfigs[i]->count;
if (channels > maxChannels) maxChannels = channels;
}
}
DEBUG_PRINTF_P(PSTR("Maximum LEDs on a bus: %u\nDigital buses: %u\n"), maxLedsOnBus, digitalCount);
// we may remove 300 LEDs per bus limit when NeoPixelBus is updated beyond 2.9.0
if (maxLedsOnBus <= 300 && digitalCount > 5) {
DEBUG_PRINTF_P(PSTR("Switching to parallel I2S."));
useParallel = true;
BusManager::useParallelOutput();
mem = BusManager::memUsage(maxChannels, maxLedsOnBus, 8); // use alternate memory calculation (hse to be used *after* useParallelOutput())
}
#endif
// create buses/outputs
for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
if (busConfigs[i] == nullptr || (!useParallel && i > 10)) break;
if (useParallel && i < 8) {
// if for some unexplained reason the above pre-calculation was wrong, update
unsigned memT = BusManager::memUsage(*busConfigs[i]); // includes x8 memory allocation for parallel I2S
if (memT > mem) mem = memT; // if we have unequal LED count use the largest
} else
mem += BusManager::memUsage(*busConfigs[i]); // includes global buffer
if (mem <= MAX_LED_MEMORY) BusManager::add(*busConfigs[i]);
delete busConfigs[i];
busConfigs[i] = nullptr;
}
strip.finalizeInit(); // also loads default ledmap if present
BusManager::setBrightness(bri); // fix re-initialised bus' brightness #4005 BusManager::setBrightness(bri); // fix re-initialised bus' brightness #4005
if (aligned) strip.makeAutoSegments(); if (aligned) strip.makeAutoSegments();
else strip.fixInvalidSegments(); else strip.fixInvalidSegments();
@ -573,6 +534,7 @@ void WLED::beginStrip()
strip.makeAutoSegments(); strip.makeAutoSegments();
strip.setBrightness(0); strip.setBrightness(0);
strip.setShowCallback(handleOverlayDraw); strip.setShowCallback(handleOverlayDraw);
doInitBusses = false;
if (turnOnAtBoot) { if (turnOnAtBoot) {
if (briS > 0) bri = briS; if (briS > 0) bri = briS;

View File

@ -371,7 +371,7 @@ WLED_GLOBAL bool noWifiSleep _INIT(false);
WLED_GLOBAL bool force802_3g _INIT(false); WLED_GLOBAL bool force802_3g _INIT(false);
#endif // WLED_SAVE_RAM #endif // WLED_SAVE_RAM
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
#if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32S3)) #if defined(LOLIN_WIFI_FIX) && (defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3))
WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_8_5dBm); WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_8_5dBm);
#else #else
WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_19_5dBm); WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_19_5dBm);
@ -398,6 +398,9 @@ WLED_GLOBAL byte bootPreset _INIT(0); // save preset to load
WLED_GLOBAL bool useGlobalLedBuffer _INIT(false); // double buffering disabled on ESP8266 WLED_GLOBAL bool useGlobalLedBuffer _INIT(false); // double buffering disabled on ESP8266
#else #else
WLED_GLOBAL bool useGlobalLedBuffer _INIT(true); // double buffering enabled on ESP32 WLED_GLOBAL bool useGlobalLedBuffer _INIT(true); // double buffering enabled on ESP32
#ifndef CONFIG_IDF_TARGET_ESP32C3
WLED_GLOBAL bool useParallelI2S _INIT(false); // parallel I2S for ESP32
#endif
#endif #endif
#ifdef WLED_USE_IC_CCT #ifdef WLED_USE_IC_CCT
WLED_GLOBAL bool cctICused _INIT(true); // CCT IC used (Athom 15W bulbs) WLED_GLOBAL bool cctICused _INIT(true); // CCT IC used (Athom 15W bulbs)
@ -893,7 +896,7 @@ WLED_GLOBAL bool e131NewData _INIT(false);
// led fx library object // led fx library object
WLED_GLOBAL BusManager busses _INIT(BusManager()); WLED_GLOBAL BusManager busses _INIT(BusManager());
WLED_GLOBAL WS2812FX strip _INIT(WS2812FX()); WLED_GLOBAL WS2812FX strip _INIT(WS2812FX());
WLED_GLOBAL BusConfig* busConfigs[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES] _INIT({nullptr}); //temporary, to remember values from network callback until after WLED_GLOBAL std::vector<BusConfig> busConfigs; //temporary, to remember values from network callback until after
WLED_GLOBAL bool doInitBusses _INIT(false); WLED_GLOBAL bool doInitBusses _INIT(false);
WLED_GLOBAL int8_t loadLedmap _INIT(-1); WLED_GLOBAL int8_t loadLedmap _INIT(-1);
WLED_GLOBAL uint8_t currentLedmap _INIT(0); WLED_GLOBAL uint8_t currentLedmap _INIT(0);

View File

@ -289,6 +289,7 @@ void getSettingsJS(byte subPage, Print& settingsScript)
printSetFormValue(settingsScript,PSTR("FR"),strip.getTargetFps()); printSetFormValue(settingsScript,PSTR("FR"),strip.getTargetFps());
printSetFormValue(settingsScript,PSTR("AW"),Bus::getGlobalAWMode()); printSetFormValue(settingsScript,PSTR("AW"),Bus::getGlobalAWMode());
printSetFormCheckbox(settingsScript,PSTR("LD"),useGlobalLedBuffer); printSetFormCheckbox(settingsScript,PSTR("LD"),useGlobalLedBuffer);
printSetFormCheckbox(settingsScript,PSTR("PR"),BusManager::hasParallelOutput()); // get it from bus manager not global variable
unsigned sumMa = 0; unsigned sumMa = 0;
for (int s = 0; s < BusManager::getNumBusses(); s++) { for (int s = 0; s < BusManager::getNumBusses(); s++) {