/* To Do
clean up code
update resistor values
*/
#define MaxTrains 3
#define MaxBlocks 10
#define PinOffset 4 // offset from first block to first LED pin
// starting block - 1 (arrays are zero based)
#define StartingBlock 6
#define MainStreetBlock 9
#define StationTime 120 // time in station
#define ADADelay 60 // time to add to station time for a ADA load
#define ADADelayPercent 90 // what percent of time we hit an ADA load
// time in each block
int block_time[10] = {30,30+StationTime, 30, 30,StationTime,30,30,StationTime,60,StationTime}; // time in seconds for each block
struct trainData {
uint8_t current_block;
uint8_t time_in_block; // remaining time in block. May be altered by occupied blocks ahead
uint8_t laps;
bool running;
// name
};
trainData trains[MaxTrains]; // create trains
struct blockData {
bool occupied;
uint8_t next_block;
uint8_t travel_time; //track speed through block in seconds
};
blockData blocks[MaxBlocks]; // create blocks
void setup() {
// put your setup code here, to run once:
int i;
// Initialize random number generator
randomSeed(analogRead(0));
// fill in time per block, next block and setup LED pins
for(i=0; i <MaxBlocks; i++){
blocks[i].travel_time = block_time[i];
blocks[i].next_block = i+1; // set next block
pinMode(i+PinOffset, OUTPUT); // define LED Pins
}
// set last block to point to the first
blocks[MaxBlocks-1].next_block = 0;
// create first train
// set train starting block and speed, set block to occupied
trains[0].current_block = StartingBlock;
trains[0].time_in_block = blocks[StartingBlock].travel_time;
trains[0].running = true;
digitalWrite(StartingBlock+PinOffset, HIGH);
Serial.begin(115200);
Serial.print("Train 1 ");
Serial.print("Block ");
Serial.println(StartingBlock+1);
}
void loop() {
// put your main code here, to run repeatedly:
int i;
delay(50); // should be 1000ms for real time operation
for(i=0; i < MaxTrains; i++){
// if the train is running and doesn't have a red light
if(trains[i].running && (blocks[blocks[trains[i].current_block].next_block].occupied == false)){
trains[i].time_in_block = trains[i].time_in_block - 1; // decrement our time in this block
if (trains[i].time_in_block == 0){
blocks[trains[i].current_block].occupied = false; // mark current block free
digitalWrite(trains[i].current_block+PinOffset, LOW); // Turn off LED
trains[i].current_block = blocks[trains[i].current_block].next_block; // increment to the next block
blocks[trains[i].current_block].occupied = true;
digitalWrite(trains[i].current_block+PinOffset, HIGH); // Turn on LED
trains[i].time_in_block = blocks[trains[i].current_block].travel_time;
// insert ADA delay?
if(( trains[i].current_block == 4) && (random(100) > 100 - ADADelayPercent)){
trains[i].time_in_block = trains[i].time_in_block + ADADelay;
Serial.print("Insert ADA Delay - Train ");
Serial.println(i+1);
}
//increment lap counter for each lap
if(trains[i].current_block == StartingBlock){
trains[i].laps = trains[i].laps +1;
}
Serial.print("Train ");
Serial.print(i+1);
Serial.print(" Block "); // show the first block
Serial.println(trains[i].current_block +1);
}
#if 0
Serial.print("Train ");
Serial.print(i+1);
Serial.print(" block time ");
Serial.println(trains[i].time_in_block);
#endif
}
else{
if(trains[i].running == true && blocks[blocks[trains[i].current_block].next_block].occupied){
Serial.print("Train ");
Serial.print(i+1);
Serial.println(" blocked");
}
// time to start next train? (if previous train has completed 1 lap and is at block 10)
if((trains[i-1].laps == 1) && (trains[i-1].current_block == MainStreetBlock)){
Serial.println("start next train");
trains[i].current_block = StartingBlock;
trains[i].time_in_block = blocks[StartingBlock].travel_time;
trains[i].running = true;
digitalWrite(StartingBlock+PinOffset, HIGH);
}
}
}
}