implemented race prepare phase, countdown and jumpstart detection

Sat, 03 Dec 2011 16:42:53 +0100

author
Malte Bayer <mbayer@neo-soft.org>
date
Sat, 03 Dec 2011 16:42:53 +0100
changeset 37
136a79772098
parent 36
aea84f4f5a12
child 38
ff76255904c4

implemented race prepare phase, countdown and jumpstart detection

blackbox/lowlevel.c file | annotate | diff | comparison | revisions
blackbox/lowlevel.h file | annotate | diff | comparison | revisions
blackbox/main.c file | annotate | diff | comparison | revisions
blackbox/main.h file | annotate | diff | comparison | revisions
--- a/blackbox/lowlevel.c	Sat Dec 03 14:25:06 2011 +0100
+++ b/blackbox/lowlevel.c	Sat Dec 03 16:42:53 2011 +0100
@@ -45,6 +45,14 @@
     }
 }
 
+void LEDS_OFF(void) {
+    LED1_PORT &= ~_BV(LED1);
+    LED2_PORT &= ~_BV(LED1);
+    LED3_PORT &= ~_BV(LED1);
+    LED4_PORT &= ~_BV(LED1);
+    LED5_PORT &= ~_BV(LED1);
+}
+
 void init_hardware(void) {
     // reset all ports to input, no pullup
     DDRA = 0; PORTA = 0;
@@ -110,7 +118,9 @@
     OCR1A = TIMER1_7500NS;
     TIMSK |= 1<<OCIE1A; //enable timer1 interrupt
 
-    RS232_puts_p(PSTR("FreeSlot Blackbox v1.0\n"));
+    RS232_puts_p(PSTR("FreeSlot Blackbox v"));
+    RS232_puts(VERSION);
+    RS232_putc('\n');
 
 }
 
--- a/blackbox/lowlevel.h	Sat Dec 03 14:25:06 2011 +0100
+++ b/blackbox/lowlevel.h	Sat Dec 03 16:42:53 2011 +0100
@@ -3,6 +3,7 @@
 #include "main.h"
 
 void LED(uint8_t num, uint8_t state);
+void LEDS_OFF(void);
 void init_hardware(void);
 void check_rails_shortcut(void);
 
--- a/blackbox/main.c	Sat Dec 03 14:25:06 2011 +0100
+++ b/blackbox/main.c	Sat Dec 03 16:42:53 2011 +0100
@@ -13,8 +13,28 @@
 #include "main.h"
 #include "lowlevel.h"
 
-#define MAX_SLOTS       5
-uint8_t speedlimit[MAX_SLOTS];
+char ok[]               PROGMEM="OK\n";
+char busy[]             PROGMEM="BUSY\n";
+char prepare[]          PROGMEM="!RACE PREPARE\n";
+char countdownstart[]   PROGMEM="!COUNTDOWN\n";
+char racestart[]        PROGMEM="!RACE START\n";
+
+
+static uint8_t  countdown, countdown_loops;
+uint8_t  mode = 0;
+// valid race modes:
+// 0: free drive / idle
+// 1: waiting for countdown start
+// 2: race countdown initiated
+// 3: Race start condition
+
+
+#define MAX_SLOTS       6
+volatile uint8_t speedlimit[MAX_SLOTS];
+volatile uint8_t fuel[MAX_SLOTS];
+volatile uint8_t jumpstart_time[MAX_SLOTS];
+
+
 
 volatile uint8_t program_count = 0;
 volatile uint8_t program_id;
@@ -48,8 +68,6 @@
     return 0;
 }
 
-char ok[]       PROGMEM="OK\n";
-char busy[]     PROGMEM="BUSY\n";
 
 
 ISR ( USART_RXC_vect ) {
@@ -91,6 +109,18 @@
                     RS232_puts_p(ok);
                     break;
 
+                case 'I': // get Information data (incl. important global parameter dump)
+                    RS232_puts(VERSION);
+                    RS232_putc(':');
+                    for (tmp=0;tmp<MAX_SLOTS;tmp++) RS232_putc(speedlimit[tmp]); // output speed limits
+                    RS232_putc(':');
+                    for (tmp=0;tmp<MAX_SLOTS;tmp++) RS232_putc(fuel[tmp]); // output fuel levels (0=empty, 100=full, 0xff=no fuel option)
+                    RS232_putc(':');
+                    for (tmp=0;tmp<MAX_SLOTS;tmp++) RS232_putc(jumpstart_time[tmp]); // output jumpstart times
+                    RS232_putc(':');
+                    RS232_putc('\n');
+                    break;
+
             }
 
             // wait for the next packet
@@ -102,48 +132,61 @@
 }
 
 
+void jumpstart(uint8_t controller) {
+    if (jumpstart_time[controller] == 0) {
+        jumpstart_time[controller] = 1;
+        // todo: later the timestamp should written instead of just "1"
+        RS232_putc('~');
+        RS232_putc('0'-controller);
+        RS232_putc('\n');
+    }
 
+}
 
 
 int do_controller(uint8_t controller) {
     // read controller X speed & encode controller data packet
-    uint16_t tmp;
+    uint16_t tmp = 0;
     switch (controller) {
         case 0:
-            tmp = ((getADC(CONTROLLER1_SPEED) / CONTROLLER_DIVISOR) & 0x0F);
+            if (mode!=1) tmp = ((getADC(CONTROLLER1_SPEED) / CONTROLLER_DIVISOR) & 0x0F);
+            if ((mode == 2) && (tmp != 0)) { jumpstart(controller); tmp = 0; }
             if (tmp > speedlimit[controller]) tmp = speedlimit[controller];
             tmp = tmp << 1;
             if ( (PIN(CONTROLLER_PORT) & _BV(CONTROLLER1_SW)) != 0) {
                 tmp |= (1<<5);
-                LED(1,0);
-            } else LED(1,1);
+                if (mode == 0) LED(1,0);
+            } else if (mode == 0) LED(1,1);
             break;
         case 1:
-            tmp = ((getADC(CONTROLLER2_SPEED) / CONTROLLER_DIVISOR) & 0x0F);
+            if (mode!=1) tmp = ((getADC(CONTROLLER2_SPEED) / CONTROLLER_DIVISOR) & 0x0F);
+            if ((mode == 2) && (tmp != 0)) { jumpstart(controller); tmp = 0; }
             if (tmp > speedlimit[controller]) tmp = speedlimit[controller];
             tmp = tmp << 1;
             if ( (PIN(CONTROLLER_PORT) & _BV(CONTROLLER2_SW)) != 0) {
                 tmp |= (1<<5);
-                LED(2,0);
-            } else LED(2,1);
+                if (mode == 0) LED(2,0);
+            } else if (mode == 0) LED(2,1);
             break;
         case 2:
-            tmp = ((getADC(CONTROLLER3_SPEED) / CONTROLLER_DIVISOR) & 0x0F);
+            if (mode!=1) tmp = ((getADC(CONTROLLER3_SPEED) / CONTROLLER_DIVISOR) & 0x0F);
+            if ((mode == 2) && (tmp != 0)) { jumpstart(controller); tmp = 0; }
             if (tmp > speedlimit[controller]) tmp = speedlimit[controller];
             tmp = tmp << 1;
             if ( (PIN(CONTROLLER_PORT) & _BV(CONTROLLER3_SW)) != 0) {
                 tmp |= (1<<5);
-                LED(3,0);
-            } else LED(3,1);
+                if (mode == 0) LED(4,0);
+            } else if (mode == 0) LED(4,1);
             break;
         case 3:
-            tmp = ((getADC(CONTROLLER4_SPEED) / CONTROLLER_DIVISOR) & 0x0F);
+            if (mode!=1) tmp = ((getADC(CONTROLLER4_SPEED) / CONTROLLER_DIVISOR) & 0x0F);
+            if ((mode == 2) && (tmp != 0)) { jumpstart(controller); tmp = 0; }
             if (tmp > speedlimit[controller]) tmp = speedlimit[controller];
             tmp = tmp << 1;
             if ( (PIN(CONTROLLER_PORT) & _BV(CONTROLLER4_SW)) != 0) {
                 tmp |= (1<<5);
-                LED(4,0);
-            } else LED(4,1);
+                if (mode == 0) LED(5,0);
+            } else if (mode == 0) LED(5,1);
             break;
         case 4: tmp = (1<<5); break; // todo regler 5
         case 5: tmp = (1<<5); break; // todo regler 6
@@ -197,8 +240,6 @@
 ISR ( TIMER1_COMPA_vect ) {
     // trigger packet transfer:
     transmit_len = transmit_len_next;
-    //LED(2,2);
-
     // here is some more time to do something else...
 }
 
@@ -241,15 +282,12 @@
             if (transmit_len == 0) transmit_len = 0xFE; else transmit_len--; // next bit
         }
     }
-
-    //LED(3,2);
 }
 
 
 ISR ( TIMER0_OVF_vect ) {
 // TODO: last bit should be set by the sender, not from us!
     TCNT0 = TIMER0_250US;
-    //LED(1,2);
     if (timer0_delay == 0) {
         RAIL_POWER_PORT &= ~_BV(RAIL_POWER); // pull rails low
         _delay_us(28); // wait some cycles
@@ -280,13 +318,37 @@
 
 ISR (INT2_vect) {
     // Lap counter Interrupt
-    LED(5,2);
+    // do not know if this ever occurs ?! this is normally an output pin to trigger the counter start
 }
 
 void reset_vars(void) {
     uint8_t i;
     for (i=0; i<MAX_SLOTS; i++) {
         speedlimit[i] = 15;
+        fuel[i] = 100;
+        jumpstart_time[i] = 0;
+    }
+}
+
+void countdown_progress(void) {
+    // decrement COUNTDOWN_LOOPS
+    if (countdown_loops>0) {
+        countdown_loops--;
+    } else {
+        countdown--;
+        countdown_loops = COUNTDOWN_DELAY;
+    }
+    switch (countdown) {
+        case 5: LED(1, 1); break;
+        case 4: LED(2, 1); break;
+        case 3: LED(3, 1); break;
+        case 2: LED(4, 1); break;
+        case 1: LED(5, 1); break;
+        case 0: { // RACE START!
+            LEDS_OFF();
+            LED(3, 1);
+            mode = 3;
+            } break;
     }
 }
 
@@ -294,27 +356,15 @@
 int main(void)
 {
 
-    unsigned char s[30];
-    uint16_t tmp;
+    unsigned char s[10];
     uint8_t  packet_index = 1;
 
     uint8_t  btn_start = _BV(SW_START);
     uint8_t  old_start = btn_start;
-    uint8_t  mode = 0;
-    // valid race modes:
-    // 0: free drive
-    // 1: race countdown initiated
-    // 2: countdown 5
-    // 3: countdown 4
-    // 4: countdown 3
-    // 5: countdown 2
-    // 6: countdown 1
-    // 7: race start initiated (next mode will be zero = free drive)
-
-
 
     init_hardware();
     reset_vars();
+    LED(3, 1); // enable middle led == idle mode
 
     // switch on rails power
     RAIL_POWER_PORT |= _BV(RAIL_POWER);
@@ -339,28 +389,45 @@
             if (btn_start == 0) {
                 // start button press active
                 if (mode == 0) {
+                    mode = 1; // set wait for race start mode
+                    reset_vars();
+                    LED(1, 1);
+                    LED(2, 1);
+                    LED(3, 1);
+                    LED(4, 1);
+                    LED(5, 1);
+                    RS232_puts_p(prepare);
+                } else if (mode == 1) {
                     // Initiate race countdown
-                    mode = 0; // todo: set to 1
-                    // issue reset command to lap counter
-                    program_command = 6;
-                    program_parameter = 9;
-                    program_id = 0;
-                    program_count = 1;
-                    LAP_COUNTER_PORT |= _BV(LAP_COUNTER);
-                } else {
-                    // do a reset, switch back to free drive mode 0
-                    mode = 0;
-                    // issue reset command
-                    program_command = 19;
-                    program_parameter = 0;
-                    program_id = 7;
-                    program_count = 1;
-                    LAP_COUNTER_PORT &= ~_BV(LAP_COUNTER);
+                    countdown = 5;
+                    countdown_loops = COUNTDOWN_DELAY;
+                    mode = 2;
+                    LED(1, 0);
+                    LED(2, 0);
+                    LED(3, 0);
+                    LED(4, 0);
+                    LED(5, 0);
+                    RS232_puts_p(countdownstart);
                 }
             }
-            //LAP_COUNTER_PORT |= _BV(LAP_COUNTER);
-        } else old_start = btn_start;
-        // LAP_COUNTER_PORT &= ~_BV(LAP_COUNTER);
+            old_start = btn_start;
+        }
+
+        if (mode==3) {
+            // RACE START!
+            // issue reset command to lap counter
+            mode = 0;
+            RS232_puts_p(racestart);
+            program_command = 6;
+            program_parameter = 9;
+            program_id = 0;
+            program_count = 1;
+            LAP_COUNTER_PORT |= _BV(LAP_COUNTER);
+            // TODO: beep long
+            _delay_us(50);
+            LAP_COUNTER_PORT &= ~_BV(LAP_COUNTER);
+        }
+
 
         switch (packet_index) {
             case 1:
@@ -376,6 +443,9 @@
                     //if (do_program(7, 20, 15)) packet_index++; // reset / pitstop detect
                     //if (insert_queue(0, 0)) packet_index++; // null command
                 }
+
+                if ( (packet_index>1) && (mode == 2) ) countdown_progress();
+
                 break;
             case 2:
                 if (do_pace_ghost()) packet_index++;
--- a/blackbox/main.h	Sat Dec 03 14:25:06 2011 +0100
+++ b/blackbox/main.h	Sat Dec 03 16:42:53 2011 +0100
@@ -4,6 +4,10 @@
 #include <avr/wdt.h>
 #include <stdint.h>
 
+#define VERSION "1.1"
+
+#define COUNTDOWN_DELAY         10 // x/10 seconds
+
 // Hardware config
 #define LAP_COUNTER_PORT        PORTB
 #define LAP_COUNTER             PB2

mercurial