• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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