11#include " wled.h"
2+ #include " src/dependencies/json/ArduinoJson-v6.h"
23
34/*
45 * UDP sync notifier / Realtime / Hyperion / TPM2.NET
@@ -89,7 +90,6 @@ void notify(byte callMode, bool followUp)
8990 notificationTwoRequired = (followUp)? false :notifyTwice;
9091}
9192
92-
9393void realtimeLock (uint32_t timeoutMs, byte md)
9494{
9595 if (!realtimeMode && !realtimeOverride){
@@ -101,6 +101,10 @@ void realtimeLock(uint32_t timeoutMs, byte md)
101101
102102 realtimeTimeout = millis () + timeoutMs;
103103 if (timeoutMs == 255001 || timeoutMs == 65000 ) realtimeTimeout = UINT32_MAX;
104+ // if strip is off (bri==0) and not already in RTM
105+ if (bri == 0 && !realtimeMode) {
106+ strip.setBrightness (scaledBri (briLast));
107+ }
104108 realtimeMode = md;
105109
106110 if (arlsForceMaxBri && !realtimeOverride) strip.setBrightness (scaledBri (255 ));
@@ -514,3 +518,108 @@ void sendSysInfoUDP()
514518 notifier2Udp.write (data, sizeof (data));
515519 notifier2Udp.endPacket ();
516520}
521+
522+
523+ /* ********************************************************************************************\
524+ * Art-Net, DDP, E131 output - work in progress
525+ \*********************************************************************************************/
526+
527+ #define DDP_HEADER_LEN 10
528+ #define DDP_SYNCPACKET_LEN 10
529+
530+ #define DDP_FLAGS1_VER 0xc0 // version mask
531+ #define DDP_FLAGS1_VER1 0x40 // version=1
532+ #define DDP_FLAGS1_PUSH 0x01
533+ #define DDP_FLAGS1_QUERY 0x02
534+ #define DDP_FLAGS1_REPLY 0x04
535+ #define DDP_FLAGS1_STORAGE 0x08
536+ #define DDP_FLAGS1_TIME 0x10
537+
538+ #define DDP_ID_DISPLAY 1
539+ #define DDP_ID_CONFIG 250
540+ #define DDP_ID_STATUS 251
541+
542+ // 1440 channels per packet
543+ #define DDP_CHANNELS_PER_PACKET 1440 // 480 leds
544+
545+ //
546+ // Send real time DDP UDP updates to the specified client
547+ //
548+ // client - the IP address to send to
549+ // length - the number of pixels
550+ // buffer - a buffer of at least length*4 bytes long
551+ // isRGBW - true if the buffer contains 4 components per pixel
552+
553+ uint8_t sequenceNumber = 0 ; // this needs to be shared across all outputs
554+
555+ uint8_t realtimeBroadcast (IPAddress client, uint16_t length, uint8_t *buffer, bool isRGBW) {
556+ WiFiUDP ddpUdp;
557+
558+ // calclate the number of UDP packets we need to send
559+ uint16_t channelCount = length * 3 ; // 1 channel for every R,G,B value
560+ uint16_t packetCount = channelCount / DDP_CHANNELS_PER_PACKET;
561+ if (channelCount % DDP_CHANNELS_PER_PACKET) {
562+ packetCount++;
563+ }
564+
565+ // there are 3 channels per RGB pixel
566+ uint16_t channel = 0 ; // TODO: allow specifying the start channel
567+ // the current position in the buffer
568+ uint16_t bufferOffset = 0 ;
569+
570+ for (uint16_t currentPacket = 0 ; currentPacket < packetCount; currentPacket++) {
571+ if (sequenceNumber > 15 ) sequenceNumber = 0 ;
572+
573+ int rc = ddpUdp.beginPacket (client, DDP_PORT);
574+ if (rc == 0 ) {
575+ // DEBUG_PRINTLN("WiFiUDP.beginPacket returned an error");
576+ return 1 ; // problem
577+ }
578+
579+ // the amount of data is AFTER the header in the current packet
580+ uint16_t packetSize = DDP_CHANNELS_PER_PACKET;
581+
582+ uint8_t flags = DDP_FLAGS1_VER1;
583+ if (currentPacket == (packetCount - 1 )) {
584+ // last packet, set the push flag
585+ // TODO: determine if we want to send an empty push packet to each destination after sending the pixel data
586+ flags = DDP_FLAGS1_VER1 | DDP_FLAGS1_PUSH;
587+ if (channelCount % DDP_CHANNELS_PER_PACKET) {
588+ packetSize = channelCount % DDP_CHANNELS_PER_PACKET;
589+ }
590+ }
591+
592+ // write the header
593+ /* 0*/ ddpUdp.write (flags);
594+ /* 1*/ ddpUdp.write (sequenceNumber++ & 0xF );
595+ /* 2*/ ddpUdp.write (0 );
596+ /* 3*/ ddpUdp.write (DDP_ID_DISPLAY);
597+ // data offset in bytes, 32-bit number, MSB first
598+ /* 4*/ ddpUdp.write ((channel & 0xFF000000 ) >> 24 );
599+ /* 5*/ ddpUdp.write ((channel & 0x00FF0000 ) >> 16 );
600+ /* 6*/ ddpUdp.write ((channel & 0x0000FF00 ) >> 8 );
601+ /* 7*/ ddpUdp.write ((channel & 0x000000FF ));
602+ // data length in bytes, 16-bit number, MSB first
603+ /* 8*/ ddpUdp.write ((packetSize & 0xFF00 ) >> 8 );
604+ /* 9*/ ddpUdp.write (packetSize & 0xFF );
605+
606+ // write the colors, the write write(const uint8_t *buffer, size_t size)
607+ // function is just a loop internally too
608+ for (uint16_t i = 0 ; i < packetSize; i += 3 ) {
609+ ddpUdp.write (buffer[bufferOffset++]); // R
610+ ddpUdp.write (buffer[bufferOffset++]); // G
611+ ddpUdp.write (buffer[bufferOffset++]); // B
612+ if (isRGBW) bufferOffset++;
613+ }
614+
615+ rc = ddpUdp.endPacket ();
616+ if (rc == 0 ) {
617+ // DEBUG_PRINTLN("WiFiUDP.endPacket returned an error");
618+ return 1 ; // problem
619+ }
620+
621+ channel += packetSize;
622+ }
623+
624+ return 0 ;
625+ }
0 commit comments