/****************************************************************************** * @file app_shake_wake.c * @brief PA3 vibration-switch wake detector. * * The fitted switch is normally closed to ground. A vibration opens the * contact, so PA3 goes high, then returns low when the contact closes again. * A wake is accepted only after the high level has been stable for the * re-arm interval and is generated on the following high-to-low transition. ******************************************************************************/ #include "app_shake_wake.h" #include "board_pin.h" #include "asm/gpio.h" typedef struct { AppShakeWakeAllowedFn allowed; AppShakeWakeTriggerFn trigger; uint8_t enable; uint8_t armed; uint8_t trigger_pending; uint8_t high_ticks; } AppShakeWakeCtx_t; static AppShakeWakeCtx_t s_shake; static void shake_reset_detection(void) { s_shake.armed = 0; s_shake.trigger_pending = 0; s_shake.high_ticks = 0; } static void shake_pin_init(void) { #if BOARD_SHAKE_ENABLE gpio_set_die(BOARD_SHAKE_PIN, 1); gpio_direction_input(BOARD_SHAKE_PIN); gpio_set_pull_up(BOARD_SHAKE_PIN, 1); gpio_set_pull_down(BOARD_SHAKE_PIN, 0); #endif } void app_shake_wake_init(AppShakeWakeAllowedFn allowed, AppShakeWakeTriggerFn trigger) { s_shake.allowed = allowed; s_shake.trigger = trigger; s_shake.enable = 0; shake_reset_detection(); shake_pin_init(); } void app_shake_wake_set_enable(uint8_t enable) { s_shake.enable = !!enable; shake_reset_detection(); } void app_shake_wake_reset(void) { shake_reset_detection(); } void app_shake_wake_poll(void) { uint8_t pin_high; uint8_t rearm_ticks; if (!s_shake.enable) { shake_reset_detection(); return; } #if BOARD_SHAKE_ENABLE pin_high = (uint8_t)(gpio_read(BOARD_SHAKE_PIN) == BOARD_SHAKE_ACTIVE_LEVEL); #else pin_high = 0; #endif rearm_ticks = (uint8_t)(BOARD_SHAKE_REARM_MS / BOARD_SHAKE_POLL_MS); if (!rearm_ticks) { rearm_ticks = 1; } if (pin_high) { if (s_shake.high_ticks < rearm_ticks) { s_shake.high_ticks++; } if (s_shake.high_ticks >= rearm_ticks) { s_shake.armed = 1; } return; } /* The contact has closed again: this is the verified wake edge. */ s_shake.high_ticks = 0; if (s_shake.armed) { s_shake.armed = 0; s_shake.trigger_pending = 1; } if (!s_shake.trigger_pending) { return; } s_shake.trigger_pending = 0; if (!s_shake.allowed || !s_shake.allowed()) { shake_reset_detection(); return; } if (s_shake.trigger) { s_shake.trigger(); } }