diff --git a/appinfo.json b/appinfo.json index 9059dda..f9d82b7 100644 --- a/appinfo.json +++ b/appinfo.json @@ -14,7 +14,7 @@ "msgType": 0, "recency": 1, - "sgvCount": 2, + "__DEPRECATED__sgvCount": 2, "sgvs": 3, "lastSgv": 4, "trend": 5, diff --git a/src/app_keys.h b/src/app_keys.h index 731b29f..5c4443b 100644 --- a/src/app_keys.h +++ b/src/app_keys.h @@ -12,7 +12,7 @@ enum { enum { __APP_KEYS_FOR_DATA, APP_KEY_RECENCY, - APP_KEY_SGV_COUNT, + __DEPRECATED__APP_KEY_SGV_COUNT, APP_KEY_SGVS, APP_KEY_LAST_SGV, APP_KEY_TREND, diff --git a/src/app_messages.c b/src/app_messages.c new file mode 100644 index 0000000..08b0dad --- /dev/null +++ b/src/app_messages.c @@ -0,0 +1,127 @@ +#include "app_keys.h" +#include "app_messages.h" + +static const char* type_name(TupleType type) { + switch(type) { + case TUPLE_BYTE_ARRAY: return "byte array"; + case TUPLE_CSTRING: return "cstring"; + case TUPLE_UINT: return "uint"; + case TUPLE_INT: return "int"; + default: return ""; + } +} + +static bool fail_unexpected_type(uint8_t key, TupleType type, const char* expected) { + APP_LOG(APP_LOG_LEVEL_ERROR, "Expected key %d to have type %s, but has type %s", (int)key, expected, type_name(type)); + return false; +} + +static bool fail_missing_required_value(uint8_t key) { + APP_LOG(APP_LOG_LEVEL_ERROR, "Missing required value for key %d", (int)key); + return false; +} + +static bool pass_default_value(uint8_t key) { + APP_LOG(APP_LOG_LEVEL_DEBUG, "Missing value for key %d, assigning default", (int)key); + return true; +} + +bool get_int32(DictionaryIterator *data, int32_t *dest, uint8_t key, bool required, int32_t fallback) { + Tuple *t = dict_find(data, key); + if (t != NULL) { + if (t->type == TUPLE_INT) { + switch(t->length) { + case 1: *dest = t->value->int8; break; + case 2: *dest = t->value->int16; break; + default: *dest = t->value->int32; break; + } + return true; + } else if (t->type == TUPLE_UINT) { + switch(t->length) { + case 1: *dest = t->value->uint8; break; + case 2: *dest = t->value->uint16; break; + default: *dest = t->value->uint32; break; + } + return true; + } else { + return fail_unexpected_type(key, t->type, "int or uint"); + } + } else { + if (required) { + return fail_missing_required_value(key); + } else { + *dest = fallback; + return pass_default_value(key); + } + } +} + +bool get_byte_array(DictionaryIterator *data, uint8_t *dest, uint8_t key, size_t max_length, bool required, uint8_t *fallback) { + Tuple *t = dict_find(data, key); + if (t != NULL) { + if (t->type == TUPLE_BYTE_ARRAY) { + memcpy(dest, t->value->data, (t->length < max_length ? t->length : max_length) * sizeof(uint8_t)); + return true; + } else { + return fail_unexpected_type(key, t->type, "byte array"); + } + } else { + if (required) { + return fail_missing_required_value(key); + } else { + memcpy(dest, fallback, ARRAY_LENGTH(fallback)); + return pass_default_value(key); + } + } +} + +bool get_byte_array_length(DictionaryIterator *data, uint16_t *dest, uint16_t max_length, uint8_t key) { + // assumes get_byte_array has already succeeded for this key + uint16_t length = dict_find(data, key)->length; + if (max_length == 0) { + *dest = length; + } else { + *dest = length > max_length ? max_length : length; + } + return true; +} + +bool get_cstring(DictionaryIterator *data, char *dest, uint8_t key, size_t max_length, bool required, const char* fallback) { + Tuple *t = dict_find(data, key); + if (t != NULL) { + if (t->type == TUPLE_CSTRING) { + strncpy(dest, t->value->cstring, max_length); + return true; + } else { + return fail_unexpected_type(key, t->type, "cstring"); + } + } else { + if (required) { + return fail_missing_required_value(key); + } else { + strcpy(dest, fallback); + return pass_default_value(key); + } + } +} + +bool validate_data_message(DictionaryIterator *data, DataMessage *out) { + /* + * Validation is not necessary for messages from the PebbleKit JS half of + * Urchin since it is distributed with the C SDK half, but other clients + * (Pancreabble, Loop, xDrip(?)) are not guaranteed to be using exactly the + * same message format as this version of Urchin. + */ + static uint8_t zeroes[GRAPH_MAX_SGV_COUNT]; + memset(zeroes, 0, GRAPH_MAX_SGV_COUNT); + + return true + && get_int32(data, &out->recency, APP_KEY_RECENCY, false, 0) + && get_byte_array(data, out->sgvs, APP_KEY_SGVS, GRAPH_MAX_SGV_COUNT, true, NULL) + && get_byte_array_length(data, &out->sgv_count, GRAPH_MAX_SGV_COUNT, APP_KEY_SGVS) + && get_int32(data, &out->last_sgv, APP_KEY_LAST_SGV, true, 0) + && get_int32(data, &out->trend, APP_KEY_TREND, false, 0) + && get_int32(data, &out->delta, APP_KEY_DELTA, false, NO_DELTA_VALUE) + && get_cstring(data, out->status_text, APP_KEY_STATUS_TEXT, STATUS_BAR_MAX_LENGTH, false, "") + && get_byte_array(data, out->graph_extra, APP_KEY_GRAPH_EXTRA, GRAPH_MAX_SGV_COUNT, false, zeroes); +} diff --git a/src/app_messages.h b/src/app_messages.h new file mode 100644 index 0000000..7ca1cc4 --- /dev/null +++ b/src/app_messages.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include "config.h" + +typedef struct __attribute__((__packed__)) DataMessage { + int32_t recency; + uint16_t sgv_count; + uint8_t sgvs[GRAPH_MAX_SGV_COUNT]; + int32_t last_sgv; + int32_t trend; + int32_t delta; + char status_text[STATUS_BAR_MAX_LENGTH]; + uint8_t graph_extra[GRAPH_MAX_SGV_COUNT]; +} DataMessage; + +bool get_int32(DictionaryIterator *data, int32_t *dest, uint8_t key, bool required, int32_t fallback); +bool get_byte_array(DictionaryIterator *data, uint8_t *dest, uint8_t key, size_t max_length, bool required, uint8_t *fallback); +bool get_byte_array_length(DictionaryIterator *data, uint16_t *dest, uint16_t max_length, uint8_t key); +bool get_cstring(DictionaryIterator *data, char *dest, uint8_t key, size_t max_length, bool required, const char* fallback); +bool validate_data_message(DictionaryIterator *data, DataMessage *out); diff --git a/src/bg_row_element.c b/src/bg_row_element.c index c6a2af1..08d852f 100644 --- a/src/bg_row_element.c +++ b/src/bg_row_element.c @@ -92,7 +92,7 @@ void bg_row_element_destroy(BGRowElement *el) { free(el); } -void bg_row_element_update(BGRowElement *el, DictionaryIterator *data) { +void bg_row_element_update(BGRowElement *el, DataMessage *data) { last_bg_text_layer_update(el->bg_text, data); text_layer_set_font( el->bg_text, diff --git a/src/bg_row_element.h b/src/bg_row_element.h index ac9bb31..fd0ff50 100644 --- a/src/bg_row_element.h +++ b/src/bg_row_element.h @@ -1,6 +1,7 @@ #pragma once #include +#include "app_messages.h" #include "trend_arrow_component.h" typedef struct BGRowElement { @@ -12,5 +13,5 @@ typedef struct BGRowElement { BGRowElement* bg_row_element_create(Layer *parent); void bg_row_element_destroy(BGRowElement *el); -void bg_row_element_update(BGRowElement *el, DictionaryIterator *data); +void bg_row_element_update(BGRowElement *el, DataMessage *data); void bg_row_element_tick(BGRowElement *el); diff --git a/src/comm.c b/src/comm.c index d4e1f25..c6996f9 100644 --- a/src/comm.c +++ b/src/comm.c @@ -10,11 +10,14 @@ static bool update_in_progress; static AppTimer *request_timer = NULL; static AppTimer *timeout_timer = NULL; -static void (*data_callback)(DictionaryIterator *received); +static void (*data_callback)(DataMessage *data); +static void (*prefs_callback)(DictionaryIterator *received); static void schedule_update(uint32_t delay); static void request_update(); static void timeout_handler(); +static DataMessage *last_data_message; + static void clear_timer(AppTimer **timer) { if (*timer != NULL) { app_timer_cancel(*timer); @@ -65,23 +68,37 @@ static void request_update() { static void in_received_handler(DictionaryIterator *received, void *context) { phone_contact = true; update_in_progress = false; - staleness_update(received); - int msg_type = dict_find(received, APP_KEY_MSG_TYPE)->value->uint8; + + time_t now = time(NULL); + staleness_update_message_received(now); + + int32_t msg_type; + if (!get_int32(received, &msg_type, APP_KEY_MSG_TYPE, true, 0)) { + schedule_update(BAD_APP_MESSAGE_RETRY_DELAY); + return; + } + if (msg_type == MSG_TYPE_DATA) { - int32_t delay; - if (get_prefs()->update_every_minute) { - delay = 60 * 1000; + static DataMessage d; + if (validate_data_message(received, &d)) { + memcpy(last_data_message, &d, sizeof(DataMessage)); + int32_t delay; + if (get_prefs()->update_every_minute) { + delay = 60 * 1000; + } else { + int32_t next_update = (SGV_UPDATE_FREQUENCY_SECONDS - last_data_message->recency) * 1000; + delay = next_update < 0 ? LATE_DATA_UPDATE_FREQUENCY : next_update; + } + schedule_update((uint32_t) delay); + staleness_update_data_received(now, last_data_message->recency); + data_callback(last_data_message); } else { - uint32_t recency = dict_find(received, APP_KEY_RECENCY)->value->uint32; - int32_t next_update = (SGV_UPDATE_FREQUENCY_SECONDS - recency) * 1000; - delay = next_update < 0 ? LATE_DATA_UPDATE_FREQUENCY : next_update; + schedule_update(BAD_APP_MESSAGE_RETRY_DELAY); } - schedule_update((uint32_t) delay); - } - if (msg_type == MSG_TYPE_ERROR) { - schedule_update(ERROR_RETRY_DELAY); + } else if (msg_type == MSG_TYPE_PREFERENCES) { + prefs_callback(received); } else { - data_callback(received); + schedule_update(ERROR_RETRY_DELAY); } } @@ -104,8 +121,9 @@ static void bluetooth_connection_handler(bool connected) { } } -void init_comm(void (*callback)(DictionaryIterator *received)) { - data_callback = callback; +void init_comm(void (*callback_for_data)(DataMessage *data), void (*callback_for_prefs)(DictionaryIterator *received)) { + data_callback = callback_for_data; + prefs_callback = callback_for_prefs; app_message_register_inbox_received(in_received_handler); app_message_register_inbox_dropped(in_dropped_handler); app_message_register_outbox_failed(out_failed_handler); @@ -117,6 +135,8 @@ void init_comm(void (*callback)(DictionaryIterator *received)) { update_in_progress = true; timeout_timer = app_timer_register(timeout_length(), timeout_handler, NULL); + last_data_message = malloc(sizeof(DataMessage)); + app_message_open(inbound_size, outbound_size); // Request data as soon as Bluetooth reconnects @@ -124,3 +144,8 @@ void init_comm(void (*callback)(DictionaryIterator *received)) { .pebble_app_connection_handler = bluetooth_connection_handler }); } + +void deinit_comm() { + app_message_deregister_callbacks(); + free(last_data_message); +} diff --git a/src/comm.h b/src/comm.h index a093b2a..e546106 100644 --- a/src/comm.h +++ b/src/comm.h @@ -1,6 +1,7 @@ #pragma once #include +#include "app_messages.h" // Size can be up to ~390 when status bar text is 255 bytes long (as of fa6984) #define CONTENT_SIZE 512 @@ -13,5 +14,7 @@ #define IN_RETRY_DELAY 100 #define LATE_DATA_UPDATE_FREQUENCY (60*1000) #define ERROR_RETRY_DELAY (60*1000) +#define BAD_APP_MESSAGE_RETRY_DELAY (60*1000) -void init_comm(void (*callback)(DictionaryIterator *received)); +void init_comm(void (*callback_for_data)(DataMessage *data), void (*callback_for_prefs)(DictionaryIterator *received)); +void deinit_comm(); diff --git a/src/config.h b/src/config.h index 3fb3800..cef673c 100644 --- a/src/config.h +++ b/src/config.h @@ -21,6 +21,7 @@ #define GRAPH_MAX_SGV_COUNT 48 #define GRAPH_POINT_SIZE 3 #define GRAPH_INTERVAL_SIZE_SECONDS (5*60) +#define STATUS_BAR_MAX_LENGTH 256 #define BOLUS_TICK_WIDTH 2 #define BOLUS_TICK_HEIGHT 7 diff --git a/src/graph_element.c b/src/graph_element.c index b21b76e..af3a1b7 100644 --- a/src/graph_element.c +++ b/src/graph_element.c @@ -1,4 +1,3 @@ -#include "app_keys.h" #include "config.h" #include "graph_element.h" #include "layout.h" @@ -166,20 +165,11 @@ void graph_element_destroy(GraphElement *el) { free(el); } -void graph_element_update(GraphElement *el, DictionaryIterator *data) { - int count = dict_find(data, APP_KEY_SGV_COUNT)->value->int32; - count = count > GRAPH_MAX_SGV_COUNT ? GRAPH_MAX_SGV_COUNT : count; - ((GraphData*)layer_get_data(el->graph_layer))->count = count; - memcpy( - ((GraphData*)layer_get_data(el->graph_layer))->sgvs, - (uint8_t*)dict_find(data, APP_KEY_SGVS)->value->data, - count * sizeof(uint8_t) - ); - memcpy( - ((GraphData*)layer_get_data(el->graph_layer))->extra, - (uint8_t*)dict_find(data, APP_KEY_GRAPH_EXTRA)->value->data, - count * sizeof(uint8_t) - ); +void graph_element_update(GraphElement *el, DataMessage *data) { + GraphData *graph_data = layer_get_data(el->graph_layer); + graph_data->count = data->sgv_count; + memcpy(graph_data->sgvs, data->sgvs, data->sgv_count * sizeof(uint8_t)); + memcpy(graph_data->extra, data->graph_extra, data->sgv_count * sizeof(uint8_t)); layer_mark_dirty(el->graph_layer); connection_status_component_refresh(el->conn_status); } diff --git a/src/graph_element.h b/src/graph_element.h index 503724f..afc4988 100644 --- a/src/graph_element.h +++ b/src/graph_element.h @@ -1,6 +1,7 @@ #pragma once #include +#include "app_messages.h" #include "connection_status_component.h" #define GRAPH_EXTRA_BOLUS_OFFSET 0 @@ -15,12 +16,12 @@ typedef struct GraphElement { typedef struct GraphData { GColor color; - int count; + uint16_t count; uint8_t* sgvs; uint8_t* extra; } GraphData; GraphElement* graph_element_create(Layer *parent); void graph_element_destroy(GraphElement *el); -void graph_element_update(GraphElement *el, DictionaryIterator *data); +void graph_element_update(GraphElement *el, DataMessage *data); void graph_element_tick(GraphElement *el); diff --git a/src/js/main.js b/src/js/main.js index 2862d12..95f4e02 100644 --- a/src/js/main.js +++ b/src/js/main.js @@ -42,7 +42,6 @@ function main(c) { sendMessage({ msgType: c.MSG_TYPE_DATA, recency: format.recency(sgvs), - sgvCount: ys.length, // XXX: divide BG by 2 to fit into 1 byte sgvs: ys.map(function(y) { return Math.min(255, Math.floor(y / 2)); }), lastSgv: format.lastSgv(sgvs), diff --git a/src/main.c b/src/main.c index 577abc1..83e0b52 100644 --- a/src/main.c +++ b/src/main.c @@ -1,6 +1,6 @@ #include -#include "app_keys.h" +#include "app_messages.h" #include "bg_row_element.h" #include "comm.h" #include "config.h" @@ -97,41 +97,41 @@ static Window *create_main_window() { return window; } -static void data_callback(DictionaryIterator *received) { - int msg_type = dict_find(received, APP_KEY_MSG_TYPE)->value->uint8; - if (msg_type == MSG_TYPE_DATA) { - if (s_time_element != NULL) { - time_element_update(s_time_element, received); - } - if (s_graph_element != NULL) { - graph_element_update(s_graph_element, received); - } - if (s_sidebar_element != NULL) { - sidebar_element_update(s_sidebar_element, received); - } - if (s_status_bar_element != NULL) { - status_bar_element_update(s_status_bar_element, received); - } - if (s_bg_row_element != NULL) { - bg_row_element_update(s_bg_row_element, received); - } - } else if (msg_type == MSG_TYPE_PREFERENCES) { - set_prefs(received); - // recreate the window in case layout preferences have changed - window_stack_remove(s_window, false); - window_destroy(s_window); - s_window = create_main_window(); +static void data_callback(DataMessage *data) { + if (s_time_element != NULL) { + time_element_update(s_time_element, data); + } + if (s_graph_element != NULL) { + graph_element_update(s_graph_element, data); + } + if (s_sidebar_element != NULL) { + sidebar_element_update(s_sidebar_element, data); + } + if (s_status_bar_element != NULL) { + status_bar_element_update(s_status_bar_element, data); } + if (s_bg_row_element != NULL) { + bg_row_element_update(s_bg_row_element, data); + } +} + +static void prefs_callback(DictionaryIterator *received) { + set_prefs(received); + // recreate the window in case layout preferences have changed + window_stack_remove(s_window, false); + window_destroy(s_window); + s_window = create_main_window(); } static void init(void) { init_prefs(); - init_comm(data_callback); + init_comm(data_callback, prefs_callback); s_window = create_main_window(); } static void deinit(void) { window_destroy(s_window); + deinit_comm(); deinit_prefs(); } diff --git a/src/sidebar_element.c b/src/sidebar_element.c index 06bc66c..1e3a097 100644 --- a/src/sidebar_element.c +++ b/src/sidebar_element.c @@ -41,7 +41,7 @@ void sidebar_element_destroy(SidebarElement *el) { free(el); } -void sidebar_element_update(SidebarElement *el, DictionaryIterator *data) { +void sidebar_element_update(SidebarElement *el, DataMessage *data) { last_bg_text_layer_update(el->last_bg_text, data); trend_arrow_component_update(el->trend, data); delta_text_layer_update(el->delta_text, data); diff --git a/src/sidebar_element.h b/src/sidebar_element.h index 0f820ab..1154fbf 100644 --- a/src/sidebar_element.h +++ b/src/sidebar_element.h @@ -1,6 +1,7 @@ #pragma once #include +#include "app_messages.h" #include "trend_arrow_component.h" typedef struct SidebarElement { @@ -11,5 +12,5 @@ typedef struct SidebarElement { SidebarElement* sidebar_element_create(Layer *parent); void sidebar_element_destroy(SidebarElement *el); -void sidebar_element_update(SidebarElement *el, DictionaryIterator *data); +void sidebar_element_update(SidebarElement *el, DataMessage *data); void sidebar_element_tick(SidebarElement *el); diff --git a/src/staleness.c b/src/staleness.c index 5263ade..444b14f 100644 --- a/src/staleness.c +++ b/src/staleness.c @@ -82,13 +82,14 @@ ConnectionIssue connection_issue() { } } -void staleness_update(DictionaryIterator *data) { +void staleness_update_message_received(time_t received_at) { phone_contact = true; - time_t now = time(NULL); - last_phone_contact = now; - if (dict_find(data, APP_KEY_MSG_TYPE)->value->uint8 == MSG_TYPE_DATA) { - data_received = true; - last_successful_phone_contact = now; - last_data_staleness_wrt_phone = dict_find(data, APP_KEY_RECENCY)->value->int32; - } + last_phone_contact = received_at; +} + +void staleness_update_data_received(time_t received_at, int32_t recency) { + phone_contact = true; + data_received = true; + last_successful_phone_contact = received_at; + last_data_staleness_wrt_phone = recency; } diff --git a/src/staleness.h b/src/staleness.h index 28e9af5..083c69a 100644 --- a/src/staleness.h +++ b/src/staleness.h @@ -22,4 +22,5 @@ int rig_to_web_staleness(); int total_data_staleness(); int graph_staleness_padding(); ConnectionIssue connection_issue(); -void staleness_update(DictionaryIterator *data); +void staleness_update_message_received(time_t received_at); +void staleness_update_data_received(time_t received_at, int32_t recency); diff --git a/src/status_bar_element.c b/src/status_bar_element.c index dad5296..c5977e9 100644 --- a/src/status_bar_element.c +++ b/src/status_bar_element.c @@ -63,12 +63,10 @@ void status_bar_element_destroy(StatusBarElement *el) { free(el); } -void status_bar_element_update(StatusBarElement *el, DictionaryIterator *data) { - text_layer_set_text( - el->text, - dict_find(data, APP_KEY_STATUS_TEXT)->value->cstring - ); - status_bar_element_tick(el); +void status_bar_element_update(StatusBarElement *el, DataMessage *data) { + static char buffer[STATUS_BAR_MAX_LENGTH]; + strcpy(buffer, data->status_text); + text_layer_set_text(el->text, buffer); } void status_bar_element_tick(StatusBarElement *el) {} diff --git a/src/status_bar_element.h b/src/status_bar_element.h index 6eadebb..97bd828 100644 --- a/src/status_bar_element.h +++ b/src/status_bar_element.h @@ -1,6 +1,7 @@ #pragma once #include +#include "app_messages.h" #include "battery_component.h" typedef struct StatusBarElement { @@ -10,5 +11,5 @@ typedef struct StatusBarElement { StatusBarElement* status_bar_element_create(Layer *parent); void status_bar_element_destroy(StatusBarElement *el); -void status_bar_element_update(StatusBarElement *el, DictionaryIterator *data); +void status_bar_element_update(StatusBarElement *el, DataMessage *data); void status_bar_element_tick(StatusBarElement *el); diff --git a/src/text_updates.c b/src/text_updates.c index a7ffc23..9f2a42b 100644 --- a/src/text_updates.c +++ b/src/text_updates.c @@ -4,25 +4,23 @@ #include "text_updates.h" #include "format.h" -void last_bg_text_layer_update(TextLayer *text_layer, DictionaryIterator *data) { +void last_bg_text_layer_update(TextLayer *text_layer, DataMessage *data) { static char last_bg_buffer[8]; - int mgdl = dict_find(data, APP_KEY_LAST_SGV)->value->int32; - format_bg(last_bg_buffer, sizeof(last_bg_buffer), mgdl, false, get_prefs()->mmol); + format_bg(last_bg_buffer, sizeof(last_bg_buffer), data->last_sgv, false, get_prefs()->mmol); text_layer_set_text(text_layer, last_bg_buffer); } -bool is_bg_special_value(DictionaryIterator *data) { - int mgdl = dict_find(data, APP_KEY_LAST_SGV)->value->int32; - return get_error_string(mgdl) != NULL; +bool is_bg_special_value(DataMessage *data) { + return get_error_string(data->last_sgv) != NULL; } -void delta_text_layer_update(TextLayer *text_layer, DictionaryIterator *data) { +void delta_text_layer_update(TextLayer *text_layer, DataMessage *data) { static char delta_buffer[8]; int delta; if (graph_staleness_padding() > 0) { delta = NO_DELTA_VALUE; } else { - delta = dict_find(data, APP_KEY_DELTA)->value->int32; + delta = data->delta; } if (delta == NO_DELTA_VALUE) { diff --git a/src/text_updates.h b/src/text_updates.h index 6fdc42e..3868e95 100644 --- a/src/text_updates.h +++ b/src/text_updates.h @@ -1,7 +1,8 @@ #pragma once #include +#include "app_messages.h" -void last_bg_text_layer_update(TextLayer *text_layer, DictionaryIterator *data); -bool is_bg_special_value(DictionaryIterator *data); -void delta_text_layer_update(TextLayer *text_layer, DictionaryIterator *data); +void last_bg_text_layer_update(TextLayer *text_layer, DataMessage *data); +bool is_bg_special_value(DataMessage *data); +void delta_text_layer_update(TextLayer *text_layer, DataMessage *data); diff --git a/src/time_element.c b/src/time_element.c index 05b1ab5..0798e88 100644 --- a/src/time_element.c +++ b/src/time_element.c @@ -85,7 +85,7 @@ void time_element_destroy(TimeElement* el) { free(el); } -void time_element_update(TimeElement *el, DictionaryIterator *data) {} +void time_element_update(TimeElement *el, DataMessage *data) {} void time_element_tick(TimeElement *el) { static char buffer[16]; diff --git a/src/time_element.h b/src/time_element.h index 7f4154b..95b46ac 100644 --- a/src/time_element.h +++ b/src/time_element.h @@ -1,6 +1,7 @@ #pragma once #include +#include "app_messages.h" #include "battery_component.h" typedef struct TimeElement { @@ -10,5 +11,5 @@ typedef struct TimeElement { TimeElement* time_element_create(Layer *parent); void time_element_destroy(TimeElement *el); -void time_element_update(TimeElement *el, DictionaryIterator *data); +void time_element_update(TimeElement *el, DataMessage *data); void time_element_tick(TimeElement *el); diff --git a/src/trend_arrow_component.c b/src/trend_arrow_component.c index f80a54c..7edef05 100644 --- a/src/trend_arrow_component.c +++ b/src/trend_arrow_component.c @@ -1,4 +1,3 @@ -#include "app_keys.h" #include "config.h" #include "layout.h" #include "staleness.h" @@ -49,27 +48,26 @@ void trend_arrow_component_destroy(TrendArrowComponent *c) { free(c); } -void trend_arrow_component_update(TrendArrowComponent *c, DictionaryIterator *data) { +void trend_arrow_component_update(TrendArrowComponent *c, DataMessage *data) { if (graph_staleness_padding() > 0) { c->last_trend = -1; layer_set_hidden(bitmap_layer_get_layer(c->icon_layer), true); return; } - int trend = dict_find(data, APP_KEY_TREND)->value->int32; - if (trend == c->last_trend) { + if (data->trend == c->last_trend) { return; } - c->last_trend = trend; + c->last_trend = data->trend; - if (TREND_ICONS[trend] == NO_ICON) { + if (TREND_ICONS[data->trend] == NO_ICON) { layer_set_hidden(bitmap_layer_get_layer(c->icon_layer), true); } else { layer_set_hidden(bitmap_layer_get_layer(c->icon_layer), false); if (c->icon_bitmap != NULL) { gbitmap_destroy(c->icon_bitmap); } - c->icon_bitmap = gbitmap_create_with_resource(TREND_ICONS[trend]); + c->icon_bitmap = gbitmap_create_with_resource(TREND_ICONS[data->trend]); bitmap_layer_set_bitmap(c->icon_layer, c->icon_bitmap); } } diff --git a/src/trend_arrow_component.h b/src/trend_arrow_component.h index e921c24..512aa48 100644 --- a/src/trend_arrow_component.h +++ b/src/trend_arrow_component.h @@ -1,6 +1,7 @@ #pragma once #include +#include "app_messages.h" typedef struct TrendArrowComponent { BitmapLayer *icon_layer; @@ -13,6 +14,6 @@ int trend_arrow_component_height(); int trend_arrow_component_vertical_padding(); TrendArrowComponent* trend_arrow_component_create(Layer *parent, int x, int y); void trend_arrow_component_destroy(TrendArrowComponent *c); -void trend_arrow_component_update(TrendArrowComponent *c, DictionaryIterator *data); +void trend_arrow_component_update(TrendArrowComponent *c, DataMessage *data); void trend_arrow_component_reposition(TrendArrowComponent *c, int x, int y); bool trend_arrow_component_hidden(TrendArrowComponent *c);