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

Ndef library: multiple records update issue

Hello,

I have multiple records that I want to update during the runtime of the program.

What is working:

1. I can write in memory for the first time initial values.

2. I can update all records and it works.

3. I can load all records and it works.

Problem:

When I update for the first time one of the records. All other records points the same "default" location, like they are de-referenced.

However if I update each record one time, it work fine forever.

#define FILE_ID         0x1111  
#define REC_KEY         0x1908
#define TOTAL_RECORDS       3

static fds_record_desc_t  m_record_desc[TOTAL_RECORDS];
static fds_record_t       m_record[TOTAL_RECORDS];

ret_code_t ndef_file_load(uint8_t * p_buff, uint32_t size, uint8_t id)
{
    ret_code_t         err_code;
    fds_find_token_t   ftok;
    fds_flash_record_t flash_record;

    // Always clear token before running new file/record search.
    memset(&ftok, 0x00, sizeof(fds_find_token_t));

    // Search for NDEF message in FLASH.
    err_code = fds_record_find(FILE_ID, REC_KEY+id, &m_record_desc[id], &ftok);

    // If there is no record with given key and file ID,
    // create default message and store in FLASH.
    if (err_code == NRF_SUCCESS)
    {
        NRF_LOG_INFO("Found NDEF file record for id %d", id);

        // Open record for read.
        err_code = fds_record_open(&m_record_desc[id], &flash_record);
        VERIFY_SUCCESS(err_code);

        // Access the record through the flash_record structure.
        memcpy(p_buff,
               flash_record.p_data,
               flash_record.p_header->length_words * sizeof(uint32_t));

        // Print file length and raw message data.
        NRF_LOG_DEBUG("NDEF file data length: %u bytes.",
                      flash_record.p_header->length_words * sizeof(uint32_t));

        NRF_LOG_HEXDUMP_DEBUG(p_buff, flash_record.p_header->length_words * sizeof(uint32_t));

        // Close the record when done.
        err_code = fds_record_close(&m_record_desc[id]);
    }
    else if (err_code == FDS_ERR_NOT_FOUND)
    {
        NRF_LOG_INFO("NDEF file record not found, default NDEF file created.", err_code);

        // Create default NDEF message.
        ndef_file_default_message(p_buff, size, id);

        // Create record with default NDEF message.
        err_code = ndef_record_create(p_buff, size, id);
    }

    return err_code;
}

static void ndef_file_default_message(uint8_t * p_buff, uint32_t p_size, uint8_t id)
{
    for(int i=0; i<p_size; i++)
    {
        p_buff[i] = 0xFF;
    }
}

static void ndef_file_prepare_record(uint8_t const * p_buff, uint32_t size, uint8_t id)
{
    // Set up record.
    m_record[id].file_id           = FILE_ID;
    m_record[id].key               = REC_KEY + id;
    m_record[id].data.p_data       = p_buff;
    m_record[id].data.length_words = BYTES_TO_WORDS(size); // Align data length to 4 bytes.
}

static ret_code_t ndef_record_create(uint8_t const * p_buff, uint32_t size, uint8_t id)
{
    ret_code_t err_code;

    // Prepare record structure.
    ndef_file_prepare_record(p_buff, size, id);

    err_code = fds_record_write(&m_record_desc[id], &m_record[id]);
    VERIFY_SUCCESS(err_code);

    return err_code;
}

ret_code_t ndef_file_update(uint8_t const * p_buff, uint32_t size, uint8_t id)
{
    ret_code_t err_code;

    // Prepare record structure.
    ndef_file_prepare_record(p_buff, size, id);

    // Update FLASH file with new NDEF message.
    err_code = fds_record_update(&m_record_desc[id], &m_record[id]);
    VERIFY_SUCCESS(err_code);

    return err_code;
}

Records are stored in a static fds_record_t array and they got their own individual key.

Any idea on the direction to explore ?

Thanks

Parents
  • Hi,

    I do not see anything problematic in the code snippet. Your ndef_file_update() only modifies the element given by "id" of m_record_desc and m_record, and fds_record_update() will not change any other record. The only thing it will do is write a new record with the same key and file ID as the old (but with new content), and mark the old as dirty. Existing records will not be touched, and will remain in the same flash location until garbage collection is performed.

    Can you make a more complete example that demonstrates the issue that I can run on a DK on my side?

  • 1. In an init function called once before the main loop, you load the data stored in flash. If the records are already there, then they are loaded, otherwise a default value is written in flash with value 0xFF * size of the data.

    2. Now let's say that the memory was empty, now we have 3 records like this in memory:

    uint8_t data1 = 0xff;
    uint16_t data2 = 0xffff;
    uint8_t data_array[3] = {0xff,0xff,0xff};

    3. I want to update data1:

    static buffer_for_data1[1];
    
    data1 = 0x69;
    
    buffer_for_data1[0] = data1;
    ndef_file_update(buffer_for_data1, 1, record_id_of_data1);

    4. if I load data1 I get the correct value:

    data1 = 0;
    
    uint8_t load_buffer[1];
    
    rc = ndef_file_load(load_buffer, 1, record_id_of_data1);
    
    data1 = load_buffer[0]; // now we get data1 = 0x69 which is correct

    5. If I now load data2 and data_array, I get a wrong value:

    // loading data2 and data_array:
    
    data2 = 0x0434; // wrong! expecting 0xFFFF
    data_array = 0x043412 // wrong! expecting 0xFFFFFF

    6. If I update data2 and data_array, every thing is fine, no more error.

  • I fail to see the logic. Can you make a simple (but complete) that reproduces this that I can test?

Reply Children
  • hello, I have made a complete example that reproduces the problem.

    It was done using the sdk thread and zigbee and can be put in $(sdk_source)/example/multiprotocol/nle_thread

  • Hi,

    That is excellent. Can you upload it to this thread? Which Thread and Zigbee SDK version does it work with? What is the procedure to test it to reproduce the issue?

  • It is version nRF5_SDK_for_Thread_and_Zigbee_v4.0.0_dc7186b

    To test, run the code with ses and watch the NRF_LOG_INFO outputs. I have put some commentary to hopefully guide you in the code.ble_thread_dyn_template - flash test.zip

  • Hi,

    Your example clearly demonstrates an issue, but I have yet not been able to understand what causes this behavior. I am adding the log from your unmodified example here for my own reference. I will look more into this and get back to you.

    <info> app_timer: RTC: initialized.
    <info> app: BLE Thread template example started.
    <info> app: Thread version   : OPENTHREAD/20180926-01143-g8a1992e2; NRF52840; Dec 10 2019 22:48:00
    <info> app: Network name     : OpenThread
    <info> app: Thread interface has been enabled.
    <info> app: 802.15.4 Channel : 11
    <info> app: 802.15.4 PAN ID  : 0xABCD
    <info> app: Radio mode       : rx-on-when-idle
    <info> app: Fast advertising.
    <info> app: LOADING FLASH at counter = 1
    <info> flash_memory: NDEF file record <info> app: State changed! Flags: 0x009C13A5 Current role: 4
    
    <info> app: bar8        = 0xFF
    <info> app: bar16       = 0xFFFF
    <info> app: bar8_array  = 0xFFFFFFFFFFFF
    
    <info> app: LOADING FLASH at counter = 120
    <info> flash_memory: Found NDEF file record for id 0
    <info> flash_memory: Found NDEF file record for id 1
    <info> flash_memory: Found NDEF file record for id 2
    <info> app: bar8        = 0xB
    <info> app: bar16       = 0xB5B
    <info> app: bar8_array  = 0xFFFFFFFFFFFF
    
    <info> app: NOW UPDATING FLASH
    <info> flash_memory: bar8 update
    <info> flash_memory: bar16 update
    <info> flash_memory: bar8_array update
    <info> app: LOADING FLASH at counter = 280
    <info> flash_memory: Found NDEF file record for id 0
    <info> flash_memory: Found NDEF file record for id 1
    <info> flash_memory: Found NDEF file record for id 2
    <info> app: bar8        = 0x11
    <info> app: bar16       = 0x1111
    <info> app: bar8_array  = 0x111111111111

    Br,

    Einar

Related