/*

Arduino Nano - old bootloader
Robert Parnell.
27/5/22
Wascoe Siding - signal module

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

V1 - create basic structure
V2 - 10/6/22. Simulated on-line and tested OK. To check on real hardware.
  Signal 1 has 2x turnout indicators and track circuit.
  Signal 2 does not have a separate track circuit (shared), no separate turnout indicators.
  13/6/22 - added heartbeat indicator on "spare" output. Tested in real world. All OK and final.
  
  ###########################


board outputs:
S1red Signal 1 - red
S1yel Signal 1 - yellow
S1grn Signal 1 - green
S1toL Signal 1 - turnout L
S1toR Signal 1 - turnout R
TC1   Panel mimic - track circuit 1
HB   heartbeat - indicates that unit is operating
S2red Signal 2 - red
S2yel Signal 2 - yellow
S2grn Signal 2 - green

board inputs:
track circuit 1
emergency stop
signal box proceed - signal 1
signal box proceed - signal 2 (if either input is inactive, then signal is at stop)
next signal ahead status (stop or proceed)
turnout L (from lever) OR signal box proceed in other direction
turnout R - from lever
turnout 3 - from lever


*/

//outputs:
int S1red = 2;// D2 etc
int S1yel = 3; 
int S1grn = 4; 
int S1toL = 5; 
int S1toR = 6; 
int EMERGind = 7; 
int TC1 = 8;
int HB = 9; // heartbeat indicator
int S2red = 10; 
int S2yel = 11; 
int S2grn  = 12; 

//inputs:
int trackcircuit1 = A0;
int emergencystop = A1;
int signal1proceed = A2;
int signal2proceed = A3; 
int signal1aheadstatus = A4; 
int turnoutL = A5;
int turnoutR = A6; 
int signal2aheadstatus = A7;

// input values:
int trackcct1Val = 1000;
int emergStopVal = 1000;
int signal1Val = 1000;
int signal2Val = 1000;
int signal1aheadVal = 1000;
int signal2aheadVal = 1000;
int turnoutLVal = 1000;
int turnoutRVal = 1000;


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

// for setting signal to "caution" after the block has become unoccupied - if signal is set to full clear
int blockwasoccupied = false; //
int blockisoccupied = false; //
int turnoutLNormal = false;
int turnoutLReverse = false;
int turnoutLmid = false; // 
int turnoutRNormal = false;
int turnoutRmid = false;
int turnoutRReverse = false;

unsigned long startMillis; // for starting countdown after blockwas occupied
unsigned long sigatStopMillis; // for 2 second debounce of track circuit
unsigned long cautiontimer = 8000; // time period for countdown (effectively less 2secs due to debounce timer)
unsigned long currentMillis; // what will be the current value to compare countdown to



void setup() {
  
  pinMode(S1red, OUTPUT);
  pinMode(S1yel, OUTPUT);
  pinMode(S1grn, OUTPUT);
  pinMode(S2red, OUTPUT);
  pinMode(S2yel, OUTPUT);
  pinMode(S2grn, OUTPUT);
  pinMode(S1toL, OUTPUT);
  pinMode(S1toR, OUTPUT);
  pinMode(EMERGind, OUTPUT);
  pinMode(TC1, OUTPUT);
  pinMode(HB, OUTPUT);
  
  pinMode(trackcircuit1, INPUT);
  pinMode(emergencystop, INPUT);
  pinMode(signal1proceed, INPUT);
  pinMode(signal2proceed, INPUT);
  pinMode(signal1aheadstatus, INPUT);
  pinMode(turnoutL, INPUT);
  pinMode(turnoutR, INPUT);
  pinMode(signal2aheadstatus, INPUT);

  startuptest();
  Serial.begin(9600); // Any baud rate should work
  Serial.println("Hello Arduino\n");
    
}

void loop() {  
  // read input values
  // display appropriate signal
  // go back and do it again!
  readinputvalues();
  displaysignals();
  digitalWrite(HB,LOW); // on
  delay(20);
  digitalWrite(HB,HIGH); // on
  delay(20);
}

void readinputvalues(){
     trackcct1Val = analogRead(trackcircuit1); // track circuit 1 status
     if (trackcct1Val <=500) {
       blockisoccupied = true; //
       blockwasoccupied = true;
       sigatStopMillis = millis();
     }
     else {
        currentMillis=millis();
        if (currentMillis-sigatStopMillis>=2000) blockisoccupied = false;
        if (currentMillis-sigatStopMillis>=cautiontimer) blockwasoccupied = false;
     }
     emergStopVal = analogRead(emergencystop); // emergency stop status
     signal1Val = analogRead(signal1proceed); // signaller signal switch
     signal2Val = analogRead(signal2proceed); // signaller signal switch
     signal1aheadVal = analogRead(signal1aheadstatus); // the signal status in advance of this signal
     signal2aheadVal = analogRead(signal2aheadstatus); // the signal status in advance of this signal
     turnoutLVal = analogRead(turnoutL); // the turnout lever status for Left turnout
     turnoutRVal = analogRead(turnoutR); // the turnout lever status for Right turnout
     // determine L turnout status:
     if (turnoutLVal <=340){
       turnoutLNormal = true;
       turnoutLReverse = false;
       turnoutLmid = false;
            } 
      else if (turnoutLVal <=680 ){
      turnoutLmid = true; 
      turnoutLNormal = false;
      turnoutLReverse = false;
     }
     else {
       turnoutLReverse = true;
       turnoutLNormal = false;
       turnoutLmid = false;
     }
     
     // determine R turnout status:
     if (turnoutRVal <=340) {
       turnoutRNormal = true;
       turnoutRReverse = false;
       turnoutRmid = false;
     }
     else if (turnoutLVal <=680 ) {
       turnoutRReverse = false;
       turnoutRNormal = false;
       turnoutRmid = true;}
     else {
       turnoutRNormal = false;
       turnoutRmid = false;
       turnoutRReverse = true;}
       
       delay (50); // Delay for inputs switch debounce.


}

void displaysignals(){
  // check emergency stop
  // check track circuit status
  // check signal switches
  // if cleared, check signal ahead and timer
  // also determine if turnout or straight route is set
  // if nothing else affected, display clear
  if ((turnoutLmid == true) || (turnoutRmid == true)){
    emergStopVal = 0;
    // this is effectively an emergency
      }
  
  if (emergStopVal<=500){
    displaySTOP();
    digitalWrite(EMERGind,HIGH);
    Serial.println("Emergency stop activated");
    if ((blockwasoccupied == false) && (blockisoccupied == false)) digitalWrite(TC1,LOW); // track circuit mimic OFF
  }
    else{
      digitalWrite(EMERGind,LOW);
      if (blockisoccupied == true){
       displaySTOP();
       digitalWrite(TC1,HIGH); // track circuit mimic ON
      }
        else{
          // block is not occupied
          digitalWrite(TC1,LOW); // track circuit mimic OFF
          
          // ****************** SIGNAL 1 ****************
          if (signal1Val>=500){
            Serial.println("signal 1 is at stop");
          // signal is set to stop
          digitalWrite(S1red,HIGH); // on
          digitalWrite(S1yel,LOW); // off
          digitalWrite(S1grn,LOW); // off
          digitalWrite(S1toL,LOW); // off
          digitalWrite(S1toR,LOW); // off
          }
          else{
            Serial.println("Signal 1 is not at stop");
            if (signal1Val<=500){
              // signal is set to proceed
              if (turnoutLReverse==true){
                Serial.println("L turnout");
                //display turnout aspect to the left
                digitalWrite(S1red,HIGH); // on
                digitalWrite(S1yel,LOW); // off
                digitalWrite(S1grn,LOW); // off
                digitalWrite(S1toL,HIGH); // on
                digitalWrite(S1toR,LOW); // off
                
              }
              if (turnoutRReverse==true){
                Serial.println("R turnout");
                // display turnout aspect to the right
                digitalWrite(S1red,HIGH); // on
                digitalWrite(S1yel,LOW); // off
                digitalWrite(S1grn,LOW); // off
                digitalWrite(S1toL,LOW); // off
                digitalWrite(S1toR,HIGH); // on
                
              }
              if ((turnoutLNormal==true) && (turnoutRNormal==true)){
                if ((blockwasoccupied == true) || (signal1aheadVal<=500)){
                  Serial.println("Caution");
                  // display caution aspect
                  digitalWrite(S1red,LOW); // off
                  digitalWrite(S1yel,HIGH); // on
                  digitalWrite(S1grn,LOW); // off
                  digitalWrite(S1toL,LOW); // off
                  digitalWrite(S1toR,LOW); // off
                  
                }
                
              
              else {
                // display clear
                Serial.println("Clear");
                if ((blockwasoccupied == false) & (signal1aheadVal>=500)){
                digitalWrite(S1red,LOW); // off
                digitalWrite(S1yel,LOW); // off
                digitalWrite(S1grn,HIGH); // on
                digitalWrite(S1toL,LOW); // off
                digitalWrite(S1toR,LOW); // off
                
                }
              } 
              }
            }
            
          }
          // ****************** SIGNAL 2 *******************
          if ((signal2Val>=500)||(turnoutRNormal==false)||(turnoutLNormal==false)    ){
            Serial.println("Signal 2 is at stop");
          digitalWrite(S2red,HIGH); // on
          digitalWrite(S2yel,LOW); // off
          digitalWrite(S2grn,LOW); // off
          }
             else{
            // Serial.println("Signal is not at stop");
            
              //if (turnoutRVal<=500){
              //  Serial.println("R turnout");
              //  // insert - display turnout aspect to the right
              //  digitalWrite(S2red,HIGH); // on
              //  digitalWrite(S2yel,LOW); // off
              //  digitalWrite(S2grn,LOW); // off
              //  digitalWrite(S1toL,LOW); // off
              //  digitalWrite(S1toR,HIGH); // on
                
              //}
              
                if ((blockwasoccupied == true) || (signal2aheadVal<=500)){
                  Serial.println("Caution2");
                  // display caution aspect
                  digitalWrite(S2red,LOW); // off
                  digitalWrite(S2yel,HIGH); // on
                  digitalWrite(S2grn,LOW); // off
                  digitalWrite(S1toL,LOW); // off
                  digitalWrite(S1toR,LOW); // off
                  
                }
                
              
              else {
                // display clear
                Serial.println("Clear 2");
                if ((blockwasoccupied == false) & (signal2aheadVal>=500)){
                digitalWrite(S2red,LOW); // off
                digitalWrite(S2yel,LOW); // off
                digitalWrite(S2grn,HIGH); // on
                digitalWrite(S1toL,LOW); // off
                digitalWrite(S1toR,LOW); // off
                
                }
              } 
              }
           
            
          }
          
        }
    
  
  
}
void startuptest(){
  // cycle throgh and test all outputs for a short time
  
  digitalWrite(S1red,HIGH); // on
  delay (testtime);
  digitalWrite(S1red,LOW); // off
  digitalWrite(S1yel,HIGH); // on
    delay (testtime);
  digitalWrite(S1yel,LOW); // off
  digitalWrite(S1grn,HIGH); // on
  delay (testtime);
  digitalWrite(S1grn,LOW); // off
  digitalWrite(S2red,HIGH); // on
  delay (testtime);
  digitalWrite(S2red,LOW); // off
  digitalWrite(S2yel,HIGH); // on
  delay (testtime);
  digitalWrite(S2yel,LOW); // off
  digitalWrite(S2grn,HIGH); // on
  delay (testtime);
  digitalWrite(S2grn,LOW); // off
  digitalWrite(S1toL,HIGH); // on
  delay (testtime);
  digitalWrite(S1toL,LOW); // off
  digitalWrite(S1toR,HIGH); // on
  delay (testtime);
  digitalWrite(S1toR,LOW); // off
  digitalWrite(EMERGind,HIGH); // on
  delay (testtime);
  digitalWrite(EMERGind,LOW); // off
  digitalWrite(TC1,HIGH); // on
  delay (testtime);
  digitalWrite(TC1,LOW); // off
  digitalWrite(HB,HIGH); // on
  delay (testtime);
  digitalWrite(HB,LOW); // off
  
}

void displaySTOP(){
    digitalWrite(S1red,HIGH); // on
    digitalWrite(S1yel,LOW); // off
    digitalWrite(S1grn,LOW); // off
    digitalWrite(S2red,HIGH); // on
    digitalWrite(S2yel,LOW); // off
    digitalWrite(S2grn,LOW); // off
    
     
     digitalWrite(S1toL,LOW); // off
     digitalWrite(S1toR,LOW); // off
     
}