altos/telelcotwo: Add idle timeout
authorKeith Packard <keithp@keithp.com>
Wed, 6 Apr 2016 06:45:52 +0000 (23:45 -0700)
committerKeith Packard <keithp@keithp.com>
Wed, 20 Apr 2016 03:21:30 +0000 (23:21 -0400)
Puts TeleLCOTwo in a low power state (drawing about 80µA) after a
timeout (default two minutes) to keep from killing the battery if the
device is left turned on.

Signed-off-by: Keith Packard <keithp@keithp.com>
src/drivers/ao_event.c
src/drivers/ao_event.h
src/drivers/ao_lco_two.c
src/kernel/ao_config.c
src/kernel/ao_config.h

index 5c0d286310f2460f1638227f8ddb8bd87303d083..8f88d77866c391cc91645de7633ab28fe1390779 100644 (file)
@@ -41,6 +41,22 @@ ao_event_get(struct ao_event *ev)
                );
 }
 
                );
 }
 
+uint8_t
+ao_event_get_for(struct ao_event *ev, uint16_t timeout)
+{
+       uint8_t empty = 1;
+       ao_arch_critical(
+               while ((empty = ao_event_queue_empty()))
+                       if (ao_sleep_for(&ao_event_queue, timeout))
+                               break;
+               if (!empty) {
+                       *ev = ao_event_queue[ao_event_queue_remove];
+                       ao_event_queue_remove = ao_event_queue_next(ao_event_queue_remove);
+               }
+               );
+       return empty;
+}
+
 /* called with interrupts disabled */
 void
 ao_event_put_isr(uint8_t type, uint8_t unit, int32_t value)
 /* called with interrupts disabled */
 void
 ao_event_put_isr(uint8_t type, uint8_t unit, int32_t value)
index 584a845a3e14d8103ab67720d5fc754865ace603..ea89da23c07cef3598c4159c5792fae4d376cbda 100644 (file)
@@ -32,6 +32,9 @@ struct ao_event {
 void
 ao_event_get(struct ao_event *ev);
 
 void
 ao_event_get(struct ao_event *ev);
 
+uint8_t
+ao_event_get_for(struct ao_event *ev, uint16_t timeout);
+
 void
 ao_event_put_isr(uint8_t type, uint8_t unit, int32_t value);
 
 void
 ao_event_put_isr(uint8_t type, uint8_t unit, int32_t value);
 
index 0fd8e3626d45b8e709d0cc344f753937ca95d8a0..f53fef7db19fd19c8b93f738b9b6878fb465dcea 100644 (file)
@@ -29,12 +29,13 @@ static uint8_t      ao_lco_debug;
 #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 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,...) 
+#define PRINTD(l,...)
 #endif
 
 #define AO_LCO_VALID_LAST      1
 #define AO_LCO_VALID_EVER      2
 
 #endif
 
 #define AO_LCO_VALID_LAST      1
 #define AO_LCO_VALID_EVER      2
 
+static uint8_t ao_lco_suspended;
 static uint8_t ao_lco_selected;
 static uint8_t ao_lco_valid;
 static uint8_t ao_lco_channels;
 static uint8_t ao_lco_selected;
 static uint8_t ao_lco_valid;
 static uint8_t ao_lco_channels;
@@ -43,7 +44,6 @@ static uint16_t       ao_lco_tick_offset;
 /* UI values */
 static uint8_t ao_lco_armed;
 static uint8_t ao_lco_firing;
 /* 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)
 
 
 #define ao_lco_box     (ao_config.pad_box)
 
@@ -70,13 +70,45 @@ ao_lco_set_armed(int pad, int armed)
        ao_wakeup(&ao_lco_armed);
 }
 
        ao_wakeup(&ao_lco_armed);
 }
 
+static void
+ao_lco_suspend(void)
+{
+       if (!ao_lco_suspended) {
+               PRINTD(DEBUG_EVENT, "suspend\n");
+               ao_lco_suspended = 1;
+               ao_lco_selected = 0;
+               ao_lco_armed = 0;
+               ao_wakeup(&ao_pad_query);
+       }
+}
+
+static void
+ao_lco_wakeup(void)
+{
+       if (ao_lco_suspended) {
+               ao_lco_suspended = 0;
+               ao_wakeup(&ao_lco_suspended);
+       }
+}
+
 static void
 ao_lco_input(void)
 {
        static struct ao_event  event;
 static void
 ao_lco_input(void)
 {
        static struct ao_event  event;
+       uint8_t timeout;
 
 
+       ao_config_get();
        for (;;) {
        for (;;) {
-               ao_event_get(&event);
+               if (ao_config.pad_idle && !ao_lco_suspended) {
+                       timeout = ao_event_get_for(&event, AO_SEC_TO_TICKS(ao_config.pad_idle));
+                       if (timeout) {
+                               ao_lco_suspend();
+                               continue;
+                       }
+               } else {
+                       ao_event_get(&event);
+               }
+               ao_lco_wakeup();
                PRINTD(DEBUG_EVENT, "event type %d unit %d value %d\n",
                       event.type, event.unit, event.value);
                switch (event.type) {
                PRINTD(DEBUG_EVENT, "event type %d unit %d value %d\n",
                       event.type, event.unit, event.value);
                switch (event.type) {
@@ -92,7 +124,6 @@ ao_lco_input(void)
 #endif
                        case AO_BUTTON_FIRE:
                                if (ao_lco_armed) {
 #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);
                                        ao_lco_firing = event.value;
                                        PRINTD(DEBUG_EVENT, "Firing %d\n", ao_lco_firing);
                                        ao_wakeup(&ao_lco_armed);
@@ -155,6 +186,12 @@ ao_lco_igniter_status(void)
 
        for (;;) {
                ao_sleep(&ao_pad_query);
 
        for (;;) {
                ao_sleep(&ao_pad_query);
+               while (ao_lco_suspended) {
+                       ao_led_off(AO_LED_GREEN|AO_LED_AMBER|AO_LED_RED|AO_LED_REMOTE_ARM);
+                       for (c = 0; c < AO_LED_CONTINUITY_NUM; c++)
+                               ao_led_off(continuity_led[c]);
+                       ao_sleep(&ao_lco_suspended);
+               }
                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);
                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);
@@ -195,6 +232,8 @@ ao_lco_arm_warn(void)
 {
        int     i;
        for (;;) {
 {
        int     i;
        for (;;) {
+               while (ao_lco_suspended)
+                       ao_sleep(&ao_lco_suspended);
                while (!ao_lco_armed)
                        ao_sleep(&ao_lco_armed);
                for (i = 0; i < ao_lco_armed; i++) {
                while (!ao_lco_armed)
                        ao_sleep(&ao_lco_armed);
                for (i = 0; i < ao_lco_armed; i++) {
@@ -220,6 +259,9 @@ ao_lco_monitor(void)
        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 (;;) {
        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 (;;) {
+               while (ao_lco_suspended)
+                       ao_sleep(&ao_lco_suspended);
+
                PRINTD(DEBUG_STATUS, "monitor armed %d firing %d\n",
                       ao_lco_armed, ao_lco_firing);
 
                PRINTD(DEBUG_STATUS, "monitor armed %d firing %d\n",
                       ao_lco_armed, ao_lco_firing);
 
@@ -240,8 +282,9 @@ ao_lco_monitor(void)
                }
                if (ao_lco_armed && ao_lco_firing)
                        delay = AO_MS_TO_TICKS(100);
                }
                if (ao_lco_armed && ao_lco_firing)
                        delay = AO_MS_TO_TICKS(100);
-               else
+               else {
                        delay = AO_SEC_TO_TICKS(1);
                        delay = AO_SEC_TO_TICKS(1);
+               }
                ao_sleep_for(&ao_lco_armed, delay);
        }
 }
                ao_sleep_for(&ao_lco_armed, delay);
        }
 }
index d51fbb415a8fe4bb83ce03a68e83f55219ebaa38..f95ca8933cc3f526c15a9c7d2acf2d7efea4f9c4 100644 (file)
@@ -227,6 +227,8 @@ _ao_config_get(void)
 #if HAS_FIXED_PAD_BOX
                if (minor < 22)
                        ao_config.pad_box = 1;
 #if HAS_FIXED_PAD_BOX
                if (minor < 22)
                        ao_config.pad_box = 1;
+               if (minor < 23)
+                       ao_config.pad_idle = 120;
 #endif
                ao_config.minor = AO_CONFIG_MINOR;
                ao_config_dirty = 1;
 #endif
                ao_config.minor = AO_CONFIG_MINOR;
                ao_config_dirty = 1;
@@ -920,6 +922,23 @@ ao_config_pad_box_set(void)
        ao_config.pad_box = ao_cmd_lex_i;
        _ao_config_edit_finish();
 }
        ao_config.pad_box = ao_cmd_lex_i;
        _ao_config_edit_finish();
 }
+
+void
+ao_config_pad_idle_show(void)
+{
+       printf ("Idle timeout: %d\n", ao_config.pad_idle);
+}
+
+void
+ao_config_pad_idle_set(void)
+{
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       _ao_config_edit_start();
+       ao_config.pad_idle = ao_cmd_lex_i;
+       _ao_config_edit_finish();
+}
 #endif
 
 struct ao_config_var {
 #endif
 
 struct ao_config_var {
@@ -1019,6 +1038,8 @@ __code struct ao_config_var ao_config_vars[] = {
 #if HAS_FIXED_PAD_BOX
        { "B <box>\0Set pad box (1-99)",
          ao_config_pad_box_set, ao_config_pad_box_show },
 #if HAS_FIXED_PAD_BOX
        { "B <box>\0Set pad box (1-99)",
          ao_config_pad_box_set, ao_config_pad_box_show },
+       { "i <seconds>\0Set idle timeout (0 disable)",
+         ao_config_pad_idle_set, ao_config_pad_idle_show },
 #endif
        { "s\0Show",
          ao_config_show,               0 },
 #endif
        { "s\0Show",
          ao_config_show,               0 },
index f4e9af441d1567309dc70a3e274ab3c6d158c3e5..3c73ea4948d6264f82c6d7079df5c2706dcaa912 100644 (file)
@@ -57,7 +57,7 @@
 #endif
 
 #define AO_CONFIG_MAJOR        1
 #endif
 
 #define AO_CONFIG_MAJOR        1
-#define AO_CONFIG_MINOR        22
+#define AO_CONFIG_MINOR        23
 
 #define AO_AES_LEN 16
 
 
 #define AO_AES_LEN 16
 
@@ -120,6 +120,7 @@ struct ao_config {
 #endif
 #if HAS_FIXED_PAD_BOX
        uint8_t         pad_box;                /* minor version 22 */
 #endif
 #if HAS_FIXED_PAD_BOX
        uint8_t         pad_box;                /* minor version 22 */
+       uint8_t         pad_idle;               /* minor version 23 */
 #endif
 };
 
 #endif
 };