/************************************************************************************
*
* P0180-30 World Domination Panel 
*
*************************************************************************************
* for ARDUNINO MEGA2560
*
* Dependencies: 
* Adafruit Neopixel 1.12.3
* https://github.com/adafruit/Adafruit_NeoPixel
*
*************************************************************************************
*
* 2024-09-07   xsider final P0180-30-a
*
*************************************************************************************/

#include <Adafruit_NeoPixel.h>
#include <avr/power.h>
#include <string.h>

#define PINPIR         2
#define PINLEDBLUE     3
#define PINLEDGN       4
#define PINWS2812      6
#define PINLDR         A2
#define PINPIR2        7
#define PINLEDBLUE2    8
#define PINPIR3        9
#define PINLEDBLUE3   10
#define PINPWRON      11

#define FIELDS         (15*5)

#define NUMPIXELS      FIELDS*6 /* 6 LEDs per field */

#define VERSION     "P0188-30-a\n"

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PINWS2812, NEO_GRB + NEO_KHZ800);

int delayval = 20;
#define MAXLEN  254
char inputString[MAXLEN+1];         // a String to hold incoming data
int si=0;
const int datalength=7;
int a[datalength];
byte ColorStorage[FIELDS][6];
const char separator = ';';
  bool blink = false;
  unsigned long previousMillis = 0;  // will store last time LED was updated
  unsigned long lastpir = 0; // will store time last time PIR was active
  const unsigned long interval = 500;  // interval at which to blink (milliseconds)
  const unsigned long PIRTIME = 600000L;  // 10mins
  unsigned long activeled;
  const unsigned long ACTINTERVAL = 100;
  byte charcount = 0;
  int br = 0;  
  
void setup() {
  pinMode(PINPIR,INPUT);
  pinMode(PINLEDBLUE, OUTPUT);
  pinMode(PINLEDGN, OUTPUT);
 
  pixels.begin();
  // initialize serial:
  Serial.begin(115200);
  Serial.write(VERSION);
  // reserve 64 bytes for the inputString:
  inputString[0]='\0';
  for (int i=0;i<FIELDS;i++) {
    for (int k=0;k<6;k++) {
          ColorStorage[i][k]=0x1;
    }
  }
}

void loop() 
{
  byte helligkeit;
  unsigned long currentMillis;
  
  if ( digitalRead(PINPIR) )
  {
      digitalWrite(PINLEDBLUE,HIGH);
      lastpir = millis();
  }
  else
  {
    digitalWrite(PINLEDBLUE,LOW);
  }

  if ( digitalRead(PINPIR2) )
  {
      digitalWrite(PINLEDBLUE2,HIGH);
      lastpir = millis();
  }
  else
  {
    digitalWrite(PINLEDBLUE2,LOW);
  }
  if ( digitalRead(PINPIR3) )
  {
      digitalWrite(PINLEDBLUE3,HIGH);
      lastpir = millis();
  }
  else
  {
    digitalWrite(PINLEDBLUE3,LOW);
  }
  
  /* the serial routine is lossy because ws2812 serial out is blocking */
  /* host repeats requests until it is received correct */
  
  if (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    /* string is finished, we can process it */
    if (inChar == '\n' ) 
    {
      digitalWrite(PINLEDGN,HIGH);
      activeled=millis();
      inputString[charcount]='\n';
      Serial.print((char*)inputString );  /* messsage processed */
      charcount = 0;
      char* ptr = strtok(inputString, ";");
      byte ip =0;
      while (ptr && ip<datalength) 
      {
        a[ip]=atoi(ptr);
        ptr= strtok(NULL, ";");
        ip++;
      }
      
      /* if packet is not long enough, there are missing data, so no processing is done */
      if (ip==7) 
      {
        if ( a[0] < FIELDS ) 
        {
          for (int k=0;k<6;k++)
          {
            ColorStorage[ a[0] ][k] = a[k+1];
          }
        }
      } 
    }
    else 
    {
      // add it to the inputString:
      if ( charcount < MAXLEN ) 
      {
        inputString[charcount] = inChar;
        charcount++;
      }
    }
  }

  currentMillis = millis();
  //@todo: handling millis() overflow
  
  /* this increases LED on tune for communication LED */
  if ( currentMillis - activeled > ACTINTERVAL )
  {
    digitalWrite(PINLEDGN,LOW);
  }

  /* run this every second */
  if (currentMillis - previousMillis >= interval) 
  {
    previousMillis = currentMillis;
    br = ( br + analogRead(PINPIR) ) /2 ; /* simple average */
    helligkeit = map( (br>200 ? 200 : br )  , 0, 200, 100, 5);
    if ( currentMillis - lastpir > PIRTIME ) 
    {
      /* we have no motion for long time */
      /* display minimal time */
      /* switch off power supplies */
      pixels.setBrightness(2);
      digitalWrite(PINPWRON,LOW);
    }
    else 
    {
      /* power supply on */
      digitalWrite(PINPWRON,HIGH);
  
      if ( blink) 
      {
        for ( int l=0; l<FIELDS; l++ ) 
        {
          for (int k=0;k<3;k++) 
          {
            pixels.setPixelColor( (l)*3+k+((l ) / 5)*15, pixels.Color(ColorStorage[l][0],ColorStorage[l][1],ColorStorage[l][2] ) );
            pixels.setPixelColor( (l)*3+k+(( l ) / 5)*15 + 27- (l % 5 )*6, pixels.Color(ColorStorage[l][0],ColorStorage[l][1],ColorStorage[l][2] ) );
          }
        }
      }
      else 
      {
        for ( int l=0;l<FIELDS;l++ ) 
        {
          for (int k=0;k<3;k++) 
          {
            pixels.setPixelColor( (l)*3+k+((l ) / 5)*15, pixels.Color(ColorStorage[l][3],ColorStorage[l][4],ColorStorage[l][5]) );
            pixels.setPixelColor( (l)*3+k+(( l ) / 5)*15 + 27- (l % 5 )*6, pixels.Color(ColorStorage[l][3],ColorStorage[l][4],ColorStorage[l][5] )) ;
  
          }
        }
      }
      pixels.setBrightness(helligkeit);
    }

    pixels.show();
    blink = !blink;
  }
}
