Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 63 additions & 5 deletions src/fw/applib/accel_service.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,19 @@ static void prv_do_shake_handle(PebbleEvent *e, void *context) {
if (task == PebbleTask_Worker || task == PebbleTask_App) {
sys_analytics_inc(ANALYTICS_APP_METRIC_ACCEL_SHAKE_COUNT, AnalyticsClient_CurrentTask);
}
state->shake_handler(e->accel_tap.axis, e->accel_tap.direction);
state->shake_handler();
}


// ----------------------------------------------------------------------------------------------
static void prv_do_tap_handle(PebbleEvent *e, void *context) {
PebbleTask task = pebble_task_get_current();
AccelServiceState *state = (AccelServiceState *)accel_service_private_get_session(task);
PBL_ASSERTN(state->tap_handler != NULL);
// only kernel clients can subscribe to tap right now, so just increment tap count
// device analytic here
analytics_inc(ANALYTICS_DEVICE_METRIC_ACCEL_TAP_COUNT, AnalyticsClient_System);
state->tap_handler(e->accel_tap.axis, e->accel_tap.direction);
}


Expand Down Expand Up @@ -225,18 +237,30 @@ void accel_data_service_unsubscribe(void) {
accel_session_data_unsubscribe(session);
}

// ----------------------------------------------------------------------------------------------
void accel_shake_service_subscribe(AccelShakeHandler handler) {
AccelServiceState * session = accel_service_private_get_session(PebbleTask_Unknown);
accel_session_shake_subscribe(session, handler);
}


// ----------------------------------------------------------------------------------------------
void accel_shake_service_unsubscribe(void) {
AccelServiceState * session = accel_service_private_get_session(PebbleTask_Unknown);
accel_session_shake_unsubscribe(session);
}

// ----------------------------------------------------------------------------------------------
void accel_tap_service_subscribe(AccelTapHandler handler) {
AccelServiceState * session = accel_service_private_get_session(PebbleTask_Unknown);
accel_session_shake_subscribe(session, handler);
accel_session_tap_subscribe(session, handler);
}


// ----------------------------------------------------------------------------------------------
void accel_tap_service_unsubscribe(void) {
AccelServiceState * session = accel_service_private_get_session(PebbleTask_Unknown);
accel_session_shake_unsubscribe(session);
accel_session_tap_unsubscribe(session);
}


Expand Down Expand Up @@ -279,6 +303,10 @@ void accel_service_state_init(AccelServiceState *state) {
.type = PEBBLE_ACCEL_SHAKE_EVENT,
.handler = &prv_do_shake_handle,
},
.accel_tap_info = {
.type = PEBBLE_ACCEL_TAP_EVENT,
.handler = &prv_do_tap_handle,
},
.accel_double_tap_info = {
.type = PEBBLE_ACCEL_DOUBLE_TAP_EVENT,
.handler = &prv_do_double_tap_handle,
Expand All @@ -292,7 +320,17 @@ void accel_service_state_init(AccelServiceState *state) {
static void prv_session_do_shake_handle(PebbleEvent *e, void *context) {
AccelServiceState *state = context;
if (state->shake_handler != NULL) {
state->shake_handler(e->accel_tap.axis, e->accel_tap.direction);
state->shake_handler();
}
}


// ----------------------------------------------------------------------------------------------
// Event service handler for tap events
static void prv_session_do_tap_handle(PebbleEvent *e, void *context) {
AccelServiceState *state = context;
if (state->tap_handler != NULL) {
state->tap_handler(e->accel_tap.axis, e->accel_tap.direction);
}
}

Expand All @@ -319,6 +357,11 @@ AccelServiceState * accel_session_create(void) {
.handler = &prv_session_do_shake_handle,
.context = state,
},
.accel_tap_info = {
.type = PEBBLE_ACCEL_TAP_EVENT,
.handler = &prv_session_do_tap_handle,
.context = state,
},
.accel_double_tap_info = {
.type = PEBBLE_ACCEL_DOUBLE_TAP_EVENT,
.handler = &prv_session_do_double_tap_handle,
Expand All @@ -345,7 +388,7 @@ void accel_session_delete(AccelServiceState * session) {


// ----------------------------------------------------------------------------------------------
void accel_session_shake_subscribe(AccelServiceState * session, AccelTapHandler handler) {
void accel_session_shake_subscribe(AccelServiceState * session, AccelShakeHandler handler) {
AccelServiceState *state = (AccelServiceState *)session;
state->shake_handler = handler;
event_service_client_subscribe(&state->accel_shake_info);
Expand All @@ -359,6 +402,21 @@ void accel_session_shake_unsubscribe(AccelServiceState *state) {
}


// ----------------------------------------------------------------------------------------------
void accel_session_tap_subscribe(AccelServiceState * session, AccelTapHandler handler) {
AccelServiceState *state = (AccelServiceState *)session;
state->tap_handler = handler;
event_service_client_subscribe(&state->accel_tap_info);
}


// ----------------------------------------------------------------------------------------------
void accel_session_tap_unsubscribe(AccelServiceState *state) {
event_service_client_unsubscribe(&state->accel_tap_info);
state->tap_handler = NULL;
}


// -----------------------------------------------------------------------------------------------
void accel_session_double_tap_subscribe(AccelServiceState *state, AccelTapHandler handler) {
state->double_tap_handler = handler;
Expand Down
12 changes: 12 additions & 0 deletions src/fw/applib/accel_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ _Static_assert(ACCEL_AXIS_Z == (int)AXIS_Z,
#define ACCEL_DEFAULT_SAMPLING_RATE ACCEL_SAMPLING_25HZ
#define ACCEL_MINIMUM_SAMPLING_RATE ACCEL_SAMPLING_10HZ

//! Callback type for accelerometer shake events
typedef void (*AccelShakeHandler)(void);

//! Callback type for accelerometer tap events
//! @param axis the axis on which a tap was registered (x, y, or z)
//! @param direction the direction (-1 or +1) of the tap
Expand All @@ -68,6 +71,15 @@ typedef void (*AccelDataHandler)(AccelData *data, uint32_t num_samples);
//! @param timestamp the timestamp, in ms, of the first sample.
typedef void (*AccelRawDataHandler)(AccelRawData *data, uint32_t num_samples, uint64_t timestamp);

//! Subscribe to the accelerometer shake event service. Once subscribed, the handler
//! gets called on every shake event emitted by the accelerometer.
//! @param handler A callback to be executed on shake event
void accel_shake_service_subscribe(AccelShakeHandler handler);

//! Unsubscribe from the accelerometer shake event service. Once unsubscribed,
//! the previously registered handler will no longer be called.
void accel_shake_service_unsubscribe(void);

//! Subscribe to the accelerometer tap event service. Once subscribed, the handler
//! gets called on every tap event emitted by the accelerometer.
//! @param handler A callback to be executed on tap event
Expand Down
17 changes: 15 additions & 2 deletions src/fw/applib/accel_service_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ typedef struct AccelServiceState {

// User-provided callbacks for various events
AccelDataHandler data_handler;
AccelTapHandler shake_handler;
AccelShakeHandler shake_handler;
AccelTapHandler tap_handler;
AccelTapHandler double_tap_handler;
AccelRawDataHandler raw_data_handler;
AccelRawDataHandler__deprecated raw_data_handler_deprecated;

// Configuration for our other types of events
EventServiceInfo accel_shake_info;
EventServiceInfo accel_tap_info;
EventServiceInfo accel_double_tap_info;

#if LOG_DOMAIN_ACCEL
Expand Down Expand Up @@ -56,13 +58,24 @@ void accel_session_delete(AccelServiceState *session);
//! only.
//! @param session An Accel session created by accel_session_create()
//! @param handler A callback to be executed on shake event
void accel_session_shake_subscribe(AccelServiceState *session, AccelTapHandler handler);
void accel_session_shake_subscribe(AccelServiceState *session, AccelShakeHandler handler);

//! Unsubscribe from the accelerometer shake event service by session ref. Used by kernel clients
//! only.
//! @param session An Accel session created by accel_session_create()
void accel_session_shake_unsubscribe(AccelServiceState *session);

//! Subscribe to the accelerometer tap event service by session ref. Used by kernel clients
//! only.
//! @param session An Accel session created by accel_session_create()
//! @param handler A callback to be executed on tap event
void accel_session_tap_subscribe(AccelServiceState *session, AccelTapHandler handler);

//! Unsubscribe from the accelerometer tap event service by session ref. Used by kernel
//! clients only.
//! @param session An Accel session created by accel_session_create()
void accel_session_tap_unsubscribe(AccelServiceState *session);

//! Subscribe to the accelerometer double tap event service by session ref. Used by kernel clients
//! only.
//! @param session An Accel session created by accel_session_create()
Expand Down
13 changes: 8 additions & 5 deletions src/fw/drivers/accel.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,13 +168,16 @@ extern void accel_cb_new_sample(AccelDriverSample const *data);

//! Function called by driver whenever shake is detected.
//!
//! @param axis Axis which the shake was detected on
//! @param direction The sign indicates whether the shake was on the positive or
//! negative axis
//!
//! @note It is up to the implementer to filter out shake events triggered by the
//! vibrate motor.
extern void accel_cb_shake_detected(IMUCoordinateAxis axis, int32_t direction);
extern void accel_cb_shake_detected(void);

//! Function called by driver whenever a tap is detected.
//!
//! @param axis Axis which the tap was detected on
//! @param direction The sign indicates whether the tap was on the positive or
//! negative axis
extern void accel_cb_tap_detected(IMUCoordinateAxis axis, int32_t direction);

//! Function called by driver whenever a double tap is detected.
//!
Expand Down
21 changes: 1 addition & 20 deletions src/fw/drivers/imu/bma255/bma255.c
Original file line number Diff line number Diff line change
Expand Up @@ -277,26 +277,7 @@ static void prv_handle_motion_interrupts(void) {

bool anymotion = (int0_status & BMA255_INT_STATUS_0_SLOPE_MASK);
if (anymotion) {
const AccelConfig *cfg = &BOARD_CONFIG_ACCEL.accel_config;
IMUCoordinateAxis axis = AXIS_X;
bool invert = false;

if (int2_status & BMA255_INT_STATUS_2_SLOPE_FIRST_X) {
axis = AXIS_X;
invert = cfg->axes_inverts[AXIS_X];
} else if (int2_status & BMA255_INT_STATUS_2_SLOPE_FIRST_Y) {
axis = AXIS_Y;
invert = cfg->axes_inverts[AXIS_Y];
} else if (int2_status & BMA255_INT_STATUS_2_SLOPE_FIRST_Z) {
axis = AXIS_Z;
invert = cfg->axes_inverts[AXIS_Z];
} else {
BMA255_DBG("No Axis?: 0x%"PRIx8" 0x%"PRIx8, int0_status, int2_status);
}
int32_t direction = ((int2_status & BMA255_INT_STATUS_2_SLOPE_SIGN) == 0) ? 1 : -1;
direction *= (invert ? -1 : 1);

accel_cb_shake_detected(axis, direction);
accel_cb_shake_detected();
}
}

Expand Down
7 changes: 1 addition & 6 deletions src/fw/drivers/imu/bmi160/bmi160.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,12 +326,7 @@ static void prv_handle_motion_interrupts(void) {
// debug
bool anymotion = ((int0_status & BMI160_INT_STATUS_0_ANYM_MASK) != 0);
if (anymotion) {
int32_t direction;
IMUCoordinateAxis axis = prv_get_axis_direction(int0_status, int2_status,
BMI160_INT_STATUS_2_ANYM_SIGN,
BMI160_INT_STATUS_2_ANYM_FIRST_X, &direction);
BMI160_DBG("Anymotion on axis %"PRIu8" in direction %"PRId32, axis, direction);
accel_cb_shake_detected(axis, direction);
accel_cb_shake_detected();
}
bool double_tap = ((int0_status & BMI160_INT_STATUS_0_D_TAP_MASK) != 0);
if (double_tap) {
Expand Down
26 changes: 2 additions & 24 deletions src/fw/drivers/imu/lis2dw12/lis2dw12.c
Original file line number Diff line number Diff line change
Expand Up @@ -377,30 +377,8 @@ static void prv_lis2dw12_process_interrupts(void) {
(unsigned long)(now_ms - s_last_wake_event_ms));
} else {
s_last_wake_event_ms = now_ms;

// Use wake_up_src already read by all_sources_get - don't re-read the register
// as that can clear flags and cause race conditions with pulsed interrupts
IMUCoordinateAxis axis = AXIS_X;
int32_t direction = 1;

// Determine which axis triggered from already-read wake_up_src
const AccelConfig *cfg = &BOARD_CONFIG_ACCEL.accel_config;
if (all_sources.wake_up_src.x_wu) {
axis = AXIS_X;
} else if (all_sources.wake_up_src.y_wu) {
axis = AXIS_Y;
} else if (all_sources.wake_up_src.z_wu) {
axis = AXIS_Z;
}

// Use last known sample for direction instead of reading new data during interrupt
// Reading acceleration data here can interfere with FIFO operation
int16_t val = s_last_sample_mg[cfg->axes_offsets[axis]];
bool invert = cfg->axes_inverts[axis];
direction = (val >= 0 ? 1 : -1) * (invert ? -1 : 1);

PBL_LOG(LOG_LEVEL_DEBUG, "LIS2DW12: Shake detected; axis=%d, direction=%lu", axis, direction);
accel_cb_shake_detected(axis, direction);
PBL_LOG(LOG_LEVEL_DEBUG, "LIS2DW12: Shake detected");
accel_cb_shake_detected();
}

// The wake-up interrupt is latched - if the wake condition is still true (device still
Expand Down
27 changes: 2 additions & 25 deletions src/fw/drivers/imu/lsm6dso/lsm6dso.c
Original file line number Diff line number Diff line change
Expand Up @@ -848,31 +848,8 @@ static void prv_lsm6dso_process_interrupts(void) {
s_last_wake_event_ms = now_ms;
lsm6dso_wake_up_src_t wake_src;
if (lsm6dso_read_reg(&lsm6dso_ctx, LSM6DSO_WAKE_UP_SRC, (uint8_t *)&wake_src, 1) == 0) {
IMUCoordinateAxis axis = AXIS_X;
int32_t direction = 1; // LSM6DSO does not give sign directly for wake-up; approximate via
// sign of latest sample on axis
// Determine which axis triggered: order X,Y,Z
const AccelConfig *cfg = &BOARD_CONFIG_ACCEL.accel_config;
if (wake_src.x_wu) {
axis = AXIS_X;
} else if (wake_src.y_wu) {
axis = AXIS_Y;
} else if (wake_src.z_wu) {
axis = AXIS_Z;
}
// Read current sample to infer direction
int16_t accel_raw[3];
if (lsm6dso_acceleration_raw_get(&lsm6dso_ctx, accel_raw) == 0) {
int16_t val = accel_raw[cfg->axes_offsets[axis]];
bool invert = cfg->axes_inverts[axis];
direction = (val >= 0 ? 1 : -1) * (invert ? -1 : 1);
int16_t mg_x = prv_get_axis_projection_mg(X_AXIS, accel_raw);
int16_t mg_y = prv_get_axis_projection_mg(Y_AXIS, accel_raw);
int16_t mg_z = prv_get_axis_projection_mg(Z_AXIS, accel_raw);
prv_note_new_sample_mg(mg_x, mg_y, mg_z);
}
PBL_LOG(LOG_LEVEL_DEBUG, "LSM6DSO: Shake detected; axis=%d, direction=%lu", axis, direction);
accel_cb_shake_detected(axis, direction);
PBL_LOG(LOG_LEVEL_DEBUG, "LSM6DSO: Shake detected");
accel_cb_shake_detected();
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/fw/kernel/events.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ typedef struct PebblePhoneCaller PebblePhoneCaller;
typedef enum {
PEBBLE_NULL_EVENT = 0,
PEBBLE_ACCEL_SHAKE_EVENT,
PEBBLE_ACCEL_TAP_EVENT,
PEBBLE_ACCEL_DOUBLE_TAP_EVENT,
PEBBLE_BT_CONNECTION_EVENT,
PEBBLE_BT_CONNECTION_DEBOUNCED_EVENT,
Expand Down
10 changes: 9 additions & 1 deletion src/fw/services/common/accel_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -725,9 +725,17 @@ void accel_cb_new_sample(AccelDriverSample const *data) {
prv_dispatch_data(true /* post_event */);
}

void accel_cb_shake_detected(IMUCoordinateAxis axis, int32_t direction) {
void accel_cb_shake_detected(void) {
PebbleEvent e = {
.type = PEBBLE_ACCEL_SHAKE_EVENT,
};

event_put(&e);
}

void accel_cb_tap_detected(IMUCoordinateAxis axis, int32_t direction) {
PebbleEvent e = {
.type = PEBBLE_ACCEL_TAP_EVENT,
.accel_tap = {
.axis = axis,
.direction = direction,
Expand Down
1 change: 1 addition & 0 deletions src/fw/services/common/analytics/analytics_metric_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
DEVICE(ANALYTICS_DEVICE_METRIC_I2C_ERROR_COUNT, UINT8) \
DEVICE(ANALYTICS_DEVICE_METRIC_BUTTON_PRESSED_COUNT, UINT16) \
DEVICE(ANALYTICS_DEVICE_METRIC_ACCEL_SHAKE_COUNT, UINT16) \
DEVICE(ANALYTICS_DEVICE_METRIC_ACCEL_TAP_COUNT, UINT16) \
DEVICE(ANALYTICS_DEVICE_METRIC_ACCEL_DOUBLE_TAP_COUNT, UINT16) \
DEVICE(ANALYTICS_DEVICE_METRIC_ACCEL_PEEK_COUNT, UINT32) \
DEVICE(ANALYTICS_DEVICE_METRIC_ACCEL_SAMPLE_COUNT, UINT32) \
Expand Down
4 changes: 2 additions & 2 deletions src/fw/services/normal/stationary.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ void stationary_handle_battery_connection_change_event(void) {

//! A movement of the watch will make the watch wake up. In this state, the watch
//! will have a low tap threshold, so it will be sensitive to motion
static void prv_accel_tap_handler(AccelAxisType axis, int32_t direction) {
static void prv_accel_shake_handler(void) {
prv_handle_action(StationaryActionWakeUp);
}

Expand Down Expand Up @@ -249,7 +249,7 @@ static void prv_exit_disabled_state(void) {
s_stationary_count_down = STATIONARY_WAIT_BEFORE_ENGAGING_TIME_MINS;
PBL_ASSERTN(s_accel_session == NULL);
s_accel_session = accel_session_create();
accel_session_shake_subscribe(s_accel_session, prv_accel_tap_handler);
accel_session_shake_subscribe(s_accel_session, prv_accel_shake_handler);
event_service_client_subscribe(&s_button_event_info);

#if DEBUG_STATIONARY
Expand Down
Loading