]> git.earman.xyz Git - sensor-watch.git/commitdiff
working data acquisition face!
authorJoey Castillo <joeycastillo@utexas.edu>
Sun, 20 Feb 2022 01:53:35 +0000 (20:53 -0500)
committerJoey Castillo <joeycastillo@utexas.edu>
Sun, 20 Feb 2022 01:53:41 +0000 (20:53 -0500)
apps/spi-test/app.c
movement/watch_faces/sensor/accelerometer_data_acquisition_face.c
movement/watch_faces/sensor/accelerometer_data_acquisition_face.h

index fab49c316a7fcb2afbf20866cd194726845fc458..b1f28d8b56e632d0b141e26be01f33975e84fb46 100644 (file)
@@ -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;
 }
index b6199029790ccb1c7297f240f13f0cdb0f6b5008..4fb75aa98bbbbd43e1170712ad4c2ffd5efb7723 100644 (file)
 #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();
index f6ca8c5b0d232ad786fcf99e01226ad8e09b0eee..6da79f8bb700f0d7ff9610cf54f2566e1d3146d3 100644 (file)
 
 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;