/////////////////////////////////////////////////////////////////////////////// #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; } } ///////////////////////////////////////////////////////////////////////////////