capsules_extra/usb/cdc.rs
1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Communications Class Device for USB
6//!
7//! This capsule allows Tock to support a serial port over USB.
8
9use core::cell::Cell;
10use core::cmp;
11
12use super::descriptors;
13use super::descriptors::Buffer64;
14use super::descriptors::CdcInterfaceDescriptor;
15use super::descriptors::EndpointAddress;
16use super::descriptors::EndpointDescriptor;
17use super::descriptors::InterfaceDescriptor;
18use super::descriptors::TransferDirection;
19use super::usbc_client_ctrl::ClientCtrl;
20
21use kernel::deferred_call::{DeferredCall, DeferredCallClient};
22use kernel::hil;
23use kernel::hil::time::{Alarm, AlarmClient, ConvertTicks};
24use kernel::hil::uart;
25use kernel::hil::usb::TransferType;
26use kernel::utilities::cells::OptionalCell;
27use kernel::utilities::cells::TakeCell;
28use kernel::utilities::cells::VolatileCell;
29use kernel::ErrorCode;
30
31/// Identifying number for the endpoint when transferring data from us to the
32/// host.
33const ENDPOINT_IN_NUM: usize = 2;
34/// Identifying number for the endpoint when transferring data from the host to
35/// us.
36const ENDPOINT_OUT_NUM: usize = 3;
37
38static LANGUAGES: &[u16; 1] = &[
39 0x0409, // English (United States)
40];
41/// Platform-specific packet length for the `SAM4L` USB hardware.
42pub const MAX_CTRL_PACKET_SIZE_SAM4L: u8 = 8;
43/// Platform-specific packet length for the `nRF52` USB hardware.
44pub const MAX_CTRL_PACKET_SIZE_NRF52840: u8 = 64;
45/// Platform-specific packet length for the `earlgrey` USB hardware.
46pub const MAX_CTRL_PACKET_SIZE_EARLGREY: u8 = 64;
47/// Number of ms to buffer uart transmissions before beginning to drop them.
48///
49/// This is useful in that it allows users time to connect over CDC without losing message,
50/// while still guaranteeing that blocking uart transmissions eventually get a callback even
51/// if a debug output is not connected.
52pub const CDC_BUFFER_TIMEOUT_MS: u32 = 10000;
53
54const N_ENDPOINTS: usize = 3;
55
56/// States of the CDC driver.
57#[derive(Debug, Copy, Clone, PartialEq)]
58enum State {
59 /// Default state. User must call `enable()`.
60 Disabled,
61 /// `enable()` has been called. The descriptor format has been passed to the
62 /// hardware.
63 Enabled,
64 /// `attach()` has been called. The hardware should be ready for a host to
65 /// connect.
66 Attached,
67 /// The host has enumerated this USB device. Things should be functional at
68 /// this point.
69 Enumerated,
70 /// We are seeing the CDC messages that we expect to signal that a CDC
71 /// client has connected. We want to see that both line coding and line
72 /// state ctrl messages have been received. We stay in the "connecting"
73 /// state until the USB transfers for both ctrl messages have completed.
74 Connecting { line_coding: bool, line_state: bool },
75 /// We have seen the necessary setup messages in the `Connecting` state, now
76 /// we delay just to ensure the host has enough time to receive _and
77 /// display_ messages.
78 ConnectingDelay,
79 /// A CDC client is connected. We can safely send data.
80 Connected,
81}
82
83/// States of the Control Endpoint related to CDC-ACM.
84#[derive(Debug, Copy, Clone, PartialEq)]
85enum CtrlState {
86 /// No ongoing ctrl transcation.
87 Idle,
88 /// Host has sent a SET_LINE_CODING configuration request.
89 SetLineCoding,
90 /// Host has send a SET_CONTROL_LINE_STATE configuration request.
91 SetControlLineState,
92}
93
94#[derive(PartialEq)]
95enum CDCCntrlMessage {
96 NotSupported,
97 SetLineCoding = 0x20,
98 SetControlLineState = 0x22,
99 SendBreak = 0x23,
100}
101
102impl From<u8> for CDCCntrlMessage {
103 fn from(num: u8) -> Self {
104 match num {
105 0x20 => CDCCntrlMessage::SetLineCoding,
106 0x22 => CDCCntrlMessage::SetControlLineState,
107 0x23 => CDCCntrlMessage::SendBreak,
108 _ => CDCCntrlMessage::NotSupported,
109 }
110 }
111}
112
113/// Implementation of the Abstract Control Model (ACM) for the Communications
114/// Class Device (CDC) over USB.
115pub struct CdcAcm<'a, U: 'a, A: 'a + Alarm<'a>> {
116 /// Helper USB client library for handling many USB operations.
117 client_ctrl: ClientCtrl<'a, 'static, U>,
118
119 /// 64 byte buffers for each endpoint.
120 buffers: [Buffer64; N_ENDPOINTS],
121
122 /// Current state of the CDC driver. This helps us track if a CDC client is
123 /// connected and listening or not.
124 state: Cell<State>,
125
126 /// Current state of the Control Endpoint. This tracks which configuration
127 /// request the host is currently sending us.
128 ctrl_state: Cell<CtrlState>,
129
130 /// A holder reference for the TX buffer we are transmitting from.
131 tx_buffer: TakeCell<'static, [u8]>,
132 /// The number of bytes the client has asked us to send. We track this so we
133 /// can pass it back to the client when the transmission has finished.
134 tx_len: Cell<usize>,
135 /// Where in the `tx_buffer` we need to start sending from when we continue.
136 tx_offset: Cell<usize>,
137 /// The TX client to use when transmissions finish.
138 tx_client: OptionalCell<&'a dyn uart::TransmitClient>,
139
140 /// A holder for the buffer to receive bytes into. We use this as a flag as
141 /// well, if we have a buffer then we are actively doing a receive.
142 rx_buffer: TakeCell<'static, [u8]>,
143 /// How many bytes the client wants us to receive.
144 rx_len: Cell<usize>,
145 /// How many bytes we have received so far.
146 rx_offset: Cell<usize>,
147 /// The RX client to use when RX data is received.
148 rx_client: OptionalCell<&'a dyn uart::ReceiveClient>,
149
150 /// Alarm used to indicate that data should be dropped and callbacks
151 /// returned.
152 timeout_alarm: &'a A,
153 /// Used to track whether we are in the initial boot up period during which
154 /// messages can be queued despite a CDC host not being connected (which is
155 /// useful for ensuring debug messages early in the boot process can be
156 /// delivered over the console).
157 boot_period: Cell<bool>,
158
159 /// Deferred Call
160 deferred_call: DeferredCall,
161 /// Flag to mark we are waiting on a deferred call for dropping a TX. This
162 /// can happen if an upper layer told us to transmit a buffer, but there is
163 /// no host connected and therefore we cannot actually transmit. However,
164 /// normal UART semantics are that we can always send (perhaps with a
165 /// delay), even if nothing is actually listening. To keep the upper layers
166 /// happy and to allow this CDC layer to just drop messages, we always
167 /// return Ok(()) for TX, and then use a deferred call to signal the
168 /// transmit done callback.
169 deferred_call_pending_droptx: Cell<bool>,
170 /// Flag to mark we need a deferred call to signal a callback after an RX
171 /// abort occurs.
172 deferred_call_pending_abortrx: Cell<bool>,
173
174 /// Optional host-initiated function. This function (if supplied) is called
175 /// when the host sends a special message to the device. The normal signal
176 /// for calling this function is the host configuring the baud rate to be
177 /// 1200 baud.
178 ///
179 /// This was originally added for the bootloader to allow the host to tell
180 /// the device to enter bootloader mode.
181 host_initiated_function: Option<&'a (dyn Fn() + 'a)>,
182}
183
184impl<'a, U: hil::usb::UsbController<'a>, A: 'a + Alarm<'a>> CdcAcm<'a, U, A> {
185 pub fn new(
186 controller: &'a U,
187 max_ctrl_packet_size: u8,
188 vendor_id: u16,
189 product_id: u16,
190 strings: &'static [&'static str; 3],
191 timeout_alarm: &'a A,
192 host_initiated_function: Option<&'a (dyn Fn() + 'a)>,
193 ) -> Self {
194 let interfaces: &mut [InterfaceDescriptor] = &mut [
195 InterfaceDescriptor {
196 interface_number: 0,
197 interface_class: 0x02, // CDC communication
198 interface_subclass: 0x02, // abstract control model (ACM)
199 interface_protocol: 0x01, // V.25ter (AT commands)
200 ..InterfaceDescriptor::default()
201 },
202 InterfaceDescriptor {
203 interface_number: 1,
204 interface_class: 0x0a, // CDC data
205 interface_subclass: 0x00, // none
206 interface_protocol: 0x00, // none
207 ..InterfaceDescriptor::default()
208 },
209 ];
210
211 let cdc_descriptors: &mut [CdcInterfaceDescriptor] = &mut [
212 CdcInterfaceDescriptor {
213 subtype: descriptors::CdcInterfaceDescriptorSubType::Header,
214 field1: 0x10, // CDC
215 field2: 0x11, // CDC
216 },
217 CdcInterfaceDescriptor {
218 subtype: descriptors::CdcInterfaceDescriptorSubType::CallManagement,
219 field1: 0x00, // Capabilities
220 field2: 0x01, // Data interface 1
221 },
222 CdcInterfaceDescriptor {
223 subtype: descriptors::CdcInterfaceDescriptorSubType::AbstractControlManagement,
224 field1: 0x06, // Capabilities
225 field2: 0x00, // unused
226 },
227 CdcInterfaceDescriptor {
228 subtype: descriptors::CdcInterfaceDescriptorSubType::Union,
229 field1: 0x00, // Interface 0
230 field2: 0x01, // Interface 1
231 },
232 ];
233
234 let endpoints: &[&[EndpointDescriptor]] = &[
235 &[EndpointDescriptor {
236 endpoint_address: EndpointAddress::new_const(4, TransferDirection::DeviceToHost),
237 transfer_type: TransferType::Interrupt,
238 max_packet_size: 8,
239 interval: 16,
240 }],
241 &[
242 EndpointDescriptor {
243 endpoint_address: EndpointAddress::new_const(
244 2,
245 TransferDirection::DeviceToHost,
246 ),
247 transfer_type: TransferType::Bulk,
248 max_packet_size: 64,
249 interval: 0,
250 },
251 EndpointDescriptor {
252 endpoint_address: EndpointAddress::new_const(
253 3,
254 TransferDirection::HostToDevice,
255 ),
256 transfer_type: TransferType::Bulk,
257 max_packet_size: 64,
258 interval: 0,
259 },
260 ],
261 ];
262
263 let (device_descriptor_buffer, other_descriptor_buffer) =
264 descriptors::create_descriptor_buffers(
265 descriptors::DeviceDescriptor {
266 vendor_id,
267 product_id,
268 manufacturer_string: 1,
269 product_string: 2,
270 serial_number_string: 3,
271 class: 0x2, // Class: CDC
272 max_packet_size_ep0: max_ctrl_packet_size,
273 ..descriptors::DeviceDescriptor::default()
274 },
275 descriptors::ConfigurationDescriptor::default(),
276 interfaces,
277 endpoints,
278 None, // No HID descriptor
279 Some(cdc_descriptors),
280 );
281
282 Self {
283 client_ctrl: ClientCtrl::new(
284 controller,
285 device_descriptor_buffer,
286 other_descriptor_buffer,
287 None, // No HID descriptor
288 None, // No report descriptor
289 LANGUAGES,
290 strings,
291 ),
292 buffers: [
293 Buffer64::default(),
294 Buffer64::default(),
295 Buffer64::default(),
296 ],
297 state: Cell::new(State::Disabled),
298 ctrl_state: Cell::new(CtrlState::Idle),
299 tx_buffer: TakeCell::empty(),
300 tx_len: Cell::new(0),
301 tx_offset: Cell::new(0),
302 tx_client: OptionalCell::empty(),
303 rx_buffer: TakeCell::empty(),
304 rx_len: Cell::new(0),
305 rx_offset: Cell::new(0),
306 rx_client: OptionalCell::empty(),
307 timeout_alarm,
308 boot_period: Cell::new(true),
309 deferred_call: DeferredCall::new(),
310 deferred_call_pending_droptx: Cell::new(false),
311 deferred_call_pending_abortrx: Cell::new(false),
312 host_initiated_function,
313 }
314 }
315
316 #[inline]
317 pub fn controller(&self) -> &'a U {
318 self.client_ctrl.controller()
319 }
320
321 #[inline]
322 fn buffer(&'a self, i: usize) -> &'a [VolatileCell<u8>; 64] {
323 &self.buffers[i - 1].buf
324 }
325
326 /// This is a helper function used to indicate successful uart transmission to
327 /// a higher layer client despite not actually being connected to a host. Allows
328 /// blocking debug interfaces to function in the same way they do when an actual UART
329 /// interface is in use. This should only be called in an upcall.
330 fn indicate_tx_success(&self) {
331 self.tx_len.set(0);
332 self.tx_offset.set(0);
333 self.tx_client.map(|client| {
334 self.tx_buffer.take().map(|buf| {
335 client.transmitted_buffer(buf, 0, Err(ErrorCode::FAIL));
336 });
337 });
338 }
339
340 /// Helper function to update the connecting state variable as we progress
341 /// through various setup steps that indicate a host is actually connecting
342 /// to our serial port.
343 ///
344 /// - `line_coding`: if true, set. if false, leave to previous value.
345 /// - `line_state`: if true, set. if false, leave to previous value.
346 fn set_connecting_state(&self, line_coding: bool, line_state: bool) {
347 match self.state.get() {
348 State::Enumerated => {
349 self.state.set(State::Connecting {
350 line_coding,
351 line_state,
352 });
353 }
354 State::Connecting {
355 line_coding: old_lc,
356 line_state: old_ls,
357 } => {
358 self.state.set(State::Connecting {
359 line_coding: if line_coding { true } else { old_lc },
360 line_state: if line_state { true } else { old_ls },
361 });
362 }
363 _ => {}
364 }
365 }
366}
367
368impl<'a, U: hil::usb::UsbController<'a>, A: 'a + Alarm<'a>> hil::usb::Client<'a>
369 for CdcAcm<'a, U, A>
370{
371 fn enable(&'a self) {
372 // Set up the default control endpoint
373 self.client_ctrl.enable();
374
375 // Setup buffers for IN and OUT data transfer.
376 self.controller()
377 .endpoint_set_in_buffer(ENDPOINT_IN_NUM, self.buffer(ENDPOINT_IN_NUM));
378 self.controller()
379 .endpoint_in_enable(TransferType::Bulk, ENDPOINT_IN_NUM);
380
381 self.controller()
382 .endpoint_set_out_buffer(ENDPOINT_OUT_NUM, self.buffer(ENDPOINT_OUT_NUM));
383 self.controller()
384 .endpoint_out_enable(TransferType::Bulk, ENDPOINT_OUT_NUM);
385
386 self.state.set(State::Enabled);
387
388 self.timeout_alarm.set_alarm(
389 self.timeout_alarm.now(),
390 self.timeout_alarm.ticks_from_ms(CDC_BUFFER_TIMEOUT_MS),
391 );
392 }
393
394 fn attach(&'a self) {
395 self.client_ctrl.attach();
396 self.state.set(State::Attached);
397 }
398
399 fn bus_reset(&'a self) {
400 // We take a bus reset to mean the enumeration has finished.
401 self.state.set(State::Enumerated);
402 }
403
404 /// Handle a Control Setup transaction.
405 ///
406 /// CDC uses special values here, and we can use these to know when a CDC
407 /// client is connected or not.
408 fn ctrl_setup(&'a self, endpoint: usize) -> hil::usb::CtrlSetupResult {
409 descriptors::SetupData::get(&self.client_ctrl.ctrl_buffer.buf).map(|setup_data| {
410 let b_request = setup_data.request_code;
411
412 match CDCCntrlMessage::from(b_request) {
413 CDCCntrlMessage::SetLineCoding => {
414 self.ctrl_state.set(CtrlState::SetLineCoding);
415 }
416 CDCCntrlMessage::SetControlLineState => {
417 // Bit 0 and 1 of the value (setup_data.value) can be set
418 // D0: Indicates to DCE if DTE is present or not.
419 // - 0 -> Not present
420 // - 1 -> Present
421 // D1: Carrier control for half duplex modems.
422 // - 0 -> Deactivate carrier
423 // - 1 -> Activate carrier
424 //
425 // Currently we don't care about the value, just that this
426 // event has occurred. If it has happened, update the flag
427 // in `State::Connecting`.
428 self.set_connecting_state(false, true);
429
430 self.ctrl_state.set(CtrlState::SetControlLineState);
431 }
432 CDCCntrlMessage::SendBreak => {
433 // On Mac, we seem to get the SEND_BREAK to signal that a
434 // client disconnects.
435 self.state.set(State::Enumerated)
436 }
437 _ => {}
438 }
439 });
440
441 self.client_ctrl.ctrl_setup(endpoint)
442 }
443
444 /// Handle a Control In transaction
445 fn ctrl_in(&'a self, endpoint: usize) -> hil::usb::CtrlInResult {
446 self.client_ctrl.ctrl_in(endpoint)
447 }
448
449 /// Handle a Control Out transaction
450 fn ctrl_out(&'a self, endpoint: usize, packet_bytes: u32) -> hil::usb::CtrlOutResult {
451 // Check what state our Ctrl endpoint is in.
452 match self.ctrl_state.get() {
453 CtrlState::SetLineCoding => {
454 // We got a Ctrl SET_LINE_CODING setup, now we are getting the data.
455 // We can parse the data we got.
456 descriptors::CdcAcmSetLineCodingData::get(&self.client_ctrl.ctrl_buffer.buf).map(
457 |line_coding| {
458 // If the device is configuring the baud rate to what we
459 // expect, we continue with the connecting process.
460 if line_coding.baud_rate == 115200 {
461 self.set_connecting_state(true, false);
462 }
463
464 // Check if the baud rate we got matches the special flag
465 // value (1200 baud). If so, we run an optional function
466 // provided when the CDC stack was configured.
467 if line_coding.baud_rate == 1200 {
468 self.host_initiated_function.map(|f| {
469 f();
470 });
471 }
472 },
473 );
474 }
475 _ => {}
476 }
477
478 self.client_ctrl.ctrl_out(endpoint, packet_bytes)
479 }
480
481 fn ctrl_status(&'a self, endpoint: usize) {
482 self.client_ctrl.ctrl_status(endpoint)
483 }
484
485 /// Handle the completion of a Control transfer
486 fn ctrl_status_complete(&'a self, endpoint: usize) {
487 self.ctrl_state.set(CtrlState::Idle);
488
489 // Here we check to see if we just got connected to a CDC client. If so,
490 // we do a delay before transmitting if needed.
491 match self.state.get() {
492 State::Connecting {
493 line_coding,
494 line_state,
495 } => {
496 if line_coding && line_state {
497 self.state.set(State::ConnectingDelay);
498
499 // Wait a 100 ms before sending data.
500 self.timeout_alarm.set_alarm(
501 self.timeout_alarm.now(),
502 self.timeout_alarm.ticks_from_ms(100),
503 );
504 }
505 }
506 _ => {}
507 }
508
509 self.client_ctrl.ctrl_status_complete(endpoint)
510 }
511
512 /// Handle a Bulk/Interrupt IN transaction.
513 ///
514 /// This is called when we can send data to the host. It should get called
515 /// when we tell the controller we want to resume the IN endpoint (meaning
516 /// we know we have data to send) and afterwards until we return
517 /// `hil::usb::InResult::Delay` from this function. That means we can use
518 /// this as a callback to mean that the transmission finished by waiting
519 /// until this function is called when we don't have anything left to send.
520 fn packet_in(&'a self, transfer_type: TransferType, endpoint: usize) -> hil::usb::InResult {
521 match transfer_type {
522 TransferType::Bulk => {
523 self.tx_buffer
524 .take()
525 .map_or(hil::usb::InResult::Delay, |tx_buf| {
526 // Check if we have any bytes to send.
527 let offset = self.tx_offset.get();
528 let remaining = self.tx_len.get() - offset;
529 if remaining > 0 {
530 // We do, so we go ahead and send those.
531
532 // Get packet that we have shared with the underlying
533 // USB stack to copy the tx into.
534 let packet = self.buffer(endpoint);
535
536 // Calculate how much more we can send.
537 let to_send = cmp::min(packet.len(), remaining);
538
539 // Copy from the TX buffer to the outgoing USB packet.
540 for i in 0..to_send {
541 packet[i].set(tx_buf[offset + i]);
542 }
543
544 // Update our state on how much more there is to send.
545 self.tx_offset.set(offset + to_send);
546
547 // Put the TX buffer back so we can keep sending from it.
548 self.tx_buffer.replace(tx_buf);
549
550 // Return that we have data to send.
551 hil::usb::InResult::Packet(to_send)
552 } else {
553 // We don't have anything to send, so that means we are
554 // ok to signal the callback.
555
556 // Signal the callback and pass back the TX buffer.
557 self.tx_client.map(move |tx_client| {
558 tx_client.transmitted_buffer(tx_buf, self.tx_len.get(), Ok(()))
559 });
560
561 // Return that we have nothing else to do to the USB
562 // driver.
563 hil::usb::InResult::Delay
564 }
565 })
566 }
567 TransferType::Control | TransferType::Isochronous | TransferType::Interrupt => {
568 // Nothing to do for CDC ACM.
569 hil::usb::InResult::Delay
570 }
571 }
572 }
573
574 /// Handle a Bulk/Interrupt OUT transaction
575 fn packet_out(
576 &'a self,
577 transfer_type: TransferType,
578 endpoint: usize,
579 packet_bytes: u32,
580 ) -> hil::usb::OutResult {
581 match transfer_type {
582 TransferType::Bulk => {
583 // Start by checking to see if we even care about this RX or
584 // not.
585 self.rx_buffer.take().map(|rx_buf| {
586 let rx_offset = self.rx_offset.get();
587
588 // How many more bytes can we store in our RX buffer?
589 let available_bytes = rx_buf.len() - rx_offset;
590 let copy_length = cmp::min(packet_bytes as usize, available_bytes);
591
592 // Do the copy into the RX buffer.
593 let packet = self.buffer(endpoint);
594 for i in 0..copy_length {
595 rx_buf[rx_offset + i] = packet[i].get();
596 }
597
598 // Keep track of how many bytes we have received so far.
599 let total_received_bytes = rx_offset + copy_length;
600
601 // Update how many bytes we have gotten.
602 self.rx_offset.set(total_received_bytes);
603
604 // Check if we have received at least as many bytes as the
605 // client asked for.
606 if total_received_bytes >= self.rx_len.get() {
607 self.rx_client.map(move |client| {
608 client.received_buffer(
609 rx_buf,
610 total_received_bytes,
611 Ok(()),
612 uart::Error::None,
613 );
614 });
615 } else {
616 // Make sure to put the RX buffer back.
617 self.rx_buffer.replace(rx_buf);
618 }
619 });
620
621 // No error cases to report to the USB.
622 hil::usb::OutResult::Ok
623 }
624 TransferType::Control | TransferType::Isochronous | TransferType::Interrupt => {
625 // Nothing to do for CDC ACM.
626 hil::usb::OutResult::Ok
627 }
628 }
629 }
630
631 fn packet_transmitted(&'a self, _endpoint: usize) {
632 // Check if more to send.
633 self.tx_buffer.take().map(|tx_buf| {
634 // Check if we have any bytes to send.
635 let remaining = self.tx_len.get() - self.tx_offset.get();
636 if remaining > 0 {
637 // We do, so ask to send again.
638 self.tx_buffer.replace(tx_buf);
639 self.controller().endpoint_resume_in(ENDPOINT_IN_NUM);
640 } else {
641 // We don't have anything to send, so that means we are
642 // ok to signal the callback.
643
644 // Signal the callback and pass back the TX buffer.
645 self.tx_client.map(move |tx_client| {
646 tx_client.transmitted_buffer(tx_buf, self.tx_len.get(), Ok(()))
647 });
648 }
649 });
650 }
651}
652
653impl<'a, U: hil::usb::UsbController<'a>, A: 'a + Alarm<'a>> uart::Configure for CdcAcm<'a, U, A> {
654 fn configure(&self, _parameters: uart::Parameters) -> Result<(), ErrorCode> {
655 // Since this is not a real UART, we don't need to consider these
656 // parameters.
657 Ok(())
658 }
659}
660
661impl<'a, U: hil::usb::UsbController<'a>, A: 'a + Alarm<'a>> uart::Transmit<'a>
662 for CdcAcm<'a, U, A>
663{
664 fn set_transmit_client(&self, client: &'a dyn uart::TransmitClient) {
665 self.tx_client.set(client);
666 }
667
668 fn transmit_buffer(
669 &self,
670 tx_buffer: &'static mut [u8],
671 tx_len: usize,
672 ) -> Result<(), (ErrorCode, &'static mut [u8])> {
673 if self.tx_buffer.is_some() {
674 // We are already handling a transmission, we cannot queue another
675 // request.
676 Err((ErrorCode::BUSY, tx_buffer))
677 } else if tx_len > tx_buffer.len() {
678 // Can't send more bytes than will fit in the buffer.
679 Err((ErrorCode::SIZE, tx_buffer))
680 } else {
681 // Ok, we can handle this transmission. Initialize all of our state
682 // for our TX state machine.
683 self.tx_len.set(tx_len);
684 self.tx_offset.set(0);
685 self.tx_buffer.replace(tx_buffer);
686
687 // Don't try to send if there is no CDC client connected.
688 if self.state.get() == State::Connected {
689 // Then signal to the lower layer that we are ready to do a TX
690 // by putting data in the IN endpoint.
691 self.controller().endpoint_resume_in(ENDPOINT_IN_NUM);
692 Ok(())
693 } else if self.boot_period.get() {
694 // indicate success because we will try to send it once a host connects
695 Ok(())
696 } else {
697 // indicate success, but we will not actually queue this message -- just schedule
698 // a deferred callback to return the buffer immediately.
699 self.deferred_call_pending_droptx.set(true);
700 self.deferred_call.set();
701 Ok(())
702 }
703 }
704 }
705
706 fn transmit_abort(&self) -> Result<(), ErrorCode> {
707 Err(ErrorCode::FAIL)
708 }
709
710 fn transmit_word(&self, _word: u32) -> Result<(), ErrorCode> {
711 Err(ErrorCode::FAIL)
712 }
713}
714
715impl<'a, U: hil::usb::UsbController<'a>, A: 'a + Alarm<'a>> uart::Receive<'a> for CdcAcm<'a, U, A> {
716 fn set_receive_client(&self, client: &'a dyn uart::ReceiveClient) {
717 self.rx_client.set(client);
718 }
719
720 fn receive_buffer(
721 &self,
722 rx_buffer: &'static mut [u8],
723 rx_len: usize,
724 ) -> Result<(), (ErrorCode, &'static mut [u8])> {
725 if self.rx_buffer.is_some() {
726 Err((ErrorCode::BUSY, rx_buffer))
727 } else if rx_len > rx_buffer.len() {
728 Err((ErrorCode::SIZE, rx_buffer))
729 } else {
730 self.rx_buffer.replace(rx_buffer);
731 self.rx_offset.set(0);
732 self.rx_len.set(rx_len);
733
734 Ok(())
735 }
736 }
737
738 fn receive_abort(&self) -> Result<(), ErrorCode> {
739 if self.rx_buffer.is_none() {
740 // If we have nothing pending then aborting is very easy.
741 Ok(())
742 } else {
743 // If we do have a receive pending then we need to start a deferred
744 // call to set the callback and return `BUSY`.
745 self.deferred_call_pending_abortrx.set(true);
746 self.deferred_call.set();
747 Err(ErrorCode::BUSY)
748 }
749 }
750
751 fn receive_word(&self) -> Result<(), ErrorCode> {
752 Err(ErrorCode::FAIL)
753 }
754}
755
756impl<'a, U: hil::usb::UsbController<'a>, A: 'a + Alarm<'a>> AlarmClient for CdcAcm<'a, U, A> {
757 fn alarm(&self) {
758 self.boot_period.set(false);
759
760 // This alarm is used in two cases. The main is when we first start to
761 // delay outgoing messages until a host has a chance to connect. The
762 // second is to delay after a host does connect to help ensure messages
763 // actually get printed. If this timer goes off, then either no host
764 // connected, and we want to start dropping messages, or something did
765 // connect and we just executed the delay.
766 if self.state.get() == State::ConnectingDelay {
767 self.state.set(State::Connected);
768 if self.tx_buffer.is_some() {
769 self.controller().endpoint_resume_in(ENDPOINT_IN_NUM);
770 }
771 } else {
772 // no client has connected, but we do not want to block indefinitely, so go ahead
773 // and deliver a callback.
774 self.indicate_tx_success();
775 }
776 }
777}
778
779impl<'a, U: hil::usb::UsbController<'a>, A: 'a + Alarm<'a>> DeferredCallClient
780 for CdcAcm<'a, U, A>
781{
782 fn handle_deferred_call(&self) {
783 if self.deferred_call_pending_droptx.replace(false) {
784 self.indicate_tx_success()
785 }
786
787 if self.deferred_call_pending_abortrx.replace(false) {
788 // Signal the RX callback with CANCEL error.
789 self.rx_buffer.take().map(|rx_buf| {
790 let rx_offset = self.rx_offset.get();
791
792 // The total number of bytes we have received so far.
793 let total_received_bytes = rx_offset;
794
795 self.rx_client.map(move |client| {
796 client.received_buffer(
797 rx_buf,
798 total_received_bytes,
799 Err(ErrorCode::CANCEL),
800 uart::Error::None,
801 );
802 });
803 });
804 }
805 }
806
807 fn register(&'static self) {
808 self.deferred_call.register(self);
809 }
810}