summaryrefslogtreecommitdiffstats
path: root/apps/spi-test/app.c
blob: fab49c316a7fcb2afbf20866cd194726845fc458 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <peripheral_clk_config.h>
#include "watch.h"
#include "watch_utility.h"
#include "spiflash.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))

typedef union {
    struct {
        int16_t temperature : 16;
        int8_t char1 : 8;
        int8_t char2 : 8;
        int32_t timestamp : 32;
    } header;
    struct {
        int16_t x_accel : 16;
        int16_t y_accel : 16;
        int16_t z_accel : 16;
        int32_t counter : 16;
    } data;
    uint64_t value;
} acceleromter_training_record_t;

static void cb_alarm_pressed(void) {
    printf("Alarm button was pressed!\n");
}

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 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;

    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);

    return false;
}