diff options
| author | Dario Nieuwenhuis <[email protected]> | 2022-09-26 13:00:21 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2022-09-26 13:00:21 +0200 |
| commit | f27a47a37b59bf3b9079f4d4d5f43caf7b7872f8 (patch) | |
| tree | 732f73b4da7a2e726203f2876651a2141d9468be /embassy-usb-serial/src | |
| parent | f4f58249722bc656a13865e06535d208440c3e4a (diff) | |
usb: move classes into the `embassy-usb` crate.
Diffstat (limited to 'embassy-usb-serial/src')
| -rw-r--r-- | embassy-usb-serial/src/fmt.rs | 225 | ||||
| -rw-r--r-- | embassy-usb-serial/src/lib.rs | 359 |
2 files changed, 0 insertions, 584 deletions
diff --git a/embassy-usb-serial/src/fmt.rs b/embassy-usb-serial/src/fmt.rs deleted file mode 100644 index 066970813..000000000 --- a/embassy-usb-serial/src/fmt.rs +++ /dev/null | |||
| @@ -1,225 +0,0 @@ | |||
| 1 | #![macro_use] | ||
| 2 | #![allow(unused_macros)] | ||
| 3 | |||
| 4 | #[cfg(all(feature = "defmt", feature = "log"))] | ||
| 5 | compile_error!("You may not enable both `defmt` and `log` features."); | ||
| 6 | |||
| 7 | macro_rules! assert { | ||
| 8 | ($($x:tt)*) => { | ||
| 9 | { | ||
| 10 | #[cfg(not(feature = "defmt"))] | ||
| 11 | ::core::assert!($($x)*); | ||
| 12 | #[cfg(feature = "defmt")] | ||
| 13 | ::defmt::assert!($($x)*); | ||
| 14 | } | ||
| 15 | }; | ||
| 16 | } | ||
| 17 | |||
| 18 | macro_rules! assert_eq { | ||
| 19 | ($($x:tt)*) => { | ||
| 20 | { | ||
| 21 | #[cfg(not(feature = "defmt"))] | ||
| 22 | ::core::assert_eq!($($x)*); | ||
| 23 | #[cfg(feature = "defmt")] | ||
| 24 | ::defmt::assert_eq!($($x)*); | ||
| 25 | } | ||
| 26 | }; | ||
| 27 | } | ||
| 28 | |||
| 29 | macro_rules! assert_ne { | ||
| 30 | ($($x:tt)*) => { | ||
| 31 | { | ||
| 32 | #[cfg(not(feature = "defmt"))] | ||
| 33 | ::core::assert_ne!($($x)*); | ||
| 34 | #[cfg(feature = "defmt")] | ||
| 35 | ::defmt::assert_ne!($($x)*); | ||
| 36 | } | ||
| 37 | }; | ||
| 38 | } | ||
| 39 | |||
| 40 | macro_rules! debug_assert { | ||
| 41 | ($($x:tt)*) => { | ||
| 42 | { | ||
| 43 | #[cfg(not(feature = "defmt"))] | ||
| 44 | ::core::debug_assert!($($x)*); | ||
| 45 | #[cfg(feature = "defmt")] | ||
| 46 | ::defmt::debug_assert!($($x)*); | ||
| 47 | } | ||
| 48 | }; | ||
| 49 | } | ||
| 50 | |||
| 51 | macro_rules! debug_assert_eq { | ||
| 52 | ($($x:tt)*) => { | ||
| 53 | { | ||
| 54 | #[cfg(not(feature = "defmt"))] | ||
| 55 | ::core::debug_assert_eq!($($x)*); | ||
| 56 | #[cfg(feature = "defmt")] | ||
| 57 | ::defmt::debug_assert_eq!($($x)*); | ||
| 58 | } | ||
| 59 | }; | ||
| 60 | } | ||
| 61 | |||
| 62 | macro_rules! debug_assert_ne { | ||
| 63 | ($($x:tt)*) => { | ||
| 64 | { | ||
| 65 | #[cfg(not(feature = "defmt"))] | ||
| 66 | ::core::debug_assert_ne!($($x)*); | ||
| 67 | #[cfg(feature = "defmt")] | ||
| 68 | ::defmt::debug_assert_ne!($($x)*); | ||
| 69 | } | ||
| 70 | }; | ||
| 71 | } | ||
| 72 | |||
| 73 | macro_rules! todo { | ||
| 74 | ($($x:tt)*) => { | ||
| 75 | { | ||
| 76 | #[cfg(not(feature = "defmt"))] | ||
| 77 | ::core::todo!($($x)*); | ||
| 78 | #[cfg(feature = "defmt")] | ||
| 79 | ::defmt::todo!($($x)*); | ||
| 80 | } | ||
| 81 | }; | ||
| 82 | } | ||
| 83 | |||
| 84 | macro_rules! unreachable { | ||
| 85 | ($($x:tt)*) => { | ||
| 86 | { | ||
| 87 | #[cfg(not(feature = "defmt"))] | ||
| 88 | ::core::unreachable!($($x)*); | ||
| 89 | #[cfg(feature = "defmt")] | ||
| 90 | ::defmt::unreachable!($($x)*); | ||
| 91 | } | ||
| 92 | }; | ||
| 93 | } | ||
| 94 | |||
| 95 | macro_rules! panic { | ||
| 96 | ($($x:tt)*) => { | ||
| 97 | { | ||
| 98 | #[cfg(not(feature = "defmt"))] | ||
| 99 | ::core::panic!($($x)*); | ||
| 100 | #[cfg(feature = "defmt")] | ||
| 101 | ::defmt::panic!($($x)*); | ||
| 102 | } | ||
| 103 | }; | ||
| 104 | } | ||
| 105 | |||
| 106 | macro_rules! trace { | ||
| 107 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 108 | { | ||
| 109 | #[cfg(feature = "log")] | ||
| 110 | ::log::trace!($s $(, $x)*); | ||
| 111 | #[cfg(feature = "defmt")] | ||
| 112 | ::defmt::trace!($s $(, $x)*); | ||
| 113 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 114 | let _ = ($( & $x ),*); | ||
| 115 | } | ||
| 116 | }; | ||
| 117 | } | ||
| 118 | |||
| 119 | macro_rules! debug { | ||
| 120 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 121 | { | ||
| 122 | #[cfg(feature = "log")] | ||
| 123 | ::log::debug!($s $(, $x)*); | ||
| 124 | #[cfg(feature = "defmt")] | ||
| 125 | ::defmt::debug!($s $(, $x)*); | ||
| 126 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 127 | let _ = ($( & $x ),*); | ||
| 128 | } | ||
| 129 | }; | ||
| 130 | } | ||
| 131 | |||
| 132 | macro_rules! info { | ||
| 133 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 134 | { | ||
| 135 | #[cfg(feature = "log")] | ||
| 136 | ::log::info!($s $(, $x)*); | ||
| 137 | #[cfg(feature = "defmt")] | ||
| 138 | ::defmt::info!($s $(, $x)*); | ||
| 139 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 140 | let _ = ($( & $x ),*); | ||
| 141 | } | ||
| 142 | }; | ||
| 143 | } | ||
| 144 | |||
| 145 | macro_rules! warn { | ||
| 146 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 147 | { | ||
| 148 | #[cfg(feature = "log")] | ||
| 149 | ::log::warn!($s $(, $x)*); | ||
| 150 | #[cfg(feature = "defmt")] | ||
| 151 | ::defmt::warn!($s $(, $x)*); | ||
| 152 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 153 | let _ = ($( & $x ),*); | ||
| 154 | } | ||
| 155 | }; | ||
| 156 | } | ||
| 157 | |||
| 158 | macro_rules! error { | ||
| 159 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 160 | { | ||
| 161 | #[cfg(feature = "log")] | ||
| 162 | ::log::error!($s $(, $x)*); | ||
| 163 | #[cfg(feature = "defmt")] | ||
| 164 | ::defmt::error!($s $(, $x)*); | ||
| 165 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 166 | let _ = ($( & $x ),*); | ||
| 167 | } | ||
| 168 | }; | ||
| 169 | } | ||
| 170 | |||
| 171 | #[cfg(feature = "defmt")] | ||
| 172 | macro_rules! unwrap { | ||
| 173 | ($($x:tt)*) => { | ||
| 174 | ::defmt::unwrap!($($x)*) | ||
| 175 | }; | ||
| 176 | } | ||
| 177 | |||
| 178 | #[cfg(not(feature = "defmt"))] | ||
| 179 | macro_rules! unwrap { | ||
| 180 | ($arg:expr) => { | ||
| 181 | match $crate::fmt::Try::into_result($arg) { | ||
| 182 | ::core::result::Result::Ok(t) => t, | ||
| 183 | ::core::result::Result::Err(e) => { | ||
| 184 | ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); | ||
| 185 | } | ||
| 186 | } | ||
| 187 | }; | ||
| 188 | ($arg:expr, $($msg:expr),+ $(,)? ) => { | ||
| 189 | match $crate::fmt::Try::into_result($arg) { | ||
| 190 | ::core::result::Result::Ok(t) => t, | ||
| 191 | ::core::result::Result::Err(e) => { | ||
| 192 | ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 199 | pub struct NoneError; | ||
| 200 | |||
| 201 | pub trait Try { | ||
| 202 | type Ok; | ||
| 203 | type Error; | ||
| 204 | fn into_result(self) -> Result<Self::Ok, Self::Error>; | ||
| 205 | } | ||
| 206 | |||
| 207 | impl<T> Try for Option<T> { | ||
| 208 | type Ok = T; | ||
| 209 | type Error = NoneError; | ||
| 210 | |||
| 211 | #[inline] | ||
| 212 | fn into_result(self) -> Result<T, NoneError> { | ||
| 213 | self.ok_or(NoneError) | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | impl<T, E> Try for Result<T, E> { | ||
| 218 | type Ok = T; | ||
| 219 | type Error = E; | ||
| 220 | |||
| 221 | #[inline] | ||
| 222 | fn into_result(self) -> Self { | ||
| 223 | self | ||
| 224 | } | ||
| 225 | } | ||
diff --git a/embassy-usb-serial/src/lib.rs b/embassy-usb-serial/src/lib.rs deleted file mode 100644 index 15c2bb0a7..000000000 --- a/embassy-usb-serial/src/lib.rs +++ /dev/null | |||
| @@ -1,359 +0,0 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![feature(type_alias_impl_trait)] | ||
| 3 | |||
| 4 | // This mod MUST go first, so that the others see its macros. | ||
| 5 | pub(crate) mod fmt; | ||
| 6 | |||
| 7 | use core::cell::Cell; | ||
| 8 | use core::mem::{self, MaybeUninit}; | ||
| 9 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 10 | |||
| 11 | use embassy_sync::blocking_mutex::CriticalSectionMutex; | ||
| 12 | use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request}; | ||
| 13 | use embassy_usb::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; | ||
| 14 | use embassy_usb::types::*; | ||
| 15 | use embassy_usb::Builder; | ||
| 16 | |||
| 17 | /// This should be used as `device_class` when building the `UsbDevice`. | ||
| 18 | pub const USB_CLASS_CDC: u8 = 0x02; | ||
| 19 | |||
| 20 | const USB_CLASS_CDC_DATA: u8 = 0x0a; | ||
| 21 | const CDC_SUBCLASS_ACM: u8 = 0x02; | ||
| 22 | const CDC_PROTOCOL_NONE: u8 = 0x00; | ||
| 23 | |||
| 24 | const CS_INTERFACE: u8 = 0x24; | ||
| 25 | const CDC_TYPE_HEADER: u8 = 0x00; | ||
| 26 | const CDC_TYPE_CALL_MANAGEMENT: u8 = 0x01; | ||
| 27 | const CDC_TYPE_ACM: u8 = 0x02; | ||
| 28 | const CDC_TYPE_UNION: u8 = 0x06; | ||
| 29 | |||
| 30 | const REQ_SEND_ENCAPSULATED_COMMAND: u8 = 0x00; | ||
| 31 | #[allow(unused)] | ||
| 32 | const REQ_GET_ENCAPSULATED_COMMAND: u8 = 0x01; | ||
| 33 | const REQ_SET_LINE_CODING: u8 = 0x20; | ||
| 34 | const REQ_GET_LINE_CODING: u8 = 0x21; | ||
| 35 | const REQ_SET_CONTROL_LINE_STATE: u8 = 0x22; | ||
| 36 | |||
| 37 | pub struct State<'a> { | ||
| 38 | control: MaybeUninit<Control<'a>>, | ||
| 39 | shared: ControlShared, | ||
| 40 | } | ||
| 41 | |||
| 42 | impl<'a> State<'a> { | ||
| 43 | pub fn new() -> Self { | ||
| 44 | Self { | ||
| 45 | control: MaybeUninit::uninit(), | ||
| 46 | shared: Default::default(), | ||
| 47 | } | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | /// Packet level implementation of a CDC-ACM serial port. | ||
| 52 | /// | ||
| 53 | /// This class can be used directly and it has the least overhead due to directly reading and | ||
| 54 | /// writing USB packets with no intermediate buffers, but it will not act like a stream-like serial | ||
| 55 | /// port. The following constraints must be followed if you use this class directly: | ||
| 56 | /// | ||
| 57 | /// - `read_packet` must be called with a buffer large enough to hold max_packet_size bytes. | ||
| 58 | /// - `write_packet` must not be called with a buffer larger than max_packet_size bytes. | ||
| 59 | /// - If you write a packet that is exactly max_packet_size bytes long, it won't be processed by the | ||
| 60 | /// host operating system until a subsequent shorter packet is sent. A zero-length packet (ZLP) | ||
| 61 | /// can be sent if there is no other data to send. This is because USB bulk transactions must be | ||
| 62 | /// terminated with a short packet, even if the bulk endpoint is used for stream-like data. | ||
| 63 | pub struct CdcAcmClass<'d, D: Driver<'d>> { | ||
| 64 | _comm_ep: D::EndpointIn, | ||
| 65 | _data_if: InterfaceNumber, | ||
| 66 | read_ep: D::EndpointOut, | ||
| 67 | write_ep: D::EndpointIn, | ||
| 68 | control: &'d ControlShared, | ||
| 69 | } | ||
| 70 | |||
| 71 | struct Control<'a> { | ||
| 72 | shared: &'a ControlShared, | ||
| 73 | } | ||
| 74 | |||
| 75 | /// Shared data between Control and CdcAcmClass | ||
| 76 | struct ControlShared { | ||
| 77 | line_coding: CriticalSectionMutex<Cell<LineCoding>>, | ||
| 78 | dtr: AtomicBool, | ||
| 79 | rts: AtomicBool, | ||
| 80 | } | ||
| 81 | |||
| 82 | impl Default for ControlShared { | ||
| 83 | fn default() -> Self { | ||
| 84 | ControlShared { | ||
| 85 | dtr: AtomicBool::new(false), | ||
| 86 | rts: AtomicBool::new(false), | ||
| 87 | line_coding: CriticalSectionMutex::new(Cell::new(LineCoding { | ||
| 88 | stop_bits: StopBits::One, | ||
| 89 | data_bits: 8, | ||
| 90 | parity_type: ParityType::None, | ||
| 91 | data_rate: 8_000, | ||
| 92 | })), | ||
| 93 | } | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | impl<'a> Control<'a> { | ||
| 98 | fn shared(&mut self) -> &'a ControlShared { | ||
| 99 | self.shared | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | impl<'d> ControlHandler for Control<'d> { | ||
| 104 | fn reset(&mut self) { | ||
| 105 | let shared = self.shared(); | ||
| 106 | shared.line_coding.lock(|x| x.set(LineCoding::default())); | ||
| 107 | shared.dtr.store(false, Ordering::Relaxed); | ||
| 108 | shared.rts.store(false, Ordering::Relaxed); | ||
| 109 | } | ||
| 110 | |||
| 111 | fn control_out(&mut self, req: control::Request, data: &[u8]) -> OutResponse { | ||
| 112 | match req.request { | ||
| 113 | REQ_SEND_ENCAPSULATED_COMMAND => { | ||
| 114 | // We don't actually support encapsulated commands but pretend we do for standards | ||
| 115 | // compatibility. | ||
| 116 | OutResponse::Accepted | ||
| 117 | } | ||
| 118 | REQ_SET_LINE_CODING if data.len() >= 7 => { | ||
| 119 | let coding = LineCoding { | ||
| 120 | data_rate: u32::from_le_bytes(data[0..4].try_into().unwrap()), | ||
| 121 | stop_bits: data[4].into(), | ||
| 122 | parity_type: data[5].into(), | ||
| 123 | data_bits: data[6], | ||
| 124 | }; | ||
| 125 | self.shared().line_coding.lock(|x| x.set(coding)); | ||
| 126 | debug!("Set line coding to: {:?}", coding); | ||
| 127 | |||
| 128 | OutResponse::Accepted | ||
| 129 | } | ||
| 130 | REQ_SET_CONTROL_LINE_STATE => { | ||
| 131 | let dtr = (req.value & 0x0001) != 0; | ||
| 132 | let rts = (req.value & 0x0002) != 0; | ||
| 133 | |||
| 134 | let shared = self.shared(); | ||
| 135 | shared.dtr.store(dtr, Ordering::Relaxed); | ||
| 136 | shared.rts.store(rts, Ordering::Relaxed); | ||
| 137 | debug!("Set dtr {}, rts {}", dtr, rts); | ||
| 138 | |||
| 139 | OutResponse::Accepted | ||
| 140 | } | ||
| 141 | _ => OutResponse::Rejected, | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> { | ||
| 146 | match req.request { | ||
| 147 | // REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below. | ||
| 148 | REQ_GET_LINE_CODING if req.length == 7 => { | ||
| 149 | debug!("Sending line coding"); | ||
| 150 | let coding = self.shared().line_coding.lock(|x| x.get()); | ||
| 151 | assert!(buf.len() >= 7); | ||
| 152 | buf[0..4].copy_from_slice(&coding.data_rate.to_le_bytes()); | ||
| 153 | buf[4] = coding.stop_bits as u8; | ||
| 154 | buf[5] = coding.parity_type as u8; | ||
| 155 | buf[6] = coding.data_bits; | ||
| 156 | InResponse::Accepted(&buf[0..7]) | ||
| 157 | } | ||
| 158 | _ => InResponse::Rejected, | ||
| 159 | } | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> { | ||
| 164 | /// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For | ||
| 165 | /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64. | ||
| 166 | pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, max_packet_size: u16) -> Self { | ||
| 167 | let control = state.control.write(Control { shared: &state.shared }); | ||
| 168 | |||
| 169 | let control_shared = &state.shared; | ||
| 170 | |||
| 171 | assert!(builder.control_buf_len() >= 7); | ||
| 172 | |||
| 173 | let mut func = builder.function(USB_CLASS_CDC, CDC_SUBCLASS_ACM, CDC_PROTOCOL_NONE); | ||
| 174 | |||
| 175 | // Control interface | ||
| 176 | let mut iface = func.interface(); | ||
| 177 | iface.handler(control); | ||
| 178 | let comm_if = iface.interface_number(); | ||
| 179 | let data_if = u8::from(comm_if) + 1; | ||
| 180 | let mut alt = iface.alt_setting(USB_CLASS_CDC, CDC_SUBCLASS_ACM, CDC_PROTOCOL_NONE); | ||
| 181 | |||
| 182 | alt.descriptor( | ||
| 183 | CS_INTERFACE, | ||
| 184 | &[ | ||
| 185 | CDC_TYPE_HEADER, // bDescriptorSubtype | ||
| 186 | 0x10, | ||
| 187 | 0x01, // bcdCDC (1.10) | ||
| 188 | ], | ||
| 189 | ); | ||
| 190 | alt.descriptor( | ||
| 191 | CS_INTERFACE, | ||
| 192 | &[ | ||
| 193 | CDC_TYPE_ACM, // bDescriptorSubtype | ||
| 194 | 0x00, // bmCapabilities | ||
| 195 | ], | ||
| 196 | ); | ||
| 197 | alt.descriptor( | ||
| 198 | CS_INTERFACE, | ||
| 199 | &[ | ||
| 200 | CDC_TYPE_UNION, // bDescriptorSubtype | ||
| 201 | comm_if.into(), // bControlInterface | ||
| 202 | data_if.into(), // bSubordinateInterface | ||
| 203 | ], | ||
| 204 | ); | ||
| 205 | alt.descriptor( | ||
| 206 | CS_INTERFACE, | ||
| 207 | &[ | ||
| 208 | CDC_TYPE_CALL_MANAGEMENT, // bDescriptorSubtype | ||
| 209 | 0x00, // bmCapabilities | ||
| 210 | data_if.into(), // bDataInterface | ||
| 211 | ], | ||
| 212 | ); | ||
| 213 | |||
| 214 | let comm_ep = alt.endpoint_interrupt_in(8, 255); | ||
| 215 | |||
| 216 | // Data interface | ||
| 217 | let mut iface = func.interface(); | ||
| 218 | let data_if = iface.interface_number(); | ||
| 219 | let mut alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NONE); | ||
| 220 | let read_ep = alt.endpoint_bulk_out(max_packet_size); | ||
| 221 | let write_ep = alt.endpoint_bulk_in(max_packet_size); | ||
| 222 | |||
| 223 | CdcAcmClass { | ||
| 224 | _comm_ep: comm_ep, | ||
| 225 | _data_if: data_if, | ||
| 226 | read_ep, | ||
| 227 | write_ep, | ||
| 228 | control: control_shared, | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | /// Gets the maximum packet size in bytes. | ||
| 233 | pub fn max_packet_size(&self) -> u16 { | ||
| 234 | // The size is the same for both endpoints. | ||
| 235 | self.read_ep.info().max_packet_size | ||
| 236 | } | ||
| 237 | |||
| 238 | /// Gets the current line coding. The line coding contains information that's mainly relevant | ||
| 239 | /// for USB to UART serial port emulators, and can be ignored if not relevant. | ||
| 240 | pub fn line_coding(&self) -> LineCoding { | ||
| 241 | self.control.line_coding.lock(|x| x.get()) | ||
| 242 | } | ||
| 243 | |||
| 244 | /// Gets the DTR (data terminal ready) state | ||
| 245 | pub fn dtr(&self) -> bool { | ||
| 246 | self.control.dtr.load(Ordering::Relaxed) | ||
| 247 | } | ||
| 248 | |||
| 249 | /// Gets the RTS (request to send) state | ||
| 250 | pub fn rts(&self) -> bool { | ||
| 251 | self.control.rts.load(Ordering::Relaxed) | ||
| 252 | } | ||
| 253 | |||
| 254 | /// Writes a single packet into the IN endpoint. | ||
| 255 | pub async fn write_packet(&mut self, data: &[u8]) -> Result<(), EndpointError> { | ||
| 256 | self.write_ep.write(data).await | ||
| 257 | } | ||
| 258 | |||
| 259 | /// Reads a single packet from the OUT endpoint. | ||
| 260 | pub async fn read_packet(&mut self, data: &mut [u8]) -> Result<usize, EndpointError> { | ||
| 261 | self.read_ep.read(data).await | ||
| 262 | } | ||
| 263 | |||
| 264 | /// Waits for the USB host to enable this interface | ||
| 265 | pub async fn wait_connection(&mut self) { | ||
| 266 | self.read_ep.wait_enabled().await | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 270 | /// Number of stop bits for LineCoding | ||
| 271 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
| 272 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 273 | pub enum StopBits { | ||
| 274 | /// 1 stop bit | ||
| 275 | One = 0, | ||
| 276 | |||
| 277 | /// 1.5 stop bits | ||
| 278 | OnePointFive = 1, | ||
| 279 | |||
| 280 | /// 2 stop bits | ||
| 281 | Two = 2, | ||
| 282 | } | ||
| 283 | |||
| 284 | impl From<u8> for StopBits { | ||
| 285 | fn from(value: u8) -> Self { | ||
| 286 | if value <= 2 { | ||
| 287 | unsafe { mem::transmute(value) } | ||
| 288 | } else { | ||
| 289 | StopBits::One | ||
| 290 | } | ||
| 291 | } | ||
| 292 | } | ||
| 293 | |||
| 294 | /// Parity for LineCoding | ||
| 295 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
| 296 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 297 | pub enum ParityType { | ||
| 298 | None = 0, | ||
| 299 | Odd = 1, | ||
| 300 | Even = 2, | ||
| 301 | Mark = 3, | ||
| 302 | Space = 4, | ||
| 303 | } | ||
| 304 | |||
| 305 | impl From<u8> for ParityType { | ||
| 306 | fn from(value: u8) -> Self { | ||
| 307 | if value <= 4 { | ||
| 308 | unsafe { mem::transmute(value) } | ||
| 309 | } else { | ||
| 310 | ParityType::None | ||
| 311 | } | ||
| 312 | } | ||
| 313 | } | ||
| 314 | |||
| 315 | /// Line coding parameters | ||
| 316 | /// | ||
| 317 | /// This is provided by the host for specifying the standard UART parameters such as baud rate. Can | ||
| 318 | /// be ignored if you don't plan to interface with a physical UART. | ||
| 319 | #[derive(Clone, Copy, Debug)] | ||
| 320 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 321 | pub struct LineCoding { | ||
| 322 | stop_bits: StopBits, | ||
| 323 | data_bits: u8, | ||
| 324 | parity_type: ParityType, | ||
| 325 | data_rate: u32, | ||
| 326 | } | ||
| 327 | |||
| 328 | impl LineCoding { | ||
| 329 | /// Gets the number of stop bits for UART communication. | ||
| 330 | pub fn stop_bits(&self) -> StopBits { | ||
| 331 | self.stop_bits | ||
| 332 | } | ||
| 333 | |||
| 334 | /// Gets the number of data bits for UART communication. | ||
| 335 | pub fn data_bits(&self) -> u8 { | ||
| 336 | self.data_bits | ||
| 337 | } | ||
| 338 | |||
| 339 | /// Gets the parity type for UART communication. | ||
| 340 | pub fn parity_type(&self) -> ParityType { | ||
| 341 | self.parity_type | ||
| 342 | } | ||
| 343 | |||
| 344 | /// Gets the data rate in bits per second for UART communication. | ||
| 345 | pub fn data_rate(&self) -> u32 { | ||
| 346 | self.data_rate | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | impl Default for LineCoding { | ||
| 351 | fn default() -> Self { | ||
| 352 | LineCoding { | ||
| 353 | stop_bits: StopBits::One, | ||
| 354 | data_bits: 8, | ||
| 355 | parity_type: ParityType::None, | ||
| 356 | data_rate: 8_000, | ||
| 357 | } | ||
| 358 | } | ||
| 359 | } | ||
