Skip to content

Commit c560df9

Browse files
committed
Fix OTA silently transferring a zero-length image
DfuService::OnServiceData arms the 10s one-shot inactivity timer before dispatching each access. The image-size write then calls DfuImage::Erase(), which erases the whole image slot a sector at a time and takes tens of seconds. That timer runs on the FreeRTOS timer task, so it fires part-way through the erase and calls Reset(), zeroing applicationSize. The erase then finishes and the handler carries on regardless: it sets state = Init and reports success. ReceiveFirmwareImage later calls dfuImage.Init(20, 0, crc), so IsComplete() -- totalWriteIndex == totalSize, now 0 == 0 -- is already true when the first data packet arrives. The watch tells the host the entire image has been received, emits no packet-receipt notifications, writes nothing to flash, and validation CRCs zero bytes. From the host side this looks like an instant "whole image received" reply a fraction of a second after Begin DFU, followed by a validation failure - with no indication that the erase timed out. Recovery mode is unaffected because its erase is fast enough to finish inside the 10s window, which is why OTA can fail from the running firmware while succeeding from recovery. Stop the timer around the erase and restart it afterwards. Tested on a PineTime: before this change every OTA update from the running firmware failed as described; after it, updates complete and validate normally without needing recovery mode.
1 parent 71d1f5b commit c560df9

1 file changed

Lines changed: 6 additions & 0 deletions

File tree

‎src/components/ble/DfuService.cpp‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,13 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf* om) {
145145
vTaskDelay(pdMS_TO_TICKS(5));
146146
}
147147

148+
// Erasing the image slot takes far longer than the 10s inactivity timeout, and that
149+
// timer runs on the FreeRTOS timer task, so it fires while this call blocks. Its
150+
// Reset() zeroes applicationSize, the erase then completes and the transfer carries
151+
// on with a zero-length image. Hold the timeout off for the duration of the erase.
152+
xTimerStop(timeoutTimer, 0);
148153
dfuImage.Erase();
154+
xTimerStart(timeoutTimer, 0);
149155

150156
uint8_t data[] {16, 1, 1};
151157
notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 3);

0 commit comments

Comments
 (0)