From 74421c7e65f9a735bcc394eed027b59baef1cb97 Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Sat, 3 Aug 2024 08:46:34 -0400 Subject: [PATCH] Day roll back repeat fix --- movement/watch_faces/clock/clock_face.c | 32 +++++++++-------- .../watch_faces/clock/simple_clock_face.c | 34 +++++++++++-------- movement/watch_faces/settings/set_time_face.c | 1 + .../settings/set_time_hackwatch_face.c | 9 +++-- watch-library/shared/watch/watch_utility.c | 21 +++++++----- 5 files changed, 58 insertions(+), 39 deletions(-) diff --git a/movement/watch_faces/clock/clock_face.c b/movement/watch_faces/clock/clock_face.c index 68019d8..f9ec58a 100644 --- a/movement/watch_faces/clock/clock_face.c +++ b/movement/watch_faces/clock/clock_face.c @@ -280,27 +280,31 @@ void clock_face_resign(movement_settings_t *settings, void *context) { (void) context; } -static void check_and_act_on_daylight_savings(bool dst_active, watch_date_time date_time) { - if (!dst_active) return; - uint8_t dst_result = is_dst(date_time); - switch (dst_result) - { - case DST_STARTED: - date_time.unit.hour = (date_time.unit.hour + 1) % 24; - break; - case DST_ENDING: - date_time.unit.hour = (date_time.unit.hour + 24 - 1) % 24; - break; - default: +static void check_and_act_on_daylight_savings(movement_settings_t *settings, watch_date_time date_time) { + if (!settings ->bit.dst_active) return; + uint8_t dst_result = get_dst_status(date_time); + + if (settings ->bit.dst_skip_rolling_back && dst_result == DST_ENDED) { + settings ->bit.dst_skip_rolling_back = false; return; } - watch_rtc_set_date_time(date_time); + else if (dst_result == DST_ENDING && !settings ->bit.dst_skip_rolling_back) { + settings ->bit.dst_skip_rolling_back = true; + date_time.unit.hour = (date_time.unit.hour + 24 - 1) % 24; + watch_rtc_set_date_time(date_time); + return; + } + else if (dst_result == DST_STARTING) { + date_time.unit.hour = (date_time.unit.hour + 1) % 24; + watch_rtc_set_date_time(date_time); + return; + } } bool clock_face_wants_background_task(movement_settings_t *settings, void *context) { clock_state_t *state = (clock_state_t *) context; watch_date_time date_time = watch_rtc_get_date_time(); - check_and_act_on_daylight_savings(settings->bit.dst_active, date_time); + check_and_act_on_daylight_savings(settings, date_time); if (!state->time_signal_enabled) return false; return date_time.unit.minute == 0; diff --git a/movement/watch_faces/clock/simple_clock_face.c b/movement/watch_faces/clock/simple_clock_face.c index c0f8372..a7e08a9 100644 --- a/movement/watch_faces/clock/simple_clock_face.c +++ b/movement/watch_faces/clock/simple_clock_face.c @@ -150,27 +150,31 @@ void simple_clock_face_resign(movement_settings_t *settings, void *context) { (void) context; } -static void check_and_act_on_daylight_savings(bool dst_active, watch_date_time date_time) { - if (!dst_active) return; - uint8_t dst_result = is_dst(date_time); - switch (dst_result) - { - case DST_STARTED: - date_time.unit.hour = (date_time.unit.hour + 1) % 24; - break; - case DST_ENDING: - date_time.unit.hour = (date_time.unit.hour + 24 - 1) % 24; - break; - default: +static void check_and_act_on_daylight_savings(movement_settings_t *settings, watch_date_time date_time) { + if (!settings ->bit.dst_active) return; + uint8_t dst_result = get_dst_status(date_time); + + if (settings ->bit.dst_skip_rolling_back && (dst_result == DST_ENDED)) { + settings ->bit.dst_skip_rolling_back = false; return; } - watch_rtc_set_date_time(date_time); + else if (dst_result == DST_ENDING && !settings ->bit.dst_skip_rolling_back) { + settings ->bit.dst_skip_rolling_back = true; + date_time.unit.hour = (date_time.unit.hour + 24 - 1) % 24; + watch_rtc_set_date_time(date_time); + return; + } + else if (dst_result == DST_STARTING) { + date_time.unit.hour = (date_time.unit.hour + 1) % 24; + watch_rtc_set_date_time(date_time); + return; + } } bool simple_clock_face_wants_background_task(movement_settings_t *settings, void *context) { simple_clock_state_t *state = (simple_clock_state_t *)context; - watch_date_time date_time = watch_rtc_get_date_time(); - check_and_act_on_daylight_savings(settings->bit.dst_active, date_time); + date_time = watch_rtc_get_date_time(); + check_and_act_on_daylight_savings(settings, date_time); if (!state->signal_enabled) return false; return date_time.unit.minute == 0; diff --git a/movement/watch_faces/settings/set_time_face.c b/movement/watch_faces/settings/set_time_face.c index b16cb6d..3f7d0c7 100644 --- a/movement/watch_faces/settings/set_time_face.c +++ b/movement/watch_faces/settings/set_time_face.c @@ -72,6 +72,7 @@ static void _handle_alarm_button(movement_settings_t *settings, watch_date_time break; } watch_rtc_set_date_time(date_time); + settings->bit.dst_skip_rolling_back = false; } static void _abort_quick_ticks() { diff --git a/movement/watch_faces/settings/set_time_hackwatch_face.c b/movement/watch_faces/settings/set_time_hackwatch_face.c index bdd1b0a..be293ab 100644 --- a/movement/watch_faces/settings/set_time_hackwatch_face.c +++ b/movement/watch_faces/settings/set_time_hackwatch_face.c @@ -94,6 +94,7 @@ bool set_time_hackwatch_face_loop(movement_event_t event, movement_settings_t *s } date_time_settings.unit.second = 0; watch_rtc_set_date_time(date_time_settings); + settings->bit.dst_skip_rolling_back = false; } break; case EVENT_ALARM_BUTTON_DOWN: @@ -134,8 +135,10 @@ bool set_time_hackwatch_face_loop(movement_event_t event, movement_settings_t *s } break; } - if (current_page != 2) // Do not set time when we are at seconds, it was already set previously + if (current_page != 2) { // Do not set time when we are at seconds, it was already set previously watch_rtc_set_date_time(date_time_settings); + settings->bit.dst_skip_rolling_back = false; + } break; case EVENT_ALARM_LONG_UP://Setting seconds on long release @@ -178,8 +181,10 @@ bool set_time_hackwatch_face_loop(movement_event_t event, movement_settings_t *s if (settings->bit.time_zone > 40) settings->bit.time_zone = 0; break; } - if (current_page != 2) // Do not set time when we are at seconds, it was already set previously + if (current_page != 2) { // Do not set time when we are at seconds, it was already set previously watch_rtc_set_date_time(date_time_settings); + settings->bit.dst_skip_rolling_back = false; + } //TODO: Do not update whole RTC, just what we are changing break; case EVENT_TIMEOUT: diff --git a/watch-library/shared/watch/watch_utility.c b/watch-library/shared/watch/watch_utility.c index 1410e41..5938b60 100644 --- a/watch-library/shared/watch/watch_utility.c +++ b/watch-library/shared/watch/watch_utility.c @@ -83,38 +83,43 @@ uint8_t is_leap(uint16_t y) return !(y%4) && ((y%100) || !(y%400)); } -uint8_t is_dst(watch_date_time date_time) { - uint8_t weekday_first_of_month; +uint8_t get_dst_status(watch_date_time date_time) { watch_date_time dst_start_time; watch_date_time dst_end_time; uint32_t unix_dst_start_time; uint32_t unix_dst_end_time; uint32_t unix_curr_time; + dst_start_time.unit.year = date_time.unit.year; dst_start_time.unit.month = 3; dst_start_time.unit.hour = 2; dst_start_time.unit.minute = 0; dst_start_time.unit.second = 0; - weekday_first_of_month = watch_utility_get_iso8601_weekday_number(date_time.unit.year, dst_start_time.unit.month, 1); - dst_start_time.unit.day = 15 - weekday_first_of_month; + dst_start_time.unit.day = 15 - watch_utility_get_iso8601_weekday_number(dst_start_time.unit.year + WATCH_RTC_REFERENCE_YEAR, dst_start_time.unit.month, 1); unix_dst_start_time = watch_utility_date_time_to_unix_time(dst_start_time, 0); + dst_end_time.unit.year = date_time.unit.year; dst_end_time.unit.month = 11; dst_end_time.unit.hour = 2; dst_end_time.unit.minute = 0; dst_end_time.unit.second = 0; - weekday_first_of_month = watch_utility_get_iso8601_weekday_number(date_time.unit.year, dst_end_time.unit.month, 1); - dst_end_time.unit.day = 15 - weekday_first_of_month; + dst_end_time.unit.day = 15 - watch_utility_get_iso8601_weekday_number(dst_end_time.unit.year + WATCH_RTC_REFERENCE_YEAR, dst_end_time.unit.month, 1); unix_dst_end_time = watch_utility_date_time_to_unix_time(dst_end_time, 0); + if (date_time.unit.second > 45) // In emu, it's been seen that we may trigger at 59sec rather than exactly 0 each time + date_time.unit.minute = (date_time.unit.minute + 1) % 60; date_time.unit.second = 0; unix_curr_time = watch_utility_date_time_to_unix_time(date_time, 0); - if (unix_curr_time == unix_dst_start_time) return DST_STARTED; + if (unix_curr_time == unix_dst_start_time) return DST_STARTING; if (unix_curr_time == unix_dst_end_time) return DST_ENDING; if (unix_curr_time > unix_dst_end_time || unix_curr_time < unix_dst_start_time) return DST_ENDED; return DST_OCCURRING; -} +} + +bool dst_occurring(watch_date_time date_time) { + return get_dst_status(date_time) <= DST_OCCURRING; +} uint16_t watch_utility_days_since_new_year(uint16_t year, uint8_t month, uint8_t day) { uint16_t DAYS_SO_FAR[] = {