From 064175e316cebb331fad6d7ffc4da2ab10ea3957 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Sun, 11 May 2025 16:07:12 -0400 Subject: [PATCH] new settings watch face --- movement_config.h | 2 +- movement_faces.h | 1 + watch-faces.mk | 1 + watch-faces/settings/preferences_face.h | 5 +- watch-faces/settings/settings_face.c | 296 ++++++++++++++++++++++++ watch-faces/settings/settings_face.h | 97 ++++++++ 6 files changed, 400 insertions(+), 2 deletions(-) create mode 100644 watch-faces/settings/settings_face.c create mode 100644 watch-faces/settings/settings_face.h diff --git a/movement_config.h b/movement_config.h index 2645af5e..6a63fc6f 100644 --- a/movement_config.h +++ b/movement_config.h @@ -38,7 +38,7 @@ const watch_face_t watch_faces[] = { voltage_face, days_since_face, accel_interrupt_count_face, - preferences_face, + settings_face, set_time_face, }; diff --git a/movement_faces.h b/movement_faces.h index d7aa6bba..fb5d9b34 100644 --- a/movement_faces.h +++ b/movement_faces.h @@ -44,6 +44,7 @@ #include "voltage_face.h" #include "set_time_face.h" #include "preferences_face.h" +#include "settings_face.h" #include "light_sensor_face.h" #include "irda_demo_face.h" #include "file_demo_face.h" diff --git a/watch-faces.mk b/watch-faces.mk index d6dd8f44..567618fe 100644 --- a/watch-faces.mk +++ b/watch-faces.mk @@ -19,6 +19,7 @@ SRCS += \ ./watch-faces/sensor/voltage_face.c \ ./watch-faces/settings/set_time_face.c \ ./watch-faces/settings/preferences_face.c \ + ./watch-faces/settings/settings_face.c \ ./watch-faces/demo/light_sensor_face.c \ ./watch-faces/demo/irda_demo_face.c \ ./watch-faces/demo/file_demo_face.c \ diff --git a/watch-faces/settings/preferences_face.h b/watch-faces/settings/preferences_face.h index 7b085d86..77f6409c 100644 --- a/watch-faces/settings/preferences_face.h +++ b/watch-faces/settings/preferences_face.h @@ -25,7 +25,10 @@ #pragma once /* - * PREFERENCES face + * Legacy PREFERENCES face + * + * This face is deprecated and will be removed in a future release. + * Please use the Settings watch face instead. * * The Preferences watch face allows you to configure various options on your * Sensor Watch. Like all other screens, you advance the field you’re setting diff --git a/watch-faces/settings/settings_face.c b/watch-faces/settings/settings_face.c new file mode 100644 index 00000000..113ccb8a --- /dev/null +++ b/watch-faces/settings/settings_face.c @@ -0,0 +1,296 @@ +/* + * MIT License + * + * 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 +#include "settings_face.h" +#include "watch.h" + +static void clock_setting_display(uint8_t subsecond) { + watch_display_text_with_fallback(WATCH_POSITION_TOP, "CLOCK", "CL"); + if (subsecond % 2) { + if (movement_clock_mode_24h()) watch_display_text(WATCH_POSITION_BOTTOM, "24h"); + else watch_display_text(WATCH_POSITION_BOTTOM, "12h"); + } +} + +static void clock_setting_advance(void) { + movement_set_clock_mode_24h(((movement_clock_mode_24h() + 1) % MOVEMENT_NUM_CLOCK_MODES)); +} + +static void beep_setting_display(uint8_t subsecond) { + watch_display_text_with_fallback(WATCH_POSITION_TOP_LEFT, "BTN", "BT"); + watch_display_text_with_fallback(WATCH_POSITION_BOTTOM, "beep ", " beep "); + if (subsecond % 2) { + if (movement_button_should_sound()) { + watch_display_text(WATCH_POSITION_TOP_RIGHT, " Y"); + } else { + watch_display_text(WATCH_POSITION_TOP_RIGHT, " N"); + } + } +} + +static void beep_setting_advance(void) { + movement_set_button_should_sound(!movement_button_should_sound()); +} + +static void timeout_setting_display(uint8_t subsecond) { + watch_display_text_with_fallback(WATCH_POSITION_TOP, "TMOUt", "TO"); + if (subsecond % 2) { + switch (movement_get_fast_tick_timeout()) { + case 0: + watch_display_text(WATCH_POSITION_BOTTOM, "60 SeC"); + break; + case 1: + watch_display_text(WATCH_POSITION_BOTTOM, "2 n&in"); + break; + case 2: + watch_display_text(WATCH_POSITION_BOTTOM, "5 n&in"); + break; + case 3: + watch_display_text(WATCH_POSITION_BOTTOM, "30n&in"); + break; + } + } +} + +static void timeout_setting_advance(void) { + movement_set_fast_tick_timeout((movement_get_fast_tick_timeout() + 1)); +} + +static void low_energy_setting_display(uint8_t subsecond) { + watch_display_text_with_fallback(WATCH_POSITION_TOP, "LoEne", "LE"); + if (subsecond % 2) { + switch (movement_get_low_energy_timeout()) { + case 0: + watch_display_text(WATCH_POSITION_BOTTOM, " Never"); + break; + case 1: + watch_display_text(WATCH_POSITION_BOTTOM, "10n&in"); + break; + case 2: + watch_display_text(WATCH_POSITION_BOTTOM, "1 hour"); + break; + case 3: + watch_display_text(WATCH_POSITION_BOTTOM, "2 hour"); + break; + case 4: + watch_display_text(WATCH_POSITION_BOTTOM, "6 hour"); + break; + case 5: + watch_display_text(WATCH_POSITION_BOTTOM, "12 hr"); + break; + case 6: + watch_display_text(WATCH_POSITION_BOTTOM, " 1 day"); + break; + case 7: + watch_display_text(WATCH_POSITION_BOTTOM, " 7 day"); + break; + } + } +} + +static void low_energy_setting_advance(void) { + movement_set_low_energy_timeout((movement_get_low_energy_timeout() + 1)); +} + +static void led_duration_setting_display(uint8_t subsecond) { + char buf[8]; + + watch_display_text_with_fallback(WATCH_POSITION_TOP_LEFT, "LED", "LT"); + if (subsecond % 2) { + if (movement_get_backlight_dwell() == 0) { + watch_display_text(WATCH_POSITION_BOTTOM, "instnt"); + } else if (movement_get_backlight_dwell() == 0b111) { + watch_display_text(WATCH_POSITION_BOTTOM, "no LEd"); + } else { + sprintf(buf, " %1d SeC", (movement_get_backlight_dwell() * 2 - 1) % 10); + watch_display_text(WATCH_POSITION_BOTTOM, buf); + } + } +} + +static void led_duration_setting_advance(void) { + movement_set_backlight_dwell(movement_get_backlight_dwell() + 1); + if (movement_get_backlight_dwell() > 3) { + // set all bits to disable the LED + movement_set_backlight_dwell(0b111); + } +} + +static void red_led_setting_display(uint8_t subsecond) { + char buf[8]; + movement_color_t color = movement_backlight_color(); + + watch_display_text_with_fallback(WATCH_POSITION_TOP_LEFT, "LED", "LT"); + watch_display_text(WATCH_POSITION_BOTTOM, " red "); + if (subsecond % 2) { + sprintf(buf, "%2d", color.red); + watch_display_text(WATCH_POSITION_TOP_RIGHT, buf); + } +} + +static void red_led_setting_advance(void) { + movement_color_t color = movement_backlight_color(); + color.red++; + movement_set_backlight_color(color); +} + +static void green_led_setting_display(uint8_t subsecond) { + char buf[8]; + movement_color_t color = movement_backlight_color(); + + watch_display_text_with_fallback(WATCH_POSITION_TOP_LEFT, "LED", "LT"); + watch_display_text(WATCH_POSITION_BOTTOM, " green"); + if (subsecond % 2) { + sprintf(buf, "%2d", color.green); + watch_display_text(WATCH_POSITION_TOP_RIGHT, buf); + } +} + +static void green_led_setting_advance(void) { + movement_color_t color = movement_backlight_color(); + color.green++; + movement_set_backlight_color(color); +} + +static void blue_led_setting_display(uint8_t subsecond) { + char buf[8]; + movement_color_t color = movement_backlight_color(); + + watch_display_text_with_fallback(WATCH_POSITION_TOP_LEFT, "LED", "LT"); + watch_display_text_with_fallback(WATCH_POSITION_BOTTOM, "blue ", " blue "); + if (subsecond % 2) { + sprintf(buf, "%2d", color.blue); + watch_display_text(WATCH_POSITION_TOP_RIGHT, buf); + } +} + +static void blue_led_setting_advance(void) { + movement_color_t color = movement_backlight_color(); + color.blue++; + movement_set_backlight_color(color); +} + +void settings_face_setup(uint8_t watch_face_index, void ** context_ptr) { + (void) watch_face_index; + if (*context_ptr == NULL) { + *context_ptr = malloc(sizeof(settings_state_t)); + settings_state_t *state = (settings_state_t *)*context_ptr; + int8_t current_setting = 0; + + state->num_settings = 5; // baseline, without LED settings +#ifdef WATCH_RED_TCC_CHANNEL + state->num_settings++; +#endif +#ifdef WATCH_GREEN_TCC_CHANNEL + state->num_settings++; +#endif +#ifdef WATCH_BLUE_TCC_CHANNEL + state->num_settings++; +#endif + + state->settings_screens = malloc(state->num_settings * sizeof(settings_screen_t)); + state->settings_screens[current_setting].display = clock_setting_display; + state->settings_screens[current_setting].advance = clock_setting_advance; + current_setting++; + state->settings_screens[current_setting].display = beep_setting_display; + state->settings_screens[current_setting].advance = beep_setting_advance; + current_setting++; + state->settings_screens[current_setting].display = timeout_setting_display; + state->settings_screens[current_setting].advance = timeout_setting_advance; + current_setting++; + state->settings_screens[current_setting].display = low_energy_setting_display; + state->settings_screens[current_setting].advance = low_energy_setting_advance; + current_setting++; + state->settings_screens[current_setting].display = led_duration_setting_display; + state->settings_screens[current_setting].advance = led_duration_setting_advance; + current_setting++; +#ifdef WATCH_RED_TCC_CHANNEL + state->settings_screens[current_setting].display = red_led_setting_display; + state->settings_screens[current_setting].advance = red_led_setting_advance; + current_setting++; +#endif +#ifdef WATCH_GREEN_TCC_CHANNEL + state->settings_screens[current_setting].display = green_led_setting_display; + state->settings_screens[current_setting].advance = green_led_setting_advance; + current_setting++; +#endif +#ifdef WATCH_BLUE_TCC_CHANNEL + state->settings_screens[current_setting].display = blue_led_setting_display; + state->settings_screens[current_setting].advance = blue_led_setting_advance; + current_setting++; +#endif + } +} + +void settings_face_activate(void *context) { + settings_state_t *state = (settings_state_t *)context; + state->current_page = 0; + movement_request_tick_frequency(4); // we need to manually blink some pixels +} + +bool settings_face_loop(movement_event_t event, void *context) { + settings_state_t *state = (settings_state_t *)context; + + switch (event.event_type) { + case EVENT_LIGHT_BUTTON_DOWN: + state->current_page = (state->current_page + 1) % state->num_settings; + // fall through + case EVENT_TICK: + case EVENT_ACTIVATE: + watch_clear_display(); + state->settings_screens[state->current_page].display(event.subsecond); + break; + case EVENT_MODE_BUTTON_UP: + movement_force_led_off(); + movement_move_to_next_face(); + return false; + case EVENT_ALARM_BUTTON_UP: + state->settings_screens[state->current_page].advance(); + break; + case EVENT_TIMEOUT: + movement_move_to_face(0); + break; + default: + return movement_default_loop_handler(event); + } + + if (state->current_page > 4) { + movement_color_t color = movement_backlight_color(); + // this bitwise math turns #000 into #000000, #111 into #111111, etc. + movement_force_led_on(color.red | color.red << 4, + color.green | color.green << 4, + color.blue | color.blue << 4); + return false; + } else { + movement_force_led_off(); + return true; + } +} + +void settings_face_resign(void *context) { + (void) context; + movement_force_led_off(); + movement_store_settings(); +} diff --git a/watch-faces/settings/settings_face.h b/watch-faces/settings/settings_face.h new file mode 100644 index 00000000..7f47ff7c --- /dev/null +++ b/watch-faces/settings/settings_face.h @@ -0,0 +1,97 @@ +/* + * MIT License + * + * Copyright (c) 2022-2024 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 + +/* + * SETTINGS face (replaces old Preferences watch face) + * + * The Settings watch face allows you to configure various options on your + * Sensor Watch. Like all other screens, you advance the field you’re setting + * with the Light button, and advance its value with the Alarm button. The + * Settings watch face labels each setting with a two-letter code up top + * when using the classic LCD, or something more readable on the custom LCD. + * The following list describes each setting and their options: + * + * CL / Clock - Clock mode. + * This setting allows you to select a 12-or 24-hour clock display. All + * watch faces that support displaying the time will respect this setting; + * for example, both Simple Clock, World Clock and Sunrise/Sunset will + * display the time in 24 hour format if the 24 hour clock is selected here. + * + * BT / BTN - Button beep. + * This setting allows you to choose whether the Mode button should emit + * a beep when pressed, and if so, how loud it should be. Options are + * "Y" for yes and "N" for no. + * + * TO / Tmout - Timeout. + * Sets the time until screens that time out (like Settings and Time Set) + * snap back to the first screen. 60 seconds is a good default for the + * stock firmware, but if you choose a custom firmware with faces that + * you’d like to keep on screen for longer, you can set that here. + * + * LE / LoEne - Low Energy mode. + * Sets the time until the watch enters its low energy sleep mode. + * Options range from 1 hour to 7 days, or Never. The more often Sensor + * Watch goes to sleep, the longer its battery will last — but you will + * lose the seconds indicator while it is asleep. This setting allows + * you to make a tradeoff between the device’s responsiveness and its + * longevity. + * + * LT / LED - Light Duration and Color + * The first LED screen lets you choose how long the LED should stay lit + * when the LIGHT button is pressed. Options are 1 second, 3 seconds + * and 5 seconds, or “No LED” to disable the LED entirely. + * The remaining screens set the intensity of the red, green or blue LEDs + * depending on the target Sensor Board hardware to allow a custom color + * blend. Values range from 0 (off) to 15 (full intensity). + * On the LED color screens, the LED remains on so that you can see the + * effect of mixing the LED colors. + */ + +#include "movement.h" + +typedef struct { + void (*display)(uint8_t subsecond); + void (*advance)(); +} settings_screen_t; + +typedef struct { + int8_t current_page; + int8_t num_settings; + settings_screen_t *settings_screens; +} settings_state_t; + +void settings_face_setup(uint8_t watch_face_index, void ** context_ptr); +void settings_face_activate(void *context); +bool settings_face_loop(movement_event_t event, void *context); +void settings_face_resign(void *context); + +#define settings_face ((const watch_face_t){ \ + settings_face_setup, \ + settings_face_activate, \ + settings_face_loop, \ + settings_face_resign, \ + NULL, \ +})