]> git.earman.xyz Git - sensor-watch.git/commitdiff
launcher app with clock and preferences menu
authorJoey Castillo <jose.castillo@gmail.com>
Sun, 3 Oct 2021 22:49:21 +0000 (18:49 -0400)
committerJoey Castillo <jose.castillo@gmail.com>
Sun, 3 Oct 2021 23:08:40 +0000 (19:08 -0400)
12 files changed:
launcher/launcher.c
launcher/launcher.h
launcher/launcher_config.h
launcher/make/Makefile
launcher/widgets/clock/simple_clock_widget.c [new file with mode: 0644]
launcher/widgets/clock/simple_clock_widget.h [new file with mode: 0644]
launcher/widgets/fake_widget_1.c
launcher/widgets/fake_widget_1.h
launcher/widgets/fake_widget_2.c
launcher/widgets/fake_widget_2.h
launcher/widgets/settings/preferences_widget.c [new file with mode: 0644]
launcher/widgets/settings/preferences_widget.h [new file with mode: 0644]

index ff10cf6eb76d21145bf6aa31ece9562be4f23c93..8dc3819929b557e62e9c3baa938dcdc8f1785b77 100644 (file)
@@ -13,7 +13,10 @@ void cb_alarm_pressed();
 void cb_tick();
 
 void launcher_request_tick_frequency(uint8_t freq) {
+    // FIXME: there is an issue where after changing tick frequencies on a widget switch, something glitchy happens on the next one.
     watch_rtc_disable_all_periodic_callbacks();
+    launcher_state.subsecond = 0;
+    launcher_state.tick_frequency = freq;
     watch_rtc_register_periodic_callback(cb_tick, freq);
 }
 
@@ -21,26 +24,24 @@ void launcher_illuminate_led() {
     launcher_state.light_ticks = 3;
 }
 
-void launcher_move_to_next_widget() {
+void launcher_move_to_widget(uint8_t widget_index) {
     launcher_state.widget_changed = true;
     widgets[launcher_state.current_widget].resign(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]);
-    launcher_state.current_widget = (launcher_state.current_widget + 1) % LAUNCHER_NUM_WIDGETS;
+    launcher_state.current_widget = widget_index;
+    watch_clear_display();
     widgets[launcher_state.current_widget].activate(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]);
-    watch_display_string(widgets[launcher_state.current_widget].widget_name, 0);
+    widgets[launcher_state.current_widget].loop(EVENT_ACTIVATE, &launcher_state.launcher_settings, launcher_state.subsecond, widget_contexts[launcher_state.current_widget]);
 }
 
-void launcher_move_to_first_widget() {
-    launcher_state.widget_changed = true;
-    widgets[launcher_state.current_widget].resign(&launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]);
-    launcher_state.current_widget = 0;
-    widgets[0].activate(&launcher_state.launcher_settings, widget_contexts[0]);
-    watch_display_string(widgets[launcher_state.current_widget].widget_name, 0);
+void launcher_move_to_next_widget() {
+    launcher_move_to_widget((launcher_state.current_widget + 1) % LAUNCHER_NUM_WIDGETS);
 }
 
 void app_init() {
     memset(&launcher_state, 0, sizeof(launcher_state));
     launcher_state.launcher_settings.bit.led_green_color = 0xF;
-    launcher_state.launcher_settings.bit.led_red_color = 0x0;
+    watch_date_time date_time = watch_rtc_get_date_time();
+    watch_rtc_set_date_time(date_time);
 }
 
 void app_wake_from_deep_sleep() {
@@ -60,10 +61,10 @@ void app_setup() {
     launcher_request_tick_frequency(1);
 
     for(uint8_t i = 0; i < LAUNCHER_NUM_WIDGETS; i++) {
-        widgets[i].setup(&launcher_state.launcher_settings, widget_contexts[i]);
+        widgets[i].setup(&launcher_state.launcher_settings, &widget_contexts[i]);
     }
 
-    launcher_move_to_first_widget();
+    launcher_move_to_widget(0);
 }
 
 void app_prepare_for_sleep() {
@@ -77,8 +78,8 @@ LauncherEvent event;
 bool app_loop() {
     // play a beep if the widget has changed in response to a user's press of the MODE button
     if (launcher_state.widget_changed) {
-        // low note for nonzero case, high note for return to clock
-        watch_buzzer_play_note(launcher_state.current_widget ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 100);
+        // low note for nonzero case, high note for return to widget 0
+        watch_buzzer_play_note(launcher_state.current_widget ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 50);
         launcher_state.widget_changed = false;
     }
 
@@ -102,7 +103,7 @@ bool app_loop() {
     }
 
     if (event) {
-        widgets[launcher_state.current_widget].loop(event, &launcher_state.launcher_settings, widget_contexts[launcher_state.current_widget]);
+        widgets[launcher_state.current_widget].loop(event, &launcher_state.launcher_settings, launcher_state.subsecond, widget_contexts[launcher_state.current_widget]);
         event = 0;
     }
 
@@ -139,5 +140,13 @@ void cb_alarm_pressed() {
 
 void cb_tick() {
     event = EVENT_TICK;
-    if (launcher_state.light_ticks) launcher_state.light_ticks--;
+    watch_date_time date_time = watch_rtc_get_date_time();
+    if (date_time.unit.second != launcher_state.last_second) {
+        if (launcher_state.light_ticks) launcher_state.light_ticks--;
+
+        launcher_state.last_second = date_time.unit.second;
+        launcher_state.subsecond = 0;
+    } else {
+        launcher_state.subsecond++;
+    }
 }
index 7a794545fcf2715698ae5ee1765e5c4f0ff2b876..e49575e791208e0c940df6f4da024aae48834ee1 100644 (file)
@@ -6,12 +6,13 @@
 // TODO: none of this is implemented
 typedef union {
     struct {
+        uint32_t reserved : 3;
         uint32_t clock_mode_24h : 1;        // determines whether clock should use 12 or 24 hour mode.
+        uint32_t button_should_sound : 1;   // if true, pressing a button emits a sound.
         uint32_t signal_should_sound : 1;   // if true, a double beep is played at the top of each hour.
         uint32_t alarm_should_sound : 1;    // if true, the alarm interrupt can match a time and play a song.
         uint32_t alarm_minute : 6;          // the minute of the alarm we want to match
         uint32_t alarm_hour : 5;            // the second of the alarm we want to match
-        uint32_t note_index : 4;            // the index of the tone to play on button press, or 0xF for no tone.
         uint32_t screensaver_interval : 3;  // 0 to disable screensaver, or a screensaver activation interval.
         uint32_t led_duration : 3;          // how many seconds to shine the LED for, or 0 to disable it.
         uint32_t led_red_color : 4;         // for general purpose illumination, the red LED value (0-15)
@@ -37,11 +38,10 @@ typedef enum LauncherEvent {
 
 typedef void (*launcher_widget_setup)(LauncherSettings *settings, void ** context_ptr);
 typedef void (*launcher_widget_activate)(LauncherSettings *settings, void *context);
-typedef void (*launcher_widget_loop)(LauncherEvent event, LauncherSettings *settings, void *context);
+typedef void (*launcher_widget_loop)(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context);
 typedef void (*launcher_widget_resign)(LauncherSettings *settings, void *context);
 
 typedef struct WatchWidget {
-    char widget_name[11];
     launcher_widget_setup setup;
     launcher_widget_activate activate;
     launcher_widget_loop loop;
@@ -64,10 +64,16 @@ typedef struct LauncherState {
     uint8_t light_down_timestamp;
     uint8_t mode_down_timestamp;
     uint8_t alarm_down_timestamp;
+
+    // stuff for subsecond tracking
+    uint8_t tick_frequency;
+    uint8_t last_second;
+    uint8_t subsecond;
 } LauncherState;
 
+void launcher_move_to_widget(uint8_t widget_index);
 void launcher_move_to_next_widget();
-void launcher_move_to_first_widget();
 void launcher_illuminate_led();
+void launcher_request_tick_frequency(uint8_t freq);
 
 #endif // LAUNCHER_H_
index db9d1be1ad4078b12a0596049a579bfbde6ce379..9bc43c47de3d214a6f5c01707b81d6cefa348391 100644 (file)
@@ -1,12 +1,16 @@
 #ifndef LAUNCHER_CONFIG_H_
 #define LAUNCHER_CONFIG_H_
 
+#include "simple_clock_widget.h"
+#include "preferences_widget.h"
 #include "fake_widget_1.h"
 #include "fake_widget_2.h"
 
-#define LAUNCHER_NUM_WIDGETS 2
+#define LAUNCHER_NUM_WIDGETS 4
 
 WatchWidget widgets[LAUNCHER_NUM_WIDGETS] = {
+    simple_clock_widget,
+    preferences_widget,
     fake_widget_1,
     fake_widget_2,
 };
index f02c1853fc46542854d5210d1ffd5c5fbf744f54..4fba03510f25506a1ca7a21d8c0e3f0e1dedca50 100755 (executable)
@@ -11,6 +11,8 @@ include $(TOP)/make.mk
 INCLUDES += \
   -I../ \
   -I../widgets/ \
+  -I../widgets/clock/ \
+  -I../widgets/settings/ \
 
 # If you add any other source files you wish to compile, add them after ../app.c
 # Note that you will need to add a backslash at the end of any line you wish to continue, i.e.
@@ -20,6 +22,8 @@ INCLUDES += \
 #   ../utils/temperature.c
 SRCS += \
   ../launcher.c \
+  ../widgets/clock/simple_clock_widget.c \
+  ../widgets/settings/preferences_widget.c \
   ../widgets/fake_widget_1.c \
   ../widgets/fake_widget_2.c \
 
diff --git a/launcher/widgets/clock/simple_clock_widget.c b/launcher/widgets/clock/simple_clock_widget.c
new file mode 100644 (file)
index 0000000..51c6c9c
--- /dev/null
@@ -0,0 +1,86 @@
+#include <stdlib.h>
+#include "simple_clock_widget.h"
+#include "watch.h"
+
+void simple_clock_widget_setup(LauncherSettings *settings, void ** context_ptr) {
+    (void) settings;
+    // the only context we need is the timestamp of the previous tick.
+    *context_ptr = malloc(sizeof(uint32_t));
+}
+
+void simple_clock_widget_activate(LauncherSettings *settings, void *context) {
+    if (settings->bit.clock_mode_24h) {
+        watch_set_indicator(WATCH_INDICATOR_24H);
+    }
+    watch_set_colon();
+    // this ensures that none of the timestamp fields will match, so we can re-render them all.
+    *((uint32_t *)context) = 0xFFFFFFFF;
+}
+
+void simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context) {
+    printf("simple_clock_widget_loop\n");
+    (void) subsecond;
+    const char weekdays[7][3] = {"SA", "SU", "MO", "TU", "WE", "TH", "FR"};
+    char buf[11];
+    uint8_t pos;
+
+    watch_date_time date_time;
+    uint32_t previous_date_time;
+    switch (event) {
+        case EVENT_TICK:
+        case EVENT_ACTIVATE:
+            date_time = watch_rtc_get_date_time();
+            previous_date_time = *((uint32_t *)context);
+            *((uint32_t *)context) = date_time.reg;
+
+            if (date_time.reg >> 6 == previous_date_time >> 6) {
+                // everything before seconds is the same, don't waste cycles setting those segments.
+                pos = 8;
+                sprintf(buf, "%02d", date_time.unit.second);
+            } else if (date_time.reg >> 12 == previous_date_time >> 12) {
+                // everything before minutes is the same.
+                pos = 6;
+                sprintf(buf, "%02d%02d", date_time.unit.minute, date_time.unit.second);
+            } else {
+                // other stuff changed; let's do it all.
+                if (!settings->bit.clock_mode_24h) {
+                    // if we are in 12 hour mode, do some cleanup.
+                    if (date_time.unit.hour < 12) {
+                        watch_clear_indicator(WATCH_INDICATOR_PM);
+                    } else {
+                        watch_set_indicator(WATCH_INDICATOR_PM);
+                    }
+                    date_time.unit.hour %= 12;
+                    if (date_time.unit.hour == 0) date_time.unit.hour = 12;
+                }
+                pos = 0;
+                sprintf(buf, "%s%2d%2d%02d%02d", weekdays[simple_clock_widget_get_weekday(date_time.unit.year, date_time.unit.month, date_time.unit.day)], date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second);
+            }
+            watch_display_string(buf, pos);
+            break;
+        case EVENT_MODE_BUTTON_UP:
+            launcher_move_to_next_widget();
+            return;
+        case EVENT_LIGHT_BUTTON_UP:
+            launcher_illuminate_led();
+            break;
+        case EVENT_ALARM_BUTTON_UP:
+            break;
+        default:
+            break;
+    }
+}
+
+void simple_clock_widget_resign(LauncherSettings *settings, void *context) {
+    (void) settings;
+    (void) context;
+}
+
+uint8_t simple_clock_widget_get_weekday(uint16_t year, uint16_t month, uint16_t day) {
+    year += 20;
+    if (month <= 2) {
+        month += 12;
+        year--;
+    }
+    return (day + 13 * (month + 1) / 5 + year + year / 4 + 525) % 7;
+}
diff --git a/launcher/widgets/clock/simple_clock_widget.h b/launcher/widgets/clock/simple_clock_widget.h
new file mode 100644 (file)
index 0000000..459721b
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef SIMPLE_CLOCK_WIDGET_H_
+#define SIMPLE_CLOCK_WIDGET_H_
+
+#include "launcher.h"
+
+void simple_clock_widget_setup(LauncherSettings *settings, void ** context_ptr);
+void simple_clock_widget_activate(LauncherSettings *settings, void *context);
+void simple_clock_widget_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context);
+void simple_clock_widget_resign(LauncherSettings *settings, void *context);
+
+uint8_t simple_clock_widget_get_weekday(uint16_t day, uint16_t month, uint16_t year);
+
+#define simple_clock_widget { \
+    simple_clock_widget_setup, \
+    simple_clock_widget_activate, \
+    simple_clock_widget_loop, \
+    simple_clock_widget_resign, \
+}
+
+#endif // FAKE_WIDGET_H_
\ No newline at end of file
index aa4af2c2e83713e3ce1d87009a314a2ca78cb82f..15ffcbd2f7e66ec5a70e1f8b3ee722b40e0a6404 100644 (file)
@@ -1,8 +1,9 @@
 #include "fake_widget_1.h"
+#include "watch.h"
 
 void fake_widget_1_setup(LauncherSettings *settings, void ** context_ptr) {
     (void) settings;
-    // *context_ptr = NULL;
+    *context_ptr = NULL;
 }
 
 void fake_widget_1_activate(LauncherSettings *settings, void *context) {
@@ -10,14 +11,17 @@ void fake_widget_1_activate(LauncherSettings *settings, void *context) {
     (void) context;
 }
 
-void fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, void *context) {
+void fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context) {
+    printf("fake_widget_1_loop\n");
     (void) settings;
+    (void) subsecond;
     (void) context;
+    watch_display_string("W1 d get01", 0);
 
     switch (event) {
         case EVENT_MODE_BUTTON_UP:
             launcher_move_to_next_widget();
-            break;
+            return;
         case EVENT_LIGHT_BUTTON_UP:
             launcher_illuminate_led();
             break;
index 00db80cb72683a4f78babfcf87664b276487c66f..18180156e1f87683ada5d53133e92365b82855f4 100644 (file)
@@ -5,11 +5,10 @@
 
 void fake_widget_1_setup(LauncherSettings *settings, void ** context_ptr);
 void fake_widget_1_activate(LauncherSettings *settings, void *context);
-void fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, void *context);
+void fake_widget_1_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context);
 void fake_widget_1_resign(LauncherSettings *settings, void *context);
 
 #define fake_widget_1 { \
-    "W1 d get01", \
     fake_widget_1_setup, \
     fake_widget_1_activate, \
     fake_widget_1_loop, \
index 4ce00ce2a77c72297a9bb33eece05017626eaec4..f3ffc14b44ff89185c476c499b3ad75c211fa710 100644 (file)
@@ -1,4 +1,5 @@
 #include "fake_widget_2.h"
+#include "watch.h"
 
 void fake_widget_2_setup(LauncherSettings *settings, void ** context_ptr) {
     (void) settings;
@@ -10,14 +11,17 @@ void fake_widget_2_activate(LauncherSettings *settings, void *context) {
     (void) context;
 }
 
-void fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, void *context) {
+void fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context) {
+    printf("fake_widget_2_loop\n");
     (void) settings;
+    (void) subsecond;
     (void) context;
+    watch_display_string("W1 d get02", 0);
 
     switch (event) {
         case EVENT_MODE_BUTTON_UP:
             launcher_move_to_next_widget();
-            break;
+            return;
         case EVENT_LIGHT_BUTTON_UP:
             launcher_illuminate_led();
             break;
index 31bf30bc62e190fb0488b24a98a98e7d6dc43edf..1f6bd503b22e4a537450de68279bae52ff6da7d9 100644 (file)
@@ -5,11 +5,10 @@
 
 void fake_widget_2_setup(LauncherSettings *settings, void ** context_ptr);
 void fake_widget_2_activate(LauncherSettings *settings, void *context);
-void fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, void *context);
+void fake_widget_2_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context);
 void fake_widget_2_resign(LauncherSettings *settings, void *context);
 
 #define fake_widget_2 { \
-    "W1 d get02", \
     fake_widget_2_setup, \
     fake_widget_2_activate, \
     fake_widget_2_loop, \
diff --git a/launcher/widgets/settings/preferences_widget.c b/launcher/widgets/settings/preferences_widget.c
new file mode 100644 (file)
index 0000000..5877c23
--- /dev/null
@@ -0,0 +1,121 @@
+#include <stdlib.h>
+#include "preferences_widget.h"
+#include "watch.h"
+
+#define PREFERENCES_WIDGET_NUM_PREFEFENCES (5)
+const char preferences_widget_titles[PREFERENCES_WIDGET_NUM_PREFEFENCES][11] = {"CL", "Bt  Beep", "SC", "Lt   grn", "Lt   red"};
+
+void preferences_widget_setup(LauncherSettings *settings, void ** context_ptr) {
+    (void) settings;
+    *context_ptr = malloc(sizeof(uint8_t));
+}
+
+void preferences_widget_activate(LauncherSettings *settings, void *context) {
+    (void) settings;
+    *((uint8_t *)context) = 0;
+    launcher_request_tick_frequency(4); // we need to manually blink some pixels
+}
+
+void preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context) {
+    (void) settings;
+    (void) context;
+    printf("preferences_widget_loop\n");
+    uint8_t current_page = *((uint8_t *)context);
+    switch (event) {
+        case EVENT_MODE_BUTTON_UP:
+            launcher_move_to_next_widget();
+            return;
+        case EVENT_LIGHT_BUTTON_UP:
+            current_page = (current_page + 1) % PREFERENCES_WIDGET_NUM_PREFEFENCES;
+            *((uint8_t *)context) = current_page;
+            break;
+        case EVENT_ALARM_BUTTON_UP:
+            switch (current_page) {
+                case 0:
+                    settings->bit.clock_mode_24h = !(settings->bit.clock_mode_24h);
+                    break;
+                case 1:
+                    settings->bit.button_should_sound = !(settings->bit.button_should_sound);
+                    break;
+                case 2:
+                    settings->bit.screensaver_interval = settings->bit.screensaver_interval + 1;
+                    break;
+                case 3:
+                    settings->bit.led_green_color = settings->bit.led_green_color + 1;
+                    break;
+                case 4:
+                    settings->bit.led_red_color = settings->bit.led_red_color + 1;
+                    break;
+            }
+            break;
+        default:
+            break;
+    }
+
+    watch_clear_display();
+    watch_display_string((char *)preferences_widget_titles[current_page], 0);
+    if (current_page > 2) {
+        // this is a hack, launcher should be able to illumate with a custom color.
+        launcher_illuminate_led();
+        watch_set_led_color(settings->bit.led_red_color ? (0xF | settings->bit.led_red_color << 4) : 0,
+                            settings->bit.led_green_color ? (0xF | settings->bit.led_green_color << 4) : 0);
+    } else {
+        watch_set_led_off();
+    }
+
+    if (subsecond % 2) return;
+    char buf[3];
+    switch (current_page) {
+        case 0:
+            if (settings->bit.clock_mode_24h) watch_display_string("24h", 4);
+            else watch_display_string("12h", 4);
+            break;
+        case 1:
+            if (settings->bit.button_should_sound) watch_display_string("y", 9);
+            else watch_display_string("n", 9);
+            break;
+        case 2:
+            switch (settings->bit.screensaver_interval) {
+                case 0:
+                    watch_display_string("never", 4);
+                    break;
+                case 1:
+                    watch_display_string("1 hour", 4);
+                    break;
+                case 2:
+                    watch_display_string("2 hour", 4);
+                    break;
+                case 3:
+                    watch_display_string("6 hour", 4);
+                    break;
+                case 4:
+                    watch_display_string("12 hr", 4);
+                    break;
+                case 5:
+                    watch_display_string(" 1 day", 4);
+                    break;
+                case 6:
+                    watch_display_string(" 2 day", 4);
+                    break;
+                case 7:
+                    watch_display_string(" 7 day", 4);
+                    break;
+            }
+            break;
+        case 3:
+            sprintf(buf, "%2d", settings->bit.led_green_color);
+            watch_display_string(buf, 8);
+            break;
+        case 4:
+            sprintf(buf, "%2d", settings->bit.led_red_color);
+            watch_display_string(buf, 8);
+            break;
+    }
+}
+
+void preferences_widget_resign(LauncherSettings *settings, void *context) {
+    (void) settings;
+    (void) context;
+    watch_set_led_off();
+    launcher_request_tick_frequency(1);
+}
diff --git a/launcher/widgets/settings/preferences_widget.h b/launcher/widgets/settings/preferences_widget.h
new file mode 100644 (file)
index 0000000..fcbcd0d
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef PREFERENCES_WIDGET_H_
+#define PREFERENCES_WIDGET_H_
+
+#include "launcher.h"
+
+void preferences_widget_setup(LauncherSettings *settings, void ** context_ptr);
+void preferences_widget_activate(LauncherSettings *settings, void *context);
+void preferences_widget_loop(LauncherEvent event, LauncherSettings *settings, uint8_t subsecond, void *context);
+void preferences_widget_resign(LauncherSettings *settings, void *context);
+
+#define preferences_widget { \
+    preferences_widget_setup, \
+    preferences_widget_activate, \
+    preferences_widget_loop, \
+    preferences_widget_resign, \
+}
+
+#endif // PREFERENCES_WIDGET_H_
\ No newline at end of file