From 30c8da7f553146e22be456f0852351dff7269e1f Mon Sep 17 00:00:00 2001 From: Ekaitz Zarraga Date: Sun, 19 Nov 2023 15:28:45 +0100 Subject: Fit naming conventions --- movement/make/Makefile | 2 +- movement/movement_faces.h | 2 +- movement/watch_faces/complication/couchTo5k_face.c | 267 --------------------- movement/watch_faces/complication/couchTo5k_face.h | 87 ------- .../watch_faces/complication/couch_to_5k_face.c | 267 +++++++++++++++++++++ .../watch_faces/complication/couch_to_5k_face.h | 87 +++++++ 6 files changed, 356 insertions(+), 356 deletions(-) delete mode 100644 movement/watch_faces/complication/couchTo5k_face.c delete mode 100644 movement/watch_faces/complication/couchTo5k_face.h create mode 100644 movement/watch_faces/complication/couch_to_5k_face.c create mode 100644 movement/watch_faces/complication/couch_to_5k_face.h diff --git a/movement/make/Makefile b/movement/make/Makefile index 646e3cb8..d27b796a 100644 --- a/movement/make/Makefile +++ b/movement/make/Makefile @@ -118,7 +118,7 @@ SRCS += \ ../watch_faces/complication/flashlight_face.c \ ../watch_faces/clock/decimal_time_face.c \ ../watch_faces/clock/wyoscan_face.c \ - ../watch_faces/complication/couchTo5k_face.c \ + ../watch_faces/complication/couch_to_5k_face.c \ # New watch faces go above this line. # Leave this line at the bottom of the file; it has all the targets for making your project. diff --git a/movement/movement_faces.h b/movement/movement_faces.h index 4a98fcf2..a88b3222 100644 --- a/movement/movement_faces.h +++ b/movement/movement_faces.h @@ -95,7 +95,7 @@ #include "flashlight_face.h" #include "decimal_time_face.h" #include "wyoscan_face.h" -#include "couchTo5k_face.h" +#include "couch_to_5k_face.h" // New includes go above this line. #endif // MOVEMENT_FACES_H_ diff --git a/movement/watch_faces/complication/couchTo5k_face.c b/movement/watch_faces/complication/couchTo5k_face.c deleted file mode 100644 index 79c22a5b..00000000 --- a/movement/watch_faces/complication/couchTo5k_face.c +++ /dev/null @@ -1,267 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2023 Ekaitz Zarraga - * - * 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 -#include "couchTo5k_face.h" - -// They go: Warmup, Run, Walk, Run, Walk, Run, Walk ... , End (0) -// Time is defined in seconds -// Maybe do /10 to reduce memory usage? -// (i don't want to use floats) - -// uint16_t C25K_WEEK_TEST[] = {10, 10, 10, 0}; -uint16_t C25K_WEEK_1[] = {300, 60, 90, 60, 90, 60, 90, 60, 90, 60, 90, 60, - 90, 60, 90, 60, 90, 0}; -uint16_t C25K_WEEK_2[] = {300, 90, 120, 90, 120, 90, 120, 90, 120, 90, 120, - 90, 120, 0}; -uint16_t C25K_WEEK_3[] = {300, 90, 90, 180, 180, 90, 90, 180, 180, 0}; -uint16_t C25K_WEEK_4[] = {300, 180, 90, 300, 150, 180, 90, 300, 0}; -uint16_t C25K_WEEK_5_1[] = {300, 300, 180, 300, 180, 300, 0 }; -uint16_t C25K_WEEK_5_2[] = {300, 480, 300, 480 , 0}; -uint16_t C25K_WEEK_5_3[] = {300, 1200, 0}; -uint16_t C25K_WEEK_6_1[] = {300, 300, 180, 480, 180, 300, 0 }; -uint16_t C25K_WEEK_6_2[] = {300, 600, 180, 600 , 0}; -uint16_t C25K_WEEK_6_3[] = {300, 1500, 0}; -uint16_t C25K_WEEK_7[] = {300, 1500, 0}; -uint16_t C25K_WEEK_8[] = {300, 1680, 0}; -uint16_t C25K_WEEK_9[] = {300, 1800, 0}; - - -#define C25K_SESSIONS_LENGTH 3*9 -uint16_t *C25K_SESSIONS[C25K_SESSIONS_LENGTH]; - -static inline bool _finished(couchTo5k_state_t *state){ - return state->exercise_type == C25K_FINISHED; -} -static inline bool _cleared(couchTo5k_state_t *state){ - return state->timer == C25K_SESSIONS[state->session][0] - && state->exercise == 0; -} -static inline void _next_session(couchTo5k_state_t *state){ - if (++state->session >= C25K_SESSIONS_LENGTH){ - state->session = 0; - } -} - -static inline void _assign_exercise_type(couchTo5k_state_t *state){ - if (state->exercise == 0){ - state->exercise_type = C25K_WARMUP; - } else if (state->exercise % 2 == 1){ - state->exercise_type = C25K_RUN; - } else { - state->exercise_type = C25K_WALK; - } -} - -static void _next_exercise(couchTo5k_state_t *state){ - state->exercise++; - state->timer = C25K_SESSIONS[state->session][state->exercise]; - // If the new timer starts in zero, it's finished - if (state->timer == 0){ - movement_play_alarm_beeps(7, BUZZER_NOTE_C8); - state->exercise_type = C25K_FINISHED; - return; - } - movement_play_alarm_beeps(4, BUZZER_NOTE_A7); - _assign_exercise_type(state); -} - -static void _init_session(couchTo5k_state_t *state){ - state->exercise = 0; // Restart exercise counter - state->timer = C25K_SESSIONS[state->session][state->exercise]; - _assign_exercise_type(state); -} - -static char *_exercise_type_to_str(exercise_type_t t){ - switch (t){ - case C25K_WARMUP: - return "WU"; - case C25K_RUN: - return "RU"; - case C25K_WALK: - return "WA"; - case C25K_FINISHED: - return "--"; - default: - return " "; - } -} -static void _display(couchTo5k_state_t *state, char *buf){ - // TODO only repaint needed parts - uint8_t seconds = state->timer % 60; - sprintf(buf, "%s%2d%2d%02d%02d", - _exercise_type_to_str(state->exercise_type), - (state->session + 1) % 100, - ((state->timer - seconds) / 60) % 100, - seconds, - (state->exercise + 1) % 100); - watch_display_string(buf, 0); -} - - -void couchTo5k_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(couchTo5k_state_t)); - memset(*context_ptr, 0, sizeof(couchTo5k_state_t)); - // Do any one-time tasks in here; the inside of this conditional - // happens only at boot. - // C25K_SESSIONS[0] = C25K_WEEK_TEST; - C25K_SESSIONS[0] = C25K_WEEK_1; - C25K_SESSIONS[1] = C25K_WEEK_1; - C25K_SESSIONS[2] = C25K_WEEK_1; - C25K_SESSIONS[3] = C25K_WEEK_2; - C25K_SESSIONS[4] = C25K_WEEK_2; - C25K_SESSIONS[5] = C25K_WEEK_2; - C25K_SESSIONS[6] = C25K_WEEK_3; - C25K_SESSIONS[7] = C25K_WEEK_3; - C25K_SESSIONS[8] = C25K_WEEK_3; - C25K_SESSIONS[9] = C25K_WEEK_4; - C25K_SESSIONS[10] = C25K_WEEK_4; - C25K_SESSIONS[11] = C25K_WEEK_4; - C25K_SESSIONS[12] = C25K_WEEK_5_1; - C25K_SESSIONS[13] = C25K_WEEK_5_2; - C25K_SESSIONS[14] = C25K_WEEK_5_3; - C25K_SESSIONS[15] = C25K_WEEK_6_1; - C25K_SESSIONS[16] = C25K_WEEK_6_2; - C25K_SESSIONS[17] = C25K_WEEK_6_3; - C25K_SESSIONS[18] = C25K_WEEK_7; - C25K_SESSIONS[19] = C25K_WEEK_7; - C25K_SESSIONS[20] = C25K_WEEK_7; - C25K_SESSIONS[21] = C25K_WEEK_8; - C25K_SESSIONS[22] = C25K_WEEK_8; - C25K_SESSIONS[23] = C25K_WEEK_8; - C25K_SESSIONS[24] = C25K_WEEK_9; - C25K_SESSIONS[25] = C25K_WEEK_9; - C25K_SESSIONS[26] = C25K_WEEK_9; - } - // Do any pin or peripheral setup here; this will be called whenever the - // watch wakes from deep sleep. -} - -void couchTo5k_face_activate(movement_settings_t *settings, void *context) { - (void) settings; - (void) context; - // Handle any tasks related to your watch face coming on screen. - watch_set_colon(); -} - - -bool couchTo5k_face_loop(movement_event_t event, movement_settings_t *settings, - void *context) { - couchTo5k_state_t *state = (couchTo5k_state_t *)context; - static char buf[11]; - static bool paused = true; - - switch (event.event_type) { - case EVENT_ACTIVATE: - // Show your initial UI here. - movement_request_tick_frequency(1); - _init_session(state); - paused = true; - _display(state, buf); - break; - case EVENT_TICK: - if ( !paused && !_finished(state) ) { - if (state->timer == 0){ - _next_exercise(state); - } else { - state->timer--; - } - } - _display(state, buf); - break; - case EVENT_LIGHT_BUTTON_UP: - // This is the next-exercise / reset button. - - // When finished move to the next session and leave it paused - if ( _finished(state) ){ - _next_session(state); - _init_session(state); - paused = true; - break; - } - // When paused and cleared move to next, when only paused, clear - if ( paused ) { - if ( _cleared(state) ){ - _next_session(state); - } - _init_session(state); - } - break; - case EVENT_ALARM_BUTTON_UP: - if (settings->bit.button_should_sound) { - watch_buzzer_play_note(BUZZER_NOTE_C8, 50); - } - paused = !paused; - break; - case EVENT_TIMEOUT: - // Your watch face will receive this event after a period of - // inactivity. If it makes sense to resign, - // movement_move_to_face(0); - break; - case EVENT_LOW_ENERGY_UPDATE: - // If you did not resign in EVENT_TIMEOUT, you can use this event - // to update the display once a minute. Avoid displaying - // fast-updating values like seconds, since the display won't - // update again for 60 seconds. You should also consider starting - // the tick animation, to show the wearer that this is sleep mode: - // watch_start_tick_animation(500); - break; - default: - // Movement's default loop handler will step in for any cases you - // don't handle above: - // * EVENT_LIGHT_BUTTON_DOWN lights the LED - // * EVENT_MODE_BUTTON_UP moves to the next watch face in the list - // * EVENT_MODE_LONG_PRESS returns to the first watch face (or - // skips to the secondary watch face, if configured) - // You can override any of these behaviors by adding a case for - // these events to this switch statement. - return movement_default_loop_handler(event, settings); - } - - // return true if the watch can enter standby mode. Generally speaking, you - // should always return true. - // Exceptions: - // * If you are displaying a color using the low-level watch_set_led_color - // function, you should return false. - // * If you are sounding the buzzer using the low-level - // watch_set_buzzer_on function, you should return false. - // Note that if you are driving the LED or buzzer using Movement functions - // like movement_illuminate_led or movement_play_alarm, you can still - // return true. This guidance only applies to the low-level watch_ - // functions. - return true; -} - -void couchTo5k_face_resign(movement_settings_t *settings, void *context) { - (void) settings; - (void) context; - - // handle any cleanup before your watch face goes off-screen. -} - diff --git a/movement/watch_faces/complication/couchTo5k_face.h b/movement/watch_faces/complication/couchTo5k_face.h deleted file mode 100644 index 149db599..00000000 --- a/movement/watch_faces/complication/couchTo5k_face.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2023 Ekaitz Zarraga - * - * 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 COUCHTO5K_FACE_H_ -#define COUCHTO5K_FACE_H_ - -#include "movement.h" - -/* - * Couch To 5k; - * - * - * The program is designed to train 3 times a week. Each training is a - * *session*. Each of the rounds you have in the training is an *exercise*. - * - * The training goes like this: - * 5min warm-up walk -> Run X minutes -> Walk Y minutes -> ... -> Stop - * - * The watch face shows it like this: The weekday indicator shows if you need - * to Warm Up (`WU`), run (`rU`), walk (`WA`) or stop (`--`). - * - * The month-day indicator shows the session you are in (from 1 to 27). - * - * The timer shows the time you have left in the exercise and the exercise you - * are doing (MM:SS:ee). When an exercise finishes you are notified with an - * alarm. When the whole session finishes, a different tone is played for a - * longer period. - * - * Pressing the ALARM button pauses/resumes the clock. - * - * Pressing the LIGHT button does nothing if the timer is not paused. When it - * is paused it clears the current session (it restarts it to the beginning) - * and if it was already cleared or the current session was finished moves to - * the next session. - */ - -typedef enum { - C25K_WARMUP, - C25K_RUN, - C25K_WALK, - C25K_FINISHED -} exercise_type_t; - -typedef struct { - // Anything you need to keep track of, put it here! - uint8_t session; - uint8_t exercise; - exercise_type_t exercise_type; - uint16_t timer; -} couchTo5k_state_t; - -void couchTo5k_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr); -void couchTo5k_face_activate(movement_settings_t *settings, void *context); -bool couchTo5k_face_loop(movement_event_t event, movement_settings_t *settings, void *context); -void couchTo5k_face_resign(movement_settings_t *settings, void *context); - -#define couchTo5k_face ((const watch_face_t){ \ - couchTo5k_face_setup, \ - couchTo5k_face_activate, \ - couchTo5k_face_loop, \ - couchTo5k_face_resign, \ - NULL, \ -}) - -#endif // COUCHTO5K_FACE_H_ - diff --git a/movement/watch_faces/complication/couch_to_5k_face.c b/movement/watch_faces/complication/couch_to_5k_face.c new file mode 100644 index 00000000..32c2b32b --- /dev/null +++ b/movement/watch_faces/complication/couch_to_5k_face.c @@ -0,0 +1,267 @@ +/* + * MIT License + * + * Copyright (c) 2023 Ekaitz Zarraga + * + * 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 +#include "couch_to_5k_face.h" + +// They go: Warmup, Run, Walk, Run, Walk, Run, Walk ... , End (0) +// Time is defined in seconds +// Maybe do /10 to reduce memory usage? +// (i don't want to use floats) + +// uint16_t C25K_WEEK_TEST[] = {10, 10, 10, 0}; +uint16_t C25K_WEEK_1[] = {300, 60, 90, 60, 90, 60, 90, 60, 90, 60, 90, 60, + 90, 60, 90, 60, 90, 0}; +uint16_t C25K_WEEK_2[] = {300, 90, 120, 90, 120, 90, 120, 90, 120, 90, 120, + 90, 120, 0}; +uint16_t C25K_WEEK_3[] = {300, 90, 90, 180, 180, 90, 90, 180, 180, 0}; +uint16_t C25K_WEEK_4[] = {300, 180, 90, 300, 150, 180, 90, 300, 0}; +uint16_t C25K_WEEK_5_1[] = {300, 300, 180, 300, 180, 300, 0 }; +uint16_t C25K_WEEK_5_2[] = {300, 480, 300, 480 , 0}; +uint16_t C25K_WEEK_5_3[] = {300, 1200, 0}; +uint16_t C25K_WEEK_6_1[] = {300, 300, 180, 480, 180, 300, 0 }; +uint16_t C25K_WEEK_6_2[] = {300, 600, 180, 600 , 0}; +uint16_t C25K_WEEK_6_3[] = {300, 1500, 0}; +uint16_t C25K_WEEK_7[] = {300, 1500, 0}; +uint16_t C25K_WEEK_8[] = {300, 1680, 0}; +uint16_t C25K_WEEK_9[] = {300, 1800, 0}; + + +#define C25K_SESSIONS_LENGTH 3*9 +uint16_t *C25K_SESSIONS[C25K_SESSIONS_LENGTH]; + +static inline bool _finished(couch_to_5k_state_t *state){ + return state->exercise_type == C25K_FINISHED; +} +static inline bool _cleared(couch_to_5k_state_t *state){ + return state->timer == C25K_SESSIONS[state->session][0] + && state->exercise == 0; +} +static inline void _next_session(couch_to_5k_state_t *state){ + if (++state->session >= C25K_SESSIONS_LENGTH){ + state->session = 0; + } +} + +static inline void _assign_exercise_type(couch_to_5k_state_t *state){ + if (state->exercise == 0){ + state->exercise_type = C25K_WARMUP; + } else if (state->exercise % 2 == 1){ + state->exercise_type = C25K_RUN; + } else { + state->exercise_type = C25K_WALK; + } +} + +static void _next_exercise(couch_to_5k_state_t *state){ + state->exercise++; + state->timer = C25K_SESSIONS[state->session][state->exercise]; + // If the new timer starts in zero, it's finished + if (state->timer == 0){ + movement_play_alarm_beeps(7, BUZZER_NOTE_C8); + state->exercise_type = C25K_FINISHED; + return; + } + movement_play_alarm_beeps(4, BUZZER_NOTE_A7); + _assign_exercise_type(state); +} + +static void _init_session(couch_to_5k_state_t *state){ + state->exercise = 0; // Restart exercise counter + state->timer = C25K_SESSIONS[state->session][state->exercise]; + _assign_exercise_type(state); +} + +static char *_exercise_type_to_str(exercise_type_t t){ + switch (t){ + case C25K_WARMUP: + return "WU"; + case C25K_RUN: + return "RU"; + case C25K_WALK: + return "WA"; + case C25K_FINISHED: + return "--"; + default: + return " "; + } +} +static void _display(couch_to_5k_state_t *state, char *buf){ + // TODO only repaint needed parts + uint8_t seconds = state->timer % 60; + sprintf(buf, "%s%2d%2d%02d%02d", + _exercise_type_to_str(state->exercise_type), + (state->session + 1) % 100, + ((state->timer - seconds) / 60) % 100, + seconds, + (state->exercise + 1) % 100); + watch_display_string(buf, 0); +} + + +void couch_to_5k_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(couch_to_5k_state_t)); + memset(*context_ptr, 0, sizeof(couch_to_5k_state_t)); + // Do any one-time tasks in here; the inside of this conditional + // happens only at boot. + // C25K_SESSIONS[0] = C25K_WEEK_TEST; + C25K_SESSIONS[0] = C25K_WEEK_1; + C25K_SESSIONS[1] = C25K_WEEK_1; + C25K_SESSIONS[2] = C25K_WEEK_1; + C25K_SESSIONS[3] = C25K_WEEK_2; + C25K_SESSIONS[4] = C25K_WEEK_2; + C25K_SESSIONS[5] = C25K_WEEK_2; + C25K_SESSIONS[6] = C25K_WEEK_3; + C25K_SESSIONS[7] = C25K_WEEK_3; + C25K_SESSIONS[8] = C25K_WEEK_3; + C25K_SESSIONS[9] = C25K_WEEK_4; + C25K_SESSIONS[10] = C25K_WEEK_4; + C25K_SESSIONS[11] = C25K_WEEK_4; + C25K_SESSIONS[12] = C25K_WEEK_5_1; + C25K_SESSIONS[13] = C25K_WEEK_5_2; + C25K_SESSIONS[14] = C25K_WEEK_5_3; + C25K_SESSIONS[15] = C25K_WEEK_6_1; + C25K_SESSIONS[16] = C25K_WEEK_6_2; + C25K_SESSIONS[17] = C25K_WEEK_6_3; + C25K_SESSIONS[18] = C25K_WEEK_7; + C25K_SESSIONS[19] = C25K_WEEK_7; + C25K_SESSIONS[20] = C25K_WEEK_7; + C25K_SESSIONS[21] = C25K_WEEK_8; + C25K_SESSIONS[22] = C25K_WEEK_8; + C25K_SESSIONS[23] = C25K_WEEK_8; + C25K_SESSIONS[24] = C25K_WEEK_9; + C25K_SESSIONS[25] = C25K_WEEK_9; + C25K_SESSIONS[26] = C25K_WEEK_9; + } + // Do any pin or peripheral setup here; this will be called whenever the + // watch wakes from deep sleep. +} + +void couch_to_5k_face_activate(movement_settings_t *settings, void *context) { + (void) settings; + (void) context; + // Handle any tasks related to your watch face coming on screen. + watch_set_colon(); +} + + +bool couch_to_5k_face_loop(movement_event_t event, movement_settings_t *settings, + void *context) { + couch_to_5k_state_t *state = (couch_to_5k_state_t *)context; + static char buf[11]; + static bool paused = true; + + switch (event.event_type) { + case EVENT_ACTIVATE: + // Show your initial UI here. + movement_request_tick_frequency(1); + _init_session(state); + paused = true; + _display(state, buf); + break; + case EVENT_TICK: + if ( !paused && !_finished(state) ) { + if (state->timer == 0){ + _next_exercise(state); + } else { + state->timer--; + } + } + _display(state, buf); + break; + case EVENT_LIGHT_BUTTON_UP: + // This is the next-exercise / reset button. + + // When finished move to the next session and leave it paused + if ( _finished(state) ){ + _next_session(state); + _init_session(state); + paused = true; + break; + } + // When paused and cleared move to next, when only paused, clear + if ( paused ) { + if ( _cleared(state) ){ + _next_session(state); + } + _init_session(state); + } + break; + case EVENT_ALARM_BUTTON_UP: + if (settings->bit.button_should_sound) { + watch_buzzer_play_note(BUZZER_NOTE_C8, 50); + } + paused = !paused; + break; + case EVENT_TIMEOUT: + // Your watch face will receive this event after a period of + // inactivity. If it makes sense to resign, + // movement_move_to_face(0); + break; + case EVENT_LOW_ENERGY_UPDATE: + // If you did not resign in EVENT_TIMEOUT, you can use this event + // to update the display once a minute. Avoid displaying + // fast-updating values like seconds, since the display won't + // update again for 60 seconds. You should also consider starting + // the tick animation, to show the wearer that this is sleep mode: + // watch_start_tick_animation(500); + break; + default: + // Movement's default loop handler will step in for any cases you + // don't handle above: + // * EVENT_LIGHT_BUTTON_DOWN lights the LED + // * EVENT_MODE_BUTTON_UP moves to the next watch face in the list + // * EVENT_MODE_LONG_PRESS returns to the first watch face (or + // skips to the secondary watch face, if configured) + // You can override any of these behaviors by adding a case for + // these events to this switch statement. + return movement_default_loop_handler(event, settings); + } + + // return true if the watch can enter standby mode. Generally speaking, you + // should always return true. + // Exceptions: + // * If you are displaying a color using the low-level watch_set_led_color + // function, you should return false. + // * If you are sounding the buzzer using the low-level + // watch_set_buzzer_on function, you should return false. + // Note that if you are driving the LED or buzzer using Movement functions + // like movement_illuminate_led or movement_play_alarm, you can still + // return true. This guidance only applies to the low-level watch_ + // functions. + return true; +} + +void couch_to_5k_face_resign(movement_settings_t *settings, void *context) { + (void) settings; + (void) context; + + // handle any cleanup before your watch face goes off-screen. +} + diff --git a/movement/watch_faces/complication/couch_to_5k_face.h b/movement/watch_faces/complication/couch_to_5k_face.h new file mode 100644 index 00000000..3c36ce6f --- /dev/null +++ b/movement/watch_faces/complication/couch_to_5k_face.h @@ -0,0 +1,87 @@ +/* + * MIT License + * + * Copyright (c) 2023 Ekaitz Zarraga + * + * 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 COUCHTO5K_FACE_H_ +#define COUCHTO5K_FACE_H_ + +#include "movement.h" + +/* + * Couch To 5k; + * + * + * The program is designed to train 3 times a week. Each training is a + * *session*. Each of the rounds you have in the training is an *exercise*. + * + * The training goes like this: + * 5min warm-up walk -> Run X minutes -> Walk Y minutes -> ... -> Stop + * + * The watch face shows it like this: The weekday indicator shows if you need + * to Warm Up (`WU`), run (`rU`), walk (`WA`) or stop (`--`). + * + * The month-day indicator shows the session you are in (from 1 to 27). + * + * The timer shows the time you have left in the exercise and the exercise you + * are doing (MM:SS:ee). When an exercise finishes you are notified with an + * alarm. When the whole session finishes, a different tone is played for a + * longer period. + * + * Pressing the ALARM button pauses/resumes the clock. + * + * Pressing the LIGHT button does nothing if the timer is not paused. When it + * is paused it clears the current session (it restarts it to the beginning) + * and if it was already cleared or the current session was finished moves to + * the next session. + */ + +typedef enum { + C25K_WARMUP, + C25K_RUN, + C25K_WALK, + C25K_FINISHED +} exercise_type_t; + +typedef struct { + // Anything you need to keep track of, put it here! + uint8_t session; + uint8_t exercise; + exercise_type_t exercise_type; + uint16_t timer; +} couch_to_5k_state_t; + +void couch_to_5k_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr); +void couch_to_5k_face_activate(movement_settings_t *settings, void *context); +bool couch_to_5k_face_loop(movement_event_t event, movement_settings_t *settings, void *context); +void couch_to_5k_face_resign(movement_settings_t *settings, void *context); + +#define couch_to_5k_face ((const watch_face_t){ \ + couch_to_5k_face_setup, \ + couch_to_5k_face_activate, \ + couch_to_5k_face_loop, \ + couch_to_5k_face_resign, \ + NULL, \ +}) + +#endif // COUCHTO5K_FACE_H_ + -- cgit v1.2.3