]> git.earman.xyz Git - sensor-watch.git/commitdiff
integrate utz, use DST-aware time zones instead of bare offsets
authorjoeycastillo <joeycastillo@utexas.edu>
Tue, 24 Sep 2024 03:27:10 +0000 (23:27 -0400)
committerjoeycastillo <joeycastillo@utexas.edu>
Tue, 24 Sep 2024 03:27:10 +0000 (23:27 -0400)
Makefile
movement.c
movement.h
movement_config.h
movement_faces.h
watch-faces.mk
watch-faces/clock/world_clock_face.c
watch-faces/clock/world_clock_face.h
watch-faces/settings/set_time_face.c
watch-library/shared/watch/watch_utility.c

index 1916662d16880b5b45dde54c08eb832ce3f3d07b..3dbdf4b8487654c5bf652772a083725aced0ef96 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -30,6 +30,7 @@ INCLUDES += \
   -I./ \
   -I./tinyusb/src \
   -I./littlefs \
+  -I./utz \
   -I./filesystem \
   -I./shell \
   -I./watch-library/shared/watch \
@@ -42,6 +43,8 @@ SRCS += \
   ./littlefs/lfs.c \
   ./littlefs/lfs_util.c \
   ./filesystem/filesystem.c \
+  ./utz/utz.c \
+  ./utz/zones.c \
   ./shell/shell.c \
   ./shell/shell_cmd_list.c \
   ./watch-library/shared/watch/watch_common_buzzer.c \
index df93d24e21c0261cf31c3298d934bd94a663d359..9a512fcbd95789cac9dd3ce6638da4be683fef58 100644 (file)
@@ -38,6 +38,7 @@
 #include "movement.h"
 #include "filesystem.h"
 #include "shell.h"
+#include "utz.h"
 
 /// FIXME: #SecondMovement needs to bring back the following include (and remove the default signal_tune)
 // #include "movement_custom_signal_tunes.h"
@@ -62,50 +63,6 @@ const int32_t movement_le_inactivity_deadlines[8] = {INT_MAX, 600, 3600, 7200, 2
 const int16_t movement_timeout_inactivity_deadlines[4] = {60, 120, 300, 1800};
 movement_event_t event;
 
-const int16_t movement_timezone_offsets[] = {
-    0,      //  0 :   0:00:00 (UTC)
-    60,     //  1 :   1:00:00 (Central European Time)
-    120,    //  2 :   2:00:00 (South African Standard Time)
-    180,    //  3 :   3:00:00 (Arabia Standard Time)
-    210,    //  4 :   3:30:00 (Iran Standard Time)
-    240,    //  5 :   4:00:00 (Georgia Standard Time)
-    270,    //  6 :   4:30:00 (Afghanistan Time)
-    300,    //  7 :   5:00:00 (Pakistan Standard Time)
-    330,    //  8 :   5:30:00 (Indian Standard Time)
-    345,    //  9 :   5:45:00 (Nepal Time)
-    360,    // 10 :   6:00:00 (Kyrgyzstan time)
-    390,    // 11 :   6:30:00 (Myanmar Time)
-    420,    // 12 :   7:00:00 (Thailand Standard Time)
-    480,    // 13 :   8:00:00 (China Standard Time, Australian Western Standard Time)
-    525,    // 14 :   8:45:00 (Australian Central Western Standard Time)
-    540,    // 15 :   9:00:00 (Japan Standard Time, Korea Standard Time)
-    570,    // 16 :   9:30:00 (Australian Central Standard Time)
-    600,    // 17 :  10:00:00 (Australian Eastern Standard Time)
-    630,    // 18 :  10:30:00 (Lord Howe Standard Time)
-    660,    // 19 :  11:00:00 (Solomon Islands Time)
-    720,    // 20 :  12:00:00 (New Zealand Standard Time)
-    765,    // 21 :  12:45:00 (Chatham Standard Time)
-    780,    // 22 :  13:00:00 (Tonga Time)
-    825,    // 23 :  13:45:00 (Chatham Daylight Time)
-    840,    // 24 :  14:00:00 (Line Islands Time)
-    -720,   // 25 : -12:00:00 (Baker Island Time)
-    -660,   // 26 : -11:00:00 (Niue Time)
-    -600,   // 27 : -10:00:00 (Hawaii-Aleutian Standard Time)
-    -570,   // 28 :  -9:30:00 (Marquesas Islands Time)
-    -540,   // 29 :  -9:00:00 (Alaska Standard Time)
-    -480,   // 30 :  -8:00:00 (Pacific Standard Time)
-    -420,   // 31 :  -7:00:00 (Mountain Standard Time)
-    -360,   // 32 :  -6:00:00 (Central Standard Time)
-    -300,   // 33 :  -5:00:00 (Eastern Standard Time)
-    -270,   // 34 :  -4:30:00 (Venezuelan Standard Time)
-    -240,   // 35 :  -4:00:00 (Atlantic Standard Time)
-    -210,   // 36 :  -3:30:00 (Newfoundland Standard Time)
-    -180,   // 37 :  -3:00:00 (Brasilia Time)
-    -150,   // 38 :  -2:30:00 (Newfoundland Daylight Time)
-    -120,   // 39 :  -2:00:00 (Fernando de Noronha Time)
-    -60,    // 40 :  -1:00:00 (Azores Standard Time)
-};
-
 const char movement_valid_position_0_chars[] = " AaBbCcDdEeFGgHhIiJKLMNnOoPQrSTtUuWXYZ-='+\\/0123456789";
 const char movement_valid_position_1_chars[] = " ABCDEFHlJLNORTtUX-='01378";
 
@@ -348,6 +305,30 @@ uint8_t movement_claim_backup_register(void) {
     return movement_state.next_available_backup_register++;
 }
 
+int32_t movement_get_current_timezone_offset_for_zone(uint8_t zone_index) {
+    watch_date_time date_time = watch_rtc_get_date_time();
+    uzone_t time_zone;
+    uoffset_t offset;
+    udatetime_t udate_time = {
+        .date.dayofmonth = date_time.unit.day,
+        .date.dayofweek = dayofweek(date_time.unit.year + WATCH_RTC_REFERENCE_YEAR - UYEAR_OFFSET, date_time.unit.month, date_time.unit.day),
+        .date.month = date_time.unit.month,
+        .date.year = date_time.unit.year + WATCH_RTC_REFERENCE_YEAR - UYEAR_OFFSET,
+        .time.hour = date_time.unit.hour,
+        .time.minute = date_time.unit.minute,
+        .time.second = date_time.unit.second
+    };
+
+    unpack_zone(&zone_defns[zone_index], "", &time_zone);
+    get_current_offset(&time_zone, &udate_time, &offset);
+
+    return offset.hours * 3600 + offset.minutes * 60;
+}
+
+int32_t movement_get_current_timezone_offset(void) {
+    return movement_get_current_timezone_offset_for_zone(movement_state.settings.bit.time_zone);
+}
+
 void app_init(void) {
     _watch_init();
 
@@ -381,6 +362,7 @@ void app_init(void) {
     movement_state.settings.bit.clock_mode_24h = true;
 #else
     movement_state.settings.bit.clock_mode_24h = MOVEMENT_DEFAULT_24H_MODE;
+    movement_state.settings.bit.time_zone = 15;
 #endif
     movement_state.settings.bit.led_red_color = MOVEMENT_DEFAULT_RED_COLOR;
     movement_state.settings.bit.led_green_color = MOVEMENT_DEFAULT_GREEN_COLOR;
index fd323ea62d8fc3503eae73a06d09d6089618af00..7eecd2be1ddc55e286a97ec1c4e4bc1e5c325e02 100644 (file)
@@ -27,6 +27,7 @@
 #include <stdio.h>
 #include <stdbool.h>
 #include "watch.h"
+#include "utz.h"
 
 // Movement Preferences
 // These four 32-bit structs store information about the wearer and their preferences. Tentatively, the plan is
@@ -314,3 +315,6 @@ void movement_play_alarm(void);
 void movement_play_alarm_beeps(uint8_t rounds, watch_buzzer_note_t alarm_note);
 
 uint8_t movement_claim_backup_register(void);
+
+int32_t movement_get_current_timezone_offset_for_zone(uint8_t zone_index);
+int32_t movement_get_current_timezone_offset(void);
index e90efd4c3a3a5e14d442c013599521f965d76200..902e72a3cf7c853ee2804e40a096649fd5afadce 100644 (file)
@@ -29,6 +29,7 @@
 
 const watch_face_t watch_faces[] = {
     simple_clock_face,
+    world_clock_face,
     preferences_face,
     set_time_face,
 };
index b7791f65dc9bd03effd083bd2c27cebd56827157..f4ca6917aa1f71984a8daae80ba9d4aded89e989 100644 (file)
@@ -25,6 +25,7 @@
 #pragma once
 
 #include "simple_clock_face.h"
+#include "world_clock_face.h"
 #include "set_time_face.h"
 #include "preferences_face.h"
 // New includes go above this line.
index 338c3b9986aa54629515ce939076897806f4ba4c..c84a17e57cc94661fc15cec38b3dfbbacc5403fb 100644 (file)
@@ -1,4 +1,5 @@
 SRCS += \
   ./watch-faces/clock/simple_clock_face.c \
+  ./watch-faces/clock/world_clock_face.c \
   ./watch-faces/settings/set_time_face.c \
   ./watch-faces/settings/preferences_face.c \
index 8f530133880ae2a42353d65ade9fa682c4e29791..924651b269ef16726b8d08b594d6113bb0cc7712 100644 (file)
 #include "watch.h"
 #include "watch_utility.h"
 #include "watch_common_display.h"
+#include "zones.h"
+
+void _update_timezone_offset(world_clock_state_t *state);
+void _update_timezone_offset(world_clock_state_t *state) {
+    state->current_offset = movement_get_current_timezone_offset_for_zone(state->settings.bit.timezone_index);
+}
 
 void world_clock_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
     (void) settings;
@@ -35,9 +41,10 @@ void world_clock_face_setup(movement_settings_t *settings, uint8_t watch_face_in
     if (*context_ptr == NULL) {
         *context_ptr = malloc(sizeof(world_clock_state_t));
         memset(*context_ptr, 0, sizeof(world_clock_state_t));
+        world_clock_state_t *state = (world_clock_state_t *)*context_ptr;
+        state->settings.bit.timezone_index = 15;
         uint8_t backup_register = movement_claim_backup_register();
         if (backup_register) {
-            world_clock_state_t *state = (world_clock_state_t *)*context_ptr;
             state->settings.reg = watch_get_backup_data(backup_register);
             state->backup_register = backup_register;
         }
@@ -47,7 +54,9 @@ void world_clock_face_setup(movement_settings_t *settings, uint8_t watch_face_in
 void world_clock_face_activate(movement_settings_t *settings, void *context) {
     (void) settings;
     world_clock_state_t *state = (world_clock_state_t *)context;
+
     state->current_screen = 0;
+    _update_timezone_offset(state);
 
     if (watch_tick_animation_is_running()) watch_stop_tick_animation();
 }
@@ -55,7 +64,6 @@ void world_clock_face_activate(movement_settings_t *settings, void *context) {
 static bool world_clock_face_do_display_mode(movement_event_t event, movement_settings_t *settings, world_clock_state_t *state) {
     char buf[11];
 
-    uint32_t timestamp;
     uint32_t previous_date_time;
     watch_date_time date_time;
     switch (event.event_type) {
@@ -67,8 +75,7 @@ static bool world_clock_face_do_display_mode(movement_event_t event, movement_se
         case EVENT_TICK:
         case EVENT_LOW_ENERGY_UPDATE:
             date_time = watch_rtc_get_date_time();
-            timestamp = watch_utility_date_time_to_unix_time(date_time, movement_timezone_offsets[settings->bit.time_zone] * 60);
-            date_time = watch_utility_date_time_from_unix_time(timestamp, movement_timezone_offsets[state->settings.bit.timezone_index] * 60);
+            date_time = watch_utility_date_time_convert_zone(date_time, movement_get_current_timezone_offset(), state->current_offset);
             previous_date_time = state->previous_date_time;
             state->previous_date_time = date_time.reg;
             if ((date_time.reg >> 6) == (previous_date_time >> 6) && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
@@ -81,6 +88,9 @@ static bool world_clock_face_do_display_mode(movement_event_t event, movement_se
                 sprintf(buf, "%02d%02d", date_time.unit.minute, date_time.unit.second);
                 watch_display_text(WATCH_POSITION_MINUTES, buf);
                 watch_display_text(WATCH_POSITION_SECONDS, buf + 2);
+                if (date_time.unit.minute % 15 == 0) {
+                    _update_timezone_offset(state);
+                }
             } else {
                 // other stuff changed; let's do it all.
                 if (!settings->bit.clock_mode_24h) {
@@ -127,6 +137,7 @@ static bool _world_clock_face_do_settings_mode(movement_event_t event, movement_
             state->current_screen++;
             if (state->current_screen > 3) {
                 movement_request_tick_frequency(1);
+                _update_timezone_offset(state);
                 state->current_screen = 0;
                 if (state->backup_register) watch_store_backup_data(state->settings.reg, state->backup_register);
                 event.event_type = EVENT_ACTIVATE;
@@ -149,7 +160,7 @@ static bool _world_clock_face_do_settings_mode(movement_event_t event, movement_
                     break;
                 case 3:
                     state->settings.bit.timezone_index++;
-                    if (state->settings.bit.timezone_index > 40) state->settings.bit.timezone_index = 0;
+                    if (state->settings.bit.timezone_index >= NUM_ZONE_NAMES) state->settings.bit.timezone_index = 0;
                     break;
             }
             break;
@@ -161,12 +172,12 @@ static bool _world_clock_face_do_settings_mode(movement_event_t event, movement_
     }
 
     char buf[13];
-    sprintf(buf, "%c%c %3d%02d  ",
+
+    watch_clear_colon();
+    sprintf(buf, "%c%c  %s",
         movement_valid_position_0_chars[state->settings.bit.char_0],
         movement_valid_position_1_chars[state->settings.bit.char_1],
-        (int8_t) (movement_timezone_offsets[state->settings.bit.timezone_index] / 60),
-        (int8_t) (movement_timezone_offsets[state->settings.bit.timezone_index] % 60) * (movement_timezone_offsets[state->settings.bit.timezone_index] < 0 ? -1 : 1));
-    watch_set_colon();
+        (char *) (3 + zone_names + 11 * state->settings.bit.timezone_index));
     watch_clear_indicator(WATCH_INDICATOR_PM);
 
     // blink up the parameter we're setting
@@ -177,7 +188,6 @@ static bool _world_clock_face_do_settings_mode(movement_event_t event, movement_
                 buf[state->current_screen - 1] = '_';
                 break;
             case 3:
-                watch_clear_colon();
                 sprintf(buf + 3, "       ");
                 break;
         }
index 92e91a6ff28bc63f71f0457ecc466c2045bf2bfa..bca82cd94ac90892dfbf9591f25b3e53eba11b29 100644 (file)
@@ -62,6 +62,7 @@ typedef struct {
     uint8_t backup_register;
     uint8_t current_screen;
     uint32_t previous_date_time;
+    int32_t current_offset;
 } world_clock_state_t;
 
 void world_clock_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
index 549ad8b765b797d4acd5e71fab3a2f00198d65f9..c1c92577c19425e473c01d1d0f8dee312d608430 100644 (file)
 #include "set_time_face.h"
 #include "watch.h"
 #include "watch_utility.h"
+#include "zones.h"
 
 #define SET_TIME_FACE_NUM_SETTINGS (7)
-const char set_time_face_titles[SET_TIME_FACE_NUM_SETTINGS][3] = {"HR", "M1", "SE", "YR", "MO", "DA", "ZO"};
+const char set_time_face_titles[SET_TIME_FACE_NUM_SETTINGS][3] = {"HR", "M1", "SE", "YR", "MO", "DA", "  "};
 
 static bool _quick_ticks_running;
 
@@ -58,7 +59,7 @@ static void _handle_alarm_button(movement_settings_t *settings, watch_date_time
         }
         case 6: // time zone
             settings->bit.time_zone++;
-            if (settings->bit.time_zone > 40) settings->bit.time_zone = 0;
+            if (settings->bit.time_zone >= NUM_ZONE_NAMES) settings->bit.time_zone = 0;
             break;
     }
     if (date_time.unit.day > days_in_month(date_time.unit.month, date_time.unit.year + WATCH_RTC_REFERENCE_YEAR))
@@ -145,13 +146,12 @@ bool set_time_face_loop(movement_event_t event, movement_settings_t *settings, v
         watch_clear_indicator(WATCH_INDICATOR_PM);
         sprintf(buf, "%2d%02d%02d", date_time.unit.year + 20, date_time.unit.month, date_time.unit.day);
     } else {
+        watch_display_text(WATCH_POSITION_TOP_RIGHT, " Z");
         if (event.subsecond % 2) {
-            watch_clear_colon();
             memset(buf, ' ', sizeof(buf));
         } else {
-            watch_set_colon();
-            if (movement_timezone_offsets[settings->bit.time_zone] < 0) watch_display_text(WATCH_POSITION_TOP_RIGHT, " -");
-            sprintf(buf, "%2d%02d  ", (int8_t) abs(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));
+            watch_display_text(WATCH_POSITION_TOP_LEFT, (char *) (zone_names + 11 * settings->bit.time_zone));
+            sprintf(buf, "%s", (char *) (3 + zone_names + 11 * settings->bit.time_zone));
         }
     }
 
index 51b8538cd44ac328f6da700eb94be84cfe8de35a..95869776adff04d77a0d8aef45a5b1c95f65a088 100644 (file)
@@ -315,11 +315,3 @@ uint32_t watch_utility_offset_timestamp(uint32_t now, int8_t hours, int8_t minut
     new += seconds;
     return new;
 }
-
-uint8_t days_in_month(uint8_t month, uint16_t year) {
-    static const uint8_t days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-    uint8_t days = days_in_month[month - 1];
-    if (month == 2 && is_leap(year))
-        days += 1;
-    return days;
-}