// https://wokwi.com/projects/427977547001701377
// https://forum.arduino.cc/t/analog-reading-to-digital/1366479
// camsysca + hacking on the beach
// three tracks can be referred to as 0, 1 and 2 or
# define IN   0
# define CEN  1
# define OUT  2
# define DOCCUPIED LOW  //... low is blocked is button or switch closed
struct TRACK {
  byte currentState;
  byte detPins[2];   // inputs: west detector, east detector
  byte lampPins[4];  // outputs: green west, red west, green east, red east
};
// three tracks
TRACK track[3] = {
  {0},  // track 0 not here yet
  {  0,               //... make it clear : 0 = EMPTY by default
    {A14, A1},
    {34, 35, 14, 10}
  },
  {0}   // track 2 not here yet
};
//... enum to give numbers nice names
enum {EMPTY = 0, WESTBOUND_ENTERED, WESTBOUND_DEPARTS, EASTBOUND_ENTERED, EASTBOUND_DEPARTS, DEADLOCK};
char *stateTags[] = {"EMPTY", "WEST ENTERED", "WEST DEPART", "EAST ENTERED", "EAST DEPART", "DEADLOCK"};
//... what functionality did I kill or frustrate -> int TrackCenState;
void setup() {
  Serial.begin(115200);  //... 21st century
  setPinModes();
  lampTest();
}
void loop() {
//... process_Track reads the inputs for now
  process_Track(track + CEN);  // (&track[CEN]) if you prefer
  LEDSet(track + CEN);  
  delay(20); //... poor man's debounce
}
void process_Track(TRACK *theTrack)
{
  bool det_East = digitalRead(theTrack->detPins[0]) == DOCCUPIED;
  bool det_West = digitalRead(theTrack->detPins[1]) == DOCCUPIED;
  static int printedState = -1;
  if (printedState != theTrack->currentState) {
    Serial.print(det_West ? "WEST blocked " : "   <west>    ");
    Serial.print(det_East ? "EAST blocked " : "   <east>    ");
    Serial.print("state is ");
    Serial.println(stateTags[theTrack->currentState]);
    printedState = theTrack->currentState;
  }
  switch (theTrack->currentState) {
    case EMPTY:
      if (det_East) theTrack->currentState = WESTBOUND_ENTERED;
      if (det_West) theTrack->currentState = EASTBOUND_ENTERED;
      break;
    case WESTBOUND_ENTERED:
      if (det_West) theTrack->currentState = WESTBOUND_DEPARTS;
      break;
    case EASTBOUND_ENTERED:
      if (det_East) theTrack->currentState = EASTBOUND_DEPARTS;
      break;
    case WESTBOUND_DEPARTS:
      if (!det_West) theTrack->currentState = EMPTY;
      break;
    case EASTBOUND_DEPARTS:
      if (!det_East) theTrack->currentState = EMPTY;
      break;
    case DEADLOCK:  //both entered simultaneously, must clear by backing one of them up; if perchance they both clear, we can go to empty
      if (!det_East && !det_West) theTrack->currentState = EMPTY;
      else if (!det_East) theTrack->currentState = EASTBOUND_ENTERED;
      else if (!det_West) theTrack->currentState = WESTBOUND_ENTERED;
      //last else would just remain  in DEADLOCK
      break;
  }
}
enum signals {sGW = 0, sRW, sGE, sRE};
void LEDSet (TRACK *theTrack)
{
  switch (theTrack->currentState) {
  case EMPTY:
    digitalWrite(theTrack->lampPins[sGW], HIGH);
    digitalWrite(theTrack->lampPins[sGE], HIGH);
    digitalWrite(theTrack->lampPins[sRW], LOW);
    digitalWrite(theTrack->lampPins[sRE], LOW);
    break;
  case WESTBOUND_DEPARTS:
  case WESTBOUND_ENTERED:
    digitalWrite(theTrack->lampPins[sGW], LOW);
    digitalWrite(theTrack->lampPins[sGE], HIGH);
    digitalWrite(theTrack->lampPins[sRW], HIGH);
    digitalWrite(theTrack->lampPins[sRE], LOW);
    break;
    
  case EASTBOUND_DEPARTS:
  case EASTBOUND_ENTERED:
    digitalWrite(theTrack->lampPins[sGW], HIGH);
    digitalWrite(theTrack->lampPins[sGE], LOW);
    digitalWrite(theTrack->lampPins[sRW], LOW);
    digitalWrite(theTrack->lampPins[sRE], HIGH);
    break;
  case DEADLOCK:  //both ends approached simultaneously; shouldn't happen often, but long de lays() increase the risk
    digitalWrite(theTrack->lampPins[sGW], LOW);
    digitalWrite(theTrack->lampPins[sGE], LOW);
    digitalWrite(theTrack->lampPins[sRW], HIGH);
    digitalWrite(theTrack->lampPins[sRE], HIGH);
    break;
  }
}
# define LAMPTIME 266  //... life very short
// just for TRACK 1 now. loop it over N tracks
void setPinModes() {
  for (byte ii = 0; ii < 2; ii++)
    pinMode(track[CEN].detPins[ii], INPUT_PULLUP);
  for (byte ii = 0; ii < 4; ii++)
    pinMode(track[CEN].lampPins[ii], OUTPUT); // Signal green Center West
}
// also TRACK 1 only
void lampTest() {
  for (byte ii = 0; ii < 4; ii++) {
    digitalWrite(track[CEN].lampPins[ii], HIGH);
    delay(LAMPTIME);
    digitalWrite(track[CEN].lampPins[ii], LOW);    
  }
  delay(LAMPTIME * 4);
}
WEST EAST