X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=blobdiff_plain;f=src%2Fdrivers%2Fao_lco.c;fp=src%2Fdrivers%2Fao_lco.c;h=8180c49de1137dc69af68f59702d9aa571e3cd1f;hp=464e05ab363c1bf115a7321cf0859b5d976eccb1;hb=dda3f459eaff8d4e41cb44584c8ef77b8e2b3b1c;hpb=55c1be449ef7ce389a3d94686051d272c858bee4 diff --git a/src/drivers/ao_lco.c b/src/drivers/ao_lco.c index 464e05ab..8180c49d 100644 --- a/src/drivers/ao_lco.c +++ b/src/drivers/ao_lco.c @@ -36,29 +36,42 @@ static uint8_t ao_lco_debug; #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 @@ -69,9 +82,11 @@ ao_lco_set_voltage(uint16_t decivolts) 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 @@ -85,6 +100,33 @@ ao_lco_set_display(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) @@ -123,6 +165,188 @@ ao_lco_pad_first(uint8_t box) 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) { @@ -184,17 +408,49 @@ 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; } @@ -241,7 +497,7 @@ ao_lco_get_channels(uint8_t box, struct ao_pad_query *query) 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]; } @@ -323,6 +579,7 @@ static void ao_lco_igniter_status(void) { uint8_t c; + uint8_t t = 0; for (;;) { ao_sleep(&ao_pad_query); @@ -343,18 +600,27 @@ ao_lco_igniter_status(void) 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; } } @@ -379,12 +645,12 @@ ao_lco_monitor(void) { 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); @@ -392,19 +658,17 @@ ao_lco_monitor(void) 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);