working data acquisition face!

This commit is contained in:
Joey Castillo 2022-02-19 20:53:35 -05:00
parent 1ce103b6f6
commit 4cd86bff53
3 changed files with 316 additions and 298 deletions

View file

@ -5,31 +5,41 @@
#include "watch.h" #include "watch.h"
#include "watch_utility.h" #include "watch_utility.h"
#include "spiflash.h" #include "spiflash.h"
#include "lis2dw.h"
#define ACCELEROMETER_TRAINING_RECORD_DELETED ((uint64_t)(0b00)) #define ACCELEROMETER_DATA_ACQUISITION_INVALID ((uint64_t)(0b11)) // all bits are 1 when the flash is erased
#define ACCELEROMETER_TRAINING_RECORD_DATA ((uint64_t)(0b01)) #define ACCELEROMETER_DATA_ACQUISITION_HEADER ((uint64_t)(0b10))
#define ACCELEROMETER_TRAINING_RECORD_HEADER ((uint64_t)(0b10)) #define ACCELEROMETER_DATA_ACQUISITION_DATA ((uint64_t)(0b01))
#define ACCELEROMETER_TRAINING_RECORD_INVALID ((uint64_t)(0b11)) #define ACCELEROMETER_DATA_ACQUISITION_DELETED ((uint64_t)(0b00)) // You can always write a 0 to any 1 bit
typedef union { typedef union {
struct { struct {
int16_t temperature : 16; struct {
int8_t char1 : 8; uint16_t record_type : 2; // see above, helps us identify record types when reading back
int8_t char2 : 8; uint16_t range : 2; // accelerometer range (see lis2dw_range_t)
int32_t timestamp : 32; 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; } header;
struct { struct {
int16_t x_accel : 16; struct {
int16_t y_accel : 16; uint16_t record_type : 2; // duplicate; this is the same field as info above
int16_t z_accel : 16; uint16_t accel : 14; // X acceleration value, raw, offset by 16384
int32_t counter : 16; } 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; } data;
uint64_t value; uint64_t value;
} acceleromter_training_record_t; } accelerometer_data_acquisition_record_t;
static void cb_alarm_pressed(void) {
printf("Alarm button was pressed!\n");
}
static bool wait_for_flash_ready(void) { static bool wait_for_flash_ready(void) {
watch_set_pin_level(A3, false); watch_set_pin_level(A3, false);
@ -43,125 +53,6 @@ static bool wait_for_flash_ready(void) {
return ok; 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) { static void write_buffer_to_page(uint8_t *buf, uint16_t page) {
uint32_t address = 256 * 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 used_byte = 0x7F >> (page % 8);
uint8_t offset_in_buf = address_to_mark_used % 256; 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); watch_set_pin_level(A3, false);
spi_flash_read_data(header_page * 256, used_pages, 256); spi_flash_read_data(header_page * 256, used_pages, 256);
used_pages[offset_in_buf] = used_byte; 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(); wait_for_flash_ready();
} }
bool app_loop(void) { static void print_records_at_page(uint16_t page) {
// delay_ms(5000); 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; wait_for_flash_ready();
spi_flash_read_data(page * 256, (void *)records, 256);
// simulate logging 15 seconds of data for(int i = 0; i < 32; i++) {
watch_date_time date_time = watch_rtc_get_date_time(); switch (records[i].header.info.record_type) {
acceleromter_training_record_t record; case ACCELEROMETER_DATA_ACQUISITION_HEADER:
printing_header = true;
record.header.temperature = 0xC30; timestamp = records[i].header.timestamp;
record.header.temperature |= (ACCELEROMETER_TRAINING_RECORD_HEADER << 14); // temperature = records[i].header.info.temperature;
record.header.char1 = 'W'; printf("%c%c.sample%lld.", records[i].header.char1, records[i].header.char2, timestamp);
record.header.char2 = 'A'; range = records[i].header.info.range;
record.header.timestamp = watch_utility_date_time_to_unix_time(date_time, 0);; break;
case ACCELEROMETER_DATA_ACQUISITION_DATA:
acceleromter_training_record_t records[32]; if (printing_header) {
memset(records, 0xFF, sizeof(records)); printing_header = false;
records[0] = record; uint8_t filter = 0;
uint16_t pos = 1; switch (records[i].data.z.filter) {
uint32_t counter = 0; case LIS2DW_BANDWIDTH_FILTER_DIV2:
filter = 2;
printf("logging 15*25 data points for timestamp %ld\n", record.header.timestamp); break;
for(uint8_t i = 0; i < 15; i++) { case LIS2DW_BANDWIDTH_FILTER_DIV4:
for(uint8_t j = 0; j < 25; j++) { filter = 4;
record.data.x_accel = arc4random() & 0x3FFF; break;
record.data.x_accel |= ACCELEROMETER_TRAINING_RECORD_DATA << 14; case LIS2DW_BANDWIDTH_FILTER_DIV10:
record.data.y_accel = arc4random() & 0x3FFF; filter = 10;
record.data.z_accel = arc4random() & 0x3FFF; break;
record.data.counter = i; case LIS2DW_BANDWIDTH_FILTER_DIV20:
records[pos++] = record; filter = 20;
if (pos >= 32) { break;
printf("pos overflowed at counter %ld\n", counter); }
int16_t next_available_page = get_next_available_page(); switch (range) {
if (next_available_page > 0) { case LIS2DW_RANGE_16_G:
write_buffer_to_page((uint8_t *)records, next_available_page); lsb_value = (records[i].data.y.lpmode == LIS2DW_LP_MODE_1) ? 7.808 : 1.952;
wait_for_flash_ready(); 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; printf("%lld,%f,%f,%f\n",
memset(records, 0xFF, sizeof(records)); (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;
} }

View file

@ -27,14 +27,16 @@
#include "accelerometer_data_acquisition_face.h" #include "accelerometer_data_acquisition_face.h"
#include "watch_utility.h" #include "watch_utility.h"
#include "lis2dw.h" #include "lis2dw.h"
#include "spiflash.h"
#define ACCELEROMETER_RANGE LIS2DW_RANGE_4_G #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_FILTER LIS2DW_BANDWIDTH_FILTER_DIV2
#define ACCELEROMETER_LOW_NOISE true #define ACCELEROMETER_LOW_NOISE true
#define SECONDS_TO_RECORD 15 #define SECONDS_TO_RECORD 15
static const char activity_types[][3] = { static const char activity_types[][3] = {
"TE", // Testing
"ID", // Idle "ID", // Idle
"OF", // Off-wrist "OF", // Off-wrist
"SL", // Sleeping "SL", // Sleeping
@ -49,7 +51,6 @@ static const char activity_types[][3] = {
"SU", // Stairs Up "SU", // Stairs Up
"SD", // Stairs Down "SD", // Stairs Down
"WL", // Weight Lifting "WL", // Weight Lifting
"TE", // Testing
}; };
static void update(accelerometer_data_acquisition_state_t *state); 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 start_reading(accelerometer_data_acquisition_state_t *state, movement_settings_t *settings);
static void continue_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); 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 accelerometer_data_acquisition_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
(void) settings; (void) settings;
(void) watch_face_index; (void) watch_face_index;
accelerometer_data_acquisition_state_t *state = (accelerometer_data_acquisition_state_t *)*context_ptr;
if (*context_ptr == NULL) { if (*context_ptr == NULL) {
*context_ptr = malloc(sizeof(accelerometer_data_acquisition_state_t)); *context_ptr = malloc(sizeof(accelerometer_data_acquisition_state_t));
memset(*context_ptr, 0, 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->beep_with_countdown = true;
state->countdown_length = 3; 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 accelerometer_data_acquisition_face_activate(movement_settings_t *settings, void *context) {
(void) settings; (void) settings;
accelerometer_data_acquisition_state_t *state = (accelerometer_data_acquisition_state_t *)context; 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) { 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: case ACCELEROMETER_DATA_ACQUISITION_MODE_COUNTDOWN:
if (state->countdown_ticks > 0) { if (state->countdown_ticks > 0) {
state->countdown_ticks--; state->countdown_ticks--;
printf("countdown: %d\n", state->countdown_ticks);
if (state->countdown_ticks == 0) { if (state->countdown_ticks == 0) {
// at zero, begin reading // at zero, begin reading
state->mode = ACCELEROMETER_DATA_ACQUISITION_MODE_SENSING; 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 // beep for last two ticks before reading
if (state->beep_with_countdown) watch_buzzer_play_note(BUZZER_NOTE_C5, 75); 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); update(state);
break; break;
@ -187,8 +219,6 @@ bool accelerometer_data_acquisition_face_loop(movement_event_t event, movement_s
break; 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; return true;
} }
@ -231,8 +261,9 @@ static void update(accelerometer_data_acquisition_state_t *state) {
watch_set_colon(); 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); 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 // Bell if beep enabled
if (state->beep_with_countdown) watch_set_indicator(WATCH_INDICATOR_BELL); 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) { static void update_settings(accelerometer_data_acquisition_state_t *state) {
printf("TODO: Settings screen\n");
char buf[12]; char buf[12];
watch_clear_colon(); watch_clear_colon();
if (state->beep_with_countdown) watch_set_indicator(WATCH_INDICATOR_BELL); 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) { static void start_reading(accelerometer_data_acquisition_state_t *state, movement_settings_t *settings) {
(void) state; printf("Start reading\n");
watch_enable_i2c(); lis2dw_fifo_t fifo;
lis2dw_begin(); lis2dw_read_fifo(&fifo); // dump the fifo, this starts a fresh round of data in continue_reading
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();
accelerometer_data_acquisition_record_t record; accelerometer_data_acquisition_record_t record;
watch_date_time date_time = watch_rtc_get_date_time(); 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.char2 = activity_types[state->activity_type_index][1];
record.header.timestamp = state->starting_timestamp; 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; 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) { static void continue_reading(accelerometer_data_acquisition_state_t *state) {
printf("Continue reading\n");
lis2dw_fifo_t fifo; lis2dw_fifo_t fifo;
lis2dw_read_fifo(&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++) { 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) { static void finish_reading(accelerometer_data_acquisition_state_t *state) {
printf("finishing\n"); printf("Finish reading\n");
if (state->pos != 0) { if (state->pos != 0) {
_write_page(state); write_page(state);
} }
lis2dw_set_data_rate(LIS2DW_DATA_RATE_POWERDOWN); lis2dw_set_data_rate(LIS2DW_DATA_RATE_POWERDOWN);
watch_disable_i2c(); watch_disable_i2c();

View file

@ -34,29 +34,29 @@
typedef union { typedef union {
struct { struct {
union { struct {
int16_t record_type : 2; // see above, helps us identify record types when reading back uint16_t record_type : 2; // see above, helps us identify record types when reading back
int16_t range : 2; // accelerometer range (see lis2dw_range_t) uint16_t range : 2; // accelerometer range (see lis2dw_range_t)
int16_t temperature : 12; // raw value from the temperature sensor uint16_t temperature : 12; // raw value from the temperature sensor
} info; } info;
int8_t char1 : 8; // First character of the activity type uint8_t char1 : 8; // First character of the activity type
int8_t char2 : 8; // Second character of the activity type uint8_t char2 : 8; // Second character of the activity type
int32_t timestamp : 32; // UNIX timestamp for the measurement uint32_t timestamp : 32; // UNIX timestamp for the measurement
} header; } header;
struct { struct {
union { struct {
int16_t record_type : 2; // duplicate; this is the same field as info above uint16_t record_type : 2; // duplicate; this is the same field as info above
int16_t accel : 14; // X acceleration value, raw uint16_t accel : 14; // X acceleration value, raw, offset by 16384
} x; } x;
union { struct {
int16_t lpmode : 2; // low power mode (see lis2dw_low_power_mode_t) uint16_t lpmode : 2; // low power mode (see lis2dw_low_power_mode_t)
int16_t accel : 14; // Y acceleration value, raw uint16_t accel : 14; // Y acceleration value, raw, offset by 16384
} y; } y;
union { struct {
int16_t filter : 2; // bandwidth filtering selection (see lis2dw_bandwidth_filtering_mode_t) uint16_t filter : 2; // bandwidth filtering selection (see lis2dw_bandwidth_filtering_mode_t)
int16_t accel : 14; // Z acceleration value, raw uint16_t accel : 14; // Z acceleration value, raw, offset by 16384
} z; } z;
int32_t counter : 16; // number of seconds since timestamp in header uint32_t counter : 16; // number of seconds since timestamp in header
} data; } data;
uint64_t value; uint64_t value;
} accelerometer_data_acquisition_record_t; } accelerometer_data_acquisition_record_t;