1
1
/*
2
2
* MIT License
3
3
*
4
+ * Copyright (c) 2024 Joseph Bryant
4
5
* Copyright (c) 2023 Konrad Rieck
5
6
* Copyright (c) 2022 Wesley Ellis
6
7
*
@@ -68,17 +69,30 @@ static inline void button_beep(movement_settings_t *settings) {
68
69
watch_buzzer_play_note (BUZZER_NOTE_C7 , 50 );
69
70
}
70
71
71
- static void start (countdown_state_t * state , movement_settings_t * settings ) {
72
- watch_date_time now = watch_rtc_get_date_time ();
72
+ static void schedule_countdown (countdown_state_t * state , movement_settings_t * settings ) {
73
73
74
- state -> mode = cd_running ;
75
- state -> now_ts = watch_utility_date_time_to_unix_time (now , get_tz_offset (settings ));
76
- state -> target_ts = watch_utility_offset_timestamp (state -> now_ts , state -> hours , state -> minutes , state -> seconds );
74
+ // Calculate the new state->now_ts but don't update it until we've updated the target -
75
+ // avoid possible race where the old target is compared to the new time and immediately triggers
76
+ uint32_t new_now = watch_utility_date_time_to_unix_time (watch_rtc_get_date_time (), get_tz_offset (settings ));
77
+ state -> target_ts = watch_utility_offset_timestamp (new_now , state -> hours , state -> minutes , state -> seconds );
78
+ state -> now_ts = new_now ;
77
79
watch_date_time target_dt = watch_utility_date_time_from_unix_time (state -> target_ts , get_tz_offset (settings ));
78
- movement_schedule_background_task (target_dt );
79
- watch_set_indicator (WATCH_INDICATOR_BELL );
80
+ movement_schedule_background_task_for_face (state -> watch_face_index , target_dt );
81
+ }
82
+
83
+ static void auto_repeat (countdown_state_t * state , movement_settings_t * settings ) {
84
+ movement_play_alarm ();
85
+ load_countdown (state );
86
+ schedule_countdown (state , settings );
80
87
}
81
88
89
+ static void start (countdown_state_t * state , movement_settings_t * settings ) {
90
+ state -> mode = cd_running ;
91
+ schedule_countdown (state , settings );
92
+ }
93
+
94
+
95
+
82
96
static void draw (countdown_state_t * state , uint8_t subsecond ) {
83
97
char buf [16 ];
84
98
@@ -100,7 +114,7 @@ static void draw(countdown_state_t *state, uint8_t subsecond) {
100
114
break ;
101
115
case cd_reset :
102
116
case cd_paused :
103
- watch_clear_indicator (WATCH_INDICATOR_BELL );
117
+ watch_clear_indicator (WATCH_INDICATOR_SIGNAL );
104
118
sprintf (buf , "CD %2d%02d%02d" , state -> hours , state -> minutes , state -> seconds );
105
119
break ;
106
120
case cd_setting :
@@ -127,13 +141,13 @@ static void draw(countdown_state_t *state, uint8_t subsecond) {
127
141
128
142
static void pause (countdown_state_t * state ) {
129
143
state -> mode = cd_paused ;
130
- movement_cancel_background_task ( );
131
- watch_clear_indicator (WATCH_INDICATOR_BELL );
144
+ movement_cancel_background_task_for_face ( state -> watch_face_index );
145
+ watch_clear_indicator (WATCH_INDICATOR_SIGNAL );
132
146
}
133
147
134
148
static void reset (countdown_state_t * state ) {
135
149
state -> mode = cd_reset ;
136
- movement_cancel_background_task ( );
150
+ movement_cancel_background_task_for_face ( state -> watch_face_index );
137
151
load_countdown (state );
138
152
}
139
153
@@ -142,6 +156,15 @@ static void ring(countdown_state_t *state) {
142
156
reset (state );
143
157
}
144
158
159
+ static void times_up (movement_settings_t * settings , countdown_state_t * state ) {
160
+ if (state -> repeat ) {
161
+ auto_repeat (state , settings );
162
+ }
163
+ else {
164
+ ring (state );
165
+ }
166
+ }
167
+
145
168
static void settings_increment (countdown_state_t * state ) {
146
169
switch (state -> selection ) {
147
170
case 0 :
@@ -170,6 +193,7 @@ void countdown_face_setup(movement_settings_t *settings, uint8_t watch_face_inde
170
193
memset (* context_ptr , 0 , sizeof (countdown_state_t ));
171
194
state -> minutes = DEFAULT_MINUTES ;
172
195
state -> mode = cd_reset ;
196
+ state -> watch_face_index = watch_face_index ;
173
197
store_countdown (state );
174
198
}
175
199
}
@@ -180,9 +204,11 @@ void countdown_face_activate(movement_settings_t *settings, void *context) {
180
204
if (state -> mode == cd_running ) {
181
205
watch_date_time now = watch_rtc_get_date_time ();
182
206
state -> now_ts = watch_utility_date_time_to_unix_time (now , get_tz_offset (settings ));
183
- watch_set_indicator (WATCH_INDICATOR_BELL );
207
+ watch_set_indicator (WATCH_INDICATOR_SIGNAL );
184
208
}
185
209
watch_set_colon ();
210
+ if (state -> repeat )
211
+ watch_set_indicator (WATCH_INDICATOR_BELL );
186
212
187
213
movement_request_tick_frequency (1 );
188
214
quick_ticks_running = false;
@@ -252,6 +278,7 @@ bool countdown_face_loop(movement_event_t event, movement_settings_t *settings,
252
278
// Only start the timer if we have a valid time.
253
279
start (state , settings );
254
280
button_beep (settings );
281
+ watch_set_indicator (WATCH_INDICATOR_SIGNAL );
255
282
}
256
283
break ;
257
284
case cd_setting :
@@ -261,9 +288,19 @@ bool countdown_face_loop(movement_event_t event, movement_settings_t *settings,
261
288
draw (state , event .subsecond );
262
289
break ;
263
290
case EVENT_ALARM_LONG_PRESS :
264
- if (state -> mode == cd_setting ) {
265
- quick_ticks_running = true;
266
- movement_request_tick_frequency (8 );
291
+ switch (state -> mode ) {
292
+ case cd_setting :
293
+ quick_ticks_running = true;
294
+ movement_request_tick_frequency (8 );
295
+ break ;
296
+ default :
297
+ // Toggle auto-repeat
298
+ button_beep (settings );
299
+ state -> repeat = !state -> repeat ;
300
+ if (state -> repeat )
301
+ watch_set_indicator (WATCH_INDICATOR_BELL );
302
+ else
303
+ watch_clear_indicator (WATCH_INDICATOR_BELL );
267
304
}
268
305
break ;
269
306
case EVENT_LIGHT_LONG_PRESS :
@@ -285,7 +322,7 @@ bool countdown_face_loop(movement_event_t event, movement_settings_t *settings,
285
322
abort_quick_ticks (state );
286
323
break ;
287
324
case EVENT_BACKGROUND_TASK :
288
- ring ( state );
325
+ times_up ( settings , state );
289
326
break ;
290
327
case EVENT_TIMEOUT :
291
328
abort_quick_ticks (state );
0 commit comments