From: voloved <36523934+voloved@users.noreply.github.com> Date: Sun, 6 Jul 2025 19:33:56 +0000 (-0400) Subject: Tally face port (#38) X-Git-Url: https://git.earman.xyz/?a=commitdiff_plain;h=4e710066b9de1de07fe21d563bbe164020d110db;p=sensor-watch.git Tally face port (#38) * Moved tally face over * Bugfix on tally_face_should_move_back * changed watch_display_text logic * Negative numbers don't appear small * remove tally face from movement_config.h --- diff --git a/legacy/watch_faces/complication/tally_face.c b/legacy/watch_faces/complication/tally_face.c deleted file mode 100644 index 128e84a..0000000 --- a/legacy/watch_faces/complication/tally_face.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2022 Andrew Mike - * - * 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 "tally_face.h" -#include "watch.h" - -#define TALLY_FACE_MAX 9999 -#define TALLY_FACE_MIN -99 - -static bool _init_val; -static bool _quick_ticks_running; - -static const int16_t _tally_default[] = { - 0, - -#ifdef TALLY_FACE_PRESETS_MTG - 20, - 40, -#endif /* TALLY_FACE_PRESETS_MTG */ - -#ifdef TALLY_FACE_PRESETS_YUGIOH - 4000, - 8000, -#endif /* TALLY_FACE_PRESETS_YUGIOH */ - -}; - -#define TALLY_FACE_PRESETS_SIZE() (sizeof(_tally_default) / sizeof(int16_t)) - -void tally_face_setup(uint8_t watch_face_index, void ** context_ptr) { - (void) watch_face_index; - if (*context_ptr == NULL) { - *context_ptr = malloc(sizeof(tally_state_t)); - memset(*context_ptr, 0, sizeof(tally_state_t)); - tally_state_t *state = (tally_state_t *)*context_ptr; - state->tally_default_idx = 0; - state->tally_idx = _tally_default[state->tally_default_idx]; - _init_val = true; - } -} - -void tally_face_activate(void *context) { - (void) context; - _quick_ticks_running = false; -} - -static void start_quick_cyc(void){ - _quick_ticks_running = true; - movement_request_tick_frequency(8); -} - -static void stop_quick_cyc(void){ - _quick_ticks_running = false; - movement_request_tick_frequency(1); -} - -static void tally_face_increment(tally_state_t *state, bool sound_on) { - bool soundOn = !_quick_ticks_running && sound_on; - _init_val = false; - if (state->tally_idx >= TALLY_FACE_MAX){ - if (soundOn) watch_buzzer_play_note(BUZZER_NOTE_E7, 30); - } - else { - state->tally_idx++; - print_tally(state, sound_on); - if (soundOn) watch_buzzer_play_note(BUZZER_NOTE_E6, 30); - } -} - -static void tally_face_decrement(tally_state_t *state, bool sound_on) { - bool soundOn = !_quick_ticks_running && sound_on; - _init_val = false; - if (state->tally_idx <= TALLY_FACE_MIN){ - if (soundOn) watch_buzzer_play_note(BUZZER_NOTE_C5SHARP_D5FLAT, 30); - } - else { - state->tally_idx--; - print_tally(state, sound_on); - if (soundOn) watch_buzzer_play_note(BUZZER_NOTE_C6SHARP_D6FLAT, 30); - } -} - -static bool tally_face_should_move_back(tally_state_t *state) { - if (TALLY_FACE_PRESETS_SIZE() <= 1) { return false; } - return state->tally_idx == _tally_default[state->tally_default_idx]; -} - -bool tally_face_loop(movement_event_t event, void *context) { - tally_state_t *state = (tally_state_t *)context; - static bool using_led = false; - - if (using_led) { - if(!HAL_GPIO_BTN_MODE_read() && !HAL_GPIO_BTN_LIGHT_read() && !HAL_GPIO_BTN_ALARM_read()) - using_led = false; - else { - if (event.event_type == EVENT_LIGHT_BUTTON_DOWN || event.event_type == EVENT_ALARM_BUTTON_DOWN) - movement_illuminate_led(); - return true; - } - } - - switch (event.event_type) { - case EVENT_TICK: - if (_quick_ticks_running) { - bool light_pressed = HAL_GPIO_BTN_LIGHT_read(); - bool alarm_pressed = HAL_GPIO_BTN_ALARM_read(); - if (light_pressed && alarm_pressed) stop_quick_cyc(); - else if (light_pressed) tally_face_increment(state, movement_button_should_sound()); - else if (alarm_pressed) tally_face_decrement(state, movement_button_should_sound()); - else stop_quick_cyc(); - } - break; - case EVENT_ALARM_BUTTON_UP: - tally_face_decrement(state, movement_button_should_sound()); - break; - case EVENT_ALARM_LONG_PRESS: - tally_face_decrement(state, movement_button_should_sound()); - start_quick_cyc(); - break; - case EVENT_MODE_LONG_PRESS: - if (tally_face_should_move_back(state)) { - _init_val = true; - movement_move_to_face(0); - } - else { - state->tally_idx = _tally_default[state->tally_default_idx]; // reset tally index - _init_val = true; - //play a reset tune - if (movement_button_should_sound()) watch_buzzer_play_note(BUZZER_NOTE_G6, 30); - if (movement_button_should_sound()) watch_buzzer_play_note(BUZZER_NOTE_REST, 30); - if (movement_button_should_sound()) watch_buzzer_play_note(BUZZER_NOTE_E6, 30); - print_tally(state, movement_button_should_sound()); - } - break; - case EVENT_LIGHT_BUTTON_UP: - tally_face_increment(state, movement_button_should_sound()); - break; - case EVENT_LIGHT_BUTTON_DOWN: - case EVENT_ALARM_BUTTON_DOWN: - if (HAL_GPIO_BTN_MODE_read()) { - movement_illuminate_led(); - using_led = true; - } - break; - case EVENT_LIGHT_LONG_PRESS: - if (TALLY_FACE_PRESETS_SIZE() > 1 && _init_val){ - state->tally_default_idx = (state->tally_default_idx + 1) % TALLY_FACE_PRESETS_SIZE(); - state->tally_idx = _tally_default[state->tally_default_idx]; - if (movement_button_should_sound()) watch_buzzer_play_note(BUZZER_NOTE_E6, 30); - if (movement_button_should_sound()) watch_buzzer_play_note(BUZZER_NOTE_REST, 30); - if (movement_button_should_sound()) watch_buzzer_play_note(BUZZER_NOTE_G6, 30); - print_tally(state, movement_button_should_sound()); - } - else{ - tally_face_increment(state, movement_button_should_sound()); - start_quick_cyc(); - } - break; - case EVENT_ACTIVATE: - print_tally(state, movement_button_should_sound()); - break; - case EVENT_TIMEOUT: - // ignore timeout - break; - default: - movement_default_loop_handler(event); - break; - } - - return true; -} - -// print tally index at the center of display. -void print_tally(tally_state_t *state, bool sound_on) { - char buf[14]; - if (sound_on) - watch_set_indicator(WATCH_INDICATOR_BELL); - else - watch_clear_indicator(WATCH_INDICATOR_BELL); - if (state->tally_idx >= 0) - sprintf(buf, "TA %4d ", (int)(state->tally_idx)); // center of LCD display - else - sprintf(buf, "TA %-3d", (int)(state->tally_idx)); // center of LCD display - watch_display_string(buf, 0); -} - -void tally_face_resign(void *context) { - (void) context; -} diff --git a/legacy/watch_faces/complication/tally_face.h b/legacy/watch_faces/complication/tally_face.h deleted file mode 100644 index 7b18a33..0000000 --- a/legacy/watch_faces/complication/tally_face.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2022 Andrew Mike - * - * 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 TALLY_FACE_H_ -#define TALLY_FACE_H_ - -/* - * TALLY face - * - * Tally face is designed to act as a tally counter. - * - * Alarm - * Press: Decrement - * Hold : Fast Decrement - * - * Light - * Press: Increment - * Hold : On initial value: Cycles through other initial values. - * Else: Fast Increment - * - * Mode - * Press: Next face - * Hold : On initial value: Go to first face. - * Else: Resets counter - * - * Incrementing or Decrementing the tally will beep if Beeping is set in the global Preferences - */ - -#include "movement.h" - -typedef struct { - int16_t tally_idx; - uint8_t tally_default_idx; -} tally_state_t; - -//#define TALLY_FACE_PRESETS_MTG -//#define TALLY_FACE_PRESETS_YUGIOH - - -void tally_face_setup(uint8_t watch_face_index, void ** context_ptr); -void tally_face_activate(void *context); -bool tally_face_loop(movement_event_t event, void *context); -void tally_face_resign(void *context); - -void print_tally(tally_state_t *state, bool sound_on); - -#define tally_face ((const watch_face_t){ \ - tally_face_setup, \ - tally_face_activate, \ - tally_face_loop, \ - tally_face_resign, \ - NULL, \ -}) - -#endif // TALLY_FACE_H_ diff --git a/movement_faces.h b/movement_faces.h index 4cac85e..f5c087b 100644 --- a/movement_faces.h +++ b/movement_faces.h @@ -59,5 +59,6 @@ #include "periodic_table_face.h" #include "squash_face.h" #include "totp_face.h" +#include "tally_face.h" #include "probability_face.h" // New includes go above this line. diff --git a/watch-faces.mk b/watch-faces.mk index 1bc3f84..665ec4b 100644 --- a/watch-faces.mk +++ b/watch-faces.mk @@ -15,6 +15,7 @@ SRCS += \ ./watch-faces/complication/breathing_face.c \ ./watch-faces/complication/squash_face.c \ ./watch-faces/complication/totp_face.c \ + ./watch-faces/complication/tally_face.c \ ./watch-faces/demo/all_segments_face.c \ ./watch-faces/demo/character_set_face.c \ ./watch-faces/demo/light_sensor_face.c \ diff --git a/watch-faces/complication/tally_face.c b/watch-faces/complication/tally_face.c new file mode 100644 index 0000000..c2d202e --- /dev/null +++ b/watch-faces/complication/tally_face.c @@ -0,0 +1,209 @@ +/* + * MIT License + * + * Copyright (c) 2022-2025 Andrew Mike and David Volovskiy + * + * 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 "tally_face.h" +#include "watch.h" + +#define TALLY_FACE_MAX 9999 +#define TALLY_FACE_MIN -999 + +static bool _init_val; +static bool _quick_ticks_running; + +static const int16_t _tally_default[] = { + 0, + +#ifdef TALLY_FACE_PRESETS_MTG + 20, + 40, +#endif /* TALLY_FACE_PRESETS_MTG */ + +#ifdef TALLY_FACE_PRESETS_YUGIOH + 4000, + 8000, +#endif /* TALLY_FACE_PRESETS_YUGIOH */ + +}; + +#define TALLY_FACE_PRESETS_SIZE() (sizeof(_tally_default) / sizeof(int16_t)) + +void tally_face_setup(uint8_t watch_face_index, void ** context_ptr) { + (void) watch_face_index; + if (*context_ptr == NULL) { + *context_ptr = malloc(sizeof(tally_state_t)); + memset(*context_ptr, 0, sizeof(tally_state_t)); + tally_state_t *state = (tally_state_t *)*context_ptr; + state->tally_default_idx = 0; + state->tally_idx = _tally_default[state->tally_default_idx]; + _init_val = true; + } +} + +void tally_face_activate(void *context) { + (void) context; + _quick_ticks_running = false; +} + +static void start_quick_cyc(void){ + _quick_ticks_running = true; + movement_request_tick_frequency(8); +} + +static void stop_quick_cyc(void){ + _quick_ticks_running = false; + movement_request_tick_frequency(1); +} + +static void tally_face_increment(tally_state_t *state, bool sound_on) { + bool soundOn = !_quick_ticks_running && sound_on; + _init_val = false; + if (state->tally_idx >= TALLY_FACE_MAX){ + if (soundOn) watch_buzzer_play_note(BUZZER_NOTE_E7, 30); + } + else { + state->tally_idx++; + print_tally(state, sound_on); + if (soundOn) watch_buzzer_play_note(BUZZER_NOTE_E6, 30); + } +} + +static void tally_face_decrement(tally_state_t *state, bool sound_on) { + bool soundOn = !_quick_ticks_running && sound_on; + _init_val = false; + if (state->tally_idx <= TALLY_FACE_MIN){ + if (soundOn) watch_buzzer_play_note(BUZZER_NOTE_C5SHARP_D5FLAT, 30); + } + else { + state->tally_idx--; + print_tally(state, sound_on); + if (soundOn) watch_buzzer_play_note(BUZZER_NOTE_C6SHARP_D6FLAT, 30); + } +} + +static bool tally_face_should_move_back(tally_state_t *state) { + return state->tally_idx == _tally_default[state->tally_default_idx]; +} + +bool tally_face_loop(movement_event_t event, void *context) { + tally_state_t *state = (tally_state_t *)context; + static bool using_led = false; + + if (using_led) { + if(!HAL_GPIO_BTN_MODE_read() && !HAL_GPIO_BTN_LIGHT_read() && !HAL_GPIO_BTN_ALARM_read()) + using_led = false; + else { + if (event.event_type == EVENT_LIGHT_BUTTON_DOWN || event.event_type == EVENT_ALARM_BUTTON_DOWN) + movement_illuminate_led(); + return true; + } + } + + switch (event.event_type) { + case EVENT_TICK: + if (_quick_ticks_running) { + bool light_pressed = HAL_GPIO_BTN_LIGHT_read(); + bool alarm_pressed = HAL_GPIO_BTN_ALARM_read(); + if (light_pressed && alarm_pressed) stop_quick_cyc(); + else if (light_pressed) tally_face_increment(state, movement_button_should_sound()); + else if (alarm_pressed) tally_face_decrement(state, movement_button_should_sound()); + else stop_quick_cyc(); + } + break; + case EVENT_ALARM_BUTTON_UP: + tally_face_decrement(state, movement_button_should_sound()); + break; + case EVENT_ALARM_LONG_PRESS: + tally_face_decrement(state, movement_button_should_sound()); + start_quick_cyc(); + break; + case EVENT_MODE_LONG_PRESS: + if (tally_face_should_move_back(state)) { + _init_val = true; + movement_move_to_face(0); + } + else { + state->tally_idx = _tally_default[state->tally_default_idx]; // reset tally index + _init_val = true; + //play a reset tune + if (movement_button_should_sound()) watch_buzzer_play_note(BUZZER_NOTE_G6, 30); + if (movement_button_should_sound()) watch_buzzer_play_note(BUZZER_NOTE_REST, 30); + if (movement_button_should_sound()) watch_buzzer_play_note(BUZZER_NOTE_E6, 30); + print_tally(state, movement_button_should_sound()); + } + break; + case EVENT_LIGHT_BUTTON_UP: + tally_face_increment(state, movement_button_should_sound()); + break; + case EVENT_LIGHT_BUTTON_DOWN: + case EVENT_ALARM_BUTTON_DOWN: + if (HAL_GPIO_BTN_MODE_read()) { + movement_illuminate_led(); + using_led = true; + } + break; + case EVENT_LIGHT_LONG_PRESS: + if (TALLY_FACE_PRESETS_SIZE() > 1 && _init_val){ + state->tally_default_idx = (state->tally_default_idx + 1) % TALLY_FACE_PRESETS_SIZE(); + state->tally_idx = _tally_default[state->tally_default_idx]; + if (movement_button_should_sound()) watch_buzzer_play_note(BUZZER_NOTE_E6, 30); + if (movement_button_should_sound()) watch_buzzer_play_note(BUZZER_NOTE_REST, 30); + if (movement_button_should_sound()) watch_buzzer_play_note(BUZZER_NOTE_G6, 30); + print_tally(state, movement_button_should_sound()); + } + else{ + tally_face_increment(state, movement_button_should_sound()); + start_quick_cyc(); + } + break; + case EVENT_ACTIVATE: + print_tally(state, movement_button_should_sound()); + break; + case EVENT_TIMEOUT: + // ignore timeout + break; + default: + movement_default_loop_handler(event); + break; + } + + return true; +} + +// print tally index at the center of display. +void print_tally(tally_state_t *state, bool sound_on) { + char buf[6]; + if (sound_on) + watch_set_indicator(WATCH_INDICATOR_BELL); + else + watch_clear_indicator(WATCH_INDICATOR_BELL); + watch_display_text_with_fallback(WATCH_POSITION_TOP, "TALLY", "TA"); + sprintf(buf, "%4d", (int)(state->tally_idx)); + watch_display_text(WATCH_POSITION_BOTTOM, buf); +} + +void tally_face_resign(void *context) { + (void) context; +} diff --git a/watch-faces/complication/tally_face.h b/watch-faces/complication/tally_face.h new file mode 100644 index 0000000..7b18a33 --- /dev/null +++ b/watch-faces/complication/tally_face.h @@ -0,0 +1,76 @@ +/* + * MIT License + * + * Copyright (c) 2022 Andrew Mike + * + * 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 TALLY_FACE_H_ +#define TALLY_FACE_H_ + +/* + * TALLY face + * + * Tally face is designed to act as a tally counter. + * + * Alarm + * Press: Decrement + * Hold : Fast Decrement + * + * Light + * Press: Increment + * Hold : On initial value: Cycles through other initial values. + * Else: Fast Increment + * + * Mode + * Press: Next face + * Hold : On initial value: Go to first face. + * Else: Resets counter + * + * Incrementing or Decrementing the tally will beep if Beeping is set in the global Preferences + */ + +#include "movement.h" + +typedef struct { + int16_t tally_idx; + uint8_t tally_default_idx; +} tally_state_t; + +//#define TALLY_FACE_PRESETS_MTG +//#define TALLY_FACE_PRESETS_YUGIOH + + +void tally_face_setup(uint8_t watch_face_index, void ** context_ptr); +void tally_face_activate(void *context); +bool tally_face_loop(movement_event_t event, void *context); +void tally_face_resign(void *context); + +void print_tally(tally_state_t *state, bool sound_on); + +#define tally_face ((const watch_face_t){ \ + tally_face_setup, \ + tally_face_activate, \ + tally_face_loop, \ + tally_face_resign, \ + NULL, \ +}) + +#endif // TALLY_FACE_H_