#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>     
#include <FastLED.h>

#define bytes_to_short(h,l) ( ((h << 8) & 0xff00) | (l & 0x00FF) );
#define UDP_TX_PACKET_MAX_SIZE 4096
#define MYIPADDR 192,168,2,10
#define LED_PIN    10
#define LED_PIN2    11
#define LED_PIN3    12
#define LED_PIN4    13
#define NUM_LEDS   680
#define STRIP_LEDS   170 //170leds=1universe, 2 Universes per output pin maximum to achieve 60FPS+ with ws2812
#define LED_TYPE WS2812
#define COLOR_ORDER RGB

CRGB leds[STRIP_LEDS];
CRGB leds2[STRIP_LEDS];
CRGB leds3[STRIP_LEDS];
CRGB leds4[STRIP_LEDS];

//Universe+Subnet setup
int subnet = 0;
int startUniverse = 0;
String resp, value;
byte mac[] = { 0xC2, 0xA3, 0x8B, 0xA8, 0x52, 0xB5};

byte remoteIp[4];        // holds received packet's originating IP
unsigned int remotePort; // holds received packet's originating port

const int number_of_channels = 510; //510 channels MAX as 3ch. per pixel needed
const int channel_position = 0; // Starting channel, do not touch if not necessary
//buffers
const int MAX_BUFFER_UDP = 4096; //definition to do to make work UDP lib 
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to store incoming data
byte buffer_dmx[number_of_channels + 1]; //buffer to store filetered DMX data

// art net parameters
unsigned int localPort = 6454;      // artnet UDP port is by default 6454
const int art_net_header_size = 17;
const int max_packet_size=576;
char ArtNetHead[8] = "Art-Net";
char OpHbyteReceive = 0;
char OpLbyteReceive = 0;
short is_artnet_version_1 = 0;
short is_artnet_version_2 = 0;
short seq_artnet = 0;
uint16_t  incoming_universe = 0;
uint16_t  dmx_length = 0;
boolean is_opcode_is_dmx = 0;
boolean is_opcode_is_artpoll = 0;
boolean match_artnet = 1;
short Opcode = 0;
EthernetUDP Udp;

void setup() { 
  FastLED.addLeds<LED_TYPE,LED_PIN,COLOR_ORDER>(leds, STRIP_LEDS);
  FastLED.addLeds<LED_TYPE,LED_PIN2,COLOR_ORDER>(leds2, STRIP_LEDS);        
  FastLED.addLeds<LED_TYPE,LED_PIN3,COLOR_ORDER>(leds3, STRIP_LEDS);       
  FastLED.addLeds<LED_TYPE,LED_PIN4,COLOR_ORDER>(leds4, STRIP_LEDS);
   
  Ethernet.init(17);
  IPAddress ip(MYIPADDR);
  Ethernet.begin(mac, ip); 
  Udp.begin(localPort);
}
void loop() {
  
  int packetSize = Udp.parsePacket();
  Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
  //read header
  match_artnet = 1;
  for (int i = 0; i < 7; i++) {
    //if not corresponding, this is not an artnet packet
    if (char(packetBuffer[i]) != ArtNetHead[i]) {
      match_artnet = 0; break;
    }
  }
  //if its an artnet header
  if (match_artnet == 1) {
    Opcode = bytes_to_short(packetBuffer[9], packetBuffer[8]);
    incoming_universe = packetBuffer[14] | packetBuffer[15] << 8;
    dmx_length = packetBuffer[17] | packetBuffer[16] << 8;
   
    if (Opcode == 0x5000) {
      is_opcode_is_dmx = 1; is_opcode_is_artpoll = 0;
    }
    //artpoll
    else if (Opcode == 0x2000) {
      is_opcode_is_artpoll = 1; is_opcode_is_dmx = 0;
      //Serial.println("Artpoll packet received!");
      return;
    }
    //DMX data read
    if (is_opcode_is_dmx = 1) { 
      for (int i = channel_position; i <= number_of_channels; i++) {
        buffer_dmx[i] = byte(packetBuffer[i + 18]);
      }
    } 
    int x = 0;
    int y = 0;

    for (int z = 0; z < number_of_channels; z++) {
      if (y < NUM_LEDS && x == 0) {       
        if(incoming_universe == subnet*16 + startUniverse){
            leds[y].red   = buffer_dmx[z];
            leds[y].green = buffer_dmx[z + 1];
            leds[y].blue  = buffer_dmx[z + 2];
        }
        else if(incoming_universe == subnet*16 + (startUniverse+1)){
            leds2[y].red   = buffer_dmx[z];
            leds2[y].green = buffer_dmx[z + 1];
            leds2[y].blue  = buffer_dmx[z + 2];
        }
        else if(incoming_universe == subnet*16 + (startUniverse+2)){
            leds3[y].red   = buffer_dmx[z];
            leds3[y].green = buffer_dmx[z + 1];
            leds3[y].blue  = buffer_dmx[z + 2];
        }
        else if(incoming_universe == subnet*16 + (startUniverse+3)){
            leds4[y].red   = buffer_dmx[z];
            leds4[y].green = buffer_dmx[z + 1];
            leds4[y].blue  = buffer_dmx[z + 2];
        }
        y++; 
        x = 3; 
      }
      x--;
    }   
      FastLED.show();   
      Udp.flush();  
  }
}
