From a4fcbb9f67c6fcf32c5bb35aa24b0eb6fadf1384 Mon Sep 17 00:00:00 2001 From: TroyHacks <5659019+troyhacks@users.noreply.github.com> Date: Fri, 10 Mar 2023 13:29:00 -0500 Subject: [PATCH] Art-Net transmit support for network LEDs Like DDP, this allows WLED to address network systems using the Art-Net protocol. Universe starts at zero, because that's the first universe in Art-Net. Works with RGB. It's coded to also work with RGBW, but I couldn't find a great place to enable it without mucking with things I don't understand. --- wled00/bus_manager.cpp | 32 +++++++++++----------- wled00/data/settings_leds.htm | 2 +- wled00/udp.cpp | 51 +++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 17 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 6ab90b2f6..9e4d54a4d 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -383,24 +383,24 @@ uint8_t BusOnOff::getPins(uint8_t* pinArray) { BusNetwork::BusNetwork(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) { _valid = false; -// switch (bc.type) { -// case TYPE_NET_ARTNET_RGB: -// _rgbw = false; -// _UDPtype = 2; -// break; -// case TYPE_NET_E131_RGB: -// _rgbw = false; -// _UDPtype = 1; -// break; -// case TYPE_NET_DDP_RGB: -// _rgbw = false; -// _UDPtype = 0; -// break; -// default: // TYPE_NET_DDP_RGB / TYPE_NET_DDP_RGBW + switch (bc.type) { + case TYPE_NET_ARTNET_RGB: + _rgbw = false; + _UDPtype = 2; + break; + case TYPE_NET_E131_RGB: + _rgbw = false; + _UDPtype = 1; + break; + case TYPE_NET_DDP_RGB: + _rgbw = false; + _UDPtype = 0; + break; + default: // TYPE_NET_DDP_RGB / TYPE_NET_DDP_RGBW _rgbw = bc.type == TYPE_NET_DDP_RGBW; _UDPtype = 0; -// break; -// } + break; + } _UDPchannels = _rgbw ? 4 : 3; _data = (byte *)malloc(bc.count * _UDPchannels); if (_data == nullptr) return; diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 15e39efb2..e6bbde58d 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -345,7 +345,7 @@ ${i+1}: '} - +
Color Order: diff --git a/wled00/udp.cpp b/wled00/udp.cpp index effd597a0..b6370a596 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -791,6 +791,57 @@ uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, uint8 case 2: //ArtNet { + // calculate the number of UDP packets we need to send + size_t channelCount = length * (isRGBW?4:3); // 1 channel for every R,G,B,(W?) value + size_t ARTNET_CHANNELS_PER_PACKET = isRGBW?512:510; // 512/4=128 RGBW LEDs, 510/3=170 RGB LEDs + size_t packetCount = ((channelCount-1)/ARTNET_CHANNELS_PER_PACKET)+1; + + uint32_t channel = 0; + size_t bufferOffset = 0; + + sequenceNumber++; + + for (size_t currentPacket = 0; currentPacket < packetCount; currentPacket++) { + + if (sequenceNumber > 255) sequenceNumber = 0; + + if (!ddpUdp.beginPacket(client, ARTNET_DEFAULT_PORT)) { + DEBUG_PRINTLN(F("Art-Net WiFiUDP.beginPacket returned an error")); + return 1; // borked + } + + size_t packetSize = ARTNET_CHANNELS_PER_PACKET; + + if (currentPacket == (packetCount - 1U)) { + // last packet + if (channelCount % ARTNET_CHANNELS_PER_PACKET) { + packetSize = channelCount % ARTNET_CHANNELS_PER_PACKET; + } + } + + const byte ART_NET_HEADER[12] = {0x41,0x72,0x74,0x2d,0x4e,0x65,0x74,0x00,0x00,0x50,0x00,0x0e}; + + ddpUdp.write(ART_NET_HEADER,12); // This doesn't change. Hard coded ID, OpCode, and protocol version. + ddpUdp.write(sequenceNumber & 0xFF); // sequence number. 1..255 + ddpUdp.write(0x00); // physical - more an FYI, not really used for anything. 0..3 + ddpUdp.write((currentPacket) & 0xFF); // Universe LSB. 1 full packet == 1 full universe, so just use current packet number. + ddpUdp.write(0x00); // Universe MSB, unused. + ddpUdp.write(0xFF & (packetSize >> 8)); // 16-bit length of channel data, MSB + ddpUdp.write(0xFF & (packetSize )); // 16-bit length of channel data, LSB + + for (size_t i = 0; i < packetSize; i += (isRGBW?4:3)) { + ddpUdp.write(scale8(buffer[bufferOffset++], bri)); // R + ddpUdp.write(scale8(buffer[bufferOffset++], bri)); // G + ddpUdp.write(scale8(buffer[bufferOffset++], bri)); // B + if (isRGBW) ddpUdp.write(scale8(buffer[bufferOffset++], bri)); // W + } + + if (!ddpUdp.endPacket()) { + DEBUG_PRINTLN(F("Art-Net WiFiUDP.endPacket returned an error")); + return 1; // borked + } + channel += packetSize; + } } break; } return 0;