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

How to use FDS for reading and writing data?

Hello everybody,

I used SDK14.2 S132

I defined fds_write and read function like that;

static ret_code_t kls_fds_write(uint32_t file_id, uint32_t record_key , uint8_t write_data[], uint16_t length)
{		
	fds_record_t        record;
	fds_record_desc_t   record_desc;
	
	// Set up record.
	record.file_id           = file_id;
	record.key               = record_key;
	record.data.p_data       = &write_data;
	record.data.length_words = length;
	
	ret_code_t rc;
	rc = fds_record_write(&record_desc, &record);
	if (rc != FDS_SUCCESS)
	{
			/* Handle error. */
			NRF_LOG_INFO("FDS Write Handle error.");
			return rc;
	}
	NRF_LOG_INFO("Writing Record ID = %d \r\n",record_desc.record_id);
	return NRF_SUCCESS;
	

	
}
	
static ret_code_t kls_fds_read(uint32_t file_id, uint32_t record_key , uint8_t read_data[])
{	
		fds_flash_record_t  flash_record;
		fds_record_desc_t   record_desc;
		fds_find_token_t    ftok;
		/* It is required to zero the token before first use. */
		memset(&ftok, 0x00, sizeof(fds_find_token_t));
		
		uint32_t *data;
		uint32_t err_code;
		
		NRF_LOG_INFO("Start searching... \r\n");
		// Loop until all records with the given key and file ID have been found.
		while (fds_record_find(file_id, record_key, &record_desc, &ftok) == FDS_SUCCESS)
		{
				err_code = fds_record_open(&record_desc, &flash_record);
				if ( err_code != FDS_SUCCESS)
				{
					return err_code;		
				}
				
				NRF_LOG_INFO("Found Record ID = %d\r\n",record_desc.record_id);
				NRF_LOG_INFO("Data = ");
				
				data = (uint32_t *) flash_record.p_data;
				for (uint8_t i=0;i<flash_record.p_header->length_words;i++)
				{
					NRF_LOG_INFO("0x%8x ",data[i]);
					read_data[i] = data[i] ; 
				}
				NRF_LOG_INFO("\r\n");
				// Access the record through the flash_record structure.
				// Close the record when done.
				err_code = fds_record_close(&record_desc);
				if (err_code != FDS_SUCCESS)
				{
					return err_code;	
				}
		}
		return NRF_SUCCESS;		
}

Also, I wrote a function to register particular data;

static void save_data( uint8_t *p_data)
{
	NRF_LOG_INFO("save_data");
	uint8_t source_data_0[10] ;			
	
	// assign source datas  ********************************	
	for (uint32_t i = 0; i < 10; i++)	
	{
		source_data_0[i] = p_data[i];
	}
	while (flag_write_fds == false);
	kls_fds_write(FILE_ID, RECORD_KEY ,source_data_0, 10);
	
	NRF_LOG_RAW_HEXDUMP_INFO(source_data_0, 10);
	
	allow_advertisement = false;

}

Then I used save_data like this;

save_data(nus_data_array);


Then I read data via fds_read

while (flag_write_fds == 0);
kls_fds_read(FILE_ID_SSN, RECORD_KEY_SSN, dest_data_0);
	
NRF_LOG_INFO("dest_data_0 : ");
NRF_LOG_HEXDUMP_INFO(dest_data_0, 10);

As a result;

0> <info> app: save_data
0> <info> app: Writing Record ID = 1 
0> 
0> 41 30 31 31 30 30 30 34|A0110004
0> 30 00 |0.

This is exactly what I want it to be. There is no problem, But when I want to read save_data array;

Result is;

0> <info> app: Start searching...
0> <info> app: Found Record ID = 1
0> 
0> <info> app: Data = 
0> <info> app: 0x20005CC8 
0> <info> app: 0x 9731 
0> <info> app: 0x20005CC8 
0> <info> app: 0x20005CE8 
0> <info> app: 0x 971B 
0> <info> app: 0x 29 
0> <info> app: 0x 0 
0> <info> app: 0x200027B0 
0> <info> app: 0x 2 
0> <info> app: 0x 12A3 
0> <info> app: 
0> 
0> <info> app: dest_data_0 : 
0> <info> app: C8 31 C8 E8 1B 29 00 B0|È1Èè.).°
0> <info> app: 02 A3 |.£

It's a meaningless result.

Q1- Is the problem reading data or writing data or all of them?

Q2- What do I need to do to correctly write and read the data?

Parents Reply Children
  • I got carried away and made an example. I based it on the Flash Data Storage Example and changed cli.c and main.c a little so that you can print out record details as well as the actual data. Use the Command Line Interface library to write and print records. Have a look at the attached files to see the changes I made and how it can be done. 

    /**
     * Copyright (c) 2017 - 2017, Nordic Semiconductor ASA
     * 
     * All rights reserved.
     * 
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     * 
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     * 
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     * 
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     * 
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     * 
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     * 
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     * 
     */
    
    #include <stdint.h>
    #include <string.h>
    #include "nrf.h"
    #include "nordic_common.h"
    #ifdef SOFTDEVICE_PRESENT
    #include "nrf_sdh.h"
    #include "nrf_sdh_ble.h"
    #else
    #include "nrf_drv_clock.h"
    #endif
    #include "fds.h"
    #include "app_timer.h"
    #include "app_error.h"
    #include "nrf_cli.h"
    #include "fds_example.h"
    
    #define NRF_LOG_MODULE_NAME app
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    
    
    /* A tag identifying the SoftDevice BLE configuration. */
    #define APP_BLE_CONN_CFG_TAG    1
    
    
    /* 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_GREEN("Event: %s received (%s)",
                      fds_evt_str[p_evt->id],
                      fds_err_str[p_evt->result]);
    
        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);
                }
            } 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);
                }
                m_delete_all.pending = false;
            } break;
    
            default:
                break;
        }
    }
    
    
    /**@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.");
    
            m_delete_all.delete_next = record_delete_next();
            if (!m_delete_all.delete_next)
            {
                NRF_LOG_CYAN("No records left to delete.");
            }
        }
    }
    
    
    #ifdef SOFTDEVICE_PRESENT
    /**@brief   Function for initializing the SoftDevice and enabling the BLE stack. */
    static void ble_stack_init(void)
    {
        ret_code_t rc;
        uint32_t   ram_start;
    
        /* Enable the SoftDevice. */
        rc = nrf_sdh_enable_request();
        APP_ERROR_CHECK(rc);
    
        rc = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
        APP_ERROR_CHECK(rc);
    
        rc = nrf_sdh_ble_enable(&ram_start);
        APP_ERROR_CHECK(rc);
    }
    #else
    static void clock_init(void)
    {
        /* Initialize the clock. */
        ret_code_t rc = nrf_drv_clock_init();
        APP_ERROR_CHECK(rc);
    
        nrf_drv_clock_lfclk_request(NULL);
    
        /* Wait for the clock to be ready. */
        while (!nrf_clock_lf_is_running()) {;}
    }
    #endif
    
    
    /**@brief   Initialize the timer. */
    static void timer_init(void)
    {
        ret_code_t err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief   Initialize logging. */
    static void log_init(void)
    {
        ret_code_t rc = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(rc);
    }
    
    
    /**@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();
        }
    }
    
    
    int main(void)
    {
        ret_code_t rc;
    
    #ifdef SOFTDEVICE_PRESENT
        ble_stack_init();
    #else
        clock_init();
    #endif
    
        timer_init();
        log_init();
        cli_init();
    
        NRF_LOG_INFO("\033[2J\033[;Hfds example started!")
    
        /* Register first to receive an event when initialization is complete. */
        (void) fds_register(fds_evt_handler);
    
        NRF_LOG_INFO("Initializing fds...");
    
        rc = fds_init();
        APP_ERROR_CHECK(rc);
    
        /* Wait for fds to initialize. */
        wait_for_fds_ready();
    
        NRF_LOG_INFO("Available commands:");
        NRF_LOG_INFO("- print all\t\tprint records");
        NRF_LOG_INFO("- print config\tprint configuration");
        NRF_LOG_INFO("- print data\tprint all records with data");
        NRF_LOG_INFO("- update\t\tupdate configuration");
        NRF_LOG_INFO("- stat\t\tshow statistics");
        NRF_LOG_INFO("- write\t\twrite a new record");
        NRF_LOG_INFO("- delete\t\tdelete a record");
        NRF_LOG_INFO("- delete_all\tdelete all records");
        NRF_LOG_INFO("- gc\t\trun garbage collection");
    
        NRF_LOG_INFO("Reading flash usage statistics...");
    
        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);
    
        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));
    
            NRF_LOG_INFO("Config file found, updating boot count to %d.", m_dummy_cfg.boot_count);
    
            /* Update boot count. */
            m_dummy_cfg.boot_count++;
    
            /* Close the record when done reading. */
            rc = fds_record_close(&desc);
            APP_ERROR_CHECK(rc);
    
            /* Write the updated record to flash. */
            rc = fds_record_update(&desc, &m_dummy_record);
            APP_ERROR_CHECK(rc);
        }
        else
        {
            /* System config not found; write a new one. */
            NRF_LOG_INFO("Writing config file...");
    
            rc = fds_record_write(&desc, &m_dummy_record);
            APP_ERROR_CHECK(rc);
        }
    
        cli_start();
    
        /* Enter main loop. */
        for (;;)
        {
            if (!NRF_LOG_PROCESS())
            {
                power_manage();
            }
            cli_process();
            delete_all_process();
        }
    }
    
    
    /**
     * @}
     */
    

    diff --git a/main (2).c b/main.c
    index d789a58..388fe5c 100644
    --- a/main (2).c	
    +++ b/main.c
    @@ -277,7 +277,7 @@ int main(void)
         log_init();
         cli_init();
     
    -    NRF_LOG_INFO("fds example started!")
    +    NRF_LOG_INFO("\033[2J\033[;Hfds example started!")
     
         /* Register first to receive an event when initialization is complete. */
         (void) fds_register(fds_evt_handler);
    @@ -293,6 +293,7 @@ int main(void)
         NRF_LOG_INFO("Available commands:");
         NRF_LOG_INFO("- print all\t\tprint records");
         NRF_LOG_INFO("- print config\tprint configuration");
    +    NRF_LOG_INFO("- print data\tprint all records with data");
         NRF_LOG_INFO("- update\t\tupdate configuration");
         NRF_LOG_INFO("- stat\t\tshow statistics");
         NRF_LOG_INFO("- write\t\twrite a new record");
    

    /**
     * Copyright (c) 2017 - 2017, Nordic Semiconductor ASA
     * 
     * All rights reserved.
     * 
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     * 
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     * 
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     * 
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     * 
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     * 
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     * 
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     * 
     */
    
    #include <string.h>
    
    #include "app_error.h"
    #include "boards.h"
    #include "nrf_cli.h"
    #include "nrf_cli_uart.h"
    #include "nrf_drv_uart.h"
    #include "fds.h"
    #include "nrf_soc.h"
    #include "sdk_config.h"
    #include "fds_example.h"
    
    
    #define PRINT_HELP  "print records\r\n"                                                             \
                        "usage: print all|config|data"
    
    #define PRINT_ALL_HELP  "print all records\r\n"                                                     \
                            "usage: print all"
    
    #define PRINT_CFG_HELP  "print configuration\r\n"                                                   \
                            "usage: print config"
                            
    #define PRINT_DATA_HELP "print all records with data\r\n"                                                   \
                            "usage: print all records with data"
    
    #define WRITE_HELP  "write a record\r\n"                                                            \
                        "usage: write file_id key \"data\"\r\n"                                         \
                        "- file_id:\tfile ID, in HEX\r\n"                                               \
                        "- key:\trecord key, in HEX\r\n"                                                \
                        "- data:\trecord contents"
    
    #define DELETE_HELP "delete a record\r\n"                                                           \
                        "usage: delete file_id key\r\n"                                                 \
                        "- file_id:\tfile ID, in HEX\r\n"                                               \
                        "- key:\trecord key, in HEX\r\n"                                                \
    
    #define DELETE_ALL_HELP "delete all records\r\n"                                                    \
                            "usage: delete_all"                                                         \
    
    #define UPDATE_HELP "update configuration\r\n"                                                      \
                        "usage: update on|off on|off boot_count device_name"                            \
    
    #define STAT_HELP   "print statistics\r\n"                                                          \
                        "usage: stat"
    
    #define GC_HELP     "run garbage collection\r\n"                                                    \
                        "usage: gc"
    
    
    NRF_CLI_UART_DEF(cli_uart, 0, 64, 16);
    NRF_CLI_DEF(m_cli_uart, "fds example:~$ ", &cli_uart.transport, '\r', 4);
    
    
    /* Defined in main.c */
    extern char const * fds_err_str[];
    
    
    void cli_init(void)
    {
        nrf_drv_uart_config_t uart_config = NRF_DRV_UART_DEFAULT_CONFIG;
        uart_config.pseltxd               = TX_PIN_NUMBER;
        uart_config.pselrxd               = RX_PIN_NUMBER;
        uart_config.hwfc                  = NRF_UART_HWFC_DISABLED;
    
        ret_code_t rc = nrf_cli_init(&m_cli_uart, &uart_config, true, true, NRF_LOG_SEVERITY_INFO);
        APP_ERROR_CHECK(rc);
    }
    
    
    void cli_start(void)
    {
        ret_code_t rc = nrf_cli_start(&m_cli_uart);
        APP_ERROR_CHECK(rc);
    }
    
    
    void cli_process(void)
    {
        nrf_cli_process(&m_cli_uart);
    }
    
    
    static void cli_unknown_param_help(nrf_cli_t const * p_cli,
                                       char const * p_param,
                                       char const * p_cmd)
    {
        nrf_cli_fprintf(p_cli,
                        NRF_CLI_ERROR,
                        "%s: unknown parameter '%s'\r\n"
                        "Try '%s -h' for help.\r\n",
                        p_cmd,
                        p_param,
                        p_cmd);
    }
    
    
    static void cli_wrong_param_count_help(nrf_cli_t const * p_cli, char const * p_cmd)
    {
        nrf_cli_fprintf(p_cli,
                        NRF_CLI_ERROR,
                        "%s: wrong parameter count.\r\n"
                        "Try '%s -h' for help.\r\n",
                        p_cmd,
                        p_cmd);
    }
    
    
    static void record_write(nrf_cli_t const * p_cli,
                             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_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
                        "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_cli_fprintf(p_cli, NRF_CLI_ERROR,
                            "error: fds_record_write() returned %s.\r\n",
                            fds_err_str[rc]);
        }
    }
    
    
    static void record_update(nrf_cli_t const * p_cli, 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_cli_fprintf(p_cli, NRF_CLI_ERROR,
                                "error: fds_record_update() returned %s.\r\n",
                                fds_err_str[rc]);
            }
        }
        else
        {
            nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "error: could not find config file.\r\n");
        }
    }
    
    
    static void record_delete(nrf_cli_t const * p_cli, uint32_t fid, uint32_t key)
    {
        fds_find_token_t tok   = {0};
        fds_record_desc_t desc = {0};
    
        nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
                        "deleting record...\r\n"
                        "file: 0x%x, key: 0x%x\r\n",
                        fid,
                        key);
    
        if (fds_record_find(fid, key, &desc, &tok) == FDS_SUCCESS)
        {
            ret_code_t rc = fds_record_delete(&desc);
            if (rc != FDS_SUCCESS)
            {
                nrf_cli_fprintf(p_cli, NRF_CLI_ERROR,
                                "error: fds_record_delete() returned %s.\r\n", fds_err_str[rc]);
    
                return;
            }
    
            nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT, "record id: 0x%x\r\n", desc.record_id);
        }
        else
        {
            nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "error: record not found!\r\n");
        }
    }
    
    
    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;
        }
    }
    
    
    static void print_cmd(nrf_cli_t const * p_cli, size_t argc, char ** argv)
    {
        if (nrf_cli_help_requested(p_cli))
        {
            nrf_cli_help_print(p_cli, NULL, 0);
        }
        else if (argc != 2)
        {
            cli_wrong_param_count_help(p_cli, "print");
        }
        else
        {
            cli_unknown_param_help(p_cli, argv[1], "print");
        }
    }
    
    
    static void print_cfg_cmd(nrf_cli_t const * p_cli, size_t argc, char ** argv)
    {
        fds_record_desc_t desc = {0};
        fds_find_token_t  tok  = {0};
    
        while (fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &tok) == FDS_SUCCESS)
        {
            ret_code_t rc;
            fds_flash_record_t frec = {0};
    
            rc = fds_record_open(&desc, &frec);
            switch (rc)
            {
                case FDS_SUCCESS:
                    break;
    
                case FDS_ERR_CRC_CHECK_FAILED:
                    nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "error: CRC check failed!\r\n");
                    continue;
    
                case FDS_ERR_NOT_FOUND:
                    nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "error: record not found!\r\n");
                    continue;
    
                default:
                {
                    nrf_cli_fprintf(p_cli, NRF_CLI_ERROR,
                                    "error: unexpecte error %s.\r\n",
                                    fds_err_str[rc]);
    
                    continue;
                }
            }
    
            configuration_t * p_cfg = (configuration_t*)frec.p_data;
    
            nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
                            "config1:\t%s\r\n"
                            "config2:\t%s\r\n"
                            "boot count:\t%u\r\n"
                            "device name:\t%s\r\n",
                            p_cfg->config1_on ? "on" : "off",
                            p_cfg->config2_on ? "on" : "off",
                            p_cfg->boot_count,
                            p_cfg->device_name);
    
            rc = fds_record_close(&desc);
            APP_ERROR_CHECK(rc);
        }
    }
    
    
    static void print_all_cmd(nrf_cli_t const * p_cli, size_t argc, char ** argv)
    {
        fds_find_token_t tok   = {0};
        fds_record_desc_t desc = {0};
    
        nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
                        "rec. id\t"
                        "\tfile id\t"
                        "\trec. key"
                        "\tlength\r\n");
    
        while (fds_record_iterate(&desc, &tok) != FDS_ERR_NOT_FOUND)
        {
            ret_code_t rc;
            fds_flash_record_t frec = {0};
    
            rc = fds_record_open(&desc, &frec);
            switch (rc)
            {
                case FDS_SUCCESS:
                    break;
    
                case FDS_ERR_CRC_CHECK_FAILED:
                    nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "error: CRC check failed!\r\n");
                    continue;
    
                case FDS_ERR_NOT_FOUND:
                    nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "error: record not found!\r\n");
                    continue;
    
                default:
                {
                    nrf_cli_fprintf(p_cli, NRF_CLI_ERROR,
                                    "error: unexpecte error %s.\r\n",
                                    fds_err_str[rc]);
    
                    continue;
                }
            }
    
            uint32_t const len = frec.p_header->length_words * sizeof(uint32_t);
    
            nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
                            " 0x%04x\t"
                            "\t 0x%04x\t"
                            "\t 0x%04x\t"
                            "\t %4u bytes\r\n",
                            frec.p_header->record_id,
                            frec.p_header->file_id,
                            frec.p_header->record_key,
                            len);
    
            rc = fds_record_close(&desc);
            APP_ERROR_CHECK(rc);
        }
    }
    
    
    static void write_cmd(nrf_cli_t const * p_cli, size_t argc, char ** argv)
    {
    
        if (nrf_cli_help_requested(p_cli))
        {
            nrf_cli_help_print(p_cli, NULL, 0);
        }
        else if (argc != 4)
        {
            cli_wrong_param_count_help(p_cli, "write");
        }
        else
        {
            /* Must be statically allocated, because it is going to be written in flash. */
            static uint8_t m_data[256];
    
            uint16_t const fid  = strtol(argv[1], NULL, 16);
            uint16_t const key  = strtol(argv[2], NULL, 16);
    
            uint32_t const len  = strlen(argv[3]) < sizeof(m_data) ?
                                  strlen(argv[3]) : sizeof(m_data);
    
            /* Copy data to static variable. */
            memset(m_data, 0x00, sizeof(m_data));
            memcpy(m_data, argv[3], len);
    
            record_write(p_cli, fid, key, m_data, len);
        }
    }
    
    
    static void update_cmd(nrf_cli_t const * p_cli, size_t argc, char ** argv)
    {
        if (nrf_cli_help_requested(p_cli))
        {
            nrf_cli_help_print(p_cli, NULL, 0);
        }
        else if (argc != 5)
        {
            cli_wrong_param_count_help(p_cli, "update");
        }
        else
        {
            /* Must be statically allocated, because it is going to be written in flash. */
            static configuration_t cfg = {0};
    
            cfg.config1_on = !strcmp(argv[1], "on");
            cfg.config2_on = !strcmp(argv[2], "on");
            cfg.boot_count = strtol(argv[3], NULL, 10);
    
            uint16_t const len = strlen(argv[4]) < sizeof(cfg.device_name) ?
                                 strlen(argv[4]) : sizeof(cfg.device_name);
    
            memcpy(cfg.device_name, argv[4], len);
    
            nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
                "updating configuration: %s, %s, boot_count=%u, device_name=\"%s\"\r\n",
                cfg.config1_on ? "on" : "off",
                cfg.config2_on ? "on" : "off",
                cfg.boot_count,
                cfg.device_name);
    
            record_update(p_cli, &cfg);
        }
    }
    
    
    static void delete_cmd(nrf_cli_t const * p_cli, size_t argc, char ** argv)
    {
        if (nrf_cli_help_requested(p_cli))
        {
            nrf_cli_help_print(p_cli, NULL, 0);
        }
        else if (argc < 3)
        {
            cli_wrong_param_count_help(p_cli, "delete");
        }
        else
        {
            uint32_t const fid  = strtol(argv[1], NULL, 16);
            uint32_t const key  = strtol(argv[2], NULL, 16);
    
            record_delete(p_cli, fid, key);
        }
    }
    
    
    static void delete_all_cmd(nrf_cli_t const * p_cli, size_t argc, char ** argv)
    {
        if (nrf_cli_help_requested(p_cli))
        {
            nrf_cli_help_print(p_cli, NULL, 0);
        }
        else if (argc != 1)
        {
            cli_wrong_param_count_help(p_cli, "delete_all");
        }
        else
        {
            delete_all_begin();
        }
    }
    
    
    static void stat_cmd(nrf_cli_t const * p_cli, size_t argc, char **argv)
    {
        if (nrf_cli_help_requested(p_cli))
        {
            nrf_cli_help_print(p_cli, NULL, 0);
        }
        else
        {
            /* Print fds_stat(). */
            fds_stat_t stat = {0};
    
            ret_code_t rc = fds_stat(&stat);
            APP_ERROR_CHECK(rc);
    
            nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
                            "total pages:\t%u\r\n"
                            "total records:\t%u\r\n"
                            "valid records:\t%u\r\n"
                            "dirty records:\t%u\r\n"
                            "largest contig:\t%u\r\n"
                            "freeable words:\t%u (%u bytes)\r\n",
                            stat.pages_available,
                            stat.valid_records + stat.dirty_records,
                            stat.valid_records,
                            stat.dirty_records,
                            stat.largest_contig,
                            stat.freeable_words,
                            stat.freeable_words * sizeof(uint32_t));
        }
    }
    
    
    static void gc_cmd(nrf_cli_t const * p_cli, size_t argc, char ** argv)
    {
        ret_code_t rc = fds_gc();
        switch (rc)
        {
            case FDS_SUCCESS:
                break;
    
            default:
                nrf_cli_fprintf(p_cli, NRF_CLI_ERROR,
                                "error: garbage collection returned %s\r\n", fds_err_str[rc]);
                break;
        }
    }
    
    static void convert_raw_data_to_human_readable(nrf_cli_t const * p_cli, uint32_t raw_data)
    {
        nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
                "|");
        for(uint8_t i = 0; i < 4; i++)
        {
            nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
                        "%c",
                        (uint8_t)(raw_data >> (8 * i)));
        }
        nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
                "|\r\n");
    }
    
    static void print_data_cmd(nrf_cli_t const * p_cli, size_t argc, char ** argv)
    {
        fds_find_token_t tok   = {0};
        fds_record_desc_t desc = {0};
    
    
        while (fds_record_iterate(&desc, &tok) != FDS_ERR_NOT_FOUND)
        {
            
            nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
                            "rec. id\t"
                            "\tfile id\t"
                            "\trec. key\t"
                            "\tlength\r\n");
            
            ret_code_t rc;
            fds_flash_record_t frec = {0};
    
            rc = fds_record_open(&desc, &frec);
            switch (rc)
            {
                case FDS_SUCCESS:
                    break;
    
                case FDS_ERR_CRC_CHECK_FAILED:
                    nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "error: CRC check failed!\r\n");
                    continue;
    
                case FDS_ERR_NOT_FOUND:
                    nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "error: record not found!\r\n");
                    continue;
    
                default:
                {
                    nrf_cli_fprintf(p_cli, NRF_CLI_ERROR,
                                    "error: unexpecte error %s.\r\n",
                                    fds_err_str[rc]);
    
                    continue;
                }
            }
    
            uint32_t const len = frec.p_header->length_words * sizeof(uint32_t);
    
            nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
                            " 0x%04x\t"
                            "\t 0x%04x\t"
                            "\t 0x%04x\t"
                            "\t %4u bytes\r\n",
                            frec.p_header->record_id,
                            frec.p_header->file_id,
                            frec.p_header->record_key,
                            len);
    
            uint32_t * data = (uint32_t *)frec.p_data;
            
            nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT, "\r\nData:\r\n");
            for(uint32_t i; i < len / 4; i++)
            {
                nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
                                " 0x%08x\t",
                                *data);
                convert_raw_data_to_human_readable(p_cli, *data);
                data++;
            }
            
            nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT, "\r\n\r\n");
            
            rc = fds_record_close(&desc);
            APP_ERROR_CHECK(rc);
        }
    }
    
    NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_print)
    {
        NRF_CLI_CMD(all,        NULL, PRINT_ALL_HELP,   print_all_cmd),
        NRF_CLI_CMD(config,     NULL, PRINT_CFG_HELP,   print_cfg_cmd),
        NRF_CLI_CMD(data,       NULL, PRINT_DATA_HELP,  print_data_cmd),
        NRF_CLI_SUBCMD_SET_END
    };
    
    
    NRF_CLI_CMD_REGISTER(print,      &m_print, PRINT_HELP,      print_cmd);
    NRF_CLI_CMD_REGISTER(write,      NULL,     WRITE_HELP,      write_cmd);
    NRF_CLI_CMD_REGISTER(update,     NULL,     UPDATE_HELP,     update_cmd);
    NRF_CLI_CMD_REGISTER(delete,     NULL,     DELETE_HELP,     delete_cmd);
    NRF_CLI_CMD_REGISTER(delete_all, NULL,     DELETE_ALL_HELP, delete_all_cmd);
    NRF_CLI_CMD_REGISTER(gc,         NULL,     GC_HELP,         gc_cmd);
    NRF_CLI_CMD_REGISTER(stat,       NULL,     STAT_HELP,       stat_cmd);
    

    diff --git a/cli (2).c b/cli.c
    index 3637067..47eed07 100644
    --- a/cli (2).c	
    +++ b/cli.c
    @@ -52,13 +52,16 @@
     
     
     #define PRINT_HELP  "print records\r\n"                                                             \
    -                    "usage: print all|config"
    +                    "usage: print all|config|data"
     
     #define PRINT_ALL_HELP  "print all records\r\n"                                                     \
                             "usage: print all"
     
     #define PRINT_CFG_HELP  "print configuration\r\n"                                                   \
                             "usage: print config"
    +                        
    +#define PRINT_DATA_HELP "print all records with data\r\n"                                                   \
    +                        "usage: print all records with data"
     
     #define WRITE_HELP  "write a record\r\n"                                                            \
                         "usage: write file_id key \"data\"\r\n"                                         \
    @@ -533,11 +536,98 @@ static void gc_cmd(nrf_cli_t const * p_cli, size_t argc, char ** argv)
         }
     }
     
    +static void convert_raw_data_to_human_readable(nrf_cli_t const * p_cli, uint32_t raw_data)
    +{
    +    nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
    +            "|");
    +    for(uint8_t i = 0; i < 4; i++)
    +    {
    +        nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
    +                    "%c",
    +                    (uint8_t)(raw_data >> (8 * i)));
    +    }
    +    nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
    +            "|\r\n");
    +}
    +
    +static void print_data_cmd(nrf_cli_t const * p_cli, size_t argc, char ** argv)
    +{
    +    fds_find_token_t tok   = {0};
    +    fds_record_desc_t desc = {0};
    +
    +
    +    while (fds_record_iterate(&desc, &tok) != FDS_ERR_NOT_FOUND)
    +    {
    +        
    +        nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
    +                        "rec. id\t"
    +                        "\tfile id\t"
    +                        "\trec. key\t"
    +                        "\tlength\r\n");
    +        
    +        ret_code_t rc;
    +        fds_flash_record_t frec = {0};
    +
    +        rc = fds_record_open(&desc, &frec);
    +        switch (rc)
    +        {
    +            case FDS_SUCCESS:
    +                break;
    +
    +            case FDS_ERR_CRC_CHECK_FAILED:
    +                nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "error: CRC check failed!\r\n");
    +                continue;
    +
    +            case FDS_ERR_NOT_FOUND:
    +                nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "error: record not found!\r\n");
    +                continue;
    +
    +            default:
    +            {
    +                nrf_cli_fprintf(p_cli, NRF_CLI_ERROR,
    +                                "error: unexpecte error %s.\r\n",
    +                                fds_err_str[rc]);
    +
    +                continue;
    +            }
    +        }
    +
    +        uint32_t const len = frec.p_header->length_words * sizeof(uint32_t);
    +
    +        nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
    +                        " 0x%04x\t"
    +                        "\t 0x%04x\t"
    +                        "\t 0x%04x\t"
    +                        "\t %4u bytes\r\n",
    +                        frec.p_header->record_id,
    +                        frec.p_header->file_id,
    +                        frec.p_header->record_key,
    +                        len);
    +
    +        uint32_t * data = (uint32_t *)frec.p_data;
    +        
    +        nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT, "\r\nData:\r\n");
    +        for(uint32_t i; i < len / 4; i++)
    +        {
    +            nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT,
    +                            " 0x%08x\t",
    +                            *data);
    +            convert_raw_data_to_human_readable(p_cli, *data);
    +            data++;
    +        }
    +        
    +        nrf_cli_fprintf(p_cli, NRF_CLI_DEFAULT, "\r\n\r\n");
    +        
    +        rc = fds_record_close(&desc);
    +        APP_ERROR_CHECK(rc);
    +    }
    +}
     
     NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_print)
     {
    -    NRF_CLI_CMD(all,    NULL, PRINT_ALL_HELP, print_all_cmd),
    -    NRF_CLI_CMD(config, NULL, PRINT_CFG_HELP, print_cfg_cmd),
    +    NRF_CLI_CMD(all,        NULL, PRINT_ALL_HELP,   print_all_cmd),
    +    NRF_CLI_CMD(config,     NULL, PRINT_CFG_HELP,   print_cfg_cmd),
    +    NRF_CLI_CMD(data,       NULL, PRINT_DATA_HELP,  print_data_cmd),
         NRF_CLI_SUBCMD_SET_END
     };
     
    

  • Printing is done in print_data_cmd() in cli.c.

  • Thank you so much for your solution. But I have to store data into uint8_t array[10]. It means, I want to write "abcdefghij" via nus_data . I can do this shown as below, there is no problem.

    0> <info> app: save_data
    0> <info> app: Writing Record ID = 1 
    0>
    0> 61 62 63 64 65 66 67 68|abcdefgh
    0> 69 6A |ij

    Then I want to read "abcdefghij" and store it in uint8_t array [10].

    That's why I figure out your "convert_raw_data_to_human_readable" function as below:

    static void convert_raw_data_to_human_readable(uint8_t *out_data , uint32_t in_data)
    {
        for(uint8_t i = 0; i < 4; i++)
    	{
    		out_data[i] = (uint8_t)(in_data >> (8 * i));
        }
    }

    And I put the function inside kls_fds_read() function like this;

    uint32_t *data     = (uint32_t *) flash_record.p_data;
    uint32_t const len = flash_record.p_header->length_words * sizeof(uint32_t);
    				
    for(uint32_t i; i < len / 4; i++)
    {
        convert_raw_data_to_human_readable(read_data, *data);
        data++;
    }

    Finally, I'm trying to write on my destination array(dest_data_0[10]);

    static void first_Setup(void)
    {
    	NRF_LOG_INFO("first_Setup Start");
    	uint8_t dest_data_0[10]  = {0};
    
    	
    	while (flag_write_fds == 0);
    	kls_fds_read(FILE_ID, RECORD_KEY, dest_data_0);
    }

    But I did not get the data I wrote.

    RTT Viewer output:

     0> <info> app: first_Setup Start

    0> <info> app: Found Record ID = 1
    0>
    0> <info> app: Data =
    0> <info> app: dest_data_0 :
    0> <info> app: 00 00 00 00 00 00 00 00|........
    0> <info> app: 00 00 |..

  • I'm still a little confused about the flow in your code. How about something like this:

    uint8_t * pointer_to_record_data;
    pointer_to_record_data = (uint8_t *)frec.p_data;
    
    uint8_t test_data_0[10];
    
    if(frec.p_header->record_key == A_RELEVANT_RECORD_KEY)
    {
        for(uint8_t i = 0; i < 10; i++)
        {
            test_data_0[i] = *pointer_to_record_data;
            pointer_to_record_data++;
        }
    }

    to get the record data stored in your array. 

  • How can I do data storing or printing without using CLI? Because I do not want to print data or anything else. I only want to store the data in an array that I write with fds_write. 

    I wil try to explain what I need;

    1. Write " uint8_t a[4] = { 'a', 'b', 'c', '\0' }; "  this array via FDS write
    2. Read "a[4]" from FDS 
    3. Store "a[4]" into uint8_t "b[4]" ; 
    4. The value of the b[4] (read_data) should print like this ;  NRF_LOG_HEXDUMP_INFO(b, sizeof(b));

    Result must be;

    0> <info> app:  61 62 63 00            |abc.   

    I want to do all of this without using cli.

Related