1use core::convert::TryInto;
2use core::mem;
3use usb_device::class_prelude::*;
4use usb_device::descriptor::lang_id::LangID;
5use usb_device::device::DEFAULT_ALTERNATE_SETTING;
6use usb_device::Result;
7
8pub const USB_CLASS_CDC: u8 = 0x02;
10
11const USB_CLASS_CDC_DATA: u8 = 0x0a;
12const CDC_SUBCLASS_ACM: u8 = 0x02;
13const CDC_PROTOCOL_NONE: u8 = 0x00;
14
15const CS_INTERFACE: u8 = 0x24;
16const CDC_TYPE_HEADER: u8 = 0x00;
17const CDC_TYPE_CALL_MANAGEMENT: u8 = 0x01;
18const CDC_TYPE_ACM: u8 = 0x02;
19const CDC_TYPE_UNION: u8 = 0x06;
20
21const REQ_SEND_ENCAPSULATED_COMMAND: u8 = 0x00;
22#[allow(unused)]
23const REQ_GET_ENCAPSULATED_COMMAND: u8 = 0x01;
24const REQ_SET_LINE_CODING: u8 = 0x20;
25const REQ_GET_LINE_CODING: u8 = 0x21;
26const REQ_SET_CONTROL_LINE_STATE: u8 = 0x22;
27
28pub struct CdcAcmClass<'a, B: UsbBus> {
43 comm_if: InterfaceNumber,
44 comm_if_name: Option<(StringIndex, &'static str)>,
45 comm_ep: EndpointIn<'a, B>,
46 data_if: InterfaceNumber,
47 data_if_name: Option<(StringIndex, &'static str)>,
48 read_ep: EndpointOut<'a, B>,
49 write_ep: EndpointIn<'a, B>,
50 line_coding: LineCoding,
51 dtr: bool,
52 rts: bool,
53}
54
55impl<'a, B: UsbBus> CdcAcmClass<'a, B> {
56 pub fn new<'alloc: 'a>(
59 alloc: &'alloc UsbBusAllocator<B>,
60 max_packet_size: u16,
61 ) -> CdcAcmClass<'a, B> {
62 Self::new_with_interface_names(alloc, max_packet_size, None, None)
63 }
64
65 pub fn new_with_interface_names<'alloc: 'a>(
69 alloc: &'alloc UsbBusAllocator<B>,
70 max_packet_size: u16,
71 comm_if_name: Option<&'static str>,
72 data_if_name: Option<&'static str>,
73 ) -> CdcAcmClass<'a, B> {
74 let comm_if_name = comm_if_name.map(|s| (alloc.string(), s));
75 let data_if_name = data_if_name.map(|s| (alloc.string(), s));
76 CdcAcmClass {
77 comm_if: alloc.interface(),
78 comm_if_name,
79 comm_ep: alloc.interrupt(8, 255),
80 data_if: alloc.interface(),
81 data_if_name,
82 read_ep: alloc.bulk(max_packet_size),
83 write_ep: alloc.bulk(max_packet_size),
84 line_coding: LineCoding {
85 stop_bits: StopBits::One,
86 data_bits: 8,
87 parity_type: ParityType::None,
88 data_rate: 9_600,
89 },
90 dtr: false,
91 rts: false,
92 }
93 }
94
95 pub fn max_packet_size(&self) -> u16 {
97 self.read_ep.max_packet_size()
99 }
100
101 pub fn line_coding(&self) -> &LineCoding {
104 &self.line_coding
105 }
106
107 pub fn dtr(&self) -> bool {
109 self.dtr
110 }
111
112 pub fn rts(&self) -> bool {
114 self.rts
115 }
116
117 pub fn write_packet(&mut self, data: &[u8]) -> Result<usize> {
119 self.write_ep.write(data)
120 }
121
122 pub fn read_packet(&mut self, data: &mut [u8]) -> Result<usize> {
124 self.read_ep.read(data)
125 }
126
127 pub fn write_ep(&self) -> &EndpointIn<'a, B> {
129 &self.write_ep
130 }
131
132 pub fn write_ep_mut(&mut self) -> &mut EndpointIn<'a, B> {
134 &mut self.write_ep
135 }
136
137 pub fn read_ep(&self) -> &EndpointOut<'a, B> {
139 &self.read_ep
140 }
141
142 pub fn read_ep_mut(&mut self) -> &mut EndpointOut<'a, B> {
144 &mut self.read_ep
145 }
146}
147
148impl<B: UsbBus> UsbClass<B> for CdcAcmClass<'_, B> {
149 fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> {
150 writer.iad(
151 self.comm_if,
152 2,
153 USB_CLASS_CDC,
154 CDC_SUBCLASS_ACM,
155 CDC_PROTOCOL_NONE,
156 None,
157 )?;
158
159 writer.interface_alt(
160 self.comm_if,
161 DEFAULT_ALTERNATE_SETTING,
162 USB_CLASS_CDC,
163 CDC_SUBCLASS_ACM,
164 CDC_PROTOCOL_NONE,
165 self.comm_if_name.map(|n| n.0),
166 )?;
167
168 writer.write(
169 CS_INTERFACE,
170 &[
171 CDC_TYPE_HEADER, 0x10,
173 0x01, ],
175 )?;
176
177 writer.write(
178 CS_INTERFACE,
179 &[
180 CDC_TYPE_ACM, 0x00, ],
183 )?;
184
185 writer.write(
186 CS_INTERFACE,
187 &[
188 CDC_TYPE_UNION, self.comm_if.into(), self.data_if.into(), ],
192 )?;
193
194 writer.write(
195 CS_INTERFACE,
196 &[
197 CDC_TYPE_CALL_MANAGEMENT, 0x00, self.data_if.into(), ],
201 )?;
202
203 writer.endpoint(&self.comm_ep)?;
204
205 writer.interface_alt(
206 self.data_if,
207 DEFAULT_ALTERNATE_SETTING,
208 USB_CLASS_CDC_DATA,
209 0x00,
210 0x00,
211 self.data_if_name.map(|n| n.0),
212 )?;
213
214 writer.endpoint(&self.write_ep)?;
215 writer.endpoint(&self.read_ep)?;
216
217 Ok(())
218 }
219
220 fn get_string(&self, index: StringIndex, _lang_id: LangID) -> Option<&str> {
221 match (self.comm_if_name, self.data_if_name) {
222 (Some((i, s)), _) if i == index => Some(s),
223 (_, Some((i, s))) if i == index => Some(s),
224 _ => None,
225 }
226 }
227
228 fn reset(&mut self) {
229 self.line_coding = LineCoding::default();
230 self.dtr = false;
231 self.rts = false;
232 }
233
234 fn control_in(&mut self, xfer: ControlIn<B>) {
235 let req = xfer.request();
236
237 if !(req.request_type == control::RequestType::Class
238 && req.recipient == control::Recipient::Interface
239 && req.index == u8::from(self.comm_if) as u16)
240 {
241 return;
242 }
243
244 match req.request {
245 REQ_GET_LINE_CODING if req.length == 7 => {
247 xfer.accept(|data| {
248 data[0..4].copy_from_slice(&self.line_coding.data_rate.to_le_bytes());
249 data[4] = self.line_coding.stop_bits as u8;
250 data[5] = self.line_coding.parity_type as u8;
251 data[6] = self.line_coding.data_bits;
252
253 Ok(7)
254 })
255 .ok();
256 }
257 _ => {
258 xfer.reject().ok();
259 }
260 }
261 }
262
263 fn control_out(&mut self, xfer: ControlOut<B>) {
264 let req = xfer.request();
265
266 if !(req.request_type == control::RequestType::Class
267 && req.recipient == control::Recipient::Interface
268 && req.index == u8::from(self.comm_if) as u16)
269 {
270 return;
271 }
272
273 match req.request {
274 REQ_SEND_ENCAPSULATED_COMMAND => {
275 xfer.accept().ok();
278 }
279 REQ_SET_LINE_CODING if xfer.data().len() >= 7 => {
280 self.line_coding.data_rate =
281 u32::from_le_bytes(xfer.data()[0..4].try_into().unwrap());
282 self.line_coding.stop_bits = xfer.data()[4].into();
283 self.line_coding.parity_type = xfer.data()[5].into();
284 self.line_coding.data_bits = xfer.data()[6];
285
286 xfer.accept().ok();
287 }
288 REQ_SET_CONTROL_LINE_STATE => {
289 self.dtr = (req.value & 0x0001) != 0;
290 self.rts = (req.value & 0x0002) != 0;
291
292 xfer.accept().ok();
293 }
294 _ => {
295 xfer.reject().ok();
296 }
297 };
298 }
299}
300
301#[derive(Copy, Clone, PartialEq, Eq)]
303pub enum StopBits {
304 One = 0,
306
307 OnePointFive = 1,
309
310 Two = 2,
312}
313
314impl From<u8> for StopBits {
315 fn from(value: u8) -> Self {
316 if value <= 2 {
317 unsafe { mem::transmute(value) }
318 } else {
319 StopBits::One
320 }
321 }
322}
323
324#[derive(Copy, Clone, PartialEq, Eq)]
326pub enum ParityType {
327 None = 0,
328 Odd = 1,
329 Even = 2,
330 Mark = 3,
331 Space = 4,
332}
333
334impl From<u8> for ParityType {
335 fn from(value: u8) -> Self {
336 if value <= 4 {
337 unsafe { mem::transmute(value) }
338 } else {
339 ParityType::None
340 }
341 }
342}
343
344pub struct LineCoding {
349 stop_bits: StopBits,
350 data_bits: u8,
351 parity_type: ParityType,
352 data_rate: u32,
353}
354
355impl LineCoding {
356 pub fn stop_bits(&self) -> StopBits {
358 self.stop_bits
359 }
360
361 pub fn data_bits(&self) -> u8 {
363 self.data_bits
364 }
365
366 pub fn parity_type(&self) -> ParityType {
368 self.parity_type
369 }
370
371 pub fn data_rate(&self) -> u32 {
373 self.data_rate
374 }
375}
376
377impl Default for LineCoding {
378 fn default() -> Self {
379 LineCoding {
380 stop_bits: StopBits::One,
381 data_bits: 8,
382 parity_type: ParityType::None,
383 data_rate: 9_600,
384 }
385 }
386}