From df2dac5a073537fc45657f5310a68f33884804aa Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Mon, 29 Jul 2024 18:12:46 -0400 Subject: [PATCH] debouince now uses cb_fast_tick and holding the button now also gets debounced --- movement/movement.c | 106 ++++++++++++++++++++++++++++---------------- movement/movement.h | 9 +++- 2 files changed, 74 insertions(+), 41 deletions(-) diff --git a/movement/movement.c b/movement/movement.c index 87110da4..9f6f2959 100644 --- a/movement/movement.c +++ b/movement/movement.c @@ -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) { for(uint8_t i = 0; i < MOVEMENT_NUM_FACES; i++) { // 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.light_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_reset_inactivity_countdown(); @@ -485,12 +477,12 @@ void app_wake_from_standby(void) { static void _sleep_mode_app_loop(void) { 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. while (movement_state.le_mode_ticks == -1) { // we also have to handle background tasks here in the mini-runloop 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; 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) { // force alarm off if the user pressed a button. if (movement_state.alarm_ticks) movement_state.alarm_ticks = 0; - if ( movement_state.debounce_occurring) - return EVENT_NONE; if (pin_level) { // 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; *down_timestamp = 0; _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 if (diff > MOVEMENT_LONG_PRESS_TICKS) return button_down_event_type + 3; else return button_down_event_type + 1; } } -void cb_light_btn_interrupt(void) { - bool pin_level = watch_get_pin_level(BTN_LIGHT); +static void light_btn_action(bool pin_level) { _movement_reset_inactivity_countdown(); event.event_type = _figure_out_button_event(pin_level, EVENT_LIGHT_BUTTON_DOWN, &movement_state.light_down_timestamp); } -void cb_mode_btn_interrupt(void) { - bool pin_level = watch_get_pin_level(BTN_MODE); +static void mode_btn_action(bool pin_level) { _movement_reset_inactivity_countdown(); event.event_type = _figure_out_button_event(pin_level, EVENT_MODE_BUTTON_DOWN, &movement_state.mode_down_timestamp); } -void cb_alarm_btn_interrupt(void) { - bool pin_level = watch_get_pin_level(BTN_ALARM); +static void alarm_btn_action(bool pin_level) { _movement_reset_inactivity_countdown(); 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 (event_type == EVENT_ALARM_BUTTON_UP) movement_state.ignore_alarm_after_sleep = false; + if (movement_state.ignore_alarm_btn_after_sleep){ + if (event_type == EVENT_ALARM_BUTTON_UP || event_type == EVENT_ALARM_LONG_UP) movement_state.ignore_alarm_btn_after_sleep = false; return; } 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) { // wake up! @@ -695,23 +698,48 @@ void cb_alarm_fired(void) { } void cb_fast_tick(void) { - movement_state.fast_ticks++; - if (!movement_state.debounce_occurring) { - 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; + if (movement_state.debounce_ticks_light == 0) { + if (movement_state.debounce_prev_pin_light == watch_get_pin_level(BTN_LIGHT)) + light_btn_action(movement_state.debounce_prev_pin_light); + movement_state.debounce_ticks_light = -1; } + 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. // but if for whatever reason it isn't, this forces the fast tick off after 20 seconds. if (movement_state.fast_ticks >= 128 * 20) { diff --git a/movement/movement.h b/movement/movement.h index 1af89753..3601d48c 100644 --- a/movement/movement.h +++ b/movement/movement.h @@ -267,11 +267,16 @@ typedef struct { bool needs_background_tasks_handled; bool has_scheduled_background_task; bool needs_wake; - bool debounce_occurring; // low energy mode countdown 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?) int16_t timeout_ticks;