summaryrefslogtreecommitdiffstats
path: root/movement
diff options
context:
space:
mode:
Diffstat (limited to 'movement')
-rw-r--r--movement/alt_fw/backer.h (renamed from movement/alt_fw/standard.h)0
-rw-r--r--movement/alt_fw/deep_space_now.h4
-rw-r--r--movement/alt_fw/the_stargazer.h7
-rw-r--r--movement/make/Makefile2
-rwxr-xr-xmovement/make/make_alternate_fw.sh10
-rw-r--r--movement/movement.c15
-rw-r--r--movement/movement_config.h2
-rw-r--r--movement/movement_faces.h2
-rw-r--r--movement/watch_faces/clock/simple_clock_face.c12
-rw-r--r--movement/watch_faces/clock/weeknumber_clock_face.c167
-rw-r--r--movement/watch_faces/clock/weeknumber_clock_face.h53
-rw-r--r--movement/watch_faces/complication/alarm_face.c46
-rw-r--r--movement/watch_faces/complication/countdown_face.c1
-rw-r--r--movement/watch_faces/complication/counter_face.c22
-rw-r--r--movement/watch_faces/complication/counter_face.h1
-rw-r--r--movement/watch_faces/complication/sailing_face.c275
-rw-r--r--movement/watch_faces/complication/sailing_face.h68
-rw-r--r--movement/watch_faces/complication/stopwatch_face.c48
-rw-r--r--movement/watch_faces/complication/sunrise_sunset_face.c17
-rw-r--r--movement/watch_faces/complication/tomato_face.c1
-rw-r--r--movement/watch_faces/settings/set_time_face.c4
21 files changed, 698 insertions, 59 deletions
diff --git a/movement/alt_fw/standard.h b/movement/alt_fw/backer.h
index 3abcf457..3abcf457 100644
--- a/movement/alt_fw/standard.h
+++ b/movement/alt_fw/backer.h
diff --git a/movement/alt_fw/deep_space_now.h b/movement/alt_fw/deep_space_now.h
index f07fe2cb..6cb34237 100644
--- a/movement/alt_fw/deep_space_now.h
+++ b/movement/alt_fw/deep_space_now.h
@@ -32,15 +32,15 @@
#define MOVEMENT_CUSTOM_BOOT_COMMANDS() { \
/* Standard Time */\
- /*\
watch_store_backup_data(0x1e0c0c, 4);\
watch_store_backup_data(0x010115, 5);\
watch_store_backup_data(0x130105, 6);\
- */\
/* Daylight Saving Time */\
+ /*\
watch_store_backup_data(0x1f0c0c, 4);\
watch_store_backup_data(0x020115, 5);\
watch_store_backup_data(0x110105, 6);\
+ */\
watch_store_backup_data(0x0597b9, 2);\
}
diff --git a/movement/alt_fw/the_stargazer.h b/movement/alt_fw/the_stargazer.h
index 50a89aad..a13dc3ac 100644
--- a/movement/alt_fw/the_stargazer.h
+++ b/movement/alt_fw/the_stargazer.h
@@ -27,11 +27,8 @@
#include "movement_faces.h"
-#define MOVEMENT_CUSTOM_BOOT_COMMANDS() { \
- movement_state.settings.bit.led_green_color = 0x0;\
- movement_state.settings.bit.led_red_color = 0xF;\
- watch_store_backup_data(movement_state.settings.reg, 0);\
-}
+#define MOVEMENT_DEFAULT_RED_COLOR 0xF
+#define MOVEMENT_DEFAULT_GREEN_COLOR 0x0
const watch_face_t watch_faces[] = {
simple_clock_face,
diff --git a/movement/make/Makefile b/movement/make/Makefile
index bf9351eb..60084594 100644
--- a/movement/make/Makefile
+++ b/movement/make/Makefile
@@ -43,6 +43,7 @@ SRCS += \
../watch_faces/clock/simple_clock_face.c \
../watch_faces/clock/world_clock_face.c \
../watch_faces/clock/beats_face.c \
+ ../watch_faces/clock/weeknumber_clock_face.c \
../watch_faces/settings/preferences_face.c \
../watch_faces/settings/set_time_face.c \
../watch_faces/sensor/thermistor_readout_face.c \
@@ -60,6 +61,7 @@ SRCS += \
../watch_faces/complication/totp_face_lfs.c \
../watch_faces/complication/sunrise_sunset_face.c \
../watch_faces/complication/countdown_face.c \
+ ../watch_faces/complication/sailing_face.c \
../watch_faces/complication/counter_face.c \
../watch_faces/complication/blinky_face.c \
../watch_faces/complication/moon_phase_face.c \
diff --git a/movement/make/make_alternate_fw.sh b/movement/make/make_alternate_fw.sh
index 575c9e52..d1ce7673 100755
--- a/movement/make/make_alternate_fw.sh
+++ b/movement/make/make_alternate_fw.sh
@@ -3,7 +3,7 @@
fw_dir="firmware/download"
sim_dir="firmware/simulate"
colors=("green" "blue")
-variants=("standard" "alt_time" "deep_space_now" "focus" "the_athlete" "the_backpacker" "the_stargazer")
+variants=("standard" "backer" "alt_time" "deep_space_now" "focus" "the_athlete" "the_backpacker" "the_stargazer")
if [ -d "$fw_dir" ] ; then
rm -r "$fw_dir"
@@ -25,12 +25,12 @@ do
make LED=$COLOR FIRMWARE=$VARIANT
mv "build/watch.uf2" "$fw_dir/$variant-$color.uf2"
done
- make clean
+ rm -rf ./build-sim
emmake make FIRMWARE=$VARIANT
mkdir "$sim_dir/$variant/"
- mv "build/watch.wasm" "$sim_dir/$variant/"
- mv "build/watch.js" "$sim_dir/$variant/"
- mv "build/watch.html" "$sim_dir/$variant/index.html"
+ mv "build-sim/watch.wasm" "$sim_dir/$variant/"
+ mv "build-sim/watch.js" "$sim_dir/$variant/"
+ mv "build-sim/watch.html" "$sim_dir/$variant/index.html"
done
echo "Done."
diff --git a/movement/movement.c b/movement/movement.c
index 0ded11e3..3997b4a4 100644
--- a/movement/movement.c
+++ b/movement/movement.c
@@ -37,7 +37,9 @@
#ifndef MOVEMENT_FIRMWARE
#include "movement_config.h"
#elif MOVEMENT_FIRMWARE == MOVEMENT_FIRMWARE_STANDARD
-#include "alt_fw/standard.h"
+#include "movement_config.h"
+#elif MOVEMENT_FIRMWARE == MOVEMENT_FIRMWARE_BACKER
+#include "alt_fw/backer.h"
#elif MOVEMENT_FIRMWARE == MOVEMENT_FIRMWARE_ALT_TIME
#include "alt_fw/alt_time.h"
#elif MOVEMENT_FIRMWARE == MOVEMENT_FIRMWARE_FOCUS
@@ -57,6 +59,14 @@
#define MOVEMENT_SECONDARY_FACE_INDEX 0
#endif
+// Set default LED colors if not set
+#ifndef MOVEMENT_DEFAULT_RED_COLOR
+#define MOVEMENT_DEFAULT_RED_COLOR 0x0
+#endif
+#ifndef MOVEMENT_DEFAULT_GREEN_COLOR
+#define MOVEMENT_DEFAULT_GREEN_COLOR 0xF
+#endif
+
#if __EMSCRIPTEN__
#include <emscripten.h>
#endif
@@ -284,7 +294,8 @@ uint8_t movement_claim_backup_register(void) {
void app_init(void) {
memset(&movement_state, 0, sizeof(movement_state));
- movement_state.settings.bit.led_green_color = 0xF;
+ movement_state.settings.bit.led_red_color = MOVEMENT_DEFAULT_RED_COLOR;
+ movement_state.settings.bit.led_green_color = MOVEMENT_DEFAULT_GREEN_COLOR;
movement_state.settings.bit.button_should_sound = true;
movement_state.settings.bit.le_interval = 1;
movement_state.settings.bit.led_duration = 1;
diff --git a/movement/movement_config.h b/movement/movement_config.h
index 19a501ea..9e446d4d 100644
--- a/movement/movement_config.h
+++ b/movement/movement_config.h
@@ -32,7 +32,7 @@ const watch_face_t watch_faces[] = {
world_clock_face,
sunrise_sunset_face,
moon_phase_face,
- thermistor_readout_face,
+ stopwatch_face,
preferences_face,
set_time_face,
};
diff --git a/movement/movement_faces.h b/movement/movement_faces.h
index 282be0e6..9333401b 100644
--- a/movement/movement_faces.h
+++ b/movement/movement_faces.h
@@ -45,6 +45,7 @@
#include "hello_there_face.h"
#include "sunrise_sunset_face.h"
#include "countdown_face.h"
+#include "sailing_face.h"
#include "counter_face.h"
#include "blinky_face.h"
#include "moon_phase_face.h"
@@ -58,6 +59,7 @@
#include "frequency_correction_face.h"
#include "alarm_face.h"
#include "ratemeter_face.h"
+#include "weeknumber_clock_face.h"
// New includes go above this line.
#endif // MOVEMENT_FACES_H_
diff --git a/movement/watch_faces/clock/simple_clock_face.c b/movement/watch_faces/clock/simple_clock_face.c
index 7721b12a..fd1d167c 100644
--- a/movement/watch_faces/clock/simple_clock_face.c
+++ b/movement/watch_faces/clock/simple_clock_face.c
@@ -140,17 +140,7 @@ bool simple_clock_face_loop(movement_event_t event, movement_settings_t *setting
case EVENT_BACKGROUND_TASK:
// uncomment this line to snap back to the clock face when the hour signal sounds:
// movement_move_to_face(state->watch_face_index);
- if (watch_is_buzzer_or_led_enabled()) {
- // if we are in the foreground, we can just beep.
- movement_play_signal();
- } else {
- // if we were in the background, we need to enable the buzzer peripheral first,
- watch_enable_buzzer();
- // beep quickly (this call blocks for 275 ms),
- movement_play_signal();
- // and then turn the buzzer peripheral off again.
- watch_disable_buzzer();
- }
+ movement_play_signal();
break;
default:
break;
diff --git a/movement/watch_faces/clock/weeknumber_clock_face.c b/movement/watch_faces/clock/weeknumber_clock_face.c
new file mode 100644
index 00000000..deaaedbd
--- /dev/null
+++ b/movement/watch_faces/clock/weeknumber_clock_face.c
@@ -0,0 +1,167 @@
+/*
+ * MIT License
+ *
+ * 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 "weeknumber_clock_face.h"
+#include "watch.h"
+#include "watch_utility.h"
+
+static void _update_alarm_indicator(bool settings_alarm_enabled, weeknumber_clock_state_t *state) {
+ state->alarm_enabled = settings_alarm_enabled;
+ if (state->alarm_enabled) watch_set_indicator(WATCH_INDICATOR_SIGNAL);
+ else watch_clear_indicator(WATCH_INDICATOR_SIGNAL);
+}
+
+void weeknumber_clock_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(weeknumber_clock_state_t));
+ weeknumber_clock_state_t *state = (weeknumber_clock_state_t *)*context_ptr;
+ state->signal_enabled = false;
+ state->watch_face_index = watch_face_index;
+ }
+}
+
+void weeknumber_clock_face_activate(movement_settings_t *settings, void *context) {
+ weeknumber_clock_state_t *state = (weeknumber_clock_state_t *)context;
+
+ if (watch_tick_animation_is_running()) watch_stop_tick_animation();
+
+ if (settings->bit.clock_mode_24h) watch_set_indicator(WATCH_INDICATOR_24H);
+
+ // handle chime indicator
+ if (state->signal_enabled) watch_set_indicator(WATCH_INDICATOR_BELL);
+ else watch_clear_indicator(WATCH_INDICATOR_BELL);
+
+ // show alarm indicator if there is an active alarm
+ _update_alarm_indicator(settings->bit.alarm_enabled, state);
+
+ watch_set_colon();
+
+ // this ensures that none of the timestamp fields will match, so we can re-render them all.
+ state->previous_date_time = 0xFFFFFFFF;
+}
+
+bool weeknumber_clock_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
+ weeknumber_clock_state_t *state = (weeknumber_clock_state_t *)context;
+ char buf[11];
+ uint8_t pos;
+
+ watch_date_time date_time;
+ uint32_t previous_date_time;
+ switch (event.event_type) {
+ case EVENT_ACTIVATE:
+ case EVENT_TICK:
+ case EVENT_LOW_ENERGY_UPDATE:
+ date_time = watch_rtc_get_date_time();
+ previous_date_time = state->previous_date_time;
+ state->previous_date_time = date_time.reg;
+
+ // check the battery voltage once a day...
+ if (date_time.unit.day != state->last_battery_check) {
+ state->last_battery_check = date_time.unit.day;
+ watch_enable_adc();
+ uint16_t voltage = watch_get_vcc_voltage();
+ watch_disable_adc();
+ // 2.2 volts will happen when the battery has maybe 5-10% remaining?
+ // we can refine this later.
+ state->battery_low = (voltage < 2200);
+ }
+
+ // ...and set the LAP indicator if low.
+ if (state->battery_low) watch_set_indicator(WATCH_INDICATOR_LAP);
+
+ if ((date_time.reg >> 12) == (previous_date_time >> 12) && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
+ // everything before minutes is the same.
+ pos = 6;
+ sprintf(buf, "%02d%02d", date_time.unit.minute, watch_utility_get_weeknumber(date_time.unit.year, date_time.unit.month, date_time.unit.day));
+ } 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;
+ if (event.event_type == EVENT_LOW_ENERGY_UPDATE) {
+ if (!watch_tick_animation_is_running()) watch_start_tick_animation(500);
+ sprintf(buf, "%s%2d%2d%02d ", watch_utility_get_weekday(date_time), date_time.unit.day, date_time.unit.hour, date_time.unit.minute);
+ } else {
+ sprintf(buf, "%s%2d%2d%02d%02d", watch_utility_get_weekday(date_time), date_time.unit.day, date_time.unit.hour, date_time.unit.minute, watch_utility_get_weeknumber(date_time.unit.year, date_time.unit.month, date_time.unit.day));
+ }
+ }
+ watch_display_string(buf, pos);
+ // handle alarm indicator
+ if (state->alarm_enabled != settings->bit.alarm_enabled) _update_alarm_indicator(settings->bit.alarm_enabled, state);
+ break;
+ case EVENT_MODE_BUTTON_UP:
+ movement_move_to_next_face();
+ return false;
+ case EVENT_LIGHT_BUTTON_DOWN:
+ movement_illuminate_led();
+ break;
+ case EVENT_ALARM_LONG_PRESS:
+ state->signal_enabled = !state->signal_enabled;
+ if (state->signal_enabled) watch_set_indicator(WATCH_INDICATOR_BELL);
+ else watch_clear_indicator(WATCH_INDICATOR_BELL);
+ break;
+ case EVENT_BACKGROUND_TASK:
+ // uncomment this line to snap back to the clock face when the hour signal sounds:
+ // movement_move_to_face(state->watch_face_index);
+ if (watch_is_buzzer_or_led_enabled()) {
+ // if we are in the foreground, we can just beep.
+ movement_play_signal();
+ } else {
+ // beep quickly (this call blocks for 275 ms),
+ movement_play_signal();
+ }
+ break;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+void weeknumber_clock_face_resign(movement_settings_t *settings, void *context) {
+ (void) settings;
+ (void) context;
+}
+
+bool weeknumber_clock_face_wants_background_task(movement_settings_t *settings, void *context) {
+ (void) settings;
+ weeknumber_clock_state_t *state = (weeknumber_clock_state_t *)context;
+ if (!state->signal_enabled) return false;
+
+ watch_date_time date_time = watch_rtc_get_date_time();
+
+ return date_time.unit.minute == 0;
+}
diff --git a/movement/watch_faces/clock/weeknumber_clock_face.h b/movement/watch_faces/clock/weeknumber_clock_face.h
new file mode 100644
index 00000000..f0298ea8
--- /dev/null
+++ b/movement/watch_faces/clock/weeknumber_clock_face.h
@@ -0,0 +1,53 @@
+/*
+ * MIT License
+ *
+ * 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 WEEKNUMBER_CLOCK_FACE_H_
+#define WEEKNUMBER_CLOCK_FACE_H_
+
+#include "movement.h"
+
+typedef struct {
+ uint32_t previous_date_time;
+ uint8_t last_battery_check;
+ uint8_t watch_face_index;
+ bool signal_enabled;
+ bool battery_low;
+ bool alarm_enabled;
+} weeknumber_clock_state_t;
+
+void weeknumber_clock_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
+void weeknumber_clock_face_activate(movement_settings_t *settings, void *context);
+bool weeknumber_clock_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
+void weeknumber_clock_face_resign(movement_settings_t *settings, void *context);
+bool weeknumber_clock_face_wants_background_task(movement_settings_t *settings, void *context);
+
+#define weeknumber_clock_face ((const watch_face_t){ \
+ weeknumber_clock_face_setup, \
+ weeknumber_clock_face_activate, \
+ weeknumber_clock_face_loop, \
+ weeknumber_clock_face_resign, \
+ weeknumber_clock_face_wants_background_task, \
+})
+
+#endif // SIMPLE_CLOCK_FACE_H_
diff --git a/movement/watch_faces/complication/alarm_face.c b/movement/watch_faces/complication/alarm_face.c
index b1ace2c2..181a5aba 100644
--- a/movement/watch_faces/complication/alarm_face.c
+++ b/movement/watch_faces/complication/alarm_face.c
@@ -72,7 +72,7 @@ static const uint8_t _blink_idx2[ALARM_SETTING_STATES] = {3, 1, 5, 7, 8, 9};
static const BuzzerNote _buzzer_notes[3] = {BUZZER_NOTE_B6, BUZZER_NOTE_C8, BUZZER_NOTE_A8};
static const uint8_t _buzzer_segdata[3][2] = {{0, 3}, {1, 3}, {2, 2}};
-int8_t _wait_ticks;
+static int8_t _wait_ticks;
static uint8_t _get_weekday_idx(watch_date_time date_time) {
date_time.unit.year += 20;
@@ -103,11 +103,11 @@ static void _alarm_face_draw(movement_settings_t *settings, alarm_state_t *state
if (!settings->bit.clock_mode_24h) {
if (h >= 12) {
watch_set_indicator(WATCH_INDICATOR_PM);
- h = h % 12;
- h += h ? 0 : 12;
+ h %= 12;
} else {
watch_clear_indicator(WATCH_INDICATOR_PM);
}
+ if (h == 0) h = 12;
}
sprintf(buf, "%c%c%2d%2d%02d ",
_dow_strings[i][0], _dow_strings[i][1],
@@ -159,7 +159,8 @@ static void _alarm_resume_setting(movement_settings_t *settings, alarm_state_t *
static void _alarm_update_alarm_enabled(movement_settings_t *settings, alarm_state_t *state) {
// save indication for active alarms to movement settings
bool active_alarms = false;
- watch_date_time *now = NULL;
+ watch_date_time now;
+ bool now_init = false;
uint8_t weekday_idx;
uint16_t now_minutes_of_day;
uint16_t alarm_minutes_of_day;
@@ -170,10 +171,11 @@ static void _alarm_update_alarm_enabled(movement_settings_t *settings, alarm_sta
active_alarms = true;
break;
} else {
- if (now == NULL) {
- *now = watch_rtc_get_date_time();
- weekday_idx = _get_weekday_idx(*now);
- now_minutes_of_day = now->unit.hour * 60 + now->unit.minute;
+ if (!now_init) {
+ now = watch_rtc_get_date_time();
+ now_init = true;
+ weekday_idx = _get_weekday_idx(now);
+ now_minutes_of_day = now.unit.hour * 60 + now.unit.minute;
}
alarm_minutes_of_day = state->alarm[i].hour * 60 + state->alarm[i].minute;
// no more shortcuts: check days and times for all possible cases...
@@ -251,7 +253,6 @@ void alarm_face_resign(movement_settings_t *settings, void *context) {
state->is_setting = false;
_alarm_update_alarm_enabled(settings, state);
watch_set_led_off();
- watch_store_backup_data(settings->reg, 0);
state->alarm_quick_ticks = false;
_wait_ticks = -1;
movement_request_tick_frequency(1);
@@ -270,15 +271,7 @@ bool alarm_face_wants_background_task(movement_settings_t *settings, void *conte
if (state->alarm[i].minute == now.unit.minute) {
if (state->alarm[i].hour == now.unit.hour) {
state->alarm_playing_idx = i;
- if (state->alarm[i].day == ALARM_DAY_EACH_DAY) return true;
- if (state->alarm[i].day == ALARM_DAY_ONE_TIME) {
- // erase this alarm
- state->alarm[i].day = ALARM_DAY_EACH_DAY;
- state->alarm[i].minute = state->alarm[i].hour = 0;
- state->alarm[i].enabled = false;
- _alarm_update_alarm_enabled(settings, state);
- return true;
- }
+ if (state->alarm[i].day == ALARM_DAY_EACH_DAY || state->alarm[i].day == ALARM_DAY_ONE_TIME) return true;
uint8_t weekday_idx = _get_weekday_idx(now);
if (state->alarm[i].day == weekday_idx) return true;
if (state->alarm[i].day == ALARM_DAY_WORKDAY && weekday_idx < 5) return true;
@@ -307,7 +300,7 @@ bool alarm_face_loop(movement_event_t event, movement_settings_t *settings, void
state->alarm[state->alarm_idx].minute = (state->alarm[state->alarm_idx].minute + 1) % 60;
} else _abort_quick_ticks(state);
} else if (!state->is_setting) {
- if (_wait_ticks >= 0 && _wait_ticks <= INT8_MAX) _wait_ticks++;
+ if (_wait_ticks >= 0) _wait_ticks++;
if (_wait_ticks == 2) {
// extra long press of alarm button
_wait_ticks = -1;
@@ -428,16 +421,23 @@ bool alarm_face_loop(movement_event_t event, movement_settings_t *settings, void
if (watch_is_buzzer_or_led_enabled()) {
_alarm_play_short_beep(state->alarm[state->alarm_playing_idx].pitch);
} else {
- // enable, play beep and disable buzzer again
- watch_enable_buzzer();
+ // play beep
_alarm_play_short_beep(state->alarm[state->alarm_playing_idx].pitch);
- watch_disable_buzzer();
}
} else {
// regular alarm beeps
- movement_play_alarm_beeps((state->alarm[state->alarm_idx].beeps == (ALARM_MAX_BEEP_ROUNDS - 1) ? 20 : state->alarm[state->alarm_playing_idx].beeps),
+ movement_play_alarm_beeps((state->alarm[state->alarm_playing_idx].beeps == (ALARM_MAX_BEEP_ROUNDS - 1) ? 20 : state->alarm[state->alarm_playing_idx].beeps),
_buzzer_notes[state->alarm[state->alarm_playing_idx].pitch]);
}
+ // one time alarm? -> erase it
+ if (state->alarm[state->alarm_playing_idx].day == ALARM_DAY_ONE_TIME) {
+ state->alarm[state->alarm_playing_idx].day = ALARM_DAY_EACH_DAY;
+ state->alarm[state->alarm_playing_idx].minute = state->alarm[state->alarm_playing_idx].hour = 0;
+ state->alarm[state->alarm_playing_idx].beeps = 5;
+ state->alarm[state->alarm_playing_idx].pitch = 1;
+ state->alarm[state->alarm_playing_idx].enabled = false;
+ _alarm_update_alarm_enabled(settings, state);
+ }
break;
case EVENT_MODE_BUTTON_UP:
movement_move_to_next_face();
diff --git a/movement/watch_faces/complication/countdown_face.c b/movement/watch_faces/complication/countdown_face.c
index b0decb01..b2206b8f 100644
--- a/movement/watch_faces/complication/countdown_face.c
+++ b/movement/watch_faces/complication/countdown_face.c
@@ -140,6 +140,7 @@ void countdown_face_activate(movement_settings_t *settings, void *context) {
if(state->mode == cd_running) {
watch_date_time now = watch_rtc_get_date_time();
state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
+ watch_set_indicator(WATCH_INDICATOR_BELL);
}
watch_set_colon();
}
diff --git a/movement/watch_faces/complication/counter_face.c b/movement/watch_faces/complication/counter_face.c
index ac0388ab..fb03ce67 100644
--- a/movement/watch_faces/complication/counter_face.c
+++ b/movement/watch_faces/complication/counter_face.c
@@ -59,6 +59,7 @@ bool counter_face_loop(movement_event_t event, movement_settings_t *settings, vo
state->counter_idx=0;//reset counter index
}
print_counter(state);
+ beep_counter(state);
break;
case EVENT_ALARM_LONG_PRESS:
state->counter_idx=0; // reset counter index
@@ -77,6 +78,27 @@ bool counter_face_loop(movement_event_t event, movement_settings_t *settings, vo
return true;
}
+// beep counter index times
+void beep_counter(counter_state_t *state) {
+
+ int low_count = state->counter_idx/5;
+ int high_count = state->counter_idx - low_count * 5;
+
+ for (int i=0; i<low_count; i++) {
+ watch_buzzer_play_note(BUZZER_NOTE_A6, 50);
+ watch_buzzer_play_note(BUZZER_NOTE_REST, 100);
+ }
+
+ //sleep between high and low
+ watch_buzzer_play_note(BUZZER_NOTE_REST, 200);
+
+ for (int i=0; i<high_count; i++) {
+ watch_buzzer_play_note(BUZZER_NOTE_B6, 50);
+ watch_buzzer_play_note(BUZZER_NOTE_REST, 100);
+ }
+}
+
+
// print counter index at the center of display.
void print_counter(counter_state_t *state) {
char buf[14];
diff --git a/movement/watch_faces/complication/counter_face.h b/movement/watch_faces/complication/counter_face.h
index 2d389a15..430f5a8e 100644
--- a/movement/watch_faces/complication/counter_face.h
+++ b/movement/watch_faces/complication/counter_face.h
@@ -39,6 +39,7 @@ bool counter_face_loop(movement_event_t event, movement_settings_t *settings, vo
void counter_face_resign(movement_settings_t *settings, void *context);
void print_counter(counter_state_t *state);
+void beep_counter(counter_state_t *state);
#define counter_face ((const watch_face_t){ \
counter_face_setup, \
diff --git a/movement/watch_faces/complication/sailing_face.c b/movement/watch_faces/complication/sailing_face.c
new file mode 100644
index 00000000..97868a54
--- /dev/null
+++ b/movement/watch_faces/complication/sailing_face.c
@@ -0,0 +1,275 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Wesley Ellis
+ * Copyright (c) 2022 Niclas Hoyer
+ *
+ * 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 "sailing_face.h"
+#include "watch.h"
+#include "watch_utility.h"
+
+#define sl_SELECTIONS 6
+#define DEFAULT_MINUTES { 5,4,1,0,0,0 }
+#define UNUSED(x) (void)(x)
+
+static inline int32_t get_tz_offset(movement_settings_t *settings) {
+ return movement_timezone_offsets[settings->bit.time_zone] * 60;
+}
+
+static void reset(sailing_state_t *state) {
+ state->index = 0;
+ state->mode = sl_waiting;
+ movement_cancel_background_task();
+ watch_clear_indicator(WATCH_INDICATOR_BELL);
+}
+
+static void start(sailing_state_t *state, movement_settings_t *settings) {
+ uint8_t minutes = state->minutes[state->index];
+ if (minutes == 0) {
+ reset(state);
+ return;
+ }
+ if (state->index < 5) {
+ minutes -= state->minutes[state->index+1];
+ }
+
+ state->mode = sl_running;
+ watch_date_time now = watch_rtc_get_date_time();
+ state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
+ state->target_ts = watch_utility_offset_timestamp(state->now_ts, 0, minutes, 0);
+ watch_date_time target_dt = watch_utility_date_time_from_unix_time(state->target_ts, get_tz_offset(settings));
+ movement_schedule_background_task_for_face(state->watch_face_index, target_dt);
+ watch_set_indicator(WATCH_INDICATOR_BELL);
+}
+
+static void draw(sailing_state_t *state, uint8_t subsecond, movement_settings_t *settings) {
+ UNUSED(settings);
+
+ char tmp[24];
+ char buf[16];
+
+ uint32_t delta;
+ div_t result;
+ uint8_t min, sec;
+ uint8_t add = 0;
+
+ switch (state->mode) {
+ case sl_running:
+ if (state->index < 5) {
+ add = state->minutes[state->index+1];
+ }
+ if (state->now_ts >= state->target_ts) {
+ delta = 0;
+ } else {
+ delta = state->target_ts - state->now_ts;
+ }
+ result = div(delta, 60);
+ min = result.quot + add;
+ sec = result.rem;
+
+ if (min > 0) {
+ sprintf(buf, "SL %2d%02d", min, sec);
+ } else {
+ sprintf(buf, "SL %2d ", sec);
+ }
+ break;
+ case sl_waiting:
+ sprintf(buf, "SL %2d%02d", state->minutes[0], 0);
+ break;
+ case sl_setting:
+ // this sprintf to a larger tmp is to guarantee that no buffer overflows
+ // occur here (and to squelch the corresponding compiler warning)
+ sprintf(tmp, "SL %1d%1d%1d%1d%1d%1d",
+ state->minutes[0],
+ state->minutes[1],
+ state->minutes[2],
+ state->minutes[3],
+ state->minutes[4],
+ state->minutes[5]
+ );
+ memcpy(buf, tmp, sizeof(buf));
+ if (subsecond % 2) {
+ buf[4 + state->selection] = ' ';
+ }
+ break;
+ }
+ watch_display_string(buf, 0);
+}
+
+static void ring(sailing_state_t *state, movement_settings_t *settings) {
+ movement_play_signal();
+ state->index += 1;
+ if (state->index > 5) {
+ reset(state);
+ return;
+ }
+ uint8_t next_min = state->minutes[state->index];
+ if (next_min == 0) {
+ reset(state);
+ return;
+ }
+ movement_cancel_background_task();
+ start(state, settings);
+}
+
+static void settings_increment(sailing_state_t *state) {
+ state->minutes[state->selection] += 1;
+ uint8_t max = 10;
+ if (state->selection > 0) {
+ max = state->minutes[state->selection-1];
+ }
+ if (state->minutes[state->selection] >= max) {
+ state->minutes[state->selection] = 0;
+ }
+ // ensure that minutes are decreasing
+ if (state->selection < 5) {
+ for (uint8_t i = 0; i < 5; i++) {
+ if (state->minutes[i+1] >= state->minutes[i]) {
+ if (state->minutes[i] > 0) {
+ state->minutes[i+1] = state->minutes[i] - 1;
+ } else {
+ state->minutes[i+1] = 0;
+ }
+ }
+ }
+ }
+ return;
+}
+
+void sailing_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(sailing_state_t));
+ sailing_state_t *state = (sailing_state_t *)*context_ptr;
+ memset(*context_ptr, 0, sizeof(sailing_state_t));
+ static const uint8_t default_minutes[6] = DEFAULT_MINUTES;
+ memcpy(&state->minutes, default_minutes, sizeof(default_minutes));
+ state->watch_face_index = watch_face_index;
+ }
+}
+
+void sailing_face_activate(movement_settings_t *settings, void *context) {
+ (void) settings;
+ sailing_state_t *state = (sailing_state_t *)context;
+ if(state->mode == sl_running) {
+ watch_date_time now = watch_rtc_get_date_time();
+ state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
+ }
+}
+
+
+bool sailing_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
+ (void) settings;
+ sailing_state_t *state = (sailing_state_t *)context;
+
+ switch (event.event_type) {
+ case EVENT_ACTIVATE:
+ draw(state, event.subsecond, settings);
+ break;
+ case EVENT_TICK:
+ if (state->mode == sl_running) {
+ state->now_ts++;
+ }
+ draw(state, event.subsecond, settings);
+ break;
+ case EVENT_MODE_BUTTON_UP:
+ movement_move_to_next_face();
+ break;
+ case EVENT_LIGHT_LONG_PRESS:
+ if (state->mode == sl_running) {
+ reset(state);
+ }
+ break;
+ case EVENT_LIGHT_BUTTON_UP:
+ switch(state->mode) {
+ case sl_running:
+ movement_illuminate_led();
+ break;
+ case sl_waiting:
+ state->mode = sl_setting;
+ movement_request_tick_frequency(4);
+ break;
+ case sl_setting:
+ state->selection++;
+ if(state->selection >= sl_SELECTIONS) {
+ state->selection = 0;
+ state->mode = sl_waiting;
+ movement_request_tick_frequency(1);
+ }
+ break;
+ }
+ draw(state, event.subsecond, settings);
+ break;
+ case EVENT_ALARM_BUTTON_UP:
+ switch(state->mode) {
+ case sl_running:
+ ring(state, settings);
+ break;
+ case sl_waiting:
+ movement_play_signal();
+ start(state, settings);
+ break;
+ case sl_setting:
+ settings_increment(state);
+ break;
+ }
+ draw(state, event.subsecond, settings);
+ break;
+ case EVENT_BACKGROUND_TASK:
+ ring(state, settings);
+ break;
+ case EVENT_ALARM_LONG_PRESS:
+ if (state->mode == sl_setting) {
+ static const uint8_t default_minutes[6] = DEFAULT_MINUTES;
+ memcpy(&state->minutes, default_minutes, sizeof(default_minutes));
+ state->index = 0;
+ draw(state, event.subsecond, settings);
+ break;
+ }
+ break;
+ case EVENT_TIMEOUT:
+ if (state->mode != sl_running) {
+ movement_move_to_face(0);
+ }
+ break;
+ case EVENT_LOW_ENERGY_UPDATE:
+ default:
+ break;
+ }
+
+ return true;
+}
+
+void sailing_face_resign(movement_settings_t *settings, void *context) {
+ (void) settings;
+ sailing_state_t *state = (sailing_state_t *)context;
+ if (state->mode == sl_setting) {
+ state->selection = 0;
+ state->mode = sl_waiting;
+ }
+}
diff --git a/movement/watch_faces/complication/sailing_face.h b/movement/watch_faces/complication/sailing_face.h
new file mode 100644
index 00000000..31799097
--- /dev/null
+++ b/movement/watch_faces/complication/sailing_face.h
@@ -0,0 +1,68 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2022 Wesley Ellis
+ * Copyright (c) 2022 Niclas Hoyer
+ *
+ * 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 SAILING_FACE_H_
+#define SAILING_FACE_H_
+
+#include "movement.h"
+
+/*
+A sailing sailing/timer face
+*/
+
+
+typedef enum {
+ sl_waiting,
+ sl_running,
+ sl_setting
+} sailing_mode_t;
+
+typedef struct {
+ uint8_t watch_face_index;
+ uint32_t target_ts;
+ uint32_t now_ts;
+ uint8_t index;
+ uint8_t minutes[6];
+ uint8_t selection;
+ sailing_mode_t mode;
+} sailing_state_t;
+
+
+void sailing_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
+void sailing_face_activate(movement_settings_t *settings, void *context);
+bool sailing_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
+void sailing_face_resign(movement_settings_t *settings, void *context);
+
+#define sailing_face ((const watch_face_t){ \
+ sailing_face_setup, \
+ sailing_face_activate, \
+ sailing_face_loop, \
+ sailing_face_resign, \
+ NULL, \
+})
+
+#endif // sailing_FACE_H_
diff --git a/movement/watch_faces/complication/stopwatch_face.c b/movement/watch_faces/complication/stopwatch_face.c
index e85bbd65..2a69e9d5 100644
--- a/movement/watch_faces/complication/stopwatch_face.c
+++ b/movement/watch_faces/complication/stopwatch_face.c
@@ -29,6 +29,12 @@
#include "watch.h"
#include "watch_utility.h"
+// distant future for background task: January 1, 2083
+// see stopwatch_face_activate for details
+static const watch_date_time distant_future = {
+ .unit = {0, 0, 0, 1, 1, 63}
+};
+
void stopwatch_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
(void) settings;
(void) watch_face_index;
@@ -49,6 +55,7 @@ static void _stopwatch_face_update_display(stopwatch_state_t *stopwatch_state, b
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;
+ movement_cancel_background_task();
watch_display_string("st39235959", 0);
return;
}
@@ -72,12 +79,21 @@ static void _stopwatch_face_update_display(stopwatch_state_t *stopwatch_state, b
void stopwatch_face_activate(movement_settings_t *settings, void *context) {
(void) settings;
- (void) context;
if (watch_tick_animation_is_running()) watch_stop_tick_animation();
+
+ stopwatch_state_t *stopwatch_state = (stopwatch_state_t *)context;
+ if (stopwatch_state->running) {
+ // because the low power update happens on the minute mark, and the wearer could start
+ // the stopwatch anytime, the low power update could fire up to 59 seconds later than
+ // we need it to, causing the stopwatch to display stale data.
+ // So let's schedule a background task that will never fire. This will keep the watch
+ // from entering low energy mode while the stopwatch is on screen. This background task
+ // will remain scheduled until the stopwatch stops OR this watch face resigns.
+ movement_schedule_background_task(distant_future);
+ }
}
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;
switch (event.event_type) {
@@ -103,6 +119,9 @@ bool stopwatch_face_loop(movement_event_t event, movement_settings_t *settings,
}
break;
case EVENT_ALARM_BUTTON_DOWN:
+ if (settings->bit.button_should_sound) {
+ watch_buzzer_play_note(BUZZER_NOTE_C8, 50);
+ }
stopwatch_state->running = !stopwatch_state->running;
if (stopwatch_state->running) {
// we're running now, so we need to set the start_time.
@@ -118,15 +137,28 @@ bool stopwatch_face_loop(movement_event_t event, movement_settings_t *settings,
// 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);
}
+ // schedule our keepalive task when running...
+ movement_schedule_background_task(distant_future);
+ } else {
+ // and cancel it when stopped.
+ movement_cancel_background_task();
}
break;
case EVENT_TIMEOUT:
// explicitly ignore the timeout event so we stay on screen
break;
case EVENT_LOW_ENERGY_UPDATE:
- if (!watch_tick_animation_is_running()) watch_start_tick_animation(500);
- _stopwatch_face_update_display(stopwatch_state, false);
- watch_set_indicator(WATCH_INDICATOR_BELL);
+ if (!watch_tick_animation_is_running()) watch_start_tick_animation(1000);
+ if (!stopwatch_state->running) {
+ // since the tick animation is running, displaying the stopped time could be misleading,
+ // as it could imply that the stopwatch is running. instead, show a blank display to
+ // indicate that we are in sleep mode.
+ watch_display_string("st ---- ", 0);
+ } else {
+ // this OTOH shouldn't happen anymore; if we're running, we shouldn't enter low energy mode
+ _stopwatch_face_update_display(stopwatch_state, false);
+ watch_set_indicator(WATCH_INDICATOR_BELL);
+ }
break;
default:
break;
@@ -138,4 +170,8 @@ bool stopwatch_face_loop(movement_event_t event, movement_settings_t *settings,
void stopwatch_face_resign(movement_settings_t *settings, void *context) {
(void) settings;
(void) context;
-} \ No newline at end of file
+
+ // regardless of whether we're running or stopped, cancel the task
+ // that was keeping us awake while on screen.
+ movement_cancel_background_task();
+}
diff --git a/movement/watch_faces/complication/sunrise_sunset_face.c b/movement/watch_faces/complication/sunrise_sunset_face.c
index 8dea812e..7807de83 100644
--- a/movement/watch_faces/complication/sunrise_sunset_face.c
+++ b/movement/watch_faces/complication/sunrise_sunset_face.c
@@ -96,6 +96,11 @@ static void _sunrise_sunset_face_update(movement_settings_t *settings, sunrise_s
if (seconds < 30) scratch_time.unit.minute = floor(minutes);
else scratch_time.unit.minute = ceil(minutes);
+ if (scratch_time.unit.minute == 60) {
+ scratch_time.unit.minute = 0;
+ scratch_time.unit.hour = (scratch_time.unit.hour + 1) % 24;
+ }
+
if (date_time.reg < scratch_time.reg) _sunrise_sunset_set_expiration(state, scratch_time);
if (date_time.reg < scratch_time.reg || show_next_match) {
@@ -118,6 +123,11 @@ static void _sunrise_sunset_face_update(movement_settings_t *settings, sunrise_s
if (seconds < 30) scratch_time.unit.minute = floor(minutes);
else scratch_time.unit.minute = ceil(minutes);
+ if (scratch_time.unit.minute == 60) {
+ scratch_time.unit.minute = 0;
+ scratch_time.unit.hour = (scratch_time.unit.hour + 1) % 24;
+ }
+
if (date_time.reg < scratch_time.reg) _sunrise_sunset_set_expiration(state, scratch_time);
if (date_time.reg < scratch_time.reg || show_next_match) {
@@ -371,8 +381,11 @@ bool sunrise_sunset_face_loop(movement_event_t event, movement_settings_t *setti
}
break;
case EVENT_TIMEOUT:
- if (state->page || state->rise_index) {
- // on timeout, exit settings mode and return to the next sunrise or sunset
+ if (watch_get_backup_data(1) == 0) {
+ // if no location set, return home
+ movement_move_to_face(0);
+ } else if (state->page || state->rise_index) {
+ // otherwise on timeout, exit settings mode and return to the next sunrise or sunset
state->page = 0;
state->rise_index = 0;
movement_request_tick_frequency(1);
diff --git a/movement/watch_faces/complication/tomato_face.c b/movement/watch_faces/complication/tomato_face.c
index 37798daf..ed5554f2 100644
--- a/movement/watch_faces/complication/tomato_face.c
+++ b/movement/watch_faces/complication/tomato_face.c
@@ -124,6 +124,7 @@ void tomato_face_activate(movement_settings_t *settings, void *context) {
if (state->mode == tomato_run) {
watch_date_time now = watch_rtc_get_date_time();
state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
+ watch_set_indicator(WATCH_INDICATOR_BELL);
}
watch_set_colon();
}
diff --git a/movement/watch_faces/settings/set_time_face.c b/movement/watch_faces/settings/set_time_face.c
index af5421f1..1605f119 100644
--- a/movement/watch_faces/settings/set_time_face.c
+++ b/movement/watch_faces/settings/set_time_face.c
@@ -66,8 +66,8 @@ bool set_time_face_loop(movement_event_t event, movement_settings_t *settings, v
date_time.unit.second = 0;
break;
case 3: // year
- // only allow 2021-2030. fix this sometime next decade
- date_time.unit.year = ((date_time.unit.year % 10) + 1);
+ // only allow 2021-2050. fix this if we make it that far.
+ date_time.unit.year = ((date_time.unit.year % 30) + 1);
break;
case 4: // month
date_time.unit.month = (date_time.unit.month % 12) + 1;