Hello,
I am having an odd issue when loading an app that uses FDS with softdevice, if I load the app without a bootloader the FDS library seems to work just fine but if I use the bootloader to load the app the FDS library is stuck at the fds_init method, Is there a way to get a workaround of this, I am using sdk 15.0.0.
include "flashconfig.h" #include <stdint.h> #include <stdbool.h> #include "fds.h" #include "nrf_log.h" #include "nrf_log_ctrl.h" #include <string.h> #include "SoftwareSerial.h" /* File ID and Key used for the configuration record. */ #define CONFIG_FILE (0xF010) #define CONFIG_REC_KEY (0x7010) extern char const *fds_err_str[]; /* A dummy structure to save in flash. */ typedef struct { uint32_t boot_count; char device_name[16]; bool config1_on; bool config2_on; } configuration_t; /* Array to map FDS return values to strings. */ char const *fds_err_str[] = { "FDS_SUCCESS", "FDS_ERR_OPERATION_TIMEOUT", "FDS_ERR_NOT_INITIALIZED", "FDS_ERR_UNALIGNED_ADDR", "FDS_ERR_INVALID_ARG", "FDS_ERR_NULL_ARG", "FDS_ERR_NO_OPEN_RECORDS", "FDS_ERR_NO_SPACE_IN_FLASH", "FDS_ERR_NO_SPACE_IN_QUEUES", "FDS_ERR_RECORD_TOO_LARGE", "FDS_ERR_NOT_FOUND", "FDS_ERR_NO_PAGES", "FDS_ERR_USER_LIMIT_REACHED", "FDS_ERR_CRC_CHECK_FAILED", "FDS_ERR_BUSY", "FDS_ERR_INTERNAL", }; /* Array to map FDS events to strings. */ static char const *fds_evt_str[] = { "FDS_EVT_INIT", "FDS_EVT_WRITE", "FDS_EVT_UPDATE", "FDS_EVT_DEL_RECORD", "FDS_EVT_DEL_FILE", "FDS_EVT_GC", }; /* Dummy configuration data. */ static configuration_t m_dummy_cfg = { .config1_on = false, .config2_on = true, .boot_count = 0x0, .device_name = "dummy", }; /* A record containing dummy configuration data. */ static fds_record_t const m_dummy_record = { .file_id = CONFIG_FILE, .key = CONFIG_REC_KEY, .data.p_data = &m_dummy_cfg, /* The length of a record is always expressed in 4-byte units (words). */ .data.length_words = (sizeof(m_dummy_cfg) + 3) / sizeof(uint32_t), }; /* Keep track of the progress of a delete_all operation. */ static struct { bool delete_next; //!< Delete next record. bool pending; //!< Waiting for an fds FDS_EVT_DEL_RECORD event, to delete the next record. } m_delete_all; /* Flag to check fds initialization. */ static bool volatile m_fds_initialized; static void fds_evt_handler(fds_evt_t const *p_evt) { NRF_LOG_INFO("Event: %s received (%s)", fds_evt_str[p_evt->id], fds_err_str[p_evt->result]); NRF_LOG_FLUSH(); switch (p_evt->id) { case FDS_EVT_INIT: if (p_evt->result == FDS_SUCCESS) { m_fds_initialized = true; } break; case FDS_EVT_WRITE: { if (p_evt->result == FDS_SUCCESS) { NRF_LOG_INFO("Record ID:\t0x%04x", p_evt->write.record_id); NRF_LOG_INFO("File ID:\t0x%04x", p_evt->write.file_id); NRF_LOG_INFO("Record key:\t0x%04x", p_evt->write.record_key); NRF_LOG_FLUSH(); } } break; case FDS_EVT_DEL_RECORD: { if (p_evt->result == FDS_SUCCESS) { NRF_LOG_INFO("Record ID:\t0x%04x", p_evt->del.record_id); NRF_LOG_INFO("File ID:\t0x%04x", p_evt->del.file_id); NRF_LOG_INFO("Record key:\t0x%04x", p_evt->del.record_key); NRF_LOG_FLUSH(); } m_delete_all.pending = false; } break; default: break; } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /**@brief Sleep until an event is received. */ static void power_manage(void) { #ifdef SOFTDEVICE_PRESENT (void)sd_app_evt_wait(); #else __WFE(); #endif } /**@brief Wait for fds to initialize. */ static void wait_for_fds_ready(void) { while (!m_fds_initialized) { power_manage(); } } static void record_write(uint32_t fid, uint32_t key, void const *p_data, uint32_t len) { fds_record_t const rec = { .file_id = fid, .key = key, .data.p_data = p_data, .data.length_words = (len + 3) / sizeof(uint32_t)}; NRF_LOG_INFO("writing record to flash...\r\n" "file: 0x%x, key: 0x%x, \"%s\", len: %u bytes\r\n", fid, key, p_data, len); ret_code_t rc = fds_record_write(NULL, &rec); if (rc != FDS_SUCCESS) { NRF_LOG_INFO( "error: fds_record_write() returned %s.\r\n", fds_err_str[rc]); } } static void record_update(configuration_t const *p_cfg) { fds_record_desc_t desc = {0}; fds_find_token_t ftok = {0}; if (fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &ftok) == FDS_SUCCESS) { fds_record_t const rec = { .file_id = CONFIG_FILE, .key = CONFIG_REC_KEY, .data.p_data = p_cfg, .data.length_words = (sizeof(configuration_t) + 3) / sizeof(uint32_t)}; ret_code_t rc = fds_record_update(&desc, &rec); if (rc != FDS_SUCCESS) { NRF_LOG_INFO( "error: fds_record_update() returned %s.\r\n", fds_err_str[rc]); NRF_LOG_FLUSH(); } } else { NRF_LOG_INFO("error: could not find config file.\r\n"); NRF_LOG_FLUSH(); } } static void record_delete(uint32_t fid, uint32_t key) { fds_find_token_t tok = {0}; fds_record_desc_t desc = {0}; NRF_LOG_INFO( "deleting record...\r\n" "file: 0x%x, key: 0x%x\r\n", fid, key); NRF_LOG_FLUSH(); if (fds_record_find(fid, key, &desc, &tok) == FDS_SUCCESS) { ret_code_t rc = fds_record_delete(&desc); if (rc != FDS_SUCCESS) { NRF_LOG_INFO( "error: fds_record_delete() returned %s.\r\n", fds_err_str[rc]); NRF_LOG_FLUSH(); return; } NRF_LOG_INFO("record id: 0x%x\r\n", desc.record_id); NRF_LOG_FLUSH(); } else { NRF_LOG_INFO("error: record not found!\r\n"); NRF_LOG_FLUSH(); } } bool record_delete_next(void) { fds_find_token_t tok = {0}; fds_record_desc_t desc = {0}; if (fds_record_iterate(&desc, &tok) == FDS_SUCCESS) { ret_code_t rc = fds_record_delete(&desc); if (rc != FDS_SUCCESS) { return false; } return true; } else { /* No records left to delete. */ return false; } } /**@brief Begin deleting all records, one by one. */ void delete_all_begin(void) { m_delete_all.delete_next = true; } /**@brief Process a delete all command. * * Delete records, one by one, until no records are left. */ void delete_all_process(void) { if (m_delete_all.delete_next & !m_delete_all.pending) { NRF_LOG_INFO("Deleting next record."); NRF_LOG_FLUSH(); m_delete_all.delete_next = record_delete_next(); if (!m_delete_all.delete_next) { NRF_LOG_INFO("No records left to delete."); NRF_LOG_FLUSH(); } } } // run garbage collection static void gc_cmd() { ret_code_t rc = fds_gc(); switch (rc) { case FDS_SUCCESS: NRF_LOG_INFO( "file system is now clean\r\n"); NRF_LOG_FLUSH(); break; default: NRF_LOG_INFO( "error: garbage collection returned %s\r\n", fds_err_str[rc]); NRF_LOG_FLUSH(); break; } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void flashconfig_begin() { ret_code_t rc; NRF_LOG_INFO("FDS example started.") NRF_LOG_FLUSH(); SoftwareSerial_printf("FDS example started.\r\n"); /* Register first to receive an event when initialization is complete. */ (void)fds_register(fds_evt_handler); NRF_LOG_INFO("Initializing fds..."); NRF_LOG_FLUSH(); SoftwareSerial_printf("Initializing fds...\r\n"); rc = fds_init(); APP_ERROR_CHECK(rc); /* Wait for fds to initialize. */ wait_for_fds_ready(); NRF_LOG_INFO("Reading flash usage statistics..."); NRF_LOG_FLUSH(); SoftwareSerial_printf("Reading flash usage statistics...\r\n"); fds_stat_t stat = {0}; rc = fds_stat(&stat); APP_ERROR_CHECK(rc); NRF_LOG_INFO("Found %d valid records.", stat.valid_records); NRF_LOG_INFO("Found %d dirty records (ready to be garbage collected).", stat.dirty_records); NRF_LOG_FLUSH(); SoftwareSerial_printf("Found %d valid records.\r\n", stat.valid_records); SoftwareSerial_printf("Found %d dirty records (ready to be garbage collected).\r\n", stat.dirty_records); if (stat.dirty_records > 0) { gc_cmd(); wait_for_fds_ready(); } fds_record_desc_t desc = {0}; fds_find_token_t tok = {0}; rc = fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &tok); if (rc != FDS_SUCCESS) { /* System config not found; write a new one. */ NRF_LOG_INFO("Writing config file..."); NRF_LOG_FLUSH(); SoftwareSerial_printf("Writing config file...\r\n"); rc = fds_record_write(&desc, &m_dummy_record); APP_ERROR_CHECK(rc); } } bool flashconfig_setESN(char *newESN) { bool result=false; ret_code_t rc; fds_record_desc_t desc = {0}; fds_find_token_t tok = {0}; rc = fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &tok); if (rc == FDS_SUCCESS) { /* A config file is in flash. Let's update it. */ fds_flash_record_t config = {0}; /* Open the record and read its contents. */ rc = fds_record_open(&desc, &config); APP_ERROR_CHECK(rc); //wait_for_fds_ready(); /* Copy the configuration from flash into m_dummy_cfg. */ memcpy(&m_dummy_cfg, config.p_data, sizeof(configuration_t)); char mytmp[16]={0}; memcpy(mytmp,newESN,sizeof(mytmp)); NRF_LOG_INFO("Comparing %s vs %s", m_dummy_cfg.device_name, mytmp); NRF_LOG_FLUSH(); SoftwareSerial_printf("Comparing %s vs %s\r\n", m_dummy_cfg.device_name, mytmp); /* Update ESN field. */ int rescmp = strcmp(m_dummy_cfg.device_name, mytmp); if(rescmp!=0) { memset(m_dummy_cfg.device_name, 0, sizeof(m_dummy_cfg.device_name)); memcpy(m_dummy_cfg.device_name, mytmp, strlen(mytmp)); result = true; NRF_LOG_INFO("The ESN is different, updating ESN %s.", m_dummy_cfg.device_name); NRF_LOG_FLUSH(); SoftwareSerial_printf("The ESN is different, updating ESN %s.\r\n", m_dummy_cfg.device_name); } else { NRF_LOG_INFO("The ESN %s is already the same we have.", m_dummy_cfg.device_name); NRF_LOG_FLUSH(); SoftwareSerial_printf("The ESN %s is already the same we have.\r\n", m_dummy_cfg.device_name); result = false; } /* Close the record when done reading. */ rc = fds_record_close(&desc); APP_ERROR_CHECK(rc); /* Update ESN record. */ if(rescmp!=0) { /* Write the updated record to flash. */ rc = fds_record_update(&desc, &m_dummy_record); APP_ERROR_CHECK(rc); NRF_LOG_INFO("FDS UPDATED"); NRF_LOG_FLUSH(); SoftwareSerial_printf("FDS UPDATED\r\n"); } } return result; } char *flashconfig_getESN() { ret_code_t rc; fds_record_desc_t desc = {0}; fds_find_token_t tok = {0}; rc = fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &tok); if (rc == FDS_SUCCESS) { /* A config file is in flash. Let's update it. */ fds_flash_record_t config = {0}; /* Open the record and read its contents. */ rc = fds_record_open(&desc, &config); APP_ERROR_CHECK(rc); /* Copy the configuration from flash into m_dummy_cfg. */ memcpy(&m_dummy_cfg, config.p_data, sizeof(configuration_t)); /* Close the record when done reading. */ rc = fds_record_close(&desc); APP_ERROR_CHECK(rc); } return m_dummy_cfg.device_name; }
#ifndef FLASHCONFIG_H_ #define FLASHCONFIG_H_ #include <stdint.h> #include <stdbool.h> void flashconfig_begin(); bool flashconfig_setESN(char* newESN); char* flashconfig_getESN(); #endif
When I load the app using the bootloader the app is always crashing at this point.
rc = fds_init(); APP_ERROR_CHECK(rc); /* Wait for fds to initialize. */ wait_for_fds_ready();
Do you have an idea of what could it be causing it?
The main function is like this:
#include <stdbool.h> #include <stdint.h> #include "nrf.h" #include "nrf_drv_timer.h" #include "bsp.h" #include "app_error.h" #include <string.h> #include "flashconfig.h" int main(void) { NRF_POWER->TASKS_CONSTLAT = 1; et_code_t err_code = nrf_drv_clock_init(); APP_ERROR_CHECK(err_code); flashconfig_begin(); flashconfig_getESN(); return 0; }