Mesh DFU not working after 1st successful update. Integrating DFU process into the application.


///////////////////////////////////////////////////////////////////////////////
#include "nrf_mesh_dfu.h"
#include "app_util.h"

/*****************************************************************************
 * Definitions
 *****************************************************************************/
/* LED mask bit 0 (1,2,..) represents BSP_LED_0 (1,2,..) from boards.h */
#define LEDS_MASK_DFU_RUNNING   (0x05)  /* BSP_LED_0 and BSP_LED_2 */
#define LEDS_MASK_DFU_ENDED     (0x03)  /* BSP_LED_0 and BSP_LED_1 */


/*****************************************************************************
 * Forward declaration of static functions
 *****************************************************************************/


/*****************************************************************************
 * Static variables
 *****************************************************************************/
static nrf_mesh_evt_handler_t m_evt_handler;
static bool m_device_provisioned;

static bool fw_updated_event_is_for_me(const nrf_mesh_evt_dfu_t * p_evt)
{
    switch (p_evt->fw_outdated.transfer.dfu_type)
    {
        case NRF_MESH_DFU_TYPE_APPLICATION:
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "DFU type Application\n");
            return (p_evt->fw_outdated.current.application.app_id == p_evt->fw_outdated.transfer.id.application.app_id &&
                    p_evt->fw_outdated.current.application.company_id == p_evt->fw_outdated.transfer.id.application.company_id &&
                    p_evt->fw_outdated.current.application.app_version < p_evt->fw_outdated.transfer.id.application.app_version);

        case NRF_MESH_DFU_TYPE_BOOTLOADER:
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "DFU type Bootloader\n");
            return (p_evt->fw_outdated.current.bootloader.bl_id == p_evt->fw_outdated.transfer.id.bootloader.bl_id &&
                    p_evt->fw_outdated.current.bootloader.bl_version < p_evt->fw_outdated.transfer.id.bootloader.bl_version);

        case NRF_MESH_DFU_TYPE_SOFTDEVICE:
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "DFU type Softdevice\n");
            return false;

        default:
            return false;
    }
}

static const uint32_t * optimal_bank_address(void)
{
    /* The incoming transfer has to fit on both sides of the bank address: First it needs to fit
     * above the bank address when we receive it, then it needs to fit below the bank address when
     * we install it. We want to put the bank address in the middle of the available application
     * code area, to maximize the potential transfer size we can accept. */
    const uint32_t * p_start;
    uint32_t dummy;
    ERROR_CHECK(mesh_stack_persistence_flash_usage(&p_start, &dummy));

    uint32_t middle_of_app_area = (CODE_START + (intptr_t) p_start) / 2;

    /* The bank can't start in the middle of the application code, and should be page aligned: */
    return (const uint32_t *) ALIGN_VAL(MAX(middle_of_app_area, CODE_END), PAGE_SIZE);
}

static void mesh_evt_handler(const nrf_mesh_evt_t* p_evt)
{
    switch (p_evt->type)
    {
        case NRF_MESH_EVT_DFU_FIRMWARE_OUTDATED:
        case NRF_MESH_EVT_DFU_FIRMWARE_OUTDATED_NO_AUTH:
            if (fw_updated_event_is_for_me(&p_evt->params.dfu))
            {
                const uint32_t * p_bank = optimal_bank_address();
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Requesting DFU transfer with bank at 0x%p\n", p_bank);

                ERROR_CHECK(nrf_mesh_dfu_request(p_evt->params.dfu.fw_outdated.transfer.dfu_type,
                                                 &p_evt->params.dfu.fw_outdated.transfer.id,
                                                 p_bank));
                hal_led_mask_set(HAL_LED_MASK, false); /* Turn off all LEDs */
            }
            else
            {
                /**
                 * While preparing for the start of the DFU process, the DFU module
                 * will notify about any other ongoing DFU transfers by sending
                 * @ref NRF_MESH_EVT_DFU_FIRMWARE_OUTDATED_NO_AUTH or
                 * @ref NRF_MESH_EVT_DFU_FIRMWARE_OUTDATED.
                 *
                 * Check the current DFU state to avoid reverting the target state
                 * to the relay state.
                 */
                nrf_mesh_dfu_transfer_state_t state;
                uint32_t error_code = nrf_mesh_dfu_state_get(&state);
                if (error_code == NRF_SUCCESS && (state.state == NRF_MESH_DFU_STATE_INITIALIZED ||
                                                  state.state == NRF_MESH_DFU_STATE_FIND_FWID ||
                                                  state.state == NRF_MESH_DFU_STATE_RELAY_CANDIDATE ||
                                                  state.state == NRF_MESH_DFU_STATE_RELAY))
                {
                    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Starting relay\n");
                    ERROR_CHECK(nrf_mesh_dfu_relay(p_evt->params.dfu.fw_outdated.transfer.dfu_type,
                                                    &p_evt->params.dfu.fw_outdated.transfer.id));
                }
            }
            break;

        case NRF_MESH_EVT_DFU_START:
            hal_led_mask_set(LEDS_MASK_DFU_RUNNING, true);
            break;

        case NRF_MESH_EVT_DFU_END:
            hal_led_mask_set(HAL_LED_MASK, false); /* Turn off all LEDs */
            hal_led_mask_set(LEDS_MASK_DFU_ENDED, true);
            break;

        case NRF_MESH_EVT_DFU_BANK_AVAILABLE:
            hal_led_mask_set(HAL_LED_MASK, false); /* Turn off all LEDs */
            ERROR_CHECK(nrf_mesh_dfu_bank_flash(p_evt->params.dfu.bank.transfer.dfu_type));
            break;

        default:
            break;

    }
}


///////////////////////////////////////////////////////////////////////////////


Hello

I need to integrate MESH DFU Example to Light_switch Example, I took part of the code from DFU example and added his to light_switch example main.c.
The first time the update is successful. 
I increase the value --application-version and generate a new package.
I start to send an update, my nrf52840-DK with the serial starts to send, in the console percentages grow, but my DK without the serial does not react with LEDs in any way, as it happens when the update is in progress for the first time.

What am I doing wrong, what is missing?

  • I have a guess that by combining the two examples the total size of the hex file exceeds the amount of available memory for the update.
    Has anyone been able integrating dfu mesh process to light_switch example?  so that it is successfully updated every time?

  • Hello,

    Sergnrf said:
    I have a guess that by combining the two examples the total size of the hex file exceeds the amount of available memory for the update.

    That could be the case. Did you try checking the size of the old and the new application? (you can use nRF Connect for Desktop -> Programmer to see how much space the .hex file will take). Will they both fit in the flash at the same time in addition to the SoftDevice and Bootloader?)

    I am not sure whether the LEDs not responding is due to the image not being transferred, or if the LEDs are set up to do other things. They are controlled by the application in the DFU sample. Are they set up the same way in your light_switch application?

    You don't strictly need the LEDs to determine whether the DFU is ongoing. You can monitor the DFU related events, and for example write something to the log when they occur. Do any of the DFU related events from the dfu example trigger in your light switch implementation?

    Best regards,

    Edvin


  • this is what the memory looks like after the first successful update

  • when I run the update for the first time, I see the following message in RTT Viewer
    5881588>, nrf_mesh_dfu.c,  418,   New firmware!
    when I run the updates for the second time, there are no messages related to the update

    Сan you provide detailed instructions on how to combine your examples?

  • Sergnrf said:
    this is what the memory looks like after the first successful update

    That looks correct. Just to clarify, the green lines at the top is the flash used for network credentials and stuff like that. This is not erased between DFUs. The green chunk in the middle is the new application. This is where it is stored while transferring. This will be erased and re-written the next time you do a DFU. The bottom green chunk is the current application. It is probably the same as the middle green chunk, since it is copied from there. The blue and orange are the SoftDevice and MBR. The bluetooth stack. This is not updated in an application DFU (only if the image contains a SoftDevice update).

    So my guess is that your new application is not set up to handle DFUs. I don't know what your code looks like, but looking at the DFU example I would guess that you need all the events that says something with DFU in your mesh_evt_handler().

    Also, does nrf_mesh_dfu_init() get called inside nrf_mesh.c -> nrf_mesh_init(). What does nrf_mesh_dfu_init() return?

    Best regards,

    Edvin

Related