Skip to content

Commit 9bf8c4d

Browse files
committed
Detect USB requests and reset or enter error state
Per the DFU spec, a USB reset should cause the device to either reenumerate as the application or enter an error state if invalid. Register a USB reset callback to detect and handle USB resets, taking care not to trigger the first time the bootloader is enumerated. Run the manifest callback if present when manifesting via USB reset.
1 parent da0ec9d commit 9bf8c4d

1 file changed

Lines changed: 34 additions & 0 deletions

File tree

src/dfu.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,10 @@ dfu_control_class_request(usbd_device *usbd_dev,
331331
return status;
332332
}
333333

334+
/* Track dfu enumeration status to distinguish between the first USB
335+
reset after bootup versus a subsequent USB reset and re-enumeration */
336+
static bool dfu_enumerated = false;
337+
334338
static void dfu_set_config(usbd_device* usbd_dev, uint16_t wValue) {
335339
(void)wValue;
336340

@@ -339,6 +343,35 @@ static void dfu_set_config(usbd_device* usbd_dev, uint16_t wValue) {
339343
USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
340344
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
341345
dfu_control_class_request);
346+
347+
dfu_enumerated = true;
348+
}
349+
350+
static void dfu_on_usb_reset(void) {
351+
/* Ignore the first USB reset after boot, before anyone has had
352+
a chance to do anything to the device; otherwise we'd never
353+
enter DFU mode when the application is valid */
354+
if (!dfu_enumerated) {
355+
return;
356+
}
357+
358+
/* On subsequent USB reset requests, either manifest by resetting
359+
or enter the error state if firmware is invalid, per the spec */
360+
if (validate_application()) {
361+
/* Manifest by resetting after responding */
362+
dfu_set_state(STATE_DFU_MANIFEST);
363+
364+
if (dfu_manifest_request_callback) {
365+
dfu_manifest_request_callback();
366+
}
367+
368+
/* Reset and launch the application if the manifest callback
369+
didn't already do it */
370+
scb_reset_system();
371+
} else {
372+
/* Enter the error state and await further commands */
373+
dfu_set_status(DFU_STATUS_ERR_FIRMWARE);
374+
}
342375
}
343376

344377
void dfu_setup(usbd_device* usbd_dev,
@@ -349,6 +382,7 @@ void dfu_setup(usbd_device* usbd_dev,
349382
dfu_state_change_callback = on_state_change;
350383
dfu_status_change_callback = on_status_change;
351384

385+
usbd_register_reset_callback(usbd_dev, dfu_on_usb_reset);
352386
usbd_register_set_config_callback(usbd_dev, dfu_set_config);
353387
current_dfu_state = STATE_DFU_IDLE;
354388
current_dfu_status = DFU_STATUS_OK;

0 commit comments

Comments
 (0)