]> git.earman.xyz Git - sensor-watch.git/commitdiff
movement: make stopwatch work off-screen + in low energy mode
authorJoey Castillo <joeycastillo@utexas.edu>
Sun, 6 Feb 2022 20:05:28 +0000 (15:05 -0500)
committerJoey Castillo <joeycastillo@utexas.edu>
Sun, 6 Feb 2022 20:05:28 +0000 (15:05 -0500)
movement/watch_faces/complication/stopwatch_face.c
movement/watch_faces/complication/stopwatch_face.h

index 4a145abf371645f72628308580ac42067498a0ed..e85bbd65f62f95b753059b933bbe8fa6067ca97f 100644 (file)
@@ -1,46 +1,95 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Wesley Ellis
+ * Copyright (c) 2022 Joey Castillo
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
 #include <stdlib.h>
 #include <string.h>
 #include "stopwatch_face.h"
 #include "watch.h"
+#include "watch_utility.h"
 
 void stopwatch_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
     (void) settings;
     (void) watch_face_index;
-    if (*context_ptr == NULL) *context_ptr = malloc(sizeof(stopwatch_state_t));
+    if (*context_ptr == NULL) {
+        *context_ptr = malloc(sizeof(stopwatch_state_t));
+        memset(*context_ptr, 0, sizeof(stopwatch_state_t));
+    }
+}
+
+static void _stopwatch_face_update_display(stopwatch_state_t *stopwatch_state, bool show_seconds) {
+    if (stopwatch_state->running) {
+        watch_date_time now = watch_rtc_get_date_time();
+        uint32_t now_timestamp = watch_utility_date_time_to_unix_time(now, 0);
+        uint32_t start_timestamp = watch_utility_date_time_to_unix_time(stopwatch_state->start_time, 0);
+        stopwatch_state->seconds_counted = now_timestamp - start_timestamp;
+    }
+
+    if (stopwatch_state->seconds_counted >= 3456000) {
+        // display maxes out just shy of 40 days, thanks to the limit on the day digits (0-39)
+        stopwatch_state->running = false;
+        watch_display_string("st39235959", 0);
+        return;
+    }
+
+    watch_duration_t duration = watch_utility_seconds_to_duration(stopwatch_state->seconds_counted);
+    char buf[14];
+
+    sprintf(buf, "st  %02d%02d  ", duration.hours, duration.minutes);
+    watch_display_string(buf, 0);
+
+    if (duration.days != 0) {
+        sprintf(buf, "%2d", (uint8_t)duration.days);
+        watch_display_string(buf, 2);
+    }
+
+    if (show_seconds) {
+        sprintf(buf, "%02d", duration.seconds);
+        watch_display_string(buf, 8);
+    }
 }
 
 void stopwatch_face_activate(movement_settings_t *settings, void *context) {
     (void) settings;
-    memset(context, 0, sizeof(stopwatch_state_t));
+    (void) context;
+    if (watch_tick_animation_is_running()) watch_stop_tick_animation();
 }
 
 bool stopwatch_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
     (void) settings;
-
     stopwatch_state_t *stopwatch_state = (stopwatch_state_t *)context;
-    char buf[14];
 
     switch (event.event_type) {
         case EVENT_ACTIVATE:
             watch_set_colon();
-            stopwatch_state->running = false;
-            watch_display_string("st 00000", 0);
-            break;
+            // fall through
         case EVENT_TICK:
-            if (stopwatch_state->running) {
-                stopwatch_state->seconds++;
-                if (stopwatch_state->seconds == 60) {
-                    stopwatch_state->minutes++;
-                    stopwatch_state->seconds = 0;
-                }
-                if (stopwatch_state->minutes == 60) {
-                    stopwatch_state->hours++;
-                    stopwatch_state->minutes = 0;
-                }
+            if (stopwatch_state->start_time.reg == 0) {
+                watch_display_string("st  000000", 0);
+            } else {
+                _stopwatch_face_update_display(stopwatch_state, true);
             }
-
-            sprintf(buf, "st%2d%02d%02d", stopwatch_state->hours, stopwatch_state->minutes, stopwatch_state->seconds);
-            watch_display_string(buf, 0);
             break;
         case EVENT_MODE_BUTTON_UP:
             movement_move_to_next_face();
@@ -48,20 +97,35 @@ bool stopwatch_face_loop(movement_event_t event, movement_settings_t *settings,
         case EVENT_LIGHT_BUTTON_DOWN:
             movement_illuminate_led();
             if (!stopwatch_state->running) {
-                stopwatch_state->seconds = 0;
-                stopwatch_state->minutes = 0;
-                stopwatch_state->hours = 0;
-                watch_display_string("st 00000", 0);
+                stopwatch_state->start_time.reg = 0;
+                stopwatch_state->seconds_counted = 0;
+                watch_display_string("st  000000", 0);
             }
             break;
         case EVENT_ALARM_BUTTON_DOWN:
             stopwatch_state->running = !stopwatch_state->running;
+            if (stopwatch_state->running) {
+                // we're running now, so we need to set the start_time.
+                if (stopwatch_state->start_time.reg == 0) {
+                    // if starting from the reset state, easy: we start now.
+                    stopwatch_state->start_time = watch_rtc_get_date_time();
+                } else {
+                    // if resuming with time already on the clock, the original start time isn't valid anymore!
+                    // so let's fetch the current time...
+                    uint32_t timestamp = watch_utility_date_time_to_unix_time(watch_rtc_get_date_time(), 0);
+                    // ...subtract the seconds we've already counted...
+                    timestamp -= stopwatch_state->seconds_counted;
+                    // and resume from the "virtual" start time that's that many seconds ago.
+                    stopwatch_state->start_time = watch_utility_date_time_from_unix_time(timestamp, 0);
+                }
+            }
             break;
         case EVENT_TIMEOUT:
             // explicitly ignore the timeout event so we stay on screen
             break;
         case EVENT_LOW_ENERGY_UPDATE:
-            stopwatch_state->running = false;
+            if (!watch_tick_animation_is_running()) watch_start_tick_animation(500);
+            _stopwatch_face_update_display(stopwatch_state, false);
             watch_set_indicator(WATCH_INDICATOR_BELL);
             break;
         default:
index c6e3aadb5b19f375d99b0b0a634f20a84809a868..a30c7fb65a3f1d55f1e4629a4684222e2a68561f 100644 (file)
@@ -1,3 +1,28 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Wesley Ellis
+ * Copyright (c) 2022 Joey Castillo
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
 #ifndef STOPWATCH_FACE_H_
 #define STOPWATCH_FACE_H_
 
@@ -5,9 +30,8 @@
 
 typedef struct {
     bool running;
-    uint8_t seconds;
-    uint8_t minutes;
-    uint8_t hours;
+    watch_date_time start_time; // while running, show the difference between this time and now
+    uint32_t seconds_counted;   // set this value when paused, and show that instead.
 } stopwatch_state_t;
 
 void stopwatch_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);