diff options
| author | Gerhard de Clercq <[email protected]> | 2025-04-22 12:20:21 +0200 |
|---|---|---|
| committer | Gerhard de Clercq <[email protected]> | 2025-04-22 12:20:33 +0200 |
| commit | 3c9661cebc0f093d8d9a194adca2d1c815ebfd2e (patch) | |
| tree | 93fd4383efeb8177a0399ac75e1f4332de57aac5 | |
| parent | fb5ce05b26ae0c90a872a8e0787c9419178d475a (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.
| -rw-r--r-- | embassy-usb-dfu/src/application.rs | 36 |
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 | }; |
| 14 | use crate::Reset; | 14 | use 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. | ||
| 21 | pub 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 | |||
| 26 | impl<'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 |
| 17 | pub struct Control<'d, STATE: NorFlash, RST: Reset> { | 33 | pub 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 | ||
| 26 | impl<'d, STATE: NorFlash, RST: Reset> Control<'d, STATE, RST> { | 42 | impl<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 | ||
| 40 | impl<'d, STATE: NorFlash, RST: Reset> Handler for Control<'d, STATE, RST> { | 56 | impl<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. |
| 112 | pub fn usb_dfu<'d, D: Driver<'d>, STATE: NorFlash, RST: Reset>( | 126 | pub 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); |
