/* HW03 Drag Race Xmas Tree using SevSeg library
  Date: 9/6/2022
  Author n.blizard
  *
  Purpose - Drag Race
  Algorithm - use schematic and some code from Lab03 part 2
    Use 3 yellow LEDs, 1 Red LED, 1 Green LED, + curr limit resistors
    Use 4 digit 7 segment display
  Use pushbutton to initiate the start sequence
    use Analog pins since all digital pins are in use for 7 seg display
   Steps
    make a separate progam (w/o digital timer) for the LED sequencing
    then merge the two programs and retests with timer
    Setup
      turn off all LEDs
      blank 7 seg display
    initialze -- see function initializeRun
    Sequence the Xmas Tree -- see function xmasTreeSequence
    Timing and display -- see function runTimingAndDisplay

  Add functions
  void initializeRun ()
    turn on green LED (first step in loop)
    wait for user to press button to start run
      debounce the button while refreshing display
    turn off red LED
    Clear 7 segment display
    initialize variables:
  void xmasTreeSequence ()
    turn off green LED
    Blink three yellow LEDs in sequence (500 msec cascade, 20 msec delay)
    continue to refresh display and checking for cheating (button push)
    turn on green LED and ready to start timer
  void runTimingAndDisplay ()
    record start time
    display running time in msec

  void checkCheated ()
    if button pressed before green light, driver cheated
    display "----" (>9999)
    light red LED
    abort run (goto end of loop)
    clear flag
    debounce button while still refreshing display
  endOfRun
  =====================  carryovers ========  FIX ME
  add 3 functions
    void displayTime() - combines minutes and seconds into one number
      and display using setNumber()
    void waitOneSecondWhileRefreshingTheTime() - continuously
      refresh the display using refreshDisplay() lib call while
      waiting for one second (1000 msec)
    void updateTime() - increment secons and increments minutes if
      seconds >= 60 (use mod 60)
    (test the math first by using Serialprint func)
  loop
    3 function calls
*/

#include "SevSeg.h"
#define RED_LIGHT   0   // red light is on pin A1 (index 0 in array)
#define GREEN_LIGHT   4  // green light is on A5  (index 4 in array)

SevSeg sevseg; //Instantiate a seven segment controller object


// globals
//unsigned long msec = 0;  // initialize to zero
const int TIME_TICK = 500;   // delay between yellow lights (msec)
const int TIME_MAX = 10000;  // max display ("----")

//xmas tree specific variables
byte buttonPin = A0;
bool PRESSED = LOW;  // low if pressed
byte r3ygLED [] = {A1, A2, A3, A4, A5};  // R Y1 Y2 Y3 G
bool cheatedFlag = false; // set to true if cheated
bool greenFlag = false;  // set to true if green light lit
bool abortFlag = false; // set to true if run must be aborted
byte debounceDelay = 100; // msec to prevent multiple messages
unsigned long runningTime  = 0;

void setup() {
  //sev segment specific variables
  byte numDigits = 4;
  byte digitPins[] = {2, 3, 4, 5};
  byte segmentPins[] = {6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
  bool resistorsOnSegments = true; // 'true' means resistors are on segment pins
  byte hardwareConfig = COMMON_CATHODE; // See README.md for options
  bool updateWithDelays = false; // Default 'false' is Recommended
  bool leadingZeros = false; // Use 'true' if you'd like to keep the leading zeros
  bool disableDecPoint = false; // Use 'true' if your decimal point doesn't exist or isn't connected

  // initialize 7 segment display
  sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments,
               updateWithDelays, leadingZeros, disableDecPoint);
  sevseg.setBrightness(90);
  sevseg.refreshDisplay(); // Must run repeatedly

  // initialize serial print
  Serial.begin(9600);

  //set input pinMode for button
  pinMode(A0, INPUT_PULLUP);
  //analogWrite(A0, LOW);  // to ensure its low


  //set output pinModes for leds (1-5)
  for (int j = 0; j < 5; j++) {
    pinMode(r3ygLED[j], OUTPUT);
  }
}

void loop() {
  
  // this initial press starts the sequence
  delay(2000); // between runs
  initializeRun ();
  //greenFlag = false;  // set to true if green light lit, reinitize every run
  xmasTreeSequence ();
  if (greenFlag) {
    runTimingAndDisplay ();
  }
  else {
    Serial.println("..run aborted");
  }  
  
}

void initializeRun ()  {
  // initialize variables:
  abortFlag = false;
  greenFlag = true;
  cheatedFlag = false;
  // turn on green LED (first step in loop)
  Serial.println("-----------------------------------------------");
  Serial.println("..ready, get in position, press button to start");
  digitalWrite(r3ygLED[GREEN_LIGHT], HIGH);

  buttonPressed();  // wait until pressed

  // wait for user to press button while refreshing display
  //   check for cheating (defined as pushing button before green light)
  // debounce the button while refreshing display
  // turn off red LED
  digitalWrite(r3ygLED[RED_LIGHT], LOW);

  // Clear 7 segment display
  // initialize variables:

  
}
void xmasTreeSequence ()  {
  // turn off green LED
  digitalWrite(r3ygLED[GREEN_LIGHT], LOW);
  greenFlag = false;  // reset greenFlag to check for cheating
  // Blink three yellow LEDs in sequence (500 msec cascade)
  // continue to refresh display and checking for cheating (button push)
  // turn on green LED
  // tests all LEDs in setup

  unsigned long futureTime;

  for (int j = 1; j < 4; j++) {
    futureTime = millis() + TIME_TICK;
   
    digitalWrite(r3ygLED[j], HIGH);
   
    while (millis() < futureTime ) {
      cheatingCheck();
    }
   
    digitalWrite(r3ygLED[j], LOW);
   
    futureTime = millis() + TIME_TICK;
    
    while (millis() < futureTime ) {
      cheatingCheck();
    }
  }
  // assuming made it this far, set greenFlagtrue
  if (!cheatedFlag) {
    greenFlag = true;
    Serial.print("greenFlag = ");
    Serial.println(greenFlag);
    digitalWrite(r3ygLED[GREEN_LIGHT], HIGH);
  }  
  
}
void runTimingAndDisplay () {
  long startTime;
  if (greenFlag) {  // ok to start timer and wait for driver to respond
   startTime = millis();
   Serial.println("..started Timer");
  }
  buttonPressed();  // wait for driver response (after seeing green light)
  Serial.println("..driver started run");
  Serial.println("..press button to stop run");
  // call time to display in while loop

  while ( analogRead(buttonPin) != PRESSED) {           // FIXME FOR BUTTON PUSH TO END
    runningTime = millis() - startTime;
    displayTime( runningTime ) ;
    Serial.println(runningTime);
    tooSlow();  // special case if run exceeds max time
    if (abortFlag) {
      break;
    }
  }
  delay(TIME_TICK);  
  // update display continously with elapsed time
  //buttonPressed(); // wait for driver response at end of run  (FIXME replace with a sensor)
  long endTime = millis();
  long elapsedTime = endTime - startTime;
  
  // stop timer
  // record start time
  // display running time in msec
  // check cheated flag and disqualify (display ----)
  
  endRun ( elapsedTime );  // stop run if button pressed

}
void buttonPressed() {
  
  // int buttonP = analogRead(buttonPin);
  // Serial.println("buttonlow");
  while (analogRead(buttonPin) != PRESSED) {   //digitalRead(BP)  goes high if pressed
    // hang here until button is pressed
    //Serial.println(analogRead(buttonPin));
  }
  // now execute the following code after button is pressed
  //Serial.println("buttonhigh");
  //debounce button
  delay(TIME_TICK);
  // refresh display
  refreshDisplay();
}

void refreshDisplay() {

  // this function refreshes display while waiting 
  
  displayTime( runningTime) ;  // display running time
}

void cheatingCheck() {
  // this function checks the state of the button and if pressed before the
  // green light flag is true, sets the state of cheated to true as well.
  // read the state of the button every time this function is called
  // do not wait for button to be pressed, if not pressed, move on

  if ( (!analogRead(buttonPin)) && !greenFlag) {    // button pressed and greenFlag false
    Serial.println("YOU CHEATED!");
    cheatedFlag = true;  // flag that cheating occurred
    greenFlag = false;  // do not permit to run
    abortFlag = true;
    cheatedStop();  // call the redlight function
  }
  delay (debounceDelay);
}
void cheatedStop () {
  // display "----" (>9999)
  displayTime(TIME_MAX);
  // light red LED
  // abort run (goto end of loop)
  Serial.println ("Cheating Stop");
  digitalWrite(r3ygLED[RED_LIGHT], HIGH);
}
void endRun( long elapsedTimer){
  Serial.println("..Stopping Run");
  Serial.print("..elapsed Time = ");
  Serial.print(elapsedTimer);
  Serial.println(" msec");
}

void displayTime( unsigned long timeToDisplay ) {
/* Purpose: display timetodisplay using setNumber() and refresh display
*/ 

  sevseg.setNumber(timeToDisplay, 0);   //  select segment 2 for decimal pt
  sevseg.refreshDisplay();  // must refresh after every update
 }

 
void tooSlow( ) {
/*
  Purpose: if runningTime >= TIME_MAX, abourt test
  and display "----" 
*/
  if (runningTime >= TIME_MAX) {
    Serial.println("..TOO SLOW, GO BACK TO START AND RETRY");
    displayTime (runningTime);
    abortFlag = true;
  }
}  

// END OF PROGRAM