From 8668d305269379aab4de9b9331437e29ceaf6c68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thiago=20Vin=C3=ADcius=20Freire=20de=20Ara=C3=BAjo=20Ribei?= =?UTF-8?q?ro?= Date: Sat, 4 Apr 2015 21:08:16 -0300 Subject: [PATCH 1/6] Use timestamps instead of counting seconds * Break down Timer.current_time into two fields: * Timer.start_timestamp * Timer.paused_offset Combining those two with a reference timestamp (usually 'now'), it is possible to calculate the ellapsed time. The benefits are: that we don't have to rely on the app_timer_register callback; Timers are able to be restored to the correct time, after being backgrounded, or even if the Pebble Smartwatch has been powered off in between launches; It leaves the task of tracking the passage of time up to Pebble itself, where it excels. The downside is that the timestamp depends on the local time, since there is currently no API to use another time. Because of that, the timers will be affected by changing timezones or when entering or leaving DST. In order to avoid this, we need to use a time source that is increasing and monotonic. * Get rid of app_timer_register. * Use TickTimerService firing at each SECOND_UNIT to update the timers. NOTE: This commit changes the timer data structure, but leaves migration. This is going to be fixed soon. --- src/common.c | 6 +- src/common.h | 2 +- src/timer.c | 195 +++++++++++++++++++----------------- src/timer.h | 20 ++-- src/timers.c | 73 ++++++++++---- src/timers.h | 3 + src/windows/win-controls.c | 9 +- src/windows/win-main.c | 19 ++-- src/windows/win-timer-add.c | 3 +- src/windows/win-timer.c | 9 +- 10 files changed, 203 insertions(+), 136 deletions(-) diff --git a/src/common.c b/src/common.c index 5137f5e..0eea5a3 100644 --- a/src/common.c +++ b/src/common.c @@ -47,9 +47,9 @@ graphics_draw_text(ctx, text, GTextAlignmentLeft, NULL); } -void timer_draw_row(Timer* timer, GContext* ctx) { +void timer_draw_row(Timer* timer, TimerTimestamp timestamp, GContext* ctx) { char* time_left = malloc(12); - timer_time_str(timer->current_time, settings()->timers_hours, time_left, 12); + timer_display_str(timer, timestamp, settings()->timers_hours, time_left, 12); graphics_context_set_text_color(ctx, GColorBlack); graphics_context_set_fill_color(ctx, GColorBlack); @@ -95,7 +95,7 @@ void timer_draw_row(Timer* timer, GContext* ctx) { } if (timer->type == TIMER_TYPE_TIMER) { - uint8_t width = (144 * timer->current_time) / timer->length; + uint8_t width = (144 * timer_get_display_time(timer, timestamp)) / timer->length; graphics_fill_rect(ctx, GRect(0, 31, width, 2), 0, GCornerNone); } diff --git a/src/common.h b/src/common.h index 8e98e6f..4847dc6 100644 --- a/src/common.h +++ b/src/common.h @@ -35,6 +35,6 @@ src/common.h #include "timer.h" void menu_draw_row_icon_text(GContext* ctx, char* text, GBitmap* icon); -void timer_draw_row(Timer* timer, GContext* ctx); +void timer_draw_row(Timer* timer, TimerTimestamp reference, GContext* ctx); void menu_draw_option(GContext* ctx, char* option, char* value); void uppercase(char* str); diff --git a/src/timer.c b/src/timer.c index c217ea6..399adc0 100644 --- a/src/timer.c +++ b/src/timer.c @@ -36,14 +36,62 @@ src/timer.c #include "settings.h" #include "windows/win-vibrate.h" -static void timer_tick(void* context); -static void timer_finish(Timer* timer); -static void timer_schedule_tick(Timer* timer); -static void timer_cancel_tick(Timer* timer); +static void timer_finish(Timer* timer, TimerTimestamp reference); static void timer_schedule_wakeup(Timer* timer, uint16_t offset); static void timer_cancel_wakeup(Timer* timer); static void timer_set_id(Timer* timer); static void timer_completed_action(Timer* timer); +static void timer_transition_to_stop(Timer* timer, TimerTimestamp reference_time); +static void timer_transition_to_start(Timer* timer, TimerTimestamp reference_time); +static void timer_transition_to(Timer* timer, TimerTimestamp reference_time, TimerStatus new_status); +static void timer_set_running_time(Timer* timer, TimerTimestamp reference_time, int32_t running_time); +static bool timer_has_finished(Timer* timer, TimerTimestamp reference); + +TimerTimestamp timer_get_end_timestamp(Timer* timer) { + switch (timer->type) { + case TIMER_TYPE_TIMER: return timer->start_timestamp + timer->length - timer->paused_offset; + default: return 0; + } +} + +uint32_t timer_get_running_time(Timer* timer, TimerTimestamp reference_time) { + if (TIMER_STATUS_RUNNING == timer->status) { + return reference_time - timer->start_timestamp + timer->paused_offset; + } else { + // Both reference_time and timer->start_timestamp are meaningless. + return timer->paused_offset; + } +} + +static void timer_transition_to_stop(Timer* timer, TimerTimestamp reference_time) { + timer->paused_offset += reference_time - timer->start_timestamp; +} + +static void timer_transition_to_start(Timer* timer, TimerTimestamp reference_time) { + timer->start_timestamp = reference_time; +} + +static void timer_transition_to(Timer* timer, TimerTimestamp reference_time, TimerStatus new_status) { + if (TIMER_STATUS_RUNNING != timer->status && TIMER_STATUS_RUNNING == new_status) { + timer_transition_to_start(timer, reference_time); + } else if (TIMER_STATUS_RUNNING == timer-> status && TIMER_STATUS_RUNNING != new_status) { + timer_transition_to_stop(timer, reference_time); + } + timer->status = new_status; +} + +static void timer_set_running_time(Timer* timer, TimerTimestamp reference_time, int32_t running_time) { + timer->start_timestamp = reference_time; + timer->paused_offset = running_time; +} + +int32_t timer_get_display_time(Timer* timer, TimerTimestamp reference_time) { + switch (timer->type) { + case TIMER_TYPE_TIMER: return timer->length - timer_get_running_time(timer, reference_time); + case TIMER_TYPE_STOPWATCH: return timer_get_running_time(timer, reference_time); + default: return 0; + } +} void timer_time_str(uint32_t timer_time, bool showHours, char* str, int str_len) { int hours = timer_time / 3600; @@ -57,70 +105,53 @@ void timer_time_str(uint32_t timer_time, bool showHours, char* str, int str_len) } } -void timer_start(Timer* timer) { - switch (timer->type) { - case TIMER_TYPE_TIMER: - timer->current_time = timer->length; - break; - case TIMER_TYPE_STOPWATCH: - timer->current_time = 0; - break; - } - timer->status = TIMER_STATUS_RUNNING; - timer_schedule_tick(timer); - timer_schedule_wakeup(timer, 0); - timers_mark_updated(); +void timer_display_str(Timer* timer, TimerTimestamp reference, bool showHours, char* str, int str_len) { + int32_t current_time = timer_get_display_time(timer, reference); + return timer_time_str(current_time, showHours, str, str_len); } -void timer_pause(Timer* timer) { - timer->status = TIMER_STATUS_PAUSED; - timer_cancel_tick(timer); +void timer_start(Timer* timer, TimerTimestamp reference) { + timer_reset(timer); + timer_resume(timer, reference); +} + +void timer_pause(Timer* timer, TimerTimestamp reference) { + timer_transition_to(timer, reference, TIMER_STATUS_PAUSED); timer_cancel_wakeup(timer); timers_mark_updated(); } -void timer_resume(Timer* timer) { - timer->status = TIMER_STATUS_RUNNING; - timer_schedule_tick(timer); +void timer_resume(Timer* timer, TimerTimestamp reference) { + timer_transition_to(timer, reference, TIMER_STATUS_RUNNING); timer_schedule_wakeup(timer, 0); timers_mark_updated(); } void timer_reset(Timer* timer) { - timer_pause(timer); - switch (timer->type) { - case TIMER_TYPE_TIMER: - timer->current_time = timer->length; - break; - case TIMER_TYPE_STOPWATCH: - timer->current_time = 0; - break; - } - timer->status = TIMER_STATUS_STOPPED; + // Magic starts + timer_transition_to(timer, 0, TIMER_STATUS_STOPPED); + timer_set_running_time(timer, 0, 0); + // The next timer_transition_to(timer, reference, TIMER_STATUS_RUNNING) + // call on this timer will work correctly. This is because the reference + // time doesn't matter on a stop -> start transition. + // Magic ends + timer_cancel_wakeup(timer); timers_mark_updated(); } -void timer_restore(Timer* timer, uint16_t seconds_elapsed) { - timer->timer = NULL; - if (timer->status == TIMER_STATUS_RUNNING) { - switch (timer->type) { - case TIMER_TYPE_STOPWATCH: - timer->current_time += seconds_elapsed; - break; - case TIMER_TYPE_TIMER: { - if (seconds_elapsed >= timer->current_time) { - timer->current_time = 0; - timer->status = TIMER_STATUS_DONE; - } - else { - timer->current_time -= seconds_elapsed; - } - break; - } - } - } +void timer_restart(Timer* timer, TimerTimestamp reference) { + timer_transition_to(timer, reference, TIMER_STATUS_RUNNING); + uint32_t running_time = timer_get_running_time(timer, reference); + timer_set_running_time(timer, reference, running_time % timer->length); + timer_schedule_wakeup(timer, 0); + timers_mark_updated(); +} + +void timer_restore(Timer* timer, TimerTimestamp reference) { + timer_tick(timer, reference); + if (timer->status == TIMER_STATUS_RUNNING) { - timer_resume(timer); + timer_resume(timer, reference); } } @@ -153,8 +184,8 @@ Timer* timer_create_timer(void) { timer->type = TIMER_TYPE_TIMER; timer->vibration = settings()->timers_vibration; timer->length = settings()->timers_duration; + timer->paused_offset = 0; timer->wakeup_id = -1; - timer->timer = NULL; timer->repeat = 0; timer->label[0] = 0; timer->status = TIMER_STATUS_STOPPED; @@ -165,51 +196,37 @@ Timer* timer_create_timer(void) { Timer* timer_create_stopwatch(void) { Timer* stopwatch = malloc(sizeof(Timer)); stopwatch->type = TIMER_TYPE_STOPWATCH; - stopwatch->length = stopwatch->current_time = 0; + stopwatch->length = 0; + stopwatch->paused_offset = 0; stopwatch->label[0] = 0; stopwatch->status = TIMER_STATUS_STOPPED; timer_set_id(stopwatch); return stopwatch; } -static void timer_tick(void* context) { - Timer* timer = (Timer*)context; - timer->timer = NULL; - switch (timer->type) { - case TIMER_TYPE_STOPWATCH: - timer->current_time += 1; - break; - case TIMER_TYPE_TIMER: - timer->current_time -= 1; - if (timer->current_time <= 0) { - timer_finish(timer); - } - break; +void timer_tick(Timer* timer, TimerTimestamp reference) { + if (TIMER_STATUS_RUNNING == timer->status && + TIMER_TYPE_TIMER == timer->type && + timer_has_finished(timer, reference)) { + timer_finish(timer, reference); } - if (timer->status == TIMER_STATUS_RUNNING) { - timer_schedule_tick(timer); + if (TIMER_STATUS_RUNNING == timer->status) { + timers_mark_updated(); } - timers_mark_updated(); -} - -static void timer_finish(Timer* timer) { - timer->status = TIMER_STATUS_DONE; - timer_completed_action(timer); } -static void timer_schedule_tick(Timer* timer) { - timer_cancel_tick(timer); - timer->timer = app_timer_register(1000, timer_tick, (void*)timer); +static bool timer_has_finished(Timer* timer, TimerTimestamp reference) { + return reference >= timer_get_end_timestamp(timer); } -static void timer_cancel_tick(Timer* timer) { - if (! timer) { - return; - } - if (timer->timer) { - app_timer_cancel(timer->timer); - timer->timer = NULL; +static void timer_finish(Timer* timer, TimerTimestamp reference) { + timer_transition_to(timer, reference, TIMER_STATUS_DONE); + if (timer->repeat == TIMER_REPEAT_INFINITE) { + timer_restart(timer, reference); + } else { + timer_set_running_time(timer, reference, timer->length); } + timer_completed_action(timer); } static void timer_schedule_wakeup(Timer* timer, uint16_t offset) { @@ -220,8 +237,7 @@ static void timer_schedule_wakeup(Timer* timer, uint16_t offset) { return; } timer_cancel_wakeup(timer); - time_t wakeup_time = time(NULL); - wakeup_time += timer->current_time; + TimerTimestamp wakeup_time = timer_get_end_timestamp(timer); wakeup_time -= 2; wakeup_time -= offset; timer->wakeup_id = wakeup_schedule(wakeup_time, timer->id, false); @@ -318,8 +334,5 @@ static void timer_completed_action(Timer* timer) { default: break; } - if (timer->repeat == TIMER_REPEAT_INFINITE) { - timer_start(timer); - } timers_highlight(timer); } diff --git a/src/timer.h b/src/timer.h index 8913045..c1cf187 100644 --- a/src/timer.h +++ b/src/timer.h @@ -54,16 +54,18 @@ typedef enum { TIMER_STATUS_DONE = 3, } TimerStatus; +typedef time_t TimerTimestamp; + typedef struct Timer { uint16_t id; TimerType type; uint32_t length; - uint32_t current_time; + int32_t paused_offset; + TimerTimestamp start_timestamp; TimerStatus status; TimerVibration vibration; uint8_t repeat; uint8_t repeat_count; - AppTimer* timer; WakeupId wakeup_id; char label[24]; } Timer; @@ -71,12 +73,18 @@ typedef struct Timer { #define TIMER_REPEAT_INFINITE 100 void timer_time_str(uint32_t timer_time, bool showHours, char* str, int str_len); -void timer_start(Timer* timer); -void timer_pause(Timer* timer); -void timer_resume(Timer* timer); +void timer_display_str(Timer* timer, TimerTimestamp reference, bool showHours, char* str, int str_len); +void timer_start(Timer* timer, TimerTimestamp reference); +void timer_pause(Timer* timer, TimerTimestamp reference); +void timer_resume(Timer* timer, TimerTimestamp reference); void timer_reset(Timer* timer); -void timer_restore(Timer* timer, uint16_t seconds_elapsed); +void timer_restart(Timer* timer, TimerTimestamp reference); +void timer_restore(Timer* timer, TimerTimestamp reference); Timer* timer_clone(Timer* timer); char* timer_vibe_str(TimerVibration vibe, bool shortStr); Timer* timer_create_timer(void); Timer* timer_create_stopwatch(void); +void timer_tick(Timer* timer, TimerTimestamp reference); +uint32_t timer_get_running_time(Timer* timer, TimerTimestamp reference); +TimerTimestamp timer_get_end_timestamp(Timer* timer); +int32_t timer_get_display_time(Timer* timer, TimerTimestamp reference); diff --git a/src/timers.c b/src/timers.c index 6236001..fe80ca4 100644 --- a/src/timers.c +++ b/src/timers.c @@ -48,16 +48,25 @@ typedef struct { static void timers_cleanup(void); static void timers_migrate_1(void); static void timers_migrate_2(void); +static TimerTimestamp new_timestamp(void); +static void timers_fire_update_handlers(void); LinkedRoot* timers = NULL; LinkedRoot* update_handlers = NULL; LinkedRoot* highlight_handlers = NULL; +static TimerTimestamp current_time; +static bool update_marked; +static bool queue_updates; + void timers_init(void) { timers_cleanup(); timers = linked_list_create_root(); update_handlers = linked_list_create_root(); highlight_handlers = linked_list_create_root(); + current_time = new_timestamp(); + queue_updates = false; + update_marked = false; } uint8_t timers_count(void) { @@ -103,7 +112,7 @@ bool timers_remove(uint8_t position) { if (NULL == timer) { return false; } - timer_pause(timer); + timer_reset(timer); linked_list_remove(timers, position); free(timer); timers_mark_updated(); @@ -112,6 +121,7 @@ bool timers_remove(uint8_t position) { Timer* timers_find_last_wakeup(void) { Timer* last = NULL; + uint32_t wakeup_time; uint16_t last_wakeup_time = 0; uint8_t count = timers_count(); for (uint8_t c = 0; c < count; c += 1) { @@ -119,9 +129,10 @@ Timer* timers_find_last_wakeup(void) { if (timer->wakeup_id < 0) { continue; } - if (timer->current_time > last_wakeup_time) { + wakeup_time = timer_get_end_timestamp(timer); + if (wakeup_time > last_wakeup_time) { last = timer; - last_wakeup_time = timer->current_time; + last_wakeup_time = wakeup_time; } } return last; @@ -160,6 +171,15 @@ void timers_clear(void) { } void timers_mark_updated(void) { + if (queue_updates) { + update_marked = true; + } else { + timers_fire_update_handlers(); + update_marked = false; + } +} + +void timers_fire_update_handlers(void) { uint8_t handler_count = linked_list_count(update_handlers); for (uint8_t h = 0; h < handler_count; h += 1) { TimersUpdatedHandler handler = linked_list_get(update_handlers, h); @@ -183,6 +203,27 @@ void timers_register_highlight_handler(TimerHighlightHandler handler) { linked_list_append(highlight_handlers, handler); } +static TimerTimestamp new_timestamp() { + return time(NULL); +} + +void timers_update_timestamp(void) { + current_time = new_timestamp(); + queue_updates = true; + for (uint8_t t = 0; t < timers_count(); ++t) { + Timer* timer = timers_get(t); + timer_tick(timer, current_time); + } + if (update_marked) { + timers_fire_update_handlers(); + queue_updates = false; + } +} + +TimerTimestamp timers_current_timestamp() { + return current_time; +} + static void timers_cleanup(void) { timers_clear(); free(timers); @@ -234,8 +275,7 @@ void timers_restore(void) { timers_clear(); - time_t now = time(NULL); - uint16_t seconds_elapsed = 0; + TimerTimestamp now = timers_current_timestamp(); TimerBlock* block = NULL; if (persist_exists(PERSIST_TIMER_START)) { @@ -243,7 +283,6 @@ void timers_restore(void) { persist_read_data(PERSIST_TIMER_START, block, sizeof(TimerBlock)); uint8_t num_timers = block->total_timers; uint8_t block_offset = 0; - seconds_elapsed = now - block->save_time; for (uint8_t t = 0; t < num_timers; t += 1) { if (! block) { @@ -252,7 +291,7 @@ void timers_restore(void) { } Timer* timer = timer_clone(&block->timers[t % TIMER_BLOCK_SIZE]); timers_add(timer); - timer_restore(timer, seconds_elapsed); + timer_restore(timer, now); if (t % TIMER_BLOCK_SIZE == (TIMER_BLOCK_SIZE - 1)) { free(block); block = NULL; @@ -272,6 +311,8 @@ static void timers_migrate_1(void) { return; } + TimerTimestamp now = timers_current_timestamp(); + int block = 0; OldTimerBlock* timerBlock = malloc(sizeof(OldTimerBlock)); persist_read_data(PERSIST_TIMER_START, timerBlock, sizeof(OldTimerBlock)); @@ -292,11 +333,10 @@ static void timers_migrate_1(void) { OldTimer* old_timer = &timerBlock->timers[t % TIMER_BLOCK_SIZE]; - int seconds_elapsed = time(NULL) - timerBlock->time; - Timer* timer = malloc(sizeof(Timer)); timer->id = old_timer->id; - timer->current_time = old_timer->time_left; + //FIXME after implementing migrate_3 + //timer->current_time = old_timer->time_left; timer->length = old_timer->length; timer->repeat = old_timer->repeat ? TIMER_REPEAT_INFINITE : 0; switch (old_timer->status) { @@ -342,8 +382,7 @@ static void timers_migrate_1(void) { break; } timer->wakeup_id = -1; - timer->timer = NULL; - timer_restore(timer, seconds_elapsed); + timer_restore(timer, now); timers_add(timer); } if (NULL != timerBlock) { @@ -357,6 +396,8 @@ static void timers_migrate_2(void) { return; } + TimerTimestamp now = timers_current_timestamp(); + int block_number = 0; TimerBlockTiny* block = malloc(sizeof(TimerBlockTiny)); persist_read_data(PERSIST_TIMER_START, block, sizeof(TimerBlockTiny)); @@ -377,11 +418,10 @@ static void timers_migrate_2(void) { TimerTiny* timer_tiny = &block->timers[t % TIMER_BLOCK_SIZE]; - int seconds_elapsed = time(NULL) - block->save_time; - Timer* timer = malloc(sizeof(Timer)); timer->id = timer_tiny->id; - timer->current_time = timer_tiny->current_time; + //FIXME after implementing migrate_3 + //timer->current_time = timer_tiny->current_time; timer->length = timer_tiny->length; timer->repeat = timer_tiny->repeat; timer->repeat_count = timer_tiny->repeat_count; @@ -389,9 +429,8 @@ static void timers_migrate_2(void) { timer->vibration = timer_tiny->vibration; timer->type = timer_tiny->type; timer->wakeup_id = timer_tiny->wakeup_id; - timer->timer = NULL; strcpy(timer->label, timer_tiny->label); - timer_restore(timer, seconds_elapsed); + timer_restore(timer, now); timers_add(timer); } if (NULL != block) { diff --git a/src/timers.h b/src/timers.h index ffef389..7ffd34c 100644 --- a/src/timers.h +++ b/src/timers.h @@ -78,6 +78,9 @@ Timer* timers_find_wakeup_collision(Timer* timer); // Empty list the timers. void timers_clear(void); +void timers_update_timestamp(void); +TimerTimestamp timers_current_timestamp(); + void timers_mark_updated(void); void timers_highlight(Timer* timer); void timers_register_update_handler(TimersUpdatedHandler handler); diff --git a/src/windows/win-controls.c b/src/windows/win-controls.c index ebd15ba..e6d1000 100644 --- a/src/windows/win-controls.c +++ b/src/windows/win-controls.c @@ -113,6 +113,7 @@ static void menu_draw_row(GContext* ctx, const Layer* cell_layer, MenuIndex* cel static void menu_select(struct MenuLayer* menu, MenuIndex* cell_index, void* callback_context) { uint8_t num_timers = timers_count(); + TimerTimestamp timestamp = timers_current_timestamp(); switch (cell_index->row) { case MENU_ROW_RESUME: for (uint8_t t = 0; t < num_timers; t += 1) { @@ -121,14 +122,14 @@ static void menu_select(struct MenuLayer* menu, MenuIndex* cell_index, void* cal case TIMER_STATUS_RUNNING: break; case TIMER_STATUS_PAUSED: - timer_resume(timer); + timer_resume(timer, timestamp); break; case TIMER_STATUS_DONE: timer_reset(timer); - timer_start(timer); + timer_start(timer, timestamp); break; case TIMER_STATUS_STOPPED: - timer_start(timer); + timer_start(timer, timestamp); break; } } @@ -137,7 +138,7 @@ static void menu_select(struct MenuLayer* menu, MenuIndex* cell_index, void* cal for (uint8_t t = 0; t < num_timers; t += 1) { Timer* timer = timers_get(t); if (timer->status == TIMER_STATUS_RUNNING) { - timer_pause(timer); + timer_pause(timer, timestamp); } } break; diff --git a/src/windows/win-main.c b/src/windows/win-main.c index 5cc30e6..30d138d 100644 --- a/src/windows/win-main.c +++ b/src/windows/win-main.c @@ -96,7 +96,7 @@ void win_main_init(void) { win_vibration_init(); win_duration_init(); win_vibrate_init(); - tick_timer_service_subscribe(MINUTE_UNIT, tick_handler); + tick_timer_service_subscribe(SECOND_UNIT, tick_handler); } void win_main_show(void) { @@ -121,9 +121,8 @@ static void window_unload(Window* window) { } static void tick_handler(struct tm *tick_time, TimeUnits units_changed) { - if (settings()->show_clock) { - menu_layer_reload_data(s_menu); - } + timers_update_timestamp(); + menu_layer_reload_data(s_menu); } static uint16_t menu_num_sections(struct MenuLayer* menu, void* callback_context) { @@ -193,7 +192,7 @@ static void menu_draw_row_clock(GContext* ctx, const Layer* cell_layer) { static void menu_draw_row_timers(GContext* ctx, const Layer* cell_layer, uint16_t row_index) { Timer* timer = timers_get(row_index); if (! timer) { return; } - timer_draw_row(timer, ctx); + timer_draw_row(timer, timers_current_timestamp(), ctx); } static void menu_draw_row_other(GContext* ctx, const Layer* cell_layer, uint16_t row_index) { @@ -229,18 +228,19 @@ static void menu_select(struct MenuLayer* menu, MenuIndex* cell_index, void* cal static void menu_select_timers(uint16_t row_index) { Timer* timer = timers_get(row_index); + TimerTimestamp timestamp = timers_current_timestamp(); if (! timer) { return; } switch (timer->status) { case TIMER_STATUS_STOPPED: { - timer_start(timer); + timer_start(timer, timestamp); break; } case TIMER_STATUS_RUNNING: - timer_pause(timer); + timer_pause(timer, timestamp); break; case TIMER_STATUS_PAUSED: - timer_resume(timer); + timer_resume(timer, timestamp); break; case TIMER_STATUS_DONE: timer_reset(timer); @@ -249,6 +249,7 @@ static void menu_select_timers(uint16_t row_index) { } static void menu_select_other(uint16_t row_index) { + TimerTimestamp timestamp = timers_current_timestamp(); switch (row_index) { case MENU_ROW_OTHER_ADD_TIMER: win_timer_add_show_new(); @@ -256,7 +257,7 @@ static void menu_select_other(uint16_t row_index) { case MENU_ROW_OTHER_ADD_STOPWATCH: { Timer* stopwatch = timer_create_stopwatch(); if (settings()->timers_start_auto) { - timer_start(stopwatch); + timer_start(stopwatch, timestamp); } timers_add(stopwatch); timers_mark_updated(); diff --git a/src/windows/win-timer-add.c b/src/windows/win-timer-add.c index 04204ab..00aa5eb 100644 --- a/src/windows/win-timer-add.c +++ b/src/windows/win-timer-add.c @@ -209,6 +209,7 @@ static void menu_select_main(uint16_t row) { } static void menu_select_footer(void) { + TimerTimestamp timestamp = timers_current_timestamp(); if (s_timer->length == 0) { vibes_short_pulse(); menu_layer_set_selected_index(s_menu, (MenuIndex) { MENU_SECTION_MAIN, MENU_ROW_DURATION }, MenuRowAlignCenter, true); @@ -228,7 +229,7 @@ static void menu_select_footer(void) { Timer* timer = timer_clone(s_timer); timer_reset(timer); if (settings()->timers_start_auto) { - timer_start(timer); + timer_start(timer, timestamp); } timers_add(timer); window_stack_pop(true); diff --git a/src/windows/win-timer.c b/src/windows/win-timer.c index 98b12f0..7e4d243 100644 --- a/src/windows/win-timer.c +++ b/src/windows/win-timer.c @@ -110,7 +110,7 @@ static void window_unload(Window* window) { } static void layer_header_update(Layer* layer, GContext* ctx) { - timer_draw_row(s_timer, ctx); + timer_draw_row(s_timer, timers_current_timestamp(), ctx); } static uint16_t menu_num_sections(struct MenuLayer* menu, void* callback_context) { @@ -155,18 +155,19 @@ static void menu_draw_row(GContext* ctx, const Layer* cell_layer, MenuIndex* cel } static void menu_select(struct MenuLayer* menu, MenuIndex* cell_index, void* callback_context) { + TimerTimestamp timestamp = timers_current_timestamp(); switch (cell_index->row) { case MENU_ROW_PAUSE: { switch (s_timer->status) { case TIMER_STATUS_RUNNING: - timer_pause(s_timer); + timer_pause(s_timer, timestamp); break; case TIMER_STATUS_PAUSED: - timer_resume(s_timer); + timer_resume(s_timer, timestamp); break; case TIMER_STATUS_DONE: case TIMER_STATUS_STOPPED: - timer_start(s_timer); + timer_start(s_timer, timestamp); break; } break; From 12bb0cc9998339ee7c67c260d1bc721a62f7d29d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thiago=20Vin=C3=ADcius=20Freire=20de=20Ara=C3=BAjo=20Ribei?= =?UTF-8?q?ro?= Date: Sun, 5 Apr 2015 11:04:06 -0300 Subject: [PATCH 2/6] Fix migration to storage version 4 This commit adds code to properly migrate data to the new storage version. --- src/migration.h | 21 +++++++++ src/timer.c | 21 +++++++++ src/timer.h | 1 + src/timers.c | 78 +++++++++++++++++++++++++++------ src/timers.h | 3 +- tests/timers.c | 114 +++++++++++++++++++++++++++++++++++------------- 6 files changed, 193 insertions(+), 45 deletions(-) diff --git a/src/migration.h b/src/migration.h index 400954b..bca61af 100644 --- a/src/migration.h +++ b/src/migration.h @@ -93,6 +93,27 @@ typedef struct { time_t save_time; } TimerBlockTiny; +typedef struct TimerV3 { + uint16_t id; + TimerType type; + uint32_t length; + uint32_t current_time; + TimerStatus status; + TimerVibration vibration; + uint8_t repeat; + uint8_t repeat_count; + AppTimer* timer; + WakeupId wakeup_id; + char label[24]; +} TimerV3; + +typedef struct { + TimerV3 timers[TIMER_BLOCK_SIZE]; + uint8_t total_timers; + time_t save_time; +} TimerBlockV3; + + // Struct of the original settings. typedef struct { bool save_timers_auto; // Automatically save timers on exit and load them when the app restarts? diff --git a/src/timer.c b/src/timer.c index 399adc0..a57cbba 100644 --- a/src/timer.c +++ b/src/timer.c @@ -45,7 +45,9 @@ static void timer_transition_to_stop(Timer* timer, TimerTimestamp reference_time static void timer_transition_to_start(Timer* timer, TimerTimestamp reference_time); static void timer_transition_to(Timer* timer, TimerTimestamp reference_time, TimerStatus new_status); static void timer_set_running_time(Timer* timer, TimerTimestamp reference_time, int32_t running_time); +static void timer_add_running_time(Timer* timer, int32_t add_seconds); static bool timer_has_finished(Timer* timer, TimerTimestamp reference); +static uint32_t timer_display2running_time(Timer* timer, uint32_t display_time); TimerTimestamp timer_get_end_timestamp(Timer* timer) { switch (timer->type) { @@ -93,6 +95,18 @@ int32_t timer_get_display_time(Timer* timer, TimerTimestamp reference_time) { } } +static uint32_t timer_display2running_time(Timer* timer, uint32_t display_time) { + switch (timer->type) { + case TIMER_TYPE_TIMER: return timer->length - display_time; + case TIMER_TYPE_STOPWATCH: return display_time; + default: return 0; + } +} + +static void timer_add_running_time(Timer* timer, int32_t add_seconds) { + timer->paused_offset += add_seconds; +} + void timer_time_str(uint32_t timer_time, bool showHours, char* str, int str_len) { int hours = timer_time / 3600; int minutes = (showHours ? (timer_time % 3600) : timer_time) / 60; @@ -155,6 +169,13 @@ void timer_restore(Timer* timer, TimerTimestamp reference) { } } +void timer_restore_legacy(Timer* timer, TimerTimestamp reference, uint32_t offset, uint32_t display_time) { + uint32_t running_time = timer_display2running_time(timer, display_time); + timer_set_running_time(timer, reference, running_time); + timer_add_running_time(timer, offset); + timer_restore(timer, reference); +} + Timer* timer_clone(Timer* timer) { Timer* new_timer = malloc(sizeof(Timer)); memcpy(new_timer, timer, sizeof(Timer)); diff --git a/src/timer.h b/src/timer.h index c1cf187..b97e681 100644 --- a/src/timer.h +++ b/src/timer.h @@ -80,6 +80,7 @@ void timer_resume(Timer* timer, TimerTimestamp reference); void timer_reset(Timer* timer); void timer_restart(Timer* timer, TimerTimestamp reference); void timer_restore(Timer* timer, TimerTimestamp reference); +void timer_restore_legacy(Timer* timer, TimerTimestamp reference, uint32_t offset, uint32_t display_time); Timer* timer_clone(Timer* timer); char* timer_vibe_str(TimerVibration vibe, bool shortStr); Timer* timer_create_timer(void); diff --git a/src/timers.c b/src/timers.c index fe80ca4..0b058f2 100644 --- a/src/timers.c +++ b/src/timers.c @@ -48,6 +48,7 @@ typedef struct { static void timers_cleanup(void); static void timers_migrate_1(void); static void timers_migrate_2(void); +static void timers_migrate_3(void); static TimerTimestamp new_timestamp(void); static void timers_fire_update_handlers(void); @@ -273,9 +274,12 @@ void timers_restore(void) { return; } - timers_clear(); + if (TIMERS_VERSION_V3 == persist_read_int(PERSIST_TIMERS_VERSION)) { + timers_migrate_3(); + return; + } - TimerTimestamp now = timers_current_timestamp(); + timers_clear(); TimerBlock* block = NULL; if (persist_exists(PERSIST_TIMER_START)) { @@ -291,7 +295,7 @@ void timers_restore(void) { } Timer* timer = timer_clone(&block->timers[t % TIMER_BLOCK_SIZE]); timers_add(timer); - timer_restore(timer, now); + timer_restore(timer, timers_current_timestamp()); if (t % TIMER_BLOCK_SIZE == (TIMER_BLOCK_SIZE - 1)) { free(block); block = NULL; @@ -311,8 +315,6 @@ static void timers_migrate_1(void) { return; } - TimerTimestamp now = timers_current_timestamp(); - int block = 0; OldTimerBlock* timerBlock = malloc(sizeof(OldTimerBlock)); persist_read_data(PERSIST_TIMER_START, timerBlock, sizeof(OldTimerBlock)); @@ -333,10 +335,10 @@ static void timers_migrate_1(void) { OldTimer* old_timer = &timerBlock->timers[t % TIMER_BLOCK_SIZE]; + int seconds_elapsed = time(NULL) - timerBlock->time; + Timer* timer = malloc(sizeof(Timer)); timer->id = old_timer->id; - //FIXME after implementing migrate_3 - //timer->current_time = old_timer->time_left; timer->length = old_timer->length; timer->repeat = old_timer->repeat ? TIMER_REPEAT_INFINITE : 0; switch (old_timer->status) { @@ -382,7 +384,7 @@ static void timers_migrate_1(void) { break; } timer->wakeup_id = -1; - timer_restore(timer, now); + timer_restore_legacy(timer, timers_current_timestamp(), seconds_elapsed, old_timer->time_left); timers_add(timer); } if (NULL != timerBlock) { @@ -396,8 +398,6 @@ static void timers_migrate_2(void) { return; } - TimerTimestamp now = timers_current_timestamp(); - int block_number = 0; TimerBlockTiny* block = malloc(sizeof(TimerBlockTiny)); persist_read_data(PERSIST_TIMER_START, block, sizeof(TimerBlockTiny)); @@ -418,10 +418,10 @@ static void timers_migrate_2(void) { TimerTiny* timer_tiny = &block->timers[t % TIMER_BLOCK_SIZE]; + int seconds_elapsed = time(NULL) - block->save_time; + Timer* timer = malloc(sizeof(Timer)); timer->id = timer_tiny->id; - //FIXME after implementing migrate_3 - //timer->current_time = timer_tiny->current_time; timer->length = timer_tiny->length; timer->repeat = timer_tiny->repeat; timer->repeat_count = timer_tiny->repeat_count; @@ -430,10 +430,62 @@ static void timers_migrate_2(void) { timer->type = timer_tiny->type; timer->wakeup_id = timer_tiny->wakeup_id; strcpy(timer->label, timer_tiny->label); - timer_restore(timer, now); + timer_restore_legacy(timer, timers_current_timestamp(), seconds_elapsed, timer_tiny->current_time); timers_add(timer); } if (NULL != block) { free(block); } } + +static void timers_migrate_3(void) { + + if (! persist_exists(PERSIST_TIMER_START)) { + return; + } + + time_t now = time(NULL); + uint16_t seconds_elapsed = 0; + + TimerBlockV3* block = NULL; + if (persist_exists(PERSIST_TIMER_START)) { + block = malloc(sizeof(TimerBlockV3)); + persist_read_data(PERSIST_TIMER_START, block, sizeof(TimerBlockV3)); + uint8_t num_timers = block->total_timers; + uint8_t block_offset = 0; + seconds_elapsed = now - block->save_time; + + for (uint8_t t = 0; t < num_timers; t += 1) { + if (! block) { + block = malloc(sizeof(TimerBlockV3)); + persist_read_data(PERSIST_TIMER_START + block_offset, block, sizeof(TimerBlockV3)); + } + TimerV3* timer_v3 = &block->timers[t % TIMER_BLOCK_SIZE]; + Timer* timer = malloc(sizeof(Timer)); + + timer->id = timer_v3->id; + timer->type = timer_v3->type; + timer->length = timer_v3->length; + //timer->paused_offset is set by timer_restore_legacy + //timer->start_timestamp is set by timer_restore_legacy + timer->status = timer_v3->status; + timer->vibration = timer_v3->vibration; + timer->repeat = timer_v3->repeat; + timer->repeat_count = timer_v3->repeat_count; + timer->wakeup_id = timer_v3->wakeup_id; + strncpy(timer->label, timer_v3->label, 24); + timer_restore_legacy(timer, timers_current_timestamp(), seconds_elapsed, timer_v3->current_time); + timers_add(timer); + + if (t % TIMER_BLOCK_SIZE == (TIMER_BLOCK_SIZE - 1)) { + free(block); + block = NULL; + block_offset += 1; + } + } + if (block) { + free(block); + block = NULL; + } + } +} diff --git a/src/timers.h b/src/timers.h index 7ffd34c..86d4fd8 100644 --- a/src/timers.h +++ b/src/timers.h @@ -34,7 +34,8 @@ src/timers.h #define TIMER_BLOCK_SIZE 4 -#define TIMERS_VERSION_CURRENT 3 +#define TIMERS_VERSION_CURRENT 4 +#define TIMERS_VERSION_V3 3 #define TIMERS_VERSION_TINY 2 typedef void (*TimersUpdatedHandler)(void); diff --git a/tests/timers.c b/tests/timers.c index 7685713..53fb09f 100644 --- a/tests/timers.c +++ b/tests/timers.c @@ -201,7 +201,7 @@ char* timer_str(void) { return 0; } -char* timers_migrate_from_1_to_3(void) { +char* timers_migrate_from_1_to_4(void) { OldTimerBlock* block = malloc(sizeof(OldTimerBlock)); block->count = 2; block->time = time(NULL); @@ -218,25 +218,25 @@ char* timers_migrate_from_1_to_3(void) { free(block); timers_restore(); - mu_assert(2 == timers_count(), "Migrate 1->3: Incorrect number of timers"); + mu_assert(2 == timers_count(), "Migrate 1->4: Incorrect number of timers"); Timer* tmr1 = timers_get(0); Timer* tmr2 = timers_get(1); - mu_assert(tmr1->type == TIMER_TYPE_TIMER, "Migrate 1->3: Timer 1 wrong type"); - mu_assert(tmr1->length == 3000, "Migrate 1->3: Timer 1 wrong length"); - mu_assert(tmr1->current_time == 200, "Migrate 1->3: Timer 1 wrong time"); - mu_assert(tmr1->status == TIMER_STATUS_PAUSED, "Migrate 1->3: Timer 1 wrong status"); - mu_assert(tmr1->repeat == TIMER_REPEAT_INFINITE, "Migrate 1->3: Timer 1 wrong repeat"); - mu_assert(tmr1->vibration == TIMER_VIBE_DOUBLE , "Migrate 1->3: Timer 1 wrong vibration"); - mu_assert(tmr2->type == TIMER_TYPE_STOPWATCH , "Migrate 1->3: Timer 2 wrong type"); - mu_assert(tmr2->current_time == 50, "Migrate 1->3: Timer 2 wrong time"); - mu_assert(tmr2->status == TIMER_STATUS_RUNNING , "Migrate 1->3: Timer 2 wrong status"); + mu_assert(tmr1->type == TIMER_TYPE_TIMER, "Migrate 1->4: Timer 1 wrong type"); + mu_assert(tmr1->length == 3000, "Migrate 1->4: Timer 1 wrong length"); + mu_assert(timer_get_display_time(tmr1, timers_current_timestamp()) == 200, "Migrate 1->4: Timer 1 wrong time"); + mu_assert(tmr1->status == TIMER_STATUS_PAUSED, "Migrate 1->4: Timer 1 wrong status"); + mu_assert(tmr1->repeat == TIMER_REPEAT_INFINITE, "Migrate 1->4: Timer 1 wrong repeat"); + mu_assert(tmr1->vibration == TIMER_VIBE_DOUBLE , "Migrate 1->4: Timer 1 wrong vibration"); + mu_assert(tmr2->type == TIMER_TYPE_STOPWATCH , "Migrate 1->4: Timer 2 wrong type"); + mu_assert(timer_get_display_time(tmr2, timers_current_timestamp()) == 50, "Migrate 1->4: Timer 2 wrong time"); + mu_assert(tmr2->status == TIMER_STATUS_RUNNING , "Migrate 1->4: Timer 2 wrong status"); return 0; } -char* timers_migrate_from_2_to_3(void) { +char* timers_migrate_from_2_to_4(void) { TimerBlockTiny* block = malloc(sizeof(TimerBlockTiny)); block->total_timers = 2; block->save_time = time(NULL); @@ -261,27 +261,78 @@ char* timers_migrate_from_2_to_3(void) { free(block); timers_restore(); - mu_assert(2 == timers_count(), "Migrate 2->3: Incorrect number of timers"); + mu_assert(2 == timers_count(), "Migrate 2->4: Incorrect number of timers"); Timer* tmr1 = timers_get(0); Timer* tmr2 = timers_get(1); - mu_assert(tmr1->type == TIMER_TYPE_TIMER, "Migrate 2->3: Timer 1 wrong type"); - mu_assert(tmr1->length == 60, "Migrate 2->3: Timer 1 wrong length"); - mu_assert(tmr1->current_time == 45, "Migrate 2->3: Timer 1 wrong current time"); - mu_assert(tmr1->id == 5, "Migrate 2->3: Timer 1 wrong ID"); - mu_assert(0 == strcmp(tmr1->label, "LABEL #1"), "Migrate 2->3: Timer 1 wrong label"); - mu_assert(tmr1->repeat == TIMER_REPEAT_INFINITE, "Migrate 2->3: Timer 1 wrong repeat"); - mu_assert(tmr1->vibration == TIMER_VIBE_SOLID, "Migrate 2->3: Timer 1 wrong vibration"); - mu_assert(tmr1->status == TIMER_STATUS_PAUSED, "Migrate 2->3: Timer 1 wrong status"); - mu_assert(tmr1->wakeup_id == 70, "Migrate 2->3: Timer 1 wrong wakeup ID"); - - mu_assert(tmr2->type == TIMER_TYPE_STOPWATCH, "Migrate 2->3: Timer 2 wrong wakeup type"); - mu_assert(tmr2->current_time == 500, "Migrate 2->3: Timer 2 wrong current time"); - mu_assert(tmr2->id == 10, "Migrate 2->3: Timer 2 wrong id"); - mu_assert(0 == strcmp(tmr2->label, "LABEL #2"), "Migrate 2->3: Timer 2 wrong label"); - mu_assert(tmr2->status == TIMER_STATUS_RUNNING, "Migrate 2->3: Timer 2 wrong status"); - mu_assert(tmr2->wakeup_id == 60, "Migrate 2->3: Timer 2 wrong wakeup ID"); + mu_assert(tmr1->type == TIMER_TYPE_TIMER, "Migrate 2->4: Timer 1 wrong type"); + mu_assert(tmr1->length == 60, "Migrate 2->4: Timer 1 wrong length"); + mu_assert(timer_get_display_time(tmr1, timers_current_timestamp()) == 45, "Migrate 2->4: Timer 1 wrong display time"); + mu_assert(tmr1->id == 5, "Migrate 2->4: Timer 1 wrong ID"); + mu_assert(0 == strcmp(tmr1->label, "LABEL #1"), "Migrate 2->4: Timer 1 wrong label"); + mu_assert(tmr1->repeat == TIMER_REPEAT_INFINITE, "Migrate 2->4: Timer 1 wrong repeat"); + mu_assert(tmr1->vibration == TIMER_VIBE_SOLID, "Migrate 2->4: Timer 1 wrong vibration"); + mu_assert(tmr1->status == TIMER_STATUS_PAUSED, "Migrate 2->4: Timer 1 wrong status"); + mu_assert(tmr1->wakeup_id == 70, "Migrate 2->4: Timer 1 wrong wakeup ID"); + + mu_assert(tmr2->type == TIMER_TYPE_STOPWATCH, "Migrate 2->4: Timer 2 wrong wakeup type"); + mu_assert(timer_get_display_time(tmr2, timers_current_timestamp()) == 500, "Migrate 2->4: Timer 2 wrong display time"); + mu_assert(tmr2->id == 10, "Migrate 2->4: Timer 2 wrong id"); + mu_assert(0 == strcmp(tmr2->label, "LABEL #2"), "Migrate 2->4: Timer 2 wrong label"); + mu_assert(tmr2->status == TIMER_STATUS_RUNNING, "Migrate 2->4: Timer 2 wrong status"); + mu_assert(tmr2->wakeup_id == 60, "Migrate 2->4: Timer 2 wrong wakeup ID"); + + return 0; +} + +char* timers_migrate_from_3_to_4(void) { + + TimerBlockV3* block = malloc(sizeof(TimerBlockV3)); + block->total_timers = 2; + block->save_time = time(NULL); + block->timers[0].type = TIMER_TYPE_TIMER; + block->timers[0].length = 75; + block->timers[0].current_time = 45; + block->timers[0].id = 20; + strcpy(block->timers[0].label, "LABEL #1"); + block->timers[0].repeat = TIMER_REPEAT_INFINITE; + block->timers[0].vibration = TIMER_VIBE_SOLID; + block->timers[0].status = TIMER_STATUS_PAUSED; + block->timers[0].wakeup_id = 70; + block->timers[1].type = TIMER_TYPE_STOPWATCH; + block->timers[1].current_time = 500; + block->timers[1].id = 10; + strcpy(block->timers[1].label, "LABEL #2"); + block->timers[1].status = TIMER_STATUS_RUNNING; + block->timers[1].wakeup_id = 60; + + persist_write_data(PERSIST_TIMER_START, block, sizeof(TimerBlockV3)); + persist_write_int(PERSIST_TIMERS_VERSION, TIMERS_VERSION_V3); + free(block); + + timers_restore(); + mu_assert(2 == timers_count(), "Migrate 3->4: Incorrect number of timers"); + + Timer *tmr1 = timers_get(0); + Timer *tmr2 = timers_get(1); + + mu_assert(tmr1->type == TIMER_TYPE_TIMER, "Migrate 3->4: Timer 1 wrong type"); + mu_assert(tmr1->length == 75, "Migrate 3->4: Timer 1 wrong length"); + mu_assert(timer_get_display_time(tmr1, timers_current_timestamp()) == 45, "Migrate 3->4: Timer 1 wrong display time"); + mu_assert(tmr1->id == 20, "Migrate 3->4: Timer 1 wrong id"); + mu_assert(0 == strcmp(tmr1->label, "LABEL #1"), "Migrate 3->4: Timer 1 wrong label"); + mu_assert(tmr1->repeat == TIMER_REPEAT_INFINITE, "Migrate 3->4: Timer 1 wrong repeat"); + mu_assert(tmr1->vibration == TIMER_VIBE_SOLID, "Migrate 3->4: Timer 1 wrong vibration"); + mu_assert(tmr1->status == TIMER_STATUS_PAUSED, "Migrate 3->4: Timer 1 wrong status"); + mu_assert(tmr1->wakeup_id == 70, "Migrate 3->4: Timer 1 wrong wakeup_id"); + + mu_assert(tmr2->type == TIMER_TYPE_STOPWATCH, "Migrate 3->4: Timer 2 wrong type"); + mu_assert(timer_get_display_time(tmr2, timers_current_timestamp()) == 500, "Migrate 3->4: Timer 2 wrong display time"); + mu_assert(tmr2->id == 10, "Migrate 3->4: Timer 2 wrong id"); + mu_assert(0 == strcmp(tmr2->label, "LABEL #2"), "Migrate 3->4: Timer 2 wrong label"); + mu_assert(tmr2->status == TIMER_STATUS_RUNNING, "Migrate 3->4: Timer 2 wrong status"); + mu_assert(tmr2->wakeup_id == 60, "Migrate 3->4: Timer 2 wrong wakeup_id"); return 0; } @@ -303,7 +354,8 @@ char* timers_tests(void) { mu_run_test(timers_save_persists_one_timer); mu_run_test(timers_save_persists_multiple_timers); mu_run_test(timer_str); - mu_run_test(timers_migrate_from_1_to_3); - mu_run_test(timers_migrate_from_2_to_3); + mu_run_test(timers_migrate_from_1_to_4); + mu_run_test(timers_migrate_from_2_to_4); + mu_run_test(timers_migrate_from_3_to_4); return 0; } From 13b92e5d7567d3f385cba4baa58bc6117d278cd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thiago=20Vin=C3=ADcius=20Freire=20de=20Ara=C3=BAjo=20Ribei?= =?UTF-8?q?ro?= Date: Sun, 5 Apr 2015 11:27:07 -0300 Subject: [PATCH 3/6] Fix timer_restore_legacy when timer not running We should only account for offset if the timer was running. --- src/timer.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/timer.c b/src/timer.c index a57cbba..b4b669d 100644 --- a/src/timer.c +++ b/src/timer.c @@ -172,7 +172,9 @@ void timer_restore(Timer* timer, TimerTimestamp reference) { void timer_restore_legacy(Timer* timer, TimerTimestamp reference, uint32_t offset, uint32_t display_time) { uint32_t running_time = timer_display2running_time(timer, display_time); timer_set_running_time(timer, reference, running_time); - timer_add_running_time(timer, offset); + if (TIMER_STATUS_RUNNING == timer->status) { + timer_add_running_time(timer, offset); + } timer_restore(timer, reference); } From 547fdf6ff83de9dee773fbf8ffabd4847adfd1ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thiago=20Vin=C3=ADcius=20Freire=20de=20Ara=C3=BAjo=20Ribei?= =?UTF-8?q?ro?= Date: Sun, 12 Apr 2015 11:50:43 -0300 Subject: [PATCH 4/6] Avoid adding code using timers_count on loops See issue #18, for details. --- src/timers.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/timers.c b/src/timers.c index 0b058f2..bfb247c 100644 --- a/src/timers.c +++ b/src/timers.c @@ -211,7 +211,8 @@ static TimerTimestamp new_timestamp() { void timers_update_timestamp(void) { current_time = new_timestamp(); queue_updates = true; - for (uint8_t t = 0; t < timers_count(); ++t) { + const uint8_t count = timers_count(); + for (uint8_t t = 0; t < count; ++t) { Timer* timer = timers_get(t); timer_tick(timer, current_time); } From 8cace4e8d9329b246a608babe1c15fe51f3fd042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thiago=20Vin=C3=ADcius=20Freire=20de=20Ara=C3=BAjo=20Ribei?= =?UTF-8?q?ro?= Date: Sun, 12 Apr 2015 12:00:51 -0300 Subject: [PATCH 5/6] Redo mark updated queueing logic * Dealing with the update_marked flag only in timers_fire_update_handlers and timers_mark_update. * Fix derp on timers_update_timestamp, which would only disable queueing if something had been actually queued. It should always disable. --- src/timers.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/timers.c b/src/timers.c index bfb247c..40b5db1 100644 --- a/src/timers.c +++ b/src/timers.c @@ -172,20 +172,21 @@ void timers_clear(void) { } void timers_mark_updated(void) { - if (queue_updates) { - update_marked = true; - } else { + update_marked = true; + if (!queue_updates) { timers_fire_update_handlers(); - update_marked = false; } } void timers_fire_update_handlers(void) { - uint8_t handler_count = linked_list_count(update_handlers); - for (uint8_t h = 0; h < handler_count; h += 1) { - TimersUpdatedHandler handler = linked_list_get(update_handlers, h); - handler(); + if (update_marked) { + uint8_t handler_count = linked_list_count(update_handlers); + for (uint8_t h = 0; h < handler_count; h += 1) { + TimersUpdatedHandler handler = linked_list_get(update_handlers, h); + handler(); + } } + update_marked = false; } void timers_highlight(Timer* timer) { @@ -216,10 +217,8 @@ void timers_update_timestamp(void) { Timer* timer = timers_get(t); timer_tick(timer, current_time); } - if (update_marked) { - timers_fire_update_handlers(); - queue_updates = false; - } + queue_updates = false; + timers_fire_update_handlers(); } TimerTimestamp timers_current_timestamp() { From 0140c4fd06435d4f62b23001f15f6021fef28519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thiago=20Vin=C3=ADcius=20Freire=20de=20Ara=C3=BAjo=20Ribei?= =?UTF-8?q?ro?= Date: Mon, 6 Jul 2015 19:57:52 -0300 Subject: [PATCH 6/6] TimerBlock: remove save_time This field is useless, as of current timer implementation. --- src/timers.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/timers.c b/src/timers.c index 40b5db1..c756986 100644 --- a/src/timers.c +++ b/src/timers.c @@ -42,7 +42,6 @@ src/timers.c typedef struct { Timer timers[TIMER_BLOCK_SIZE]; uint8_t total_timers; - time_t save_time; } TimerBlock; static void timers_cleanup(void); @@ -242,7 +241,6 @@ void timers_save(void) { if (NULL == block) { block = malloc(sizeof(TimerBlock)); block->total_timers = timers_count(); - block->save_time = time(NULL); } uint8_t timer_block_pos = b % TIMER_BLOCK_SIZE;