//
// Wascoe Siding Loco Points interlocking
// R. Parnell 2019
//
// V10 - slow serial communication speed down to improve reliability and reduce false data causing issues
//
// Version 8 - 30/7/21. Reorganised loco track circuit occupancy into a single void to help with debounce issues which may be causing breif activation of loco points.
// Work on a "caution" aspect to display for a few seconds, following a block occupancy. Red -> yellow -> green instead of Red -> green. 
// - after block becomes unoccupied, check millis value (Arduino timer)
// - add period of time for "caution" to millis value {endtime = millis value + caution value
// - if signal setting is clear, then show "caution" instead, until entdtime millis value is greater than current millis value
// - "<pointsfailed>" changed to "<pointsfailed7>" to help distance the text from <pointsnotfailed> 7/11/21
//
// Version 7 - March 2021. Ensure signals are red before changing points. Can defeat programming by quickly pressing buttons/switches.
// Phantom activation of loco departure track circuit. To debug.
// Changing points - they keep attempting to change after successfully having changed over. To debug.
//
//
// Version 6 - 6/12/20. When points change, it keeps trying to change them for 2 or 3 cycles after they have successfully changed over.
// Added short delays in serial data in case there is a backlog of requests to change points.
// increased point detection to 2 seconds from 1.5 seconds
// reduced block occupancy delay from 5 seconds to 3.5 seconds
//
//
// Version 5 - 28/11/20. Set "local" panel mimic to not flash points during transit, as this also operates the points motor and causes a pulsating motor operation.
//  added 1 second delay to loco track circuit occupancy to assist with debounce
//
// Version 4- 25/11/20. Hopefully fixed erroneous signal change issue
//  monitored serial data and found regular corruption.
//  It appears that a random "corrupt" word became equal to a valid word
//  ie: "setACWclear" was corrupted to "setclear" which was also valid.
//  Data words changed to more unique words that are impossible to truncate to a valid word.
//
// Version 3- commenced 13/11/20
//  *Increased points operation time period to 12 seconds to suit new, slower motor
//  *Added a flashing mimic diagram indication during the 12 second operation to show
//    that something is acutually happening
//
// Version 2 - commenced 25/7/20 to remove a couple of bugs:
//    *Random glitch of S2 momentary clearing, then returning to required state.
//    *Signal switch set to stop during occupancy of block - currently flicks back to previous state
//
// Uses Arduino Mega 2560 R3. Idential programming for local and remote units.
// An input pin determines what section of programming to operate on - local or remote.
//
// With contributed ideas and
// suggestions from various Wascoe Siding members during discussions throughout 2019.
//
// final testing and debugging from 22/10/19
//

// Note: uses Serial port1, not Serial port 0.
// pin 18/19 not 0/1 as serial port 0 is also the USB comms port and
// serial 1 can pick up comms at any time.
// If data coming in on Serial 0 when powered up, the sketch
// halts indefinitely as it expects the USB port to be talking to it.
// Aruidno Mega 2560 limitation.


// define outputs
// all outputs at signal box (remote end) are active LOW to suit external switching
// all outputs at loco (local end) are active HIGH to suit relay modules

// global variables/inputs/outputs listed here:

int SIG2red = 24; // signal 2 red = pin D24
int SIG2yel = 25; // signal 2 yelow = pin D25

int SIG3grn = 27; // signal 3 green = pin D27
int SIG3yel = 29; // signal 3 yelow = pin D29
int SIG3red = 31; // signal 3 red = pin D31

int SIG1grn  = 33; // signal 1 green = pin D33
int SIG1yel  = 35; // signal 1 yeLOW = pin D35
int SIG1red  = 37; // signal 1 red = pin D37
int SIG1MN   = 39; // signal 1 MAIN route ind = pin D39
int SIG1LOCO = 41; // signal 1 LOCO route ind = pin D41

int pointN = 43; // points Normal indicator = pin D43
int pointR = 45; // points Reverse indicator = pin D45

int LOCAL  = 47; // local control mode = D47
int REMOTE = 49; // Remote control mode = D49

int blockocc = 51; // block occupancy indicator = pin D51

int emergSTOP = 53; // emergency STOp indicator = pin D53

int locotrack = 22; // loco track circuit occupancy
int ptsfailed = 23; // points failed indicator

int SWstopval = 1000; // STOP signal selector switch on panel 

int setlocal   = A11; // jumper to select either local or remote
int setremote = A12; // jumper to select either local or remote
//int localRX = A14; // used to validate local data coming in
//int remoteRX = A15; // used to validata remote data coming in

int SWITCHpointsN = A4; // switch input points Normal A4
int SWITCHpointsR = A5; // switch input points reverse A5

int SWITCHanticlear = A6; // switch inputs for signal indications clockwise and anticlockwise
int SWTICHanticaution = A7;
int SWITCHstop = A8;
int SWITCHcwcaution = A9;
int SWITCHclear = A10;

int setlocalval = 1000; // set input as inactive (LOW)
int setremoteval = 1000; // set input as inactive (LOW)

int Rxdata = false; //global variable to determine if data is being received. Zero = no, 1 = yes

int dt = 3000; // set test time of each lamp (mS), reduced for debugging

const byte numChars = 32;
char receivedChars[numChars];
int newData = false;

int pointsREVERSE = false;
int pointsNORMAL = false;

int datacount = 0;

int pointsFAILED = false;

int pointsNval = 1000;
int pointsRval = 1000;

int stoptime = 0;
int sSSWstopval = 1000;

int pointsdetectN = A2;
int pointsdetectR = A3;

int zdatacount = 0;
int SSWstopval = 1000; // set switch value to high

int zzstop = 0; // time counter for switch being at stop

int locotrackcircuitval = 1000; // put here 30/7/21
int locotrackcct = A13; // switch inputs for signal indications clockwise and anticlockwise
int blockstatus = A0;
int SWITCHemergSTOP = A1;

// for setting signal to "caution" after the block has become unoccupied - if signal is set to full clear
int blockwasoccupied = false; // 
unsigned long startMillis; // for starting countdown after blockwas occupied
unsigned long cautiontimer = 7000; // time period for countdown
unsigned long currentMillis; // what will be the current value to compare countdown to


//#########################

void setup() {
  // Loco points signal controller
  // March 2019
  
  // R. Parnell
}

//#########################

void loop() {
  Serial1.begin(2400);  // to talk to other unit via wire link. Changed to 2400 from 9600 21/2/22
  Serial.begin(9600); // to talk to USB port for debugging

  //  Serial11.begin(9600);
  //  Serial1.println("Start - setting up. 13/6/19.");

  const byte numChars = 32;
  char receivedChars[numChars];
  boolean newData = false;

  // Common to both local and remote units - define output pins as follows:

  pinMode(SIG2red, OUTPUT);
  pinMode(SIG2yel, OUTPUT);

  pinMode(SIG3red, OUTPUT);
  pinMode(SIG3yel, OUTPUT);
  pinMode(SIG3grn, OUTPUT);

  pinMode(SIG1red, OUTPUT);
  pinMode(SIG1yel, OUTPUT);
  pinMode(SIG1grn, OUTPUT);
  pinMode(SIG1MN, OUTPUT);
  pinMode(SIG1LOCO, OUTPUT);

  pinMode(pointN, OUTPUT);
  pinMode(pointR, OUTPUT);

  pinMode(LOCAL, OUTPUT);
  pinMode(REMOTE, OUTPUT);

  pinMode(blockocc, OUTPUT);
  pinMode(emergSTOP, OUTPUT);
  pinMode(locotrack, OUTPUT);
  pinMode(ptsfailed, OUTPUT); // points failure

  //check for either local or remote mode. Display indicator and set variable
  delay (300);

  determinelocalremote();

  // if neither local or remote, then oscillate between the indicators until such time as something is set
  // Can proceed if only 1 local or remote input is HIGH.

  //once local or remote is set, do the respective loop for that operating mode

  // turn all outputs off
  // DO THIS AFTER DETERMINING LOCAL OR REMOTE UNIT as opposite active output states for local and remote

  if (setremoteval < 300) {
    // I am the remote (signal box) end
    // turn off all outputs for signal box end
    digitalWrite(SIG2red, LOW);
    digitalWrite(SIG2yel, LOW);
    digitalWrite(SIG3red, LOW);
    digitalWrite(SIG3yel, LOW);
    digitalWrite(SIG3grn, LOW);
    digitalWrite(SIG1red, LOW);
    digitalWrite(SIG1yel, LOW);
    digitalWrite(SIG1grn, LOW);
    digitalWrite(SIG1MN, LOW);
    digitalWrite(SIG1LOCO, LOW);
    digitalWrite(pointN, LOW);
    digitalWrite(pointR, LOW);
    digitalWrite(LOCAL, LOW);
    digitalWrite(REMOTE, LOW);
    digitalWrite(blockocc, LOW);
    digitalWrite(emergSTOP, LOW);
    digitalWrite(ptsfailed, LOW); // points failure
    digitalWrite(locotrack, LOW);
    Serial1.println("testing each signal box lamp output");
    delay (250);
    Testremotelamps(); // run through test lamp sequencer

  }

  if (setlocalval < 300) {
    // I am the local end
    // turn off all outputs for local end

    digitalWrite(SIG2red, HIGH);
    digitalWrite(SIG2yel, HIGH);
    digitalWrite(SIG3red, HIGH);
    digitalWrite(SIG3yel, HIGH);
    digitalWrite(SIG3grn, HIGH);
    digitalWrite(SIG1red, HIGH);
    digitalWrite(SIG1yel, HIGH);
    digitalWrite(SIG1grn, HIGH);
    digitalWrite(SIG1MN, HIGH);
    digitalWrite(SIG1LOCO, HIGH);
    digitalWrite(pointN, HIGH);
    digitalWrite(pointR, HIGH);
    digitalWrite(LOCAL, HIGH);
    digitalWrite(REMOTE, HIGH);
    digitalWrite(blockocc, HIGH);
    digitalWrite(emergSTOP, HIGH);
    digitalWrite(ptsfailed, HIGH); // points failure
    digitalWrite(locotrack, HIGH);
    Serial1.println("testing each LOCAL lamp output");
    delay (250);
    Testlamps();
  }
  //now all signals are at stop, wait 5 seconds then set points for main
  // Serial1.println("all signals stop after testing lamps");
  //ALLRED();
  if (setlocalval < 300) digitalWrite(pointN, HIGH); // set points to normal in case they are not already

  delay (4000); //remarked out to save time during debugging

  //Serial1.begin(9600); remarked out 21/2/22 since serial link speed is already established.


  if (setlocalval < 300 ) goto Localmodeloop;
  if (setremoteval < 300) goto Remotemodeloop;


  //                                   ###################################
  ///                                     ### end of initialisation ###
  ///                                     ### end of initialisation ###
  ///                                     ### end of initialisation ###
   //                                   ###################################

  // LOCAL LOCAL LOCAL LOCAL LOCAL LOCAL LOCAL LOCAL
  //
  //  #                      #
  //  #      ###   ###  ###  #
  //  #     #   # #        # #
  //  #     #   # #    ##### #
  //  #     #   # #    #   # #
  //  #####  ###   ###  #### #
  //
  // LOCAL LOCAL LOCAL LOCAL LOCAL LOCAL LOCAL LOCAL start


Localmodeloop: // LOCAL MODE LOOP START ###################

// localmodeloop should only be run once, then carry on through localmodeloop2 indefinitely.

  ALLRED();
  digitalWrite(SWITCHstop, INPUT_PULLUP);
  // check for red signal setting. Loop through until it has been set red for 5 seconds
  //Serial1.println ("I am running the local mode loop....."); // debugging
  stoptime = 0;
SSWITCHSTOP:
  // Serial.println ("SSWITCHSTOP loop"); // debugging
  SSWstopval = analogRead(SWITCHstop); // read the input status
  delay (15);
  if (SSWstopval > 300) {
    goto SSWITCHSTOP;
    stoptime = 0;
  }
  if (SSWstopval < 300) stoptime = stoptime + 1;
  if  (stoptime == 89) goto localmodeloop2;
  // Serial1.println ("I am in the first part of local mode loop waiting for switch to be set to stop....."); // debugging
  goto SSWITCHSTOP;
  // this section in localmodeloop above working OK 11/10/19
  // the above section runs ONCE, then enters localmodeloop2 indefinitely...
  
//#######################################################################################################################################

localmodeloop2: // ##############
  // this is the main "local mode" loop which runs indefinietly once started

  //Serial.println ("I am in localmodeloop2");//debugging
  digitalWrite(LOCAL, LOW); //turn Local output on (green LED on front cabinet door) labelled "NORMAL"
  checkcriticalinputs(); // check critical inputs
  receiveremotedata(); //
  decodeREMOTEdata();  // checks data loop from other end and sets REMOTE LED and input as required
  // a loop withing decodeREMOTEdata() clycles through until RXdata is lost
  // Serial1.println ("I have checked and decoded any remote data"); //debugging

  zdatacount = 0; // sets number of times Rxdata has been false

Rxdataloop:
  if (Rxdata == false)  zdatacount = zdatacount + 1;
  if (zdatacount < 90) Rxdata = true;       //value increased to 90 from 50 7/11/21
  if (zdatacount == 90) Rxdata = false;     //value increased to 90 from 50 7/11/21

  if (Rxdata == true) {
    // then don't check local switches. Continue to act on incoming data
    //   Serial.println("Incoming data is TRUE - I'm acting upon incoming data");//debugging
    checkcriticalinputs(); // check critical inputs
    receiveremotedata();
    decodeREMOTEdata();
  }
  if (zdatacount < 50) goto Rxdataloop; //loop back while ever data is coming in

  if (Rxdata == false) {
    // if false, check signal switch to be at stop for 5 seconds, then check switches

    stoptime = 0;

TIMEatSTOP:
        sSSWstopval = analogRead(SWITCHstop); // read the input status
    delay (15);
    
    //check critical inputs in here
    //check for incoming data. If data incoming, then reset the STOP time and act on data
    checkcriticalinputs(); // check critical inputs
    receiveremotedata();
    decodeREMOTEdata();
    //Serial1.println("Stoptime loop counter (up to 50)");//debugging
    //Serial1.println(stoptime);//debugging
    //Serial1.println ("switch at stop time not elapsed and no Rx data. Looping through many times"); // debugging
    if (sSSWstopval > 300 && Rxdata == false) goto TIMEatSTOP; // if swtich is not at stop, keep checking
    if (sSSWstopval < 300 && Rxdata == false) stoptime = stoptime + 1; // not that it is at stop, count time
    if  (stoptime < 50 && Rxdata == false) goto TIMEatSTOP; // if time not elapsed, go back and wait

    if (Rxdata == true) goto Endofsubroutine;
    //Serial.println ("STOPPED for required time, now check switches");//debugging

    // 11/10/19 dinner

    // at this point, data is not coming in and switch has been at stop for required time
    // now check switches continuously and act upon them.
    // if signal switch remains at stop for 5 seconds during these checks, then check for incoming data and get out of the loop

NoActivityLoop:
    delay (10);
    // Serial.println("I'm in the no data coming in loop - getting out by data coming in, checking switches. then 5 seconds at stop");//debugging
    // Serial.println("zzstop value:");//debugging
    // Serial.println(zzstop);//debugging

    //insert routine to check points button switches here. If not pressed, then check other switches 17/11/19. Fixed 17/11/19.

Onlyonebutton:
    int SWpointsNval = 1000;
    int SWpointsRval = 1000;
    SWpointsNval = analogRead(SWITCHpointsN);
    SWpointsRval = analogRead(SWITCHpointsR);
    if (SWpointsNval < 300 && SWpointsRval < 300) goto Onlyonebutton; // if both points buttons are active, then ignore them until only one is active

    if (SWpointsNval < 300) {
      //  Serial.println("Points NORMAL button has been pressed"); //debugging
      POINTSnormal(); // points N switch is active, go and set them to Normal
      stoptime = 0;
      zzstop = 0;
    }
    if (SWpointsRval < 300) {
      // Serial.println("Points REVERSE button has been pressed"); //debugging
      POINTSreverse(); // points R switch is active, go and set them to Reverse
      stoptime = 0;
      zzstop = 0;
    }


    checkcriticalinputs(); // check critical inputs
    sSSWstopval = analogRead(SWITCHstop); // read the input status
    if (sSSWstopval > 300) {
      // Serial.println(" I'm in the NoActivityLoop. Apparently the signal switch is not at stop");//debugging
      checkswitches(); // if switch is not at stop, go and check other switches and act upon setting
      goto NoActivityLoop; // since the switches are in use, keep checking them
    }
    if (sSSWstopval <=300 ) ALLSTOP(); // added 25/3/22

     // now see if any data is coming in
    receiveremotedata(); //
    decodeREMOTEdata();
    //  zzstop = zzstop - 1; //decrement counter as enough time has elapsed at stop
    //  }
    // if data is coming in, wait for signal switch to be at stop for 5 seconds then go and act on data

    if (Rxdata == false) goto NoActivityLoop;


    //   Serial1.println ("we now have data and switch still has been at stop for required time. Check incoming data again");//debugging
Endofsubroutine:
    delay (1); // do nothing as I have jumped to the end
Serial1.println("End of local mode loop subroutine"); //debugging
  }


  goto localmodeloop2;

  // ## end of loco mode loop ## @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  // ## NOTE: outputs are ACTIVE LOW for remote end

  // ## start of remote mode loop ##
  // ## NOTE: outputs are ACTIVE HIGH for local end




  //***************************************************************************************

  // ############################################
  // ####
  // #### Remote mode loop ####
  // ####
  // ############################################
  // this is happening at the remote (signal box) end
  // check switches and send switch state to other end
  // listen for incoming data and act
  // if no data incoming, then display alert

Remotemodeloop:

  digitalWrite(REMOTE, HIGH);
  Serial1.println ("I am running the remote mode loop.....");
  checkremoteswitches(); // check signal box switches
  receiveLOCALdata();    // receive and decode data from local end
  decodeLOCALdata();

  if (Rxdata == false)  zzstop = zzstop + 1;
  if (Rxdata == true) zzstop = 0;

  if (zzstop == 80) {
    // there is no data coming form local end, flash emerg, points fail, local and remote LEDs
    digitalWrite(REMOTE, HIGH);
    digitalWrite(LOCAL, HIGH);
    digitalWrite(emergSTOP, HIGH);
    digitalWrite(ptsfailed, HIGH);
    zzstop = zzstop - 1;
    delay (80);
    digitalWrite(REMOTE, LOW);
    digitalWrite(LOCAL, LOW);
    digitalWrite(emergSTOP, LOW);
    digitalWrite(ptsfailed, LOW);
    delay (80);
    digitalWrite(LOCAL, HIGH);

  }

  // check signal box emergency switch input
  // Send switch setting data
  //decode data and display accordingly

  goto Remotemodeloop;
}


//########################################################################################################
//########################################################################################################



void checkcriticalinputs() {

  // note: critical inputs can only occur from local unit end
  //Serial.println ("I am checking criticalinputs subroutine");// debugging
  POINTSnotset(); // check that points are set one way or the other

  // removed to become global variable 30/7/21. int locotrackcct = A13; // switch inputs for signal indications clockwise and anticlockwise

  pinMode(locotrackcct, INPUT);
  pinMode(SWITCHemergSTOP, INPUT);
  pinMode(blockstatus, INPUT);

  digitalWrite(SWITCHemergSTOP, INPUT_PULLUP);  // set pull-up on analog pin
  digitalWrite(blockstatus, INPUT_PULLUP);
  digitalWrite(locotrackcct, INPUT_PULLUP);

  int blockval = 1000; // set  input as inactive
  int emergval = 1000; // set emergency input as inactive
  // int locotrackcircuitval = 1000; removed 30/7/21 to universal variable


  //locotrackcircuitval = analogRead(locotrackcct); // read input
  locotrackocc(); //check loco track circuit occupancy
  blockval = analogRead(blockstatus); // read input status
  emergval = analogRead(SWITCHemergSTOP); // read input

  
  // all working above this remark 16/6/19

  if (blockval < 300) {
    digitalWrite(blockocc, LOW);
    ALLSTOP();
  //Serial.println("block is occupied"); // debugging 25/3/22
BLOCKLOOP:
    Serial1.println("<blockocc1>");

    //locotrackcircuitval = analogRead(locotrackcct); // read input
    locotrackocc(); //check loco track circuit occupancy
    blockval = analogRead(blockstatus); // read input status
    emergval = analogRead(SWITCHemergSTOP); // read input
    
    if (emergval < 300) {
      Serial1.println("<emergstop1>");
      digitalWrite(emergSTOP, LOW);
    }
    if (emergval > 300) {

      Serial1.println("<emergstop0>");
      digitalWrite(emergSTOP, HIGH);

    }
    if (blockval < 300) goto BLOCKLOOP;
    if (emergval < 300) goto BLOCKLOOP;

    for (int i = 0; i <= 10; i++) {
      safetydelay();
      // block has now become unoccupied
    } // loop through 100mS delay, flicking LED for a total of 1 second to allow motor to operate

      
      locotrackocc(); //check loco track circuit occupancy
   // locotrackcircuitval = analogRead(locotrackcct); // read input
   // if (locotrackcircuitval < 300) LOCOOCCUPIED();
  //  if (locotrackcircuitval > 300) LOCOUNOCCUPIED();

    for (int i = 0; i <= 10; i++) {
      safetydelay();
    } // loop through 100mS delay, flicking LED for a total of 1 second to allow motor to operate

locotrackocc(); //check loco track circuit occupancy
    
    for (int i = 0; i <= 10; i++) {
      safetydelay();
    } // loop through 100mS delay, flicking LED for a total of 1 second 

    locotrackocc(); //check loco track circuit occupancy

    for (int i = 0; i <= 10; i++) {
      safetydelay();
    } // loop through 100mS delay, flicking LED for a total of 1 second 

    locotrackocc(); //check loco track circuit occupancy

    for (int i = 0; i <= 10; i++) {
      safetydelay();
    } // loop through 100mS delay, flicking LED for a total of 1 second 

   locotrackocc(); //check loco track circuit occupancy
   
      blockwasoccupied = true; // flag that something has occupied the block - inserted here 25/3/22
      startMillis = millis(); // read millis value for "caution" timer - inserted here 25/3/22
    
    Serial1.println("<blockocc0>");
    //30/7/21 

    digitalWrite(blockocc, HIGH);



    // now it is activated, wait for it to be inactive.
    // once inactive, wait 5 seconds.
    // during this, check emergency input and show status

  }

  if (blockval > 300) {
    Serial1.println("<blockocc0>");
    digitalWrite(blockocc, HIGH);

  }

  if (emergval < 300) {

    digitalWrite(emergSTOP, LOW);
    ALLSTOP();

ELOOP:

    Serial1.println("<emergstop>");

    locotrackocc(); //check loco track circuit occupancy
    blockval = analogRead(blockstatus); // read input status
    emergval = analogRead(SWITCHemergSTOP); // read input
    
    if (blockval < 300) {
      Serial1.println("<blockocc1>");
      digitalWrite(blockocc, LOW);
      // receivedChars = "setstop";
    }
    if (blockval > 300) {

      Serial1.println("<blockocc0>");
      digitalWrite(blockocc, HIGH);

    }
    if (emergval < 300) goto ELOOP;
    if (blockval < 300) goto ELOOP;


    for (int i = 0; i <= 7; i++) {
      safetydelay();
    } // loop through 100mS delay, flicking LED for a total of 1 second to allow motor to operate

    locotrackocc(); //check loco track circuit occupancy

    for (int i = 0; i <= 7; i++) {
      safetydelay();
    } // loop through 100mS delay, flicking LED for a total of 1 second to allow motor to operate

    locotrackocc(); //check loco track circuit occupancy
    
    for (int i = 0; i <= 7; i++) {
      safetydelay();
    } // loop through 100mS delay, flicking LED for a total of 1 second to allow motor to operate

    locotrackocc(); //check loco track circuit occupancy

    for (int i = 0; i <= 7; i++) {
      safetydelay();
    } // loop through 100mS delay, flicking LED for a total of 1 second to allow motor to operate

    locotrackocc(); //check loco track circuit occupancy

    for (int i = 0; i <= 7; i++) {
      safetydelay();
    } // loop through 100mS delay, flicking LED for a total of 1 second to allow motor to operate

    locotrackocc(); //check loco track circuit occupancy

// loco occupancy values reduced to 300 from 500 - 8/3/21 to prevent possible false triggering.
// time delay after block occupancy reduced to 3.5 seconds (5 x [7x10ms loops]) after feedback from board 6/12/20

    Serial1.println("<emergstop0>");

    // now it is activated, wait for it to be inactive.
    // once inactive, wait 5 seconds.
    // during this, check block occupancy and show status

  }

  if (emergval > 300) {

    Serial1.println("<emergstop0>");


  }



}
// end of checking critical inputs. This routine working fine 16/6/19
//#########################

// outputs change output status only. Serial1 data is sent from either local or remote mode loops.

void LOCOOCCUPIED() {
  
  Serial1.println("<locoocc1>");
  digitalWrite(locotrack, LOW); // turn on LOCO T/C on local panel
  delay (1000); //added 28/11/20
}

void LOCOUNOCCUPIED() {
  
  Serial1.println("<locooccupied0>");
  digitalWrite(locotrack, HIGH); // turn off LOCO T/C on local panel
  }

void EMERGSTOP() {

  digitalWrite(SIG2red, LOW);
  digitalWrite(SIG2yel, HIGH);
  digitalWrite(SIG3red, LOW);
  digitalWrite(SIG3yel, HIGH);
  digitalWrite(SIG3grn, HIGH);
  digitalWrite(SIG1red, LOW);
  digitalWrite(SIG1yel, HIGH);
  digitalWrite(SIG1grn, HIGH);
  digitalWrite(SIG1MN, HIGH);
  digitalWrite(SIG1LOCO, HIGH);

  Serial1.println("<emergstop1>"); // send "emergstop" to remote
 
}

//##########################################


void ALLRED() {        // note - ALLRED for when block occupied or points operating
  digitalWrite(SIG2red, LOW);
  digitalWrite(SIG2yel, HIGH);
  digitalWrite(SIG3red, LOW);
  digitalWrite(SIG3yel, HIGH);
  digitalWrite(SIG3grn, HIGH);
  digitalWrite(SIG1red, LOW);
  digitalWrite(SIG1yel, HIGH);
  digitalWrite(SIG1grn, HIGH);
  digitalWrite(SIG1MN, HIGH);
  digitalWrite(SIG1LOCO, HIGH);

  Serial1.println("<allstop1>"); // send message to remote
 }

// #########################

void sigboxALLRED() {        // as displayed in signal box
  digitalWrite(SIG2red, HIGH);
  digitalWrite(SIG2yel, LOW);
  digitalWrite(SIG3red, HIGH);
  digitalWrite(SIG3yel, LOW);
  digitalWrite(SIG3grn, LOW);
  digitalWrite(SIG1red, HIGH);
  digitalWrite(SIG1yel, LOW);
  digitalWrite(SIG1grn, LOW);
  digitalWrite(SIG1MN, LOW);
  digitalWrite(SIG1LOCO, LOW);
}
//#########################

void ALLSTOP() {        // all signals at stop as set by signal switch
  ALLRED(); // the outputs are the same as ALLSTOP()


}
// #########################################
//
//  ###  #   # #####  ###  #   #     ####  #####  ###
// #     #   # #     #     #  #      #   #   #   #
// #     ##### ###   #     ###       ####    #    ###
// #     #   # #     #     #  #      #       #       #
//  ###  #   # #####  ###  #   #     #       #    ###
//
// #########################################

void POINTSnotset() { // Check points blade position. If not N or R, then emergency stop.

  //Serial1.println ("I am running the checking points (pointsnotset subroutine)....."); // debugging


  pinMode(pointsdetectN, INPUT);
  pinMode(pointsdetectR, INPUT);
  digitalWrite(pointsdetectN, INPUT_PULLUP);  // set pull-up
  digitalWrite(pointsdetectR, INPUT_PULLUP);

  pointsNval = analogRead(pointsdetectN); // read the input status
  pointsRval = analogRead(pointsdetectR); // read the input status

  if (pointsNval > 300 && pointsRval > 300) {
    POINTSFAIL();
    safetydelay();
    safetydelay();
    //  Serial.println("points initial detect fail");//debugging

  }

  if (pointsNval < 300) goto ENDFAILLOOP;
  if (pointsRval < 300) goto ENDFAILLOOP;

  pointsNval = analogRead(pointsdetectN); // read the input status
  pointsRval = analogRead(pointsdetectR); // read the input status

  if (pointsNval > 300 && pointsRval > 300) {
    POINTSFAIL();
    safetydelay();
    safetydelay();
    //  Serial.println("points 2nd detect fail");//debugging

  }

  if (pointsNval < 300) goto ENDFAILLOOP;
  if (pointsRval < 300) goto ENDFAILLOOP;

  pointsNval = analogRead(pointsdetectN); // read the input status
  pointsRval = analogRead(pointsdetectR); // read the input status

  if (pointsNval > 300 && pointsRval > 300) {
    POINTSFAIL();
    safetydelay();
    safetydelay();
    //   Serial.println("points 3rd detect fail");//debugging

  }

  if (pointsNval < 300) goto ENDFAILLOOP;
  if (pointsRval < 300) goto ENDFAILLOOP;

  pointsNval = analogRead(pointsdetectN); // read the input status
  pointsRval = analogRead(pointsdetectR); // read the input status

  if (pointsNval > 300 && pointsRval > 300) {
    POINTSFAIL();
    safetydelay();
    safetydelay();
    //   Serial.println("points 4th detect fail");//debugging

  }

  if (pointsNval < 300) goto ENDFAILLOOP;
  if (pointsRval < 300) goto ENDFAILLOOP;

  pointsNval = analogRead(pointsdetectN); // read the input status
  pointsRval = analogRead(pointsdetectR); // read the input status

  if (pointsNval > 300 && pointsRval > 300) {
    POINTSFAIL();
    safetydelay();
    safetydelay();
    //   Serial.println("points 5th detect fail");//debugging

  }

  if (pointsNval < 300) goto ENDFAILLOOP;
  if (pointsRval < 300) goto ENDFAILLOOP;

  pointsNval = analogRead(pointsdetectN); // read the input status
  pointsRval = analogRead(pointsdetectR); // read the input status

  if (pointsNval > 300 && pointsRval > 300) {
    POINTSFAIL();
    safetydelay();
    safetydelay();
    //   Serial.println("points 6th detect fail");//debugging

  }

  if (pointsNval < 300) goto ENDFAILLOOP;
  if (pointsRval < 300) goto ENDFAILLOOP;

  pointsNval = analogRead(pointsdetectN); // read the input status
  pointsRval = analogRead(pointsdetectR); // read the input status

  if (pointsNval > 300 && pointsRval > 300) {
    POINTSFAIL();
    safetydelay();
    safetydelay();
    //   Serial.println("points 7th detect fail");//debugging

  }

  if (pointsNval < 300) goto ENDFAILLOOP;
  if (pointsRval < 300) goto ENDFAILLOOP;

  pointsNval = analogRead(pointsdetectN); // read the input status
  pointsRval = analogRead(pointsdetectR); // read the input status

  if (pointsNval > 300 && pointsRval > 300) {
    POINTSFAIL();
    safetydelay();
    safetydelay();
    //    Serial.println("points 8th detect fail");//debugging

  }

  if (pointsNval < 300) goto ENDFAILLOOP;
  if (pointsRval < 300) goto ENDFAILLOOP;

  pointsNval = analogRead(pointsdetectN); // read the input status
  pointsRval = analogRead(pointsdetectR); // read the input status

  if (pointsNval > 300 && pointsRval > 300) {
    POINTSFAIL();
    safetydelay();
    safetydelay();
    //   Serial.println("points 9th detect fail");//debugging

  }

  if (pointsNval < 300) goto ENDFAILLOOP;
  if (pointsRval < 300) goto ENDFAILLOOP;

  pointsNval = analogRead(pointsdetectN); // read the input status
  pointsRval = analogRead(pointsdetectR); // read the input status

  if (pointsNval > 300 && pointsRval > 300) {
    POINTSFAIL();
    safetydelay();
    safetydelay();
    //    Serial.println("points 10th detect fail");//debugging

  }

  if (pointsNval < 300) goto ENDFAILLOOP;
  if (pointsRval < 300) goto ENDFAILLOOP;

  pointsNval = analogRead(pointsdetectN); // read the input status
  pointsRval = analogRead(pointsdetectR); // read the input status

  if (pointsNval > 300 && pointsRval > 300) {
    POINTSFAIL();
    safetydelay();
    safetydelay();
    //   Serial.println("points 11th detect fail");//debugging

  }

  if (pointsNval < 300) goto ENDFAILLOOP;
  if (pointsRval < 300) goto ENDFAILLOOP;

  pointsNval = analogRead(pointsdetectN); // read the input status
  pointsRval = analogRead(pointsdetectR); // read the input status

  if (pointsNval > 300 && pointsRval > 300) {
    POINTSFAIL();
    safetydelay();
    safetydelay();
    //  Serial.println("points 12th detect fail");//debugging

  }

  if (pointsNval < 300) goto ENDFAILLOOP;
  if (pointsRval < 300) goto ENDFAILLOOP;


  //allow signaller to try again since still failed
  //
  // after subroutine, go back to "POINTS" within this routine

  int SWITCHpointsN = A4; // button switch input points Normal A4
  int SWITCHpointsR = A5; // button switch input points reverse A5
  pinMode(SWITCHpointsN, INPUT);
  pinMode(SWITCHpointsR, INPUT);
  digitalWrite(SWITCHpointsN, INPUT_PULLUP);  // set pull-up
  digitalWrite(SWITCHpointsR, INPUT_PULLUP);
  int SWITCHpointsNval = 1000; // set  input as inactive
  int SWITCHpointsRval = 1000; // set  input as inactive

  POINTSFAIL();

FAILLOOP:
  // Serial.println ("points failure - looping through until they are set");
  // ploop:
  Serial1.println ("<pointsfailed7>");
  digitalWrite(pointR, HIGH);
  digitalWrite(pointN, HIGH);
  digitalWrite(ptsfailed, HIGH);

  safetydelay();
  Serial1.println ("<pointsnotfailed>");
  // Serial.println ("turning off points fail lamp to flash it during failure");// turn off sigbox points failed lamp to "flash" it.
  digitalWrite(ptsfailed, LOW);
  safetydelay();

 
  // now that points have failed, enable points control button and keep checking blades until sorted out
  pointsNval = analogRead(pointsdetectN); // check points blades
  pointsRval = analogRead(pointsdetectR);
  SWITCHpointsNval = analogRead(SWITCHpointsN); // read the input status
  SWITCHpointsRval = analogRead(SWITCHpointsR); // read the input status

  if (SWITCHpointsNval < 300) {
    digitalWrite(pointR, HIGH);
    digitalWrite(pointN, LOW);

      Serial1.println("<pointssetnormal>");
    pointsNORMAL = true;
   
    for (int i = 0; i <= 25; i++) {
      safetydelay();
      
    } // loop through 100mS delay, flicking LED for a total of 2.5 seconds to allow motor to operate
    // 8/3/21 - the 2.5 second delay may not be relevant with slow motor operaion####


  }

  if (SWITCHpointsRval < 300) {
    // 8/3/21 - this section operates point motor once blade has been detected one way or the other. Reconsider this. (Linked to mimic display?)
    digitalWrite(pointN, HIGH);
    digitalWrite(pointR, LOW);

    
    Serial1.println("<pointssetreverse>");
    pointsREVERSE = true;
   
    for (int i = 0; i <= 25; i++) {
      safetydelay();
    } // loop through 100mS delay, flicking LED for a total of 2.5 seconds to allow motor to operate


  }

  if (pointsNval < 300) goto ENDFAILLOOP;
  if (pointsRval < 300) goto ENDFAILLOOP;

  goto FAILLOOP;


ENDFAILLOOP:
  if (pointsNval < 300) {
    digitalWrite(pointR, HIGH);
    digitalWrite(pointN, LOW);
    pointsREVERSE = false;
    pointsNORMAL = true;

    Serial1.println("<pointssetnormal>");
    
  }
  if (pointsRval < 300) {
    digitalWrite(pointN, HIGH);
    digitalWrite(pointR, LOW);
    pointsREVERSE = true;
    pointsNORMAL = false;

     Serial1.println("<pointssetreverse>");
   
  }


  POINTSNOTFAILED();

  Serial1.println("<pointsnotfailed>");
  
}


// end of checking for points failure - POINTSnotset()###################################
//#######################################################################


void POINTSFAIL() {

  digitalWrite(SIG2red, LOW);
  digitalWrite(SIG2yel, HIGH);
  digitalWrite(SIG3red, LOW);
  digitalWrite(SIG3yel, HIGH);
  digitalWrite(SIG3grn, HIGH);
  digitalWrite(SIG1red, LOW);
  digitalWrite(SIG1yel, HIGH);
  digitalWrite(SIG1grn, HIGH);
  digitalWrite(SIG1MN, HIGH);
  digitalWrite(SIG1LOCO, HIGH);
  digitalWrite(pointN, HIGH); // as points have failed, turn off both route settings
  digitalWrite(pointR, HIGH); // as points have failed, turn off both route settings

  digitalWrite(blockocc, HIGH);
  digitalWrite(emergSTOP, HIGH);
  digitalWrite(ptsfailed, LOW); // points failure alert
  //  vloop:
  Serial1.println("<pointsfailed7>"); // send to remote

  pointsFAILED = true;
  pointsREVERSE = false;
  pointsNORMAL = false;

  // Serial.println("Points have failed - please check. POINTSFAIL()");
}

void POINTSNOTFAILED() {

  digitalWrite(emergSTOP, HIGH);
  digitalWrite(ptsfailed, HIGH);
  pointsFAILED = false;

  Serial1.println("<pointsnotfailed>");
  // Serial.println("points no longer failed"); //debugging

  // do nothing else

}
// #########################################

// set points to normal, check points blade position then carry on.

void POINTSnormal() {
   ALLRED(); // added 8/3/21
  digitalWrite(pointR, HIGH);
  digitalWrite(pointN, LOW);
  // 13/11/20: insert flashing mimic diagram and 12 second delay here
  // 28/11/20: removed local flashing of mimic as it is connected to the motor and pulsates it. Send command to flash signal box end only.
  for (int i = 0; i <= 30; i++) {
    safetydelay();
    safetydelay();
  //  digitalWrite(pointN, HIGH); // removed 28/11/20
  digitalWrite(emergSTOP, HIGH); // added 28/11/20 to falsh emergstop LED instead.
    Serial1.println("<normaltransiton>");
    safetydelay();
    safetydelay();
   // digitalWrite(pointN, LOW); // removed 28/11/20
   digitalWrite(emergSTOP, LOW); // added 28/11/20
    Serial1.println("<normaltransitoff>");


  } // loop through 100mS delay, flicking mimic LEDs during motor operation for a total of 12 seconds

  // end of modification 13/11/20

  safetydelay();
  Serial1.println("<pointssetnormal>");

  pointsNORMAL = true;
  // operate points, then check for point blade detection. Once detected that they have changed, carry on.
  for (int i = 0; i <= 20; i++) {
    safetydelay();
  } // loop through 100mS delay 15 times, flicking LED for a total of 1.5 seconds to allow motor to operate
  // loop increased to 20 times (2 seconds) 6/12/20, to help with slow motor operaion.

  int pointsdetectN = A2;
  int pointsdetectR = A3;
  pinMode(pointsdetectN, INPUT);
  pinMode(pointsdetectR, INPUT);
  digitalWrite(pointsdetectN, INPUT_PULLUP);  // set pull-up
  digitalWrite(pointsdetectR, INPUT_PULLUP);
  int pointsNval = 1000; // set  input as inactive
  int pointsRval = 1000; // set  input as inactive

  // check if blade has made it across. Loop for a short time period until it has made it.
  // make provision to intervene if point
  // blades don't make it over in reasonable time frame


POINTSN:
  pointsNval = analogRead(pointsdetectN); // read the input status
  pointsRval = analogRead(pointsdetectR); // read the input status

  if (pointsdetectN > 300) {
    POINTSFAIL();
    pointsREVERSE = false;
    pointsNORMAL = false;
  }

  if (pointsdetectN < 300) {
    //   Serial1.println("               Points have been set NORMAL");
    POINTSNOTFAILED();
    //  yloop:
    Serial1.println("<pointsnotfailed>");
    //   receiveACK();
    //   decodeACK();
    //   if(RxACK == false) goto yloop; // loop until ack
    pointsREVERSE = false;
    pointsNORMAL = true;
    for (int i = 0; i <= 10; i++) {
      safetydelay();
    } // loop through 100mS delay 10 times, flicking LED for a total of 1 second to allow motor to operate


  }

// 7/11/21: insert command to send message to signal box that points change is complete. Wait for acknowledgement 
// of the message. Loop around until message is received. Once received, continue.

}



// #########################################

// set points to REVERSE, check points blade position then carry on.
void POINTSreverse() {
  ALLRED(); // added 8/3/21
  digitalWrite(pointR, LOW);
  digitalWrite(pointN, HIGH);

  // 13/11/20: insert flashing mimic diagram and 12 second delay here
 // 28/11/20: removed local flashing of mimic as it is connected to the motor and pulsates it. Send command to flash signal box end only.

  for (int i = 0; i <= 30; i++) {
    safetydelay();
    safetydelay();
  //  digitalWrite(pointR, HIGH); // removed 28/11/20. Added emergency stop lamp to flash at local panel only.
  digitalWrite(emergSTOP, HIGH); // added 28/11/20
    Serial1.println("<reversetransiton>");
    safetydelay();
    safetydelay();
   // digitalWrite(pointR, LOW); // removed 28/11/20
   digitalWrite(emergSTOP, LOW); // added 28/11/20 to flash emergstop LED instead.
    Serial1.println("<reversetransitoff>");


  } // loop through 100mS delay, flicking mimic LEDs during motor operation for a total of 12 seconds

  // end of modification 13/11/20
  safetydelay();
  Serial1.println("<pointssetreverse>");

  pointsREVERSE = true;
  for (int i = 0; i <= 15; i++) {
    safetydelay();
  } // loop through 100mS delay 25 times, flicking LED for a total of 1.5 seconds to allow motor to operate

  int pointsdetectN = A2;
  int pointsdetectR = A3;
  pinMode(pointsdetectN, INPUT);
  pinMode(pointsdetectR, INPUT);
  digitalWrite(pointsdetectN, INPUT_PULLUP);  // set pull-up
  digitalWrite(pointsdetectR, INPUT_PULLUP);
  int pointsNval = 1000; // set  input as inactive
  int pointsRval = 1000; // set  input as inactive
  //pointsNval = analogRead(pointsdetectN); // check points blades
  //pointsRval = analogRead(pointsdetectR);

  // check if blade has made it across. Loop for a short time period until it has made it.
  // make provision to intervene if point
  // blades don't make it over in reasonable time frame

  

POINTSR:
  pointsNval = analogRead(pointsdetectN); // read the input status
  pointsRval = analogRead(pointsdetectR); // read the input status

  if (pointsdetectR > 300) {
    POINTSFAIL();
    pointsREVERSE = false;
    pointsNORMAL = false;
  }

  if (pointsdetectR < 300) {
    //  Serial.println("               Points have been set REVERSE");
    POINTSNOTFAILED();
    //  aaloop:
    Serial1.println("<pointsnotfailed1>");
    //  receiveACK();
    //  decodeACK();
    //   if(RxACK == false) goto aaloop; // loop until ack
    pointsREVERSE = true;
    pointsNORMAL = false;
    for (int i = 0; i <= 10; i++) {
      safetydelay();
    } // loop through 100mS delay 10 times, flicking LED for a total of 1 second to allow motor to operate

  }


// 7/11/21: insert command to send message to signal box that points change is complete. Wait for acknowledgement 
// of the message. Loop around until message is received. Once received, continue.

}
//############################################
//
//  ###  #####  ###       ##### #   # ####
// #       #   #   #        #   ##  # #   #
//  ###    #   #            #   # # # #   #
//     #   #   # ###        #   #  ## #   #
//  ###  #####  ####      ##### #   # ####
//
//############################################


void clockwiseclear() {
  digitalWrite(SIG2red, LOW);
  digitalWrite(SIG2yel, HIGH); // loco departure signal

  digitalWrite(SIG3red, LOW);
  digitalWrite(SIG3yel, HIGH);
  digitalWrite(SIG3grn, HIGH); // main line anticlockwise signal

  digitalWrite(SIG1red, HIGH);
  digitalWrite(SIG1yel, HIGH);
  digitalWrite(SIG1grn, LOW);  // main line clockwise signal
  digitalWrite(SIG1MN, LOW);
  digitalWrite(SIG1LOCO, HIGH);

  Serial1.println("<clockwiseclear1>"); // send message to remote

}

//#########################

void sigboxclockwiseclear() {
  digitalWrite(SIG2red, HIGH);
  digitalWrite(SIG2yel, LOW); // loco departure signal

  digitalWrite(SIG3red, HIGH);
  digitalWrite(SIG3yel, LOW);
  digitalWrite(SIG3grn, LOW); // main line anticlockwise signal

  digitalWrite(SIG1red, LOW);
  digitalWrite(SIG1yel, LOW);
  digitalWrite(SIG1grn, HIGH);  // main line clockwise signal
  digitalWrite(SIG1MN, HIGH);
  digitalWrite(SIG1LOCO, LOW);




}
//#########################
//#########################

void clockwisecaution() {
  digitalWrite(SIG2red, LOW);
  digitalWrite(SIG2yel, HIGH);

  digitalWrite(SIG3red, LOW);
  digitalWrite(SIG3yel, HIGH);
  digitalWrite(SIG3grn, HIGH);

  digitalWrite(SIG1red, HIGH);
  digitalWrite(SIG1yel, LOW);
  digitalWrite(SIG1grn, HIGH);
  digitalWrite(SIG1MN, LOW);
  digitalWrite(SIG1LOCO, HIGH);


  Serial1.println("<clockwisecaution1>"); // send message to remote

}

//###########################
void sigboxclockwisecaution() {

  digitalWrite(SIG2red, HIGH);
  digitalWrite(SIG2yel, LOW);

  digitalWrite(SIG3red, HIGH);
  digitalWrite(SIG3yel, LOW);
  digitalWrite(SIG3grn, LOW);

  digitalWrite(SIG1red, LOW);
  digitalWrite(SIG1yel, HIGH);
  digitalWrite(SIG1grn, LOW);
  digitalWrite(SIG1MN, HIGH);
  digitalWrite(SIG1LOCO, LOW);


}
//#########################

void clockwiseloco() {
  digitalWrite(SIG2red, LOW);
  digitalWrite(SIG2yel, HIGH);

  digitalWrite(SIG3red, LOW);
  digitalWrite(SIG3yel, HIGH);
  digitalWrite(SIG3grn, HIGH);

  digitalWrite(SIG1red, HIGH);
  digitalWrite(SIG1yel, LOW);
  digitalWrite(SIG1grn, HIGH);
  digitalWrite(SIG1MN, HIGH);
  digitalWrite(SIG1LOCO, LOW);

  Serial1.println("<clockwiseloco1>"); // send message to remote

}

//#########################

void sigboxclockwiseloco() {
  digitalWrite(SIG2red, HIGH);
  digitalWrite(SIG2yel, LOW);

  digitalWrite(SIG3red, HIGH);
  digitalWrite(SIG3yel, LOW);
  digitalWrite(SIG3grn, LOW);

  digitalWrite(SIG1red, LOW);
  digitalWrite(SIG1yel, HIGH);
  digitalWrite(SIG1grn, LOW);
  digitalWrite(SIG1MN, LOW);
  digitalWrite(SIG1LOCO, HIGH);


}
//#########################

void locodepart() {
  digitalWrite(SIG2red, HIGH);
  digitalWrite(SIG2yel, LOW);

  digitalWrite(SIG3red, LOW);
  digitalWrite(SIG3yel, HIGH);
  digitalWrite(SIG3grn, HIGH);

  digitalWrite(SIG1red, LOW);
  digitalWrite(SIG1yel, HIGH);
  digitalWrite(SIG1grn, HIGH);
  digitalWrite(SIG1MN, HIGH);
  digitalWrite(SIG1LOCO, HIGH);

  Serial1.println("<locodepart>"); // send message to remote

}

//#########################

void sigboxlocodepart() {
  digitalWrite(SIG2red, LOW);
  digitalWrite(SIG2yel, HIGH);

  digitalWrite(SIG3red, HIGH);
  digitalWrite(SIG3yel, LOW);
  digitalWrite(SIG3grn, LOW);

  digitalWrite(SIG1red, HIGH);
  digitalWrite(SIG1yel, LOW);
  digitalWrite(SIG1grn, LOW);
  digitalWrite(SIG1MN, LOW);
  digitalWrite(SIG1LOCO, LOW);


}
//#########################

void anticlockwiseclear() {
  digitalWrite(SIG2red, LOW);
  digitalWrite(SIG2yel, HIGH);

  digitalWrite(SIG3red, HIGH);
  digitalWrite(SIG3yel, HIGH);
  digitalWrite(SIG3grn, LOW);

  digitalWrite(SIG1red, LOW);
  digitalWrite(SIG1yel, HIGH);
  digitalWrite(SIG1grn, HIGH);
  digitalWrite(SIG1MN, HIGH);
  digitalWrite(SIG1LOCO, HIGH);

  Serial1.println("<anticlockwiseclear2>"); // send message to remote

}
//#########################

void sigboxanticlockwiseclear() {
  digitalWrite(SIG2red, HIGH);
  digitalWrite(SIG2yel, LOW);

  digitalWrite(SIG3red, LOW);
  digitalWrite(SIG3yel, LOW);
  digitalWrite(SIG3grn, HIGH);

  digitalWrite(SIG1red, HIGH);
  digitalWrite(SIG1yel, LOW);
  digitalWrite(SIG1grn, LOW);
  digitalWrite(SIG1MN, LOW);
  digitalWrite(SIG1LOCO, LOW);

}
//#########################

void anticlockwisecaution() {
  digitalWrite(SIG2red, LOW);
  digitalWrite(SIG2yel, HIGH);

  digitalWrite(SIG3red, HIGH);
  digitalWrite(SIG3yel, LOW);
  digitalWrite(SIG3grn, HIGH);

  digitalWrite(SIG1red, LOW);
  digitalWrite(SIG1yel, HIGH);
  digitalWrite(SIG1grn, HIGH);
  digitalWrite(SIG1MN, HIGH);
  digitalWrite(SIG1LOCO, HIGH);

  Serial1.println("<anticlockwisecaution2>"); // send message to remote


}

//#########################

void sigboxanticlockwisecaution() {
  digitalWrite(SIG2red, HIGH);
  digitalWrite(SIG2yel, LOW);

  digitalWrite(SIG3red, LOW);
  digitalWrite(SIG3yel, HIGH);
  digitalWrite(SIG3grn, LOW);

  digitalWrite(SIG1red, HIGH);
  digitalWrite(SIG1yel, LOW);
  digitalWrite(SIG1grn, LOW);
  digitalWrite(SIG1MN, LOW);
  digitalWrite(SIG1LOCO, LOW);


}
//@@@@@@@@@@@@@@@@@@@ LOCAL unit - receive data from other end


//@@@@@@@@@@@@@@@@@@@@ check switch settings

void checkswitches() {   // check physical switch inputs at local end only and act accordingly

  // this routine only happens if data has been lost.
  // to get out of this routine, switch for STOP must be held in this position for 5 seconds

  int SWstopval = 1000; // set switch value to high
  int CWcautionval = 1000;
  int CWclearval = 1000;
  int ACWcautionval = 1000;
  int ACWclearval = 1000;

  int SWpointsNval = 1000; // "normal" button
  int SWpointsRval = 1000; // "reverse" button

  digitalWrite(SWITCHpointsN, INPUT_PULLUP);
  digitalWrite(SWITCHpointsR, INPUT_PULLUP);
  digitalWrite(SWTICHanticaution, INPUT_PULLUP);
  digitalWrite(SWITCHanticlear, INPUT_PULLUP);
  digitalWrite(SWITCHstop, INPUT_PULLUP);
  digitalWrite(SWITCHcwcaution, INPUT_PULLUP);
  digitalWrite(SWITCHclear, INPUT_PULLUP);

SWITCHSTOP:
  int switchisatstop = false;
  SWstopval = analogRead(SWITCHstop); // read the input status
  delay (5);
  if (SWstopval < 300) {
    ALLSTOP(); // if active, display indication
    zzstop = zzstop + 1; // increment counter for switch being at stop for time period
    // if any other button or switch is selected, counter resets
    switchisatstop = true;
    
Onlyonebutton:
    SWpointsNval = analogRead(SWITCHpointsN);
    SWpointsRval = analogRead(SWITCHpointsR);
    if (SWpointsNval < 300 && SWpointsRval < 300) goto Onlyonebutton; // if both points buttons are active, then ignore them until only one is active

    if (SWpointsNval < 300) {
      //  Serial.println("Points NORMAL button has been pressed"); //debugging
      POINTSnormal(); // points N switch is active, go and set them to Normal
      stoptime = 0;
      zzstop = 0;
    }
    if (SWpointsRval < 300) {
      //  Serial.println("Points REVERSE button has been pressed"); //debugging
      POINTSreverse(); // points R switch is active, go and set them to Reverse
      stoptime = 0;
      zzstop = 0;
    }
  }

  // if switch is at stop, goto end

  if (SWstopval <= 300) goto ENDSWITCHCHECK;

  if (pointsREVERSE == true) tofromloco();  // act on signal setting switches
  if (pointsNORMAL == true) mainlinesignals(); // act on signal setting switches

ENDSWITCHCHECK:

  delay (1);  // effectively do nothing

}

void tofromloco() {

  // Serial.println("  Checking switches for signals to/from loco");

  int SWITCHanticlear = A6; // switch inputs for signal indications clockwise and anticlockwise
  int SWTICHanticaution = A7;
  int SWITCHcwcaution = A9;
  int SWITCHclear = A10;

  int CWcautionval = 1000;
  int CWclearval = 1000;
  int ACWcautionval = 1000;
  int ACWclearval = 1000;

  digitalWrite(SWITCHcwcaution, INPUT_PULLUP);
  digitalWrite(SWITCHclear, INPUT_PULLUP);
  digitalWrite(SWTICHanticaution, INPUT_PULLUP);
  digitalWrite(SWITCHanticlear, INPUT_PULLUP);

  CWcautionval = analogRead(SWITCHcwcaution); // read input
  CWclearval = analogRead(SWITCHclear);
  ACWcautionval = analogRead(SWTICHanticaution);
  ACWclearval = analogRead(SWITCHanticlear);

  if (CWcautionval < 300) {
    clockwiseloco();
    stoptime = 0;
    zzstop = 0;
    //  Serial1.println("<clockwiseloco>"); // send data to other end
  }
  if (CWclearval < 300) {
    clockwiseloco();
    stoptime = 0;
    zzstop = 0;
  }
  // if (CWclearval < 300) Serial1.println("<clockwiseloco>"); // send data to other end

  if (ACWcautionval < 300) {
    locodepart();
    stoptime = 0;
    zzstop = 0;
  }

  // if (ACWcautionval < 300) Serial1.println("<locodepart>"); // send data to other end

  if (ACWclearval < 300) {
    locodepart();
    stoptime = 0;
    zzstop = 0;
  }
  // if (ACWclearval < 300) Serial1.println("<locodepart>"); // send data to other end

  // Serial1.println("I have checked to/from loco signal");
  // delay (2000); // for debugging

}

void mainlinesignals() {

// this is where the local panel sets the signal indicatios
// bug 25/3/22 - not going back to stop when switch is selected. Needs block occupancy to work. [same for "tofromloco"]
// If a signal is set to clear, goes back to caution after a train passes, then clears a few seconds later - is working 25/3/22.

  Serial.println("checking other signal switches"); // 25/3/22 debugging
  
  digitalWrite(SWITCHstop, INPUT_PULLUP);
  
  SWstopval = 1000;
  int CWcautionval = 1000;
  int CWclearval = 1000;
  int ACWcautionval = 1000;
  int ACWclearval = 1000;

  int SWITCHanticlear = A6; // switch inputs for signal indications clockwise and anticlockwise
  int SWTICHanticaution = A7;
  int SWITCHcwcaution = A9;
  int SWITCHclear = A10;

  digitalWrite(SWITCHcwcaution, INPUT_PULLUP);
  digitalWrite(SWITCHclear, INPUT_PULLUP);
  digitalWrite(SWTICHanticaution, INPUT_PULLUP);
  digitalWrite(SWITCHanticlear, INPUT_PULLUP);

  SWstopval = analogRead(SWITCHstop); // read the input status
  CWcautionval = analogRead(SWITCHcwcaution); // read input
  CWclearval = analogRead(SWITCHclear);
  ACWcautionval = analogRead(SWTICHanticaution);
  ACWclearval = analogRead(SWITCHanticlear);
  
   currentMillis = millis(); // added 25/3/22
      if (currentMillis - startMillis >= cautiontimer){
        blockwasoccupied = false; // since the time has elapsed, the block was not recently occupied
      }

  if (CWcautionval < 300) {
    clockwisecaution();
    stoptime = 0;
    zzstop = 0;
      }
  if (CWclearval < 300) {
    if (blockwasoccupied == true)clockwisecaution(); // 25/3/22. Code to set to caution if block has just been occupied
    else {clockwiseclear();}
    stoptime = 0;
    zzstop = 0;
      }
  if (ACWcautionval < 300) {
    anticlockwisecaution();
    stoptime = 0;
    zzstop = 0;
      }

  if (ACWclearval < 300) {
    if (blockwasoccupied == true)anticlockwisecaution(); // 25/3/22. Code to set to caution if block has just been occupied
    else {anticlockwiseclear();}
    stoptime = 0;
    zzstop = 0;
      }

  if (SWstopval <= 300) { // added 25/3/22
    ALLSTOP();
    delay (100);
      }
     
}

//#########################

//@@@@@@@@@@@@@@@@@@@@ check switch settings

void checkremoteswitches() {// check physical switch inputs in signal box and act accordingly

delay (20); // added 6/12/20. Could be causing issues, especially when changing points at other end.

  // only inputs to check are physical switches and emergency stop input,
  // 8 all up
  //  Serial1.println("I am checking signal box switches routine");
  int SWstopval = 1000; // set switch value to high
  int CWcautionval = 1000;
  int CWclearval = 1000;
  int ACWcautionval = 1000;
  int ACWclearval = 1000;
  int sigboxemergstop = 1000;
  int pointsnormal = 1000;
  int pointsreverse = 1000;

  int SWTICHanticaution = A7;
  int SWITCHanticlear = A6;
  int SWITCHstop = A8;
  int SWITCHcwcaution = A9;
  int SWITCHclear = A10;
  int SWITCHsigboxemerg = A1;
  int SWITCHsigboxnormal = A4;
  int SWITCHsigboxreverse = A5;

  digitalWrite(SWTICHanticaution, INPUT_PULLUP);
  digitalWrite(SWITCHanticlear, INPUT_PULLUP);
  digitalWrite(SWITCHstop, INPUT_PULLUP);
  digitalWrite(SWITCHcwcaution, INPUT_PULLUP);
  digitalWrite(SWITCHclear, INPUT_PULLUP);
  digitalWrite(SWITCHsigboxemerg, INPUT_PULLUP);
  digitalWrite(SWITCHsigboxnormal, INPUT_PULLUP);
  digitalWrite(SWITCHsigboxreverse, INPUT_PULLUP);

  CWcautionval = analogRead(SWITCHcwcaution); // read input
  CWclearval = analogRead(SWITCHclear);
  ACWcautionval = analogRead(SWTICHanticaution);
  ACWclearval = analogRead(SWITCHanticlear);
  SWstopval = analogRead(SWITCHstop);
  sigboxemergstop = analogRead(SWITCHsigboxemerg);
  pointsnormal = analogRead(SWITCHsigboxnormal);
  pointsreverse  = analogRead(SWITCHsigboxreverse);

  if (CWcautionval < 300) {
    Serial1.println("<setcaution1>"); // send data to other end

  }
  if (CWclearval < 300) {
    Serial1.println("<setclear1>"); // send data to other end
  }
  if (ACWcautionval < 300) {
    Serial1.println("<setACWcaution2>"); // send data to other end
  }
  if (ACWclearval < 300) {
    Serial1.println("<setACWclear2>"); // send data to other end
  }
  if (SWstopval < 300) {
    Serial1.println("<setstop>"); // send data to other end
  }
  if (sigboxemergstop < 300) {
    Serial1.println("<setsigboxemerg>"); // send data to other end
    SigBoxEmerg(); // goes to this routine until emerg input inactive
  }
  if (pointsnormal < 300) {
normalloop:
    Serial1.println("<setnormal>"); // send data to other end
    pointsnormal = analogRead(SWITCHsigboxnormal);
    if (pointsnormal < 300) goto normalloop;
  }
  if (pointsreverse  < 300) {
reverseloop:
    Serial1.println("<setreverse>"); // send data to other end
    pointsreverse  = analogRead(SWITCHsigboxreverse);
    if (pointsreverse < 300) goto reverseloop;

  }


}

// @@@@@@
void SigBoxEmerg() {

  // signal box emergency input has been activated. Loop through until inactive

  int sigboxemergstop = 1000;
  int SWITCHsigboxemerg = A1;
  sigboxALLRED();
  // insert line to turn emergency LED on remote panel, then off at end of emerg
  digitalWrite(emergSTOP, HIGH);
  delay (2);
SigBoxEmergLoop:
  Serial1.println("<setsigboxemerg>"); // send data to other end
  sigboxemergstop = analogRead(SWITCHsigboxemerg);
  if (sigboxemergstop < 300) goto SigBoxEmergLoop; // send data to other end

  // now that emergency input is inactive, tell other end
  // EndSBemerg:
  digitalWrite(emergSTOP, LOW); // turn off sigbox emergency LED now issue has finished.

  Serial1.println("<setsigboxemerg>"); // send data to other end
  delay (1000); // wait 5 seconds after emergency is over
  sigboxemergstop = analogRead(SWITCHsigboxemerg);
  if (sigboxemergstop < 300) goto SigBoxEmergLoop; // send data to other end
  Serial1.println("<setsigboxemerg>"); // send data to other end
  delay (1000); // wait 5 seconds after emergency is over
  sigboxemergstop = analogRead(SWITCHsigboxemerg);
  if (sigboxemergstop < 300) goto SigBoxEmergLoop; // send data to other end
  Serial1.println("<setsigboxemerg>"); // send data to other end
  delay (1000); // wait 5 seconds after emergency is over
  sigboxemergstop = analogRead(SWITCHsigboxemerg);
  if (sigboxemergstop < 300) goto SigBoxEmergLoop; // send data to other end
  Serial1.println("<setsigboxemerg>"); // send data to other end
  delay (1000); // wait 5 seconds after emergency is over
  sigboxemergstop = analogRead(SWITCHsigboxemerg);
  if (sigboxemergstop < 300) goto SigBoxEmergLoop; // send data to other end
  Serial1.println("<setsigboxemerg>"); // send data to other end
  delay (1000); // wait 5 seconds after emergency is over
  sigboxemergstop = analogRead(SWITCHsigboxemerg);
  if (sigboxemergstop < 300) goto SigBoxEmergLoop; // send data to other end
  Serial1.println("<endsigboxemerg>"); // send data to other end
  delay (20);
  Serial1.println("<endsigboxemerg>"); // send data to other end
  delay (20);
  Serial1.println("<endsigboxemerg>"); // send data to other end
  delay (20);
  Serial1.println("<endsigboxemerg>"); // send data to other end


}
//#########################
void undetermined() { // flash local/remote LEDs if both inputs are invalid. Unit can either be LOCAL or REMOTE, not both or neither.

  digitalWrite(LOCAL, LOW);
  digitalWrite(REMOTE, LOW);

  delay (600);

  digitalWrite(LOCAL, HIGH);
  digitalWrite(REMOTE, HIGH);

  delay (600);

  Serial1.println("northing will be happening until local or remote is set");
}

//#######################

void Testlamps() {

  // run through test of each output
  // runs once, at power up/initialisation
  digitalWrite(SIG2red, LOW);
  digitalWrite(LOCAL, LOW);
  delay (dt);

  digitalWrite(SIG2red, HIGH);
  digitalWrite(SIG2yel, LOW);
  digitalWrite(LOCAL, HIGH);
  delay (dt);
  digitalWrite(SIG2yel, HIGH);
  digitalWrite(LOCAL, LOW);


  // xxxxxxxxxxxxxxxxxxxxx

  digitalWrite(SIG3red, LOW);
  delay (dt);
  digitalWrite(LOCAL, HIGH);
  digitalWrite(SIG3red, HIGH);

  digitalWrite(SIG3yel, LOW);
  delay (dt);
  digitalWrite(LOCAL, LOW);
  digitalWrite(SIG3yel, HIGH);

  digitalWrite(SIG3grn, LOW);
  delay (dt);
  digitalWrite(LOCAL, HIGH);
  digitalWrite(SIG3grn, HIGH);

  // xxxxxxxxxxxxxxxxxxxxx

  digitalWrite(SIG1red, LOW);
  delay (dt);
  digitalWrite(LOCAL, LOW);
  digitalWrite(SIG1red, HIGH);

  digitalWrite(SIG1yel, LOW);
  delay (dt);
  digitalWrite(LOCAL, HIGH);
  digitalWrite(SIG1yel, HIGH);

  digitalWrite(SIG1grn, LOW);
  delay (dt);
  digitalWrite(LOCAL, LOW);
  digitalWrite(SIG1grn, HIGH);

  digitalWrite(SIG1MN, LOW);
  delay (dt);
  digitalWrite(LOCAL, HIGH);
  digitalWrite(SIG1MN, HIGH);

  digitalWrite(SIG1LOCO, LOW);
  delay (dt);
  digitalWrite(LOCAL, LOW);
  digitalWrite(SIG1LOCO, HIGH);

  // xxxxxxxxxxxxxxxxxxxxx



  digitalWrite(blockocc, LOW);
  delay (dt);
  digitalWrite(LOCAL, HIGH);
  digitalWrite(blockocc, HIGH);

  digitalWrite(emergSTOP, LOW);
  delay (dt);
  digitalWrite(LOCAL, LOW);
  digitalWrite(emergSTOP, HIGH);

  digitalWrite(locotrack, LOW); // loco track circuit
  delay (dt);
  digitalWrite(LOCAL, HIGH);
  digitalWrite(locotrack, HIGH);

  digitalWrite(ptsfailed, LOW); // points failure
  delay (dt);
  digitalWrite(LOCAL, LOW);
  digitalWrite(ptsfailed, HIGH);

  // Serial.println("lamp test finished");

  //end of test of all lamps
  //now, set all signals to stop, turn everything else off

  digitalWrite(pointN, HIGH);
  digitalWrite(pointR, HIGH);


  digitalWrite(REMOTE, HIGH);

  digitalWrite(blockocc, HIGH);
  digitalWrite(emergSTOP, HIGH);
  digitalWrite(ptsfailed, HIGH);
  digitalWrite(locotrack, HIGH);

  ALLRED(); // set all signals to stop

}

//#######################

void Testremotelamps() {

  dt = 700; // set sigbox test lamp time to .7 second


  // run through test of each output
  // runs once, at power up/initialisation
  digitalWrite(SIG2red, HIGH);
  delay (dt);
  digitalWrite(SIG2red, LOW);

  digitalWrite(SIG2yel, HIGH);
  delay (dt);
  digitalWrite(SIG2yel, LOW);

  // xxxxxxxxxxxxxxxxxxxxx

  digitalWrite(SIG3red, HIGH);
  delay (dt);
  digitalWrite(SIG3red, LOW);

  digitalWrite(SIG3yel, HIGH);
  delay (dt);
  digitalWrite(SIG3yel, LOW);

  digitalWrite(SIG3grn, HIGH);
  delay (dt);
  digitalWrite(SIG3grn, LOW);

  // xxxxxxxxxxxxxxxxxxxxx

  digitalWrite(SIG1red, HIGH);
  delay (dt);
  digitalWrite(SIG1red, LOW);

  digitalWrite(SIG1yel, HIGH);
  delay (dt);
  digitalWrite(SIG1yel, LOW);

  digitalWrite(SIG1grn, HIGH);
  delay (dt);
  digitalWrite(SIG1grn, LOW);

  digitalWrite(SIG1MN, HIGH);
  delay (dt);
  digitalWrite(SIG1MN, LOW);

  digitalWrite(SIG1LOCO, HIGH);
  delay (dt);
  digitalWrite(SIG1LOCO, LOW);

  // xxxxxxxxxxxxxxxxxxxxx

  digitalWrite(LOCAL, HIGH);
  delay (dt);
  digitalWrite(LOCAL, LOW);

  digitalWrite(REMOTE, HIGH);
  delay (dt);
  digitalWrite(REMOTE, LOW);

  digitalWrite(blockocc, HIGH);
  delay (dt);
  digitalWrite(blockocc, LOW);

  digitalWrite(emergSTOP, HIGH);
  delay (dt);
  digitalWrite(emergSTOP, LOW);

  digitalWrite(ptsfailed, HIGH); // loco track circuit
  delay (dt);
  digitalWrite(ptsfailed, LOW);

  digitalWrite(locotrack, HIGH); // points failure
  delay (dt);
  digitalWrite(locotrack, LOW);

  // Serial.println("signal box panel lamp test finished");

  //end of test of all lamps
  //now, set all signals to stop, turn everything else off

  digitalWrite(pointN, LOW);
  digitalWrite(pointR, LOW);

  digitalWrite(LOCAL, LOW);
  digitalWrite(REMOTE, LOW);

  digitalWrite(blockocc, LOW);
  digitalWrite(emergSTOP, LOW);
  digitalWrite(ptsfailed, LOW);
  digitalWrite(locotrack, LOW);

  sigboxALLRED(); // set all signals to stop

}



void receiveremotedata() {

  // this is the local end receiving data from the signal box (remote) end
  delay (80); // give time for other end to send data. If no data coming in within this time, then
// 6/12/20 - delay reduced from 180ms to 80ms
  //digitalWrite(LOCAL, HIGH);
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  // if (Serial1.available() > 0) {
  while (Serial1.available() > 0 && newData == false) {
    rc = Serial1.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}


// ####################################
//
// ####  #   #   ####    #   #####   #
// #   #  # #    #   #  # #    #    # #
// ####    #     #   # #####   #   #####
// #  #   # #    #   # #   #   #   #   #
// #   # #   #   ####  #   #   #   #   #
//
// ####################################

void decodeREMOTEdata() {

  // what is being received at local end from signal box
  // likely an issue or turned off.
  // without above delay, local unit is too quick to decode any data 16/10/19

  // Rxdataloop:
  //Serial1.println("Start of Rx data loop"); // for debugging
  Rxdata = false;
 
  digitalWrite(REMOTE, HIGH); // flicker "remote" LED when data coming in
  delay (5);
  if (newData == true) {
    Serial.print("This just in from the signalbox ... ");
    Serial.println(receivedChars);
    newData = false;

    if (strcmp(receivedChars, "setsigboxemerg")  == 0) {
      digitalWrite(REMOTE, LOW);
      digitalWrite(emergSTOP, LOW);
      ALLSTOP();
      Rxdata = true;
      datacount = 0;
      zdatacount = 0;
      delay (50);
      // set signal box LEDs to stop and show emergstop LEd.
    }
    if (strcmp(receivedChars, "endsigboxemerg")  == 0) {
      digitalWrite(REMOTE, LOW);
      digitalWrite(emergSTOP, HIGH);
      Rxdata = true;
      datacount = 0;
      zdatacount = 0;
      // turn off emerg LED on panel,
      delay (50);
    }

    if (strcmp(receivedChars, "setcaution1")  == 0) {
      
      digitalWrite(REMOTE, LOW);
      if (pointsREVERSE == true) {
        clockwiseloco();
      }
      if (pointsNORMAL == true) {
        clockwisecaution();
      }
      Rxdata = true;
      datacount = 0;
      zdatacount = 0;
      delay (50);
    }

    if (strcmp(receivedChars, "setstop")  == 0) {
      
      digitalWrite(REMOTE, LOW);
      ALLRED();
      Rxdata = true;
      datacount = 0;
      zdatacount = 0;
      delay (50);
    }
    currentMillis = millis();
      if (currentMillis - startMillis >= cautiontimer){
        blockwasoccupied = false; // since the time has elapsed, the block was not recently occupied
      }
    if (strcmp(receivedChars, "setclear1")  == 0) {
      digitalWrite(REMOTE, LOW);
      
      if (pointsREVERSE == true) {
        clockwiseloco();
      }
      if (pointsNORMAL == true) {
         // 30/7/21: set to caution if block has just become unoccupied
         //block has just become unoccupied. Check that delay has elapsed. If not, display caution until it has elapsed
    
    currentMillis = millis();
       if (currentMillis - startMillis <= cautiontimer) { //modified 25/3/22
       if (blockwasoccupied == true) clockwisecaution(); //test whether the period has elapsed
    // if block just occupied and time not elapsed, show caution, otherwise show clear
    
   }
      else{
           clockwiseclear();
      }
      
      
      }
      // "caution delay" above added 30/7/21
      Rxdata = true;
      datacount = 0;
      zdatacount = 0;
      delay (50);
    }

    if (strcmp(receivedChars, "setACWclear2")  == 0) {
       // 30/7/21: insert logic to display "caution" instead of clear, if block has just become unoccupied
   
      
      digitalWrite(REMOTE, LOW);
      
      if (pointsREVERSE == true) {
        locodepart();
          }
          
      if (pointsNORMAL == true) {
        currentMillis = millis();
        if (currentMillis - startMillis <= cautiontimer){
          if(blockwasoccupied == true) anticlockwisecaution();   //test whether the period has elapsed
            
         else{
            anticlockwiseclear();
        }
      }
       if (currentMillis - startMillis >= cautiontimer){
        blockwasoccupied = false; // since the time has elapsed, the block was not recently occupied
      }
      // "caution delay" above added 30/7/21
      Rxdata = true;
      datacount = 0;
      zdatacount = 0;
      delay (50);
    }

    if (strcmp(receivedChars, "setnormal")  == 0) {
      
      digitalWrite(REMOTE, LOW);
      POINTSnormal();
      Rxdata = true;
      datacount = 0;
      zdatacount = 0;
      delay (50);
    }
    if (strcmp(receivedChars, "setreverse")  == 0) {
      
      digitalWrite(REMOTE, LOW);
      POINTSreverse();
      Rxdata = true;
      datacount = 0;
      zdatacount = 0;
      delay (50);
    }

    if (strcmp(receivedChars, "setACWcaution2")  == 0) {
      
      digitalWrite(REMOTE, LOW);
      if (pointsREVERSE == true) {
        locodepart();
      }
      if (pointsNORMAL == true) {
        anticlockwisecaution();
      }

      Rxdata = true;
      datacount = 0;
      zdatacount = 0;
      // turn loco occupied LED off
      delay (50);
    }

  }


}
}



void determinelocalremote() {

  // happens once, just after power-up
  pinMode(setlocal, INPUT);
  pinMode(setremote, INPUT);
  digitalWrite(setlocal, INPUT_PULLUP);  // set pull-up on analog pin
  digitalWrite(setremote, INPUT_PULLUP);
  //Serial.println("detect local or remote");
  delay (10);

LOCALREMOTE: // check what setting this device is configured to be
  digitalWrite(LOCAL, HIGH); // active low on local end - turn off
  digitalWrite(REMOTE, LOW); // active high on remote end - turn off


  setlocalval = analogRead(setlocal); // read the input status
  setremoteval = analogRead(setremote); // read the input status

  if (setlocalval < 300 && setremoteval < 300) undetermined(); // flash local/remote until sorted out
  if (setlocalval > 300 && setremoteval > 300) undetermined(); // flash local/remote until sorted out

  if (setlocalval < 300 && setremoteval < 300) goto LOCALREMOTE; // go back to LOCALREMOTE if both inputs invalid
  if (setlocalval > 300 && setremoteval > 300) goto LOCALREMOTE;

  if (setlocalval < 300 ) {
    digitalWrite(LOCAL, LOW); // active low on local end
    digitalWrite(REMOTE, HIGH);

    //  Serial1.print("I have set local value to be true"); // debugging
    //  setaslocal = true;
    //  setasremote = false;
  }

  if (setremoteval < 300) {
    digitalWrite(LOCAL, LOW); // active high on local end
    digitalWrite(REMOTE, HIGH);
    //   setasremote = true;
    //  setaslocal = false;

  }

  //if (setlocalval < 300) Serial1.println(" debugging: I am set as local as defined by low input ");

  //if (setremoteval < 300) Serial1.println(" debugging: I am set as remote (signal box) as defined by low input ");

}


//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@


void receiveLOCALdata() {
  //receiving data in signal box from other end
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;
  // if (Serial1.available() > 0) {
  while (Serial1.available() > 0 && newData == false) {
    rc = Serial1.read();
    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }
    else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}

//#########################
void safetydelay() {
  Serial1.println("<safetydelay>");
  delay (100);
}
//########################
void decodeLOCALdata() {
  // decode data in signal box from other end
  Rxdata = false;
  digitalWrite(LOCAL, LOW); // flicker Local LED when data coming in
  delay (15);
  if (newData == true) {
    newData = false;
    if (strcmp(receivedChars, "emergstop1")  == 0) { //strcmp means "String Compare". Compares "receivedChars" to the word next to it
      digitalWrite(LOCAL, HIGH);
      digitalWrite(emergSTOP, HIGH);
      sigboxALLRED();
      Rxdata = true;
      // set signal box LEDs to stop and show emergstop LED.
    }
    if (strcmp(receivedChars, "allstop1")  == 0) {
      digitalWrite(LOCAL, HIGH);
      sigboxALLRED();
      Rxdata = true;
      // set signal box LEDs to stop and show emergstop LED.
    }
    if (strcmp(receivedChars, "emergstop0")  == 0) {
      digitalWrite(LOCAL, HIGH);
      digitalWrite(emergSTOP, LOW);
      Rxdata = true;
      // turn off emerg LED on panel.
    }
    if (strcmp(receivedChars, "blockocc1")  == 0) {
      digitalWrite(LOCAL, HIGH);
      digitalWrite(blockocc, HIGH);
      sigboxALLRED();
      Rxdata = true;
        // turn on block occupied and all red LEDs, don't send data
    }
    if (strcmp(receivedChars, "blockocc0")  == 0) {
      digitalWrite(LOCAL, HIGH);
      digitalWrite(blockocc, LOW);
      Rxdata = true;
      // turn off block occupied LED
    }
    if (strcmp(receivedChars, "locoocc1")  == 0) {
      digitalWrite(LOCAL, HIGH);
      digitalWrite(locotrack, HIGH);
      Rxdata = true;
      // loco occupied LED
    }
    if (strcmp(receivedChars, "locooccupied0")  == 0) {
      digitalWrite(LOCAL, HIGH);
      digitalWrite(locotrack, LOW);
      Rxdata = true;
      // turn loco occupied LED off
    }
    if (strcmp(receivedChars, "clockwiseclear1")  == 0) {
      digitalWrite(LOCAL, HIGH);
        sigboxclockwiseclear();
      Rxdata = true;
    }
    if (strcmp(receivedChars, "clockwisecaution1")  == 0) {
      digitalWrite(LOCAL, HIGH);
      sigboxclockwisecaution();
      Rxdata = true;
    }
    if (strcmp(receivedChars, "clockwiseloco1")  == 0) {
      digitalWrite(LOCAL, HIGH);
      sigboxclockwiseloco();
      Rxdata = true;
    }
    if (strcmp(receivedChars, "locodepart")  == 0) {
      digitalWrite(LOCAL, HIGH);
      sigboxlocodepart();
      Rxdata = true;
    }
    if (strcmp(receivedChars, "anticlockwiseclear2")  == 0) {
        digitalWrite(LOCAL, HIGH);
      sigboxanticlockwiseclear();
      Rxdata = true;
    }
    if (strcmp(receivedChars, "anticlockwisecaution2")  == 0) {
      digitalWrite(LOCAL, HIGH);
      sigboxanticlockwisecaution();
      Rxdata = true;
    }
    if (strcmp(receivedChars, "pointssetnormal")  == 0) {
      digitalWrite(LOCAL, HIGH);
      digitalWrite(pointN, HIGH);
      digitalWrite(pointR, LOW);
      digitalWrite(ptsfailed, LOW);
      Rxdata = true;
    }
    // added normaltransiton, normaltransitoff, reversetransiton, reversetransitoff to allow flashing when points in transit
    // to display in signal box ONLY. 28/11/20.

    if (strcmp(receivedChars, "normaltransiton")  == 0) {
      digitalWrite(LOCAL, HIGH);
      digitalWrite(pointN, HIGH);
      digitalWrite(pointR, LOW);
      digitalWrite(ptsfailed, LOW);
      Rxdata = true;
      Serial1.println("<setstop>"); // added 8/3/21. Now that the points change is in-progress, ensure signals are kept at stop and stop sending commands to set points.
    }
    if (strcmp(receivedChars, "normaltransitoff")  == 0) {
      digitalWrite(LOCAL, HIGH);
      digitalWrite(pointN, LOW);
      digitalWrite(pointR, LOW);
      digitalWrite(ptsfailed, LOW);
      Rxdata = true;
       Serial1.println("<setstop>"); // added 8/3/21. Now that the points change is in-progress, ensure signals are kept at stop and stop sending commands to set points.
 
    }
    if (strcmp(receivedChars, "reversetransiton")  == 0) {
      digitalWrite(LOCAL, HIGH);
      digitalWrite(pointN, LOW);
      digitalWrite(pointR, HIGH);
      digitalWrite(ptsfailed, LOW);
      Rxdata = true;
       Serial1.println("<setstop>"); // added 8/3/21. Now that the points change is in-progress, ensure signals are kept at stop and stop sending commands to set points.
 
    }
    if (strcmp(receivedChars, "reversetransitoff")  == 0) {
      digitalWrite(LOCAL, HIGH);
      digitalWrite(pointN, LOW);
      digitalWrite(pointR, LOW);
      digitalWrite(ptsfailed, LOW);
      Rxdata = true;
       Serial1.println("<setstop>"); // added 8/3/21. Now that the points change is in-progress, ensure signals are kept at stop and stop sending commands to set points.
 
    }
    //
    if (strcmp(receivedChars, "pointssetreverse")  == 0) {
      digitalWrite(LOCAL, HIGH);
      digitalWrite(pointN, LOW);
      digitalWrite(pointR, HIGH);
      digitalWrite(ptsfailed, LOW);
      Rxdata = true;
    }
    if (strcmp(receivedChars, "pointsfailed7")  == 0) {
      digitalWrite(LOCAL, HIGH);
      digitalWrite(pointN, LOW);
      digitalWrite(pointR, LOW);
      digitalWrite(ptsfailed, HIGH);
      sigboxALLRED();
      Rxdata = true;
    }
    if (strcmp(receivedChars, "safetydelay")  == 0) {
      digitalWrite(LOCAL, HIGH);
      Rxdata = true;
    }
    if (strcmp(receivedChars, "pointsnotfailed")  == 0) {
      digitalWrite(LOCAL, HIGH);
      digitalWrite(ptsfailed, LOW);
      Rxdata = true;
    }
  }
  delay (15);
}
// ############################
void locotrackocc(){
  locotrackcircuitval = 1000; // added 8/11/21
  locotrackcircuitval = analogRead(locotrackcct); // read input
  int tccount = 0;
   if (locotrackcircuitval < 400) {
    tccount = tccount +1;
    delay (30); // contact debounce time
    locotrackcircuitval = analogRead(locotrackcct); // read input
    if (locotrackcircuitval < 400) {
    delay (30); // second 50mS - could be legit activiation
    locotrackcircuitval = analogRead(locotrackcct); // read input
    tccount = tccount +1; //add another block to counter
    if (locotrackcircuitval < 400) {
    delay (30); // second 50mS - could be legit activiation
    tccount = tccount +1; //add another block to counter
    }
    }
  }
     if (tccount == 3) { // at least 90mS of occupancy - must be occupied
    LOCOOCCUPIED();
    tccount = 0;
}
    if (locotrackcircuitval > 400) {
    LOCOUNOCCUPIED();
  }
  
  
}