diff options
author | tslil clingman <tslil@posteo.de> | 2023-01-28 11:52:27 +0100 |
---|---|---|
committer | joeycastillo <joeycastillo@utexas.edu> | 2023-02-10 16:09:55 -0600 |
commit | f571da434607b50ea5a829f8fdb6cdadfeb0c2a4 (patch) | |
tree | 91d239e1604883c7f81c4bac9c00487b4afeecea | |
parent | eca75cfb2387464ecce93e8f2527839ba66c81bf (diff) | |
download | Sensor-Watch-f571da434607b50ea5a829f8fdb6cdadfeb0c2a4.tar.gz Sensor-Watch-f571da434607b50ea5a829f8fdb6cdadfeb0c2a4.tar.bz2 Sensor-Watch-f571da434607b50ea5a829f8fdb6cdadfeb0c2a4.zip |
habit face
Track a single habit, occuring at most once per day, with an eight-day
look back and total count
-rw-r--r-- | movement/make/Makefile | 1 | ||||
-rw-r--r-- | movement/movement_faces.h | 1 | ||||
-rw-r--r-- | movement/watch_faces/complication/habit_face.c | 157 | ||||
-rw-r--r-- | movement/watch_faces/complication/habit_face.h | 53 |
4 files changed, 212 insertions, 0 deletions
diff --git a/movement/make/Makefile b/movement/make/Makefile index 58895862..6865960c 100644 --- a/movement/make/Makefile +++ b/movement/make/Makefile @@ -96,6 +96,7 @@ SRCS += \ ../watch_faces/complication/morsecalc_face.c \ ../watch_faces/complication/rpn_calculator_face.c \ ../watch_faces/complication/ships_bell_face.c \ + ../watch_faces/complication/habit_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 806e82a5..901260eb 100644 --- a/movement/movement_faces.h +++ b/movement/movement_faces.h @@ -74,6 +74,7 @@ #include "morsecalc_face.h" #include "rpn_calculator_face.h" #include "ships_bell_face.h" +#include "habit_face.h" // New includes go above this line. #endif // MOVEMENT_FACES_H_ diff --git a/movement/watch_faces/complication/habit_face.c b/movement/watch_faces/complication/habit_face.c new file mode 100644 index 00000000..ffc1e94a --- /dev/null +++ b/movement/watch_faces/complication/habit_face.c @@ -0,0 +1,157 @@ +/* + * MIT License + * + * Copyright (c) 2023 tslil clingman + * + * 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 "habit_face.h" +#include "watch_private_display.h" +#include "watch_rtc.h" +#include "watch_slcd.h" +#include "watch_utility.h" +#include <stdlib.h> +#include <string.h> + +static inline uint32_t today_unix(const uint32_t utc_offset) { + const watch_date_time dt = watch_rtc_get_date_time(); + return watch_utility_convert_to_unix_time(dt.unit.year + 2020, dt.unit.month, + dt.unit.day, 0, 0, 0, utc_offset); +} + +static inline uint32_t days_since_unix(const uint32_t since, + const uint32_t until) { + return (until - since) / (60 * 60 * 24); +} + +typedef struct { + uint16_t total_count; + uint8_t lookback; + uint32_t last_update; + bool display_total; +} habit_state_t; + +void habit_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(habit_state_t)); + memset(*context_ptr, 0, sizeof(habit_state_t)); + habit_state_t *state = (habit_state_t *)*context_ptr; + state->lookback = 0; + state->last_update = watch_utility_offset_timestamp( + today_unix(settings->bit.time_zone), -24, 0, 0); + } +} + +static inline void display_state(habit_state_t *state) { + const bool can_do = (state->lookback & 1) == 0; + char buf[16]; + + if (can_do) { + watch_clear_indicator(WATCH_INDICATOR_LAP); + } else { + watch_set_indicator(WATCH_INDICATOR_LAP); + } + + if (state->display_total) { + sprintf(buf, "HA %03dtot", state->total_count); + watch_display_string(buf, 0); + } else { + sprintf(buf, "HA d%c", can_do ? 'o' : 'n'); + uint8_t copy = state->lookback; + for (uint8_t c = 0; copy; copy >>= 2, c++) { + switch (copy & 3) { + case 0: + break; + case 1: + buf[4 + c] = 'I'; + break; + case 2: + buf[4 + c] = '1'; + break; + case 3: + buf[4 + c] = '|'; + break; + } + } + watch_display_string(buf, 0); + if (can_do) { + const uint64_t segmap = Segment_Map[4] >> 48; + watch_set_pixel((segmap & 0xFF) >> 6, segmap & 0x3F); + } + } +} + +void habit_face_activate(movement_settings_t *settings, void *context) { + (void)settings; + habit_state_t *state = (habit_state_t *)context; + display_state(state); +} + +bool habit_face_loop(movement_event_t event, movement_settings_t *settings, + void *context) { + habit_state_t *state = (habit_state_t *)context; + + const uint32_t today_now_unix = today_unix(settings->bit.time_zone); + const bool can_do = (state->lookback & 1) == 0; + + switch (event.event_type) { + case EVENT_ACTIVATE: + case EVENT_TICK: { + display_state(state); + if (today_now_unix > state->last_update) { + uint8_t num_shifts = days_since_unix(state->last_update, today_now_unix); + if (num_shifts > 7) + num_shifts = 7; + state->lookback <<= num_shifts; + state->last_update = today_now_unix; + } + break; + } + case EVENT_LIGHT_BUTTON_UP: { + state->display_total = !state->display_total; + display_state(state); + break; + } + case EVENT_ALARM_BUTTON_UP: { + if (can_do) { + state->lookback |= 1; + state->total_count++; + state->last_update = today_now_unix; + display_state(state); + }; + break; + } + case EVENT_TIMEOUT: { + movement_move_to_face(0); + break; + } + default: + return movement_default_loop_handler(event, settings); + } + return true; +} + +void habit_face_resign(movement_settings_t *settings, void *context) { + (void)settings; + (void)context; +} diff --git a/movement/watch_faces/complication/habit_face.h b/movement/watch_faces/complication/habit_face.h new file mode 100644 index 00000000..80a4884f --- /dev/null +++ b/movement/watch_faces/complication/habit_face.h @@ -0,0 +1,53 @@ +/* + * MIT License + * + * Copyright (c) 2023 tslil clingman + * + * 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 HABIT_FACE_H_ +#define HABIT_FACE_H_ + +#include "movement.h" + +/* + * Habit tracking face + * + * Allows the user to record a single succesful instance of a particular habit + * occuring per day, and displays history for eight days prior as well as a + * total counter. + * + */ + +void habit_face_setup(movement_settings_t *settings, uint8_t watch_face_index, + void **context_ptr); +void habit_face_activate(movement_settings_t *settings, void *context); +bool habit_face_loop(movement_event_t event, movement_settings_t *settings, void *context); +void habit_face_resign(movement_settings_t *settings, void *context); + +#define habit_face ((const watch_face_t){ \ + habit_face_setup, \ + habit_face_activate, \ + habit_face_loop, \ + habit_face_resign, \ + NULL, \ +}) + +#endif // HABIT_FACE_H_ |