diff --git a/CHANGELOG.md b/CHANGELOG.md index d587cb5d..50e55ed8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,14 @@ ### Development versions after the 0.10.2 release +#### Build 2009290 + +- Added basic DDP protocol support +- Added Washing Machine effect (PR #1208) + #### Build 2009260 -- Added Loxone parser +- Added Loxone parser (PR #1185) - Added support for kelvin input via `K=` HTTP and `"col":[[val]]` JSON API calls - Added supplementary UDP socket (#1205) - TMP2.net receivable by default diff --git a/wled00/const.h b/wled00/const.h index cc65791e..a6810120 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -57,6 +57,7 @@ #define REALTIME_MODE_ADALIGHT 5 #define REALTIME_MODE_ARTNET 6 #define REALTIME_MODE_TPM2NET 7 +#define REALTIME_MODE_DDP 8 //realtime override modes #define REALTIME_OVERRIDE_NONE 0 diff --git a/wled00/data/settings_sync.htm b/wled00/data/settings_sync.htm index a144e76a..89030c3c 100644 --- a/wled00/data/settings_sync.htm +++ b/wled00/data/settings_sync.htm @@ -5,7 +5,7 @@ function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#sync- function adj(){if (d.Sf.DI.value == 6454) {if (d.Sf.DA.value == 1) d.Sf.DA.value = 0; if (d.Sf.EU.value == 1) d.Sf.EU.value = 0;} else if (d.Sf.DI.value == 5568) {if (d.Sf.DA.value == 0) d.Sf.DA.value = 1; if (d.Sf.EU.value == 0) d.Sf.EU.value = 1;} } function SP(){var p = d.Sf.DI.value; d.getElementById("xp").style.display = (p > 0)?"none":"block"; if (p > 0) d.Sf.EP.value = p;} -function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568: d.Sf.DI.value = 5568; break; case 6454: d.Sf.DI.value = 6454; break; }; SP();} +function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568: d.Sf.DI.value = 5568; break; case 6454: d.Sf.DI.value = 6454; break; case 4048: d.Sf.DI.value = 4048; break; }; SP();} function S(){GetV();SetVal();} function GetV(){var d=document;} @@ -47,6 +47,7 @@ Type:
Port:
diff --git a/wled00/e131.cpp b/wled00/e131.cpp index 2656f9e2..12e2ba85 100644 --- a/wled00/e131.cpp +++ b/wled00/e131.cpp @@ -7,25 +7,66 @@ * E1.31 handler */ -void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet){ - //E1.31 protocol support +//DDP protocol support, called by handleE131Packet +//handles RGB data only +void handleDDPPacket(e131_packet_t* p) { + int lastPushSeq = e131LastSequenceNumber[0]; + + //reject late packets belonging to previous frame (assuming 4 packets max. before push) + if (e131SkipOutOfSequence && lastPushSeq) { + int sn = p->sequenceNum & 0xF; + if (sn) { + if (lastPushSeq > 5) { + if (sn > (lastPushSeq -5) && sn < lastPushSeq) return; + } else { + if (sn > (10 + lastPushSeq) || sn < lastPushSeq) return; + } + } + } + + uint32_t offsetLeds = htonl(p->channelOffset) /3; + uint16_t packetLeds = htons(p->dataLen) /3; + uint8_t* data = p->data; + uint16_t c = 0; + if (p->flags & DDP_TIMECODE_FLAG) c = 4; //packet has timecode flag, we do not support it, but data starts 4 bytes later + + realtimeLock(realtimeTimeoutMs, REALTIME_MODE_DDP); + + for (uint16_t i = offsetLeds; i < offsetLeds + packetLeds; i++) { + setRealtimePixel(i, data[c++], data[c++], data[c++], 0); + } + + bool push = p->flags & DDP_PUSH_FLAG; + if (push) { + e131NewData = true; + byte sn = p->sequenceNum & 0xF; + if (sn) e131LastSequenceNumber[0] = sn; + } +} + +//E1.31 and Art-Net protocol support +void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ uint16_t uni = 0, dmxChannels = 0; uint8_t* e131_data = nullptr; uint8_t seq = 0, mde = REALTIME_MODE_E131; - if (isArtnet) + if (protocol == P_ARTNET) { uni = p->art_universe; dmxChannels = htons(p->art_length); e131_data = p->art_data; seq = p->art_sequence_number; mde = REALTIME_MODE_ARTNET; - } else { + } else if (protocol == P_E131) { uni = htons(p->universe); dmxChannels = htons(p->property_value_count) -1; e131_data = p->property_values; seq = p->sequence_number; + } else { //DDP + realtimeIP = clientIP; + handleDDPPacket(p); + return; } #ifdef WLED_ENABLE_DMX @@ -133,7 +174,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet){ } } else { // All subsequent universes start at the first channel. - dmxOffset = isArtnet ? 0 : 1; + dmxOffset = (protocol == P_ARTNET) ? 0 : 1; uint16_t ledsInFirstUniverse = (MAX_CHANNELS_PER_UNIVERSE - DMXAddress) / 3; previousLeds = ledsInFirstUniverse + (previousUniverses - 1) * MAX_LEDS_PER_UNIVERSE; } diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index fb15e95a..4c22152b 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -44,7 +44,7 @@ void initDMX(); void handleDMX(); //e131.cpp -void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet); +void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol); //file.cpp bool handleFileRead(AsyncWebServerRequest*, String path); diff --git a/wled00/html_settings.h b/wled00/html_settings.h index 258a2111..98e0c922 100644 --- a/wled00/html_settings.h +++ b/wled00/html_settings.h @@ -357,7 +357,7 @@ onclick="Save()">Save)====="; // Autogenerated from wled00/data/settings_sync.htm, do not edit!! const char PAGE_settings_sync[] PROGMEM = R"=====(Sync Settings