fmt
This commit is contained in:
parent
0b26b2d360
commit
6513d03fdf
@ -1,10 +1,14 @@
|
|||||||
|
|
||||||
use embassy_boot::BlockingFirmwareUpdater;
|
use embassy_boot::BlockingFirmwareUpdater;
|
||||||
use embassy_time::{Instant, Duration};
|
use embassy_time::{Duration, Instant};
|
||||||
use embassy_usb::{Handler, control::{RequestType, Recipient, OutResponse, InResponse}, Builder, driver::Driver};
|
use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType};
|
||||||
|
use embassy_usb::driver::Driver;
|
||||||
|
use embassy_usb::{Builder, Handler};
|
||||||
use embedded_storage::nor_flash::NorFlash;
|
use embedded_storage::nor_flash::NorFlash;
|
||||||
|
|
||||||
use crate::consts::{DfuAttributes, Request, Status, State, USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_RT};
|
use crate::consts::{
|
||||||
|
DfuAttributes, Request, State, Status, APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_RT,
|
||||||
|
USB_CLASS_APPN_SPEC,
|
||||||
|
};
|
||||||
|
|
||||||
/// Internal state for the DFU class
|
/// Internal state for the DFU class
|
||||||
pub struct Control<'d, DFU: NorFlash, STATE: NorFlash> {
|
pub struct Control<'d, DFU: NorFlash, STATE: NorFlash> {
|
||||||
@ -17,7 +21,13 @@ pub struct Control<'d, DFU: NorFlash, STATE: NorFlash> {
|
|||||||
|
|
||||||
impl<'d, DFU: NorFlash, STATE: NorFlash> Control<'d, DFU, STATE> {
|
impl<'d, DFU: NorFlash, STATE: NorFlash> Control<'d, DFU, STATE> {
|
||||||
pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes) -> Self {
|
pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes) -> Self {
|
||||||
Control { updater, attrs, state: State::AppIdle, detach_start: None, timeout: None }
|
Control {
|
||||||
|
updater,
|
||||||
|
attrs,
|
||||||
|
state: State::AppIdle,
|
||||||
|
detach_start: None,
|
||||||
|
timeout: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,7 +37,11 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> Handler for Control<'d, DFU, STATE> {
|
|||||||
let delta = Instant::now() - start;
|
let delta = Instant::now() - start;
|
||||||
let timeout = self.timeout.unwrap();
|
let timeout = self.timeout.unwrap();
|
||||||
#[cfg(feature = "defmt")]
|
#[cfg(feature = "defmt")]
|
||||||
defmt::info!("Received RESET with delta = {}, timeout = {}", delta.as_millis(), timeout.as_millis());
|
defmt::info!(
|
||||||
|
"Received RESET with delta = {}, timeout = {}",
|
||||||
|
delta.as_millis(),
|
||||||
|
timeout.as_millis()
|
||||||
|
);
|
||||||
if delta < timeout {
|
if delta < timeout {
|
||||||
self.updater.mark_dfu().expect("Failed to mark DFU mode in bootloader");
|
self.updater.mark_dfu().expect("Failed to mark DFU mode in bootloader");
|
||||||
cortex_m::asm::dsb();
|
cortex_m::asm::dsb();
|
||||||
@ -36,7 +50,11 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> Handler for Control<'d, DFU, STATE> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn control_out(&mut self, req: embassy_usb::control::Request, _: &[u8]) -> Option<embassy_usb::control::OutResponse> {
|
fn control_out(
|
||||||
|
&mut self,
|
||||||
|
req: embassy_usb::control::Request,
|
||||||
|
_: &[u8],
|
||||||
|
) -> Option<embassy_usb::control::OutResponse> {
|
||||||
if (req.request_type, req.recipient) != (RequestType::Class, Recipient::Interface) {
|
if (req.request_type, req.recipient) != (RequestType::Class, Recipient::Interface) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -53,13 +71,15 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> Handler for Control<'d, DFU, STATE> {
|
|||||||
self.state = State::AppDetach;
|
self.state = State::AppDetach;
|
||||||
Some(OutResponse::Accepted)
|
Some(OutResponse::Accepted)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => None,
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn control_in<'a>(&'a mut self, req: embassy_usb::control::Request, buf: &'a mut [u8]) -> Option<embassy_usb::control::InResponse<'a>> {
|
fn control_in<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
req: embassy_usb::control::Request,
|
||||||
|
buf: &'a mut [u8],
|
||||||
|
) -> Option<embassy_usb::control::InResponse<'a>> {
|
||||||
if (req.request_type, req.recipient) != (RequestType::Class, Recipient::Interface) {
|
if (req.request_type, req.recipient) != (RequestType::Class, Recipient::Interface) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -72,7 +92,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> Handler for Control<'d, DFU, STATE> {
|
|||||||
buf[0..6].copy_from_slice(&[Status::Ok as u8, 0x32, 0x00, 0x00, self.state as u8, 0x00]);
|
buf[0..6].copy_from_slice(&[Status::Ok as u8, 0x32, 0x00, 0x00, self.state as u8, 0x00]);
|
||||||
Some(InResponse::Accepted(buf))
|
Some(InResponse::Accepted(buf))
|
||||||
}
|
}
|
||||||
_ => None
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,17 +106,16 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> Handler for Control<'d, DFU, STATE> {
|
|||||||
/// it should expose a DFU device, and a software reset will be issued.
|
/// it should expose a DFU device, and a software reset will be issued.
|
||||||
///
|
///
|
||||||
/// 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.
|
/// 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.
|
||||||
pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash>(builder: &mut Builder<'d, D>, handler: &'d mut Control<'d, DFU, STATE>, timeout: Duration) {
|
pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash>(
|
||||||
|
builder: &mut Builder<'d, D>,
|
||||||
|
handler: &'d mut Control<'d, DFU, STATE>,
|
||||||
|
timeout: Duration,
|
||||||
|
) {
|
||||||
#[cfg(feature = "defmt")]
|
#[cfg(feature = "defmt")]
|
||||||
defmt::info!("Application USB DFU initializing");
|
defmt::info!("Application USB DFU initializing");
|
||||||
let mut func = builder.function(0x00, 0x00, 0x00);
|
let mut func = builder.function(0x00, 0x00, 0x00);
|
||||||
let mut iface = func.interface();
|
let mut iface = func.interface();
|
||||||
let mut alt = iface.alt_setting(
|
let mut alt = iface.alt_setting(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_RT, None);
|
||||||
USB_CLASS_APPN_SPEC,
|
|
||||||
APPN_SPEC_SUBCLASS_DFU,
|
|
||||||
DFU_PROTOCOL_RT,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
let timeout = timeout.as_millis() as u16;
|
let timeout = timeout.as_millis() as u16;
|
||||||
alt.descriptor(
|
alt.descriptor(
|
||||||
DESC_DFU_FUNCTIONAL,
|
DESC_DFU_FUNCTIONAL,
|
||||||
@ -104,8 +123,10 @@ pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash>(builder: &mut
|
|||||||
handler.attrs.bits(),
|
handler.attrs.bits(),
|
||||||
(timeout & 0xff) as u8,
|
(timeout & 0xff) as u8,
|
||||||
((timeout >> 8) & 0xff) as u8,
|
((timeout >> 8) & 0xff) as u8,
|
||||||
0x40, 0x00, // 64B control buffer size for application side
|
0x40,
|
||||||
0x10, 0x01, // DFU 1.1
|
0x00, // 64B control buffer size for application side
|
||||||
|
0x10,
|
||||||
|
0x01, // DFU 1.1
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
use embassy_boot::BlockingFirmwareUpdater;
|
use embassy_boot::BlockingFirmwareUpdater;
|
||||||
use embassy_usb::{
|
use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType};
|
||||||
control::{InResponse, OutResponse, Recipient, RequestType},
|
use embassy_usb::driver::Driver;
|
||||||
driver::Driver,
|
use embassy_usb::{Builder, Handler};
|
||||||
Builder, Handler,
|
use embedded_storage::nor_flash::{NorFlash, NorFlashErrorKind};
|
||||||
};
|
|
||||||
use embedded_storage::nor_flash::{NorFlashErrorKind, NorFlash};
|
|
||||||
|
|
||||||
use crate::consts::{DfuAttributes, Request, State, Status, USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_DFU, DESC_DFU_FUNCTIONAL};
|
use crate::consts::{
|
||||||
|
DfuAttributes, Request, State, Status, APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_DFU,
|
||||||
|
USB_CLASS_APPN_SPEC,
|
||||||
|
};
|
||||||
|
|
||||||
/// Internal state for USB DFU
|
/// Internal state for USB DFU
|
||||||
pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> {
|
pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> {
|
||||||
@ -69,17 +70,11 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Handler for Co
|
|||||||
match e {
|
match e {
|
||||||
embassy_boot::FirmwareUpdaterError::Flash(e) => match e {
|
embassy_boot::FirmwareUpdaterError::Flash(e) => match e {
|
||||||
NorFlashErrorKind::NotAligned => self.status = Status::ErrWrite,
|
NorFlashErrorKind::NotAligned => self.status = Status::ErrWrite,
|
||||||
NorFlashErrorKind::OutOfBounds => {
|
NorFlashErrorKind::OutOfBounds => self.status = Status::ErrAddress,
|
||||||
self.status = Status::ErrAddress
|
|
||||||
}
|
|
||||||
_ => self.status = Status::ErrUnknown,
|
_ => self.status = Status::ErrUnknown,
|
||||||
},
|
},
|
||||||
embassy_boot::FirmwareUpdaterError::Signature(_) => {
|
embassy_boot::FirmwareUpdaterError::Signature(_) => self.status = Status::ErrVerify,
|
||||||
self.status = Status::ErrVerify
|
embassy_boot::FirmwareUpdaterError::BadState => self.status = Status::ErrUnknown,
|
||||||
}
|
|
||||||
embassy_boot::FirmwareUpdaterError::BadState => {
|
|
||||||
self.status = Status::ErrUnknown
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -101,17 +96,11 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, const BLOCK_SIZE: usize> Handler for Co
|
|||||||
match e {
|
match e {
|
||||||
embassy_boot::FirmwareUpdaterError::Flash(e) => match e {
|
embassy_boot::FirmwareUpdaterError::Flash(e) => match e {
|
||||||
NorFlashErrorKind::NotAligned => self.status = Status::ErrWrite,
|
NorFlashErrorKind::NotAligned => self.status = Status::ErrWrite,
|
||||||
NorFlashErrorKind::OutOfBounds => {
|
NorFlashErrorKind::OutOfBounds => self.status = Status::ErrAddress,
|
||||||
self.status = Status::ErrAddress
|
|
||||||
}
|
|
||||||
_ => self.status = Status::ErrUnknown,
|
_ => self.status = Status::ErrUnknown,
|
||||||
},
|
},
|
||||||
embassy_boot::FirmwareUpdaterError::Signature(_) => {
|
embassy_boot::FirmwareUpdaterError::Signature(_) => self.status = Status::ErrVerify,
|
||||||
self.status = Status::ErrVerify
|
embassy_boot::FirmwareUpdaterError::BadState => self.status = Status::ErrUnknown,
|
||||||
}
|
|
||||||
embassy_boot::FirmwareUpdaterError::BadState => {
|
|
||||||
self.status = Status::ErrUnknown
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,20 +163,17 @@ pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash, const BLOCK_SI
|
|||||||
) {
|
) {
|
||||||
let mut func = builder.function(0x00, 0x00, 0x00);
|
let mut func = builder.function(0x00, 0x00, 0x00);
|
||||||
let mut iface = func.interface();
|
let mut iface = func.interface();
|
||||||
let mut alt = iface.alt_setting(
|
let mut alt = iface.alt_setting(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_DFU, None);
|
||||||
USB_CLASS_APPN_SPEC,
|
|
||||||
APPN_SPEC_SUBCLASS_DFU,
|
|
||||||
DFU_PROTOCOL_DFU,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
alt.descriptor(
|
alt.descriptor(
|
||||||
DESC_DFU_FUNCTIONAL,
|
DESC_DFU_FUNCTIONAL,
|
||||||
&[
|
&[
|
||||||
handler.attrs.bits(),
|
handler.attrs.bits(),
|
||||||
0xc4, 0x09, // 2500ms timeout, doesn't affect operation as DETACH not necessary in bootloader code
|
0xc4,
|
||||||
|
0x09, // 2500ms timeout, doesn't affect operation as DETACH not necessary in bootloader code
|
||||||
(BLOCK_SIZE & 0xff) as u8,
|
(BLOCK_SIZE & 0xff) as u8,
|
||||||
((BLOCK_SIZE & 0xff00) >> 8) as u8,
|
((BLOCK_SIZE & 0xff00) >> 8) as u8,
|
||||||
0x10, 0x01, // DFU 1.1
|
0x10,
|
||||||
|
0x01, // DFU 1.1
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
pub(crate) const USB_CLASS_APPN_SPEC: u8 = 0xFE;
|
pub(crate) const USB_CLASS_APPN_SPEC: u8 = 0xFE;
|
||||||
pub(crate) const APPN_SPEC_SUBCLASS_DFU: u8 = 0x01;
|
pub(crate) const APPN_SPEC_SUBCLASS_DFU: u8 = 0x01;
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
@ -12,5 +12,8 @@ mod application;
|
|||||||
#[cfg(feature = "application")]
|
#[cfg(feature = "application")]
|
||||||
pub use self::application::*;
|
pub use self::application::*;
|
||||||
|
|
||||||
#[cfg(any(all(feature = "bootloader", feature = "application"), not(any(feature = "bootloader", feature = "application"))))]
|
#[cfg(any(
|
||||||
|
all(feature = "bootloader", feature = "application"),
|
||||||
|
not(any(feature = "bootloader", feature = "application"))
|
||||||
|
))]
|
||||||
compile_error!("usb-dfu must be compiled with exactly one of `bootloader`, or `application` features");
|
compile_error!("usb-dfu must be compiled with exactly one of `bootloader`, or `application` features");
|
||||||
|
Loading…
Reference in New Issue
Block a user