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
  • Can you show us how you print out your data? And maybe post more of your code?

    Values like 0x20005CC8 look like addresses in RAM, so it might be that you are simply printing out the location of your data, and not the data itself. 

  • Yes, you are exactly right. Because 

    void         const * p_data;    //!< Location of the record data in flash.

    It means, I read the location, not Data itself. So how can I read Data itself?

  • 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
     };
     
    

Reply
  • 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
     };
     
    

Children
  • 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