#define AO_LCO_BOX_DIGIT_1 1
#define AO_LCO_BOX_DIGIT_10 2
+#define AO_LCO_DRAG_RACE_START_TIME AO_SEC_TO_TICKS(5)
+#define AO_LCO_DRAG_RACE_STOP_TIME AO_SEC_TO_TICKS(2)
+
static uint8_t ao_lco_min_box, ao_lco_max_box;
static uint8_t ao_lco_selected[AO_PAD_MAX_BOXES];
-static uint8_t ao_lco_armed;
-static uint8_t ao_lco_firing;
static uint8_t ao_lco_valid[AO_PAD_MAX_BOXES];
static uint8_t ao_lco_channels[AO_PAD_MAX_BOXES];
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 uint8_t ao_lco_box;
static struct ao_pad_query ao_pad_query;
+static uint8_t ao_lco_display_mutex;
+
static void
ao_lco_set_pad(uint8_t pad)
{
- ao_seven_segment_set(AO_LCO_PAD_DIGIT, pad);
+ ao_mutex_get(&ao_lco_display_mutex);
+ ao_seven_segment_set(AO_LCO_PAD_DIGIT, pad | (ao_lco_drag_race << 4));
+ ao_mutex_put(&ao_lco_display_mutex);
}
static void
ao_lco_set_box(uint8_t box)
{
- ao_seven_segment_set(AO_LCO_BOX_DIGIT_1, box % 10);
- ao_seven_segment_set(AO_LCO_BOX_DIGIT_10, box / 10);
+ ao_mutex_get(&ao_lco_display_mutex);
+ ao_seven_segment_set(AO_LCO_BOX_DIGIT_1, box % 10 | (ao_lco_drag_race << 4));
+ ao_seven_segment_set(AO_LCO_BOX_DIGIT_10, box / 10 | (ao_lco_drag_race << 4));
+ ao_mutex_put(&ao_lco_display_mutex);
}
static void
tenths = decivolts % 10;
ones = (decivolts / 10) % 10;
tens = (decivolts / 100) % 10;
+ ao_mutex_get(&ao_lco_display_mutex);
ao_seven_segment_set(AO_LCO_PAD_DIGIT, tenths);
ao_seven_segment_set(AO_LCO_BOX_DIGIT_1, ones | 0x10);
ao_seven_segment_set(AO_LCO_BOX_DIGIT_10, tens);
+ ao_mutex_put(&ao_lco_display_mutex);
}
static void
}
}
+#define SEVEN_SEGMENT_d ((0 << 0) | \
+ (0 << 1) | \
+ (1 << 2) | \
+ (1 << 3) | \
+ (1 << 4) | \
+ (1 << 5) | \
+ (1 << 6))
+
+
+#define SEVEN_SEGMENT_r ((0 << 0) | \
+ (0 << 1) | \
+ (0 << 2) | \
+ (1 << 3) | \
+ (1 << 4) | \
+ (0 << 5) | \
+ (0 << 6))
+
+static void
+ao_lco_set_display_drag(void)
+{
+ ao_mutex_get(&ao_lco_display_mutex);
+ ao_seven_segment_direct(AO_LCO_BOX_DIGIT_10, SEVEN_SEGMENT_d | 0x80);
+ ao_seven_segment_direct(AO_LCO_BOX_DIGIT_1, SEVEN_SEGMENT_r | 0x80);
+ ao_mutex_put(&ao_lco_display_mutex);
+ ao_lco_set_pad(ao_lco_pad);
+}
+
#define MASK_SIZE(n) (((n) + 7) >> 3)
#define MASK_ID(n) ((n) >> 3)
#define MASK_SHIFT(n) ((n) & 7)
return 0;
}
+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;
+static uint16_t ao_lco_drag_warn_time;
+static uint16_t ao_lco_drag_display_time;
+static uint8_t ao_lco_drag_display_on;
+
+#define AO_LCO_DRAG_BEEP_TIME AO_MS_TO_TICKS(50)
+#define AO_LCO_DRAG_WARN_TIME AO_SEC_TO_TICKS(5)
+
+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)
+{
+ PRINTD("beep %d\n", beeps);
+ if (!ao_lco_drag_beep_count)
+ ao_lco_drag_beep_start();
+ ao_lco_drag_beep_count += beeps;
+}
+
+static uint16_t
+ao_lco_drag_beep_check(uint16_t now, uint16_t delay)
+{
+ PRINTD("beep check count %d delta %d\n",
+ ao_lco_drag_beep_count,
+ (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_count) {
+ if (delay > AO_LCO_DRAG_BEEP_TIME)
+ delay = AO_LCO_DRAG_BEEP_TIME;
+ }
+ 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_drag();
+ ao_lco_fire_down = 0;
+ ao_lco_drag_display_on = 1;
+ ao_lco_drag_display_time = ao_time() + AO_SEC_TO_TICKS(5);
+}
+
+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;
+ }
+ return delay;
+}
+
+static uint16_t
+ao_lco_drag_warn_check(uint16_t now, uint16_t delay)
+{
+ uint16_t warn_delay = ~0;
+
+ if (ao_lco_drag_race) {
+ if ((int16_t) (now - ao_lco_drag_warn_time) >= 0) {
+ ao_lco_drag_beep(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;
+ return delay;
+}
+
+static uint16_t
+ao_lco_drag_display_check(uint16_t now, uint16_t delay)
+{
+ uint16_t display_delay;
+
+ if (ao_lco_drag_display_on) {
+ if ((int16_t) (now - ao_lco_drag_display_time) >= 0) {
+ ao_lco_drag_display_on = 0;
+ ao_lco_set_display();
+ } else {
+ display_delay = ao_lco_drag_display_time - now;
+ if (delay > display_delay)
+ delay = display_delay;
+ }
+ }
+ return delay;
+}
+
+static void
+ao_lco_drag_monitor(void)
+{
+ uint16_t delay = ~0;
+ uint16_t now;
+
+ for (;;) {
+ PRINTD("Drag monitor active %d delay %d\n", ao_lco_drag_active, delay);
+ if (delay == (uint16_t) ~0)
+ ao_sleep(&ao_lco_drag_active);
+ else
+ ao_sleep_for(&ao_lco_drag_active, 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);
+ delay = ao_lco_drag_display_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;
+ }
+ }
+}
+
static void
ao_lco_input(void)
{
case AO_BUTTON_ARM:
ao_lco_armed = event.value;
PRINTD("Armed %d\n", ao_lco_armed);
- if (ao_lco_pad != 0) {
- memset(ao_lco_selected, 0, sizeof (ao_lco_selected));
- ao_lco_selected[ao_lco_box] = (1 << (ao_lco_pad - 1));
- ao_wakeup(&ao_lco_armed);
+ if (ao_lco_armed) {
+ 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);
+ break;
+ }
+ }
+ } else if (ao_lco_pad != 0) {
+ memset(ao_lco_selected, 0, sizeof (ao_lco_selected));
+ ao_lco_selected[ao_lco_box] = (1 << (ao_lco_pad - 1));
+ }
}
+ 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);
+ } else {
+ if (event.value) {
+ ao_lco_fire_down = 1;
+ ao_lco_fire_tick = ao_time();
+ ao_lco_drag_active = 1;
+ /* ao_lco_fire_down will already be off if we just enabled drag mode */
+ if (ao_lco_fire_down && 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_wakeup(&ao_lco_drag_active);
+ } else {
+ ao_lco_fire_down = 0;
+ if (ao_lco_drag_active)
+ ao_wakeup(&ao_lco_drag_active);
+ }
}
break;
}
ao_lco_valid[box] = 1;
} else
ao_lco_valid[box] = 0;
- PRINTD("ao_lco_get_channels(%d) valid %d\n", box, ao_lco_valid[box]);
+ PRINTD("ao_lco_get_channels(%d) rssi %d valid %d ret %d\n", box, ao_radio_cmac_rssi, ao_lco_valid[box], r);
ao_wakeup(&ao_pad_query);
return ao_lco_valid[box];
}
ao_lco_igniter_status(void)
{
uint8_t c;
+ uint8_t t = 0;
for (;;) {
ao_sleep(&ao_pad_query);
ao_led_on(AO_LED_REMOTE_ARM);
else
ao_led_off(AO_LED_REMOTE_ARM);
+
for (c = 0; c < AO_LED_CONTINUITY_NUM; c++) {
uint8_t status;
- 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]);
+ if (ao_lco_drag_race) {
+ if (ao_lco_selected[ao_lco_box] & (1 << c) && t)
+ 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;
}
}
{
uint16_t delay;
uint8_t box;
- struct ao_pad_query pad_query;
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");
ao_add_task(&ao_lco_igniter_status_task, ao_lco_igniter_status, "lco igniter status");
+ ao_add_task(&ao_lco_drag_task, ao_lco_drag_monitor, "drag race");
for (;;) {
PRINTD("monitor armed %d firing %d\n",
ao_lco_armed, ao_lco_firing);
if (ao_lco_armed && ao_lco_firing) {
ao_lco_ignite();
} else {
+ ao_lco_update();
if (ao_lco_armed) {
- for (box = 0; box < AO_PAD_MAX_BOXES; box++) {
+ for (box = ao_lco_min_box; box <= ao_lco_max_box; box++) {
if (ao_lco_selected[box]) {
PRINTD("Arming box %d pads %x\n",
box, ao_lco_selected[box]);
- if (!ao_lco_valid[box])
- ao_lco_get_channels(box, &pad_query);
if (ao_lco_valid[box])
ao_lco_arm(box, ao_lco_selected[box], ao_lco_tick_offset[ao_lco_box]);
}
}
}
- ao_lco_update();
}
if (ao_lco_armed && ao_lco_firing)
delay = AO_MS_TO_TICKS(100);