embassy-usb-dfu: Change return of reset to ()

Also adds &self to the Reset trait, which makes it easier to implement
cleanup/delays before actually resetting.
This commit is contained in:
Matthew Tran 2025-05-08 00:09:21 -05:00
parent 6c6ae4f9fc
commit d35df5cfba
5 changed files with 18 additions and 22 deletions

View File

@ -1,5 +1,3 @@
use core::marker::PhantomData;
use embassy_boot::BlockingFirmwareState; use embassy_boot::BlockingFirmwareState;
use embassy_time::{Duration, Instant}; use embassy_time::{Duration, Instant};
use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType};
@ -36,19 +34,19 @@ pub struct Control<MARK: DfuMarker, RST: Reset> {
state: State, state: State,
timeout: Option<Duration>, timeout: Option<Duration>,
detach_start: Option<Instant>, detach_start: Option<Instant>,
_rst: PhantomData<RST>, reset: RST,
} }
impl<MARK: DfuMarker, RST: Reset> Control<MARK, RST> { impl<MARK: DfuMarker, RST: Reset> Control<MARK, RST> {
/// Create a new DFU instance to expose a DFU interface. /// Create a new DFU instance to expose a DFU interface.
pub fn new(dfu_marker: MARK, attrs: DfuAttributes) -> Self { pub fn new(dfu_marker: MARK, attrs: DfuAttributes, reset: RST) -> Self {
Control { Control {
dfu_marker, dfu_marker,
attrs, attrs,
state: State::AppIdle, state: State::AppIdle,
detach_start: None, detach_start: None,
timeout: None, timeout: None,
_rst: PhantomData, reset,
} }
} }
} }
@ -65,7 +63,7 @@ impl<MARK: DfuMarker, RST: Reset> Handler for Control<MARK, RST> {
); );
if delta < timeout { if delta < timeout {
self.dfu_marker.mark_dfu(); self.dfu_marker.mark_dfu();
RST::sys_reset() self.reset.sys_reset()
} }
} }
} }

View File

@ -1,5 +1,3 @@
use core::marker::PhantomData;
use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterError}; use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterError};
use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType};
use embassy_usb::driver::Driver; use embassy_usb::driver::Driver;
@ -20,12 +18,12 @@ pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_S
status: Status, status: Status,
offset: usize, offset: usize,
buf: AlignedBuffer<BLOCK_SIZE>, buf: AlignedBuffer<BLOCK_SIZE>,
_rst: PhantomData<RST>, reset: RST,
} }
impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Control<'d, DFU, STATE, RST, BLOCK_SIZE> { impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Control<'d, DFU, STATE, RST, BLOCK_SIZE> {
/// Create a new DFU instance to handle DFU transfers. /// Create a new DFU instance to handle DFU transfers.
pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes) -> Self { pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes, reset: RST) -> Self {
Self { Self {
updater, updater,
attrs, attrs,
@ -33,7 +31,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Co
status: Status::Ok, status: Status::Ok,
offset: 0, offset: 0,
buf: AlignedBuffer([0; BLOCK_SIZE]), buf: AlignedBuffer([0; BLOCK_SIZE]),
_rst: PhantomData, reset,
} }
} }
@ -155,14 +153,14 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Ha
} }
match Request::try_from(req.request) { match Request::try_from(req.request) {
Ok(Request::GetStatus) => { Ok(Request::GetStatus) => {
//TODO: Configurable poll timeout, ability to add string for Vendor error
buf[0..6].copy_from_slice(&[self.status as u8, 0x32, 0x00, 0x00, self.state as u8, 0x00]);
match self.state { match self.state {
State::DlSync => self.state = State::Download, State::DlSync => self.state = State::Download,
State::ManifestSync => RST::sys_reset(), State::ManifestSync => self.reset.sys_reset(),
_ => {} _ => {}
} }
//TODO: Configurable poll timeout, ability to add string for Vendor error
buf[0..6].copy_from_slice(&[self.status as u8, 0x32, 0x00, 0x00, self.state as u8, 0x00]);
Some(InResponse::Accepted(&buf[0..6])) Some(InResponse::Accepted(&buf[0..6]))
} }
Ok(Request::GetState) => { Ok(Request::GetState) => {

View File

@ -26,10 +26,10 @@ compile_error!("usb-dfu must be compiled with exactly one of `dfu`, or `applicat
/// This crate exposes `ResetImmediate` when compiled with cortex-m or esp32c3 support, which immediately issues a /// This crate exposes `ResetImmediate` when compiled with cortex-m or esp32c3 support, which immediately issues a
/// reset request without interfacing with any other peripherals. /// reset request without interfacing with any other peripherals.
/// ///
/// If alternate behaviour is desired, a custom implementation of Reset can be provided as a type argument to the usb_dfu function. /// If alternate behaviour is desired, a custom implementation of Reset can be provided as an argument to the usb_dfu function.
pub trait Reset { pub trait Reset {
/// Reset the device. /// Reset the device.
fn sys_reset() -> !; fn sys_reset(&self);
} }
/// Reset immediately. /// Reset immediately.
@ -38,7 +38,7 @@ pub struct ResetImmediate;
#[cfg(feature = "esp32c3-hal")] #[cfg(feature = "esp32c3-hal")]
impl Reset for ResetImmediate { impl Reset for ResetImmediate {
fn sys_reset() -> ! { fn sys_reset(&self) {
esp32c3_hal::reset::software_reset(); esp32c3_hal::reset::software_reset();
loop {} loop {}
} }
@ -50,7 +50,7 @@ pub struct ResetImmediate;
#[cfg(feature = "cortex-m")] #[cfg(feature = "cortex-m")]
impl Reset for ResetImmediate { impl Reset for ResetImmediate {
fn sys_reset() -> ! { fn sys_reset(&self) {
cortex_m::peripheral::SCB::sys_reset() cortex_m::peripheral::SCB::sys_reset()
} }
} }

View File

@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) {
let mut config_descriptor = [0; 256]; let mut config_descriptor = [0; 256];
let mut bos_descriptor = [0; 256]; let mut bos_descriptor = [0; 256];
let mut control_buf = [0; 64]; let mut control_buf = [0; 64];
let mut state = Control::new(firmware_state, DfuAttributes::CAN_DOWNLOAD); let mut state = Control::new(firmware_state, DfuAttributes::CAN_DOWNLOAD, ResetImmediate);
let mut builder = Builder::new( let mut builder = Builder::new(
driver, driver,
config, config,
@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) {
&mut control_buf, &mut control_buf,
); );
usb_dfu::<_, _, ResetImmediate>(&mut builder, &mut state, Duration::from_millis(2500)); usb_dfu(&mut builder, &mut state, Duration::from_millis(2500));
let mut dev = builder.build(); let mut dev = builder.build();
dev.run().await dev.run().await

View File

@ -55,7 +55,7 @@ fn main() -> ! {
let mut config_descriptor = [0; 256]; let mut config_descriptor = [0; 256];
let mut bos_descriptor = [0; 256]; let mut bos_descriptor = [0; 256];
let mut control_buf = [0; 4096]; let mut control_buf = [0; 4096];
let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD); let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD, ResetImmediate);
let mut builder = Builder::new( let mut builder = Builder::new(
driver, driver,
config, config,
@ -77,7 +77,7 @@ fn main() -> ! {
msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS), msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
)); ));
usb_dfu::<_, _, _, ResetImmediate, 4096>(&mut builder, &mut state); usb_dfu::<_, _, _, _, 4096>(&mut builder, &mut state);
let mut dev = builder.build(); let mut dev = builder.build();
embassy_futures::block_on(dev.run()); embassy_futures::block_on(dev.run());