STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
test_emmc_log.c
Go to the documentation of this file.
1/*
2 * Host tests for the eMMC flight log, against a RAM disk.
3 *
4 * The decoder below re-reads the disk image with its own CRC and its own
5 * reading of the layout in emmc_log.h, so a bug in the writer cannot hide by
6 * being decoded by the same code.
7 */
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11
12#include "emmc_log.h"
13
14#define CHECK(condition) \
15 do { \
16 if (!(condition)) { \
17 fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, #condition); \
18 exit(1); \
19 } \
20 } while (0)
21
22#define DATA_START 64U
23#define CHUNKS 4U
24#define BS EMMC_BLOCK_SIZE
25
26/* ---- RAM disk -------------------------------------------------------- */
27
28typedef struct {
29 uint8_t* blocks;
30 uint32_t capacity;
31 unsigned starts, reads, writes;
33 int write_failures; /* the next N writes fail, nothing lands */
34 bool torn_armed; /* the next write lands only torn_mask blocks */
35 uint32_t torn_mask; /* bit i = block i of that write lands */
36 bool powered_off; /* after a torn write, everything fails */
38 unsigned locks;
39} disk_t;
40
41static void disk_new(disk_t* d, uint32_t capacity) {
42 memset(d, 0, sizeof *d);
43 d->capacity = capacity;
44 d->blocks = calloc(capacity, BS);
45 CHECK(d->blocks != NULL);
46}
47
48/* Same contents, fresh power-up: counters and faults cleared. */
49static void disk_power_cycle(disk_t* d) {
50 uint8_t* b = d->blocks;
51 uint32_t c = d->capacity;
52 memset(d, 0, sizeof *d);
53 d->blocks = b;
54 d->capacity = c;
55}
56
57static emmc_status_t f_start(void* ctx, uint32_t* count) {
58 disk_t* d = ctx;
59 CHECK(d->lock_depth == 0);
60 d->starts++;
61 if (d->start_result != EMMC_OK) {
62 return d->start_result;
63 }
64 *count = d->capacity;
65 return EMMC_OK;
66}
67
68static emmc_status_t f_read(void* ctx, uint32_t lba, void* buf, uint32_t count,
69 uint32_t budget) {
70 disk_t* d = ctx;
71 CHECK(d->lock_depth == 0); /* never hold the queue lock across I/O */
72 CHECK(budget > 0);
73 CHECK(d->starts > 0);
74 CHECK(lba < d->capacity && count <= d->capacity - lba);
75 d->reads++;
76 if (d->powered_off) {
77 return EMMC_ERR_IO;
78 }
79 memcpy(buf, d->blocks + (size_t)lba * BS, (size_t)count * BS);
80 return EMMC_OK;
81}
82
83static emmc_status_t f_write(void* ctx, uint32_t lba, const void* buf,
84 uint32_t count, uint32_t budget) {
85 disk_t* d = ctx;
86 CHECK(d->lock_depth == 0);
87 CHECK(budget > 0);
88 CHECK(d->starts > 0);
89 CHECK(lba < d->capacity && count <= d->capacity - lba);
90 d->writes++;
91 if (d->powered_off) {
92 return EMMC_ERR_IO;
93 }
94 if (d->write_failures > 0) {
95 d->write_failures--;
96 return EMMC_ERR_IO;
97 }
98 if (d->torn_armed) {
99 for (uint32_t i = 0; i < count && i < 32; ++i) {
100 if (d->torn_mask & (UINT32_C(1) << i)) {
101 memcpy(d->blocks + (size_t)(lba + i) * BS,
102 (const uint8_t*)buf + (size_t)i * BS, BS);
103 }
104 }
105 d->powered_off = true;
106 return EMMC_ERR_IO;
107 }
108 memcpy(d->blocks + (size_t)lba * BS, buf, (size_t)count * BS);
109 return EMMC_OK;
110}
111
112static void f_lock(void* ctx) {
113 disk_t* d = ctx;
114 CHECK(d->lock_depth == 0); /* not re-entrant on the board either */
115 d->lock_depth++;
116 d->locks++;
117}
118
119static void f_unlock(void* ctx) {
120 disk_t* d = ctx;
121 CHECK(d->lock_depth == 1);
122 d->lock_depth--;
123}
124
126
128static uint8_t scratch[BS];
129
135
136static void log_new(emmc_log_t* log, disk_t* d) {
138 CHECK(emmc_log_init(log, &port, d, &c, chunks, CHUNKS, scratch) == EMMC_OK);
139}
140
141static void drain(emmc_log_t* log, uint32_t now) {
142 for (int i = 0; i < 64 && emmc_log_backlog(log) > 0; ++i) {
143 CHECK(emmc_log_service(log, now) == EMMC_OK);
144 }
145 CHECK(emmc_log_backlog(log) == 0);
146}
147
148/* ---- independent decoder ---------------------------------------------- */
149
150static uint32_t ref_crc(const uint8_t* p, size_t n) {
151 uint32_t crc = 0xFFFFFFFFu;
152 for (size_t i = 0; i < n; ++i) {
153 crc ^= p[i];
154 for (int k = 0; k < 8; ++k) {
155 crc = (crc >> 1) ^ (0xEDB88320u & (0u - (crc & 1u)));
156 }
157 }
158 return ~crc;
159}
160
161static uint32_t rd32(const uint8_t* p) {
162 return (uint32_t)p[0] | (uint32_t)p[1] << 8 | (uint32_t)p[2] << 16 |
163 (uint32_t)p[3] << 24;
164}
165
166typedef struct {
167 uint8_t type, len;
168 uint32_t t;
169 uint32_t session;
170 uint8_t data[255];
171} rec_t;
172
173typedef struct {
174 uint32_t epoch;
175 uint32_t blocks; /* valid blocks from DATA_START, contiguous */
176 uint32_t pads;
177 unsigned count;
178 rec_t rec[2048];
179} image_t;
180
182
183static void decode(const disk_t* d) {
184 memset(&img, 0, sizeof img);
185 const uint8_t* s = d->blocks;
186 CHECK(rd32(s) == 0x31425353u && rd32(s + 508) == ref_crc(s, 508));
187 CHECK(rd32(s + 4) == 1u && rd32(s + 12) == DATA_START &&
188 rd32(s + 16) == d->capacity);
189 img.epoch = rd32(s + 8);
190 for (uint32_t k = 0; DATA_START + k < d->capacity; ++k) {
191 const uint8_t* b = d->blocks + (size_t)(DATA_START + k) * BS;
192 if (rd32(b) != 0x31474C53u || rd32(b + 4) != img.epoch ||
193 rd32(b + 8) != k || rd32(b + 508) != ref_crc(b, 508)) {
194 break;
195 }
196 img.blocks++;
197 uint16_t used = (uint16_t)(b[18] | b[19] << 8);
198 CHECK(used <= 488);
199 if (b[16] == 2) {
200 CHECK(used == 0);
201 img.pads++;
202 continue;
203 }
204 CHECK(b[16] == 1);
205 for (uint16_t o = 0; o < used;) {
206 const uint8_t* r = b + 20 + o;
207 CHECK(img.count < 2048);
208 rec_t* x = &img.rec[img.count++];
209 x->type = r[0];
210 x->len = r[1];
211 x->t = rd32(r + 2);
212 x->session = rd32(b + 12);
213 memcpy(x->data, r + 6, x->len);
214 o = (uint16_t)(o + 6 + x->len);
215 CHECK(o <= used);
216 }
217 }
218}
219
220/* ---- tests ------------------------------------------------------------- */
221
222static void test_crc(void) {
223 CHECK(emmc_log_crc32("123456789", 9) == 0xCBF43926u);
224 uint8_t b[512];
225 for (int i = 0; i < 512; ++i) {
226 b[i] = (uint8_t)(i * 7 + 3);
227 }
228 CHECK(emmc_log_crc32(b, 512) == ref_crc(b, 512));
229}
230
231/* The eMMC is untouched until ARMED: no start, no read, no write. */
232static void test_no_io_before_arm(void) {
233 disk_t d;
234 emmc_log_t log;
235 disk_new(&d, DATA_START + 32 * 8);
236 log_new(&log, &d);
237 uint8_t x = 1;
238 CHECK(!emmc_log_append(&log, 0x10, 0, &x, 1));
240 CHECK(!emmc_log_append(&log, 0x10, 0, &x, 1));
241 for (uint32_t t = 0; t < 10000; t += 100) {
242 CHECK(emmc_log_service(&log, t) == EMMC_OK);
243 }
244 CHECK(d.starts == 0 && d.reads == 0 && d.writes == 0);
246 free(d.blocks);
247}
248
249static void fill_payload(uint8_t* p, unsigned i) {
250 for (unsigned j = 0; j < 32; ++j) {
251 p[j] = (uint8_t)(i + j);
252 }
253}
254
255static void test_session_roundtrip(void) {
256 disk_t d;
257 emmc_log_t log;
258 disk_new(&d, DATA_START + 32 * 16);
259 log_new(&log, &d);
261 for (unsigned i = 0; i < 100; ++i) {
262 uint8_t p[32];
263 fill_payload(p, i);
264 CHECK(emmc_log_append(&log, 0x10, 10 + i, p, 32));
265 }
267 drain(&log, 300);
268 CHECK(d.starts == 1);
269 CHECK(d.lock_depth == 0 && d.locks > 0);
270
271 decode(&d);
272 CHECK(img.epoch == 1);
273 CHECK(img.blocks == 32 * log.stats.chunks_written);
274 CHECK(img.count == 102);
275 CHECK(img.rec[0].type == EMMC_REC_SESSION_START &&
276 img.rec[0].data[0] == FLIGHT_ARMED && img.rec[0].t == 5);
277 for (unsigned i = 0; i < 100; ++i) {
278 uint8_t p[32];
279 fill_payload(p, i);
280 const rec_t* r = &img.rec[1 + i];
281 CHECK(r->type == 0x10 && r->len == 32 && r->t == 10 + i);
282 CHECK(memcmp(r->data, p, 32) == 0 && r->session == 1);
283 }
284 CHECK(img.rec[101].type == EMMC_REC_SESSION_END &&
285 img.rec[101].data[0] == FLIGHT_IDLE);
286 CHECK(log.stats.dropped == 0 && log.stats.records == 102);
287 /* Nothing written past the log's own end. */
288 for (size_t i = (size_t)(DATA_START + img.blocks) * BS;
289 i < (size_t)d.capacity * BS; ++i) {
290 CHECK(d.blocks[i] == 0);
291 }
292 free(d.blocks);
293}
294
295/* Re-arming in one power-up opens session 2 without re-initialising the
296 * card; a power cycle mounts, finds the end and opens session 3 after it. */
297static void test_sessions_and_remount(void) {
298 disk_t d;
299 emmc_log_t log;
300 disk_new(&d, DATA_START + 32 * 16);
301 log_new(&log, &d);
302 uint8_t x = 7;
303 for (int s = 0; s < 2; ++s) {
305 CHECK(emmc_log_append(&log, 0x11, 1, &x, 1));
307 drain(&log, 3);
308 }
309 CHECK(d.starts == 1);
310 uint32_t end = log.head;
311
313 log_new(&log, &d);
315 CHECK(emmc_log_append(&log, 0x11, 1, &x, 1));
316 emmc_log_flush(&log);
317 drain(&log, 0);
318 CHECK(d.starts == 1);
319 CHECK(log.head == end + 32);
320
321 decode(&d);
322 CHECK(img.blocks == 3 * 32);
323 CHECK(img.count == 3 + 3 + 2);
324 CHECK(img.rec[0].session == 1 && img.rec[3].session == 2);
325 CHECK(img.rec[6].session == 3 && img.rec[7].type == 0x11);
326 free(d.blocks);
327}
328
329/* Launch and apogee keep recording; the log records each change. */
331 disk_t d;
332 emmc_log_t log;
333 disk_new(&d, DATA_START + 32 * 16);
334 log_new(&log, &d);
338 uint8_t x = 1;
339 for (unsigned i = 0; i < 4; ++i) {
341 CHECK(emmc_log_on_state(&log, s, n, i));
342 s = n;
343 CHECK(emmc_log_append(&log, 0x10, i, &x, 1));
344 }
346 emmc_log_flush(&log);
347 drain(&log, 0);
348 decode(&d);
349 /* START, data, STATE(A->L), data, data (un-arm ignored), STATE(L->R),
350 * data */
351 CHECK(img.count == 7);
352 CHECK(img.rec[2].type == EMMC_REC_STATE &&
353 img.rec[2].data[0] == FLIGHT_ARMED &&
354 img.rec[2].data[1] == FLIGHT_LAUNCHED);
355 CHECK(img.rec[4].type == 0x10);
356 CHECK(img.rec[5].type == EMMC_REC_STATE &&
357 img.rec[5].data[1] == FLIGHT_RECOVERY);
358 free(d.blocks);
359}
360
361/* A partly filled chunk reaches the card flush_interval after the writer
362 * first sees it, padded out. */
363static void test_flush_interval(void) {
364 disk_t d;
365 emmc_log_t log;
366 disk_new(&d, DATA_START + 32 * 16);
367 log_new(&log, &d);
369 CHECK(emmc_log_service(&log, 1000) == EMMC_OK);
370 CHECK(emmc_log_service(&log, 1999) == EMMC_OK);
371 CHECK(d.writes == 0);
372 CHECK(emmc_log_service(&log, 2000) == EMMC_OK);
373 CHECK(d.writes == 2); /* superblock + the chunk */
374 CHECK(log.stats.pad_blocks == 31);
375 decode(&d);
376 CHECK(img.blocks == 32 && img.pads == 31 && img.count == 1);
377 free(d.blocks);
378}
379
380/* With the writer stalled, appends never block: they drop, are counted, and
381 * the first record after room returns says how many. */
382static void test_backpressure(void) {
383 disk_t d;
384 emmc_log_t log;
385 disk_new(&d, DATA_START + 32 * 16);
386 log_new(&log, &d);
388 uint8_t p[200] = {0};
389 unsigned ok = 0, refused = 0;
390 for (unsigned i = 0; i < 2000; ++i) {
391 if (emmc_log_append(&log, 0x10, i, p, sizeof p)) {
392 ok++;
393 } else {
394 refused++;
395 }
396 }
397 /* 2 records of 206 B per 488 B block (the 7 B SESSION_START fits beside
398 * them in the first), 32 blocks a chunk, every chunk full. */
399 CHECK(ok == 2 * 32 * CHUNKS);
400 CHECK(refused == 2000 - ok && log.stats.dropped == refused);
401 CHECK(emmc_log_backlog(&log) == CHUNKS);
402
403 drain(&log, 0);
404 CHECK(emmc_log_append(&log, 0x10, 5000, p, sizeof p));
405 emmc_log_flush(&log);
406 drain(&log, 0);
407 decode(&d);
408 const rec_t* r = &img.rec[img.count - 2];
409 CHECK(r->type == EMMC_REC_DROPPED && rd32(r->data) == refused);
410 CHECK(img.rec[img.count - 1].t == 5000);
411 free(d.blocks);
412}
413
414/* Power lost part-way through a chunk: the next power-up resumes right
415 * after the last block that landed. */
416static void test_torn_write(void) {
417 disk_t d;
418 emmc_log_t log;
419 disk_new(&d, DATA_START + 32 * 16);
420 log_new(&log, &d);
421 uint8_t x = 3;
423 CHECK(emmc_log_append(&log, 0x10, 0, &x, 1));
424 emmc_log_flush(&log);
425 drain(&log, 0);
426 CHECK(emmc_log_append(&log, 0x10, 1, &x, 1));
427 emmc_log_flush(&log);
428 d.torn_armed = true;
429 d.torn_mask = 0x3FFu; /* 10 of 32 blocks land */
431
433 log_new(&log, &d);
435 emmc_log_flush(&log);
436 drain(&log, 0);
437 CHECK(log.head == DATA_START + 32 + 10 + 32);
438 decode(&d);
439 CHECK(img.blocks == 32 + 10 + 32);
440 CHECK(img.rec[img.count - 1].session == 2);
441 free(d.blocks);
442}
443
444/* A torn write that lands out of order leaves a hole. Resuming at the hole
445 * would overwrite the blocks after it, so the mount looks past it. */
446static void test_torn_write_hole(void) {
447 disk_t d;
448 emmc_log_t log;
449 disk_new(&d, DATA_START + 32 * 16);
450 log_new(&log, &d);
452 emmc_log_flush(&log);
453 drain(&log, 0);
455 d.torn_armed = true;
456 /* Blocks 0-2 and 9-12 land. The binary search probes 32, 48, 40, 36,
457 * 34, 35 and stops at 35, inside the hole. */
458 d.torn_mask = 0x7u | (0xFu << 9);
460
462 log_new(&log, &d);
464 emmc_log_flush(&log);
465 drain(&log, 0);
466 CHECK(log.head == DATA_START + 32 + 13 + 32);
467 /* Blocks 8-12 of the torn chunk survived the new session's write. */
468 const uint8_t* b = d.blocks + (size_t)(DATA_START + 32 + 12) * BS;
469 CHECK(rd32(b + 8) == 32 + 12 && rd32(b + 508) == ref_crc(b, 508));
470 free(d.blocks);
471}
472
473/* A card holding an older log with an unreadable superblock is formatted
474 * with a newer epoch, so the old blocks never read as this log's. */
475static void test_stale_epoch(void) {
476 disk_t d;
477 emmc_log_t log;
478 disk_new(&d, DATA_START + 32 * 16);
479 log_new(&log, &d);
481 emmc_log_flush(&log);
482 drain(&log, 0);
483 CHECK(log.epoch == 1);
484 d.blocks[100] ^= 0xFF; /* corrupt the superblock */
485
487 log_new(&log, &d);
489 emmc_log_flush(&log);
490 drain(&log, 0);
491 CHECK(log.epoch == 2);
492 CHECK(log.head == DATA_START + 32);
493 decode(&d);
494 CHECK(img.epoch == 2 && img.blocks == 32);
495 free(d.blocks);
496}
497
498static void test_start_failure(void) {
499 disk_t d;
500 emmc_log_t log;
501 disk_new(&d, DATA_START + 32 * 16);
503 log_new(&log, &d);
504 uint8_t x = 1;
506 CHECK(emmc_log_append(&log, 0x10, 0, &x, 1));
507 emmc_log_flush(&log);
509 CHECK(log.disk == EMMC_DISK_FAULT && !log.recording);
510 CHECK(log.stats.chunks_lost == 1 && d.writes == 0);
511 CHECK(!emmc_log_append(&log, 0x10, 0, &x, 1));
514 CHECK(emmc_log_service(&log, 0) == EMMC_OK);
515 CHECK(d.starts == 1); /* no init loop (datasheet: read disturb) */
516 free(d.blocks);
517}
518
519static void test_write_retry(void) {
520 disk_t d;
521 emmc_log_t log;
522 disk_new(&d, DATA_START + 32 * 16);
523 log_new(&log, &d);
525 emmc_log_flush(&log);
526 /* Mount writes the superblock first, then chunk writes fail twice. */
527 CHECK(emmc_log_service(&log, 0) == EMMC_OK);
528 CHECK(log.stats.chunks_written == 1);
529 emmc_log_flush(&log);
530 CHECK(emmc_log_append(&log, 0x10, 0, "a", 1));
531 emmc_log_flush(&log);
532 d.write_failures = 2;
535 CHECK(emmc_log_service(&log, 0) == EMMC_OK);
536 CHECK(log.stats.write_errors == 2 && log.disk == EMMC_DISK_MOUNTED);
537
538 CHECK(emmc_log_append(&log, 0x10, 0, "b", 1));
539 emmc_log_flush(&log);
540 d.write_failures = 3;
541 for (int i = 0; i < 3; ++i) {
543 }
544 CHECK(log.disk == EMMC_DISK_FAULT && log.stats.chunks_lost == 1);
545 CHECK(!emmc_log_append(&log, 0x10, 0, "c", 1));
546 free(d.blocks);
547}
548
549static void test_full(void) {
550 disk_t d;
551 emmc_log_t log;
552 disk_new(&d, DATA_START + 32 * 2 + 5); /* room for two chunks */
553 log_new(&log, &d);
555 for (int i = 0; i < 3; ++i) {
556 CHECK(emmc_log_append(&log, 0x10, 0, "x", 1));
557 emmc_log_flush(&log);
558 }
559 CHECK(emmc_log_service(&log, 0) == EMMC_OK);
560 CHECK(emmc_log_service(&log, 0) == EMMC_OK);
562 CHECK(log.disk == EMMC_DISK_FULL && !log.recording);
563 CHECK(log.stats.chunks_written == 2 && log.stats.chunks_lost == 1);
564 CHECK(!emmc_log_append(&log, 0x10, 0, "x", 1));
565 free(d.blocks);
566}
567
568static void test_invalid_init(void) {
569 disk_t d;
570 emmc_log_t log;
572 disk_new(&d, 1024);
573 CHECK(emmc_log_init(&log, &port, &d, &c, chunks, 1, scratch) ==
577 CHECK(emmc_log_init(&log, &port, &d, &c, chunks, 2, NULL) ==
579 emmc_port_t half = port;
580 half.unlock = NULL;
581 CHECK(emmc_log_init(&log, &half, &d, &c, chunks, 2, scratch) ==
583 c.data_start_lba = 0;
584 CHECK(emmc_log_init(&log, &port, &d, &c, chunks, 2, scratch) ==
586 free(d.blocks);
587}
588
589int main(void) {
590 test_crc();
602 test_full();
604 puts("14 emmc log test groups passed");
605 return 0;
606}
flight_state_t
@ FLIGHT_RECOVERY
@ FLIGHT_SELF_TEST
@ FLIGHT_ARMED
@ FLIGHT_IDLE
@ FLIGHT_LAUNCHED
flight_event_t
@ FLIGHT_EV_LAUNCH_DETECTED
@ FLIGHT_EV_ARM
@ FLIGHT_EV_UNARM
@ FLIGHT_EV_APOGEE_DETECTED
bool emmc_log_on_state(emmc_log_t *log, flight_state_t from, flight_state_t to, uint32_t now_ms)
Definition emmc_log.c:200
uint32_t emmc_log_crc32(const void *data, uint32_t len)
Definition emmc_log.c:31
emmc_status_t emmc_log_service(emmc_log_t *log, uint32_t now_ms)
Definition emmc_log.c:424
emmc_status_t emmc_log_init(emmc_log_t *log, const emmc_port_t *port, void *context, const emmc_log_config_t *config, emmc_log_chunk_t *chunks, uint8_t chunk_count, uint8_t *scratch)
Definition emmc_log.c:177
uint8_t emmc_log_backlog(const emmc_log_t *log)
Definition emmc_log.c:252
bool emmc_log_append(emmc_log_t *log, uint8_t type, uint32_t t_ms, const void *data, uint8_t len)
Definition emmc_log.c:235
void emmc_log_flush(emmc_log_t *log)
Definition emmc_log.c:246
emmc_log_config_t emmc_log_default_config(void)
Definition emmc_log.c:167
@ EMMC_DISK_FULL
Definition emmc_log.h:95
@ EMMC_DISK_FAULT
Definition emmc_log.h:96
@ EMMC_DISK_UNMOUNTED
Definition emmc_log.h:93
@ EMMC_DISK_MOUNTED
Definition emmc_log.h:94
#define EMMC_LOG_MAX_CHUNKS
Definition emmc_log.h:57
#define EMMC_REC_DROPPED
Definition emmc_log.h:74
#define EMMC_REC_STATE
Definition emmc_log.h:72
#define EMMC_REC_SESSION_END
Definition emmc_log.h:73
#define EMMC_REC_SESSION_START
Definition emmc_log.h:71
emmc_status_t
Definition emmc_port.h:22
@ EMMC_ERR_NOT_READY
Definition emmc_port.h:26
@ EMMC_ERR_IO
Definition emmc_port.h:24
@ EMMC_ERR_PARAM
Definition emmc_port.h:27
@ EMMC_ERR_TIMEOUT
Definition emmc_port.h:25
@ EMMC_OK
Definition emmc_port.h:23
static const emmc_port_t port
Definition emmc_stm32.c:210
std::vector< daq::SensorDataChunkCollection > chunks
Definition main.cpp:55
static bool ok
Definition flight_e2e.c:435
#define DATA_START
Definition flight_e2e.c:105
#define BS
Definition flight_e2e.c:104
int32_t p
Definition flight_e2e.c:78
static uint32_t rd32(const uint8_t *p)
Definition flight_e2e.c:169
flight_state_t flight_state_next(flight_state_t state, flight_event_t event)
Definition flight_state.c:3
#define NULL
Definition usbd_def.h:44
*brief create JSON pointer *sa reference_tokens const string_t const string_t & b
Definition json.hpp:13878
size_type count(const key_type &key) const
Definition json.hpp:19264
*brief create JSON pointer *sa reference_tokens end()
return o
Definition json.hpp:13897
*brief user defined string literal for JSON values *sa std::size_t n
Definition json.hpp:24474
int lock_depth
emmc_status_t start_result
unsigned writes
uint8_t * blocks
unsigned locks
bool torn_armed
unsigned starts
bool powered_off
uint32_t torn_mask
int write_failures
unsigned reads
uint32_t capacity
uint32_t data_start_lba
Definition emmc_log.h:85
uint32_t records
Definition emmc_log.h:100
uint32_t chunks_lost
Definition emmc_log.h:103
uint32_t write_errors
Definition emmc_log.h:104
uint32_t chunks_written
Definition emmc_log.h:102
uint32_t pad_blocks
Definition emmc_log.h:105
uint32_t dropped
Definition emmc_log.h:101
bool recording
Definition emmc_log.h:124
emmc_log_stats_t stats
Definition emmc_log.h:145
emmc_disk_state_t disk
Definition emmc_log.h:139
uint32_t epoch
Definition emmc_log.h:141
uint32_t head
Definition emmc_log.h:142
void(* unlock)(void *context)
Definition emmc_port.h:56
uint32_t blocks
Definition flight_e2e.c:155
rec_t rec[2048]
unsigned count
uint32_t pads
uint32_t epoch
uint32_t session
uint8_t data[64]
Definition flight_e2e.c:150
uint32_t t
int main()
static boot_report_t r
static void test_session_roundtrip(void)
static void f_lock(void *ctx)
static void decode(const disk_t *d)
static void disk_power_cycle(disk_t *d)
static void test_invalid_init(void)
static emmc_status_t f_start(void *ctx, uint32_t *count)
static void test_sessions_and_remount(void)
#define CHECK(condition)
static void fill_payload(uint8_t *p, unsigned i)
static emmc_log_config_t config(void)
static image_t img
static emmc_status_t f_read(void *ctx, uint32_t lba, void *buf, uint32_t count, uint32_t budget)
static void test_stale_epoch(void)
static void test_torn_write(void)
#define CHUNKS
static void test_no_io_before_arm(void)
static emmc_status_t f_write(void *ctx, uint32_t lba, const void *buf, uint32_t count, uint32_t budget)
static uint32_t ref_crc(const uint8_t *p, size_t n)
static void test_write_retry(void)
static void test_flush_interval(void)
static void test_full(void)
static void f_unlock(void *ctx)
static uint32_t rd32(const uint8_t *p)
static void disk_new(disk_t *d, uint32_t capacity)
static void test_crc(void)
static void test_backpressure(void)
static void test_start_failure(void)
static uint8_t scratch[BS]
static void test_flight_keeps_recording(void)
static void test_torn_write_hole(void)
static void log_new(emmc_log_t *log, disk_t *d)
static void drain(emmc_log_t *log, uint32_t now)