diff --git a/platformio.ini b/platformio.ini index 0870cde9d..62c8ca518 100644 --- a/platformio.ini +++ b/platformio.ini @@ -138,7 +138,7 @@ lib_compat_mode = strict lib_deps = fastled/FastLED @ 3.6.0 IRremoteESP8266 @ 2.8.2 - makuna/NeoPixelBus @ 2.8.0 + makuna/NeoPixelBus @ 2.8.3 #https://github.com/makuna/NeoPixelBus.git#CoreShaderBeta https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.2.1 # for I2C interface diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index b9a62bb2c..589fa67ee 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1219,6 +1219,50 @@ void WS2812FX::finalizeInit() { _hasWhiteChannel = _isOffRefreshRequired = false; + #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 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) && !Bus::is2Pin(busConfigs[i]->type)) { + digitalCount++; + if (busConfigs[i]->count > maxLedsOnBus) maxLedsOnBus = busConfigs[i]->count; + //unsigned channels = Bus::getNumberOfChannels(busConfigs[i]->type); + //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 && useParallelI2S) BusManager::useParallelOutput(); // must call before creating buses + else useParallelI2S = false; // enforce single I2S + #endif + + // create buses/outputs + unsigned mem = 0; + for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { + if (busConfigs[i] == nullptr) break; + #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) + #if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32S2) + // TODO: once I2S memory is larger than RMT it will ignore RMT + if (BusManager::hasParallelOutput() && i > 3) { // will use RMT and then x8 I2S + 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 + #else // classic ESP32 + if (BusManager::hasParallelOutput() && i < 8) { // 1-8 are RMT if using x1 I2S + 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 + #endif + #endif + mem += BusManager::memUsage(*busConfigs[i]); // includes global buffer + if (mem <= MAX_LED_MEMORY) BusManager::add(*busConfigs[i]); + delete busConfigs[i]; + busConfigs[i] = nullptr; + } + //if busses failed to load, add default (fresh install, FS issue, ...) if (BusManager::getNumBusses() == 0) { DEBUG_PRINTLN(F("No busses, init default")); @@ -1298,9 +1342,11 @@ void WS2812FX::finalizeInit() { if (Bus::isPWM(dataType) || Bus::isOnOff(dataType)) count = 1; prevLen += count; BusConfig defCfg = BusConfig(dataType, defPin, start, count, DEFAULT_LED_COLOR_ORDER, false, 0, RGBW_MODE_MANUAL_ONLY, 0, useGlobalLedBuffer); + mem += BusManager::memUsage(defCfg); if (BusManager::add(defCfg) == -1) break; } } + DEBUG_PRINTF_P(PSTR("LED buffer size: %uB/%uB\n"), mem, BusManager::getTotalBuffers()); _length = 0; for (int i=0; ibegin(); } + DEBUG_PRINTF_P(PSTR("Heap after buses: %d\n"), ESP.getFreeHeap()); Segment::maxWidth = _length; Segment::maxHeight = 1; diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 2c0ba41a9..44b841ac4 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -18,10 +18,11 @@ #endif #include "const.h" #include "pin_manager.h" -#include "bus_wrapper.h" #include "bus_manager.h" +#include "bus_wrapper.h" extern bool cctICused; +extern bool useParallelI2S; //colors.cpp uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb); @@ -121,7 +122,7 @@ uint8_t *Bus::allocateData(size_t size) { } -BusDigital::BusDigital(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)) , _skip(bc.skipAmount) //sacrificial pixels , _colorOrder(bc.colorOrder) @@ -220,7 +221,7 @@ void BusDigital::show() { if (!_valid) return; 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 (_data) { @@ -246,6 +247,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 Bus::_cct = _data[offset+channels-1]; Bus::calculateCCT(c, cctWW, cctCW); + if (_type == TYPE_WS2812_WWA) c = RGBW32(cctWW, cctCW, 0, W(c)); // may need swapping } unsigned pix = i; if (_reversed) pix = _len - pix -1; @@ -331,8 +333,8 @@ void IRAM_ATTR BusDigital::setPixelColor(unsigned pix, uint32_t c) { uint8_t cctWW = 0, cctCW = 0; Bus::calculateCCT(c, cctWW, cctCW); 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); } } @@ -364,16 +366,24 @@ uint32_t IRAM_ATTR BusDigital::getPixelColor(unsigned pix) const { 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; } } -uint8_t BusDigital::getPins(uint8_t* pinArray) const { +unsigned BusDigital::getPins(uint8_t* pinArray) const { unsigned numPins = is2Pin(_type) + 1; if (pinArray) for (unsigned i = 0; i < numPins; i++) pinArray[i] = _pins[i]; return numPins; } +unsigned BusDigital::getBufferSize() const { + return isOk() ? PolyBus::getDataSize(_busPtr, _iType) : 0; +} + void BusDigital::setColorOrder(uint8_t colorOrder) { // upper nibble contains W swap information if ((colorOrder & 0x0F) > 5) return; @@ -397,7 +407,7 @@ std::vector BusDigital::getLEDTypes() { {TYPE_SM16825, "D", PSTR("SM16825 RGBCW")}, {TYPE_WS2812_1CH_X3, "D", PSTR("WS2811 White")}, //{TYPE_WS2812_2CH_X3, "D", PSTR("WS2811 CCT")}, // not implemented - //{TYPE_WS2812_WWA, "D", PSTR("WS2811 WWA")}, // not implemented + {TYPE_WS2812_WWA, "D", PSTR("WS2811 WWA")}, // amber ignored {TYPE_WS2801, "2P", PSTR("WS2801")}, {TYPE_APA102, "2P", PSTR("APA102")}, {TYPE_LPD8806, "2P", PSTR("LPD8806")}, @@ -418,8 +428,9 @@ void BusDigital::cleanup() { _valid = false; _busPtr = nullptr; if (_data != nullptr) freeData(); - PinManager::deallocatePin(_pins[1], PinOwner::BusDigital); - PinManager::deallocatePin(_pins[0], PinOwner::BusDigital); + PinManager::deallocateMultiplePins(_pins, 2, PinOwner::BusDigital); + //PinManager::deallocatePin(_pins[1], PinOwner::BusDigital); + //PinManager::deallocatePin(_pins[0], PinOwner::BusDigital); } @@ -448,7 +459,7 @@ void BusDigital::cleanup() { #endif #endif -BusPwm::BusPwm(BusConfig &bc) +BusPwm::BusPwm(const BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed, bc.refreshReq) // hijack Off refresh flag to indicate usage of dithering { if (!isPWM(bc.type)) return; @@ -610,7 +621,7 @@ void BusPwm::show() { } } -uint8_t BusPwm::getPins(uint8_t* pinArray) const { +unsigned BusPwm::getPins(uint8_t* pinArray) const { if (!_valid) return 0; unsigned numPins = numPWMPins(_type); if (pinArray) for (unsigned i = 0; i < numPins; i++) pinArray[i] = _pins[i]; @@ -646,7 +657,7 @@ void BusPwm::deallocatePins() { } -BusOnOff::BusOnOff(BusConfig &bc) +BusOnOff::BusOnOff(const BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed) , _onoffdata(0) { @@ -686,7 +697,7 @@ void BusOnOff::show() { 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 (pinArray) pinArray[0] = _pin; return 1; @@ -699,7 +710,7 @@ std::vector BusOnOff::getLEDTypes() { }; } -BusNetwork::BusNetwork(BusConfig &bc) +BusNetwork::BusNetwork(const BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite, bc.count) , _broadcastLock(false) { @@ -750,7 +761,7 @@ void BusNetwork::show() { _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]; return 4; } @@ -778,7 +789,7 @@ void BusNetwork::cleanup() { //utility to get the approx. memory usage of a given BusConfig -uint32_t BusManager::memUsage(BusConfig &bc) { +uint32_t BusManager::memUsage(const BusConfig &bc) { if (Bus::isOnOff(bc.type) || Bus::isPWM(bc.type)) return OUTPUT_MAX_PINS; unsigned len = bc.count + bc.skipAmount; @@ -791,19 +802,23 @@ uint32_t BusManager::memUsage(BusConfig &bc) { multiplier = 5; } #else //ESP32 RMT uses double buffer, parallel I2S uses 8x buffer (3 times) - multiplier = PolyBus::isParallelI2S1Output() ? 24 : 2; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + multiplier = useParallelI2S ? 24 : 2; + #else + multiplier = 2; + #endif #endif } return (len * multiplier + bc.doubleBuffer * (bc.count + bc.skipAmount)) * channels; } -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); +unsigned BusManager::getTotalBuffers() { + unsigned size = 0; + for (unsigned i=0; igetBufferSize(); + return size; } -int BusManager::add(BusConfig &bc) { +int BusManager::add(const BusConfig &bc) { if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1; if (Bus::isVirtual(bc.type)) { busses[numBusses] = new BusNetwork(bc); @@ -843,10 +858,13 @@ String BusManager::getLEDTypesJSONString() { } void BusManager::useParallelOutput() { - _parallelOutputs = 8; // hardcoded since we use NPB I2S x8 methods PolyBus::setParallelI2S1Output(); } +bool BusManager::hasParallelOutput() { + return PolyBus::isParallelI2S1Output(); +} + //do not call this method from system context (network callback) void BusManager::removeAll() { DEBUG_PRINTLN(F("Removing all.")); @@ -854,7 +872,6 @@ void BusManager::removeAll() { while (!canAllShow()) yield(); for (unsigned i = 0; i < numBusses; i++) delete busses[i]; numBusses = 0; - _parallelOutputs = 1; PolyBus::setParallelI2S1Output(false); } @@ -876,9 +893,10 @@ void BusManager::esp32RMTInvertIdle() { if (u > 3) return; rmt = u; #else - if (u < _parallelOutputs) continue; - if (u >= _parallelOutputs + 8) return; // only 8 RMT channels - rmt = u - _parallelOutputs; + unsigned numI2S = 1 + PolyBus::isParallelI2S1Output()*7; + if (u < numI2S) continue; + if (u >= numI2S + 8) return; // only 8 RMT channels + rmt = u - numI2S; #endif if (busses[u]->getLength()==0 || !busses[u]->isDigital() || busses[u]->is2Pin()) continue; //assumes that bus number to rmt channel mapping stays 1:1 @@ -994,7 +1012,7 @@ uint16_t BusManager::getTotalLength() { return len; } -bool PolyBus::useParallelI2S = false; +bool PolyBus::_useParallelI2S = false; // Bus static member definition int16_t Bus::_cct = -1; @@ -1008,4 +1026,3 @@ Bus* BusManager::busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES]; ColorOrderMap BusManager::colorOrderMap = {}; uint16_t BusManager::_milliAmpsUsed = 0; uint16_t BusManager::_milliAmpsMax = ABL_MILLIAMPS_DEFAULT; -uint8_t BusManager::_parallelOutputs = 1; diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index d90a66151..5f582971a 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -82,46 +82,47 @@ class Bus { virtual void begin() {}; virtual void show() = 0; - virtual bool canShow() const { return true; } - virtual void setStatusPixel(uint32_t c) {} + virtual bool canShow() const { return true; } + virtual void setStatusPixel(uint32_t c) {} virtual void setPixelColor(unsigned pix, uint32_t c) = 0; - virtual void setBrightness(uint8_t b) { _bri = b; }; - virtual void setColorOrder(uint8_t co) {} - virtual uint32_t getPixelColor(unsigned pix) const { return 0; } - virtual uint8_t getPins(uint8_t* pinArray = nullptr) const { return 0; } - virtual uint16_t getLength() const { return isOk() ? _len : 0; } - virtual uint8_t getColorOrder() const { return COL_ORDER_RGB; } - virtual uint8_t skippedLeds() const { return 0; } - virtual uint16_t getFrequency() const { return 0U; } - virtual uint16_t getLEDCurrent() const { return 0; } - virtual uint16_t getUsedCurrent() const { return 0; } - virtual uint16_t getMaxCurrent() const { return 0; } + virtual void setBrightness(uint8_t b) { _bri = b; }; + virtual void setColorOrder(uint8_t co) {} + virtual uint32_t getPixelColor(unsigned pix) const { return 0; } + virtual unsigned getPins(uint8_t* pinArray = nullptr) const { return 0; } + virtual uint16_t getLength() const { return isOk() ? _len : 0; } + virtual uint8_t getColorOrder() const { return COL_ORDER_RGB; } + virtual unsigned skippedLeds() const { return 0; } + virtual uint16_t getFrequency() const { return 0U; } + virtual uint16_t getLEDCurrent() const { return 0; } + virtual uint16_t getUsedCurrent() const { return 0; } + virtual uint16_t getMaxCurrent() const { return 0; } + virtual unsigned getBufferSize() const { return 1; } - inline bool hasRGB() const { return _hasRgb; } - inline bool hasWhite() const { return _hasWhite; } - inline bool hasCCT() const { return _hasCCT; } - inline bool isDigital() const { return isDigital(_type); } - inline bool is2Pin() const { return is2Pin(_type); } - inline bool isOnOff() const { return isOnOff(_type); } - inline bool isPWM() const { return isPWM(_type); } - inline bool isVirtual() const { return isVirtual(_type); } - inline bool is16bit() const { return is16bit(_type); } - inline bool mustRefresh() const { return mustRefresh(_type); } - inline void setReversed(bool reversed) { _reversed = reversed; } - inline void setStart(uint16_t start) { _start = start; } - inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; } - inline uint8_t getAutoWhiteMode() const { return _autoWhiteMode; } - inline uint32_t getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); } - inline uint16_t getStart() const { return _start; } - inline uint8_t getType() const { return _type; } - inline bool isOk() const { return _valid; } - inline bool isReversed() const { return _reversed; } - inline bool isOffRefreshRequired() const { return _needsRefresh; } - inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start + _len; } + inline bool hasRGB() const { return _hasRgb; } + inline bool hasWhite() const { return _hasWhite; } + inline bool hasCCT() const { return _hasCCT; } + inline bool isDigital() const { return isDigital(_type); } + inline bool is2Pin() const { return is2Pin(_type); } + inline bool isOnOff() const { return isOnOff(_type); } + inline bool isPWM() const { return isPWM(_type); } + inline bool isVirtual() const { return isVirtual(_type); } + inline bool is16bit() const { return is16bit(_type); } + inline bool mustRefresh() const { return mustRefresh(_type); } + inline void setReversed(bool reversed) { _reversed = reversed; } + inline void setStart(uint16_t start) { _start = start; } + inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; } + inline uint8_t getAutoWhiteMode() const { return _autoWhiteMode; } + inline unsigned getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); } + inline uint16_t getStart() const { return _start; } + inline uint8_t getType() const { return _type; } + inline bool isOk() const { return _valid; } + inline bool isReversed() const { return _reversed; } + inline bool isOffRefreshRequired() const { return _needsRefresh; } + inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start + _len; } - static inline std::vector 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 uint32_t getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); } + static inline std::vector getLEDTypes() { return {{TYPE_NONE, "", PSTR("None")}}; } // not used. just for reference for derived classes + static constexpr uint8_t getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK + static constexpr uint8_t getNumberOfChannels(uint8_t type) { return (type == TYPE_WS2812_WWA) ? 3 : hasWhite(type) + 3*hasRGB(type) + hasCCT(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); } @@ -198,7 +199,7 @@ class Bus { class BusDigital : public Bus { public: - BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com); + BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com); ~BusDigital() { cleanup(); } void show() override; @@ -209,12 +210,13 @@ class BusDigital : public Bus { void setColorOrder(uint8_t colorOrder) override; [[gnu::hot]] uint32_t getPixelColor(unsigned pix) const override; uint8_t getColorOrder() const override { return _colorOrder; } - uint8_t getPins(uint8_t* pinArray = nullptr) const override; - uint8_t skippedLeds() const override { return _skip; } + unsigned getPins(uint8_t* pinArray = nullptr) const override; + unsigned skippedLeds() const override { return _skip; } uint16_t getFrequency() const override { return _frequencykHz; } uint16_t getLEDCurrent() const override { return _milliAmpsPerLed; } uint16_t getUsedCurrent() const override { return _milliAmpsTotal; } uint16_t getMaxCurrent() const override { return _milliAmpsMax; } + unsigned getBufferSize() const override; void begin() override; void cleanup(); @@ -250,13 +252,14 @@ class BusDigital : public Bus { class BusPwm : public Bus { public: - BusPwm(BusConfig &bc); + BusPwm(const BusConfig &bc); ~BusPwm() { cleanup(); } void setPixelColor(unsigned pix, uint32_t c) override; 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; } + unsigned getBufferSize() const override { return OUTPUT_MAX_PINS; } void show() override; void cleanup() { deallocatePins(); } @@ -277,12 +280,12 @@ class BusPwm : public Bus { class BusOnOff : public Bus { public: - BusOnOff(BusConfig &bc); + BusOnOff(const BusConfig &bc); ~BusOnOff() { cleanup(); } void setPixelColor(unsigned pix, uint32_t c) override; uint32_t getPixelColor(unsigned pix) const override; - uint8_t getPins(uint8_t* pinArray) const override; + unsigned getPins(uint8_t* pinArray) const override; void show() override; void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); } @@ -296,13 +299,14 @@ class BusOnOff : public Bus { class BusNetwork : public Bus { public: - BusNetwork(BusConfig &bc); + BusNetwork(const BusConfig &bc); ~BusNetwork() { cleanup(); } 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; 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 getBufferSize() const override { return isOk() ? _len * _UDPchannels : 0; } void show() override; void cleanup(); @@ -379,13 +383,14 @@ class BusManager { BusManager() {}; //utility to get the approx. memory usage of a given BusConfig - static uint32_t memUsage(BusConfig &bc); - static uint32_t memUsage(unsigned channels, unsigned count, unsigned buses = 1); + static uint32_t memUsage(const BusConfig &bc); + static unsigned getTotalBuffers(); static uint16_t currentMilliamps() { return _milliAmpsUsed + MA_FOR_ESP; } static uint16_t ablMilliampsMax() { return _milliAmpsMax; } - static int add(BusConfig &bc); + static int add(const BusConfig &bc); static void useParallelOutput(); // workaround for inaccessible PolyBus + static bool hasParallelOutput(); // workaround for inaccessible PolyBus //do not call this method from system context (network callback) static void removeAll(); @@ -420,7 +425,6 @@ class BusManager { static ColorOrderMap colorOrderMap; static uint16_t _milliAmpsUsed; static uint16_t _milliAmpsMax; - static uint8_t _parallelOutputs; #ifdef ESP32_DATA_IDLE_HIGH static void esp32RMTInvertIdle() ; diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index d2a18c9d8..943a0b818 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -1,23 +1,8 @@ #ifndef BusWrapper_h #define BusWrapper_h +//#define NPB_CONF_4STEP_CADENCE #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 #define P_8266_HS_MOSI 13 @@ -55,110 +40,98 @@ #define I_8266_DM_TM2_3 19 #define I_8266_BB_TM2_3 20 //UCS8903 (RGB) -#define I_8266_U0_UCS_3 49 -#define I_8266_U1_UCS_3 50 -#define I_8266_DM_UCS_3 51 -#define I_8266_BB_UCS_3 52 +#define I_8266_U0_UCS_3 21 +#define I_8266_U1_UCS_3 22 +#define I_8266_DM_UCS_3 23 +#define I_8266_BB_UCS_3 24 //UCS8904 (RGBW) -#define I_8266_U0_UCS_4 53 -#define I_8266_U1_UCS_4 54 -#define I_8266_DM_UCS_4 55 -#define I_8266_BB_UCS_4 56 +#define I_8266_U0_UCS_4 25 +#define I_8266_U1_UCS_4 26 +#define I_8266_DM_UCS_4 27 +#define I_8266_BB_UCS_4 28 //FW1906 GRBCW -#define I_8266_U0_FW6_5 66 -#define I_8266_U1_FW6_5 67 -#define I_8266_DM_FW6_5 68 -#define I_8266_BB_FW6_5 69 +#define I_8266_U0_FW6_5 29 +#define I_8266_U1_FW6_5 30 +#define I_8266_DM_FW6_5 31 +#define I_8266_BB_FW6_5 32 //ESP8266 APA106 -#define I_8266_U0_APA106_3 81 -#define I_8266_U1_APA106_3 82 -#define I_8266_DM_APA106_3 83 -#define I_8266_BB_APA106_3 84 +#define I_8266_U0_APA106_3 33 +#define I_8266_U1_APA106_3 34 +#define I_8266_DM_APA106_3 35 +#define I_8266_BB_APA106_3 36 //WS2805 (RGBCW) -#define I_8266_U0_2805_5 89 -#define I_8266_U1_2805_5 90 -#define I_8266_DM_2805_5 91 -#define I_8266_BB_2805_5 92 +#define I_8266_U0_2805_5 37 +#define I_8266_U1_2805_5 38 +#define I_8266_DM_2805_5 39 +#define I_8266_BB_2805_5 40 //TM1914 (RGB) -#define I_8266_U0_TM1914_3 99 -#define I_8266_U1_TM1914_3 100 -#define I_8266_DM_TM1914_3 101 -#define I_8266_BB_TM1914_3 102 +#define I_8266_U0_TM1914_3 41 +#define I_8266_U1_TM1914_3 42 +#define I_8266_DM_TM1914_3 43 +#define I_8266_BB_TM1914_3 44 //SM16825 (RGBCW) -#define I_8266_U0_SM16825_5 103 -#define I_8266_U1_SM16825_5 104 -#define I_8266_DM_SM16825_5 105 -#define I_8266_BB_SM16825_5 106 +#define I_8266_U0_SM16825_5 45 +#define I_8266_U1_SM16825_5 46 +#define I_8266_DM_SM16825_5 47 +#define I_8266_BB_SM16825_5 48 /*** ESP32 Neopixel methods ***/ //RGB -#define I_32_RN_NEO_3 21 -#define I_32_I0_NEO_3 22 -#define I_32_I1_NEO_3 23 +#define I_32_RN_NEO_3 1 +#define I_32_I2_NEO_3 2 //RGBW -#define I_32_RN_NEO_4 25 -#define I_32_I0_NEO_4 26 -#define I_32_I1_NEO_4 27 +#define I_32_RN_NEO_4 5 +#define I_32_I2_NEO_4 6 //400Kbps -#define I_32_RN_400_3 29 -#define I_32_I0_400_3 30 -#define I_32_I1_400_3 31 +#define I_32_RN_400_3 9 +#define I_32_I2_400_3 10 //TM1814 (RGBW) -#define I_32_RN_TM1_4 33 -#define I_32_I0_TM1_4 34 -#define I_32_I1_TM1_4 35 +#define I_32_RN_TM1_4 13 +#define I_32_I2_TM1_4 14 //TM1829 (RGB) -#define I_32_RN_TM2_3 36 -#define I_32_I0_TM2_3 37 -#define I_32_I1_TM2_3 38 +#define I_32_RN_TM2_3 17 +#define I_32_I2_TM2_3 18 //UCS8903 (RGB) -#define I_32_RN_UCS_3 57 -#define I_32_I0_UCS_3 58 -#define I_32_I1_UCS_3 59 +#define I_32_RN_UCS_3 21 +#define I_32_I2_UCS_3 22 //UCS8904 (RGBW) -#define I_32_RN_UCS_4 60 -#define I_32_I0_UCS_4 61 -#define I_32_I1_UCS_4 62 +#define I_32_RN_UCS_4 25 +#define I_32_I2_UCS_4 26 //FW1906 GRBCW -#define I_32_RN_FW6_5 63 -#define I_32_I0_FW6_5 64 -#define I_32_I1_FW6_5 65 +#define I_32_RN_FW6_5 29 +#define I_32_I2_FW6_5 30 //APA106 -#define I_32_RN_APA106_3 85 -#define I_32_I0_APA106_3 86 -#define I_32_I1_APA106_3 87 +#define I_32_RN_APA106_3 33 +#define I_32_I2_APA106_3 34 //WS2805 (RGBCW) -#define I_32_RN_2805_5 93 -#define I_32_I0_2805_5 94 -#define I_32_I1_2805_5 95 +#define I_32_RN_2805_5 37 +#define I_32_I2_2805_5 38 //TM1914 (RGB) -#define I_32_RN_TM1914_3 96 -#define I_32_I0_TM1914_3 97 -#define I_32_I1_TM1914_3 98 +#define I_32_RN_TM1914_3 41 +#define I_32_I2_TM1914_3 42 //SM16825 (RGBCW) -#define I_32_RN_SM16825_5 107 -#define I_32_I0_SM16825_5 108 -#define I_32_I1_SM16825_5 109 +#define I_32_RN_SM16825_5 45 +#define I_32_I2_SM16825_5 46 //APA102 -#define I_HS_DOT_3 39 //hardware SPI -#define I_SS_DOT_3 40 //soft SPI +#define I_HS_DOT_3 101 //hardware SPI +#define I_SS_DOT_3 102 //soft SPI //LPD8806 -#define I_HS_LPD_3 41 -#define I_SS_LPD_3 42 +#define I_HS_LPD_3 103 +#define I_SS_LPD_3 104 //WS2801 -#define I_HS_WS1_3 43 -#define I_SS_WS1_3 44 +#define I_HS_WS1_3 105 +#define I_SS_WS1_3 106 //P9813 -#define I_HS_P98_3 45 -#define I_SS_P98_3 46 +#define I_HS_P98_3 107 +#define I_SS_P98_3 108 //LPD6803 -#define I_HS_LPO_3 47 -#define I_SS_LPO_3 48 +#define I_HS_LPO_3 109 +#define I_SS_LPO_3 110 // In the following NeoGammaNullMethod can be replaced with NeoGammaWLEDMethod to perform Gamma correction implicitly @@ -230,66 +203,95 @@ /*** ESP32 Neopixel methods ***/ #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 -#define B_32_RN_NEO_3 NeoPixelBusLg -#define B_32_I0_NEO_3 NeoPixelBusLg -#define B_32_I1_NEO_3 NeoPixelBusLg -#define B_32_I1_NEO_3P NeoPixelBusLg // parallel I2S +#define B_32_RN_NEO_3 NeoPixelBusLg // ESP32, S2, S3, C3 +//#define B_32_IN_NEO_3 NeoPixelBusLg // ESP32 (dynamic I2S selection) +#define B_32_I2_NEO_3 NeoPixelBusLg // ESP32, S2, S3 (automatic I2S selection, see typedef above) +#define B_32_IP_NEO_3 NeoPixelBusLg // parallel I2S (ESP32, S2, S3) //RGBW #define B_32_RN_NEO_4 NeoPixelBusLg -#define B_32_I0_NEO_4 NeoPixelBusLg -#define B_32_I1_NEO_4 NeoPixelBusLg -#define B_32_I1_NEO_4P NeoPixelBusLg // parallel I2S +#define B_32_I2_NEO_4 NeoPixelBusLg +#define B_32_IP_NEO_4 NeoPixelBusLg // parallel I2S //400Kbps #define B_32_RN_400_3 NeoPixelBusLg -#define B_32_I0_400_3 NeoPixelBusLg -#define B_32_I1_400_3 NeoPixelBusLg -#define B_32_I1_400_3P NeoPixelBusLg // parallel I2S +#define B_32_I2_400_3 NeoPixelBusLg +#define B_32_IP_400_3 NeoPixelBusLg // parallel I2S //TM1814 (RGBW) #define B_32_RN_TM1_4 NeoPixelBusLg -#define B_32_I0_TM1_4 NeoPixelBusLg -#define B_32_I1_TM1_4 NeoPixelBusLg -#define B_32_I1_TM1_4P NeoPixelBusLg // parallel I2S +#define B_32_I2_TM1_4 NeoPixelBusLg +#define B_32_IP_TM1_4 NeoPixelBusLg // parallel I2S //TM1829 (RGB) #define B_32_RN_TM2_3 NeoPixelBusLg -#define B_32_I0_TM2_3 NeoPixelBusLg -#define B_32_I1_TM2_3 NeoPixelBusLg -#define B_32_I1_TM2_3P NeoPixelBusLg // parallel I2S +#define B_32_I2_TM2_3 NeoPixelBusLg +#define B_32_IP_TM2_3 NeoPixelBusLg // parallel I2S //UCS8903 #define B_32_RN_UCS_3 NeoPixelBusLg -#define B_32_I0_UCS_3 NeoPixelBusLg -#define B_32_I1_UCS_3 NeoPixelBusLg -#define B_32_I1_UCS_3P NeoPixelBusLg // parallel I2S +#define B_32_I2_UCS_3 NeoPixelBusLg +#define B_32_IP_UCS_3 NeoPixelBusLg // parallel I2S //UCS8904 #define B_32_RN_UCS_4 NeoPixelBusLg -#define B_32_I0_UCS_4 NeoPixelBusLg -#define B_32_I1_UCS_4 NeoPixelBusLg -#define B_32_I1_UCS_4P NeoPixelBusLg// parallel I2S +#define B_32_I2_UCS_4 NeoPixelBusLg +#define B_32_IP_UCS_4 NeoPixelBusLg// parallel I2S //APA106 #define B_32_RN_APA106_3 NeoPixelBusLg -#define B_32_I0_APA106_3 NeoPixelBusLg -#define B_32_I1_APA106_3 NeoPixelBusLg -#define B_32_I1_APA106_3P NeoPixelBusLg // parallel I2S +#define B_32_I2_APA106_3 NeoPixelBusLg +#define B_32_IP_APA106_3 NeoPixelBusLg // parallel I2S //FW1906 GRBCW #define B_32_RN_FW6_5 NeoPixelBusLg -#define B_32_I0_FW6_5 NeoPixelBusLg -#define B_32_I1_FW6_5 NeoPixelBusLg -#define B_32_I1_FW6_5P NeoPixelBusLg // parallel I2S +#define B_32_I2_FW6_5 NeoPixelBusLg +#define B_32_IP_FW6_5 NeoPixelBusLg // parallel I2S //WS2805 RGBWC #define B_32_RN_2805_5 NeoPixelBusLg -#define B_32_I0_2805_5 NeoPixelBusLg -#define B_32_I1_2805_5 NeoPixelBusLg -#define B_32_I1_2805_5P NeoPixelBusLg // parallel I2S +#define B_32_I2_2805_5 NeoPixelBusLg +#define B_32_IP_2805_5 NeoPixelBusLg // parallel I2S //TM1914 (RGB) #define B_32_RN_TM1914_3 NeoPixelBusLg -#define B_32_I0_TM1914_3 NeoPixelBusLg -#define B_32_I1_TM1914_3 NeoPixelBusLg -#define B_32_I1_TM1914_3P NeoPixelBusLg // parallel I2S +#define B_32_I2_TM1914_3 NeoPixelBusLg +#define B_32_IP_TM1914_3 NeoPixelBusLg // parallel I2S //Sm16825 (RGBWC) #define B_32_RN_SM16825_5 NeoPixelBusLg -#define B_32_I0_SM16825_5 NeoPixelBusLg -#define B_32_I1_SM16825_5 NeoPixelBusLg -#define B_32_I1_SM16825_5P NeoPixelBusLg // parallel I2S +#define B_32_I2_SM16825_5 NeoPixelBusLg +#define B_32_IP_SM16825_5 NeoPixelBusLg // parallel I2S #endif //APA102 @@ -328,11 +330,11 @@ //handles pointer type conversion for all possible bus types class PolyBus { private: - static bool useParallelI2S; + static bool _useParallelI2S; public: - static inline void setParallelI2S1Output(bool b = true) { useParallelI2S = b; } - static inline bool isParallelI2S1Output(void) { return useParallelI2S; } + static inline void setParallelI2S1Output(bool b = true) { _useParallelI2S = b; } + static inline bool isParallelI2S1Output(void) { return _useParallelI2S; } // initialize SPI bus speed for DotStar methods template @@ -436,34 +438,19 @@ class PolyBus { case I_32_RN_TM1914_3: beginTM1914(busPtr); break; case I_32_RN_SM16825_5: (static_cast(busPtr))->Begin(); break; // I2S1 bus or parellel buses - #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_NEO_3: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - case I_32_I1_NEO_4: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - case I_32_I1_400_3: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - case I_32_I1_TM1_4: if (useParallelI2S) beginTM1814(busPtr); else beginTM1814(busPtr); break; - case I_32_I1_TM2_3: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - case I_32_I1_UCS_3: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - case I_32_I1_UCS_4: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - case I_32_I1_FW6_5: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - case I_32_I1_APA106_3: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - case I_32_I1_2805_5: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - case I_32_I1_TM1914_3: if (useParallelI2S) beginTM1914(busPtr); else beginTM1914(busPtr); break; - case I_32_I1_SM16825_5: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - #endif - // I2S0 bus - #ifndef WLED_NO_I2S0_PIXELBUS - case I_32_I0_NEO_3: (static_cast(busPtr))->Begin(); break; - case I_32_I0_NEO_4: (static_cast(busPtr))->Begin(); break; - case I_32_I0_400_3: (static_cast(busPtr))->Begin(); break; - case I_32_I0_TM1_4: beginTM1814(busPtr); break; - case I_32_I0_TM2_3: (static_cast(busPtr))->Begin(); break; - case I_32_I0_UCS_3: (static_cast(busPtr))->Begin(); break; - case I_32_I0_UCS_4: (static_cast(busPtr))->Begin(); break; - case I_32_I0_FW6_5: (static_cast(busPtr))->Begin(); break; - case I_32_I0_APA106_3: (static_cast(busPtr))->Begin(); break; - case I_32_I0_2805_5: (static_cast(busPtr))->Begin(); break; - case I_32_I0_TM1914_3: beginTM1914(busPtr); break; - case I_32_I0_SM16825_5: (static_cast(busPtr))->Begin(); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_NEO_4: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_400_3: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_TM1_4: if (_useParallelI2S) beginTM1814(busPtr); else beginTM1814(busPtr); break; + case I_32_I2_TM2_3: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_UCS_3: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_UCS_4: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_FW6_5: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_APA106_3: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_2805_5: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_TM1914_3: if (_useParallelI2S) beginTM1914(busPtr); else beginTM1914(busPtr); break; + case I_32_I2_SM16825_5: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; #endif // 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(busPtr, pins[1], -1, pins[0], -1, clock_kHz); break; @@ -484,7 +471,7 @@ class PolyBus { #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 // 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 > 7) channel -= 8; // accommodate parallel I2S1 which is used 1st on classic ESP32 else if (channel > 0) channel--; // accommodate I2S1 which is used as 1st bus on classic ESP32 #endif void* busPtr = nullptr; @@ -555,34 +542,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_SM16825_5: busPtr = new B_32_RN_SM16825_5(len, pins[0], (NeoBusChannel)channel); break; // I2S1 bus or paralell buses - #ifndef WLED_NO_I2S1_PIXELBUS - 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_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_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_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_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_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_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_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_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_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_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_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; - #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; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + 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_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_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_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_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_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_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_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_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_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_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_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 #endif // for 2-wire: pins[1] is clk, pins[0] is dat. begin expects (len, clk, dat) @@ -669,34 +641,19 @@ class PolyBus { case I_32_RN_TM1914_3: (static_cast(busPtr))->Show(consistent); break; case I_32_RN_SM16825_5: (static_cast(busPtr))->Show(consistent); break; // I2S1 bus or paralell buses - #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_NEO_3: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_NEO_4: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_400_3: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_TM1_4: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_TM2_3: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_UCS_3: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_UCS_4: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_APA106_3: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_FW6_5: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_2805_5: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_TM1914_3: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_SM16825_5: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - #endif - // I2S0 bus - #ifndef WLED_NO_I2S0_PIXELBUS - case I_32_I0_NEO_3: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_NEO_4: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_400_3: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_TM1_4: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_TM2_3: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_UCS_3: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_UCS_4: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_APA106_3: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_FW6_5: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_2805_5: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_TM1914_3: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_SM16825_5: (static_cast(busPtr))->Show(consistent); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_NEO_4: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_400_3: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_TM1_4: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_TM2_3: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_UCS_3: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_UCS_4: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_APA106_3: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_FW6_5: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_2805_5: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_TM1914_3: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_SM16825_5: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; #endif #endif case I_HS_DOT_3: (static_cast(busPtr))->Show(consistent); break; @@ -779,34 +736,19 @@ class PolyBus { case I_32_RN_TM1914_3: return (static_cast(busPtr))->CanShow(); break; case I_32_RN_SM16825_5: return (static_cast(busPtr))->CanShow(); break; // I2S1 bus or paralell buses - #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_NEO_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_NEO_4: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_400_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_TM1_4: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_TM2_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_UCS_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_UCS_4: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_APA106_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_FW6_5: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_2805_5: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_TM1914_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_SM16825_5: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - #endif - // I2S0 bus - #ifndef WLED_NO_I2S0_PIXELBUS - case I_32_I0_NEO_3: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_NEO_4: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_400_3: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_TM1_4: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_TM2_3: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_UCS_3: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_UCS_4: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_APA106_3: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_FW6_5: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_2805_5: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_TM1914_3: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_SM16825_5: return (static_cast(busPtr))->CanShow(); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_NEO_4: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_400_3: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_TM1_4: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_TM2_3: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_UCS_3: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_UCS_4: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_APA106_3: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_FW6_5: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_2805_5: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_TM1914_3: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_SM16825_5: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; #endif #endif case I_HS_DOT_3: return (static_cast(busPtr))->CanShow(); break; @@ -916,34 +858,19 @@ class PolyBus { case I_32_RN_TM1914_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; case I_32_RN_SM16825_5: (static_cast(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); break; // I2S1 bus or paralell buses - #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_NEO_3: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_32_I1_NEO_4: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, col); break; - case I_32_I1_400_3: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_32_I1_TM1_4: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, col); break; - case I_32_I1_TM2_3: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_32_I1_UCS_3: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, Rgb48Color(RgbColor(col))); break; - case I_32_I1_UCS_4: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break; - case I_32_I1_APA106_3: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_32_I1_FW6_5: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); else (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; - case I_32_I1_2805_5: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); else (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; - case I_32_I1_TM1914_3: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_32_I1_SM16825_5: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); else (static_cast(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(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_32_I0_NEO_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; - case I_32_I0_400_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_32_I0_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; - case I_32_I0_TM2_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_32_I0_UCS_3: (static_cast(busPtr))->SetPixelColor(pix, Rgb48Color(RgbColor(col))); break; - case I_32_I0_UCS_4: (static_cast(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break; - case I_32_I0_APA106_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_32_I0_FW6_5: (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; - case I_32_I0_2805_5: (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; - case I_32_I0_TM1914_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_32_I0_SM16825_5: (static_cast(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_32_I2_NEO_4: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_I2_400_3: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_32_I2_TM1_4: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_I2_TM2_3: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_32_I2_UCS_3: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, Rgb48Color(RgbColor(col))); break; + case I_32_I2_UCS_4: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break; + case I_32_I2_APA106_3: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_32_I2_FW6_5: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); else (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; + case I_32_I2_2805_5: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); else (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; + case I_32_I2_TM1914_3: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_32_I2_SM16825_5: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); else (static_cast(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); break; #endif #endif case I_HS_DOT_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; @@ -1027,34 +954,19 @@ class PolyBus { case I_32_RN_TM1914_3: (static_cast(busPtr))->SetLuminance(b); break; case I_32_RN_SM16825_5: (static_cast(busPtr))->SetLuminance(b); break; // I2S1 bus or paralell buses - #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_NEO_3: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_NEO_4: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_400_3: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_TM1_4: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_TM2_3: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_UCS_3: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_UCS_4: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_APA106_3: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_FW6_5: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_2805_5: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_TM1914_3: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_SM16825_5: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - #endif - // I2S0 bus - #ifndef WLED_NO_I2S0_PIXELBUS - case I_32_I0_NEO_3: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_NEO_4: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_400_3: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_TM1_4: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_TM2_3: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_UCS_3: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_UCS_4: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_APA106_3: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_FW6_5: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_2805_5: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_TM1914_3: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_SM16825_5: (static_cast(busPtr))->SetLuminance(b); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_NEO_4: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_400_3: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_TM1_4: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_TM2_3: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_UCS_3: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_UCS_4: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_APA106_3: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_FW6_5: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_2805_5: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_TM1914_3: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_SM16825_5: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; #endif #endif case I_HS_DOT_3: (static_cast(busPtr))->SetLuminance(b); break; @@ -1139,34 +1051,19 @@ class PolyBus { case I_32_RN_TM1914_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; case I_32_RN_SM16825_5: { Rgbww80Color c = (static_cast(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 - #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_NEO_3: col = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; - case I_32_I1_NEO_4: col = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; - case I_32_I1_400_3: col = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; - case I_32_I1_TM1_4: col = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; - case I_32_I1_TM2_3: col = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; - case I_32_I1_UCS_3: { Rgb48Color c = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(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(busPtr))->GetPixelColor(pix) : (static_cast(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(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; - case I_32_I1_FW6_5: { RgbwwColor c = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(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(busPtr))->GetPixelColor(pix) : (static_cast(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(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; - case I_32_I1_SM16825_5: { Rgbww80Color c = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(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(busPtr))->GetPixelColor(pix); break; - case I_32_I0_NEO_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; - case I_32_I0_400_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; - case I_32_I0_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; - case I_32_I0_TM2_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; - case I_32_I0_UCS_3: { Rgb48Color c = (static_cast(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(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(busPtr))->GetPixelColor(pix); break; - case I_32_I0_FW6_5: { RgbwwColor c = (static_cast(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(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(busPtr))->GetPixelColor(pix); break; - case I_32_I0_SM16825_5: { Rgbww80Color c = (static_cast(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 + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_NEO_4: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_400_3: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_TM1_4: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_TM2_3: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_UCS_3: { Rgb48Color c = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,0); } break; + case I_32_I2_UCS_4: { Rgbw64Color c = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,c.W/257); } break; + case I_32_I2_APA106_3: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_FW6_5: { RgbwwColor c = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(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(busPtr))->GetPixelColor(pix) : (static_cast(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_TM1914_3: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_SM16825_5: { Rgbww80Color c = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(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 case I_HS_DOT_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; @@ -1269,34 +1166,19 @@ class PolyBus { case I_32_RN_TM1914_3: delete (static_cast(busPtr)); break; case I_32_RN_SM16825_5: delete (static_cast(busPtr)); break; // I2S1 bus or paralell buses - #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_NEO_3: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_NEO_4: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_400_3: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_TM1_4: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_TM2_3: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_UCS_3: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_UCS_4: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_APA106_3: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_FW6_5: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_2805_5: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_TM1914_3: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_SM16825_5: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - #endif - // I2S0 bus - #ifndef WLED_NO_I2S0_PIXELBUS - case I_32_I0_NEO_3: delete (static_cast(busPtr)); break; - case I_32_I0_NEO_4: delete (static_cast(busPtr)); break; - case I_32_I0_400_3: delete (static_cast(busPtr)); break; - case I_32_I0_TM1_4: delete (static_cast(busPtr)); break; - case I_32_I0_TM2_3: delete (static_cast(busPtr)); break; - case I_32_I0_UCS_3: delete (static_cast(busPtr)); break; - case I_32_I0_UCS_4: delete (static_cast(busPtr)); break; - case I_32_I0_APA106_3: delete (static_cast(busPtr)); break; - case I_32_I0_FW6_5: delete (static_cast(busPtr)); break; - case I_32_I0_2805_5: delete (static_cast(busPtr)); break; - case I_32_I0_TM1914_3: delete (static_cast(busPtr)); break; - case I_32_I0_SM16825_5: delete (static_cast(busPtr)); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_NEO_4: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_400_3: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_TM1_4: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_TM2_3: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_UCS_3: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_UCS_4: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_APA106_3: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_FW6_5: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_2805_5: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_TM1914_3: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_SM16825_5: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; #endif #endif case I_HS_DOT_3: delete (static_cast(busPtr)); break; @@ -1312,6 +1194,104 @@ 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(busPtr))->PixelsSize(); break; + case I_8266_U1_NEO_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_NEO_3: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_NEO_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_NEO_4: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_NEO_4: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_NEO_4: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_NEO_4: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_400_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_400_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_400_3: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_400_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_TM1_4: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_TM1_4: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_TM1_4: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_TM1_4: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_TM2_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_TM2_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_TM2_3: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_TM2_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_UCS_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_UCS_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_UCS_3: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_UCS_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_UCS_4: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_UCS_4: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_UCS_4: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_UCS_4: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_APA106_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_APA106_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_APA106_3: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_APA106_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_FW6_5: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_FW6_5: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_FW6_5: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_FW6_5: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_2805_5: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_2805_5: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_2805_5: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_2805_5: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_TM1914_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_TM1914_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_TM1914_3: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_TM1914_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_SM16825_5: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_SM16825_5: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_SM16825_5: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_SM16825_5: size = (static_cast(busPtr))->PixelsSize(); break; + #endif + #ifdef ARDUINO_ARCH_ESP32 + // RMT buses + case I_32_RN_NEO_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_NEO_4: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_400_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_TM1_4: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_TM2_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_UCS_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_UCS_4: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_APA106_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_FW6_5: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_2805_5: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_TM1914_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_SM16825_5: size = (static_cast(busPtr))->PixelsSize()*2; break; + // I2S1 bus or paralell buses + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_NEO_4: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_400_3: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_TM1_4: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_TM2_3: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_UCS_3: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_UCS_4: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_APA106_3: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_FW6_5: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_2805_5: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_TM1914_3: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_SM16825_5: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + #endif + #endif + case I_HS_DOT_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_SS_DOT_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_HS_LPD_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_SS_LPD_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_HS_LPO_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_SS_LPO_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_HS_WS1_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_SS_WS1_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_HS_P98_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_SS_P98_3: size = (static_cast(busPtr))->PixelsSize(); break; + } + return size; + } + //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) { if (!Bus::isDigital(busType)) return I_NONE; @@ -1372,26 +1352,33 @@ class PolyBus { uint8_t offset = 0; // 0 = RMT (num 1-8), 1 = I2S0 (used by Audioreactive), 2 = I2S1 #if defined(CONFIG_IDF_TARGET_ESP32S2) // ESP32-S2 only has 4 RMT channels - if (num > 4) return I_NONE; - if (num > 3) offset = 1; // only one I2S (use last to allow Audioreactive) + 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 > 3) offset = 1; // only one I2S0 (use last to allow Audioreactive) + } #elif defined(CONFIG_IDF_TARGET_ESP32C3) // On ESP32-C3 only the first 2 RMT channels are usable for transmitting if (num > 1) return I_NONE; //if (num > 1) offset = 1; // I2S not supported yet (only 1 I2S) #elif defined(CONFIG_IDF_TARGET_ESP32S3) // On ESP32-S3 only the first 4 RMT channels are usable for transmitting - if (num > 3) return I_NONE; - //if (num > 3) offset = num -4; // I2S not supported yet + if (_useParallelI2S) { + 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 - // standard ESP32 has 8 RMT and 2 I2S channels - if (useParallelI2S) { - if (num > 16) return I_NONE; - if (num < 8) offset = 2; // prefer 8 parallel I2S1 channels - if (num == 16) offset = 1; + // standard ESP32 has 8 RMT and x1/x8 I2S1 channels + if (_useParallelI2S) { + if (num > 15) return I_NONE; + if (num < 8) offset = 1; // prefer 8 parallel I2S1 channels } else { if (num > 9) return I_NONE; - if (num > 8) offset = 1; - if (num == 0) offset = 2; // prefer I2S1 for 1st bus (less flickering but more RAM needed) + if (num == 0) offset = 1; // prefer I2S1 for 1st bus (less flickering but more RAM needed) } #endif switch (busType) { diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 38e804ed9..e4536156c 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -118,6 +118,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { Bus::setCCTBlend(strip.cctBlending); strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS 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 // 2D Matrix Settings @@ -162,34 +165,6 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { DEBUG_PRINTF_P(PSTR("Heap before buses: %d\n"), ESP.getFreeHeap()); int s = 0; // bus iterator 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) { if (s >= WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES) break; @@ -220,24 +195,12 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { maMax = 0; } 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); - 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() - } + + 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() 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 @@ -823,6 +786,9 @@ void serializeConfig() { hw_led["fps"] = strip.getTargetFps(); hw_led[F("rgbwm")] = Bus::getGlobalAWMode(); // global auto white mode override 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 // 2D Matrix Settings diff --git a/wled00/const.h b/wled00/const.h index 928b150da..640d2d8f6 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -59,19 +59,19 @@ #define WLED_MIN_VIRTUAL_BUSSES 3 #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) - #define WLED_MAX_BUSSES 7 // will allow 5 digital & 2 analog RGB - #define WLED_MAX_DIGITAL_CHANNELS 5 + #define WLED_MAX_BUSSES 14 // will allow 12 digital & 2 analog RGB + #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 + #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 4 #else // 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_DIGITAL_CHANNELS 17 + #define WLED_MAX_BUSSES 19 // will allow 16 digital & 3 analog RGB + #define WLED_MAX_DIGITAL_CHANNELS 16 // x1/x8 I2S1 + x8 RMT //#define WLED_MAX_ANALOG_CHANNELS 16 #define WLED_MIN_VIRTUAL_BUSSES 4 #endif diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 956cf7d90..86a15cde9 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -42,10 +42,10 @@ if (loc) d.Sf.action = getURL('/settings/leds'); } 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) - maxD = d; // maxD - max digital channels (can be changed if using ESP32 parallel I2S) - maxA = a; // maxA - max analog channels - maxV = v; // maxV - min virtual buses + oMaxB = maxB = b; // maxB - max buses (can be changed if using ESP32 parallel I2S): 20 - ESP32, 14 - S3/S2, 6 - C3, 4 - 8266 + maxD = d; // maxD - max digital channels (can be changed if using ESP32 parallel I2S): 17 - ESP32, 12 - S3/S2, 2 - C3, 3 - 8266 + maxA = a; // maxA - max analog channels: 16 - ESP32, 8 - S3/S2, 6 - C3, 5 - 8266 + maxV = v; // maxV - min virtual buses: 4 - ESP32/S3, 3 - S2/C3, 2 - ESP8266 maxPB = p; // maxPB - max LEDs per bus maxM = m; // maxM - max LED memory maxL = l; // maxL - max LEDs (will serve to determine ESP >1664 == ESP32) @@ -250,6 +250,7 @@ } // enable/disable LED fields + let dC = 0; // count of digital buses (for parallel I2S) let LTs = d.Sf.querySelectorAll("#mLC select[name^=LT]"); LTs.forEach((s,i)=>{ 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 t = parseInt(s.value); memu += getMem(t, n); // calc memory + dC += (isDig(t) && !isD2P(t)); setPinConfig(n,t); gId("abl"+n).style.display = (!abl || !isDig(t)) ? "none" : "inline"; // show/hide individual ABL settings if (change) { // did we change LED type? @@ -295,8 +297,7 @@ // do we have a led count field if (nm=="LC") { 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 if (c) { let s = parseInt(gId("ls"+n).value); //start value @@ -350,6 +351,17 @@ else LC.style.color = d.ro_gpio.some((e)=>e==parseInt(LC.value)) ? "orange" : "#fff"; } }); + const S2 = (oMaxB == 14) && (maxV == 3); + const S3 = (oMaxB == 14) && (maxV == 4); + 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 enPPL(sDI); @@ -789,6 +801,7 @@ Swap:
Make a segment for each output:
Custom bus start indices:
Use global LED buffer:
diff --git a/wled00/set.cpp b/wled00/set.cpp index 160eb48f0..d4b6f5475 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -139,6 +139,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) Bus::setGlobalAWMode(request->arg(F("AW")).toInt()); strip.setTargetFps(request->arg(F("FR")).toInt()); useGlobalLedBuffer = request->hasArg(F("LD")); + #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) + useParallelI2S = request->hasArg(F("PR")); + #endif bool busesChanged = false; for (int s = 0; s < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; s++) { diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 1f978a39b..2967c067f 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -179,46 +179,7 @@ void WLED::loop() DEBUG_PRINTLN(F("Re-init busses.")); bool aligned = strip.checkSegmentAlignment(); //see if old segments match old bus(ses) BusManager::removeAll(); - 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 (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 + strip.finalizeInit(); // will create buses and also load default ledmap if present BusManager::setBrightness(bri); // fix re-initialised bus' brightness #4005 if (aligned) strip.makeAutoSegments(); else strip.fixInvalidSegments(); @@ -563,6 +524,7 @@ void WLED::beginStrip() strip.makeAutoSegments(); strip.setBrightness(0); strip.setShowCallback(handleOverlayDraw); + doInitBusses = false; if (turnOnAtBoot) { if (briS > 0) bri = briS; diff --git a/wled00/wled.h b/wled00/wled.h index d0cee80d2..4459fe6de 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -367,7 +367,7 @@ WLED_GLOBAL bool noWifiSleep _INIT(false); WLED_GLOBAL bool force802_3g _INIT(false); #endif // WLED_SAVE_RAM #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); #else WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_19_5dBm); @@ -394,6 +394,9 @@ WLED_GLOBAL byte bootPreset _INIT(0); // save preset to load WLED_GLOBAL bool useGlobalLedBuffer _INIT(false); // double buffering disabled on ESP8266 #else 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 #ifdef WLED_USE_IC_CCT WLED_GLOBAL bool cctICused _INIT(true); // CCT IC used (Athom 15W bulbs) diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 2a19cdfab..79ebf6785 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -289,6 +289,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) printSetFormValue(settingsScript,PSTR("FR"),strip.getTargetFps()); printSetFormValue(settingsScript,PSTR("AW"),Bus::getGlobalAWMode()); printSetFormCheckbox(settingsScript,PSTR("LD"),useGlobalLedBuffer); + printSetFormCheckbox(settingsScript,PSTR("PR"),BusManager::hasParallelOutput()); // get it from bus manager not global variable unsigned sumMa = 0; for (int s = 0; s < BusManager::getNumBusses(); s++) {