Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ In OTA DFU mode:

The OTA fallback is intentional and prevents devices from getting stuck in UF2 mode after failed OTA updates.

A device with a valid application that sits in DFU for 6 minutes with no activity (no BLE connection or DFU traffic, no drive access) boots its application. A device with no valid application stays in DFU.

If the bootloader recorded a fault since the last UF2 drive session, `INFO_UF2.TXT` shows a `Last-Fault:` line with the fault id, program counter, and info word. It appears only if the next boot reaches the drive before an application boots, since the application's RAM use wipes the record.

---
Expand Down
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ it and is upstream Adafruit history, kept for provenance.

## OTAFIX 2.6

- A board with a valid application that sits in DFU for 6 minutes with no activity boots its application. A BLE connection or DFU write, a UF2 drive read or write, USB enumeration, and serial DFU traffic each restart the 6 minutes; a board with no valid application keeps waiting.
- A SoftDevice flash timeout during a BLE or serial transfer, or the activation settings save, is retried every 100 ms, up to 20 times, instead of resetting the bootloader.
- `INFO_UF2.TXT` shows a `Last-Fault: id=0x.. pc=0x.. info=0x..` line for a SoftDevice or SDK fault the bootloader recorded since the last UF2 drive session. It appears only if the next boot reaches the drive before an application boots, since the application's RAM use wipes the record. The record lives in a 16-byte RAM region behind a magic word and is cleared once printed; for an SDK error `info` is the error code.
- A device with no valid application that is plugged into a USB host comes up as a UF2 drive showing NO FIRMWARE instead of waiting for a phone. On battery (no VBUS) it goes straight to the BLE OTA wait, and with VBUS but no host enumerating within 3 s (a charger or power bank) it falls through to the same wait. A cabled board with no application returns to the drive after an aborted copy, and after an eject on boards built with `UF2_EXIT_ON_EJECT` (`mesh_tracker_x1`, `t1000_e`). When the cable is pulled while the drive is up (VBUS gone for 250 ms), it goes to the BLE OTA wait. Plugging a cable into a board with no application that is waiting for BLE, with no phone connected, brings the drive up (VBUS present for 250 ms); a cable already present when the wait began, or a phone connected, leaves the wait alone.
Expand Down
57 changes: 57 additions & 0 deletions lib/sdk11/components/libraries/bootloader_dfu/bootloader.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,17 @@ static bool m_cancel_timeout_on_usb; /**< If set the timeout is cancelled when U
APP_TIMER_DEF( _dfu_startup_timer );
volatile bool dfu_startup_packet_received = false;

#ifndef DFU_INACTIVITY_TIMEOUT_MS
#define DFU_INACTIVITY_TIMEOUT_MS (6 * 60 * 1000)
#endif
#define DFU_INACTIVITY_TICK_MS 1000

// dfu_activity() only sets a flag, so it is cheap from any context; a 1 s tick turns it into the idle count.
APP_TIMER_DEF( _dfu_inactivity_timer );
static volatile bool m_dfu_activity;
static bool m_inactivity_armed;
static uint32_t m_inactivity_idle_ms;

/**@brief Function for handling callbacks from pstorage module.
*
* @details Handles pstorage results for clear and storage operation. For detailed description of
Expand Down Expand Up @@ -99,6 +110,43 @@ static void dfu_startup_timer_handler(void * p_context)
}
}

void dfu_activity(void)
{
m_dfu_activity = true;
}

// A session that sat idle with a valid application ends like the startup timeout, so main() boots the application.
// A started transfer has invalidated bank 0, and with no application the wait stays.
static void dfu_inactivity_timer_handler(void * p_context)
{
if (!m_inactivity_armed) return;

if (m_dfu_activity)
{
m_dfu_activity = false;
m_inactivity_idle_ms = 0;
}
else
{
m_inactivity_idle_ms += DFU_INACTIVITY_TICK_MS;
}

if (m_inactivity_idle_ms < DFU_INACTIVITY_TIMEOUT_MS)
{
app_timer_start(_dfu_inactivity_timer, APP_TIMER_TICKS(DFU_INACTIVITY_TICK_MS), NULL);
return;
}

m_inactivity_armed = false;
if (m_update_status == BOOTLOADER_UPDATING && bootloader_app_is_valid())
{
dfu_update_status_t update_status;
update_status.status_code = DFU_TIMEOUT;

bootloader_dfu_update_process(update_status);
}
}

/**@brief Function for waiting for events.
*
* @details This function will place the chip in low power mode while waiting for events from
Expand Down Expand Up @@ -355,8 +403,17 @@ uint32_t bootloader_dfu_start(bool ota, uint32_t timeout_ms, bool cancel_timeout
err_code = dfu_transport_serial_update_start();
}

m_dfu_activity = false;
m_inactivity_idle_ms = 0;
m_inactivity_armed = true;
app_timer_create(&_dfu_inactivity_timer, APP_TIMER_MODE_SINGLE_SHOT, dfu_inactivity_timer_handler);
app_timer_start(_dfu_inactivity_timer, APP_TIMER_TICKS(DFU_INACTIVITY_TICK_MS), NULL);

wait_for_events();

m_inactivity_armed = false;
app_timer_stop(_dfu_inactivity_timer);

return err_code;
}

Expand Down
6 changes: 6 additions & 0 deletions lib/sdk11/components/libraries/bootloader_dfu/bootloader.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ bool bootloader_app_is_valid(void);
*/
uint32_t bootloader_dfu_start(bool ota, uint32_t timeout_ms, bool cancel_timeout_on_usb);

/**@brief Function for telling the DFU inactivity timeout that the session is not idle.
*
* @details Safe to call from any context, before or during a session.
*/
void dfu_activity(void);

/**@brief Function for exiting bootloader and booting into application.
*
* @details This function will disable SoftDevice and all interrupts before jumping to application.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,8 @@ static void on_dfu_evt(ble_dfu_t * p_dfu, ble_dfu_evt_t * p_evt)
uint32_t err_code;
ble_dfu_resp_val_t resp_val;

dfu_activity();

switch (p_evt->ble_dfu_evt_type)
{
case BLE_DFU_VALIDATE:
Expand Down Expand Up @@ -923,6 +925,7 @@ static void on_ble_evt(ble_evt_t * p_ble_evt)
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
dfu_activity();
m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
m_is_advertising = false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "app_util.h"
#include "hci_transport.h"
#include "app_timer.h"
#include "bootloader.h"
#include "app_scheduler.h"
#include "boards.h"

Expand Down Expand Up @@ -200,6 +201,7 @@ static void process_dfu_packet(void * p_event_data, uint16_t event_size)
// Adafruit modification for startup dfu
extern bool dfu_startup_packet_received;
dfu_startup_packet_received = true;
dfu_activity();

while (false == DATA_QUEUE_EMPTY())
{
Expand Down
2 changes: 2 additions & 0 deletions src/usb/msc_uf2.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer,
int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
{
(void) lun;
dfu_activity();
memset(buffer, 0, bufsize);

// since we return block size each, offset should always be zero
Expand All @@ -179,6 +180,7 @@ int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buf
int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
{
(void) lun;
dfu_activity();

uint32_t count = 0;
while ( count < bufsize )
Expand Down
1 change: 1 addition & 0 deletions src/usb/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ bool usb_host_mounted(void) {

void tud_mount_cb(void) {
_host_mounted = true;
dfu_activity();
led_state(STATE_USB_MOUNTED);
}

Expand Down
Loading