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        let mut config = usb_serial_jtag_driver_config_t {
120            tx_buffer_size: config.tx_buffer_size as _,
121            rx_buffer_size: config.rx_buffer_size as _,
122        };
123
124        esp!(unsafe { usb_serial_jtag_driver_install(&mut config) })?;
125
126        Ok(Self(PhantomData))
127    }
128
129    /// Check if the USB Serial is connected
130    pub fn is_connected(&self) -> bool {
131        unsafe { usb_serial_jtag_is_connected() }
132    }
133
134    /// Read bytes into a slice
135    ///
136    /// # Arguments
137    /// - `buf`: The buffer to read into
138    /// - `timeout`: The timeout in ticks
139    ///
140    /// # Returns
141    /// The number of bytes read or an error if the operation failed or the timeout was reached
142    pub fn read(&mut self, buf: &mut [u8], timeout: TickType_t) -> Result<usize, EspError> {
143        let len = unsafe {
144            usb_serial_jtag_read_bytes(buf.as_mut_ptr() as *mut _, buf.len() as _, timeout)
145        };
146
147        Ok(len as _)
148    }
149
150    /// Write bytes from a slice
151    ///
152    /// # Arguments
153    /// - `bytes`: The bytes to write
154    /// - `timeout`: The timeout in ticks
155    ///
156    /// # Returns
157    /// The number of bytes written or an error if the operation failed or the timeout was reached
158    pub fn write(&mut self, bytes: &[u8], timeout: TickType_t) -> Result<usize, EspError> {
159        let len = unsafe {
160            usb_serial_jtag_write_bytes(bytes.as_ptr() as *const _, bytes.len() as _, timeout)
161        };
162
163        Ok(len as _)
164    }
165}
166
167impl Drop for UsbSerialDriver<'_> {
168    fn drop(&mut self) {
169        esp!(unsafe { usb_serial_jtag_driver_uninstall() }).unwrap();
170    }
171}
172
173unsafe impl Send for UsbSerialDriver<'_> {}
174
175impl embedded_io::ErrorType for UsbSerialDriver<'_> {
176    type Error = EspIOError;
177}
178
179impl embedded_io::Read for UsbSerialDriver<'_> {
180    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
181        UsbSerialDriver::read(self, buf, delay::BLOCK).map_err(EspIOError)
182    }
183}
184
185impl embedded_io::Write for UsbSerialDriver<'_> {
186    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
187        UsbSerialDriver::write(self, buf, delay::BLOCK).map_err(EspIOError)
188    }
189
190    fn flush(&mut self) -> Result<(), Self::Error> {
191        Ok(())
192    }
193}
194
195impl embedded_hal_0_2::serial::Write<u8> for UsbSerialDriver<'_> {
196    type Error = EspError;
197
198    fn flush(&mut self) -> nb::Result<(), Self::Error> {
199        Ok(())
200    }
201
202    fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
203        UsbSerialDriver::write(self, &[byte], delay::BLOCK)?;
204
205        Ok(())
206    }
207}
208
209impl core::fmt::Write for UsbSerialDriver<'_> {
210    fn write_str(&mut self, s: &str) -> core::fmt::Result {
211        let buf = s.as_bytes();
212        let mut offset = 0;
213
214        while offset < buf.len() {
215            offset += self
216                .write(buf, delay::BLOCK)
217                .map_err(|_| core::fmt::Error)?
218        }
219
220        Ok(())
221    }
222}
223
224crate::impl_peripheral!(USB_SERIAL);