accelrometer: add tap event, test by adding tap to set countdown
This commit is contained in:
parent
c2b800bb69
commit
4b5e15cc1d
56
movement.c
56
movement.c
@ -519,6 +519,47 @@ void movement_set_alarm_enabled(bool value) {
|
||||
movement_state.settings.bit.alarm_enabled = value;
|
||||
}
|
||||
|
||||
void movement_enable_tap_detection_if_available(void) {
|
||||
#ifdef HAS_ACCELEROMETER
|
||||
// disable event on INT1/A3 (normally tracks orientation changes)
|
||||
eic_disable_event(HAL_GPIO_A3_pin());
|
||||
|
||||
// configure tap duration threshold and enable Z axis
|
||||
lis2dw_configure_tap_threshold(0, 0, 12, LIS2DW_REG_TAP_THS_Z_Z_AXIS_ENABLE);
|
||||
lis2dw_configure_tap_duration(10, 2, 2);
|
||||
|
||||
// ramp data rate up to 400 Hz and high performance mode
|
||||
lis2dw_set_low_noise_mode(true);
|
||||
lis2dw_set_data_rate(LIS2DW_DATA_RATE_HP_400_HZ);
|
||||
lis2dw_set_mode(LIS2DW_MODE_HIGH_PERFORMANCE);
|
||||
|
||||
// Settling time (1 sample duration, i.e. 1/400Hz)
|
||||
delay_ms(3);
|
||||
|
||||
// enable tap detection on INT1/A3.
|
||||
lis2dw_configure_int1(LIS2DW_CTRL4_INT1_SINGLE_TAP | LIS2DW_CTRL4_INT1_6D);
|
||||
// and enable the cb_accelerometer_event interrupt callback, so we can catch tap events.
|
||||
watch_register_interrupt_callback(HAL_GPIO_A3_pin(), cb_accelerometer_event, INTERRUPT_TRIGGER_RISING);
|
||||
#endif
|
||||
}
|
||||
|
||||
void movement_disable_tap_detection_if_available(void) {
|
||||
#ifdef HAS_ACCELEROMETER
|
||||
// Ramp data rate back down to the usual lowest rate to save power.
|
||||
lis2dw_set_low_noise_mode(false);
|
||||
lis2dw_set_data_rate(LIS2DW_DATA_RATE_LOWEST);
|
||||
lis2dw_set_mode(LIS2DW_MODE_LOW_POWER);
|
||||
// disable the interrupt on INT1/A3...
|
||||
eic_disable_interrupt(HAL_GPIO_A3_pin());
|
||||
// ...disable Z axis (not sure if this is needed, does this save power?)...
|
||||
lis2dw_configure_tap_threshold(0, 0, 0, 0);
|
||||
// ...re-enable tracking of orientation changes...
|
||||
lis2dw_configure_int1(LIS2DW_CTRL4_INT1_6D);
|
||||
// ...and re-enable the event.
|
||||
eic_enable_event(HAL_GPIO_A3_pin());
|
||||
#endif
|
||||
}
|
||||
|
||||
void app_init(void) {
|
||||
_watch_init();
|
||||
|
||||
@ -958,18 +999,19 @@ void cb_tick(void) {
|
||||
|
||||
#ifdef HAS_ACCELEROMETER
|
||||
void cb_accelerometer_event(void) {
|
||||
// This callback is not currently in use! Tap tracking will require using an interrupt on A3 instead of an event.
|
||||
// I imagine watch faces will request tap tracking in a specific context, and we'll expose a Movement function
|
||||
// that swaps out the mode for as long as the watch face needs taps. (the sampling rate required for tap tracking
|
||||
// will to consume a lot more power, so we can't leave it on all the time.)
|
||||
uint8_t int_src = lis2dw_get_interrupt_source();
|
||||
|
||||
if (int_src & LIS2DW_REG_ALL_INT_SRC_DOUBLE_TAP) event.event_type = EVENT_DOUBLE_TAP;
|
||||
if (int_src & LIS2DW_REG_ALL_INT_SRC_SINGLE_TAP) event.event_type = EVENT_SINGLE_TAP;
|
||||
if (int_src & LIS2DW_REG_ALL_INT_SRC_DOUBLE_TAP) {
|
||||
event.event_type = EVENT_DOUBLE_TAP;
|
||||
printf("Double tap!\n");
|
||||
}
|
||||
if (int_src & LIS2DW_REG_ALL_INT_SRC_SINGLE_TAP) {
|
||||
event.event_type = EVENT_SINGLE_TAP;
|
||||
printf("Single tap!\n");
|
||||
}
|
||||
}
|
||||
|
||||
void cb_accelerometer_wake(void) {
|
||||
printf("Woke up from accelerometer!\n");
|
||||
event.event_type = EVENT_ACCELEROMETER_WAKE;
|
||||
// reset the stationary minutes counter; we're counting consecutive stationary minutes.
|
||||
stationary_minutes = 0;
|
||||
|
||||
@ -375,3 +375,7 @@ void movement_store_settings(void);
|
||||
/// Worth considering a better way to handle this.
|
||||
bool movement_alarm_enabled(void);
|
||||
void movement_set_alarm_enabled(bool value);
|
||||
|
||||
// if the board has an accelerometer, these functions will enable or disable tap detection.
|
||||
void movement_enable_tap_detection_if_available(void);
|
||||
void movement_disable_tap_detection_if_available(void);
|
||||
|
||||
@ -32,6 +32,7 @@
|
||||
|
||||
#define CD_SELECTIONS 3
|
||||
#define DEFAULT_MINUTES 3
|
||||
#define TAP_DETECTION_SECONDS 5
|
||||
|
||||
static bool quick_ticks_running;
|
||||
|
||||
@ -45,6 +46,11 @@ static void abort_quick_ticks(countdown_state_t *state) {
|
||||
}
|
||||
}
|
||||
|
||||
static void abort_tap_detection(countdown_state_t *state) {
|
||||
state->tap_detection_ticks = 0;
|
||||
movement_disable_tap_detection_if_available();
|
||||
}
|
||||
|
||||
static inline void store_countdown(countdown_state_t *state) {
|
||||
/* Store set countdown time */
|
||||
state->set_hours = state->hours;
|
||||
@ -132,7 +138,14 @@ static void draw(countdown_state_t *state, uint8_t subsecond) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
watch_display_text(WATCH_POSITION_BOTTOM, buf);
|
||||
|
||||
if (state->tap_detection_ticks) {
|
||||
watch_set_indicator(WATCH_INDICATOR_SIGNAL);
|
||||
} else {
|
||||
watch_clear_indicator(WATCH_INDICATOR_SIGNAL);
|
||||
}
|
||||
}
|
||||
|
||||
static void pause(countdown_state_t *state) {
|
||||
@ -206,6 +219,13 @@ void countdown_face_activate(void *context) {
|
||||
|
||||
movement_request_tick_frequency(1);
|
||||
quick_ticks_running = false;
|
||||
#if HAS_ACCELEROMETER
|
||||
if (state->mode != cd_running) {
|
||||
state->tap_detection_ticks = TAP_DETECTION_SECONDS;
|
||||
state->has_tapped_once = false;
|
||||
movement_enable_tap_detection_if_available();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool countdown_face_loop(movement_event_t event, void *context) {
|
||||
@ -227,6 +247,12 @@ bool countdown_face_loop(movement_event_t event, void *context) {
|
||||
if (state->mode == cd_running) {
|
||||
state->now_ts++;
|
||||
}
|
||||
|
||||
if (state->tap_detection_ticks > 0) {
|
||||
state->tap_detection_ticks--;
|
||||
if (state->tap_detection_ticks == 0) movement_disable_tap_detection_if_available();
|
||||
}
|
||||
|
||||
draw(state, event.subsecond);
|
||||
break;
|
||||
case EVENT_MODE_BUTTON_UP:
|
||||
@ -264,8 +290,9 @@ bool countdown_face_loop(movement_event_t event, void *context) {
|
||||
break;
|
||||
case cd_reset:
|
||||
case cd_paused:
|
||||
// Only start the timer if we have a valid time.
|
||||
if (!(state->hours == 0 && state->minutes == 0 && state->seconds == 0)) {
|
||||
// Only start the timer if we have a valid time.
|
||||
abort_tap_detection(state);
|
||||
start(state);
|
||||
button_beep();
|
||||
watch_set_indicator(WATCH_INDICATOR_SIGNAL);
|
||||
@ -281,6 +308,7 @@ bool countdown_face_loop(movement_event_t event, void *context) {
|
||||
switch(state->mode) {
|
||||
case cd_reset:
|
||||
// long press in reset mode enters settings
|
||||
abort_tap_detection(state);
|
||||
state->mode = cd_setting;
|
||||
movement_request_tick_frequency(4);
|
||||
button_beep();
|
||||
@ -338,6 +366,21 @@ bool countdown_face_loop(movement_event_t event, void *context) {
|
||||
case EVENT_LIGHT_BUTTON_DOWN:
|
||||
// intentionally squelch the light default event; we only show the light when cd is running or reset
|
||||
break;
|
||||
case EVENT_SINGLE_TAP:
|
||||
if (state->has_tapped_once == false) {
|
||||
// on first tap, set the countdown to 1 minute
|
||||
state->has_tapped_once = true;
|
||||
state->hours = 0;
|
||||
state->minutes = 1;
|
||||
state->seconds = 0;
|
||||
} else {
|
||||
// on subsequent taps, increment the countdown by 1 minute, up to 59 taps
|
||||
state->minutes = state->minutes < 59 ? state->minutes + 1 : state->minutes;
|
||||
}
|
||||
// reset the tap detection timer
|
||||
state->tap_detection_ticks = TAP_DETECTION_SECONDS;
|
||||
draw(state, event.subsecond);
|
||||
break;
|
||||
default:
|
||||
movement_default_loop_handler(event);
|
||||
break;
|
||||
@ -353,4 +396,7 @@ void countdown_face_resign(void *context) {
|
||||
state->mode = cd_reset;
|
||||
store_countdown(state);
|
||||
}
|
||||
|
||||
// return accelerometer to the state it was in before
|
||||
abort_tap_detection(state);
|
||||
}
|
||||
|
||||
@ -61,6 +61,8 @@ typedef struct {
|
||||
uint8_t set_minutes;
|
||||
uint8_t set_seconds;
|
||||
uint8_t selection;
|
||||
uint8_t tap_detection_ticks;
|
||||
bool has_tapped_once;
|
||||
countdown_mode_t mode;
|
||||
bool repeat;
|
||||
uint8_t watch_face_index;
|
||||
|
||||
@ -253,6 +253,24 @@ void lis2dw_configure_6d_threshold(uint8_t threshold) {
|
||||
watch_i2c_write8(LIS2DW_ADDRESS, LIS2DW_REG_TAP_THS_X, configuration | ((threshold & 0b11) << 5));
|
||||
}
|
||||
|
||||
void lis2dw_configure_tap_threshold(uint8_t threshold_x, uint8_t threshold_y, uint8_t threshold_z, uint8_t axes_to_enable) {
|
||||
uint8_t configuration;
|
||||
// if (axes_to_enable & LIS2DW_REG_TAP_THS_Z_X_AXIS_ENABLE); // X axis tap not implemented
|
||||
// if (axes_to_enable & LIS2DW_REG_TAP_THS_Z_Y_AXIS_ENABLE); // Y axis tap not implemented
|
||||
// tap enable bitmask is the high bits of LIS2DW_REG_TAP_THS_Z
|
||||
configuration = axes_to_enable & 0b00100000; // NOTE: should be 0b11100000 to allow use of all three axes, but we're not using X or Y.
|
||||
if (axes_to_enable & LIS2DW_REG_TAP_THS_Z_Z_AXIS_ENABLE) {
|
||||
// mask out high bits if set
|
||||
configuration |= (threshold_z & 0b00011111);
|
||||
}
|
||||
watch_i2c_write8(LIS2DW_ADDRESS, LIS2DW_REG_TAP_THS_Z, configuration);
|
||||
}
|
||||
|
||||
void lis2dw_configure_tap_duration(uint8_t latency, uint8_t quiet, uint8_t shock) {
|
||||
uint8_t configuration = (latency << 4) | ((quiet & 0b11) << 2) | (shock & 0b11);
|
||||
watch_i2c_write8(LIS2DW_ADDRESS, LIS2DW_REG_INT1_DUR, configuration);
|
||||
}
|
||||
|
||||
void lis2dw_configure_int1(uint8_t sources) {
|
||||
watch_i2c_write8(LIS2DW_ADDRESS, LIS2DW_REG_CTRL4_INT1, sources);
|
||||
}
|
||||
|
||||
@ -227,8 +227,14 @@ typedef enum {
|
||||
#define LIS2DW_FIFO_SAMPLE_COUNT (0b00111111)
|
||||
|
||||
#define LIS2DW_REG_TAP_THS_X 0x30
|
||||
|
||||
#define LIS2DW_REG_TAP_THS_Y 0x31
|
||||
|
||||
#define LIS2DW_REG_TAP_THS_Z 0x32
|
||||
#define LIS2DW_REG_TAP_THS_Z_X_AXIS_ENABLE 0b10000000
|
||||
#define LIS2DW_REG_TAP_THS_Z_Y_AXIS_ENABLE 0b01000000
|
||||
#define LIS2DW_REG_TAP_THS_Z_Z_AXIS_ENABLE 0b00100000
|
||||
|
||||
#define LIS2DW_REG_INT1_DUR 0x33
|
||||
|
||||
#define LIS2DW_REG_WAKE_UP_THS 0x34
|
||||
@ -353,6 +359,10 @@ void lis2dw_configure_wakeup_threshold(uint8_t threshold);
|
||||
|
||||
void lis2dw_configure_6d_threshold(uint8_t threshold);
|
||||
|
||||
void lis2dw_configure_tap_threshold(uint8_t threshold_x, uint8_t threshold_y, uint8_t threshold_z, uint8_t axes_to_enable);
|
||||
|
||||
void lis2dw_configure_tap_duration(uint8_t latency, uint8_t quiet, uint8_t shock);
|
||||
|
||||
void lis2dw_configure_int1(uint8_t sources);
|
||||
|
||||
void lis2dw_configure_int2(uint8_t sources);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user