diff --git a/src/dap.rs b/src/dap.rs index 5bffa2c..ed7aaa2 100644 --- a/src/dap.rs +++ b/src/dap.rs @@ -9,6 +9,7 @@ mod request; mod response; mod state; +use bitflags::bitflags; pub use command::*; pub use request::*; pub use response::*; @@ -35,13 +36,26 @@ pub struct TransferConfig { pub match_mask: u32, } +bitflags! { + struct Capabilities: u8 { + const SWD = 0x01; + const JTAG = 0x02; + const SWO_UART = 0x04; + const SWO_MANCHESTER = 0x08; + const ATOMIC_COMMANDS = 0x10; + const TEST_DOMAIN_TIMER = 0x20; + const SWO_STREAMING = 0x40; + } +} + /// DAP handler. pub struct Dap<'a, DEPS, LEDS, WAIT, JTAG, SWD, SWO> { state: State, - swo: Option, + swo: SWO, swo_streaming: bool, version_string: &'a str, transfer_config: TransferConfig, + capabilities: Capabilities, // mode: Option, leds: LEDS, wait: WAIT, @@ -61,11 +75,38 @@ where dependencies: DEPS, leds: LEDS, wait: WAIT, - swo: Option, + swo: SWO, version_string: &'a str, ) -> Self { - // TODO: Replace with const assert - assert!(SWD::AVAILABLE || JTAG::AVAILABLE); + assert!(SWD::available(&dependencies) || JTAG::available(&dependencies)); + + let capabilities = { + let mut caps = Capabilities::empty(); + + // Bit 0: SWD optional + if SWD::available(&dependencies) { + caps.insert(Capabilities::SWD); + } + // Bit 1: JTAG optional + if JTAG::available(&dependencies) { + caps.insert(Capabilities::JTAG); + } + // Bit 2: SWO UART optional + // Bit 3: SWO Manchester optional + if swo.support().uart { + caps.insert(Capabilities::SWO_UART); + } + if swo.support().manchester { + caps.insert(Capabilities::SWO_MANCHESTER); + } + // Bit 4: Atomic commands not supported + // Bit 5: Test Domain Timer not supported + // Bit 6: SWO Streaming Trace optional + if swo.support().streaming { + caps.insert(Capabilities::SWO_STREAMING); + } + caps + }; Dap { state: State::new(dependencies), @@ -81,6 +122,7 @@ where // mode: None, leds, wait, + capabilities, } } @@ -152,7 +194,7 @@ where } } - fn process_info(&mut self, mut req: Request, resp: &mut ResponseWriter, version: DapVersion) { + fn process_info(&self, mut req: Request, resp: &mut ResponseWriter, version: DapVersion) { match DapInfoID::try_from(req.next_u8()) { // Return 0-length string for VendorID, ProductID, SerialNumber // to indicate they should be read from USB descriptor instead @@ -170,33 +212,11 @@ where Ok(DapInfoID::TargetName) => resp.write_u8(0), Ok(DapInfoID::Capabilities) => { resp.write_u8(1); - // Bit 0: SWD supported - // Bit 1: JTAG supported - // Bit 2: SWO UART supported - // Bit 3: SWO Manchester not supported - // Bit 4: Atomic commands not supported - // Bit 5: Test Domain Timer not supported - // Bit 6: SWO Streaming Trace supported - let swd = (SWD::AVAILABLE as u8) << 0; - let jtag = (JTAG::AVAILABLE as u8) << 1; - let swo = match &self.swo { - Some(swo) => { - let support = swo.support(); - (support.uart as u8) << 2 | (support.manchester as u8) << 3 - } - None => 0, - }; - let atomic = 0 << 4; - let swo_streaming = 1 << 6; - resp.write_u8(swd | jtag | swo | atomic | swo_streaming); + resp.write_u8(self.capabilities.bits); } Ok(DapInfoID::SWOTraceBufferSize) => { resp.write_u8(4); - let size = match &self.swo { - Some(swo) => swo.buffer_size(), - None => 0, - }; - resp.write_u32(size as u32); + resp.write_u32(self.swo.buffer_size()); } Ok(DapInfoID::MaxPacketCount) => { resp.write_u8(1); @@ -249,11 +269,15 @@ where info!( "DAP connect: {}, SWD: {}, JTAG: {}", port, - SWD::AVAILABLE, - JTAG::AVAILABLE + self.capabilities.contains(Capabilities::SWD), + self.capabilities.contains(Capabilities::JTAG), ); - match (SWD::AVAILABLE, JTAG::AVAILABLE, port) { + match ( + self.capabilities.contains(Capabilities::SWD), + self.capabilities.contains(Capabilities::JTAG), + port, + ) { // SWD (true, true, ConnectPort::Default) | (true, true, ConnectPort::SWD) @@ -298,8 +322,8 @@ where let idx = req.next_u8(); let word = req.next_u32(); - match (SWD::AVAILABLE, JTAG::AVAILABLE, &mut self.state) { - (_, true, State::Jtag(jtag)) => { + match &mut self.state { + State::Jtag(jtag) => { let config = jtag.config(); if !config.select_index(idx) { resp.write_err(); @@ -311,16 +335,14 @@ where resp.write_ok(); } - (true, _, State::Swd(swd)) => { + State::Swd(swd) => { let wait_retries = self.transfer_config.wait_retries; match swd.write_dp(wait_retries, swd::DPRegister::DPIDR, word) { Ok(_) => resp.write_ok(), Err(_) => resp.write_err(), } } - _ => { - resp.write_err(); - } + _ => resp.write_err(), } } @@ -470,48 +492,34 @@ where } fn process_swo_mode(&mut self, mut req: Request, resp: &mut ResponseWriter) { - let mode = req.next_u8(); + let success = match swo::SwoMode::try_from(req.next_u8()) { + Ok(mode) => self.swo.set_mode(mode), + _ => false, + }; - let swo = if let Some(swo) = &mut self.swo { - swo + if success { + resp.write_ok(); } else { resp.write_err(); - return; - }; - - match swo::SwoMode::try_from(mode) { - Ok(mode) => { - swo.set_mode(mode); - resp.write_ok(); - } - _ => resp.write_err(), } } fn process_swo_baudrate(&mut self, mut req: Request, resp: &mut ResponseWriter) { let target = req.next_u32(); - let actual = if let Some(swo) = &mut self.swo { - swo.set_baudrate(target) - } else { - 0 - }; + let actual = self.swo.set_baudrate(target); resp.write_u32(actual); } fn process_swo_control(&mut self, mut req: Request, resp: &mut ResponseWriter) { - let swo = if let Some(swo) = &mut self.swo { - swo - } else { - resp.write_err(); - return; + let success = match swo::SwoControl::try_from(req.next_u8()) { + Ok(control) => self.swo.set_control(control), + _ => false, }; - match swo::SwoControl::try_from(req.next_u8()) { - Ok(control) => { - swo.set_control(control); - resp.write_ok(); - } - _ => resp.write_err(), + if success { + resp.write_ok(); + } else { + resp.write_err(); } } @@ -520,11 +528,7 @@ where // Bit 0: trace capture active // Bit 6: trace stream error (always written as 0) // Bit 7: trace buffer overflow (always written as 0) - let (active, len) = if let Some(swo) = &self.swo { - (swo.is_active(), swo.bytes_available()) - } else { - (false, 0) - }; + let (active, len) = (self.swo.is_active(), self.swo.bytes_available()); resp.write_u8(active as u8); // Trace count: remaining bytes in buffer @@ -536,11 +540,8 @@ where // Bit 0: trace capture active // Bit 6: trace stream error (always written as 0) // Bit 7: trace buffer overflow (always written as 0) - let (active, len) = if let Some(swo) = &self.swo { - (swo.is_active(), swo.bytes_available()) - } else { - (false, 0) - }; + let (active, len) = (self.swo.is_active(), self.swo.bytes_available()); + resp.write_u8(active as u8); // Trace count: remaining bytes in buffer. resp.write_u32(len); @@ -551,11 +552,7 @@ where } fn process_swo_data(&mut self, mut req: Request, resp: &mut ResponseWriter) { - let active = if let Some(swo) = &mut self.swo { - swo.is_active() - } else { - false - }; + let active = self.swo.is_active(); // Write status byte to response resp.write_u8(active as u8); @@ -572,11 +569,7 @@ where } // Read data from UART - let len = if let Some(swo) = &mut self.swo { - swo.polling_data(&mut buf) - } else { - 0 - }; + let len = self.swo.polling_data(&mut buf); resp.skip(len as _); // Go back and write length @@ -1261,7 +1254,7 @@ fn transfer_with_retry( #[cfg(test)] mod test { use super::*; - use crate::mock_device::*; + use crate::{mock_device::*, swo::NoSwo}; use mockall::predicate::*; struct FakeLEDs {} @@ -1283,7 +1276,7 @@ mod test { StdDelayUs, MockSwdJtagDevice, MockSwdJtagDevice, - swo::MockSwo, + NoSwo, >; #[test] @@ -1292,7 +1285,7 @@ mod test { MockSwdJtagDevice::new(), FakeLEDs {}, StdDelayUs {}, - None, + NoSwo, "test_dap", ); @@ -1319,7 +1312,7 @@ mod test { MockSwdJtagDevice::new(), FakeLEDs {}, StdDelayUs {}, - None, + NoSwo, "test_dap", ); @@ -1349,7 +1342,7 @@ mod test { MockSwdJtagDevice::new(), FakeLEDs {}, StdDelayUs {}, - None, + NoSwo, "test_dap", ); @@ -1382,7 +1375,7 @@ mod test { MockSwdJtagDevice::new(), FakeLEDs {}, StdDelayUs {}, - None, + NoSwo, "test_dap", ); @@ -1416,7 +1409,7 @@ mod test { MockSwdJtagDevice::new(), FakeLEDs {}, StdDelayUs {}, - None, + NoSwo, "test_dap", ); diff --git a/src/jtag.rs b/src/jtag.rs index 157407e..31c1a7d 100644 --- a/src/jtag.rs +++ b/src/jtag.rs @@ -183,8 +183,8 @@ const DAP_TRANSFER_OK_FAULT: u32 = 0x02; /// JTAG interface. pub trait Jtag: From { - /// If JTAG is available or not. - const AVAILABLE: bool; + /// Returns whether JTAG is available or not. + fn available(deps: &DEPS) -> bool; /// Returns a mutable reference to the JTAG interface configuration. fn config(&mut self) -> &mut Config; diff --git a/src/mock_device.rs b/src/mock_device.rs index cd8a3e3..3ffe130 100644 --- a/src/mock_device.rs +++ b/src/mock_device.rs @@ -51,7 +51,9 @@ impl swj::Dependencies for MockSwdJtagDevice { } impl swd::Swd for MockSwdJtagDevice { - const AVAILABLE: bool = true; + fn available(_: &Self) -> bool { + true + } fn set_clock(&mut self, max_frequency: u32) -> bool { SwdJtagDevice::set_clock(self, max_frequency) @@ -79,7 +81,9 @@ impl swd::Swd for MockSwdJtagDevice { } impl jtag::Jtag for MockSwdJtagDevice { - const AVAILABLE: bool = true; + fn available(_: &Self) -> bool { + true + } fn set_clock(&mut self, max_frequency: u32) -> bool { SwdJtagDevice::set_clock(self, max_frequency) diff --git a/src/swd.rs b/src/swd.rs index 602c7da..02f71c1 100644 --- a/src/swd.rs +++ b/src/swd.rs @@ -111,8 +111,8 @@ impl Default for Config { /// Definition of SWD communication. pub trait Swd: From { - /// If SWD is available or not. - const AVAILABLE: bool; + /// Returns whether SWD is available or not. + fn available(deps: &DEPS) -> bool; /// Returns a mutable reference to the SWD interface configuration. fn config(&mut self) -> &mut Config; diff --git a/src/swo.rs b/src/swo.rs index 2fd5a6f..c0f650b 100644 --- a/src/swo.rs +++ b/src/swo.rs @@ -29,8 +29,12 @@ pub enum SwoControl { #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct SwoSupport { + /// `true` if the UART encoding is supported. pub uart: bool, + /// `true` if the Manchester encoding is supported. pub manchester: bool, + /// `true` if the USB interface has a trace endpoint. + pub streaming: bool, } #[derive(Copy, Clone, Debug)] @@ -42,12 +46,11 @@ pub struct SwoStatus { pub bytes_available: u32, } -#[cfg_attr(test, mockall::automock)] pub trait Swo { - fn set_transport(&mut self, transport: SwoTransport); - fn set_mode(&mut self, mode: SwoMode); + fn set_transport(&mut self, transport: SwoTransport) -> bool; + fn set_mode(&mut self, mode: SwoMode) -> bool; fn set_baudrate(&mut self, baudrate: u32) -> u32; - fn set_control(&mut self, control: SwoControl); + fn set_control(&mut self, control: SwoControl) -> bool; fn polling_data(&mut self, buf: &mut [u8]) -> u32; fn streaming_data(&mut self); // -> SomeBufferFromStreaming; // TODO: What is a good interface? fn is_active(&self) -> bool; @@ -56,3 +59,49 @@ pub trait Swo { fn support(&self) -> SwoSupport; fn status(&mut self) -> SwoStatus; } + +/// Marker struct for no SWO support. +pub struct NoSwo; + +impl Swo for NoSwo { + fn set_transport(&mut self, _transport: SwoTransport) -> bool { + false + } + fn set_mode(&mut self, _mode: SwoMode) -> bool { + false + } + fn set_baudrate(&mut self, _baudrate: u32) -> u32 { + 0 + } + fn set_control(&mut self, _control: SwoControl) -> bool { + false + } + fn polling_data(&mut self, _buf: &mut [u8]) -> u32 { + 0 + } + fn streaming_data(&mut self) {} + fn is_active(&self) -> bool { + false + } + fn bytes_available(&self) -> u32 { + 0 + } + fn buffer_size(&self) -> u32 { + 0 + } + fn support(&self) -> SwoSupport { + SwoSupport { + uart: false, + manchester: false, + streaming: false, + } + } + fn status(&mut self) -> SwoStatus { + SwoStatus { + active: false, + trace_error: false, + trace_overrun: false, + bytes_available: 0, + } + } +}