aboutsummaryrefslogtreecommitdiff
path: root/embassy-usb-dfu
diff options
context:
space:
mode:
authorGerhard de Clercq <[email protected]>2025-04-22 12:20:21 +0200
committerGerhard de Clercq <[email protected]>2025-04-22 12:20:33 +0200
commit3c9661cebc0f093d8d9a194adca2d1c815ebfd2e (patch)
tree93fd4383efeb8177a0399ac75e1f4332de57aac5 /embassy-usb-dfu
parentfb5ce05b26ae0c90a872a8e0787c9419178d475a (diff)
[embassy-usb-dfu] Add generic DFU marking interface
This commit adds an interface that allows users to customise how the bootloader is informed that DFU mode is needed on the next boot.
Diffstat (limited to 'embassy-usb-dfu')
-rw-r--r--embassy-usb-dfu/src/application.rs36
1 files changed, 25 insertions, 11 deletions
diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs
index f0d7626f6..e93c241ad 100644
--- a/embassy-usb-dfu/src/application.rs
+++ b/embassy-usb-dfu/src/application.rs
@@ -13,9 +13,25 @@ use crate::consts::{
13}; 13};
14use crate::Reset; 14use crate::Reset;
15 15
16/// Generic interface for a system that can signal to the bootloader that USB DFU mode is needed on the next boot.
17///
18/// By default this trait is implemented for `BlockingFirmwareState<'d, STATE>` but you could also implement this generic
19/// interface yourself instead in more complex situations. This could for instance be when you cannot hand ownership of a
20/// `BlockingFirmwareState` instance over directly to the DFU `Control` instance and need to use a more complex mechanism.
21pub trait DfuMarker {
22 /// Signal to the bootloader that DFU mode should be used on the next boot.
23 fn mark_dfu(&mut self);
24}
25
26impl<'d, STATE: NorFlash> DfuMarker for BlockingFirmwareState<'d, STATE> {
27 fn mark_dfu(&mut self) {
28 self.mark_dfu().expect("Failed to mark DFU mode in bootloader")
29 }
30}
31
16/// Internal state for the DFU class 32/// Internal state for the DFU class
17pub struct Control<'d, STATE: NorFlash, RST: Reset> { 33pub struct Control<MARK: DfuMarker, RST: Reset> {
18 firmware_state: BlockingFirmwareState<'d, STATE>, 34 dfu_marker: MARK,
19 attrs: DfuAttributes, 35 attrs: DfuAttributes,
20 state: State, 36 state: State,
21 timeout: Option<Duration>, 37 timeout: Option<Duration>,
@@ -23,11 +39,11 @@ pub struct Control<'d, STATE: NorFlash, RST: Reset> {
23 _rst: PhantomData<RST>, 39 _rst: PhantomData<RST>,
24} 40}
25 41
26impl<'d, STATE: NorFlash, RST: Reset> Control<'d, STATE, RST> { 42impl<MARK: DfuMarker, RST: Reset> Control<MARK, RST> {
27 /// Create a new DFU instance to expose a DFU interface. 43 /// Create a new DFU instance to expose a DFU interface.
28 pub fn new(firmware_state: BlockingFirmwareState<'d, STATE>, attrs: DfuAttributes) -> Self { 44 pub fn new(dfu_marker: MARK, attrs: DfuAttributes) -> Self {
29 Control { 45 Control {
30 firmware_state, 46 dfu_marker,
31 attrs, 47 attrs,
32 state: State::AppIdle, 48 state: State::AppIdle,
33 detach_start: None, 49 detach_start: None,
@@ -37,7 +53,7 @@ impl<'d, STATE: NorFlash, RST: Reset> Control<'d, STATE, RST> {
37 } 53 }
38} 54}
39 55
40impl<'d, STATE: NorFlash, RST: Reset> Handler for Control<'d, STATE, RST> { 56impl<MARK: DfuMarker, RST: Reset> Handler for Control<MARK, RST> {
41 fn reset(&mut self) { 57 fn reset(&mut self) {
42 if let Some(start) = self.detach_start { 58 if let Some(start) = self.detach_start {
43 let delta = Instant::now() - start; 59 let delta = Instant::now() - start;
@@ -48,9 +64,7 @@ impl<'d, STATE: NorFlash, RST: Reset> Handler for Control<'d, STATE, RST> {
48 timeout.as_millis() 64 timeout.as_millis()
49 ); 65 );
50 if delta < timeout { 66 if delta < timeout {
51 self.firmware_state 67 self.dfu_marker.mark_dfu();
52 .mark_dfu()
53 .expect("Failed to mark DFU mode in bootloader");
54 RST::sys_reset() 68 RST::sys_reset()
55 } 69 }
56 } 70 }
@@ -109,9 +123,9 @@ impl<'d, STATE: NorFlash, RST: Reset> Handler for Control<'d, STATE, RST> {
109/// it should expose a DFU device, and a software reset will be issued. 123/// it should expose a DFU device, and a software reset will be issued.
110/// 124///
111/// To apply USB DFU updates, the bootloader must be capable of recognizing the DFU magic and exposing a device to handle the full DFU transaction with the host. 125/// To apply USB DFU updates, the bootloader must be capable of recognizing the DFU magic and exposing a device to handle the full DFU transaction with the host.
112pub fn usb_dfu<'d, D: Driver<'d>, STATE: NorFlash, RST: Reset>( 126pub fn usb_dfu<'d, D: Driver<'d>, MARK: DfuMarker, RST: Reset>(
113 builder: &mut Builder<'d, D>, 127 builder: &mut Builder<'d, D>,
114 handler: &'d mut Control<'d, STATE, RST>, 128 handler: &'d mut Control<MARK, RST>,
115 timeout: Duration, 129 timeout: Duration,
116) { 130) {
117 let mut func = builder.function(0x00, 0x00, 0x00); 131 let mut func = builder.function(0x00, 0x00, 0x00);