battery-minus_worker.c (3988B)
1 /* 2 * Copyright (c) 2015, Natacha Porté 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include <pebble_worker.h> 18 19 #include "../src/storage.h" 20 21 static struct event current_page[PAGE_LENGTH]; 22 static unsigned index; 23 static BatteryChargeState previous; 24 25 /****************************** 26 * LOW LEVEL EVENT MANAGEMENT * 27 ******************************/ 28 29 static void 30 append_event(struct event *event) { 31 int ret; 32 33 if (index >= PAGE_LENGTH) { 34 APP_LOG(APP_LOG_LEVEL_ERROR, 35 "invalid value %u for index", index); 36 return; 37 } 38 39 current_page[index] = *event; 40 index = (index + 1) % PAGE_LENGTH; 41 42 ret = persist_write_data(1, current_page, sizeof current_page); 43 if (ret < 0 || (unsigned)ret != sizeof current_page) 44 APP_LOG(APP_LOG_LEVEL_ERROR, 45 "unexpected return value %d for persist_wride_data", 46 ret); 47 } 48 49 static uint8_t 50 convert_state(BatteryChargeState *state) { 51 if (state->charge_percent > 100) return ANOMALOUS_VALUE; 52 return state->charge_percent | (state->is_charging ? 0x80 : 0); 53 } 54 55 /********************* 56 * HIGH LEVEL EVENTS * 57 *********************/ 58 59 static void 60 new_event(uint8_t before, uint8_t after) { 61 struct event event; 62 63 event.time = time(0); 64 event.before = before; 65 event.after = after; 66 append_event(&event); 67 } 68 69 static void 70 app_started(void) { 71 uint8_t current = convert_state(&previous); 72 73 if (current == ANOMALOUS_VALUE) { 74 new_event(APP_STARTED, UNKNOWN); 75 new_event(ANOMALOUS_VALUE, previous.charge_percent); 76 } else 77 new_event(APP_STARTED, current); 78 } 79 80 static void 81 app_stopped(void) { 82 uint8_t current = convert_state(&previous); 83 84 new_event(APP_CLOSED, current == ANOMALOUS_VALUE ? UNKNOWN : current); 85 } 86 87 static void 88 battery_update(BatteryChargeState *before, BatteryChargeState *after) { 89 uint8_t i_before = convert_state(before); 90 uint8_t i_after = convert_state(after); 91 92 if (i_after == ANOMALOUS_VALUE) 93 new_event(ANOMALOUS_VALUE, after->charge_percent); 94 else 95 new_event(i_before == ANOMALOUS_VALUE ? UNKNOWN : i_before, 96 i_after); 97 } 98 99 /***************** 100 * EVENT HANDLER * 101 *****************/ 102 103 static void 104 battery_handler(BatteryChargeState charge) { 105 if (charge.charge_percent == previous.charge_percent 106 && charge.is_charging == previous.is_charging) 107 return; 108 109 battery_update(&previous, &charge); 110 previous = charge; 111 } 112 113 /*********************************** 114 * INITIALIZATION AND FINALIZATION * 115 ***********************************/ 116 117 static bool 118 init(void) { 119 int ret = persist_read_data(1, current_page, sizeof current_page); 120 121 if (ret == E_DOES_NOT_EXIST) { 122 APP_LOG(APP_LOG_LEVEL_INFO, 123 "no configuration found, initializing to zero"); 124 memset(current_page, 0, sizeof current_page); 125 } else if (ret != sizeof current_page) { 126 APP_LOG(APP_LOG_LEVEL_ERROR, 127 "unexpected return value %d for persist_read_data", 128 ret); 129 return false; 130 } else if (current_page[0].time) { 131 for (index = 1; 132 index < PAGE_LENGTH 133 && current_page[index - 1].time < current_page[index].time; 134 index += 1); 135 } else 136 index = 0; 137 138 previous = battery_state_service_peek(); 139 app_started(); 140 141 battery_state_service_subscribe(&battery_handler); 142 143 return true; 144 } 145 146 static void 147 deinit(void) { 148 battery_state_service_unsubscribe(); 149 app_stopped(); 150 } 151 152 int 153 main(void) { 154 if (!init()) return 1; 155 worker_event_loop(); 156 deinit(); 157 return 0; 158 }