diff --git a/apps/spi-test/app.c b/apps/spi-test/app.c index fab49c3..b1f28d8 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,125 +53,6 @@ static bool wait_for_flash_ready(void) { return ok; } -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; - 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"); - timestamp = records[i].header.timestamp; - temperature = records[i].header.temperature & 0x3FFF; - break; - case ACCELEROMETER_TRAINING_RECORD_INVALID: - printf(",,,,\n"); - break; - } - } -} - -static void print_records() { - uint8_t buf[256]; - 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++) { - uint8_t pages_written = buf[j]; - uint8_t start = 0; - if (i == 0 && j == 0) { - pages_written <<= 4; - start = 4; - } - for(int k = start; k < 7; k++) { - if ((pages_written & 0x80) == 0) { - print_records_at_page(i * 2048 + j * 8 + k); - } - pages_written <<= 1; - } - } - } - -} - -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) { -} - -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; @@ -184,14 +75,6 @@ static void write_buffer_to_page(uint8_t *buf, uint16_t page) { 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; @@ -203,58 +86,134 @@ static void write_buffer_to_page(uint8_t *buf, uint16_t page) { wait_for_flash_ready(); } -bool app_loop(void) { - // delay_ms(5000); +static void print_records_at_page(uint16_t page) { + 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; - 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(); + wait_for_flash_ready(); + spi_flash_read_data(page * 256, (void *)records, 256); + for(int i = 0; i < 32; i++) { + switch (records[i].header.info.record_type) { + case ACCELEROMETER_DATA_ACQUISITION_HEADER: + printing_header = true; + timestamp = records[i].header.timestamp; + // 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_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"); } - pos = 0; - memset(records, 0xFF, sizeof(records)); + 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() { + uint8_t buf[256]; + 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++) { + uint8_t pages_written = buf[j]; + uint8_t start = 0; + if (i == 0 && j == 0) { + pages_written <<= 4; + start = 4; + } + for(int k = start; k < 8; k++) { + if ((pages_written & 0x80) == 0) { + print_records_at_page(i * 2048 + j * 8 + k); + } + pages_written <<= 1; } } } - 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); - - return false; +} + +void app_init(void) { +} + +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) { +} + +void app_wake_from_standby(void) { +} + +bool app_loop(void) { + delay_ms(5000); + + 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 b619902..4fb75aa 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,18 +317,110 @@ 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; + } + } + } + + 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("\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]); + } + } + + 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 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) { + if (state->next_available_page > 0) { + write_buffer_to_page((uint8_t *)(state->records), state->next_available_page); + wait_for_flash_ready(); + } + 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, 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 >> 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 (state->pos >= 32) { + write_page(state); + } +} 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(); + 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(); @@ -310,89 +432,26 @@ static void start_reading(accelerometer_data_acquisition_state_t *state, movemen record.header.char2 = activity_types[state->activity_type_index][1]; record.header.timestamp = state->starting_timestamp; - uint8_t range = 0; - - 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; - } - state->records[state->pos++] = record; - - printf("TRAINING_%c%c_%d_RANGE%d_", record.header.char1, record.header.char2, record.header.timestamp, range); - - deleteme = true; -} - -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(); - } - // 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) { - 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; - 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); - } } 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 f6ca8c5..6da79f8 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;