Skip to content

Commit 7a62066

Browse files
authored
Merge pull request #4107 from bugadani/cmsisdap
Add CMSIS-DAP driver
2 parents fce0602 + b0eacf0 commit 7a62066

File tree

2 files changed

+129
-0
lines changed

2 files changed

+129
-0
lines changed

embassy-usb/src/class/cmsis_dap_v2.rs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
//! CMSIS-DAP V2 class implementation.
2+
3+
use core::mem::MaybeUninit;
4+
5+
use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
6+
use crate::types::StringIndex;
7+
use crate::{msos, Builder, Handler};
8+
9+
/// State for the CMSIS-DAP v2 USB class.
10+
pub struct State {
11+
control: MaybeUninit<Control>,
12+
}
13+
14+
struct Control {
15+
iface_string: StringIndex,
16+
}
17+
18+
impl Handler for Control {
19+
fn get_string(&mut self, index: StringIndex, _lang_id: u16) -> Option<&str> {
20+
if index == self.iface_string {
21+
Some("CMSIS-DAP v2 Interface")
22+
} else {
23+
warn!("unknown string index requested");
24+
None
25+
}
26+
}
27+
}
28+
29+
impl State {
30+
/// Create a new `State`.
31+
pub const fn new() -> Self {
32+
Self {
33+
control: MaybeUninit::uninit(),
34+
}
35+
}
36+
}
37+
38+
/// USB device class for CMSIS-DAP v2 probes.
39+
pub struct CmsisDapV2Class<'d, D: Driver<'d>> {
40+
read_ep: D::EndpointOut,
41+
write_ep: D::EndpointIn,
42+
trace_ep: Option<D::EndpointIn>,
43+
max_packet_size: u16,
44+
}
45+
46+
impl<'d, D: Driver<'d>> CmsisDapV2Class<'d, D> {
47+
/// Creates a new CmsisDapV2Class with the provided UsbBus and `max_packet_size` in bytes. For
48+
/// full-speed devices, `max_packet_size` has to be 64.
49+
///
50+
/// The `trace` parameter enables the trace output endpoint. This is optional and can be
51+
/// disabled if the probe does not support trace output.
52+
pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State, max_packet_size: u16, trace: bool) -> Self {
53+
// DAP - Custom Class 0
54+
let iface_string = builder.string();
55+
let mut function = builder.function(0xFF, 0, 0);
56+
function.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
57+
function.msos_feature(msos::RegistryPropertyFeatureDescriptor::new(
58+
"DeviceInterfaceGUIDs",
59+
// CMSIS-DAP standard GUID, from https://arm-software.github.io/CMSIS_5/DAP/html/group__DAP__ConfigUSB__gr.html
60+
msos::PropertyData::RegMultiSz(&["{CDB3B5AD-293B-4663-AA36-1AAE46463776}"]),
61+
));
62+
let mut interface = function.interface();
63+
let mut alt = interface.alt_setting(0xFF, 0, 0, Some(iface_string));
64+
let read_ep = alt.endpoint_bulk_out(max_packet_size);
65+
let write_ep = alt.endpoint_bulk_in(max_packet_size);
66+
let trace_ep = if trace {
67+
Some(alt.endpoint_bulk_in(max_packet_size))
68+
} else {
69+
None
70+
};
71+
drop(function);
72+
73+
builder.handler(state.control.write(Control { iface_string }));
74+
75+
CmsisDapV2Class {
76+
read_ep,
77+
write_ep,
78+
trace_ep,
79+
max_packet_size,
80+
}
81+
}
82+
83+
/// Waits for the USB host to enable this interface
84+
pub async fn wait_connection(&mut self) {
85+
self.read_ep.wait_enabled().await;
86+
}
87+
88+
/// Write data to the host.
89+
pub async fn write_packet(&mut self, data: &[u8]) -> Result<(), EndpointError> {
90+
for chunk in data.chunks(self.max_packet_size as usize) {
91+
self.write_ep.write(chunk).await?;
92+
}
93+
if data.len() % self.max_packet_size as usize == 0 {
94+
self.write_ep.write(&[]).await?;
95+
}
96+
Ok(())
97+
}
98+
99+
/// Write data to the host via the trace output endpoint.
100+
///
101+
/// Returns `EndpointError::Disabled` if the trace output endpoint is not enabled.
102+
pub async fn write_trace(&mut self, data: &[u8]) -> Result<(), EndpointError> {
103+
let Some(ep) = self.trace_ep.as_mut() else {
104+
return Err(EndpointError::Disabled);
105+
};
106+
107+
for chunk in data.chunks(self.max_packet_size as usize) {
108+
ep.write(chunk).await?;
109+
}
110+
if data.len() % self.max_packet_size as usize == 0 {
111+
ep.write(&[]).await?;
112+
}
113+
Ok(())
114+
}
115+
116+
/// Read data from the host.
117+
pub async fn read_packet(&mut self, data: &mut [u8]) -> Result<usize, EndpointError> {
118+
let mut n = 0;
119+
120+
loop {
121+
let i = self.read_ep.read(&mut data[n..]).await?;
122+
n += i;
123+
if i < self.max_packet_size as usize {
124+
return Ok(n);
125+
}
126+
}
127+
}
128+
}

embassy-usb/src/class/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Implementations of well-known USB classes.
22
pub mod cdc_acm;
33
pub mod cdc_ncm;
4+
pub mod cmsis_dap_v2;
45
pub mod hid;
56
pub mod midi;
67
pub mod uac1;

0 commit comments

Comments
 (0)