1 /**
2 *****************************************************************************************
3 *
4 * @file app_log_store.c
5 *
6 * @brief App Log tore Implementation.
7 *
8 *****************************************************************************************
9 * @attention
10 #####Copyright (c) 2019 GOODIX
11 All rights reserved.
12
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions are met:
15 * Redistributions of source code must retain the above copyright
16 notice, this list of conditions and the following disclaimer.
17 * Redistributions in binary form must reproduce the above copyright
18 notice, this list of conditions and the following disclaimer in the
19 documentation and/or other materials provided with the distribution.
20 * Neither the name of GOODIX nor the names of its contributors may be used
21 to endorse or promote products derived from this software without
22 specific prior written permission.
23
24 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
28 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 POSSIBILITY OF SUCH DAMAGE.
35 *****************************************************************************************
36 */
37
38
39 /*
40 * INCLUDE FILES
41 *****************************************************************************************
42 */
43 #if APP_LOG_STORE_ENABLE
44 #include "utility.h"
45
46 /*
47 * DEFINE
48 *****************************************************************************************
49 */
50 #define APP_LOG_STORE_MAGIC 0x47444442 /**< Magic for app log store: "GDDB". */
51 #define APP_LOG_STORE_TIME_SIZE 26 /**< [00000000.000] */
52 #define APP_LOG_STORE_TIME_DEFAULT "[1970/01/01 00:00:00:000] "
53 #define APP_LOG_STORE_CACHE_SIZE ((APP_LOG_STORE_LINE_SIZE) * (APP_LOG_STORE_CACHE_NUM))
54 #define APP_LOG_STORE_ONECE_OP_SIZE 1024
55 #define APP_LOG_STORE_BUSY_BIT (0x01 << 0)
56 #define APP_LOG_STORE_SAVE_BIT (0x01 << 1)
57 #define APP_LOG_STORE_DUMP_BIT (0x01 << 2)
58
59 #define OFFSET_0 0
60 #define OFFSET_1 1
61 #define OFFSET_2 2
62
63
64 /*
65 * STRUCTURES
66 *****************************************************************************************
67 */
68 /**@brief App log store head info. */
69 typedef struct {
70 uint32_t magic; /**< Magic for app log store. */
71 uint32_t db_addr; /**< Start address of app log db flash. */
72 uint32_t db_size; /**< Size of app log db flash. */
73 uint32_t offset; /**< Offset of end log data. */
74 uint16_t flip_over; /**< Is flip over. */
75 uint16_t check_sum; /**< Check sum for head info. */
76 } log_store_head_t;
77
78 /**@brief App log store environment variable. */
79 struct log_store_env_t {
80 bool initialized;
81 uint8_t store_status;
82 log_store_head_t store_head;
83 uint16_t head_nv_tag;
84 uint16_t blk_size;
85 };
86
87 /*
88 * LOCAL VARIABLE DEFINITIONS
89 *****************************************************************************************
90 */
91 static struct log_store_env_t s_log_store_env;
92 static app_log_store_op_t s_log_store_ops;
93 static app_log_store_dump_cb_t s_log_store_dump_cb;
94 static uint32_t s_log_store_dump_offset;
95 static ring_buffer_t s_log_store_rbuf;
96 static uint8_t s_log_store_cache[APP_LOG_STORE_CACHE_SIZE];
97
98 /*
99 * LOCAL FUNCTION DEFINITIONS
100 *****************************************************************************************
101 */
log_store_check_sum_calc(uint8_t * p_data,uint32_t len)102 static uint32_t log_store_check_sum_calc(uint8_t *p_data, uint32_t len)
103 {
104 uint32_t check_sum = 0;
105
106 if (p_data && len) {
107 for (uint8_t i = 0; i < len; i++) {
108 check_sum += p_data[i];
109 }
110 }
111
112 return check_sum;
113 }
114
log_store_head_check(log_store_head_t * p_head,uint32_t db_addr,uint32_t db_size)115 static bool log_store_head_check(log_store_head_t *p_head, uint32_t db_addr, uint32_t db_size)
116 {
117 uint16_t head_len = sizeof(log_store_head_t);
118 uint8_t *head_data = (uint8_t *)p_head;
119
120 if (p_head->magic != APP_LOG_STORE_MAGIC ||
121 p_head->db_addr != db_addr ||
122 p_head->db_size != db_size ||
123 p_head->offset > db_size) {
124 return false;
125 }
126
127 if (p_head->check_sum != log_store_check_sum_calc(head_data, head_len - OFFSET_2)) {
128 return false;
129 }
130
131 return true;
132 }
133
log_store_head_update(uint16_t nv_tag,log_store_head_t * p_head)134 static bool log_store_head_update(uint16_t nv_tag, log_store_head_t *p_head)
135 {
136 uint16_t head_len = sizeof(log_store_head_t);
137 uint8_t *head_data = (uint8_t *)p_head;
138
139 p_head->check_sum = log_store_check_sum_calc(head_data, head_len - OFFSET_2);
140
141 if (nvds_put(nv_tag, head_len, (uint8_t *)p_head)) {
142 return false;
143 }
144
145 return true;
146 }
147
log_store_time_stamp_encode(uint8_t * p_buffer,uint8_t buffer_size)148 static bool log_store_time_stamp_encode(uint8_t *p_buffer, uint8_t buffer_size)
149 {
150 if (buffer_size != APP_LOG_STORE_TIME_SIZE) {
151 return false;
152 }
153
154 app_log_store_time_t rtc_time = {0};
155
156 s_log_store_ops.time_get(&rtc_time);
157
158 if (APP_LOG_STORE_TIME_SIZE == snprintf_s((char *)p_buffer, APP_LOG_STORE_TIME_SIZE, \
159 APP_LOG_STORE_TIME_SIZE, \
160 "[%04d/%02d/%02d %02d:%02d:%02d:%03d] ", \
161 rtc_time.year, rtc_time.month, rtc_time.day, \
162 rtc_time.hour, rtc_time.min, \
163 rtc_time.sec, rtc_time.msec)) {
164 return true;
165 }
166
167 return false;
168 }
169
log_store_data_flash_write(void)170 static void log_store_data_flash_write(void)
171 {
172 uint32_t align_num = 0;
173 uint32_t read_len;
174 uint8_t read_buff[APP_LOG_STORE_ONECE_OP_SIZE];
175
176 if ((s_log_store_env.store_head.offset % s_log_store_env.blk_size) == 0) {
177 if (s_log_store_ops.flash_erase) {
178 s_log_store_ops.flash_erase(s_log_store_env.store_head.db_addr + s_log_store_env.store_head.offset,
179 s_log_store_env.blk_size);
180 }
181 }
182
183 align_num = ALIGN_NUM(APP_LOG_STORE_ONECE_OP_SIZE, s_log_store_env.store_head.offset);
184 if (align_num != s_log_store_env.store_head.offset) {
185 read_len = ring_buffer_read(&s_log_store_rbuf, read_buff, align_num - s_log_store_env.store_head.offset);
186 } else {
187 read_len = ring_buffer_read(&s_log_store_rbuf, read_buff, APP_LOG_STORE_ONECE_OP_SIZE);
188 }
189
190 if (s_log_store_ops.flash_write && read_len) {
191 s_log_store_ops.flash_write(s_log_store_env.store_head.db_addr + s_log_store_env.store_head.offset, read_buff,
192 read_len);
193 s_log_store_env.store_head.offset += read_len;
194 }
195
196 if (s_log_store_env.store_head.offset >= s_log_store_env.store_head.db_size) {
197 s_log_store_env.store_head.offset = 0;
198 s_log_store_env.store_head.flip_over = 1;
199 }
200
201 log_store_head_update(s_log_store_env.head_nv_tag, &s_log_store_env.store_head);
202 }
203
log_store_to_flash(void)204 static void log_store_to_flash(void)
205 {
206 #if (APP_LOG_STORE_RUN_ON_OS == 0)
207 if (s_log_store_env.store_status & APP_LOG_STORE_BUSY_BIT) {
208 return;
209 }
210
211 s_log_store_env.store_status |= APP_LOG_STORE_BUSY_BIT;
212 #endif
213
214 log_store_data_flash_write();
215
216 s_log_store_env.store_status &= ~APP_LOG_STORE_SAVE_BIT;
217 #if (APP_LOG_STORE_RUN_ON_OS == 0)
218 s_log_store_env.store_status &= ~APP_LOG_STORE_BUSY_BIT;
219 #endif
220 }
221
log_dump_from_flash(void)222 static void log_dump_from_flash(void)
223 {
224 uint8_t dump_buffer[APP_LOG_STORE_ONECE_OP_SIZE];
225 uint16_t dump_len;
226
227 if (s_log_store_env.store_status & APP_LOG_STORE_BUSY_BIT) {
228 return;
229 }
230
231 s_log_store_env.store_status |= APP_LOG_STORE_BUSY_BIT;
232
233 if (s_log_store_ops.flash_read) {
234 uint32_t align_num = ALIGN_NUM(APP_LOG_STORE_ONECE_OP_SIZE, s_log_store_env.store_head.offset);
235 if (align_num != s_log_store_env.store_head.offset &&
236 (s_log_store_dump_offset + APP_LOG_STORE_ONECE_OP_SIZE) == align_num) {
237 dump_len = (s_log_store_env.store_head.offset + APP_LOG_STORE_ONECE_OP_SIZE - align_num);
238 } else {
239 dump_len = APP_LOG_STORE_ONECE_OP_SIZE;
240 }
241
242 s_log_store_ops.flash_read(s_log_store_dump_offset + s_log_store_env.store_head.db_addr, dump_buffer, dump_len);
243
244 if (s_log_store_dump_cb) {
245 s_log_store_dump_cb(dump_buffer, dump_len);
246 }
247
248 s_log_store_dump_offset += dump_len;
249 } else {
250 s_log_store_env.store_status &= ~APP_LOG_STORE_DUMP_BIT;
251 }
252
253 if (s_log_store_env.store_head.db_size == s_log_store_dump_offset) {
254 s_log_store_dump_offset = 0;
255 }
256
257 if (s_log_store_env.store_head.offset == s_log_store_dump_offset) {
258 s_log_store_dump_offset = 0;
259 s_log_store_env.store_status &= ~APP_LOG_STORE_DUMP_BIT;
260 }
261
262 s_log_store_env.store_status &= ~APP_LOG_STORE_BUSY_BIT;
263 }
264
265
266 /*
267 * GLOBAL FUNCTION DEFINITIONS
268 *****************************************************************************************
269 */
app_log_store_init(app_log_store_info_t * p_info,app_log_store_op_t * p_op_func)270 uint16_t app_log_store_init(app_log_store_info_t *p_info, app_log_store_op_t *p_op_func)
271 {
272 uint16_t head_len = sizeof(log_store_head_t);
273
274 if (s_log_store_env.initialized) {
275 return SDK_ERR_DISALLOWED;
276 }
277
278 if (p_info == NULL ||
279 p_op_func == NULL ||
280 p_op_func->flash_init == NULL ||
281 p_op_func->flash_read == NULL ||
282 p_op_func->flash_write == NULL ||
283 p_op_func->flash_erase == NULL ||
284 p_info->db_size == 0 ||
285 p_info->blk_size == 0 ||
286 (p_info->db_addr % p_info->blk_size) != 0) {
287 return SDK_ERR_INVALID_PARAM;
288 }
289
290 nvds_get(p_info->nv_tag, &head_len, (uint8_t *)&s_log_store_env.store_head);
291
292 if (!log_store_head_check(&s_log_store_env.store_head, p_info->db_addr, p_info->db_size)) {
293 s_log_store_env.store_head.magic = APP_LOG_STORE_MAGIC;
294 s_log_store_env.store_head.db_addr = p_info->db_addr;
295 s_log_store_env.store_head.db_size = p_info->db_size;
296 s_log_store_env.store_head.offset = 0;
297 s_log_store_env.store_head.flip_over = 0;
298
299 if (!log_store_head_update(p_info->nv_tag, &s_log_store_env.store_head)) {
300 return SDK_ERR_SDK_INTERNAL;
301 }
302 }
303
304 ring_buffer_init(&s_log_store_rbuf, s_log_store_cache, APP_LOG_STORE_CACHE_SIZE);
305
306 memcpy_s(&s_log_store_ops, sizeof (s_log_store_ops), p_op_func, sizeof(s_log_store_ops));
307
308 s_log_store_env.head_nv_tag = p_info->nv_tag;
309 s_log_store_env.blk_size = p_info->blk_size;
310 s_log_store_env.initialized = true;
311
312 p_op_func->flash_init();
313
314 return SDK_SUCCESS;
315 }
316
317
app_log_store_save(const uint8_t * p_data,const uint16_t length)318 uint16_t app_log_store_save(const uint8_t *p_data, const uint16_t length)
319 {
320 uint8_t time_encode[APP_LOG_STORE_TIME_SIZE] = APP_LOG_STORE_TIME_DEFAULT;
321
322 if (!s_log_store_env.initialized) {
323 return SDK_ERR_DISALLOWED;
324 }
325
326 if (s_log_store_env.store_status & APP_LOG_STORE_BUSY_BIT) {
327 return SDK_ERR_BUSY;
328 }
329
330 s_log_store_env.store_status |= APP_LOG_STORE_BUSY_BIT;
331
332 if (s_log_store_ops.time_get) {
333 log_store_time_stamp_encode(time_encode, APP_LOG_STORE_TIME_SIZE);
334 time_encode[APP_LOG_STORE_TIME_SIZE - 1] = ' ';
335 }
336
337 ring_buffer_write(&s_log_store_rbuf, time_encode, APP_LOG_STORE_TIME_SIZE);
338 ring_buffer_write(&s_log_store_rbuf, p_data, length);
339
340 if (ring_buffer_items_count_get(&s_log_store_rbuf >= APP_LOG_STORE_ONECE_OP_SIZE)) {
341 s_log_store_env.store_status |= APP_LOG_STORE_SAVE_BIT;
342 #if APP_LOG_STORE_RUN_ON_OS
343 log_store_to_flash();
344 #endif
345 }
346
347 s_log_store_env.store_status &= ~APP_LOG_STORE_BUSY_BIT;
348
349 return SDK_SUCCESS;
350 }
351
352
app_log_store_flush(void)353 void app_log_store_flush(void)
354 {
355 uint32_t items_count = 0;
356
357 if (!s_log_store_env.initialized) {
358 return;
359 }
360
361 do {
362 items_count = ring_buffer_items_count_get(&s_log_store_rbuf);
363 if (items_count) {
364 log_store_data_flash_write();
365 }
366 } while (items_count >= APP_LOG_STORE_ONECE_OP_SIZE);
367 }
368
app_log_store_dump(app_log_store_dump_cb_t dump_cb)369 uint16_t app_log_store_dump(app_log_store_dump_cb_t dump_cb)
370 {
371 if (!s_log_store_env.initialized) {
372 return SDK_ERR_DISALLOWED;
373 }
374
375 if (s_log_store_env.store_status & APP_LOG_STORE_DUMP_BIT) {
376 return SDK_ERR_BUSY;
377 }
378
379 if (dump_cb == NULL) {
380 return SDK_ERR_POINTER_NULL;
381 }
382
383 s_log_store_dump_cb = dump_cb;
384
385 app_log_store_flush();
386
387 if (s_log_store_env.store_head.flip_over == 0 && s_log_store_env.store_head.offset == 0) {
388 return SDK_SUCCESS;
389 }
390
391 if (s_log_store_env.store_head.flip_over) {
392 uint32_t align_num;
393
394 align_num = ALIGN_NUM(s_log_store_env.blk_size, s_log_store_env.store_head.offset);
395
396 s_log_store_dump_offset = align_num >= s_log_store_env.store_head.db_size ? 0 : align_num;
397 } else {
398 s_log_store_dump_offset = 0;
399 }
400
401 s_log_store_env.store_status |= APP_LOG_STORE_DUMP_BIT;
402
403 return SDK_SUCCESS;
404 }
405
app_log_store_clear(void)406 void app_log_store_clear(void)
407 {
408 s_log_store_env.store_head.offset = 0;
409 s_log_store_env.store_head.flip_over = 0;
410
411 log_store_head_update(s_log_store_env.head_nv_tag, &s_log_store_env.store_head);
412 }
413
app_log_store_dump_ongoing(void)414 bool app_log_store_dump_ongoing(void)
415 {
416 return (s_log_store_env.store_status & APP_LOG_STORE_DUMP_BIT) ? true : false;
417 }
418
app_log_store_schedule(void)419 void app_log_store_schedule(void)
420 {
421 #if APP_LOG_STORE_RUN_ON_OS == 0
422 if (s_log_store_env.store_status & APP_LOG_STORE_SAVE_BIT) {
423 log_store_to_flash();
424 }
425 #endif
426
427 if (s_log_store_env.store_status & APP_LOG_STORE_DUMP_BIT) {
428 log_dump_from_flash();
429 }
430 }
431 #endif
432
433