From 149911e4addf203d90ed84f8a6884508637ef6d1 Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Fri, 2 Aug 2024 01:23:21 -0400 Subject: [PATCH] Time now auto-updates with DST --- movement/movement.c | 16 +++++++++ movement/movement.h | 1 + movement/watch_faces/clock/clock_face.c | 24 +++++++++++--- .../watch_faces/clock/simple_clock_face.c | 24 +++++++++++--- movement/watch_faces/settings/set_time_face.c | 10 ++---- watch-library/shared/watch/watch_utility.c | 33 +++++++++++++++++++ watch-library/shared/watch/watch_utility.h | 13 ++++++++ 7 files changed, 105 insertions(+), 16 deletions(-) diff --git a/movement/movement.c b/movement/movement.c index 8b45535f..5c804fe6 100644 --- a/movement/movement.c +++ b/movement/movement.c @@ -34,6 +34,7 @@ #include "filesystem.h" #include "movement.h" #include "shell.h" +#include "watch_utility.h" #ifndef MOVEMENT_FIRMWARE #include "movement_config.h" @@ -467,6 +468,21 @@ uint8_t movement_claim_backup_register(void) { return movement_state.next_available_backup_register++; } +int16_t get_timezone_offset(uint8_t timezone_idx, watch_date_time date_time) { + if (!movement_state.settings.bit.dst_active) return movement_timezone_offsets[timezone_idx]; + uint8_t dst_result = is_dst(date_time); + switch (dst_result) + { + case DST_STARTED: + case DST_OCCURRING: + return movement_timezone_offsets[movement_dst_jump_table[timezone_idx]]; + case DST_ENDING: + case DST_ENDED: + default: + return movement_timezone_offsets[timezone_idx]; + } +} + void app_init(void) { #if defined(NO_FREQCORR) watch_rtc_freqcorr_write(0, 0); diff --git a/movement/movement.h b/movement/movement.h index d19ab3fc..a89e3778 100644 --- a/movement/movement.h +++ b/movement/movement.h @@ -314,5 +314,6 @@ void movement_play_alarm(void); void movement_play_alarm_beeps(uint8_t rounds, BuzzerNote alarm_note); uint8_t movement_claim_backup_register(void); +int16_t get_timezone_offset(uint8_t timezone_idx, watch_date_time date_time); #endif // MOVEMENT_H_ diff --git a/movement/watch_faces/clock/clock_face.c b/movement/watch_faces/clock/clock_face.c index eab5cd8d..68019d85 100644 --- a/movement/watch_faces/clock/clock_face.c +++ b/movement/watch_faces/clock/clock_face.c @@ -280,12 +280,28 @@ void clock_face_resign(movement_settings_t *settings, void *context) { (void) context; } -bool clock_face_wants_background_task(movement_settings_t *settings, void *context) { - (void) settings; - clock_state_t *state = (clock_state_t *) context; - if (!state->time_signal_enabled) return false; +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: + return; + } + watch_rtc_set_date_time(date_time); +} +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); + 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 fbc2c4b3..c0f83723 100644 --- a/movement/watch_faces/clock/simple_clock_face.c +++ b/movement/watch_faces/clock/simple_clock_face.c @@ -150,12 +150,28 @@ void simple_clock_face_resign(movement_settings_t *settings, void *context) { (void) context; } -bool simple_clock_face_wants_background_task(movement_settings_t *settings, void *context) { - (void) settings; - simple_clock_state_t *state = (simple_clock_state_t *)context; - if (!state->signal_enabled) return false; +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: + return; + } + watch_rtc_set_date_time(date_time); +} +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); + 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 fb0c8064..90edac25 100644 --- a/movement/watch_faces/settings/set_time_face.c +++ b/movement/watch_faces/settings/set_time_face.c @@ -67,13 +67,6 @@ static void _handle_alarm_button(movement_settings_t *settings, watch_date_time if (settings->bit.time_zone > 40) settings->bit.time_zone = 0; break; case 7: // daylight savings time - if (settings->bit.dst_active) { // deactivate DST - date_time.unit.hour = (date_time.unit.hour + 24 - 1) % 24; - settings->bit.time_zone = movement_dst_inverse_jump_table[settings->bit.time_zone]; - } else { // activate DST - date_time.unit.hour = (date_time.unit.hour + 1) % 24; - settings->bit.time_zone = movement_dst_jump_table[settings->bit.time_zone]; - } settings->bit.dst_active = !settings->bit.dst_active; break; } @@ -161,8 +154,9 @@ bool set_time_face_loop(movement_event_t event, movement_settings_t *settings, v watch_clear_colon(); sprintf(buf, "%s ", set_time_face_titles[current_page]); } else { + int16_t tz = get_timezone_offset(settings->bit.time_zone, date_time); watch_set_colon(); - sprintf(buf, "%s %3d%02d ", set_time_face_titles[current_page], (int8_t) (movement_timezone_offsets[settings->bit.time_zone] / 60), (int8_t) (movement_timezone_offsets[settings->bit.time_zone] % 60) * (movement_timezone_offsets[settings->bit.time_zone] < 0 ? -1 : 1)); + sprintf(buf, "%s %3d%02d ", set_time_face_titles[current_page], (int8_t) (tz / 60), (int8_t) (tz % 60) * (tz < 0 ? -1 : 1)); } } else { // daylight savings watch_clear_colon(); diff --git a/watch-library/shared/watch/watch_utility.c b/watch-library/shared/watch/watch_utility.c index 64b3bb79..1410e414 100644 --- a/watch-library/shared/watch/watch_utility.c +++ b/watch-library/shared/watch/watch_utility.c @@ -83,6 +83,39 @@ 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; + 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.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; + unix_dst_start_time = watch_utility_date_time_to_unix_time(dst_start_time, 0); + + 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; + unix_dst_end_time = watch_utility_date_time_to_unix_time(dst_end_time, 0); + + 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_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; +} + uint16_t watch_utility_days_since_new_year(uint16_t year, uint8_t month, uint8_t day) { uint16_t DAYS_SO_FAR[] = { 0, // Jan diff --git a/watch-library/shared/watch/watch_utility.h b/watch-library/shared/watch/watch_utility.h index e2326d13..d3f3981a 100644 --- a/watch-library/shared/watch/watch_utility.h +++ b/watch-library/shared/watch/watch_utility.h @@ -45,6 +45,13 @@ typedef struct { uint32_t days; // 0-4294967295 } watch_duration_t; +typedef enum { + DST_STARTED, + DST_OCCURRING, + DST_ENDING, + DST_ENDED +} dst_t; + /** @brief Returns a two-letter weekday for the given timestamp, suitable for display * in positions 0-1 of the watch face * @param date_time The watch_date_time whose weekday you want. @@ -78,6 +85,12 @@ uint16_t watch_utility_days_since_new_year(uint16_t year, uint8_t month, uint8_t */ uint8_t is_leap(uint16_t year); +/** @brief Returns off of dst_t based off if DST is occurring, srted, ended, or none of those. + * @param date_time The watch_date_time that you wish to convert. + * @return DST_OCCURRING, DST_HAPPENING, DST_ENDING, DST_ENDED + */ +uint8_t is_dst(watch_date_time date_time); + /** @brief Returns the UNIX time (seconds since 1970) for a given date/time in UTC. * @param date_time The watch_date_time that you wish to convert. * @param year The year of the date you wish to convert.