mirror of
https://github.com/oltaco/Adafruit_nRF52_Bootloader_OTAFIX.git
synced 2026-10-15 17:41:30 +00:00
In case a RESET command is received in the middle of a OTA DFU, reboot to bootloader to allow the DFU app to recover previously interrupted transfers, instead of reverting to the last working firmware and launching it
This commit is contained in:
@@ -44,7 +44,8 @@ typedef enum
|
||||
BOOTLOADER_SETTINGS_SAVING, /**< Bootloader status for indicating that saving of bootloader settings is in progress. */
|
||||
BOOTLOADER_COMPLETE, /**< Bootloader status for indicating that all operations for the update procedure has completed and it is safe to reset the system. */
|
||||
BOOTLOADER_TIMEOUT, /**< Bootloader status field for indicating that a timeout has occured and current update process should be aborted. */
|
||||
BOOTLOADER_RESET, /**< Bootloader status field for indicating that a reset has been requested and current update process should be aborted. */
|
||||
BOOTLOADER_SYS_RESET, /**< Bootloader status field for indicating that a reset has been requested and current update process should be aborted. */
|
||||
BOOTLOADER_RESET_TO_SELF, /**< Bootloader status field for indicating that a reset has been requested and current update process should be aborted and the bootloader must be reentered. */
|
||||
} bootloader_status_t;
|
||||
|
||||
static pstorage_handle_t m_bootsettings_handle; /**< Pstorage handle to use for registration and identifying the bootloader module on subsequent calls to the pstorage module for load and store of bootloader setting in flash. */
|
||||
@@ -136,7 +137,8 @@ static void wait_for_events(void)
|
||||
|
||||
if ((m_update_status == BOOTLOADER_COMPLETE) ||
|
||||
(m_update_status == BOOTLOADER_TIMEOUT) ||
|
||||
(m_update_status == BOOTLOADER_RESET) )
|
||||
(m_update_status == BOOTLOADER_SYS_RESET) ||
|
||||
(m_update_status == BOOTLOADER_RESET_TO_SELF))
|
||||
{
|
||||
// When update has completed or a timeout/reset occured we will return.
|
||||
return;
|
||||
@@ -320,7 +322,9 @@ void bootloader_dfu_update_process(dfu_update_status_t update_status)
|
||||
}
|
||||
else if (update_status.status_code == DFU_RESET)
|
||||
{
|
||||
m_update_status = BOOTLOADER_RESET;
|
||||
m_update_status = update_status.restart_into_bootloader == false
|
||||
? BOOTLOADER_SYS_RESET
|
||||
: BOOTLOADER_RESET_TO_SELF;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -328,6 +332,10 @@ void bootloader_dfu_update_process(dfu_update_status_t update_status)
|
||||
}
|
||||
}
|
||||
|
||||
bool bootloader_must_reset_to_self(void)
|
||||
{
|
||||
return m_update_status == BOOTLOADER_RESET_TO_SELF;
|
||||
}
|
||||
|
||||
uint32_t bootloader_init(void)
|
||||
{
|
||||
|
||||
@@ -32,6 +32,13 @@
|
||||
*/
|
||||
uint32_t bootloader_init(void);
|
||||
|
||||
/**@brief Function to check if bootloader must be reentered after a reset
|
||||
* @details: This function can only be called after bootloader_dfu_start returns
|
||||
* @retval true If device must reboot to the bootloader
|
||||
* @retval false If device must reboot to the application, if possible
|
||||
*/
|
||||
bool bootloader_must_reset_to_self(void);
|
||||
|
||||
/**@brief Function for validating application region in flash.
|
||||
* @retval true If Application region is valid.
|
||||
* @retval false If Application region is not valid.
|
||||
|
||||
@@ -82,6 +82,7 @@ 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.
|
||||
@@ -710,6 +711,14 @@ void dfu_reset(void)
|
||||
|
||||
update_status.status_code = DFU_RESET;
|
||||
|
||||
// If we are still receiving packets, and we are expecting more of them,
|
||||
// and we receive the RESET command, this means the DFU app is trying
|
||||
// to interrupt and recover a failed previous attempt of FLASHing a new
|
||||
// application. Make sure to reboot into DFU mode instead of starting
|
||||
// a previously stored application (specially valid for double bank
|
||||
// bootloaders
|
||||
update_status.restart_into_bootloader = (m_dfu_state == DFU_STATE_RX_DATA_PKT && m_data_received != m_image_size);
|
||||
|
||||
bootloader_dfu_update_process(update_status);
|
||||
}
|
||||
|
||||
|
||||
@@ -607,6 +607,14 @@ void dfu_reset(void)
|
||||
|
||||
update_status.status_code = DFU_RESET;
|
||||
|
||||
// If we are still receiving packets, and we are expecting more of them,
|
||||
// and we receive the RESET command, this means the DFU app is trying
|
||||
// to interrupt and recover a failed previous attempt of FLASHing a new
|
||||
// application. Make sure to reboot into DFU mode instead of starting
|
||||
// a previously stored application (specially valid for double bank
|
||||
// bootloaders
|
||||
update_status.restart_into_bootloader = (m_dfu_state == DFU_STATE_RX_DATA_PKT && m_data_received != m_image_size);
|
||||
|
||||
bootloader_dfu_update_process(update_status);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#define DFU_TYPES_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "nrf_sdm.h"
|
||||
#include "nrf_mbr.h"
|
||||
#include "nrf.h"
|
||||
@@ -154,6 +155,7 @@ typedef struct
|
||||
uint32_t bl_size; /**< Size of the recieved BootLoader. */
|
||||
uint32_t app_size; /**< Size of the recieved Application. */
|
||||
uint32_t sd_image_start; /**< Location in flash where the received SoftDevice image is stored. */
|
||||
bool restart_into_bootloader; /**< If the chip must be reset and must reenter bootloader mode. */
|
||||
} dfu_update_status_t;
|
||||
|
||||
/**@brief Update complete handler type. */
|
||||
|
||||
+19
-4
@@ -134,6 +134,7 @@ uint32_t* dbl_reset_mem = ((uint32_t*) DFU_DBL_RESET_MEM);
|
||||
// true if ble, false if serial
|
||||
bool _ota_dfu = false;
|
||||
bool _ota_connected = false;
|
||||
bool _ota_was_active = false;
|
||||
bool _sd_inited = false;
|
||||
|
||||
bool is_ota(void) {
|
||||
@@ -192,6 +193,10 @@ int main(void) {
|
||||
// Return when DFU process is complete (or not entered at all)
|
||||
check_dfu_mode();
|
||||
|
||||
// Check if we must reenter the bootloader after reset, instead of
|
||||
// launching the user application
|
||||
bool bootloader_must_be_reentered = bootloader_must_reset_to_self();
|
||||
|
||||
// Reset peripherals
|
||||
board_teardown();
|
||||
|
||||
@@ -202,7 +207,9 @@ int main(void) {
|
||||
* - sd_softdevice_vector_table_base_set(APP_ADDR)
|
||||
* - jump to App reset
|
||||
*/
|
||||
if (bootloader_app_is_valid() && !bootloader_dfu_sd_in_progress()) {
|
||||
if (!bootloader_must_be_reentered &&
|
||||
bootloader_app_is_valid() &&
|
||||
!bootloader_dfu_sd_in_progress()) {
|
||||
PRINTF("App is valid\r\n");
|
||||
if (is_sd_existed()) {
|
||||
// MBR forward IRQ to SD (if not already)
|
||||
@@ -220,9 +227,14 @@ int main(void) {
|
||||
bootloader_app_start();
|
||||
}
|
||||
|
||||
// No application was loaded, reset the system with the OTA DFU update
|
||||
NRF_POWER->GPREGRET = DFU_MAGIC_OTA_RESET;
|
||||
|
||||
// No application was loaded or we need to reenter the bootloader
|
||||
|
||||
// Reset the system with the OTA DFU update in case we were in it,
|
||||
// to allow completion of FLASHING, otherwise, default to normal reset
|
||||
if (_ota_was_active) {
|
||||
NRF_POWER->GPREGRET = DFU_MAGIC_OTA_RESET;
|
||||
}
|
||||
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
@@ -440,6 +452,9 @@ uint32_t proc_ble(void) {
|
||||
sd_ble_gap_phy_update(evt->evt.gap_evt.conn_handle, &phys);
|
||||
|
||||
_ota_connected = true;
|
||||
|
||||
// Remember someone connected to BLE
|
||||
_ota_was_active = true;
|
||||
led_state(STATE_BLE_CONNECTED);
|
||||
break;
|
||||
}
|
||||
|
||||
+3
-1
@@ -171,6 +171,7 @@ void tud_msc_write10_complete_cb(uint8_t lun)
|
||||
dfu_update_status_t update_status;
|
||||
memset(&update_status, 0, sizeof(dfu_update_status_t ));
|
||||
update_status.status_code = DFU_RESET;
|
||||
update_status.restart_into_bootloader = false;
|
||||
|
||||
bootloader_dfu_update_process(update_status);
|
||||
|
||||
@@ -195,9 +196,10 @@ void tud_msc_write10_complete_cb(uint8_t lun)
|
||||
{
|
||||
// update bootloader always end with reset
|
||||
update_status.status_code = DFU_RESET;
|
||||
update_status.restart_into_bootloader = false;
|
||||
|
||||
// Location of current stored new bootloader
|
||||
uint32_t * new_bootloader = (uint32_t *) BOOTLOADER_ADDR_NEW_RECIEVED;
|
||||
uint32_t * new_bootloader = (uint32_t *) BOOTLOADER_ADDR_NEW_RECEIVED;
|
||||
|
||||
PRINT_HEX(new_bootloader);
|
||||
|
||||
|
||||
@@ -32,4 +32,4 @@
|
||||
#define BOOTLOADER_ADDR_END BOOTLOADER_MBR_PARAMS_PAGE_ADDRESS
|
||||
|
||||
// Address where new bootloader is written before activation (skip application data)
|
||||
#define BOOTLOADER_ADDR_NEW_RECIEVED (USER_FLASH_END-DFU_BL_IMAGE_MAX_SIZE)
|
||||
#define BOOTLOADER_ADDR_NEW_RECEIVED (USER_FLASH_END-DFU_BL_IMAGE_MAX_SIZE)
|
||||
|
||||
Reference in New Issue
Block a user