#include "FastLED.h"
#define NUM_LEDS_PER_STRIP 28
CRGB centis_digit[NUM_LEDS_PER_STRIP];
CRGB decis_digit[NUM_LEDS_PER_STRIP];
CRGB seconds_digit[NUM_LEDS_PER_STRIP];
CRGB decas_digit[NUM_LEDS_PER_STRIP];

// define states FSM
#define s_idle 0
#define s_idle_released 1
#define s_started 2
#define s_started_released 3
#define s_stopped 4
#define s_stopped_released 5

#define pushbutton 2 // drukknop pin 2
#define lightbarrier 19 // lichtsluit pin 19

const uint32_t digits[10] = {
// 7 segments – 4 leds per segment
//  ggggffffeeeeddddccccbbbbaaaa
  0b0000111111111111111111111111, // 0
  0b0000000000000000111111110000, // 1
  0b1111000011111111000011111111, // 2
  0b1111000000001111111111111111, // 3
  0b1111111100000000111111110000, // 4
  0b1111111100001111111100001111, // 5
  0b1111111111111111111100001111, // 6
  0b0000000000000000111111111111, // 7
  0b1111111111111111111111111111, // 8
  0b1111111100001111111111111111 // 9
};
// global variables
byte centiseconds = 0;
byte deciseconds = 0;
byte seconds = 0;
byte decaseconds;
unsigned long previousMillis = 0;
unsigned long currentMillis;

// prototype functions
void chronmeter(void);
void showtime(byte centi, byte deci, byte sec, byte deca);

void setup() {
// one ledstrip for each digit
// data pins: pin 10, 11, 12 and 13
  FastLED.addLeds<NEOPIXEL, 10>(centis_digit, NUM_LEDS_PER_STRIP);
  FastLED.addLeds<NEOPIXEL, 11>(decis_digit, NUM_LEDS_PER_STRIP);
  FastLED.addLeds<NEOPIXEL, 12>(seconds_digit, NUM_LEDS_PER_STRIP);
  FastLED.addLeds<NEOPIXEL, 13>(decas_digit, NUM_LEDS_PER_STRIP);

  Serial.begin(9600);
  
  pinMode(pushbutton, INPUT);
  pinMode(lightbarrier, INPUT);
  
}

void loop() {
  int karakter = 0;
  boolean received_char = 0;
  boolean running = 0;
  byte state = s_idle; // initiele toestand
  
  Serial.println("Here we go!");

 while(1) { 
    Serial.println (state);

    switch (state) 
    {
      case s_idle: // initiele toestand   
      if (!digitalRead(pushbutton)) // overgangsvoorwaarde: druknop losgelaten  
      {
        state = s_idle_released; // Ga naar toestand s_idle_released
      }
      break;
  
      case s_idle_released: // initiele toestand released
      if(digitalRead(pushbutton) || (received_char && karakter == 'G')) // overgangsvoorwaarde: druknop ingedrukt OF karakter G ontvangen
      {
        running = 1; previousMillis = millis(); // start timer
        if (received_char) received_char = 0;
        Serial.write('g'); // karakter g sturen 
        state = s_started; // Ga naar toestand s_started
      } 
      break;
      
      case s_started: // start toestand
      if(!digitalRead(pushbutton)) // overgangsvoorwaarde: druknop losgelaten 
      {
        state = s_started_released; // Ga naar toestand s_started_released
      }
      break;
  
      case s_started_released: // start toestand released 
      if(digitalRead(pushbutton) || (received_char && karakter == 'S') || digitalRead(lightbarrier) == 1 ) // overgangsvoorwaarde: druknop ingedrukt OF karakter S ontvangen OF lichsluis onderbroken 
      {
        running = 0;
        if (received_char) received_char = 0;
        Serial.write('s'); // karakter s sturen 
        state = s_stopped; // Ga naar toestand s_stopped
      } 
      break;
      
      case s_stopped: // stop toestand 
      if (!digitalRead(pushbutton)) // overgangsvoorwaarde: druknop losgelaten 
      {
        state = s_stopped_released; //  Ga naar toestand s_stopped_released
      }
      break;
  
      case s_stopped_released: // stop toestand released 
      if(digitalRead(pushbutton) || (received_char && karakter == 'R'))  // overgangsvoorwaarde: druknop ingedrukt OF karakter R ontvangen 
      {
        // Tijd resetten 
        centiseconds = 0; // hondersten 
        deciseconds = 0; // tienden  
        seconds = 0;  // eenheden
        decaseconds = 0;  // tientallen
        if (received_char) received_char = 0;
        Serial.write('r'); // karakter r sturen 
        state = s_idle; //  Ga naar toestand s_idle 
      }
      break; 
      
      //default:
      //break; 
    
    } // end of switch(state)
    
    if(received_char && karakter == '?')  // remote vraagt de huidige state van de main 
    {
    received_char = 0;
    Serial.write (state); // huidige state sturen
    }

  if (running) chronometer();
  // display aansturen
  
  showtime(centiseconds, deciseconds, seconds,decaseconds);

  if (Serial.available() > 0) {
    // read the incoming byte:
    karakter = Serial.read();
    received_char = 1;
  }

  
}
}
void chronometer(void)
{
    
currentMillis = millis(); 
 //If it is true, it means 1 centisecond had passed.
 //Update centiseconds, deciseconds, seconds and decaseconds 
  if (currentMillis - previousMillis >= 10)
  {  
    previousMillis = currentMillis;
    centiseconds=centiseconds + 1;
    if (centiseconds >= 10)
  {
      centiseconds = 0;
      deciseconds = deciseconds + 1;
      if (deciseconds >= 10)
    {
        deciseconds = 0;
        seconds = seconds+1;
        if (seconds >=10)
    {
          seconds = 0; 
          decaseconds = decaseconds +1 ;
          if (decaseconds >= 10)
      {
           decaseconds = 0; 
          ; // overflow
          }
        }
      }
  }
  }
}

void showtime(byte centi, byte deci, byte sec, byte deca) {

  for(int i=0;i<NUM_LEDS_PER_STRIP; i++){
    if bitRead(digits[centi], i) centis_digit[i] = CRGB::Red;
    else centis_digit[i] = CRGB::Black ;
  }

  for(int i=0;i<NUM_LEDS_PER_STRIP; i++){
    if bitRead(digits[deci], i) decis_digit[i] = CRGB::Red;
    else decis_digit[i] = CRGB::Black ;
  }
  
  for(int i=0;i<NUM_LEDS_PER_STRIP; i++){
    if bitRead(digits[sec], i) seconds_digit[i] = CRGB::Red;
    else seconds_digit[i] = CRGB::Black ;
  }

  for(int i=0;i<NUM_LEDS_PER_STRIP; i++){
    if bitRead(digits[deca], i) decas_digit[i] = CRGB::Red;
    else decas_digit[i] = CRGB::Black ;
  }
  
    FastLED.show();

    // delay(100);
}