18 char prepare[] PROGMEM="!RACE PREPARE\n"; |
18 char prepare[] PROGMEM="!RACE PREPARE\n"; |
19 char countdownstart[] PROGMEM="!COUNTDOWN\n"; |
19 char countdownstart[] PROGMEM="!COUNTDOWN\n"; |
20 char racestart[] PROGMEM="!RACE START\n"; |
20 char racestart[] PROGMEM="!RACE START\n"; |
21 |
21 |
22 typedef union { |
22 typedef union { |
23 uint32_t u32; |
23 uint32_t value; |
24 uint16_t word[2]; // high, low word |
24 uint16_t word[2]; // high, low word |
25 uint8_t byte[4]; // all four bytes |
25 uint8_t byte[4]; // all four bytes |
26 } u32; |
26 } u32; |
|
27 |
|
28 #define MAX_SLOTS 6 |
|
29 typedef struct { |
|
30 uint8_t speedlimit, fuel, laps; |
|
31 uint16_t jumpstart_time; |
|
32 u32 lap_time_start, lap_time; |
|
33 } cardata; |
27 |
34 |
28 static unsigned char s[10]; |
35 static unsigned char s[10]; |
29 static uint8_t countdown, countdown_loops; |
36 static uint8_t countdown, countdown_loops; |
30 uint8_t mode = 0; |
37 uint8_t mode = 0; |
31 // valid race modes: |
38 // valid race modes: |
32 // 0: free drive / idle |
39 // 0: free drive / idle |
33 // 1: waiting for countdown start |
40 // 1: waiting for countdown start |
34 // 2: race countdown initiated |
41 // 2: race countdown initiated |
35 // 3: Race start condition |
42 // 3: Race start condition |
36 |
43 |
37 |
|
38 #define MAX_SLOTS 6 |
|
39 volatile u32 sysclk; |
44 volatile u32 sysclk; |
40 volatile uint8_t sysclk_packettimer = 0; |
45 volatile uint8_t sysclk_packettimer = 0; |
41 |
46 volatile cardata slot[MAX_SLOTS]; |
42 volatile uint8_t speedlimit[MAX_SLOTS]; |
|
43 volatile uint8_t fuel[MAX_SLOTS]; |
|
44 volatile uint16_t jumpstart_time[MAX_SLOTS]; |
|
45 |
|
46 volatile uint16_t lap_time_start_low[MAX_SLOTS]; |
|
47 volatile uint16_t lap_time_start_high[MAX_SLOTS]; |
|
48 volatile uint16_t lap_time_low[MAX_SLOTS]; |
|
49 volatile uint16_t lap_time_high[MAX_SLOTS]; |
|
50 |
47 |
51 volatile uint16_t car0, car1; |
48 volatile uint16_t car0, car1; |
52 volatile uint16_t car0_new, car0_old; |
49 volatile uint16_t car0_new, car0_old; |
53 volatile uint16_t car1_new, car1_old; |
50 volatile uint16_t car1_new, car1_old; |
54 uint8_t car0_state, car1_state; |
51 uint8_t car0_state, car1_state; |
117 |
114 |
118 case 'L': // Limit maximum speed for a car |
115 case 'L': // Limit maximum speed for a car |
119 tmp = buffer[2]-'0'; |
116 tmp = buffer[2]-'0'; |
120 if (tmp > 9) |
117 if (tmp > 9) |
121 tmp = buffer[2]-'A'+10; |
118 tmp = buffer[2]-'A'+10; |
122 speedlimit[buffer[1]-'0'] = tmp; |
119 slot[buffer[1]-'0'].speedlimit = tmp; |
123 RS232_puts_p(ok); |
120 RS232_puts_p(ok); |
124 break; |
121 break; |
125 |
122 |
126 case 'I': // get Information data (incl. important global parameter dump) |
123 case 'I': // get Information data (incl. important global parameter dump) |
127 RS232_puts(VERSION); |
124 RS232_puts(VERSION); |
128 RS232_putc(':'); |
125 RS232_putc(':'); |
129 for (tmp=0;tmp<MAX_SLOTS;tmp++) RS232_putc(speedlimit[tmp]); // output speed limits |
126 for (tmp=0;tmp<MAX_SLOTS;tmp++) RS232_putc(slot[tmp].speedlimit); // output speed limits |
130 RS232_putc(':'); |
127 RS232_putc(':'); |
131 for (tmp=0;tmp<MAX_SLOTS;tmp++) { |
128 for (tmp=0;tmp<MAX_SLOTS;tmp++) { |
132 itoa(fuel[tmp], s, 16); |
129 itoa(slot[tmp].fuel, s, 16); |
133 RS232_putc(s); // output fuel levels (0=empty, 100=full, 0xff=no fuel option) |
130 RS232_putc(s); // output fuel levels (0=empty, 100=full, 0xff=no fuel option) |
134 RS232_putc(','); |
131 RS232_putc(','); |
135 } |
132 } |
136 RS232_putc(':'); |
133 RS232_putc(':'); |
137 for (tmp=0;tmp<MAX_SLOTS;tmp++) { |
134 for (tmp=0;tmp<MAX_SLOTS;tmp++) { |
138 itoa(jumpstart_time[tmp], s, 16); |
135 itoa(slot[tmp].jumpstart_time, s, 16); |
139 RS232_puts(s); // output jumpstart times |
136 RS232_puts(s); // output jumpstart times |
140 RS232_putc(','); |
137 RS232_putc(','); |
141 } |
138 } |
142 RS232_putc(':'); |
139 RS232_putc(':'); |
143 RS232_putc('\n'); |
140 RS232_putc('\n'); |
173 uint16_t tmp = 0; |
170 uint16_t tmp = 0; |
174 switch (controller) { |
171 switch (controller) { |
175 case 0: |
172 case 0: |
176 if (mode!=1) tmp = ((getADC(CONTROLLER1_SPEED) / CONTROLLER_DIVISOR) & 0x0F); |
173 if (mode!=1) tmp = ((getADC(CONTROLLER1_SPEED) / CONTROLLER_DIVISOR) & 0x0F); |
177 if ((mode == 2) && (tmp != 0)) { jumpstart(controller); tmp = 0; } |
174 if ((mode == 2) && (tmp != 0)) { jumpstart(controller); tmp = 0; } |
178 if (tmp > speedlimit[controller]) tmp = speedlimit[controller]; |
175 if (tmp > slot[controller].speedlimit) tmp = slot[controller].speedlimit; |
179 tmp = tmp << 1; |
176 tmp = tmp << 1; |
180 if ( (PIN(CONTROLLER_PORT) & _BV(CONTROLLER1_SW)) != 0) { |
177 if ( (PIN(CONTROLLER_PORT) & _BV(CONTROLLER1_SW)) != 0) { |
181 tmp |= (1<<5); |
178 tmp |= (1<<5); |
182 if (mode == 0) LED(1,0); |
179 if (mode == 0) LED(1,0); |
183 } else if (mode == 0) LED(1,1); |
180 } else if (mode == 0) LED(1,1); |
184 break; |
181 break; |
185 case 1: |
182 case 1: |
186 if (mode!=1) tmp = ((getADC(CONTROLLER2_SPEED) / CONTROLLER_DIVISOR) & 0x0F); |
183 if (mode!=1) tmp = ((getADC(CONTROLLER2_SPEED) / CONTROLLER_DIVISOR) & 0x0F); |
187 if ((mode == 2) && (tmp != 0)) { jumpstart(controller); tmp = 0; } |
184 if ((mode == 2) && (tmp != 0)) { jumpstart(controller); tmp = 0; } |
188 if (tmp > speedlimit[controller]) tmp = speedlimit[controller]; |
185 if (tmp > slot[controller].speedlimit) tmp = slot[controller].speedlimit; |
189 tmp = tmp << 1; |
186 tmp = tmp << 1; |
190 if ( (PIN(CONTROLLER_PORT) & _BV(CONTROLLER2_SW)) != 0) { |
187 if ( (PIN(CONTROLLER_PORT) & _BV(CONTROLLER2_SW)) != 0) { |
191 tmp |= (1<<5); |
188 tmp |= (1<<5); |
192 if (mode == 0) LED(2,0); |
189 if (mode == 0) LED(2,0); |
193 } else if (mode == 0) LED(2,1); |
190 } else if (mode == 0) LED(2,1); |
194 break; |
191 break; |
195 case 2: |
192 case 2: |
196 if (mode!=1) tmp = ((getADC(CONTROLLER3_SPEED) / CONTROLLER_DIVISOR) & 0x0F); |
193 if (mode!=1) tmp = ((getADC(CONTROLLER3_SPEED) / CONTROLLER_DIVISOR) & 0x0F); |
197 if ((mode == 2) && (tmp != 0)) { jumpstart(controller); tmp = 0; } |
194 if ((mode == 2) && (tmp != 0)) { jumpstart(controller); tmp = 0; } |
198 if (tmp > speedlimit[controller]) tmp = speedlimit[controller]; |
195 if (tmp > slot[controller].speedlimit) tmp = slot[controller].speedlimit; |
199 tmp = tmp << 1; |
196 tmp = tmp << 1; |
200 if ( (PIN(CONTROLLER_PORT) & _BV(CONTROLLER3_SW)) != 0) { |
197 if ( (PIN(CONTROLLER_PORT) & _BV(CONTROLLER3_SW)) != 0) { |
201 tmp |= (1<<5); |
198 tmp |= (1<<5); |
202 if (mode == 0) LED(4,0); |
199 if (mode == 0) LED(4,0); |
203 } else if (mode == 0) LED(4,1); |
200 } else if (mode == 0) LED(4,1); |
204 break; |
201 break; |
205 case 3: |
202 case 3: |
206 if (mode!=1) tmp = ((getADC(CONTROLLER4_SPEED) / CONTROLLER_DIVISOR) & 0x0F); |
203 if (mode!=1) tmp = ((getADC(CONTROLLER4_SPEED) / CONTROLLER_DIVISOR) & 0x0F); |
207 if ((mode == 2) && (tmp != 0)) { jumpstart(controller); tmp = 0; } |
204 if ((mode == 2) && (tmp != 0)) { jumpstart(controller); tmp = 0; } |
208 if (tmp > speedlimit[controller]) tmp = speedlimit[controller]; |
205 if (tmp > slot[controller].speedlimit) tmp = slot[controller].speedlimit; |
209 tmp = tmp << 1; |
206 tmp = tmp << 1; |
210 if ( (PIN(CONTROLLER_PORT) & _BV(CONTROLLER4_SW)) != 0) { |
207 if ( (PIN(CONTROLLER_PORT) & _BV(CONTROLLER4_SW)) != 0) { |
211 tmp |= (1<<5); |
208 tmp |= (1<<5); |
212 if (mode == 0) LED(5,0); |
209 if (mode == 0) LED(5,0); |
213 } else if (mode == 0) LED(5,1); |
210 } else if (mode == 0) LED(5,1); |
273 |
270 |
274 // reset both car counters to overflow |
271 // reset both car counters to overflow |
275 car0_old = TIMER1_500NS; |
272 car0_old = TIMER1_500NS; |
276 car1_old = TIMER1_500NS; |
273 car1_old = TIMER1_500NS; |
277 |
274 |
278 sysclk.word[1]++; // increment 500ns timer low word |
275 sysclk.value++; // increment 500ns timer |
279 if (sysclk.word[1] == 0) sysclk.word[0]++; // increment upper 16bits |
|
280 } |
276 } |
281 |
277 |
282 ISR ( TIMER2_COMP_vect ) { |
278 ISR ( TIMER2_COMP_vect ) { |
283 //OCR2 = TIMER2_50US; // make sure that timer2 is 50µs !!! |
279 //OCR2 = TIMER2_50US; // make sure that timer2 is 50µs !!! |
284 // data packet timer 100µs pro bit... |
280 // data packet timer 100µs pro bit... |
389 } |
385 } |
390 |
386 |
391 void reset_vars(void) { |
387 void reset_vars(void) { |
392 uint8_t i; |
388 uint8_t i; |
393 for (i=0; i<MAX_SLOTS; i++) { |
389 for (i=0; i<MAX_SLOTS; i++) { |
394 if (i<4) speedlimit[i] = 15; else speedlimit[i] = 0; |
390 if (i<4) slot[i].speedlimit = 15; else slot[i].speedlimit = 0; |
395 fuel[i] = 100; |
391 slot[i].fuel = 100; |
396 jumpstart_time[i] = 0; |
392 slot[i].jumpstart_time = 0; |
397 } |
393 } |
398 sysclk.word[1] = 0; |
394 sysclk.value = 0; |
399 sysclk.word[0] = 0; |
|
400 } |
395 } |
401 |
396 |
402 void countdown_progress(void) { |
397 void countdown_progress(void) { |
403 // decrement COUNTDOWN_LOOPS |
398 // decrement COUNTDOWN_LOOPS |
404 if (countdown_loops>0) { |
399 if (countdown_loops>0) { |
412 case 4: LED(2, 1); break; |
407 case 4: LED(2, 1); break; |
413 case 3: LED(3, 1); break; |
408 case 3: LED(3, 1); break; |
414 case 2: LED(4, 1); break; |
409 case 2: LED(4, 1); break; |
415 case 1: LED(5, 1); break; |
410 case 1: LED(5, 1); break; |
416 case 0: { // RACE START! |
411 case 0: { // RACE START! |
417 sysclk.word[1] = 1; |
412 sysclk.value = 0; |
418 sysclk.word[0] = 0; |
|
419 LEDS_OFF(); |
413 LEDS_OFF(); |
420 LED(3, 1); |
414 LED(3, 1); |
421 mode = 3; |
415 mode = 3; |
422 } break; |
416 } break; |
423 } |
417 } |
424 } |
418 } |
425 |
419 |
426 void check_cars(void) { |
420 void check_cars(void) { |
427 uint16_t diff_low, diff_high; |
421 u32 clk, diff; |
|
422 clk.value = sysclk.value; // freeze system clock time |
428 |
423 |
429 if (car0 != car0_state) { |
424 if (car0 != car0_state) { |
430 car0_state = car0; |
425 car0_state = car0; |
431 if (car0_state != 0) { |
426 if (car0_state != 0) { |
432 diff_high = sysclk.word[0] - lap_time_start_high[car0-1]; |
427 diff.value = clk.value - slot[car0-1].lap_time_start.value; |
433 diff_low = sysclk.word[1] - lap_time_start_low[car0-1]; // this could be a bug ;) |
428 if ( diff.value > 3000 ) { // minimum 1.5 second for 1 lap! |
434 if ( (diff_high > 0) || (diff_low>2000) ) { // minimum 1 second for 1 lap! |
429 slot[car0-1].lap_time_start.value = clk.value; |
435 lap_time_start_low[car0-1] = sysclk.word[1]; |
430 slot[car0-1].lap_time.value = diff.value; |
436 lap_time_start_high[car0-1] = sysclk.word[0]; |
|
437 lap_time_low[car0-1] = diff_low; |
|
438 lap_time_high[car0-1] = diff_high; |
|
439 RS232_putc('L'); |
431 RS232_putc('L'); |
440 RS232_putc('A'); |
432 RS232_putc('A'); |
441 RS232_putc('0'+car0_state); |
433 RS232_putc('0'+car0_state); |
442 RS232_putc(':'); |
434 RS232_putc(':'); |
443 itoa(diff_high, s, 16); |
435 ultoa(diff.value, s, 16); |
444 RS232_puts(s); |
|
445 RS232_putc(','); |
|
446 itoa(diff_low, s, 16); |
|
447 RS232_puts(s); |
436 RS232_puts(s); |
448 RS232_putc('\n'); |
437 RS232_putc('\n'); |
449 } |
438 } |
450 } |
439 } |
451 } car0 = 0; |
440 } car0 = 0; |
452 |
441 |
453 if (car1 != car1_state) { |
442 if (car1 != car1_state) { |
454 car1_state = car1; |
443 car1_state = car1; |
455 if (car1_state != 0) { |
444 if (car1_state != 0) { |
456 diff_high = sysclk.word[0] - lap_time_start_high[car1-1]; |
445 diff.value = clk.value - slot[car1-1].lap_time_start.value; |
457 diff_low = sysclk.word[1] - lap_time_start_low[car1-1]; // this could be a bug ;) |
446 if ( diff.value > 3000 ) { // minimum 1.5 second for 1 lap! |
458 if ( (diff_high > 0) || (diff_low>2000) ) { // minimum 1 second for 1 lap! |
447 slot[car1-1].lap_time_start.value = clk.value; |
459 lap_time_start_low[car1-1] = sysclk.word[1]; |
448 slot[car1-1].lap_time.value = diff.value; |
460 lap_time_start_high[car1-1] = sysclk.word[0]; |
|
461 lap_time_low[car1-1] = diff_low; |
|
462 lap_time_high[car1-1] = diff_high; |
|
463 RS232_putc('L'); |
449 RS232_putc('L'); |
464 RS232_putc('B'); |
450 RS232_putc('B'); |
465 RS232_putc('0'+car1_state); |
451 RS232_putc('0'+car1_state); |
466 RS232_putc(':'); |
452 RS232_putc(':'); |
467 itoa(diff_high, s, 16); |
453 ultoa(diff.value, s, 16); |
468 RS232_puts(s); |
|
469 RS232_putc(','); |
|
470 itoa(diff_low, s, 16); |
|
471 RS232_puts(s); |
454 RS232_puts(s); |
472 RS232_putc('\n'); |
455 RS232_putc('\n'); |
473 } |
456 } |
474 } |
457 } |
475 } car1 = 0; |
458 } car1 = 0; |