diff options
| author | Joey Castillo <joeycastillo@utexas.edu> | 2022-02-18 16:34:52 -0500 | 
|---|---|---|
| committer | Joey Castillo <joeycastillo@utexas.edu> | 2022-02-18 16:34:52 -0500 | 
| commit | efde4190f1c1d989530d1bd555739dffa1664da5 (patch) | |
| tree | f0131dad29d3c8c365eecdbdb5d11b6e2e9fd43d | |
| parent | 8cba4516bbd51f6459f1699979138c741f407f64 (diff) | |
| download | Sensor-Watch-efde4190f1c1d989530d1bd555739dffa1664da5.tar.gz Sensor-Watch-efde4190f1c1d989530d1bd555739dffa1664da5.tar.bz2 Sensor-Watch-efde4190f1c1d989530d1bd555739dffa1664da5.zip | |
movement: WIP app for capturing accelerometer data
| -rwxr-xr-x | movement/make/Makefile | 1 | ||||
| -rw-r--r-- | movement/movement_config.h | 3 | ||||
| -rw-r--r-- | movement/movement_faces.h | 1 | ||||
| -rw-r--r-- | movement/watch_faces/sensor/accelerometer_data_acquisition_face.c | 304 | ||||
| -rw-r--r-- | movement/watch_faces/sensor/accelerometer_data_acquisition_face.h | 97 | ||||
| -rw-r--r-- | watch-library/shared/driver/lis2dw.c | 1 | 
6 files changed, 404 insertions, 3 deletions
| diff --git a/movement/make/Makefile b/movement/make/Makefile index 9231d5ce..c1808d68 100755 --- a/movement/make/Makefile +++ b/movement/make/Makefile @@ -50,6 +50,7 @@ SRCS += \    ../watch_faces/complication/countdown_face.c \    ../watch_faces/complication/blinky_face.c \    ../watch_faces/complication/moon_phase_face.c \ +  ../watch_faces/sensor/accelerometer_data_acquisition_face.c \  # New watch faces go above this line.  # Leave this line at the bottom of the file; it has all the targets for making your project. diff --git a/movement/movement_config.h b/movement/movement_config.h index e68fcc9a..2969de55 100644 --- a/movement/movement_config.h +++ b/movement/movement_config.h @@ -28,9 +28,8 @@  #include "movement_faces.h"  const watch_face_t watch_faces[] = { +    accelerometer_data_acquisition_face,      simple_clock_face, -    beats_face, -    voltage_face,      preferences_face,      set_time_face,  }; diff --git a/movement/movement_faces.h b/movement/movement_faces.h index ae94efa7..e4ef102b 100644 --- a/movement/movement_faces.h +++ b/movement/movement_faces.h @@ -45,6 +45,7 @@  #include "countdown_face.h"  #include "blinky_face.h"  #include "moon_phase_face.h" +#include "accelerometer_data_acquisition_face.h"  // New includes go above this line.  #endif // MOVEMENT_FACES_H_ diff --git a/movement/watch_faces/sensor/accelerometer_data_acquisition_face.c b/movement/watch_faces/sensor/accelerometer_data_acquisition_face.c new file mode 100644 index 00000000..d16ea0d3 --- /dev/null +++ b/movement/watch_faces/sensor/accelerometer_data_acquisition_face.c @@ -0,0 +1,304 @@ +/* + * MIT License + * + * Copyright (c) 2022 Joey Castillo + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <stdlib.h> +#include <string.h> +#include "accelerometer_data_acquisition_face.h" + +static const char activity_types[][3] = { +    "ID",   // Idle +    "SL",   // Sleeping +    "WH",   // Washing Hands +    "WA",   // Walking +    "JO",   // Jogging +    "RU",   // Running +    "BI",   // Biking +    "HI",   // Hiking +    "EL",   // Elliptical +    "SU",   // Stairs Up +    "SD",   // Stairs Down +    "WL",   // Weight Lifting +    "TE",   // Testing +}; + +static void update(accelerometer_data_acquisition_state_t *state); +static void update_settings(accelerometer_data_acquisition_state_t *state); +static void advance_current_setting(accelerometer_data_acquisition_state_t *state); +static void start_reading(accelerometer_data_acquisition_state_t *state); +static void continue_reading(accelerometer_data_acquisition_state_t *state); +static void finish_reading(accelerometer_data_acquisition_state_t *state); + +void accelerometer_data_acquisition_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) { +    (void) settings; +    (void) watch_face_index; +    if (*context_ptr == NULL) { +        *context_ptr = malloc(sizeof(accelerometer_data_acquisition_state_t)); +        memset(*context_ptr, 0, sizeof(accelerometer_data_acquisition_state_t)); +        accelerometer_data_acquisition_state_t *state = (accelerometer_data_acquisition_state_t *)*context_ptr; +        state->beep_with_countdown = true; +        state->countdown_length = 10; +    } +    // Do any pin or peripheral setup here; this will be called whenever the watch wakes from deep sleep. +} + +void accelerometer_data_acquisition_face_activate(movement_settings_t *settings, void *context) { +    (void) settings; +    accelerometer_data_acquisition_state_t *state = (accelerometer_data_acquisition_state_t *)context; +    state->next_available_page = 123; +} + +bool accelerometer_data_acquisition_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { +    (void) settings; +    accelerometer_data_acquisition_state_t *state = (accelerometer_data_acquisition_state_t *)context; + +    switch (event.event_type) { +        case EVENT_ACTIVATE: +        case EVENT_TICK: +            switch (state->mode) { +                case ACCELEROMETER_DATA_ACQUISITION_MODE_IDLE: +                    update(state); +                    break; +                case ACCELEROMETER_DATA_ACQUISITION_MODE_COUNTDOWN: +                    if (state->countdown_ticks > 0) { +                        state->countdown_ticks--; +                        if (state->countdown_ticks == 0) { +                            // at zero, begin reading +                            state->mode = ACCELEROMETER_DATA_ACQUISITION_MODE_SENSING; +                            state->reading_ticks = 15; +                            // also beep if the user asked for it +                            if (state->beep_with_countdown) watch_buzzer_play_note(BUZZER_NOTE_C6, 75); +                            start_reading(state); +                        } else if (state->countdown_ticks < 3) { +                            // beep for last two ticks before reading +                            if (state->beep_with_countdown) watch_buzzer_play_note(BUZZER_NOTE_C5, 75); +                        } +                    } +                    update(state); +                    break; +                case ACCELEROMETER_DATA_ACQUISITION_MODE_SENSING: +                    if (state->reading_ticks > 0) { +                        state->reading_ticks--; +                        if (state->reading_ticks > 0) { +                            continue_reading(state); +                        } else { +                            finish_reading(state); +                            state->mode = ACCELEROMETER_DATA_ACQUISITION_MODE_IDLE; +                            watch_buzzer_play_note(BUZZER_NOTE_C4, 125); +                            watch_buzzer_play_note(BUZZER_NOTE_REST, 50); +                            watch_buzzer_play_note(BUZZER_NOTE_C4, 125); +                        } +                    } +                    update(state); +                    break; +                case ACCELEROMETER_DATA_ACQUISITION_MODE_SETTINGS: +                    update_settings(state); +                    break; +            } +            break; +        case EVENT_MODE_BUTTON_UP: +            movement_move_to_next_face(); +            break; +        case EVENT_LIGHT_BUTTON_UP: +            switch (state->mode) { +                case ACCELEROMETER_DATA_ACQUISITION_MODE_IDLE: +                    state->activity_type_index = (state->activity_type_index + 1) % (sizeof(activity_types) / sizeof(activity_types[0])); +                    update(state); +                    break; +                case ACCELEROMETER_DATA_ACQUISITION_MODE_SETTINGS: +                    state->settings_page++; +                    if (state->settings_page > ACCELEROMETER_DATA_ACQUISITION_SETTINGS_PAGE_REPEAT) { +                        state->settings_page = 0; +                        state->mode = ACCELEROMETER_DATA_ACQUISITION_MODE_IDLE; +                        update(state); +                    } else { +                        update_settings(state); +                    } +                    break; +                default: +                    break; +            } +            break; +        case EVENT_LIGHT_LONG_PRESS: +            movement_illuminate_led(); +            break; +        case EVENT_ALARM_BUTTON_UP: +            printf("Alarm up! Mode is %d\n", state->mode); +            switch (state->mode) { +                case ACCELEROMETER_DATA_ACQUISITION_MODE_IDLE: +                    state->countdown_ticks = state->countdown_length; +                    printf("Setting countdown ticks to %d\n", state->countdown_ticks); +                    state->mode = ACCELEROMETER_DATA_ACQUISITION_MODE_COUNTDOWN; +                    printf("and mode to %d\n", state->mode); +                    update(state); +                    break; +                case ACCELEROMETER_DATA_ACQUISITION_MODE_COUNTDOWN: +                    // cancel countdown +                    state->countdown_ticks = 0; +                    state->mode = ACCELEROMETER_DATA_ACQUISITION_MODE_IDLE; +                    update(state); +                    break; +                case ACCELEROMETER_DATA_ACQUISITION_MODE_SETTINGS: +                    advance_current_setting(state); +                    update_settings(state); +                    break; +                default: +                    break; +            } +            break; +        case EVENT_ALARM_LONG_PRESS: +            printf("Alarm long\n"); +            if (state->mode == ACCELEROMETER_DATA_ACQUISITION_MODE_IDLE) { +                state->repeat_ticks = 0; +                state->mode = ACCELEROMETER_DATA_ACQUISITION_MODE_SETTINGS; +                update_settings(state); +            } +            break; +        default: +            break; +    } + +    // return true if the watch can enter standby mode. If you are PWM'ing an LED or buzzing the buzzer here, +    // you should return false since the PWM driver does not operate in standby mode. +    return true; +} + +void accelerometer_data_acquisition_face_resign(movement_settings_t *settings, void *context) { +    (void) settings; +    accelerometer_data_acquisition_state_t *state = (accelerometer_data_acquisition_state_t *)context; +    if (state->reading_ticks) { +        state->reading_ticks = 0; +        finish_reading(state); +    } +    state->mode = ACCELEROMETER_DATA_ACQUISITION_MODE_IDLE; +    state->settings_page = 0; +    state->countdown_ticks = 0; +    state->repeat_ticks = 0; +    state->reading_ticks = 0; +} + +static void update(accelerometer_data_acquisition_state_t *state) { +    char buf[14]; +    uint8_t ticks = 0; +    switch (state->mode) { +        case ACCELEROMETER_DATA_ACQUISITION_MODE_IDLE: +            ticks = state->countdown_length; +            break; +        case ACCELEROMETER_DATA_ACQUISITION_MODE_COUNTDOWN: +            ticks = state->countdown_ticks; +            break; +        case ACCELEROMETER_DATA_ACQUISITION_MODE_SENSING: +            ticks = state->reading_ticks; +            break; +        default: +            ticks = 0; +            break; +    } +    sprintf(buf, "%s%2dre%2d#o", +            activity_types[state->activity_type_index], +            ticks, +            (8192 - state->next_available_page) / 82); +    watch_display_string(buf, 0); + +    watch_set_colon(); + +    // special case: display full if full +    if (state->next_available_page < 0) watch_display_string(" FUL", 6); + +    // Bell if beep enabled +    if (state->beep_with_countdown) watch_set_indicator(WATCH_INDICATOR_BELL); +    else watch_clear_indicator(WATCH_INDICATOR_BELL); + +    // Signal if sensing +    if (state->reading_ticks) watch_set_indicator(WATCH_INDICATOR_SIGNAL); +    else watch_clear_indicator(WATCH_INDICATOR_SIGNAL); + +    // LAP if repeating +    if (state->repeat_ticks) watch_set_indicator(WATCH_INDICATOR_LAP); +    else watch_clear_indicator(WATCH_INDICATOR_LAP); + +} + +static void update_settings(accelerometer_data_acquisition_state_t *state) { +    printf("TODO: Settings screen\n"); +    char buf[12]; +    watch_clear_colon(); +    if (state->beep_with_countdown) watch_set_indicator(WATCH_INDICATOR_BELL); +    else watch_clear_indicator(WATCH_INDICATOR_BELL); +    switch (state->settings_page) { +        case ACCELEROMETER_DATA_ACQUISITION_SETTINGS_PAGE_SOUND: +            sprintf(buf, "SO  Beep %c", state->beep_with_countdown ? 'Y' : 'N'); +            watch_display_string(buf, 0); +            break; +        case ACCELEROMETER_DATA_ACQUISITION_SETTINGS_PAGE_DELAY: +            sprintf(buf, "DL  %2d SeC", state->countdown_length); +            watch_display_string(buf, 0); +            break; +        case ACCELEROMETER_DATA_ACQUISITION_SETTINGS_PAGE_REPEAT: +            watch_display_string("rE  no1n&p", 0); +            break; +    } +} + +static void advance_current_setting(accelerometer_data_acquisition_state_t *state) { +    switch (state->settings_page) { +        case ACCELEROMETER_DATA_ACQUISITION_SETTINGS_PAGE_SOUND: +            state->beep_with_countdown = !state->beep_with_countdown; +            break; +        case ACCELEROMETER_DATA_ACQUISITION_SETTINGS_PAGE_DELAY: +            // this is so lazy, i'm sorry +            if (state->countdown_length == 1) state->countdown_length = 3; +            else if (state->countdown_length == 3) state->countdown_length = 10; +            else if (state->countdown_length == 10) state->countdown_length = 30; +            else state->countdown_length = 1; +            break; +        case ACCELEROMETER_DATA_ACQUISITION_SETTINGS_PAGE_REPEAT: +            // TODO: repeat setting +            break; +    } +} + +static void start_reading(accelerometer_data_acquisition_state_t *state) { +    (void) state; +    printf("TODO: Activate I2C bus and turn on accelerometer\n"); +    printf("TODO: Write header\n"); +} + +static void continue_reading(accelerometer_data_acquisition_state_t *state) { +    printf("TODO: Write one second of data\n"); +    for(uint8_t j = 0; j < 25; j++) { +        state->pos++; +        if (state->pos >= 32) { +            state->next_available_page++; +            state->pos = 0; +        } +    } +} + +static void finish_reading(accelerometer_data_acquisition_state_t *state) { +    if (state->pos != 0) { +        state->next_available_page++; +        state->pos = 0; +    } +    printf("TODO: Turn off accelerometer and disable I2C bus\n"); +} diff --git a/movement/watch_faces/sensor/accelerometer_data_acquisition_face.h b/movement/watch_faces/sensor/accelerometer_data_acquisition_face.h new file mode 100644 index 00000000..a8c74ccc --- /dev/null +++ b/movement/watch_faces/sensor/accelerometer_data_acquisition_face.h @@ -0,0 +1,97 @@ +/* + * MIT License + * + * Copyright (c) 2022 Joey Castillo + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef ACCELEROMETER_DATA_ACQUISITION_FACE_H_ +#define ACCELEROMETER_DATA_ACQUISITION_FACE_H_ + +#include "movement.h" + +#define ACCELEROMETER_DATA_ACQUISITION_INVALID ((uint64_t)(0b11))   // all bits are 1 when the flash is erased +#define ACCELEROMETER_DATA_ACQUISITION_HEADER ((uint64_t)(0b10)) +#define ACCELEROMETER_DATA_ACQUISITION_DATA ((uint64_t)(0b01))     +#define ACCELEROMETER_DATA_ACQUISITION_DELETED ((uint64_t)(0b00))   // You can always write a 0 to any 1 bit + +typedef union { +    struct { +        int16_t temperature_and_type : 16; // high two bits are record type, val & 0xFFF is temperature +        int8_t char1 : 8; +        int8_t char2 : 8; +        int32_t timestamp : 32; +    } header; +    struct { +        int16_t x_accel_and_type : 16;   // high two bits are record type, val & 0x3FFF is x_accel +        int16_t y_accel : 16; +        int16_t z_accel : 16; +        int32_t counter : 16; +    } data; +    uint64_t value; +} accelerometer_data_acquisition_record_t; + +typedef enum { +    ACCELEROMETER_DATA_ACQUISITION_MODE_IDLE, +    ACCELEROMETER_DATA_ACQUISITION_MODE_COUNTDOWN, +    ACCELEROMETER_DATA_ACQUISITION_MODE_SENSING, +    ACCELEROMETER_DATA_ACQUISITION_MODE_SETTINGS, +} accelerometer_data_acquisition_mode_t; + +typedef enum { +    ACCELEROMETER_DATA_ACQUISITION_SETTINGS_PAGE_SOUND, +    ACCELEROMETER_DATA_ACQUISITION_SETTINGS_PAGE_DELAY, +    ACCELEROMETER_DATA_ACQUISITION_SETTINGS_PAGE_REPEAT, +    // ACCELEROMETER_DATA_ACQUISITION_SETTINGS_PAGE_NAME, +} accelerometer_data_acquisition_settings_page_t; + +typedef struct { +    // mode +    accelerometer_data_acquisition_mode_t mode; +    accelerometer_data_acquisition_settings_page_t settings_page; +    // current settings +    uint8_t activity_type_index;   // active activity type +    bool beep_with_countdown;   // should we beep at the countdown +    uint8_t countdown_length;   // how many seconds to count down +    uint16_t repeat_interval;   // how many seconds to wait for a repeat +    // info about the flash chip +    int16_t next_available_page; +    // transient properties +    uint8_t countdown_ticks; +    uint8_t repeat_ticks; +    uint8_t reading_ticks; +    accelerometer_data_acquisition_record_t records[32]; +    uint16_t pos; +} accelerometer_data_acquisition_state_t; + +void accelerometer_data_acquisition_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr); +void accelerometer_data_acquisition_face_activate(movement_settings_t *settings, void *context); +bool accelerometer_data_acquisition_face_loop(movement_event_t event, movement_settings_t *settings, void *context); +void accelerometer_data_acquisition_face_resign(movement_settings_t *settings, void *context); + +#define accelerometer_data_acquisition_face ((const watch_face_t){ \ +    accelerometer_data_acquisition_face_setup, \ +    accelerometer_data_acquisition_face_activate, \ +    accelerometer_data_acquisition_face_loop, \ +    accelerometer_data_acquisition_face_resign, \ +    NULL, \ +}) + +#endif // ACCELEROMETER_DATA_ACQUISITION_FACE_H_ diff --git a/watch-library/shared/driver/lis2dw.c b/watch-library/shared/driver/lis2dw.c index 275c1c7c..b2c93d85 100644 --- a/watch-library/shared/driver/lis2dw.c +++ b/watch-library/shared/driver/lis2dw.c @@ -148,7 +148,6 @@ inline void lis2dw_enable_fifo(void) {  bool lis2dw_read_fifo(lis2dw_fifo_t *fifo_data) {      uint8_t temp = watch_i2c_read8(LIS2DW_ADDRESS, LIS2DW_REG_FIFO_SAMPLE);      bool overrun = !!(temp & LIS2DW_FIFO_SAMPLE_OVERRUN); -    uint8_t buffer[6];      fifo_data->count = temp & LIS2DW_FIFO_SAMPLE_COUNT; | 
