diff options
| -rw-r--r-- | apps/spi-test/app.c | 321 | ||||
| -rw-r--r-- | movement/watch_faces/sensor/accelerometer_data_acquisition_face.c | 221 | ||||
| -rw-r--r-- | movement/watch_faces/sensor/accelerometer_data_acquisition_face.h | 34 | 
3 files changed, 297 insertions, 279 deletions
| diff --git a/apps/spi-test/app.c b/apps/spi-test/app.c index fab49c31..b1f28d8b 100644 --- a/apps/spi-test/app.c +++ b/apps/spi-test/app.c @@ -5,31 +5,41 @@  #include "watch.h"  #include "watch_utility.h"  #include "spiflash.h" +#include "lis2dw.h" -#define ACCELEROMETER_TRAINING_RECORD_DELETED ((uint64_t)(0b00)) -#define ACCELEROMETER_TRAINING_RECORD_DATA ((uint64_t)(0b01)) -#define ACCELEROMETER_TRAINING_RECORD_HEADER ((uint64_t)(0b10)) -#define ACCELEROMETER_TRAINING_RECORD_INVALID ((uint64_t)(0b11)) +#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 : 16; -        int8_t char1 : 8; -        int8_t char2 : 8; -        int32_t timestamp : 32; +        struct { +            uint16_t record_type : 2;   // see above, helps us identify record types when reading back +            uint16_t range : 2;         // accelerometer range (see lis2dw_range_t) +            uint16_t temperature : 12;  // raw value from the temperature sensor +        } info; +        uint8_t char1 : 8;              // First character of the activity type +        uint8_t char2 : 8;              // Second character of the activity type +        uint32_t timestamp : 32;        // UNIX timestamp for the measurement      } header;      struct { -        int16_t x_accel : 16; -        int16_t y_accel : 16; -        int16_t z_accel : 16; -        int32_t counter : 16; +        struct { +            uint16_t record_type : 2;   // duplicate; this is the same field as info above +            uint16_t accel : 14;        // X acceleration value, raw, offset by 16384 +        } x; +        struct { +            uint16_t lpmode : 2;        // low power mode (see lis2dw_low_power_mode_t) +            uint16_t accel : 14;        // Y acceleration value, raw, offset by 16384 +        } y; +        struct { +            uint16_t filter : 2;        // bandwidth filtering selection (see lis2dw_bandwidth_filtering_mode_t) +            uint16_t accel : 14;        // Z acceleration value, raw, offset by 16384 +        } z; +        uint32_t counter : 16;          // number of seconds since timestamp in header      } data;      uint64_t value; -} acceleromter_training_record_t; - -static void cb_alarm_pressed(void) { -    printf("Alarm button was pressed!\n"); -} +} accelerometer_data_acquisition_record_t;  static bool wait_for_flash_ready(void) {      watch_set_pin_level(A3, false); @@ -43,31 +53,109 @@ static bool wait_for_flash_ready(void) {      return ok;  } +static void write_buffer_to_page(uint8_t *buf, uint16_t page) { +    uint32_t address = 256 * page; + +    wait_for_flash_ready(); +    watch_set_pin_level(A3, false); +    spi_flash_command(CMD_ENABLE_WRITE); +    wait_for_flash_ready(); +    watch_set_pin_level(A3, false); +    spi_flash_write_data(address, buf, 256); +    wait_for_flash_ready(); + +    uint8_t buf2[256]; +    watch_set_pin_level(A3, false); +    spi_flash_read_data(address, buf2, 256); +    wait_for_flash_ready(); + +    uint8_t used_pages[256] = {0xFF}; +    uint16_t address_to_mark_used = page / 8; +    uint8_t header_page = address_to_mark_used / 256; +    uint8_t used_byte = 0x7F >> (page % 8); +    uint8_t offset_in_buf = address_to_mark_used % 256; + +    watch_set_pin_level(A3, false); +    spi_flash_read_data(header_page * 256, used_pages, 256); +    used_pages[offset_in_buf] = used_byte; +    watch_set_pin_level(A3, false); +    spi_flash_command(CMD_ENABLE_WRITE); +    wait_for_flash_ready(); +    watch_set_pin_level(A3, false); +    spi_flash_write_data(header_page * 256, used_pages, 256); +    wait_for_flash_ready(); +} +  static void print_records_at_page(uint16_t page) { -    if (page < 650) return; -    acceleromter_training_record_t records[32]; -    static uint32_t timestamp = 0; -    static uint16_t temperature = 0; +    accelerometer_data_acquisition_record_t records[32]; +    static uint64_t timestamp = 0; +    // static uint16_t temperature = 0; +    static lis2dw_range_t range = LIS2DW_RANGE_2_G; +    static double lsb_value = 1; +    static bool printing_header = false; +      wait_for_flash_ready();      spi_flash_read_data(page * 256, (void *)records, 256);      for(int i = 0; i < 32; i++) { -        switch (records[i].header.temperature >> 14) { -            case ACCELEROMETER_TRAINING_RECORD_DELETED: -                break; -            case ACCELEROMETER_TRAINING_RECORD_DATA: -                printf("%ld,%d,%d,%d,%d\n", timestamp + records[i].data.counter, records[i].data.x_accel, records[i].data.y_accel, records[i].data.z_accel, temperature); -                break; -            case ACCELEROMETER_TRAINING_RECORD_HEADER: -                printf("=== BEGIN %c%c EVENT AT %d ===\n", records[i].header.char1, records[i].header.char2, records[i].header.timestamp); -                printf("timestamp,x_raw,y_raw,z_raw,temperature\n"); +        switch (records[i].header.info.record_type) { +            case ACCELEROMETER_DATA_ACQUISITION_HEADER: +                printing_header = true;                  timestamp = records[i].header.timestamp; -                temperature = records[i].header.temperature & 0x3FFF; +                // temperature = records[i].header.info.temperature; +                printf("%c%c.sample%lld.", records[i].header.char1, records[i].header.char2, timestamp); +                range = records[i].header.info.range;                  break; -            case ACCELEROMETER_TRAINING_RECORD_INVALID: -                printf(",,,,\n"); +            case ACCELEROMETER_DATA_ACQUISITION_DATA: +                if (printing_header) { +                    printing_header = false; +                    uint8_t filter = 0; +                    switch (records[i].data.z.filter) { +                        case LIS2DW_BANDWIDTH_FILTER_DIV2: +                            filter = 2; +                            break; +                        case LIS2DW_BANDWIDTH_FILTER_DIV4: +                            filter = 4; +                            break; +                        case LIS2DW_BANDWIDTH_FILTER_DIV10: +                            filter = 10; +                            break; +                        case LIS2DW_BANDWIDTH_FILTER_DIV20: +                            filter = 20; +                            break; +                    } +                    switch (range) { +                        case LIS2DW_RANGE_16_G: +                            lsb_value = (records[i].data.y.lpmode == LIS2DW_LP_MODE_1) ? 7.808 : 1.952; +                            break; +                        case LIS2DW_RANGE_8_G: +                            lsb_value = (records[i].data.y.lpmode == LIS2DW_LP_MODE_1) ? 3.904 : 0.976; +                            break; +                        case LIS2DW_RANGE_4_G: +                            lsb_value = (records[i].data.y.lpmode == LIS2DW_LP_MODE_1) ? 1.952 : 0.488; +                            break; +                        case LIS2DW_RANGE_2_G: +                            lsb_value = (records[i].data.y.lpmode == LIS2DW_LP_MODE_1) ? 0.976 : 0.244; +                            break; +                    } +                    printf("RANGE%d_LP%d_FILT%d.CSV\n", range, records[i].data.y.lpmode + 1, filter); +                    printf("timestamp,accX,accY,accZ\n"); +                } +                printf("%lld,%f,%f,%f\n", +                        (timestamp * 100 + records[i].data.counter) * 10, +                        9.80665 * ((double)(records[i].data.x.accel - 8192)) * lsb_value / 1000, +                        9.80665 * ((double)(records[i].data.y.accel - 8192)) * lsb_value / 1000, +                        9.80665 * ((double)(records[i].data.z.accel - 8192)) * lsb_value / 1000); +                break; +            case ACCELEROMETER_DATA_ACQUISITION_INVALID: +            case ACCELEROMETER_DATA_ACQUISITION_DELETED: +                // don't print anything                  break;          } +        records[i].header.info.record_type = ACCELEROMETER_DATA_ACQUISITION_DELETED;      } + +    // uncomment this to mark all pages deleted +    // write_buffer_to_page((uint8_t *)records, page);  }  static void print_records() { @@ -82,7 +170,7 @@ static void print_records() {                  pages_written <<= 4;                  start = 4;              } -            for(int k = start; k < 7; k++) { +            for(int k = start; k < 8; k++) {                  if ((pages_written & 0x80) == 0) {                      print_records_at_page(i * 2048 + j * 8 + k);                  } @@ -94,44 +182,28 @@ static void print_records() {  }  void app_init(void) { -    delay_ms(5000); -    spi_flash_init(); -    watch_register_extwake_callback(BTN_ALARM, cb_alarm_pressed, true); - -    bool erase = false; -    if (erase) { -        printf("Erasing...\n"); -        wait_for_flash_ready(); -        watch_set_pin_level(A3, false); -        spi_flash_command(CMD_ENABLE_WRITE); -        wait_for_flash_ready(); -        watch_set_pin_level(A3, false); -        spi_flash_command(CMD_CHIP_ERASE); -        delay_ms(10000); -    } - -    uint8_t buf[256] = {0xFF}; - -    wait_for_flash_ready(); -    spi_flash_read_data(0, buf, 256); -    printf("byte 0 was %02x\n", buf[0]); -    if (buf[0] & 0xF0) { -        buf[0] = 0x0F; -        printf("setting it to 0x0F\n"); -        wait_for_flash_ready(); -        watch_set_pin_level(A3, false); -        spi_flash_command(CMD_ENABLE_WRITE); -        wait_for_flash_ready(); -        spi_flash_write_data(0, buf, 256); -    } - -    print_records();  }  void app_wake_from_backup(void) {  }  void app_setup(void) { +    spi_flash_init(); +    delay_ms(5000); + +    // bool erase = false; +    // if (erase) { +    //     printf("Erasing...\n"); +    //     wait_for_flash_ready(); +    //     watch_set_pin_level(A3, false); +    //     spi_flash_command(CMD_ENABLE_WRITE); +    //     wait_for_flash_ready(); +    //     watch_set_pin_level(A3, false); +    //     spi_flash_command(CMD_CHIP_ERASE); +    //     delay_ms(10000); +    // } +  +    print_records();  }  void app_prepare_for_standby(void) { @@ -140,121 +212,8 @@ void app_prepare_for_standby(void) {  void app_wake_from_standby(void) {  } -static int16_t get_next_available_page(void) { -    uint8_t buf[256] = {0}; - -    uint16_t page = 0; -    for(int16_t i = 0; i < 4; i++) { -        wait_for_flash_ready(); -        spi_flash_read_data(i * 256, buf, 256); -        for(int16_t j = 0; j < 256; j++) { -            if(buf[j] == 0) { -                page += 8; -            } else { -                page += __builtin_clz(((uint32_t)buf[j]) << 24); -                break; -            } -        } -    } - -    if (page >= 8192) return -1; - -    return page; -} - -static void write_buffer_to_page(uint8_t *buf, uint16_t page) { -    uint32_t address = 256 * page; - -    wait_for_flash_ready(); -    watch_set_pin_level(A3, false); -    spi_flash_command(CMD_ENABLE_WRITE); -    wait_for_flash_ready(); -    watch_set_pin_level(A3, false); -    spi_flash_write_data(address, buf, 256); -    wait_for_flash_ready(); - -    uint8_t buf2[256]; -    watch_set_pin_level(A3, false); -    spi_flash_read_data(address, buf2, 256); -    wait_for_flash_ready(); - -    uint8_t used_pages[256] = {0xFF}; -    uint16_t address_to_mark_used = page / 8; -    uint8_t header_page = address_to_mark_used / 256; -    uint8_t used_byte = 0x7F >> (page % 8); -    uint8_t offset_in_buf = address_to_mark_used % 256; - -    printf("\tWe wrote 256 bytes to address %ld, which was page %d.\n", address, page); - -    for(int i = 0; i < 256; i++) { -        if (buf[i] != buf2[i]) { -            printf("\tData mismatch detected at offset  %d: %d != %d.\n", i, buf[i], buf2[i]); -        } -    } - -    watch_set_pin_level(A3, false); -    spi_flash_read_data(header_page * 256, used_pages, 256); -    used_pages[offset_in_buf] = used_byte; -    watch_set_pin_level(A3, false); -    spi_flash_command(CMD_ENABLE_WRITE); -    wait_for_flash_ready(); -    watch_set_pin_level(A3, false); -    spi_flash_write_data(header_page * 256, used_pages, 256); -    wait_for_flash_ready(); -} -  bool app_loop(void) { -    // delay_ms(5000); - -    return; -         -    // simulate logging 15 seconds of data -    watch_date_time date_time = watch_rtc_get_date_time(); -    acceleromter_training_record_t record; - -    record.header.temperature = 0xC30; -    record.header.temperature |= (ACCELEROMETER_TRAINING_RECORD_HEADER << 14); -    record.header.char1 = 'W'; -    record.header.char2 = 'A'; -    record.header.timestamp = watch_utility_date_time_to_unix_time(date_time, 0);; - -    acceleromter_training_record_t records[32]; -    memset(records, 0xFF, sizeof(records)); -    records[0] = record; -    uint16_t pos = 1; -    uint32_t counter = 0; - -    printf("logging 15*25 data points for timestamp %ld\n", record.header.timestamp); -    for(uint8_t i = 0; i < 15; i++) { -        for(uint8_t j = 0; j < 25; j++) { -            record.data.x_accel = arc4random() & 0x3FFF; -            record.data.x_accel |= ACCELEROMETER_TRAINING_RECORD_DATA << 14; -            record.data.y_accel = arc4random() & 0x3FFF; -            record.data.z_accel = arc4random() & 0x3FFF; -            record.data.counter = i; -            records[pos++] = record; -            if (pos >= 32) { -                printf("pos overflowed at counter %ld\n", counter); -                int16_t next_available_page = get_next_available_page(); -                if (next_available_page > 0) { -                    write_buffer_to_page((uint8_t *)records, next_available_page); -                    wait_for_flash_ready(); -                } -                pos = 0; -                memset(records, 0xFF, sizeof(records)); -            } -        } -    } -    if (records[0].header.temperature >> 14 != ACCELEROMETER_TRAINING_RECORD_INVALID) { -        int16_t next_available_page = get_next_available_page(); -        if (next_available_page > 0) { -            printf("Partial write\n"); -            write_buffer_to_page((uint8_t *)records, next_available_page); -            wait_for_flash_ready(); -        } -    } - -    delay_ms(60000); +    delay_ms(5000); -    return false; +    return true;  } diff --git a/movement/watch_faces/sensor/accelerometer_data_acquisition_face.c b/movement/watch_faces/sensor/accelerometer_data_acquisition_face.c index b6199029..4fb75aa9 100644 --- a/movement/watch_faces/sensor/accelerometer_data_acquisition_face.c +++ b/movement/watch_faces/sensor/accelerometer_data_acquisition_face.c @@ -27,14 +27,16 @@  #include "accelerometer_data_acquisition_face.h"  #include "watch_utility.h"  #include "lis2dw.h" +#include "spiflash.h"  #define ACCELEROMETER_RANGE LIS2DW_RANGE_4_G -#define ACCELEROMETER_LPMODE LIS2DW_LP_MODE_1 +#define ACCELEROMETER_LPMODE LIS2DW_LP_MODE_2  #define ACCELEROMETER_FILTER LIS2DW_BANDWIDTH_FILTER_DIV2  #define ACCELEROMETER_LOW_NOISE true  #define SECONDS_TO_RECORD 15  static const char activity_types[][3] = { +    "TE",   // Testing      "ID",   // Idle      "OF",   // Off-wrist      "SL",   // Sleeping @@ -49,7 +51,6 @@ static const char activity_types[][3] = {      "SU",   // Stairs Up      "SD",   // Stairs Down      "WL",   // Weight Lifting -    "TE",   // Testing  };  static void update(accelerometer_data_acquisition_state_t *state); @@ -58,23 +59,43 @@ static void advance_current_setting(accelerometer_data_acquisition_state_t *stat  static void start_reading(accelerometer_data_acquisition_state_t *state, movement_settings_t *settings);  static void continue_reading(accelerometer_data_acquisition_state_t *state);  static void finish_reading(accelerometer_data_acquisition_state_t *state); +static bool wait_for_flash_ready(void); +static int16_t get_next_available_page(void); +static void write_buffer_to_page(uint8_t *buf, uint16_t page); +static void write_page(accelerometer_data_acquisition_state_t *state); +static void log_data_point(accelerometer_data_acquisition_state_t *state, lis2dw_reading_t reading, uint8_t centiseconds);  void accelerometer_data_acquisition_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {      (void) settings;      (void) watch_face_index; +    accelerometer_data_acquisition_state_t *state = (accelerometer_data_acquisition_state_t *)*context_ptr;      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 = (accelerometer_data_acquisition_state_t *)*context_ptr;          state->beep_with_countdown = true;          state->countdown_length = 3;      } +    spi_flash_init(); +    wait_for_flash_ready(); +    uint8_t buf[256] = {0xFF}; +    spi_flash_read_data(0, buf, 256); +    if (buf[0] & 0xF0) { +        // mark first four pages as used +        buf[0] = 0x0F; +        wait_for_flash_ready(); +        watch_set_pin_level(A3, false); +        spi_flash_command(CMD_ENABLE_WRITE); +        wait_for_flash_ready(); +        spi_flash_write_data(0, buf, 256); +    } +  }  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; +    state->next_available_page = get_next_available_page();  }  bool accelerometer_data_acquisition_face_loop(movement_event_t event, movement_settings_t *settings, void *context) { @@ -91,6 +112,7 @@ bool accelerometer_data_acquisition_face_loop(movement_event_t event, movement_s                  case ACCELEROMETER_DATA_ACQUISITION_MODE_COUNTDOWN:                      if (state->countdown_ticks > 0) {                          state->countdown_ticks--; +                        printf("countdown: %d\n", state->countdown_ticks);                          if (state->countdown_ticks == 0) {                              // at zero, begin reading                              state->mode = ACCELEROMETER_DATA_ACQUISITION_MODE_SENSING; @@ -102,6 +124,16 @@ bool accelerometer_data_acquisition_face_loop(movement_event_t event, movement_s                              // beep for last two ticks before reading                              if (state->beep_with_countdown) watch_buzzer_play_note(BUZZER_NOTE_C5, 75);                          } +                        if (state->countdown_ticks == 1) { +                            watch_enable_i2c(); +                            lis2dw_begin(); +                            lis2dw_set_data_rate(LIS2DW_DATA_RATE_25_HZ); +                            lis2dw_set_range(ACCELEROMETER_RANGE); +                            lis2dw_set_low_power_mode(ACCELEROMETER_LPMODE); +                            lis2dw_set_bandwidth_filtering(ACCELEROMETER_FILTER); +                            if (ACCELEROMETER_LOW_NOISE) lis2dw_set_low_noise_mode(true); +                            lis2dw_enable_fifo(); +                        }                      }                      update(state);                      break; @@ -187,8 +219,6 @@ bool accelerometer_data_acquisition_face_loop(movement_event_t event, movement_s              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;  } @@ -231,8 +261,9 @@ static void update(accelerometer_data_acquisition_state_t *state) {      watch_set_colon(); -    // special case: display full if full +    // special case: display full if full, <1% if nearly full      if (state->next_available_page < 0) watch_display_string(" FUL", 6); +    else if (state->next_available_page > 8110) watch_display_string("<1", 6);      // Bell if beep enabled      if (state->beep_with_countdown) watch_set_indicator(WATCH_INDICATOR_BELL); @@ -249,7 +280,6 @@ static void update(accelerometer_data_acquisition_state_t *state) {  }  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); @@ -287,112 +317,141 @@ static void advance_current_setting(accelerometer_data_acquisition_state_t *stat      }  } -bool deleteme = false; +static int16_t get_next_available_page(void) { +    uint8_t buf[256] = {0}; + +    uint16_t page = 0; +    for(int16_t i = 0; i < 4; i++) { +        wait_for_flash_ready(); +        spi_flash_read_data(i * 256, buf, 256); +        for(int16_t j = 0; j < 256; j++) { +            if(buf[j] == 0) { +                page += 8; +            } else { +                page += __builtin_clz(((uint32_t)buf[j]) << 24); +                break; +            } +        } +    } -static void start_reading(accelerometer_data_acquisition_state_t *state, movement_settings_t *settings) { -    (void) state; -    watch_enable_i2c(); -    lis2dw_begin(); -    lis2dw_set_data_rate(LIS2DW_DATA_RATE_25_HZ); -    lis2dw_set_range(ACCELEROMETER_RANGE); -    lis2dw_set_low_power_mode(ACCELEROMETER_LPMODE); -    lis2dw_set_bandwidth_filtering(ACCELEROMETER_FILTER); -    if (ACCELEROMETER_LOW_NOISE) lis2dw_set_low_noise_mode(true); -    lis2dw_enable_fifo(); +    if (page >= 8192) return -1; -    accelerometer_data_acquisition_record_t record; -    watch_date_time date_time = watch_rtc_get_date_time(); -    state->starting_timestamp = watch_utility_date_time_to_unix_time(date_time, movement_timezone_offsets[settings->bit.time_zone] * 60); -    record.header.info.record_type = ACCELEROMETER_DATA_ACQUISITION_HEADER; -    record.header.info.range = ACCELEROMETER_RANGE; -    record.header.info.temperature = lis2dw_get_temperature(); -    record.header.char1 = activity_types[state->activity_type_index][0]; -    record.header.char2 = activity_types[state->activity_type_index][1]; -    record.header.timestamp = state->starting_timestamp; - -    uint8_t range = 0; +    return page; +} -    switch (record.header.info.range) { -        case LIS2DW_RANGE_16_G: -            range = 16; -            break; -        case LIS2DW_RANGE_8_G: -            range = 8; -            break; -        case LIS2DW_RANGE_4_G: -            range = 4; -            break; -        case LIS2DW_RANGE_2_G: -            range = 2; -            break; +static void write_buffer_to_page(uint8_t *buf, uint16_t page) { +    uint32_t address = 256 * page; + +    wait_for_flash_ready(); +    watch_set_pin_level(A3, false); +    spi_flash_command(CMD_ENABLE_WRITE); +    wait_for_flash_ready(); +    watch_set_pin_level(A3, false); +    spi_flash_write_data(address, buf, 256); +    wait_for_flash_ready(); + +    uint8_t buf2[256]; +    watch_set_pin_level(A3, false); +    spi_flash_read_data(address, buf2, 256); +    wait_for_flash_ready(); + +    uint8_t used_pages[256] = {0xFF}; +    uint16_t address_to_mark_used = page / 8; +    uint8_t header_page = address_to_mark_used / 256; +    uint8_t used_byte = 0x7F >> (page % 8); +    uint8_t offset_in_buf = address_to_mark_used % 256; + +    printf("\twrite 256 bytes to address %ld, page %d.\n", address, page); +    for(int i = 0; i < 256; i++) { +        if (buf[i] != buf2[i]) { +            printf("\tData mismatch detected at offset  %d: %d != %d.\n", i, buf[i], buf2[i]); +        }      } -    state->records[state->pos++] = record; - -    printf("TRAINING_%c%c_%d_RANGE%d_", record.header.char1, record.header.char2, record.header.timestamp, range); +    watch_set_pin_level(A3, false); +    spi_flash_read_data(header_page * 256, used_pages, 256); +    used_pages[offset_in_buf] = used_byte; +    watch_set_pin_level(A3, false); +    spi_flash_command(CMD_ENABLE_WRITE); +    wait_for_flash_ready(); +    watch_set_pin_level(A3, false); +    spi_flash_write_data(header_page * 256, used_pages, 256); +    wait_for_flash_ready(); +} -    deleteme = true; +static bool wait_for_flash_ready(void) { +    watch_set_pin_level(A3, false); +    bool ok = true; +    uint8_t read_status_response[1] = {0x00}; +    do { +        ok = spi_flash_read_command(CMD_READ_STATUS, read_status_response, 1); +    } while ((read_status_response[0] & 0x3) != 0); +    delay_ms(1); // why do i need this? +    watch_set_pin_level(A3, true); +    return ok;  } -static void _write_page(accelerometer_data_acquisition_state_t *state) { +static void write_page(accelerometer_data_acquisition_state_t *state) {      if (state->next_available_page > 0) { -        // write_buffer_to_page((uint8_t *)records, next_available_page); -        // wait_for_flash_ready(); +        write_buffer_to_page((uint8_t *)(state->records), state->next_available_page); +        wait_for_flash_ready();      } -    // state->next_available_page = get_next_available_page();      state->next_available_page++;      state->pos = 0;      memset(state->records, 0xFF, sizeof(state->records));  } -static void _log_data_point(accelerometer_data_acquisition_state_t *state, lis2dw_reading_t reading) { +static void log_data_point(accelerometer_data_acquisition_state_t *state, lis2dw_reading_t reading, uint8_t centiseconds) {      accelerometer_data_acquisition_record_t record;      record.data.x.record_type = ACCELEROMETER_DATA_ACQUISITION_DATA;      record.data.y.lpmode = ACCELEROMETER_LPMODE;      record.data.z.filter = ACCELEROMETER_FILTER; -    record.data.x.accel = reading.x; -    record.data.y.accel = reading.y; -    record.data.z.accel = reading.z; -    record.data.counter = SECONDS_TO_RECORD - state->reading_ticks + 1; +    record.data.x.accel = (reading.x >> 2) + 8192; +    record.data.y.accel = (reading.y >> 2) + 8192; +    record.data.z.accel = (reading.z >> 2) + 8192; +    record.data.counter = 100 * (SECONDS_TO_RECORD - state->reading_ticks + 1) + centiseconds; +    printf("logged data point for %d\n", record.data.counter);      state->records[state->pos++] = record; -    if (deleteme) { -        deleteme = false; -        uint8_t filter = 0; -        switch (record.data.z.filter) { -            case LIS2DW_BANDWIDTH_FILTER_DIV2: -                filter = 2; -                break; -            case LIS2DW_BANDWIDTH_FILTER_DIV4: -                filter = 4; -                break; -            case LIS2DW_BANDWIDTH_FILTER_DIV10: -                filter = 10; -                break; -            case LIS2DW_BANDWIDTH_FILTER_DIV20: -                filter = 20; -                break; -        } -        printf("LP%d_FILT%d.CSV\n", record.data.y.lpmode + 1, filter); -    } -    printf("%d, %d, %d, %d\n", record.data.counter, record.data.x.accel, record.data.y.accel, record.data.z.accel);      if (state->pos >= 32) { -        _write_page(state); +        write_page(state);      }  } -static void continue_reading(accelerometer_data_acquisition_state_t *state) { +static void start_reading(accelerometer_data_acquisition_state_t *state, movement_settings_t *settings) { +    printf("Start reading\n");      lis2dw_fifo_t fifo; +    lis2dw_read_fifo(&fifo); // dump the fifo, this starts a fresh round of data in continue_reading +    accelerometer_data_acquisition_record_t record; +    watch_date_time date_time = watch_rtc_get_date_time(); +    state->starting_timestamp = watch_utility_date_time_to_unix_time(date_time, movement_timezone_offsets[settings->bit.time_zone] * 60); +    record.header.info.record_type = ACCELEROMETER_DATA_ACQUISITION_HEADER; +    record.header.info.range = ACCELEROMETER_RANGE; +    record.header.info.temperature = lis2dw_get_temperature(); +    record.header.char1 = activity_types[state->activity_type_index][0]; +    record.header.char2 = activity_types[state->activity_type_index][1]; +    record.header.timestamp = state->starting_timestamp; + +    state->records[state->pos++] = record; +} + +static void continue_reading(accelerometer_data_acquisition_state_t *state) { +    printf("Continue reading\n"); +    lis2dw_fifo_t fifo;      lis2dw_read_fifo(&fifo); + +    fifo.count = min(fifo.count, 25); // hacky, but we need a consistent data rate; if we got a 26th data point, chuck it. +    uint8_t offset = 4 * (25 - fifo.count); // also hacky: we're sometimes short at the start. align to beginning of next second. +      for(int i = 0; i < fifo.count; i++) { -        _log_data_point(state, fifo.readings[i]); +        log_data_point(state, fifo.readings[i], i * 4 + offset);      }  }  static void finish_reading(accelerometer_data_acquisition_state_t *state) { -    printf("finishing\n"); +    printf("Finish reading\n");      if (state->pos != 0) { -        _write_page(state); +        write_page(state);      }      lis2dw_set_data_rate(LIS2DW_DATA_RATE_POWERDOWN);      watch_disable_i2c(); diff --git a/movement/watch_faces/sensor/accelerometer_data_acquisition_face.h b/movement/watch_faces/sensor/accelerometer_data_acquisition_face.h index f6ca8c5b..6da79f8b 100644 --- a/movement/watch_faces/sensor/accelerometer_data_acquisition_face.h +++ b/movement/watch_faces/sensor/accelerometer_data_acquisition_face.h @@ -34,29 +34,29 @@  typedef union {      struct { -        union { -            int16_t record_type : 2;    // see above, helps us identify record types when reading back -            int16_t range : 2;          // accelerometer range (see lis2dw_range_t) -            int16_t temperature : 12;   // raw value from the temperature sensor +        struct { +            uint16_t record_type : 2;   // see above, helps us identify record types when reading back +            uint16_t range : 2;         // accelerometer range (see lis2dw_range_t) +            uint16_t temperature : 12;  // raw value from the temperature sensor          } info; -        int8_t char1 : 8;               // First character of the activity type -        int8_t char2 : 8;               // Second character of the activity type -        int32_t timestamp : 32;         // UNIX timestamp for the measurement +        uint8_t char1 : 8;              // First character of the activity type +        uint8_t char2 : 8;              // Second character of the activity type +        uint32_t timestamp : 32;        // UNIX timestamp for the measurement      } header;      struct { -        union { -            int16_t record_type : 2;    // duplicate; this is the same field as info above -            int16_t accel : 14;         // X acceleration value, raw +        struct { +            uint16_t record_type : 2;   // duplicate; this is the same field as info above +            uint16_t accel : 14;        // X acceleration value, raw, offset by 16384          } x; -        union { -            int16_t lpmode : 2;         // low power mode (see lis2dw_low_power_mode_t) -            int16_t accel : 14;         // Y acceleration value, raw +        struct { +            uint16_t lpmode : 2;        // low power mode (see lis2dw_low_power_mode_t) +            uint16_t accel : 14;        // Y acceleration value, raw, offset by 16384          } y; -        union { -            int16_t filter : 2;         // bandwidth filtering selection (see lis2dw_bandwidth_filtering_mode_t) -            int16_t accel : 14;         // Z acceleration value, raw +        struct { +            uint16_t filter : 2;        // bandwidth filtering selection (see lis2dw_bandwidth_filtering_mode_t) +            uint16_t accel : 14;        // Z acceleration value, raw, offset by 16384          } z; -        int32_t counter : 16;           // number of seconds since timestamp in header +        uint32_t counter : 16;          // number of seconds since timestamp in header      } data;      uint64_t value;  } accelerometer_data_acquisition_record_t; | 
