aboutsummaryrefslogtreecommitdiff
path: root/embassy-usb-dfu
diff options
context:
space:
mode:
authorGerhard de Clercq <[email protected]>2024-12-02 11:04:17 +0100
committerGerhard de Clercq <[email protected]>2024-12-02 11:04:17 +0100
commited1f44e58bb38fa1c490f0094400b673bd4bccc3 (patch)
tree16f32c6169aa3940a194f07d01c853d49e2f383d /embassy-usb-dfu
parentc73a4d397d69541e5f0a3dde005afe60ba16fe05 (diff)
embassy-dfu-usb: Improve debuggability
This commit adds logging to embassy-dfu-usb which helps with debugging issues such as https://github.com/embassy-rs/embassy/issues/3536. It also cleans up a few repeated code blocks and avoid re-initialising the local buffer for every iteration.
Diffstat (limited to 'embassy-usb-dfu')
-rw-r--r--embassy-usb-dfu/Cargo.toml2
-rw-r--r--embassy-usb-dfu/src/consts.rs41
-rw-r--r--embassy-usb-dfu/src/dfu.rs78
3 files changed, 70 insertions, 51 deletions
diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml
index 16da468bd..763c9600d 100644
--- a/embassy-usb-dfu/Cargo.toml
+++ b/embassy-usb-dfu/Cargo.toml
@@ -42,4 +42,4 @@ esp32c3-hal = { version = "0.13.0", optional = true, default-features = false }
42[features] 42[features]
43dfu = [] 43dfu = []
44application = [] 44application = []
45defmt = ["dep:defmt"] 45defmt = ["dep:defmt", "embassy-boot/defmt", "embassy-usb/defmt"]
diff --git a/embassy-usb-dfu/src/consts.rs b/embassy-usb-dfu/src/consts.rs
index f8a056e5c..190b5ad5a 100644
--- a/embassy-usb-dfu/src/consts.rs
+++ b/embassy-usb-dfu/src/consts.rs
@@ -7,30 +7,29 @@ pub(crate) const DFU_PROTOCOL_DFU: u8 = 0x02;
7pub(crate) const DFU_PROTOCOL_RT: u8 = 0x01; 7pub(crate) const DFU_PROTOCOL_RT: u8 = 0x01;
8pub(crate) const DESC_DFU_FUNCTIONAL: u8 = 0x21; 8pub(crate) const DESC_DFU_FUNCTIONAL: u8 = 0x21;
9 9
10#[cfg(feature = "defmt")] 10macro_rules! define_dfu_attributes {
11defmt::bitflags! { 11 ($macro:path) => {
12 pub struct DfuAttributes: u8 { 12 $macro! {
13 const WILL_DETACH = 0b0000_1000; 13 /// Attributes supported by the DFU controller.
14 const MANIFESTATION_TOLERANT = 0b0000_0100; 14 pub struct DfuAttributes: u8 {
15 const CAN_UPLOAD = 0b0000_0010; 15 /// Generate WillDetache sequence on bus.
16 const CAN_DOWNLOAD = 0b0000_0001; 16 const WILL_DETACH = 0b0000_1000;
17 } 17 /// Device can communicate during manifestation phase.
18 const MANIFESTATION_TOLERANT = 0b0000_0100;
19 /// Capable of upload.
20 const CAN_UPLOAD = 0b0000_0010;
21 /// Capable of download.
22 const CAN_DOWNLOAD = 0b0000_0001;
23 }
24 }
25 };
18} 26}
19 27
28#[cfg(feature = "defmt")]
29define_dfu_attributes!(defmt::bitflags);
30
20#[cfg(not(feature = "defmt"))] 31#[cfg(not(feature = "defmt"))]
21bitflags::bitflags! { 32define_dfu_attributes!(bitflags::bitflags);
22 /// Attributes supported by the DFU controller.
23 pub struct DfuAttributes: u8 {
24 /// Generate WillDetache sequence on bus.
25 const WILL_DETACH = 0b0000_1000;
26 /// Device can communicate during manifestation phase.
27 const MANIFESTATION_TOLERANT = 0b0000_0100;
28 /// Capable of upload.
29 const CAN_UPLOAD = 0b0000_0010;
30 /// Capable of download.
31 const CAN_DOWNLOAD = 0b0000_0001;
32 }
33}
34 33
35#[derive(Copy, Clone, PartialEq, Eq)] 34#[derive(Copy, Clone, PartialEq, Eq)]
36#[repr(u8)] 35#[repr(u8)]
diff --git a/embassy-usb-dfu/src/dfu.rs b/embassy-usb-dfu/src/dfu.rs
index e99aa70c3..abd929a9e 100644
--- a/embassy-usb-dfu/src/dfu.rs
+++ b/embassy-usb-dfu/src/dfu.rs
@@ -1,6 +1,6 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2 2
3use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater}; 3use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterError};
4use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; 4use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType};
5use embassy_usb::driver::Driver; 5use embassy_usb::driver::Driver;
6use embassy_usb::{Builder, Handler}; 6use embassy_usb::{Builder, Handler};
@@ -19,6 +19,7 @@ pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_S
19 state: State, 19 state: State,
20 status: Status, 20 status: Status,
21 offset: usize, 21 offset: usize,
22 buf: AlignedBuffer<BLOCK_SIZE>,
22 _rst: PhantomData<RST>, 23 _rst: PhantomData<RST>,
23} 24}
24 25
@@ -31,6 +32,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Co
31 state: State::DfuIdle, 32 state: State::DfuIdle,
32 status: Status::Ok, 33 status: Status::Ok,
33 offset: 0, 34 offset: 0,
35 buf: AlignedBuffer([0; BLOCK_SIZE]),
34 _rst: PhantomData, 36 _rst: PhantomData,
35 } 37 }
36 } 38 }
@@ -42,6 +44,20 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Co
42 } 44 }
43} 45}
44 46
47impl From<FirmwareUpdaterError> for Status {
48 fn from(e: FirmwareUpdaterError) -> Self {
49 match e {
50 FirmwareUpdaterError::Flash(e) => match e {
51 NorFlashErrorKind::NotAligned => Status::ErrWrite,
52 NorFlashErrorKind::OutOfBounds => Status::ErrAddress,
53 _ => Status::ErrUnknown,
54 },
55 FirmwareUpdaterError::Signature(_) => Status::ErrVerify,
56 FirmwareUpdaterError::BadState => Status::ErrUnknown,
57 }
58 }
59}
60
45impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Handler 61impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Handler
46 for Control<'d, DFU, STATE, RST, BLOCK_SIZE> 62 for Control<'d, DFU, STATE, RST, BLOCK_SIZE>
47{ 63{
@@ -51,65 +67,67 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Ha
51 data: &[u8], 67 data: &[u8],
52 ) -> Option<embassy_usb::control::OutResponse> { 68 ) -> Option<embassy_usb::control::OutResponse> {
53 if (req.request_type, req.recipient) != (RequestType::Class, Recipient::Interface) { 69 if (req.request_type, req.recipient) != (RequestType::Class, Recipient::Interface) {
70 debug!("Unknown out request: {:?}", req);
54 return None; 71 return None;
55 } 72 }
56 match Request::try_from(req.request) { 73 match Request::try_from(req.request) {
57 Ok(Request::Abort) => { 74 Ok(Request::Abort) => {
75 info!("Abort requested");
58 self.reset_state(); 76 self.reset_state();
59 Some(OutResponse::Accepted) 77 Some(OutResponse::Accepted)
60 } 78 }
61 Ok(Request::Dnload) if self.attrs.contains(DfuAttributes::CAN_DOWNLOAD) => { 79 Ok(Request::Dnload) if self.attrs.contains(DfuAttributes::CAN_DOWNLOAD) => {
62 if req.value == 0 { 80 if req.value == 0 {
81 info!("Download starting");
63 self.state = State::Download; 82 self.state = State::Download;
64 self.offset = 0; 83 self.offset = 0;
65 } 84 }
66 85
67 let mut buf = AlignedBuffer([0; BLOCK_SIZE]); 86 if self.state != State::Download {
68 buf.as_mut()[..data.len()].copy_from_slice(data); 87 error!("Unexpected DNLOAD while chip is waiting for a GETSTATUS");
88 self.status = Status::ErrUnknown;
89 self.state = State::Error;
90 return Some(OutResponse::Rejected);
91 }
92
93 if data.len() > BLOCK_SIZE {
94 error!("USB data len exceeded block size");
95 self.status = Status::ErrUnknown;
96 self.state = State::Error;
97 return Some(OutResponse::Rejected);
98 }
99
100 debug!("Copying {} bytes to buffer", data.len());
101 self.buf.as_mut()[..data.len()].copy_from_slice(data);
102
103 let final_transfer = req.length == 0;
104 if final_transfer {
105 debug!("Receiving final transfer");
69 106
70 if req.length == 0 {
71 match self.updater.mark_updated() { 107 match self.updater.mark_updated() {
72 Ok(_) => { 108 Ok(_) => {
73 self.status = Status::Ok; 109 self.status = Status::Ok;
74 self.state = State::ManifestSync; 110 self.state = State::ManifestSync;
111 info!("Update complete");
75 } 112 }
76 Err(e) => { 113 Err(e) => {
114 error!("Error completing update: {}", e);
77 self.state = State::Error; 115 self.state = State::Error;
78 match e { 116 self.status = e.into();
79 embassy_boot::FirmwareUpdaterError::Flash(e) => match e {
80 NorFlashErrorKind::NotAligned => self.status = Status::ErrWrite,
81 NorFlashErrorKind::OutOfBounds => self.status = Status::ErrAddress,
82 _ => self.status = Status::ErrUnknown,
83 },
84 embassy_boot::FirmwareUpdaterError::Signature(_) => self.status = Status::ErrVerify,
85 embassy_boot::FirmwareUpdaterError::BadState => self.status = Status::ErrUnknown,
86 }
87 } 117 }
88 } 118 }
89 } else { 119 } else {
90 if self.state != State::Download { 120 debug!("Writing {} bytes at {}", data.len(), self.offset);
91 // Unexpected DNLOAD while chip is waiting for a GETSTATUS 121 match self.updater.write_firmware(self.offset, self.buf.as_ref()) {
92 self.status = Status::ErrUnknown;
93 self.state = State::Error;
94 return Some(OutResponse::Rejected);
95 }
96 match self.updater.write_firmware(self.offset, buf.as_ref()) {
97 Ok(_) => { 122 Ok(_) => {
98 self.status = Status::Ok; 123 self.status = Status::Ok;
99 self.state = State::DlSync; 124 self.state = State::DlSync;
100 self.offset += data.len(); 125 self.offset += data.len();
101 } 126 }
102 Err(e) => { 127 Err(e) => {
128 error!("Error writing firmware: {:?}", e);
103 self.state = State::Error; 129 self.state = State::Error;
104 match e { 130 self.status = e.into();
105 embassy_boot::FirmwareUpdaterError::Flash(e) => match e {
106 NorFlashErrorKind::NotAligned => self.status = Status::ErrWrite,
107 NorFlashErrorKind::OutOfBounds => self.status = Status::ErrAddress,
108 _ => self.status = Status::ErrUnknown,
109 },
110 embassy_boot::FirmwareUpdaterError::Signature(_) => self.status = Status::ErrVerify,
111 embassy_boot::FirmwareUpdaterError::BadState => self.status = Status::ErrUnknown,
112 }
113 } 131 }
114 } 132 }
115 } 133 }
@@ -118,6 +136,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Ha
118 } 136 }
119 Ok(Request::Detach) => Some(OutResponse::Accepted), // Device is already in DFU mode 137 Ok(Request::Detach) => Some(OutResponse::Accepted), // Device is already in DFU mode
120 Ok(Request::ClrStatus) => { 138 Ok(Request::ClrStatus) => {
139 info!("Clear status requested");
121 self.reset_state(); 140 self.reset_state();
122 Some(OutResponse::Accepted) 141 Some(OutResponse::Accepted)
123 } 142 }
@@ -131,6 +150,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Ha
131 buf: &'a mut [u8], 150 buf: &'a mut [u8],
132 ) -> Option<embassy_usb::control::InResponse<'a>> { 151 ) -> Option<embassy_usb::control::InResponse<'a>> {
133 if (req.request_type, req.recipient) != (RequestType::Class, Recipient::Interface) { 152 if (req.request_type, req.recipient) != (RequestType::Class, Recipient::Interface) {
153 debug!("Unknown in request: {:?}", req);
134 return None; 154 return None;
135 } 155 }
136 match Request::try_from(req.request) { 156 match Request::try_from(req.request) {