Wait until FLASH operation queue has enough available room, instead of silently dropping operations

This commit is contained in:
Eduardo José Tagle
2026-01-26 00:44:54 -03:00
parent 827edd212b
commit e1ea1c6dd1
5 changed files with 174 additions and 68 deletions
@@ -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
@@ -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__
/**@} */
@@ -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 ##### */
@@ -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;
}
+1 -1
View File
@@ -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