Add fallback alarm
This commit is contained in:
+91
-53
@@ -2,12 +2,12 @@
|
|||||||
#include <pebble.h>
|
#include <pebble.h>
|
||||||
|
|
||||||
// types
|
// types
|
||||||
typedef struct SetterTime {
|
typedef struct TheTime {
|
||||||
uint8_t HourWIP;
|
uint8_t HourWIP;
|
||||||
uint8_t MinuteWIP;
|
uint8_t MinuteWIP;
|
||||||
uint8_t HourSet;
|
uint8_t HourSet;
|
||||||
uint8_t MinuteSet;
|
uint8_t MinuteSet;
|
||||||
} __attribute__((__packed__)) SetterTime;
|
} __attribute__((__packed__)) TheTime;
|
||||||
|
|
||||||
// layer-age
|
// layer-age
|
||||||
static Window *s_window;
|
static Window *s_window;
|
||||||
@@ -30,7 +30,7 @@ static GBitmap *s_check_bmp;
|
|||||||
// global vars
|
// global vars
|
||||||
//// setter
|
//// setter
|
||||||
static uint8_t s_highlight_pos = 0;
|
static uint8_t s_highlight_pos = 0;
|
||||||
static struct SetterTime s_setter_time;
|
static struct TheTime s_the_time;
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
//// setter
|
//// setter
|
||||||
@@ -42,24 +42,49 @@ static const GColor s_highlight_color = GColorMediumAquamarine;
|
|||||||
|
|
||||||
/////////////////////////////////
|
/////////////////////////////////
|
||||||
|
|
||||||
static void glance_reload_callback(AppGlanceReloadSession *session, size_t limit, void *context) {
|
static void glance_reload_callback(AppGlanceReloadSession *session, size_t limit, void *target) {
|
||||||
static char s_glance_buffer[11];
|
static char s_glance_buffer[11];
|
||||||
snprintf(s_glance_buffer, sizeof(s_glance_buffer), "Up @ %02d:%02d", s_setter_time.HourSet, s_setter_time.MinuteSet);
|
snprintf(s_glance_buffer, sizeof(s_glance_buffer), "Up @ %02d:%02d", s_the_time.HourSet, s_the_time.MinuteSet);
|
||||||
AppGlanceSlice slice = {
|
AppGlanceSlice slice = {
|
||||||
.expiration_time = time(NULL) + (7 * SECONDS_PER_DAY),
|
.expiration_time = (time_t)(uintptr_t)target,
|
||||||
.layout.icon = APP_GLANCE_SLICE_DEFAULT_ICON,
|
.layout.icon = APP_GLANCE_SLICE_DEFAULT_ICON,
|
||||||
.layout.subtitle_template_string = s_glance_buffer,
|
.layout.subtitle_template_string = s_glance_buffer,
|
||||||
};
|
};
|
||||||
app_glance_add_slice(session, slice);
|
app_glance_add_slice(session, slice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns (passes through) the negative value from wakeup_schedule
|
||||||
|
// when an error is encountered
|
||||||
|
static int8_t schedule_main_alarm() {
|
||||||
|
time_t now = time(NULL);
|
||||||
|
struct tm now_tm = *localtime(&now);
|
||||||
|
struct tm target_tm = now_tm;
|
||||||
|
target_tm.tm_hour = s_the_time.HourWIP;
|
||||||
|
target_tm.tm_min = s_the_time.MinuteWIP;
|
||||||
|
target_tm.tm_sec = 0;
|
||||||
|
time_t target = mktime(&target_tm);
|
||||||
|
if (target <= now) {
|
||||||
|
target += SECONDS_PER_DAY;
|
||||||
|
}
|
||||||
|
wakeup_cancel_all();
|
||||||
|
WakeupId status = wakeup_schedule(target, 0, true);
|
||||||
|
if (status < 0) {
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "SCHEDULING ERROR: %d", status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
s_the_time.HourSet = s_the_time.HourWIP;
|
||||||
|
s_the_time.MinuteSet = s_the_time.MinuteWIP;
|
||||||
|
app_glance_reload(glance_reload_callback, (void *)(uintptr_t)target);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void setter_seconds_handler(struct tm *tick_time, TimeUnits units_changed) {
|
static void setter_seconds_handler(struct tm *tick_time, TimeUnits units_changed) {
|
||||||
struct tm now_tm = *tick_time;
|
struct tm now_tm = *tick_time;
|
||||||
|
|
||||||
// build the target time today
|
// build the target time today
|
||||||
struct tm target_tm = now_tm;
|
struct tm target_tm = now_tm;
|
||||||
target_tm.tm_hour = s_setter_time.HourSet;
|
target_tm.tm_hour = s_the_time.HourSet;
|
||||||
target_tm.tm_min = s_setter_time.MinuteSet;
|
target_tm.tm_min = s_the_time.MinuteSet;
|
||||||
target_tm.tm_sec = 0;
|
target_tm.tm_sec = 0;
|
||||||
|
|
||||||
time_t now = mktime(&now_tm);
|
time_t now = mktime(&now_tm);
|
||||||
@@ -88,24 +113,24 @@ static void update_countdown_display() {
|
|||||||
|
|
||||||
static void update_setter_display() {
|
static void update_setter_display() {
|
||||||
static char s_setter_buffer[PBL_IF_ROUND_ELSE(8, 12)];
|
static char s_setter_buffer[PBL_IF_ROUND_ELSE(8, 12)];
|
||||||
snprintf(s_setter_buffer, sizeof(s_setter_buffer), PBL_IF_ROUND_ELSE("%02d : %02d", "%02d : %02d"), s_setter_time.HourWIP, s_setter_time.MinuteWIP);
|
snprintf(s_setter_buffer, sizeof(s_setter_buffer), PBL_IF_ROUND_ELSE("%02d : %02d", "%02d : %02d"), s_the_time.HourWIP, s_the_time.MinuteWIP);
|
||||||
text_layer_set_text(s_setter_txt_layer, s_setter_buffer);
|
text_layer_set_text(s_setter_txt_layer, s_setter_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setter_up_click_handler(void *recognizer, void *ctx) {
|
static void setter_up_click_handler(void *recognizer, void *ctx) {
|
||||||
switch (s_highlight_pos) {
|
switch (s_highlight_pos) {
|
||||||
case 0:
|
case 0:
|
||||||
if (s_setter_time.HourWIP == 23) {
|
if (s_the_time.HourWIP == 23) {
|
||||||
s_setter_time.HourWIP = 0;
|
s_the_time.HourWIP = 0;
|
||||||
} else {
|
} else {
|
||||||
s_setter_time.HourWIP++;
|
s_the_time.HourWIP++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (s_setter_time.MinuteWIP == 59) {
|
if (s_the_time.MinuteWIP == 59) {
|
||||||
s_setter_time.MinuteWIP = 0;
|
s_the_time.MinuteWIP = 0;
|
||||||
} else {
|
} else {
|
||||||
s_setter_time.MinuteWIP++;
|
s_the_time.MinuteWIP++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -117,17 +142,17 @@ static void setter_up_click_handler(void *recognizer, void *ctx) {
|
|||||||
static void setter_down_click_handler(void *recognizer, void *ctx) {
|
static void setter_down_click_handler(void *recognizer, void *ctx) {
|
||||||
switch (s_highlight_pos) {
|
switch (s_highlight_pos) {
|
||||||
case 0:
|
case 0:
|
||||||
if (s_setter_time.HourWIP == 0) {
|
if (s_the_time.HourWIP == 0) {
|
||||||
s_setter_time.HourWIP = 23;
|
s_the_time.HourWIP = 23;
|
||||||
} else {
|
} else {
|
||||||
s_setter_time.HourWIP--;
|
s_the_time.HourWIP--;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (s_setter_time.MinuteWIP == 0) {
|
if (s_the_time.MinuteWIP == 0) {
|
||||||
s_setter_time.MinuteWIP = 59;
|
s_the_time.MinuteWIP = 59;
|
||||||
} else {
|
} else {
|
||||||
s_setter_time.MinuteWIP--;
|
s_the_time.MinuteWIP--;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -138,42 +163,20 @@ static void setter_down_click_handler(void *recognizer, void *ctx) {
|
|||||||
|
|
||||||
static void setter_select_click_handler(void *recognizer, void *ctx) {
|
static void setter_select_click_handler(void *recognizer, void *ctx) {
|
||||||
if (s_highlight_pos == 2) {
|
if (s_highlight_pos == 2) {
|
||||||
// schedule wakeup
|
int8_t status = schedule_main_alarm();
|
||||||
time_t now = time(NULL);
|
|
||||||
struct tm now_tm = *localtime(&now);
|
|
||||||
struct tm target_tm = now_tm;
|
|
||||||
target_tm.tm_hour = s_setter_time.HourWIP;
|
|
||||||
target_tm.tm_min = s_setter_time.MinuteWIP;
|
|
||||||
target_tm.tm_sec = 0;
|
|
||||||
time_t target = mktime(&target_tm);
|
|
||||||
if (target <= now) {
|
|
||||||
target += SECONDS_PER_DAY;
|
|
||||||
}
|
|
||||||
wakeup_cancel_all();
|
|
||||||
WakeupId status;
|
|
||||||
for (int i = 0; i < 8; ++i) {
|
|
||||||
status = wakeup_schedule(target, 0, true);
|
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
APP_LOG(APP_LOG_LEVEL_DEBUG, "SCHEDULING ERROR: %d", status);
|
return; // early return to avoid indicating alarm was set when it was not
|
||||||
return;
|
|
||||||
}
|
|
||||||
target += SECONDS_PER_DAY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// persist
|
// persist
|
||||||
s_setter_time.HourSet = s_setter_time.HourWIP;
|
persist_write_int(STORAGE_KEY_ALARM_HOUR, s_the_time.HourSet);
|
||||||
s_setter_time.MinuteSet = s_setter_time.MinuteWIP;
|
persist_write_int(STORAGE_KEY_ALARM_MINUTE, s_the_time.MinuteSet);
|
||||||
persist_write_int(STORAGE_KEY_ALARM_HOUR, s_setter_time.HourSet);
|
|
||||||
persist_write_int(STORAGE_KEY_ALARM_MINUTE, s_setter_time.MinuteSet);
|
|
||||||
|
|
||||||
// update countdown immediately
|
// update countdown immediately
|
||||||
update_countdown_display();
|
update_countdown_display();
|
||||||
|
|
||||||
// move selection back to start
|
// move selection back to start
|
||||||
s_highlight_pos = 0;
|
s_highlight_pos = 0;
|
||||||
|
|
||||||
// set app glance
|
|
||||||
app_glance_reload(glance_reload_callback, NULL);
|
|
||||||
} else {
|
} else {
|
||||||
s_highlight_pos++;
|
s_highlight_pos++;
|
||||||
}
|
}
|
||||||
@@ -183,7 +186,7 @@ static void setter_select_click_handler(void *recognizer, void *ctx) {
|
|||||||
|
|
||||||
static void setter_back_click_handler(void *recognizer, void *ctx) {
|
static void setter_back_click_handler(void *recognizer, void *ctx) {
|
||||||
if (s_highlight_pos == 0) {
|
if (s_highlight_pos == 0) {
|
||||||
window_stack_pop_all(true); // exit app
|
window_stack_pop_all(true);
|
||||||
} else {
|
} else {
|
||||||
s_highlight_pos--;
|
s_highlight_pos--;
|
||||||
}
|
}
|
||||||
@@ -224,11 +227,6 @@ static void highlight_layer_update_proc(Layer *layer, GContext *ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void setter_window_load() {
|
static void setter_window_load() {
|
||||||
s_setter_time.HourSet = persist_read_int(STORAGE_KEY_ALARM_HOUR);
|
|
||||||
s_setter_time.MinuteSet = persist_read_int(STORAGE_KEY_ALARM_MINUTE);
|
|
||||||
s_setter_time.HourWIP = s_setter_time.HourSet;
|
|
||||||
s_setter_time.MinuteWIP = s_setter_time.MinuteSet;
|
|
||||||
|
|
||||||
Layer *window_layer = window_get_root_layer(s_window);
|
Layer *window_layer = window_get_root_layer(s_window);
|
||||||
|
|
||||||
// top&bottom bars
|
// top&bottom bars
|
||||||
@@ -293,7 +291,23 @@ static void setter_window_unload() {
|
|||||||
layer_destroy(s_top_bar_layer);
|
layer_destroy(s_top_bar_layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void schedule_fallback_alarm() {
|
||||||
|
wakeup_cancel_all();
|
||||||
|
time_t target_time = time(NULL);
|
||||||
|
WakeupId status;
|
||||||
|
while (true) {
|
||||||
|
target_time += 15;
|
||||||
|
status = wakeup_schedule(target_time, 0, true);
|
||||||
|
if (status >= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void alarm_seconds_handler(struct tm *tick_time, TimeUnits units_changed) {
|
static void alarm_seconds_handler(struct tm *tick_time, TimeUnits units_changed) {
|
||||||
|
if (tick_time->tm_sec % 15 == 0) {
|
||||||
|
schedule_fallback_alarm();
|
||||||
|
}
|
||||||
vibes_short_pulse();
|
vibes_short_pulse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,6 +321,7 @@ static void alarm_window_load() {
|
|||||||
text_layer_set_text(s_alarm_txt_layer, "IMAGINE THIS IS A TRIANGLE");
|
text_layer_set_text(s_alarm_txt_layer, "IMAGINE THIS IS A TRIANGLE");
|
||||||
layer_add_child(window_layer, text_layer_get_layer(s_alarm_txt_layer));
|
layer_add_child(window_layer, text_layer_get_layer(s_alarm_txt_layer));
|
||||||
|
|
||||||
|
schedule_fallback_alarm();
|
||||||
tick_timer_service_subscribe(SECOND_UNIT, alarm_seconds_handler);
|
tick_timer_service_subscribe(SECOND_UNIT, alarm_seconds_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,12 +329,35 @@ static void alarm_window_unload() {
|
|||||||
text_layer_destroy(s_alarm_txt_layer);
|
text_layer_destroy(s_alarm_txt_layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEBUG: logic will eventually be mapped to when triangle is solved
|
||||||
|
static void alarm_select_click_handler(void *recognizer, void *ctx) {
|
||||||
|
wakeup_cancel_all();
|
||||||
|
int8_t status = schedule_main_alarm();
|
||||||
|
while (status < 0) {
|
||||||
|
s_the_time.MinuteWIP++;
|
||||||
|
if (s_the_time.MinuteWIP >= 60) {
|
||||||
|
s_the_time.MinuteWIP = 0;
|
||||||
|
s_the_time.HourWIP++;
|
||||||
|
if (s_the_time.HourWIP >= 24) {
|
||||||
|
s_the_time.HourWIP = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
status = schedule_main_alarm();
|
||||||
|
}
|
||||||
|
window_stack_pop_all(true);
|
||||||
|
}
|
||||||
|
|
||||||
static void alarm_click_config_provider(void *ctx) {
|
static void alarm_click_config_provider(void *ctx) {
|
||||||
window_single_click_subscribe(BUTTON_ID_BACK, NULL);
|
window_single_click_subscribe(BUTTON_ID_BACK, NULL);
|
||||||
|
window_long_click_subscribe(BUTTON_ID_SELECT, 5000, alarm_select_click_handler, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init() {
|
static void init() {
|
||||||
s_window = window_create();
|
s_window = window_create();
|
||||||
|
s_the_time.HourWIP = persist_read_int(STORAGE_KEY_ALARM_HOUR);
|
||||||
|
s_the_time.MinuteWIP = persist_read_int(STORAGE_KEY_ALARM_MINUTE);
|
||||||
|
s_the_time.HourSet = s_the_time.HourWIP;
|
||||||
|
s_the_time.MinuteSet = s_the_time.MinuteWIP;
|
||||||
|
|
||||||
switch (launch_reason()) {
|
switch (launch_reason()) {
|
||||||
case APP_LAUNCH_WAKEUP:
|
case APP_LAUNCH_WAKEUP:
|
||||||
|
|||||||
Reference in New Issue
Block a user