UDP on main segment only.
This commit is contained in:
parent
8d2fe315db
commit
6079effae3
@ -46,6 +46,11 @@
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
//color mangling macros
|
||||
#ifndef RGBW32
|
||||
#define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b))))
|
||||
#endif
|
||||
|
||||
/* Not used in all effects yet */
|
||||
#define WLED_FPS 42
|
||||
#define FRAMETIME_FIXED (1000/WLED_FPS)
|
||||
@ -637,12 +642,13 @@ class WS2812FX {
|
||||
resetSegments(),
|
||||
makeAutoSegments(bool forceReset = false),
|
||||
fixInvalidSegments(),
|
||||
setPixelColor(uint16_t n, uint32_t c),
|
||||
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
|
||||
show(void),
|
||||
setTargetFps(uint8_t fps),
|
||||
deserializeMap(uint8_t n=0);
|
||||
|
||||
inline void setPixelColor(uint16_t n, uint32_t c) {setPixelColor(n, byte(c>>16), byte(c>>8), byte(c), byte(c>>24));}
|
||||
|
||||
bool
|
||||
gammaCorrectBri = false,
|
||||
gammaCorrectCol = true,
|
||||
@ -910,7 +916,6 @@ class WS2812FX {
|
||||
friend class ColorTransition;
|
||||
|
||||
uint16_t
|
||||
realPixelIndex(uint16_t i),
|
||||
transitionProgress(uint8_t tNr);
|
||||
|
||||
public:
|
||||
|
@ -131,6 +131,8 @@ void WS2812FX::service() {
|
||||
|
||||
for(uint8_t i=0; i < MAX_NUM_SEGMENTS; i++)
|
||||
{
|
||||
if (realtimeMode && useMainSegmentOnly && i == getMainSegmentId()) continue;
|
||||
|
||||
_segment_index = i;
|
||||
|
||||
// reset the segment runtime data if needed, called before isActive to ensure deleted
|
||||
@ -185,34 +187,11 @@ void WS2812FX::service() {
|
||||
_triggered = false;
|
||||
}
|
||||
|
||||
void IRAM_ATTR WS2812FX::setPixelColor(uint16_t n, uint32_t c) {
|
||||
setPixelColor(n, R(c), G(c), B(c), W(c));
|
||||
}
|
||||
|
||||
//used to map from segment index to physical pixel, taking into account grouping, offsets, reverse and mirroring
|
||||
uint16_t IRAM_ATTR WS2812FX::realPixelIndex(uint16_t i) {
|
||||
int16_t iGroup = i * SEGMENT.groupLength();
|
||||
|
||||
/* reverse just an individual segment */
|
||||
int16_t realIndex = iGroup;
|
||||
if (IS_REVERSE) {
|
||||
if (IS_MIRROR) {
|
||||
realIndex = (SEGMENT.length() - 1) / 2 - iGroup; //only need to index half the pixels
|
||||
} else {
|
||||
realIndex = (SEGMENT.length() - 1) - iGroup;
|
||||
}
|
||||
}
|
||||
|
||||
realIndex += SEGMENT.start;
|
||||
return realIndex;
|
||||
}
|
||||
|
||||
void IRAM_ATTR WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
||||
{
|
||||
if (SEGLEN) {//from segment
|
||||
uint16_t realIndex = realPixelIndex(i);
|
||||
uint16_t len = SEGMENT.length();
|
||||
uint8_t segIdx;
|
||||
|
||||
if (SEGLEN) { // SEGLEN!=0 -> from segment/FX
|
||||
//color_blend(getpixel, col, _bri_t); (pseudocode for future blending of segments)
|
||||
if (_bri_t < 255) {
|
||||
r = scale8(r, _bri_t);
|
||||
@ -220,30 +199,48 @@ void IRAM_ATTR WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte
|
||||
b = scale8(b, _bri_t);
|
||||
w = scale8(w, _bri_t);
|
||||
}
|
||||
segIdx = _segment_index;
|
||||
} else // from live/realtime
|
||||
segIdx = _mainSegment;
|
||||
|
||||
if (SEGLEN || (realtimeMode && useMainSegmentOnly)) {
|
||||
uint32_t col = RGBW32(r, g, b, w);
|
||||
uint16_t len = _segments[segIdx].length();
|
||||
|
||||
/* Set all the pixels in the group */
|
||||
for (uint16_t j = 0; j < SEGMENT.grouping; j++) {
|
||||
uint16_t indexSet = realIndex + (IS_REVERSE ? -j : j);
|
||||
if (indexSet >= SEGMENT.start && indexSet < SEGMENT.stop) {
|
||||
if (IS_MIRROR) { //set the corresponding mirrored pixel
|
||||
uint16_t indexMir = SEGMENT.stop - indexSet + SEGMENT.start - 1;
|
||||
/* offset/phase */
|
||||
indexMir += SEGMENT.offset;
|
||||
if (indexMir >= SEGMENT.stop) indexMir -= len;
|
||||
// get physical pixel address (taking into account start, grouping, spacing [and offset])
|
||||
i = i * _segments[segIdx].groupLength();
|
||||
if (_segments[segIdx].options & REVERSE) { // is segment reversed?
|
||||
if (_segments[segIdx].options & MIRROR) { // is segment mirrored?
|
||||
i = (len - 1) / 2 - i; //only need to index half the pixels
|
||||
} else {
|
||||
i = (len - 1) - i;
|
||||
}
|
||||
}
|
||||
i += _segments[segIdx].start;
|
||||
|
||||
// set all the pixels in the group
|
||||
for (uint16_t j = 0; j < _segments[segIdx].grouping; j++) {
|
||||
uint16_t indexSet = i + ((_segments[segIdx].options & REVERSE) ? -j : j);
|
||||
if (indexSet >= _segments[segIdx].start && indexSet < _segments[segIdx].stop) {
|
||||
|
||||
if (_segments[segIdx].options & MIRROR) { //set the corresponding mirrored pixel
|
||||
uint16_t indexMir = _segments[segIdx].stop - indexSet + _segments[segIdx].start - 1;
|
||||
indexMir += _segments[segIdx].offset; // offset/phase
|
||||
|
||||
if (indexMir >= _segments[segIdx].stop) indexMir -= len;
|
||||
if (indexMir < customMappingSize) indexMir = customMappingTable[indexMir];
|
||||
|
||||
busses.setPixelColor(indexMir, col);
|
||||
}
|
||||
/* offset/phase */
|
||||
indexSet += SEGMENT.offset;
|
||||
if (indexSet >= SEGMENT.stop) indexSet -= len;
|
||||
indexSet += _segments[segIdx].offset; // offset/phase
|
||||
|
||||
if (indexSet >= _segments[segIdx].stop) indexSet -= len;
|
||||
if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet];
|
||||
|
||||
busses.setPixelColor(indexSet, col);
|
||||
}
|
||||
}
|
||||
} else { //live data, etc.
|
||||
} else {
|
||||
if (i < customMappingSize) i = customMappingTable[i];
|
||||
busses.setPixelColor(i, RGBW32(r, g, b, w));
|
||||
}
|
||||
@ -508,7 +505,13 @@ uint8_t WS2812FX::getActiveSegmentsNum(void) {
|
||||
|
||||
uint32_t WS2812FX::getPixelColor(uint16_t i)
|
||||
{
|
||||
i = realPixelIndex(i);
|
||||
// get physical pixel
|
||||
i = i * SEGMENT.groupLength();;
|
||||
if (IS_REVERSE) {
|
||||
if (IS_MIRROR) i = (SEGMENT.length() - 1) / 2 - i; //only need to index half the pixels
|
||||
else i = (SEGMENT.length() - 1) - i;
|
||||
}
|
||||
i += SEGMENT.start;
|
||||
|
||||
if (SEGLEN) {
|
||||
/* offset/phase */
|
||||
@ -523,7 +526,7 @@ uint32_t WS2812FX::getPixelColor(uint16_t i)
|
||||
}
|
||||
|
||||
WS2812FX::Segment& WS2812FX::getSegment(uint8_t id) {
|
||||
if (id >= MAX_NUM_SEGMENTS) return _segments[0];
|
||||
if (id >= MAX_NUM_SEGMENTS) return _segments[getMainSegmentId()];
|
||||
return _segments[id];
|
||||
}
|
||||
|
||||
|
@ -291,6 +291,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
|
||||
JsonObject if_live = interfaces["live"];
|
||||
CJSON(receiveDirect, if_live["en"]);
|
||||
CJSON(useMainSegmentOnly, if_live[F("mso")]);
|
||||
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")]);
|
||||
@ -704,6 +705,7 @@ void serializeConfig() {
|
||||
|
||||
JsonObject if_live = interfaces.createNestedObject("live");
|
||||
if_live["en"] = receiveDirect;
|
||||
if_live[F("mso")] = useMainSegmentOnly;
|
||||
if_live["port"] = e131Port;
|
||||
if_live[F("mc")] = e131Multicast;
|
||||
|
||||
|
@ -1696,6 +1696,8 @@ function setIntensity() {
|
||||
|
||||
function setLor(i) {
|
||||
var obj = {"lor": i};
|
||||
// allow canceling live mode (if sender crashes)
|
||||
if (i===0 && lastinfo.live && ["","Hyperion","UDP"].includes(lastinfo.lm)) { obj.live = false; obj.v = true; }
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,8 @@ Send notifications twice: <input type="checkbox" name="S2"><br>
|
||||
Enable instance list: <input type="checkbox" name="NL"><br>
|
||||
Make this instance discoverable: <input type="checkbox" name="NB">
|
||||
<h3>Realtime</h3>
|
||||
Receive UDP realtime: <input type="checkbox" name="RD"><br><br>
|
||||
Receive UDP realtime: <input type="checkbox" name="RD"><br>
|
||||
Use main segment only: <input type="checkbox" name="MO"><br><br>
|
||||
<i>Network DMX input</i><br>
|
||||
Type:
|
||||
<select name=DI onchange="SP(); adj();">
|
||||
|
@ -34,7 +34,7 @@ void handleDDPPacket(e131_packet_t* p) {
|
||||
|
||||
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_DDP);
|
||||
|
||||
if (!realtimeOverride) {
|
||||
if (!realtimeOverride || (realtimeMode && useMainSegmentOnly)) {
|
||||
for (uint16_t i = start; i < stop; i++) {
|
||||
setRealtimePixel(i, data[c], data[c+1], data[c+2], 0);
|
||||
c+=3;
|
||||
@ -115,7 +115,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
||||
if (uni != e131Universe) return;
|
||||
if (dmxChannels-DMXAddress+1 < 3) return;
|
||||
realtimeLock(realtimeTimeoutMs, mde);
|
||||
if (realtimeOverride) return;
|
||||
if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
|
||||
wChannel = (dmxChannels-DMXAddress+1 > 3) ? e131_data[DMXAddress+3] : 0;
|
||||
for (uint16_t i = 0; i < totalLen; i++)
|
||||
setRealtimePixel(i, e131_data[DMXAddress+0], e131_data[DMXAddress+1], e131_data[DMXAddress+2], wChannel);
|
||||
@ -125,7 +125,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
||||
if (uni != e131Universe) return;
|
||||
if (dmxChannels-DMXAddress+1 < 4) return;
|
||||
realtimeLock(realtimeTimeoutMs, mde);
|
||||
if (realtimeOverride) return;
|
||||
if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
|
||||
wChannel = (dmxChannels-DMXAddress+1 > 4) ? e131_data[DMXAddress+4] : 0;
|
||||
if (DMXOldDimmer != e131_data[DMXAddress+0]) {
|
||||
DMXOldDimmer = e131_data[DMXAddress+0];
|
||||
@ -176,7 +176,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
||||
bool is4Chan = (DMXMode == DMX_MODE_MULTIPLE_RGBW);
|
||||
const uint16_t dmxChannelsPerLed = is4Chan ? 4 : 3;
|
||||
const uint16_t ledsPerUniverse = is4Chan ? MAX_4_CH_LEDS_PER_UNIVERSE : MAX_3_CH_LEDS_PER_UNIVERSE;
|
||||
if (realtimeOverride) return;
|
||||
if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
|
||||
uint16_t previousLeds, dmxOffset;
|
||||
if (previousUniverses == 0) {
|
||||
if (dmxChannels-DMXAddress < 1) return;
|
||||
|
@ -290,7 +290,8 @@ Send notifications twice: <input type="checkbox" name="S2"><br><i>
|
||||
Reboot required to apply changes.</i><h3>Instance List</h3>
|
||||
Enable instance list: <input type="checkbox" name="NL"><br>
|
||||
Make this instance discoverable: <input type="checkbox" name="NB"><h3>Realtime
|
||||
</h3>Receive UDP realtime: <input type="checkbox" name="RD"><br><br><i>
|
||||
</h3>Receive UDP realtime: <input type="checkbox" name="RD"><br>
|
||||
Use main segment only: <input type="checkbox" name="MO"><br><br><i>
|
||||
Network DMX input</i><br>Type: <select name="DI" onchange="SP(),adj()"><option
|
||||
value="5568">E1.31 (sACN)</option><option value="6454">Art-Net</option><option
|
||||
value="0" selected="selected">Custom port</option></select><br><div id="xp">
|
||||
|
1669
wled00/html_ui.h
1669
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -292,23 +292,25 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
|
||||
doReboot = root[F("rb")] | doReboot;
|
||||
|
||||
strip.setMainSegmentId(root[F("mainseg")] | strip.getMainSegmentId()); // must be before realtimeLock() if "live"
|
||||
|
||||
realtimeOverride = root[F("lor")] | realtimeOverride;
|
||||
if (realtimeOverride > 2) realtimeOverride = REALTIME_OVERRIDE_ALWAYS;
|
||||
|
||||
bool liveEnabled = false;
|
||||
if (root.containsKey("live")) {
|
||||
bool lv = root["live"];
|
||||
if (lv) {
|
||||
if (root["live"].as<bool>()) {
|
||||
transitionDelayTemp = 0;
|
||||
jsonTransitionOnce = true;
|
||||
liveEnabled = true; // triggers realtimeLock() below
|
||||
realtimeLock(65000);
|
||||
} else {
|
||||
if (realtimeOverride == REALTIME_OVERRIDE_ONCE) realtimeOverride = REALTIME_OVERRIDE_NONE;
|
||||
strip.setBrightness(scaledBri(bri));
|
||||
realtimeTimeout = 0; //cancel realtime mode immediately
|
||||
realtimeMode = REALTIME_MODE_INACTIVE; // inform UI immediatelly
|
||||
realtimeIP[0] = 0;
|
||||
}
|
||||
else realtimeTimeout = 0; //cancel realtime mode immediately
|
||||
}
|
||||
|
||||
strip.setMainSegmentId(root[F("mainseg")] | strip.getMainSegmentId());
|
||||
|
||||
int it = 0;
|
||||
JsonVariant segVar = root["seg"];
|
||||
if (segVar.is<JsonObject>())
|
||||
@ -381,7 +383,6 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
}
|
||||
|
||||
stateUpdated(callMode);
|
||||
if (liveEnabled) realtimeTimeout = UINT32_MAX; // force indefinite timeout if this request contained {"live":true}
|
||||
|
||||
return stateResponse;
|
||||
}
|
||||
@ -463,7 +464,7 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
||||
udpn["send"] = notifyDirect;
|
||||
udpn["recv"] = receiveNotifications;
|
||||
|
||||
root[F("lor")] = realtimeOverride;
|
||||
root[F("lor")] = realtimeOverride || (realtimeMode && useMainSegmentOnly);
|
||||
}
|
||||
|
||||
root[F("mainseg")] = strip.getMainSegmentId();
|
||||
@ -536,6 +537,7 @@ void serializeInfo(JsonObject root)
|
||||
root[F("name")] = serverDescription;
|
||||
root[F("udpport")] = udpPort;
|
||||
root["live"] = (bool)realtimeMode;
|
||||
root[F("mso")] = useMainSegmentOnly; // using main segment only for live
|
||||
|
||||
switch (realtimeMode) {
|
||||
case REALTIME_MODE_INACTIVE: root["lm"] = ""; break;
|
||||
|
@ -100,7 +100,6 @@ void stateUpdated(byte callMode) {
|
||||
setValuesFromFirstSelectedSeg();
|
||||
|
||||
if (bri != briOld || stateChanged) {
|
||||
if (realtimeTimeout == UINT32_MAX) realtimeTimeout = 0;
|
||||
if (stateChanged) currentPreset = 0; //something changed, so we are no longer in the preset
|
||||
|
||||
if (callMode != CALL_MODE_NOTIFICATION && callMode != CALL_MODE_NO_NOTIFY) notify(callMode);
|
||||
|
@ -237,6 +237,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
nodeBroadcastEnabled = request->hasArg(F("NB"));
|
||||
|
||||
receiveDirect = request->hasArg(F("RD"));
|
||||
useMainSegmentOnly = request->hasArg(F("MO"));
|
||||
e131SkipOutOfSequence = request->hasArg(F("ES"));
|
||||
e131Multicast = request->hasArg(F("EM"));
|
||||
t = request->arg(F("EP")).toInt();
|
||||
|
@ -148,7 +148,9 @@ void WLED::loop()
|
||||
yield();
|
||||
handleIO();
|
||||
handleIR();
|
||||
#ifndef WLED_DISABLE_ALEXA
|
||||
handleAlexa();
|
||||
#endif
|
||||
|
||||
yield();
|
||||
|
||||
@ -159,22 +161,25 @@ void WLED::loop()
|
||||
yield();
|
||||
}
|
||||
|
||||
if (!realtimeMode || realtimeOverride) // block stuff if WARLS/Adalight is enabled
|
||||
if (!realtimeMode || realtimeOverride || (realtimeMode && useMainSegmentOnly)) // block stuff if WARLS/Adalight is enabled
|
||||
{
|
||||
if (apActive)
|
||||
dnsServer.processNextRequest();
|
||||
#ifndef WLED_DISABLE_OTA
|
||||
if (WLED_CONNECTED && aOtaEnabled)
|
||||
ArduinoOTA.handle();
|
||||
#endif
|
||||
if (apActive) dnsServer.processNextRequest();
|
||||
#ifndef WLED_DISABLE_OTA
|
||||
if (WLED_CONNECTED && aOtaEnabled) ArduinoOTA.handle();
|
||||
#endif
|
||||
handleNightlight();
|
||||
handlePlaylist();
|
||||
yield();
|
||||
|
||||
#ifndef WLED_DISABLE_HUESYNC
|
||||
handleHue();
|
||||
#ifndef WLED_DISABLE_BLYNK
|
||||
yield();
|
||||
#endif
|
||||
|
||||
#ifndef WLED_DISABLE_BLYNK
|
||||
handleBlynk();
|
||||
#endif
|
||||
yield();
|
||||
#endif
|
||||
|
||||
yield();
|
||||
|
||||
|
@ -537,6 +537,7 @@ WLED_GLOBAL IPAddress realtimeIP _INIT_N(((0, 0, 0, 0)));
|
||||
WLED_GLOBAL unsigned long realtimeTimeout _INIT(0);
|
||||
WLED_GLOBAL uint8_t tpmPacketCount _INIT(0);
|
||||
WLED_GLOBAL uint16_t tpmPayloadFrameSize _INIT(0);
|
||||
WLED_GLOBAL bool useMainSegmentOnly _INIT(false);
|
||||
|
||||
// mqtt
|
||||
WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0);
|
||||
|
@ -493,6 +493,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('c',SET_F("NB"),nodeBroadcastEnabled);
|
||||
|
||||
sappend('c',SET_F("RD"),receiveDirect);
|
||||
sappend('c',SET_F("MO"),useMainSegmentOnly);
|
||||
sappend('v',SET_F("EP"),e131Port);
|
||||
sappend('c',SET_F("ES"),e131SkipOutOfSequence);
|
||||
sappend('c',SET_F("EM"),e131Multicast);
|
||||
|
Loading…
Reference in New Issue
Block a user