25#include "px_log_fs_glue.h"
32#define PX_LOG_FS_PAGE_INVALID 0xffff
36#define PX_LOG_FS_MARKER_FREE 0xff
37#define PX_LOG_FS_MARKER_PAGE 0x5f
38#define PX_LOG_FS_MARKER_PAGE_A 0x55
39#define PX_LOG_FS_MARKER_RECORD 0xaf
40#define PX_LOG_FS_MARKER_RECORD_A 0xaa
41#define PX_LOG_FS_MARKER_BAD 0x00
61#define PX_LOG_FS_PAGE_DATA_SIZE (PX_LOG_FS_CFG_PAGE_SIZE - sizeof(px_log_fs_header_t))
63#define PX_LOG_FS_RECORDS_PER_PAGE (PX_LOG_FS_PAGE_DATA_SIZE / sizeof(px_log_fs_record_t))
65#define PX_LOG_FS_REC_OFFSET_FIRST (sizeof(px_log_fs_header_t))
67#define PX_LOG_FS_REC_OFFSET_LAST (sizeof(px_log_fs_header_t) + (PX_LOG_FS_RECORDS_PER_PAGE - 1) * sizeof(px_log_fs_record_t))
78static inline bool px_log_fs_marker_is_free(uint8_t marker)
80 if(marker == PX_LOG_FS_MARKER_FREE)
90static inline bool px_log_fs_marker_is_page(uint8_t marker)
92 if( (marker == PX_LOG_FS_MARKER_PAGE )
93 ||(marker == PX_LOG_FS_MARKER_PAGE_A) )
103static inline bool px_log_fs_marker_is_record(uint8_t marker)
105 if( (marker == PX_LOG_FS_MARKER_RECORD )
106 ||(marker == PX_LOG_FS_MARKER_RECORD_A) )
116static inline bool px_log_fs_marker_is_bad(uint8_t marker)
118 if(marker == PX_LOG_FS_MARKER_BAD)
164 if(adr->
offset == PX_LOG_FS_REC_OFFSET_LAST)
167 adr->
page = px_log_fs_page_next(handle, adr->
page);
168 adr->
offset = PX_LOG_FS_REC_OFFSET_FIRST;
181 if(adr->
offset == PX_LOG_FS_REC_OFFSET_FIRST)
184 adr->
page = px_log_fs_page_previous(handle, adr->
page);
185 adr->
offset = PX_LOG_FS_REC_OFFSET_LAST;
194static uint8_t px_log_fs_crc(
const void * data,
size_t nr_of_bytes)
197 uint8_t * data_u8 = (uint8_t *)data;
205 while(nr_of_bytes != 0)
210 crc = crc ^ (*data_u8++);
213 for(i = 8; i != 0; i--)
219 crc = (crc >> 1) ^ 0xb2;
240static bool px_log_fs_marker_wr(uint8_t marker,
243 uint8_t marker_wr = marker;
248 if(marker_rd == marker_wr)
270 if( px_log_fs_marker_is_free(header->
marker)
271 || px_log_fs_marker_is_bad(header->
marker ) )
276 if(!px_log_fs_marker_is_page(header->
marker))
279 PX_LOG_E(
"Invalid marker 0x%02X @ page %u", header->
marker, page);
280 header->
marker = PX_LOG_FS_MARKER_BAD;
285 crc = px_log_fs_crc(&header->
nr,
sizeof(header->
nr));
286 if(crc != header->
crc)
289 PX_LOG_E(
"Header CRC check failed @ page %u (0x%02X != 0x%02X)",
290 page, header->
crc, crc);
291 header->
marker = PX_LOG_FS_MARKER_BAD;
309 marker = px_log_fs_header_rd(header, page);
310 if(px_log_fs_marker_is_page(marker))
319 return PX_LOG_FS_PAGE_INVALID;
322 page = px_log_fs_page_next(handle, page);
328 uint16_t page_current)
338 page = px_log_fs_page_next(handle, page);
340 if(page == page_current)
343 return PX_LOG_FS_PAGE_INVALID;
346 marker = px_log_fs_header_rd(header, page);
347 if(px_log_fs_marker_is_page(marker))
360 header->
crc = px_log_fs_crc(&header->
nr,
sizeof(header->
nr));
366 if(memcmp(header, &header_rd,
sizeof(*header)) != 0)
369 PX_LOG_E(
"Header write failed @ page %u", page);
370 header->
marker = PX_LOG_FS_MARKER_BAD;
387 if( px_log_fs_marker_is_free(record->
marker)
388 || px_log_fs_marker_is_bad (record->
marker) )
393 if(!px_log_fs_marker_is_record(record->
marker))
396 PX_LOG_W(
"Invalid record marker %02X @ page %u offset %u",
398 record->
marker = PX_LOG_FS_MARKER_BAD;
403 crc = px_log_fs_crc(&record->
data,
sizeof(record->
data));
404 if(crc != record->
crc)
407 PX_LOG_E(
"Record CRC check failed @ page %u offset %u (0x%02X != 0x%02X)",
409 record->
marker = PX_LOG_FS_MARKER_BAD;
425 PX_LOG_E(
"Record will overflow the page");
430 record->
marker = PX_LOG_FS_MARKER_RECORD;
432 record->
crc = px_log_fs_crc(&record->
data,
sizeof(record->
data));
438 if(memcmp(record, &record_rd,
sizeof(*record)) != 0)
442 record->
marker = PX_LOG_FS_MARKER_BAD;
453 uint16_t fs_page_start,
454 uint16_t fs_page_end)
462 uint16_t page_nr_next;
463 uint16_t page_nr_diff;
464 uint16_t page_nr_diff_largest = 0;
482 page_first = px_log_fs_header_rd_first(handle, &header);
483 if(page_first == PX_LOG_FS_PAGE_INVALID)
488 handle->
page_last = PX_LOG_FS_PAGE_INVALID;
501 page_next = px_log_fs_header_rd_next(handle, &header, page);
502 if(page_next == PX_LOG_FS_PAGE_INVALID)
511 page_nr_next = header.
nr;
512 page_nr_diff = page_nr_next - page_nr;
514 if(page_nr_diff_largest < page_nr_diff)
516 PX_LOG_D(
"Diff=%u, page %u (nr %u) , page_next %u (nr %u)",
517 page_nr_diff, page, page_nr, page_next, page_nr_next);
519 page_nr_diff_largest = page_nr_diff;
528 while(page != page_first);
533 while(!px_log_fs_marker_is_free(px_log_fs_record_rd(&record, &handle->
adr_wr)))
535 px_log_fs_record_adr_next(handle, &handle->
adr_wr);
551 uint16_t fs_page_start,
552 uint16_t fs_page_end)
575 for(page = fs_page_start; page <= fs_page_end; page++)
577 marker = px_log_fs_header_rd(&header, page);
578 if(px_log_fs_marker_is_page(marker))
580 header.
marker = PX_LOG_FS_MARKER_BAD;
587 if(px_log_fs_marker_is_free(px_log_fs_header_rd(&header, page)))
593 if(page > fs_page_end)
596 page = fs_page_start;
600 handle->
page_last = PX_LOG_FS_PAGE_INVALID;
612 if(handle->
page_first == PX_LOG_FS_PAGE_INVALID)
619 px_log_fs_record_adr_previous(handle, &handle->
adr_rd);
632 if(handle->
page_first == PX_LOG_FS_PAGE_INVALID)
642 marker = px_log_fs_header_rd(&header, handle->
adr_rd.
page);
644 if(marker == PX_LOG_FS_MARKER_PAGE)
649 else if(marker == PX_LOG_FS_MARKER_FREE)
651 PX_LOG_E(
"Unexpected free page found");
658 px_log_fs_record_adr_previous(handle, &handle->
adr_rd);
686 PX_LOG_E(
"More bytes requested than can be stored in a record");
695 px_log_fs_record_adr_next(handle, &handle->
adr_rd);
701 px_log_fs_record_adr_previous(handle, &handle->
adr_rd);
708 while(!px_log_fs_marker_is_page(px_log_fs_header_rd(&header, handle->
adr_rd.
page)))
712 PX_LOG_E(
"File system must be corrupt");
719 marker = px_log_fs_record_rd(&record, &handle->
adr_rd);
720 if(px_log_fs_marker_is_record(marker))
723 if(marker == PX_LOG_FS_MARKER_RECORD_A)
732 memcpy(data, &record.
data, nr_of_bytes);
744 if(handle->
page_first == PX_LOG_FS_PAGE_INVALID)
766 PX_LOG_E(
"More bytes requested than can be stored in a record");
776 &&(handle->
adr_rd.
offset == PX_LOG_FS_REC_OFFSET_FIRST) )
782 px_log_fs_record_adr_previous(handle, &handle->
adr_rd);
787 while(!px_log_fs_marker_is_page(px_log_fs_header_rd(&header, handle->
adr_rd.
page)))
791 PX_LOG_E(
"File system must be corrupt");
798 marker = px_log_fs_record_rd(&record, &handle->
adr_rd);
799 if(px_log_fs_marker_is_record(marker))
802 if(marker == PX_LOG_FS_MARKER_RECORD_A)
811 memcpy(data, &record.
data, nr_of_bytes);
826 PX_LOG_W(
"Record is already archived");
830 marker = px_log_fs_marker_rd(&handle->
adr_rd);
831 if(marker == PX_LOG_FS_MARKER_RECORD_A)
833 PX_LOG_E(
"Record is already archived but archive flag was not set");
836 else if(marker != PX_LOG_FS_MARKER_RECORD)
842 if(!px_log_fs_marker_wr(PX_LOG_FS_MARKER_RECORD_A, &handle->
adr_rd))
844 PX_LOG_E(
"Failed to write archive marker");
853 px_log_fs_record_adr_next(handle, &adr);
855 if(adr.
offset == PX_LOG_FS_REC_OFFSET_FIRST)
861 if(!px_log_fs_marker_wr(PX_LOG_FS_MARKER_PAGE_A, &adr))
863 PX_LOG_E(
"Failed to mark page as archived. Lost whole page of records!");
877 marker = px_log_fs_marker_rd(&adr);
878 if(marker == PX_LOG_FS_MARKER_RECORD)
883 else if(marker == PX_LOG_FS_MARKER_RECORD_A)
886 PX_LOG_E(
"Out of sequence archived record detected");
889 else if(marker == PX_LOG_FS_MARKER_FREE)
909 PX_LOG_E(
"Record size too small and %u bytes will be discarded",
915 memset(&record.
data, 0xff,
sizeof(record.
data));
917 memcpy(&record.
data, data, nr_of_bytes);
923 while(!px_log_fs_marker_is_free(px_log_fs_header_rd(&header, handle->
adr_wr.
page)))
927#if PX_LOG_FS_CFG_STOP_WR_WHEN_FULL
947 marker = px_log_fs_header_rd(&header, handle->
adr_wr.
page);
948 if(px_log_fs_marker_is_page(marker))
957 PX_LOG_E(
"File system must be corrupt");
961 page = px_log_fs_page_next(handle, page);
968 header.
marker = PX_LOG_FS_MARKER_PAGE;
970 if(!px_log_fs_header_wr(&header, handle->
adr_wr.
page))
979 if(!px_log_fs_record_wr(&record, &handle->
adr_wr))
982 px_log_fs_record_adr_next(handle, &handle->
adr_wr);
986 if(handle->
page_first == PX_LOG_FS_PAGE_INVALID)
994 px_log_fs_record_adr_next(handle, &handle->
adr_wr);
1007 printf(
"Page end: 0x%04X\n", handle->
fs_page_end);
1011 printf(
"Records per page: %u\n", PX_LOG_FS_RECORDS_PER_PAGE);
1012 printf(
"First page: 0x%04X\n", handle->
page_first);
1013 printf(
"Last page: 0x%04X\n", handle->
page_last);
1016 for(i = 0; i < 16; i++)
1023 for(page = handle->
fs_page_start; page <= handle->fs_page_end; page++)
1027 printf(
"\n0x%04X: ", page);
1029 px_log_fs_header_rd(&header, page);
1032 case PX_LOG_FS_MARKER_FREE:
1035 case PX_LOG_FS_MARKER_PAGE:
1036 printf(
"P %04x ", header.
nr);
1038 case PX_LOG_FS_MARKER_PAGE_A:
1039 printf(
"P*%04x ", header.
nr);
1041 case PX_LOG_FS_MARKER_BAD:
uint16_t fs_page_start
First page in file system (must be on the start of an erase block)
uint16_t offset
Offset inside page.
uint16_t page_nr_next
Next page number to use (starts at 0)
bool archive_flag
Flag is set if current read record is archived.
px_log_fs_adr_t adr_rd
Current read address.
uint16_t page_last
Last page with records (PX_LOG_FS_PAGE_INVALID if empty)
uint16_t page_first
First page with records (PX_LOG_FS_PAGE_INVALID if empty)
px_log_fs_adr_t adr_wr
Next write address (open position)
uint16_t fs_page_end
Last page in file system (must be on the end of an erase block)
px_log_fs_err_t px_log_fs_reset(px_log_fs_handle_t *handle, uint16_t fs_page_start, uint16_t fs_page_end)
Reset log file system.
void px_log_fs_glue_wr(const void *buffer, uint16_t page, uint16_t start_byte_in_page, uint16_t nr_of_bytes)
Writes data to Serial Flash.
#define PX_LOG_FS_CFG_REC_DATA_SIZE
Record data size (total record size = PX_LOG_FS_CFG_REC_DATA_SIZE + 3 bytes overhead)
px_log_fs_err_t px_log_fs_init(px_log_fs_handle_t *handle, uint16_t fs_page_start, uint16_t fs_page_end)
Initialise log file system.
#define PX_LOG_FS_CFG_ERASE_BLOCK_SIZE
Erase block size (in pages) for file system.
px_log_fs_err_t px_log_fs_rd_next(px_log_fs_handle_t *handle, void *data, size_t nr_of_bytes)
Read next (newer) record.
px_log_fs_err_t px_log_fs_rd_first(px_log_fs_handle_t *handle, void *data, size_t nr_of_bytes)
Read first (oldest) record.
px_log_fs_err_t px_log_fs_rd_previous(px_log_fs_handle_t *handle, void *data, size_t nr_of_bytes)
Read previous (older) record.
px_log_fs_err_t px_log_fs_wr(px_log_fs_handle_t *handle, const void *data, size_t nr_of_bytes)
Write a record to the file.
px_log_fs_err_t
Error codes.
#define PX_LOG_FS_CFG_PAGE_SIZE
Page size for file system.
px_log_fs_err_t px_log_fs_rd_first_unarchived(px_log_fs_handle_t *handle, void *data, size_t nr_of_bytes)
Read first (oldest) unarchived record.
void px_log_fs_dbg_report_info(px_log_fs_handle_t *handle)
Report log file system info.
void px_log_fs_glue_rd(void *buffer, uint16_t page, uint16_t start_byte_in_page, uint16_t nr_of_bytes)
Read data from Serial Flash.
px_log_fs_err_t px_log_fs_rd_rec_set_archive(px_log_fs_handle_t *handle)
Set currently read record as archived.
void px_log_fs_glue_erase_block(uint16_t page)
Erases data in Serial Flash.
px_log_fs_err_t px_log_fs_rd_last(px_log_fs_handle_t *handle, void *data, size_t nr_of_bytes)
Read last (newest) record.
@ PX_LOG_FS_ERR_NONE
No error.
@ PX_LOG_FS_ERR_WRITE_FAIL
Failed to write.
@ PX_LOG_FS_ERR_NO_RECORD
No record found.
@ PX_LOG_FS_ERR_EMPTY
File is empty.
@ PX_LOG_FS_ERR_FATAL
Fatal file system error.
@ PX_LOG_FS_ERR_FULL
File is full.
Specification of data address in Serial Flash.
#define PX_LOG_D(format,...)
Macro to display a formatted DEBUG message.
#define PX_LOG_NAME(name)
Macro to declare a log name string once for each file to reduce code size.
#define PX_LOG_W(format,...)
Macro to display a formatted WARNING message.
#define PX_LOG_E(format,...)
Macro to display a formatted ERROR message.
#define PX_LOG_ASSERT(expression)
Macro that will test an expression, and block indefinitely if false.
Definition of a record structure.
uint8_t data[PX_LOG_FS_CFG_REC_DATA_SIZE]
Record data content.
uint8_t marker
RECORD or RECORD_A.
uint8_t crc
Checksum calculated over data (excludes marker)