Merge pull request #4859 from Liliputech/udp_name_sync_rework
new usermod hooks "onUdpPacket"
This commit is contained in:
5
usermods/udp_name_sync/library.json
Normal file
5
usermods/udp_name_sync/library.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "udp_name_sync",
|
||||||
|
"build": { "libArchive": false },
|
||||||
|
"dependencies": {}
|
||||||
|
}
|
||||||
85
usermods/udp_name_sync/udp_name_sync.cpp
Normal file
85
usermods/udp_name_sync/udp_name_sync.cpp
Normal file
@@ -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);
|
||||||
@@ -315,6 +315,7 @@ class Usermod {
|
|||||||
virtual void onMqttConnect(bool sessionPresent) {} // fired when MQTT connection is established (so usermod can subscribe)
|
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 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 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 onUpdateBegin(bool) {} // fired prior to and after unsuccessful firmware update
|
||||||
virtual void onStateChange(uint8_t mode) {} // fired upon WLED state change
|
virtual void onStateChange(uint8_t mode) {} // fired upon WLED state change
|
||||||
virtual uint16_t getId() {return USERMOD_ID_UNSPECIFIED;}
|
virtual uint16_t getId() {return USERMOD_ID_UNSPECIFIED;}
|
||||||
@@ -354,6 +355,7 @@ namespace UsermodManager {
|
|||||||
#ifndef WLED_DISABLE_ESPNOW
|
#ifndef WLED_DISABLE_ESPNOW
|
||||||
bool onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len);
|
bool onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len);
|
||||||
#endif
|
#endif
|
||||||
|
bool onUdpPacket(uint8_t* payload, size_t len);
|
||||||
void onUpdateBegin(bool);
|
void onUpdateBegin(bool);
|
||||||
void onStateChange(uint8_t);
|
void onStateChange(uint8_t);
|
||||||
Usermod* lookup(uint16_t mod_id);
|
Usermod* lookup(uint16_t mod_id);
|
||||||
|
|||||||
147
wled00/udp.cpp
147
wled00/udp.cpp
@@ -565,93 +565,82 @@ void handleNotifications()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!receiveDirect) 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
|
||||||
|
|
||||||
//TPM2.NET
|
realtimeIP = (isSupp) ? notifier2Udp.remoteIP() : notifierUdp.remoteIP();
|
||||||
if (udpIn[0] == 0x9c)
|
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_TPM2NET);
|
||||||
{
|
if (realtimeOverride) return;
|
||||||
//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
|
tpmPacketCount++; //increment the packet count
|
||||||
byte tpmType = udpIn[1];
|
if (tpmPacketCount == 1) tpmPayloadFrameSize = (udpIn[2] << 8) + udpIn[3]; //save frame size for the whole payload if this is the first packet
|
||||||
if (tpmType == 0xaa) { //TPM2.NET polling, expect answer
|
byte packetNum = udpIn[4]; //starts with 1!
|
||||||
sendTPM2Ack(); return;
|
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 (tpmType != 0xda) return; //return if notTPM2.NET data
|
|
||||||
|
|
||||||
realtimeIP = (isSupp) ? notifier2Udp.remoteIP() : notifierUdp.remoteIP();
|
//UDP realtime: 1 warls 2 drgb 3 drgbw 4 dnrgb 5 dnrgbw
|
||||||
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_TPM2NET);
|
if (udpIn[0] > 0 && udpIn[0] < 6) {
|
||||||
if (realtimeOverride) return;
|
realtimeIP = (isSupp) ? notifier2Udp.remoteIP() : notifierUdp.remoteIP();
|
||||||
|
DEBUG_PRINTLN(realtimeIP);
|
||||||
|
if (packetSize < 2) return;
|
||||||
|
|
||||||
tpmPacketCount++; //increment the packet count
|
if (udpIn[1] == 0) {
|
||||||
if (tpmPacketCount == 1) tpmPayloadFrameSize = (udpIn[2] << 8) + udpIn[3]; //save frame size for the whole payload if this is the first packet
|
realtimeTimeout = 0; // cancel realtime mode immediately
|
||||||
byte packetNum = udpIn[4]; //starts with 1!
|
return;
|
||||||
byte numPackets = udpIn[5];
|
} else {
|
||||||
|
realtimeLock(udpIn[1]*1000 +1, REALTIME_MODE_UDP);
|
||||||
|
}
|
||||||
|
if (realtimeOverride) return;
|
||||||
|
|
||||||
unsigned id = (tpmPayloadFrameSize/3)*(packetNum-1); //start LED
|
unsigned totalLen = strip.getLengthTotal();
|
||||||
unsigned totalLen = strip.getLengthTotal();
|
if (udpIn[0] == 1 && packetSize > 5) { //warls
|
||||||
for (size_t i = 6; i < tpmPayloadFrameSize + 4U && id < totalLen; i += 3, id++) {
|
for (size_t i = 2; i < packetSize -3; i += 4) {
|
||||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
setRealtimePixel(udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3], 0);
|
||||||
}
|
}
|
||||||
if (tpmPacketCount == numPackets) { //reset packet count and show if all packets were received
|
} else if (udpIn[0] == 2 && packetSize > 4) { //drgb
|
||||||
tpmPacketCount = 0;
|
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();
|
if (useMainSegmentOnly) strip.trigger();
|
||||||
else strip.show();
|
else strip.show();
|
||||||
}
|
|
||||||
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;
|
return;
|
||||||
} else {
|
|
||||||
realtimeLock(udpIn[1]*1000 +1, REALTIME_MODE_UDP);
|
|
||||||
}
|
}
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// API over UDP
|
// API over UDP
|
||||||
@@ -669,6 +658,8 @@ void handleNotifications()
|
|||||||
}
|
}
|
||||||
releaseJSONBufferLock();
|
releaseJSONBufferLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UsermodManager::onUdpPacket(udpIn, packetSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,10 @@ bool UsermodManager::onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#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::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
|
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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user