altos/telelco-v2.0: Do all drag race beeping from the beeping thread
[fw/altos] / src / telelco-v2.0 / ao_lco_v2.c
index 6f2b618aec51c39e223fb17ca151f637e151ced0..21b2c54d368c239b37ef01ccf119676fae408208 100644 (file)
@@ -23,6 +23,7 @@
 #include <ao_quadrature.h>
 #include <ao_lco_func.h>
 #include <ao_radio_cmac.h>
+#include <ao_adc_single.h>
 
 #define DEBUG  1
 
@@ -52,15 +53,12 @@ static uint16_t     ao_lco_tick_offset[AO_PAD_MAX_BOXES];
 /* UI values */
 static uint8_t ao_lco_armed;
 static uint8_t ao_lco_firing;
-static uint16_t        ao_lco_fire_tick;
-static uint8_t ao_lco_fire_down;
 static uint8_t ao_lco_drag_race;
 static uint8_t ao_lco_pad;
 static int16_t ao_lco_box;
 static uint8_t ao_lco_select_mode;
 #define AO_LCO_SELECT_PAD      0
 #define AO_LCO_SELECT_BOX      1
-#define AO_LCO_SELECT_NONE     2
 
 static struct ao_pad_query     ao_pad_query;
 
@@ -105,6 +103,7 @@ ao_lco_set_voltage(uint16_t decivolts)
 {
        uint8_t tens, ones, tenths;
 
+       PRINTD("voltage %d\n", decivolts);
        tenths = decivolts % 10;
        ones = (decivolts / 10) % 10;
        tens = (decivolts / 100) % 10;
@@ -167,24 +166,26 @@ ao_lco_pad_first(uint8_t box)
 static void
 ao_lco_set_select(void)
 {
-       switch (ao_lco_select_mode) {
-       case AO_LCO_SELECT_PAD:
-               ao_led_off(AO_LED_BOX);
-               ao_led_on(AO_LED_PAD);
-               break;
-       case AO_LCO_SELECT_BOX:
-               ao_led_off(AO_LED_PAD);
-               ao_led_on(AO_LED_BOX);
-               break;
-       default:
+       if (ao_lco_armed) {
                ao_led_off(AO_LED_PAD);
                ao_led_off(AO_LED_BOX);
-               break;
+       } else {
+               switch (ao_lco_select_mode) {
+               case AO_LCO_SELECT_PAD:
+                       ao_led_off(AO_LED_BOX);
+                       ao_led_on(AO_LED_PAD);
+                       break;
+               case AO_LCO_SELECT_BOX:
+                       ao_led_off(AO_LED_PAD);
+                       ao_led_on(AO_LED_BOX);
+                       break;
+               default:
+                       break;
+               }
        }
 }
 
 static struct ao_task  ao_lco_drag_task;
-static uint8_t         ao_lco_drag_active;
 static uint8_t         ao_lco_drag_beep_count;
 static uint8_t         ao_lco_drag_beep_on;
 static uint16_t                ao_lco_drag_beep_time;
@@ -193,37 +194,21 @@ static uint16_t           ao_lco_drag_warn_time;
 #define AO_LCO_DRAG_BEEP_TIME  AO_MS_TO_TICKS(50)
 #define AO_LCO_DRAG_WARN_TIME  AO_SEC_TO_TICKS(5)
 
+/* Request 'beeps' additional drag race beeps */
 static void
-ao_lco_drag_beep_start(void)
-{
-       ao_beep(AO_BEEP_HIGH);
-       PRINTD("beep start\n");
-       ao_lco_drag_beep_on = 1;
-       ao_lco_drag_beep_time = ao_time() + AO_LCO_DRAG_BEEP_TIME;
-}
-
-static void
-ao_lco_drag_beep_stop(void)
-{
-       ao_beep(0);
-       PRINTD("beep stop\n");
-       ao_lco_drag_beep_on = 0;
-       if (ao_lco_drag_beep_count) {
-               --ao_lco_drag_beep_count;
-               if (ao_lco_drag_beep_count)
-                       ao_lco_drag_beep_time = ao_time() + AO_LCO_DRAG_BEEP_TIME;
-       }
-}
-
-static void
-ao_lco_drag_beep(uint8_t beeps)
+ao_lco_drag_add_beeps(uint8_t beeps)
 {
        PRINTD("beep %d\n", beeps);
-       if (!ao_lco_drag_beep_count)
-               ao_lco_drag_beep_start();
+       if (ao_lco_drag_beep_count == 0)
+               ao_lco_drag_beep_time = ao_time();
        ao_lco_drag_beep_count += beeps;
+       ao_wakeup(&ao_lco_drag_beep_count);
 }
 
+/* Check whether it's time to change the beeper status, then either
+ * turn it on or off as necessary and bump the remaining beep counts
+ */
+
 static uint16_t
 ao_lco_drag_beep_check(uint16_t now, uint16_t delay)
 {
@@ -232,16 +217,32 @@ ao_lco_drag_beep_check(uint16_t now, uint16_t delay)
               (int16_t) (now - ao_lco_drag_beep_time));
        if (ao_lco_drag_beep_count) {
                if ((int16_t) (now - ao_lco_drag_beep_time) >= 0) {
-                       if (ao_lco_drag_beep_on)
-                               ao_lco_drag_beep_stop();
-                       else
-                               ao_lco_drag_beep_start();
+                       if (ao_lco_drag_beep_on) {
+                               ao_beep(0);
+                               PRINTD("beep stop\n");
+                               ao_lco_drag_beep_on = 0;
+                               if (ao_lco_drag_beep_count) {
+                                       --ao_lco_drag_beep_count;
+                                       if (ao_lco_drag_beep_count)
+                                               ao_lco_drag_beep_time = now + AO_LCO_DRAG_BEEP_TIME;
+                               }
+                       } else {
+                               ao_beep(AO_BEEP_HIGH);
+                               PRINTD("beep start\n");
+                               ao_lco_drag_beep_on = 1;
+                               ao_lco_drag_beep_time = now + AO_LCO_DRAG_BEEP_TIME;
+                       }
                }
        }
 
        if (ao_lco_drag_beep_count) {
-               if (delay > AO_LCO_DRAG_BEEP_TIME)
-                       delay = AO_LCO_DRAG_BEEP_TIME;
+               uint16_t beep_delay = 0;
+
+               if (ao_lco_drag_beep_time > now)
+                       beep_delay = ao_lco_drag_beep_time - now;
+
+               if (delay > beep_delay)
+                       delay = beep_delay;
        }
        return delay;
 }
@@ -249,66 +250,47 @@ ao_lco_drag_beep_check(uint16_t now, uint16_t delay)
 static void
 ao_lco_drag_enable(void)
 {
-       PRINTD("Drag enable\n");
-       ao_lco_drag_race = 1;
-       memset(ao_lco_selected, 0, sizeof (ao_lco_selected));
-       ao_lco_drag_beep(5);
-       ao_lco_set_display();
-       ao_lco_fire_down = 0;
+       if (!ao_lco_drag_race) {
+               PRINTD("Drag enable\n");
+               ao_lco_drag_race = 1;
+               memset(ao_lco_selected, 0, sizeof (ao_lco_selected));
+               ao_led_on(AO_LED_DRAG);
+               ao_lco_drag_add_beeps(5);
+               ao_lco_set_display();
+       }
 }
 
 static void
 ao_lco_drag_disable(void)
 {
-       PRINTD("Drag disable\n");
-       ao_lco_drag_race = 0;
-       memset(ao_lco_selected, 0, sizeof (ao_lco_selected));
-       ao_lco_drag_beep(2);
-       ao_lco_set_display();
-       ao_lco_fire_down = 0;
-}
-
-static uint16_t
-ao_lco_drag_button_check(uint16_t now, uint16_t delay)
-{
-       uint16_t        button_delay = ~0;
-
-       /*
-        * Check to see if the button has been held down long enough
-        * to switch in/out of drag race mode
-        */
-       if (ao_lco_fire_down) {
-               if (ao_lco_drag_race) {
-                       if ((int16_t) (now - ao_lco_fire_tick) >= AO_LCO_DRAG_RACE_STOP_TIME)
-                               ao_lco_drag_disable();
-                       else
-                               button_delay = ao_lco_fire_tick + AO_LCO_DRAG_RACE_STOP_TIME - now;
-               } else {
-                       if ((int16_t) (now - ao_lco_fire_tick) >= AO_LCO_DRAG_RACE_START_TIME)
-                               ao_lco_drag_enable();
-                       else
-                               button_delay = ao_lco_fire_tick + AO_LCO_DRAG_RACE_START_TIME - now;
-               }
-               if (delay > button_delay)
-                       delay = button_delay;
+       if (ao_lco_drag_race) {
+               PRINTD("Drag disable\n");
+               ao_lco_drag_race = 0;
+               ao_led_off(AO_LED_DRAG);
+               memset(ao_lco_selected, 0, sizeof (ao_lco_selected));
+               ao_lco_drag_add_beeps(2);
+               ao_lco_set_display();
        }
-       return delay;
 }
 
+/* add a beep if it's time to warn the user that drag race mode is
+ * active
+ */
+
 static uint16_t
 ao_lco_drag_warn_check(uint16_t now, uint16_t delay)
 {
-       uint16_t        warn_delay = ~0;
-
        if (ao_lco_drag_race) {
+               uint16_t        warn_delay;
+
                if ((int16_t) (now - ao_lco_drag_warn_time) >= 0) {
-                       ao_lco_drag_beep(1);
+                       ao_lco_drag_add_beeps(1);
                        ao_lco_drag_warn_time = now + AO_LCO_DRAG_WARN_TIME;
                }
                warn_delay = ao_lco_drag_warn_time - now;
+               if (delay > warn_delay)
+                       delay = warn_delay;
        }
-       if (delay > warn_delay)
-               delay = warn_delay;
        return delay;
 }
 
@@ -319,26 +301,16 @@ ao_lco_drag_monitor(void)
        uint16_t        now;
 
        for (;;) {
-               PRINTD("Drag monitor active %d delay %d\n", ao_lco_drag_active, delay);
+               PRINTD("Drag monitor count %d delay %d\n", ao_lco_drag_beep_count, delay);
                if (delay == (uint16_t) ~0)
-                       ao_sleep(&ao_lco_drag_active);
+                       ao_sleep(&ao_lco_drag_beep_count);
                else
-                       ao_sleep_for(&ao_lco_drag_active, delay);
+                       ao_sleep_for(&ao_lco_drag_beep_count, delay);
 
                delay = ~0;
-               if (!ao_lco_drag_active)
-                       continue;
-
                now = ao_time();
-               delay = ao_lco_drag_button_check(now, delay);
                delay = ao_lco_drag_warn_check(now, delay);
                delay = ao_lco_drag_beep_check(now, delay);
-
-               /* check to see if there's anything left to do here */
-               if (!ao_lco_fire_down && !ao_lco_drag_race && !ao_lco_drag_beep_count) {
-                       delay = ~0;
-                       ao_lco_drag_active = 0;
-               }
        }
 }
 
@@ -412,12 +384,11 @@ ao_lco_input(void)
                                        if (ao_lco_drag_race) {
                                                uint8_t box;
 
-                                               for (box = ao_lco_min_box; box <= ao_lco_max_box; box++) {
-                                                       if (ao_lco_selected[box]) {
-                                                               ao_wakeup(&ao_lco_armed);
+                                               for (box = ao_lco_min_box; box <= ao_lco_max_box; box++)
+                                                       if (ao_lco_selected[box])
                                                                break;
-                                                       }
-                                               }
+                                               if (box > ao_lco_max_box)
+                                                       ao_lco_armed = 0;
                                        } else {
                                                memset(ao_lco_selected, 0, sizeof (ao_lco_selected));
                                                if (ao_lco_pad != 0)
@@ -426,37 +397,39 @@ ao_lco_input(void)
                                                        ao_lco_armed = 0;
                                        }
                                }
+                               ao_lco_set_select();
                                ao_wakeup(&ao_lco_armed);
                                break;
                        case AO_BUTTON_FIRE:
                                if (ao_lco_armed) {
-                                       ao_lco_fire_down = 0;
                                        ao_lco_firing = event.value;
                                        PRINTD("Firing %d\n", ao_lco_firing);
                                        ao_wakeup(&ao_lco_armed);
                                }
                                break;
                        case AO_BUTTON_DRAG_SELECT:
-                               if (ao_lco_drag_race) {
+                               if (event.value && ao_lco_drag_race) {
                                        if (ao_lco_pad != 0) {
                                                ao_lco_selected[ao_lco_box] ^= (1 << (ao_lco_pad - 1));
                                                PRINTD("Toggle box %d pad %d (pads now %x) to drag race\n",
                                                       ao_lco_pad, ao_lco_box, ao_lco_selected[ao_lco_box]);
-                                               ao_lco_drag_beep(ao_lco_pad);
+                                               ao_lco_drag_add_beeps(ao_lco_pad);
                                        }
                                }
                                break;
-                       case AO_BUTTON_MODE_SELECT:
+                       case AO_BUTTON_DRAG_MODE:
                                if (event.value)
                                        ao_lco_drag_enable();
                                else
                                        ao_lco_drag_disable();
                                break;
-                       case AO_BUTTON_SELECT:
-                               ao_lco_select_mode++;
-                               if (ao_lco_select_mode > AO_LCO_SELECT_NONE)
-                                       ao_lco_select_mode = AO_LCO_SELECT_PAD;
-                               ao_lco_set_select();
+                       case AO_BUTTON_ENCODER_SELECT:
+                               if (event.value) {
+                                       if (!ao_lco_armed) {
+                                               ao_lco_select_mode = 1 - ao_lco_select_mode;
+                                               ao_lco_set_select();
+                                       }
+                               }
                                break;
                        }
                        break;
@@ -608,23 +581,32 @@ ao_lco_igniter_status(void)
                for (c = 0; c < AO_LED_CONTINUITY_NUM; c++) {
                        uint8_t status;
 
-                       if (ao_lco_drag_race) {
-                               if (ao_lco_selected[ao_lco_box] & (1 << c) && t)
+                       if (ao_pad_query.channels & (1 << c))
+                               status = ao_pad_query.igniter_status[c];
+                       else
+                               status = AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_OPEN;
+
+                       if (ao_lco_drag_race && (ao_lco_selected[ao_lco_box] & (1 << c))) {
+                               uint8_t on = 0;
+                               if (status == AO_PAD_IGNITER_STATUS_GOOD_IGNITER_RELAY_OPEN) {
+                                       if (t)
+                                               on = 1;
+                               } else {
+                                       if (t == 1)
+                                               on = 1;
+                               }
+                               if (on)
                                        ao_led_on(continuity_led[c]);
                                else
                                        ao_led_off(continuity_led[c]);
                        } else {
-                               if (ao_pad_query.channels & (1 << c))
-                                       status = ao_pad_query.igniter_status[c];
-                               else
-                                       status = AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_OPEN;
                                if (status == AO_PAD_IGNITER_STATUS_GOOD_IGNITER_RELAY_OPEN)
                                        ao_led_on(continuity_led[c]);
                                else
                                        ao_led_off(continuity_led[c]);
                        }
                }
-               t = 1-t;
+               t = (t + 1) & 3;
        }
 }
 
@@ -642,6 +624,35 @@ ao_lco_arm_warn(void)
        }
 }
 
+/*
+ * Light up everything for a second at power on to let the user
+ * visually inspect the system for correct operation
+ */
+static void
+ao_lco_display_test()
+{
+       ao_mutex_get(&ao_lco_display_mutex);
+       ao_seven_segment_set(AO_LCO_PAD_DIGIT, 8 | 0x10);
+       ao_seven_segment_set(AO_LCO_BOX_DIGIT_1, 8 | 0x10);
+       ao_seven_segment_set(AO_LCO_BOX_DIGIT_10, 8 | 0x10);
+       ao_mutex_put(&ao_lco_display_mutex);
+       ao_led_on(LEDS_AVAILABLE);
+       ao_delay(AO_MS_TO_TICKS(1000));
+       ao_led_off(LEDS_AVAILABLE);
+}
+
+static void
+ao_lco_batt_voltage(void)
+{
+       struct ao_adc   packet;
+       int16_t         decivolt;
+
+       ao_adc_single_get(&packet);
+       decivolt = ao_battery_decivolt(packet.v_batt);
+       ao_lco_set_voltage(decivolt);
+       ao_delay(AO_MS_TO_TICKS(1000));
+}
+
 static struct ao_task ao_lco_input_task;
 static struct ao_task ao_lco_monitor_task;
 static struct ao_task ao_lco_arm_warn_task;
@@ -653,6 +664,8 @@ ao_lco_monitor(void)
        uint16_t                delay;
        uint8_t                 box;
 
+       ao_lco_display_test();
+       ao_lco_batt_voltage();
        ao_lco_search();
        ao_add_task(&ao_lco_input_task, ao_lco_input, "lco input");
        ao_add_task(&ao_lco_arm_warn_task, ao_lco_arm_warn, "lco arm warn");