Receiving Multiple Universes

LXSeries open source projects are hosted on github.
Post Reply
djred2000
Posts: 3
Joined: Wed Jul 06, 2016 10:41 pm

Receiving Multiple Universes

Post by djred2000 »

I would like to be able to receive multiple universes of SACN using an Arduino Due and the Arduino Ethernet Shield. I'm developing a controller to output to WS2811 LED pixels using the FastLED library. So far I am only able to receive a maximum of 3 universes. It seems to just ignore the others. I am using Vixen 3 to generate the SACN. The code is based off your original SACN reception sketches.

Here is the code. Any help would be greatly appreciated.

Part of the loop:

Code: Select all

void loop() 
{
  int packetSize = ARTNETUDP.parsePacket();
  if(packetSize)
  {
    ARTNETUDP.read(DataBuffer, EthernetBufferMax);
    int opcode = artNetOpCode(DataBuffer);
    if (opcode == ARTNET_ARTDMX) 
    {
      Serial.println("ArtNet Packet Received");
      artDMXReceived();
    } 
  } 
    else 
    {
    packetSize = E131UDP.parsePacket();
    if(packetSize) 
    {
      E131UDP.read(DataBuffer, EthernetBufferMax);
      int count = checkACNHeaders(DataBuffer, packetSize);
      if (count) 
      {
        //Serial.println("E131 Packet Received");
        E131Received();
      }
    }
  }

E131 Functions

Code: Select all

//checks to see if packet is E1.31 data
int checkACNHeaders(unsigned char* messagein, int messagelength) 
{
  if ( messagein[1] == 0x10 && messagein[4] == 0x41 && messagein[12] == 0x37) 
  {  
      int addresscount = messagein[123] * 256 + messagein[124]; // number of values plus start code
      return addresscount -1; //Return how many values are in the packet.
    }
  return 0;
}

void E131Received() 
{
    
if(DataBuffer[114] == 1)
{
  Serial.println("Universe 1");
      Channel = 1; //reset channel assignment to 1 each time through loop.
      for&#40;int i = 0; i < 170; i++&#41; //set values for 170 pixels. Max number per universe. 
      &#123;
      leds&#91;i&#93; = CRGB&#40;DataBuffer&#91;E131_ADDRESS_OFFSET + Channel&#93;, DataBuffer&#91;E131_ADDRESS_OFFSET + &#40;Channel +1&#41;&#93;, DataBuffer&#91;E131_ADDRESS_OFFSET + &#40;Channel + 2&#41;&#93;&#41;;
      Channel += ChannelWidth; //increase last channel number by channel width
      &#125;
&#125;

if&#40;DataBuffer&#91;114&#93; == 2&#41;
&#123;
  Serial.println&#40;"Universe 2"&#41;;
      Channel = 1; //reset channel assignment to 1 each time through loop.
      for&#40;int i = 170; i < 340; i++&#41; //set values for 170 pixels. Max number per universe. 
      &#123;
      leds&#91;i&#93; = CRGB&#40;DataBuffer&#91;E131_ADDRESS_OFFSET + Channel&#93;, DataBuffer&#91;E131_ADDRESS_OFFSET + &#40;Channel +1&#41;&#93;, DataBuffer&#91;E131_ADDRESS_OFFSET + &#40;Channel + 2&#41;&#93;&#41;;
      Channel += ChannelWidth; //increase last channel number by channel width
      &#125;
&#125;

if&#40;DataBuffer&#91;114&#93; == 3&#41;
&#123;
  Serial.println&#40;"Universe 3"&#41;;
      Channel = 1; //reset channel assignment to 1 each time through loop.
      for&#40;int i = 340; i < 510; i++&#41; //set values for 170 pixels. Max number per universe. 
      &#123;
      leds&#91;i&#93; = CRGB&#40;DataBuffer&#91;E131_ADDRESS_OFFSET + Channel&#93;, DataBuffer&#91;E131_ADDRESS_OFFSET + &#40;Channel +1&#41;&#93;, DataBuffer&#91;E131_ADDRESS_OFFSET + &#40;Channel + 2&#41;&#93;&#41;;
      Channel += ChannelWidth; //increase last channel number by channel width
      &#125;
&#125;

if&#40;DataBuffer&#91;114&#93; == 4&#41;
&#123;
  Serial.println&#40;"Universe 4"&#41;;
      Channel = 1; //reset channel assignment to 1 each time through loop.
      for&#40;int i = 510; i < 680; i++&#41; //set values for 170 pixels. Max number per universe. 
      &#123;
      leds&#91;i&#93; = CRGB&#40;DataBuffer&#91;E131_ADDRESS_OFFSET + Channel&#93;, DataBuffer&#91;E131_ADDRESS_OFFSET + &#40;Channel +1&#41;&#93;, DataBuffer&#91;E131_ADDRESS_OFFSET + &#40;Channel + 2&#41;&#93;&#41;;
      Channel += ChannelWidth; //increase last channel number by channel width
      &#125;
&#125;

if&#40;DataBuffer&#91;114&#93; == 5&#41;
&#123;
  Serial.println&#40;"Universe 5"&#41;;
      Channel = 1; //reset channel assignment to 1 each time through loop.
      for&#40;int i = 680; i < 850; i++&#41; //set values for 170 pixels. Max number per universe. 
      &#123;
      leds&#91;i&#93; = CRGB&#40;DataBuffer&#91;E131_ADDRESS_OFFSET + Channel&#93;, DataBuffer&#91;E131_ADDRESS_OFFSET + &#40;Channel +1&#41;&#93;, DataBuffer&#91;E131_ADDRESS_OFFSET + &#40;Channel + 2&#41;&#93;&#41;;
      Channel += ChannelWidth; //increase last channel number by channel width
      &#125;
&#125;

if&#40;DataBuffer&#91;114&#93; == 6&#41;
&#123;
  Serial.println&#40;"Universe 6"&#41;;
      Channel = 1; //reset channel assignment to 1 each time through loop.
      for&#40;int i = 850; i < 1020; i++&#41; //set values for 170 pixels. Max number per universe. 
      &#123;
      leds&#91;i&#93; = CRGB&#40;DataBuffer&#91;E131_ADDRESS_OFFSET + Channel&#93;, DataBuffer&#91;E131_ADDRESS_OFFSET + &#40;Channel +1&#41;&#93;, DataBuffer&#91;E131_ADDRESS_OFFSET + &#40;Channel + 2&#41;&#93;&#41;;
      Channel += ChannelWidth; //increase last channel number by channel width
      &#125;

      FastLED.show&#40;&#41;; / 
&#125;
&#125; //end function 

admin
Site Admin
Posts: 1643
Joined: Mon Nov 05, 2007 1:26 am
Contact:

Post by admin »

I can't tell if you are sending sACN by multicast or unicast. You did not post the setup of the E131UDP object.

I'm guessing that all universes are unicast to the same IP address. If this is true, it is possible that the Ethernet shield has reached the limit of its data buffer. I'm not sure of the behavior in this case, but it is possible that it just drops the extra packets that it does not have space to store.

If the sACN is multicast, there may be a limit to how many multicast addresses that a single socket can listen on. (The E131UDP object is a wrapper around a socket). In this case, you may be able to create additional UDP objects to receive the other universes.

Your code looks identical, except for the pixel indexes on each universe. So, I'd look to limitations on the network socket end as to why it does not work for you. For testing purposes, you might find SACNView to be of use: sacnview.sourceforge.net This will allow you to view what vixen 3 is sending and will allow you to test send individual universes. I would try to determine if your sketch responds to individual universes but fails when sent all the universes. If this is the case, look at reasons the higher universe packets are not received or are dropped.
djred2000
Posts: 3
Joined: Wed Jul 06, 2016 10:41 pm

Post by djred2000 »

The SACN is being sent unicast. I did some research and it looks like the W5100 ethernet shield data buffer is only 2048 bytes.

I tried multicast but when you set the multicast IP, you have to define the universe number. Any idea how to read multiple multicast universes?
admin
Site Admin
Posts: 1643
Joined: Mon Nov 05, 2007 1:26 am
Contact:

Post by admin »

The multicast address corresponds to the universe: 239.255.0.x, where x is the universe.

The Ethernet LibraryEthernetUDP beginMulticast method does not allow a UDP object to listen to more than one multicast address. (The W5100 may not support that like a POSIX socket either). So, you need to have a separate UDP object for each universe and call beginMulticast for each one with the appropriate address. To get six multicast universes, you would need six sockets and the W5100 only supports 4. It appears that the 2048 byte buffer is per socket. So, doing it that way at least gets you 4 universes instead of 3. (A w5500 based shield has a max of 8 sockets and that might do it for you)

Alternatively, take a look at this forum post: http://forum.arduino.cc/index.php?topic=19260.0
The poster found a way to increase the buffer. The chip has 8k available and you might be able to edit the library to get what you need for a single UDP object.
djred2000
Posts: 3
Joined: Wed Jul 06, 2016 10:41 pm

Post by djred2000 »

I looked into modifying the library and I couldn't get it to work. Using 4 sockets to read 4 multicast universes does work.

I did some testing on an ESP8266 using the same code and it works a little better. It can read 6 universes but it gets backed up and can't process them in real time.
admin
Site Admin
Posts: 1643
Joined: Mon Nov 05, 2007 1:26 am
Contact:

Post by admin »

There may be a problem with the time required to push the pixel data to the LEDs at dmx speed. (This is even without taking into account the time needed to receive the network packets and move the data to the output memory.) Here's how it multiplies out:

The timing for the serial data takes 1.25 microseconds to send one bit. After all bits are sent, the line must remain fixed for another 20-50 microseconds for the pixels to stop shifting bits and to latch. Leaving out the reset and just figuring the per pixel time, you get 1.25 x 24 bits = 30 microseconds per led. A single universe can hold 170 pixels of RGB data. 30 x 170 = 5100 microseconds to send one universe. 5100 x 6 = 30600 microseconds to send all 6 universes (once)_. DMX at full speed is around 44 frames per second. Assume that you can process all 6 universes at 40 frames per second. 40 x 30600 = 1224000 microseconds. that means for 1 second of DMX, it takes at least 1.2 seconds to send the pixel data. Clearly, this won't work, even without taking into account the latch timing portion of the pixel serial signal or anything else.

If the controller you are using to send DMX can adjust its speed, say to 20 DMX frames per second (half speed) then sending the serial signal to the pixels takes only .612 seconds. That leaves time to read the packets and move data from the ethernet shield into memory. For comparison, slow ethernet is 10 mega bit per second, which is 12.5 times faster than the pixel serial signal. So, even the slowest original ethernet would be up to the task.
Post Reply