40 #include "sdk_common.h"
41 #if NRF_MODULE_ENABLED(FDS)
48 #include "nrf_error.h"
49 #include "nrf_atomic.h"
50 #include "nrf_atfifo.h"
52 #include "nrf_fstorage.h"
53 #if (FDS_BACKEND == NRF_FSTORAGE_SD)
54 #include "nrf_fstorage_sd.h"
55 #elif (FDS_BACKEND == NRF_FSTORAGE_NVMC)
56 #include "nrf_fstorage_nvmc.h"
58 #error Invalid FDS backend.
61 #if (FDS_CRC_CHECK_ON_READ)
66 static void fs_event_handler(nrf_fstorage_evt_t * evt);
68 NRF_FSTORAGE_DEF(nrf_fstorage_t m_fs) =
71 .evt_handler = fs_event_handler,
77 bool volatile initialized;
78 nrf_atomic_flag_t initializing;
83 static nrf_atomic_u32_t m_queued_op_cnt;
86 static nrf_atomic_u32_t m_users;
90 static nrf_atomic_u32_t m_latest_rec_id;
103 static void event_send(
fds_evt_t const *
const p_evt)
107 if (m_cb_table[user] != NULL)
109 m_cb_table[user](p_evt);
125 p_evt->
write.file_id = p_op->
write.header.file_id;
126 p_evt->
write.record_key = p_op->
write.header.record_key;
127 p_evt->
write.record_id = p_op->
write.header.record_id;
128 p_evt->
write.is_record_updated = 0;
133 p_evt->
write.file_id = p_op->
write.header.file_id;
134 p_evt->
write.record_key = p_op->
write.header.record_key;
135 p_evt->
write.record_id = p_op->
write.header.record_id;
141 p_evt->
del.file_id = p_op->
del.file_id;
142 p_evt->
del.record_key = p_op->
del.record_key;
143 p_evt->
del.record_id = p_op->
del.record_to_delete;
148 p_evt->
del.file_id = p_op->
del.file_id;
150 p_evt->
del.record_id = 0;
164 static bool header_has_next(
fds_header_t const * p_hdr, uint32_t
const * p_page_end)
166 uint32_t
const *
const p_hdr32 = (uint32_t*)p_hdr;
167 return ( ( p_hdr32 < p_page_end)
181 if (((uint32_t*)header_jump(p_hdr) > p_page_end))
198 static bool address_is_valid(uint32_t
const *
const p_addr)
200 return ((p_addr != NULL) &&
201 (p_addr >= (uint32_t*)m_fs.start_addr) &&
202 (p_addr <= (uint32_t*)m_fs.end_addr) &&
203 (is_word_aligned(p_addr)));
208 static fds_page_type_t page_identify(uint32_t
const *
const p_page_addr)
210 if ( (p_page_addr == NULL)
230 static bool page_is_erased(uint32_t
const *
const p_page_addr)
245 static bool page_has_space(uint16_t page, uint16_t length_words)
255 static ret_code_t page_from_record(uint16_t *
const p_page, uint32_t
const *
const p_rec)
262 if ((p_rec > m_pages[i].p_addr) &&
280 static void page_scan(uint32_t
const * p_addr,
281 uint16_t *
const words_written,
291 while (header_has_next(p_header, p_page_end))
298 if (p_header->
record_id > m_latest_rec_id)
324 p_header = header_jump(p_header);
346 static ret_code_t page_tag_write_swap(
void)
350 return nrf_fstorage_write(&m_fs, (uint32_t)m_swap_page.
p_addr, page_tag_swap,
FDS_PAGE_TAG_SIZE *
sizeof(uint32_t), NULL);
355 static ret_code_t page_tag_write_data(uint32_t
const *
const p_page_addr)
359 return nrf_fstorage_write(&m_fs, (uint32_t)p_page_addr, page_tag_data,
FDS_PAGE_TAG_SIZE *
sizeof(uint32_t), NULL);
365 static ret_code_t write_space_reserve(uint16_t length_words, uint16_t * p_page)
367 bool space_reserved =
false;
379 (page_has_space(page, total_len_words)))
381 space_reserved =
true;
396 static void write_space_free(uint16_t length_words, uint16_t page)
402 static uint32_t record_id_new(
void)
404 return nrf_atomic_u32_add(&m_latest_rec_id, 1);
413 static bool record_find_next(uint16_t page, uint32_t
const ** p_record)
421 if (p_header != NULL)
423 p_header = header_jump(p_header);
434 while (header_has_next(p_header, p_page_end))
436 switch (header_check(p_header, p_page_end))
439 *p_record = (uint32_t*)p_header;
443 p_header = header_jump(p_header);
460 static bool record_find_by_desc(
fds_record_desc_t *
const p_desc, uint16_t *
const p_page)
466 if ((address_is_valid(p_desc->
p_record)) &&
477 uint32_t
const * p_record = NULL;
479 while (record_find_next(*p_page, &p_record))
499 static ret_code_t record_find(uint16_t
const * p_file_id,
500 uint16_t
const * p_record_key,
504 if (!m_flags.initialized)
509 if (p_desc == NULL || p_token == NULL)
524 while (record_find_next(p_token->
page, &p_token->
p_addr))
529 if ((p_file_id != NULL) &&
530 (p_header->
file_id != *p_file_id))
535 if ((p_record_key != NULL) &&
559 static void records_stat(uint16_t page,
560 uint16_t * p_valid_records,
561 uint16_t * p_dirty_records,
562 uint16_t * p_freeable_words,
568 while (header_has_next(p_header, p_page_end))
570 switch (header_check(p_header, p_page_end))
573 *p_dirty_records += 1;
575 p_header = header_jump(p_header);
579 *p_valid_records += 1;
580 p_header = header_jump(p_header);
585 *p_dirty_records += 1;
586 *p_freeable_words += (p_page_end - (uint32_t*)p_header);
587 *p_corruption =
true;
600 static fds_op_t * queue_buf_get(nrf_atfifo_item_put_t * p_iput_ctx)
602 fds_op_t *
const p_op = (
fds_op_t*) nrf_atfifo_item_alloc(m_queue, p_iput_ctx);
604 memset(p_op, 0x00,
sizeof(
fds_op_t));
610 static void queue_buf_store(nrf_atfifo_item_put_t * p_iput_ctx)
612 (void) nrf_atfifo_item_put(m_queue, p_iput_ctx);
617 static fds_op_t * queue_load(nrf_atfifo_item_get_t * p_iget_ctx)
619 return (
fds_op_t*) nrf_atfifo_item_get(m_queue, p_iget_ctx);
624 static void queue_free(nrf_atfifo_item_get_t * p_iget_ctx)
627 (void) nrf_atfifo_item_free(m_queue, p_iget_ctx);
631 static bool queue_has_next(
void)
634 ASSERT(m_queued_op_cnt != 0);
635 return nrf_atomic_u32_sub(&m_queued_op_cnt, 1);
646 bool swap_set_but_not_found =
false;
650 uint32_t
const *
const p_page_addr = (uint32_t*)m_fs.start_addr + (i *
FDS_PAGE_SIZE);
657 if (page_is_erased(p_page_addr))
659 if (m_swap_page.
p_addr != NULL)
664 m_pages[page].
p_addr = p_page_addr;
675 m_swap_page.
p_addr = p_page_addr;
677 swap_set_but_not_found =
true;
686 total_pages_available--;
687 m_pages[page].
p_addr = p_page_addr;
696 m_pages[page].
p_addr = p_page_addr;
700 page_scan(p_page_addr, &m_pages[page].write_offset, &m_pages[page].can_gc);
708 if (swap_set_but_not_found)
717 m_swap_page.
p_addr = p_page_addr;
720 page_scan(p_page_addr, &m_swap_page.
write_offset, NULL);
732 if (total_pages_available < 2)
742 static ret_code_t record_header_write_begin(
fds_op_t *
const p_op, uint32_t *
const p_addr)
749 ret = nrf_fstorage_write(&m_fs, (uint32_t)(p_addr +
FDS_OFFSET_TL),
756 static ret_code_t record_header_write_id(
fds_op_t *
const p_op, uint32_t *
const p_addr)
762 p_op->
write.step = (p_op->
write.p_data != NULL) ?
765 ret = nrf_fstorage_write(&m_fs, (uint32_t)(p_addr +
FDS_OFFSET_ID),
772 static ret_code_t record_header_write_finalize(
fds_op_t *
const p_op, uint32_t *
const p_addr)
781 ret = nrf_fstorage_write(&m_fs, (uint32_t)(p_addr +
FDS_OFFSET_IC),
788 static ret_code_t record_header_flag_dirty(uint32_t *
const p_record, uint16_t page_to_gc)
792 __ALIGN(4) static uint32_t const dirty_header = {0xFFFF0000};
797 ret = nrf_fstorage_write(&m_fs, (uint32_t)p_record,
800 if (ret != NRF_SUCCESS)
805 m_pages[page_to_gc].
can_gc =
true;
811 static ret_code_t record_find_and_delete(
fds_op_t *
const p_op)
819 if (record_find_by_desc(&desc, &page))
832 ret = record_header_flag_dirty((uint32_t*)desc.
p_record, page);
845 static ret_code_t file_find_and_delete(
fds_op_t *
const p_op)
854 ret = record_find(&p_op->
del.file_id, NULL, &desc, &tok);
859 ret = record_header_flag_dirty((uint32_t*)desc.
p_record, tok.
page);
872 static ret_code_t record_write_data(
fds_op_t *
const p_op, uint32_t *
const p_addr)
879 p_op->
write.p_data, p_op->
write.header.length_words *
sizeof(uint32_t), NULL);
885 #if (FDS_CRC_CHECK_ON_READ)
886 static bool crc_verify_success(uint16_t crc, uint16_t len_words, uint32_t
const *
const p_data)
888 uint16_t computed_crc;
894 computed_crc = crc16_compute((uint8_t
const *)p_data, 6, NULL);
895 computed_crc = crc16_compute((uint8_t
const *)p_data + 8,
899 return (computed_crc == crc);
904 static void gc_init(
void)
921 static bool gc_page_next(uint16_t *
const p_next_page)
933 if ((m_pages[i].records_open == 0) && (m_pages[i].can_gc ==
true))
946 static ret_code_t gc_swap_erase(
void)
957 static ret_code_t gc_page_erase(
void)
962 if (m_pages[gc].records_open == 0)
972 ret = gc_swap_erase();
980 static ret_code_t gc_record_copy(
void)
990 return nrf_fstorage_write(&m_fs, (uint32_t)p_dest, m_gc.
p_record_src,
991 record_len *
sizeof(uint32_t),
996 static ret_code_t gc_record_find_next(
void)
1003 ret = gc_record_copy();
1008 ret = gc_page_erase();
1016 static ret_code_t gc_swap_promote(
void)
1019 return page_tag_write_data(m_pages[m_gc.
cur_page].p_addr);
1024 static ret_code_t gc_tag_new_swap(
void)
1028 return page_tag_write_swap();
1032 static ret_code_t gc_next_page(
void)
1044 return gc_record_find_next();
1049 static void gc_update_swap_offset(
void)
1058 static void gc_swap_pages(
void)
1062 uint32_t
const *
const p_addr = m_swap_page.
p_addr;
1073 static void gc_state_advance(
void)
1084 gc_update_swap_offset();
1114 static ret_code_t init_execute(uint32_t prev_ret,
fds_op_t *
const p_op)
1118 if (prev_ret != NRF_SUCCESS)
1121 m_flags.initializing =
false;
1125 switch (p_op->
init.step)
1131 ret = page_tag_write_swap();
1137 bool write_reqd =
false;
1144 ret = page_tag_write_data(m_pages[i].p_addr);
1150 m_flags.initialized =
true;
1151 m_flags.initializing =
false;
1170 ret = page_tag_write_data(m_swap_page.
p_addr);
1173 uint32_t
const *
const p_old_swap = m_swap_page.
p_addr;
1177 m_pages[gc].
p_addr = p_old_swap;
1194 m_flags.initializing =
false;
1203 static ret_code_t write_execute(uint32_t prev_ret,
fds_op_t *
const p_op)
1206 uint32_t * p_write_addr;
1214 static uint16_t page;
1216 if (prev_ret != NRF_SUCCESS)
1219 page_offsets_update(p_page, p_op);
1227 switch (p_op->
write.step)
1237 if (!record_find_by_desc(&desc, &page))
1246 ret = record_header_write_begin(p_op, p_write_addr);
1250 ret = record_header_write_id(p_op, p_write_addr);
1254 ret = record_write_data(p_op, p_write_addr);
1258 ret = record_header_write_finalize(p_op, p_write_addr);
1263 ret = record_header_flag_dirty((uint32_t*)desc.
p_record, page);
1269 #if (FDS_CRC_CHECK_ON_WRITE)
1270 if (!crc_verify_success(p_op->
write.header.crc16,
1271 p_op->
write.header.length_words,
1289 page_offsets_update(p_page, p_op);
1296 static ret_code_t delete_execute(uint32_t prev_ret,
fds_op_t *
const p_op)
1300 if (prev_ret != NRF_SUCCESS)
1305 switch (p_op->
del.step)
1309 ret = record_find_and_delete(p_op);
1313 ret = file_find_and_delete(p_op);
1335 static ret_code_t gc_execute(uint32_t prev_ret)
1339 if (prev_ret != NRF_SUCCESS)
1356 ret = gc_next_page();
1360 ret = gc_record_find_next();
1364 ret = gc_record_copy();
1368 ret = gc_page_erase();
1372 ret = gc_swap_promote();
1376 ret = gc_tag_new_swap();
1390 static void queue_process(ret_code_t result)
1393 static nrf_atfifo_item_get_t m_iget_ctx;
1397 if (m_p_cur_op == NULL)
1400 m_p_cur_op = queue_load(&m_iget_ctx);
1410 ASSERT(m_p_cur_op != NULL);
1415 result = init_execute(result, m_p_cur_op);
1420 result = write_execute(result, m_p_cur_op);
1425 result = delete_execute(result, m_p_cur_op);
1429 result = gc_execute(result);
1458 event_prepare(m_p_cur_op, &evt);
1467 result = NRF_SUCCESS;
1470 queue_free(&m_iget_ctx);
1472 if (!queue_has_next())
1481 static void queue_start(
void)
1483 if (!nrf_atomic_u32_fetch_add(&m_queued_op_cnt, 1))
1485 queue_process(NRF_SUCCESS);
1490 static void fs_event_handler(nrf_fstorage_evt_t * p_evt)
1492 queue_process(p_evt->result);
1505 uint16_t length_words = 0;
1507 nrf_atfifo_item_put_t iput_ctx;
1509 if (!m_flags.initialized)
1514 if (p_record == NULL)
1535 ret = write_space_reserve(length_words, &page);
1551 p_op = queue_buf_get(&iput_ctx);
1555 write_space_free(length_words, page);
1563 p_op->
write.page = page;
1565 p_op->
write.header.record_id = record_id_new();
1567 p_op->
write.header.record_key = p_record->
key;
1568 p_op->
write.header.length_words = length_words;
1577 #if (FDS_CRC_CHECK_ON_READ)
1580 crc = crc16_compute((uint8_t*)&p_op->
write.header, 6, NULL);
1581 crc = crc16_compute((uint8_t*)&p_op->
write.header.record_id, 4, &crc);
1584 crc = crc16_compute((uint8_t*)p_record->
data.
p_data,
1588 p_op->
write.header.crc16 = crc;
1590 queue_buf_store(&iput_ctx);
1619 m_cb_table[m_users] = cb;
1620 (void) nrf_atomic_u32_add(&m_users, 1);
1628 ret_code_t
flash_bounds_set(
const uint32_t start_addr,
const uint32_t end_addr)
1630 ret_code_t err_code = NRF_SUCCESS;
1632 const uint32_t flash_size = end_addr - start_addr;
1633 if(end_addr <= start_addr)
1641 else if (req_size > flash_size)
1651 m_fs.end_addr = end_addr;
1652 m_fs.start_addr = m_fs.end_addr - req_size;
1658 static ret_code_t flash_subsystem_init(
void)
1665 #if (FDS_BACKEND == NRF_FSTORAGE_SD)
1666 return nrf_fstorage_init(&m_fs, &nrf_fstorage_sd, NULL);
1667 #elif (FDS_BACKEND == NRF_FSTORAGE_NVMC)
1668 return nrf_fstorage_init(&m_fs, &nrf_fstorage_nvmc, NULL);
1670 #error Invalid FDS_BACKEND.
1675 static void queue_init(
void)
1677 (void) NRF_ATFIFO_INIT(m_queue);
1690 if (m_flags.initialized)
1693 event_send(&evt_success);
1697 if (nrf_atomic_flag_set_fetch(&m_flags.initializing))
1705 ret = flash_subsystem_init();
1706 if (ret != NRF_SUCCESS)
1727 m_flags.initialized =
true;
1728 m_flags.initializing =
false;
1729 event_send(&evt_success);
1739 nrf_atfifo_item_put_t iput_ctx;
1741 fds_op_t * p_op = queue_buf_get(&iput_ctx);
1775 queue_buf_store(&iput_ctx);
1787 if ((p_desc == NULL) || (p_flash_rec == NULL))
1793 if (record_find_by_desc(p_desc, &page))
1798 if (!crc_verify_success(p_header->
crc16,
1806 (void) nrf_atomic_u32_add(&m_pages[page].records_open, 1);
1837 if ((m_pages[page].records_open > 0) && (p_desc->
record_is_open))
1865 if (!m_flags.initialized)
1875 ret = write_space_reserve(length_words, &page);
1891 if (!m_flags.initialized)
1935 return write_enqueue(p_desc, p_record, NULL,
FDS_OP_WRITE);
1949 return write_enqueue(p_desc, p_record, p_tok,
FDS_OP_WRITE);
1962 return write_enqueue(p_desc, p_record, NULL,
FDS_OP_UPDATE);
1969 nrf_atfifo_item_put_t iput_ctx;
1971 if (!m_flags.initialized)
1981 p_op = queue_buf_get(&iput_ctx);
1991 queue_buf_store(&iput_ctx);
2001 nrf_atfifo_item_put_t iput_ctx;
2003 if (!m_flags.initialized)
2013 p_op = queue_buf_get(&iput_ctx);
2021 p_op->
del.file_id = file_id;
2023 queue_buf_store(&iput_ctx);
2033 nrf_atfifo_item_put_t iput_ctx;
2035 if (!m_flags.initialized)
2040 p_op = queue_buf_get(&iput_ctx);
2048 queue_buf_store(&iput_ctx);
2065 return record_find(NULL, NULL, p_desc, p_token);
2070 uint16_t record_key,
2074 return record_find(&file_id, &record_key, p_desc, p_token);
2082 return record_find(NULL, &record_key, p_desc, p_token);
2090 return record_find(&file_id, NULL, p_desc, p_token);
2111 uint32_t *
const p_record_id)
2113 if ((p_desc == NULL) || (p_record_id == NULL))
2128 uint16_t contig_words = 0;
2130 if (!m_flags.initialized)
2157 contig_words = (words_in_page - words_used);
#define CRITICAL_SECTION_ENTER()
#define FDS_PAGE_TAG_MAGIC
#define CRITICAL_SECTION_EXIT()
#define FDS_PAGE_TAG_SIZE
#define FDS_PHY_PAGES_IN_VPAGE
#define FDS_PAGE_TAG_SWAP
#define FDS_HEADER_SIZE_TL
#define FDS_PAGE_TAG_WORD_1
#define FDS_PAGE_TAG_DATA
@ FDS_OP_INIT_PROMOTE_SWAP
@ FDS_OP_DEL_RECORD_FLAG_DIRTY
@ FDS_OP_DEL_FILE_FLAG_DIRTY
#define FDS_HEADER_SIZE_IC
#define FDS_PHY_PAGE_SIZE
@ FDS_OP_WRITE_FLAG_DIRTY
@ FDS_OP_WRITE_HEADER_FINALIZE
@ FDS_OP_WRITE_HEADER_BEGIN
@ FDS_OP_WRITE_FIND_RECORD
#define FDS_PAGE_TAG_WORD_0
#define FDS_HEADER_SIZE_ID
ret_code_t fds_record_write(fds_record_desc_t *p_desc, fds_record_t const *p_record)
Function for writing a record to flash.
#define FDS_BOUND_NOT_SET
Value for unconfigured FDS physical bound.
ret_code_t fds_record_find(uint16_t file_id, uint16_t record_key, fds_record_desc_t *p_desc, fds_find_token_t *p_token)
Function for searching for records with a given record key in a file.
ret_code_t fds_init(void)
Function for initializing the module.
ret_code_t fds_record_write_reserved(fds_record_desc_t *p_desc, fds_record_t const *p_record, fds_reserve_token_t const *p_token)
Function for writing a record to a space in flash that was reserved using fds_reserve.
ret_code_t fds_reserve(fds_reserve_token_t *p_token, uint16_t length_words)
Function for reserving space in flash.
ret_code_t fds_reserve_cancel(fds_reserve_token_t *p_token)
Function for canceling an fds_reserve operation.
ret_code_t fds_stat(fds_stat_t *p_stat)
Function for retrieving file system statistics.
ret_code_t fds_record_id_from_desc(fds_record_desc_t const *p_desc, uint32_t *p_record_id)
Function for obtaining a record ID from a record descriptor.
void(* fds_cb_t)(fds_evt_t const *p_evt)
FDS event handler function prototype.
ret_code_t flash_bounds_set(const uint32_t start_addr, const uint32_t end_addr)
Set physical boundaries for FDS.
ret_code_t fds_descriptor_from_rec_id(fds_record_desc_t *p_desc, uint32_t record_id)
Function for obtaining a descriptor from a record ID.
ret_code_t fds_record_iterate(fds_record_desc_t *p_desc, fds_find_token_t *p_token)
Function for iterating through all records in flash.
ret_code_t fds_file_delete(uint16_t file_id)
Function for deleting all records in a file.
ret_code_t fds_gc(void)
Function for running garbage collection.
ret_code_t fds_record_find_in_file(uint16_t file_id, fds_record_desc_t *p_desc, fds_find_token_t *p_token)
Function for searching for any record in a file.
ret_code_t fds_record_update(fds_record_desc_t *p_desc, fds_record_t const *p_record)
Function for updating a record.
ret_code_t fds_record_open(fds_record_desc_t *p_desc, fds_flash_record_t *p_flash_record)
Function for opening a record for reading.
#define FDS_RECORD_KEY_DIRTY
Record key for deleted records.
ret_code_t fds_record_find_by_key(uint16_t record_key, fds_record_desc_t *p_desc, fds_find_token_t *p_token)
Function for searching for records with a given record key.
ret_code_t fds_register(fds_cb_t cb)
Function for registering an FDS event handler.
#define FDS_FILE_ID_INVALID
Invalid file ID.
ret_code_t fds_record_close(fds_record_desc_t *p_desc)
Function for closing a record.
ret_code_t fds_record_delete(fds_record_desc_t *p_desc)
Function for deleting a record.
@ FDS_ERR_NOT_FOUND
Error. The record was not found.
@ FDS_ERR_INTERNAL
Error. An internal error occurred.
@ FDS_ERR_INVALID_ARG
Error. The parameter contains invalid data.
@ FDS_ERR_NO_PAGES
Error. No flash pages are available.
@ FDS_ERR_USER_LIMIT_REACHED
Error. The maximum number of users has been reached.
@ FDS_ERR_NO_SPACE_IN_QUEUES
Error. There is no space in the internal queues.
@ FDS_ERR_RECORD_TOO_LARGE
Error. The record exceeds the maximum allowed size.
@ FDS_ERR_NULL_ARG
Error. The parameter is NULL.
@ FDS_ERR_NO_OPEN_RECORDS
Error. The record is not open, so it cannot be closed.
@ FDS_ERR_UNALIGNED_ADDR
Error. The input data is not aligned to a word boundary.
@ FDS_ERR_BUSY
Error. The underlying flash subsystem was busy.
@ FDS_ERR_NO_SPACE_IN_FLASH
Error. There is no space in flash memory.
@ FDS_ERR_OPERATION_TIMEOUT
Error. The operation timed out.
@ FDS_SUCCESS
The operation completed successfully.
@ FDS_ERR_CRC_CHECK_FAILED
Error. The CRC check failed.
@ FDS_ERR_NOT_INITIALIZED
Error. The module has not been initialized.
@ FDS_EVT_DEL_FILE
Event for fds_file_delete.
@ FDS_EVT_INIT
Event for fds_init.
@ FDS_EVT_GC
Event for fds_gc.
@ FDS_EVT_DEL_RECORD
Event for fds_record_delete.
@ FDS_EVT_UPDATE
Event for fds_record_update.
@ FDS_EVT_WRITE
Event for fds_record_write and fds_record_write_reserved.
#define FDS_OP_QUEUE_SIZE
#define FDS_VIRTUAL_PAGES
#define FDS_CRC_CHECK_ON_READ
struct fds_evt_t::@2::@4 write
Information for FDS_EVT_WRITE and FDS_EVT_UPDATE events.
fds_evt_id_t id
The event ID. See fds_evt_id_t.
ret_code_t result
The result of the operation related to this event.
struct fds_evt_t::@2::@5 del
Information for FDS_EVT_DEL_RECORD and FDS_EVT_DEL_FILE events.
A token to keep information about the progress of fds_record_find, fds_record_find_by_key,...
Structure that can be used to read the contents of a record stored in flash.
fds_header_t const * p_header
Location of the record header in flash.
void const * p_data
Location of the record data in flash.
uint32_t const * p_record_src
bool do_gc_page[FDS_DATA_PAGES]
struct fds_op_t::@7::@10 write
struct fds_op_t::@7::@11 del
struct fds_op_t::@7::@9 init
uint32_t volatile records_open
fds_page_type_t page_type
The record descriptor structure that is used to manipulate records.
uint16_t gc_run_count
Number of times garbage collection has been run.
uint32_t record_id
The unique record ID.
bool record_is_open
Whether the record is currently open.
uint32_t const * p_record
The last known location of the record in flash.
A record to be written to flash.
struct fds_record_t::@1 data
uint16_t file_id
The ID of the file that the record belongs to.
uint16_t key
The record key.
A token to a reserved space in flash, created by fds_reserve.
uint16_t length_words
The amount of space reserved (in 4-byte words).
uint16_t page
The logical ID of the page where space was reserved.
uint16_t words_reserved
The number of words reserved by fds_reserve().
bool corruption
Filesystem corruption has been detected.
uint16_t open_records
The number of open records.
uint16_t freeable_words
The largest number of words that can be reclaimed by garbage collection.
uint16_t valid_records
The number of valid records.
uint16_t pages_available
The number of pages available.
uint16_t largest_contig
The largest number of free contiguous words in the file system.
uint16_t words_used
The number of words written to flash, including those reserved for future writes.
uint16_t dirty_records
The number of deleted ("dirty") records.