1 /*
2 * Copyright (c) 2015-2017, Armink, <armink.ztl@gmail.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * 'Software'), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * Function: Save logs to flash.
24 * Created on: 2015-06-04
25 */
26
27 #include <easyflash.h>
28
29 #ifdef EF_USING_LOG
30
31 /* magic code on every sector header. 'EF' is 0x4546 */
32 #define LOG_SECTOR_MAGIC 0x4546
33 /* sector header size, include the sector magic code and status magic code */
34 #define LOG_SECTOR_HEADER_SIZE 4
35
36 /**
37 * Sector status magic code
38 * The sector status is 16-Bits after LOG_SECTOR_MAGIC at every sector header.
39 * =======================
40 * | header(4B) | status |
41 * -----------------------
42 * | 0x4546FFFF | empty |
43 * | 0x4546FFFE | using |
44 * | 0x4546FFFC | full |
45 * =======================
46 *
47 * State transition relationship: empty->using->full
48 * The FULL status will change to EMPTY after sector clean.
49 */
50 enum {
51 SECTOR_STATUS_MAGIC_EMPUT = 0xFFFF,
52 SECTOR_STATUS_MAGIC_USING = 0xFFFE,
53 SECTOR_STATUS_MAGIC_FULL = 0xFFFC,
54 };
55
56 typedef enum {
57 SECTOR_STATUS_EMPUT,
58 SECTOR_STATUS_USING,
59 SECTOR_STATUS_FULL,
60 SECTOR_STATUS_HEADER_ERROR,
61 } SectorStatus;
62
63 /* the stored logs start address and end address. It's like a ring buffer which implement by flash. */
64 static uint32_t log_start_addr = 0, log_end_addr = 0;
65 /* saved log area address for flash */
66 static uint32_t log_area_start_addr = 0;
67 /* initialize OK flag */
68 static bool init_ok = false;
69
70 static void find_start_and_end_addr(void);
71 static uint32_t get_next_flash_sec_addr(uint32_t cur_addr);
72
73 /**
74 * The flash save log function initialize.
75 *
76 * @return result
77 */
ef_log_init(void)78 EfErrCode ef_log_init(void)
79 {
80 EfErrCode result = EF_NO_ERR;
81
82 EF_ASSERT(LOG_AREA_SIZE);
83 EF_ASSERT(EF_ERASE_MIN_SIZE);
84 /* the log area size must be an integral multiple of erase minimum size. */
85 EF_ASSERT(LOG_AREA_SIZE % EF_ERASE_MIN_SIZE == 0);
86 /* the log area size must be more than twice of EF_ERASE_MIN_SIZE */
87 EF_ASSERT(LOG_AREA_SIZE / EF_ERASE_MIN_SIZE >= 2);
88
89 #ifdef EF_USING_ENV
90 log_area_start_addr = EF_START_ADDR + ENV_AREA_SIZE;
91 #else
92 log_area_start_addr = EF_START_ADDR;
93 #endif
94
95 /* find the log store start address and end address */
96 find_start_and_end_addr();
97 /* initialize OK */
98 init_ok = true;
99
100 return result;
101 }
102
103 /**
104 * Get flash sector current status.
105 *
106 * @param addr sector address, this function will auto calculate the sector header address by this address.
107 *
108 * @return the flash sector current status
109 */
get_sector_status(uint32_t addr)110 static SectorStatus get_sector_status(uint32_t addr)
111 {
112 uint32_t header = 0, header_addr = 0;
113 uint16_t sector_magic = 0, status_magic = 0;
114
115 /* calculate the sector header address */
116 header_addr = addr / EF_ERASE_MIN_SIZE * EF_ERASE_MIN_SIZE;
117
118 if (ef_port_read(header_addr, &header, sizeof(header)) == EF_NO_ERR) {
119 sector_magic = header >> 16;
120 status_magic = header;
121 } else {
122 EF_DEBUG("Error: Read sector header data error.\n");
123 return SECTOR_STATUS_HEADER_ERROR;
124 }
125 /* compare header magic code */
126 if (sector_magic == LOG_SECTOR_MAGIC) {
127 switch (status_magic) {
128 case SECTOR_STATUS_MAGIC_EMPUT:
129 return SECTOR_STATUS_EMPUT;
130 case SECTOR_STATUS_MAGIC_USING:
131 return SECTOR_STATUS_USING;
132 case SECTOR_STATUS_MAGIC_FULL:
133 return SECTOR_STATUS_FULL;
134 default:
135 return SECTOR_STATUS_HEADER_ERROR;
136 }
137 } else
138 return SECTOR_STATUS_HEADER_ERROR;
139 }
140
141 /**
142 * Write flash sector current status.
143 *
144 * @param addr sector address, this function will auto calculate the sector header address by this address.
145 * @param status sector cur status
146 *
147 * @return result
148 */
write_sector_status(uint32_t addr,SectorStatus status)149 static EfErrCode write_sector_status(uint32_t addr, SectorStatus status)
150 {
151 uint32_t header = 0, header_addr = 0;
152 uint16_t status_magic;
153
154 /* calculate the sector header address */
155 header_addr = addr / EF_ERASE_MIN_SIZE * EF_ERASE_MIN_SIZE;
156
157 switch (status) {
158 case SECTOR_STATUS_EMPUT: {
159 status_magic = SECTOR_STATUS_MAGIC_EMPUT;
160 break;
161 }
162 case SECTOR_STATUS_USING: {
163 status_magic = SECTOR_STATUS_MAGIC_USING;
164 break;
165 }
166 case SECTOR_STATUS_FULL: {
167 status_magic = SECTOR_STATUS_MAGIC_FULL;
168 break;
169 }
170 }
171 header = (LOG_SECTOR_MAGIC << 16) | status_magic;
172
173 return ef_port_write(header_addr, &header, sizeof(header));
174 }
175
176 /**
177 * Find the current flash sector using end address by continuous 0xFF.
178 *
179 * @param addr sector address
180 *
181 * @return current flash sector using end address
182 */
find_sec_using_end_addr(uint32_t addr)183 static uint32_t find_sec_using_end_addr(uint32_t addr)
184 {
185 /* read section data buffer size */
186 #define READ_BUF_SIZE 32
187
188 uint32_t sector_start = addr, data_start = addr, continue_ff = 0, read_buf_size = 0, i;
189 uint8_t buf[READ_BUF_SIZE];
190
191 EF_ASSERT(READ_BUF_SIZE % 4 == 0);
192 /* calculate the sector start and data start address */
193 sector_start = addr / EF_ERASE_MIN_SIZE * EF_ERASE_MIN_SIZE;
194 data_start = sector_start + LOG_SECTOR_HEADER_SIZE;
195
196 /* counts continuous 0xFF which is end of sector */
197 while (data_start < sector_start + EF_ERASE_MIN_SIZE) {
198 if (data_start + READ_BUF_SIZE < sector_start + EF_ERASE_MIN_SIZE)
199 read_buf_size = READ_BUF_SIZE;
200 else
201 read_buf_size = sector_start + EF_ERASE_MIN_SIZE - data_start;
202 ef_port_read(data_start, (uint32_t *)buf, read_buf_size);
203 for (i = 0; i < read_buf_size; i++) {
204 if (buf[i] == 0xFF)
205 continue_ff++;
206 else
207 continue_ff = 0;
208 }
209 data_start += read_buf_size;
210 }
211 /* calculate current flash sector using end address */
212 if (continue_ff >= EF_ERASE_MIN_SIZE - LOG_SECTOR_HEADER_SIZE) {
213 /* from 0 to sec_size all sector is 0xFF, so the sector is empty */
214 return sector_start + LOG_SECTOR_HEADER_SIZE;
215 } else if (continue_ff >= 4) {
216 /* form end_addr - 4 to sec_size length all area is 0xFF, so it's used part of the sector.
217 * the address must be word alignment. */
218 if (continue_ff % 4 != 0)
219 continue_ff = (continue_ff / 4 + 1) * 4;
220 return sector_start + EF_ERASE_MIN_SIZE - continue_ff;
221 } else {
222 /* all sector not has continuous 0xFF, so the sector is full */
223 return sector_start + EF_ERASE_MIN_SIZE;
224 }
225 }
226
227 /**
228 * Find the log store start address and end address.
229 * It's like a ring buffer which implement by flash.
230 * The flash log area has two state when find start address and end address.
231 * state 1 state 2
232 * |============| |============|
233 * log area start--> |############| <-- start address |############| <-- end address
234 * |############| | empty |
235 * |------------| |------------|
236 * |############| |############| <-- start address
237 * |############| |############|
238 * |------------| |------------|
239 * | . | | . |
240 * | . | | . |
241 * | . | | . |
242 * |------------| |------------|
243 * |############| <-- end address |############|
244 * | empty | |############|
245 * log area end --> |============| |============|
246 *
247 * LOG_AREA_SIZE = log area end - log area star
248 *
249 */
find_start_and_end_addr(void)250 static void find_start_and_end_addr(void)
251 {
252 size_t cur_size = 0;
253 SectorStatus cur_sec_status, last_sec_status;
254 uint32_t cur_using_sec_addr = 0;
255 /* all status sector counts */
256 size_t empty_sec_counts = 0, using_sec_counts = 0, full_sector_counts = 0;
257 /* total sector number */
258 size_t total_sec_num = LOG_AREA_SIZE / EF_ERASE_MIN_SIZE;
259 /* see comment of find_start_and_end_addr function */
260 uint8_t cur_log_sec_state = 0;
261
262 /* get the first sector status */
263 cur_sec_status = get_sector_status(log_area_start_addr);
264 last_sec_status = cur_sec_status;
265
266 for (cur_size = EF_ERASE_MIN_SIZE; cur_size < LOG_AREA_SIZE; cur_size += EF_ERASE_MIN_SIZE) {
267 /* get current sector status */
268 cur_sec_status = get_sector_status(log_area_start_addr + cur_size);
269 /* compare last and current status */
270 switch (last_sec_status) {
271 case SECTOR_STATUS_EMPUT: {
272 switch (cur_sec_status) {
273 case SECTOR_STATUS_EMPUT:
274 break;
275 case SECTOR_STATUS_USING:
276 EF_DEBUG("Error: Log area error! Now will clean all log area.\n");
277 ef_log_clean();
278 return;
279 case SECTOR_STATUS_FULL:
280 EF_DEBUG("Error: Log area error! Now will clean all log area.\n");
281 ef_log_clean();
282 return;
283 }
284 empty_sec_counts++;
285 break;
286 }
287 case SECTOR_STATUS_USING: {
288 switch (cur_sec_status) {
289 case SECTOR_STATUS_EMPUT:
290 /* like state 1 */
291 cur_log_sec_state = 1;
292 log_start_addr = log_area_start_addr;
293 cur_using_sec_addr = log_area_start_addr + cur_size - EF_ERASE_MIN_SIZE;
294 break;
295 case SECTOR_STATUS_USING:
296 EF_DEBUG("Error: Log area error! Now will clean all log area.\n");
297 ef_log_clean();
298 return;
299 case SECTOR_STATUS_FULL:
300 /* like state 2 */
301 cur_log_sec_state = 2;
302 log_start_addr = log_area_start_addr + cur_size;
303 cur_using_sec_addr = log_area_start_addr + cur_size - EF_ERASE_MIN_SIZE;
304 break;
305 }
306 using_sec_counts++;
307 break;
308 }
309 case SECTOR_STATUS_FULL: {
310 switch (cur_sec_status) {
311 case SECTOR_STATUS_EMPUT:
312 /* like state 1 */
313 if (cur_log_sec_state == 2) {
314 EF_DEBUG("Error: Log area error! Now will clean all log area.\n");
315 ef_log_clean();
316 return;
317 } else {
318 cur_log_sec_state = 1;
319 log_start_addr = log_area_start_addr;
320 log_end_addr = log_area_start_addr + cur_size;
321 cur_using_sec_addr = log_area_start_addr + cur_size - EF_ERASE_MIN_SIZE;
322 }
323 break;
324 case SECTOR_STATUS_USING:
325 if (total_sec_num <= 2) {
326 /* like state 1 */
327 cur_log_sec_state = 1;
328 log_start_addr = log_area_start_addr;
329 cur_using_sec_addr = log_area_start_addr + cur_size;
330 } else {
331 /* like state 2 when the sector is the last one */
332 if (cur_size + EF_ERASE_MIN_SIZE >= LOG_AREA_SIZE) {
333 cur_log_sec_state = 2;
334 log_start_addr = log_area_start_addr + cur_size;
335 cur_using_sec_addr = log_area_start_addr + cur_size - EF_ERASE_MIN_SIZE;
336 }
337 }
338 break;
339 case SECTOR_STATUS_FULL:
340 break;
341 }
342 full_sector_counts++;
343 break;
344 }
345 case SECTOR_STATUS_HEADER_ERROR:
346 EF_DEBUG("Error: Log sector header error! Now will clean all log area.\n");
347 ef_log_clean();
348 return;
349 }
350 last_sec_status = cur_sec_status;
351 }
352
353 /* the last sector status counts */
354 if (cur_sec_status == SECTOR_STATUS_EMPUT)
355 empty_sec_counts++;
356 else if (cur_sec_status == SECTOR_STATUS_USING)
357 using_sec_counts++;
358 else if (cur_sec_status == SECTOR_STATUS_FULL)
359 full_sector_counts++;
360 else if (cur_sec_status == SECTOR_STATUS_HEADER_ERROR) {
361 EF_DEBUG("Error: Log sector header error! Now will clean all log area.\n");
362 ef_log_clean();
363 return;
364 }
365
366 if (using_sec_counts != 1) {
367 /* this state is almost impossible */
368 EF_DEBUG("Error: There must be only one sector status is USING! Now will clean all log area.\n");
369 ef_log_clean();
370 } else {
371 /* find the end address */
372 log_end_addr = find_sec_using_end_addr(cur_using_sec_addr);
373 }
374 }
375
376 /**
377 * Get log used flash total size.
378 *
379 * @return log used flash total size. @note NOT contain sector headers
380 */
ef_log_get_used_size(void)381 size_t ef_log_get_used_size(void)
382 {
383 size_t header_total_num = 0, physical_size = 0;
384 /* must be call this function after initialize OK */
385 if (!init_ok)
386 return 0;
387
388 if (log_start_addr < log_end_addr)
389 physical_size = log_end_addr - log_start_addr;
390 else
391 physical_size = LOG_AREA_SIZE - (log_start_addr - log_end_addr);
392
393 header_total_num = physical_size / EF_ERASE_MIN_SIZE + 1;
394
395 return physical_size - header_total_num * LOG_SECTOR_HEADER_SIZE;
396 }
397
398 /**
399 * Sequential reading log data. It will ignore sector headers.
400 *
401 * @param addr address
402 * @param log log buffer
403 * @param size log size, not contain sector headers.
404 *
405 * @return result
406 */
log_seq_read(uint32_t addr,uint32_t * log,size_t size)407 static EfErrCode log_seq_read(uint32_t addr, uint32_t *log, size_t size)
408 {
409 EfErrCode result = EF_NO_ERR;
410 size_t read_size = 0, read_size_temp = 0;
411
412 while (size) {
413 /* move to sector data address */
414 if ((addr + read_size) % EF_ERASE_MIN_SIZE == 0)
415 addr += LOG_SECTOR_HEADER_SIZE;
416 /* calculate current sector last data size */
417 read_size_temp = EF_ERASE_MIN_SIZE - (addr % EF_ERASE_MIN_SIZE);
418 if (size < read_size_temp)
419 read_size_temp = size;
420 result = ef_port_read(addr + read_size, log + read_size / 4, read_size_temp);
421 if (result != EF_NO_ERR)
422 return result;
423 read_size += read_size_temp;
424 size -= read_size_temp;
425 }
426
427 return result;
428 }
429
430 /**
431 * Calculate flash physical address by log index.
432 *
433 * @param index log index
434 *
435 * @return flash physical address
436 */
log_index2addr(size_t index)437 static uint32_t log_index2addr(size_t index)
438 {
439 size_t header_total_offset = 0;
440 /* total include sector number */
441 size_t sector_num = index / (EF_ERASE_MIN_SIZE - LOG_SECTOR_HEADER_SIZE) + 1;
442
443 header_total_offset = sector_num * LOG_SECTOR_HEADER_SIZE;
444 if (log_start_addr < log_end_addr)
445 return log_start_addr + index + header_total_offset;
446 else {
447 if (log_start_addr + index + header_total_offset < log_area_start_addr + LOG_AREA_SIZE)
448 return log_start_addr + index + header_total_offset;
449 else
450 return log_start_addr + index + header_total_offset - LOG_AREA_SIZE;
451
452 }
453 }
454
455 /**
456 * Read log from flash.
457 *
458 * @param index index for saved log.
459 * Minimum index is 0.
460 * Maximum index is ef_log_get_used_size() - 1.
461 * @param log the log which will read from flash
462 * @param size read bytes size
463 *
464 * @return result
465 */
ef_log_read(size_t index,uint32_t * log,size_t size)466 EfErrCode ef_log_read(size_t index, uint32_t *log, size_t size)
467 {
468 EfErrCode result = EF_NO_ERR;
469 size_t cur_using_size = ef_log_get_used_size();
470 size_t read_size_temp = 0;
471 size_t header_total_num = 0;
472
473 if (!size)
474 return result;
475
476 EF_ASSERT(size % 4 == 0);
477 EF_ASSERT(index < cur_using_size);
478
479 if (index + size > cur_using_size) {
480 EF_DEBUG("Warning: Log read size out of bound. Cut read size.\n");
481 size = cur_using_size - index;
482 }
483 /* must be call this function after initialize OK */
484 if (!init_ok)
485 return EF_ENV_INIT_FAILED;
486
487 if (log_start_addr < log_end_addr)
488 log_seq_read(log_index2addr(index), log, size);
489 else {
490 if (log_index2addr(index) + size <= log_area_start_addr + LOG_AREA_SIZE) {
491 /* Flash log area
492 * |--------------|
493 * log_area_start_addr --> |##############|
494 * |##############|
495 * |##############|
496 * |--------------|
497 * |##############|
498 * |##############|
499 * |##############| <-- log_end_addr
500 * |--------------|
501 * log_start_addr --> |##############|
502 * read start --> |**************| <-- read end
503 * |##############|
504 * |--------------|
505 *
506 * read from (log_start_addr + log_index2addr(index)) to (log_start_addr + index + log_index2addr(index))
507 */
508 result = log_seq_read(log_index2addr(index), log, size);
509 } else if (log_index2addr(index) < log_area_start_addr + LOG_AREA_SIZE) {
510 /* Flash log area
511 * |--------------|
512 * log_area_start_addr --> |**************| <-- read end
513 * |##############|
514 * |##############|
515 * |--------------|
516 * |##############|
517 * |##############|
518 * |##############| <-- log_end_addr
519 * |--------------|
520 * log_start_addr --> |##############|
521 * read start --> |**************|
522 * |**************|
523 * |--------------|
524 * read will by 2 steps
525 * step1: read from (log_start_addr + log_index2addr(index)) to flash log area end address
526 * step2: read from flash log area start address to read size's end address
527 */
528 read_size_temp = (log_area_start_addr + LOG_AREA_SIZE) - log_index2addr(index);
529 header_total_num = read_size_temp / EF_ERASE_MIN_SIZE;
530 /* Minus some ignored bytes */
531 read_size_temp -= header_total_num * LOG_SECTOR_HEADER_SIZE;
532 result = log_seq_read(log_index2addr(index), log, read_size_temp);
533 if (result == EF_NO_ERR)
534 result = log_seq_read(log_area_start_addr, log + read_size_temp / 4, size - read_size_temp);
535 } else {
536 /* Flash log area
537 * |--------------|
538 * log_area_start_addr --> |##############|
539 * read start --> |**************|
540 * |**************| <-- read end
541 * |--------------|
542 * |##############|
543 * |##############|
544 * |##############| <-- log_end_addr
545 * |--------------|
546 * log_start_addr --> |##############|
547 * |##############|
548 * |##############|
549 * |--------------|
550 * read from (log_start_addr + log_index2addr(index) - LOG_AREA_SIZE) to read size's end address
551 */
552 result = log_seq_read(log_index2addr(index) - LOG_AREA_SIZE, log, size);
553 }
554 }
555
556 return result;
557 }
558
559 /**
560 * Write log to flash.
561 *
562 * @param log the log which will be write to flash
563 * @param size write bytes size
564 *
565 * @return result
566 */
ef_log_write(const uint32_t * log,size_t size)567 EfErrCode ef_log_write(const uint32_t *log, size_t size)
568 {
569 EfErrCode result = EF_NO_ERR;
570 size_t write_size = 0, writable_size = 0;
571 uint32_t write_addr = log_end_addr, erase_addr;
572 SectorStatus sector_status;
573
574 EF_ASSERT(size % 4 == 0);
575 /* must be call this function after initialize OK */
576 if (!init_ok)
577 return EF_ENV_INIT_FAILED;
578
579 if ((sector_status = get_sector_status(write_addr)) == SECTOR_STATUS_HEADER_ERROR)
580 return EF_WRITE_ERR;
581 /* write some log when current sector status is USING and EMPTY */
582 if ((sector_status == SECTOR_STATUS_USING) || (sector_status == SECTOR_STATUS_EMPUT)) {
583 /* write the already erased but not used area */
584 writable_size = EF_ERASE_MIN_SIZE - ((write_addr - log_area_start_addr) % EF_ERASE_MIN_SIZE);
585 if (size >= writable_size) {
586 result = ef_port_write(write_addr, log, writable_size);
587 if (result != EF_NO_ERR)
588 goto exit;
589 /* change the current sector status to FULL */
590 result = write_sector_status(write_addr, SECTOR_STATUS_FULL);
591 if (result != EF_NO_ERR)
592 goto exit;
593 write_size += writable_size;
594 } else {
595 result = ef_port_write(write_addr, log, size);
596 log_end_addr = write_addr + size;
597 goto exit;
598 }
599 }
600 /* erase and write remain log */
601 while (true) {
602 /* calculate next available sector address */
603 erase_addr = write_addr = get_next_flash_sec_addr(write_addr - 4);
604 /* move the flash log start address to next available sector address */
605 if (log_start_addr == erase_addr)
606 log_start_addr = get_next_flash_sec_addr(log_start_addr);
607 /* erase sector */
608 result = ef_port_erase(erase_addr, EF_ERASE_MIN_SIZE);
609 if (result != EF_NO_ERR)
610 goto exit;
611 /* change the sector status to USING when write begin sector start address */
612 result = write_sector_status(write_addr, SECTOR_STATUS_USING);
613 if (result == EF_NO_ERR)
614 write_addr += LOG_SECTOR_HEADER_SIZE;
615 else
616 goto exit;
617 /* calculate current sector writable data size */
618 writable_size = EF_ERASE_MIN_SIZE - LOG_SECTOR_HEADER_SIZE;
619 if (size - write_size >= writable_size) {
620 result = ef_port_write(write_addr, log + write_size / 4, writable_size);
621 if (result != EF_NO_ERR)
622 goto exit;
623 /* change the current sector status to FULL */
624 result = write_sector_status(write_addr, SECTOR_STATUS_FULL);
625 if (result != EF_NO_ERR)
626 goto exit;
627 log_end_addr = write_addr + writable_size;
628 write_size += writable_size;
629 write_addr += writable_size;
630 } else {
631 result = ef_port_write(write_addr, log + write_size / 4, size - write_size);
632 if (result != EF_NO_ERR)
633 goto exit;
634 log_end_addr = write_addr + (size - write_size);
635 break;
636 }
637 }
638
639 exit:
640 return result;
641 }
642
643 /**
644 * Get next flash sector address.The log total sector like ring buffer which implement by flash.
645 *
646 * @param cur_addr cur flash address
647 *
648 * @return next flash sector address
649 */
get_next_flash_sec_addr(uint32_t cur_addr)650 static uint32_t get_next_flash_sec_addr(uint32_t cur_addr)
651 {
652 size_t cur_sec_id = (cur_addr - log_area_start_addr) / EF_ERASE_MIN_SIZE;
653 size_t sec_total_num = LOG_AREA_SIZE / EF_ERASE_MIN_SIZE;
654
655 if (cur_sec_id + 1 >= sec_total_num) {
656 /* return to ring head */
657 return log_area_start_addr;
658 } else
659 return log_area_start_addr + (cur_sec_id + 1) * EF_ERASE_MIN_SIZE;
660 }
661
662 /**
663 * Clean all log which in flash.
664 *
665 * @return result
666 */
ef_log_clean(void)667 EfErrCode ef_log_clean(void)
668 {
669 EfErrCode result = EF_NO_ERR;
670 uint32_t write_addr = log_area_start_addr;
671
672 /* clean address */
673 log_start_addr = log_area_start_addr;
674 log_end_addr = log_start_addr + LOG_SECTOR_HEADER_SIZE;
675 /* erase log flash area */
676 result = ef_port_erase(log_area_start_addr, LOG_AREA_SIZE);
677 if (result != EF_NO_ERR)
678 goto exit;
679 /* setting first sector is USING */
680 write_sector_status(write_addr, SECTOR_STATUS_USING);
681 if (result != EF_NO_ERR)
682 goto exit;
683 write_addr += EF_ERASE_MIN_SIZE;
684 /* add sector header */
685 while (true) {
686 write_sector_status(write_addr, SECTOR_STATUS_EMPUT);
687 if (result != EF_NO_ERR)
688 goto exit;
689 write_addr += EF_ERASE_MIN_SIZE;
690 if (write_addr >= log_area_start_addr + LOG_AREA_SIZE)
691 break;
692 }
693
694 exit:
695 return result;
696 }
697
698 #endif /* EF_USING_LOG */
699