Skip to content

Commit a032117

Browse files
authored
Merge pull request #4859 from Liliputech/udp_name_sync_rework
new usermod hooks "onUdpPacket"
2 parents d70018a + c8757d4 commit a032117

File tree

5 files changed

+165
-78
lines changed

5 files changed

+165
-78
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "udp_name_sync",
3+
"build": { "libArchive": false },
4+
"dependencies": {}
5+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#include "wled.h"
2+
3+
class UdpNameSync : public Usermod {
4+
5+
private:
6+
7+
bool enabled = false;
8+
char segmentName[WLED_MAX_SEGNAME_LEN] = {0};
9+
static constexpr uint8_t kPacketType = 200; // custom usermod packet type
10+
static const char _name[];
11+
static const char _enabled[];
12+
13+
public:
14+
/**
15+
* Enable/Disable the usermod
16+
*/
17+
inline void enable(bool value) { enabled = value; }
18+
19+
/**
20+
* Get usermod enabled/disabled state
21+
*/
22+
inline bool isEnabled() const { return enabled; }
23+
24+
void setup() override {
25+
// Enabled when this usermod is compiled, set to false if you prefer runtime opt-in
26+
enable(true);
27+
}
28+
29+
void loop() override {
30+
if (!enabled) return;
31+
if (!WLED_CONNECTED) return;
32+
if (!udpConnected) return;
33+
Segment& mainseg = strip.getMainSegment();
34+
if (segmentName[0] == '\0' && !mainseg.name) return; //name was never set, do nothing
35+
36+
const char* curName = mainseg.name ? mainseg.name : "";
37+
if (strncmp(curName, segmentName, sizeof(segmentName)) == 0) return; // same name, do nothing
38+
39+
IPAddress broadcastIp = uint32_t(Network.localIP()) | ~uint32_t(Network.subnetMask());
40+
byte udpOut[WLED_MAX_SEGNAME_LEN + 2];
41+
udpOut[0] = kPacketType; // custom usermod packet type (avoid 0..5 used by core protocols)
42+
43+
if (segmentName[0] != '\0' && !mainseg.name) { // name cleared
44+
notifierUdp.beginPacket(broadcastIp, udpPort);
45+
segmentName[0] = '\0';
46+
DEBUG_PRINTLN(F("UdpNameSync: sending empty name"));
47+
udpOut[1] = 0; // explicit empty string
48+
notifierUdp.write(udpOut, 2);
49+
notifierUdp.endPacket();
50+
return;
51+
}
52+
53+
notifierUdp.beginPacket(broadcastIp, udpPort);
54+
DEBUG_PRINT(F("UdpNameSync: saving segment name "));
55+
DEBUG_PRINTLN(curName);
56+
strlcpy(segmentName, curName, sizeof(segmentName));
57+
strlcpy((char *)&udpOut[1], segmentName, sizeof(udpOut) - 1); // leave room for header byte
58+
size_t nameLen = strnlen((char *)&udpOut[1], sizeof(udpOut) - 1);
59+
notifierUdp.write(udpOut, 2 + nameLen);
60+
notifierUdp.endPacket();
61+
DEBUG_PRINT(F("UdpNameSync: Sent segment name : "));
62+
DEBUG_PRINTLN(segmentName);
63+
return;
64+
}
65+
66+
bool onUdpPacket(uint8_t * payload, size_t len) override {
67+
DEBUG_PRINT(F("UdpNameSync: Received packet"));
68+
if (!enabled) return false;
69+
if (receiveDirect) return false;
70+
if (len < 2) return false; // need type + at least 1 byte for name (can be 0)
71+
if (payload[0] != kPacketType) return false;
72+
Segment& mainseg = strip.getMainSegment();
73+
char tmp[WLED_MAX_SEGNAME_LEN] = {0};
74+
size_t copyLen = len - 1;
75+
if (copyLen > sizeof(tmp) - 1) copyLen = sizeof(tmp) - 1;
76+
memcpy(tmp, &payload[1], copyLen);
77+
tmp[copyLen] = '\0';
78+
mainseg.setName(tmp);
79+
DEBUG_PRINT(F("UdpNameSync: set segment name"));
80+
return true;
81+
}
82+
};
83+
84+
static UdpNameSync udp_name_sync;
85+
REGISTER_USERMOD(udp_name_sync);

wled00/fcn_declare.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ class Usermod {
315315
virtual void onMqttConnect(bool sessionPresent) {} // fired when MQTT connection is established (so usermod can subscribe)
316316
virtual bool onMqttMessage(char* topic, char* payload) { return false; } // fired upon MQTT message received (wled topic)
317317
virtual bool onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len) { return false; } // fired upon ESP-NOW message received
318+
virtual bool onUdpPacket(uint8_t* payload, size_t len) { return false; } //fired upon UDP packet received
318319
virtual void onUpdateBegin(bool) {} // fired prior to and after unsuccessful firmware update
319320
virtual void onStateChange(uint8_t mode) {} // fired upon WLED state change
320321
virtual uint16_t getId() {return USERMOD_ID_UNSPECIFIED;}
@@ -354,6 +355,7 @@ namespace UsermodManager {
354355
#ifndef WLED_DISABLE_ESPNOW
355356
bool onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len);
356357
#endif
358+
bool onUdpPacket(uint8_t* payload, size_t len);
357359
void onUpdateBegin(bool);
358360
void onStateChange(uint8_t);
359361
Usermod* lookup(uint16_t mod_id);

wled00/udp.cpp

Lines changed: 69 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -565,93 +565,82 @@ void handleNotifications()
565565
return;
566566
}
567567

568-
if (!receiveDirect) return;
569-
570-
//TPM2.NET
571-
if (udpIn[0] == 0x9c)
572-
{
573-
//WARNING: this code assumes that the final TMP2.NET payload is evenly distributed if using multiple packets (ie. frame size is constant)
574-
//if the number of LEDs in your installation doesn't allow that, please include padding bytes at the end of the last packet
575-
byte tpmType = udpIn[1];
576-
if (tpmType == 0xaa) { //TPM2.NET polling, expect answer
577-
sendTPM2Ack(); return;
578-
}
579-
if (tpmType != 0xda) return; //return if notTPM2.NET data
580-
581-
realtimeIP = (isSupp) ? notifier2Udp.remoteIP() : notifierUdp.remoteIP();
582-
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_TPM2NET);
583-
if (realtimeOverride) return;
584-
585-
tpmPacketCount++; //increment the packet count
586-
if (tpmPacketCount == 1) tpmPayloadFrameSize = (udpIn[2] << 8) + udpIn[3]; //save frame size for the whole payload if this is the first packet
587-
byte packetNum = udpIn[4]; //starts with 1!
588-
byte numPackets = udpIn[5];
589-
590-
unsigned id = (tpmPayloadFrameSize/3)*(packetNum-1); //start LED
591-
unsigned totalLen = strip.getLengthTotal();
592-
for (size_t i = 6; i < tpmPayloadFrameSize + 4U && id < totalLen; i += 3, id++) {
593-
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
594-
}
595-
if (tpmPacketCount == numPackets) { //reset packet count and show if all packets were received
596-
tpmPacketCount = 0;
597-
if (useMainSegmentOnly) strip.trigger();
598-
else strip.show();
599-
}
600-
return;
601-
}
568+
if (receiveDirect) {
569+
//TPM2.NET
570+
if (udpIn[0] == 0x9c) {
571+
//WARNING: this code assumes that the final TMP2.NET payload is evenly distributed if using multiple packets (ie. frame size is constant)
572+
//if the number of LEDs in your installation doesn't allow that, please include padding bytes at the end of the last packet
573+
byte tpmType = udpIn[1];
574+
if (tpmType == 0xaa) { //TPM2.NET polling, expect answer
575+
sendTPM2Ack(); return;
576+
}
577+
if (tpmType != 0xda) return; //return if notTPM2.NET data
602578

603-
//UDP realtime: 1 warls 2 drgb 3 drgbw 4 dnrgb 5 dnrgbw
604-
if (udpIn[0] > 0 && udpIn[0] < 6)
605-
{
606-
realtimeIP = (isSupp) ? notifier2Udp.remoteIP() : notifierUdp.remoteIP();
607-
DEBUG_PRINTLN(realtimeIP);
608-
if (packetSize < 2) return;
579+
realtimeIP = (isSupp) ? notifier2Udp.remoteIP() : notifierUdp.remoteIP();
580+
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_TPM2NET);
581+
if (realtimeOverride) return;
609582

610-
if (udpIn[1] == 0) {
611-
realtimeTimeout = 0; // cancel realtime mode immediately
612-
return;
613-
} else {
614-
realtimeLock(udpIn[1]*1000 +1, REALTIME_MODE_UDP);
615-
}
616-
if (realtimeOverride) return;
583+
tpmPacketCount++; //increment the packet count
584+
if (tpmPacketCount == 1) tpmPayloadFrameSize = (udpIn[2] << 8) + udpIn[3]; //save frame size for the whole payload if this is the first packet
585+
byte packetNum = udpIn[4]; //starts with 1!
586+
byte numPackets = udpIn[5];
617587

618-
unsigned totalLen = strip.getLengthTotal();
619-
if (udpIn[0] == 1 && packetSize > 5) //warls
620-
{
621-
for (size_t i = 2; i < packetSize -3; i += 4)
622-
{
623-
setRealtimePixel(udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3], 0);
624-
}
625-
} else if (udpIn[0] == 2 && packetSize > 4) //drgb
626-
{
627-
for (size_t i = 2, id = 0; i < packetSize -2 && id < totalLen; i += 3, id++)
628-
{
588+
unsigned id = (tpmPayloadFrameSize/3)*(packetNum-1); //start LED
589+
unsigned totalLen = strip.getLengthTotal();
590+
for (size_t i = 6; i < tpmPayloadFrameSize + 4U && id < totalLen; i += 3, id++) {
629591
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
630592
}
631-
} else if (udpIn[0] == 3 && packetSize > 6) //drgbw
632-
{
633-
for (size_t i = 2, id = 0; i < packetSize -3 && id < totalLen; i += 4, id++)
634-
{
635-
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
593+
if (tpmPacketCount == numPackets) { //reset packet count and show if all packets were received
594+
tpmPacketCount = 0;
595+
if (useMainSegmentOnly) strip.trigger();
596+
else strip.show();
636597
}
637-
} else if (udpIn[0] == 4 && packetSize > 7) //dnrgb
638-
{
639-
unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
640-
for (size_t i = 4; i < packetSize -2 && id < totalLen; i += 3, id++)
641-
{
642-
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
598+
return;
599+
}
600+
601+
//UDP realtime: 1 warls 2 drgb 3 drgbw 4 dnrgb 5 dnrgbw
602+
if (udpIn[0] > 0 && udpIn[0] < 6) {
603+
realtimeIP = (isSupp) ? notifier2Udp.remoteIP() : notifierUdp.remoteIP();
604+
DEBUG_PRINTLN(realtimeIP);
605+
if (packetSize < 2) return;
606+
607+
if (udpIn[1] == 0) {
608+
realtimeTimeout = 0; // cancel realtime mode immediately
609+
return;
610+
} else {
611+
realtimeLock(udpIn[1]*1000 +1, REALTIME_MODE_UDP);
643612
}
644-
} else if (udpIn[0] == 5 && packetSize > 8) //dnrgbw
645-
{
646-
unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
647-
for (size_t i = 4; i < packetSize -2 && id < totalLen; i += 4, id++)
648-
{
649-
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
613+
if (realtimeOverride) return;
614+
615+
unsigned totalLen = strip.getLengthTotal();
616+
if (udpIn[0] == 1 && packetSize > 5) { //warls
617+
for (size_t i = 2; i < packetSize -3; i += 4) {
618+
setRealtimePixel(udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3], 0);
619+
}
620+
} else if (udpIn[0] == 2 && packetSize > 4) { //drgb
621+
for (size_t i = 2, id = 0; i < packetSize -2 && id < totalLen; i += 3, id++)
622+
{
623+
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
624+
}
625+
} else if (udpIn[0] == 3 && packetSize > 6) { //drgbw
626+
for (size_t i = 2, id = 0; i < packetSize -3 && id < totalLen; i += 4, id++) {
627+
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
628+
}
629+
} else if (udpIn[0] == 4 && packetSize > 7) { //dnrgb
630+
unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
631+
for (size_t i = 4; i < packetSize -2 && id < totalLen; i += 3, id++) {
632+
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
633+
}
634+
} else if (udpIn[0] == 5 && packetSize > 8) { //dnrgbw
635+
unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
636+
for (size_t i = 4; i < packetSize -2 && id < totalLen; i += 4, id++) {
637+
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
638+
}
650639
}
640+
if (useMainSegmentOnly) strip.trigger();
641+
else strip.show();
642+
return;
651643
}
652-
if (useMainSegmentOnly) strip.trigger();
653-
else strip.show();
654-
return;
655644
}
656645

657646
// API over UDP
@@ -669,6 +658,8 @@ void handleNotifications()
669658
}
670659
releaseJSONBufferLock();
671660
}
661+
662+
UsermodManager::onUdpPacket(udpIn, packetSize);
672663
}
673664

674665

wled00/um_manager.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ bool UsermodManager::onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t
6868
return false;
6969
}
7070
#endif
71+
bool UsermodManager::onUdpPacket(uint8_t* payload, size_t len) {
72+
for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) if ((*mod)->onUdpPacket(payload, len)) return true;
73+
return false;
74+
}
7175
void UsermodManager::onUpdateBegin(bool init) { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->onUpdateBegin(init); } // notify usermods that update is to begin
7276
void UsermodManager::onStateChange(uint8_t mode) { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->onStateChange(mode); } // notify usermods that WLED state changed
7377

0 commit comments

Comments
 (0)