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

Mesh DFU target and relay: nrf_mesh_dfu_request vs. nrf_mesh_dfu_relay

My intention is to program Mesh DFU event callback in such a way that the device always takes the relay role, with an option of simultaneously being the target. However, I cannot make heads or tails of the Mesh DFU documentation.

"Integrating DFU process into the application (nRF5 SDK for Mesh v4.0.0)" document states:

Depending on the the parameters supplied in nrf_mesh_evt_dfu_t::fw_outdated, the application may decide to either:

  • Receive new firmware if the version of the application in the supplied parameters is higher than the one installed.
  • Relay the packets from other relay nodes or target.

If neither nrf_mesh_dfu_request nor nrf_mesh_dfu_relay is called as a result of a NRF_MESH_EVT_DFU_FIRMWARE_OUTDATED (or NRF_MESH_EVT_DFU_FIRMWARE_OUTDATED_NO_AUTH) event, the update is ignored.

I take the meaning of "the update is ignored" as that unless nrf_mesh_dfu_request or nrf_mesh_dfu_relay is called the device will completely ignore the DFU packets. The paragraph also says that only one of the two functions can be called (one making the device DFU target and the other DFU relay) in response to the "firmware outdated event". However, I'd like the device to always relay and optionally accept the update (which seems to be a reasonably common scenario).

Reading the API reference for nrf_mesh_dfu_relay function I find that "(It) Should only be used as a response to an NRF_MESH_EVT_DFU_REQ_RELAY." This seems to contradict directly "Integrating DFU process into the application" document cited above and the Mesh DFU example where the function is called in response to NRF_MESH_EVT_DFU_FIRMWARE_OUTDATED or NRF_MESH_EVT_DFU_FIRMWARE_OUTDATED_NO_AUTH events. Am I missing something here?

Browsing the DevZone I come across an answer stating "As long as the node has DFU support it will relay DFU packets". I read this as my node will always act as a relay regardless of whether nrf_mesh_dfu_request or nrf_mesh_dfu_relay is called in response to "firmware outdated event" (which seems to contradict "the update is ignored" statement above). Which is true?

In case "a node supporting DFU always relays" is true, what is the purpose of calling nrf_mesh_dfu_relay?

Thanks!

Parents
  • Hi HAFLN, 


    I think it will be easier to explain using our example code. The following code is from the dfu example (\examples\dfu) in the SDK: 

      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(LEDS_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))
                    {
                        ERROR_CHECK(nrf_mesh_dfu_relay(p_evt->params.dfu.fw_outdated.transfer.dfu_type,
                                                        &p_evt->params.dfu.fw_outdated.transfer.id));
                    }
                }
                break;

    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:
                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:
                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:
                return false;
    
            default:
                return false;
        }
    }

    You can find the logic of a device when the device choose to receive the image or choose to start relaying the image.

    If you have a look in the bootloader code, you can find that the opcode BL_CMD_TYPE_DFU_START_RELAY will put the bootloader into DFU_STATE_RELAY_CANDIDATE state. After entering that state, the bootloader can enter DFU_STATE_RELAY (handle_data_packet() dfu_mesh.c ) 

    If the bootloader not in the DFU_STATE_RELAY/DFU_STATE_RELAY_CANDIDATE   or not in the DFU_STATE_READY/DFU_STATE_TARGET the packet will be ignored . I think the answer in the case you pointed to may need to be corrected. 

Reply
  • Hi HAFLN, 


    I think it will be easier to explain using our example code. The following code is from the dfu example (\examples\dfu) in the SDK: 

      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(LEDS_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))
                    {
                        ERROR_CHECK(nrf_mesh_dfu_relay(p_evt->params.dfu.fw_outdated.transfer.dfu_type,
                                                        &p_evt->params.dfu.fw_outdated.transfer.id));
                    }
                }
                break;

    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:
                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:
                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:
                return false;
    
            default:
                return false;
        }
    }

    You can find the logic of a device when the device choose to receive the image or choose to start relaying the image.

    If you have a look in the bootloader code, you can find that the opcode BL_CMD_TYPE_DFU_START_RELAY will put the bootloader into DFU_STATE_RELAY_CANDIDATE state. After entering that state, the bootloader can enter DFU_STATE_RELAY (handle_data_packet() dfu_mesh.c ) 

    If the bootloader not in the DFU_STATE_RELAY/DFU_STATE_RELAY_CANDIDATE   or not in the DFU_STATE_READY/DFU_STATE_TARGET the packet will be ignored . I think the answer in the case you pointed to may need to be corrected. 

Children
No Data
Related