/***
* Switch Signal Controller Demo
* 10/29/2019
* Modified by Robby Mossman
* 11/14/2019
* 06/03/2021 - Updated Input and Output assignments for Arduino Mega Board
* 06/04/2021 - Defined what items are outputs and what is an input
* 06/04/2021 - Updated signal lights so that Green does not come on after switch finishes changing position.
* Yellow still flashes indicating which route switch is moving towards
* On power on I enabled each crossing light to turn on and bell to ding in sync with lights turning on
* 07/05/2021 - Updated changes which include crossing warning activation being separated from switch and signal head actions
* Updated PBR / PBL function to change the signal head lights to all RED on push and on release activate the motor
* and change the lights to prevent motor from running longer than needed.
* Enabled Serial.Print so I can monitor what CASE we are in and verify that the appropriate PIN is active
* Added Light and Lightoff before motor runs in order to reset lights when PBL or PBR are pushed after crossing clears
* 07/12/2021 - Added additional logging details to show time between actions in order to try and troubleshoot what appears to be a
* phantom trigger of PBL or PBR
*
* 08/10/2021 - Updated Pin assignments for installation into enclosure
*
* 08/19/2021 - Changed the signal head light so when route is select Green is on until train detected in crossing the Green turns
* off and yellow turns on. Signal does not change back to Green until train clears switch. Green also indicates the Push buttons
* are active.
*
* 08/19/2021 - Added additional functionality so when lights get turned off after being idle for a period of time when grade crossing flashers
* becomes active it turns the appropriate signal head lights back on to represent the last known condition of signal head lights
*
* 07/07/2023 - Adding Capture button on West loop at Breezeway heading towards yard
* Added Track Detection after traveling across crossing from West to East towards yard
*
* 07/27/2023 - Simply adding this comment to see what happens!
*
* 08/05/2023 - Numbered all states.
* Added a new print function: printMessage3
* Simply prints out a message
*
* Technical info about timer interrupts
* https://electronoobs.com/eng_arduino_tut140.php
*
************************************************************************/
int DIGITALTRACE = 0; // 0 no digital trace, 1 digital trace
int ENABLEprintMessage1 = 0; // 0 No printMessage1 1 printMessage1
int ENABLEprintMessage2 = 0; // 0 No printMessage1 1 printMessage1
/*
* Assign pin numbers to symbols - wired to digital IO Ports
* Relay Board 1 - Pins 35 - 49 Odd Numbers
* Relay Board 2 - Pins 34 - 48 Even Numbers
*/
#define REDL 35 // RED LEFT - Relay Board 1 - Relay 1
#define YELL 37 // YELLOW LEFT - Relay Board 1 - Relay 2
#define GRNL 39 // GREEN LEFT - Relay Board 1 - Relay 3
#define REDR 41 // RED RIGHT - Relay Board 1 - Relay 4
#define YELR 43 // YELLOW RIGHT - Relay Board 1 - Relay 5
#define GRNR 45 // GREEN RIGHT - Relay Board 1 - Relay 6
#define GRDLTL 47 // Left Grade Crossing Light - Relay Board 1 - Relay 7
#define GRDLTR 49 // Right Grade Crossing Light - Relay Board 1 - Relay 8
#define LightGreenStraightPoints 44 //Switch Light for Straight - Relay Board 2 - Relay 4
#define LightRedByPassPoints 46 //Switch Light for ByPass - Relay Board 2 - Relay 5
#define SwitchPointDetectStraight 48 //Switch Point Detect Straight
#define SwitchPointDetectByPass 50 //Switch Point Detect ByPass
#define BELL 34 // Grade crossing Bell - Relay Board 2 - Relay 1
// Switch Motor Output
#define MOTORL 36 // MOTOR MOVING SWITCH TO GO LEFT - Relay Board 2 - Relay 2
#define MOTORR 38 // MOTOR MOVING SWITCH TO GO RIGHT - Relay Board 2 - Relay 3
// The following are inputs - wired to digital IO Ports
#define PBL 8 // PUSH BUTTON TO GO LEFT Head toward ByPass (TRKDD)
#define PBR 9 // PUSH BUTTON TO GO RIGHT Head towards Station (TRKDC)
#define PBW 40 // PUSH Button to go from West to East on OUTER loop towards yard (TRKDE)
#define TRKDA 10 // Train Detection at Grade Crossing
#define TRKDC 11 // #6 Track detection to reactivate Push Buttons and change signal lights to ALL Green - Train heading towards station or Bypass both tracks are wired to share the detection
#define TRKDD 12 // #8 Track detection to reactivate Push Buttons and change signal lights to ALL Green - Train heading towards station or Bypass both tracks are wired to share the detection
#define TRKDE 42 // Track Dection after train crossing grade crossing towards yard
#define OUTERTRACKWEST 51 //Track detection on west side of double crossing
#define OUTERTRACKEAST 53 //Track detection on east side of double crossing
// USEFUL SYMBOLS (FOR READABILITY)
#define LEFT 0
#define RIGHT 1
#define PUSHED LOW
#define NOTPUSHED HIGH
#define ON HIGH
#define OFF LOW
#define WRITE 1
#define NOWRITE 0
#define YES 1
#define NO 0
#define RIGHT 1
#define LEFT 0
#define B_FLASHERLEFT 7 //Flasher light left
#define B_FLASHERRIGHT 8 //Flasher Light Right
#define B_Bell 9 // Bell
#define L_GRADECROSSING 10
#define R_GRADECROSSING 11
#define L_SWITCHLEFT 12 // PBL buttons disabled until train clears
#define L_SWITCHRIGHT 13 // PBR buttons disabled until train clears
/*
* If you expected the motor to take 3 seconds to move the switch you would
* set MOTORDELAYMS to 3000
* The BLINKINTERVAL is how long the light will be on or off at a time
* as it blinks. Again in MS
* BLINKCOUNT IS CALCULATED FOR YOU BUT BETTER TO NAKE BLINKINTERVAL TO
* DIVIDE INTO MOTORDELAYMS EVENLY
*/
#define MOTORDELAYMS 700
#define BLINKINTERVAL 160
#define BLINKCOUNT (((MOTORDELAYMS) / (BLINKINTERVAL)) / 2)
#define FLASHINTERVAL 300
#define FLASHCOUNT 20
// Do this BLINKCOUNT times
// Light On
// Delay(BLINKINTERVAL)
// Light Off
// Delay(BLINKINTERVAL)
/*********************************************
*
* New Section to add Case Enumeration
* Bill Leahy / Robby Mossman - 06/28/2021
* Updated ENUM with BREEZEWAY Items - 07/07/2023
*********************************************/
// New State Labels with State Numbers
enum {
S010_STARTOUTERTRACK,
S020_OUTER_CLEAR,
S030_OUTER_EASTBOUND_TRAIN,
S035_WAIT_FOR_OUTERTRACKEAST_RELEASE,
S040_OUTER_WESTBOUND_TRAIN,
S045_WAIT_FOR_OUTERTRACKWEST_RELEASE,
S050_START,
S060_STRAIGHT_ALL_GREEN,
S070_STRAIGHT_ALL_GREEN_WAIT,
S080_TRKDA_CAPTURE_WITHOUT_BUTTON,
S090_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_PRESENT_STRAIGHT,
S100_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_WAIT,
S110_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDC,
S120_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDD,
S130_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDE,
S140_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS,
S150_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_STRAIGHT,
S160_TRKDC_CAPTURE_WITHOUT_BUTTON,
S170_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_PRESENT_STRAIGHT,
S180_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_WAIT,
S190_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDA,
S200_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDD,
S210_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDE,
S220_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS,
S230_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_STRAIGHT,
S240_TRKDD_CAPTURE_WITHOUT_BUTTON,
S250_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_PRESENT_STRAIGHT,
S260_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_WAIT,
S270_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDA,
S280_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDC,
S290_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDE,
S300_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS,
S310_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_STRAIGHT,
S320_TRKDE_CAPTURE_WITHOUT_BUTTON,
S330_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_PRESENT_STRAIGHT,
S340_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_WAIT,
S350_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDA,
S360_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDC,
S370_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDD,
S380_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS,
S390_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_STRAIGHT,
S400_MOVE_SWITCH_STRAIGHT,
S410_WAIT_STRAIGHT,
S420_WAIT_STRAIGHT_PBR_RELEASE,
S430_TRAIN_PRESENT_STRAIGHT,
S440_TRAIN_CLEAR_STRAIGHT,
S450_TRAIN_IN_WRONG_SWITCH_4_STRAIGHT,
S460_TRAIN_IN_SWITCH_STRAIGHT,
S470_TRAIN_IN_SWITCH_STRAIGHT_ERROR,
S480_BYPASS_ALL_GREEN,
S490_BYPASS_ALL_GREEN_WAIT,
S500_MOVE_SWITCH_BYPASS,
S510_WAIT_BYPASS,
S520_WAIT_BYPASS_PBL_RELEASE,
S530_TRAIN_PRESENT_BYPASS,
S540_TRAIN_CLEAR_BYPASS,
S550_TRAIN_IN_WRONG_SWITCH_4_BYPASS,
S560_TRAIN_IN_SWITCH_BYPASS,
S570_TRAIN_IN_SWITCH_BYPASS_ERROR,
S580_MOVE_SWITCH_BYPASS_BREEZEWAY,
S590_WAIT_BYPASS_BREEZEWAY,
S600_WAIT_BYPASS_BREEZEWAY_PBW_RELEASE,
S610_TRAIN_PRESENT_BYPASS_BREEZEWAY,
S615_TRAIN_PRESENT_WESTBOUND_TO_YARD,
S616_TRAIN_PRESENT_WESTBOUND_TO_MAINLINE,
S617_TRAIN_PRESENT_U_TURN_EAST_LOOP,
S620_TRAIN_CLEAR_BYPASS_BREEZEWAY_ALL_GREEN,
S630_TRAIN_CLEAR_BYPASS_BREEZEWAY,
S640_TRAIN_IN_WRONG_SWITCH_4_BYPASS_BREEZEWAY,
S650_TRAIN_IN_SWITCH_BYPASS_BREEZEWAY,
S660_TRAIN_IN_SWITCH_BYPASS_ERROR_BREEZEWAY,
S670_TRAIN_TRAVELING_WEST_EAST_ON_BYPASS,
S680_TRAIN_TRAVELING_WEST_EAST_ON_BYPASS_WAIT,
S690_TRAIN_TRAVELING_WEST_EAST_ON_STRAIGHT,
S700_TRAIN_TRAVELING_WEST_EAST_ON_STRAIGHT_WAIT,
S900_NO_TRAIN,
S910_EASTBOUND_WON,
S920_EASTBOUND_WOFF,
S930_EASTBOUND_EON,
S940_WESTBOUND_EON,
S950_WESTBOUND_EOFF,
S960_WESTBOUND_WON,
S970_NOW_EB_EON,
S980_NOW_WB_WON,
S1000_Switch_Point_Wait,
S1050_Switch_Point_Straight,
S1100_Switch_Point_ByPass
}; // End of Enum
static char *statenames[] = {"S010_STARTOUTERTRACK",
"S020_OUTER_CLEAR",
"S030_OUTER_EASTBOUND_TRAIN",
"S035_WAIT_FOR_OUTERTRACKEAST_RELEASE",
"S040_OUTER_WESTBOUND_TRAIN",
"S435_WAIT_FOR_OUTERTRACKWEST_RELEASE",
"S050_START",
"S060_STRAIGHT_ALL_GREEN",
"S070_STRAIGHT_ALL_GREEN_WAIT",
"S080_TRKDA_CAPTURE_WITHOUT_BUTTON",
"S090_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_PRESENT_STRAIGHT",
"S100_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_WAIT",
"S110_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDC",
"S120_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDD",
"S130_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDE",
"S140_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS",
"S150_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_STRAIGHT",
"S160_TRKDC_CAPTURE_WITHOUT_BUTTON",
"S170_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_PRESENT_STRAIGHT",
"S180_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_WAIT",
"S190_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDA",
"S200_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDD",
"S210_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDE",
"S220_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS",
"S230_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_STRAIGHT",
"S240_TRKDD_CAPTURE_WITHOUT_BUTTON",
"S250_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_PRESENT_STRAIGHT",
"S260_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_WAIT",
"S270_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDA",
"S280_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDC",
"S290_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDE",
"S300_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS",
"S310_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_STRAIGHT",
"S320_TRKDE_CAPTURE_WITHOUT_BUTTON",
"S330_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_PRESENT_STRAIGHT",
"S340_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_WAIT",
"S350_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDA",
"S360_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDC",
"S370_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDD",
"S380_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS",
"S390_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_STRAIGHT",
"S400_MOVE_SWITCH_STRAIGHT",
"S410_WAIT_STRAIGHT",
"S420_WAIT_STRAIGHT_PBR_RELEASE",
"S430_TRAIN_PRESENT_STRAIGHT",
"S440_TRAIN_CLEAR_STRAIGHT",
"S450_TRAIN_IN_WRONG_SWITCH_4_STRAIGHT",
"S460_TRAIN_IN_SWITCH_STRAIGHT",
"S470_TRAIN_IN_SWITCH_STRAIGHT_ERROR",
"S480_BYPASS_ALL_GREEN",
"S490_BYPASS_ALL_GREEN_WAIT",
"S500_MOVE_SWITCH_BYPASS",
"S510_WAIT_BYPASS",
"S520_WAIT_BYPASS_PBL_RELEASE",
"S530_TRAIN_PRESENT_BYPASS",
"S540_TRAIN_CLEAR_BYPASS",
"S550_TRAIN_IN_WRONG_SWITCH_4_BYPASS",
"S560_TRAIN_IN_SWITCH_BYPASS",
"S570_TRAIN_IN_SWITCH_BYPASS_ERROR",
"S580_MOVE_SWITCH_BYPASS_BREEZEWAY",
"S590_WAIT_BYPASS_BREEZEWAY",
"S600_WAIT_BYPASS_BREEZEWAY_PBW_RELEASE",
"S610_TRAIN_PRESENT_BYPASS_BREEZEWAY",
"S615_TRAIN_PRESENT_WESTBOUND_TO_YARD",
"S616_TRAIN_PRESENT_WESTBOUND_TO_MAINLINE",
"S617_TRAIN_PRESENT_U_TURN_EAST_LOOP",
"S620_TRAIN_CLEAR_BYPASS_BREEZEWAY_ALL_GREEN",
"S630_TRAIN_CLEAR_BYPASS_BREEZEWAY",
"S640_TRAIN_IN_WRONG_SWITCH_4_BYPASS_BREEZEWAY",
"S650_TRAIN_IN_SWITCH_BYPASS_BREEZEWAY",
"S660_TRAIN_IN_SWITCH_BYPASS_ERROR_BREEZEWAY",
"S670_TRAIN_TRAVELING_WEST_EAST_ON_BYPASS",
"S680_TRAIN_TRAVELING_WEST_EAST_ON_BYPASS_WAIT",
"S690_TRAIN_TRAVELING_WEST_EAST_ON_STRAIGHT",
"S700_TRAIN_TRAVELING_WEST_EAST_ON_STRAIGHT_WAIT",
"S900_NO_TRAIN",
"S910_EASTBOUND_WON",
"S920_EASTBOUND_WOFF",
"S930_EASTBOUND_EON",
"S940_WESTBOUND_EON",
"S950_WESTBOUND_EOFF",
"S960_WESTBOUND_WON",
"S970_NOW_EB_EON",
"S980_NOW_WB_WON",
"S1000_Switch_Point_Wait",
"S1050_Switch_Point_Straight",
"S1100_Switch_Point_ByPass"
};
// Function Prototypes (these function are at the bottom of the file)
void all(int side, int dly); // Turn all lights on one side on for dly MS then turn them off
void motor(int side, int action); // Turn the motor actuator on or off in the desired direction
void light(int which); // Turn on 'which' light
void lightoff(int which); // Turn off 'which' light
int pushed(int button); // Return true if button is pushed
void blinker(int count, int which, int duration); // Blinks which light count times each on or off is duration long
void flasher(int count, int which, int duration); // Blinks which light count times each on or off is duration long
void crossingProcedure(bool bells, int duration); // Activates the entire crossing setup for a duration with bell sounds on or off
void digitalWriteWrapper(int pin, int val); //Print PIN information to Serial Monitor
// Set state machines initial starting states
int state = S050_START;
int oldstate = -1;
//char buffer[10];
int state2 = S010_STARTOUTERTRACK;
int oldstate2 = -1;
//char buffer2[10];
int state3 = S900_NO_TRAIN;
int oldstate3 = -1;
//char buffer3[10];
int state4 = S1000_Switch_Point_Wait;
int oldstate4 = -1;
//char buffer4[10];
int long timeout = 0L; //Time out variable for lights to turn off after button has been pushed
// Used in outer track state machine to timeout if no train present
unsigned long current_time = 0;
unsigned long flash_start_time = 0;
unsigned long flash2_start_time = 0;
unsigned long flash_time_limit = 7; // Seconds before flash will be
// turned off with no train detected
unsigned long flash2_time_limit = 7; // Seconds before flash2 will be
// turned off with no train detected
/*-----------------------------------------------------------------------------------
*
* About interrupt timers
Calculations (for 500ms):
System clock 16 Mhz and Prescalar 256; (every 256 system clock ticks our timer will tick)
Timer 1 speed = 16Mhz/256 = 62.5 Khz
Pulse time = 1/62.5 Khz = 16us
Count up to = 500ms / 16us = 31250 (so this is the value the
OCR register should have)
So, if we were to shoot for 45 flashes/minute which would be
0.75 cycles/sec or 1 cycle/1.33 sec or 665 ms on and 665 ms off.
Thus
Calculations (for 665ms):
System clock 16 Mhz and Prescalar 256;
Timer 1 speed = 16Mhz/256 = 62.5 Khz
Pulse time = 1/62.5 Khz = 16us
Count up to = 665ms / 16us = 41562 (so this is the value the
OCR register should have)
--------------------------------------------------------------------------------*/
// flash_enabled is for main crossing track closest Hotel
// flash_enabled2 is for main crossing track closest to river
// If either of them is set to YES then the master_flash_enabled will be set too YES
// nextside is used to make crossing lights alternate
// already_off is used to determine if lights are already off not having to turn them off again
int flash_enabled = NO;
int flash_enabled2 = NO;
int master_flash_enabled = NO;
int nextside = RIGHT;
int already_off = YES;
/************************************************************************
*
* The setup function gets executed once at the beginning
*
************************************************************************/
void setup() {
// Tell the Arduino which pins are input and which are output.
/***************************************************
* Items below are for signal head lights
****************************************************/
pinMode(REDL, OUTPUT);
pinMode(YELL, OUTPUT);
pinMode(GRNL, OUTPUT);
pinMode(REDR, OUTPUT);
pinMode(YELR, OUTPUT);
pinMode(GRNR, OUTPUT);
/***************************************************
* Items below are for the crossing lights and bell
****************************************************/
pinMode(GRDLTL, OUTPUT);
pinMode(GRDLTR, OUTPUT);
pinMode(BELL, OUTPUT);
/***************************************************
* Items below are for the switch motor
****************************************************/
pinMode(MOTORL, OUTPUT);
pinMode(MOTORR, OUTPUT);
/*************************************************************************
* Items below are for the switch point detection input and lights output
*************************************************************************/
pinMode(SwitchPointDetectStraight, INPUT_PULLUP);
pinMode(SwitchPointDetectByPass, INPUT_PULLUP);
pinMode(LightGreenStraightPoints, OUTPUT);
pinMode(LightRedByPassPoints, OUTPUT);
/***************************************************
* Items below represent push buttons and track detection
* PULLUP means if not pressed then it's high
* Pressed will be low
****************************************************/
pinMode(PBL, INPUT_PULLUP); // Push button LEFT for Switch Motor
pinMode(PBR, INPUT_PULLUP); // Push button Right for Switch Motor
pinMode(PBW, INPUT_PULLUP); // Push Button at Breezeway to Capture Block
pinMode(TRKDA, INPUT_PULLUP); // Track detection for approaching train to man and activate warning signal and bell
pinMode(TRKDC, INPUT_PULLUP); // Track detection once train clears switch heading towards station and allows buttons to reactivate and signal heads change to green
pinMode(TRKDD, INPUT_PULLUP); // Track detection once train clears switch heading towards bypass and allows buttons to reactivate and signal heads change to green
pinMode(TRKDE, INPUT_PULLUP); // Track dection heading towards yard
pinMode(OUTERTRACKWEST, INPUT_PULLUP); // Track Detection west side of outer loop
pinMode(OUTERTRACKEAST, INPUT_PULLUP); // Track Detection east side of outer loop
// Turn all lights off
digitalWriteWrapper(REDL, LOW);
digitalWriteWrapper(YELL, LOW);
digitalWriteWrapper(GRNL, LOW);
digitalWriteWrapper(REDR, LOW);
digitalWriteWrapper(YELR, LOW);
digitalWriteWrapper(GRNR, LOW);
digitalWriteWrapper(MOTORL, LOW);
digitalWriteWrapper(MOTORR, LOW);
digitalWriteWrapper(GRDLTL, LOW);
digitalWriteWrapper(GRDLTR, LOW);
digitalWriteWrapper(BELL, LOW);
Serial.begin(115200); //Print all activity from Arduino to Serial port. This is for troubleshooting. This is also part of pin 0/1
// New interrupt timer code where we setup interrupt timer
cli(); //stop interrupts while we make the settings
/*1. First we reset the control register to make sure we start with everything
disabled.*/
TCCR1A = 0; // Reset entire TCCR1A to 0
TCCR1B = 0; // Reset entire TCCR1B to 0
/*2. We set the prescalar to the desired value by changing the CS10 CS12 and CS12 bits.
*/
TCCR1B |= B00000100; //Set CS12 to 1 so we get prescalar 256
/*3. We enable compare match mode on register A*/
TIMSK1 |= B00000010; //Set OCIE1A to 1 so we enable compare match A
/*4. Set the value of register A to 31250*/
OCR1A = 41562; //Finally we set compare register A to this value
// which will give us 665 ms flashes
sei(); // Turn interrupts back on
} // void setup()
//***********************************************************************
//***********************************************************************
//***********************************************************************
/************************************************************************
*
* L OOOOO OOOOO PPPPPP
* L O O O O P P
* L O O O O P P
* L O O O O PPPPPP
* L O O O O P
* L O O O O P
* LLLLLLL OOOOO OOOOO P
*
***********************************************************************/
//***********************************************************************
//***********************************************************************
//***********************************************************************
/************************************************************************
*
* Main loop which is called over and over continuously
*
************************************************************************/
void loop() {
// Examine the state variable and go down to the case line that corresponds to its value
// If none match, go to "default"
// This secction implements a timeout fnction. If no activity is detected
// for a certain amout of time the system goes into powersave where it
// turns all lights off until someone presses a pushbutton or track detect A
// senses a rain
timeout = timeout + 1L; // Increments the variable
if (timeout > 300000000L) // Have to determine somebignumber experimentally
{
printMessage1("******** Turning all lights off ********");
// Turn off all lights 300000000L
digitalWriteWrapper(REDL, LOW);
digitalWriteWrapper(YELL, LOW);
digitalWriteWrapper(GRNL, LOW);
digitalWriteWrapper(REDR, LOW);
digitalWriteWrapper(YELR, LOW);
digitalWriteWrapper(GRNR, LOW);
//digitalWriteWrapper(GRDLTL, LOW); //Added so grade crossing ligths off off when signal lights go off 06/07/2021
//digitalWriteWrapper(GRDLTR, LOW); //Added so grade crossing ligths off off when signal lights go off 06/07/2021
printMessage1("******** Lights should now be off ********");
while (!pushed(PBL) && !pushed(PBR) && !pushed(TRKDA) && !pushed(PBW)) // while not pushing left pb and not pushing right pb, loop (if either button gets pushed it will drop out of loop)
{
// Do nothing // Infinite loop (unless a button is pushed)
}
timeout = 0L;
} // if (timeout > 300000000L)
// This is the code to enable flashing if either state machine wants it
if(flash_enabled == YES || flash_enabled2 == YES)
{
master_flash_enabled = YES;
}
else
{
master_flash_enabled = NO;
}
//master_flash_enabled = YES;
/* ---------------------------------------------------------------------------------------------
* We are going to have two variables flash_enabled and flash_enabled2. These
* will be set by the two of the state machines (state3 and state2). If either wants the crossing signal
* then it will be activated.
* The crossing signals will be operated by an interrupt timer that will go off every so many
* milliseconds. Each time it goes off the crossing lights and bell will be toggled if the
* crossing lights are supposed to be on.
*----------------------------------------------------------------------------------------------*/
/****************************************************************************************
* New Switch & State definitions created with Bill L and Robby M on 6/28/2021
*
* Sections below are for Straight traffic through the man crossing towards the station
****************************************************************************************/
/*******************************************
* Added a second state in order to have OUTER track track detection to be separate from
* inner track detection and more 07/24/2023
*
*******************************************/
//while (1) {
if(oldstate != state)
{
if(state != 999) {
Serial.println(statenames[state]);
}
else {
Serial.println("State = 999 Debugging Mode");
}
oldstate = state;
}
if(oldstate2 != state2)
{
Serial.println(statenames[state2]);
oldstate2 = state2;
}
if(oldstate3 != state3)
{
Serial.println(statenames[state3]);
oldstate3 = state3;
}
if(oldstate4 != state4)
{
Serial.println(statenames[state4]);
oldstate4 = state4;
}
switch (state2) // state2 for OUTER track on the double crossing that activates only signals and bell
{
case S010_STARTOUTERTRACK:
state2 = S020_OUTER_CLEAR;
break;
case S020_OUTER_CLEAR:
flash_enabled2 = NO;
if (pushed(OUTERTRACKWEST)) {
state2 = S030_OUTER_EASTBOUND_TRAIN;
}
else if(pushed(OUTERTRACKEAST)) {
state2 = S040_OUTER_WESTBOUND_TRAIN;
}
break;
case S030_OUTER_EASTBOUND_TRAIN:
flash_enabled2 = YES;
if(pushed(OUTERTRACKEAST))
{
state2 = S035_WAIT_FOR_OUTERTRACKEAST_RELEASE;
}
break;
case S035_WAIT_FOR_OUTERTRACKEAST_RELEASE:
if(!pushed(OUTERTRACKEAST))
{
state2 = S020_OUTER_CLEAR;
}
break;
case S040_OUTER_WESTBOUND_TRAIN:
flash_enabled2 = YES;
if (pushed(OUTERTRACKWEST)) {
state2 = S045_WAIT_FOR_OUTERTRACKWEST_RELEASE;
}
break;
case S045_WAIT_FOR_OUTERTRACKWEST_RELEASE:
if(!pushed(OUTERTRACKWEST))
{
state2 = S020_OUTER_CLEAR;
}
break;
default:
break;
} //End of switch state2
switch (state4) // state4 Switch Point Detection and Indicator
{
case S1000_Switch_Point_Wait:
//printMessage1("Now in case Start – S1000_Switch_Point_Wait");
lightoff(LightGreenStraightPoints);
lightoff(LightRedByPassPoints);
if (pushed(SwitchPointDetectStraight))
{
state = S1050_Switch_Point_Straight;
}
else if (pushed(SwitchPointDetectByPass))
{
state = S1100_Switch_Point_ByPass;
}
break;
case S1050_Switch_Point_Straight:
//printMessage1(“Now in Case Start – S1050_Switch_Point_Straight /Pin 44");
lightoff(LightRedByPassPoints);
light(LightGreenStraightPoints);
if (!pushed(SwitchPointDetectStraight))
{
state = S1000_Switch_Point_Wait;
}
break;
case S1100_Switch_Point_ByPass:
//printMessage1(“Now in Case Start – S1050_Switch_Point_Straight / Pin 45");
lightoff(LightGreenStraightPoints);
light(LightRedByPassPoints);
if (!pushed(SwitchPointDetectByPass))
{
state = S1000_Switch_Point_Wait;
}
break;
default:
Serial.println("State machine 4 in DEFAULT - ERROR");
break;
} //End of switch state4
/*-------------------------------------------------------------------------------
* This next section checks to see if there is no train detected by either the
* east or west detector and the flashing is on.
* If false it sets a variable (flash2_start_time) equal to the current
* millisecond counter
* If true it subtracts the flash2_start-time from the current millis value
* If that exceeds a preset time limit it turns off the flash.
-------------------------------------------------------------------------------*/
if(!pushed(OUTERTRACKEAST) && !pushed(OUTERTRACKWEST) && flash_enabled2 == YES)
{
current_time = millis();
if(current_time - flash2_start_time > flash2_time_limit*1000)
{
state2 = S020_OUTER_CLEAR;
}
}
else
{
flash2_start_time = millis(); // millis() Returns the number of
// milliseconds passed since the
// Arduino board began running the
// current program. This number will
// overflow (go back to zero), after
// approximately 50 days.
}
//----------------------------------------------------------- END SWITCH STATE2---------
//state = 999; // Uncomment this line to disable this switch statement
switch (state)
{
//Initial Startup checks all lights & Bell
case S050_START:
printMessage1("Now in Case S050_Start - Initialize System");
all(LEFT, 1000); // Turn all lights on left side on then off
all(RIGHT, 1000); // Turn all kights on right side on then off
//state = S400_MOVE_SWITCH_STRAIGHT;
state = S060_STRAIGHT_ALL_GREEN;
break;
case S060_STRAIGHT_ALL_GREEN:
printMessage1("Now in state S060_STRAIGHT_ALL_GREEN");
motor(RIGHT, ON); // Move switch to right
delay(MOTORDELAYMS);
motor(RIGHT, OFF);
state = S070_STRAIGHT_ALL_GREEN_WAIT;
break;
case S070_STRAIGHT_ALL_GREEN_WAIT:
//Wait for next input from either Crossing, PBR, or PBL
printMessage1("Now in Case S070_STRAIGHT_ALL_GREEN_WAIT - waiting for TRKDA, PBR, PBL, PBW");
//Change signals to ALL GREEN.
lightoff(REDL);
lightoff(REDR);
lightoff(YELL);
lightoff(YELR);
light(GRNL);
light(GRNR);
if (pushed(PBL)) {
state = S520_WAIT_BYPASS_PBL_RELEASE;
}
else if (pushed(PBR)) {
state = S420_WAIT_STRAIGHT_PBR_RELEASE;
}
else if (pushed(PBW)) {
state = S600_WAIT_BYPASS_BREEZEWAY_PBW_RELEASE;
}
else if (pushed(TRKDA)) //ADDED 07/22/2023
{
state = S080_TRKDA_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(TRKDC)) {
state = S160_TRKDC_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(TRKDD)) //ADDED 07/22/2023
{
state = S240_TRKDD_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(TRKDE)) //ADDED 07/22/2023
{
state = S320_TRKDE_CAPTURE_WITHOUT_BUTTON;
}
break;
/************************************************************
* TRKDA
*
* This section addresses train detection on Track after system restart
* and no other action has taken place
*
*************************************************************/
case S080_TRKDA_CAPTURE_WITHOUT_BUTTON:
printMessage1("Now in Case Start - S080_TRKDA_CAPTURE_WITHOUT_BUTTON - !!!NO SWITCH ACTION!!! - Lights & Motor to Straight/Right");
lightoff(YELR);
lightoff(GRNR);
lightoff(YELL);
lightoff(GRNL);
light(REDL);
//motor(RIGHT, ON); // Move switch to right
//delay(MOTORDELAYMS);
//motor(RIGHT, OFF) ;
lightoff(REDR);
light(YELR);
state = S090_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_PRESENT_STRAIGHT;
break;
case S090_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_PRESENT_STRAIGHT:
printMessage1("Now in Case Start - S090_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_PRESENT_STRAIGHT - In Crossing");
lightoff(GRNR);
light(YELR);
light(REDL);
//crossinglights(2, 0, 300);
if (!pushed(TRKDA)) {
state = S100_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_WAIT;
}
break;
case S100_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_WAIT:
printMessage1("Now in Case Start - S100_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_WAIT - In Crossing");
if (pushed(TRKDA)) {
state = S080_TRKDA_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(TRKDC)) {
//crossinglights(2, 0, 300);
state = S110_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDC;
}
else if (pushed(TRKDD)) {
//crossinglights(2, 0, 300);
state = S120_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDD;
}
else if (pushed(TRKDE)) {
//crossinglights(2, 0, 300);
state = S130_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDE;
}
break;
case S110_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDC:
if (!pushed(TRKDC)) {
state = S140_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS;
}
break;
case S120_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDD:
if (!pushed(TRKDD)) {
state = S140_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS;
}
break;
case S130_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDE:
if (!pushed(TRKDE)) {
state = S140_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS;
}
break;
case S140_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS:
printMessage1("Now in Case Start - S140_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS");
lightoff(YELR);
lightoff(REDL);
light(GRNL);
light(GRNR);
state = S150_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_STRAIGHT;
break;
case S150_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_STRAIGHT:
printMessage1("Now in Case Start - S150_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_STRAIGHT - Exited Crossing");
if (pushed(TRKDA)) {
state = S080_TRKDA_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(TRKDC)) {
state = S160_TRKDC_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(TRKDD)) {
state = S240_TRKDD_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(TRKDE)) {
state = S320_TRKDE_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(PBL)) {
state = S520_WAIT_BYPASS_PBL_RELEASE;
}
else if (pushed(PBR)) {
state = S420_WAIT_STRAIGHT_PBR_RELEASE;
}
else if (pushed(PBW)) {
state = S600_WAIT_BYPASS_BREEZEWAY_PBW_RELEASE;
}
break;
/*************************************************************
* TRKDC
*
* This section is for TRKDC if trains coming from cross over or inner loop
*
**************************************************************/
case S160_TRKDC_CAPTURE_WITHOUT_BUTTON:
printMessage1("Now in Case Start - S160_TRKDC_CAPTURE_WITHOUT_BUTTON - MOVE_SWITCH_STRAIGHT - Lights & Motor to Straight/Right");
lightoff(YELL);
lightoff(YELR);
lightoff(GRNL);
lightoff(GRNR);
light(REDL);
light(REDR);
//motor(RIGHT, ON); // Move switch to right
//delay(MOTORDELAYMS);
//motor(RIGHT, OFF) ;
state = S170_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_PRESENT_STRAIGHT;
break;
case S170_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_PRESENT_STRAIGHT:
printMessage1("Now in Case Start - S170_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_PRESENT_STRAIGHT - In Crossing");
light(REDL);
light(REDR);
//crossinglights(2, 0, 300);
if (!pushed(TRKDC)) {
//state = S220_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS;
state = S180_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_WAIT;
//state = S070_STRAIGHT_ALL_GREEN_WAIT;
}
break;
case S180_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_WAIT:
printMessage1("Now in Case Start - S180_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_WAIT - In Crossing");
/*if (pushed(TRKDC)) {
state = S160_TRKDC_CAPTURE_WITHOUT_BUTTON;
}
else */
if (pushed(TRKDA)) {
//crossinglights(2, 0, 300);
state = S190_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDA;
}
else if (pushed(TRKDD)) {
//crossinglights(2, 0, 300);
state = S200_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDD;
}
else if (pushed(TRKDE)) {
//crossinglights(2, 0, 300);
state = S210_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDE;
}
break;
case S190_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDA:
if (!pushed(TRKDA)) {
//state = S220_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS;
state = S070_STRAIGHT_ALL_GREEN_WAIT;
}
break;
case S200_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDD:
if (!pushed(TRKDD)) {
//state = S220_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS;
state = S070_STRAIGHT_ALL_GREEN_WAIT;
}
break;
case S210_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDE:
if (!pushed(TRKDE)) {
//state = S220_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS;
state = S070_STRAIGHT_ALL_GREEN_WAIT;
}
break;
case S220_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS:
printMessage1("Now in Case Start - S220_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS");
lightoff(REDR);
lightoff(REDL);
light(GRNL);
light(GRNR);
state = S230_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_STRAIGHT;
break;
case S230_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_STRAIGHT:
printMessage1("Now in Case Start - S230_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_STRAIGHT - Exited Crossing");
if (pushed(TRKDA)) {
state = S080_TRKDA_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(TRKDC)) {
state = S160_TRKDC_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(TRKDD)) {
state = S240_TRKDD_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(TRKDE)) {
state = S320_TRKDE_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(PBL)) {
state = S520_WAIT_BYPASS_PBL_RELEASE;
}
else if (pushed(PBR)) {
state = S420_WAIT_STRAIGHT_PBR_RELEASE;
}
else if (pushed(PBW)) {
state = S600_WAIT_BYPASS_BREEZEWAY_PBW_RELEASE;
}
break;
/*****************************************************
* TRKDD
*
*
*
****************************************************/
case S240_TRKDD_CAPTURE_WITHOUT_BUTTON:
printMessage1("Now in Case Start - S240_TRKDD_CAPTURE_WITHOUT_BUTTON - MOVE_SWITCH_STRAIGHT - Lights & Motor to Straight/Right");
lightoff(YELL);
lightoff(YELR);
lightoff(GRNL); //Added 07/22/2023
lightoff(GRNR); //Added 8/19
light(REDR); //added 07/22/2023
//motor(RIGHT, ON); // Move switch to right
//delay(MOTORDELAYMS);
//motor(RIGHT, OFF) ;
lightoff(REDL);
light(YELL);
state = S250_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_PRESENT_STRAIGHT;
break;
case S250_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_PRESENT_STRAIGHT:
printMessage1("Now in Case Start - S250_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_PRESENT_STRAIGHT - In Crossing");
lightoff(GRNR);
light(YELL);
light(REDR);
//crossinglights(2, 0, 300);
if (!pushed(TRKDD)) {
//state = S300_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS;
state = S260_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_WAIT;
}
break;
/*************************************************
************************************************/
case S260_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_WAIT:
printMessage1("Now in Case Start - S260_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_WAIT - In Crossing");
if (pushed(TRKDD)) {
state = S240_TRKDD_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(TRKDA)) {
//crossinglights(2, 0, 300);
state = S270_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDA;
}
else if (pushed(TRKDC)) {
//crossinglights(2, 0, 300);
state = S280_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDC;
}
else if (pushed(TRKDE)) {
//crossinglights(2, 0, 300);
state = S290_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDE;
}
break;
case S270_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDA:
if (!pushed(TRKDA)) {
lightoff(REDR);
lightoff(YELL);
state = S140_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS;
}
break;
case S280_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDC:
if (!pushed(TRKDC)) {
lightoff(YELL);
state = S220_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS;
}
break;
case S290_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDE:
if (!pushed(TRKDE)) {
lightoff(YELL);
//state = S380_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS;
state = S070_STRAIGHT_ALL_GREEN_WAIT;
}
break;
case S300_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS:
printMessage1("Now in Case Start - S300_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS");
lightoff(YELL);
lightoff(REDR);
light(GRNL);
light(GRNR);
state = S310_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_STRAIGHT;
break;
case S310_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_STRAIGHT:
printMessage1("Now in Case Start - S310_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_STRAIGHT - Exited Crossing");
if (pushed(TRKDD)) {
state = S240_TRKDD_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(TRKDC)) {
state = S160_TRKDC_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(TRKDE)) {
state = S320_TRKDE_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(TRKDA)) {
state = S080_TRKDA_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(PBL)) {
state = S520_WAIT_BYPASS_PBL_RELEASE;
}
else if (pushed(PBR)) {
state = S420_WAIT_STRAIGHT_PBR_RELEASE;
}
else if (pushed(PBW)) {
state = S600_WAIT_BYPASS_BREEZEWAY_PBW_RELEASE;
}
break;
/****************************************************
* TRKDE
*
* This section addresses train detection on TRKDE (Track leading towars yard traveling
* West. This section was originally created to detect train when system first starts up
* and no other condition has changed.
*
*
*****************************************************/
case S320_TRKDE_CAPTURE_WITHOUT_BUTTON:
printMessage1("Now in Case Start - S320_TRKDE_CAPTURE_WITHOUT_BUTTON - MOVE_SWITCH_STRAIGHT - Lights & Motor to Straight/Right");
lightoff(YELL);
lightoff(YELR);
lightoff(GRNL);
lightoff(GRNR);
lightoff(REDR);
light(REDL);
light(REDR); //changed from YELR on 9/23 by Robby M
state = S330_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_PRESENT_STRAIGHT;
break;
case S330_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_PRESENT_STRAIGHT:
printMessage1("Now in Case Start - S330_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_PRESENT_STRAIGHT - In Crossing");
//crossinglights(2, 0, 300);
if (!pushed(TRKDE)) {
//state = S380_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS;
state = S340_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_WAIT;
}
break;
case S340_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_WAIT:
printMessage1("Now in Case Start - S340_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_WAIT - In Crossing");
if (pushed(TRKDE)) {
state = S320_TRKDE_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(TRKDA)) {
//crossinglights(2, 0, 300);
state = S350_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDA;
}
else if (pushed(TRKDC)) {
//crossinglights(2, 0, 300);
state = S360_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDC;
}
else if (pushed(TRKDD)) {
//crossinglights(2, 0, 300);
state = S370_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDD;
}
break;
case S350_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDA:
if (!pushed(TRKDA)) {
lightoff(REDR);
lightoff(YELL);
state = S140_TRKDA_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS;
}
break;
case S360_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDC:
if (!pushed(TRKDC)) {
lightoff(YELR);
state = S220_TRKDC_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS;
}
break;
case S370_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_IN_TRKDD:
if (!pushed(TRKDD)) {
lightoff(REDL);
lightoff(YELR);
state = S300_TRKDD_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS;
}
break;
case S380_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS:
printMessage1("Now in Case Start - S380_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_LIGHTS");
lightoff(REDL);
lightoff(REDR);
lightoff(YELR);
light(GRNL);
light(GRNR);
state = S390_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_STRAIGHT;
break;
case S390_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_STRAIGHT:
printMessage1("Now in Case Start - S390_TRKDE_CAPTURE_WITHOUT_BUTTON_TRAIN_CLEAR_STRAIGHT - Exited Crossing");
if (pushed(TRKDE)) {
state = S320_TRKDE_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(TRKDC)) {
state = S160_TRKDC_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(TRKDD)) {
state = S240_TRKDD_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(TRKDA)) {
state = S080_TRKDA_CAPTURE_WITHOUT_BUTTON;
}
else if (pushed(PBL)) {
state = S520_WAIT_BYPASS_PBL_RELEASE;
}
else if (pushed(PBR)) {
state = S420_WAIT_STRAIGHT_PBR_RELEASE;
}
else if (pushed(PBW)) {
state = S600_WAIT_BYPASS_BREEZEWAY_PBW_RELEASE;
}
break;
/********************************
*
* This section should address trains moving straight from West to East towards
* inner loop
*
********************************/
case S400_MOVE_SWITCH_STRAIGHT:
//Move switch motor to right (Straight for station), change lights to indicate which direction is safe to travel
printMessage1("Now in Case S400_MOVE_SWITCH_STRAIGHT - Lights & Motor to Right");
lightoff(YELR);
lightoff(GRNR);
light(REDR);
motor(RIGHT, ON); // Move switch to right
delay(MOTORDELAYMS);
motor(RIGHT, OFF);
light(REDL);
lightoff(REDR);
light(GRNR);
// light(YELR);
lightoff(YELL);
lightoff(YELR);
state = S410_WAIT_STRAIGHT;
break;
case S410_WAIT_STRAIGHT:
//Wait for next input from either Crossing, PBR, or PBL
printMessage1("Now in Case S410_WAIT_STRAIGHT - waiting for TRKDA, PBR, PBL, PBW");
if (pushed(PBR)) {
state = S420_WAIT_STRAIGHT_PBR_RELEASE;
//Button pushed and move to next action.
//Block capture is complete and track dection enabled lights and bell
}
else if (pushed(PBL)) {
state = S520_WAIT_BYPASS_PBL_RELEASE;
}
/**************************
else if(pushed(PBW))
{
state = S600_WAIT_BYPASS_BREEZEWAY_PBW_RELEASE;
}
*****************/
else if (pushed(TRKDA)) {
state = S430_TRAIN_PRESENT_STRAIGHT;
}
/*******************************
else if(pushed(TRKDC))
{
state = S690_TRAIN_TRAVELING_WEST_EAST_ON_STRAIGHT;
}
else if(pushed(TRKDD))
{
state = S060_STRAIGHT_ALL_GREEN;
}
**********************************/
break;
case S420_WAIT_STRAIGHT_PBR_RELEASE:
//Once PBR is pushed wait until it is released to change lights and move the switch motor
printMessage1("S420_WAIT_STRAIGHT_PBR_RELEASE");
lightoff(GRNL);
lightoff(YELL);
light(REDL);
if (!pushed(PBR)) {
state = S400_MOVE_SWITCH_STRAIGHT;
}
break;
case S430_TRAIN_PRESENT_STRAIGHT:
//TRAIN Traveling from TRKDA into Crossing traveling West to East
printMessage1("Now in Case Start - S430_TRAIN_PRESENT_STRAIGHT - In Crossing");
lightoff(GRNR);
light(YELR);
light(REDL);
//crossinglights(2, 0, 300);
/*
if (!pushed(TRKDC) && !pushed(TRKDD)) {
state = S440_TRAIN_CLEAR_STRAIGHT;
}
*/
if (pushed(TRKDC)) {
state = S460_TRAIN_IN_SWITCH_STRAIGHT;
}
else if (pushed(TRKDD)) {
state = S450_TRAIN_IN_WRONG_SWITCH_4_STRAIGHT;
light(REDR); //reset signal head so REDR turns on, REDL is already on
lightoff(YELR); //reset signal head and turn YELR off. Tells Engineer to stop and not proceed switch is about to move
}
break;
case S440_TRAIN_CLEAR_STRAIGHT:
printMessage1("Now in Case Start - S440_TRAIN_CLEAR_STRAIGHT - Exited Crossing");
if (pushed(TRKDA))
{
state = S460_TRAIN_IN_SWITCH_STRAIGHT;
}
else if (!pushed(TRKDC))
{
state = S060_STRAIGHT_ALL_GREEN;
}
else if (pushed(TRKDD)) {
//state = S450_TRAIN_IN_WRONG_SWITCH_4_STRAIGHT;
//printMessage3("State changed to S450_TRAIN_IN_WRONG_SWITCH_4_STRAIGHT;");
state = S060_STRAIGHT_ALL_GREEN;
}
break;
case S450_TRAIN_IN_WRONG_SWITCH_4_STRAIGHT:
//Train entered straight unexpectedly and once train clears will reset the signal heads and switch motor to straight state
printMessage1("Now in Case Start - S450_TRAIN_IN_WRONG_SWITCH_4_STRAIGHT");
if (!pushed(TRKDD)) {
// light(REDR); //reset signal head so REDR turns on, REDL is already on
// lightoff(YELR); //reset signal head and turn YELR off. Tells Engineer to stop and not proceed switch is about to move
//state = S500_MOVE_SWITCH_BYPASS;
state = S070_STRAIGHT_ALL_GREEN_WAIT;
}
break;
case S460_TRAIN_IN_SWITCH_STRAIGHT:
printMessage1("Now in Case Start - S460_TRAIN_IN_SWITCH_STRAIGHT");
//lightoff(YELR);
//lightoff(REDR);
//light(GRNR);
if (!pushed(TRKDC)) {
state = S070_STRAIGHT_ALL_GREEN_WAIT;
}
break;
case S470_TRAIN_IN_SWITCH_STRAIGHT_ERROR:
printMessage1("Now in Case Start - S470_TRAIN_IN_SWITCH_STRAIGHT_ERROR");
if (!pushed(TRKDD)) {
state = S500_MOVE_SWITCH_BYPASS;
}
break;
/************************************************************
* TRAIN IN BYPASS SECTION OF TRACK
*
************************************************************/
case S480_BYPASS_ALL_GREEN:
//Change signals to ALL GREEN.
printMessage1("Now in Case Start - S480_BYPASS_ALL_GREEN");
lightoff(REDL);
lightoff(YELL);
lightoff(REDR);
lightoff(YELR);
light(GRNL);
light(GRNR);
state = S490_BYPASS_ALL_GREEN_WAIT;
break;
case S490_BYPASS_ALL_GREEN_WAIT:
//Wait for next input from either Crossing, PBR, or PBL
printMessage1("Now in Case S490_BYPASS_ALL_GREEN_WAIT - waiting for TRKDA, TRKDE, PBR, PBL, PBW");
if (pushed(TRKDA)) {
state = S430_TRAIN_PRESENT_STRAIGHT;
}
else if (pushed(PBR)) {
state = S420_WAIT_STRAIGHT_PBR_RELEASE;
}
else if (pushed(PBL)) {
state = S520_WAIT_BYPASS_PBL_RELEASE;
}
else if (pushed(PBW)) {
state = S600_WAIT_BYPASS_BREEZEWAY_PBW_RELEASE;
}
else if (pushed(TRKDE)) {
state = S400_MOVE_SWITCH_STRAIGHT;
}
else if (pushed(TRKDC)) {
state = S690_TRAIN_TRAVELING_WEST_EAST_ON_STRAIGHT;
}
break;
case S500_MOVE_SWITCH_BYPASS:
printMessage1("Now in Case Start - S500_MOVE_SWITCH_BYPASS");
lightoff(YELL);
lightoff(GRNL); //added 8/19
light(REDL);
motor(LEFT, ON); // Move switch to left
delay(MOTORDELAYMS);
motor(LEFT, OFF);
light(REDL); //Changed from REDR to REDL 07/21/2023
lightoff(REDR); //Changed from REDL to REDR 07/21/2023
light(GRNR); //Changed from GRNL to GRNR 07/21/2023
lightoff(YELR); //Changed from YELL to YELR 07/21/2023
state = S510_WAIT_BYPASS;
break;
case S510_WAIT_BYPASS:
printMessage1("Now in Case Start - WAIT_BYPASS - waiting for TRKDA, PBR, PBL");
if (pushed(TRKDA)) {
state = S530_TRAIN_PRESENT_BYPASS;
}
else if (pushed(PBL)) {
state = S520_WAIT_BYPASS_PBL_RELEASE;
}
else if (pushed(PBR)) {
state = S420_WAIT_STRAIGHT_PBR_RELEASE;
}
else if (pushed(PBW)) {
state = S600_WAIT_BYPASS_BREEZEWAY_PBW_RELEASE;
}
else if (pushed(TRKDD)) {
//state = S480_BYPASS_ALL_GREEN;
state = S560_TRAIN_IN_SWITCH_BYPASS;
}
else if (pushed(TRKDC)) {
state = S670_TRAIN_TRAVELING_WEST_EAST_ON_BYPASS;
}
break;
case S520_WAIT_BYPASS_PBL_RELEASE:
printMessage1("Now in Case Start - S520_WAIT_BYPASS_PBL_RELEASE");
lightoff(GRNR); //Added 8/19
lightoff(YELR);
light(REDR);
if (!pushed(PBL)) {
state = S500_MOVE_SWITCH_BYPASS;
}
break;
case S530_TRAIN_PRESENT_BYPASS:
printMessage1("Now in Case Start - S530_TRAIN_PRESENT_BYPASS");
lightoff(GRNL);
lightoff(GRNR); //Changed from GRNL to GRNR 07/21/2023
light(YELR); //Changed from YELL to YELR 07/21/2023
//light(REDR); //Changed from REDR to REDL 07/21/2023
//crossinglights(2, 0, 300);
if (pushed(TRKDC)) {
state = S450_TRAIN_IN_WRONG_SWITCH_4_STRAIGHT;
}
else if (pushed(TRKDD)) {
state = S560_TRAIN_IN_SWITCH_BYPASS;
}
break;
case S540_TRAIN_CLEAR_BYPASS:
printMessage1("Now in Case Start - S540_TRAIN_CLEAR_BYPASS");
if (pushed(TRKDA)) {
state = S560_TRAIN_IN_SWITCH_BYPASS;
}
else if (pushed(TRKDC)) {
state = S550_TRAIN_IN_WRONG_SWITCH_4_BYPASS;
}
else if (pushed(TRKDD)) {
//state = S480_BYPASS_ALL_GREEN; //added 07/21/2023
state = S070_STRAIGHT_ALL_GREEN_WAIT;
}
break;
case S550_TRAIN_IN_WRONG_SWITCH_4_BYPASS:
//Train entered bypass unexpectedly and once train clears will reset the signal heads and switch motor to bypass state
printMessage1("Now in Case Start - S550_TRAIN_IN_WRONG_SWITCH_4_BYPASS");
if (!pushed(TRKDC)) {
light(REDL);
//reset signal head so REDL turns on, REDR is already on
lightoff(YELL);
//reset signal head and turn YELL off. Tells Engineer to stop and not proceed switch is about to move
state = S400_MOVE_SWITCH_STRAIGHT;
}
break;
case S560_TRAIN_IN_SWITCH_BYPASS:
printMessage1("Now in Case Start - S560_TRAIN_IN_SWITCH_BYPASS");
//lightoff(YELR); //Changed from YELL to YELR 07/21/2023
//lightoff(REDR); //Changed from REDL to REDR 07/21/2023
//light(GRNR); //Changed GRNL to GRNR 07/21/2023
if (!pushed(TRKDD))
//if ((!pushed(TRKDD)) && (!pushed(TRKDC)))
{
//state = S510_WAIT_BYPASS;
state = S070_STRAIGHT_ALL_GREEN_WAIT;
}
break;
case S570_TRAIN_IN_SWITCH_BYPASS_ERROR:
printMessage1("Now in Case Start - S570_TRAIN_IN_SWITCH_BYPASS_ERROR");
if (!pushed(TRKDC)) {
state = S400_MOVE_SWITCH_STRAIGHT;
}
break;
/************************************************************
* TRAIN IN BYPASS_BREEZEWAY SECTION OF TRACK
*
************************************************************/
case S580_MOVE_SWITCH_BYPASS_BREEZEWAY:
printMessage1("Now in Case Start - S580_MOVE_SWITCH_BYPASS_BREEZEWAY");
lightoff(YELL);
lightoff(GRNL); //added 8/19
light(REDL);
//motor(LEFT, ON); // Move switch to left
delay(MOTORDELAYMS);
//motor(LEFT, OFF);
light(REDR);
lightoff(REDL);
light(GRNL);
lightoff(YELL); //added 8/19
light(GRNL); //added 8/19
state = S590_WAIT_BYPASS_BREEZEWAY;
break;
case S590_WAIT_BYPASS_BREEZEWAY:
printMessage1("Now in Case Start - S590_WAIT_BYPASS_BREEZEWAY - waiting for TRKDD, PBR, PBL, PBW");
/**********************
if(pushed(PBL))
{
state = S520_WAIT_BYPASS_PBL_RELEASE;
}
else if(pushed(PBR))
{
state = S420_WAIT_STRAIGHT_PBR_RELEASE;
}
else if(pushed(TRKDC))
{
state = S690_TRAIN_TRAVELING_WEST_EAST_ON_STRAIGHT;
}
*********************************/
if (pushed(TRKDD))
//After Capture Button (PBW) pushed wait for TRAIN to enter block.
//TRKDD indicates TRAIN has enter block and goes to next state
{
state = S610_TRAIN_PRESENT_BYPASS_BREEZEWAY;
}
else if (pushed(TRKDE)) {
state = S620_TRAIN_CLEAR_BYPASS_BREEZEWAY_ALL_GREEN;
}
break;
case S600_WAIT_BYPASS_BREEZEWAY_PBW_RELEASE:
printMessage1("Now in Case Start - S600_WAIT_BYPASS_BREEZEWAY_PBW_RELEASE");
lightoff(GRNR); //Added 8/19
lightoff(YELR);
light(REDR);
if (!pushed(PBW)) //Changed from PBL to PBW
{
state = S580_MOVE_SWITCH_BYPASS_BREEZEWAY;
}
break;
case S610_TRAIN_PRESENT_BYPASS_BREEZEWAY:
printMessage1("Now in Case Start - S610_TRAIN_PRESENT_BYPASS_Breezeway");
lightoff(REDL);
lightoff(YELL);
lightoff(GRNL);
lightoff(YELR);
lightoff(GRNR);
light(REDR);
light(YELL);
//crossinglights(2, 0, 300);
/*if (!pushed(TRKDD)) {
state = S630_TRAIN_CLEAR_BYPASS_BREEZEWAY;
}
else */
if (pushed(TRKDE)) {
state = S615_TRAIN_PRESENT_WESTBOUND_TO_YARD;
}
else if(pushed(TRKDA)) {
state = S616_TRAIN_PRESENT_WESTBOUND_TO_MAINLINE;
}
else if(pushed(TRKDC)) {
state = S617_TRAIN_PRESENT_U_TURN_EAST_LOOP;
}
break;
case S615_TRAIN_PRESENT_WESTBOUND_TO_YARD:
if(!pushed(TRKDE)) {
state = S070_STRAIGHT_ALL_GREEN_WAIT;
}
break;
case S616_TRAIN_PRESENT_WESTBOUND_TO_MAINLINE:
if(!pushed(TRKDA)) {
state = S070_STRAIGHT_ALL_GREEN_WAIT;
}
break;
case S617_TRAIN_PRESENT_U_TURN_EAST_LOOP:
if(!pushed(TRKDC)) {
state = S070_STRAIGHT_ALL_GREEN_WAIT;
}
break;
case S620_TRAIN_CLEAR_BYPASS_BREEZEWAY_ALL_GREEN:
//Change Signals to ALL GREEN. Waiting for input from Push Button or Track
//Added 07/09/2023
printMessage1("Now in Case Start - S620_TRAIN_CLEAR_BYPASS_BREEZEWAY_ALL_GREEN");
lightoff(REDL);
lightoff(YELL);
lightoff(REDR);
lightoff(YELR);
light(GRNL);
light(GRNR);
state = S630_TRAIN_CLEAR_BYPASS_BREEZEWAY;
break;
case S630_TRAIN_CLEAR_BYPASS_BREEZEWAY:
printMessage1("Now in Case Start - S630_TRAIN_CLEAR_BYPASS_BREEZEWAY");
if (pushed(PBR)) {
state = S420_WAIT_STRAIGHT_PBR_RELEASE;
}
else if (pushed(PBW)) {
state = S600_WAIT_BYPASS_BREEZEWAY_PBW_RELEASE;
}
else if (pushed(TRKDA)) {
state = S620_TRAIN_CLEAR_BYPASS_BREEZEWAY_ALL_GREEN;
}
else if (pushed(TRKDE)) {
state = S590_WAIT_BYPASS_BREEZEWAY;
}
else if (pushed(TRKDD)) {
state = S640_TRAIN_IN_WRONG_SWITCH_4_BYPASS_BREEZEWAY;
}
break;
case S640_TRAIN_IN_WRONG_SWITCH_4_BYPASS_BREEZEWAY:
//Train entered bypass unexpectedly and once train clears will reset the signal heads and switch motor to bypass state
printMessage1("Now in Case Start - S640_TRAIN_IN_WRONG_SWITCH_4_BYPASS_BREEZEWAY");
if (!pushed(TRKDC)) {
light(REDL);
//reset signal head so REDL turns on, REDR is already on
lightoff(YELL);
//reset signal head and turn YELL off. Tells Engineer to stop and not proceed switch is about to move
state = S400_MOVE_SWITCH_STRAIGHT;
}
break;
case S650_TRAIN_IN_SWITCH_BYPASS_BREEZEWAY:
printMessage1("Now in Case Start - S650_TRAIN_IN_SWITCH_BYPASS_BREEZEWAY");
//lightoff(YELL);
//light(GRNL);
if (!pushed(TRKDE))
{
state = S610_TRAIN_PRESENT_BYPASS_BREEZEWAY;
}
break;
case S660_TRAIN_IN_SWITCH_BYPASS_ERROR_BREEZEWAY:
printMessage1("Now in Case Start - S660_TRAIN_IN_SWITCH_BYPASS_ERROR_BREEZEWAY");
if (!pushed(TRKDC)) {
state = S400_MOVE_SWITCH_STRAIGHT;
}
break;
/************************************************************
* TRAIN TRAVELING West to East on Straight
* Most likely from crossover
************************************************************/
case S670_TRAIN_TRAVELING_WEST_EAST_ON_BYPASS:
//Change Signals to ALL RED. Trains Traveling West to East on Straight Towards Yard
//Added 07/09/2023
printMessage1("Now in Case Start - S670_TRAIN_TRAVELING_WEST_EAST_ON_STRAIGHT");
lightoff(YELR);
lightoff(GRNR); //Added 8/19
light(REDR);
lightoff(YELL);
lightoff(GRNL); //Added 8/19
light(REDL);
state = S700_TRAIN_TRAVELING_WEST_EAST_ON_STRAIGHT_WAIT;
break;
case S680_TRAIN_TRAVELING_WEST_EAST_ON_BYPASS_WAIT:
//Wait for next input from either Crossing, PBR, or PBL
printMessage1("Now in Case S680_TRAIN_TRAVELING_WEST_EAST_ON_STRAIGHT_WAIT - waiting for TRKDA, TRKDE, PBR, PBL, PBW");
if (pushed(TRKDA)) {
state = S430_TRAIN_PRESENT_STRAIGHT;
}
else if (pushed(PBR)) {
state = S420_WAIT_STRAIGHT_PBR_RELEASE;
}
else if (pushed(PBL)) {
state = S520_WAIT_BYPASS_PBL_RELEASE;
}
else if (pushed(PBW)) {
state = S600_WAIT_BYPASS_BREEZEWAY_PBW_RELEASE;
}
else if (pushed(TRKDE)) {
//state = S400_MOVE_SWITCH_STRAIGHT;
state = S060_STRAIGHT_ALL_GREEN;
}
break;
/************************************************************
* TRAIN TRAVELING West to East on Straight
* Most likely from crossover
************************************************************/
case S690_TRAIN_TRAVELING_WEST_EAST_ON_STRAIGHT:
//Change Signals to ALL RED. Trains Traveling West to East on Straight Towards Yard
//Added 07/09/2023
printMessage1("Now in Case Start - S690_TRAIN_TRAVELING_WEST_EAST_ON_STRAIGHT");
lightoff(YELR);
lightoff(GRNR); //Added 8/19
light(REDR);
lightoff(YELL);
lightoff(GRNL); //Added 8/19
light(REDL);
//crossinglights(2, 0, 300);
state = S700_TRAIN_TRAVELING_WEST_EAST_ON_STRAIGHT_WAIT;
break;
case S700_TRAIN_TRAVELING_WEST_EAST_ON_STRAIGHT_WAIT:
//Wait for next input from either Crossing, PBR, or PBL
printMessage1("Now in Case S700_TRAIN_TRAVELING_WEST_EAST_ON_STRAIGHT_WAIT - waiting for TRKDA, TRKDE, PBR, PBL, PBW");
if (pushed(TRKDA)) {
state = S060_STRAIGHT_ALL_GREEN;
}
else if (pushed(PBR)) {
state = S420_WAIT_STRAIGHT_PBR_RELEASE;
}
else if (pushed(PBL)) {
state = S520_WAIT_BYPASS_PBL_RELEASE;
}
else if (pushed(PBW)) {
state = S600_WAIT_BYPASS_BREEZEWAY_PBW_RELEASE;
}
else if (pushed(TRKDE)) {
state = S060_STRAIGHT_ALL_GREEN;
}
else if (pushed(TRKDD)) {
state = S060_STRAIGHT_ALL_GREEN; //May need to change this but resets everything to green
}
else if (pushed(TRKDC)) {
state = S690_TRAIN_TRAVELING_WEST_EAST_ON_STRAIGHT; //Detect train
}
break;
case 999:
// Used to stop processing state machine
break;
default: // Error condition! Should never get here!!!!
Serial.println("State Machine 1 in DEFAULT - ERROR");
digitalWriteWrapper(REDL, HIGH);
digitalWriteWrapper(YELL, HIGH);
digitalWriteWrapper(GRNL, HIGH);
digitalWriteWrapper(REDR, HIGH);
digitalWriteWrapper(YELR, HIGH);
digitalWriteWrapper(GRNR, HIGH);
break;
} //End of switch (state)
switch(state3)
{
case S900_NO_TRAIN:
flash_enabled = NO;
if(pushed(TRKDA) || pushed(TRKDE)) {
state3 = S910_EASTBOUND_WON;
}
else if(pushed(TRKDC) || pushed(TRKDD)) {
state3 = S940_WESTBOUND_EON;
}
break;
case S910_EASTBOUND_WON:
flash_enabled = YES;
if(!pushed(TRKDA) && !pushed(TRKDE)) {
state3 = S920_EASTBOUND_WOFF;
}
break;
case S920_EASTBOUND_WOFF:
if(pushed(TRKDC) || pushed(TRKDD)) {
state3 = S930_EASTBOUND_EON;
} else if(pushed(TRKDA) || pushed(TRKDE))
{
state3 = S980_NOW_WB_WON;
}
break;
case S930_EASTBOUND_EON:
if(!pushed(TRKDC) && !pushed(TRKDD)) {
state3 = S900_NO_TRAIN;
}
break;
case S940_WESTBOUND_EON:
flash_enabled = YES;
if(!pushed(TRKDC) && !pushed(TRKDD)) {
state3 = S950_WESTBOUND_EOFF;
}
break;
case S950_WESTBOUND_EOFF:
if(pushed(TRKDA) || pushed(TRKDE)) {
state3 = S960_WESTBOUND_WON;
} else if(pushed(TRKDC) || pushed(TRKDD)) {
state3 = S970_NOW_EB_EON;
}
break;
case S960_WESTBOUND_WON:
if(!pushed(TRKDA) && !pushed(TRKDE)) {
state3 =S900_NO_TRAIN;
}
break;
case S970_NOW_EB_EON:
if(!pushed(TRKDC) && !pushed(TRKDD)) {
state3 = S900_NO_TRAIN;
}
break;
case S980_NOW_WB_WON:
if(!pushed(TRKDA) && !pushed(TRKDE))
{
state3 = S900_NO_TRAIN;
}
break;
default:
Serial.println("State machine 3 in DEFAULT - ERROR");
break;
} // End of switch(state3)
/*-------------------------------------------------------------------------------
* This next section checks to see if there is no train detected by either the
* east or west detector and the flashing is on.
* If false it sets a variable (flash2_start_time) equal to the current
* millisecond counter
* If true it subtracts the flash2_start-time from the current millis value
* If that exceeds a preset time limit it turns off the flash.
-------------------------------------------------------------------------------*/
if(!pushed(TRKDA) && !pushed(TRKDC) &&
!pushed(TRKDD) &&!pushed(TRKDE) && flash_enabled == YES)
{
current_time = millis();
if(current_time - flash_start_time > flash_time_limit*1000)
{
state3 = S900_NO_TRAIN;
}
}
else
{
flash_start_time = millis(); // millis() Returns the number of
// milliseconds passed since the
// Arduino board began running the
// current program. This number will
// overflow (go back to zero), after
// approximately 50 days.
}
//} //End of While(1) The master state machines loop
} // void loop()
/************************************************************************
*
* Turn all lights on one side on for dly MS, then turn them off
*
************************************************************************/
void all(int side, int dly) {
if (side == LEFT) {
digitalWriteWrapper(REDL, HIGH);
digitalWriteWrapper(YELL, HIGH);
digitalWriteWrapper(GRNL, HIGH);
digitalWriteWrapper(GRDLTL, HIGH);
digitalWriteWrapper(BELL, HIGH);
delay(dly);
digitalWriteWrapper(REDL, LOW);
digitalWriteWrapper(YELL, LOW);
digitalWriteWrapper(GRNL, LOW);
digitalWriteWrapper(GRDLTL, LOW);
digitalWriteWrapper(BELL, LOW);
}
if (side == RIGHT) {
digitalWriteWrapper(REDR, HIGH);
digitalWriteWrapper(YELR, HIGH);
digitalWriteWrapper(GRNR, HIGH);
digitalWriteWrapper(GRDLTR, HIGH);
digitalWriteWrapper(BELL, HIGH);
delay(dly);
digitalWriteWrapper(REDR, LOW);
digitalWriteWrapper(YELR, LOW);
digitalWriteWrapper(GRNR, LOW);
digitalWriteWrapper(GRDLTR, LOW);
digitalWriteWrapper(BELL, LOW);
}
} // void all(int side, int dly)
/************************************************************************
*
* Turn the motor actuator on or off in the desired direction
*
************************************************************************/
void motor(int side, int action) {
if (side == LEFT) {
digitalWriteWrapper(MOTORL, action);
}
if (side == RIGHT) {
digitalWriteWrapper(MOTORR, action);
}
} // void motor(int side, int action)
/************************************************************************
*
* Turn on 'which' light
*
************************************************************************/
void light(int which) {
digitalWriteWrapper(which, HIGH);
} // void light(int which)
/************************************************************************
*
* Turn off 'which' light
*
************************************************************************/
void lightoff(int which) {
digitalWriteWrapper(which, LOW);
} // void lightoff(int which)
/************************************************************************
*
* Is button pushed return true or false
*
************************************************************************/
int pushed(int button) {
return (digitalRead(button) == PUSHED);
} // int pushed(int button)
/************************************************************************
*
* Blinks which light count times each on or off is duration long
*
************************************************************************/
void blinker(int count, int which, int duration) {
for (int i = 0; i < count; i++) // Blink code
{
light(which);
delay(duration);
lightoff(which);
delay(duration);
}
} // void blinker(int count, int which, int duration)
/**********************************************************
*
* Section to cause grade crossing lights to flash
*
* ********************************************************/
void flasher(int count, int which, int duration) {
for (int i = 0; i < count; i++) // Blink code
{
light(GRDLTL);
delay(duration);
lightoff(GRDLTL);
delay(duration);
light(GRDLTR);
delay(duration);
lightoff(GRDLTR);
delay(duration);
}
} // void blinker(int count, int which, int duration)
/*********************************************************
* Section to actuate bell
* 6/21/2021- Added Lights and Bell together so they are in sync
*********************************************************/
void crossinglights(int count, int which, int duration) {
for (int i = 0; i < count; i++) // Blink code
{
/****Temporary green light on / off for grass crossing simulation
light(GRNL);
delay(duration);
lightoff(GRNL);
light(GRNR);
delay(duration);
lightoff(GRNR);
light(GRNL);
delay(duration);
lightoff(GRNL);
light(GRNR);
delay(duration);
lightoff(GRNR);
***************/
/*
digitalWriteWrapper(BELL, HIGH);
light(GRDLTL);
delay(duration);
digitalWriteWrapper(BELL, LOW);
lightoff(GRDLTL);
light(GRDLTR);
delay(duration);
digitalWriteWrapper(BELL, HIGH);
light(GRDLTL);
lightoff(GRDLTR);
delay(duration);
digitalWriteWrapper(BELL, LOW);
lightoff(GRDLTL);
light(GRDLTR);
delay(duration);
lightoff(GRDLTR);
*/
}
} // void blinker(int count, int which, int duration)
/* This is the Interrupt Service Routine that gets called each time the timer
generates an interrupt
*/
//With the settings above, this ISR will trigger each 665ms.
ISR(TIMER1_COMPA_vect){
TCNT1 = 0; //First, set the timer back to 0 so it resets for next interrupt
//LED_STATE = !LED_STATE; //Invert LED state
//digitalWrite(13,LED_STATE); //Write new state to the LED on pin D5
// If we are supposed to be flashing
if(master_flash_enabled)
{
already_off = NO;
// If the next side to flash is right
if(nextside == RIGHT)
{
// Turn on the right light
light(GRDLTR);
// Turn off the left light
lightoff(GRDLTL);
// Set the next indicator so next time we will do the left side
nextside = LEFT;
light(BELL);
}
else // nextside was left
{
// Turn the left light on
light(GRDLTL);
// Turn the right side off
lightoff(GRDLTR);
// Set the next indicator so next time we will do the right side
nextside= RIGHT;
lightoff(BELL);
}
}
else // If the lights aren't supposed to be flashing turn them off
{ // And set the next indicator so we always start on right side
if(already_off == NO)
{
lightoff(GRDLTL);
lightoff(GRDLTR);
lightoff(BELL);
nextside = RIGHT;
already_off = YES;
}
}
}
/*************************************************
* Print to monitor to see what section is active
*
*************************************************/
void printMessage(char * message, int msgnumber) {
static int oldmsgnumber = 0;
if (msgnumber != oldmsgnumber) {
Serial.println(message);
oldmsgnumber = msgnumber;
}
}
/*************************************************
* Print to monitor to see what section is active
*
*************************************************/
void printMessage1(char * message) {
static char oldmsg[256] = {
0
}; // Create a 256 character buffer space and set it to empty
if (ENABLEprintMessage1 == 1) {
if (strcmp(message, oldmsg) != 0) // If the new message is not the same as the old message
{
Serial.print("Elapsed time since last action: ");
unsigned long elapsedtime = millis() / 1000L; // Convert to seconds
unsigned long minutes = elapsedtime / 60L; // Extract minutes
unsigned long seconds = elapsedtime % 60L; // Extract leftover seconds (% is modulus or remainder operator)
Serial.print(minutes);
Serial.print(":");
Serial.print(seconds);
Serial.print(" ==> ");
Serial.println(message); // Print it
strcpy(oldmsg, message); // Copy it as old message
}
}
}
/*************************************************
* Print to monitor to see what section is active
*
*************************************************/
void printMessage2(char * message) {
static char oldmsg[256] = {
0
}; // Create a 256 character buffer space and set it to empty
if (ENABLEprintMessage1 == 1) {
if (strcmp(message, oldmsg) != 0) // If the new message is not the same as the old message
{
Serial.print("Elapsed time since last action: ");
unsigned long elapsedtime = millis() / 1000L; // Convert to seconds
unsigned long minutes = elapsedtime / 60L; // Extract minutes
unsigned long seconds = elapsedtime % 60L; // Extract leftover seconds (% is modulus or remainder operator)
Serial.print(minutes);
Serial.print(":");
Serial.print(seconds);
Serial.print(" ==> ");
Serial.println(message); // Print it
strcpy(oldmsg, message); // Copy it as old message
}
}
}
void digitalWriteWrapper(int pin, int val) {
if (DIGITALTRACE == 1) {
Serial.print("Digital Write:");
Serial.print(pin);
Serial.print(" ");
Serial.println(val);
}
digitalWrite(pin, val);
}