#include <ao_quadrature.h>
#include <ao_lco_func.h>
#include <ao_radio_cmac.h>
+#include <ao_adc_single.h>
#define DEBUG 1
/* 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;
{
uint8_t tens, ones, tenths;
+ PRINTD("voltage %d\n", decivolts);
tenths = decivolts % 10;
ones = (decivolts / 10) % 10;
tens = (decivolts / 100) % 10;
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;
#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)
{
(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;
}
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;
}
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;
- }
}
}
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)
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;
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;
}
}
}
}
+/*
+ * 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;
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");