Move new ddp/udp functions into udp.cpp
This commit is contained in:
parent
7dc07f6d21
commit
d1f4cdebf3
128
wled00/DDP.cpp
128
wled00/DDP.cpp
@ -1,128 +0,0 @@
|
||||
|
||||
/*
|
||||
** Expected interface:
|
||||
**
|
||||
** realtimeBrodacast(IPAddress client, uint16_t busLength, byte rgbwData[busLength][4]);
|
||||
**
|
||||
** http://www.3waylabs.com/ddp/
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFiUdp.h>
|
||||
#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;
|
||||
}
|
16
wled00/DDP.h
16
wled00/DDP.h
@ -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);
|
114
wled00/udp.cpp
114
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;
|
||||
}
|
97
wled00/udp.h
Normal file
97
wled00/udp.h
Normal file
@ -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
|
@ -144,6 +144,7 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument<PSRAM_Allocator>;
|
||||
#include "NodeStruct.h"
|
||||
#include "pin_manager.h"
|
||||
#include "bus_manager.h"
|
||||
#include "udp.h"
|
||||
|
||||
#ifndef CLIENT_SSID
|
||||
#define CLIENT_SSID DEFAULT_CLIENT_SSID
|
||||
|
Loading…
Reference in New Issue
Block a user