Arduino E1.31 GECE controller

bob_moody

Apprentice elf
Joined
Oct 20, 2012
Messages
86
Location
Huntsville, TX
[I actually posted this in another thread by Elnino but thought it really was a seperate topic. So I'm reposting in a new thread... Bob ]
Using the base sketch from Elnino, I wanted to play with the Arduino and an Ethernet shield. I did get Elnino sketch to work and it works great in Xlights and in LOR using the 2811 pixels that I had. Since I picked up several strings of GECE's I thought I would attempt to modify the sketch and change the library and calls to use the G35 library. Here is where I am at with it.
++++++++
Well it took a little while (most of it my own fault... running LOR CP and Xlights at the same time and not realizing it) but I did manage to modify Elnino's script to support GECE pixels.
Other than converting library calls, my biggest obstacle was the bit color. The GECE's are 12 bit (4-bits each for R,G, and B). So everything worked fine when I slid the slider on Xlights from 0 to 15, After that it was generating all sorts of interesting colors.

I found that with bit swapping (x >> y ) rotating to the right 4 bits each of the colors coming in from the sACN packet and that appears to have resolved the issue. Now 0 to 255 on xLights results in only the single color being presented.

I havent looked in to it yet, but I'm hoping this sketch will fit on an Arduino mini allowing me to create a couple of those $10 utility controllers.

If any one is interested I will post the script. Thanks again to Elnino for the basis to start this project.
Bob

NEED HELP PLEASE.. It works in LOR .. sorta but not really... In Xlights, its rock solid. In LOR, the lights seem to be pulsing at the packet rate. That is to say the pin 13 LED on the Arduino is blinking and its in sync with the blinking of the lights. Although the color changes are working. Its in a permanent blink .. ARGGHHHH..
Bob
 

bluzervic

65,768 Channels, 185 Universes
Joined
Dec 31, 2011
Messages
535
Location
Fremont, Calif.
Make sure you do not run the LOR control panel at the same time as Xlights as it does cause an annoying constant blink


Not sure if that is what's happening here though....



-Blu
 

bob_moody

Apprentice elf
Joined
Oct 20, 2012
Messages
86
Location
Huntsville, TX
Thank you for the reply .. Actually that is exactly what was killing me on xlights side of things. I shut down Control Panel and Xlights works like a charm.
I shut down Xlights (and even rebooted), bring up LOR and the Control Panel and when I run a simple RGB sequence (2 secs of all RED, 2 secs of all GREEN, same with Blue and White) I get the blink.
Not sure why Xlights would work perfectly and LOR would blink unless its timing issue with the Ethernet buffer settings(?). I am going to put a serial output in the sketch to see if I can see where I am getting a 255 followed by a 0 then a 255 etc etc ...
I running on a Arduino Uno and a W5100 Ether shield.
Bob
 

bob_moody

Apprentice elf
Joined
Oct 20, 2012
Messages
86
Location
Huntsville, TX
I added a serial monitor to the sketch and can monitor the color change output on my Palm.
First there is an incedible delay which I am assuming is the serial monitor slowing things down(?)
What i am seeing now is when I'm calling for red, I see 36 packets with a value of 15 (remember GECE's are 12-bit color -- 4bit red, 4bit green, 4 bit blue). Then I see what appears as 36 packets of 0 (explaining the blink).
When the color changes to Green I see a value of 240, for Blue I see 3840, and for White I see 4095. Bit wise this is exactly what it should be. What I cant explain are the 0's
Bob
 

bob_moody

Apprentice elf
Joined
Oct 20, 2012
Messages
86
Location
Huntsville, TX
I think I have figured out the LOR blinky issue.

In the original sketch written with FastLED library the author set the parmameters for Channel_Count, Number_of_LEDS and LEDS_Per_Universe. They were based on the amount of memory available.

I added a serial monitor to the code and could see when red was called it was sending a 15 for the color, green sent a 240, blue sent a 3840 and white sent 4095. Bit wise this is correct. Remember that the GECE's use 12 bit color definitions.

What was obvious with the monitor running was, for example, when red was called, I could see 36 "15's" go by followed by a lot of "0's". This was the blink.
In the original sketch, the definitions looked like this
/// DONT CHANGE unless you know the consequences...
#define ETHERNET_BUFFER 540
#define CHANNEL_COUNT 360 //because it divides by 3 nicely
#define NUM_LEDS 240 // can not go higher than this - Runs out of SRAM
#define UNIVERSE_COUNT 2
#define LEDS_PER_UNIVERSE 120

What I assumed was that I was seeing that with a 36 count string, the first 36 were being processed properly but then there are 204 LED unaccounted for so the sketch processing all 240 known lights but for some reason the counter was not sending data to LED 37 through 240 it was wrapping back around and sending 0 which turned them off. This is my best, uneducated guess.

So I changed the parms to 36 on the NUM_LEDS and to 63 on the LEDS_PER_UNIVERSE (there is only enough adddressing for 63 lights in a GECE string).
This seems to have solved the issue. I even ran a production sequence from 2014 and they appear to be in sync!!

So.. the upshot is ..
I have no idea why my original sketch works in Xlights. I can only assume that since it knows more about the string it only sends the exact number of commands and LOR sends the packets in the blind assuming that the controller knows what to do with it all. I really dont have an explination.
However, if you have a 36 count string then set the variable NUM_LEDS to 36, if you have a 50 then set it 50 (or any custom length up tot he max of 63)

The code I am posting has comments and extra code that could/should be removed to conserve space. I am still looking in to the ETHERNET_BUFFER value and hoping the author will get back with me to better explain the value.
The G35 Library I used is here : https://github.com/sowbug/G35Arduino
[CORRECTION: After posting I went back to clean up the code. My references to NUM_LEDS being the magic bullet to fix my problem are dead wrong. I "Think" it is the Channel_Count that fixed the problem. In fact, I can do away with the NUM_LEDS variable altogether. I'm sure as I work through this a little more (now that its working) I will find other assumptions that are incorrect.]



Bob
Code:
// E1.31 Receiver and pixel controller by Andrew Huxtable (andrew@hux.net.au)
// This code may be freely distributed and used as you see fit for non-profit
// purposes and as long as the original author is credited and it remains open
// source
//
// Please configure your Lighting product to use Unicast to the IP the device is given from your DHCP server
// Multicast is not currently supported due to bandwidth/processor limitations
// GECE modification by: Bob Moody (bob_moodytx[member=2211]yahoo[/member].com)

#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <G35String.h>
// Total # of lights on string (usually 50, 48, or 36). Maximum is 63, because
// the protocol uses 6-bit addressing and bulb #63 is reserved for broadcast
// messages.
#define LIGHT_COUNT (36)
// Arduino pin number. 
#define G35_PIN (7)
G35String lights(G35_PIN, LIGHT_COUNT);

//*********************************************************************************

// enter desired universe and subnet  (sACN first universe is 1)
#define DMX_SUBNET 0
#define DMX_UNIVERSE 1 //**Start** universe

// Set a different MAC address for each...
byte mac[] = { 0x74, 0x69, 0x69, 0x2D, 0x30, 0x15 };

// Uncomment if you want to use static IP
//*******************************************************
// ethernet interface ip address
IPAddress ip(10, 0, 0, 10);  //IP address of ethernet shield
//*******************************************************

EthernetUDP Udp;

// By sacrificing some of the Ethernet receive buffer, we can allocate more to the LED array
// but this is **technically** slower because 2 packets must be processed for all 240 pixels.

/// DONT CHANGE unless you know the consequences...
 #define ETHERNET_BUFFER 540 
 #define CHANNEL_COUNT 108 //because it divides by 3 nicely
 #define NUM_LEDS 36 // can not go higher than this - Runs out of SRAM
 #define UNIVERSE_COUNT 1
 #define LEDS_PER_UNIVERSE 63
//********************************************************************************
unsigned char packetBuffer[ETHERNET_BUFFER];
void setup() {
  lights.enumerate();
  // ********************************************************  
  Ethernet.begin(mac,ip);
  Udp.begin(5568);
  // ******************************************************** 
  
    // Setup Serial
//  Serial.begin(9600);
//  delay(100);
  
//  Serial.flush();
//  delay(100);
  
  //Once the Ethernet is initialised, run a test on the LEDs
  initTest();
}

void loop() {
   //Process packets
   int packetSize = Udp.parsePacket(); //Read UDP packet count
   if(packetSize){
    Udp.read(packetBuffer,ETHERNET_BUFFER); //read UDP packet
    int count = checkACNHeaders(packetBuffer, packetSize);
    if (count) {
      sacnDMXReceived(packetBuffer, count); //process data function
    }
  }
}
 

void sacnDMXReceived(unsigned char* pbuff, int count) {
  if (count > CHANNEL_COUNT) count = CHANNEL_COUNT;
  byte b = pbuff[113]; //DMX Subnet
  if ( b == DMX_SUBNET) {
    b = pbuff[114];  //DMX Universe
    if ( b >= DMX_UNIVERSE && b <= DMX_UNIVERSE + UNIVERSE_COUNT ) {  
      if ( pbuff[125] == 0 ) {  //start code must be 0
      int ledNumber = (b - DMX_UNIVERSE) * LEDS_PER_UNIVERSE;
       // sACN packets come in seperate RGB but we have to set each led's RGB value together
       // this 'reads ahead' for all 3 colours before moving to the next led.
       for (int i = 126;i < 126+count;i = i + 3){
          byte charValueR = pbuff[i] >> 4;
          byte charValueG = pbuff[i+1] >> 4;
          byte charValueB = pbuff[i+2] >> 4;
          color_t color = lights.color(charValueR,charValueG,charValueB);
          
//          Serial.println("Color Command Received: "+String(color));
//         delay(200); 
          
          lights.set_color(ledNumber, G35::MAX_INTENSITY, color);
          ledNumber++;
        }
      }
    }
  }
}

int checkACNHeaders(unsigned char* messagein, int messagelength) {
  //Do some VERY basic checks to see if it's an E1.31 packet.
  //Bytes 4 to 12 of an E1.31 Packet contain "ACN-E1.17"
  //Only checking for the A and the 7 in the right places as well as 0x10 as the header.
  //Technically this is outside of spec and could cause problems but its enough checks for us
  //to determine if the packet should be tossed or used.
  //This improves the speed of packet processing as well as reducing the memory overhead.
  //On an Isolated network this should never be a problem....
  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 initTest() //runs at board boot to make sure pixels are working
{
  lights.fill_color(0, LIGHT_COUNT, G35::MAX_INTENSITY, COLOR_RED);
  delay(1000);
  lights.fill_color(0, LIGHT_COUNT, G35::MAX_INTENSITY, COLOR_GREEN);
  delay(1000);
  lights.fill_color(0, LIGHT_COUNT, G35::MAX_INTENSITY, COLOR_BLUE);
  delay(1000);
  lights.fill_color(0, LIGHT_COUNT, G35::MAX_INTENSITY, COLOR_BLACK);
  delay(1000);
}
 

bob_moody

Apprentice elf
Joined
Oct 20, 2012
Messages
86
Location
Huntsville, TX
Wireshark explains alot !!!
In Xlights you define your string. I defined my string to be 36 pixels which is 108 channels. So when Xlights sends out its packets, it only contains the color data for the 108 channels.
So in the code, the 3 reads to get R,G and B colors never exceeded the channel count on the controller.
In LOR, it does not know anything about your string and sends out a full 512 channel universe in each packet.
So in the code, with the original values, LOR was sending 192 additional channels that processed as 0,0,0 for color.
The G35 Library has two functions to display the LED.
Set_Color - Expects the LED # to be in range of the LED count. Odd things happen when it writes past the string
Set_Color_If_In_Range - This will return a false to calling function and not write to the string if the LED # is greater than the number of LED's
So we can either be very specific in our config (in my case)
Light_Count = 36
Channel-Count =108
and use the Set_Color function
OR
Be a little more generic
Channel_Count = 189 (Max channels for a GECE string of 63)
Light_Count = 36 (to match the length of the string)
and use Set_Color_If_In_Range function.
The only issue right now and I have no way to precisely test it is timing.
Does it take more time to throw out all the data bytes of channel colors that exceed the string length?
LOR does visually appear to be lagging just a touch with this sketch.
If anyone tries this sketch.. let me know your results ...
Bob
 
Top