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

Reading flashlog using nrf_log_backend_flash_next_entry_get does not work unless a CLI is initiated

Hello,

This subject is partly a conclusion and partly a question I would like confirmed.

Our scenario is that we would like to fetch flash logs over BLE, but not really by enabling CLI support. The way I've been trying to implement this is by using the nrf_log_backend_flash_next_entry_get and push each message over a BLE characteristic. For some reason, I had a lot of trouble getting it to work in my project, which was based on one of the basic BLE peripheral examples. But when pasting my code into the experimental BLE CLI example (15.3.0_59ac345/examples/ble_peripheral/experimental/ble_app_cli), it worked like a charm. I've been trying to copy code from the example one line at the time, and now I can make it work if I include the code for initializing an UART CLI. If I remove that, and use NRF_LOG_DEFAULT_BACKENDS_INIT() instead, I get random or no data from nrf_log_backend_flash_next_entry_get.

If this is the case, I think it should be better documented, and if it's a bug it would be nice to get it fixed. I'm including the code snipped I've been using to test the flashlog call below, I can provide more of my code if needed. I was able to paste this into the example project mentioned above without issue (I wrote a single warning on each reboot and ran the code to read it back). Some of it is adapted from where I found it used in the SDK as the documentation for the call itself (specifically on how to use the header and data correctly) was a bit lacking.

static void log_entry_process(nrf_log_header_t * p_header, uint8_t * p_data)
{
    switch (p_header->base.generic.type)
    {
        case HEADER_TYPE_STD:
        {
            const char * p_str = (const char *)((uint32_t)p_header->base.std.addr);
            uint32_t * p_args = (uint32_t *)p_data;
            switch(p_header->base.std.nargs)
            {
                case 0:
                    NRF_LOG_INFO(p_str);
                    break;
                case 1:
                    NRF_LOG_INFO(p_str, p_args[0]);
                    break;
                case 2:
                    NRF_LOG_INFO(p_str, p_args[0], p_args[1]);
                    break;
                case 3:
                    NRF_LOG_INFO(p_str, p_args[0], p_args[1], p_args[2]);
                    break;
                case 4:
                    NRF_LOG_INFO(p_str, p_args[0], p_args[1], p_args[2], p_args[3]);
                    break;
                case 5:
                    NRF_LOG_INFO(p_str, p_args[0], p_args[1], p_args[2], p_args[3], p_args[4]);
                    break;
                case 6:
                    NRF_LOG_INFO(p_str, p_args[0], p_args[1], p_args[2], p_args[3], p_args[4], p_args[5]);
                    break;

                default:
                    break;
            }
            break;
        }
        case HEADER_TYPE_HEXDUMP:
        {
            NRF_LOG_INFO("Hex data");
            break;
        }
        default:
            NRF_LOG_INFO("Unknown type %d", p_header->base.generic.type);
            break;
    }

}

static void test_flashlog()
{

    // Test log reader
    ret_code_t error_code;
    uint32_t token = 0;
    nrf_log_header_t * p_header = NULL;
    uint8_t * p_data = NULL;
    NRF_LOG_INFO("Reading flash");

    while(true)
    {
        error_code = nrf_log_backend_flash_next_entry_get(&token, &p_header, &p_data);
        if(error_code != NRF_SUCCESS)
        {
            if(error_code == NRF_ERROR_NOT_FOUND)
            {
                NRF_LOG_INFO("Flash end reached");
            }
            else
            {
                NRF_LOG_WARNING("Read flash error code %d", error_code);
        }
        break;
        }
        else
        {
            // NRF_LOG_INFO("Location %d", token);
            log_entry_process(p_header, p_data);
        }
    }
}

Related