/*

Arduino Nano - old bootloader
Robert Parnell.
28/6/23
Wascoe Siding - tunnel signal controller
(designed to be mounted on signal module PCB)
#############################

V1 - create basic structure


  
  ###########################


    board outputs:

T1 red
T1 yellow
T1 green
T2 red
T2 yellow
T3 green
track circuit mimic
HB   heartbeat - indicates that unit is operating


    board inputs:

signalafterT1
signalafterT2
trackcct
stop
T1 proceed
T2 proceed
emergency stop


*/

//outputs:
int red1 = 2;// D2 etc
int yellow1 = 3; 
int green1 = 4; 
int red2 = 5;
int yellow2 = 7; 
int green2 = 8;
int mimic = 9; 
int HB = 10; // heartbeat indicator
//int RevAlert = 11; 
//int S2grn  = 12; 

//inputs:
int nextT1 = A0;
int nextT2 = A1;
int trkcct = A2;
int stop = A3; 
int T1proceed = A4; 
int T2proceed = A6;
int emergencystop = A7;

// input values:
int nextT1Val = 1000;
int nextT2Val = 1000;
int trkcctVal = 1000;
int stopVal = 1000;
int T1proceedVal = 1000;
int T2proceedVal = 1000;
int emergencystopVal = 1000;

int testtime = 1000; // milliseconds for test lamp sequence

unsigned long HBstartMillis; // for heartbeat timer
unsigned long tunnelstartMillis; // for tunnel caution timer

unsigned long HBcurrentMillis; // what will be the current value to compare countdown to
unsigned long tunnelcurrentMillis;
unsigned long HBtimer = 500; // heartbeat timer
unsigned long tunneltimer = 10000; // timer to show caution, after train passes through tunnel

boolean caution = false; // tunnel timer up or not?
boolean HBtoggle = false; // HB LED toggle
boolean trackwasOCC = false;
boolean trackisOCC = false;
boolean displayingstop = false;

void setup() {

  pinMode(red1, OUTPUT);
  pinMode(yellow1, OUTPUT);
  pinMode(green1, OUTPUT);
  pinMode(red2, OUTPUT);
  pinMode(yellow2, OUTPUT);
  pinMode(green2, OUTPUT);
  pinMode(mimic, OUTPUT);
  pinMode(HB, OUTPUT);
  
  pinMode(nextT1, INPUT);
  pinMode(nextT2, INPUT);
  pinMode(trkcct, INPUT);
  pinMode(stop, INPUT);
  pinMode(T1proceed, INPUT);
  pinMode(T2proceed, INPUT);
  pinMode(emergencystop, INPUT);

  HBstartMillis = millis(); //start timing code for heartbeat
  tunnelstartMillis = millis(); //start timing code for alert
  
  startuptest();
  displaySTOP();

}

void loop() {  
  // read input values
  // display appropriate signal
  // go back and do it again!
  // flash heartbeat LED along the way
  
  HBcurrentMillis = millis();
  tunnelcurrentMillis = millis();
 
  if (HBcurrentMillis - HBstartMillis >= HBtimer){
    HBtoggle = !HBtoggle; // invert the status from true/false to false/true 
    digitalWrite(HB,HBtoggle); // turn HB on/off
    HBstartMillis = HBcurrentMillis;
  }
  
  readinputvalues();
  
}

void readinputvalues(){
  
  displayingstop = false;
     nextT1Val = analogRead(nextT1); // 
     nextT2Val = analogRead(nextT2); //
     trkcctVal = analogRead(trkcct); //
     stopVal = analogRead(stop); //
     T1proceedVal = analogRead(T1proceed); //
     T2proceedVal = analogRead(T2proceed); //
     emergencystopVal = analogRead(emergencystop); //
    
    
    if (stopVal <= 500) {
      displaySTOP();
      displayingstop = true;
    }
    
    if (emergencystopVal <= 500){
      displaySTOP();
      displayingstop = true;
    } 
    if (trkcctVal <=500){
      digitalWrite(mimic, HIGH);
      displaySTOP();
      displayingstop = true;
      trackwasOCC = true;
      trackisOCC = true;
      tunnelstartMillis = millis(); //start timing code for alert
      // loop through until unoccupied, via true/false logic
      delay (10); // track circuit debounce
      }
      else {
        trackisOCC = false;
        digitalWrite(mimic, LOW);
        //if (trackwasOCC == true) tunnelstartMillis = millis();
      }
      
      tunnelcurrentMillis = millis(); // 
      
      if (tunnelcurrentMillis-tunnelstartMillis <= tunneltimer) caution = true;
      else caution = false;
      
    if (trackwasOCC==true && caution == false) trackwasOCC = false; //time delay since occupancy has now passed
    
    //display other indications - only if track is NOT occupied
    if (trackisOCC==false && displayingstop == false){
      // check "proceed" switches
      // if set, check if there was a recent train in the tunnel and display "caution"
      // also check if the next signal is at stop and display "caution"
      // if both next signal is not at stop and no recent train in tunnel, display "clear"
      // do this for both directions
      if (T1proceedVal<=500) displayT1proceed();
      if (T2proceedVal<=500) displayT2proceed();
    }
 
 // end of readinputvalues() void ##############   
}


void displayT1proceed(){
  // signal 2 must be red
  digitalWrite(green2,LOW); // off
  digitalWrite(yellow2,LOW); // off
  digitalWrite(red2,HIGH); // on
  digitalWrite(red1,LOW); // T1 red must be off
  
  if (trackwasOCC == true || nextT1Val <=500 ){
    // display caution - since tunnel recently occupied or next signal is at stop
  digitalWrite(green1,LOW); // off
  digitalWrite(yellow1,HIGH); // off
  }
  else {
    // display clear
    digitalWrite(green1,HIGH); // off
  digitalWrite(yellow1,LOW); // off
  }
  //
  
}
void displayT2proceed(){
    // signal 1 must be red
  digitalWrite(green1,LOW); // off
  digitalWrite(yellow1,LOW); // off
  digitalWrite(red1,HIGH); // on
  digitalWrite(red2,LOW); // T2 red must be off
  
  if (trackwasOCC == true || nextT2Val <=500 ){
    // display caution - since tunnel recently occupied or next signal is at stop
  digitalWrite(green2,LOW); // off
  digitalWrite(yellow2,HIGH); // off
  }
  else {
    // display clear
    digitalWrite(green2,HIGH); // off
  digitalWrite(yellow2,LOW); // off
  }
  //
  
  
}
void displaySTOP(){
  
  digitalWrite(green1,LOW); // off
  digitalWrite(yellow1,LOW); // off
  digitalWrite(red1,HIGH); // on
  digitalWrite(green2,LOW); // off
  digitalWrite(yellow2,LOW); // off
  digitalWrite(red2,HIGH); // on
  
}
void startuptest(){
  // cycle through and test all outputs for a short time

  digitalWrite(mimic,HIGH); // on
  delay (testtime);
  digitalWrite(mimic,LOW); // off
  
  digitalWrite(green1,HIGH); // on
  delay (testtime);
  digitalWrite(green1,LOW); // off
  
  digitalWrite(yellow1,HIGH); // on
  delay (testtime);
  digitalWrite(yellow1,LOW); // off
  
  digitalWrite(red1,HIGH); // on
  delay (testtime);
  digitalWrite(red1,LOW); // off
  
  digitalWrite(green2,HIGH); // on
  delay (testtime);
  digitalWrite(green2,LOW); // off
  
  digitalWrite(yellow2,HIGH); // on
  delay (testtime);
  digitalWrite(yellow2,LOW); // off
  
  digitalWrite(red2,HIGH); // on
  delay (testtime);
  digitalWrite(red2,LOW); // off
  
}