WIP: accelerometer activity tracking
This commit is contained in:
parent
4b490bed4c
commit
e435969b51
20
movement.c
20
movement.c
@ -78,6 +78,7 @@ void cb_tick(void);
|
||||
void cb_accelerometer_event(void);
|
||||
void cb_accelerometer_wake(void);
|
||||
uint8_t stationary_minutes = 0;
|
||||
uint8_t active_minutes = 0;
|
||||
#endif
|
||||
|
||||
#if __EMSCRIPTEN__
|
||||
@ -155,23 +156,30 @@ static inline void _movement_disable_fast_tick_if_possible(void) {
|
||||
|
||||
static void _movement_handle_top_of_minute(void) {
|
||||
watch_date_time_t date_time = watch_rtc_get_date_time();
|
||||
static const uint8_t stationary_minutes_for_sleep = 2;
|
||||
|
||||
#ifdef HAS_ACCELEROMETER
|
||||
if (stationary_minutes < 5) {
|
||||
// if the watch has been stationary for fewer than 5 minutes, find out if it's still stationary.
|
||||
if (HAL_GPIO_A4_read()) stationary_minutes++;
|
||||
bool accelerometer_is_alseep = HAL_GPIO_A4_read();
|
||||
if (!accelerometer_is_alseep) active_minutes++;
|
||||
printf("Active minutes: %d\n", active_minutes);
|
||||
|
||||
if (stationary_minutes < 2) {
|
||||
// if the watch has been stationary for fewer minutes than the cutoff, find out if it's still stationary.
|
||||
if (accelerometer_is_alseep) stationary_minutes++;
|
||||
printf("Stationary minutes: %d\n", stationary_minutes);
|
||||
|
||||
// does this mark five stationary minutes? and are we not already asleep?
|
||||
if (stationary_minutes == 5 && movement_state.le_mode_ticks != -1) {
|
||||
// should we go to sleep? and are we not already asleep?
|
||||
if (stationary_minutes >= stationary_minutes_for_sleep && movement_state.le_mode_ticks != -1) {
|
||||
// if so, enter low energy mode.
|
||||
printf("Entering low energy mode due to inactivity.\n");
|
||||
movement_request_sleep();
|
||||
}
|
||||
}
|
||||
|
||||
// log data every five minutes, and reset the active_minutes count.
|
||||
if ((date_time.unit.minute % 5) == 0) {
|
||||
_movement_log_data();
|
||||
active_minutes = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -718,7 +726,7 @@ void app_setup(void) {
|
||||
lis2dw_enable_stationary_motion_detection(); // stationary/motion detection mode keeps the data rate at 1.6 Hz even in sleep
|
||||
lis2dw_set_range(LIS2DW_RANGE_2_G); // Application note AN5038 recommends 2g range
|
||||
lis2dw_enable_sleep(); // allow acceleromter to sleep and wake on activity
|
||||
lis2dw_configure_wakeup_threshold(8); // g threshold to wake up: (2 * FS / 64) where FS is "full scale" of ±2g.
|
||||
lis2dw_configure_wakeup_threshold(32); // g threshold to wake up: (THS * FS / 64) where FS is "full scale" of ±2g.
|
||||
lis2dw_configure_6d_threshold(3); // 0-3 is 80, 70, 60, or 50 degrees. 50 is least precise, hopefully most sensitive?
|
||||
|
||||
// set up interrupts:
|
||||
|
||||
@ -34,16 +34,16 @@ movement_activity_data_point movement_activity_log[MOVEMENT_NUM_DATA_POINTS] = {
|
||||
// the absolute number of data points logged
|
||||
uint32_t data_points = 0;
|
||||
|
||||
// hacky: we're just tapping into Movement's global state for stationary detection.
|
||||
// hacky: we're just tapping into Movement's global state for activity detection.
|
||||
// do we need better API for this? i'm less bothered now that it's all in Movement.
|
||||
extern uint8_t stationary_minutes;
|
||||
extern uint8_t active_minutes;
|
||||
|
||||
void _movement_log_data(void) {
|
||||
size_t pos = data_points % MOVEMENT_NUM_DATA_POINTS;
|
||||
movement_activity_data_point data_point = {0};
|
||||
|
||||
// Movement tracks stationary minutes when deciding whether to sleep.
|
||||
data_point.bit.stationary_minutes = stationary_minutes;
|
||||
// Movement tracks active minutes when deciding whether to sleep.
|
||||
data_point.bit.active_minutes = active_minutes;
|
||||
|
||||
// orientation changes are counted in TC2. stash them in the data point...
|
||||
data_point.bit.orientation_changes = tc_count16_get_count(2);
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t stationary_minutes: 3;
|
||||
uint32_t active_minutes: 3;
|
||||
uint32_t orientation_changes: 9;
|
||||
uint32_t measured_temperature: 10;
|
||||
uint32_t measured_light: 10;
|
||||
|
||||
@ -37,6 +37,7 @@ const watch_face_t watch_faces[] = {
|
||||
activity_logging_face,
|
||||
voltage_face,
|
||||
days_since_face,
|
||||
accel_interrupt_count_face,
|
||||
preferences_face,
|
||||
set_time_face,
|
||||
};
|
||||
@ -49,7 +50,7 @@ const watch_face_t watch_faces[] = {
|
||||
* Some folks also like to use this to hide the preferences and time set faces from the normal rotation.
|
||||
* If you don't want any faces to be excluded, set this to 0 and a long Mode press will have no effect.
|
||||
*/
|
||||
#define MOVEMENT_SECONDARY_FACE_INDEX (MOVEMENT_NUM_FACES - 4)
|
||||
#define MOVEMENT_SECONDARY_FACE_INDEX (MOVEMENT_NUM_FACES - 5)
|
||||
|
||||
/* Custom hourly chime tune. Check movement_custom_signal_tunes.h for options. */
|
||||
#define SIGNAL_TUNE_DEFAULT
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
|
||||
// hacky: we're just tapping into Movement's global state.
|
||||
// we should make better API for this.
|
||||
extern uint8_t stationary_minutes;
|
||||
extern uint8_t active_minutes;
|
||||
|
||||
static void _accel_interrupt_count_face_update_display(accel_interrupt_count_state_t *state) {
|
||||
(void) state;
|
||||
@ -48,7 +48,7 @@ static void _accel_interrupt_count_face_update_display(accel_interrupt_count_sta
|
||||
|
||||
// Orientation changes / active minutes
|
||||
uint16_t orientation_changes = tc_count16_get_count(2);
|
||||
sprintf(buf, "%-3u/%2d", orientation_changes > 999 ? 999 : orientation_changes, stationary_minutes);
|
||||
sprintf(buf, "%-3u/%2d", orientation_changes > 999 ? 999 : orientation_changes, active_minutes);
|
||||
watch_display_text(WATCH_POSITION_BOTTOM, buf);
|
||||
}
|
||||
|
||||
@ -57,9 +57,6 @@ void accel_interrupt_count_face_setup(uint8_t watch_face_index, void ** context_
|
||||
if (*context_ptr == NULL) {
|
||||
*context_ptr = malloc(sizeof(accel_interrupt_count_state_t));
|
||||
memset(*context_ptr, 0, sizeof(accel_interrupt_count_state_t));
|
||||
accel_interrupt_count_state_t *state = (accel_interrupt_count_state_t *)*context_ptr;
|
||||
/// TODO: hook up to movement methods for tracking threshold
|
||||
state->threshold = 8;
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,6 +68,9 @@ void accel_interrupt_count_face_activate(void *context) {
|
||||
|
||||
// update more quickly to catch changes, also to blink setting
|
||||
movement_request_tick_frequency(4);
|
||||
|
||||
// fetch current threshold from accelerometer
|
||||
state->threshold = lis2dw_get_wakeup_threshold();
|
||||
}
|
||||
|
||||
bool accel_interrupt_count_face_loop(movement_event_t event, void *context) {
|
||||
@ -88,7 +88,7 @@ bool accel_interrupt_count_face_loop(movement_event_t event, void *context) {
|
||||
watch_display_text(WATCH_POSITION_BOTTOM, " ");
|
||||
} else {
|
||||
watch_display_text(WATCH_POSITION_TOP_RIGHT, " ");
|
||||
watch_display_text_with_fallback(WATCH_POSITION_TOP, "W_THS", "TH");
|
||||
watch_display_text_with_fallback(WATCH_POSITION_TOP, "WAKth", "TH");
|
||||
watch_display_float_with_best_effort(state->new_threshold * 0.03125, " G");
|
||||
printf("%s\n", buf);
|
||||
}
|
||||
|
||||
@ -76,7 +76,7 @@ static void _activity_logging_face_update_display(activity_logging_state_t *stat
|
||||
watch_display_text_with_fallback(WATCH_POSITION_TOP_LEFT, "LOG", "AC");
|
||||
sprintf(buf, "%2d", state->display_index);
|
||||
watch_display_text(WATCH_POSITION_TOP_RIGHT, buf);
|
||||
sprintf(buf, "%-3u/%2d", data_points[pos].bit.orientation_changes > 999 ? 999 : data_points[pos].bit.orientation_changes, data_points[pos].bit.stationary_minutes);
|
||||
sprintf(buf, "%-3u/%2d", data_points[pos].bit.orientation_changes > 999 ? 999 : data_points[pos].bit.orientation_changes, data_points[pos].bit.active_minutes);
|
||||
watch_display_text(WATCH_POSITION_BOTTOM, buf);
|
||||
}
|
||||
}
|
||||
@ -140,7 +140,7 @@ bool activity_logging_face_loop(movement_event_t event, void *context) {
|
||||
sprintf(buf, "%3d%3d", data_points[pos].bit.measured_temperature - 300, data_points[pos].bit.orientation_changes > 999 ? 999 : data_points[pos].bit.orientation_changes);
|
||||
buf[6] = 0;
|
||||
watch_display_text(WATCH_POSITION_BOTTOM, buf);
|
||||
sprintf(buf, "%2d", data_points[pos].bit.stationary_minutes);
|
||||
sprintf(buf, "%2d", data_points[pos].bit.active_minutes);
|
||||
watch_display_text(WATCH_POSITION_TOP_RIGHT, buf);
|
||||
|
||||
state->data_dump_idx++;
|
||||
|
||||
@ -129,6 +129,8 @@ static void _watch_disable_all_pins_except_rtc(void) {
|
||||
uint32_t config = RTC->MODE0.TAMPCTRL.reg;
|
||||
uint32_t portb_pins_to_disable = 0xFFFFFFFF;
|
||||
|
||||
/// FIXME: Watch library shouldn't be responsible for this, but ovement uses PB03 for orientation tracking. Keep it on.
|
||||
portb_pins_to_disable &= 0xFFFFFFF7;
|
||||
// if there's an action set on RTC/IN[0], leave PB00 configured
|
||||
if (config & RTC_TAMPCTRL_IN0ACT_Msk) portb_pins_to_disable &= 0xFFFFFFFE;
|
||||
// same with RTC/IN[1] and PB02
|
||||
@ -150,7 +152,10 @@ static void _watch_disable_all_pins_except_rtc(void) {
|
||||
static void _watch_disable_all_peripherals_except_slcd(void) {
|
||||
_watch_disable_tcc();
|
||||
watch_disable_adc();
|
||||
watch_disable_external_interrupts();
|
||||
/// FIXME: I just disabled this next line since we need the EIC's event system connection to count orientation changes.
|
||||
// The TODO item: need to power profile the impact of keeping EIC enabled, as well as the UI implications.
|
||||
// watch_disable_external_interrupts();
|
||||
|
||||
/// TODO: Actually disable all these peripherals! #SecondMovement
|
||||
// watch_disable_i2c();
|
||||
// SERCOM3->USART.CTRLA.reg &= ~SERCOM_USART_CTRLA_ENABLE;
|
||||
|
||||
@ -288,3 +288,7 @@ lis2dw_wakeup_source_t lis2dw_get_wakeup_source() {
|
||||
lis2dw_interrupt_source_t lis2dw_get_interrupt_source(void) {
|
||||
return (lis2dw_interrupt_source_t) watch_i2c_read8(LIS2DW_ADDRESS, LIS2DW_REG_ALL_INT_SRC);
|
||||
}
|
||||
|
||||
uint8_t lis2dw_get_wakeup_threshold(void) {
|
||||
return watch_i2c_read8(LIS2DW_ADDRESS, LIS2DW_REG_WAKE_UP_THS) & 0b00111111;
|
||||
}
|
||||
|
||||
@ -375,4 +375,6 @@ lis2dw_interrupt_source_t lis2dw_get_interrupt_source(void);
|
||||
|
||||
lis2dw_wakeup_source_t lis2dw_get_wakeup_source(void);
|
||||
|
||||
uint8_t lis2dw_get_wakeup_threshold(void);
|
||||
|
||||
#endif // LIS2DW_H
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user