]> git.earman.xyz Git - sensor-watch.git/commitdiff
bring wake_face into Second Movement (renamed alarm_face)
authorJoey Castillo <joeycastillo@utexas.edu>
Wed, 21 May 2025 19:07:29 +0000 (15:07 -0400)
committerJoey Castillo <joeycastillo@utexas.edu>
Wed, 21 May 2025 19:07:29 +0000 (15:07 -0400)
legacy/watch_faces/complication/wake_face.c [deleted file]
legacy/watch_faces/complication/wake_face.h [deleted file]
movement_faces.h
watch-faces.mk
watch-faces/complication/alarm_face.c [new file with mode: 0644]
watch-faces/complication/alarm_face.h [new file with mode: 0644]

diff --git a/legacy/watch_faces/complication/wake_face.c b/legacy/watch_faces/complication/wake_face.c
deleted file mode 100644 (file)
index 30982da..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2022 Josh Berson, building on Wesley Ellis’ countdown_face.c
- *
- * 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 "wake_face.h"
-#include "watch.h"
-#include "watch_utility.h"
-
-//
-// Private
-//
-
-static
-void _wake_face_update_display(wake_face_state_t *state) {
-    uint8_t hour = state->hour;
-
-    watch_clear_display();
-    if ( movement_clock_mode_24h() )
-        watch_set_indicator(WATCH_INDICATOR_24H);
-    else {
-        if ( hour >= 12 )
-            watch_set_indicator(WATCH_INDICATOR_PM);
-        hour = hour % 12 ? hour % 12 : 12;
-    }
-
-    if ( state->mode )
-        watch_set_indicator(WATCH_INDICATOR_BELL);
-
-    static char lcdbuf[11];
-    sprintf(lcdbuf, "WA  %2d%02d  ", hour, state->minute);
-
-    watch_set_colon();
-    watch_display_string(lcdbuf, 0);
-}
-
-//
-// Exported
-//
-
-void wake_face_setup(uint8_t watch_face_index, void **context_ptr) {
-    (void) watch_face_index;
-
-    if (*context_ptr == NULL) {
-        *context_ptr = malloc(sizeof(wake_face_state_t));
-        wake_face_state_t *state = (wake_face_state_t *)*context_ptr;
-        memset(*context_ptr, 0, sizeof(wake_face_state_t));
-
-        state->hour = 5;
-        state->minute = 0;
-        state->mode = 0;
-    }
-}
-
-void wake_face_activate(void *context) {
-    (void) context;
-}
-void wake_face_resign(void *context) {
-    (void) context;
-}
-
-movement_watch_face_advisory_t wake_face_advise(void *context) {
-    wake_face_state_t *state = (wake_face_state_t *)context;
-    movement_watch_face_advisory_t retval = { 0 };
-
-    if ( state->mode ) {
-        watch_date_time_t now = watch_rtc_get_date_time();
-        retval.wants_background_task = state->hour==now.unit.hour && state->minute==now.unit.minute;
-        // We’re at the mercy of the advise handler
-        // In Safari, the emulator triggers at the ›end‹ of the minute
-        // Converting to Unix timestamps and taking a difference between now and wake
-        // is not an easy win — because the timestamp for wake has to rely on now
-        // for its date. So first we’d have to see if the TOD of wake is after that
-        // of now. If it is, take tomorrow’s date, calculating month and year rollover
-        // if need be.
-    }
-
-    return retval;
-}
-
-bool wake_face_loop(movement_event_t event, void *context) {
-    wake_face_state_t *state = (wake_face_state_t *)context;
-
-    switch (event.event_type) {
-    case EVENT_ACTIVATE:
-    case EVENT_TICK:
-        _wake_face_update_display(state);
-        break;
-    case EVENT_LIGHT_BUTTON_UP:
-        state->hour = (state->hour + 1) % 24;
-        _wake_face_update_display(state);
-        break;
-    case EVENT_LIGHT_LONG_PRESS:
-        state->hour = (state->hour + 6) % 24;
-        _wake_face_update_display(state);
-        break;
-    case EVENT_ALARM_BUTTON_UP:
-        state->minute = (state->minute + 10) % 60;
-        _wake_face_update_display(state);
-        break;
-    case EVENT_ALARM_LONG_PRESS:
-        state->mode ^= 1;
-        _wake_face_update_display(state);
-        break;
-    case EVENT_BACKGROUND_TASK:
-        movement_play_alarm();
-            // 2022-07-23: Thx @joeycastillo for the dedicated “alarm” signal
-        break;
-    case EVENT_TIMEOUT:
-        movement_move_to_face(0);
-        break;
-    case EVENT_LOW_ENERGY_UPDATE:
-        break;
-    case EVENT_LIGHT_BUTTON_DOWN:
-        // don't light up every time light is hit
-        break;
-    default:
-        movement_default_loop_handler(event);
-        break;
-    }
-
-    return true;
-}
diff --git a/legacy/watch_faces/complication/wake_face.h b/legacy/watch_faces/complication/wake_face.h
deleted file mode 100644 (file)
index 008a540..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2022 Josh Berson
- *
- * 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 WAKE_FACE_H_
-#define WAKE_FACE_H_
-
-/*
- * WAKE daily alarm face
- *
- * Basic daily alarm clock face. Seems useful if nothing else in the interest
- * of feature parity with the F-91W’s OEM module, 593.
- *
- * Also experiments with caret-free UI: One button cycles hours, the other
- * minutes, so there’s no toggling between display and adjust modes and no
- * cycling the caret through the UI.
- *   º LIGHT advances hour by 1
- *   º LIGHT long press advances hour by 6
- *   º ALARM advances minute by 10
- *   º ALARM long press cycles through signal modes (just one at the moment)
- */
-
-#include "movement.h"
-
-typedef struct {
-    uint32_t hour : 5;
-    uint32_t minute : 6;
-    uint32_t mode : 1;
-} wake_face_state_t;
-
-void wake_face_setup(uint8_t watch_face_index, void **context_ptr);
-void wake_face_activate(void *context);
-bool wake_face_loop(movement_event_t event, void *context);
-void wake_face_resign(void *context);
-movement_watch_face_advisory_t wake_face_advise(void *context);
-
-#define wake_face ((const watch_face_t){ \
-    wake_face_setup, \
-    wake_face_activate, \
-    wake_face_loop, \
-    wake_face_resign, \
-    wake_face_advise \
-})
-
-#endif // WAKE_FACE_H_
-
index 7baa7145572dc910f7588db1debb1026312c89a0..0ac1545eacbfda27617becca9235a79b9e25ac3e 100644 (file)
@@ -27,6 +27,7 @@
 #include "clock_face.h"
 #include "beats_face.h"
 #include "world_clock_face.h"
+#include "alarm_face.h"
 #include "advanced_alarm_face.h"
 #include "countdown_face.h"
 #include "stopwatch_face.h"
index 610c51ac4598c2ca1840e265808daf6db3e80a45..8a9d29c89eba976211f1613f6ade0becddc6e31e 100644 (file)
@@ -2,6 +2,7 @@ SRCS += \
   ./watch-faces/clock/clock_face.c \
   ./watch-faces/clock/beats_face.c \
   ./watch-faces/clock/world_clock_face.c \
+  ./watch-faces/complication/alarm_face.c \
   ./watch-faces/complication/advanced_alarm_face.c \
   ./watch-faces/complication/countdown_face.c \
   ./watch-faces/complication/stopwatch_face.c \
diff --git a/watch-faces/complication/alarm_face.c b/watch-faces/complication/alarm_face.c
new file mode 100644 (file)
index 0000000..010a8a4
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Josh Berson, building on Wesley Ellis’ countdown_face.c
+ * Copyright (c) 2025 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 "alarm_face.h"
+#include "watch.h"
+#include "watch_utility.h"
+
+//
+// Private
+//
+
+static void _alarm_face_display_alarm_time(alarm_face_state_t *state) {
+    uint8_t hour = state->hour;
+
+    if ( movement_clock_mode_24h() )
+        watch_set_indicator(WATCH_INDICATOR_24H);
+    else {
+        if ( hour >= 12 ) watch_set_indicator(WATCH_INDICATOR_PM);
+        else watch_clear_indicator(WATCH_INDICATOR_PM);
+        hour = hour % 12 ? hour % 12 : 12;
+    }
+
+    static char lcdbuf[7];
+    sprintf(lcdbuf, "%2d%02d  ", hour, state->minute);
+
+    watch_display_text(WATCH_POSITION_BOTTOM, lcdbuf);
+}
+
+static inline void button_beep() {
+    // play a beep as confirmation for a button press (if applicable)
+    if (movement_button_should_sound()) watch_buzzer_play_note_with_volume(BUZZER_NOTE_C7, 50, movement_button_volume());
+}
+
+//
+// Exported
+//
+
+void alarm_face_setup(uint8_t watch_face_index, void **context_ptr) {
+    (void) watch_face_index;
+
+    if (*context_ptr == NULL) {
+        *context_ptr = malloc(sizeof(alarm_face_state_t));
+        alarm_face_state_t *state = (alarm_face_state_t *)*context_ptr;
+        memset(*context_ptr, 0, sizeof(alarm_face_state_t));
+
+        // default to an 8:00 AM alarm time.
+        state->hour = 8;
+    }
+}
+
+void alarm_face_activate(void *context) {
+    alarm_face_state_t *state = (alarm_face_state_t *)context;
+    state->setting_mode = ALARM_FACE_SETTING_MODE_NONE;
+}
+void alarm_face_resign(void *context) {
+    (void) context;
+}
+
+bool alarm_face_loop(movement_event_t event, void *context) {
+    alarm_face_state_t *state = (alarm_face_state_t *)context;
+
+    switch (event.event_type) {
+        case EVENT_ACTIVATE:
+            watch_display_text_with_fallback(WATCH_POSITION_TOP_LEFT, "ALM", "AL");
+            if (state->alarm_is_on) watch_set_indicator(WATCH_INDICATOR_SIGNAL);
+            watch_set_colon();
+            _alarm_face_display_alarm_time(state);
+            break;
+        case EVENT_TICK:
+            // No action needed for tick events in normal mode; we displayed our stuff in EVENT_ACTIVATE.
+            if (state->setting_mode == ALARM_FACE_SETTING_MODE_NONE)
+                break;
+
+            // but in settings mode, we need to blink up the parameter we're setting.
+            _alarm_face_display_alarm_time(state);
+            if (event.subsecond % 2 == 0) 
+                watch_display_text((state->setting_mode == ALARM_FACE_SETTING_MODE_SETTING_HOUR) ? WATCH_POSITION_HOURS : WATCH_POSITION_MINUTES, "  ");
+            break;
+        case EVENT_LIGHT_BUTTON_DOWN:
+            switch (state->setting_mode) {
+                case ALARM_FACE_SETTING_MODE_NONE:
+                    // If we're not in a setting mode, turn on the LED like normal.
+                    movement_illuminate_led();
+                    break;
+                case ALARM_FACE_SETTING_MODE_SETTING_HOUR:
+                    // If we're setting the hour, advance to minute set mode.
+                    state->setting_mode = ALARM_FACE_SETTING_MODE_SETTING_MINUTE;
+                    break;
+                case ALARM_FACE_SETTING_MODE_SETTING_MINUTE:
+                    // If we're setting the minute, advance back to normal mode and cancel fast tick.
+                    state->setting_mode = ALARM_FACE_SETTING_MODE_NONE;
+                    movement_request_tick_frequency(1);
+                    // beep to confirm setting.
+                    button_beep();
+                    // also turn the alarm on since they just set it.
+                    state->alarm_is_on = 1;
+                    watch_set_indicator(WATCH_INDICATOR_SIGNAL);
+                    _alarm_face_display_alarm_time(state);
+                    break;
+            }
+            break;
+        case EVENT_ALARM_BUTTON_UP:
+            if (state->setting_mode == ALARM_FACE_SETTING_MODE_NONE) {
+                // in normal mode, toggle alarm on/off.
+                state->alarm_is_on ^= 1;
+                if ( state->alarm_is_on ) watch_set_indicator(WATCH_INDICATOR_SIGNAL);
+                else watch_clear_indicator(WATCH_INDICATOR_SIGNAL);
+            }
+            break;
+        case EVENT_ALARM_BUTTON_DOWN:
+            switch (state->setting_mode) {
+                case ALARM_FACE_SETTING_MODE_NONE:
+                    // nothing to do here, alarm toggle is handled in EVENT_ALARM_BUTTON_UP.
+                    break;
+                case ALARM_FACE_SETTING_MODE_SETTING_HOUR:
+                    // increment hour, wrap around to 0 at 23.
+                    state->hour = (state->hour + 1) % 24;
+                    break;
+                case ALARM_FACE_SETTING_MODE_SETTING_MINUTE:
+                    // increment minute, wrap around to 0 at 59.
+                    state->minute = (state->minute + 1) % 60;
+                    break;
+            }
+            _alarm_face_display_alarm_time(state);
+            break;
+        case EVENT_ALARM_LONG_PRESS:
+            if (state->setting_mode == ALARM_FACE_SETTING_MODE_NONE) {
+                // long press in normal mode: move to hour setting mode, request fast tick.
+                state->setting_mode = ALARM_FACE_SETTING_MODE_SETTING_HOUR;
+                movement_request_tick_frequency(4);
+                button_beep();
+            }
+            break;
+        case EVENT_BACKGROUND_TASK:
+            movement_play_alarm();
+                // 2022-07-23: Thx @joeycastillo for the dedicated “alarm” signal
+            break;
+        case EVENT_TIMEOUT:
+            movement_move_to_face(0);
+            break;
+        case EVENT_LOW_ENERGY_UPDATE:
+            break;
+        default:
+            movement_default_loop_handler(event);
+            break;
+    }
+
+    return true;
+}
+
+movement_watch_face_advisory_t alarm_face_advise(void *context) {
+    alarm_face_state_t *state = (alarm_face_state_t *)context;
+    movement_watch_face_advisory_t retval = { 0 };
+
+    if ( state->alarm_is_on ) {
+        retval.has_active_alarm = true;
+        watch_date_time_t now = movement_get_local_date_time();
+        retval.wants_background_task = (state->hour==now.unit.hour && state->minute==now.unit.minute);
+        // We’re at the mercy of the advise handler
+        // In Safari, the emulator triggers at the ›end‹ of the minute
+        // Converting to Unix timestamps and taking a difference between now and wake
+        // is not an easy win — because the timestamp for wake has to rely on now
+        // for its date. So first we’d have to see if the TOD of wake is after that
+        // of now. If it is, take tomorrow’s date, calculating month and year rollover
+        // if need be.
+    }
+
+    return retval;
+}
diff --git a/watch-faces/complication/alarm_face.h b/watch-faces/complication/alarm_face.h
new file mode 100644 (file)
index 0000000..0118943
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Josh Berson
+ * Copyright (c) 2025 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.
+ */
+
+#pragma once
+
+/*
+ * Daily ALARM face (formerly WAKE Face)
+ *
+ * Basic daily alarm clock face. Seems useful if nothing else in the interest
+ * of feature parity with the F-91W’s OEM module, 593.
+ *
+ * Also experiments with caret-free UI: One button cycles hours, the other
+ * minutes, so there’s no toggling between display and adjust modes and no
+ * cycling the caret through the UI.
+ *   º LIGHT advances hour by 1
+ *   º LIGHT long press advances hour by 6
+ *   º ALARM advances minute by 10
+ *   º ALARM long press cycles through signal modes (just one at the moment)
+ */
+
+#include "movement.h"
+
+// enum for setting alarm time
+typedef enum {
+    ALARM_FACE_SETTING_MODE_NONE = 0,
+    ALARM_FACE_SETTING_MODE_SETTING_HOUR,
+    ALARM_FACE_SETTING_MODE_SETTING_MINUTE
+} alarm_face_setting_mode_t;
+
+typedef struct {
+    uint32_t hour : 5;
+    uint32_t minute : 6;
+    uint32_t alarm_is_on : 1;
+    alarm_face_setting_mode_t setting_mode : 2;
+} alarm_face_state_t;
+
+void alarm_face_setup(uint8_t watch_face_index, void **context_ptr);
+void alarm_face_activate(void *context);
+bool alarm_face_loop(movement_event_t event, void *context);
+void alarm_face_resign(void *context);
+movement_watch_face_advisory_t alarm_face_advise(void *context);
+
+#define alarm_face ((const watch_face_t){ \
+    alarm_face_setup, \
+    alarm_face_activate, \
+    alarm_face_loop, \
+    alarm_face_resign, \
+    alarm_face_advise \
+})