diff options
| author | Joey Castillo <jose.castillo@gmail.com> | 2021-11-26 13:43:47 -0500 | 
|---|---|---|
| committer | Joey Castillo <jose.castillo@gmail.com> | 2021-11-26 13:43:47 -0500 | 
| commit | 002d368a25914527015f63967421fd0e7c5bda17 (patch) | |
| tree | 81f95271cb047988bc00221291b654232a5f2278 | |
| parent | 4a4ab81c6c11bc159796992590646d9ef8de5f1b (diff) | |
| download | Sensor-Watch-002d368a25914527015f63967421fd0e7c5bda17.tar.gz Sensor-Watch-002d368a25914527015f63967421fd0e7c5bda17.tar.bz2 Sensor-Watch-002d368a25914527015f63967421fd0e7c5bda17.zip  | |
movement: add world clock face
| -rwxr-xr-x | movement/make/Makefile | 1 | ||||
| -rw-r--r-- | movement/movement.c | 3 | ||||
| -rw-r--r-- | movement/movement.h | 2 | ||||
| -rw-r--r-- | movement/movement_config.h | 1 | ||||
| -rw-r--r-- | movement/watch_faces/clock/world_clock_face.c | 188 | ||||
| -rw-r--r-- | movement/watch_faces/clock/world_clock_face.h | 33 | 
6 files changed, 228 insertions, 0 deletions
diff --git a/movement/make/Makefile b/movement/make/Makefile index 4c895322..1118da5d 100755 --- a/movement/make/Makefile +++ b/movement/make/Makefile @@ -29,6 +29,7 @@ SRCS += \    ../lib/TOTP-MCU/TOTP.c \    ../movement.c \    ../watch_faces/clock/simple_clock_face.c \ +  ../watch_faces/clock/world_clock_face.c \    ../watch_faces/settings/preferences_face.c \    ../watch_faces/settings/set_time_face.c \    ../watch_faces/complications/pulsometer_face.c \ diff --git a/movement/movement.c b/movement/movement.c index 128011b9..2c8169b9 100644 --- a/movement/movement.c +++ b/movement/movement.c @@ -55,6 +55,9 @@ const int16_t movement_timezone_offsets[] = {      840,    // 40 :  14:00:00 (Line Islands Time)  }; +const char movement_valid_position_0_chars[] = " AaBbCcDdEeFGgHhIiJKLMNnOoPQrSTtUuWXYZ-='+\\/0123456789"; +const char movement_valid_position_1_chars[] = " ABCDEFHlJLNORTtUX-='01378"; +  void cb_mode_btn_interrupt();  void cb_light_btn_interrupt();  void cb_alarm_btn_interrupt(); diff --git a/movement/movement.h b/movement/movement.h index 0379fe7b..5c1f0dfa 100644 --- a/movement/movement.h +++ b/movement/movement.h @@ -98,6 +98,8 @@ typedef struct {  } movement_event_t;  extern const int16_t movement_timezone_offsets[]; +extern const char movement_valid_position_0_chars[]; +extern const char movement_valid_position_1_chars[];  /** @brief Perform setup for your watch face.    * @details It's tempting to say this is 'one-time' setup, but technically this function is called more than diff --git a/movement/movement_config.h b/movement/movement_config.h index 8802883d..ecf02bbf 100644 --- a/movement/movement_config.h +++ b/movement/movement_config.h @@ -2,6 +2,7 @@  #define MOVEMENT_CONFIG_H_  #include "simple_clock_face.h" +#include "world_clock_face.h"  #include "preferences_face.h"  #include "set_time_face.h"  #include "pulsometer_face.h" diff --git a/movement/watch_faces/clock/world_clock_face.c b/movement/watch_faces/clock/world_clock_face.c new file mode 100644 index 00000000..3cb094ba --- /dev/null +++ b/movement/watch_faces/clock/world_clock_face.c @@ -0,0 +1,188 @@ +#include <stdlib.h> +#include <string.h> +#include "world_clock_face.h" +#include "watch.h" +#include "watch_utility.h" + +void world_clock_face_setup(movement_settings_t *settings, void ** context_ptr) { +    (void) settings; +    if (*context_ptr == NULL) { +        *context_ptr = malloc(sizeof(world_clock_state_t)); +        world_clock_state_t *state = (world_clock_state_t *)*context_ptr; +        state->settings.char_0 = 0; +        state->settings.char_1 = 0; +        state->settings.timezone_index = 16; // start at UTC +    } +} + +void world_clock_face_activate(movement_settings_t *settings, void *context) { +    world_clock_state_t *state = (world_clock_state_t *)context; +    state->current_screen = 0; +    state->previous_date_time = 0xFFFFFFFF; + +    if (watch_tick_animation_is_running()) watch_stop_tick_animation(); +    if (settings->bit.clock_mode_24h) watch_set_indicator(WATCH_INDICATOR_24H); + +    watch_set_colon(); +} + +bool world_clock_face_do_display_mode(movement_event_t event, movement_settings_t *settings, world_clock_state_t *state) { +    char buf[11]; +    uint8_t pos; + +    uint32_t timestamp; +    uint32_t previous_date_time; +    watch_date_time date_time; +    switch (event.event_type) { +        case EVENT_ACTIVATE: +        case EVENT_TICK: +        case EVENT_LOW_ENERGY_UPDATE: +            // TODO: profile this, does this chew up power? feels like a lot of cycles to run every second. +            date_time = watch_rtc_get_date_time(); +            timestamp = watch_utility_date_time_to_unix_time(date_time, movement_timezone_offsets[settings->bit.time_zone] * 60); +            date_time = watch_utility_date_time_from_unix_time(timestamp, movement_timezone_offsets[state->settings.timezone_index] * 60); +            previous_date_time = state->previous_date_time; +            state->previous_date_time = date_time.reg; + +            if (date_time.reg >> 6 == previous_date_time >> 6 && event.event_type != EVENT_LOW_ENERGY_UPDATE) { +                // everything before seconds is the same, don't waste cycles setting those segments. +                pos = 8; +                sprintf(buf, "%02d", date_time.unit.second); +            } else 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, date_time.unit.second); +            } 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, "%c%c%2d%2d%02d  ", +                        movement_valid_position_0_chars[state->settings.char_0], +                        movement_valid_position_1_chars[state->settings.char_1], +                        date_time.unit.day, +                        date_time.unit.hour, +                        date_time.unit.minute); +                } else { +                    sprintf(buf, "%c%c%2d%2d%02d%02d", +                        movement_valid_position_0_chars[state->settings.char_0], +                        movement_valid_position_1_chars[state->settings.char_1], +                        date_time.unit.day, +                        date_time.unit.hour, +                        date_time.unit.minute, +                        date_time.unit.second); +                } +            } +            watch_display_string(buf, pos); +            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: +            movement_request_tick_frequency(4); +            state->current_screen = 1; +            break; +        default: +            break; +    } + +    return true; +} + +bool world_clock_face_do_settings_mode(movement_event_t event, movement_settings_t *settings, world_clock_state_t *state) { +    switch (event.event_type) { +        case EVENT_MODE_BUTTON_UP: +            movement_move_to_next_face(); +            return false; +        case EVENT_LIGHT_BUTTON_DOWN: +            state->current_screen++; +            if (state->current_screen > 3) { +                movement_request_tick_frequency(1); +                state->current_screen = 0; +                state->previous_date_time = 0xFFFFFFFF; +                world_clock_face_do_display_mode(event, settings, state); +            } +            break; +        case EVENT_ALARM_BUTTON_DOWN: +            switch (state->current_screen) { +                case 1: +                    state->settings.char_0++; +                    if (state->settings.char_0 >= strlen(movement_valid_position_0_chars)) { +                        state->settings.char_0 = 0; +                    } +                    break; +                case 2: +                    state->settings.char_1++; +                    if (state->settings.char_1 >= strlen(movement_valid_position_1_chars)) { +                        state->settings.char_1 = 0; +                    } +                    break; +                case 3: +                    state->settings.timezone_index++; +                    if (state->settings.timezone_index > 40) state->settings.timezone_index = 0; +                    break; +            } +            break; +        case EVENT_TIMEOUT: +            movement_move_to_face(0); +            break; +        default: +            break; +    } + +    char buf[13]; +    sprintf(buf, "%c%c %3d%02d  ", +        movement_valid_position_0_chars[state->settings.char_0], +        movement_valid_position_1_chars[state->settings.char_1], +        (int8_t) (movement_timezone_offsets[state->settings.timezone_index] / 60), +        (int8_t) (movement_timezone_offsets[state->settings.timezone_index] % 60) * (movement_timezone_offsets[state->settings.timezone_index] < 0 ? -1 : 1)); +    watch_set_colon(); +    watch_clear_indicator(WATCH_INDICATOR_PM); + +    // blink up the parameter we're setting +    if (event.subsecond % 2) { +        switch (state->current_screen) { +            case 1: +            case 2: +                buf[state->current_screen - 1] = '_'; +                break; +            case 3: +                watch_clear_colon(); +                sprintf(buf + 3, "       "); +                break; +        } +    } + +    watch_display_string(buf, 0); + +    return true; +} + +bool world_clock_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { +    world_clock_state_t *state = (world_clock_state_t *)context; + +    if (state->current_screen == 0) { +        return world_clock_face_do_display_mode(event, settings, state); +    } else { +        return world_clock_face_do_settings_mode(event, settings, state); +    } +} + +void world_clock_face_resign(movement_settings_t *settings, void *context) { +    (void) settings; +    (void) context; +    movement_request_tick_frequency(1); +} diff --git a/movement/watch_faces/clock/world_clock_face.h b/movement/watch_faces/clock/world_clock_face.h new file mode 100644 index 00000000..1c4525a4 --- /dev/null +++ b/movement/watch_faces/clock/world_clock_face.h @@ -0,0 +1,33 @@ +#ifndef WORLD_CLOCK_FACE_H_ +#define WORLD_CLOCK_FACE_H_ + +#include "movement.h" + +typedef struct { +    uint8_t char_0; +    uint8_t char_1; +    uint8_t timezone_index; +} world_clock_settings_t; + +typedef struct { +    world_clock_settings_t settings; +    uint8_t current_screen; +    uint32_t previous_date_time; +} world_clock_state_t; + +void world_clock_face_setup(movement_settings_t *settings, void ** context_ptr); +void world_clock_face_activate(movement_settings_t *settings, void *context); +bool world_clock_face_loop(movement_event_t event, movement_settings_t *settings, void *context); +void world_clock_face_resign(movement_settings_t *settings, void *context); + +uint8_t world_clock_face_get_weekday(uint16_t day, uint16_t month, uint16_t year); + +static const watch_face_t world_clock_face = { +    world_clock_face_setup, +    world_clock_face_activate, +    world_clock_face_loop, +    world_clock_face_resign, +    NULL +}; + +#endif // WORLD_CLOCK_FACE_H_  | 
