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); try { await _udp.SendAsync(packet, packet.Length, _ip, Port); } catch { Console.WriteLine("Connection to matrix failed"); } offset += chunkLength; } // Increment sequence for the next frame (wrap at 15) _sequence = (byte)((_sequence + 1) % 16); } }