68 lines
2.1 KiB
C#
68 lines
2.1 KiB
C#
using System;
|
|
using System.Net.Sockets;
|
|
using System.Threading.Tasks;
|
|
|
|
public class WledDdpClient
|
|
{
|
|
private readonly UdpClient _udp;
|
|
private readonly string _ip;
|
|
private const int Port = 4048; // Standard DDP UDP port
|
|
private byte _sequence = 1;
|
|
|
|
public WledDdpClient(string ipAddress)
|
|
{
|
|
_ip = ipAddress;
|
|
_udp = new UdpClient();
|
|
}
|
|
|
|
public async Task SendFrameAsync(byte[] rgbData)
|
|
{
|
|
// Max payload per packet to stay under standard 1500 byte MTU
|
|
const int maxPixelsPerPacket = 480;
|
|
const int maxBytesPerPacket = maxPixelsPerPacket * 3;
|
|
|
|
int totalBytes = rgbData.Length;
|
|
int offset = 0;
|
|
|
|
while (offset < totalBytes)
|
|
{
|
|
int chunkLength = Math.Min(maxBytesPerPacket, totalBytes - offset);
|
|
bool isLast = (offset + chunkLength) >= totalBytes;
|
|
|
|
byte[] packet = new byte[10 + chunkLength];
|
|
|
|
// Byte 0: Flags. 0x40 = Version 1. 0x01 = Push bit.
|
|
// We only "Push" to the display on the final chunk of the frame.
|
|
packet[0] = (byte)(isLast ? 0x41 : 0x40);
|
|
|
|
// Byte 1: Sequence (0-15)
|
|
packet[1] = _sequence;
|
|
|
|
// Byte 2: Data type (1 = RGB)
|
|
packet[2] = 1;
|
|
|
|
// Byte 3: Destination ID (Default 1)
|
|
packet[3] = 1;
|
|
|
|
// Bytes 4-7: Data Offset (32-bit Big Endian)
|
|
packet[4] = (byte)(offset >> 24);
|
|
packet[5] = (byte)(offset >> 16);
|
|
packet[6] = (byte)(offset >> 8);
|
|
packet[7] = (byte)(offset);
|
|
|
|
// Bytes 8-9: Data Length (16-bit Big Endian)
|
|
packet[8] = (byte)(chunkLength >> 8);
|
|
packet[9] = (byte)(chunkLength);
|
|
|
|
// Copy the pixel payload into the packet
|
|
Buffer.BlockCopy(rgbData, offset, packet, 10, chunkLength);
|
|
|
|
await _udp.SendAsync(packet, packet.Length, _ip, Port);
|
|
|
|
offset += chunkLength;
|
|
}
|
|
|
|
// Increment sequence for the next frame (wrap at 15)
|
|
_sequence = (byte)((_sequence + 1) % 16);
|
|
}
|
|
} |