diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 55d929e0d..380959c15 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -10,6 +10,20 @@ #include "bus_wrapper.h" #include +// enable additional debug output +#ifdef WLED_DEBUG + #ifndef ESP8266 + #include + #endif + #define DEBUG_PRINT(x) Serial.print(x) + #define DEBUG_PRINTLN(x) Serial.println(x) + #define DEBUG_PRINTF(x...) Serial.printf(x) +#else + #define DEBUG_PRINT(x) + #define DEBUG_PRINTLN(x) + #define DEBUG_PRINTF(x...) +#endif + //temporary struct for passing bus configuration to bus struct BusConfig { uint8_t type = TYPE_WS2812_RGB; @@ -23,7 +37,8 @@ struct BusConfig { type = busType; count = len; start = pstart; colorOrder = pcolorOrder; reversed = rev; skipAmount = skip; uint8_t nPins = 1; - if (type > 47) nPins = 2; + if (type >= TYPE_NET_DDP_RGB && type < 96) nPins = 4; //virtual network bus. 4 "pins" store IP address + else if (type > 47) nPins = 2; else if (type > 40 && type < 46) nPins = NUM_PWM_PINS(type); for (uint8_t i = 0; i < nPins; i++) pins[i] = ppins[i]; } @@ -135,7 +150,7 @@ class BusDigital : public Bus { _busPtr = PolyBus::create(_iType, _pins, _len, nr); _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); + DEBUG_PRINTF("Successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u)\n",nr, _len, bc.type, _pins[0],_pins[1],_iType); }; inline void show() { @@ -201,7 +216,7 @@ class BusDigital : public Bus { } void cleanup() { - //Serial.println("Digital Cleanup"); + DEBUG_PRINTLN("Digital Cleanup"); PolyBus::cleanup(_busPtr, _iType); _iType = I_NONE; _valid = false; @@ -227,6 +242,7 @@ class BusDigital : public Bus { class BusPwm : public Bus { public: BusPwm(BusConfig &bc) : Bus(bc.type, bc.start) { + _valid = false; if (!IS_PWM(bc.type)) return; uint8_t numPins = NUM_PWM_PINS(bc.type); @@ -280,10 +296,12 @@ class BusPwm : public Bus { //does no index check uint32_t getPixelColor(uint16_t pix) { + if (!_valid) return 0; return ((_data[3] << 24) | (_data[0] << 16) | (_data[1] << 8) | (_data[2])); } void show() { + if (!_valid) return; uint8_t numPins = NUM_PWM_PINS(_type); for (uint8_t i = 0; i < numPins; i++) { uint8_t scaled = (_data[i] * _bri) / 255; @@ -301,6 +319,7 @@ class BusPwm : public Bus { } uint8_t getPins(uint8_t* pinArray) { + if (!_valid) return 0; uint8_t numPins = NUM_PWM_PINS(_type); for (uint8_t i = 0; i < numPins; i++) pinArray[i] = _pins[i]; return numPins; @@ -328,13 +347,13 @@ class BusPwm : public Bus { void deallocatePins() { uint8_t numPins = NUM_PWM_PINS(_type); for (uint8_t i = 0; i < numPins; i++) { + pinManager.deallocatePin(_pins[i], PinOwner::BusPwm); 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], PinOwner::BusPwm); } #ifdef ARDUINO_ARCH_ESP32 pinManager.deallocateLedc(_ledcStart, numPins); @@ -342,6 +361,116 @@ class BusPwm : public Bus { } }; + +class BusNetwork : public Bus { + public: + BusNetwork(BusConfig &bc) : Bus(bc.type, bc.start) { + _valid = false; +// switch (bc.type) { +// case TYPE_NET_ARTNET_RGB: +// _rgbw = false; +// _UDPtype = 2; +// break; +// case TYPE_NET_E131_RGB: +// _rgbw = false; +// _UDPtype = 1; +// break; +// case TYPE_NET_DDP_RGB: +// _rgbw = false; +// _UDPtype = 0; +// break; +// default: + _rgbw = false; + _UDPtype = bc.type - TYPE_NET_DDP_RGB; +// break; +// } + _UDPchannels = _rgbw ? 4 : 3; + //_rgbw |= bc.rgbwOverride; // RGBW override in bit 7 or can have a special type + _data = (byte *)malloc(bc.count * _UDPchannels); + if (_data == nullptr) return; + memset(_data, 0, bc.count * _UDPchannels); + _len = bc.count; + //_colorOrder = bc.colorOrder; + _client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]); + _broadcastLock = false; + _valid = true; + }; + + void setPixelColor(uint16_t pix, uint32_t c) { + if (!_valid || pix >= _len) return; + uint16_t offset = pix * _UDPchannels; + _data[offset] = 0xFF & (c >> 16); + _data[offset+1] = 0xFF & (c >> 8); + _data[offset+2] = 0xFF & (c ); + if (_rgbw) _data[offset+3] = 0xFF & (c >> 24); + } + + uint32_t getPixelColor(uint16_t pix) { + if (!_valid || pix >= _len) return 0; + uint16_t offset = pix * _UDPchannels; + return ( + (_rgbw ? (_data[offset+3] << 24) : 0) + | (_data[offset] << 16) + | (_data[offset+1] << 8) + | (_data[offset+2] ) + ); + } + + void show() { + if (!_valid || !canShow()) return; + _broadcastLock = true; + realtimeBroadcast(_UDPtype, _client, _len, _data, _bri, _rgbw); + _broadcastLock = false; + } + + inline bool canShow() { + // this should be a return value from UDP routine if it is still sending data out + return !_broadcastLock; + } + + inline void setBrightness(uint8_t b) { + _bri = b; + } + + uint8_t getPins(uint8_t* pinArray) { + for (uint8_t i = 0; i < 4; i++) { + pinArray[i] = _client[i]; + } + return 4; + } + + inline bool isRgbw() { + return _rgbw; + } + + inline uint16_t getLength() { + return _len; + } + + void cleanup() { + _type = I_NONE; + _valid = false; + if (_data != nullptr) free(_data); + _data = nullptr; + } + + ~BusNetwork() { + cleanup(); + } + + private: + IPAddress _client; + uint16_t _len = 0; + //uint8_t _colorOrder; + uint8_t _bri = 255; + uint8_t _UDPtype; + uint8_t _UDPchannels; + bool _rgbw; + bool _broadcastLock; + byte *_data; +}; + + class BusManager { public: BusManager() { @@ -365,15 +494,16 @@ class BusManager { return len*6; #endif } - - if (type > 31 && type < 48) return 5; + if (type > 31 && type < 48) return 5; if (type == 44 || type == 45) return len*4; //RGBW return len*3; } int add(BusConfig &bc) { if (numBusses >= WLED_MAX_BUSSES) return -1; - if (IS_DIGITAL(bc.type)) { + if (bc.type >= TYPE_NET_DDP_RGB && bc.type < 96) { + busses[numBusses] = new BusNetwork(bc); + } else if (IS_DIGITAL(bc.type)) { busses[numBusses] = new BusDigital(bc, numBusses); } else { busses[numBusses] = new BusPwm(bc); @@ -402,7 +532,6 @@ class BusManager { uint16_t bstart = b->getStart(); if (pix < bstart || pix >= bstart + b->getLength()) continue; busses[i]->setPixelColor(pix - bstart, c); - break; } } @@ -444,6 +573,7 @@ class BusManager { return len; } + // a workaround static inline bool isRgbw(uint8_t type) { return Bus::isRgbw(type); } diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 8adaac2fe..1a499404b 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -263,6 +263,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { JsonObject if_live = interfaces["live"]; CJSON(receiveDirect, if_live["en"]); CJSON(e131Port, if_live["port"]); // 5568 + if (e131Port == DDP_DEFAULT_PORT) e131Port = E131_DEFAULT_PORT; // prevent double DDP port allocation CJSON(e131Multicast, if_live[F("mc")]); JsonObject if_live_dmx = if_live[F("dmx")]; diff --git a/wled00/const.h b/wled00/const.h index 309e39598..9348911e1 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -113,13 +113,17 @@ #define DMX_MODE_MULTIPLE_DRGB 5 //every LED is addressed with its own RGB and share a master dimmer (ledCount * 3 + 1 channels) #define DMX_MODE_MULTIPLE_RGBW 6 //every LED is addressed with its own RGBW (ledCount * 4 channels) -//Light capability byte (unused) 0bRRCCTTTT +//Light capability byte (unused) 0bRCCCTTTT //bits 0/1/2/3: specifies a type of LED driver. A single "driver" may have different chip models but must have the same protocol/behavior -//bits 4/5: specifies the class of LED driver - 0b00 (dec. 0-15) unconfigured/reserved -// - 0b01 (dec. 16-31) digital (data pin only) -// - 0b10 (dec. 32-47) analog (PWM) -// - 0b11 (dec. 48-63) digital (data + clock / SPI) -//bits 6/7 are reserved and set to 0b00 +//bits 4/5/6: specifies the class of LED driver - 0b000 (dec. 0-15) unconfigured/reserved +// - 0b001 (dec. 16-31) digital (data pin only) +// - 0b010 (dec. 32-47) analog (PWM) +// - 0b011 (dec. 48-63) digital (data + clock / SPI) +// - 0b100 (dec. 64-79) unused/reserved +// - 0b101 (dec. 80-95) digital (data + clock / SPI) +// - 0b110 (dec. 96-111) unused/reserved +// - 0b111 (dec. 112-127) unused/reserved +//bit 7 is reserved and set to 0 #define TYPE_NONE 0 //light is not configured #define TYPE_RESERVED 1 //unused. Might indicate a "virtual" light @@ -143,6 +147,10 @@ #define TYPE_APA102 51 #define TYPE_LPD8806 52 #define TYPE_P9813 53 +//Network types (master broadcast) (80-95) +#define TYPE_NET_DDP_RGB 80 //network DDP RGB bus (master broadcast bus) +#define TYPE_NET_E131_RGB 81 //network E131 RGB bus (master broadcast bus) +#define TYPE_NET_ARTNET_RGB 82 //network ArtNet RGB bus (master broadcast bus) #define IS_DIGITAL(t) ((t) & 0x10) //digital are 16-31 and 48-63 #define IS_PWM(t) ((t) > 40 && (t) < 46) @@ -242,7 +250,7 @@ #ifndef MAX_LED_MEMORY #ifdef ESP8266 -#define MAX_LED_MEMORY 5000 +#define MAX_LED_MEMORY 4000 #else #define MAX_LED_MEMORY 64000 #endif @@ -283,7 +291,7 @@ // Maximum size of node map (list of other WLED instances) #ifdef ESP8266 - #define WLED_MAX_NODES 15 + #define WLED_MAX_NODES 24 #else #define WLED_MAX_NODES 150 #endif diff --git a/wled00/data/index.js b/wled00/data/index.js index 4f19e0038..e77a37975 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -506,12 +506,12 @@ function populatePresets(fromls) pJson["0"] = {}; localStorage.setItem("wledP", JSON.stringify(pJson)); } - pmtLS = pmt; - for (var a = 0; a < is.length; a++) { - let i = is[a]; - if (expanded[i+100]) expand(i+100, true); - } - makePlSel(arr); + pmtLS = pmt; + for (var a = 0; a < is.length; a++) { + let i = is[a]; + if (expanded[i+100]) expand(i+100, true); + } + //makePlSel(arr); } else { presetError(true); } updatePA(); populateQL(); @@ -1296,14 +1296,16 @@ var plJson = {"0":{ "end": 0 }}; -var plSelContent = ""; -function makePlSel(arr) { - plSelContent = ""; +//var plSelContent = ""; +function makePlSel(incPl=false) { + var plSelContent = ""; + var arr = Object.entries(pJson); for (var i = 0; i < arr.length; i++) { var n = arr[i][1].n ? arr[i][1].n : "Preset " + arr[i][0]; - if (arr[i][1].playlist && arr[i][1].playlist.ps) continue; //remove playlists, sub-playlists not yet supported + if (!incPl && arr[i][1].playlist && arr[i][1].playlist.ps) continue; //remove playlists, sub-playlists not yet supported plSelContent += `` } + return plSelContent; } function refreshPlE(p) { @@ -1391,7 +1393,7 @@ function makeP(i,pl) { End preset:
`; @@ -1449,7 +1451,7 @@ function makePlEntry(p,i) { return `
Duration
Transition
#${i+1}

diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 469c72e16..c67885207 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -5,10 +5,11 @@ LED Settings )====="; +const char PAGE_settingsCss[] PROGMEM = R"=====()====="; // Autogenerated from wled00/data/settings.htm, do not edit!! @@ -77,18 +77,18 @@ onclick="B()">Back // Autogenerated from wled00/data/settings_leds.htm, do not edit!! const char PAGE_settings_leds[] PROGMEM = R"=====(LED Settings