diff options
Diffstat (limited to 'common/gesture.c')
-rw-r--r-- | common/gesture.c | 335 |
1 files changed, 0 insertions, 335 deletions
diff --git a/common/gesture.c b/common/gesture.c deleted file mode 100644 index 88d79448a5..0000000000 --- a/common/gesture.c +++ /dev/null @@ -1,335 +0,0 @@ -/* Copyright 2014 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* Board specific gesture recognition */ - -#include "accelgyro.h" -#include "common.h" -#include "console.h" -#include "hooks.h" -#include "gesture.h" -#include "lid_switch.h" -#include "lightbar.h" -#include "motion_sense.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -/* Console output macros */ -#define CPUTS(outstr) cputs(CC_GESTURE, outstr) -#define CPRINTS(format, args...) cprints(CC_GESTURE, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_GESTURE, format, ## args) - - -/* - * Double tap detection parameters - * Double tap works by looking for two isolated Z-axis accelerometer impulses - * preceded and followed by relatively calm periods of accelerometer motion. - * - * Define an outer and inner window. The inner window specifies how - * long the tap impulse is expected to last. The outer window specifies the - * period before the initial tap impluse and after the final tap impulse for - * which to check for relatively calm periods. In between the two impulses - * there is a minimum and maximum interstice time allowed. - */ -#define OUTER_WINDOW \ - (CONFIG_GESTURE_TAP_OUTER_WINDOW_T / \ - CONFIG_GESTURE_SAMPLING_INTERVAL_MS) -#define INNER_WINDOW \ - (CONFIG_GESTURE_TAP_INNER_WINDOW_T / \ - CONFIG_GESTURE_SAMPLING_INTERVAL_MS) -#define MIN_INTERSTICE \ - (CONFIG_GESTURE_TAP_MIN_INTERSTICE_T / \ - CONFIG_GESTURE_SAMPLING_INTERVAL_MS) -#define MAX_INTERSTICE \ - (CONFIG_GESTURE_TAP_MAX_INTERSTICE_T / \ - CONFIG_GESTURE_SAMPLING_INTERVAL_MS) -#define MAX_WINDOW OUTER_WINDOW - -/* State machine states for detecting double tap */ -enum tap_states { - /* Look for calm before the storm */ - TAP_IDLE, - /* Record first Z impulse */ - TAP_IMPULSE_1, - - /* Eye of the storm, expect Z motion to drop and then suddenly spike */ - TAP_INTERSTICE_DROP, - TAP_INTERSTICE_RISE, - - /* Record second Z impulse */ - TAP_IMPULSE_2, - /* Should be quiet after the storm */ - TAP_AFTER_EVENT -}; - -/* Tap sensor to use */ -static struct motion_sensor_t *sensor = -&motion_sensors[CONFIG_GESTURE_TAP_SENSOR]; - -/* Tap state information */ -static int history_z[MAX_WINDOW]; /* Changes in Z */ -static int history_xy[MAX_WINDOW]; /* Changes in X and Y */ -static int state, history_idx; -static int history_initialized, history_init_index; -static int tap_debug; - -/* Tap detection flag */ -static int tap_detection; - -/* - * TODO(crosbug.com/p/33102): Cleanup this function: break into multiple - * functions and generalize so it can be used for other boards. - */ -static int gesture_tap_for_battery(void) -{ - /* Current and previous accel x,y,z */ - int x, y, z; - static int x_p, y_p, z_p; - - /* Number of iterations in this state */ - static int state_cnt; - - /* - * Running sums of data diffs for inner and outer windows. - * Z data kept separate from X and Y data - */ - static int sum_z_inner, sum_z_outer, sum_xy_inner, sum_xy_outer; - - /* Total variation in each signal, normalized for window size */ - int delta_z_outer, delta_z_inner, delta_xy_outer, delta_xy_inner; - - /* Max variation seen during tap event and state cnts since max */ - static int delta_z_inner_max; - static int cnts_since_max; - - /* Interstice Z motion thresholds */ - static int z_drop_thresh, z_rise_thresh; - - int history_idx_inner, state_p; - int ret = 0; - - /* Get data */ - x = sensor->xyz[0]; - y = sensor->xyz[1]; - z = sensor->xyz[2]; - - /* - * Calculate history of change in Z sensor and keeping - * running sums for the past. - */ - history_idx_inner = history_idx - INNER_WINDOW; - if (history_idx_inner < 0) - history_idx_inner += MAX_WINDOW; - sum_z_inner -= history_z[history_idx_inner]; - sum_z_outer -= history_z[history_idx]; - history_z[history_idx] = ABS(z - z_p); - sum_z_inner += history_z[history_idx]; - sum_z_outer += history_z[history_idx]; - - /* - * Calculate history of change in X and Y sensors combined - * and keep a running sum of the change over the past. - */ - sum_xy_inner -= history_xy[history_idx_inner]; - sum_xy_outer -= history_xy[history_idx]; - history_xy[history_idx] = ABS(x - x_p) + ABS(y - y_p); - sum_xy_inner += history_xy[history_idx]; - sum_xy_outer += history_xy[history_idx]; - - /* Increment history index */ - history_idx = (history_idx == MAX_WINDOW - 1) ? 0 : (history_idx + 1); - - /* Store previous X, Y, Z data */ - x_p = x; - y_p = y; - z_p = z; - - /* - * Ignore data until we fill history buffer and wrap around. If - * detection is paused, history_init_index will store the index - * when paused, so that when re-started, we will wait until we - * wrap around again. - */ - if (history_idx == history_init_index) - history_initialized = 1; - if (!history_initialized) - return 0; - - /* - * Normalize data based on window size and isolate outer and inner - * window data. - */ - delta_z_outer = (sum_z_outer - sum_z_inner) * 1000 / - (OUTER_WINDOW - INNER_WINDOW); - delta_z_inner = sum_z_inner * 1000 / INNER_WINDOW; - delta_xy_outer = (sum_xy_outer - sum_xy_inner) * 1000 / - (OUTER_WINDOW - INNER_WINDOW); - delta_xy_inner = sum_xy_inner * 1000 / INNER_WINDOW; - - state_cnt++; - state_p = state; - - switch (state) { - case TAP_IDLE: - /* Look for a sudden increase in Z movement */ - if (delta_z_inner > 30000 && - delta_z_inner > 13 * delta_z_outer && - delta_z_inner > 1 * delta_xy_inner) { - delta_z_inner_max = delta_z_inner; - state_cnt = 0; - state = TAP_IMPULSE_1; - } - break; - - case TAP_IMPULSE_1: - /* Find the peak inner window of Z movement */ - if (delta_z_inner > delta_z_inner_max) { - delta_z_inner_max = delta_z_inner; - cnts_since_max = state_cnt; - } - - /* After inner window has passed, move to next state */ - if (state_cnt >= INNER_WINDOW) { - state = TAP_INTERSTICE_DROP; - z_drop_thresh = delta_z_inner_max / 12; - z_rise_thresh = delta_z_inner_max / 3; - state_cnt += INNER_WINDOW - cnts_since_max; - } - break; - - case TAP_INTERSTICE_DROP: - /* Check for z motion to go back down first */ - if (delta_z_inner < z_drop_thresh) - state = TAP_INTERSTICE_RISE; - - if (state_cnt > MAX_INTERSTICE) - state = TAP_IDLE; - - break; - - case TAP_INTERSTICE_RISE: - /* Then, check for z motion to go back up */ - if (delta_z_inner > z_rise_thresh) { - if (state_cnt < MIN_INTERSTICE) { - state = TAP_IDLE; - } else { - delta_z_inner_max = delta_z_inner; - state_cnt = 0; - state = TAP_IMPULSE_2; - } - } - - if (state_cnt > MAX_INTERSTICE) - state = TAP_IDLE; - break; - - case TAP_IMPULSE_2: - /* Find the peak inner window of Z movement */ - if (delta_z_inner > delta_z_inner_max) { - delta_z_inner_max = delta_z_inner; - cnts_since_max = state_cnt; - } - - /* After inner window has passed, move to next state */ - if (state_cnt >= INNER_WINDOW) { - state = TAP_AFTER_EVENT; - state_cnt += INNER_WINDOW - cnts_since_max; - } - - case TAP_AFTER_EVENT: - /* Check for small Z movement after the event */ - if (state_cnt < OUTER_WINDOW) - break; - - if (2 * delta_z_inner_max > 3 * delta_z_outer && - delta_z_outer > 1 * delta_xy_outer) - ret = 1; - - state = TAP_IDLE; - break; - } - - /* On state transitions, print debug info */ - if (tap_debug && - (state != state_p || - (state_cnt % 10000 == 9999))) { - /* make sure we don't divide by 0 */ - if (delta_z_outer == 0 || delta_xy_inner == 0) - CPRINTS("tap st %d->%d, error div by 0", - state_p, state); - else - CPRINTS("tap st %d->%d, st_cnt %-3d " - "Z_in:Z_out %-3d, Z_in:XY_in %-3d " - "dZ_in %-8.3d, dZ_in_max %-8.3d, " - "dZ_out %-8.3d", - state_p, state, state_cnt, - delta_z_inner / delta_z_outer, - delta_z_inner / delta_xy_inner, - delta_z_inner, - delta_z_inner_max, - delta_z_outer); - } - - return ret; -} - -static void gesture_chipset_resume(void) -{ - /* disable tap detection */ - tap_detection = 0; -} -DECLARE_HOOK(HOOK_CHIPSET_RESUME, gesture_chipset_resume, - GESTURE_HOOK_PRIO); - -static void gesture_chipset_suspend(void) -{ - /* - * Clear tap init and history initialized so that we have to - * record a whole new set of data, and enable tap detection - */ - history_initialized = 0; - history_init_index = history_idx; - state = TAP_IDLE; - tap_detection = 1; -} -DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, gesture_chipset_suspend, - GESTURE_HOOK_PRIO); - -void gesture_calc(uint32_t *event) -{ - /* Only check for gesture if lid is closed and tap detection is on */ - if (!tap_detection || lid_is_open()) - return; - - if (gesture_tap_for_battery()) - *event |= TASK_EVENT_MOTION_ACTIVITY_INTERRUPT( - MOTIONSENSE_ACTIVITY_DOUBLE_TAP); -} - -/*****************************************************************************/ -/* Console commands */ -static int command_tap_info(int argc, char **argv) -{ - int val; - - ccprintf("tap: %s\n", (tap_detection && !lid_is_open()) ? - "on" : "off"); - - if (argc > 1) { - if (!parse_bool(argv[1], &val)) - return EC_ERROR_PARAM1; - tap_debug = val; - } - - ccprintf("debug: %s\n", tap_debug ? "on" : "off"); - ccprintf("odr: %d\n", sensor->drv->get_data_rate(sensor)); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(tapinfo, command_tap_info, - "debug on/off", - "Print tap information"); - |