diff --git a/CHANGELOG.md b/CHANGELOG.md index 2aabf97f..7cbda3f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ ### Development versions after 0.11.1 release +#### Build 2102050 + +- Version bump to 0.12.0-a0 "Hikari" +- Added FPS indication in info +- Bumped max outputs from 7 to 10 busses for ESP32 + +#### Build 2101310 + +- First alpha configurable multipin + #### Build 2101130 - Added color transitions for all segments and slots and for segment brightness diff --git a/package.json b/package.json index ba3add2f..b9269cfd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wled", - "version": "0.11.1", + "version": "0.12.0-a0", "description": "Tools for WLED project", "main": "tools/cdata.js", "directories": { diff --git a/platformio.ini b/platformio.ini index 4c78f09a..a6159ac5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -12,7 +12,7 @@ default_envs = travis_esp8266, travis_esp32 # Release binaries -; default_envs = nodemcuv2, esp01_1m_full, esp32dev, custom_WS2801, custom_APA102, custom_LEDPIN_16, custom_LEDPIN_4, custom_LEDPIN_3, custom32_LEDPIN_16, custom32_APA102 +; default_envs = nodemcuv2, esp01_1m_full, esp32dev # Single binaries (uncomment your board) ; default_envs = nodemcuv2 diff --git a/tools/cdata.js b/tools/cdata.js index 34f37255..201193f6 100644 --- a/tools/cdata.js +++ b/tools/cdata.js @@ -398,6 +398,14 @@ const char PAGE_dmxmap[] PROGMEM = R"=====()====="; method: "plaintext", filter: "html-minify", }, + { + file: "liveviewws.htm", + name: "PAGE_liveviewws", + prepend: "=====(", + append: ")=====", + method: "plaintext", + filter: "html-minify", + }, { file: "404.htm", name: "PAGE_404", diff --git a/usermods/BME280_v2/README.md b/usermods/BME280_v2/README.md new file mode 100644 index 00000000..216ca630 --- /dev/null +++ b/usermods/BME280_v2/README.md @@ -0,0 +1,40 @@ +Hello! I have written a v2 usermod for the BME280/BMP280 sensor based on the [existing v1 usermod](https://github.com/Aircoookie/WLED/blob/master/usermods/Wemos_D1_mini%2BWemos32_mini_shield/usermod_bme280.cpp). It is not just a refactor, there are many changes which I made to fit my use case, and I hope they will fit the use cases of others as well! Most notably, this usermod is *just* for the BME280 and does not control a display like in the v1 usermod designed for the WeMos shield. + +- Requires libraries `BME280@~3.0.0` (by [finitespace](https://github.com/finitespace/BME280)) and `Wire`. Please add these under `lib_deps` in your `platform.ini` (or `platform_override.ini`). +- Data is published over MQTT so make sure you've enabled the MQTT sync interface. +- This usermod also writes to serial (GPIO1 on ESP8266). Please make sure nothing else listening on the serial TX pin of your board will get confused by log messages! + +To enable, compile with `USERMOD_BME280` defined (i.e. `platformio_override.ini`) +```ini +build_flags = + ${common.build_flags_esp8266} + -D USERMOD_BME280 +``` +or define `USERMOD_BME280` in `my_config.h` +```c++ +#define USERMOD_BME280 +``` + +Changes include: +- Adjustable measure intervals + - Temperature and pressure have separate intervals due to pressure not frequently changing at any constant altitude +- Adjustment of number of decimal places in published sensor values + - Separate adjustment for temperature, humidity and pressure values + - Values are rounded to the specified number of decimal places +- Pressure measured in units of hPa instead of Pa +- Calculation of heat index (apparent temperature) and dew point + - These, along with humidity measurements, are disabled if the sensor is a BMP280 +- 16x oversampling of sensor during measurement +- Values are only published if they are different from the previous value +- Values are published on startup (continually until the MQTT broker acknowledges a successful publication) + +Adjustments are made through preprocessor definitions at the start of the class definition. + +MQTT topics are as follows: +Measurement type | MQTT topic +--- | --- +Temperature | `/temperature` +Humidity | `/humidity` +Pressure | `/pressure` +Heat index | `/heat_index` +Dew point | `/dew_point` \ No newline at end of file diff --git a/usermods/BME280_v2/usermod_bme280.h b/usermods/BME280_v2/usermod_bme280.h new file mode 100644 index 00000000..80a31a4f --- /dev/null +++ b/usermods/BME280_v2/usermod_bme280.h @@ -0,0 +1,212 @@ +#pragma once + +#include "wled.h" +#include +#include +#include // BME280 sensor +#include // BME280 extended measurements + +class UsermodBME280 : public Usermod +{ +private: +// User-defined configuration +#define Celsius // Show temperature mesaurement in Celcius. Comment out for Fahrenheit +#define TemperatureDecimals 1 // Number of decimal places in published temperaure values +#define HumidityDecimals 0 // Number of decimal places in published humidity values +#define PressureDecimals 2 // Number of decimal places in published pressure values +#define TemperatureInterval 5 // Interval to measure temperature (and humidity, dew point if available) in seconds +#define PressureInterval 300 // Interval to measure pressure in seconds + +// Sanity checks +#if !defined(TemperatureDecimals) || TemperatureDecimals < 0 + #define TemperatureDecimals 0 +#endif +#if !defined(HumidityDecimals) || HumidityDecimals < 0 + #define HumidityDecimals 0 +#endif +#if !defined(PressureDecimals) || PressureDecimals < 0 + #define PressureDecimals 0 +#endif +#if !defined(TemperatureInterval) || TemperatureInterval < 0 + #define TemperatureInterval 1 +#endif +#if !defined(PressureInterval) || PressureInterval < 0 + #define PressureInterval TemperatureInterval +#endif + +#ifdef ARDUINO_ARCH_ESP32 // ESP32 boards + uint8_t SCL_PIN = 22; + uint8_t SDA_PIN = 21; +#else // ESP8266 boards + uint8_t SCL_PIN = 5; + uint8_t SDA_PIN = 4; + //uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8 +#endif + + // BME280 sensor settings + BME280I2C::Settings settings{ + BME280::OSR_X16, // Temperature oversampling x16 + BME280::OSR_X16, // Humidity oversampling x16 + BME280::OSR_X16, // Pressure oversampling x16 + // Defaults + BME280::Mode_Forced, + BME280::StandbyTime_1000ms, + BME280::Filter_Off, + BME280::SpiEnable_False, + BME280I2C::I2CAddr_0x76 // I2C address. I2C specific. Default 0x76 + }; + + BME280I2C bme{settings}; + + uint8_t SensorType; + + // Measurement timers + long timer; + long lastTemperatureMeasure = 0; + long lastPressureMeasure = 0; + + // Current sensor values + float SensorTemperature; + float SensorHumidity; + float SensorHeatIndex; + float SensorDewPoint; + float SensorPressure; + // Track previous sensor values + float lastTemperature; + float lastHumidity; + float lastHeatIndex; + float lastDewPoint; + float lastPressure; + + // Store packet IDs of MQTT publications + uint16_t mqttTemperaturePub = 0; + uint16_t mqttPressurePub = 0; + + void UpdateBME280Data(int SensorType) + { + float _temperature, _humidity, _pressure; + #ifdef Celsius + BME280::TempUnit tempUnit(BME280::TempUnit_Celsius); + EnvironmentCalculations::TempUnit envTempUnit(EnvironmentCalculations::TempUnit_Celsius); + #else + BME280::TempUnit tempUnit(BME280::TempUnit_Fahrenheit); + EnvironmentCalculations::TempUnit envTempUnit(EnvironmentCalculations::TempUnit_Fahrenheit); + #endif + BME280::PresUnit presUnit(BME280::PresUnit_hPa); + + bme.read(_pressure, _temperature, _humidity, tempUnit, presUnit); + + SensorTemperature = _temperature; + SensorHumidity = _humidity; + SensorPressure = _pressure; + if (SensorType == 1) + { + SensorHeatIndex = EnvironmentCalculations::HeatIndex(_temperature, _humidity, envTempUnit); + SensorDewPoint = EnvironmentCalculations::DewPoint(_temperature, _humidity, envTempUnit); + } + } + +public: + void setup() + { + Wire.begin(SDA_PIN, SCL_PIN); + + if (!bme.begin()) + { + SensorType = 0; + Serial.println("Could not find BME280I2C sensor!"); + } + else + { + switch (bme.chipModel()) + { + case BME280::ChipModel_BME280: + SensorType = 1; + Serial.println("Found BME280 sensor! Success."); + break; + case BME280::ChipModel_BMP280: + SensorType = 2; + Serial.println("Found BMP280 sensor! No Humidity available."); + break; + default: + SensorType = 0; + Serial.println("Found UNKNOWN sensor! Error!"); + } + } + } + + void loop() + { + // BME280 sensor MQTT publishing + // Check if sensor present and MQTT Connected, otherwise it will crash the MCU + if (SensorType != 0 && mqtt != nullptr) + { + // Timer to fetch new temperature, humidity and pressure data at intervals + timer = millis(); + + if (timer - lastTemperatureMeasure >= TemperatureInterval * 1000 || mqttTemperaturePub == 0) + { + lastTemperatureMeasure = timer; + + UpdateBME280Data(SensorType); + + float Temperature = roundf(SensorTemperature * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals); + float Humidity, HeatIndex, DewPoint; + + // If temperature has changed since last measure, create string populated with device topic + // from the UI and values read from sensor, then publish to broker + if (Temperature != lastTemperature) + { + String topic = String(mqttDeviceTopic) + "/temperature"; + mqttTemperaturePub = mqtt->publish(topic.c_str(), 0, false, String(Temperature, TemperatureDecimals).c_str()); + } + + lastTemperature = Temperature; // Update last sensor temperature for next loop + + if (SensorType == 1) // Only if sensor is a BME280 + { + Humidity = roundf(SensorHumidity * pow(10, HumidityDecimals)) / pow(10, HumidityDecimals); + HeatIndex = roundf(SensorHeatIndex * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals); + DewPoint = roundf(SensorDewPoint * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals); + + if (Humidity != lastHumidity) + { + String topic = String(mqttDeviceTopic) + "/humidity"; + mqtt->publish(topic.c_str(), 0, false, String(Humidity, HumidityDecimals).c_str()); + } + + if (HeatIndex != lastHeatIndex) + { + String topic = String(mqttDeviceTopic) + "/heat_index"; + mqtt->publish(topic.c_str(), 0, false, String(HeatIndex, TemperatureDecimals).c_str()); + } + + if (DewPoint != lastDewPoint) + { + String topic = String(mqttDeviceTopic) + "/dew_point"; + mqtt->publish(topic.c_str(), 0, false, String(DewPoint, TemperatureDecimals).c_str()); + } + + lastHumidity = Humidity; + lastHeatIndex = HeatIndex; + lastDewPoint = DewPoint; + } + } + + if (timer - lastPressureMeasure >= PressureInterval * 1000 || mqttPressurePub == 0) + { + lastPressureMeasure = timer; + + float Pressure = roundf(SensorPressure * pow(10, PressureDecimals)) / pow(10, PressureDecimals); + + if (Pressure != lastPressure) + { + String topic = String(mqttDeviceTopic) + "/pressure"; + mqttPressurePub = mqtt->publish(topic.c_str(), 0, true, String(Pressure, PressureDecimals).c_str()); + } + + lastPressure = Pressure; + } + } + } +}; \ No newline at end of file diff --git a/usermods/Temperature/usermod_temperature.h b/usermods/Temperature/usermod_temperature.h index d72be934..1ce0322e 100644 --- a/usermods/Temperature/usermod_temperature.h +++ b/usermods/Temperature/usermod_temperature.h @@ -5,11 +5,13 @@ #include //DS18B20 //Pin defaults for QuinLed Dig-Uno +#ifndef TEMPERATURE_PIN #ifdef ARDUINO_ARCH_ESP32 #define TEMPERATURE_PIN 18 #else //ESP8266 boards #define TEMPERATURE_PIN 14 #endif +#endif // the frequency to check temperature, 1 minute #ifndef USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL @@ -58,6 +60,7 @@ class UsermodTemperature : public Usermod { } void getTemperature() { + if (strip.isUpdating()) return; #ifdef USERMOD_DALLASTEMPERATURE_CELSIUS temperature = sensor.getTempC(sensorDeviceAddress); #else @@ -80,30 +83,28 @@ class UsermodTemperature : public Usermod { disabled = !sensor.getAddress(sensorDeviceAddress, 0); if (!disabled) { - DEBUG_PRINTLN("Dallas Temperature found"); + DEBUG_PRINTLN(F("Dallas Temperature found")); // set the resolution for this specific device sensor.setResolution(sensorDeviceAddress, 9, true); // do not block waiting for reading - sensor.setWaitForConversion(false); + sensor.setWaitForConversion(false); + // allocate pin & prevent other use + if (!pinManager.allocatePin(TEMPERATURE_PIN,false)) + disabled = true; } else { - DEBUG_PRINTLN("Dallas Temperature not found"); + DEBUG_PRINTLN(F("Dallas Temperature not found")); } } void loop() { - if (disabled) { - return; - } + if (disabled || strip.isUpdating()) return; unsigned long now = millis(); // check to see if we are due for taking a measurement // lastMeasurement will not be updated until the conversion // is complete the the reading is finished - if (now - lastMeasurement < USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL) - { - return; - } + if (now - lastMeasurement < USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL) return; // we are due for a measurement, if we are not already waiting // for a conversion to complete, then make a new request for temps @@ -125,7 +126,7 @@ class UsermodTemperature : public Usermod { // dont publish super low temperature as the graph will get messed up // the DallasTemperature library returns -127C or -196.6F when problem // reading the sensor - strcat(subuf, "/temperature"); + strcat_P(subuf, PSTR("/temperature")); mqtt->publish(subuf, 0, true, String(temperature).c_str()); } else { // publish something else to indicate status? @@ -136,34 +137,32 @@ class UsermodTemperature : public Usermod { void addToJsonInfo(JsonObject& root) { // dont add temperature to info if we are disabled - if (disabled) { - return; - } + if (disabled) return; - JsonObject user = root["u"]; - if (user.isNull()) user = root.createNestedObject("u"); + JsonObject user = root[F("u")]; + if (user.isNull()) user = root.createNestedObject(F("u")); - JsonArray temp = user.createNestedArray("Temperature"); + JsonArray temp = user.createNestedArray(F("Temperature")); if (!getTemperatureComplete) { // if we haven't read the sensor yet, let the user know // that we are still waiting for the first measurement temp.add((USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT - millis()) / 1000); - temp.add(" sec until read"); + temp.add(F(" sec until read")); return; } if (temperature <= -100) { temp.add(0); - temp.add(" Sensor Error!"); + temp.add(F(" Sensor Error!")); return; } temp.add(temperature); #ifdef USERMOD_DALLASTEMPERATURE_CELSIUS - temp.add("°C"); + temp.add(F("°C")); #else - temp.add("°F"); + temp.add(F("°F")); #endif } diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 786ea692..3fdfcff1 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -1257,7 +1257,7 @@ uint16_t WS2812FX::police_base(uint32_t color1, uint32_t color2, bool all) for (uint16_t i = idexB; i < idexR; i++) setPixelColor(i, color2); } } else { //regular dot-only mode - uint8_t size = 1 + SEGMENT.intensity >> 3; + uint8_t size = 1 + (SEGMENT.intensity >> 3); if (size > SEGLEN/2) size = 1+ SEGLEN/2; for (uint8_t i=0; i <= size; i++) { setPixelColor(idexR+i, color1); diff --git a/wled00/FX.h b/wled00/FX.h index 589a7005..b681a079 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -29,12 +29,6 @@ #ifndef WS2812FX_h #define WS2812FX_h -#ifdef ESP32_MULTISTRIP - #include "../usermods/esp32_multistrip/NpbWrapper.h" -#else - #include "NpbWrapper.h" -#endif - #include "const.h" #define FASTLED_INTERNAL //remove annoying pragma messages @@ -586,12 +580,11 @@ class WS2812FX { ablMilliampsMax = 850; currentMilliamps = 0; timebase = 0; - bus = new NeoPixelWrapper(); resetSegments(); } void - init(bool supportWhite, uint16_t countPixels, bool skipFirst), + finalizeInit(bool supportWhite, uint16_t countPixels, bool skipFirst), service(void), blur(uint8_t), fill(uint32_t), @@ -631,6 +624,8 @@ class WS2812FX { paletteFade = 0, paletteBlend = 0, milliampsPerLed = 55, +// getStripType(uint8_t strip=0), +// setStripType(uint8_t type, uint8_t strip=0), getBrightness(void), getMode(void), getSpeed(void), @@ -645,12 +640,19 @@ class WS2812FX { get_random_wheel_index(uint8_t); int8_t +// setStripPin(uint8_t strip, int8_t pin), +// getStripPin(uint8_t strip=0), +// setStripPinClk(uint8_t strip, int8_t pin), +// getStripPinClk(uint8_t strip=0), tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec); uint16_t ablMilliampsMax, currentMilliamps, - triwave16(uint16_t); +// setStripLen(uint8_t strip, uint16_t len), +// getStripLen(uint8_t strip=0), + triwave16(uint16_t), + getFps(); uint32_t now, @@ -796,8 +798,6 @@ class WS2812FX { mode_dynamic_smooth(void); private: - NeoPixelWrapper *bus; - uint32_t crgb_to_col(CRGB fastled); CRGB col_to_crgb(uint32_t); CRGBPalette16 currentPalette; @@ -809,11 +809,12 @@ class WS2812FX { uint16_t _usedSegmentData = 0; uint16_t _transitionDur = 750; + uint16_t _cumulativeFps = 2; + void load_gradient_palette(uint8_t); void handle_palette(void); bool - shouldStartBus = false, _useRgbw = false, _skipFirstMode, _triggered; @@ -861,12 +862,6 @@ class WS2812FX { uint32_t _colors_t[3]; uint8_t _bri_t; - #ifdef WLED_USE_ANALOG_LEDS - uint32_t _analogLastShow = 0; - RgbwColor _analogLastColor = 0; - uint8_t _analogLastBri = 0; - #endif - uint8_t _segment_index = 0; uint8_t _segment_index_palette_last = 99; segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 24 bytes per element diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index aef500ce..aa1f88a6 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -47,7 +47,8 @@ 19, 18, 17, 16, 15, 20, 21, 22, 23, 24, 29, 28, 27, 26, 25] */ -void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst) +//do not call this method from system context (network callback) +void WS2812FX::finalizeInit(bool supportWhite, uint16_t countPixels, bool skipFirst) { if (supportWhite == _useRgbw && countPixels == _length && _skipFirstMode == skipFirst) return; RESET_RUNTIME; @@ -55,21 +56,35 @@ void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst) _length = countPixels; _skipFirstMode = skipFirst; - uint8_t ty = 1; - if (supportWhite) ty = 2; _lengthRaw = _length; if (_skipFirstMode) { _lengthRaw += LED_SKIP_AMOUNT; } + //if busses failed to load, add default (FS issue...) + if (busses.getNumBusses() == 0) { + uint8_t defPin[] = {LEDPIN}; + BusConfig defCfg = BusConfig(TYPE_WS2812_RGB, defPin, 0, _lengthRaw, COL_ORDER_GRB); + busses.add(defCfg); + } + deserializeMap(); - bus->Begin((NeoPixelType)ty, _lengthRaw); - _segments[0].start = 0; _segments[0].stop = _length; setBrightness(_brightness); + + #ifdef ESP8266 + for (uint8_t i = 0; i < busses.getNumBusses(); i++) { + Bus* b = busses.getBus(i); + if ((!IS_DIGITAL(b->getType()) || IS_2PIN(b->getType()))) continue; + uint8_t pins[5]; + b->getPins(pins); + BusDigital* bd = static_cast(b); + if (pins[0] == 3) bd->reinit(); + } + #endif } void WS2812FX::service() { @@ -168,19 +183,17 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) } } - RgbwColor col; - col.R = r; col.G = g; col.B = b; col.W = w; - uint16_t skip = _skipFirstMode ? LED_SKIP_AMOUNT : 0; if (SEGLEN) {//from segment //color_blend(getpixel, col, _bri_t); (pseudocode for future blending of segments) if (_bri_t < 255) { - col.R = scale8(col.R, _bri_t); - col.G = scale8(col.G, _bri_t); - col.B = scale8(col.B, _bri_t); - col.W = scale8(col.W, _bri_t); + r = scale8(r, _bri_t); + g = scale8(g, _bri_t); + b = scale8(b, _bri_t); + w = scale8(w, _bri_t); } + uint32_t col = ((w << 24) | (r << 16) | (g << 8) | (b)); /* Set all the pixels in the group, ensuring _skipFirstMode is honored */ bool reversed = reverseMode ^ IS_REVERSE; @@ -192,12 +205,12 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) if (reverseMode) indexSetRev = REV(indexSet); if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet]; if (indexSetRev >= SEGMENT.start && indexSetRev < SEGMENT.stop) { - bus->SetPixelColor(indexSet + skip, col); + busses.setPixelColor(indexSet + skip, col); if (IS_MIRROR) { //set the corresponding mirrored pixel if (reverseMode) { - bus->SetPixelColor(REV(SEGMENT.start) - indexSet + skip + REV(SEGMENT.stop) + 1, col); + busses.setPixelColor(REV(SEGMENT.start) - indexSet + skip + REV(SEGMENT.stop) + 1, col); } else { - bus->SetPixelColor(SEGMENT.stop - indexSet + skip + SEGMENT.start - 1, col); + busses.setPixelColor(SEGMENT.stop - indexSet + skip + SEGMENT.start - 1, col); } } } @@ -205,11 +218,13 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) } else { //live data, etc. if (reverseMode) i = REV(i); if (i < customMappingSize) i = customMappingTable[i]; - bus->SetPixelColor(i + skip, col); + + uint32_t col = ((w << 24) | (r << 16) | (g << 8) | (b)); + busses.setPixelColor(i + skip, col); } if (skip && i == 0) { for (uint16_t j = 0; j < skip; j++) { - bus->SetPixelColor(j, RgbwColor(0, 0, 0, 0)); + busses.setPixelColor(j, BLACK); } } } @@ -260,7 +275,7 @@ void WS2812FX::show(void) { for (uint16_t i = 0; i < _length; i++) //sum up the usage of each LED { - RgbwColor c = bus->GetPixelColorRaw(i); + RgbwColor c = busses.getPixelColor(i); if(useWackyWS2815PowerModel) { @@ -289,25 +304,30 @@ void WS2812FX::show(void) { uint16_t scaleI = scale * 255; uint8_t scaleB = (scaleI > 255) ? 255 : scaleI; uint8_t newBri = scale8(_brightness, scaleB); - bus->SetBrightness(newBri); + busses.setBrightness(newBri); currentMilliamps = (powerSum0 * newBri) / puPerMilliamp; } else { currentMilliamps = powerSum / puPerMilliamp; - bus->SetBrightness(_brightness); + busses.setBrightness(_brightness); } currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate currentMilliamps += _length; //add standby power back to estimate } else { currentMilliamps = 0; - bus->SetBrightness(_brightness); + busses.setBrightness(_brightness); } // some buses send asynchronously and this method will return before // all of the data has been sent. // See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods - bus->Show(); - _lastShow = millis(); + busses.show(); + unsigned long now = millis(); + unsigned long diff = now - _lastShow; + uint16_t fpsCurr = 200; + if (diff > 0) fpsCurr = 1000 / diff; + _cumulativeFps = (3 * _cumulativeFps + fpsCurr) >> 2; + _lastShow = now; } /** @@ -315,7 +335,16 @@ void WS2812FX::show(void) { * On some hardware (ESP32), strip updates are done asynchronously. */ bool WS2812FX::isUpdating() { - return !bus->CanShow(); + return !busses.canAllShow(); +} + +/** + * Returns the refresh rate of the LED strip. Useful for finding out whether a given setup is fast enough. + * Only updates on show() or is set to 0 fps if last show is more than 2 secs ago, so accurary varies + */ +uint16_t WS2812FX::getFps() { + if (millis() - _lastShow > 2000) return 0; + return _cumulativeFps +1; } /** @@ -417,17 +446,6 @@ void WS2812FX::setBrightness(uint8_t b) { { _segments[i].setOption(SEG_OPTION_FREEZE, false); } - #if LEDPIN == LED_BUILTIN - shouldStartBus = true; - #endif - } else { - #if LEDPIN == LED_BUILTIN - if (shouldStartBus) { - shouldStartBus = false; - const uint8_t ty = _useRgbw ? 2 : 1; - bus->Begin((NeoPixelType)ty, _lengthRaw); - } - #endif } if (SEGENV.next_time > millis() + 22 && millis() - _lastShow > MIN_SHOW_DELAY) show();//apply brightness change immediately if no refresh soon } @@ -485,7 +503,7 @@ uint32_t WS2812FX::getPixelColor(uint16_t i) if (i >= _lengthRaw) return 0; - return bus->GetPixelColorRgbw(i); + return busses.getPixelColor(i); } WS2812FX::Segment& WS2812FX::getSegment(uint8_t id) { @@ -505,12 +523,13 @@ uint32_t WS2812FX::getLastShow(void) { return _lastShow; } +//TODO these need to be on a per-strip basis uint8_t WS2812FX::getColorOrder(void) { - return bus->GetColorOrder(); + return COL_ORDER_GRB; } void WS2812FX::setColorOrder(uint8_t co) { - bus->SetColorOrder(co); + //bus->SetColorOrder(co); } void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing) { @@ -962,44 +981,6 @@ bool WS2812FX::segmentsAreIdentical(Segment* a, Segment* b) return true; } -#ifdef WLED_USE_ANALOG_LEDS -void WS2812FX::setRgbwPwm(void) { - uint32_t nowUp = millis(); // Be aware, millis() rolls over every 49 days - if (nowUp - _analogLastShow < MIN_SHOW_DELAY) return; - - _analogLastShow = nowUp; - - RgbwColor c; - uint32_t col = bus->GetPixelColorRgbw(PWM_INDEX); - c.R = col >> 16; c.G = col >> 8; c.B = col; c.W = col >> 24; - - byte b = getBrightness(); - if (c == _analogLastColor && b == _analogLastBri) return; - - // check color values for Warm / Cold white mix (for RGBW) // EsplanexaDevice.cpp - #ifdef WLED_USE_5CH_LEDS - if (c.R == 255 && c.G == 255 && c.B == 255 && c.W == 255) { - bus->SetRgbwPwm(0, 0, 0, 0, c.W * b / 255); - } else if (c.R == 127 && c.G == 127 && c.B == 127 && c.W == 255) { - bus->SetRgbwPwm(0, 0, 0, c.W * b / 512, c.W * b / 255); - } else if (c.R == 0 && c.G == 0 && c.B == 0 && c.W == 255) { - bus->SetRgbwPwm(0, 0, 0, c.W * b / 255, 0); - } else if (c.R == 130 && c.G == 90 && c.B == 0 && c.W == 255) { - bus->SetRgbwPwm(0, 0, 0, c.W * b / 255, c.W * b / 512); - } else if (c.R == 255 && c.G == 153 && c.B == 0 && c.W == 255) { - bus->SetRgbwPwm(0, 0, 0, c.W * b / 255, 0); - } else { // not only white colors - bus->SetRgbwPwm(c.R * b / 255, c.G * b / 255, c.B * b / 255, c.W * b / 255); - } - #else - bus->SetRgbwPwm(c.R * b / 255, c.G * b / 255, c.B * b / 255, c.W * b / 255); - #endif - _analogLastColor = c; - _analogLastBri = b; -} -#else -void WS2812FX::setRgbwPwm() {} -#endif //load custom mapping table from JSON file void WS2812FX::deserializeMap(void) { diff --git a/wled00/NpbWrapper.h b/wled00/NpbWrapper.h deleted file mode 100644 index 7e9b8f59..00000000 --- a/wled00/NpbWrapper.h +++ /dev/null @@ -1,439 +0,0 @@ -//this code is a modified version of https://github.com/Makuna/NeoPixelBus/issues/103 -#ifndef NpbWrapper_h -#define NpbWrapper_h - -//PIN CONFIGURATION -#ifndef LEDPIN -#define LEDPIN 2 //strip pin. Any for ESP32, gpio2 or 3 is recommended for ESP8266 (gpio2/3 are labeled D4/RX on NodeMCU and Wemos) -#endif -//#define USE_APA102 // Uncomment for using APA102 LEDs. -//#define USE_WS2801 // Uncomment for using WS2801 LEDs (make sure you have NeoPixelBus v2.5.6 or newer) -//#define USE_LPD8806 // Uncomment for using LPD8806 -//#define USE_TM1814 // Uncomment for using TM1814 LEDs (make sure you have NeoPixelBus v2.5.7 or newer) -//#define USE_P9813 // Uncomment for using P9813 LEDs (make sure you have NeoPixelBus v2.5.8 or newer) -//#define WLED_USE_ANALOG_LEDS //Uncomment for using "dumb" PWM controlled LEDs (see pins below, default R: gpio5, G: 12, B: 15, W: 13) -//#define WLED_USE_H801 //H801 controller. Please uncomment #define WLED_USE_ANALOG_LEDS as well -//#define WLED_USE_5CH_LEDS //5 Channel H801 for cold and warm white -//#define WLED_USE_BWLT11 -//#define WLED_USE_SHOJO_PCB - -#ifndef BTNPIN -#define BTNPIN 0 //button pin. Needs to have pullup (gpio0 recommended) -#endif - -#ifndef TOUCHPIN -//#define TOUCHPIN T0 //touch pin. Behaves the same as button. ESP32 only. -#endif - -#ifndef IRPIN -#define IRPIN 4 //infrared pin (-1 to disable) MagicHome: 4, H801 Wifi: 0 -#endif - -#ifndef RLYPIN -#define RLYPIN 12 //pin for relay, will be set HIGH if LEDs are on (-1 to disable). Also usable for standby leds, triggers,... -#endif - -#ifndef AUXPIN -#define AUXPIN -1 //debug auxiliary output pin (-1 to disable) -#endif - -#ifndef RLYMDE -#define RLYMDE 1 //mode for relay, 0: LOW if LEDs are on 1: HIGH if LEDs are on -#endif - -//enable color order override for a specific range of the strip -//This can be useful if you want to chain multiple strings with incompatible color order -//#define COLOR_ORDER_OVERRIDE -#define COO_MIN 0 -#define COO_MAX 35 //not inclusive, this would set the override for LEDs 0-34 -#define COO_ORDER COL_ORDER_GRB - -//END CONFIGURATION - -#if defined(USE_APA102) || defined(USE_WS2801) || defined(USE_LPD8806) || defined(USE_P9813) - #ifndef CLKPIN - #define CLKPIN 0 - #endif - #ifndef DATAPIN - #define DATAPIN 2 - #endif - #if BTNPIN == CLKPIN || BTNPIN == DATAPIN - #undef BTNPIN // Deactivate button pin if it conflicts with one of the APA102 pins. - #endif -#endif - -#ifdef WLED_USE_ANALOG_LEDS - //PWM pins - PINs 15,13,12,14 (W2 = 04)are used with H801 Wifi LED Controller - #ifdef WLED_USE_H801 - #define RPIN 15 //R pin for analog LED strip - #define GPIN 13 //G pin for analog LED strip - #define BPIN 12 //B pin for analog LED strip - #define WPIN 14 //W pin for analog LED strip - #define W2PIN 04 //W2 pin for analog LED strip - #undef BTNPIN - #undef IRPIN - #define IRPIN 0 //infrared pin (-1 to disable) MagicHome: 4, H801 Wifi: 0 - #elif defined(WLED_USE_BWLT11) - //PWM pins - to use with BW-LT11 - #define RPIN 12 //R pin for analog LED strip - #define GPIN 4 //G pin for analog LED strip - #define BPIN 14 //B pin for analog LED strip - #define WPIN 5 //W pin for analog LED strip - #elif defined(WLED_USE_SHOJO_PCB) - //PWM pins - to use with Shojo PCB (https://www.bastelbunker.de/esp-rgbww-wifi-led-controller-vbs-edition/) - #define RPIN 14 //R pin for analog LED strip - #define GPIN 4 //G pin for analog LED strip - #define BPIN 5 //B pin for analog LED strip - #define WPIN 15 //W pin for analog LED strip - #define W2PIN 12 //W2 pin for analog LED strip - #elif defined(WLED_USE_PLJAKOBS_PCB) - // PWM pins - to use with esp_rgbww_controller from patrickjahns/pljakobs (https://github.com/pljakobs/esp_rgbww_controller) - #define RPIN 12 //R pin for analog LED strip - #define GPIN 13 //G pin for analog LED strip - #define BPIN 14 //B pin for analog LED strip - #define WPIN 4 //W pin for analog LED strip - #define W2PIN 5 //W2 pin for analog LED strip - #undef IRPIN - #else - //Enable override of Pins by using the platformio_override.ini file - //PWM pins - PINs 5,12,13,15 are used with Magic Home LED Controller - #ifndef RPIN - #define RPIN 5 //R pin for analog LED strip - #endif - #ifndef GPIN - #define GPIN 12 //G pin for analog LED strip - #endif - #ifndef BPIN - #define BPIN 15 //B pin for analog LED strip - #endif - #ifndef WPIN - #define WPIN 13 //W pin for analog LED strip - #endif - #endif - #undef RLYPIN - #define RLYPIN -1 //disable as pin 12 is used by analog LEDs -#endif - -//automatically uses the right driver method for each platform -#ifdef ARDUINO_ARCH_ESP32 - #ifdef USE_APA102 - #define PIXELMETHOD DotStarMethod - #elif defined(USE_WS2801) - #define PIXELMETHOD NeoWs2801Method - #elif defined(USE_LPD8806) - #define PIXELMETHOD Lpd8806Method - #elif defined(USE_TM1814) - #define PIXELMETHOD NeoTm1814Method - #elif defined(USE_P9813) - #define PIXELMETHOD P9813Method - #else - #define PIXELMETHOD NeoEsp32Rmt0Ws2812xMethod - #endif -#else //esp8266 - //autoselect the right method depending on strip pin - #ifdef USE_APA102 - #define PIXELMETHOD DotStarMethod - #elif defined(USE_WS2801) - #define PIXELMETHOD NeoWs2801Method - #elif defined(USE_LPD8806) - #define PIXELMETHOD Lpd8806Method - #elif defined(USE_TM1814) - #define PIXELMETHOD NeoTm1814Method - #elif defined(USE_P9813) - #define PIXELMETHOD P9813Method - #elif LEDPIN == 2 - #define PIXELMETHOD NeoEsp8266Uart1Ws2813Method //if you get an error here, try to change to NeoEsp8266UartWs2813Method or update Neopixelbus - #elif LEDPIN == 3 - #define PIXELMETHOD NeoEsp8266Dma800KbpsMethod - #else - #define PIXELMETHOD NeoEsp8266BitBang800KbpsMethod - #pragma message "Software BitBang will be used because of your selected LED pin. This may cause flicker. Use GPIO 2 or 3 for best results." - #endif -#endif - - -//you can now change the color order in the web settings -#ifdef USE_APA102 - #define PIXELFEATURE3 DotStarBgrFeature - #define PIXELFEATURE4 DotStarLbgrFeature -#elif defined(USE_LPD8806) - #define PIXELFEATURE3 Lpd8806GrbFeature - #define PIXELFEATURE4 Lpd8806GrbFeature -#elif defined(USE_WS2801) - #define PIXELFEATURE3 NeoRbgFeature - #define PIXELFEATURE4 NeoRbgFeature -#elif defined(USE_TM1814) - #define PIXELFEATURE3 NeoWrgbTm1814Feature - #define PIXELFEATURE4 NeoWrgbTm1814Feature -#elif defined(USE_P9813) - #define PIXELFEATURE3 P9813BgrFeature - #define PIXELFEATURE4 NeoGrbwFeature -#else - #define PIXELFEATURE3 NeoGrbFeature - #define PIXELFEATURE4 NeoGrbwFeature -#endif - - -#include -#include "const.h" - -enum NeoPixelType -{ - NeoPixelType_None = 0, - NeoPixelType_Grb = 1, - NeoPixelType_Grbw = 2, - NeoPixelType_End = 3 -}; - -class NeoPixelWrapper -{ -public: - NeoPixelWrapper() : - // initialize each member to null - _pGrb(NULL), - _pGrbw(NULL), - _type(NeoPixelType_None) - { - - } - - ~NeoPixelWrapper() - { - cleanup(); - } - - void Begin(NeoPixelType type, uint16_t countPixels) - { - cleanup(); - _type = type; - - switch (_type) - { - case NeoPixelType_Grb: - #if defined(USE_APA102) || defined(USE_WS2801) || defined(USE_LPD8806) || defined(USE_P9813) - _pGrb = new NeoPixelBrightnessBus(countPixels, CLKPIN, DATAPIN); - #else - _pGrb = new NeoPixelBrightnessBus(countPixels, LEDPIN); - #endif - _pGrb->Begin(); - break; - - case NeoPixelType_Grbw: - #if defined(USE_APA102) || defined(USE_WS2801) || defined(USE_LPD8806) || defined(USE_P9813) - _pGrbw = new NeoPixelBrightnessBus(countPixels, CLKPIN, DATAPIN); - #else - _pGrbw = new NeoPixelBrightnessBus(countPixels, LEDPIN); - #endif - _pGrbw->Begin(); - break; - } - - #ifdef WLED_USE_ANALOG_LEDS - #ifdef ARDUINO_ARCH_ESP32 - ledcSetup(0, 5000, 8); - ledcAttachPin(RPIN, 0); - ledcSetup(1, 5000, 8); - ledcAttachPin(GPIN, 1); - ledcSetup(2, 5000, 8); - ledcAttachPin(BPIN, 2); - if(_type == NeoPixelType_Grbw) - { - ledcSetup(3, 5000, 8); - ledcAttachPin(WPIN, 3); - #ifdef WLED_USE_5CH_LEDS - ledcSetup(4, 5000, 8); - ledcAttachPin(W2PIN, 4); - #endif - } - #else // ESP8266 - //init PWM pins - pinMode(RPIN, OUTPUT); - pinMode(GPIN, OUTPUT); - pinMode(BPIN, OUTPUT); - if(_type == NeoPixelType_Grbw) - { - pinMode(WPIN, OUTPUT); - #ifdef WLED_USE_5CH_LEDS - pinMode(W2PIN, OUTPUT); - #endif - } - analogWriteRange(255); //same range as one RGB channel - analogWriteFreq(880); //PWM frequency proven as good for LEDs - #endif - #endif - } - -#ifdef WLED_USE_ANALOG_LEDS - void SetRgbwPwm(uint8_t r, uint8_t g, uint8_t b, uint8_t w, uint8_t w2=0) - { - #ifdef ARDUINO_ARCH_ESP32 - ledcWrite(0, r); - ledcWrite(1, g); - ledcWrite(2, b); - switch (_type) { - case NeoPixelType_Grb: break; - #ifdef WLED_USE_5CH_LEDS - case NeoPixelType_Grbw: ledcWrite(3, w); ledcWrite(4, w2); break; - #else - case NeoPixelType_Grbw: ledcWrite(3, w); break; - #endif - } - #else // ESP8266 - analogWrite(RPIN, r); - analogWrite(GPIN, g); - analogWrite(BPIN, b); - switch (_type) { - case NeoPixelType_Grb: break; - #ifdef WLED_USE_5CH_LEDS - case NeoPixelType_Grbw: analogWrite(WPIN, w); analogWrite(W2PIN, w2); break; - #else - case NeoPixelType_Grbw: analogWrite(WPIN, w); break; - #endif - } - #endif - } -#endif - - void Show() - { - switch (_type) - { - case NeoPixelType_Grb: _pGrb->Show(); break; - case NeoPixelType_Grbw: _pGrbw->Show(); break; - } - } - - /** - * This will return true if enough time has passed since the last time Show() was called. - * This also means that calling Show() will not cause any undue waiting. If the method for - * the defined bus is hardware that sends asynchronously, then call CanShow() will let - * you know if it has finished sending the data from the last Show(). - */ - bool CanShow() - { - switch (_type) - { - case NeoPixelType_Grb: return _pGrb->CanShow(); - case NeoPixelType_Grbw: return _pGrbw->CanShow(); - default: return true; - } - } - - void SetPixelColor(uint16_t indexPixel, RgbwColor c) - { - RgbwColor col; - - uint8_t co = _colorOrder; - #ifdef COLOR_ORDER_OVERRIDE - if (indexPixel >= COO_MIN && indexPixel < COO_MAX) co = COO_ORDER; - #endif - - //reorder channels to selected order - switch (co) - { - case 0: col.G = c.G; col.R = c.R; col.B = c.B; break; //0 = GRB, default - case 1: col.G = c.R; col.R = c.G; col.B = c.B; break; //1 = RGB, common for WS2811 - case 2: col.G = c.B; col.R = c.R; col.B = c.G; break; //2 = BRG - case 3: col.G = c.R; col.R = c.B; col.B = c.G; break; //3 = RBG - case 4: col.G = c.B; col.R = c.G; col.B = c.R; break; //4 = BGR - default: col.G = c.G; col.R = c.B; col.B = c.R; break; //5 = GBR - } - col.W = c.W; - - switch (_type) { - case NeoPixelType_Grb: { - _pGrb->SetPixelColor(indexPixel, RgbColor(col.R,col.G,col.B)); - } - break; - case NeoPixelType_Grbw: { - #if defined(USE_LPD8806) || defined(USE_WS2801) - _pGrbw->SetPixelColor(indexPixel, RgbColor(col.R,col.G,col.B)); - #else - _pGrbw->SetPixelColor(indexPixel, col); - #endif - } - break; - } - } - - void SetBrightness(byte b) - { - switch (_type) { - case NeoPixelType_Grb: _pGrb->SetBrightness(b); break; - case NeoPixelType_Grbw:_pGrbw->SetBrightness(b); break; - } - } - - void SetColorOrder(byte colorOrder) { - _colorOrder = colorOrder; - } - - uint8_t GetColorOrder() { - return _colorOrder; - } - - RgbwColor GetPixelColorRaw(uint16_t indexPixel) const - { - switch (_type) { - case NeoPixelType_Grb: return _pGrb->GetPixelColor(indexPixel); break; - case NeoPixelType_Grbw: return _pGrbw->GetPixelColor(indexPixel); break; - } - return 0; - } - - // NOTE: Due to feature differences, some support RGBW but the method name - // here needs to be unique, thus GetPixeColorRgbw - uint32_t GetPixelColorRgbw(uint16_t indexPixel) const - { - RgbwColor col(0,0,0,0); - switch (_type) { - case NeoPixelType_Grb: col = _pGrb->GetPixelColor(indexPixel); break; - case NeoPixelType_Grbw: col = _pGrbw->GetPixelColor(indexPixel); break; - } - - uint8_t co = _colorOrder; - #ifdef COLOR_ORDER_OVERRIDE - if (indexPixel >= COO_MIN && indexPixel < COO_MAX) co = COO_ORDER; - #endif - - switch (co) - { - // W G R B - case 0: return ((col.W << 24) | (col.G << 8) | (col.R << 16) | (col.B)); //0 = GRB, default - case 1: return ((col.W << 24) | (col.R << 8) | (col.G << 16) | (col.B)); //1 = RGB, common for WS2811 - case 2: return ((col.W << 24) | (col.B << 8) | (col.R << 16) | (col.G)); //2 = BRG - case 3: return ((col.W << 24) | (col.B << 8) | (col.G << 16) | (col.R)); //3 = RBG - case 4: return ((col.W << 24) | (col.R << 8) | (col.B << 16) | (col.G)); //4 = BGR - case 5: return ((col.W << 24) | (col.G << 8) | (col.B << 16) | (col.R)); //5 = GBR - } - return 0; - } - - uint8_t* GetPixels(void) - { - switch (_type) { - case NeoPixelType_Grb: return _pGrb->Pixels(); break; - case NeoPixelType_Grbw: return _pGrbw->Pixels(); break; - } - return 0; - } - - -private: - NeoPixelType _type; - - // have a member for every possible type - NeoPixelBrightnessBus* _pGrb; - NeoPixelBrightnessBus* _pGrbw; - - byte _colorOrder = 0; - - void cleanup() - { - switch (_type) { - case NeoPixelType_Grb: delete _pGrb ; _pGrb = NULL; break; - case NeoPixelType_Grbw: delete _pGrbw; _pGrbw = NULL; break; - } - } -}; -#endif diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h new file mode 100644 index 00000000..8ed68020 --- /dev/null +++ b/wled00/bus_manager.h @@ -0,0 +1,379 @@ +#ifndef BusManager_h +#define BusManager_h + +/* + * Class for addressing various light types + */ + +#include "const.h" +#include "pin_manager.h" +#include "bus_wrapper.h" +#include + +//temporary struct for passing bus configuration to bus +struct BusConfig { + uint8_t type = TYPE_WS2812_RGB; + uint16_t count = 1; + uint16_t start = 0; + uint8_t colorOrder = COL_ORDER_GRB; + bool reversed = false; + uint8_t pins[5] = {LEDPIN, 255, 255, 255, 255}; + BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false) { + type = busType; count = len; start = pstart; colorOrder = pcolorOrder; reversed = rev; + uint8_t nPins = 1; + if (type > 47) nPins = 2; + else if (type > 41 && type < 46) nPins = NUM_PWM_PINS(type); + for (uint8_t i = 0; i < nPins; i++) pins[i] = ppins[i]; + } +}; + +//parent class of BusDigital and BusPwm +class Bus { + public: + Bus(uint8_t type, uint16_t start) { + _type = type; + _start = start; + }; + + virtual void show() {} + virtual bool canShow() { return true; } + + virtual void setPixelColor(uint16_t pix, uint32_t c) {}; + + virtual void setBrightness(uint8_t b) {}; + + virtual uint32_t getPixelColor(uint16_t pix) { return 0; }; + + virtual void cleanup() {}; + + virtual ~Bus() { //throw the bus under the bus + //Serial.println("Destructor!"); + } + + virtual uint8_t getPins(uint8_t* pinArray) { return 0; } + + uint16_t getStart() { + return _start; + } + + void setStart(uint16_t start) { + _start = start; + } + + virtual uint16_t getLength() { + return 1; + } + + virtual void setColorOrder() {} + + virtual uint8_t getColorOrder() { + return COL_ORDER_RGB; + } + + uint8_t getType() { + return _type; + } + + bool isOk() { + return _valid; + } + + bool reversed = false; + + protected: + uint8_t _type = TYPE_NONE; + uint8_t _bri = 255; + uint16_t _start = 0; + bool _valid = false; +}; + + +class BusDigital : public Bus { + public: + BusDigital(BusConfig &bc, uint8_t nr) : Bus(bc.type, bc.start) { + if (!IS_DIGITAL(bc.type) || !bc.count) return; + _pins[0] = bc.pins[0]; + if (!pinManager.allocatePin(_pins[0])) return; + if (IS_2PIN(bc.type)) { + _pins[1] = bc.pins[1]; + if (!pinManager.allocatePin(_pins[1])) { + cleanup(); return; + } + } + _len = bc.count; + reversed = bc.reversed; + _iType = PolyBus::getI(bc.type, _pins, nr); + if (_iType == I_NONE) return; + _busPtr = PolyBus::create(_iType, _pins, _len); + _valid = (_busPtr != nullptr); + _colorOrder = bc.colorOrder; + //Serial.printf("Successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u)\n",nr, len, type, pins[0],pins[1],_iType); + }; + + void show() { + PolyBus::show(_busPtr, _iType); + } + + bool canShow() { + return PolyBus::canShow(_busPtr, _iType); + } + + void setBrightness(uint8_t b) { + //Fix for turning off onboard LED breaking bus + #ifdef LED_BUILTIN + if (_bri == 0 && b > 0) { + if (_pins[0] == LED_BUILTIN || _pins[1] == LED_BUILTIN) PolyBus::begin(_busPtr, _iType, _pins); + } + #endif + _bri = b; + PolyBus::setBrightness(_busPtr, _iType, b); + } + + void setPixelColor(uint16_t pix, uint32_t c) { + if (reversed) pix = _len - pix -1; + PolyBus::setPixelColor(_busPtr, _iType, pix, c, _colorOrder); + } + + uint32_t getPixelColor(uint16_t pix) { + if (reversed) pix = _len - pix -1; + return PolyBus::getPixelColor(_busPtr, _iType, pix, _colorOrder); + } + + uint8_t getColorOrder() { + return _colorOrder; + } + + uint16_t getLength() { + return _len; + } + + uint8_t getPins(uint8_t* pinArray) { + uint8_t numPins = IS_2PIN(_type) ? 2 : 1; + for (uint8_t i = 0; i < numPins; i++) pinArray[i] = _pins[i]; + return numPins; + } + + void setColorOrder(uint8_t colorOrder) { + if (colorOrder > 5) return; + _colorOrder = colorOrder; + } + + void reinit() { + PolyBus::begin(_busPtr, _iType, _pins); + } + + void cleanup() { + //Serial.println("Digital Cleanup"); + PolyBus::cleanup(_busPtr, _iType); + _iType = I_NONE; + _valid = false; + _busPtr = nullptr; + pinManager.deallocatePin(_pins[0]); + pinManager.deallocatePin(_pins[1]); + } + + ~BusDigital() { + cleanup(); + } + + private: + uint8_t _colorOrder = COL_ORDER_GRB; + uint8_t _pins[2] = {255, 255}; + uint8_t _iType = I_NONE; + uint16_t _len = 0; + void * _busPtr = nullptr; +}; + + +class BusPwm : public Bus { + public: + BusPwm(BusConfig &bc) : Bus(bc.type, bc.start) { + if (!IS_PWM(bc.type)) return; + uint8_t numPins = NUM_PWM_PINS(bc.type); + + #ifdef ESP8266 + analogWriteRange(255); //same range as one RGB channel + analogWriteFreq(WLED_PWM_FREQ_ESP8266); + #else + _ledcStart = pinManager.allocateLedc(numPins); + if (_ledcStart == 255) { //no more free LEDC channels + deallocatePins(); return; + } + #endif + + for (uint8_t i = 0; i < numPins; i++) { + _pins[i] = bc.pins[i]; + if (!pinManager.allocatePin(_pins[i])) { + deallocatePins(); return; + } + #ifdef ESP8266 + pinMode(_pins[i], OUTPUT); + #else + ledcSetup(_ledcStart + i, WLED_PWM_FREQ_ESP32, 8); + ledcAttachPin(_pins[i], _ledcStart + i); + #endif + } + _valid = true; + }; + + void setPixelColor(uint16_t pix, uint32_t c) { + if (pix != 0 || !_valid) return; //only react to first pixel + uint8_t r = c >> 16; + uint8_t g = c >> 8; + uint8_t b = c ; + uint8_t w = c >> 24; + + switch (_type) { + case TYPE_ANALOG_1CH: //one channel (white), use highest RGBW value + _data[0] = max(r, max(g, max(b, w))); break; + + case TYPE_ANALOG_2CH: //warm white + cold white, we'll need some nice handling here, for now just R+G channels + case TYPE_ANALOG_3CH: //standard dumb RGB + case TYPE_ANALOG_4CH: //RGBW + case TYPE_ANALOG_5CH: //we'll want the white handling from 2CH here + RGB + _data[0] = r; _data[1] = g; _data[2] = b; _data[3] = w; _data[4] = 0; break; + + default: return; + } + } + + //does no index check + uint32_t getPixelColor(uint16_t pix) { + return ((_data[3] << 24) | (_data[0] << 16) | (_data[1] << 8) | (_data[2])); + } + + void show() { + uint8_t numPins = NUM_PWM_PINS(_type); + for (uint8_t i = 0; i < numPins; i++) { + uint8_t scaled = (_data[i] * _bri) / 255; + #ifdef ESP8266 + analogWrite(_pins[i], scaled); + #else + ledcWrite(_ledcStart + i, scaled); + #endif + } + } + + void setBrightness(uint8_t b) { + _bri = b; + } + + uint8_t getPins(uint8_t* pinArray) { + uint8_t numPins = NUM_PWM_PINS(_type); + for (uint8_t i = 0; i < numPins; i++) pinArray[i] = _pins[i]; + return numPins; + } + + void cleanup() { + deallocatePins(); + } + + private: + uint8_t _pins[5] = {255, 255, 255, 255, 255}; + uint8_t _data[5] = {255, 255, 255, 255, 255}; + #ifdef ARDUINO_ARCH_ESP32 + uint8_t _ledcStart = 255; + #endif + + void deallocatePins() { + uint8_t numPins = NUM_PWM_PINS(_type); + for (uint8_t i = 0; i < numPins; i++) { + if (!pinManager.isPinOk(_pins[i])) continue; + #ifdef ESP8266 + digitalWrite(_pins[i], LOW); //turn off PWM interrupt + #else + if (_ledcStart < 16) ledcDetachPin(_pins[i]); + #endif + pinManager.deallocatePin(_pins[i]); + } + #ifdef ARDUINO_ARCH_ESP32 + pinManager.deallocateLedc(_ledcStart, numPins); + #endif + } +}; + +class BusManager { + public: + BusManager() { + + }; + + int add(BusConfig &bc) { + if (numBusses >= WLED_MAX_BUSSES) return -1; + if (IS_DIGITAL(bc.type)) { + busses[numBusses] = new BusDigital(bc, numBusses); + } else { + busses[numBusses] = new BusPwm(bc); + } + numBusses++; + return numBusses -1; + } + + //do not call this method from system context (network callback) + void removeAll() { + //Serial.println("Removing all."); + //prevents crashes due to deleting busses while in use. + while (!canAllShow()) yield(); + for (uint8_t i = 0; i < numBusses; i++) delete busses[i]; + numBusses = 0; + } + //void remove(uint8_t id); + + void show() { + for (uint8_t i = 0; i < numBusses; i++) { + busses[i]->show(); + } + } + + void setPixelColor(uint16_t pix, uint32_t c) { + for (uint8_t i = 0; i < numBusses; i++) { + Bus* b = busses[i]; + uint16_t bstart = b->getStart(); + if (pix < bstart || pix >= bstart + b->getLength()) continue; + busses[i]->setPixelColor(pix - bstart, c); + } + } + + void setBrightness(uint8_t b) { + for (uint8_t i = 0; i < numBusses; i++) { + busses[i]->setBrightness(b); + } + } + + uint32_t getPixelColor(uint16_t pix) { + for (uint8_t i = 0; i < numBusses; i++) { + Bus* b = busses[i]; + uint16_t bstart = b->getStart(); + if (pix < bstart || pix >= bstart + b->getLength()) continue; + return b->getPixelColor(pix - bstart); + } + return 0; + } + + bool canAllShow() { + for (uint8_t i = 0; i < numBusses; i++) { + if (!busses[i]->canShow()) return false; + } + return true; + } + + Bus* getBus(uint8_t busNr) { + if (busNr >= numBusses) return nullptr; + return busses[busNr]; + } + + uint8_t getNumBusses() { + return numBusses; + } + + static bool isRgbw(uint8_t type) { + if (type == TYPE_SK6812_RGBW || type == TYPE_TM1814) return true; + if (type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) return true; + return false; + } + + private: + uint8_t numBusses = 0; + Bus* busses[WLED_MAX_BUSSES]; +}; +#endif \ No newline at end of file diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h new file mode 100644 index 00000000..da3f96e3 --- /dev/null +++ b/wled00/bus_wrapper.h @@ -0,0 +1,882 @@ +#ifndef BusWrapper_h +#define BusWrapper_h + +#include "NeoPixelBrightnessBus.h" + +//Hardware SPI Pins +#define P_8266_HS_MOSI 13 +#define P_8266_HS_CLK 14 +#define P_32_HS_MOSI 13 +#define P_32_HS_CLK 14 +#define P_32_VS_MOSI 23 +#define P_32_VS_CLK 18 + +//The dirty list of possible bus types. Quite a lot... +#define I_NONE 0 +//ESP8266 RGB +#define I_8266_U0_NEO_3 1 +#define I_8266_U1_NEO_3 2 +#define I_8266_DM_NEO_3 3 +#define I_8266_BB_NEO_3 4 +//RGBW +#define I_8266_U0_NEO_4 5 +#define I_8266_U1_NEO_4 6 +#define I_8266_DM_NEO_4 7 +#define I_8266_BB_NEO_4 8 +//400Kbps +#define I_8266_U0_400_3 9 +#define I_8266_U1_400_3 10 +#define I_8266_DM_400_3 11 +#define I_8266_BB_400_3 12 +//TM1418 (RGBW) +#define I_8266_U0_TM1_4 13 +#define I_8266_U1_TM1_4 14 +#define I_8266_DM_TM1_4 15 +#define I_8266_BB_TM1_4 16 + +/*** ESP32 Neopixel methods ***/ +//RGB +#define I_32_R0_NEO_3 17 +#define I_32_R1_NEO_3 18 +#define I_32_R2_NEO_3 19 +#define I_32_R3_NEO_3 20 +#define I_32_R4_NEO_3 21 +#define I_32_R5_NEO_3 22 +#define I_32_R6_NEO_3 23 +#define I_32_R7_NEO_3 24 +#define I_32_I0_NEO_3 25 +#define I_32_I1_NEO_3 26 +//RGBW +#define I_32_R0_NEO_4 27 +#define I_32_R1_NEO_4 28 +#define I_32_R2_NEO_4 29 +#define I_32_R3_NEO_4 30 +#define I_32_R4_NEO_4 31 +#define I_32_R5_NEO_4 32 +#define I_32_R6_NEO_4 33 +#define I_32_R7_NEO_4 34 +#define I_32_I0_NEO_4 35 +#define I_32_I1_NEO_4 36 +//400Kbps +#define I_32_R0_400_3 37 +#define I_32_R1_400_3 38 +#define I_32_R2_400_3 39 +#define I_32_R3_400_3 40 +#define I_32_R4_400_3 41 +#define I_32_R5_400_3 42 +#define I_32_R6_400_3 43 +#define I_32_R7_400_3 44 +#define I_32_I0_400_3 45 +#define I_32_I1_400_3 46 +//TM1418 (RGBW) +#define I_32_R0_TM1_4 47 +#define I_32_R1_TM1_4 48 +#define I_32_R2_TM1_4 49 +#define I_32_R3_TM1_4 50 +#define I_32_R4_TM1_4 51 +#define I_32_R5_TM1_4 52 +#define I_32_R6_TM1_4 53 +#define I_32_R7_TM1_4 54 +#define I_32_I0_TM1_4 55 +#define I_32_I1_TM1_4 56 +//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S) + +//APA102 +#define I_HS_DOT_3 57 //hardware SPI +#define I_SS_DOT_3 58 //soft SPI + +//LPD8806 +#define I_HS_LPD_3 59 +#define I_SS_LPD_3 60 + +//WS2801 +#define I_HS_WS1_3 61 +#define I_SS_WS1_3 62 + +//P9813 +#define I_HS_P98_3 63 +#define I_SS_P98_3 64 + + +/*** ESP8266 Neopixel methods ***/ +#ifdef ESP8266 +//RGB +#define B_8266_U0_NEO_3 NeoPixelBrightnessBus //3 chan, esp8266, gpio1 +#define B_8266_U1_NEO_3 NeoPixelBrightnessBus //3 chan, esp8266, gpio2 +#define B_8266_DM_NEO_3 NeoPixelBrightnessBus //3 chan, esp8266, gpio3 +#define B_8266_BB_NEO_3 NeoPixelBrightnessBus //3 chan, esp8266, bb (any pin but 16) +//RGBW +#define B_8266_U0_NEO_4 NeoPixelBrightnessBus //4 chan, esp8266, gpio1 +#define B_8266_U1_NEO_4 NeoPixelBrightnessBus //4 chan, esp8266, gpio2 +#define B_8266_DM_NEO_4 NeoPixelBrightnessBus //4 chan, esp8266, gpio3 +#define B_8266_BB_NEO_4 NeoPixelBrightnessBus //4 chan, esp8266, bb (any pin) +//400Kbps +#define B_8266_U0_400_3 NeoPixelBrightnessBus //3 chan, esp8266, gpio1 +#define B_8266_U1_400_3 NeoPixelBrightnessBus //3 chan, esp8266, gpio2 +#define B_8266_DM_400_3 NeoPixelBrightnessBus //3 chan, esp8266, gpio3 +#define B_8266_BB_400_3 NeoPixelBrightnessBus //3 chan, esp8266, bb (any pin) +//TM1418 (RGBW) +#define B_8266_U0_TM1_4 NeoPixelBrightnessBus +#define B_8266_U1_TM1_4 NeoPixelBrightnessBus +#define B_8266_DM_TM1_4 NeoPixelBrightnessBus +#define B_8266_BB_TM1_4 NeoPixelBrightnessBus +#endif + +/*** ESP32 Neopixel methods ***/ +#ifdef ARDUINO_ARCH_ESP32 +//RGB +#define B_32_R0_NEO_3 NeoPixelBrightnessBus +#define B_32_R1_NEO_3 NeoPixelBrightnessBus +#define B_32_R2_NEO_3 NeoPixelBrightnessBus +#define B_32_R3_NEO_3 NeoPixelBrightnessBus +#define B_32_R4_NEO_3 NeoPixelBrightnessBus +#define B_32_R5_NEO_3 NeoPixelBrightnessBus +#define B_32_R6_NEO_3 NeoPixelBrightnessBus +#define B_32_R7_NEO_3 NeoPixelBrightnessBus +#define B_32_I0_NEO_3 NeoPixelBrightnessBus +#define B_32_I1_NEO_3 NeoPixelBrightnessBus +//RGBW +#define B_32_R0_NEO_4 NeoPixelBrightnessBus +#define B_32_R1_NEO_4 NeoPixelBrightnessBus +#define B_32_R2_NEO_4 NeoPixelBrightnessBus +#define B_32_R3_NEO_4 NeoPixelBrightnessBus +#define B_32_R4_NEO_4 NeoPixelBrightnessBus +#define B_32_R5_NEO_4 NeoPixelBrightnessBus +#define B_32_R6_NEO_4 NeoPixelBrightnessBus +#define B_32_R7_NEO_4 NeoPixelBrightnessBus +#define B_32_I0_NEO_4 NeoPixelBrightnessBus +#define B_32_I1_NEO_4 NeoPixelBrightnessBus +//400Kbps +#define B_32_R0_400_3 NeoPixelBrightnessBus +#define B_32_R1_400_3 NeoPixelBrightnessBus +#define B_32_R2_400_3 NeoPixelBrightnessBus +#define B_32_R3_400_3 NeoPixelBrightnessBus +#define B_32_R4_400_3 NeoPixelBrightnessBus +#define B_32_R5_400_3 NeoPixelBrightnessBus +#define B_32_R6_400_3 NeoPixelBrightnessBus +#define B_32_R7_400_3 NeoPixelBrightnessBus +#define B_32_I0_400_3 NeoPixelBrightnessBus +#define B_32_I1_400_3 NeoPixelBrightnessBus +//TM1418 (RGBW) +#define B_32_R0_TM1_4 NeoPixelBrightnessBus +#define B_32_R1_TM1_4 NeoPixelBrightnessBus +#define B_32_R2_TM1_4 NeoPixelBrightnessBus +#define B_32_R3_TM1_4 NeoPixelBrightnessBus +#define B_32_R4_TM1_4 NeoPixelBrightnessBus +#define B_32_R5_TM1_4 NeoPixelBrightnessBus +#define B_32_R6_TM1_4 NeoPixelBrightnessBus +#define B_32_R7_TM1_4 NeoPixelBrightnessBus +#define B_32_I0_TM1_4 NeoPixelBrightnessBus +#define B_32_I1_TM1_4 NeoPixelBrightnessBus +//Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S) + +#endif + +//APA102 +#define B_HS_DOT_3 NeoPixelBrightnessBus //hardware SPI +#define B_SS_DOT_3 NeoPixelBrightnessBus //soft SPI + +//LPD8806 +#define B_HS_LPD_3 NeoPixelBrightnessBus +#define B_SS_LPD_3 NeoPixelBrightnessBus + +//WS2801 +#define B_HS_WS1_3 NeoPixelBrightnessBus +#define B_SS_WS1_3 NeoPixelBrightnessBus + +//P9813 +#define B_HS_P98_3 NeoPixelBrightnessBus +#define B_SS_P98_3 NeoPixelBrightnessBus + +//handles pointer type conversion for all possible bus types +class PolyBus { + public: + static void begin(void* busPtr, uint8_t busType, uint8_t* pins) { + switch (busType) { + case I_NONE: break; + #ifdef ESP8266 + case I_8266_U0_NEO_3: (static_cast(busPtr))->Begin(); break; + case I_8266_U1_NEO_3: (static_cast(busPtr))->Begin(); break; + case I_8266_DM_NEO_3: (static_cast(busPtr))->Begin(); break; + case I_8266_BB_NEO_3: (static_cast(busPtr))->Begin(); break; + case I_8266_U0_NEO_4: (static_cast(busPtr))->Begin(); break; + case I_8266_U1_NEO_4: (static_cast(busPtr))->Begin(); break; + case I_8266_DM_NEO_4: (static_cast(busPtr))->Begin(); break; + case I_8266_BB_NEO_4: (static_cast(busPtr))->Begin(); break; + case I_8266_U0_400_3: (static_cast(busPtr))->Begin(); break; + case I_8266_U1_400_3: (static_cast(busPtr))->Begin(); break; + case I_8266_DM_400_3: (static_cast(busPtr))->Begin(); break; + case I_8266_BB_400_3: (static_cast(busPtr))->Begin(); break; + case I_8266_U0_TM1_4: (static_cast(busPtr))->Begin(); break; + case I_8266_U1_TM1_4: (static_cast(busPtr))->Begin(); break; + case I_8266_DM_TM1_4: (static_cast(busPtr))->Begin(); break; + case I_8266_BB_TM1_4: (static_cast(busPtr))->Begin(); break; + case I_HS_DOT_3: (static_cast(busPtr))->Begin(); break; + case I_HS_LPD_3: (static_cast(busPtr))->Begin(); break; + case I_HS_WS1_3: (static_cast(busPtr))->Begin(); break; + case I_HS_P98_3: (static_cast(busPtr))->Begin(); break; + #endif + #ifdef ARDUINO_ARCH_ESP32 + case I_32_R0_NEO_3: (static_cast(busPtr))->Begin(); break; + case I_32_R1_NEO_3: (static_cast(busPtr))->Begin(); break; + case I_32_R2_NEO_3: (static_cast(busPtr))->Begin(); break; + case I_32_R3_NEO_3: (static_cast(busPtr))->Begin(); break; + case I_32_R4_NEO_3: (static_cast(busPtr))->Begin(); break; + case I_32_R5_NEO_3: (static_cast(busPtr))->Begin(); break; + case I_32_R6_NEO_3: (static_cast(busPtr))->Begin(); break; + case I_32_R7_NEO_3: (static_cast(busPtr))->Begin(); break; + case I_32_I0_NEO_3: (static_cast(busPtr))->Begin(); break; + case I_32_I1_NEO_3: (static_cast(busPtr))->Begin(); break; + case I_32_R0_NEO_4: (static_cast(busPtr))->Begin(); break; + case I_32_R1_NEO_4: (static_cast(busPtr))->Begin(); break; + case I_32_R2_NEO_4: (static_cast(busPtr))->Begin(); break; + case I_32_R3_NEO_4: (static_cast(busPtr))->Begin(); break; + case I_32_R4_NEO_4: (static_cast(busPtr))->Begin(); break; + case I_32_R5_NEO_4: (static_cast(busPtr))->Begin(); break; + case I_32_R6_NEO_4: (static_cast(busPtr))->Begin(); break; + case I_32_R7_NEO_4: (static_cast(busPtr))->Begin(); break; + case I_32_I0_NEO_4: (static_cast(busPtr))->Begin(); break; + case I_32_I1_NEO_4: (static_cast(busPtr))->Begin(); break; + case I_32_R0_400_3: (static_cast(busPtr))->Begin(); break; + case I_32_R1_400_3: (static_cast(busPtr))->Begin(); break; + case I_32_R2_400_3: (static_cast(busPtr))->Begin(); break; + case I_32_R3_400_3: (static_cast(busPtr))->Begin(); break; + case I_32_R4_400_3: (static_cast(busPtr))->Begin(); break; + case I_32_R5_400_3: (static_cast(busPtr))->Begin(); break; + case I_32_R6_400_3: (static_cast(busPtr))->Begin(); break; + case I_32_R7_400_3: (static_cast(busPtr))->Begin(); break; + case I_32_I0_400_3: (static_cast(busPtr))->Begin(); break; + case I_32_I1_400_3: (static_cast(busPtr))->Begin(); break; + case I_32_R0_TM1_4: (static_cast(busPtr))->Begin(); break; + case I_32_R1_TM1_4: (static_cast(busPtr))->Begin(); break; + case I_32_R2_TM1_4: (static_cast(busPtr))->Begin(); break; + case I_32_R3_TM1_4: (static_cast(busPtr))->Begin(); break; + case I_32_R4_TM1_4: (static_cast(busPtr))->Begin(); break; + case I_32_R5_TM1_4: (static_cast(busPtr))->Begin(); break; + case I_32_R6_TM1_4: (static_cast(busPtr))->Begin(); break; + case I_32_R7_TM1_4: (static_cast(busPtr))->Begin(); break; + case I_32_I0_TM1_4: (static_cast(busPtr))->Begin(); break; + case I_32_I1_TM1_4: (static_cast(busPtr))->Begin(); break; + // 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: (static_cast(busPtr))->Begin(pins[1], -1, pins[0], -1); break; + case I_HS_LPD_3: (static_cast(busPtr))->Begin(pins[1], -1, pins[0], -1); break; + case I_HS_WS1_3: (static_cast(busPtr))->Begin(pins[1], -1, pins[0], -1); break; + case I_HS_P98_3: (static_cast(busPtr))->Begin(pins[1], -1, pins[0], -1); break; + #endif + case I_SS_DOT_3: (static_cast(busPtr))->Begin(); break; + case I_SS_LPD_3: (static_cast(busPtr))->Begin(); break; + case I_SS_WS1_3: (static_cast(busPtr))->Begin(); break; + case I_SS_P98_3: (static_cast(busPtr))->Begin(); break; + } + }; + static void* create(uint8_t busType, uint8_t* pins, uint16_t len) { + void* busPtr = nullptr; + switch (busType) { + case I_NONE: break; + #ifdef ESP8266 + case I_8266_U0_NEO_3: busPtr = new B_8266_U0_NEO_3(len, pins[0]); break; + case I_8266_U1_NEO_3: busPtr = new B_8266_U1_NEO_3(len, pins[0]); break; + case I_8266_DM_NEO_3: busPtr = new B_8266_DM_NEO_3(len, pins[0]); break; + case I_8266_BB_NEO_3: busPtr = new B_8266_BB_NEO_3(len, pins[0]); break; + case I_8266_U0_NEO_4: busPtr = new B_8266_U0_NEO_4(len, pins[0]); break; + case I_8266_U1_NEO_4: busPtr = new B_8266_U1_NEO_4(len, pins[0]); break; + case I_8266_DM_NEO_4: busPtr = new B_8266_DM_NEO_4(len, pins[0]); break; + case I_8266_BB_NEO_4: busPtr = new B_8266_BB_NEO_4(len, pins[0]); break; + case I_8266_U0_400_3: busPtr = new B_8266_U0_400_3(len, pins[0]); break; + case I_8266_U1_400_3: busPtr = new B_8266_U1_400_3(len, pins[0]); break; + case I_8266_DM_400_3: busPtr = new B_8266_DM_400_3(len, pins[0]); break; + case I_8266_BB_400_3: busPtr = new B_8266_BB_400_3(len, pins[0]); break; + case I_8266_U0_TM1_4: busPtr = new B_8266_U0_TM1_4(len, pins[0]); break; + case I_8266_U1_TM1_4: busPtr = new B_8266_U1_TM1_4(len, pins[0]); break; + case I_8266_DM_TM1_4: busPtr = new B_8266_DM_TM1_4(len, pins[0]); break; + case I_8266_BB_TM1_4: busPtr = new B_8266_BB_TM1_4(len, pins[0]); break; + #endif + #ifdef ARDUINO_ARCH_ESP32 + case I_32_R0_NEO_3: busPtr = new B_32_R0_NEO_3(len, pins[0]); break; + case I_32_R1_NEO_3: busPtr = new B_32_R1_NEO_3(len, pins[0]); break; + case I_32_R2_NEO_3: busPtr = new B_32_R2_NEO_3(len, pins[0]); break; + case I_32_R3_NEO_3: busPtr = new B_32_R3_NEO_3(len, pins[0]); break; + case I_32_R4_NEO_3: busPtr = new B_32_R4_NEO_3(len, pins[0]); break; + case I_32_R5_NEO_3: busPtr = new B_32_R5_NEO_3(len, pins[0]); break; + case I_32_R6_NEO_3: busPtr = new B_32_R6_NEO_3(len, pins[0]); break; + case I_32_R7_NEO_3: busPtr = new B_32_R7_NEO_3(len, pins[0]); break; + case I_32_I0_NEO_3: busPtr = new B_32_I0_NEO_3(len, pins[0]); break; + case I_32_I1_NEO_3: busPtr = new B_32_I1_NEO_3(len, pins[0]); break; + case I_32_R0_NEO_4: busPtr = new B_32_R0_NEO_4(len, pins[0]); break; + case I_32_R1_NEO_4: busPtr = new B_32_R1_NEO_4(len, pins[0]); break; + case I_32_R2_NEO_4: busPtr = new B_32_R2_NEO_4(len, pins[0]); break; + case I_32_R3_NEO_4: busPtr = new B_32_R3_NEO_4(len, pins[0]); break; + case I_32_R4_NEO_4: busPtr = new B_32_R4_NEO_4(len, pins[0]); break; + case I_32_R5_NEO_4: busPtr = new B_32_R5_NEO_4(len, pins[0]); break; + case I_32_R6_NEO_4: busPtr = new B_32_R6_NEO_4(len, pins[0]); break; + case I_32_R7_NEO_4: busPtr = new B_32_R7_NEO_4(len, pins[0]); break; + case I_32_I0_NEO_4: busPtr = new B_32_I0_NEO_4(len, pins[0]); break; + case I_32_I1_NEO_4: busPtr = new B_32_I1_NEO_4(len, pins[0]); break; + case I_32_R0_400_3: busPtr = new B_32_R0_400_3(len, pins[0]); break; + case I_32_R1_400_3: busPtr = new B_32_R1_400_3(len, pins[0]); break; + case I_32_R2_400_3: busPtr = new B_32_R2_400_3(len, pins[0]); break; + case I_32_R3_400_3: busPtr = new B_32_R3_400_3(len, pins[0]); break; + case I_32_R4_400_3: busPtr = new B_32_R4_400_3(len, pins[0]); break; + case I_32_R5_400_3: busPtr = new B_32_R5_400_3(len, pins[0]); break; + case I_32_R6_400_3: busPtr = new B_32_R6_400_3(len, pins[0]); break; + case I_32_R7_400_3: busPtr = new B_32_R7_400_3(len, pins[0]); break; + case I_32_I0_400_3: busPtr = new B_32_I0_400_3(len, pins[0]); break; + case I_32_I1_400_3: busPtr = new B_32_I1_400_3(len, pins[0]); break; + case I_32_R0_TM1_4: busPtr = new B_32_R0_TM1_4(len, pins[0]); break; + case I_32_R1_TM1_4: busPtr = new B_32_R1_TM1_4(len, pins[0]); break; + case I_32_R2_TM1_4: busPtr = new B_32_R2_TM1_4(len, pins[0]); break; + case I_32_R3_TM1_4: busPtr = new B_32_R3_TM1_4(len, pins[0]); break; + case I_32_R4_TM1_4: busPtr = new B_32_R4_TM1_4(len, pins[0]); break; + case I_32_R5_TM1_4: busPtr = new B_32_R5_TM1_4(len, pins[0]); break; + case I_32_R6_TM1_4: busPtr = new B_32_R6_TM1_4(len, pins[0]); break; + case I_32_R7_TM1_4: busPtr = new B_32_R7_TM1_4(len, pins[0]); break; + case I_32_I0_TM1_4: busPtr = new B_32_I0_TM1_4(len, pins[0]); break; + case I_32_I1_TM1_4: busPtr = new B_32_I1_TM1_4(len, pins[0]); break; + #endif + // for 2-wire: pins[1] is clk, pins[0] is dat. begin expects (len, clk, dat) + case I_HS_DOT_3: busPtr = new B_HS_DOT_3(len, pins[1], pins[0]); break; + case I_SS_DOT_3: busPtr = new B_SS_DOT_3(len, pins[1], pins[0]); break; + case I_HS_LPD_3: busPtr = new B_HS_LPD_3(len, pins[1], pins[0]); break; + case I_SS_LPD_3: busPtr = new B_SS_LPD_3(len, pins[1], pins[0]); break; + case I_HS_WS1_3: busPtr = new B_HS_WS1_3(len, pins[1], pins[0]); break; + case I_SS_WS1_3: busPtr = new B_SS_WS1_3(len, pins[1], pins[0]); break; + case I_HS_P98_3: busPtr = new B_HS_P98_3(len, pins[1], pins[0]); break; + case I_SS_P98_3: busPtr = new B_SS_P98_3(len, pins[1], pins[0]); break; + } + begin(busPtr, busType, pins); + return busPtr; + }; + static void show(void* busPtr, uint8_t busType) { + switch (busType) { + case I_NONE: break; + #ifdef ESP8266 + case I_8266_U0_NEO_3: (static_cast(busPtr))->Show(); break; + case I_8266_U1_NEO_3: (static_cast(busPtr))->Show(); break; + case I_8266_DM_NEO_3: (static_cast(busPtr))->Show(); break; + case I_8266_BB_NEO_3: (static_cast(busPtr))->Show(); break; + case I_8266_U0_NEO_4: (static_cast(busPtr))->Show(); break; + case I_8266_U1_NEO_4: (static_cast(busPtr))->Show(); break; + case I_8266_DM_NEO_4: (static_cast(busPtr))->Show(); break; + case I_8266_BB_NEO_4: (static_cast(busPtr))->Show(); break; + case I_8266_U0_400_3: (static_cast(busPtr))->Show(); break; + case I_8266_U1_400_3: (static_cast(busPtr))->Show(); break; + case I_8266_DM_400_3: (static_cast(busPtr))->Show(); break; + case I_8266_BB_400_3: (static_cast(busPtr))->Show(); break; + case I_8266_U0_TM1_4: (static_cast(busPtr))->Show(); break; + case I_8266_U1_TM1_4: (static_cast(busPtr))->Show(); break; + case I_8266_DM_TM1_4: (static_cast(busPtr))->Show(); break; + case I_8266_BB_TM1_4: (static_cast(busPtr))->Show(); break; + #endif + #ifdef ARDUINO_ARCH_ESP32 + case I_32_R0_NEO_3: (static_cast(busPtr))->Show(); break; + case I_32_R1_NEO_3: (static_cast(busPtr))->Show(); break; + case I_32_R2_NEO_3: (static_cast(busPtr))->Show(); break; + case I_32_R3_NEO_3: (static_cast(busPtr))->Show(); break; + case I_32_R4_NEO_3: (static_cast(busPtr))->Show(); break; + case I_32_R5_NEO_3: (static_cast(busPtr))->Show(); break; + case I_32_R6_NEO_3: (static_cast(busPtr))->Show(); break; + case I_32_R7_NEO_3: (static_cast(busPtr))->Show(); break; + case I_32_I0_NEO_3: (static_cast(busPtr))->Show(); break; + case I_32_I1_NEO_3: (static_cast(busPtr))->Show(); break; + case I_32_R0_NEO_4: (static_cast(busPtr))->Show(); break; + case I_32_R1_NEO_4: (static_cast(busPtr))->Show(); break; + case I_32_R2_NEO_4: (static_cast(busPtr))->Show(); break; + case I_32_R3_NEO_4: (static_cast(busPtr))->Show(); break; + case I_32_R4_NEO_4: (static_cast(busPtr))->Show(); break; + case I_32_R5_NEO_4: (static_cast(busPtr))->Show(); break; + case I_32_R6_NEO_4: (static_cast(busPtr))->Show(); break; + case I_32_R7_NEO_4: (static_cast(busPtr))->Show(); break; + case I_32_I0_NEO_4: (static_cast(busPtr))->Show(); break; + case I_32_I1_NEO_4: (static_cast(busPtr))->Show(); break; + case I_32_R0_400_3: (static_cast(busPtr))->Show(); break; + case I_32_R1_400_3: (static_cast(busPtr))->Show(); break; + case I_32_R2_400_3: (static_cast(busPtr))->Show(); break; + case I_32_R3_400_3: (static_cast(busPtr))->Show(); break; + case I_32_R4_400_3: (static_cast(busPtr))->Show(); break; + case I_32_R5_400_3: (static_cast(busPtr))->Show(); break; + case I_32_R6_400_3: (static_cast(busPtr))->Show(); break; + case I_32_R7_400_3: (static_cast(busPtr))->Show(); break; + case I_32_I0_400_3: (static_cast(busPtr))->Show(); break; + case I_32_I1_400_3: (static_cast(busPtr))->Show(); break; + case I_32_R0_TM1_4: (static_cast(busPtr))->Show(); break; + case I_32_R1_TM1_4: (static_cast(busPtr))->Show(); break; + case I_32_R2_TM1_4: (static_cast(busPtr))->Show(); break; + case I_32_R3_TM1_4: (static_cast(busPtr))->Show(); break; + case I_32_R4_TM1_4: (static_cast(busPtr))->Show(); break; + case I_32_R5_TM1_4: (static_cast(busPtr))->Show(); break; + case I_32_R6_TM1_4: (static_cast(busPtr))->Show(); break; + case I_32_R7_TM1_4: (static_cast(busPtr))->Show(); break; + case I_32_I0_TM1_4: (static_cast(busPtr))->Show(); break; + case I_32_I1_TM1_4: (static_cast(busPtr))->Show(); break; + #endif + case I_HS_DOT_3: (static_cast(busPtr))->Show(); break; + case I_SS_DOT_3: (static_cast(busPtr))->Show(); break; + case I_HS_LPD_3: (static_cast(busPtr))->Show(); break; + case I_SS_LPD_3: (static_cast(busPtr))->Show(); break; + case I_HS_WS1_3: (static_cast(busPtr))->Show(); break; + case I_SS_WS1_3: (static_cast(busPtr))->Show(); break; + case I_HS_P98_3: (static_cast(busPtr))->Show(); break; + case I_SS_P98_3: (static_cast(busPtr))->Show(); break; + } + }; + static bool canShow(void* busPtr, uint8_t busType) { + switch (busType) { + case I_NONE: return true; + #ifdef ESP8266 + case I_8266_U0_NEO_3: return (static_cast(busPtr))->CanShow(); break; + case I_8266_U1_NEO_3: return (static_cast(busPtr))->CanShow(); break; + case I_8266_DM_NEO_3: return (static_cast(busPtr))->CanShow(); break; + case I_8266_BB_NEO_3: return (static_cast(busPtr))->CanShow(); break; + case I_8266_U0_NEO_4: return (static_cast(busPtr))->CanShow(); break; + case I_8266_U1_NEO_4: return (static_cast(busPtr))->CanShow(); break; + case I_8266_DM_NEO_4: return (static_cast(busPtr))->CanShow(); break; + case I_8266_BB_NEO_4: return (static_cast(busPtr))->CanShow(); break; + case I_8266_U0_400_3: return (static_cast(busPtr))->CanShow(); break; + case I_8266_U1_400_3: return (static_cast(busPtr))->CanShow(); break; + case I_8266_DM_400_3: return (static_cast(busPtr))->CanShow(); break; + case I_8266_BB_400_3: return (static_cast(busPtr))->CanShow(); break; + case I_8266_U0_TM1_4: return (static_cast(busPtr))->CanShow(); break; + case I_8266_U1_TM1_4: return (static_cast(busPtr))->CanShow(); break; + case I_8266_DM_TM1_4: return (static_cast(busPtr))->CanShow(); break; + case I_8266_BB_TM1_4: return (static_cast(busPtr))->CanShow(); break; + #endif + #ifdef ARDUINO_ARCH_ESP32 + case I_32_R0_NEO_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_R1_NEO_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_R2_NEO_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_R3_NEO_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_R4_NEO_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_R5_NEO_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_R6_NEO_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_R7_NEO_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_I0_NEO_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_I1_NEO_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_R0_NEO_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_R1_NEO_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_R2_NEO_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_R3_NEO_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_R4_NEO_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_R5_NEO_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_R6_NEO_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_R7_NEO_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_I0_NEO_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_I1_NEO_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_R0_400_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_R1_400_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_R2_400_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_R3_400_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_R4_400_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_R5_400_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_R6_400_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_R7_400_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_I0_400_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_I1_400_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_R0_TM1_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_R1_TM1_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_R2_TM1_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_R3_TM1_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_R4_TM1_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_R5_TM1_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_R6_TM1_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_R7_TM1_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_I0_TM1_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_I1_TM1_4: return (static_cast(busPtr))->CanShow(); break; + #endif + case I_HS_DOT_3: return (static_cast(busPtr))->CanShow(); break; + case I_SS_DOT_3: return (static_cast(busPtr))->CanShow(); break; + case I_HS_LPD_3: return (static_cast(busPtr))->CanShow(); break; + case I_SS_LPD_3: return (static_cast(busPtr))->CanShow(); break; + case I_HS_WS1_3: return (static_cast(busPtr))->CanShow(); break; + case I_SS_WS1_3: return (static_cast(busPtr))->CanShow(); break; + case I_HS_P98_3: return (static_cast(busPtr))->CanShow(); break; + case I_SS_P98_3: return (static_cast(busPtr))->CanShow(); break; + } + return true; + }; + static void setPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint32_t c, uint8_t co) { + uint8_t r = c >> 16; + uint8_t g = c >> 8; + uint8_t b = c >> 0; + uint8_t w = c >> 24; + RgbwColor col; + + //TODO make color order override possible on a per-strip basis + #ifdef COLOR_ORDER_OVERRIDE + if (indexPixel >= COO_MIN && indexPixel < COO_MAX) co = COO_ORDER; + #endif + + //reorder channels to selected order + switch (co) + { + case 0: col.G = g; col.R = r; col.B = b; break; //0 = GRB, default + case 1: col.G = r; col.R = g; col.B = b; break; //1 = RGB, common for WS2811 + case 2: col.G = b; col.R = r; col.B = g; break; //2 = BRG + case 3: col.G = r; col.R = b; col.B = g; break; //3 = RBG + case 4: col.G = b; col.R = g; col.B = r; break; //4 = BGR + default: col.G = g; col.R = b; col.B = r; break; //5 = GBR + } + col.W = w; + + switch (busType) { + case I_NONE: break; + #ifdef ESP8266 + case I_8266_U0_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_8266_U1_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_8266_DM_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_8266_BB_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_8266_U0_NEO_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_8266_U1_NEO_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_8266_DM_NEO_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_8266_BB_NEO_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_8266_U0_400_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_8266_U1_400_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_8266_DM_400_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_8266_BB_400_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_8266_U0_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_8266_U1_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_8266_DM_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_8266_BB_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + #endif + #ifdef ARDUINO_ARCH_ESP32 + case I_32_R0_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_32_R1_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_32_R2_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_32_R3_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_32_R4_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_32_R5_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_32_R6_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_32_R7_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_32_I0_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_32_I1_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_32_R0_NEO_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_R1_NEO_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_R2_NEO_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_R3_NEO_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_R4_NEO_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_R5_NEO_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_R6_NEO_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_R7_NEO_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_I0_NEO_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_I1_NEO_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_R0_400_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_32_R1_400_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_32_R2_400_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_32_R3_400_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_32_R4_400_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_32_R5_400_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_32_R6_400_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_32_R7_400_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_32_I0_400_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_32_I1_400_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_32_R0_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_R1_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_R2_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_R3_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_R4_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_R5_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_R6_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_R7_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_I0_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_I1_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + #endif + case I_HS_DOT_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_SS_DOT_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_HS_LPD_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_SS_LPD_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_HS_WS1_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_SS_WS1_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_HS_P98_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + case I_SS_P98_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + } + }; + static void setBrightness(void* busPtr, uint8_t busType, uint8_t b) { + switch (busType) { + case I_NONE: break; + #ifdef ESP8266 + case I_8266_U0_NEO_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_8266_U1_NEO_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_8266_DM_NEO_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_8266_BB_NEO_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_8266_U0_NEO_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_8266_U1_NEO_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_8266_DM_NEO_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_8266_BB_NEO_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_8266_U0_400_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_8266_U1_400_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_8266_DM_400_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_8266_BB_400_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_8266_U0_TM1_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_8266_U1_TM1_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_8266_DM_TM1_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_8266_BB_TM1_4: (static_cast(busPtr))->SetBrightness(b); break; + #endif + #ifdef ARDUINO_ARCH_ESP32 + case I_32_R0_NEO_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R1_NEO_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R2_NEO_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R3_NEO_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R4_NEO_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R5_NEO_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R6_NEO_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R7_NEO_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_I0_NEO_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_I1_NEO_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R0_NEO_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R1_NEO_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R2_NEO_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R3_NEO_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R4_NEO_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R5_NEO_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R6_NEO_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R7_NEO_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_I0_NEO_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_I1_NEO_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R0_400_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R1_400_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R2_400_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R3_400_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R4_400_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R5_400_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R6_400_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R7_400_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_I0_400_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_I1_400_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R0_TM1_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R1_TM1_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R2_TM1_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R3_TM1_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R4_TM1_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R5_TM1_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R6_TM1_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_R7_TM1_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_I0_TM1_4: (static_cast(busPtr))->SetBrightness(b); break; + case I_32_I1_TM1_4: (static_cast(busPtr))->SetBrightness(b); break; + #endif + case I_HS_DOT_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_SS_DOT_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_HS_LPD_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_SS_LPD_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_HS_WS1_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_SS_WS1_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_HS_P98_3: (static_cast(busPtr))->SetBrightness(b); break; + case I_SS_P98_3: (static_cast(busPtr))->SetBrightness(b); break; + } + }; + static uint32_t getPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint8_t co) { + RgbwColor col(0,0,0,0); + switch (busType) { + case I_NONE: break; + #ifdef ESP8266 + case I_8266_U0_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_U1_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_DM_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_BB_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_U0_NEO_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_U1_NEO_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_DM_NEO_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_BB_NEO_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_U0_400_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_U1_400_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_DM_400_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_BB_400_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_U0_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_U1_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_DM_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_BB_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + #endif + #ifdef ARDUINO_ARCH_ESP32 + case I_32_R0_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R1_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R2_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R3_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R4_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R5_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R6_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R7_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I0_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I1_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R0_NEO_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R1_NEO_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R2_NEO_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R3_NEO_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R4_NEO_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R5_NEO_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R6_NEO_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R7_NEO_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I0_NEO_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I1_NEO_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R0_400_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R1_400_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R2_400_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R3_400_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R4_400_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R5_400_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R6_400_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R7_400_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I0_400_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I1_400_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R0_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R1_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R2_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R3_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R4_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R5_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R6_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_R7_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I0_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I1_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + #endif + case I_HS_DOT_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_SS_DOT_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_HS_LPD_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_SS_LPD_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_HS_WS1_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_SS_WS1_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_HS_P98_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_SS_P98_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + } + + #ifdef COLOR_ORDER_OVERRIDE + if (indexPixel >= COO_MIN && indexPixel < COO_MAX) co = COO_ORDER; + #endif + + switch (co) + { + // W G R B + case 0: return ((col.W << 24) | (col.G << 8) | (col.R << 16) | (col.B)); //0 = GRB, default + case 1: return ((col.W << 24) | (col.R << 8) | (col.G << 16) | (col.B)); //1 = RGB, common for WS2811 + case 2: return ((col.W << 24) | (col.B << 8) | (col.R << 16) | (col.G)); //2 = BRG + case 3: return ((col.W << 24) | (col.B << 8) | (col.G << 16) | (col.R)); //3 = RBG + case 4: return ((col.W << 24) | (col.R << 8) | (col.B << 16) | (col.G)); //4 = BGR + case 5: return ((col.W << 24) | (col.G << 8) | (col.B << 16) | (col.R)); //5 = GBR + } + return 0; + } + + static void cleanup(void* busPtr, uint8_t busType) { + if (busPtr == nullptr) return; + switch (busType) { + case I_NONE: break; + #ifdef ESP8266 + case I_8266_U0_NEO_3: delete (static_cast(busPtr)); break; + case I_8266_U1_NEO_3: delete (static_cast(busPtr)); break; + case I_8266_DM_NEO_3: delete (static_cast(busPtr)); break; + case I_8266_BB_NEO_3: delete (static_cast(busPtr)); break; + case I_8266_U0_NEO_4: delete (static_cast(busPtr)); break; + case I_8266_U1_NEO_4: delete (static_cast(busPtr)); break; + case I_8266_DM_NEO_4: delete (static_cast(busPtr)); break; + case I_8266_BB_NEO_4: delete (static_cast(busPtr)); break; + case I_8266_U0_400_3: delete (static_cast(busPtr)); break; + case I_8266_U1_400_3: delete (static_cast(busPtr)); break; + case I_8266_DM_400_3: delete (static_cast(busPtr)); break; + case I_8266_BB_400_3: delete (static_cast(busPtr)); break; + case I_8266_U0_TM1_4: delete (static_cast(busPtr)); break; + case I_8266_U1_TM1_4: delete (static_cast(busPtr)); break; + case I_8266_DM_TM1_4: delete (static_cast(busPtr)); break; + case I_8266_BB_TM1_4: delete (static_cast(busPtr)); break; + #endif + #ifdef ARDUINO_ARCH_ESP32 + case I_32_R0_NEO_3: delete (static_cast(busPtr)); break; + case I_32_R1_NEO_3: delete (static_cast(busPtr)); break; + case I_32_R2_NEO_3: delete (static_cast(busPtr)); break; + case I_32_R3_NEO_3: delete (static_cast(busPtr)); break; + case I_32_R4_NEO_3: delete (static_cast(busPtr)); break; + case I_32_R5_NEO_3: delete (static_cast(busPtr)); break; + case I_32_R6_NEO_3: delete (static_cast(busPtr)); break; + case I_32_R7_NEO_3: delete (static_cast(busPtr)); break; + case I_32_I0_NEO_3: delete (static_cast(busPtr)); break; + case I_32_I1_NEO_3: delete (static_cast(busPtr)); break; + case I_32_R0_NEO_4: delete (static_cast(busPtr)); break; + case I_32_R1_NEO_4: delete (static_cast(busPtr)); break; + case I_32_R2_NEO_4: delete (static_cast(busPtr)); break; + case I_32_R3_NEO_4: delete (static_cast(busPtr)); break; + case I_32_R4_NEO_4: delete (static_cast(busPtr)); break; + case I_32_R5_NEO_4: delete (static_cast(busPtr)); break; + case I_32_R6_NEO_4: delete (static_cast(busPtr)); break; + case I_32_R7_NEO_4: delete (static_cast(busPtr)); break; + case I_32_I0_NEO_4: delete (static_cast(busPtr)); break; + case I_32_I1_NEO_4: delete (static_cast(busPtr)); break; + case I_32_R0_400_3: delete (static_cast(busPtr)); break; + case I_32_R1_400_3: delete (static_cast(busPtr)); break; + case I_32_R2_400_3: delete (static_cast(busPtr)); break; + case I_32_R3_400_3: delete (static_cast(busPtr)); break; + case I_32_R4_400_3: delete (static_cast(busPtr)); break; + case I_32_R5_400_3: delete (static_cast(busPtr)); break; + case I_32_R6_400_3: delete (static_cast(busPtr)); break; + case I_32_R7_400_3: delete (static_cast(busPtr)); break; + case I_32_I0_400_3: delete (static_cast(busPtr)); break; + case I_32_I1_400_3: delete (static_cast(busPtr)); break; + case I_32_R0_TM1_4: delete (static_cast(busPtr)); break; + case I_32_R1_TM1_4: delete (static_cast(busPtr)); break; + case I_32_R2_TM1_4: delete (static_cast(busPtr)); break; + case I_32_R3_TM1_4: delete (static_cast(busPtr)); break; + case I_32_R4_TM1_4: delete (static_cast(busPtr)); break; + case I_32_R5_TM1_4: delete (static_cast(busPtr)); break; + case I_32_R6_TM1_4: delete (static_cast(busPtr)); break; + case I_32_R7_TM1_4: delete (static_cast(busPtr)); break; + case I_32_I0_TM1_4: delete (static_cast(busPtr)); break; + case I_32_I1_TM1_4: delete (static_cast(busPtr)); break; + #endif + case I_HS_DOT_3: delete (static_cast(busPtr)); break; + case I_SS_DOT_3: delete (static_cast(busPtr)); break; + case I_HS_LPD_3: delete (static_cast(busPtr)); break; + case I_SS_LPD_3: delete (static_cast(busPtr)); break; + case I_HS_WS1_3: delete (static_cast(busPtr)); break; + case I_SS_WS1_3: delete (static_cast(busPtr)); break; + case I_HS_P98_3: delete (static_cast(busPtr)); break; + case I_SS_P98_3: delete (static_cast(busPtr)); break; + } + } + + //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 (!IS_DIGITAL(busType)) return I_NONE; + if (IS_2PIN(busType)) { //SPI LED chips + bool isHSPI = false; + #ifdef ESP8266 + if (pins[0] == P_8266_HS_MOSI && pins[1] == P_8266_HS_CLK) isHSPI = true; + #else + if(!num) isHSPI = true; // temporary hack to limit use of hardware SPI to a single SPI peripheral: only allow ESP32 hardware serial on segment 0 + #endif + uint8_t t = I_NONE; + switch (busType) { + case TYPE_APA102: t = I_SS_DOT_3; break; + case TYPE_LPD8806: t = I_SS_LPD_3; break; + case TYPE_WS2801: t = I_SS_WS1_3; break; + case TYPE_P9813: t = I_SS_P98_3; break; + default: t=I_NONE; + } + if (t > I_NONE && isHSPI) t--; //hardware SPI has one smaller ID than software + return t; + } else { + #ifdef ESP8266 + uint8_t offset = pins[0] -1; //for driver: 0 = uart0, 1 = uart1, 2 = dma, 3 = bitbang + if (offset > 3) offset = 3; + switch (busType) { + case TYPE_WS2812_RGB: + case TYPE_WS2812_WWA: + return I_8266_U0_NEO_3 + offset; + case TYPE_SK6812_RGBW: + return I_8266_U0_NEO_4 + offset; + case TYPE_WS2811_400KHZ: + return I_8266_U0_400_3 + offset; + } + #else //ESP32 + uint8_t offset = num; //RMT bus # == bus index in BusManager + if (offset > 9) return I_NONE; + switch (busType) { + case TYPE_WS2812_RGB: + case TYPE_WS2812_WWA: + return I_32_R0_NEO_3 + offset; + case TYPE_SK6812_RGBW: + return I_32_R0_NEO_4 + offset; + case TYPE_WS2811_400KHZ: + return I_32_R0_400_3 + offset; + } + #endif + } + return I_NONE; + } +}; + +#endif \ No newline at end of file diff --git a/wled00/button.cpp b/wled00/button.cpp index 7adbf68b..458ff22a 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -17,9 +17,7 @@ void shortPressAction() bool isButtonPressed() { - #if defined(BTNPIN) && BTNPIN > -1 - if (digitalRead(BTNPIN) == LOW) return true; - #endif + if (btnPin>=0 && digitalRead(btnPin) == LOW) return true; #ifdef TOUCHPIN if (touchRead(TOUCHPIN) <= TOUCH_THRESHOLD) return true; #endif @@ -29,8 +27,7 @@ bool isButtonPressed() void handleButton() { -#if (defined(BTNPIN) && BTNPIN > -1) || defined(TOUCHPIN) - if (!buttonEnabled) return; + if (btnPin<0 || !buttonEnabled) return; if (isButtonPressed()) //pressed { @@ -75,7 +72,6 @@ void handleButton() buttonWaitTime = 0; shortPressAction(); } -#endif } void handleIO() @@ -88,37 +84,39 @@ void handleIO() lastOnTime = millis(); if (offMode) { - #if RLYPIN >= 0 - digitalWrite(RLYPIN, RLYMDE); - #endif + if (rlyPin>=0) { + pinMode(rlyPin, OUTPUT); + digitalWrite(rlyPin, rlyMde); + } offMode = false; } } else if (millis() - lastOnTime > 600) { - if (!offMode) { - #if LEDPIN == LED_BUILTIN - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, HIGH); + if (!offMode) { + #ifdef ESP8266 + //turn off built-in LED if strip is turned off + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, HIGH); #endif - #if RLYPIN >= 0 - digitalWrite(RLYPIN, !RLYMDE); - #endif - } + if (rlyPin>=0) { + pinMode(rlyPin, OUTPUT); + digitalWrite(rlyPin, !rlyMde); + } + } offMode = true; } - #if AUXPIN >= 0 //output - if (auxActive || auxActiveBefore) + if (auxPin>=1 && (auxActive || auxActiveBefore)) { if (!auxActiveBefore) { auxActiveBefore = true; switch (auxTriggeredState) { - case 0: pinMode(AUXPIN, INPUT); break; - case 1: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, HIGH); break; - case 2: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, LOW); break; + case 0: pinMode(auxPin, INPUT); break; + case 1: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, HIGH); break; + case 2: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, LOW); break; } auxStartTime = millis(); } @@ -128,11 +126,10 @@ void handleIO() auxActiveBefore = false; switch (auxDefaultState) { - case 0: pinMode(AUXPIN, INPUT); break; - case 1: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, HIGH); break; - case 2: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, LOW); break; + case 0: pinMode(auxPin, INPUT); break; + case 1: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, HIGH); break; + case 2: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, LOW); break; } } } - #endif } diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 43d2615e..2175c97b 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -30,8 +30,6 @@ void deserializeConfig() { return; } - //deserializeJson(doc, json); - //int rev_major = doc[F("rev")][0]; // 1 //int rev_minor = doc[F("rev")][1]; // 0 @@ -89,7 +87,9 @@ void deserializeConfig() { JsonObject hw = doc[F("hw")]; + // initialize LED pins and lengths prior to other HW JsonObject hw_led = hw[F("led")]; + CJSON(ledCount, hw_led[F("total")]); if (ledCount > MAX_LEDS) ledCount = MAX_LEDS; @@ -98,22 +98,51 @@ void deserializeConfig() { CJSON(strip.reverseMode, hw_led[F("rev")]); CJSON(strip.rgbwMode, hw_led[F("rgbwm")]); - JsonObject hw_led_ins_0 = hw_led[F("ins")][0]; - //bool hw_led_ins_0_en = hw_led_ins_0[F("en")]; // true - //int hw_led_ins_0_start = hw_led_ins_0[F("start")]; // 0 - //int hw_led_ins_0_len = hw_led_ins_0[F("len")]; // 1200 + JsonArray ins = hw_led["ins"]; + uint8_t s = 0; + useRGBW = false; + busses.removeAll(); + for (JsonObject elm : ins) { + if (s >= WLED_MAX_BUSSES) break; + uint8_t pins[5] = {255, 255, 255, 255, 255}; + JsonArray pinArr = elm[F("pin")]; + if (pinArr.size() == 0) continue; + pins[0] = pinArr[0]; + uint8_t i = 0; + for (int p : pinArr) { + pins[i] = p; + i++; + if (i>4) break; + } - //int hw_led_ins_0_pin_0 = hw_led_ins_0[F("pin")][0]; // 2 - - strip.setColorOrder(hw_led_ins_0[F("order")]); - //bool hw_led_ins_0_rev = hw_led_ins_0[F("rev")]; // false - skipFirstLed = hw_led_ins_0[F("skip")]; // 0 - useRGBW = (hw_led_ins_0[F("type")] == TYPE_SK6812_RGBW); + uint16_t length = elm[F("len")]; + if (length==0) continue; + uint8_t colorOrder = (int)elm[F("order")]; + //only use skip from the first strip (this shouldn't have been in ins obj. but remains here for compatibility) + if (s==0) skipFirstLed = elm[F("skip")]; + uint16_t start = elm[F("start")] | 0; + if (start >= ledCount) continue; + //limit length of strip if it would exceed total configured LEDs + if (start + length > ledCount) length = ledCount - start; + uint8_t ledType = elm[F("type")] | TYPE_WS2812_RGB; + bool reversed = elm[F("rev")]; + //RGBW mode is enabled if at least one of the strips is RGBW + useRGBW = (useRGBW || BusManager::isRgbw(ledType)); + s++; + BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed); + busses.add(bc); + } + strip.finalizeInit(useRGBW, ledCount, skipFirstLed); JsonObject hw_btn_ins_0 = hw[F("btn")][F("ins")][0]; - buttonEnabled = hw_btn_ins_0[F("en")] | buttonEnabled; - - //int hw_btn_ins_0_pin_0 = hw_btn_ins_0[F("pin")][0]; // 0 + CJSON(buttonEnabled, hw_btn_ins_0[F("type")]); + int hw_btn_pin = hw_btn_ins_0[F("pin")][0]; + if (pinManager.allocatePin(hw_btn_pin,false)) { + btnPin = hw_btn_pin; + pinMode(btnPin, INPUT_PULLUP); + } else { + btnPin = -1; + } JsonArray hw_btn_ins_0_macros = hw_btn_ins_0[F("macros")]; CJSON(macroButton, hw_btn_ins_0_macros[0]); @@ -122,11 +151,24 @@ void deserializeConfig() { //int hw_btn_ins_0_type = hw_btn_ins_0[F("type")]; // 0 - //int hw_ir_pin = hw[F("ir")][F("pin")]; // 4 - CJSON(irEnabled, hw[F("ir")][F("type")]); // 0 + #ifndef WLED_DISABLE_INFRARED + int hw_ir_pin = hw[F("ir")][F("pin")]; // 4 + if (pinManager.allocatePin(hw_ir_pin,false)) { + irPin = hw_ir_pin; + } else { + irPin = -1; + } + #endif + CJSON(irEnabled, hw[F("ir")][F("type")]); - //int hw_relay_pin = hw[F("relay")][F("pin")]; // 12 - //bool hw_relay_rev = hw[F("relay")][F("rev")]; // false + int hw_relay_pin = hw[F("relay")][F("pin")]; + if (pinManager.allocatePin(hw_relay_pin,true)) { + rlyPin = hw_relay_pin; + pinMode(rlyPin, OUTPUT); + } else { + rlyPin = -1; + } + CJSON(rlyMde, hw[F("relay")][F("rev")]); //int hw_status_pin = hw[F("status")][F("pin")]; // -1 @@ -404,70 +446,57 @@ void serializeConfig() { JsonArray hw_led_ins = hw_led.createNestedArray("ins"); - JsonObject hw_led_ins_0 = hw_led_ins.createNestedObject(); - hw_led_ins_0[F("en")] = true; - hw_led_ins_0[F("start")] = 0; - hw_led_ins_0[F("len")] = ledCount; - JsonArray hw_led_ins_0_pin = hw_led_ins_0.createNestedArray("pin"); - hw_led_ins_0_pin.add(LEDPIN); - #ifdef DATAPIN - hw_led_ins_0_pin.add(DATAPIN); - #endif - hw_led_ins_0[F("order")] = strip.getColorOrder(); - hw_led_ins_0[F("rev")] = false; - hw_led_ins_0[F("skip")] = skipFirstLed ? 1 : 0; - - //this is very crude and temporary - byte ledType = TYPE_WS2812_RGB; - if (useRGBW) ledType = TYPE_SK6812_RGBW; - #ifdef USE_WS2801 - ledType = TYPE_WS2801; - #endif - #ifdef USE_APA102 - ledType = TYPE_APA102; - #endif - #ifdef USE_LPD8806 - ledType = TYPE_LPD8806; - #endif - #ifdef USE_P9813 - ledType = TYPE_P9813; - #endif - #ifdef USE_TM1814 - ledType = TYPE_TM1814; - #endif - - hw_led_ins_0[F("type")] = ledType; + uint16_t start = 0; + for (uint8_t s = 0; s < busses.getNumBusses(); s++) { + Bus *bus = busses.getBus(s); + if (!bus || bus->getLength()==0) break; + JsonObject ins = hw_led_ins.createNestedObject(); + ins[F("en")] = true; + ins[F("start")] = bus->getStart(); + ins[F("len")] = bus->getLength(); + JsonArray ins_pin = ins.createNestedArray("pin"); + uint8_t pins[5]; + uint8_t nPins = bus->getPins(pins); + for (uint8_t i = 0; i < nPins; i++) ins_pin.add(pins[i]); + ins[F("order")] = bus->getColorOrder(); + ins[F("rev")] = bus->reversed; + ins[F("skip")] = (skipFirstLed && s == 0) ? 1 : 0; + ins[F("type")] = bus->getType(); + } JsonObject hw_btn = hw.createNestedObject("btn"); JsonArray hw_btn_ins = hw_btn.createNestedArray("ins"); - #if defined(BTNPIN) && BTNPIN > -1 + // button BTNPIN JsonObject hw_btn_ins_0 = hw_btn_ins.createNestedObject(); hw_btn_ins_0[F("type")] = (buttonEnabled) ? BTN_TYPE_PUSH : BTN_TYPE_NONE; JsonArray hw_btn_ins_0_pin = hw_btn_ins_0.createNestedArray("pin"); - hw_btn_ins_0_pin.add(BTNPIN); + hw_btn_ins_0_pin.add(btnPin); JsonArray hw_btn_ins_0_macros = hw_btn_ins_0.createNestedArray("macros"); hw_btn_ins_0_macros.add(macroButton); hw_btn_ins_0_macros.add(macroLongPress); hw_btn_ins_0_macros.add(macroDoublePress); + + #ifndef WLED_DISABLE_INFRARED + if (irPin>=0) { + JsonObject hw_ir = hw.createNestedObject("ir"); + hw_ir[F("pin")] = irPin; + hw_ir[F("type")] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled ) + } #endif - #if defined(IRPIN) && IRPIN > -1 - JsonObject hw_ir = hw.createNestedObject("ir"); - hw_ir[F("pin")] = IRPIN; - hw_ir[F("type")] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled ) - #endif - - #if defined(RLYPIN) && RLYPIN > -1 JsonObject hw_relay = hw.createNestedObject("relay"); - hw_relay[F("pin")] = RLYPIN; - hw_relay[F("rev")] = (RLYMDE) ? false : true; - JsonObject hw_status = hw.createNestedObject("status"); - hw_status[F("pin")] = -1; - #endif + hw_relay[F("pin")] = rlyPin; + hw_relay[F("rev")] = rlyMde; + + //JsonObject hw_status = hw.createNestedObject("status"); + //hw_status[F("pin")] = -1; + + JsonObject hw_aux = hw.createNestedObject("aux"); + hw_aux[F("pin")] = auxPin; JsonObject light = doc.createNestedObject("light"); light[F("scale-bri")] = briMultiplier; diff --git a/wled00/const.h b/wled00/const.h index 933d301c..43aff244 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -13,6 +13,12 @@ //increase if you need more #define WLED_MAX_USERMODS 4 +#ifdef ESP8266 +#define WLED_MAX_BUSSES 3 +#else +#define WLED_MAX_BUSSES 10 +#endif + //Usermod IDs #define USERMOD_ID_RESERVED 0 //Unused. Might indicate no usermod present #define USERMOD_ID_UNSPECIFIED 1 //Default value for a general user mod that does not specify a custom ID @@ -95,6 +101,7 @@ #define TYPE_GS8608 23 //same driver as WS2812, but will require signal 2x per second (else displays test pattern) #define TYPE_WS2811_400KHZ 24 //half-speed WS2812 protocol, used by very old WS2811 units #define TYPE_SK6812_RGBW 30 +#define TYPE_TM1814 31 //"Analog" types (PWM) (32-47) #define TYPE_ONOFF 40 //binary output (relays etc.) #define TYPE_ANALOG_1CH 41 //single channel PWM. Uses value of brightest RGBW channel @@ -107,8 +114,11 @@ #define TYPE_APA102 51 #define TYPE_LPD8806 52 #define TYPE_P9813 53 -#define TYPE_TM1814 54 +#define IS_DIGITAL(t) (t & 0x10) //digital are 16-31 and 48-63 +#define IS_PWM(t) (t > 40 && t < 46) +#define NUM_PWM_PINS(t) (t - 40) //for analog PWM 41-45 only +#define IS_2PIN(t) (t > 47) //Color orders #define COL_ORDER_GRB 0 //GRB(w),defaut @@ -159,6 +169,9 @@ #define ERR_FS_QUOTA 11 // The FS is full or the maximum file size is reached #define ERR_FS_PLOAD 12 // It was attempted to load a preset that does not exist #define ERR_FS_GENERAL 19 // A general unspecified filesystem error occured +#define ERR_OVERTEMP 30 // An attached temperature sensor has measured above threshold temperature (not implemented) +#define ERR_OVERCURRENT 31 // An attached current sensor has measured a current above the threshold (not implemented) +#define ERR_UNDERVOLT 32 // An attached voltmeter has measured a voltage below the threshold (not implemented) //Timer mode types #define NL_MODE_SET 0 //After nightlight time elapsed, set to target brightness @@ -171,7 +184,11 @@ // maximum number of LEDs - more than 1500 LEDs (or 500 DMA "LEDPIN 3" driven ones) will cause a low memory condition on ESP8266 #ifndef MAX_LEDS -#define MAX_LEDS 1500 +#ifdef ESP8266 +#define MAX_LEDS 1536 +#else +#define MAX_LEDS 8192 +#endif #endif #define MAX_LEDS_DMA 500 @@ -181,7 +198,11 @@ #define E131_MAX_UNIVERSE_COUNT 9 -#define ABL_MILLIAMPS_DEFAULT 850; // auto lower brightness to stay close to milliampere limit +#define ABL_MILLIAMPS_DEFAULT 850 // auto lower brightness to stay close to milliampere limit + +// PWM settings +#define WLED_PWM_FREQ_ESP8266 880 //PWM frequency proven as good for LEDs +#define WLED_PWM_FREQ_ESP32 5000 #define TOUCH_THRESHOLD 32 // limit to recognize a touch, higher value means more sensitive @@ -193,4 +214,9 @@ #define JSON_BUFFER_SIZE 16384 #endif +//this is merely a default now and can be changed at runtime +#ifndef LEDPIN +#define LEDPIN 2 +#endif + #endif diff --git a/wled00/data/index.js b/wled00/data/index.js index 15f6df5d..563e6fb0 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -464,7 +464,7 @@ function populateInfo(i) } } var vcn = "Kuuhaku"; - if (i.ver.startsWith("0.11.")) vcn = "Mirai"; + if (i.ver.startsWith("0.12.")) vcn = "Hikari"; if (i.cn) vcn = i.cn; cn += `v${i.ver} "${vcn}"

@@ -473,7 +473,8 @@ function populateInfo(i) ${inforow("Signal strength",i.wifi.signal +"% ("+ i.wifi.rssi, " dBm)")} ${inforow("Uptime",getRuntimeStr(i.uptime))} ${inforow("Free heap",heap," kB")} - ${inforow("Estimated current",pwru)} + ${inforow("Estimated current",pwru)} + ${inforow("Frames / second",i.leds.fps)} ${inforow("MAC address",i.mac)} ${inforow("Filesystem",i.fs.u + "/" + i.fs.t + " kB (" +Math.round(i.fs.u*100/i.fs.t) + "%)")} ${inforow("Environment",i.arch + " " + i.core + " (" + i.lwip + ")")} diff --git a/wled00/data/liveviewws.htm b/wled00/data/liveviewws.htm new file mode 100644 index 00000000..bc1e8293 --- /dev/null +++ b/wled00/data/liveviewws.htm @@ -0,0 +1,62 @@ + + + + + + + WLED Live Preview + + + +
+ + + \ No newline at end of file diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 6a0dee0a..9c92af3b 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -5,7 +5,7 @@ LED Settings

WLED Software Update

-Installed version: 0.11.1
Download the latest binary: Download the latest binary:

@@ -78,6 +78,17 @@ update();var tmout=null;function update(){if(document.hidden)return clearTimeout )====="; +// Autogenerated from wled00/data/liveviewws.htm, do not edit!! +const char PAGE_liveviewws[] PROGMEM = R"=====( +WLED Live Preview
)====="; + + // Autogenerated from wled00/data/404.htm, do not edit!! const char PAGE_404[] PROGMEM = R"=====(Back