Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions usermods/udp_name_sync/library.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "udp_name_sync",
"build": { "libArchive": false },
"dependencies": {}
}
85 changes: 85 additions & 0 deletions usermods/udp_name_sync/udp_name_sync.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#include "wled.h"

class UdpNameSync : public Usermod {

private:

bool enabled = false;
char segmentName[WLED_MAX_SEGNAME_LEN] = {0};
static constexpr uint8_t kPacketType = 200; // custom usermod packet type
static const char _name[];
static const char _enabled[];

public:
/**
* Enable/Disable the usermod
*/
inline void enable(bool value) { enabled = value; }

/**
* Get usermod enabled/disabled state
*/
inline bool isEnabled() const { return enabled; }

void setup() override {
// Enabled when this usermod is compiled, set to false if you prefer runtime opt-in
enable(true);
}

void loop() override {
if (!enabled) return;
if (!WLED_CONNECTED) return;
if (!udpConnected) return;
Segment& mainseg = strip.getMainSegment();
if (segmentName[0] == '\0' && !mainseg.name) return; //name was never set, do nothing

const char* curName = mainseg.name ? mainseg.name : "";
if (strncmp(curName, segmentName, sizeof(segmentName)) == 0) return; // same name, do nothing

IPAddress broadcastIp = uint32_t(Network.localIP()) | ~uint32_t(Network.subnetMask());
byte udpOut[WLED_MAX_SEGNAME_LEN + 2];
udpOut[0] = kPacketType; // custom usermod packet type (avoid 0..5 used by core protocols)

if (segmentName[0] != '\0' && !mainseg.name) { // name cleared
notifierUdp.beginPacket(broadcastIp, udpPort);
segmentName[0] = '\0';
DEBUG_PRINTLN(F("UdpNameSync: sending empty name"));
udpOut[1] = 0; // explicit empty string
notifierUdp.write(udpOut, 2);
notifierUdp.endPacket();
return;
}

notifierUdp.beginPacket(broadcastIp, udpPort);
DEBUG_PRINT(F("UdpNameSync: saving segment name "));
DEBUG_PRINTLN(curName);
strlcpy(segmentName, curName, sizeof(segmentName));
strlcpy((char *)&udpOut[1], segmentName, sizeof(udpOut) - 1); // leave room for header byte
size_t nameLen = strnlen((char *)&udpOut[1], sizeof(udpOut) - 1);
notifierUdp.write(udpOut, 2 + nameLen);
notifierUdp.endPacket();
DEBUG_PRINT(F("UdpNameSync: Sent segment name : "));
DEBUG_PRINTLN(segmentName);
return;
}

bool onUdpPacket(uint8_t * payload, size_t len) override {
DEBUG_PRINT(F("UdpNameSync: Received packet"));
if (!enabled) return false;
if (receiveDirect) return false;
if (len < 2) return false; // need type + at least 1 byte for name (can be 0)
if (payload[0] != kPacketType) return false;
Segment& mainseg = strip.getMainSegment();
char tmp[WLED_MAX_SEGNAME_LEN] = {0};
size_t copyLen = len - 1;
if (copyLen > sizeof(tmp) - 1) copyLen = sizeof(tmp) - 1;
memcpy(tmp, &payload[1], copyLen);
tmp[copyLen] = '\0';
mainseg.setName(tmp);
DEBUG_PRINT(F("UdpNameSync: set segment name"));
return true;
}
};

static UdpNameSync udp_name_sync;
REGISTER_USERMOD(udp_name_sync);
2 changes: 2 additions & 0 deletions wled00/fcn_declare.h
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,7 @@ class Usermod {
virtual void onMqttConnect(bool sessionPresent) {} // fired when MQTT connection is established (so usermod can subscribe)
virtual bool onMqttMessage(char* topic, char* payload) { return false; } // fired upon MQTT message received (wled topic)
virtual bool onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len) { return false; } // fired upon ESP-NOW message received
virtual bool onUdpPacket(uint8_t* payload, size_t len) { return false; } //fired upon UDP packet received
virtual void onUpdateBegin(bool) {} // fired prior to and after unsuccessful firmware update
virtual void onStateChange(uint8_t mode) {} // fired upon WLED state change
virtual uint16_t getId() {return USERMOD_ID_UNSPECIFIED;}
Expand Down Expand Up @@ -481,6 +482,7 @@ namespace UsermodManager {
#ifndef WLED_DISABLE_ESPNOW
bool onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len);
#endif
bool onUdpPacket(uint8_t* payload, size_t len);
void onUpdateBegin(bool);
void onStateChange(uint8_t);
Usermod* lookup(uint16_t mod_id);
Expand Down
147 changes: 69 additions & 78 deletions wled00/udp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -565,93 +565,82 @@ void handleNotifications()
return;
}

if (!receiveDirect) return;

//TPM2.NET
if (udpIn[0] == 0x9c)
{
//WARNING: this code assumes that the final TMP2.NET payload is evenly distributed if using multiple packets (ie. frame size is constant)
//if the number of LEDs in your installation doesn't allow that, please include padding bytes at the end of the last packet
byte tpmType = udpIn[1];
if (tpmType == 0xaa) { //TPM2.NET polling, expect answer
sendTPM2Ack(); return;
}
if (tpmType != 0xda) return; //return if notTPM2.NET data

realtimeIP = (isSupp) ? notifier2Udp.remoteIP() : notifierUdp.remoteIP();
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_TPM2NET);
if (realtimeOverride) return;

tpmPacketCount++; //increment the packet count
if (tpmPacketCount == 1) tpmPayloadFrameSize = (udpIn[2] << 8) + udpIn[3]; //save frame size for the whole payload if this is the first packet
byte packetNum = udpIn[4]; //starts with 1!
byte numPackets = udpIn[5];

unsigned id = (tpmPayloadFrameSize/3)*(packetNum-1); //start LED
unsigned totalLen = strip.getLengthTotal();
for (size_t i = 6; i < tpmPayloadFrameSize + 4U && id < totalLen; i += 3, id++) {
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
}
if (tpmPacketCount == numPackets) { //reset packet count and show if all packets were received
tpmPacketCount = 0;
if (useMainSegmentOnly) strip.trigger();
else strip.show();
}
return;
}
if (receiveDirect) {
//TPM2.NET
if (udpIn[0] == 0x9c) {
//WARNING: this code assumes that the final TMP2.NET payload is evenly distributed if using multiple packets (ie. frame size is constant)
//if the number of LEDs in your installation doesn't allow that, please include padding bytes at the end of the last packet
byte tpmType = udpIn[1];
if (tpmType == 0xaa) { //TPM2.NET polling, expect answer
sendTPM2Ack(); return;
}
if (tpmType != 0xda) return; //return if notTPM2.NET data

//UDP realtime: 1 warls 2 drgb 3 drgbw 4 dnrgb 5 dnrgbw
if (udpIn[0] > 0 && udpIn[0] < 6)
{
realtimeIP = (isSupp) ? notifier2Udp.remoteIP() : notifierUdp.remoteIP();
DEBUG_PRINTLN(realtimeIP);
if (packetSize < 2) return;
realtimeIP = (isSupp) ? notifier2Udp.remoteIP() : notifierUdp.remoteIP();
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_TPM2NET);
if (realtimeOverride) return;

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

unsigned totalLen = strip.getLengthTotal();
if (udpIn[0] == 1 && packetSize > 5) //warls
{
for (size_t i = 2; i < packetSize -3; i += 4)
{
setRealtimePixel(udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3], 0);
}
} else if (udpIn[0] == 2 && packetSize > 4) //drgb
{
for (size_t i = 2, id = 0; i < packetSize -2 && id < totalLen; i += 3, id++)
{
unsigned id = (tpmPayloadFrameSize/3)*(packetNum-1); //start LED
unsigned totalLen = strip.getLengthTotal();
for (size_t i = 6; i < tpmPayloadFrameSize + 4U && id < totalLen; i += 3, id++) {
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
}
} else if (udpIn[0] == 3 && packetSize > 6) //drgbw
{
for (size_t i = 2, id = 0; i < packetSize -3 && id < totalLen; i += 4, id++)
{
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
if (tpmPacketCount == numPackets) { //reset packet count and show if all packets were received
tpmPacketCount = 0;
if (useMainSegmentOnly) strip.trigger();
else strip.show();
}
} else if (udpIn[0] == 4 && packetSize > 7) //dnrgb
{
unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
for (size_t i = 4; i < packetSize -2 && id < totalLen; i += 3, id++)
{
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
return;
}

//UDP realtime: 1 warls 2 drgb 3 drgbw 4 dnrgb 5 dnrgbw
if (udpIn[0] > 0 && udpIn[0] < 6) {
realtimeIP = (isSupp) ? notifier2Udp.remoteIP() : notifierUdp.remoteIP();
DEBUG_PRINTLN(realtimeIP);
if (packetSize < 2) return;

if (udpIn[1] == 0) {
realtimeTimeout = 0; // cancel realtime mode immediately
return;
} else {
realtimeLock(udpIn[1]*1000 +1, REALTIME_MODE_UDP);
}
} else if (udpIn[0] == 5 && packetSize > 8) //dnrgbw
{
unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
for (size_t i = 4; i < packetSize -2 && id < totalLen; i += 4, id++)
{
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
if (realtimeOverride) return;

unsigned totalLen = strip.getLengthTotal();
if (udpIn[0] == 1 && packetSize > 5) { //warls
for (size_t i = 2; i < packetSize -3; i += 4) {
setRealtimePixel(udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3], 0);
}
} else if (udpIn[0] == 2 && packetSize > 4) { //drgb
for (size_t i = 2, id = 0; i < packetSize -2 && id < totalLen; i += 3, id++)
{
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
}
} else if (udpIn[0] == 3 && packetSize > 6) { //drgbw
for (size_t i = 2, id = 0; i < packetSize -3 && id < totalLen; i += 4, id++) {
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
}
} else if (udpIn[0] == 4 && packetSize > 7) { //dnrgb
unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
for (size_t i = 4; i < packetSize -2 && id < totalLen; i += 3, id++) {
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
}
} else if (udpIn[0] == 5 && packetSize > 8) { //dnrgbw
unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
for (size_t i = 4; i < packetSize -2 && id < totalLen; i += 4, id++) {
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
}
}
if (useMainSegmentOnly) strip.trigger();
else strip.show();
return;
}
if (useMainSegmentOnly) strip.trigger();
else strip.show();
return;
}

// API over UDP
Expand All @@ -669,6 +658,8 @@ void handleNotifications()
}
releaseJSONBufferLock();
}

UsermodManager::onUdpPacket(udpIn, packetSize);
}


Expand Down
4 changes: 4 additions & 0 deletions wled00/um_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ bool UsermodManager::onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t
return false;
}
#endif
bool UsermodManager::onUdpPacket(uint8_t* payload, size_t len) {
for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) if ((*mod)->onUdpPacket(payload, len)) return true;
return false;
}
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
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

Expand Down