Skip to main content

esp_idf_hal/
usb_serial.rs

1//! USB Serial / JTAG peripheral and driver
2//!
3//! Communication through a virtualized UART-like USB-CDC interface.
4#![allow(non_camel_case_types)]
5
6use core::marker::PhantomData;
7
8use crate::io::EspIOError;
9use crate::sys::{
10    esp, usb_serial_jtag_driver_config_t, usb_serial_jtag_driver_install,
11    usb_serial_jtag_driver_uninstall, usb_serial_jtag_is_connected, usb_serial_jtag_read_bytes,
12    usb_serial_jtag_write_bytes, EspError, TickType_t,
13};
14use crate::{delay, gpio};
15
16/// A type alias for the USB Serial driver configuration
17pub type UsbSerialConfig = config::Config;
18
19/// USB D- GPIO pin
20#[cfg(esp32c3)]
21pub type UsbDMinGpio<'d> = gpio::Gpio18<'d>;
22/// USB D+ GPIO pin
23#[cfg(esp32c3)]
24pub type UsbDPlusGpio<'d> = gpio::Gpio19<'d>;
25/// USB D- GPIO pin
26#[cfg(esp32c5)]
27pub type UsbDMinGpio<'d> = gpio::Gpio13<'d>;
28/// USB D+ GPIO pin
29#[cfg(esp32c5)]
30pub type UsbDPlusGpio<'d> = gpio::Gpio14<'d>;
31/// USB D- GPIO pin
32#[cfg(any(esp32c6, esp32c61))]
33pub type UsbDMinGpio<'d> = gpio::Gpio12<'d>;
34/// USB D+ GPIO pin
35#[cfg(any(esp32c6, esp32c61))]
36pub type UsbDPlusGpio<'d> = gpio::Gpio13<'d>;
37/// USB D- GPIO pin
38#[cfg(esp32h2)]
39pub type UsbDMinGpio<'d> = gpio::Gpio26<'d>;
40/// USB D+ GPIO pin
41#[cfg(esp32h2)]
42pub type UsbDPlusGpio<'d> = gpio::Gpio27<'d>;
43/// USB D- GPIO pin
44#[cfg(esp32p4)]
45pub type UsbDMinGpio<'d> = gpio::Gpio24<'d>;
46/// USB D+ GPIO pin
47#[cfg(esp32p4)]
48pub type UsbDPlusGpio<'d> = gpio::Gpio25<'d>;
49// TODO
50// #[cfg(esp32p4)]
51// pub type UsbDMinGpio2<'d> = gpio::Gpio26<'d>;
52// #[cfg(esp32p4)]
53// pub type UsbDPlusGpio2<'d> = gpio::Gpio27<'d>;
54/// USB D- GPIO pin
55#[cfg(esp32s3)]
56pub type UsbDMinGpio<'d> = gpio::Gpio19<'d>;
57/// USB D+ GPIO pin
58#[cfg(esp32s3)]
59pub type UsbDPlusGpio<'d> = gpio::Gpio20<'d>;
60
61/// USB Serial driver configuration
62pub mod config {
63    /// USB Serial driver configuration
64    #[derive(Debug, Clone)]
65    #[non_exhaustive]
66    pub struct Config {
67        pub tx_buffer_size: usize,
68        pub rx_buffer_size: usize,
69    }
70
71    impl Config {
72        /// Create a new configuration with default values
73        pub const fn new() -> Self {
74            Self {
75                tx_buffer_size: 256,
76                rx_buffer_size: 256,
77            }
78        }
79
80        /// Set the transmit buffer size
81        #[must_use]
82        pub fn tx_buffer_size(mut self, tx_buffer_size: usize) -> Self {
83            self.tx_buffer_size = tx_buffer_size;
84            self
85        }
86
87        /// Set the receive buffer size
88        #[must_use]
89        pub fn rx_buffer_size(mut self, rx_buffer_size: usize) -> Self {
90            self.rx_buffer_size = rx_buffer_size;
91            self
92        }
93    }
94
95    impl Default for Config {
96        fn default() -> Self {
97            Self::new()
98        }
99    }
100}
101
102/// USB-SERIAL driver
103pub struct UsbSerialDriver<'d>(PhantomData<&'d mut ()>);
104
105impl<'d> UsbSerialDriver<'d> {
106    /// Create a new USB Serial driver
107    ///
108    /// # Arguments
109    /// - `usb_serial`: The USB Serial peripheral
110    /// - `config`: The driver configuration
111    /// - `usb_d_min`: The USB D- GPIO pin
112    /// - `usb_d_plus`: The USB D+ GPIO pin
113    pub fn new(
114        _usb_serial: USB_SERIAL<'d>,
115        _usb_d_min: UsbDMinGpio<'d>,
116        _usb_d_plus: UsbDPlusGpio<'d>,
117        config: &config::Config,
118    ) -> Result<Self, EspError> {
119        #[allow(clippy::needless_update)]
120        let mut config = usb_serial_jtag_driver_config_t {
121            tx_buffer_size: config.tx_buffer_size as _,
122            rx_buffer_size: config.rx_buffer_size as _,
123            ..Default::default()
124        };
125
126        esp!(unsafe { usb_serial_jtag_driver_install(&mut config) })?;
127
128        Ok(Self(PhantomData))
129    }
130
131    /// Check if the USB Serial is connected
132    pub fn is_connected(&self) -> bool {
133        unsafe { usb_serial_jtag_is_connected() }
134    }
135
136    /// Read bytes into a slice
137    ///
138    /// # Arguments
139    /// - `buf`: The buffer to read into
140    /// - `timeout`: The timeout in ticks
141    ///
142    /// # Returns
143    /// The number of bytes read or an error if the operation failed or the timeout was reached
144    pub fn read(&mut self, buf: &mut [u8], timeout: TickType_t) -> Result<usize, EspError> {
145        let len = unsafe {
146            usb_serial_jtag_read_bytes(buf.as_mut_ptr() as *mut _, buf.len() as _, timeout)
147        };
148
149        Ok(len as _)
150    }
151
152    /// Write bytes from a slice
153    ///
154    /// # Arguments
155    /// - `bytes`: The bytes to write
156    /// - `timeout`: The timeout in ticks
157    ///
158    /// # Returns
159    /// The number of bytes written or an error if the operation failed or the timeout was reached
160    pub fn write(&mut self, bytes: &[u8], timeout: TickType_t) -> Result<usize, EspError> {
161        let len = unsafe {
162            usb_serial_jtag_write_bytes(bytes.as_ptr() as *const _, bytes.len() as _, timeout)
163        };
164
165        Ok(len as _)
166    }
167}
168
169impl Drop for UsbSerialDriver<'_> {
170    fn drop(&mut self) {
171        esp!(unsafe { usb_serial_jtag_driver_uninstall() }).unwrap();
172    }
173}
174
175unsafe impl Send for UsbSerialDriver<'_> {}
176
177impl embedded_io::ErrorType for UsbSerialDriver<'_> {
178    type Error = EspIOError;
179}
180
181impl embedded_io::Read for UsbSerialDriver<'_> {
182    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
183        UsbSerialDriver::read(self, buf, delay::BLOCK).map_err(EspIOError)
184    }
185}
186
187impl embedded_io::Write for UsbSerialDriver<'_> {
188    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
189        UsbSerialDriver::write(self, buf, delay::BLOCK).map_err(EspIOError)
190    }
191
192    fn flush(&mut self) -> Result<(), Self::Error> {
193        Ok(())
194    }
195}
196
197impl embedded_hal_0_2::serial::Write<u8> for UsbSerialDriver<'_> {
198    type Error = EspError;
199
200    fn flush(&mut self) -> nb::Result<(), Self::Error> {
201        Ok(())
202    }
203
204    fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
205        UsbSerialDriver::write(self, &[byte], delay::BLOCK)?;
206
207        Ok(())
208    }
209}
210
211impl core::fmt::Write for UsbSerialDriver<'_> {
212    fn write_str(&mut self, s: &str) -> core::fmt::Result {
213        let buf = s.as_bytes();
214        let mut offset = 0;
215
216        while offset < buf.len() {
217            offset += self
218                .write(buf, delay::BLOCK)
219                .map_err(|_| core::fmt::Error)?
220        }
221
222        Ok(())
223    }
224}
225
226crate::impl_peripheral!(USB_SERIAL);