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}