diff --git a/lib/sdk11/components/libraries/bootloader_dfu/bootloader.c b/lib/sdk11/components/libraries/bootloader_dfu/bootloader.c index 875ab6c..7955790 100644 --- a/lib/sdk11/components/libraries/bootloader_dfu/bootloader.c +++ b/lib/sdk11/components/libraries/bootloader_dfu/bootloader.c @@ -186,10 +186,34 @@ static void bootloader_settings_save(bootloader_settings_t * p_settings) { if ( is_ota() ) { - uint32_t err_code = pstorage_clear(&m_bootsettings_handle, sizeof(bootloader_settings_t)); + uint32_t err_code; + while(1) { + err_code = pstorage_clear(&m_bootsettings_handle, sizeof(bootloader_settings_t)); + if (err_code != NRF_ERROR_NO_MEM) + break; + // This means the write/erase queue of commands was completely full - Should not + // happen, but better safe than sorry, wait until space becomes available - + // the pstorage event handler is only run from the main loop, and we are also + // running from a BLE event on the main loop: This means if we wait here, the FLASH + // completion events will never be handled (will be queued by app_scheduler, but + // not handled, and that means this wait will never end... So, process SOC events + // from the SD (but NOT BLE events!) - This will free entries on the pstorage queue + // as soon as operations are complete, allowing this op to be queued + while (NRF_ERROR_NOT_FOUND != proc_soc()) { + // nothing + } + } APP_ERROR_CHECK(err_code); - err_code = pstorage_store(&m_bootsettings_handle, (uint8_t *) p_settings, sizeof(bootloader_settings_t), 0); + while(1) { + err_code = pstorage_store(&m_bootsettings_handle, (uint8_t *) p_settings, sizeof(bootloader_settings_t), 0); + if (err_code != NRF_ERROR_NO_MEM) + break; + // No space, wait until an entry in the queue is freed + while (NRF_ERROR_NOT_FOUND != proc_soc()) { + // nothing + } + } APP_ERROR_CHECK(err_code); } else diff --git a/lib/sdk11/components/libraries/bootloader_dfu/bootloader.h b/lib/sdk11/components/libraries/bootloader_dfu/bootloader.h index efd72e7..5f94e7b 100644 --- a/lib/sdk11/components/libraries/bootloader_dfu/bootloader.h +++ b/lib/sdk11/components/libraries/bootloader_dfu/bootloader.h @@ -92,6 +92,8 @@ uint32_t bootloader_dfu_sd_update_finalize(void); void bootloader_mbr_addrs_populate(void); +extern uint32_t proc_soc(void); + #endif // BOOTLOADER_H__ /**@} */ diff --git a/lib/sdk11/components/libraries/bootloader_dfu/dfu_dual_bank.c b/lib/sdk11/components/libraries/bootloader_dfu/dfu_dual_bank.c index 4516e4f..00956e7 100644 --- a/lib/sdk11/components/libraries/bootloader_dfu/dfu_dual_bank.c +++ b/lib/sdk11/components/libraries/bootloader_dfu/dfu_dual_bank.c @@ -82,7 +82,6 @@ static void pstorage_callback_handler(pstorage_handle_t * p_handle, APP_ERROR_CHECK(result); } - /**@brief Function for handling the DFU timeout. * * @param[in] p_context The timeout context. @@ -136,19 +135,28 @@ static void dfu_prepare_func_app_erase(uint32_t image_size) // Doing a SoftDevice update thus current application must be cleared to ensure enough space // for new SoftDevice. m_dfu_state = DFU_STATE_PREPARING; - - if ( is_ota() ) - { - uint32_t err_code = pstorage_clear(&m_storage_handle_app, m_image_size); - APP_ERROR_CHECK(err_code); - } - else - { - flash_nrf5x_erase(DFU_BANK_0_REGION_START, m_image_size); + + if ( is_ota() ) + { + uint32_t err_code; + while(1) { + err_code = pstorage_clear(&m_storage_handle_app, m_image_size); + if (err_code != NRF_ERROR_NO_MEM) + break; + // No space, wait until an entry in the queue is freed + while (NRF_ERROR_NOT_FOUND != proc_soc()) { + // nothing + } + } + APP_ERROR_CHECK(err_code); + } + else + { + flash_nrf5x_erase(DFU_BANK_0_REGION_START, m_image_size); - // invoke complete callback - pstorage_callback_handler(&m_storage_handle_app, PSTORAGE_CLEAR_OP_CODE, NRF_SUCCESS, NULL, 0); - } + // invoke complete callback + pstorage_callback_handler(&m_storage_handle_app, PSTORAGE_CLEAR_OP_CODE, NRF_SUCCESS, NULL, 0); + } } @@ -163,19 +171,28 @@ static void dfu_prepare_func_swap_erase(uint32_t image_size) mp_storage_handle_active = &m_storage_handle_swap; m_dfu_state = DFU_STATE_PREPARING; - - if ( is_ota() ) - { - uint32_t err_code = pstorage_clear(&m_storage_handle_swap, image_size); - APP_ERROR_CHECK(err_code); - } - else - { - flash_nrf5x_erase(DFU_BANK_1_REGION_START, image_size); + + if ( is_ota() ) + { + uint32_t err_code; + while(1) { + err_code = pstorage_clear(&m_storage_handle_swap, image_size); + if (err_code != NRF_ERROR_NO_MEM) + break; + // No space, wait until an entry in the queue is freed + while (NRF_ERROR_NOT_FOUND != proc_soc()) { + // nothing + } + } + APP_ERROR_CHECK(err_code); + } + else + { + flash_nrf5x_erase(DFU_BANK_1_REGION_START, image_size); - // invoke complete callback - pstorage_callback_handler(&m_storage_handle_swap, PSTORAGE_CLEAR_OP_CODE, NRF_SUCCESS, NULL, 0); - } + // invoke complete callback + pstorage_callback_handler(&m_storage_handle_swap, PSTORAGE_CLEAR_OP_CODE, NRF_SUCCESS, NULL, 0); + } } @@ -263,26 +280,45 @@ static uint32_t dfu_activate_app(void) uint32_t err_code = NRF_SUCCESS; // Erase BANK 0. - if ( is_ota() ) - { - err_code = pstorage_clear(&m_storage_handle_app, m_start_packet.app_image_size); - APP_ERROR_CHECK(err_code); - - err_code = pstorage_store(&m_storage_handle_app, - (uint8_t *)m_storage_handle_swap.block_id, - m_start_packet.app_image_size, - 0); - } - else - { + if ( is_ota() ) + { + while(1) { + err_code = pstorage_clear(&m_storage_handle_app, m_start_packet.app_image_size); + if (err_code != NRF_ERROR_NO_MEM) + break; + // No space, wait until an entry in the queue is freed + while (NRF_ERROR_NOT_FOUND != proc_soc()) { + // nothing + } + } + APP_ERROR_CHECK(err_code); + + while(1) { + err_code = pstorage_store(&m_storage_handle_app, + (uint8_t *)m_storage_handle_swap.block_id, + m_start_packet.app_image_size, + 0); + + if (err_code != NRF_ERROR_NO_MEM) + break; + // No space, wait until an entry in the queue is freed + while (NRF_ERROR_NOT_FOUND != proc_soc()) { + // nothing + } + } + VERIFY_SUCCESS(err_code); + + } + else + { flash_nrf5x_erase(DFU_BANK_0_REGION_START, m_start_packet.app_image_size); pstorage_callback_handler(&m_storage_handle_app, PSTORAGE_CLEAR_OP_CODE, NRF_SUCCESS, NULL, 0); - + flash_nrf5x_write(DFU_BANK_0_REGION_START, (uint8_t *)DFU_BANK_1_REGION_START, m_start_packet.app_image_size, false); - flash_nrf5x_flush(false); + flash_nrf5x_flush(false); pstorage_callback_handler(&m_storage_handle_app, PSTORAGE_STORE_OP_CODE, NRF_SUCCESS, (uint8_t *) DFU_BANK_1_REGION_START, m_start_packet.app_image_size); - } - + } + if (err_code == NRF_SUCCESS) { dfu_update_status_t update_status = { 0 }; @@ -430,13 +466,13 @@ uint32_t dfu_start_pkt_handle(dfu_update_packet_t * p_packet) } if ( DFU_STATE_IDLE != m_dfu_state ) - return NRF_ERROR_INVALID_STATE; - - // Valid peer activity detected. Hence restart the DFU timer. - err_code = dfu_timer_restart(); - VERIFY_SUCCESS(err_code); - - m_functions.prepare(m_image_size); + return NRF_ERROR_INVALID_STATE; + + // Valid peer activity detected. Hence restart the DFU timer. + err_code = dfu_timer_restart(); + VERIFY_SUCCESS(err_code); + + m_functions.prepare(m_image_size); return NRF_SUCCESS; } @@ -486,17 +522,25 @@ uint32_t dfu_data_pkt_handle(dfu_update_packet_t * p_packet) if ( is_ota() ) { - err_code = pstorage_store(mp_storage_handle_active, (uint8_t *)p_data, data_length, m_data_received); - VERIFY_SUCCESS(err_code); + while(1) { + err_code = pstorage_store(mp_storage_handle_active, (uint8_t *)p_data, data_length, m_data_received); + if (err_code != NRF_ERROR_NO_MEM) + break; + // No space, wait until an entry in the queue is freed + while (NRF_ERROR_NOT_FOUND != proc_soc()) { + // nothing + } + } + VERIFY_SUCCESS(err_code); } else { - flash_nrf5x_write( - (mp_storage_handle_active == &m_storage_handle_app - ? DFU_BANK_0_REGION_START - : DFU_BANK_1_REGION_START) - + m_data_received, p_data, data_length, false); - pstorage_callback_handler(mp_storage_handle_active, PSTORAGE_STORE_OP_CODE, NRF_SUCCESS, (uint8_t *) p_data, data_length); + flash_nrf5x_write( + (mp_storage_handle_active == &m_storage_handle_app + ? DFU_BANK_0_REGION_START + : DFU_BANK_1_REGION_START) + + m_data_received, p_data, data_length, false); + pstorage_callback_handler(mp_storage_handle_active, PSTORAGE_STORE_OP_CODE, NRF_SUCCESS, (uint8_t *) p_data, data_length); } m_data_received += data_length; @@ -508,8 +552,8 @@ uint32_t dfu_data_pkt_handle(dfu_update_packet_t * p_packet) } else { - if ( !is_ota() ) flash_nrf5x_flush(false); - + if ( !is_ota() ) flash_nrf5x_flush(false); + // The entire image has been received. Return NRF_SUCCESS. err_code = NRF_SUCCESS; } @@ -561,7 +605,7 @@ uint32_t dfu_init_pkt_handle(dfu_update_packet_t * p_packet) case DFU_STATE_RDY: m_dfu_state = DFU_STATE_RX_INIT_PKT; // When receiving init packet in state ready just update and fall through this case. - /* FALLTHRU */ + /* FALLTHRU */ case DFU_STATE_RX_INIT_PKT: // DFU initialization has been done and a start packet has been received. @@ -811,7 +855,7 @@ uint32_t dfu_bl_image_swap(void) uint32_t dfu_bl_image_validate(void) { bootloader_settings_t bootloader_settings;\ - + sd_mbr_command_t sd_mbr_cmd_1; sd_mbr_command_t sd_mbr_cmd_2; @@ -829,6 +873,10 @@ uint32_t dfu_bl_image_validate(void) sd_mbr_cmd_1.params.compare.ptr2 = (uint32_t *)(bl_image_start_1); sd_mbr_cmd_1.params.compare.len = bootloader_settings.bl_image_size / sizeof(uint32_t); + uint32_t err_code = sd_mbr_command(&sd_mbr_cmd_1); + if (err_code == NRF_SUCCESS) + return NRF_SUCCESS; + uint32_t bl_image_start_2 = (bootloader_settings.sd_image_size == 0) ? DFU_BANK_1_REGION_START : bootloader_settings.sd_image_start + @@ -839,7 +887,7 @@ uint32_t dfu_bl_image_validate(void) sd_mbr_cmd_2.params.compare.ptr2 = (uint32_t *)(bl_image_start_2); sd_mbr_cmd_2.params.compare.len = bootloader_settings.bl_image_size / sizeof(uint32_t); - return sd_mbr_command(&sd_mbr_cmd_1) && sd_mbr_command(&sd_mbr_cmd_2); + return sd_mbr_command(&sd_mbr_cmd_2); } return NRF_SUCCESS; } @@ -863,7 +911,7 @@ uint32_t dfu_sd_image_validate(void) uint32_t block_size = (bootloader_settings.sd_image_start - sd_start) / 2; uint32_t image_end = bootloader_settings.sd_image_start + bootloader_settings.sd_image_size; - + /* ##### FIX START ##### */ block_size &= ~(uint32_t)(CODE_PAGE_SIZE - 1); /* ##### FIX END ##### */ diff --git a/lib/sdk11/components/libraries/bootloader_dfu/dfu_single_bank.c b/lib/sdk11/components/libraries/bootloader_dfu/dfu_single_bank.c index bf003c6..af25970 100644 --- a/lib/sdk11/components/libraries/bootloader_dfu/dfu_single_bank.c +++ b/lib/sdk11/components/libraries/bootloader_dfu/dfu_single_bank.c @@ -140,7 +140,16 @@ static void dfu_prepare_func_app_erase(uint32_t image_size) if ( is_ota() ) { - uint32_t err_code = pstorage_clear(&m_storage_handle_app, m_image_size); + uint32_t err_code; + while(1) { + err_code = pstorage_clear(&m_storage_handle_app, m_image_size); + if (err_code != NRF_ERROR_NO_MEM) + break; + // No space, wait until an entry in the queue is freed + while (NRF_ERROR_NOT_FOUND != proc_soc()) { + // nothing + } + } APP_ERROR_CHECK(err_code); } else @@ -414,7 +423,15 @@ uint32_t dfu_data_pkt_handle(dfu_update_packet_t * p_packet) if ( is_ota() ) { - err_code = pstorage_store(mp_storage_handle_active, (uint8_t *)p_data, data_length, m_data_received); + while(1) { + err_code = pstorage_store(mp_storage_handle_active, (uint8_t *)p_data, data_length, m_data_received); + if (err_code != NRF_ERROR_NO_MEM) + break; + // No space, wait until an entry in the queue is freed + while (NRF_ERROR_NOT_FOUND != proc_soc()) { + // nothing + } + } VERIFY_SUCCESS(err_code); } else @@ -742,6 +759,17 @@ uint32_t dfu_bl_image_validate(void) if (bootloader_settings.bl_image_size != 0) { + /* + * The problem with updating the bootloader from a dual to single bank bootloader is that the new + * bootloader expects the firmware image to be at the start of BANK 0, while it's actually loaded + * to BANK1 by the old bootloader. After the update the new single bank bootloader verifies that + * the image was correctly written to flash by comparing itself with the firmware image that it + * expects to be located in BANK0. Since the actual firmware image is in BANK 1 this check will + * fail and the new bootloader updates itself with whatever data located in BANK0 using the MBR. + + * The fix is to modify the dfu_bl_image_validate() function in dfu_single_bank.c run verification + * on both addresses (BANK0 and BANK1) + */ uint32_t bl_image_start_1 = (bootloader_settings.sd_image_size == 0) ? DFU_BANK_0_REGION_START : bootloader_settings.sd_image_start + @@ -752,6 +780,10 @@ uint32_t dfu_bl_image_validate(void) sd_mbr_cmd_1.params.compare.ptr2 = (uint32_t *)(bl_image_start_1); sd_mbr_cmd_1.params.compare.len = bootloader_settings.bl_image_size / sizeof(uint32_t); + uint32_t err_code = sd_mbr_command(&sd_mbr_cmd_1); + if (err_code == NRF_SUCCESS) + return NRF_SUCCESS; + uint32_t bl_image_start_2 = (bootloader_settings.sd_image_size == 0) ? DFU_BANK_1_REGION_START : bootloader_settings.sd_image_start + @@ -762,7 +794,7 @@ uint32_t dfu_bl_image_validate(void) sd_mbr_cmd_2.params.compare.ptr2 = (uint32_t *)(bl_image_start_2); sd_mbr_cmd_2.params.compare.len = bootloader_settings.bl_image_size / sizeof(uint32_t); - return sd_mbr_command(&sd_mbr_cmd_1) && sd_mbr_command(&sd_mbr_cmd_2); + return sd_mbr_command(&sd_mbr_cmd_2); } return NRF_SUCCESS; } diff --git a/src/pstorage_platform.h b/src/pstorage_platform.h index bbc573c..959005c 100644 --- a/src/pstorage_platform.h +++ b/src/pstorage_platform.h @@ -78,7 +78,7 @@ static __INLINE uint32_t pstorage_flash_page_end() #define PSTORAGE_SWAP_ADDR PSTORAGE_DATA_END_ADDR #define PSTORAGE_MAX_BLOCK_SIZE PSTORAGE_FLASH_PAGE_SIZE /**< Maximum size of block that can be registered with the module. Should be configured based on system requirements. And should be greater than or equal to the minimum size. */ -#define PSTORAGE_CMD_QUEUE_SIZE 10 /**< Maximum number of flash access commands that can be maintained by the module for all applications. Configurable. */ +#define PSTORAGE_CMD_QUEUE_SIZE 18 /**< Maximum number of flash access commands that can be maintained by the module for all applications. Configurable. */ /**@breif Define this flag in case Raw access to persistent memory is to be enabled. Raw mode * unlike the data mode is for uses other than storing data from various mode. This mode is