usbd_serial/
serial_port.rs

1use crate::buffer::{Buffer, DefaultBufferStore};
2use crate::cdc_acm::*;
3use core::borrow::BorrowMut;
4use core::slice;
5use usb_device::class_prelude::*;
6use usb_device::descriptor::lang_id::LangID;
7use usb_device::Result;
8
9/// USB (CDC-ACM) serial port with built-in buffering to implement stream-like behavior.
10///
11/// The RS and WS type arguments specify the storage for the read/write buffers, respectively. By
12/// default an internal 128 byte buffer is used for both directions.
13pub struct SerialPort<'a, B, RS = DefaultBufferStore, WS = DefaultBufferStore>
14where
15    B: UsbBus,
16    RS: BorrowMut<[u8]>,
17    WS: BorrowMut<[u8]>,
18{
19    inner: CdcAcmClass<'a, B>,
20    pub(crate) read_buf: Buffer<RS>,
21    pub(crate) write_buf: Buffer<WS>,
22    write_state: WriteState,
23}
24
25/// If this many full size packets have been sent in a row, a short packet will be sent so that the
26/// host sees the data in a timely manner.
27const SHORT_PACKET_INTERVAL: usize = 10;
28
29/// Keeps track of the type of the last written packet.
30enum WriteState {
31    /// No packets in-flight
32    Idle,
33
34    /// Short packet currently in-flight
35    Short,
36
37    /// Full packet current in-flight. A full packet must be followed by a short packet for the host
38    /// OS to see the transaction. The data is the number of subsequent full packets sent so far. A
39    /// short packet is forced every SHORT_PACKET_INTERVAL packets so that the OS sees data in a
40    /// timely manner.
41    Full(usize),
42}
43
44impl<'a, B> SerialPort<'a, B>
45where
46    B: UsbBus,
47{
48    /// Creates a new USB serial port with the provided UsbBus and 128 byte read/write buffers.
49    pub fn new<'alloc: 'a>(
50        alloc: &'alloc UsbBusAllocator<B>,
51    ) -> SerialPort<'a, B, DefaultBufferStore, DefaultBufferStore> {
52        Self::new_with_interface_names(alloc, None, None)
53    }
54    /// Same as SerialPort::new, but allows specifying the names of the interfaces
55    pub fn new_with_interface_names<'alloc: 'a>(
56        alloc: &'alloc UsbBusAllocator<B>,
57        comm_if_name: Option<&'static str>,
58        data_if_name: Option<&'static str>,
59    ) -> SerialPort<'a, B, DefaultBufferStore, DefaultBufferStore> {
60        SerialPort::new_with_store_and_interface_names(
61            alloc,
62            DefaultBufferStore::default(),
63            DefaultBufferStore::default(),
64            comm_if_name,
65            data_if_name,
66        )
67    }
68}
69
70impl<'a, B, RS, WS> SerialPort<'a, B, RS, WS>
71where
72    B: UsbBus,
73    RS: BorrowMut<[u8]>,
74    WS: BorrowMut<[u8]>,
75{
76    /// Creates a new USB serial port with the provided UsbBus and buffer backing stores.
77    pub fn new_with_store<'alloc: 'a>(
78        alloc: &'alloc UsbBusAllocator<B>,
79        read_store: RS,
80        write_store: WS,
81    ) -> SerialPort<'a, B, RS, WS> {
82        Self::new_with_store_and_interface_names(alloc, read_store, write_store, None, None)
83    }
84
85    /// Creates a new USB serial port with the provided UsbBus and buffer backing stores.
86    pub fn new_with_store_and_interface_names<'alloc: 'a>(
87        alloc: &'alloc UsbBusAllocator<B>,
88        read_store: RS,
89        write_store: WS,
90        comm_if_name: Option<&'static str>,
91        data_if_name: Option<&'static str>,
92    ) -> SerialPort<'a, B, RS, WS> {
93        SerialPort {
94            inner: CdcAcmClass::new_with_interface_names(alloc, 64, comm_if_name, data_if_name),
95            read_buf: Buffer::new(read_store),
96            write_buf: Buffer::new(write_store),
97            write_state: WriteState::Idle,
98        }
99    }
100
101    /// Gets the current line coding.
102    pub fn line_coding(&self) -> &LineCoding {
103        self.inner.line_coding()
104    }
105
106    /// Gets the DTR (data terminal ready) state
107    pub fn dtr(&self) -> bool {
108        self.inner.dtr()
109    }
110
111    /// Gets the RTS (request to send) state
112    pub fn rts(&self) -> bool {
113        self.inner.rts()
114    }
115
116    /// Writes bytes from `data` into the port and returns the number of bytes written.
117    ///
118    /// # Errors
119    ///
120    /// * [`WouldBlock`](usb_device::UsbError::WouldBlock) - No bytes could be written because the
121    ///   buffers are full.
122    ///
123    /// Other errors from `usb-device` may also be propagated.
124    pub fn write(&mut self, data: &[u8]) -> Result<usize> {
125        let count = self.write_buf.write(data);
126
127        match self.flush() {
128            Ok(_) | Err(UsbError::WouldBlock) => {}
129            Err(err) => {
130                return Err(err);
131            }
132        };
133
134        if count == 0 {
135            Err(UsbError::WouldBlock)
136        } else {
137            Ok(count)
138        }
139    }
140
141    /// Poll the endpoint and try to put them into the serial buffer.
142    pub(crate) fn poll(&mut self) -> Result<()> {
143        let Self {
144            inner, read_buf, ..
145        } = self;
146
147        read_buf.write_all(inner.max_packet_size() as usize, |buf_data| {
148            match inner.read_packet(buf_data) {
149                Ok(c) => Ok(c),
150                Err(UsbError::WouldBlock) => Ok(0),
151                Err(err) => Err(err),
152            }
153        })?;
154
155        Ok(())
156    }
157
158    /// Reads bytes from the port into `data` and returns the number of bytes read.
159    ///
160    /// # Errors
161    ///
162    /// * [`WouldBlock`](usb_device::UsbError::WouldBlock) - No bytes available for reading.
163    ///
164    /// Other errors from `usb-device` may also be propagated.
165    pub fn read(&mut self, data: &mut [u8]) -> Result<usize> {
166        // Try to read a packet from the endpoint and write it into the buffer if it fits. Propagate
167        // errors except `WouldBlock`.
168        self.poll()?;
169
170        if self.read_buf.available_read() == 0 {
171            // No data available for reading.
172            return Err(UsbError::WouldBlock);
173        }
174
175        self.read_buf.read(data.len(), |buf_data| {
176            data[..buf_data.len()].copy_from_slice(buf_data);
177
178            Ok(buf_data.len())
179        })
180    }
181
182    /// Sends as much as possible of the current write buffer. Returns `Ok` if all data that has
183    /// been written has been completely written to hardware buffers `Err(WouldBlock)` if there is
184    /// still data remaining, and other errors if there's an error sending data to the host. Note
185    /// that even if this method returns `Ok`, data may still be in hardware buffers on either side.
186    pub fn flush(&mut self) -> Result<()> {
187        let buf = &mut self.write_buf;
188        let inner = &mut self.inner;
189        let write_state = &mut self.write_state;
190
191        let full_count = match *write_state {
192            WriteState::Full(c) => c,
193            _ => 0,
194        };
195
196        if buf.available_read() > 0 {
197            // There's data in the write_buf, so try to write that first.
198
199            let max_write_size = if full_count >= SHORT_PACKET_INTERVAL {
200                inner.max_packet_size() - 1
201            } else {
202                inner.max_packet_size()
203            } as usize;
204
205            buf.read(max_write_size, |buf_data| {
206                // This may return WouldBlock which will be propagated.
207                inner.write_packet(buf_data)?;
208
209                *write_state = if buf_data.len() == inner.max_packet_size() as usize {
210                    WriteState::Full(full_count + 1)
211                } else {
212                    WriteState::Short
213                };
214
215                Ok(buf_data.len())
216            })?;
217
218            Err(UsbError::WouldBlock)
219        } else if full_count != 0 {
220            // Write a ZLP to complete the transaction if there's nothing else to write and the last
221            // packet was a full one. This may return WouldBlock which will be propagated.
222            inner.write_packet(&[])?;
223
224            *write_state = WriteState::Short;
225
226            Err(UsbError::WouldBlock)
227        } else {
228            // No data left in writer_buf.
229
230            *write_state = WriteState::Idle;
231
232            Ok(())
233        }
234    }
235}
236
237impl<B, RS, WS> UsbClass<B> for SerialPort<'_, B, RS, WS>
238where
239    B: UsbBus,
240    RS: BorrowMut<[u8]>,
241    WS: BorrowMut<[u8]>,
242{
243    fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> {
244        self.inner.get_configuration_descriptors(writer)
245    }
246
247    fn get_string(&self, index: StringIndex, lang_id: LangID) -> Option<&str> {
248        self.inner.get_string(index, lang_id)
249    }
250
251    fn reset(&mut self) {
252        self.inner.reset();
253        self.read_buf.clear();
254        self.write_buf.clear();
255        self.write_state = WriteState::Idle;
256    }
257
258    fn endpoint_in_complete(&mut self, addr: EndpointAddress) {
259        if addr == self.inner.write_ep().address() {
260            self.flush().ok();
261        }
262    }
263
264    fn control_in(&mut self, xfer: ControlIn<B>) {
265        self.inner.control_in(xfer);
266    }
267
268    fn control_out(&mut self, xfer: ControlOut<B>) {
269        self.inner.control_out(xfer);
270    }
271}
272
273impl<B, RS, WS> embedded_hal::serial::Write<u8> for SerialPort<'_, B, RS, WS>
274where
275    B: UsbBus,
276    RS: BorrowMut<[u8]>,
277    WS: BorrowMut<[u8]>,
278{
279    type Error = UsbError;
280
281    fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
282        match <SerialPort<'_, B, RS, WS>>::write(self, slice::from_ref(&word)) {
283            Ok(0) | Err(UsbError::WouldBlock) => Err(nb::Error::WouldBlock),
284            Ok(_) => Ok(()),
285            Err(err) => Err(nb::Error::Other(err)),
286        }
287    }
288
289    fn flush(&mut self) -> nb::Result<(), Self::Error> {
290        match <SerialPort<'_, B, RS, WS>>::flush(self) {
291            Err(UsbError::WouldBlock) => Err(nb::Error::WouldBlock),
292            Ok(_) => Ok(()),
293            Err(err) => Err(nb::Error::Other(err)),
294        }
295    }
296}
297
298impl<B, RS, WS> embedded_hal::serial::Read<u8> for SerialPort<'_, B, RS, WS>
299where
300    B: UsbBus,
301    RS: BorrowMut<[u8]>,
302    WS: BorrowMut<[u8]>,
303{
304    type Error = UsbError;
305
306    fn read(&mut self) -> nb::Result<u8, Self::Error> {
307        let mut buf: u8 = 0;
308
309        match <SerialPort<'_, B, RS, WS>>::read(self, slice::from_mut(&mut buf)) {
310            Ok(0) | Err(UsbError::WouldBlock) => Err(nb::Error::WouldBlock),
311            Ok(_) => Ok(buf),
312            Err(err) => Err(nb::Error::Other(err)),
313        }
314    }
315}