From 077b4d5c89ef574337eae2dcbce44df703566a04 Mon Sep 17 00:00:00 2001 From: Phil Bolduc Date: Sun, 19 Sep 2021 12:08:05 -0700 Subject: [PATCH 01/10] Add initial DDP UDP output --- wled00/DDP.cpp | 123 +++++++++++++++++++++++++++++++++++++++++++++++++ wled00/DDP.h | 4 ++ 2 files changed, 127 insertions(+) create mode 100644 wled00/DDP.cpp create mode 100644 wled00/DDP.h diff --git a/wled00/DDP.cpp b/wled00/DDP.cpp new file mode 100644 index 000000000..9c3818d93 --- /dev/null +++ b/wled00/DDP.cpp @@ -0,0 +1,123 @@ + +/* +** Expected interface: +** +** realtimeBrodacast(IPAddress client, uint16_t busLength, byte rgbwData[busLength][4]); +** +*/ + +#include +#include +#include "DDP.h" + +#define DDP_HEADER_LEN 10 +#define DDP_SYNCPACKET_LEN 10 + +#define DDP_FLAGS1_VER 0xc0 // version mask +#define DDP_FLAGS1_VER1 0x40 // version=1 +#define DDP_FLAGS1_PUSH 0x01 +#define DDP_FLAGS1_QUERY 0x02 +#define DDP_FLAGS1_REPLY 0x04 +#define DDP_FLAGS1_STORAGE 0x08 +#define DDP_FLAGS1_TIME 0x10 + +#define DDP_ID_DISPLAY 1 +#define DDP_ID_CONFIG 250 +#define DDP_ID_STATUS 251 + +//1440 channels per packet +#define DDP_CHANNELS_PER_PACKET 1440 // 480 leds + + +// +// copies a 4 byte rgbw buffer to a 3 byte rgb buffer (skipping the w channel) +// +// destination - the buffer to write to +// source - the buffer to read from +// length - the number of 4 byte channels in the source buffer +// +void copyRgbwToRgb(byte *destination, byte *source, uint16_t length) { + + uint16_t destinationOffset = 0; + uint16_t sourceOffset = 0; + + for (uint16_t offset = 0; offset < length; offset++) + { + destination[destinationOffset+0] = source[sourceOffset+0]; + destination[destinationOffset+1] = source[sourceOffset+1]; + destination[destinationOffset+2] = source[sourceOffset+2]; + + destinationOffset += 3; + sourceOffset += 4; + } +} + +// +// Send real time DDP UDP updates to the specified client +// +// client - the IP address to send to +// busLength - the number of pixels +// rgbwData - a buffer of at least busLength*4 bytes long +// +uint8_t realtimeBrodacast(IPAddress client, uint16_t busLength, byte *rgbwData) { + + WiFiUDP ddpUdp; + + // calclate the number of UDP packets we need to send + uint16_t channelCount = busLength * 3; + uint16_t packetCount = channelCount / DDP_CHANNELS_PER_PACKET; + if (channelCount % DDP_CHANNELS_PER_PACKET) { + packetCount++; + } + + // allocate a buffer for the UDP packet + size_t bufferSize = DDP_HEADER_LEN + DDP_CHANNELS_PER_PACKET ; + byte* buffer = (byte*)malloc(bufferSize); + if (!buffer) { + return 1; + } + + memset(buffer, 0, bufferSize); + + // set common header values + buffer[0] = DDP_FLAGS1_VER1; + buffer[2] = 1; + buffer[3] = DDP_ID_DISPLAY; + + // there are 3 channels per RGB pixel + int channel = 0; // TODO: allow specifying the start channel + + for (int packetIndex = 0; packetIndex < packetCount; packetIndex++) { + + // how much data is after the header + uint16_t packetSize = DDP_CHANNELS_PER_PACKET; + + if (packetIndex == (packetCount -1)) { + // last packet, set the push flag + buffer[0] = DDP_FLAGS1_VER1 | DDP_FLAGS1_PUSH; + + if (channelCount % DDP_CHANNELS_PER_PACKET) { + packetSize = channelCount % DDP_CHANNELS_PER_PACKET; + } + } + + //offset + buffer[4] = (channel & 0xFF000000) >> 24; + buffer[5] = (channel & 0xFF0000) >> 16; + buffer[6] = (channel & 0xFF00) >> 8; + buffer[7] = (channel & 0xFF); + + //size + buffer[8] = (packetSize & 0xFF00) >> 8; + buffer[9] = packetSize & 0xFF; + + // copy the data into our buffer + copyRgbwToRgb(&buffer[DDP_HEADER_LEN], rgbwData, busLength); + + ddpUdp.beginPacket(client, DDP_PORT); + ddpUdp.write(buffer, packetSize); + ddpUdp.endPacket(); + + channel += packetSize; + } +} diff --git a/wled00/DDP.h b/wled00/DDP.h new file mode 100644 index 000000000..b591ec32b --- /dev/null +++ b/wled00/DDP.h @@ -0,0 +1,4 @@ +#define DDP_PORT 4048 + +#define DDP_PUSH_FLAG 0x01 +#define DDP_TIMECODE_FLAG 0x10 From 95c87919a8707c0f9cd5c23e492002d3281acc5e Mon Sep 17 00:00:00 2001 From: Phil Bolduc Date: Sun, 19 Sep 2021 12:11:57 -0700 Subject: [PATCH 02/10] return ok status code and free buffer --- wled00/DDP.cpp | 5 ++++- wled00/DDP.h | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/wled00/DDP.cpp b/wled00/DDP.cpp index 9c3818d93..c682232d1 100644 --- a/wled00/DDP.cpp +++ b/wled00/DDP.cpp @@ -62,7 +62,7 @@ void copyRgbwToRgb(byte *destination, byte *source, uint16_t length) { uint8_t realtimeBrodacast(IPAddress client, uint16_t busLength, byte *rgbwData) { WiFiUDP ddpUdp; - + // calclate the number of UDP packets we need to send uint16_t channelCount = busLength * 3; uint16_t packetCount = channelCount / DDP_CHANNELS_PER_PACKET; @@ -120,4 +120,7 @@ uint8_t realtimeBrodacast(IPAddress client, uint16_t busLength, byte *rgbwData) channel += packetSize; } + + free(buffer); + return 0; } diff --git a/wled00/DDP.h b/wled00/DDP.h index b591ec32b..82dd0cdc4 100644 --- a/wled00/DDP.h +++ b/wled00/DDP.h @@ -2,3 +2,15 @@ #define DDP_PUSH_FLAG 0x01 #define DDP_TIMECODE_FLAG 0x10 + +// +// Send real time DDP UDP updates to the specified client +// +// client - the IP address to send to +// busLength - the number of pixels +// rgbwData - a buffer of at least busLength*4 bytes long +// +// Returns +// 0 - Ok +// 1 - could not allocate buffer +uint8_t realtimeBrodacast(IPAddress client, uint16_t busLength, byte *rgbwData); From 6472d35d913005216102c4faa76841e7a50f92ba Mon Sep 17 00:00:00 2001 From: Phil Bolduc Date: Sun, 19 Sep 2021 15:20:06 -0700 Subject: [PATCH 03/10] optimze copyRgbwToRgb, do not copy too much data into buffer --- wled00/DDP.cpp | 55 ++++++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/wled00/DDP.cpp b/wled00/DDP.cpp index c682232d1..2cc85c131 100644 --- a/wled00/DDP.cpp +++ b/wled00/DDP.cpp @@ -4,6 +4,7 @@ ** ** realtimeBrodacast(IPAddress client, uint16_t busLength, byte rgbwData[busLength][4]); ** +** http://www.3waylabs.com/ddp/ */ #include @@ -32,24 +33,24 @@ // // copies a 4 byte rgbw buffer to a 3 byte rgb buffer (skipping the w channel) // -// destination - the buffer to write to -// source - the buffer to read from -// length - the number of 4 byte channels in the source buffer -// -void copyRgbwToRgb(byte *destination, byte *source, uint16_t length) { - - uint16_t destinationOffset = 0; - uint16_t sourceOffset = 0; +// Parameters: +// destination - the buffer to write to must be able to hold length*3 bytes +// source - the buffer to read from +// length - the number of 4 byte channels in the source buffer +// Returns: +// the pointer in the source where we have copied up to +// +uint8_t* copyRgbwToRgb(uint8_t *destination, uint8_t *source, uint16_t length) { - for (uint16_t offset = 0; offset < length; offset++) + while (length--) { - destination[destinationOffset+0] = source[sourceOffset+0]; - destination[destinationOffset+1] = source[sourceOffset+1]; - destination[destinationOffset+2] = source[sourceOffset+2]; - - destinationOffset += 3; - sourceOffset += 4; + *(destination++) = *(source++); // R + *(destination++) = *(source++); // G + *(destination++) = *(source++); // B + source++; // W } + + return source; } // @@ -59,7 +60,7 @@ void copyRgbwToRgb(byte *destination, byte *source, uint16_t length) { // busLength - the number of pixels // rgbwData - a buffer of at least busLength*4 bytes long // -uint8_t realtimeBrodacast(IPAddress client, uint16_t busLength, byte *rgbwData) { +uint8_t realtimeBrodacast(IPAddress client, uint16_t busLength, uint8_t *rgbwData) { WiFiUDP ddpUdp; @@ -71,8 +72,8 @@ uint8_t realtimeBrodacast(IPAddress client, uint16_t busLength, byte *rgbwData) } // allocate a buffer for the UDP packet - size_t bufferSize = DDP_HEADER_LEN + DDP_CHANNELS_PER_PACKET ; - byte* buffer = (byte*)malloc(bufferSize); + size_t bufferSize = (DDP_HEADER_LEN + DDP_CHANNELS_PER_PACKET) * sizeof(uint8_t); + uint8_t* buffer = (byte*)malloc(bufferSize); if (!buffer) { return 1; } @@ -87,13 +88,19 @@ uint8_t realtimeBrodacast(IPAddress client, uint16_t busLength, byte *rgbwData) // there are 3 channels per RGB pixel int channel = 0; // TODO: allow specifying the start channel - for (int packetIndex = 0; packetIndex < packetCount; packetIndex++) { + // if we need to split + // + // + + + for (uint16_t currentPacket = 0; currentPacket < packetCount; currentPacket++) { // how much data is after the header uint16_t packetSize = DDP_CHANNELS_PER_PACKET; - if (packetIndex == (packetCount -1)) { + if (currentPacket == (packetCount - 1)) { // last packet, set the push flag + // TODO: determine if we want to send an empty push packet to each destination after sending the pixel data buffer[0] = DDP_FLAGS1_VER1 | DDP_FLAGS1_PUSH; if (channelCount % DDP_CHANNELS_PER_PACKET) { @@ -101,18 +108,18 @@ uint8_t realtimeBrodacast(IPAddress client, uint16_t busLength, byte *rgbwData) } } - //offset + // data offset in bytes, 32-bit number, MSB first buffer[4] = (channel & 0xFF000000) >> 24; buffer[5] = (channel & 0xFF0000) >> 16; buffer[6] = (channel & 0xFF00) >> 8; buffer[7] = (channel & 0xFF); - //size + // data length in bytes, 16-bit number, MSB first buffer[8] = (packetSize & 0xFF00) >> 8; buffer[9] = packetSize & 0xFF; - // copy the data into our buffer - copyRgbwToRgb(&buffer[DDP_HEADER_LEN], rgbwData, busLength); + // copy the data from the source buffer into our pack + rgbwData = copyRgbwToRgb(&buffer[DDP_HEADER_LEN], rgbwData, packetSize); ddpUdp.beginPacket(client, DDP_PORT); ddpUdp.write(buffer, packetSize); From 7dc07f6d2106395c551a53b780f897000e551622 Mon Sep 17 00:00:00 2001 From: Phil Bolduc Date: Sun, 19 Sep 2021 15:30:17 -0700 Subject: [PATCH 04/10] Change parameter order for better stack alignment --- wled00/DDP.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/wled00/DDP.cpp b/wled00/DDP.cpp index 2cc85c131..dfbb8fcb4 100644 --- a/wled00/DDP.cpp +++ b/wled00/DDP.cpp @@ -57,15 +57,15 @@ uint8_t* copyRgbwToRgb(uint8_t *destination, uint8_t *source, uint16_t length) { // Send real time DDP UDP updates to the specified client // // client - the IP address to send to -// busLength - the number of pixels -// rgbwData - a buffer of at least busLength*4 bytes long +// length - the number of pixels +// rgbwData - a buffer of at least length*4 bytes long // -uint8_t realtimeBrodacast(IPAddress client, uint16_t busLength, uint8_t *rgbwData) { +uint8_t realtimeBrodacast(IPAddress client, uint8_t *rgbwData, uint16_t length) { WiFiUDP ddpUdp; // calclate the number of UDP packets we need to send - uint16_t channelCount = busLength * 3; + uint16_t channelCount = length * 3; // 1 channel for every R,G,B value uint16_t packetCount = channelCount / DDP_CHANNELS_PER_PACKET; if (channelCount % DDP_CHANNELS_PER_PACKET) { packetCount++; @@ -73,7 +73,7 @@ uint8_t realtimeBrodacast(IPAddress client, uint16_t busLength, uint8_t *rgbwDat // allocate a buffer for the UDP packet size_t bufferSize = (DDP_HEADER_LEN + DDP_CHANNELS_PER_PACKET) * sizeof(uint8_t); - uint8_t* buffer = (byte*)malloc(bufferSize); + uint8_t* buffer = (uint8_t*)malloc(bufferSize); if (!buffer) { return 1; } @@ -86,12 +86,7 @@ uint8_t realtimeBrodacast(IPAddress client, uint16_t busLength, uint8_t *rgbwDat buffer[3] = DDP_ID_DISPLAY; // there are 3 channels per RGB pixel - int channel = 0; // TODO: allow specifying the start channel - - // if we need to split - // - // - + uint16_t channel = 0; // TODO: allow specifying the start channel for (uint16_t currentPacket = 0; currentPacket < packetCount; currentPacket++) { From d1f4cdebf3987d08fb8ec5902f6ef4d2aa411c27 Mon Sep 17 00:00:00 2001 From: Phil Bolduc Date: Mon, 20 Sep 2021 15:04:16 -0700 Subject: [PATCH 05/10] Move new ddp/udp functions into udp.cpp --- wled00/DDP.cpp | 128 ------------------------------------------------- wled00/DDP.h | 16 ------- wled00/udp.cpp | 114 +++++++++++++++++++++++++++++++++++++++++++ wled00/udp.h | 97 +++++++++++++++++++++++++++++++++++++ wled00/wled.h | 1 + 5 files changed, 212 insertions(+), 144 deletions(-) delete mode 100644 wled00/DDP.cpp delete mode 100644 wled00/DDP.h create mode 100644 wled00/udp.h diff --git a/wled00/DDP.cpp b/wled00/DDP.cpp deleted file mode 100644 index dfbb8fcb4..000000000 --- a/wled00/DDP.cpp +++ /dev/null @@ -1,128 +0,0 @@ - -/* -** Expected interface: -** -** realtimeBrodacast(IPAddress client, uint16_t busLength, byte rgbwData[busLength][4]); -** -** http://www.3waylabs.com/ddp/ -*/ - -#include -#include -#include "DDP.h" - -#define DDP_HEADER_LEN 10 -#define DDP_SYNCPACKET_LEN 10 - -#define DDP_FLAGS1_VER 0xc0 // version mask -#define DDP_FLAGS1_VER1 0x40 // version=1 -#define DDP_FLAGS1_PUSH 0x01 -#define DDP_FLAGS1_QUERY 0x02 -#define DDP_FLAGS1_REPLY 0x04 -#define DDP_FLAGS1_STORAGE 0x08 -#define DDP_FLAGS1_TIME 0x10 - -#define DDP_ID_DISPLAY 1 -#define DDP_ID_CONFIG 250 -#define DDP_ID_STATUS 251 - -//1440 channels per packet -#define DDP_CHANNELS_PER_PACKET 1440 // 480 leds - - -// -// copies a 4 byte rgbw buffer to a 3 byte rgb buffer (skipping the w channel) -// -// Parameters: -// destination - the buffer to write to must be able to hold length*3 bytes -// source - the buffer to read from -// length - the number of 4 byte channels in the source buffer -// Returns: -// the pointer in the source where we have copied up to -// -uint8_t* copyRgbwToRgb(uint8_t *destination, uint8_t *source, uint16_t length) { - - while (length--) - { - *(destination++) = *(source++); // R - *(destination++) = *(source++); // G - *(destination++) = *(source++); // B - source++; // W - } - - return source; -} - -// -// Send real time DDP UDP updates to the specified client -// -// client - the IP address to send to -// length - the number of pixels -// rgbwData - a buffer of at least length*4 bytes long -// -uint8_t realtimeBrodacast(IPAddress client, uint8_t *rgbwData, uint16_t length) { - - WiFiUDP ddpUdp; - - // calclate the number of UDP packets we need to send - uint16_t channelCount = length * 3; // 1 channel for every R,G,B value - uint16_t packetCount = channelCount / DDP_CHANNELS_PER_PACKET; - if (channelCount % DDP_CHANNELS_PER_PACKET) { - packetCount++; - } - - // allocate a buffer for the UDP packet - size_t bufferSize = (DDP_HEADER_LEN + DDP_CHANNELS_PER_PACKET) * sizeof(uint8_t); - uint8_t* buffer = (uint8_t*)malloc(bufferSize); - if (!buffer) { - return 1; - } - - memset(buffer, 0, bufferSize); - - // set common header values - buffer[0] = DDP_FLAGS1_VER1; - buffer[2] = 1; - buffer[3] = DDP_ID_DISPLAY; - - // there are 3 channels per RGB pixel - uint16_t channel = 0; // TODO: allow specifying the start channel - - for (uint16_t currentPacket = 0; currentPacket < packetCount; currentPacket++) { - - // how much data is after the header - uint16_t packetSize = DDP_CHANNELS_PER_PACKET; - - if (currentPacket == (packetCount - 1)) { - // last packet, set the push flag - // TODO: determine if we want to send an empty push packet to each destination after sending the pixel data - buffer[0] = DDP_FLAGS1_VER1 | DDP_FLAGS1_PUSH; - - if (channelCount % DDP_CHANNELS_PER_PACKET) { - packetSize = channelCount % DDP_CHANNELS_PER_PACKET; - } - } - - // data offset in bytes, 32-bit number, MSB first - buffer[4] = (channel & 0xFF000000) >> 24; - buffer[5] = (channel & 0xFF0000) >> 16; - buffer[6] = (channel & 0xFF00) >> 8; - buffer[7] = (channel & 0xFF); - - // data length in bytes, 16-bit number, MSB first - buffer[8] = (packetSize & 0xFF00) >> 8; - buffer[9] = packetSize & 0xFF; - - // copy the data from the source buffer into our pack - rgbwData = copyRgbwToRgb(&buffer[DDP_HEADER_LEN], rgbwData, packetSize); - - ddpUdp.beginPacket(client, DDP_PORT); - ddpUdp.write(buffer, packetSize); - ddpUdp.endPacket(); - - channel += packetSize; - } - - free(buffer); - return 0; -} diff --git a/wled00/DDP.h b/wled00/DDP.h deleted file mode 100644 index 82dd0cdc4..000000000 --- a/wled00/DDP.h +++ /dev/null @@ -1,16 +0,0 @@ -#define DDP_PORT 4048 - -#define DDP_PUSH_FLAG 0x01 -#define DDP_TIMECODE_FLAG 0x10 - -// -// Send real time DDP UDP updates to the specified client -// -// client - the IP address to send to -// busLength - the number of pixels -// rgbwData - a buffer of at least busLength*4 bytes long -// -// Returns -// 0 - Ok -// 1 - could not allocate buffer -uint8_t realtimeBrodacast(IPAddress client, uint16_t busLength, byte *rgbwData); diff --git a/wled00/udp.cpp b/wled00/udp.cpp index 23a9de14e..25756b663 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -1,4 +1,5 @@ #include "wled.h" +#include "src/dependencies/json/ArduinoJson-v6.h" /* * UDP sync notifier / Realtime / Hyperion / TPM2.NET @@ -511,3 +512,116 @@ void sendSysInfoUDP() notifier2Udp.write(data, sizeof(data)); notifier2Udp.endPacket(); } + + +/*********************************************************************************************\ + * Art-Net, DDP, E131 output - work in progress +\*********************************************************************************************/ + +#define DDP_HEADER_LEN 10 +#define DDP_SYNCPACKET_LEN 10 + +#define DDP_FLAGS1_VER 0xc0 // version mask +#define DDP_FLAGS1_VER1 0x40 // version=1 +#define DDP_FLAGS1_PUSH 0x01 +#define DDP_FLAGS1_QUERY 0x02 +#define DDP_FLAGS1_REPLY 0x04 +#define DDP_FLAGS1_STORAGE 0x08 +#define DDP_FLAGS1_TIME 0x10 + +#define DDP_ID_DISPLAY 1 +#define DDP_ID_CONFIG 250 +#define DDP_ID_STATUS 251 + +// 1440 channels per packet +#define DDP_CHANNELS_PER_PACKET 1440 // 480 leds + +// +// copies a 4 byte rgbw buffer to a 3 byte rgb buffer (skipping the w channel) +// +// Parameters: +// destination - the buffer to write to must be able to hold length*3 bytes +// source - the buffer to read from +// length - the number of 4 byte channels in the source buffer +// Returns: +// the pointer in the source where we have copied up to +// +uint8_t* copyRgbwToRgb(uint8_t *destination, uint8_t *source, uint16_t length) { + + while (length--) + { + *(destination++) = *(source++); // R + *(destination++) = *(source++); // G + *(destination++) = *(source++); // B + source++; // W + } + + return source; +} + +// +// Send real time DDP UDP updates to the specified client +// +// client - the IP address to send to +// length - the number of pixels +// rgbwData - a buffer of at least length*4 bytes long +// +uint8_t realtimeBrodacast(IPAddress client, uint8_t *rgbwData, uint16_t length) { + + WiFiUDP ddpUdp; + + // calclate the number of UDP packets we need to send + uint16_t channelCount = length * 3; // 1 channel for every R,G,B value + uint16_t packetCount = channelCount / DDP_CHANNELS_PER_PACKET; + if (channelCount % DDP_CHANNELS_PER_PACKET) { + packetCount++; + } + + // allocatea buffer on the stack for the UDP packet + uint8_t buffer[DDP_HEADER_LEN + DDP_CHANNELS_PER_PACKET] = { 0 }; + + // set common header values + buffer[0] = DDP_FLAGS1_VER1; + buffer[2] = 1; + buffer[3] = DDP_ID_DISPLAY; + + // there are 3 channels per RGB pixel + uint16_t channel = 0; // TODO: allow specifying the start channel + + for (uint16_t currentPacket = 0; currentPacket < packetCount; currentPacket++) { + + // how much data is after the header + uint16_t packetSize = DDP_CHANNELS_PER_PACKET; + + if (currentPacket == (packetCount - 1)) { + // last packet, set the push flag + // TODO: determine if we want to send an empty push packet to each destination after sending the pixel data + buffer[0] = DDP_FLAGS1_VER1 | DDP_FLAGS1_PUSH; + + if (channelCount % DDP_CHANNELS_PER_PACKET) { + packetSize = channelCount % DDP_CHANNELS_PER_PACKET; + } + } + + // data offset in bytes, 32-bit number, MSB first + buffer[4] = (channel & 0xFF000000) >> 24; + buffer[5] = (channel & 0xFF0000) >> 16; + buffer[6] = (channel & 0xFF00) >> 8; + buffer[7] = (channel & 0xFF); + + // data length in bytes, 16-bit number, MSB first + buffer[8] = (packetSize & 0xFF00) >> 8; + buffer[9] = packetSize & 0xFF; + + // copy the data from the source buffer into our pack + rgbwData = copyRgbwToRgb(&buffer[DDP_HEADER_LEN], rgbwData, packetSize); + + ddpUdp.beginPacket(client, DDP_PORT); + ddpUdp.write(buffer, packetSize); + ddpUdp.endPacket(); + + channel += packetSize; + } + + return 0; +} \ No newline at end of file diff --git a/wled00/udp.h b/wled00/udp.h new file mode 100644 index 000000000..929da5b8f --- /dev/null +++ b/wled00/udp.h @@ -0,0 +1,97 @@ +#ifndef UDP_H +#define UDP_H + +// expected to be included from wled.h where other dependencies are loaded first + +void notify(byte callMode, bool followUp); +void realtimeLock(uint32_t timeoutMs, byte md); +void sendTPM2Ack(); +void handleNotifications(); +void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w); + +/*********************************************************************************************\ + Refresh aging for remote units, drop if too old... +\*********************************************************************************************/ +void refreshNodeList(); + +/*********************************************************************************************\ + Broadcast system info to other nodes. (to update node lists) +\*********************************************************************************************/ +void sendSysInfoUDP(); + +/*********************************************************************************************\ + * Art-Net, DDP, E131 output - work in progress +\*********************************************************************************************/ + +// Send real time DDP UDP updates to the specified client +// +// client - the IP address to send to +// rgbwData - a buffer of at least length*4 bytes long +// length - the number of pixels +// +// Returns +// 0 - Ok +// 1 - could not allocate buffer +// +uint8_t realtimeBrodacast(IPAddress client, uint8_t *rgbwData, uint16_t length); + +#define DDP_PORT 4048 + +#define DDP_PUSH_FLAG 0x01 +#define DDP_TIMECODE_FLAG 0x10 + +#ifdef UPD_OUTPUT // just disable out for now +// Base class for all UDP output types. +class UDPOutputData { +public: + UDPOutputData(const JsonDocument& config); + virtual ~UDPOutputData(); + + virtual bool IsPingable() = 0; + + virtual void PrepareData(unsigned char* channelData /*,UDPOutputMessages& msgs*/) = 0; + virtual void PostPrepareData(unsigned char* channelData /*,UDPOutputMessages& msgs*/) { } + + int startChannel; + int channelCount; + IPAddress ipAddress; + + UDPOutputData(UDPOutputData const&) = delete; + void operator=(UDPOutputData const& x) = delete; + +protected: + // functions and settings to detect duplicate frames to avoid sending the same data as last time + void SaveFrame(unsigned char* channelData, int len); + bool NeedToOutputFrame(unsigned char* channelData, int startChannel, int savedIdx, int count); + bool deDuplicate = false; + int skippedFrames; + unsigned char* lastData; +}; + +// Art-Net - https://en.wikipedia.org/wiki/Art-Net +class ArtNetOutputData : public UDPOutputData { + // TODO +}; + +// Distributed Display Protocol (DDP) +class DDPOutputData : public UDPOutputData { +public: + explicit DDPOutputData(const JsonDocument& config); + virtual ~DDPOutputData(); + + virtual bool IsPingable() override { return true; } + virtual void PrepareData(unsigned char* channelData /*,UDPOutputMessages& msgs*/) override; +}; + +// E1.31 (Streaming-ACN) Protocol +class E131OutputData : public UDPOutputData { + // TODO +}; + +class UDPOutput { +public: + void AddOutput(UDPOutputData*); +}; +#endif // UPD_OUTPUT + +#endif \ No newline at end of file diff --git a/wled00/wled.h b/wled00/wled.h index 00920b960..5e2da98fa 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -144,6 +144,7 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument; #include "NodeStruct.h" #include "pin_manager.h" #include "bus_manager.h" +#include "udp.h" #ifndef CLIENT_SSID #define CLIENT_SSID DEFAULT_CLIENT_SSID From 83f4eeb3b5c5aaa6333d9ca90dabf2e4d6211722 Mon Sep 17 00:00:00 2001 From: Phil Bolduc Date: Mon, 20 Sep 2021 15:21:19 -0700 Subject: [PATCH 06/10] Add support for RGB and RGBW, fix bug where not enough data written --- wled00/udp.cpp | 53 ++++++++++++++++++++++++++++---------------------- wled00/udp.h | 10 +++------- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/wled00/udp.cpp b/wled00/udp.cpp index 25756b663..9eef4e6f7 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -564,9 +564,10 @@ uint8_t* copyRgbwToRgb(uint8_t *destination, uint8_t *source, uint16_t length) { // // client - the IP address to send to // length - the number of pixels -// rgbwData - a buffer of at least length*4 bytes long +// buffer - a buffer of at least length*4 bytes long +// isRGBW - true if the buffer contains 4 components per pixel // -uint8_t realtimeBrodacast(IPAddress client, uint8_t *rgbwData, uint16_t length) { +void realtimeBrodacast(IPAddress client, uint8_t *buffer, uint16_t length, bool isRGBW) { WiFiUDP ddpUdp; @@ -578,25 +579,25 @@ uint8_t realtimeBrodacast(IPAddress client, uint8_t *rgbwData, uint16_t length) } // allocatea buffer on the stack for the UDP packet - uint8_t buffer[DDP_HEADER_LEN + DDP_CHANNELS_PER_PACKET] = { 0 }; + uint8_t packet[DDP_HEADER_LEN + DDP_CHANNELS_PER_PACKET] = { 0 }; // set common header values - buffer[0] = DDP_FLAGS1_VER1; - buffer[2] = 1; - buffer[3] = DDP_ID_DISPLAY; + packet[0] = DDP_FLAGS1_VER1; + packet[2] = 1; + packet[3] = DDP_ID_DISPLAY; // there are 3 channels per RGB pixel uint16_t channel = 0; // TODO: allow specifying the start channel for (uint16_t currentPacket = 0; currentPacket < packetCount; currentPacket++) { - // how much data is after the header + // the amount of data is AFTER the header uint16_t packetSize = DDP_CHANNELS_PER_PACKET; if (currentPacket == (packetCount - 1)) { // last packet, set the push flag // TODO: determine if we want to send an empty push packet to each destination after sending the pixel data - buffer[0] = DDP_FLAGS1_VER1 | DDP_FLAGS1_PUSH; + packet[0] = DDP_FLAGS1_VER1 | DDP_FLAGS1_PUSH; if (channelCount % DDP_CHANNELS_PER_PACKET) { packetSize = channelCount % DDP_CHANNELS_PER_PACKET; @@ -604,24 +605,30 @@ uint8_t realtimeBrodacast(IPAddress client, uint8_t *rgbwData, uint16_t length) } // data offset in bytes, 32-bit number, MSB first - buffer[4] = (channel & 0xFF000000) >> 24; - buffer[5] = (channel & 0xFF0000) >> 16; - buffer[6] = (channel & 0xFF00) >> 8; - buffer[7] = (channel & 0xFF); + packet[4] = (channel & 0xFF000000) >> 24; + packet[5] = (channel & 0xFF0000) >> 16; + packet[6] = (channel & 0xFF00) >> 8; + packet[7] = (channel & 0xFF); // data length in bytes, 16-bit number, MSB first - buffer[8] = (packetSize & 0xFF00) >> 8; - buffer[9] = packetSize & 0xFF; + packet[8] = (packetSize & 0xFF00) >> 8; + packet[9] = packetSize & 0xFF; - // copy the data from the source buffer into our pack - rgbwData = copyRgbwToRgb(&buffer[DDP_HEADER_LEN], rgbwData, packetSize); - - ddpUdp.beginPacket(client, DDP_PORT); - ddpUdp.write(buffer, packetSize); - ddpUdp.endPacket(); + if (isRGBW) { + // copy the data from the source buffer into our packet + buffer = copyRgbwToRgb(&packet[DDP_HEADER_LEN], buffer, packetSize); + ddpUdp.beginPacket(client, DDP_PORT); + ddpUdp.write(packet, DDP_HEADER_LEN + packetSize); + ddpUdp.endPacket(); + } else { + // write the rgb values directly from the user supplied buffer + ddpUdp.beginPacket(client, DDP_PORT); + ddpUdp.write(packet, DDP_HEADER_LEN); + ddpUdp.write(buffer, packetSize); + ddpUdp.endPacket(); + buffer += packetSize; // advance the buffer over the written bytes + } channel += packetSize; } - - return 0; -} \ No newline at end of file +} diff --git a/wled00/udp.h b/wled00/udp.h index 929da5b8f..7f23d57fe 100644 --- a/wled00/udp.h +++ b/wled00/udp.h @@ -26,14 +26,10 @@ void sendSysInfoUDP(); // Send real time DDP UDP updates to the specified client // // client - the IP address to send to -// rgbwData - a buffer of at least length*4 bytes long +// buffer - a buffer of at least length*3 or length*4 bytes long // length - the number of pixels -// -// Returns -// 0 - Ok -// 1 - could not allocate buffer -// -uint8_t realtimeBrodacast(IPAddress client, uint8_t *rgbwData, uint16_t length); +// isRGBW - true if the buffer contains 4 components per pixel +void realtimeBrodacast(IPAddress client, uint8_t *buffer, uint16_t length, bool isRGBW); #define DDP_PORT 4048 From 700f641e298d56a637a9e6132636075adb30cc9d Mon Sep 17 00:00:00 2001 From: Phil Bolduc Date: Mon, 20 Sep 2021 15:51:12 -0700 Subject: [PATCH 07/10] Change signature of realtimeBoroadcast to match blazoncek --- wled00/udp.cpp | 2 +- wled00/udp.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/udp.cpp b/wled00/udp.cpp index 9eef4e6f7..2900d031b 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -567,7 +567,7 @@ uint8_t* copyRgbwToRgb(uint8_t *destination, uint8_t *source, uint16_t length) { // buffer - a buffer of at least length*4 bytes long // isRGBW - true if the buffer contains 4 components per pixel // -void realtimeBrodacast(IPAddress client, uint8_t *buffer, uint16_t length, bool isRGBW) { +void realtimeBoroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bool isRGBW) { WiFiUDP ddpUdp; diff --git a/wled00/udp.h b/wled00/udp.h index 7f23d57fe..cc1462033 100644 --- a/wled00/udp.h +++ b/wled00/udp.h @@ -29,7 +29,7 @@ void sendSysInfoUDP(); // buffer - a buffer of at least length*3 or length*4 bytes long // length - the number of pixels // isRGBW - true if the buffer contains 4 components per pixel -void realtimeBrodacast(IPAddress client, uint8_t *buffer, uint16_t length, bool isRGBW); +void realtimeBoroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bool isRGBW); #define DDP_PORT 4048 From cc661b26fa9a5c6a41282fb90901e37a60cfea81 Mon Sep 17 00:00:00 2001 From: Phil Bolduc Date: Mon, 20 Sep 2021 16:57:54 -0700 Subject: [PATCH 08/10] fix spelling error, be smarter how we write data to udp --- wled00/bus_manager.h | 2 +- wled00/fcn_declare.h | 2 +- wled00/udp.cpp | 79 +++++++++++++++++++++++--------------------- wled00/udp.h | 2 +- 4 files changed, 44 insertions(+), 41 deletions(-) diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 0bec1e3f7..71cd3a6fe 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -386,7 +386,7 @@ class BusVirtual : public Bus { void show() { if (!_valid || _broadcastLock) return; _broadcastLock = true; - realtimeBoroadcast(_client, _len, _data, _rgbw); + realtimeBroadcast(_client, _len, _data, _rgbw); _broadcastLock = false; } diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 3556bbd24..ea1f4897f 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -197,7 +197,7 @@ bool updateVal(const String* req, const char* key, byte* val, byte minv=0, byte //udp.cpp void notify(byte callMode, bool followUp=false); -void realtimeBoroadcast(IPAddress client, uint16_t length, byte *buffer, bool isRGBW); +uint8_t realtimeBroadcast(IPAddress client, uint16_t length, byte *buffer, bool isRGBW); void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC); void handleNotifications(); void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w); diff --git a/wled00/udp.cpp b/wled00/udp.cpp index a64f0e3aa..48667b992 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -90,13 +90,6 @@ void notify(byte callMode, bool followUp) notificationTwoRequired = (followUp)? false:notifyTwice; } - -void realtimeBoroadcast(IPAddress client, uint16_t length, byte *buffer, bool isRGBW) -{ - -} - - void realtimeLock(uint32_t timeoutMs, byte md) { if (!realtimeMode && !realtimeOverride){ @@ -546,24 +539,29 @@ void sendSysInfoUDP() // 1440 channels per packet #define DDP_CHANNELS_PER_PACKET 1440 // 480 leds -// -// copies a 4 byte rgbw buffer to a 3 byte rgb buffer (skipping the w channel) -// -// Parameters: -// destination - the buffer to write to must be able to hold length*3 bytes -// source - the buffer to read from -// length - the number of 4 byte channels in the source buffer -// Returns: -// the pointer in the source where we have copied up to -// -uint8_t* copyRgbwToRgb(uint8_t *destination, uint8_t *source, uint16_t length) { - + +uint8_t *writeRgbwTo(WiFiUDP ddpUdp, uint8_t *source, uint16_t length) { + // Note: WiFiUDP.write(buffer, size) is just a wrapper around WiFiUDP.write(byte) + // No benefit to copy to another buffer while (length--) { - *(destination++) = *(source++); // R - *(destination++) = *(source++); // G - *(destination++) = *(source++); // B - source++; // W + ddpUdp.write(*(source++)); // R + ddpUdp.write(*(source++)); // G + ddpUdp.write(*(source++)); // B + source++; // W + } + + return source; +} + +uint8_t *writeRgbTo(WiFiUDP ddpUdp, uint8_t *source, uint16_t length) { + // Note: WiFiUDP.write(buffer, size) is just a wrapper around WiFiUDP.write(byte) + // No benefit to copy to another buffer + while (length--) + { + ddpUdp.write(*(source++)); // R + ddpUdp.write(*(source++)); // G + ddpUdp.write(*(source++)); // B } return source; @@ -577,7 +575,12 @@ uint8_t* copyRgbwToRgb(uint8_t *destination, uint8_t *source, uint16_t length) { // buffer - a buffer of at least length*4 bytes long // isRGBW - true if the buffer contains 4 components per pixel // -void realtimeBroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bool isRGBW) { +uint8_t realtimeBroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bool isRGBW) { + + // function to write the bytes into WiFiUDP + uint8_t *(*writeTo)(WiFiUDP, uint8_t *, uint16_t) = isRGBW + ? &writeRgbwTo + : &writeRgbTo; WiFiUDP ddpUdp; @@ -589,7 +592,7 @@ void realtimeBroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bool } // allocatea buffer on the stack for the UDP packet - uint8_t packet[DDP_HEADER_LEN + DDP_CHANNELS_PER_PACKET] = { 0 }; + uint8_t packet[DDP_HEADER_LEN] = { 0 }; // set common header values packet[0] = DDP_FLAGS1_VER1; @@ -624,21 +627,21 @@ void realtimeBroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bool packet[8] = (packetSize & 0xFF00) >> 8; packet[9] = packetSize & 0xFF; - if (isRGBW) { - // copy the data from the source buffer into our packet - buffer = copyRgbwToRgb(&packet[DDP_HEADER_LEN], buffer, packetSize); - ddpUdp.beginPacket(client, DDP_PORT); - ddpUdp.write(packet, DDP_HEADER_LEN + packetSize); - ddpUdp.endPacket(); - } else { - // write the rgb values directly from the user supplied buffer - ddpUdp.beginPacket(client, DDP_PORT); - ddpUdp.write(packet, DDP_HEADER_LEN); - ddpUdp.write(buffer, packetSize); - ddpUdp.endPacket(); - buffer += packetSize; // advance the buffer over the written bytes + int rc = ddpUdp.beginPacket(client, DDP_PORT); + if (rc == 0) { + return 1; // problem + } + // write the header + ddpUdp.write(packet, DDP_HEADER_LEN + packetSize); + // write the colors, and adjust buffer to point at end of data written + buffer = (*writeTo)(ddpUdp, buffer, packetSize); + rc = ddpUdp.endPacket(); + if (rc == 0) { + return 1; // problem } channel += packetSize; } + + return 0; } diff --git a/wled00/udp.h b/wled00/udp.h index 39eb7a7d1..3765cea08 100644 --- a/wled00/udp.h +++ b/wled00/udp.h @@ -29,7 +29,7 @@ void sendSysInfoUDP(); // buffer - a buffer of at least length*3 or length*4 bytes long // length - the number of pixels // isRGBW - true if the buffer contains 4 components per pixel -void realtimeBroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bool isRGBW); +uint8_t realtimeBroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bool isRGBW); #define DDP_PORT 4048 From 109bb62209438de9e0b1d81c40ef00c6ab5b5b3d Mon Sep 17 00:00:00 2001 From: Phil Bolduc Date: Mon, 20 Sep 2021 19:01:54 -0700 Subject: [PATCH 09/10] fix corrupt heap when writing upd --- wled00/udp.cpp | 76 ++++++++++++++++++-------------------------------- 1 file changed, 27 insertions(+), 49 deletions(-) diff --git a/wled00/udp.cpp b/wled00/udp.cpp index 48667b992..7508f3e6f 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -539,34 +539,6 @@ void sendSysInfoUDP() // 1440 channels per packet #define DDP_CHANNELS_PER_PACKET 1440 // 480 leds - -uint8_t *writeRgbwTo(WiFiUDP ddpUdp, uint8_t *source, uint16_t length) { - // Note: WiFiUDP.write(buffer, size) is just a wrapper around WiFiUDP.write(byte) - // No benefit to copy to another buffer - while (length--) - { - ddpUdp.write(*(source++)); // R - ddpUdp.write(*(source++)); // G - ddpUdp.write(*(source++)); // B - source++; // W - } - - return source; -} - -uint8_t *writeRgbTo(WiFiUDP ddpUdp, uint8_t *source, uint16_t length) { - // Note: WiFiUDP.write(buffer, size) is just a wrapper around WiFiUDP.write(byte) - // No benefit to copy to another buffer - while (length--) - { - ddpUdp.write(*(source++)); // R - ddpUdp.write(*(source++)); // G - ddpUdp.write(*(source++)); // B - } - - return source; -} - // // Send real time DDP UDP updates to the specified client // @@ -577,11 +549,6 @@ uint8_t *writeRgbTo(WiFiUDP ddpUdp, uint8_t *source, uint16_t length) { // uint8_t realtimeBroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bool isRGBW) { - // function to write the bytes into WiFiUDP - uint8_t *(*writeTo)(WiFiUDP, uint8_t *, uint16_t) = isRGBW - ? &writeRgbwTo - : &writeRgbTo; - WiFiUDP ddpUdp; // calclate the number of UDP packets we need to send @@ -592,25 +559,28 @@ uint8_t realtimeBroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bo } // allocatea buffer on the stack for the UDP packet - uint8_t packet[DDP_HEADER_LEN] = { 0 }; + uint8_t header[DDP_HEADER_LEN] = { 0 }; // set common header values - packet[0] = DDP_FLAGS1_VER1; - packet[2] = 1; - packet[3] = DDP_ID_DISPLAY; + header[0] = DDP_FLAGS1_VER1; + header[2] = 1; + header[3] = DDP_ID_DISPLAY; // there are 3 channels per RGB pixel uint16_t channel = 0; // TODO: allow specifying the start channel + // the current position in the buffer + uint16_t bufferOffset = 0; + for (uint16_t currentPacket = 0; currentPacket < packetCount; currentPacket++) { - // the amount of data is AFTER the header + // the amount of data is AFTER the header in the current packet uint16_t packetSize = DDP_CHANNELS_PER_PACKET; if (currentPacket == (packetCount - 1)) { // last packet, set the push flag // TODO: determine if we want to send an empty push packet to each destination after sending the pixel data - packet[0] = DDP_FLAGS1_VER1 | DDP_FLAGS1_PUSH; + header[0] = DDP_FLAGS1_VER1 | DDP_FLAGS1_PUSH; if (channelCount % DDP_CHANNELS_PER_PACKET) { packetSize = channelCount % DDP_CHANNELS_PER_PACKET; @@ -618,25 +588,33 @@ uint8_t realtimeBroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bo } // data offset in bytes, 32-bit number, MSB first - packet[4] = (channel & 0xFF000000) >> 24; - packet[5] = (channel & 0xFF0000) >> 16; - packet[6] = (channel & 0xFF00) >> 8; - packet[7] = (channel & 0xFF); + header[4] = (channel & 0xFF000000) >> 24; + header[5] = (channel & 0xFF0000) >> 16; + header[6] = (channel & 0xFF00) >> 8; + header[7] = (channel & 0xFF); // data length in bytes, 16-bit number, MSB first - packet[8] = (packetSize & 0xFF00) >> 8; - packet[9] = packetSize & 0xFF; + header[8] = (packetSize & 0xFF00) >> 8; + header[9] = packetSize & 0xFF; int rc = ddpUdp.beginPacket(client, DDP_PORT); - if (rc == 0) { + if (rc == 0) { + //DEBUG_PRINTLN("WiFiUDP.beginPacket returned an error"); return 1; // problem } // write the header - ddpUdp.write(packet, DDP_HEADER_LEN + packetSize); - // write the colors, and adjust buffer to point at end of data written - buffer = (*writeTo)(ddpUdp, buffer, packetSize); + ddpUdp.write(header, DDP_HEADER_LEN); + // write the colors, the write write(const uint8_t *buffer, size_t size) + // function is just a loop internally too + for (uint16_t i = 0; i < packetSize; i += 3) { + ddpUdp.write(buffer[bufferOffset++]); // R + ddpUdp.write(buffer[bufferOffset++]); // G + ddpUdp.write(buffer[bufferOffset++]); // B + if (isRGBW) bufferOffset++; + } rc = ddpUdp.endPacket(); if (rc == 0) { + //DEBUG_PRINTLN("WiFiUDP.endPacket returned an error"); return 1; // problem } From fd8d17c5e54e971df0cbf99227a00ad3d3ba0587 Mon Sep 17 00:00:00 2001 From: Phil Bolduc Date: Mon, 20 Sep 2021 20:47:48 -0700 Subject: [PATCH 10/10] Removed local buffer as WiFiUDP loops over input array anyways --- wled00/udp.cpp | 67 ++++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/wled00/udp.cpp b/wled00/udp.cpp index 7508f3e6f..392b2d1ff 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -546,9 +546,10 @@ void sendSysInfoUDP() // length - the number of pixels // buffer - a buffer of at least length*4 bytes long // isRGBW - true if the buffer contains 4 components per pixel -// -uint8_t realtimeBroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bool isRGBW) { +uint8_t sequenceNumber = 0; // this needs to be shared across all outputs + +uint8_t realtimeBroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bool isRGBW) { WiFiUDP ddpUdp; // calclate the number of UDP packets we need to send @@ -558,52 +559,47 @@ uint8_t realtimeBroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bo packetCount++; } - // allocatea buffer on the stack for the UDP packet - uint8_t header[DDP_HEADER_LEN] = { 0 }; - - // set common header values - header[0] = DDP_FLAGS1_VER1; - header[2] = 1; - header[3] = DDP_ID_DISPLAY; - // there are 3 channels per RGB pixel uint16_t channel = 0; // TODO: allow specifying the start channel // the current position in the buffer uint16_t bufferOffset = 0; - for (uint16_t currentPacket = 0; currentPacket < packetCount; currentPacket++) { - - // the amount of data is AFTER the header in the current packet - uint16_t packetSize = DDP_CHANNELS_PER_PACKET; - - if (currentPacket == (packetCount - 1)) { - // last packet, set the push flag - // TODO: determine if we want to send an empty push packet to each destination after sending the pixel data - header[0] = DDP_FLAGS1_VER1 | DDP_FLAGS1_PUSH; - - if (channelCount % DDP_CHANNELS_PER_PACKET) { - packetSize = channelCount % DDP_CHANNELS_PER_PACKET; - } - } - - // data offset in bytes, 32-bit number, MSB first - header[4] = (channel & 0xFF000000) >> 24; - header[5] = (channel & 0xFF0000) >> 16; - header[6] = (channel & 0xFF00) >> 8; - header[7] = (channel & 0xFF); - - // data length in bytes, 16-bit number, MSB first - header[8] = (packetSize & 0xFF00) >> 8; - header[9] = packetSize & 0xFF; + if (sequenceNumber > 15) sequenceNumber = 0; int rc = ddpUdp.beginPacket(client, DDP_PORT); if (rc == 0) { //DEBUG_PRINTLN("WiFiUDP.beginPacket returned an error"); return 1; // problem } + + // the amount of data is AFTER the header in the current packet + uint16_t packetSize = DDP_CHANNELS_PER_PACKET; + + uint8_t flags = DDP_FLAGS1_VER1; + if (currentPacket == (packetCount - 1)) { + // last packet, set the push flag + // TODO: determine if we want to send an empty push packet to each destination after sending the pixel data + flags = DDP_FLAGS1_VER1 | DDP_FLAGS1_PUSH; + if (channelCount % DDP_CHANNELS_PER_PACKET) { + packetSize = channelCount % DDP_CHANNELS_PER_PACKET; + } + } + // write the header - ddpUdp.write(header, DDP_HEADER_LEN); + /*0*/ddpUdp.write(flags); + /*1*/ddpUdp.write(sequenceNumber++ & 0xF); + /*2*/ddpUdp.write(0); + /*3*/ddpUdp.write(DDP_ID_DISPLAY); + // data offset in bytes, 32-bit number, MSB first + /*4*/ddpUdp.write((channel & 0xFF000000) >> 24); + /*5*/ddpUdp.write((channel & 0x00FF0000) >> 16); + /*6*/ddpUdp.write((channel & 0x0000FF00) >> 8); + /*7*/ddpUdp.write((channel & 0x000000FF)); + // data length in bytes, 16-bit number, MSB first + /*8*/ddpUdp.write((packetSize & 0xFF00) >> 8); + /*9*/ddpUdp.write(packetSize & 0xFF); + // write the colors, the write write(const uint8_t *buffer, size_t size) // function is just a loop internally too for (uint16_t i = 0; i < packetSize; i += 3) { @@ -612,6 +608,7 @@ uint8_t realtimeBroadcast(IPAddress client, uint16_t length, uint8_t *buffer, bo ddpUdp.write(buffer[bufferOffset++]); // B if (isRGBW) bufferOffset++; } + rc = ddpUdp.endPacket(); if (rc == 0) { //DEBUG_PRINTLN("WiFiUDP.endPacket returned an error");