diff --git a/.gitignore b/.gitignore index e7b13c9f..3180a079 100644 --- a/.gitignore +++ b/.gitignore @@ -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* - diff --git a/lib/sdk11/components/libraries/bootloader_dfu/bootloader.c b/lib/sdk11/components/libraries/bootloader_dfu/bootloader.c index bd9b8cce..059b6fdd 100644 --- a/lib/sdk11/components/libraries/bootloader_dfu/bootloader.c +++ b/lib/sdk11/components/libraries/bootloader_dfu/bootloader.c @@ -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(); } diff --git a/lib/sdk11/components/libraries/bootloader_dfu/bootloader.h b/lib/sdk11/components/libraries/bootloader_dfu/bootloader.h index 9b6f7540..5c68e9bc 100644 --- a/lib/sdk11/components/libraries/bootloader_dfu/bootloader.h +++ b/lib/sdk11/components/libraries/bootloader_dfu/bootloader.h @@ -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 diff --git a/lib/sdk11/components/libraries/bootloader_dfu/dfu_transport_serial.c b/lib/sdk11/components/libraries/bootloader_dfu/dfu_transport_serial.c index 71f08526..b8c65ae3 100644 --- a/lib/sdk11/components/libraries/bootloader_dfu/dfu_transport_serial.c +++ b/lib/sdk11/components/libraries/bootloader_dfu/dfu_transport_serial.c @@ -10,10 +10,11 @@ * */ -#include "dfu_transport.h" -#include -#include "dfu.h" -#include +#include "dfu_transport.h" +#include +#include "bootloader.h" +#include "dfu.h" +#include #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()) { diff --git a/src/usb/msc_uf2.c b/src/usb/msc_uf2.c index 96d705bc..f4a60787 100644 --- a/src/usb/msc_uf2.c +++ b/src/usb/msc_uf2.c @@ -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;