From 8c7e9fa558917030a7550440aacebd7a207a5591 Mon Sep 17 00:00:00 2001 From: Christian Buschau Date: Tue, 19 Sep 2023 15:21:00 +0200 Subject: [PATCH 1/4] day_one_face: cleanup --- .../watch_faces/complication/day_one_face.c | 45 ++++++++++--------- .../watch_faces/complication/day_one_face.h | 11 ++++- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/movement/watch_faces/complication/day_one_face.c b/movement/watch_faces/complication/day_one_face.c index 25ce1c23..e7602995 100644 --- a/movement/watch_faces/complication/day_one_face.c +++ b/movement/watch_faces/complication/day_one_face.c @@ -32,15 +32,15 @@ static uint32_t _day_one_face_juliandaynum(uint16_t year, uint16_t month, uint16 return (1461 * (year + 4800 + (month - 14) / 12)) / 4 + (367 * (month - 2 - 12 * ((month - 14) / 12))) / 12 - (3 * ((year + 4900 + (month - 14) / 12) / 100))/4 + day - 32075; } -static void _day_one_face_update(day_one_state_t state) { +static void _day_one_face_update(day_one_state_t *state) { char buf[15]; watch_date_time date_time = watch_rtc_get_date_time(); uint32_t julian_date = _day_one_face_juliandaynum(date_time.unit.year + WATCH_RTC_REFERENCE_YEAR, date_time.unit.month, date_time.unit.day); - uint32_t julian_birthdate = _day_one_face_juliandaynum(state.birth_year, state.birth_month, state.birth_day); + uint32_t julian_birthdate = _day_one_face_juliandaynum(state->birth_year, state->birth_month, state->birth_day); if (julian_date < julian_birthdate) { - sprintf(buf, "DA %6lu", julian_birthdate - julian_date); + sprintf(buf, "DA %6lu", julian_birthdate - julian_date); } else { - sprintf(buf, "DA %6lu", julian_date - julian_birthdate); + sprintf(buf, "DA %6lu", julian_date - julian_birthdate); } watch_display_string(buf, 0); } @@ -71,8 +71,7 @@ void day_one_face_activate(movement_settings_t *settings, void *context) { // stash the current year, useful in birthday setting mode. watch_date_time date_time = watch_rtc_get_date_time(); state->current_year = date_time.unit.year + WATCH_RTC_REFERENCE_YEAR; - // reset the current page to 0, display days alive. - state->current_page = 0; + state->current_page = PAGE_DISPLAY; // fetch the user's birth date from the birthday register. movement_birthdate_t movement_birthdate = (movement_birthdate_t) watch_get_backup_data(2); @@ -90,91 +89,95 @@ bool day_one_face_loop(movement_event_t event, movement_settings_t *settings, vo switch (event.event_type) { case EVENT_ACTIVATE: - _day_one_face_update(*state); + _day_one_face_update(state); break; case EVENT_LOW_ENERGY_UPDATE: case EVENT_TICK: - if (state->current_page != 0) { + if (state->current_page != PAGE_DISPLAY) { // if in settings mode, update whatever the current page is switch (state->current_page) { - case 1: + case PAGE_YEAR: watch_display_string("YR ", 0); if (event.subsecond % 2) { sprintf(buf, "%4d", state->birth_year); watch_display_string(buf, 4); } break; - case 2: + case PAGE_MONTH: watch_display_string("MO ", 0); if (event.subsecond % 2) { sprintf(buf, "%2d", state->birth_month); watch_display_string(buf, 4); } break; - case 3: + case PAGE_DAY: watch_display_string("DA ", 0); if (event.subsecond % 2) { sprintf(buf, "%2d", state->birth_day); watch_display_string(buf, 6); } break; + default: + break; } } else { // otherwise, check if we have to update. the display only needs to change at midnight! watch_date_time date_time = watch_rtc_get_date_time(); if (date_time.unit.hour == 0 && date_time.unit.minute == 0 && date_time.unit.second == 0) { - _day_one_face_update(*state); + _day_one_face_update(state); } } break; case EVENT_LIGHT_BUTTON_DOWN: // only illuminate if we're in display mode - if (state->current_page == 0) movement_illuminate_led(); + if (state->current_page == PAGE_DISPLAY) movement_illuminate_led(); break; case EVENT_LIGHT_BUTTON_UP: // otherwise use the light button to advance settings pages. - if (state->current_page != 0) { + if (state->current_page != PAGE_DISPLAY) { // go to next setting page... state->current_page = (state->current_page + 1) % 4; if (state->current_page == 0) { // ...unless we've been pushed back to display mode. movement_request_tick_frequency(1); // force display since it normally won't update til midnight. - _day_one_face_update(*state); + _day_one_face_update(state); } } break; case EVENT_ALARM_BUTTON_UP: // if we are on a settings page, increment whatever value we're setting. - if (state->current_page != 0) { + if (state->current_page != PAGE_DISPLAY) { state->birthday_changed = true; switch (state->current_page) { - case 1: + case PAGE_YEAR: state->birth_year = state->birth_year + 1; if (state->birth_year > state->current_year) state->birth_year = 1900; break; - case 2: + case PAGE_MONTH: state->birth_month = (state->birth_month % 12) + 1; break; - case 3: + case PAGE_DAY: state->birth_day = state->birth_day + 1; if (state->birth_day == 0 || state->birth_day > days_in_month[state->birth_month - 1]) { state->birth_day = 1; } break; + default: + break; } } break; case EVENT_ALARM_LONG_PRESS: // if we aren't already in settings mode, put us there. - if (state->current_page == 0) { + if (state->current_page == PAGE_DISPLAY) { state->current_page++; movement_request_tick_frequency(4); } break; case EVENT_TIMEOUT: // return home if we're on a settings page (this saves our changes when we resign). - if (state->current_page != 0) { + if (state->current_page != PAGE_DISPLAY) { movement_move_to_face(0); } break; diff --git a/movement/watch_faces/complication/day_one_face.h b/movement/watch_faces/complication/day_one_face.h index ab8372bf..5d822a5e 100644 --- a/movement/watch_faces/complication/day_one_face.h +++ b/movement/watch_faces/complication/day_one_face.h @@ -27,11 +27,18 @@ #include "movement.h" -// The Day One face is designed to count upwards from the wearer's date of birth. It also functions as an +// The Day One face is designed to count the days since or until a given date. It also functions as an // interface for setting the birth date register, which other watch faces can use for various purposes. +typedef enum { + PAGE_DISPLAY, + PAGE_YEAR, + PAGE_MONTH, + PAGE_DAY +} day_one_page_t; + typedef struct { - uint8_t current_page; + day_one_page_t current_page; uint16_t current_year; uint16_t birth_year; uint8_t birth_month; From 1022359252742c8950a403348310fc66f0e59787 Mon Sep 17 00:00:00 2001 From: Christian Buschau Date: Tue, 19 Sep 2023 17:53:07 +0200 Subject: [PATCH 2/4] day_one_face: allow years until 2080 This is the same limit introduced in commit 7fd51ca --- movement/watch_faces/complication/day_one_face.c | 9 +++------ movement/watch_faces/complication/day_one_face.h | 1 - 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/movement/watch_faces/complication/day_one_face.c b/movement/watch_faces/complication/day_one_face.c index e7602995..c2c3d210 100644 --- a/movement/watch_faces/complication/day_one_face.c +++ b/movement/watch_faces/complication/day_one_face.c @@ -54,7 +54,7 @@ void day_one_face_setup(movement_settings_t *settings, uint8_t watch_face_index, movement_birthdate_t movement_birthdate = (movement_birthdate_t) watch_get_backup_data(2); if (movement_birthdate.reg == 0) { // if birth date is totally blank, set a reasonable starting date. this works well for anyone under 63, but - // you can keep pressing to go back to 1900; just pass the current year. also picked this date because if you + // you can keep pressing to go back to 1900; just pass the year 2080. also picked this date because if you // set it to 1959-01-02, it counts up from the launch of Luna-1, the first spacecraft to leave the well. movement_birthdate.bit.year = 1959; movement_birthdate.bit.month = 1; @@ -68,9 +68,6 @@ void day_one_face_activate(movement_settings_t *settings, void *context) { (void) settings; day_one_state_t *state = (day_one_state_t *)context; - // stash the current year, useful in birthday setting mode. - watch_date_time date_time = watch_rtc_get_date_time(); - state->current_year = date_time.unit.year + WATCH_RTC_REFERENCE_YEAR; state->current_page = PAGE_DISPLAY; // fetch the user's birth date from the birthday register. @@ -137,7 +134,7 @@ bool day_one_face_loop(movement_event_t event, movement_settings_t *settings, vo if (state->current_page != PAGE_DISPLAY) { // go to next setting page... state->current_page = (state->current_page + 1) % 4; - if (state->current_page == 0) { + if (state->current_page == PAGE_DISPLAY) { // ...unless we've been pushed back to display mode. movement_request_tick_frequency(1); // force display since it normally won't update til midnight. @@ -152,7 +149,7 @@ bool day_one_face_loop(movement_event_t event, movement_settings_t *settings, vo switch (state->current_page) { case PAGE_YEAR: state->birth_year = state->birth_year + 1; - if (state->birth_year > state->current_year) state->birth_year = 1900; + if (state->birth_year > 2080) state->birth_year = 1900; break; case PAGE_MONTH: state->birth_month = (state->birth_month % 12) + 1; diff --git a/movement/watch_faces/complication/day_one_face.h b/movement/watch_faces/complication/day_one_face.h index 5d822a5e..c2a87c82 100644 --- a/movement/watch_faces/complication/day_one_face.h +++ b/movement/watch_faces/complication/day_one_face.h @@ -39,7 +39,6 @@ typedef enum { typedef struct { day_one_page_t current_page; - uint16_t current_year; uint16_t birth_year; uint8_t birth_month; uint8_t birth_day; From e8b7985dde2ef7a680429b8992e481d30b676b32 Mon Sep 17 00:00:00 2001 From: Christian Buschau Date: Tue, 19 Sep 2023 18:31:56 +0200 Subject: [PATCH 3/4] day_one_face: enable quick cycle through settings This allows the alarm button to be held down in the date settings and quickly cycle through the dates instead of having to push for each single increment like in other faces. --- .../watch_faces/complication/day_one_face.c | 66 +++++++++++++------ .../watch_faces/complication/day_one_face.h | 1 + 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/movement/watch_faces/complication/day_one_face.c b/movement/watch_faces/complication/day_one_face.c index c2c3d210..d0cf9f75 100644 --- a/movement/watch_faces/complication/day_one_face.c +++ b/movement/watch_faces/complication/day_one_face.c @@ -27,6 +27,8 @@ #include "day_one_face.h" #include "watch.h" +static const uint8_t days_in_month[12] = {31, 29, 31, 30, 31, 30, 30, 31, 30, 31, 30, 31}; + static uint32_t _day_one_face_juliandaynum(uint16_t year, uint16_t month, uint16_t day) { // from here: https://en.wikipedia.org/wiki/Julian_day#Julian_day_number_calculation return (1461 * (year + 4800 + (month - 14) / 12)) / 4 + (367 * (month - 2 - 12 * ((month - 14) / 12))) / 12 - (3 * ((year + 4900 + (month - 14) / 12) / 100))/4 + day - 32075; @@ -45,6 +47,34 @@ static void _day_one_face_update(day_one_state_t *state) { watch_display_string(buf, 0); } +static void _day_one_face_abort_quick_cycle(day_one_state_t *state) { + if (state->quick_cycle) { + state->quick_cycle = false; + movement_request_tick_frequency(4); + } +} + +static void _day_one_face_increment(day_one_state_t *state) { + state->birthday_changed = true; + switch (state->current_page) { + case PAGE_YEAR: + state->birth_year = state->birth_year + 1; + if (state->birth_year > 2080) state->birth_year = 1900; + break; + case PAGE_MONTH: + state->birth_month = (state->birth_month % 12) + 1; + break; + case PAGE_DAY: + state->birth_day = state->birth_day + 1; + if (state->birth_day == 0 || state->birth_day > days_in_month[state->birth_month - 1]) { + state->birth_day = 1; + } + break; + default: + break; + } +} + void day_one_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) { (void) settings; (void) watch_face_index; @@ -69,6 +99,7 @@ void day_one_face_activate(movement_settings_t *settings, void *context) { day_one_state_t *state = (day_one_state_t *)context; state->current_page = PAGE_DISPLAY; + state->quick_cycle = false; // fetch the user's birth date from the birthday register. movement_birthdate_t movement_birthdate = (movement_birthdate_t) watch_get_backup_data(2); @@ -81,7 +112,6 @@ bool day_one_face_loop(movement_event_t event, movement_settings_t *settings, vo (void) settings; day_one_state_t *state = (day_one_state_t *)context; - const uint8_t days_in_month[12] = {31, 29, 31, 30, 31, 30, 30, 31, 30, 31, 30, 31}; char buf[6]; switch (event.event_type) { @@ -91,6 +121,13 @@ bool day_one_face_loop(movement_event_t event, movement_settings_t *settings, vo case EVENT_LOW_ENERGY_UPDATE: case EVENT_TICK: if (state->current_page != PAGE_DISPLAY) { + if (state->quick_cycle) { + if (watch_get_pin_level(BTN_ALARM)) { + _day_one_face_increment(state); + } else { + _day_one_face_abort_quick_cycle(state); + } + } // if in settings mode, update whatever the current page is switch (state->current_page) { case PAGE_YEAR: @@ -145,24 +182,8 @@ bool day_one_face_loop(movement_event_t event, movement_settings_t *settings, vo case EVENT_ALARM_BUTTON_UP: // if we are on a settings page, increment whatever value we're setting. if (state->current_page != PAGE_DISPLAY) { - state->birthday_changed = true; - switch (state->current_page) { - case PAGE_YEAR: - state->birth_year = state->birth_year + 1; - if (state->birth_year > 2080) state->birth_year = 1900; - break; - case PAGE_MONTH: - state->birth_month = (state->birth_month % 12) + 1; - break; - case PAGE_DAY: - state->birth_day = state->birth_day + 1; - if (state->birth_day == 0 || state->birth_day > days_in_month[state->birth_month - 1]) { - state->birth_day = 1; - } - break; - default: - break; - } + _day_one_face_abort_quick_cycle(state); + _day_one_face_increment(state); } break; case EVENT_ALARM_LONG_PRESS: @@ -170,9 +191,16 @@ bool day_one_face_loop(movement_event_t event, movement_settings_t *settings, vo if (state->current_page == PAGE_DISPLAY) { state->current_page++; movement_request_tick_frequency(4); + } else { + state->quick_cycle = true; + movement_request_tick_frequency(8); } break; + case EVENT_ALARM_LONG_UP: + _day_one_face_abort_quick_cycle(state); + break; case EVENT_TIMEOUT: + _day_one_face_abort_quick_cycle(state); // return home if we're on a settings page (this saves our changes when we resign). if (state->current_page != PAGE_DISPLAY) { movement_move_to_face(0); diff --git a/movement/watch_faces/complication/day_one_face.h b/movement/watch_faces/complication/day_one_face.h index c2a87c82..018bd09b 100644 --- a/movement/watch_faces/complication/day_one_face.h +++ b/movement/watch_faces/complication/day_one_face.h @@ -43,6 +43,7 @@ typedef struct { uint8_t birth_month; uint8_t birth_day; bool birthday_changed; + bool quick_cycle; } day_one_state_t; void day_one_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr); From 984990fb6639c9b24f2edcc8ca50390e1ce3aa0c Mon Sep 17 00:00:00 2001 From: Christian Buschau Date: Wed, 20 Sep 2023 00:55:51 +0200 Subject: [PATCH 4/4] day_one_face: show set date on short alarm button press --- .../watch_faces/complication/day_one_face.c | 161 +++++++++++------- .../watch_faces/complication/day_one_face.h | 4 +- 2 files changed, 107 insertions(+), 58 deletions(-) diff --git a/movement/watch_faces/complication/day_one_face.c b/movement/watch_faces/complication/day_one_face.c index d0cf9f75..27601edc 100644 --- a/movement/watch_faces/complication/day_one_face.c +++ b/movement/watch_faces/complication/day_one_face.c @@ -100,6 +100,7 @@ void day_one_face_activate(movement_settings_t *settings, void *context) { state->current_page = PAGE_DISPLAY; state->quick_cycle = false; + state->ticks = 0; // fetch the user's birth date from the birthday register. movement_birthdate_t movement_birthdate = (movement_birthdate_t) watch_get_backup_data(2); @@ -112,7 +113,7 @@ bool day_one_face_loop(movement_event_t event, movement_settings_t *settings, vo (void) settings; day_one_state_t *state = (day_one_state_t *)context; - char buf[6]; + char buf[9]; switch (event.event_type) { case EVENT_ACTIVATE: @@ -120,80 +121,126 @@ bool day_one_face_loop(movement_event_t event, movement_settings_t *settings, vo break; case EVENT_LOW_ENERGY_UPDATE: case EVENT_TICK: - if (state->current_page != PAGE_DISPLAY) { - if (state->quick_cycle) { - if (watch_get_pin_level(BTN_ALARM)) { - _day_one_face_increment(state); - } else { - _day_one_face_abort_quick_cycle(state); - } + if (state->quick_cycle) { + if (watch_get_pin_level(BTN_ALARM)) { + _day_one_face_increment(state); + } else { + _day_one_face_abort_quick_cycle(state); } + } + switch (state->current_page) { // if in settings mode, update whatever the current page is - switch (state->current_page) { - case PAGE_YEAR: - watch_display_string("YR ", 0); - if (event.subsecond % 2) { - sprintf(buf, "%4d", state->birth_year); - watch_display_string(buf, 4); - } - break; - case PAGE_MONTH: - watch_display_string("MO ", 0); - if (event.subsecond % 2) { - sprintf(buf, "%2d", state->birth_month); - watch_display_string(buf, 4); - } - break; - case PAGE_DAY: - watch_display_string("DA ", 0); - if (event.subsecond % 2) { - sprintf(buf, "%2d", state->birth_day); - watch_display_string(buf, 6); - } - break; - default: - break; - } - } else { + case PAGE_YEAR: + watch_display_string("YR ", 0); + if (event.subsecond % 2) { + sprintf(buf, "%4d", state->birth_year); + watch_display_string(buf, 4); + } + break; + case PAGE_MONTH: + watch_display_string("MO ", 0); + if (event.subsecond % 2) { + sprintf(buf, "%2d", state->birth_month); + watch_display_string(buf, 4); + } + break; + case PAGE_DAY: + watch_display_string("DA ", 0); + if (event.subsecond % 2) { + sprintf(buf, "%2d", state->birth_day); + watch_display_string(buf, 6); + } + break; // otherwise, check if we have to update. the display only needs to change at midnight! - watch_date_time date_time = watch_rtc_get_date_time(); - if (date_time.unit.hour == 0 && date_time.unit.minute == 0 && date_time.unit.second == 0) { - _day_one_face_update(state); - } + case PAGE_DISPLAY: { + watch_date_time date_time = watch_rtc_get_date_time(); + if (date_time.unit.hour == 0 && date_time.unit.minute == 0 && date_time.unit.second == 0) { + _day_one_face_update(state); + } + break;} + case PAGE_DATE: + if (state->ticks > 0) { + state->ticks--; + } else { + state->current_page = PAGE_DISPLAY; + _day_one_face_update(state); + } + break; + default: + break; } break; case EVENT_LIGHT_BUTTON_DOWN: // only illuminate if we're in display mode - if (state->current_page == PAGE_DISPLAY) movement_illuminate_led(); + switch (state->current_page) { + case PAGE_DISPLAY: + // fall through + case PAGE_DATE: + movement_illuminate_led(); + break; + default: + break; + } break; case EVENT_LIGHT_BUTTON_UP: // otherwise use the light button to advance settings pages. - if (state->current_page != PAGE_DISPLAY) { - // go to next setting page... - state->current_page = (state->current_page + 1) % 4; - if (state->current_page == PAGE_DISPLAY) { - // ...unless we've been pushed back to display mode. - movement_request_tick_frequency(1); - // force display since it normally won't update til midnight. - _day_one_face_update(state); - } + switch (state->current_page) { + case PAGE_YEAR: + // fall through + case PAGE_MONTH: + // fall through + case PAGE_DAY: + // go to next setting page... + state->current_page = (state->current_page + 1) % 4; + if (state->current_page == PAGE_DISPLAY) { + // ...unless we've been pushed back to display mode. + movement_request_tick_frequency(1); + // force display since it normally won't update til midnight. + _day_one_face_update(state); + } + break; + default: + break; } break; case EVENT_ALARM_BUTTON_UP: // if we are on a settings page, increment whatever value we're setting. - if (state->current_page != PAGE_DISPLAY) { - _day_one_face_abort_quick_cycle(state); - _day_one_face_increment(state); + switch (state->current_page) { + case PAGE_YEAR: + // fall through + case PAGE_MONTH: + // fall through + case PAGE_DAY: + _day_one_face_abort_quick_cycle(state); + _day_one_face_increment(state); + break; + case PAGE_DISPLAY: + state->current_page = PAGE_DATE; + sprintf(buf, "%04d%02d%02d", state->birth_year % 10000, state->birth_month % 100, state->birth_day % 100); + watch_display_string(buf, 2); + state->ticks = 2; + break; + default: + break; } break; case EVENT_ALARM_LONG_PRESS: // if we aren't already in settings mode, put us there. - if (state->current_page == PAGE_DISPLAY) { - state->current_page++; - movement_request_tick_frequency(4); - } else { - state->quick_cycle = true; - movement_request_tick_frequency(8); + switch (state->current_page) { + case PAGE_DISPLAY: + state->current_page++; + movement_request_tick_frequency(4); + break; + case PAGE_YEAR: + // fall through + case PAGE_MONTH: + // fall through + case PAGE_DAY: + state->quick_cycle = true; + movement_request_tick_frequency(8); + break; + default: + break; } break; case EVENT_ALARM_LONG_UP: diff --git a/movement/watch_faces/complication/day_one_face.h b/movement/watch_faces/complication/day_one_face.h index 018bd09b..db1d05ed 100644 --- a/movement/watch_faces/complication/day_one_face.h +++ b/movement/watch_faces/complication/day_one_face.h @@ -34,7 +34,8 @@ typedef enum { PAGE_DISPLAY, PAGE_YEAR, PAGE_MONTH, - PAGE_DAY + PAGE_DAY, + PAGE_DATE } day_one_page_t; typedef struct { @@ -44,6 +45,7 @@ typedef struct { uint8_t birth_day; bool birthday_changed; bool quick_cycle; + uint8_t ticks; } day_one_state_t; void day_one_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);