From: kbc-yam <66929688+kbc-yam@users.noreply.github.com> Date: Sun, 3 Aug 2025 17:09:19 +0000 (+0900) Subject: Add Japanese Era (Wareki) Display Feature (for Custom LCD) (#57) X-Git-Url: https://git.earman.xyz/?a=commitdiff_plain;h=5e0cc986596ee7c2fc398003705689b9ec206f50;p=sensor-watch.git Add Japanese Era (Wareki) Display Feature (for Custom LCD) (#57) --- diff --git a/legacy/watch_faces/complication/wareki_face.c b/legacy/watch_faces/complication/wareki_face.c deleted file mode 100644 index ec87659..0000000 --- a/legacy/watch_faces/complication/wareki_face.c +++ /dev/null @@ -1,218 +0,0 @@ -#include -#include -#include "wareki_face.h" -#include "filesystem.h" -#include "watch_utility.h" - - -//Long press status flag -static bool _alarm_button_press; -static bool _light_button_press; - - -void wareki_setup(uint8_t watch_face_index, void ** context_ptr) { - (void) watch_face_index; - - //printf("wareki_setup() \n"); - if (*context_ptr == NULL) { - *context_ptr = malloc(sizeof(wareki_state_t)); - memset(*context_ptr, 0, sizeof(wareki_state_t)); - // Do any one-time tasks in here; the inside of this conditional happens only at boot. - } - -} - - -// splash view -static void draw_wareki_splash(wareki_state_t *state) { - (void) state; - char buf[11]; - - watch_clear_colon(); - - sprintf(buf, "%s","wa ------"); - - watch_display_string(buf, 0); -} - - -//draw year and Japanese wareki -static void draw_year_and_wareki(wareki_state_t *state) { - char buf[27]; - - if(state->disp_year < REIWA_GANNEN){ - //Heisei - sprintf(buf, " h%2d%4d ", (int)state->disp_year - HEISEI_GANNEN + 1, (int)state->disp_year); - } - else{ - //Reiwa - sprintf(buf, " r%2d%4d ", (int)state->disp_year - REIWA_GANNEN + 1 , (int)state->disp_year); - } - watch_display_string(buf, 0); -} - - -void wareki_activate(void *context) { - - //printf("wareki_activate() \n"); - - wareki_state_t *state = (wareki_state_t *)context; - - if (watch_sleep_animation_is_running()) watch_stop_sleep_animation(); - - state->active = false; - - _alarm_button_press = false; - _light_button_press = false; - - state->real_year = watch_rtc_get_date_time().unit.year + WATCH_RTC_REFERENCE_YEAR; - state->start_year = state->real_year; - state->disp_year = state->real_year; - - movement_request_tick_frequency(1); -} - - -void addYear(wareki_state_t* state,int count){ - - state->disp_year = state->disp_year + count; - - if(state->disp_year > REIWA_LIMIT ){ - state->disp_year = REIWA_LIMIT; - } - else{ - //watch_buzzer_play_note(BUZZER_NOTE_C8, 30); - } -} - - -void subYear(wareki_state_t* state,int count){ - - state->disp_year = state->disp_year - count; - - if(state->disp_year < 1989 ){ - state->disp_year = 1989; - } - else{ - //watch_buzzer_play_note(BUZZER_NOTE_C7, 30); - } -} - - -bool wareki_loop(movement_event_t event, void *context) { - wareki_state_t *state = (wareki_state_t *)context; - - state->real_year = watch_rtc_get_date_time().unit.year + WATCH_RTC_REFERENCE_YEAR; - - if( state->real_year != state->start_year ){ - state->start_year = state->real_year; - state->disp_year = state->real_year; - } - - - switch (event.event_type) { - case EVENT_ACTIVATE: - draw_wareki_splash(state); - break; - case EVENT_MODE_BUTTON_UP: - movement_move_to_next_face(); - break; - - case EVENT_LOW_ENERGY_UPDATE: - case EVENT_TICK: - - //printf("tick %d\n",state->disp_year ); - - if (_alarm_button_press && HAL_GPIO_BTN_ALARM_read()){ - //printf("ALARM ON\n"); - } - else{ - //printf("ALARM OFF\n"); - _alarm_button_press = false; - } - - if (_light_button_press && HAL_GPIO_BTN_LIGHT_read()){ - //printf("LIGHT ON\n"); - } - else{ - //printf("LIGHT OFF\n"); - _light_button_press = false; - } - - if (_alarm_button_press) { - addYear(state,1); - } - if (_light_button_press) { - subYear(state,1); - } - - draw_year_and_wareki(state); - - break; - - case EVENT_LIGHT_BUTTON_DOWN: - //printf("LIGHT DOWN\n"); - subYear(state,1); - break; - case EVENT_LIGHT_LONG_PRESS: - //printf("LIGHTPRESS \n"); - _light_button_press = true; - movement_request_tick_frequency(8); - break; - case EVENT_LIGHT_LONG_UP: - //printf("LIGHTPRESS UP\n"); - _light_button_press = false; - movement_request_tick_frequency(4); - break; - case EVENT_LIGHT_BUTTON_UP: - //printf("LIGHT UP\n"); - _light_button_press = false; - movement_request_tick_frequency(4); - break; - case EVENT_ALARM_BUTTON_DOWN: - //printf("ALARM DOWN\n"); - addYear(state,1); - break; - case EVENT_ALARM_LONG_PRESS: - //printf("LONGPRESS \n"); - _alarm_button_press = true; - movement_request_tick_frequency(8); - break; - case EVENT_ALARM_LONG_UP: - //printf("LONGPRESS UP\n"); - _alarm_button_press = false; - movement_request_tick_frequency(4); - break; - case EVENT_ALARM_BUTTON_UP: - //printf("ALARM UP\n"); - movement_request_tick_frequency(4); - break; - - case EVENT_TIMEOUT: - //printf("time out ! \n"); - 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_sleep_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); - } - - return true; -} - -void wareki_resign(void *context) { - (void) context; -} - diff --git a/legacy/watch_faces/complication/wareki_face.h b/legacy/watch_faces/complication/wareki_face.h deleted file mode 100644 index 4dffc46..0000000 --- a/legacy/watch_faces/complication/wareki_face.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef WAREKI_FACE_H_ -#define WAREKI_FACE_H_ - -#include "movement.h" - -#define REIWA_LIMIT 2018 + 31 -#define REIWA_GANNEN 2019 -#define HEISEI_GANNEN 1989 - -typedef struct { - bool active; - uint32_t disp_year; //Current displayed year - uint32_t start_year; //Year when this screen was launched - uint32_t real_year; //The actual current year -} wareki_state_t; - - -void wareki_setup(uint8_t watch_face_index, void ** context_ptr); -void wareki_activate(void *context); -bool wareki_loop(movement_event_t event, void *context); -void wareki_resign(void *context); -void addYear(wareki_state_t* state,int count); -void subYear(wareki_state_t* state,int count); - -#define wareki_face ((const watch_face_t){ \ - wareki_setup, \ - wareki_activate, \ - wareki_loop, \ - wareki_resign, \ - NULL, \ -}) - -#endif // WAREKI_FACE_H_ - diff --git a/movement_faces.h b/movement_faces.h index 9d3083c..e8fb0fe 100644 --- a/movement_faces.h +++ b/movement_faces.h @@ -62,6 +62,7 @@ #include "tally_face.h" #include "probability_face.h" #include "ke_decimal_time_face.h" +#include "wareki_face.h" #include "deadline_face.h" #include "wordle_face.h" // New includes go above this line. diff --git a/watch-faces.mk b/watch-faces.mk index 767e183..0c78fb4 100644 --- a/watch-faces.mk +++ b/watch-faces.mk @@ -38,5 +38,6 @@ SRCS += \ ./watch-faces/complication/kitchen_conversions_face.c \ ./watch-faces/complication/periodic_table_face.c \ ./watch-faces/clock/ke_decimal_time_face.c \ + ./watch-faces/complication/wareki_face.c \ ./watch-faces/complication/deadline_face.c \ # New watch faces go above this line. diff --git a/watch-faces/complication/wareki_face.c b/watch-faces/complication/wareki_face.c new file mode 100644 index 0000000..103a503 --- /dev/null +++ b/watch-faces/complication/wareki_face.c @@ -0,0 +1,293 @@ +/* + +The displayed Japanese Era can be changed by the buttons on the watch, making it also usable as a converter between the Gregorian calendar and the Japanese Era. + +Light button: Subtract one year from the Japanese Era. +Start/Stop button: Add one year to the Japanese Era. +Button operations support long-press functionality. + +Japanese Era Notations: + +r : REIWA (令和) +h : HEISEI (平成) +s : SHOWA(昭和) +*/ + +#include +#include +#include "wareki_face.h" +#include "filesystem.h" +#include "watch_utility.h" +#include "watch.h" + +//Long press status flag +static bool _alarm_button_press; +static bool _light_button_press; + + +void wareki_setup(uint8_t watch_face_index, void ** context_ptr) { + (void) watch_face_index; + + //printf("wareki_setup() \n"); + + if (*context_ptr == NULL) { + *context_ptr = malloc(sizeof(wareki_state_t)); + memset(*context_ptr, 0, sizeof(wareki_state_t)); + + //debug code + // watch_date_time datetime = watch_rtc_get_date_time(); + // datetime.unit.year = 2022 - WATCH_RTC_REFERENCE_YEAR; + // datetime.unit.month = 12; + // datetime.unit.day = 31; + // datetime.unit.hour = 23; + // datetime.unit.minute= 59; + // datetime.unit.second= 30; + // watch_rtc_set_date_time(datetime); + // settings->bit.clock_mode_24h = true; //24時間表記 + // settings->bit.to_interval = 1;//0=60sec 1=2m 2=5m 3=30m + // watch_store_backup_data(settings->reg, 0); + } +} + + +// splash view +static void draw_wareki_splash(wareki_state_t *state) { + (void) state; + + watch_clear_colon(); + + watch_display_text_with_fallback(WATCH_POSITION_TOP_LEFT, "WA ", "wa"); + watch_display_text(WATCH_POSITION_TOP_RIGHT, " "); + watch_display_text(WATCH_POSITION_BOTTOM, " "); +} + + +//draw year and Japanese wareki +static void draw_year_and_wareki(wareki_state_t *state) { + char buf[16]; + + bool is_custom_lcd = watch_get_lcd_type() == WATCH_LCD_TYPE_CUSTOM; + + if(state->disp_year == REIWA_GANNEN){ + //The first year of Reiwa (2019) began on May 1. The period before May 1 is Heisei 31. + //In other words, 2019 is Heisei Year 31 and it is possible that it is Reiwa Year 1. + watch_display_text_with_fallback(WATCH_POSITION_TOP_LEFT, "H31", " r"); + + if (is_custom_lcd) + { + //For custom LCDs, display both Heisei and Reiwa. + watch_display_text(WATCH_POSITION_TOP_RIGHT, "r1"); + } + else{ + watch_display_text(WATCH_POSITION_TOP_RIGHT, " 1"); + } + } + else if(state->disp_year == HEISEI_GANNEN){ + //The year 1989 could be Showa 64 or it could be Heisei 1. + watch_display_text_with_fallback(WATCH_POSITION_TOP_LEFT, "S64", " h"); + + if (is_custom_lcd) + { + //For custom LCDs, display both Showa and Heisei. + watch_display_text(WATCH_POSITION_TOP_RIGHT, "h1"); + } + else{ + watch_display_text(WATCH_POSITION_TOP_RIGHT, " 1"); + } + } + else if(state->disp_year < HEISEI_GANNEN){ + //Showa + //sprintf(buf, " h%2d%4d ", (int)state->disp_year - HEISEI_GANNEN + 1, (int)state->disp_year); + + watch_display_text_with_fallback(WATCH_POSITION_TOP_LEFT, "Sho", "s "); + + sprintf(buf, "%2d", (int)state->disp_year - SHOWA_GANNEN + 1); + watch_display_text(WATCH_POSITION_TOP_RIGHT, buf); + } + else if(state->disp_year < REIWA_GANNEN){ + //Heisei + //sprintf(buf, " h%2d%4d ", (int)state->disp_year - HEISEI_GANNEN + 1, (int)state->disp_year); + + watch_display_text_with_fallback(WATCH_POSITION_TOP_LEFT, "HEI", "h "); + + sprintf(buf, "%2d", (int)state->disp_year - HEISEI_GANNEN + 1); + watch_display_text(WATCH_POSITION_TOP_RIGHT, buf); + } + else{ + //Reiwa + //sprintf(buf, " r%2d%4d ", (int)state->disp_year - REIWA_GANNEN + 1 , (int)state->disp_year); + + watch_display_text_with_fallback(WATCH_POSITION_TOP_LEFT, "REI", "r "); + + sprintf(buf, "%2d", (int)state->disp_year - REIWA_GANNEN + 1); + watch_display_text(WATCH_POSITION_TOP_RIGHT, buf); + } + + sprintf(buf, "%4d ",(int)state->disp_year); + watch_display_text(WATCH_POSITION_BOTTOM, buf); +} + + +void wareki_activate(void *context) { + + //printf("wareki_activate() \n"); + + wareki_state_t *state = (wareki_state_t *)context; + + if (watch_sleep_animation_is_running()) watch_stop_sleep_animation(); + + state->active = false; + + _alarm_button_press = false; + _light_button_press = false; + + state->real_year = watch_rtc_get_date_time().unit.year + WATCH_RTC_REFERENCE_YEAR; + state->start_year = state->real_year; + state->disp_year = state->real_year; + + movement_request_tick_frequency(1); +} + + +void addYear(wareki_state_t* state,int count){ + + state->disp_year = state->disp_year + count; + + if(state->disp_year > REIWA_LIMIT ){ + state->disp_year = REIWA_LIMIT; + } + else{ + } +} + + +void subYear(wareki_state_t* state,int count){ + + state->disp_year = state->disp_year - count; + + if(state->disp_year < SHOWA_GANNEN ){ + state->disp_year = SHOWA_GANNEN; + } + else{ + } +} + + +bool wareki_loop(movement_event_t event, void *context) { + wareki_state_t *state = (wareki_state_t *)context; + + state->real_year = watch_rtc_get_date_time().unit.year + WATCH_RTC_REFERENCE_YEAR; + + if( state->real_year != state->start_year ){ + state->start_year = state->real_year; + state->disp_year = state->real_year; + } + + + switch (event.event_type) { + case EVENT_ACTIVATE: + draw_wareki_splash(state); + break; + case EVENT_MODE_BUTTON_UP: + movement_move_to_next_face(); + break; + + case EVENT_LOW_ENERGY_UPDATE: + case EVENT_TICK: + + //printf("tick %d\n",state->disp_year ); + + if (_alarm_button_press && HAL_GPIO_BTN_ALARM_pin() ){ + //printf("ALARM ON\n"); + } + else{ + //printf("ALARM OFF\n"); + _alarm_button_press = false; + } + + + if (_light_button_press && HAL_GPIO_BTN_LIGHT_pin()){ + //printf("LIGHT ON\n"); + } + else{ + //printf("LIGHT OFF\n"); + _light_button_press = false; + } + + if (_alarm_button_press) { + addYear(state,1); + } + if (_light_button_press) { + subYear(state,1); + } + + draw_year_and_wareki(state); + + break; + + case EVENT_LIGHT_BUTTON_DOWN: + //printf("LIGHT DOWN\n"); + subYear(state,1); + break; + case EVENT_LIGHT_LONG_PRESS: + //printf("LIGHTPRESS \n"); + _light_button_press = true; + movement_request_tick_frequency(8); + break; + case EVENT_LIGHT_LONG_UP: + //printf("LIGHTPRESS UP\n"); + _light_button_press = false; + movement_request_tick_frequency(4); + break; + case EVENT_LIGHT_BUTTON_UP: + //printf("LIGHT UP\n"); + _light_button_press = false; + movement_request_tick_frequency(4); + break; + case EVENT_ALARM_BUTTON_DOWN: + //printf("ALARM DOWN\n"); + addYear(state,1); + break; + case EVENT_ALARM_LONG_PRESS: + //printf("LONGPRESS \n"); + _alarm_button_press = true; + movement_request_tick_frequency(8); + break; + case EVENT_ALARM_LONG_UP: + //printf("LONGPRESS UP\n"); + _alarm_button_press = false; + movement_request_tick_frequency(4); + break; + case EVENT_ALARM_BUTTON_UP: + //printf("ALARM UP\n"); + movement_request_tick_frequency(4); + break; + + case EVENT_TIMEOUT: + //printf("time out ! \n"); + 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 movement_default_loop_handler(event); + } + + return true; +} + +void wareki_resign(void *context) { + (void) context; +} + diff --git a/watch-faces/complication/wareki_face.h b/watch-faces/complication/wareki_face.h new file mode 100644 index 0000000..070642e --- /dev/null +++ b/watch-faces/complication/wareki_face.h @@ -0,0 +1,35 @@ +#ifndef WAREKI_FACE_H_ +#define WAREKI_FACE_H_ + +#include "movement.h" + +#define REIWA_LIMIT 2018 + 99 +#define REIWA_GANNEN 2019 +#define HEISEI_GANNEN 1989 +#define SHOWA_GANNEN 1926 + +typedef struct { + bool active; + uint32_t disp_year; //Current displayed year + uint32_t start_year; //Year when this screen was launched + uint32_t real_year; //The actual current year +} wareki_state_t; + +void wareki_setup(uint8_t watch_face_index, void ** context_ptr); +void wareki_activate(void *context); +bool wareki_loop(movement_event_t event, void *context); +void wareki_resign(void *context); + +void addYear(wareki_state_t* state,int count); +void subYear(wareki_state_t* state,int count); + +#define wareki_face ((const watch_face_t){ \ + wareki_setup, \ + wareki_activate, \ + wareki_loop, \ + wareki_resign, \ + NULL, \ +}) + +#endif // WAREKI_FACE_H_ +