4 Lane Pinewood Derby Track

So I am working on a DIY electronic timer for a pinewood derby track. I found a general 2 lane schematic and program from the Derby Talk forums: Will GP Software communicate with an Arduino? - Derby Talk
I believe I have made most of the necessary changes to use it for a 4 lane track. However, I am not a programmer, with a very rudimentary knowledge of programming. The timer will be utilizing the Arduino UNO. It will connect to a laptop via USB port and interface with the Grand Prix Race Manager v9 software: GrandPrix Race Manager . My inputs for the four lanes (1-4)will be landing on 11D, 10D, 03D, & 04D respectively. Here is the code I have modified:

/* Pinewood Derby Timer
 * By Jason Scholten
 Pinewood Derby timer that works with the GrandPrix Race Manager Software.
 See the "Read Me" file in the sketch folder for setup instructions.
*/

int ready = 13;           //Timer ready LED
int start = 12;           //Start gate switch
int fin1 = 11;            //Lane 1 finish line detector
int fin2 = 10;            //Lane 2 finish line detector
int fin1 = 3;             //Lane 3 finish line detector
int fin2 = 4;             //Lane 4 finish line detector
int reset = 9;            //Reset switch
int lane1win = 8;         //Lane 1 win LED
int lane2win = 7;         //Lane 2 win LED
int timing = 6;           //"timing" LED
int finished = 5;         //Red finished LED

int time1 = 0;             //lane 1 raw timing data
int time2 = 0;             //lane 2 raw timing data
int time3 = 0;             //lane 3 raw timing data
int time4 = 0;             //lane 4 raw timing data
int winner = 0;            //winner light bit
int startpush = LOW;       //start button status
int starttime = 0;         //start time in millis
int rss = HIGH;            //reset button status
int fnl1;                  //lane 1 lane detector status
int fnl2;                  //lane 2 lane detector status
int fnl3;                  //lane 3 lane detector status
int fnl4;                  //lane 4 lane detector status
int running = 0;           //track timing status bit
int fractional1;           //lane 1 timing display interger
int fractional2;           //lane 2 timing display interger
int fractional3;           //lane 3 timing display interger
int fractional4;           //lane 4 timing display interger
int lane1 = 0;             //lane 1 finish
int lane2 = 0;             //lane 2 finish
int lane3 = 0;             //lane 3 finish
int lane4 = 0;             //lane 4 finish
int crss = 0;              //computer reset
int force = 0;             //force data send

void setup()
{  
  pinMode(timing, OUTPUT);
  pinMode(start, INPUT);
  pinMode(fin1, INPUT);
  pinMode(fin2, INPUT);
  pinMode(fin3, INPUT);
  pinMode(fin4, INPUT);
  pinMode(reset, INPUT);
  pinMode(lane1win, OUTPUT);
  pinMode(lane2win, OUTPUT);
  pinMode(lane3win, OUTPUT);
  pinMode(lane4win, OUTPUT);
  pinMode(ready, OUTPUT);
  pinMode(finished, OUTPUT);
  
  digitalWrite(reset, HIGH);
  Serial.begin(9600);
}

void loop()
{
  if (Serial.available() > 0 && running == 0) {   //looks for initial reset from software
    crss = Serial.read();
  }
  
  rss = digitalRead(reset);                        //manual initial reset
  
  if (crss == 65 && running == 0 || rss == LOW && running == 0) {
    Serial.println("C");
    digitalWrite(ready, HIGH);
    running = 1;
    crss = 0;
    delay(100);
  }
    
  startpush = digitalRead(start);
  rss = digitalRead(reset);
  
  if (startpush == HIGH && rss == HIGH && running == 1 && crss == 0) {    //timer start
    starttime = millis();     
    digitalWrite(timing, HIGH);
    digitalWrite(ready, LOW);
    Serial.println("B");
    running = 2; 
    delay(100); 
  }
  
  fnl1 = digitalRead(fin1);                                  //timing on lane 1
  if (fnl1 == LOW && running == 2 && lane1 == 0) {
    time1 = millis() - starttime;
    lane1 = 1;
  }
    
  fnl2 = digitalRead(fin2);                                  //timing on lane 2
  if (fnl2 == LOW && running == 2 && lane2 == 0) {
    time2 = millis() - starttime;
    lane2 = 1;
  }

  fnl1 = digitalRead(fin1);                                  //timing on lane 3
  if (fnl3 == LOW && running == 2 && lane3 == 0) {
    time3 = millis() - starttime;
    lane3 = 1;
  }
    
  fnl2 = digitalRead(fin2);                                 //timing on lane 4
  if (fnl4 == LOW && running == 2 && lane4 == 0) {
    time4 = millis() - starttime;
    lane4 = 1;
  }
    
  if (lane1 == 1 && lane2 != 1 lane3 != 1 && lane4 != 1 && winner == 0) {  //winner lights lane 1
    digitalWrite(lane1win, HIGH);
    winner = 1;}
    
  if (lane1 != 1 && lane2 == 1 lane3 != 1 && lane4 != 1 && winner == 0) {  //winner lights lane 2
    digitalWrite(lane2win, HIGH);
    winner = 2;

  if (lane1 != 1 && lane2 != 1 lane3 == 1 && lane4 != 1 && winner == 0) {  //winner lights lane 3
    digitalWrite(lane3win, HIGH);
    winner = 3;}
    
  if (lane1 != 1 && lane2 != 1 lane3 != 1 && lane4 == 1 && winner == 0) {  //winner lights lane 4
    digitalWrite(lane4win, HIGH);
    winner = 4;
  }
    
  if (Serial.available() > 0 && running == 2) {        //Force Data Send detect       
    force = Serial.read();
  }
    
  if (force == 70 && lane1 == 1 && lane2 == 0 && lane3 == 0 && lane4 == 0 && running == 2) {  //forces lane 1 to quit timing
    lane2 = 1;lane3 = 1;lane4 = 1;
  }
  
  if (force == 70 && lane1 == 0 && lane2 == 1 && lane3 == 0 && lane4 == 0 && running == 2) {  //forces lane 2 to quit timing
    lane1 = 1;lane3 = 1;lane4 = 1;
  }

  if (force == 70 && lane1 == 0 && lane2 == 0 && lane3 == 1 && lane4 == 0 && running == 2) {  //forces lane 3 to quit timing
    lane1 = 1;lane2 = 1;lane4 = 1;
  }
  
  if (force == 70 && lane1 == 0 && lane2 == 0 && lane3 == 0 && lane4 == 1 && running == 2) {  //forces lane 4 to quit timing
    lane1 = 1;lane2 = 1;lane3 = 1;
  }
      
  if (lane1 == 1 && lane2 == 1 && running == 2) {
    digitalWrite(finished, HIGH);
    Serial.print("1 - ");                                  //serial print for lane 1
    Serial.print( (int) (time1 / 1000L));
    Serial.print(".");
    fractional1 = (int)(time1 % 1000L);
    if (fractional1 == 0)
      Serial.print("000");
    else if (fractional1 < 10)
      Serial.print("00");
    else if (fractional1 < 100)
      Serial.print("0");
    Serial.println(fractional1);
        
    Serial.print("2 - ");                                    //serial print for lane 2
    Serial.print( (int) (time2 / 1000L));
    Serial.print(".");
    fractional2 = (int)(time2 % 1000L);
    if (fractional2 == 0)
      Serial.print("000");
    else if (fractional2 < 10)
      Serial.print("00");
    else if (fractional2 < 100)
      Serial.print("0");
    Serial.println(fractional2);

    Serial.print("3 - ");                                    //serial print for lane 3
    Serial.print( (int) (time3 / 1000L));
    Serial.print(".");
    fractional3 = (int)(time3 % 1000L);
    if (fractional3 == 0)
      Serial.print("000");
    else if (fractional3 < 10)
      Serial.print("00");
    else if (fractional3 < 100)
      Serial.print("0");
    Serial.println(fractional3);
        
    Serial.print("4 - ");                                    //serial print for lane 4
    Serial.print( (int) (time4 / 1000L));
    Serial.print(".");
    fractional4 = (int)(time4 % 1000L);
    if (fractional4 == 0)
      Serial.print("000");
    else if (fractional4 < 10)
      Serial.print("00");
    else if (fractional4 < 100)
      Serial.print("0");
    Serial.println(fractional4);
    digitalWrite(timing, LOW);  

    running = 3;
  }
    
  if (Serial.available() > 0 && running == 3) {       //computer timer reset
    crss = Serial.read();
  }
  
  rss = digitalRead(reset);                             //manual timer reset
  
  if (crss == 65 && running == 3 || rss == LOW && running == 3) {
    starttime = 0;
    time1 = 0;
    time2 = 0;
    time3 = 0;
    time4 = 0;
    running = 4;
    lane1 = 0;
    lane2 = 0;
    lane3 = 0;
    lane4 = 0;
    winner = 0;
    digitalWrite(lane1win, LOW);
    digitalWrite(lane2win, LOW);
    digitalWrite(lane3win, LOW);
    digitalWrite(lane4win, LOW);
    digitalWrite(finished, LOW);
    digitalWrite(ready, HIGH);
    crss = 0;
    y = 0;
    Serial.flush();
  } 
  
  if (crss == 0 && running == 4) {                       //serial ready status
    Serial.print("C");
    running = 1;
  }
}

The section I am most unsure about is in the middle where it talks about forcing Lane 1-4 to quit timing. I am not sure if I made the additions of Lanes 3 and 4 correctly. The original code and schematic can be found here : grandprix-race-central.com/modules.php?name=Downloads&d_op=getit&lid=23
Any feedback and advice would be most appreciated, thanks.

You have the internal pull-up resistor enabled for the reset switch, but not the start switch. Why is that?

  if (Serial.available() > 0 && running == 0) {   //looks for initial reset from software

For timing applications, speed is critical. The status of running is quick to check. The availability of serial data is not. The status of running should be tested first. If running is not 0, there is then no reason to make the function call to test for serial data. Therefore, the if test evaluates much faster.

  if (crss == 65 && running == 0 || rss == LOW && running == 0) {

In this code, you may need to evaluate running twice.

if(running == 0 && (rss == LOW || crss == 'A')

This code only evaluates running once, and performs the test in the likely-to-be-true order. In general, how often is crss likely to be true? Your test has that evaluation performed first, when it is the least likely to be true evaluation.

65 may mean something to you today. Two weeks from now, probably not. Checking for crss equal to 'A' is the same as checking for it equal to 65, but in the future, it is more likely that you will remember that 'A' means the letter A than you are to remember that 65 means the letter A.

  [glow]rss = digitalRead(reset);[/glow]                        //manual initial reset
  
  if (crss == 65 && running == 0 || rss == LOW && running == 0) {
    // ... snipped some stuff
  }
    
  startpush = digitalRead(start);
  [glow]rss = digitalRead(reset);[/glow]

How fast can you push the reset button? It is highly unlikely that rss will change.

  if (startpush == HIGH && rss == HIGH && running == 1 && crss == 0) {    //timer start

Does the value in crss really matter?

  fnl1 = digitalRead(fin1);                                  //timing on lane 1
  if (fnl1 == LOW && running == 2 && lane1 == 0) {
    time1 = millis() - starttime;
    lane1 = 1;
  }
    
  fnl2 = digitalRead(fin2);                                  //timing on lane 2

No, no. Read all 4 finish pins right after each other. Then, evaluate the status of the race.
Also, record the value of millis() before you read the pins, rather than calling it several times after reading the pins.

  if (lane1 == 1 && lane2 != 1[glow] [/glow]lane3 != 1 && lane4 != 1 && winner == 0) {  //winner lights lane 1

You are missing an operator here, and in the following similar rows.

  if (lane1 == 1 && lane2 == 1 && running == 2) {

Lanes 3 and 4 no longer matter? Wouldn't want to be in one of those lanes.

Thats for the catch on the last 2 notes. As far as the others go, I did not write this program, I am simply trying to add 2 lanes to an existing 2 lane program. The orignal program is stated to work with 2 lanes when wired with the supplied schematic. I could not answer why the writer put somethings in one way or another, I am not a programmer.

My concern is that the program meets 3 criteria: Will it report back the order of lane compleation, Will it report back the time of compleation for each lane, and can it handle very close finishes or non finishes.

I will get those errors towrds the bottom fixed tonight. But once those are corrected, does it appear the program would meet my goals, or would additinal changes be mandatory for it to report on all four lanes?

Will it report back the order of lane compleation

No. It only determines the winner.

Will it report back the time of compleation for each lane

Yes (for the first two lanes as currently written).

can it handle very close finishes or non finishes.

Depending on your definition of very close, yes it can handle close finishes. The changes I suggested can help. So would not even concerning yourself with serial input while a race is underway.

How you should handle non-finishes is not clear.