This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

FDS on app not working when loading app using a bootloader

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;

}

Parents Reply Children
No Data
Related