diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index d12176ee..481b9651 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -379,6 +379,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { CJSON(e131SkipOutOfSequence, if_live_dmx[F("seqskip")]); CJSON(DMXAddress, if_live_dmx[F("addr")]); if (!DMXAddress || DMXAddress > 510) DMXAddress = 1; + CJSON(DMXSegmentSpacing, if_live_dmx[F("dss")]); + if (DMXSegmentSpacing > 150) DMXSegmentSpacing = 0; CJSON(DMXMode, if_live_dmx["mode"]); tdd = if_live[F("timeout")] | -1; @@ -837,6 +839,7 @@ void serializeConfig() { if_live_dmx[F("uni")] = e131Universe; if_live_dmx[F("seqskip")] = e131SkipOutOfSequence; if_live_dmx[F("addr")] = DMXAddress; + if_live_dmx[F("dss")] = DMXSegmentSpacing; if_live_dmx["mode"] = DMXMode; if_live[F("timeout")] = realtimeTimeoutMs / 100; diff --git a/wled00/const.h b/wled00/const.h index f092fe63..6f8f269d 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -147,9 +147,13 @@ #define DMX_MODE_SINGLE_RGB 1 //all LEDs same RGB color (3 channels) #define DMX_MODE_SINGLE_DRGB 2 //all LEDs same RGB color and master dimmer (4 channels) #define DMX_MODE_EFFECT 3 //trigger standalone effects of WLED (11 channels) +#define DMX_MODE_EFFECT_W 7 //trigger standalone effects of WLED (13 channels) #define DMX_MODE_MULTIPLE_RGB 4 //every LED is addressed with its own RGB (ledCount * 3 channels) #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) +#define DMX_MODE_EFFECT_SEGMENT 8 //trigger standalone effects of WLED (11 channels per segement) +#define DMX_MODE_EFFECT_SEGMENT_W 9 //trigger standalone effects of WLED (13 channels per segement) +#define DMX_MODE_PRESET 10 //apply presets (1 channel) //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 diff --git a/wled00/data/settings_sync.htm b/wled00/data/settings_sync.htm index b7f4f2ef..9fc2e16e 100644 --- a/wled00/data/settings_sync.htm +++ b/wled00/data/settings_sync.htm @@ -148,15 +148,20 @@ Start universe:
Reboot required. Check out LedFx!
Skip out-of-sequence packets:
DMX start address:
+DMX segment spacing:
DMX mode:
E1.31 info
Timeout: ms
diff --git a/wled00/e131.cpp b/wled00/e131.cpp index cce5233a..310a3ea7 100644 --- a/wled00/e131.cpp +++ b/wled00/e131.cpp @@ -132,7 +132,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ return; // nothing to do break; - case DMX_MODE_SINGLE_RGB: // RGB only + case DMX_MODE_SINGLE_RGB: // 3 channel: [R,G,B] if (uni != e131Universe) return; if (availDMXLen < 3) return; @@ -145,7 +145,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ setRealtimePixel(i, e131_data[dataOffset+0], e131_data[dataOffset+1], e131_data[dataOffset+2], wChannel); break; - case DMX_MODE_SINGLE_DRGB: // Dimmer + RGB + case DMX_MODE_SINGLE_DRGB: // 4 channel: [Dimmer,R,G,B] if (uni != e131Universe) return; if (availDMXLen < 4) return; @@ -162,38 +162,67 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ setRealtimePixel(i, e131_data[dataOffset+1], e131_data[dataOffset+2], e131_data[dataOffset+3], wChannel); break; - case DMX_MODE_EFFECT: // Length 1: Apply Preset ID, length 11-13: apply effect config - if (uni != e131Universe) return; - if (availDMXLen < 11) { - if (availDMXLen > 1) return; - applyPreset(e131_data[dataOffset+0], CALL_MODE_NOTIFICATION); - return; - } - - if (bri != e131_data[dataOffset+0]) { - bri = e131_data[dataOffset+0]; - } - if (e131_data[dataOffset+1] < strip.getModeCount()) - effectCurrent = e131_data[dataOffset+ 1]; - effectSpeed = e131_data[dataOffset+ 2]; // flickers - effectIntensity = e131_data[dataOffset+ 3]; - effectPalette = e131_data[dataOffset+ 4]; - col[0] = e131_data[dataOffset+ 5]; - col[1] = e131_data[dataOffset+ 6]; - col[2] = e131_data[dataOffset+ 7]; - colSec[0] = e131_data[dataOffset+ 8]; - colSec[1] = e131_data[dataOffset+ 9]; - colSec[2] = e131_data[dataOffset+10]; - if (availDMXLen > 11) - { - col[3] = e131_data[dataOffset+11]; //white - colSec[3] = e131_data[dataOffset+12]; - } - transitionDelayTemp = 0; // act fast - colorUpdated(CALL_MODE_NOTIFICATION); // don't send UDP - return; // don't activate realtime live mode + case DMX_MODE_PRESET: // 1 channel: WLED Preset number [#] + if (uni != e131Universe || availDMXLen < 1) return; + applyPreset(e131_data[dataOffset], CALL_MODE_NOTIFICATION); + return; break; + case DMX_MODE_EFFECT: // 11 channels [bri,effectCurrent,effectSpeed,effectIntensity,effectPalette,R,G,B,R2,G2,B2] + case DMX_MODE_EFFECT_W: // 13 channels, same as above but with extra +2 white channels [..,W,W2] + case DMX_MODE_EFFECT_SEGMENT: // 11 channels per segment; max[#] = floor[512/(11+DMXSegmentSpacing)] = 46,42,39, .. + case DMX_MODE_EFFECT_SEGMENT_W: // 13 Channels per segment; max[#] = floor[512/(13+DMXSegmentSpacing)] = 39,36,34,32, .. + { + if (uni != e131Universe) return; + bool segmentUpdated = false; + bool isSegmentMode = DMXMode == DMX_MODE_EFFECT_SEGMENT || DMXMode == DMX_MODE_EFFECT_SEGMENT_W; + uint8_t dmxEffectChannels = (DMXMode == DMX_MODE_EFFECT || DMXMode == DMX_MODE_EFFECT_SEGMENT) ? 11 : 13; + for (uint8_t seg = 0; seg < strip.getSegmentsNum(); seg++) { + if (isSegmentMode) + dataOffset = DMXAddress + seg * (dmxEffectChannels + DMXSegmentSpacing); + else + dataOffset = DMXAddress; + // Modify address for Art-Net data + if (protocol == P_ARTNET && dataOffset > 0) + dataOffset--; + // Skip out of universe addresses + if (dataOffset > dmxChannels - dmxEffectChannels) + return; + + if (e131_data[dataOffset+1] < strip.getModeCount()) + effectCurrent = e131_data[dataOffset+ 1]; + effectSpeed = e131_data[dataOffset+ 2]; // flickers + effectIntensity = e131_data[dataOffset+ 3]; + effectPalette = e131_data[dataOffset+ 4]; + col[0] = e131_data[dataOffset+ 5]; + col[1] = e131_data[dataOffset+ 6]; + col[2] = e131_data[dataOffset+ 7]; + colSec[0] = e131_data[dataOffset+ 8]; + colSec[1] = e131_data[dataOffset+ 9]; + colSec[2] = e131_data[dataOffset+10]; + if (dmxEffectChannels == 13) { + col[3] = e131_data[dataOffset+11]; // white + colSec[3] = e131_data[dataOffset+12]; + } + if (isSegmentMode) { + opacity = e131_data[dataOffset+ 0]; + segmentUpdated |= applyValuesToSegment(seg); + } else { + if (bri != e131_data[dataOffset+0]) + bri = e131_data[dataOffset+0]; + transitionDelayTemp = 0; // act fast + colorUpdated(CALL_MODE_NOTIFICATION); // don't send UDP + return; // don't activate realtime live mode + } + } + if (segmentUpdated) { + transitionDelayTemp = 0; + stateUpdated(CALL_MODE_NOTIFICATION); + return; + } + break; + } + case DMX_MODE_MULTIPLE_DRGB: case DMX_MODE_MULTIPLE_RGB: case DMX_MODE_MULTIPLE_RGBW: @@ -279,7 +308,11 @@ void handleArtnetPollReply(IPAddress ipAddress) { case DMX_MODE_SINGLE_RGB: case DMX_MODE_SINGLE_DRGB: + case DMX_MODE_PRESET: case DMX_MODE_EFFECT: + case DMX_MODE_EFFECT_W: + case DMX_MODE_EFFECT_SEGMENT: + case DMX_MODE_EFFECT_SEGMENT_W: break; // 1 universe is enough case DMX_MODE_MULTIPLE_DRGB: diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 823c7f98..612e8fcb 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -153,6 +153,7 @@ void toggleOnOff(); void applyBri(); void applyFinalBri(); void applyValuesToSelectedSegs(); +bool applyValuesToSegment(uint8_t i); void colorUpdated(byte callMode); void stateUpdated(byte callMode); void updateInterfaces(uint8_t callMode); diff --git a/wled00/led.cpp b/wled00/led.cpp index 34dd85d9..af05c4be 100644 --- a/wled00/led.cpp +++ b/wled00/led.cpp @@ -46,6 +46,22 @@ void applyValuesToSelectedSegs() } } +// applies global legacy values to segment i (opacity, col, colSec, effectCurrent...) +bool applyValuesToSegment(uint8_t i) +{ + if (i >= strip.getSegmentsNum()) {return false;} + Segment& seg = strip.getSegment(i); + if (opacity != seg.opacity) {seg.setOpacity(opacity); stateChanged = true;} + if (effectSpeed != seg.speed) {seg.speed = effectSpeed; stateChanged = true;} + if (effectIntensity != seg.intensity) {seg.intensity = effectIntensity; stateChanged = true;} + if (effectPalette != seg.palette) {seg.palette = effectPalette; stateChanged = true;} + if (effectCurrent != seg.mode) {strip.setMode(i, effectCurrent); stateChanged = true;} + uint32_t col0 = RGBW32( col[0], col[1], col[2], col[3]); + uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]); + if (col0 != seg.colors[0]) {seg.setColor(0, col0); stateChanged = true;} + if (col1 != seg.colors[1]) {seg.setColor(1, col1); stateChanged = true;} + return stateChanged; +} void resetTimebase() { diff --git a/wled00/set.cpp b/wled00/set.cpp index 8caad36c..ca2290f1 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -266,8 +266,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) if (t >= 0 && t <= 63999) e131Universe = t; t = request->arg(F("DA")).toInt(); if (t >= 0 && t <= 510) DMXAddress = t; + t = request->arg(F("XX")).toInt(); + if (t >= 0 && t <= 150) DMXSegmentSpacing = t; t = request->arg(F("DM")).toInt(); - if (t >= DMX_MODE_DISABLED && t <= DMX_MODE_MULTIPLE_RGBW) DMXMode = t; + if (t >= DMX_MODE_DISABLED && t <= DMX_MODE_PRESET) DMXMode = t; t = request->arg(F("ET")).toInt(); if (t > 99 && t <= 65000) realtimeTimeoutMs = t; arlsForceMaxBri = request->hasArg(F("FB")); diff --git a/wled00/wled.h b/wled00/wled.h index f7dd1703..95d3c1ac 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -388,6 +388,7 @@ WLED_GLOBAL uint16_t e131Universe _INIT(1); // settings fo WLED_GLOBAL uint16_t e131Port _INIT(5568); // DMX in port. E1.31 default is 5568, Art-Net is 6454 WLED_GLOBAL byte DMXMode _INIT(DMX_MODE_MULTIPLE_RGB); // DMX mode (s.a.) WLED_GLOBAL uint16_t DMXAddress _INIT(1); // DMX start address of fixture, a.k.a. first Channel [for E1.31 (sACN) protocol] +WLED_GLOBAL uint16_t DMXSegmentSpacing _INIT(0); // Number of void/unused channels between each segments DMX channels WLED_GLOBAL byte e131LastSequenceNumber[E131_MAX_UNIVERSE_COUNT]; // to detect packet loss WLED_GLOBAL bool e131Multicast _INIT(false); // multicast or unicast WLED_GLOBAL bool e131SkipOutOfSequence _INIT(false); // freeze instead of flickering @@ -496,6 +497,7 @@ WLED_GLOBAL byte briOld _INIT(0); // global brightnes w WLED_GLOBAL byte briT _INIT(0); // global brightness during transition WLED_GLOBAL byte briLast _INIT(128); // brightness before turned off. Used for toggle function WLED_GLOBAL byte whiteLast _INIT(128); // white channel before turned off. Used for toggle function +WLED_GLOBAL byte opacity _INIT(128); // global segment opacity (set) // button WLED_GLOBAL bool buttonPublishMqtt _INIT(false); diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 801a5bb1..fdace73f 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -501,6 +501,7 @@ void getSettingsJS(byte subPage, char* dest) sappend('c',SET_F("EM"),e131Multicast); sappend('v',SET_F("EU"),e131Universe); sappend('v',SET_F("DA"),DMXAddress); + sappend('v',SET_F("XX"),DMXSegmentSpacing); sappend('v',SET_F("DM"),DMXMode); sappend('v',SET_F("ET"),realtimeTimeoutMs); sappend('c',SET_F("FB"),arlsForceMaxBri);