When in bootloader mode and USB is disconnected the system now jumpt to app state to avoid leave the device stuck on bootloader

This commit is contained in:
jesuslg123 committed 2026-03-08 21:20:03 +01:00
1 parent 8023c1e6a0
commit 57ce8b2e93
5 files changed
+109 -66

No files matched your search

+1 -1
View File
@@ -56,6 +56,7 @@ dkms.conf
segger/Output
_build/
cmake-build-*/
bin/
*.emSession
*.jlink
@@ -68,4 +69,3 @@ Makefile.user
# Exclude all SoftDevice S340 files
lib/softdevice/s340*
@@ -48,12 +48,29 @@ typedef enum
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. */
static bootloader_status_t m_update_status; /**< Current update status for the bootloader module to ensure correct behaviour when updating settings and when update completes. */
static bool m_cancel_timeout_on_usb; /**< If set the timeout is cancelled when USB is enumerated. Otherwise, the timeout is only cancelled when DFU update is started. */
APP_TIMER_DEF( _dfu_startup_timer );
volatile bool dfu_startup_packet_received = false;
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. */
static bootloader_status_t m_update_status; /**< Current update status for the bootloader module to ensure correct behaviour when updating settings and when update completes. */
static bool m_cancel_timeout_on_usb; /**< If set the timeout is cancelled when USB is enumerated. Otherwise, the timeout is only cancelled when DFU update is started. */
static bool m_usb_was_mounted; /**< Tracks whether the USB DFU session was ever enumerated so we can exit when cable is later removed. */
static bool m_startup_dfu_has_activity; /**< Tracks whether any valid serial or UF2 update traffic has started. */
APP_TIMER_DEF( _dfu_startup_timer );
static void bootloader_timeout_startup_dfu(void)
{
if (!m_startup_dfu_has_activity)
{
dfu_update_status_t update_status;
update_status.status_code = DFU_TIMEOUT;
bootloader_dfu_update_process(update_status);
}
}
void bootloader_dfu_activity_mark(void)
{
m_startup_dfu_has_activity = true;
}
/**@brief Function for handling callbacks from pstorage module.
*
@@ -79,26 +96,20 @@ static void pstorage_callback_handler(pstorage_handle_t * p_handle,
/* Terminate the forced DFU mode on startup if no packets is received
* by put an terminal handler to scheduler
*/
static void dfu_startup_timer_handler(void * p_context)
{
#ifdef NRF_USBD
if (m_cancel_timeout_on_usb && tud_mounted())
{
return;
}
#endif
// nRF52832 forced DFU on startup
// No packets are received within timeout, exit DFU mode
// dfu_startup_packet_received is set by process_dfu_packet() in dfu_transport_serial.c
if (!dfu_startup_packet_received)
{
dfu_update_status_t update_status;
update_status.status_code = DFU_TIMEOUT;
bootloader_dfu_update_process(update_status);
}
}
static void dfu_startup_timer_handler(void * p_context)
{
#ifdef NRF_USBD
if (m_cancel_timeout_on_usb && tud_mounted())
{
m_usb_was_mounted = true;
return;
}
#endif
// nRF52832 forced DFU on startup
// No update activity is received within timeout, exit DFU mode
bootloader_timeout_startup_dfu();
}
/**@brief Function for waiting for events.
*
@@ -126,14 +137,29 @@ static void wait_for_events(void)
// Event received. Process it from the scheduler.
app_sched_execute();
#ifdef NRF_USBD
// skip if usb is not inited ( e.g OTA / finializing sd/bootloader )
if ( tusb_inited() )
{
tud_task();
tud_cdc_write_flush();
}
#endif
#ifdef NRF_USBD
// skip if usb is not inited ( e.g OTA / finializing sd/bootloader )
if ( tusb_inited() )
{
tud_task();
tud_cdc_write_flush();
}
if (m_cancel_timeout_on_usb)
{
if (tusb_inited() && tud_mounted())
{
m_usb_was_mounted = true;
}
else if (m_usb_was_mounted &&
!(NRF_POWER->USBREGSTATUS & POWER_USBREGSTATUS_VBUSDETECT_Msk))
{
// Only exit startup DFU after USB was actually unplugged, not on a host-side
// re-enumeration or temporary unmount.
bootloader_timeout_startup_dfu();
}
}
#endif
if ((m_update_status == BOOTLOADER_COMPLETE) ||
(m_update_status == BOOTLOADER_TIMEOUT) ||
@@ -353,15 +379,17 @@ uint32_t bootloader_init(void)
}
uint32_t bootloader_dfu_start(bool ota, uint32_t timeout_ms, bool cancel_timeout_on_usb)
{
uint32_t err_code;
m_cancel_timeout_on_usb = cancel_timeout_on_usb && !ota;
// Clear swap if banked update is used.
err_code = dfu_init();
VERIFY_SUCCESS(err_code);
uint32_t bootloader_dfu_start(bool ota, uint32_t timeout_ms, bool cancel_timeout_on_usb)
{
uint32_t err_code;
m_cancel_timeout_on_usb = cancel_timeout_on_usb && !ota;
m_usb_was_mounted = false;
m_startup_dfu_has_activity = false;
// Clear swap if banked update is used.
err_code = dfu_init();
VERIFY_SUCCESS(err_code);
if ( ota )
{
@@ -369,15 +397,13 @@ uint32_t bootloader_dfu_start(bool ota, uint32_t timeout_ms, bool cancel_timeout
}else
{
// DFU mode with timeout can be
// - Forced startup DFU for nRF52832 or
// - Makecode single tap reset but no enumerated (battery power)
if ( timeout_ms )
{
dfu_startup_packet_received = false;
app_timer_create(&_dfu_startup_timer, APP_TIMER_MODE_SINGLE_SHOT, dfu_startup_timer_handler);
app_timer_start(_dfu_startup_timer, APP_TIMER_TICKS(timeout_ms), NULL);
}
// - Forced startup DFU for nRF52832 or
// - Makecode single tap reset but no enumerated (battery power)
if ( timeout_ms )
{
app_timer_create(&_dfu_startup_timer, APP_TIMER_MODE_SINGLE_SHOT, dfu_startup_timer_handler);
app_timer_start(_dfu_startup_timer, APP_TIMER_TICKS(timeout_ms), NULL);
}
err_code = dfu_transport_serial_update_start();
}
@@ -68,11 +68,18 @@ void bootloader_app_start(void);
*/
void bootloader_settings_get(bootloader_settings_t * const p_settings);
/**@brief Function for processing DFU status update.
*
* @param[in] update_status DFU update status.
*/
void bootloader_dfu_update_process(dfu_update_status_t update_status);
/**@brief Function for processing DFU status update.
*
* @param[in] update_status DFU update status.
*/
void bootloader_dfu_update_process(dfu_update_status_t update_status);
/**@brief Mark that startup DFU has received valid update activity.
*
* @details This suppresses the startup timeout or USB unplug fallback that is only
* meant for the "entered bootloader, but never started an update" case.
*/
void bootloader_dfu_activity_mark(void);
/**@brief Function getting state of SoftDevice update in progress.
* After a successfull SoftDevice transfer the system restarts in orderto disable SoftDevice
@@ -10,10 +10,11 @@
*
*/
#include "dfu_transport.h"
#include <stddef.h>
#include "dfu.h"
#include <dfu_types.h>
#include "dfu_transport.h"
#include <stddef.h>
#include "bootloader.h"
#include "dfu.h"
#include <dfu_types.h>
#include "app_error.h"
#include "app_util.h"
#include "hci_transport.h"
@@ -197,9 +198,8 @@ static void process_dfu_packet(void * p_event_data, uint16_t event_size)
uint32_t index;
dfu_update_packet_t * packet;
// Adafruit modification for startup dfu
extern bool dfu_startup_packet_received;
dfu_startup_packet_received = true;
// Mark that startup DFU has transitioned into a real update flow.
bootloader_dfu_activity_mark();
while (false == DATA_QUEUE_EMPTY())
{
+11 -1
View File
@@ -145,9 +145,19 @@ int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t*
uint32_t count = 0;
while ( count < bufsize )
{
int written;
// Consider non-uf2 block write as successful
// only break if write_block is busy with flashing (return 0)
if ( 0 == write_block(lba, buffer, &_wr_state) ) break;
written = write_block(lba, buffer, &_wr_state);
if ( written > 0 )
{
bootloader_dfu_activity_mark();
}
else if ( written == 0 )
{
break;
}
lba++;
buffer += 512;