ACwing FC firmware
STM32WB55: attitude IEKF, altitude Kalman filter, flight core, protocol v2
Loading...
Searching...
No Matches
log_store.c
Go to the documentation of this file.
1
5#include "log_store.h"
6#include <string.h>
7
8static const log_flash_t *F;
9static uint16_t s_nsect;
10static uint16_t s_wp; /* next sector to write */
11static uint32_t s_serial; /* last serial written */
12static uint16_t s_last_id;
13static uint8_t s_used[4096 / 8]; /* bit per sector holding a header (16 MB max) */
14
16static uint8_t s_n;
17
18/* writer */
19static uint8_t s_open;
20static uint16_t s_cur; /* sector being written */
21static uint16_t s_seq;
22static uint32_t s_t0;
23static uint32_t s_pos; /* byte offset in the current sector */
24static uint8_t s_page[LOG_PAGE];
25static uint32_t s_page_base; /* offset in the sector of s_page[0] */
26
27/* ------------------------------------------------------------------ CRCs */
28uint8_t log_crc8(const uint8_t *p, uint32_t n)
29{
30 uint8_t c = 0;
31 while (n--) {
32 c ^= *p++;
33 for (int k = 0; k < 8; ++k) c = (uint8_t)((c & 0x80u) ? ((unsigned)c << 1) ^ 0x07u : ((unsigned)c << 1));
34 }
35 return c;
36}
37
38uint16_t log_crc16(const uint8_t *p, uint32_t n)
39{
40 uint16_t c = 0xFFFFu;
41 while (n--) {
42 c ^= (uint16_t)(*p++) << 8;
43 for (int k = 0; k < 8; ++k) c = (uint16_t)((c & 0x8000u) ? ((unsigned)c << 1) ^ 0x1021u : ((unsigned)c << 1));
44 }
45 return c;
46}
47
48/* ------------------------------------------------------------------ helpers */
49static uint32_t addr(uint16_t sect) { return (uint32_t)sect * LOG_SECTOR; }
50static uint16_t next(uint16_t s) { return (uint16_t)((s + 1u) % s_nsect); }
51static void set_used(uint16_t s, uint8_t on)
52{
53 if (on) s_used[s >> 3] |= (uint8_t)(1u << (s & 7u)); else s_used[s >> 3] &= (uint8_t)~(1u << (s & 7u));
54}
55static uint8_t is_used(uint16_t s) { return (uint8_t)((s_used[s >> 3] >> (s & 7u)) & 1u); }
56
57static int hdr_ok(const log_sector_hdr_t *h)
58{
59 return h->magic == LOG_MAGIC && h->format == LOG_FORMAT &&
60 h->crc == log_crc16((const uint8_t *)h, LOG_HDR_SIZE - 2u);
61}
62
63static int read_hdr(uint16_t s, log_sector_hdr_t *h)
64{
65 if (F->read(F->ctx, addr(s), h, sizeof *h) != 0) return -1;
66 return hdr_ok(h) ? 0 : -1;
67}
68
69/* the oldest log loses sector 'sect' (about to be erased) */
70static void forget_sector(uint16_t sect)
71{
72 if (!is_used(sect)) return;
73 set_used(sect, 0);
74 if (s_n && s_list[0].first == sect && !s_list[0].active) {
75 s_list[0].first = next(sect);
76 s_list[0].truncated = 1u;
77 if (--s_list[0].nsect == 0u) { memmove(&s_list[0], &s_list[1], (s_n - 1u) * sizeof s_list[0]); s_n--; }
78 }
79}
80
81/* ------------------------------------------------------------------ mount */
83{
84 F = f;
85 s_nsect = (uint16_t)(f->size / LOG_SECTOR);
86 if (s_nsect == 0u || s_nsect > sizeof s_used * 8u) return -1;
87 memset(s_used, 0, sizeof s_used);
88 s_n = 0; s_open = 0; s_serial = 0; s_last_id = 0; s_wp = 0;
89
90 /* newest sector = highest serial */
91 uint8_t any = 0;
92 uint16_t newest = 0;
93 for (uint16_t s = 0; s < s_nsect; ++s) {
95 if (read_hdr(s, &h) != 0) continue;
96 set_used(s, 1);
97 if (!any || (int32_t)(h.serial - s_serial) > 0) { s_serial = h.serial; newest = s; s_last_id = h.log_id; }
98 any = 1;
99 }
100 if (!any) return 0;
101 s_wp = next(newest);
102
103 /* logs in ring order, oldest first: start after the newest sector */
104 uint16_t s = s_wp;
105 for (uint16_t k = 0; k < s_nsect; ++k, s = next(s)) {
106 if (!is_used(s)) continue;
108 if (read_hdr(s, &h) != 0) continue;
109 log_entry_t *e = s_n ? &s_list[s_n - 1u] : NULL;
110 if (e && e->id == h.log_id && (uint16_t)(e->first + e->nsect) % s_nsect == s) { e->nsect++; continue; }
111 if (s_n == LOG_LIST_MAX) { memmove(&s_list[0], &s_list[1], (LOG_LIST_MAX - 1u) * sizeof s_list[0]); s_n--; }
112 e = &s_list[s_n++];
113 memset(e, 0, sizeof *e);
114 e->id = h.log_id; e->first = s; e->nsect = 1; e->t0_ms = h.t0_ms;
115 e->truncated = (uint8_t)(h.seq != 0u);
116 }
117 return 0;
118}
119
120uint8_t log_count(void) { return s_n; }
121const log_entry_t *log_entry(uint8_t i) { return i < s_n ? &s_list[i] : NULL; }
122uint8_t log_is_open(void) { return s_open; }
123
124const log_entry_t *log_find(uint16_t id)
125{
126 for (uint8_t i = 0; i < s_n; ++i) if (s_list[i].id == id) return &s_list[i];
127 return NULL;
128}
129
130uint8_t log_used_pct(void)
131{
132 if (!s_nsect) return 0;
133 uint32_t n = 0;
134 for (uint16_t s = 0; s < s_nsect; ++s) n += is_used(s);
135 return (uint8_t)((n * 100u + s_nsect / 2u) / s_nsect);
136}
137
138/* ------------------------------------------------------------------ writer */
139static int flush_page(void)
140{
141 const uint32_t used = s_pos - s_page_base;
142 if (used == 0u) return 0;
143 const int r = F->prog(F->ctx, addr(s_cur) + s_page_base, s_page, used);
144 memset(s_page, 0xFF, sizeof s_page);
146 return r;
147}
148
149/* new sector for the open log: erase it, header in the page buffer */
150static int start_sector(void)
151{
152 if (s_n && s_list[s_n - 1u].active) {
153 /* the open log would overwrite its own first sector: stop it */
154 if (s_list[s_n - 1u].nsect >= s_nsect) return -1;
155 }
156 s_cur = s_wp;
158 if (F->erase(F->ctx, addr(s_cur)) != 0) return -1;
159 s_wp = next(s_cur);
160
162 memset(&h, 0, sizeof h);
163 h.magic = LOG_MAGIC; h.serial = ++s_serial; h.log_id = s_last_id; h.seq = s_seq;
164 h.t0_ms = s_t0; h.format = LOG_FORMAT;
165 h.crc = log_crc16((const uint8_t *)&h, LOG_HDR_SIZE - 2u);
166 memset(s_page, 0xFF, sizeof s_page);
167 memcpy(s_page, &h, sizeof h);
169 set_used(s_cur, 1);
170 if (s_seq == 0u) {
171 if (s_n == LOG_LIST_MAX) { memmove(&s_list[0], &s_list[1], (LOG_LIST_MAX - 1u) * sizeof s_list[0]); s_n--; }
172 log_entry_t *e = &s_list[s_n++];
173 memset(e, 0, sizeof *e);
174 e->id = s_last_id; e->first = s_cur; e->nsect = 1; e->t0_ms = s_t0; e->active = 1;
175 } else {
176 s_list[s_n - 1u].nsect++;
177 }
178 s_seq++;
179 return 0;
180}
181
182int log_open(uint32_t t0)
183{
184 if (!F || s_open) return -1;
185 s_last_id = (uint16_t)(s_last_id + 1u);
186 if (s_last_id == 0u) s_last_id = 1u;
187 s_seq = 0; s_t0 = t0;
188 if (start_sector() != 0) return -1;
189 s_open = 1;
190 return 0;
191}
192
193int log_append(uint8_t type, const void *payload, uint8_t len)
194{
195 if (!s_open || len > LOG_REC_MAX || type == 0xFFu) return -1;
196 uint8_t rec[LOG_REC_MAX + LOG_REC_OVERHEAD];
197 rec[0] = type; rec[1] = len;
198 memcpy(&rec[2], payload, len);
199 rec[2u + len] = log_crc8(rec, 2u + len);
200 const uint32_t n = (uint32_t)len + LOG_REC_OVERHEAD;
201
202 if (s_pos + n > LOG_SECTOR) {
203 if (flush_page() != 0) return -1;
204 if (start_sector() != 0) { s_open = 0; s_list[s_n - 1u].active = 0; return -1; }
205 }
206 for (uint32_t k = 0; k < n; ++k) {
207 s_page[s_pos - s_page_base] = rec[k];
208 s_pos++;
209 if (s_pos - s_page_base == LOG_PAGE && flush_page() != 0) return -1;
210 }
211 return 0;
212}
213
214int log_close(void)
215{
216 if (!s_open) return 0;
217 const int r = flush_page();
218 s_open = 0;
219 if (s_n) s_list[s_n - 1u].active = 0;
220 return r;
221}
222
223/* ------------------------------------------------------------------ reader */
224uint32_t log_size(uint16_t id)
225{
226 const log_entry_t *e = log_find(id);
227 return e ? (uint32_t)e->nsect * LOG_SECTOR : 0u;
228}
229
230int log_read(uint16_t id, uint32_t off, void *buf, uint32_t n)
231{
232 const log_entry_t *e = log_find(id);
233 if (!e || e->active || off + n > (uint32_t)e->nsect * LOG_SECTOR) return -1; /* closed logs only */
234 uint8_t *b = (uint8_t *)buf;
235 while (n) {
236 const uint16_t sect = (uint16_t)((e->first + off / LOG_SECTOR) % s_nsect);
237 const uint32_t in = off % LOG_SECTOR;
238 uint32_t k = LOG_SECTOR - in;
239 if (k > n) k = n;
240 if (F->read(F->ctx, addr(sect) + in, b, k) != 0) return -1;
241 b += k; off += k; n -= k;
242 }
243 return 0;
244}
245
247{
248 if (!F || s_open) return -1;
249 for (uint16_t s = 0; s < s_nsect; ++s) {
250 if (!is_used(s)) continue;
251 if (F->erase(F->ctx, addr(s)) != 0) return -1;
252 set_used(s, 0);
253 }
254 s_n = 0; s_wp = 0; s_last_id = 0;
255 return 0;
256}
static batt_state_t s
Definition battery.c:21
double b[6]
Definition calib_mgr.c:53
uint32_t n
Definition calib_mgr.c:35
float used
Definition calib_mgr.c:50
#define LOG_PAGE
Definition log_format.h:31
#define LOG_MAGIC
"ACLG"
Definition log_format.h:29
#define LOG_HDR_SIZE
Definition log_format.h:32
#define LOG_REC_MAX
largest payload
Definition log_format.h:34
#define LOG_SECTOR
Definition log_format.h:30
#define LOG_REC_OVERHEAD
type, len, crc8
Definition log_format.h:33
#define LOG_FORMAT
Definition log_format.h:28
static int hdr_ok(const log_sector_hdr_t *h)
Definition log_store.c:57
uint8_t log_count(void)
Definition log_store.c:120
static log_entry_t s_list[LOG_LIST_MAX]
Definition log_store.c:15
const log_entry_t * log_find(uint16_t id)
Definition log_store.c:124
static uint16_t s_seq
Definition log_store.c:21
static uint8_t is_used(uint16_t s)
Definition log_store.c:55
static uint16_t s_last_id
Definition log_store.c:12
int log_append(uint8_t type, const void *payload, uint8_t len)
Definition log_store.c:193
int log_read(uint16_t id, uint32_t off, void *buf, uint32_t n)
bytes of a closed log 'id' from 'offset' (sectors concatenated, headers included)
Definition log_store.c:230
static uint32_t s_page_base
Definition log_store.c:25
static uint32_t addr(uint16_t sect)
Definition log_store.c:49
static uint8_t s_used[4096/8]
Definition log_store.c:13
int log_close(void)
Definition log_store.c:214
static uint16_t s_cur
Definition log_store.c:20
static int flush_page(void)
Definition log_store.c:139
static void forget_sector(uint16_t sect)
Definition log_store.c:70
static uint32_t s_t0
Definition log_store.c:22
int log_open(uint32_t t0)
0 = ok
Definition log_store.c:182
int log_mount(const log_flash_t *f)
0 = ok (empty flash is ok)
Definition log_store.c:82
uint16_t log_crc16(const uint8_t *p, uint32_t n)
Definition log_store.c:38
static uint8_t s_page[LOG_PAGE]
Definition log_store.c:24
const log_entry_t * log_entry(uint8_t i)
oldest first
Definition log_store.c:121
uint8_t log_used_pct(void)
Definition log_store.c:130
static uint16_t s_wp
Definition log_store.c:10
uint32_t log_size(uint16_t id)
nsect × LOG_SECTOR, 0 unknown
Definition log_store.c:224
uint8_t log_crc8(const uint8_t *p, uint32_t n)
Definition log_store.c:28
static uint16_t next(uint16_t s)
Definition log_store.c:50
uint8_t log_is_open(void)
Definition log_store.c:122
static uint16_t s_nsect
Definition log_store.c:9
static int read_hdr(uint16_t s, log_sector_hdr_t *h)
Definition log_store.c:63
static void set_used(uint16_t s, uint8_t on)
Definition log_store.c:51
static uint8_t s_open
Definition log_store.c:19
static int start_sector(void)
Definition log_store.c:150
static uint32_t s_serial
Definition log_store.c:11
int log_erase_all(void)
erases every sector that holds data; logs restart from id 1
Definition log_store.c:246
static const log_flash_t * F
Definition log_store.c:8
static uint8_t s_n
Definition log_store.c:16
static uint32_t s_pos
Definition log_store.c:23
Flight-log store: ring of sectors on a NOR flash (format in log_format.h).
#define LOG_LIST_MAX
Definition log_store.h:25
uint8_t on
Definition log_task.c:48
uint32_t off
Definition log_task.c:50
Definition log_store.h:36
uint32_t t0_ms
Definition log_store.h:42
uint16_t first
sector of the lowest seq still present
Definition log_store.h:38
uint16_t id
Definition log_store.h:37
uint16_t nsect
Definition log_store.h:39
uint8_t active
being written now
Definition log_store.h:41
uint8_t truncated
seq 0 overwritten
Definition log_store.h:40
flash backend; addresses in bytes from the start of the log area
Definition log_store.h:28
int(* erase)(void *ctx, uint32_t addr)
one 4 KB sector, blocking
Definition log_store.h:33
void * ctx
Definition log_store.h:29
uint32_t size
multiple of LOG_SECTOR
Definition log_store.h:30
int(* read)(void *ctx, uint32_t addr, void *buf, uint32_t n)
Definition log_store.h:31
int(* prog)(void *ctx, uint32_t addr, const void *buf, uint32_t n)
inside one 256-byte page
Definition log_store.h:32
sector header
Definition log_format.h:38
uint16_t log_id
increments for every new log
Definition log_format.h:41
uint16_t crc
CRC-16/CCITT-FALSE of the 18 bytes above
Definition log_format.h:46
uint32_t serial
global sector write counter: the newest sector has the highest
Definition log_format.h:40
uint16_t seq
sector index inside the log, 0 = first
Definition log_format.h:42
uint8_t format
LOG_FORMAT
Definition log_format.h:44
uint32_t t0_ms
uptime when the log started
Definition log_format.h:43