From 4c2a7503373c0584de77f9b0e5632a58ab8bbd1f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 25 Dec 2015 11:26:34 -0800 Subject: [PATCH] altos: Add ao_lco_two.c; alternate LCO interface code The LCO interface is likely to end up very device specific as the interactions depends on the input devices. Here's a version for TeleLCOTwo, which has two arming switches and a firing button. Signed-off-by: Keith Packard --- src/drivers/ao_lco_two.c | 271 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 src/drivers/ao_lco_two.c diff --git a/src/drivers/ao_lco_two.c b/src/drivers/ao_lco_two.c new file mode 100644 index 00000000..0fd8e362 --- /dev/null +++ b/src/drivers/ao_lco_two.c @@ -0,0 +1,271 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include +#include + +#define DEBUG 1 + +#if DEBUG +static uint8_t ao_lco_debug; +#define DEBUG_EVENT 1 +#define DEBUG_STATUS 2 +#define PRINTD(l, ...) do { if (!(ao_lco_debug & l)) break; printf ("\r%5u %s: ", ao_tick_count, __func__); printf(__VA_ARGS__); flush(); } while(0) +#else +#define PRINTD(l,...) +#endif + +#define AO_LCO_VALID_LAST 1 +#define AO_LCO_VALID_EVER 2 + +static uint8_t ao_lco_selected; +static uint8_t ao_lco_valid; +static uint8_t ao_lco_channels; +static uint16_t ao_lco_tick_offset; + +/* UI values */ +static uint8_t ao_lco_armed; +static uint8_t ao_lco_firing; +static uint8_t ao_lco_fire_down; + +#define ao_lco_box (ao_config.pad_box) + +static struct ao_pad_query ao_pad_query; + +#define MASK_SIZE(n) (((n) + 7) >> 3) +#define MASK_ID(n) ((n) >> 3) +#define MASK_SHIFT(n) ((n) & 7) + +static void +ao_lco_set_armed(int pad, int armed) +{ + uint8_t bit = (1 << pad); + + if (armed) { + ao_lco_selected |= bit; + ao_lco_armed |= bit; + } else { + ao_lco_selected &= ~bit; + ao_lco_armed &= ~bit; + } + PRINTD(DEBUG_EVENT, "pad %d bit 0x%x armed %d ao_lco_selected 0x%x ao_lco_armed 0x%x\n", + pad, bit, armed, ao_lco_selected, ao_lco_armed); + ao_wakeup(&ao_lco_armed); +} + +static void +ao_lco_input(void) +{ + static struct ao_event event; + + for (;;) { + ao_event_get(&event); + PRINTD(DEBUG_EVENT, "event type %d unit %d value %d\n", + event.type, event.unit, event.value); + switch (event.type) { + case AO_EVENT_BUTTON: + switch (event.unit) { + case AO_BUTTON_ARM_0: + ao_lco_set_armed(0, event.value); + break; +#if AO_BUTTON_ARM_NUM > 1 + case AO_BUTTON_ARM_1: + ao_lco_set_armed(1, event.value); + break; +#endif + case AO_BUTTON_FIRE: + if (ao_lco_armed) { + ao_lco_fire_down = 0; + ao_lco_firing = event.value; + PRINTD(DEBUG_EVENT, "Firing %d\n", ao_lco_firing); + ao_wakeup(&ao_lco_armed); + } + break; + } + break; + } + } +} + +static AO_LED_TYPE continuity_led[AO_LED_CONTINUITY_NUM] = { +#ifdef AO_LED_CONTINUITY_0 + AO_LED_CONTINUITY_0, +#endif +#ifdef AO_LED_CONTINUITY_1 + AO_LED_CONTINUITY_1, +#endif +#ifdef AO_LED_CONTINUITY_2 + AO_LED_CONTINUITY_2, +#endif +#ifdef AO_LED_CONTINUITY_3 + AO_LED_CONTINUITY_3, +#endif +#ifdef AO_LED_CONTINUITY_4 + AO_LED_CONTINUITY_4, +#endif +#ifdef AO_LED_CONTINUITY_5 + AO_LED_CONTINUITY_5, +#endif +#ifdef AO_LED_CONTINUITY_6 + AO_LED_CONTINUITY_6, +#endif +#ifdef AO_LED_CONTINUITY_7 + AO_LED_CONTINUITY_7, +#endif +}; + +static uint8_t +ao_lco_get_channels(void) +{ + int8_t r; + + r = ao_lco_query(ao_lco_box, &ao_pad_query, &ao_lco_tick_offset); + if (r == AO_RADIO_CMAC_OK) { + ao_lco_channels = ao_pad_query.channels; + ao_lco_valid = AO_LCO_VALID_LAST | AO_LCO_VALID_EVER; + } else + ao_lco_valid &= ~AO_LCO_VALID_LAST; + PRINTD(DEBUG_STATUS, "ao_lco_get_channels() rssi %d valid %d ret %d offset %d\n", ao_radio_cmac_rssi, ao_lco_valid, r, ao_lco_tick_offset); + ao_wakeup(&ao_pad_query); + return ao_lco_valid; +} + +static void +ao_lco_igniter_status(void) +{ + uint8_t c; + uint8_t t = 0; + + for (;;) { + ao_sleep(&ao_pad_query); + PRINTD(DEBUG_STATUS, "RSSI %d VALID %d\n", ao_radio_cmac_rssi, ao_lco_valid); + if (!(ao_lco_valid & AO_LCO_VALID_LAST)) { + ao_led_on(AO_LED_RED); + ao_led_off(AO_LED_GREEN|AO_LED_AMBER); + continue; + } + if (ao_radio_cmac_rssi < -90) { + ao_led_on(AO_LED_AMBER); + ao_led_off(AO_LED_RED|AO_LED_GREEN); + } else { + ao_led_on(AO_LED_GREEN); + ao_led_off(AO_LED_RED|AO_LED_AMBER); + } + if (ao_pad_query.arm_status) + 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; + PRINTD(DEBUG_STATUS, "\tchannel %d status %d\n", c, status); + 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; + } +} + +static void +ao_lco_arm_warn(void) +{ + int i; + for (;;) { + while (!ao_lco_armed) + ao_sleep(&ao_lco_armed); + for (i = 0; i < ao_lco_armed; i++) { + ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(100)); + ao_delay(AO_MS_TO_TICKS(100)); + } + ao_delay(AO_MS_TO_TICKS(300)); + } +} + +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; +static struct ao_task ao_lco_igniter_status_task; + +static void +ao_lco_monitor(void) +{ + uint16_t delay; + + 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_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200)); + for (;;) { + PRINTD(DEBUG_STATUS, "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_get_channels(); + if (ao_lco_armed) { + if (ao_lco_selected) { + PRINTD(DEBUG_STATUS, "Arming pads %x\n", + ao_lco_selected); + if (ao_lco_valid & AO_LCO_VALID_EVER) { + ao_lco_arm(ao_lco_box, ao_lco_selected, ao_lco_tick_offset); + ao_delay(AO_MS_TO_TICKS(10)); + } + } + } + } + if (ao_lco_armed && ao_lco_firing) + delay = AO_MS_TO_TICKS(100); + else + delay = AO_SEC_TO_TICKS(1); + ao_sleep_for(&ao_lco_armed, delay); + } +} + +#if DEBUG +void +ao_lco_set_debug(void) +{ + ao_cmd_decimal(); + if (ao_cmd_status == ao_cmd_success) + ao_lco_debug = ao_cmd_lex_i; +} + +__code struct ao_cmds ao_lco_cmds[] = { + { ao_lco_set_debug, "D <0 off, 1 on>\0Debug" }, + { 0, NULL } +}; +#endif + +void +ao_lco_init(void) +{ + ao_add_task(&ao_lco_monitor_task, ao_lco_monitor, "lco monitor"); +#if DEBUG + ao_cmd_register(&ao_lco_cmds[0]); +#endif +} -- 2.30.2