debouince now uses cb_fast_tick and holding the button now also gets debounced

This commit is contained in:
David Volovskiy 2024-07-29 18:12:46 -04:00
parent 7d5aaf60ca
commit df2dac5a07
2 changed files with 74 additions and 41 deletions

View File

@ -183,17 +183,6 @@ static inline void _movement_disable_fast_tick_if_possible(void) {
} }
} }
#define DEBOUNCE_FREQ 64 // 64 HZ is 15.625ms
static void cb_debounce(void) {
movement_state.debounce_occurring = false;
watch_rtc_disable_periodic_callback(DEBOUNCE_FREQ);
}
static inline void _movement_enable_debounce_tick(void) {
movement_state.debounce_occurring = true;
watch_rtc_register_periodic_callback(cb_debounce, DEBOUNCE_FREQ);
}
static void _movement_handle_background_tasks(void) { static void _movement_handle_background_tasks(void) {
for(uint8_t i = 0; i < MOVEMENT_NUM_FACES; i++) { for(uint8_t i = 0; i < MOVEMENT_NUM_FACES; i++) {
// For each face, if the watch face wants a background task... // For each face, if the watch face wants a background task...
@ -409,6 +398,9 @@ void app_init(void) {
movement_state.settings.bit.led_duration = MOVEMENT_DEFAULT_LED_DURATION; movement_state.settings.bit.led_duration = MOVEMENT_DEFAULT_LED_DURATION;
movement_state.light_ticks = -1; movement_state.light_ticks = -1;
movement_state.alarm_ticks = -1; movement_state.alarm_ticks = -1;
movement_state.debounce_ticks_light = -1;
movement_state.debounce_ticks_alarm = -1;
movement_state.debounce_ticks_mode = -1;
movement_state.next_available_backup_register = 4; movement_state.next_available_backup_register = 4;
_movement_reset_inactivity_countdown(); _movement_reset_inactivity_countdown();
@ -485,12 +477,12 @@ void app_wake_from_standby(void) {
static void _sleep_mode_app_loop(void) { static void _sleep_mode_app_loop(void) {
movement_state.needs_wake = false; movement_state.needs_wake = false;
movement_state.ignore_alarm_btn_after_sleep = true;
// as long as le_mode_ticks is -1 (i.e. we are in low energy mode), we wake up here, update the screen, and go right back to sleep. // as long as le_mode_ticks is -1 (i.e. we are in low energy mode), we wake up here, update the screen, and go right back to sleep.
while (movement_state.le_mode_ticks == -1) { while (movement_state.le_mode_ticks == -1) {
// we also have to handle background tasks here in the mini-runloop // we also have to handle background tasks here in the mini-runloop
if (movement_state.needs_background_tasks_handled) _movement_handle_background_tasks(); if (movement_state.needs_background_tasks_handled) _movement_handle_background_tasks();
movement_state.ignore_alarm_after_sleep = true;
event.event_type = EVENT_LOW_ENERGY_UPDATE; event.event_type = EVENT_LOW_ENERGY_UPDATE;
watch_faces[movement_state.current_face_idx].loop(event, &movement_state.settings, watch_face_contexts[movement_state.current_face_idx]); watch_faces[movement_state.current_face_idx].loop(event, &movement_state.settings, watch_face_contexts[movement_state.current_face_idx]);
@ -638,8 +630,6 @@ bool app_loop(void) {
static movement_event_type_t _figure_out_button_event(bool pin_level, movement_event_type_t button_down_event_type, uint16_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. // force alarm off if the user pressed a button.
if (movement_state.alarm_ticks) movement_state.alarm_ticks = 0; if (movement_state.alarm_ticks) movement_state.alarm_ticks = 0;
if ( movement_state.debounce_occurring)
return EVENT_NONE;
if (pin_level) { if (pin_level) {
// handle rising edge // handle rising edge
@ -654,36 +644,49 @@ static movement_event_type_t _figure_out_button_event(bool pin_level, movement_e
uint16_t diff = movement_state.fast_ticks - *down_timestamp; uint16_t diff = movement_state.fast_ticks - *down_timestamp;
*down_timestamp = 0; *down_timestamp = 0;
_movement_disable_fast_tick_if_possible(); _movement_disable_fast_tick_if_possible();
_movement_enable_debounce_tick();
// any press over a half second is considered a long press. Fire the long-up event // 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; if (diff > MOVEMENT_LONG_PRESS_TICKS) return button_down_event_type + 3;
else return button_down_event_type + 1; else return button_down_event_type + 1;
} }
} }
void cb_light_btn_interrupt(void) { static void light_btn_action(bool pin_level) {
bool pin_level = watch_get_pin_level(BTN_LIGHT);
_movement_reset_inactivity_countdown(); _movement_reset_inactivity_countdown();
event.event_type = _figure_out_button_event(pin_level, EVENT_LIGHT_BUTTON_DOWN, &movement_state.light_down_timestamp); event.event_type = _figure_out_button_event(pin_level, EVENT_LIGHT_BUTTON_DOWN, &movement_state.light_down_timestamp);
} }
void cb_mode_btn_interrupt(void) { static void mode_btn_action(bool pin_level) {
bool pin_level = watch_get_pin_level(BTN_MODE);
_movement_reset_inactivity_countdown(); _movement_reset_inactivity_countdown();
event.event_type = _figure_out_button_event(pin_level, EVENT_MODE_BUTTON_DOWN, &movement_state.mode_down_timestamp); event.event_type = _figure_out_button_event(pin_level, EVENT_MODE_BUTTON_DOWN, &movement_state.mode_down_timestamp);
} }
void cb_alarm_btn_interrupt(void) { static void alarm_btn_action(bool pin_level) {
bool pin_level = watch_get_pin_level(BTN_ALARM);
_movement_reset_inactivity_countdown(); _movement_reset_inactivity_countdown();
uint8_t event_type = _figure_out_button_event(pin_level, EVENT_ALARM_BUTTON_DOWN, &movement_state.alarm_down_timestamp); uint8_t event_type = _figure_out_button_event(pin_level, EVENT_ALARM_BUTTON_DOWN, &movement_state.alarm_down_timestamp);
if (movement_state.ignore_alarm_after_sleep){ if (movement_state.ignore_alarm_btn_after_sleep){
if (event_type == EVENT_ALARM_BUTTON_UP) movement_state.ignore_alarm_after_sleep = false; if (event_type == EVENT_ALARM_BUTTON_UP || event_type == EVENT_ALARM_LONG_UP) movement_state.ignore_alarm_btn_after_sleep = false;
return; return;
} }
event.event_type = event_type; event.event_type = event_type;
} }
void cb_light_btn_interrupt(void) {
movement_state.debounce_prev_pin_light = watch_get_pin_level(BTN_LIGHT);
movement_state.debounce_ticks_light = 1;
_movement_enable_fast_tick_if_needed();
}
void cb_mode_btn_interrupt(void) {
movement_state.debounce_prev_pin_mode = watch_get_pin_level(BTN_MODE);
movement_state.debounce_ticks_mode = 1;
_movement_enable_fast_tick_if_needed();
}
void cb_alarm_btn_interrupt(void) {
movement_state.debounce_prev_pin_alarm = watch_get_pin_level(BTN_ALARM);
movement_state.debounce_ticks_alarm = 1;
_movement_enable_fast_tick_if_needed();
}
void cb_alarm_btn_extwake(void) { void cb_alarm_btn_extwake(void) {
// wake up! // wake up!
@ -695,23 +698,48 @@ void cb_alarm_fired(void) {
} }
void cb_fast_tick(void) { void cb_fast_tick(void) {
movement_state.fast_ticks++; if (movement_state.debounce_ticks_light == 0) {
if (!movement_state.debounce_occurring) { if (movement_state.debounce_prev_pin_light == watch_get_pin_level(BTN_LIGHT))
if (movement_state.light_ticks > 0) movement_state.light_ticks--; light_btn_action(movement_state.debounce_prev_pin_light);
if (movement_state.alarm_ticks > 0) movement_state.alarm_ticks--; movement_state.debounce_ticks_light = -1;
// 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;
} }
else if (movement_state.debounce_ticks_light > 0) {
movement_state.debounce_ticks_light--;
return;
}
if (movement_state.debounce_ticks_alarm == 0) {
if (movement_state.debounce_prev_pin_alarm == watch_get_pin_level(BTN_ALARM))
alarm_btn_action(movement_state.debounce_prev_pin_alarm);
movement_state.debounce_ticks_alarm = -1;
}
else if (movement_state.debounce_ticks_alarm > 0) {
movement_state.debounce_ticks_alarm--;
return;
}
if (movement_state.debounce_ticks_mode == 0) {
if (movement_state.debounce_prev_pin_mode == watch_get_pin_level(BTN_MODE))
mode_btn_action(movement_state.debounce_prev_pin_mode);
movement_state.debounce_ticks_mode = -1;
}
else if (movement_state.debounce_ticks_mode > 0) {
movement_state.debounce_ticks_mode--;
return;
}
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. // 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 20 seconds. // but if for whatever reason it isn't, this forces the fast tick off after 20 seconds.
if (movement_state.fast_ticks >= 128 * 20) { if (movement_state.fast_ticks >= 128 * 20) {

View File

@ -267,11 +267,16 @@ typedef struct {
bool needs_background_tasks_handled; bool needs_background_tasks_handled;
bool has_scheduled_background_task; bool has_scheduled_background_task;
bool needs_wake; bool needs_wake;
bool debounce_occurring;
// low energy mode countdown // low energy mode countdown
int32_t le_mode_ticks; int32_t le_mode_ticks;
bool ignore_alarm_after_sleep; int8_t debounce_ticks_light;
int8_t debounce_ticks_alarm;
int8_t debounce_ticks_mode;
bool debounce_prev_pin_light;
bool debounce_prev_pin_alarm;
bool debounce_prev_pin_mode;
bool ignore_alarm_btn_after_sleep;
// app resignation countdown (TODO: consolidate with LE countdown?) // app resignation countdown (TODO: consolidate with LE countdown?)
int16_t timeout_ticks; int16_t timeout_ticks;