Movement: implement auto firing of long press events and introduce long up event. (Also re-implement alarm_enabled and alarm_note)

This commit is contained in:
TheOnePerson 2022-10-23 13:07:32 +02:00
parent f8f0ce479d
commit 1a80003775
2 changed files with 46 additions and 18 deletions

View file

@ -22,6 +22,8 @@
* SOFTWARE.
*/
#define MOVEMENT_LONG_PRESS_TICKS 64
#include <stdio.h>
#include <string.h>
#include <limits.h>
@ -250,11 +252,16 @@ void movement_play_signal(void) {
}
void movement_play_alarm(void) {
movement_play_alarm_beeps(5, BUZZER_NOTE_C8);
}
void movement_play_alarm_beeps(uint8_t rounds, BuzzerNote alarm_note) {
if (rounds == 0) rounds = 1;
if (rounds > 20) rounds = 20;
movement_request_wake();
// alarm length: 75 ticks short of 5 seconds, or 4.414 seconds:
// our tone is 0.375 seconds of beep and 0.625 of silence, repeated five times.
// so 4.375 + a few ticks to wake up from sleep mode.
movement_state.alarm_ticks = 128 * 5 - 75;
movement_state.alarm_note = alarm_note;
// our tone is 0.375 seconds of beep and 0.625 of silence, repeated as given.
movement_state.alarm_ticks = 128 * rounds - 75;
_movement_enable_fast_tick_if_needed();
}
@ -453,10 +460,13 @@ bool app_loop(void) {
if (movement_state.alarm_ticks >= 0) {
uint8_t buzzer_phase = (movement_state.alarm_ticks + 80) % 128;
if(buzzer_phase == 127) {
// failsafe: buzzer could have been disabled in the meantime
if (!watch_is_buzzer_or_led_enabled()) watch_enable_buzzer();
// play 4 beeps plus pause
for(uint8_t i = 0; i < 4; i++) {
// TODO: This method of playing the buzzer blocks the UI while it's beeping.
// It might be better to time it with the fast tick.
watch_buzzer_play_note(BUZZER_NOTE_C8, (i != 3) ? 50 : 75);
watch_buzzer_play_note(movement_state.alarm_note, (i != 3) ? 50 : 75);
if (i != 3) watch_buzzer_play_note(BUZZER_NOTE_REST, 50);
}
}
@ -503,7 +513,7 @@ bool app_loop(void) {
return can_sleep;
}
static movement_event_type_t _figure_out_button_event(bool pin_level, movement_event_type_t button_down_event_type, uint8_t *down_timestamp) {
static movement_event_type_t _figure_out_button_event(bool pin_level, movement_event_type_t button_down_event_type, uint16_t *down_timestamp) {
// force alarm off if the user pressed a button.
if (movement_state.alarm_ticks) movement_state.alarm_ticks = 0;
@ -513,15 +523,15 @@ static movement_event_type_t _figure_out_button_event(bool pin_level, movement_e
*down_timestamp = movement_state.fast_ticks + 1;
return button_down_event_type;
} else {
// this line is hack but it handles the situation where the light button was held for more than 10 seconds.
// this line is hack but it handles the situation where the light button was held for more than 20 seconds.
// fast tick is disabled by then, and the LED would get stuck on since there's no one left decrementing light_ticks.
if (movement_state.light_ticks == 1) movement_state.light_ticks = 0;
// now that that's out of the way, handle falling edge
uint16_t diff = movement_state.fast_ticks - *down_timestamp;
*down_timestamp = 0;
_movement_disable_fast_tick_if_possible();
// any press over a half second is considered a long press.
if (diff > 64) return button_down_event_type + 2;
// any press over a half second is considered a long press. Fire the long-up event
if (diff > MOVEMENT_LONG_PRESS_TICKS) return button_down_event_type + 3;
else return button_down_event_type + 1;
}
}
@ -557,9 +567,21 @@ void cb_fast_tick(void) {
movement_state.fast_ticks++;
if (movement_state.light_ticks > 0) movement_state.light_ticks--;
if (movement_state.alarm_ticks > 0) movement_state.alarm_ticks--;
// check timestamps and auto-fire the long-press events
// Notice: is it possible that two or more buttons have an identical timestamp? In this case
// only one of these buttons would receive the long press event. Don't bother for now...
if (movement_state.light_down_timestamp > 0)
if (movement_state.fast_ticks - movement_state.light_down_timestamp == MOVEMENT_LONG_PRESS_TICKS + 1)
event.event_type = EVENT_LIGHT_LONG_PRESS;
if (movement_state.mode_down_timestamp > 0)
if (movement_state.fast_ticks - movement_state.mode_down_timestamp == MOVEMENT_LONG_PRESS_TICKS + 1)
event.event_type = EVENT_MODE_LONG_PRESS;
if (movement_state.alarm_down_timestamp > 0)
if (movement_state.fast_ticks - movement_state.alarm_down_timestamp == MOVEMENT_LONG_PRESS_TICKS + 1)
event.event_type = EVENT_ALARM_LONG_PRESS;
// this is just a fail-safe; fast tick should be disabled as soon as the button is up, the LED times out, and/or the alarm finishes.
// but if for whatever reason it isn't, this forces the fast tick off after 10 seconds.
if (movement_state.fast_ticks >= 1280) watch_rtc_disable_periodic_callback(128);
// but if for whatever reason it isn't, this forces the fast tick off after 20 seconds.
if (movement_state.fast_ticks >= 128 * 20) watch_rtc_disable_periodic_callback(128);
}
void cb_tick(void) {

View file

@ -61,7 +61,8 @@ typedef union {
// altimeter to display feet or meters as easily as it tells a thermometer to display degrees in F or C.
bool clock_mode_24h : 1; // indicates whether clock should use 12 or 24 hour mode.
bool use_imperial_units : 1; // indicates whether to use metric units (the default) or imperial.
uint8_t reserved : 7; // room for more preferences if needed.
bool alarm_enabled : 1; // indicates whether there is at least one alarm enabled.
uint8_t reserved : 6; // room for more preferences if needed.
} bit;
uint32_t reg;
} movement_settings_t;
@ -109,13 +110,16 @@ typedef enum {
EVENT_TIMEOUT, // Your watch face has been inactive for a while. You may want to resign, depending on your watch face's intended use case.
EVENT_LIGHT_BUTTON_DOWN, // The light button has been pressed, but not yet released.
EVENT_LIGHT_BUTTON_UP, // The light button was pressed and released.
EVENT_LIGHT_LONG_PRESS, // The light button was held for >2 seconds, and released.
EVENT_LIGHT_LONG_PRESS, // The light button was held for >2 seconds, but not yet released.
EVENT_LIGHT_LONG_UP, // The light button was held for >2 seconds, and released.
EVENT_MODE_BUTTON_DOWN, // The mode button has been pressed, but not yet released.
EVENT_MODE_BUTTON_UP, // The mode button was pressed and released.
EVENT_MODE_LONG_PRESS, // The mode button was held for >2 seconds, and released. NOTE: your watch face will resign immediately after receiving this event.
EVENT_MODE_LONG_PRESS, // The mode button was held for >2 seconds, but not yet released.
EVENT_MODE_LONG_UP, // The mode button was held for >2 seconds, and released. NOTE: your watch face will resign immediately after receiving this event.
EVENT_ALARM_BUTTON_DOWN, // The alarm button has been pressed, but not yet released.
EVENT_ALARM_BUTTON_UP, // The alarm button was pressed and released.
EVENT_ALARM_LONG_PRESS, // The alarm button was held for >2 seconds, and released.
EVENT_ALARM_LONG_PRESS, // The alarm button was held for >2 seconds, but not yet released.
EVENT_ALARM_LONG_UP, // The alarm button was held for >2 seconds, and released.
} movement_event_type_t;
typedef struct {
@ -252,11 +256,12 @@ typedef struct {
// alarm stuff
int16_t alarm_ticks;
bool is_buzzing;
BuzzerNote alarm_note;
// button tracking for long press
uint8_t light_down_timestamp;
uint8_t mode_down_timestamp;
uint8_t alarm_down_timestamp;
uint16_t light_down_timestamp;
uint16_t mode_down_timestamp;
uint16_t alarm_down_timestamp;
// background task handling
bool needs_background_tasks_handled;
@ -300,6 +305,7 @@ void movement_request_wake(void);
void movement_play_signal(void);
void movement_play_alarm(void);
void movement_play_alarm_beeps(uint8_t rounds, BuzzerNote alarm_note);
uint8_t movement_claim_backup_register(void);