/*
   Next_block_left  |  Far_left  |  Home_left|...>This Control Point(cp)<...|Home_right  |  Far_right  |  Next_block_right

  2 |  1 home_left |...>This Control Point(cp)<...| Home_right  5  |  6

  left is "west" and right is "east"

  0 = triggered logic
  1 = empty
  2 = west/towards
  3 = east/away

  2=rx west
  3=tx west

  4=East/right facing R
  5=East/right facing Y
  6=East/right facing G
  7=West/left facing R
  8=West/left facing Y
  9=West/left facing G

  10=rx east
  11=tx east

  Y  ;//A0/ is next block left occupied
  R  ;//A1/ is far sensor Far_left triggered
  HL ;//A2/ is near sensor Home_left triggered
  HR ;//A3/ is near sensor Home_right triggered
  R  ;//A4/ is far sensor Far_right triggered
  Y  ;//A5/ is next block right occupied
  0, 1, 2, 3/\4 5, 6, 7
*/

# include <SoftwareSerial.h>
SoftwareSerial Ws(2, 3); //rx,tx com to left 2<->11, 3<->10
SoftwareSerial Es(10, 11); // rx,tx com to right 10<->3,11<->2


#define DEBUG 1
#define Turnout 0

#if DEBUG == 1
#define debug(dx) Serial.print(dx)
#define debugln(dx) Serial.println(dx)
#else
#define debug(dx)
#define debugln(dx)
#endif

#define  TO Turnout 
#define  bl00  PIN_A0

char wa;
char ea;

int cp[2];// value must be >= # of rows in sigs[]
int cpfL;// facing west/left (east bond movement)
int cpfR;//facing east/right (west bond movement)

bool termL;// is there another board to comuniate with to the Left/ West? 0 = no, 1 = yes
bool termR;// is there another board to comuniate with to the right/ East?

int O[6];// value must be >= # of rows in bks[]
int HLW;// HOME_LEFT_WEST
int FLW;// FAR_LEFT_WEST
int TLW;// Farther_Left_West
int HRE;// HOME_RIGHT_EAST
int FRE;// FAR_RIGHT_EAST
int TRE;// Farther_Right_East

int BL[8];// place holder array for sensor inputs
int WB[5];// place holder array for serial inputs from west or left
int EB[5];// place holder array for serial inputs from east or right

bool SC;// initial condition varialble

unsigned long CM;
unsigned long Cu[8];// timing variables, counts up time if block not triggered
unsigned long Cd[8];// counts up if block triggered
//unsigned long cpdt[2];// timers for change of signa

unsigned long BT = 0;

bool bState;

enum {
  L04 = 4, L05, L06,
  L07, L08, L09,
  Llast,
};
// ocupancy function---V---
typedef struct {
  const char    *desc;//cp
  int          term;
  int          FHR;// sensor past next cp
  int          NR;//WD entering block from far end
  int          FR;//WHD exiting block at far end
  int          HR;//EHD entering block controlled by signal
  int          HM;//ED home under signal
  int          ocp;// previous occupancy desc.
  int          hmdt;// home delay
  int          hrdt;// home red delay
} bks_t;
//---------signal function------V----------------------------------------
typedef struct {
  const char    *desc;
  int          HB;
  int          NB;
  int          FB;
  int          TB;
  int          term;
  int          pcp;
  int          hmdt;
  int          hrdt;
} sig_t;
//------light head function----V-------------------------------------------
typedef struct {
  const char *desc;
  int        ledR;
  int        ledY;
  int        ledG;
  int        cpst;
  int        hmdt;
  int        hrdt;
} lt_hd;
// User defined functions------------------------------------------------
int block (bks_t * s);
int sig (sig_t * s);
void head (lt_hd * s);
// end user defined functions-------------------------------------------
//----------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  Es.begin(9600);
  Ws.begin(9600);

  SC = 0;
  cpfL = 1;
  cpfR = 1;
  HLW = 1;
  HRE = 1;

  for (int outPin = L04; outPin < Llast; outPin++) {
    pinMode(outPin, OUTPUT);
  }
  Ws.write('A');
  Es.write('A');

}
/* software serial refs
  if (mySerial.available())
    Serial.write(mySerial.read());
  if (Serial.available())
    mySerial.write(Serial.read());
  }*/
//----------------------------------------------------------------
void loop() {
  CM = millis();

  for (int b = 0; b < 8; b++) {
    BL[b] = digitalRead(bl00 + b);//sesnor reads
    (BL[b] == 0) ? (Cd[b] = CM) : CM;// triggered = Cd growing("Time Off"), not triggered = Cu graowing("Time On")
  }

  debugln("home sensors read check");
  debugln(BL[0]);
  debugln(BL[1]);

  //------------------------------------
  if ((CM - BT) > 600) {// BLINKER TIMER VARIABLE
    BT = CM;
    (bState == 1)?(bState = 0):(bState = 1);
  }
  //----------------------------------------------
  if ((CM < 7000) && ((termL == 0) || (termR == 0))) {
    (Ws.available() > 0) ? (termL = 1) : (termL = 0);
    (Es.available() > 0) ? (termR = 1) : (termR = 0);
    // A = active

    Ws.write('A');
    Es.write('A');
    (Ws.available() > 0) ? (wa = 'A') : (wa = 'N');
    (Es.available() > 0) ? (ea = 'A') : (ea = 'N');
   // wa = Ws.read();
   // ea = Es.read();

    debug("wa = ");
    debugln(wa);
    debug("ea = ");
    debugln(ea);
    delay(25);
  }
  //-----------------------------------------------------------
  if ((CM > 7200) || ((termL == 1) && (termR == 1))) {// time more that 7 seconds after statup

    for (int w = 0; w < 5; w++) {
      if (termL == 1) {
        WB[w] = Ws.read();
        debug("WB ");
        debug(w);
        debug(" is ");
        debugln(WB[w]);
      }
      else {
        if(w == 2){
          WB[w] = 3;
        }
        else{
        WB[w] = 1;
        debug("termL is not 1:WB");
        debug(w);
        debug("is <>");
        debugln(WB[w]);
        }
      }
    }
    Ws.flush();

    for (int e = 0; e < 5; e++) {
      if (termR == 1) {
        EB[e] = Es.read();
        debugln(EB[e]);
      }
      else {
        if(e == 2){
          EB[e] = 3;
        }
        else{
        EB[e] = 1;
        debug("termR is not 1:EB");
        debug(e);
        debug("is <>");
        debugln(EB[e]);
        }
      }
    }
    Es.flush();

    //------------------------------------------------
    //  desc   term     FHR     NR     FR      HR    HM    ocp     hmdt      hrdt
    bks_t bks [] = {
      {"HLW", termL,   WB[3],   WB[1], WB[0], BL[0], BL[1], HLW,    1,       0},// block to left of cp
      {"HRE", termR,   EB[3],   EB[1], EB[0], BL[1], BL[0], HRE,    0,       1},// block to right of cp
    };

#define B_SIZE (sizeof(bks)/sizeof(bks_t))
    for (int o = 0; o < B_SIZE; o++) {// occupancy block function
      O[o] = block (& bks[o]);// should = "<" number of rows in table above

    }
    HLW = O[0];
    HRE = O[1];

    //TLW = WB[2];
    FLW = WB[2];//convert bks [] info to HLW-> info
    // need to arrange according to bks[] table above
    // row 1 = O[0], row 2 = O[1]...
    FRE = EB[2];
    //TRE = EB[2];

    if ((HLW != 1) && (HRE != 1)) {
      SC = 1;
    }
    debug("ocupancy checks:(");
    debug(HLW);
    debug(")(");
    debug(HRE);
    debugln(") end ocp transmission");


    //-----------------*********************
    // desc    HB     NB   FB   TB   term   pcp   hmdt   hrdt
    sig_t sigs [] = {
      {"cpfL", BL[0], HRE, FRE, FRE, termR, cpfL,  0,    1},// west to east bond move
      {"cpfR", BL[1], HLW, FLW, FLW, termL, cpfR,  1,    0},// east to west bound move
    };
#define S_SIZE (sizeof(sigs)/sizeof(sig_t))
    for (int l = 0; l < S_SIZE; l++) {// signal function
      cp[l] =  sig (& sigs[l]);
    }

    cpfL = cp[0];
    cpfR = cp[1];
/*
    if ((CM - Cu[1] > 6000) && (cpfL < 3) && (termR = 0)) {
      Cu[1] = CM;
      cpfL++;
    }
    if ((CM - Cu[0] > 6000) && (cpfR < 3) && (termL = 0)) {
      Cu[0] = CM;
      cpfR++;
    }*/
    debugln("cp checks");
    debugln(cpfL);
    debugln(cpfR);
    //********^
    lt_hd lits [] = {
      {"FWest", L07, L08, L09, cpfL, 1, 0 },
      {"Feast", L04, L05, L06, cpfR, 0, 1 },
    };
#define H_SIZE (sizeof(lits)/sizeof(lt_hd))
    for (int h = 0; h < H_SIZE; h++) {// signal head output function
      head (& lits[h]);
    }
    Es.write(BL[1]);
    Es.write(HRE);
    Es.write(cpfR);
    Es.write(BL[0]);
    Ws.write(BL[0]);
    Ws.write(HLW);
    Ws.write(cpfL);
    Ws.write(BL[1]);
  }
}
// END VOID LOOPS
//-------------------------------------------------------
//  desc   term     FHR     NR     FR      HR    HM    ocp     hmdt      hrdt
int block (bks_t * s) {
  int OD;

  if ((s->ocp) == 1) {
    if ((((s->NR) == 3) && ((s->FR) == 0))) {
      Cd[s->hmdt] = 0;
      OD = 2;
      return OD;
    }
    if((((s->HR) == 0))){
      Cd[s->hmdt] = 0;
      OD = 2;
      return OD;
    }
    if (((s->FR) == 0 )) {
      OD = 3;
      return OD;
    }
    if((s->HM) == 0){
      Cu[s->hmdt] = CM;
      Cd[s->hrdt] = 0;
      OD = 3;
      return OD;
    }
    else {
      OD = 1;
      return OD;
    }
  }
  if ((s->ocp) == 3) {// train moving away from cp
    if (((s->HR) == 0) || ((s->HM) == 0) || ((s->FR) == 0)) {// if any sensors triggere, direction stays gree
      OD = 3;
      return OD;
    }
    if((((s->HM) == 1) && (CM - Cd[s->hmdt] > 700) && (Cd[s->hrdt] == 0))){// protects from false sig while crossing cp
      OD = 3;
      return OD;
    } 

    if(((s->term) == 0) && (CM - Cd[s->hrdt] > 2200) && (Cd[s->hrdt] != 0)){// **** set timeout of block if term 0***MUST = 4X TIMEOUT IN SIG
      OD = 1;
      return OD;
    }
    if(((s->term) == 1) && (CM - Cd[s->hrdt] > 700) && (Cd[s->hrdt] != 0)){
      if (((s->FR) == 1) && ((s->HR) == 1) && ((CM - Cd[s->hmdt] > 700))){
        OD = 0;
        return OD;
      }
     if ((((s->FHR) == 0) && ((s->FR) == 1))) {
      OD = 1;
      return OD;
    }
      else{
        OD = 3;
        return OD;
      }
    }
    else {
      OD = 3;
      return OD;
    }
  }
  if ((s->ocp) == 2) {
    if (((s->FR) == 0) || ((s->HR) == 0) || ((s->HM) == 0)) {
      OD = 2;
      return OD;
    }
    if ((CM - Cd[s->hrdt] > 700)) {
     if((CM -Cd[s->hmdt] > 2200) && (Cd[s->hmdt] != 0)){//**** set time to delay drop to green behind train****
      OD = 1;
      return OD;
     }
      if(((s->NR) == 3) && ((s->FR) == 1) && ((s->HR) == 1) && ((s->term) == 1)){
      OD = 0;
      return OD;
     }
     else{
       OD = 2;
       return OD;
     }
    }
    else {
      OD = 2;
      return OD;
    }
  }
  if ((s->ocp) == 0) {
    if(((s->NR) == 3) && ((s->FR) == 0)){
      OD = 2;
      return OD;
    }
    if(((s->NR) != 3) && ((s->FR) == 0)){
      OD = 3;
      return OD;
    }
    if ((s->HR) == 0) {
      OD = 2;
      return OD;
    }
    else {
      OD = 0;
      return OD;
    }
  }
}
//--------------------------------------------
// desc    HB     NB   FB   TB   term   pcp  hmdt  hrdt
int sig (sig_t * s) {
  int cp;
  debugln("sig time check");
  debugln(Cu[0]);
  if((((s->NB) == 3) && (CM - Cu[s->hmdt] > 1100))){
    cp = 0;
    return cp;
  }
  if (((s->NB) == 0)) {// if near block is occupied "not 1, !1" sig is always red
    cp = 0;
    return cp;
  }
  if(((s->NB) == 2)){
    cp = 4;
    return cp;
  }
  if (SC == 0) {// initial condition indications
    if ((s->term) == 0) {// if no next block in direction of signal
      cp = 1;            // initial indication is solid yellow
      return cp;
    }
    if ((s->term) == 1) {// if next block exists
      cp = 2;            // initial indication is blinking yellow
      return cp;
    }
  }
  if (((s->term) == 0) && (CM - Cd[s->hrdt] > 6000) && ((s->pcp) < 3)) {
    Cd[s->hrdt] = CM;
    debug(s->pcp);
    cp = (s->pcp);
    cp++;
    debug(" => this cycle is returning cp =");
    debugln(cp);
    return cp++;
  }
  if(((s->pcp) == 4) && ((CM - Cd[s->hmdt] > 1100)) && (Cd[s->hmdt] !=0)){
    cp = 3;
    return cp;
  }
  if (((s->NB) == 1) && ((s->FB) == 0)) {
    cp = 1;
    return cp;
  }
  if (((s->NB) == 1) && ((s->FB) == 1)) {
    cp = 2;
    return cp;
  }
  if (((s->NB) == 1) && ((s->FB) == 2)) {
    cp = 3;
    return cp;
  }
  else{
    cp = (s->pcp);
    return cp;
  }
}
//-------------------------------------------------
void head (lt_hd * s) {
  digitalWrite((s->ledR), HIGH);
  digitalWrite((s->ledY), HIGH);
  digitalWrite((s->ledG), HIGH);
  if (((s->cpst) == 0) || ((s->cpst) == 4)) {// red
    digitalWrite((s->ledR), LOW);

  }
  if (((s->cpst) == 1) || ((s->cpst) == 5)) {// yellow
    digitalWrite((s->ledY), LOW);

  }
  if ((s->cpst) == 2) {// blinking yellow
    digitalWrite((s->ledY), bState);

  }
  if ((s->cpst) == 3) {//green
    digitalWrite((s->ledG), LOW);
  }
}
nano:12
nano:11
nano:10
nano:9
nano:8
nano:7
nano:6
nano:5
nano:4
nano:3
nano:2
nano:GND.2
nano:RESET.2
nano:0
nano:1
nano:13
nano:3.3V
nano:AREF
nano:A0
nano:A1
nano:A2
nano:A3
nano:A4
nano:A5
nano:A6
nano:A7
nano:5V
nano:RESET
nano:GND.1
nano:VIN
nano:12.2
nano:5V.2
nano:13.2
nano:11.2
nano:RESET.3
nano:GND.3
led5:A
led5:C
led4:A
led4:C
led3:A
led3:C
led1:A
led1:C
led2:A
led2:C
led6:A
led6:C
wlr:1
wlr:2
elr:1
elr:2
west trigger:1
west trigger:2
west trigger:3
sw1:1
sw1:2
sw1:3
west trigger res:1
west trigger res:2
east trigger res:1
east trigger res:2