diff --git a/embassy-hal-common/Cargo.toml b/embassy-hal-common/Cargo.toml index 2028b0e0c..fee6da6ff 100644 --- a/embassy-hal-common/Cargo.toml +++ b/embassy-hal-common/Cargo.toml @@ -12,5 +12,4 @@ embassy = { version = "0.1.0", path = "../embassy" } defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } cortex-m = "0.7.3" -usb-device = "0.2.8" num-traits = { version = "0.2.14", default-features = false } diff --git a/embassy-hal-common/src/lib.rs b/embassy-hal-common/src/lib.rs index 1af30c6b4..6ee2ccd59 100644 --- a/embassy-hal-common/src/lib.rs +++ b/embassy-hal-common/src/lib.rs @@ -10,7 +10,6 @@ mod macros; pub mod peripheral; pub mod ratio; pub mod ring_buffer; -pub mod usb; /// Low power blocking wait loop using WFE/SEV. pub fn low_power_wait_until(mut condition: impl FnMut() -> bool) { diff --git a/embassy-hal-common/src/usb/cdc_acm.rs b/embassy-hal-common/src/usb/cdc_acm.rs deleted file mode 100644 index 5a85b3846..000000000 --- a/embassy-hal-common/src/usb/cdc_acm.rs +++ /dev/null @@ -1,338 +0,0 @@ -// Copied from https://github.com/mvirkkunen/usbd-serial -#![allow(dead_code)] - -use core::convert::TryInto; -use core::mem; -use usb_device::class_prelude::*; -use usb_device::Result; - -/// This should be used as `device_class` when building the `UsbDevice`. -pub const USB_CLASS_CDC: u8 = 0x02; - -const USB_CLASS_CDC_DATA: u8 = 0x0a; -const CDC_SUBCLASS_ACM: u8 = 0x02; -const CDC_PROTOCOL_NONE: u8 = 0x00; - -const CS_INTERFACE: u8 = 0x24; -const CDC_TYPE_HEADER: u8 = 0x00; -const CDC_TYPE_CALL_MANAGEMENT: u8 = 0x01; -const CDC_TYPE_ACM: u8 = 0x02; -const CDC_TYPE_UNION: u8 = 0x06; - -const REQ_SEND_ENCAPSULATED_COMMAND: u8 = 0x00; -#[allow(unused)] -const REQ_GET_ENCAPSULATED_COMMAND: u8 = 0x01; -const REQ_SET_LINE_CODING: u8 = 0x20; -const REQ_GET_LINE_CODING: u8 = 0x21; -const REQ_SET_CONTROL_LINE_STATE: u8 = 0x22; - -/// Packet level implementation of a CDC-ACM serial port. -/// -/// This class can be used directly and it has the least overhead due to directly reading and -/// writing USB packets with no intermediate buffers, but it will not act like a stream-like serial -/// port. The following constraints must be followed if you use this class directly: -/// -/// - `read_packet` must be called with a buffer large enough to hold max_packet_size bytes, and the -/// method will return a `WouldBlock` error if there is no packet to be read. -/// - `write_packet` must not be called with a buffer larger than max_packet_size bytes, and the -/// method will return a `WouldBlock` error if the previous packet has not been sent yet. -/// - If you write a packet that is exactly max_packet_size bytes long, it won't be processed by the -/// host operating system until a subsequent shorter packet is sent. A zero-length packet (ZLP) -/// can be sent if there is no other data to send. This is because USB bulk transactions must be -/// terminated with a short packet, even if the bulk endpoint is used for stream-like data. -pub struct CdcAcmClass<'a, B: UsbBus> { - comm_if: InterfaceNumber, - comm_ep: EndpointIn<'a, B>, - data_if: InterfaceNumber, - read_ep: EndpointOut<'a, B>, - write_ep: EndpointIn<'a, B>, - line_coding: LineCoding, - dtr: bool, - rts: bool, -} - -impl CdcAcmClass<'_, B> { - /// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For - /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64. - pub fn new(alloc: &UsbBusAllocator, max_packet_size: u16) -> CdcAcmClass<'_, B> { - CdcAcmClass { - comm_if: alloc.interface(), - comm_ep: alloc.interrupt(8, 255), - data_if: alloc.interface(), - read_ep: alloc.bulk(max_packet_size), - write_ep: alloc.bulk(max_packet_size), - line_coding: LineCoding { - stop_bits: StopBits::One, - data_bits: 8, - parity_type: ParityType::None, - data_rate: 8_000, - }, - dtr: false, - rts: false, - } - } - - /// Gets the maximum packet size in bytes. - pub fn max_packet_size(&self) -> u16 { - // The size is the same for both endpoints. - self.read_ep.max_packet_size() - } - - /// Gets the current line coding. The line coding contains information that's mainly relevant - /// for USB to UART serial port emulators, and can be ignored if not relevant. - pub fn line_coding(&self) -> &LineCoding { - &self.line_coding - } - - /// Gets the DTR (data terminal ready) state - pub fn dtr(&self) -> bool { - self.dtr - } - - /// Gets the RTS (request to send) state - pub fn rts(&self) -> bool { - self.rts - } - - /// Writes a single packet into the IN endpoint. - pub fn write_packet(&mut self, data: &[u8]) -> Result { - self.write_ep.write(data) - } - - /// Reads a single packet from the OUT endpoint. - pub fn read_packet(&mut self, data: &mut [u8]) -> Result { - self.read_ep.read(data) - } - - /// Gets the address of the IN endpoint. - pub fn write_ep_address(&self) -> EndpointAddress { - self.write_ep.address() - } - - /// Gets the address of the OUT endpoint. - pub fn read_ep_address(&self) -> EndpointAddress { - self.read_ep.address() - } -} - -impl UsbClass for CdcAcmClass<'_, B> { - fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> { - writer.iad( - self.comm_if, - 2, - USB_CLASS_CDC, - CDC_SUBCLASS_ACM, - CDC_PROTOCOL_NONE, - )?; - - writer.interface( - self.comm_if, - USB_CLASS_CDC, - CDC_SUBCLASS_ACM, - CDC_PROTOCOL_NONE, - )?; - - writer.write( - CS_INTERFACE, - &[ - CDC_TYPE_HEADER, // bDescriptorSubtype - 0x10, - 0x01, // bcdCDC (1.10) - ], - )?; - - writer.write( - CS_INTERFACE, - &[ - CDC_TYPE_ACM, // bDescriptorSubtype - 0x00, // bmCapabilities - ], - )?; - - writer.write( - CS_INTERFACE, - &[ - CDC_TYPE_UNION, // bDescriptorSubtype - self.comm_if.into(), // bControlInterface - self.data_if.into(), // bSubordinateInterface - ], - )?; - - writer.write( - CS_INTERFACE, - &[ - CDC_TYPE_CALL_MANAGEMENT, // bDescriptorSubtype - 0x00, // bmCapabilities - self.data_if.into(), // bDataInterface - ], - )?; - - writer.endpoint(&self.comm_ep)?; - - writer.interface(self.data_if, USB_CLASS_CDC_DATA, 0x00, 0x00)?; - - writer.endpoint(&self.write_ep)?; - writer.endpoint(&self.read_ep)?; - - Ok(()) - } - - fn reset(&mut self) { - self.line_coding = LineCoding::default(); - self.dtr = false; - self.rts = false; - } - - fn control_in(&mut self, xfer: ControlIn) { - let req = xfer.request(); - - if !(req.request_type == control::RequestType::Class - && req.recipient == control::Recipient::Interface - && req.index == u8::from(self.comm_if) as u16) - { - return; - } - - match req.request { - // REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below. - REQ_GET_LINE_CODING if req.length == 7 => { - xfer.accept(|data| { - data[0..4].copy_from_slice(&self.line_coding.data_rate.to_le_bytes()); - data[4] = self.line_coding.stop_bits as u8; - data[5] = self.line_coding.parity_type as u8; - data[6] = self.line_coding.data_bits; - - Ok(7) - }) - .ok(); - } - _ => { - xfer.reject().ok(); - } - } - } - - fn control_out(&mut self, xfer: ControlOut) { - let req = xfer.request(); - - if !(req.request_type == control::RequestType::Class - && req.recipient == control::Recipient::Interface - && req.index == u8::from(self.comm_if) as u16) - { - return; - } - - match req.request { - REQ_SEND_ENCAPSULATED_COMMAND => { - // We don't actually support encapsulated commands but pretend we do for standards - // compatibility. - xfer.accept().ok(); - } - REQ_SET_LINE_CODING if xfer.data().len() >= 7 => { - self.line_coding.data_rate = - u32::from_le_bytes(xfer.data()[0..4].try_into().unwrap()); - self.line_coding.stop_bits = xfer.data()[4].into(); - self.line_coding.parity_type = xfer.data()[5].into(); - self.line_coding.data_bits = xfer.data()[6]; - - xfer.accept().ok(); - } - REQ_SET_CONTROL_LINE_STATE => { - self.dtr = (req.value & 0x0001) != 0; - self.rts = (req.value & 0x0002) != 0; - - xfer.accept().ok(); - } - _ => { - xfer.reject().ok(); - } - }; - } -} - -/// Number of stop bits for LineCoding -#[derive(Copy, Clone, PartialEq, Eq)] -pub enum StopBits { - /// 1 stop bit - One = 0, - - /// 1.5 stop bits - OnePointFive = 1, - - /// 2 stop bits - Two = 2, -} - -impl From for StopBits { - fn from(value: u8) -> Self { - if value <= 2 { - unsafe { mem::transmute(value) } - } else { - StopBits::One - } - } -} - -/// Parity for LineCoding -#[derive(Copy, Clone, PartialEq, Eq)] -pub enum ParityType { - None = 0, - Odd = 1, - Event = 2, - Mark = 3, - Space = 4, -} - -impl From for ParityType { - fn from(value: u8) -> Self { - if value <= 4 { - unsafe { mem::transmute(value) } - } else { - ParityType::None - } - } -} - -/// Line coding parameters -/// -/// This is provided by the host for specifying the standard UART parameters such as baud rate. Can -/// be ignored if you don't plan to interface with a physical UART. -pub struct LineCoding { - stop_bits: StopBits, - data_bits: u8, - parity_type: ParityType, - data_rate: u32, -} - -impl LineCoding { - /// Gets the number of stop bits for UART communication. - pub fn stop_bits(&self) -> StopBits { - self.stop_bits - } - - /// Gets the number of data bits for UART communication. - pub fn data_bits(&self) -> u8 { - self.data_bits - } - - /// Gets the parity type for UART communication. - pub fn parity_type(&self) -> ParityType { - self.parity_type - } - - /// Gets the data rate in bits per second for UART communication. - pub fn data_rate(&self) -> u32 { - self.data_rate - } -} - -impl Default for LineCoding { - fn default() -> Self { - LineCoding { - stop_bits: StopBits::One, - data_bits: 8, - parity_type: ParityType::None, - data_rate: 8_000, - } - } -} diff --git a/embassy-hal-common/src/usb/mod.rs b/embassy-hal-common/src/usb/mod.rs deleted file mode 100644 index bab72d8b6..000000000 --- a/embassy-hal-common/src/usb/mod.rs +++ /dev/null @@ -1,267 +0,0 @@ -use core::cell::RefCell; -use core::marker::PhantomData; -use core::pin::Pin; - -use usb_device::bus::UsbBus; -use usb_device::class::UsbClass; -use usb_device::device::UsbDevice; - -mod cdc_acm; -pub mod usb_serial; - -use crate::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; -use embassy::interrupt::Interrupt; -pub use usb_serial::{ReadInterface, UsbSerial, WriteInterface}; - -/// Marker trait to mark an interrupt to be used with the [`Usb`] abstraction. -pub unsafe trait USBInterrupt: Interrupt + Send {} - -pub struct State<'bus, B, T, I>(StateStorage>) -where - B: UsbBus, - T: ClassSet, - I: USBInterrupt; - -impl<'bus, B, T, I> State<'bus, B, T, I> -where - B: UsbBus, - T: ClassSet, - I: USBInterrupt, -{ - pub fn new() -> Self { - Self(StateStorage::new()) - } -} - -pub(crate) struct StateInner<'bus, B, T, I> -where - B: UsbBus, - T: ClassSet, - I: USBInterrupt, -{ - device: UsbDevice<'bus, B>, - pub(crate) classes: T, - _interrupt: PhantomData, -} - -pub struct Usb<'bus, B, T, I> -where - B: UsbBus, - T: ClassSet, - I: USBInterrupt, -{ - // Don't you dare moving out `PeripheralMutex` - inner: RefCell>>, -} - -impl<'bus, B, T, I> Usb<'bus, B, T, I> -where - B: UsbBus, - T: ClassSet, - I: USBInterrupt, -{ - /// safety: the returned instance is not leak-safe - pub unsafe fn new>( - state: &'bus mut State<'bus, B, T, I>, - device: UsbDevice<'bus, B>, - class_set: S, - irq: I, - ) -> Self { - let mutex = PeripheralMutex::new_unchecked(irq, &mut state.0, || StateInner { - device, - classes: class_set.into_class_set(), - _interrupt: PhantomData, - }); - Self { - inner: RefCell::new(mutex), - } - } -} - -impl<'bus, 'c, B, T, I> Usb<'bus, B, T, I> -where - B: UsbBus, - T: ClassSet + SerialState<'bus, 'c, B, Index0>, - I: USBInterrupt, -{ - /// Take a serial class that was passed as the first class in a tuple - pub fn take_serial_0<'a>( - self: Pin<&'a Self>, - ) -> ( - ReadInterface<'a, 'bus, 'c, Index0, B, T, I>, - WriteInterface<'a, 'bus, 'c, Index0, B, T, I>, - ) { - let this = self.get_ref(); - - let r = ReadInterface { - inner: &this.inner, - _buf_lifetime: PhantomData, - _index: PhantomData, - }; - - let w = WriteInterface { - inner: &this.inner, - _buf_lifetime: PhantomData, - _index: PhantomData, - }; - (r, w) - } -} - -impl<'bus, 'c, B, T, I> Usb<'bus, B, T, I> -where - B: UsbBus, - T: ClassSet + SerialState<'bus, 'c, B, Index1>, - I: USBInterrupt, -{ - /// Take a serial class that was passed as the second class in a tuple - pub fn take_serial_1<'a>( - self: Pin<&'a Self>, - ) -> ( - ReadInterface<'a, 'bus, 'c, Index1, B, T, I>, - WriteInterface<'a, 'bus, 'c, Index1, B, T, I>, - ) { - let this = self.get_ref(); - - let r = ReadInterface { - inner: &this.inner, - _buf_lifetime: PhantomData, - _index: PhantomData, - }; - - let w = WriteInterface { - inner: &this.inner, - _buf_lifetime: PhantomData, - _index: PhantomData, - }; - (r, w) - } -} - -impl<'bus, B, T, I> PeripheralState for StateInner<'bus, B, T, I> -where - B: UsbBus, - T: ClassSet, - I: USBInterrupt, -{ - type Interrupt = I; - fn on_interrupt(&mut self) { - self.classes.poll_all(&mut self.device); - } -} - -pub trait ClassSet: Send { - fn poll_all(&mut self, device: &mut UsbDevice<'_, B>) -> bool; -} - -pub trait IntoClassSet> { - fn into_class_set(self) -> C; -} - -pub struct ClassSet1 -where - B: UsbBus, - C1: UsbClass, -{ - class: C1, - _bus: PhantomData, -} - -pub struct ClassSet2 -where - B: UsbBus, - C1: UsbClass, - C2: UsbClass, -{ - class1: C1, - class2: C2, - _bus: PhantomData, -} - -/// The first class into a [`ClassSet`] -pub struct Index0; - -/// The second class into a [`ClassSet`] -pub struct Index1; - -impl ClassSet for ClassSet1 -where - B: UsbBus + Send, - C1: UsbClass + Send, -{ - fn poll_all(&mut self, device: &mut UsbDevice<'_, B>) -> bool { - device.poll(&mut [&mut self.class]) - } -} - -impl ClassSet for ClassSet2 -where - B: UsbBus + Send, - C1: UsbClass + Send, - C2: UsbClass + Send, -{ - fn poll_all(&mut self, device: &mut UsbDevice<'_, B>) -> bool { - device.poll(&mut [&mut self.class1, &mut self.class2]) - } -} - -impl IntoClassSet> for C1 -where - B: UsbBus + Send, - C1: UsbClass + Send, -{ - fn into_class_set(self) -> ClassSet1 { - ClassSet1 { - class: self, - _bus: PhantomData, - } - } -} - -impl IntoClassSet> for (C1, C2) -where - B: UsbBus + Send, - C1: UsbClass + Send, - C2: UsbClass + Send, -{ - fn into_class_set(self) -> ClassSet2 { - ClassSet2 { - class1: self.0, - class2: self.1, - _bus: PhantomData, - } - } -} - -/// Trait for a USB State that has a serial class inside -pub trait SerialState<'bus, 'a, B: UsbBus, I> { - fn get_serial(&mut self) -> &mut UsbSerial<'bus, 'a, B>; -} - -impl<'bus, 'a, B: UsbBus> SerialState<'bus, 'a, B, Index0> - for ClassSet1> -{ - fn get_serial(&mut self) -> &mut UsbSerial<'bus, 'a, B> { - &mut self.class - } -} - -impl<'bus, 'a, B, C2> SerialState<'bus, 'a, B, Index0> for ClassSet2, C2> -where - B: UsbBus, - C2: UsbClass, -{ - fn get_serial(&mut self) -> &mut UsbSerial<'bus, 'a, B> { - &mut self.class1 - } -} - -impl<'bus, 'a, B, C1> SerialState<'bus, 'a, B, Index1> for ClassSet2> -where - B: UsbBus, - C1: UsbClass, -{ - fn get_serial(&mut self) -> &mut UsbSerial<'bus, 'a, B> { - &mut self.class2 - } -} diff --git a/embassy-hal-common/src/usb/usb_serial.rs b/embassy-hal-common/src/usb/usb_serial.rs deleted file mode 100644 index 94f687890..000000000 --- a/embassy-hal-common/src/usb/usb_serial.rs +++ /dev/null @@ -1,345 +0,0 @@ -use core::cell::RefCell; -use core::marker::{PhantomData, Unpin}; -use core::pin::Pin; -use core::task::{Context, Poll}; - -use embassy::io::{self, AsyncBufRead, AsyncWrite}; -use embassy::waitqueue::WakerRegistration; -use usb_device::bus::UsbBus; -use usb_device::class_prelude::*; -use usb_device::UsbError; - -use super::cdc_acm::CdcAcmClass; -use super::StateInner; -use crate::peripheral::PeripheralMutex; -use crate::ring_buffer::RingBuffer; -use crate::usb::{ClassSet, SerialState, USBInterrupt}; - -pub struct ReadInterface<'a, 'bus, 'c, I, B, T, INT> -where - I: Unpin, - B: UsbBus, - T: SerialState<'bus, 'c, B, I> + ClassSet, - INT: USBInterrupt, -{ - // Don't you dare moving out `PeripheralMutex` - pub(crate) inner: &'a RefCell>>, - pub(crate) _buf_lifetime: PhantomData<&'c T>, - pub(crate) _index: PhantomData, -} - -/// Write interface for USB CDC_ACM -/// -/// This interface is buffered, meaning that after the write returns the bytes might not be fully -/// on the wire just yet -pub struct WriteInterface<'a, 'bus, 'c, I, B, T, INT> -where - I: Unpin, - B: UsbBus, - T: SerialState<'bus, 'c, B, I> + ClassSet, - INT: USBInterrupt, -{ - // Don't you dare moving out `PeripheralMutex` - pub(crate) inner: &'a RefCell>>, - pub(crate) _buf_lifetime: PhantomData<&'c T>, - pub(crate) _index: PhantomData, -} - -impl<'a, 'bus, 'c, I, B, T, INT> AsyncBufRead for ReadInterface<'a, 'bus, 'c, I, B, T, INT> -where - I: Unpin, - B: UsbBus, - T: SerialState<'bus, 'c, B, I> + ClassSet, - INT: USBInterrupt, -{ - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.get_mut(); - let mut mutex = this.inner.borrow_mut(); - mutex.with(|state| { - let serial = state.classes.get_serial(); - let serial = Pin::new(serial); - - match serial.poll_fill_buf(cx) { - Poll::Ready(Ok(buf)) => { - let buf: &[u8] = buf; - // NOTE(unsafe) This part of the buffer won't be modified until the user calls - // consume, which will invalidate this ref - let buf: &[u8] = unsafe { core::mem::transmute(buf) }; - Poll::Ready(Ok(buf)) - } - Poll::Ready(Err(_)) => Poll::Ready(Err(io::Error::Other)), - Poll::Pending => Poll::Pending, - } - }) - } - - fn consume(self: Pin<&mut Self>, amt: usize) { - let this = self.get_mut(); - let mut mutex = this.inner.borrow_mut(); - mutex.with(|state| { - let serial = state.classes.get_serial(); - let serial = Pin::new(serial); - - serial.consume(amt); - }) - } -} - -impl<'a, 'bus, 'c, I, B, T, INT> AsyncWrite for WriteInterface<'a, 'bus, 'c, I, B, T, INT> -where - I: Unpin, - B: UsbBus, - T: SerialState<'bus, 'c, B, I> + ClassSet, - INT: USBInterrupt, -{ - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - let this = self.get_mut(); - let mut mutex = this.inner.borrow_mut(); - mutex.with(|state| { - let serial = state.classes.get_serial(); - let serial = Pin::new(serial); - - serial.poll_write(cx, buf) - }) - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.get_mut(); - let mut mutex = this.inner.borrow_mut(); - mutex.with(|state| { - let serial = state.classes.get_serial(); - let serial = Pin::new(serial); - - serial.poll_flush(cx) - }) - } -} - -pub struct UsbSerial<'bus, 'a, B: UsbBus> { - inner: CdcAcmClass<'bus, B>, - read_buf: RingBuffer<'a>, - write_buf: RingBuffer<'a>, - read_waker: WakerRegistration, - write_waker: WakerRegistration, - write_state: WriteState, - read_error: bool, - write_error: bool, -} - -impl<'bus, 'a, B: UsbBus> AsyncBufRead for UsbSerial<'bus, 'a, B> { - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.get_mut(); - - if this.read_error { - this.read_error = false; - return Poll::Ready(Err(io::Error::Other)); - } - - let buf = this.read_buf.pop_buf(); - if buf.is_empty() { - this.read_waker.register(cx.waker()); - return Poll::Pending; - } - Poll::Ready(Ok(buf)) - } - - fn consume(self: Pin<&mut Self>, amt: usize) { - self.get_mut().read_buf.pop(amt); - } -} - -impl<'bus, 'a, B: UsbBus> AsyncWrite for UsbSerial<'bus, 'a, B> { - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - let this = self.get_mut(); - - if this.write_error { - this.write_error = false; - return Poll::Ready(Err(io::Error::Other)); - } - - let write_buf = this.write_buf.push_buf(); - if write_buf.is_empty() { - trace!("buf full, registering waker"); - this.write_waker.register(cx.waker()); - return Poll::Pending; - } - - let count = write_buf.len().min(buf.len()); - write_buf[..count].copy_from_slice(&buf[..count]); - this.write_buf.push(count); - - this.flush_write(); - Poll::Ready(Ok(count)) - } - - fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } -} - -/// Keeps track of the type of the last written packet. -enum WriteState { - /// No packets in-flight - Idle, - - /// Short packet currently in-flight - Short, - - /// Full packet current in-flight. A full packet must be followed by a short packet for the host - /// OS to see the transaction. The data is the number of subsequent full packets sent so far. A - /// short packet is forced every SHORT_PACKET_INTERVAL packets so that the OS sees data in a - /// timely manner. - Full(usize), -} - -impl<'bus, 'a, B: UsbBus> UsbSerial<'bus, 'a, B> { - pub fn new( - alloc: &'bus UsbBusAllocator, - read_buf: &'a mut [u8], - write_buf: &'a mut [u8], - ) -> Self { - Self { - inner: CdcAcmClass::new(alloc, 64), - read_buf: RingBuffer::new(read_buf), - write_buf: RingBuffer::new(write_buf), - read_waker: WakerRegistration::new(), - write_waker: WakerRegistration::new(), - write_state: WriteState::Idle, - read_error: false, - write_error: false, - } - } - - fn flush_write(&mut self) { - /// If this many full size packets have been sent in a row, a short packet will be sent so that the - /// host sees the data in a timely manner. - const SHORT_PACKET_INTERVAL: usize = 10; - - let full_size_packets = match self.write_state { - WriteState::Full(c) => c, - _ => 0, - }; - - let ep_size = self.inner.max_packet_size() as usize; - let max_size = if full_size_packets > SHORT_PACKET_INTERVAL { - ep_size - 1 - } else { - ep_size - }; - - let buf = { - let buf = self.write_buf.pop_buf(); - if buf.len() > max_size { - &buf[..max_size] - } else { - buf - } - }; - - if !buf.is_empty() { - trace!("writing packet len {}", buf.len()); - let count = match self.inner.write_packet(buf) { - Ok(c) => { - trace!("write packet: OK {}", c); - c - } - Err(UsbError::WouldBlock) => { - trace!("write packet: WouldBlock"); - 0 - } - Err(_) => { - trace!("write packet: error"); - self.write_error = true; - return; - } - }; - - if buf.len() == ep_size { - self.write_state = WriteState::Full(full_size_packets + 1); - } else { - self.write_state = WriteState::Short; - } - self.write_buf.pop(count); - } else if full_size_packets > 0 { - trace!("writing empty packet"); - match self.inner.write_packet(&[]) { - Ok(_) => { - trace!("write empty packet: OK"); - } - Err(UsbError::WouldBlock) => { - trace!("write empty packet: WouldBlock"); - return; - } - Err(_) => { - trace!("write empty packet: Error"); - self.write_error = true; - return; - } - } - self.write_state = WriteState::Idle; - } - } -} - -impl UsbClass for UsbSerial<'_, '_, B> -where - B: UsbBus, -{ - fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<(), UsbError> { - self.inner.get_configuration_descriptors(writer) - } - - fn reset(&mut self) { - self.inner.reset(); - self.read_buf.clear(); - self.write_buf.clear(); - self.write_state = WriteState::Idle; - self.read_waker.wake(); - self.write_waker.wake(); - } - - fn endpoint_in_complete(&mut self, addr: EndpointAddress) { - trace!("DONE endpoint_in_complete"); - if addr == self.inner.write_ep_address() { - trace!("DONE writing packet, waking"); - self.write_waker.wake(); - - self.flush_write(); - } - } - - fn endpoint_out(&mut self, addr: EndpointAddress) { - if addr == self.inner.read_ep_address() { - let buf = self.read_buf.push_buf(); - let count = match self.inner.read_packet(buf) { - Ok(c) => c, - Err(UsbError::WouldBlock) => 0, - Err(_) => { - self.read_error = true; - return; - } - }; - - if count > 0 { - self.read_buf.push(count); - self.read_waker.wake(); - } - } - } - - fn control_in(&mut self, xfer: ControlIn) { - self.inner.control_in(xfer); - } - - fn control_out(&mut self, xfer: ControlOut) { - self.inner.control_out(xfer); - } -} diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 2d0116bd5..1b2847a0d 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -31,12 +31,15 @@ pool-32 = [] pool-64 = [] pool-128 = [] +nightly = ["embedded-io/async"] + [dependencies] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } embassy = { version = "0.1.0", path = "../embassy" } +embedded-io = "0.2.0" managed = { version = "0.8.0", default-features = false, features = [ "map" ] } heapless = { version = "0.7.5", default-features = false } diff --git a/embassy-net/src/device.rs b/embassy-net/src/device.rs index f66ebc193..1f4fa5208 100644 --- a/embassy-net/src/device.rs +++ b/embassy-net/src/device.rs @@ -4,7 +4,6 @@ use smoltcp::phy::DeviceCapabilities; use smoltcp::time::Instant as SmolInstant; use crate::packet_pool::PacketBoxExt; -use crate::Result; use crate::{Packet, PacketBox, PacketBuf}; #[derive(PartialEq, Eq, Clone, Copy)] @@ -78,9 +77,9 @@ pub struct RxToken { } impl smoltcp::phy::RxToken for RxToken { - fn consume(mut self, _timestamp: SmolInstant, f: F) -> Result + fn consume(mut self, _timestamp: SmolInstant, f: F) -> smoltcp::Result where - F: FnOnce(&mut [u8]) -> Result, + F: FnOnce(&mut [u8]) -> smoltcp::Result, { f(&mut self.pkt) } @@ -92,9 +91,9 @@ pub struct TxToken<'a> { } impl<'a> smoltcp::phy::TxToken for TxToken<'a> { - fn consume(self, _timestamp: SmolInstant, len: usize, f: F) -> Result + fn consume(self, _timestamp: SmolInstant, len: usize, f: F) -> smoltcp::Result where - F: FnOnce(&mut [u8]) -> Result, + F: FnOnce(&mut [u8]) -> smoltcp::Result, { let mut buf = self.pkt.slice(0..len); let r = f(&mut buf)?; diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index ffe786b36..ded841909 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -1,5 +1,9 @@ #![cfg_attr(not(feature = "std"), no_std)] #![allow(clippy::new_without_default)] +#![cfg_attr( + feature = "nightly", + feature(generic_associated_types, type_alias_impl_trait) +)] // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; @@ -20,9 +24,7 @@ pub use stack::{ }; #[cfg(feature = "tcp")] -mod tcp_socket; -#[cfg(feature = "tcp")] -pub use tcp_socket::TcpSocket; +pub mod tcp; // smoltcp reexports pub use smoltcp::phy::{DeviceCapabilities, Medium}; @@ -32,4 +34,3 @@ pub use smoltcp::time::Instant as SmolInstant; pub use smoltcp::wire::{EthernetAddress, HardwareAddress}; pub use smoltcp::wire::{IpAddress, IpCidr, Ipv4Address, Ipv4Cidr}; pub type Interface = smoltcp::iface::Interface<'static, device::DeviceAdapter>; -pub use smoltcp::{Error, Result}; diff --git a/embassy-net/src/tcp/io_impl.rs b/embassy-net/src/tcp/io_impl.rs new file mode 100644 index 000000000..155733497 --- /dev/null +++ b/embassy-net/src/tcp/io_impl.rs @@ -0,0 +1,67 @@ +use core::future::Future; +use core::task::Poll; +use futures::future::poll_fn; + +use super::{Error, TcpSocket}; + +impl<'d> embedded_io::asynch::Read for TcpSocket<'d> { + type ReadFuture<'a> = impl Future> + where + Self: 'a; + + fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { + poll_fn(move |cx| { + // CAUTION: smoltcp semantics around EOF are different to what you'd expect + // from posix-like IO, so we have to tweak things here. + self.with(|s, _| match s.recv_slice(buf) { + // No data ready + Ok(0) => { + s.register_recv_waker(cx.waker()); + Poll::Pending + } + // Data ready! + Ok(n) => Poll::Ready(Ok(n)), + // EOF + Err(smoltcp::Error::Finished) => Poll::Ready(Ok(0)), + // Connection reset. TODO: this can also be timeouts etc, investigate. + Err(smoltcp::Error::Illegal) => Poll::Ready(Err(Error::ConnectionReset)), + // smoltcp returns no errors other than the above. + Err(_) => unreachable!(), + }) + }) + } +} + +impl<'d> embedded_io::asynch::Write for TcpSocket<'d> { + type WriteFuture<'a> = impl Future> + where + Self: 'a; + + fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { + poll_fn(move |cx| { + self.with(|s, _| match s.send_slice(buf) { + // Not ready to send (no space in the tx buffer) + Ok(0) => { + s.register_send_waker(cx.waker()); + Poll::Pending + } + // Some data sent + Ok(n) => Poll::Ready(Ok(n)), + // Connection reset. TODO: this can also be timeouts etc, investigate. + Err(smoltcp::Error::Illegal) => Poll::Ready(Err(Error::ConnectionReset)), + // smoltcp returns no errors other than the above. + Err(_) => unreachable!(), + }) + }) + } + + type FlushFuture<'a> = impl Future> + where + Self: 'a; + + fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { + poll_fn(move |_| { + Poll::Ready(Ok(())) // TODO: Is there a better implementation for this? + }) + } +} diff --git a/embassy-net/src/tcp_socket.rs b/embassy-net/src/tcp/mod.rs similarity index 58% rename from embassy-net/src/tcp_socket.rs rename to embassy-net/src/tcp/mod.rs index 5637505d4..3bfd4c7b6 100644 --- a/embassy-net/src/tcp_socket.rs +++ b/embassy-net/src/tcp/mod.rs @@ -1,17 +1,46 @@ use core::marker::PhantomData; use core::mem; -use core::pin::Pin; -use core::task::{Context, Poll}; -use embassy::io; -use embassy::io::{AsyncBufRead, AsyncWrite}; +use core::task::Poll; use smoltcp::iface::{Context as SmolContext, SocketHandle}; use smoltcp::socket::TcpSocket as SyncTcpSocket; use smoltcp::socket::{TcpSocketBuffer, TcpState}; use smoltcp::time::Duration; use smoltcp::wire::IpEndpoint; +#[cfg(feature = "nightly")] +mod io_impl; + use super::stack::Stack; -use crate::{Error, Result}; + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Error { + ConnectionReset, +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ConnectError { + /// The socket is already connected or listening. + InvalidState, + /// The remote host rejected the connection with a RST packet. + ConnectionReset, + /// Connect timed out. + TimedOut, + /// No route to host. + NoRoute, +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum AcceptError { + /// The socket is already connected or listening. + InvalidState, + /// Invalid listen port + InvalidPort, + /// The remote host rejected the connection with a RST packet. + ConnectionReset, +} pub struct TcpSocket<'a> { handle: SocketHandle, @@ -37,17 +66,25 @@ impl<'a> TcpSocket<'a> { } } - pub async fn connect(&mut self, remote_endpoint: T) -> Result<()> + pub async fn connect(&mut self, remote_endpoint: T) -> Result<(), ConnectError> where T: Into, { let local_port = Stack::with(|stack| stack.get_local_port()); - self.with(|s, cx| s.connect(cx, remote_endpoint, local_port))?; + match self.with(|s, cx| s.connect(cx, remote_endpoint, local_port)) { + Ok(()) => {} + Err(smoltcp::Error::Illegal) => return Err(ConnectError::InvalidState), + Err(smoltcp::Error::Unaddressable) => return Err(ConnectError::NoRoute), + // smoltcp returns no errors other than the above. + Err(_) => unreachable!(), + } futures::future::poll_fn(|cx| { self.with(|s, _| match s.state() { - TcpState::Closed | TcpState::TimeWait => Poll::Ready(Err(Error::Unaddressable)), - TcpState::Listen => Poll::Ready(Err(Error::Illegal)), + TcpState::Closed | TcpState::TimeWait => { + Poll::Ready(Err(ConnectError::ConnectionReset)) + } + TcpState::Listen => unreachable!(), TcpState::SynSent | TcpState::SynReceived => { s.register_send_waker(cx.waker()); Poll::Pending @@ -58,11 +95,17 @@ impl<'a> TcpSocket<'a> { .await } - pub async fn accept(&mut self, local_endpoint: T) -> Result<()> + pub async fn accept(&mut self, local_endpoint: T) -> Result<(), AcceptError> where T: Into, { - self.with(|s, _| s.listen(local_endpoint))?; + match self.with(|s, _| s.listen(local_endpoint)) { + Ok(()) => {} + Err(smoltcp::Error::Illegal) => return Err(AcceptError::InvalidState), + Err(smoltcp::Error::Unaddressable) => return Err(AcceptError::InvalidPort), + // smoltcp returns no errors other than the above. + Err(_) => unreachable!(), + } futures::future::poll_fn(|cx| { self.with(|s, _| match s.state() { @@ -130,11 +173,6 @@ impl<'a> TcpSocket<'a> { } } -fn to_ioerr(_err: Error) -> io::Error { - // todo - io::Error::Other -} - impl<'a> Drop for TcpSocket<'a> { fn drop(&mut self) { Stack::with(|stack| { @@ -143,63 +181,12 @@ impl<'a> Drop for TcpSocket<'a> { } } -impl<'a> AsyncBufRead for TcpSocket<'a> { - fn poll_fill_buf<'z>( - self: Pin<&'z mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { - self.with(|s, _| match s.peek(1 << 30) { - // No data ready - Ok(buf) if buf.is_empty() => { - s.register_recv_waker(cx.waker()); - Poll::Pending - } - // Data ready! - Ok(buf) => { - // Safety: - // - User can't touch the inner TcpSocket directly at all. - // - The socket itself won't touch these bytes until consume() is called, which - // requires the user to release this borrow. - let buf: &'z [u8] = unsafe { core::mem::transmute(&*buf) }; - Poll::Ready(Ok(buf)) - } - // EOF - Err(Error::Finished) => Poll::Ready(Ok(&[][..])), - // Error - Err(e) => Poll::Ready(Err(to_ioerr(e))), - }) - } - - fn consume(self: Pin<&mut Self>, amt: usize) { - if amt == 0 { - // smoltcp's recv returns Finished if we're at EOF, - // even if we're "reading" 0 bytes. - return; - } - self.with(|s, _| s.recv(|_| (amt, ()))).unwrap() +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + embedded_io::ErrorKind::Other } } -impl<'a> AsyncWrite for TcpSocket<'a> { - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - self.with(|s, _| match s.send_slice(buf) { - // Not ready to send (no space in the tx buffer) - Ok(0) => { - s.register_send_waker(cx.waker()); - Poll::Pending - } - // Some data sent - Ok(n) => Poll::Ready(Ok(n)), - // Error - Err(e) => Poll::Ready(Err(to_ioerr(e))), - }) - } - - fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) // TODO: Is there a better implementation for this? - } +impl<'d> embedded_io::Io for TcpSocket<'d> { + type Error = Error; } diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index b7c09286f..cf61abcc8 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -19,10 +19,10 @@ flavors = [ time = ["embassy/time"] -defmt = ["dep:defmt", "embassy/defmt", "embassy-usb?/defmt"] +defmt = ["dep:defmt", "embassy/defmt", "embassy-usb?/defmt", "embedded-io?/defmt"] # Enable nightly-only features -nightly = ["embassy/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-usb", "embedded-storage-async"] +nightly = ["embassy/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-usb", "embedded-storage-async", "dep:embedded-io"] # Reexport the PAC for the currently enabled chip at `embassy_nrf::pac`. # This is unstable because semver-minor (non-breaking) releases of embassy-nrf may major-bump (breaking) the PAC version. @@ -73,6 +73,7 @@ embassy-usb = {version = "0.1.0", path = "../embassy-usb", optional=true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8", optional = true} embedded-hal-async = { version = "0.1.0-alpha.0", optional = true} +embedded-io = { version = "0.2.0", features = ["async"], optional = true } defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index b49c12788..fc4e9c8d0 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -14,18 +14,17 @@ //! Please also see [crate::uarte] to understand when [BufferedUarte] should be used. use core::cmp::min; +use core::future::Future; use core::marker::PhantomData; -use core::mem; -use core::pin::Pin; use core::sync::atomic::{compiler_fence, Ordering}; -use core::task::{Context, Poll}; +use core::task::Poll; use embassy::interrupt::InterruptExt; -use embassy::io::{AsyncBufRead, AsyncWrite}; use embassy::util::Unborrow; use embassy::waitqueue::WakerRegistration; use embassy_hal_common::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; use embassy_hal_common::ring_buffer::RingBuffer; use embassy_hal_common::{low_power_wait_until, unborrow}; +use futures::future::poll_fn; use crate::gpio::Pin as GpioPin; use crate::pac; @@ -197,82 +196,99 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { } } -impl<'d, U: UarteInstance, T: TimerInstance> AsyncBufRead for BufferedUarte<'d, U, T> { - fn poll_fill_buf( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { - self.inner.with(|state| { - compiler_fence(Ordering::SeqCst); - trace!("poll_read"); +impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarte<'d, U, T> { + type Error = core::convert::Infallible; +} - // We have data ready in buffer? Return it. - let buf = state.rx.pop_buf(); - if !buf.is_empty() { - trace!(" got {:?} {:?}", buf.as_ptr() as u32, buf.len()); - let buf: &[u8] = buf; - let buf: &[u8] = unsafe { mem::transmute(buf) }; - return Poll::Ready(Ok(buf)); +impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarte<'d, U, T> { + type ReadFuture<'a> = impl Future> + where + Self: 'a; + + fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { + poll_fn(move |cx| { + let mut do_pend = false; + let res = self.inner.with(|state| { + compiler_fence(Ordering::SeqCst); + trace!("poll_read"); + + // We have data ready in buffer? Return it. + let data = state.rx.pop_buf(); + if !data.is_empty() { + trace!(" got {:?} {:?}", data.as_ptr() as u32, data.len()); + let len = data.len().min(data.len()); + buf[..len].copy_from_slice(&data[..len]); + state.rx.pop(len); + do_pend = true; + return Poll::Ready(Ok(len)); + } + + trace!(" empty"); + state.rx_waker.register(cx.waker()); + Poll::Pending + }); + if do_pend { + self.inner.pend(); } - trace!(" empty"); - state.rx_waker.register(cx.waker()); - Poll::>::Pending + res }) } - - fn consume(mut self: Pin<&mut Self>, amt: usize) { - self.inner.with(|state| { - trace!("consume {:?}", amt); - state.rx.pop(amt); - }); - self.inner.pend(); - } } -impl<'d, U: UarteInstance, T: TimerInstance> AsyncWrite for BufferedUarte<'d, U, T> { - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - let poll = self.inner.with(|state| { - trace!("poll_write: {:?}", buf.len()); +impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write + for BufferedUarte<'d, U, T> +{ + type WriteFuture<'a> = impl Future> + where + Self: 'a; - let tx_buf = state.tx.push_buf(); - if tx_buf.is_empty() { - trace!("poll_write: pending"); - state.tx_waker.register(cx.waker()); - return Poll::Pending; - } + fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { + poll_fn(move |cx| { + let res = self.inner.with(|state| { + trace!("poll_write: {:?}", buf.len()); - let n = min(tx_buf.len(), buf.len()); - tx_buf[..n].copy_from_slice(&buf[..n]); - state.tx.push(n); + let tx_buf = state.tx.push_buf(); + if tx_buf.is_empty() { + trace!("poll_write: pending"); + state.tx_waker.register(cx.waker()); + return Poll::Pending; + } - trace!("poll_write: queued {:?}", n); + let n = min(tx_buf.len(), buf.len()); + tx_buf[..n].copy_from_slice(&buf[..n]); + state.tx.push(n); - compiler_fence(Ordering::SeqCst); + trace!("poll_write: queued {:?}", n); - Poll::Ready(Ok(n)) - }); + compiler_fence(Ordering::SeqCst); - self.inner.pend(); + Poll::Ready(Ok(n)) + }); - poll + self.inner.pend(); + + res + }) } - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.inner.with(|state| { - trace!("poll_flush"); + type FlushFuture<'a> = impl Future> + where + Self: 'a; - if !state.tx.is_empty() { - trace!("poll_flush: pending"); - state.tx_waker.register(cx.waker()); - return Poll::Pending; - } + fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { + poll_fn(move |cx| { + self.inner.with(|state| { + trace!("poll_flush"); - Poll::Ready(Ok(())) + if !state.tx.is_empty() { + trace!("poll_flush: pending"); + state.tx_waker.register(cx.waker()); + return Poll::Pending; + } + + Poll::Ready(Ok(())) + }) }) } } diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 3b1809023..865f33d70 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -64,6 +64,7 @@ pub(crate) mod util; #[cfg(feature = "_time-driver")] mod time_driver; +#[cfg(feature = "nightly")] pub mod buffered_uarte; pub mod gpio; #[cfg(feature = "gpiote")] diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 8152b07d4..9686e016e 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -53,17 +53,17 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa rand_core = "0.6.3" sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/thalesfragoso/embedded-sdmmc-rs", branch = "async", optional = true } -synopsys-usb-otg = { version = "0.3", features = ["cortex-m", "hs"], optional = true } critical-section = "0.2.5" bare-metal = "1.0.0" atomic-polyfill = "0.1.5" stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", features = ["rt"] } -vcell = { version = "0.1.3", optional = true } +vcell = "0.1.3" bxcan = "0.6.2" nb = "1.0.0" stm32-fmc = "0.2.4" seq-macro = "0.2.2" cfg-if = "1.0.0" +embedded-io = { version = "0.2.0", features = ["async"], optional = true } [build-dependencies] proc-macro2 = "1.0.36" @@ -71,12 +71,12 @@ quote = "1.0.15" stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features = false, features = ["metadata"]} [features] +defmt = ["dep:defmt", "embassy/defmt", "embedded-io?/defmt" ] sdmmc-rs = ["embedded-sdmmc"] -net = ["embassy-net", "vcell"] +net = ["embassy-net" ] memory-x = ["stm32-metapac/memory-x"] subghz = [] exti = [] -usb-otg = ["synopsys-usb-otg"] # Features starting with `_` are for internal use only. They're not intended # to be enabled by other crates, and are not covered by semver guarantees. @@ -90,7 +90,7 @@ time-driver-tim12 = ["_time-driver"] time-driver-tim15 = ["_time-driver"] # Enable nightly-only features -nightly = ["embassy/nightly", "embedded-hal-1", "embedded-hal-async", "embedded-storage-async"] +nightly = ["embassy/nightly", "embassy-net?/nightly", "embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io"] # Reexport stm32-metapac at `embassy_stm32::pac`. # This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version. diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index aa3e64131..490f2d8f2 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -244,200 +244,200 @@ fn main() { #[rustfmt::skip] let signals: HashMap<_, _> = [ - // (kind, signal) => (trait, cfgs) - (("usart", "TX"), (quote!(crate::usart::TxPin), quote!())), - (("usart", "RX"), (quote!(crate::usart::RxPin), quote!())), - (("usart", "CTS"), (quote!(crate::usart::CtsPin), quote!())), - (("usart", "RTS"), (quote!(crate::usart::RtsPin), quote!())), - (("usart", "CK"), (quote!(crate::usart::CkPin), quote!())), - (("usart", "TX"), (quote!(crate::usart::TxPin), quote!())), - (("usart", "RX"), (quote!(crate::usart::RxPin), quote!())), - (("usart", "CTS"), (quote!(crate::usart::CtsPin), quote!())), - (("usart", "RTS"), (quote!(crate::usart::RtsPin), quote!())), - (("usart", "CK"), (quote!(crate::usart::CkPin), quote!())), - (("spi", "SCK"), (quote!(crate::spi::SckPin), quote!())), - (("spi", "MOSI"), (quote!(crate::spi::MosiPin), quote!())), - (("spi", "MISO"), (quote!(crate::spi::MisoPin), quote!())), - (("i2c", "SDA"), (quote!(crate::i2c::SdaPin), quote!())), - (("i2c", "SCL"), (quote!(crate::i2c::SclPin), quote!())), - (("rcc", "MCO_1"), (quote!(crate::rcc::McoPin), quote!())), - (("rcc", "MCO_2"), (quote!(crate::rcc::McoPin), quote!())), - (("dcmi", "D0"), (quote!(crate::dcmi::D0Pin), quote!())), - (("dcmi", "D1"), (quote!(crate::dcmi::D1Pin), quote!())), - (("dcmi", "D2"), (quote!(crate::dcmi::D2Pin), quote!())), - (("dcmi", "D3"), (quote!(crate::dcmi::D3Pin), quote!())), - (("dcmi", "D4"), (quote!(crate::dcmi::D4Pin), quote!())), - (("dcmi", "D5"), (quote!(crate::dcmi::D5Pin), quote!())), - (("dcmi", "D6"), (quote!(crate::dcmi::D6Pin), quote!())), - (("dcmi", "D7"), (quote!(crate::dcmi::D7Pin), quote!())), - (("dcmi", "D8"), (quote!(crate::dcmi::D8Pin), quote!())), - (("dcmi", "D9"), (quote!(crate::dcmi::D9Pin), quote!())), - (("dcmi", "D10"), (quote!(crate::dcmi::D10Pin), quote!())), - (("dcmi", "D11"), (quote!(crate::dcmi::D11Pin), quote!())), - (("dcmi", "D12"), (quote!(crate::dcmi::D12Pin), quote!())), - (("dcmi", "D13"), (quote!(crate::dcmi::D13Pin), quote!())), - (("dcmi", "HSYNC"), (quote!(crate::dcmi::HSyncPin), quote!())), - (("dcmi", "VSYNC"), (quote!(crate::dcmi::VSyncPin), quote!())), - (("dcmi", "PIXCLK"), (quote!(crate::dcmi::PixClkPin), quote!())), - (("otgfs", "DP"), (quote!(crate::usb_otg::DpPin), quote!(#[cfg(feature="usb-otg")]))), - (("otgfs", "DM"), (quote!(crate::usb_otg::DmPin), quote!(#[cfg(feature="usb-otg")]))), - (("otghs", "DP"), (quote!(crate::usb_otg::DpPin), quote!(#[cfg(feature="usb-otg")]))), - (("otghs", "DM"), (quote!(crate::usb_otg::DmPin), quote!(#[cfg(feature="usb-otg")]))), - (("otghs", "ULPI_CK"), (quote!(crate::usb_otg::UlpiClkPin), quote!(#[cfg(feature="usb-otg")]))), - (("otghs", "ULPI_DIR"), (quote!(crate::usb_otg::UlpiDirPin), quote!(#[cfg(feature="usb-otg")]))), - (("otghs", "ULPI_NXT"), (quote!(crate::usb_otg::UlpiNxtPin), quote!(#[cfg(feature="usb-otg")]))), - (("otghs", "ULPI_STP"), (quote!(crate::usb_otg::UlpiStpPin), quote!(#[cfg(feature="usb-otg")]))), - (("otghs", "ULPI_D0"), (quote!(crate::usb_otg::UlpiD0Pin), quote!(#[cfg(feature="usb-otg")]))), - (("otghs", "ULPI_D1"), (quote!(crate::usb_otg::UlpiD1Pin), quote!(#[cfg(feature="usb-otg")]))), - (("otghs", "ULPI_D2"), (quote!(crate::usb_otg::UlpiD2Pin), quote!(#[cfg(feature="usb-otg")]))), - (("otghs", "ULPI_D3"), (quote!(crate::usb_otg::UlpiD3Pin), quote!(#[cfg(feature="usb-otg")]))), - (("otghs", "ULPI_D4"), (quote!(crate::usb_otg::UlpiD4Pin), quote!(#[cfg(feature="usb-otg")]))), - (("otghs", "ULPI_D5"), (quote!(crate::usb_otg::UlpiD5Pin), quote!(#[cfg(feature="usb-otg")]))), - (("otghs", "ULPI_D6"), (quote!(crate::usb_otg::UlpiD6Pin), quote!(#[cfg(feature="usb-otg")]))), - (("otghs", "ULPI_D7"), (quote!(crate::usb_otg::UlpiD7Pin), quote!(#[cfg(feature="usb-otg")]))), - (("can", "TX"), (quote!(crate::can::TxPin), quote!())), - (("can", "RX"), (quote!(crate::can::RxPin), quote!())), - (("eth", "REF_CLK"), (quote!(crate::eth::RefClkPin), quote!(#[cfg(feature="net")]))), - (("eth", "MDIO"), (quote!(crate::eth::MDIOPin), quote!(#[cfg(feature="net")]))), - (("eth", "MDC"), (quote!(crate::eth::MDCPin), quote!(#[cfg(feature="net")]))), - (("eth", "CRS_DV"), (quote!(crate::eth::CRSPin), quote!(#[cfg(feature="net")]))), - (("eth", "RXD0"), (quote!(crate::eth::RXD0Pin), quote!(#[cfg(feature="net")]))), - (("eth", "RXD1"), (quote!(crate::eth::RXD1Pin), quote!(#[cfg(feature="net")]))), - (("eth", "TXD0"), (quote!(crate::eth::TXD0Pin), quote!(#[cfg(feature="net")]))), - (("eth", "TXD1"), (quote!(crate::eth::TXD1Pin), quote!(#[cfg(feature="net")]))), - (("eth", "TX_EN"), (quote!(crate::eth::TXEnPin), quote!(#[cfg(feature="net")]))), - (("fmc", "A0"), (quote!(crate::fmc::A0Pin), quote!())), - (("fmc", "A1"), (quote!(crate::fmc::A1Pin), quote!())), - (("fmc", "A2"), (quote!(crate::fmc::A2Pin), quote!())), - (("fmc", "A3"), (quote!(crate::fmc::A3Pin), quote!())), - (("fmc", "A4"), (quote!(crate::fmc::A4Pin), quote!())), - (("fmc", "A5"), (quote!(crate::fmc::A5Pin), quote!())), - (("fmc", "A6"), (quote!(crate::fmc::A6Pin), quote!())), - (("fmc", "A7"), (quote!(crate::fmc::A7Pin), quote!())), - (("fmc", "A8"), (quote!(crate::fmc::A8Pin), quote!())), - (("fmc", "A9"), (quote!(crate::fmc::A9Pin), quote!())), - (("fmc", "A10"), (quote!(crate::fmc::A10Pin), quote!())), - (("fmc", "A11"), (quote!(crate::fmc::A11Pin), quote!())), - (("fmc", "A12"), (quote!(crate::fmc::A12Pin), quote!())), - (("fmc", "A13"), (quote!(crate::fmc::A13Pin), quote!())), - (("fmc", "A14"), (quote!(crate::fmc::A14Pin), quote!())), - (("fmc", "A15"), (quote!(crate::fmc::A15Pin), quote!())), - (("fmc", "A16"), (quote!(crate::fmc::A16Pin), quote!())), - (("fmc", "A17"), (quote!(crate::fmc::A17Pin), quote!())), - (("fmc", "A18"), (quote!(crate::fmc::A18Pin), quote!())), - (("fmc", "A19"), (quote!(crate::fmc::A19Pin), quote!())), - (("fmc", "A20"), (quote!(crate::fmc::A20Pin), quote!())), - (("fmc", "A21"), (quote!(crate::fmc::A21Pin), quote!())), - (("fmc", "A22"), (quote!(crate::fmc::A22Pin), quote!())), - (("fmc", "A23"), (quote!(crate::fmc::A23Pin), quote!())), - (("fmc", "A24"), (quote!(crate::fmc::A24Pin), quote!())), - (("fmc", "A25"), (quote!(crate::fmc::A25Pin), quote!())), - (("fmc", "D0"), (quote!(crate::fmc::D0Pin), quote!())), - (("fmc", "D1"), (quote!(crate::fmc::D1Pin), quote!())), - (("fmc", "D2"), (quote!(crate::fmc::D2Pin), quote!())), - (("fmc", "D3"), (quote!(crate::fmc::D3Pin), quote!())), - (("fmc", "D4"), (quote!(crate::fmc::D4Pin), quote!())), - (("fmc", "D5"), (quote!(crate::fmc::D5Pin), quote!())), - (("fmc", "D6"), (quote!(crate::fmc::D6Pin), quote!())), - (("fmc", "D7"), (quote!(crate::fmc::D7Pin), quote!())), - (("fmc", "D8"), (quote!(crate::fmc::D8Pin), quote!())), - (("fmc", "D9"), (quote!(crate::fmc::D9Pin), quote!())), - (("fmc", "D10"), (quote!(crate::fmc::D10Pin), quote!())), - (("fmc", "D11"), (quote!(crate::fmc::D11Pin), quote!())), - (("fmc", "D12"), (quote!(crate::fmc::D12Pin), quote!())), - (("fmc", "D13"), (quote!(crate::fmc::D13Pin), quote!())), - (("fmc", "D14"), (quote!(crate::fmc::D14Pin), quote!())), - (("fmc", "D15"), (quote!(crate::fmc::D15Pin), quote!())), - (("fmc", "D16"), (quote!(crate::fmc::D16Pin), quote!())), - (("fmc", "D17"), (quote!(crate::fmc::D17Pin), quote!())), - (("fmc", "D18"), (quote!(crate::fmc::D18Pin), quote!())), - (("fmc", "D19"), (quote!(crate::fmc::D19Pin), quote!())), - (("fmc", "D20"), (quote!(crate::fmc::D20Pin), quote!())), - (("fmc", "D21"), (quote!(crate::fmc::D21Pin), quote!())), - (("fmc", "D22"), (quote!(crate::fmc::D22Pin), quote!())), - (("fmc", "D23"), (quote!(crate::fmc::D23Pin), quote!())), - (("fmc", "D24"), (quote!(crate::fmc::D24Pin), quote!())), - (("fmc", "D25"), (quote!(crate::fmc::D25Pin), quote!())), - (("fmc", "D26"), (quote!(crate::fmc::D26Pin), quote!())), - (("fmc", "D27"), (quote!(crate::fmc::D27Pin), quote!())), - (("fmc", "D28"), (quote!(crate::fmc::D28Pin), quote!())), - (("fmc", "D29"), (quote!(crate::fmc::D29Pin), quote!())), - (("fmc", "D30"), (quote!(crate::fmc::D30Pin), quote!())), - (("fmc", "D31"), (quote!(crate::fmc::D31Pin), quote!())), - (("fmc", "DA0"), (quote!(crate::fmc::DA0Pin), quote!())), - (("fmc", "DA1"), (quote!(crate::fmc::DA1Pin), quote!())), - (("fmc", "DA2"), (quote!(crate::fmc::DA2Pin), quote!())), - (("fmc", "DA3"), (quote!(crate::fmc::DA3Pin), quote!())), - (("fmc", "DA4"), (quote!(crate::fmc::DA4Pin), quote!())), - (("fmc", "DA5"), (quote!(crate::fmc::DA5Pin), quote!())), - (("fmc", "DA6"), (quote!(crate::fmc::DA6Pin), quote!())), - (("fmc", "DA7"), (quote!(crate::fmc::DA7Pin), quote!())), - (("fmc", "DA8"), (quote!(crate::fmc::DA8Pin), quote!())), - (("fmc", "DA9"), (quote!(crate::fmc::DA9Pin), quote!())), - (("fmc", "DA10"), (quote!(crate::fmc::DA10Pin), quote!())), - (("fmc", "DA11"), (quote!(crate::fmc::DA11Pin), quote!())), - (("fmc", "DA12"), (quote!(crate::fmc::DA12Pin), quote!())), - (("fmc", "DA13"), (quote!(crate::fmc::DA13Pin), quote!())), - (("fmc", "DA14"), (quote!(crate::fmc::DA14Pin), quote!())), - (("fmc", "DA15"), (quote!(crate::fmc::DA15Pin), quote!())), - (("fmc", "SDNWE"), (quote!(crate::fmc::SDNWEPin), quote!())), - (("fmc", "SDNCAS"), (quote!(crate::fmc::SDNCASPin), quote!())), - (("fmc", "SDNRAS"), (quote!(crate::fmc::SDNRASPin), quote!())), - (("fmc", "SDNE0"), (quote!(crate::fmc::SDNE0Pin), quote!())), - (("fmc", "SDNE1"), (quote!(crate::fmc::SDNE1Pin), quote!())), - (("fmc", "SDCKE0"), (quote!(crate::fmc::SDCKE0Pin), quote!())), - (("fmc", "SDCKE1"), (quote!(crate::fmc::SDCKE1Pin), quote!())), - (("fmc", "SDCLK"), (quote!(crate::fmc::SDCLKPin), quote!())), - (("fmc", "NBL0"), (quote!(crate::fmc::NBL0Pin), quote!())), - (("fmc", "NBL1"), (quote!(crate::fmc::NBL1Pin), quote!())), - (("fmc", "NBL2"), (quote!(crate::fmc::NBL2Pin), quote!())), - (("fmc", "NBL3"), (quote!(crate::fmc::NBL3Pin), quote!())), - (("fmc", "INT"), (quote!(crate::fmc::INTPin), quote!())), - (("fmc", "NL"), (quote!(crate::fmc::NLPin), quote!())), - (("fmc", "NWAIT"), (quote!(crate::fmc::NWaitPin), quote!())), - (("fmc", "NE1"), (quote!(crate::fmc::NE1Pin), quote!())), - (("fmc", "NE2"), (quote!(crate::fmc::NE2Pin), quote!())), - (("fmc", "NE3"), (quote!(crate::fmc::NE3Pin), quote!())), - (("fmc", "NE4"), (quote!(crate::fmc::NE4Pin), quote!())), - (("fmc", "NCE"), (quote!(crate::fmc::NCEPin), quote!())), - (("fmc", "NOE"), (quote!(crate::fmc::NOEPin), quote!())), - (("fmc", "NWE"), (quote!(crate::fmc::NWEPin), quote!())), - (("fmc", "Clk"), (quote!(crate::fmc::ClkPin), quote!())), - (("fmc", "BA0"), (quote!(crate::fmc::BA0Pin), quote!())), - (("fmc", "BA1"), (quote!(crate::fmc::BA1Pin), quote!())), - (("timer", "CH1"), (quote!(crate::pwm::Channel1Pin), quote!())), - (("timer", "CH1N"), (quote!(crate::pwm::Channel1ComplementaryPin), quote!())), - (("timer", "CH2"), (quote!(crate::pwm::Channel2Pin), quote!())), - (("timer", "CH2N"), (quote!(crate::pwm::Channel2ComplementaryPin), quote!())), - (("timer", "CH3"), (quote!(crate::pwm::Channel3Pin), quote!())), - (("timer", "CH3N"), (quote!(crate::pwm::Channel3ComplementaryPin), quote!())), - (("timer", "CH4"), (quote!(crate::pwm::Channel4Pin), quote!())), - (("timer", "CH4N"), (quote!(crate::pwm::Channel4ComplementaryPin), quote!())), - (("timer", "ETR"), (quote!(crate::pwm::ExternalTriggerPin), quote!())), - (("timer", "BKIN"), (quote!(crate::pwm::BreakInputPin), quote!())), - (("timer", "BKIN_COMP1"), (quote!(crate::pwm::BreakInputComparator1Pin), quote!())), - (("timer", "BKIN_COMP2"), (quote!(crate::pwm::BreakInputComparator2Pin), quote!())), - (("timer", "BKIN2"), (quote!(crate::pwm::BreakInput2Pin), quote!())), - (("timer", "BKIN2_COMP1"), (quote!(crate::pwm::BreakInput2Comparator1Pin), quote!())), - (("timer", "BKIN2_COMP2"), (quote!(crate::pwm::BreakInput2Comparator2Pin), quote!())), - (("sdmmc", "CK"), (quote!(crate::sdmmc::CkPin), quote!())), - (("sdmmc", "CMD"), (quote!(crate::sdmmc::CmdPin), quote!())), - (("sdmmc", "D0"), (quote!(crate::sdmmc::D0Pin), quote!())), - (("sdmmc", "D1"), (quote!(crate::sdmmc::D1Pin), quote!())), - (("sdmmc", "D2"), (quote!(crate::sdmmc::D2Pin), quote!())), - (("sdmmc", "D3"), (quote!(crate::sdmmc::D3Pin), quote!())), - (("sdmmc", "D4"), (quote!(crate::sdmmc::D4Pin), quote!())), - (("sdmmc", "D5"), (quote!(crate::sdmmc::D5Pin), quote!())), - (("sdmmc", "D6"), (quote!(crate::sdmmc::D6Pin), quote!())), - (("sdmmc", "D6"), (quote!(crate::sdmmc::D7Pin), quote!())), - (("sdmmc", "D8"), (quote!(crate::sdmmc::D8Pin), quote!())), + // (kind, signal) => trait + (("usart", "TX"), quote!(crate::usart::TxPin)), + (("usart", "RX"), quote!(crate::usart::RxPin)), + (("usart", "CTS"), quote!(crate::usart::CtsPin)), + (("usart", "RTS"), quote!(crate::usart::RtsPin)), + (("usart", "CK"), quote!(crate::usart::CkPin)), + (("usart", "TX"), quote!(crate::usart::TxPin)), + (("usart", "RX"), quote!(crate::usart::RxPin)), + (("usart", "CTS"), quote!(crate::usart::CtsPin)), + (("usart", "RTS"), quote!(crate::usart::RtsPin)), + (("usart", "CK"), quote!(crate::usart::CkPin)), + (("spi", "SCK"), quote!(crate::spi::SckPin)), + (("spi", "MOSI"), quote!(crate::spi::MosiPin)), + (("spi", "MISO"), quote!(crate::spi::MisoPin)), + (("i2c", "SDA"), quote!(crate::i2c::SdaPin)), + (("i2c", "SCL"), quote!(crate::i2c::SclPin)), + (("rcc", "MCO_1"), quote!(crate::rcc::McoPin)), + (("rcc", "MCO_2"), quote!(crate::rcc::McoPin)), + (("dcmi", "D0"), quote!(crate::dcmi::D0Pin)), + (("dcmi", "D1"), quote!(crate::dcmi::D1Pin)), + (("dcmi", "D2"), quote!(crate::dcmi::D2Pin)), + (("dcmi", "D3"), quote!(crate::dcmi::D3Pin)), + (("dcmi", "D4"), quote!(crate::dcmi::D4Pin)), + (("dcmi", "D5"), quote!(crate::dcmi::D5Pin)), + (("dcmi", "D6"), quote!(crate::dcmi::D6Pin)), + (("dcmi", "D7"), quote!(crate::dcmi::D7Pin)), + (("dcmi", "D8"), quote!(crate::dcmi::D8Pin)), + (("dcmi", "D9"), quote!(crate::dcmi::D9Pin)), + (("dcmi", "D10"), quote!(crate::dcmi::D10Pin)), + (("dcmi", "D11"), quote!(crate::dcmi::D11Pin)), + (("dcmi", "D12"), quote!(crate::dcmi::D12Pin)), + (("dcmi", "D13"), quote!(crate::dcmi::D13Pin)), + (("dcmi", "HSYNC"), quote!(crate::dcmi::HSyncPin)), + (("dcmi", "VSYNC"), quote!(crate::dcmi::VSyncPin)), + (("dcmi", "PIXCLK"), quote!(crate::dcmi::PixClkPin)), + (("otgfs", "DP"), quote!(crate::usb_otg::DpPin)), + (("otgfs", "DM"), quote!(crate::usb_otg::DmPin)), + (("otghs", "DP"), quote!(crate::usb_otg::DpPin)), + (("otghs", "DM"), quote!(crate::usb_otg::DmPin)), + (("otghs", "ULPI_CK"), quote!(crate::usb_otg::UlpiClkPin)), + (("otghs", "ULPI_DIR"), quote!(crate::usb_otg::UlpiDirPin)), + (("otghs", "ULPI_NXT"), quote!(crate::usb_otg::UlpiNxtPin)), + (("otghs", "ULPI_STP"), quote!(crate::usb_otg::UlpiStpPin)), + (("otghs", "ULPI_D0"), quote!(crate::usb_otg::UlpiD0Pin)), + (("otghs", "ULPI_D1"), quote!(crate::usb_otg::UlpiD1Pin)), + (("otghs", "ULPI_D2"), quote!(crate::usb_otg::UlpiD2Pin)), + (("otghs", "ULPI_D3"), quote!(crate::usb_otg::UlpiD3Pin)), + (("otghs", "ULPI_D4"), quote!(crate::usb_otg::UlpiD4Pin)), + (("otghs", "ULPI_D5"), quote!(crate::usb_otg::UlpiD5Pin)), + (("otghs", "ULPI_D6"), quote!(crate::usb_otg::UlpiD6Pin)), + (("otghs", "ULPI_D7"), quote!(crate::usb_otg::UlpiD7Pin)), + (("can", "TX"), quote!(crate::can::TxPin)), + (("can", "RX"), quote!(crate::can::RxPin)), + (("eth", "REF_CLK"), quote!(crate::eth::RefClkPin)), + (("eth", "MDIO"), quote!(crate::eth::MDIOPin)), + (("eth", "MDC"), quote!(crate::eth::MDCPin)), + (("eth", "CRS_DV"), quote!(crate::eth::CRSPin)), + (("eth", "RXD0"), quote!(crate::eth::RXD0Pin)), + (("eth", "RXD1"), quote!(crate::eth::RXD1Pin)), + (("eth", "TXD0"), quote!(crate::eth::TXD0Pin)), + (("eth", "TXD1"), quote!(crate::eth::TXD1Pin)), + (("eth", "TX_EN"), quote!(crate::eth::TXEnPin)), + (("fmc", "A0"), quote!(crate::fmc::A0Pin)), + (("fmc", "A1"), quote!(crate::fmc::A1Pin)), + (("fmc", "A2"), quote!(crate::fmc::A2Pin)), + (("fmc", "A3"), quote!(crate::fmc::A3Pin)), + (("fmc", "A4"), quote!(crate::fmc::A4Pin)), + (("fmc", "A5"), quote!(crate::fmc::A5Pin)), + (("fmc", "A6"), quote!(crate::fmc::A6Pin)), + (("fmc", "A7"), quote!(crate::fmc::A7Pin)), + (("fmc", "A8"), quote!(crate::fmc::A8Pin)), + (("fmc", "A9"), quote!(crate::fmc::A9Pin)), + (("fmc", "A10"), quote!(crate::fmc::A10Pin)), + (("fmc", "A11"), quote!(crate::fmc::A11Pin)), + (("fmc", "A12"), quote!(crate::fmc::A12Pin)), + (("fmc", "A13"), quote!(crate::fmc::A13Pin)), + (("fmc", "A14"), quote!(crate::fmc::A14Pin)), + (("fmc", "A15"), quote!(crate::fmc::A15Pin)), + (("fmc", "A16"), quote!(crate::fmc::A16Pin)), + (("fmc", "A17"), quote!(crate::fmc::A17Pin)), + (("fmc", "A18"), quote!(crate::fmc::A18Pin)), + (("fmc", "A19"), quote!(crate::fmc::A19Pin)), + (("fmc", "A20"), quote!(crate::fmc::A20Pin)), + (("fmc", "A21"), quote!(crate::fmc::A21Pin)), + (("fmc", "A22"), quote!(crate::fmc::A22Pin)), + (("fmc", "A23"), quote!(crate::fmc::A23Pin)), + (("fmc", "A24"), quote!(crate::fmc::A24Pin)), + (("fmc", "A25"), quote!(crate::fmc::A25Pin)), + (("fmc", "D0"), quote!(crate::fmc::D0Pin)), + (("fmc", "D1"), quote!(crate::fmc::D1Pin)), + (("fmc", "D2"), quote!(crate::fmc::D2Pin)), + (("fmc", "D3"), quote!(crate::fmc::D3Pin)), + (("fmc", "D4"), quote!(crate::fmc::D4Pin)), + (("fmc", "D5"), quote!(crate::fmc::D5Pin)), + (("fmc", "D6"), quote!(crate::fmc::D6Pin)), + (("fmc", "D7"), quote!(crate::fmc::D7Pin)), + (("fmc", "D8"), quote!(crate::fmc::D8Pin)), + (("fmc", "D9"), quote!(crate::fmc::D9Pin)), + (("fmc", "D10"), quote!(crate::fmc::D10Pin)), + (("fmc", "D11"), quote!(crate::fmc::D11Pin)), + (("fmc", "D12"), quote!(crate::fmc::D12Pin)), + (("fmc", "D13"), quote!(crate::fmc::D13Pin)), + (("fmc", "D14"), quote!(crate::fmc::D14Pin)), + (("fmc", "D15"), quote!(crate::fmc::D15Pin)), + (("fmc", "D16"), quote!(crate::fmc::D16Pin)), + (("fmc", "D17"), quote!(crate::fmc::D17Pin)), + (("fmc", "D18"), quote!(crate::fmc::D18Pin)), + (("fmc", "D19"), quote!(crate::fmc::D19Pin)), + (("fmc", "D20"), quote!(crate::fmc::D20Pin)), + (("fmc", "D21"), quote!(crate::fmc::D21Pin)), + (("fmc", "D22"), quote!(crate::fmc::D22Pin)), + (("fmc", "D23"), quote!(crate::fmc::D23Pin)), + (("fmc", "D24"), quote!(crate::fmc::D24Pin)), + (("fmc", "D25"), quote!(crate::fmc::D25Pin)), + (("fmc", "D26"), quote!(crate::fmc::D26Pin)), + (("fmc", "D27"), quote!(crate::fmc::D27Pin)), + (("fmc", "D28"), quote!(crate::fmc::D28Pin)), + (("fmc", "D29"), quote!(crate::fmc::D29Pin)), + (("fmc", "D30"), quote!(crate::fmc::D30Pin)), + (("fmc", "D31"), quote!(crate::fmc::D31Pin)), + (("fmc", "DA0"), quote!(crate::fmc::DA0Pin)), + (("fmc", "DA1"), quote!(crate::fmc::DA1Pin)), + (("fmc", "DA2"), quote!(crate::fmc::DA2Pin)), + (("fmc", "DA3"), quote!(crate::fmc::DA3Pin)), + (("fmc", "DA4"), quote!(crate::fmc::DA4Pin)), + (("fmc", "DA5"), quote!(crate::fmc::DA5Pin)), + (("fmc", "DA6"), quote!(crate::fmc::DA6Pin)), + (("fmc", "DA7"), quote!(crate::fmc::DA7Pin)), + (("fmc", "DA8"), quote!(crate::fmc::DA8Pin)), + (("fmc", "DA9"), quote!(crate::fmc::DA9Pin)), + (("fmc", "DA10"), quote!(crate::fmc::DA10Pin)), + (("fmc", "DA11"), quote!(crate::fmc::DA11Pin)), + (("fmc", "DA12"), quote!(crate::fmc::DA12Pin)), + (("fmc", "DA13"), quote!(crate::fmc::DA13Pin)), + (("fmc", "DA14"), quote!(crate::fmc::DA14Pin)), + (("fmc", "DA15"), quote!(crate::fmc::DA15Pin)), + (("fmc", "SDNWE"), quote!(crate::fmc::SDNWEPin)), + (("fmc", "SDNCAS"), quote!(crate::fmc::SDNCASPin)), + (("fmc", "SDNRAS"), quote!(crate::fmc::SDNRASPin)), + (("fmc", "SDNE0"), quote!(crate::fmc::SDNE0Pin)), + (("fmc", "SDNE1"), quote!(crate::fmc::SDNE1Pin)), + (("fmc", "SDCKE0"), quote!(crate::fmc::SDCKE0Pin)), + (("fmc", "SDCKE1"), quote!(crate::fmc::SDCKE1Pin)), + (("fmc", "SDCLK"), quote!(crate::fmc::SDCLKPin)), + (("fmc", "NBL0"), quote!(crate::fmc::NBL0Pin)), + (("fmc", "NBL1"), quote!(crate::fmc::NBL1Pin)), + (("fmc", "NBL2"), quote!(crate::fmc::NBL2Pin)), + (("fmc", "NBL3"), quote!(crate::fmc::NBL3Pin)), + (("fmc", "INT"), quote!(crate::fmc::INTPin)), + (("fmc", "NL"), quote!(crate::fmc::NLPin)), + (("fmc", "NWAIT"), quote!(crate::fmc::NWaitPin)), + (("fmc", "NE1"), quote!(crate::fmc::NE1Pin)), + (("fmc", "NE2"), quote!(crate::fmc::NE2Pin)), + (("fmc", "NE3"), quote!(crate::fmc::NE3Pin)), + (("fmc", "NE4"), quote!(crate::fmc::NE4Pin)), + (("fmc", "NCE"), quote!(crate::fmc::NCEPin)), + (("fmc", "NOE"), quote!(crate::fmc::NOEPin)), + (("fmc", "NWE"), quote!(crate::fmc::NWEPin)), + (("fmc", "Clk"), quote!(crate::fmc::ClkPin)), + (("fmc", "BA0"), quote!(crate::fmc::BA0Pin)), + (("fmc", "BA1"), quote!(crate::fmc::BA1Pin)), + (("timer", "CH1"), quote!(crate::pwm::Channel1Pin)), + (("timer", "CH1N"), quote!(crate::pwm::Channel1ComplementaryPin)), + (("timer", "CH2"), quote!(crate::pwm::Channel2Pin)), + (("timer", "CH2N"), quote!(crate::pwm::Channel2ComplementaryPin)), + (("timer", "CH3"), quote!(crate::pwm::Channel3Pin)), + (("timer", "CH3N"), quote!(crate::pwm::Channel3ComplementaryPin)), + (("timer", "CH4"), quote!(crate::pwm::Channel4Pin)), + (("timer", "CH4N"), quote!(crate::pwm::Channel4ComplementaryPin)), + (("timer", "ETR"), quote!(crate::pwm::ExternalTriggerPin)), + (("timer", "BKIN"), quote!(crate::pwm::BreakInputPin)), + (("timer", "BKIN_COMP1"), quote!(crate::pwm::BreakInputComparator1Pin)), + (("timer", "BKIN_COMP2"), quote!(crate::pwm::BreakInputComparator2Pin)), + (("timer", "BKIN2"), quote!(crate::pwm::BreakInput2Pin)), + (("timer", "BKIN2_COMP1"), quote!(crate::pwm::BreakInput2Comparator1Pin)), + (("timer", "BKIN2_COMP2"), quote!(crate::pwm::BreakInput2Comparator2Pin)), + (("sdmmc", "CK"), quote!(crate::sdmmc::CkPin)), + (("sdmmc", "CMD"), quote!(crate::sdmmc::CmdPin)), + (("sdmmc", "D0"), quote!(crate::sdmmc::D0Pin)), + (("sdmmc", "D1"), quote!(crate::sdmmc::D1Pin)), + (("sdmmc", "D2"), quote!(crate::sdmmc::D2Pin)), + (("sdmmc", "D3"), quote!(crate::sdmmc::D3Pin)), + (("sdmmc", "D4"), quote!(crate::sdmmc::D4Pin)), + (("sdmmc", "D5"), quote!(crate::sdmmc::D5Pin)), + (("sdmmc", "D6"), quote!(crate::sdmmc::D6Pin)), + (("sdmmc", "D6"), quote!(crate::sdmmc::D7Pin)), + (("sdmmc", "D8"), quote!(crate::sdmmc::D8Pin)), ].into(); for p in METADATA.peripherals { if let Some(regs) = &p.registers { for pin in p.pins { let key = (regs.kind, pin.signal); - if let Some((tr, cfgs)) = signals.get(&key) { + if let Some(tr) = signals.get(&key) { let mut peri = format_ident!("{}", p.name); let pin_name = format_ident!("{}", pin.pin); let af = pin.af.unwrap_or(0); @@ -453,7 +453,6 @@ fn main() { } g.extend(quote! { - #cfgs pin_trait_impl!(#tr, #peri, #pin_name, #af); }) } diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index 28f0c178f..76a3dfab4 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs @@ -1,10 +1,12 @@ #![macro_use] +#[cfg(feature = "net")] #[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")] #[cfg_attr(eth_v2, path = "v2/mod.rs")] mod _version; pub mod generic_smi; +#[cfg(feature = "net")] pub use _version::*; /// Station Management Interface (SMI) on an ethernet PHY diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 1a46f8124..fbd2008c8 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -39,7 +39,7 @@ pub mod can; pub mod dac; #[cfg(dcmi)] pub mod dcmi; -#[cfg(all(eth, feature = "net"))] +#[cfg(eth)] pub mod eth; #[cfg(feature = "exti")] pub mod exti; @@ -63,7 +63,7 @@ pub mod sdmmc; pub mod spi; #[cfg(usart)] pub mod usart; -#[cfg(feature = "usb-otg")] +#[cfg(any(otgfs, otghs))] pub mod usb_otg; #[cfg(feature = "subghz")] diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs new file mode 100644 index 000000000..b2fcb504e --- /dev/null +++ b/embassy-stm32/src/usart/buffered.rs @@ -0,0 +1,238 @@ +use atomic_polyfill::{compiler_fence, Ordering}; +use core::future::Future; +use core::task::Poll; +use embassy::waitqueue::WakerRegistration; +use embassy_hal_common::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; +use embassy_hal_common::ring_buffer::RingBuffer; +use futures::future::poll_fn; + +use super::*; + +pub struct State<'d, T: Instance>(StateStorage>); +impl<'d, T: Instance> State<'d, T> { + pub fn new() -> Self { + Self(StateStorage::new()) + } +} + +struct StateInner<'d, T: Instance> { + phantom: PhantomData<&'d mut T>, + + rx_waker: WakerRegistration, + rx: RingBuffer<'d>, + + tx_waker: WakerRegistration, + tx: RingBuffer<'d>, +} + +unsafe impl<'d, T: Instance> Send for StateInner<'d, T> {} +unsafe impl<'d, T: Instance> Sync for StateInner<'d, T> {} + +pub struct BufferedUart<'d, T: Instance> { + inner: PeripheralMutex<'d, StateInner<'d, T>>, +} + +impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {} + +impl<'d, T: Instance> BufferedUart<'d, T> { + pub unsafe fn new( + state: &'d mut State<'d, T>, + _uart: Uart<'d, T, NoDma, NoDma>, + irq: impl Unborrow + 'd, + tx_buffer: &'d mut [u8], + rx_buffer: &'d mut [u8], + ) -> BufferedUart<'d, T> { + unborrow!(irq); + + let r = T::regs(); + r.cr1().modify(|w| { + w.set_rxneie(true); + w.set_idleie(true); + }); + + Self { + inner: PeripheralMutex::new_unchecked(irq, &mut state.0, move || StateInner { + phantom: PhantomData, + tx: RingBuffer::new(tx_buffer), + tx_waker: WakerRegistration::new(), + + rx: RingBuffer::new(rx_buffer), + rx_waker: WakerRegistration::new(), + }), + } + } +} + +impl<'d, T: Instance> StateInner<'d, T> +where + Self: 'd, +{ + fn on_rx(&mut self) { + let r = T::regs(); + unsafe { + let sr = sr(r).read(); + clear_interrupt_flags(r, sr); + + // This read also clears the error and idle interrupt flags on v1. + let b = rdr(r).read_volatile(); + + if sr.rxne() { + if sr.pe() { + warn!("Parity error"); + } + if sr.fe() { + warn!("Framing error"); + } + if sr.ne() { + warn!("Noise error"); + } + if sr.ore() { + warn!("Overrun error"); + } + + let buf = self.rx.push_buf(); + if !buf.is_empty() { + buf[0] = b; + self.rx.push(1); + } else { + warn!("RX buffer full, discard received byte"); + } + + if self.rx.is_full() { + self.rx_waker.wake(); + } + } + + if sr.idle() { + self.rx_waker.wake(); + }; + } + } + + fn on_tx(&mut self) { + let r = T::regs(); + unsafe { + if sr(r).read().txe() { + let buf = self.tx.pop_buf(); + if !buf.is_empty() { + r.cr1().modify(|w| { + w.set_txeie(true); + }); + tdr(r).write_volatile(buf[0].into()); + self.tx.pop(1); + self.tx_waker.wake(); + } else { + // Disable interrupt until we have something to transmit again + r.cr1().modify(|w| { + w.set_txeie(false); + }); + } + } + } + } +} + +impl<'d, T: Instance> PeripheralState for StateInner<'d, T> +where + Self: 'd, +{ + type Interrupt = T::Interrupt; + fn on_interrupt(&mut self) { + self.on_rx(); + self.on_tx(); + } +} + +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + embedded_io::ErrorKind::Other + } +} + +impl<'d, T: Instance> embedded_io::Io for BufferedUart<'d, T> { + type Error = Error; +} + +impl<'d, T: Instance> embedded_io::asynch::Read for BufferedUart<'d, T> { + type ReadFuture<'a> = impl Future> + where + Self: 'a; + + fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { + poll_fn(move |cx| { + let mut do_pend = false; + let res = self.inner.with(|state| { + compiler_fence(Ordering::SeqCst); + + // We have data ready in buffer? Return it. + let data = state.rx.pop_buf(); + if !data.is_empty() { + let len = data.len().min(buf.len()); + buf[..len].copy_from_slice(&data[..len]); + + if state.rx.is_full() { + do_pend = true; + } + state.rx.pop(len); + + return Poll::Ready(Ok(len)); + } + + state.rx_waker.register(cx.waker()); + Poll::Pending + }); + + if do_pend { + self.inner.pend(); + } + + res + }) + } +} + +impl<'d, T: Instance> embedded_io::asynch::Write for BufferedUart<'d, T> { + type WriteFuture<'a> = impl Future> + where + Self: 'a; + + fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { + poll_fn(move |cx| { + let (poll, empty) = self.inner.with(|state| { + let empty = state.tx.is_empty(); + let tx_buf = state.tx.push_buf(); + if tx_buf.is_empty() { + state.tx_waker.register(cx.waker()); + return (Poll::Pending, empty); + } + + let n = core::cmp::min(tx_buf.len(), buf.len()); + tx_buf[..n].copy_from_slice(&buf[..n]); + state.tx.push(n); + + (Poll::Ready(Ok(n)), empty) + }); + if empty { + self.inner.pend(); + } + poll + }) + } + + type FlushFuture<'a> = impl Future> + where + Self: 'a; + + fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { + poll_fn(move |cx| { + self.inner.with(|state| { + if !state.tx.is_empty() { + state.tx_waker.register(cx.waker()); + return Poll::Pending; + } + + Poll::Ready(Ok(())) + }) + }) + } +} diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 22224215c..6feecd184 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -424,227 +424,10 @@ cfg_if::cfg_if! { } } +#[cfg(feature = "nightly")] pub use buffered::*; -mod buffered { - use atomic_polyfill::{compiler_fence, Ordering}; - use core::pin::Pin; - use core::task::Context; - use core::task::Poll; - use embassy::waitqueue::WakerRegistration; - use embassy_hal_common::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; - use embassy_hal_common::ring_buffer::RingBuffer; - - use super::*; - - pub struct State<'d, T: Instance>(StateStorage>); - impl<'d, T: Instance> State<'d, T> { - pub fn new() -> Self { - Self(StateStorage::new()) - } - } - - struct StateInner<'d, T: Instance> { - phantom: PhantomData<&'d mut T>, - - rx_waker: WakerRegistration, - rx: RingBuffer<'d>, - - tx_waker: WakerRegistration, - tx: RingBuffer<'d>, - } - - unsafe impl<'d, T: Instance> Send for StateInner<'d, T> {} - unsafe impl<'d, T: Instance> Sync for StateInner<'d, T> {} - - pub struct BufferedUart<'d, T: Instance> { - inner: PeripheralMutex<'d, StateInner<'d, T>>, - } - - impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {} - - impl<'d, T: Instance> BufferedUart<'d, T> { - pub unsafe fn new( - state: &'d mut State<'d, T>, - _uart: Uart<'d, T, NoDma, NoDma>, - irq: impl Unborrow + 'd, - tx_buffer: &'d mut [u8], - rx_buffer: &'d mut [u8], - ) -> BufferedUart<'d, T> { - unborrow!(irq); - - let r = T::regs(); - r.cr1().modify(|w| { - w.set_rxneie(true); - w.set_idleie(true); - }); - - Self { - inner: PeripheralMutex::new_unchecked(irq, &mut state.0, move || StateInner { - phantom: PhantomData, - tx: RingBuffer::new(tx_buffer), - tx_waker: WakerRegistration::new(), - - rx: RingBuffer::new(rx_buffer), - rx_waker: WakerRegistration::new(), - }), - } - } - } - - impl<'d, T: Instance> StateInner<'d, T> - where - Self: 'd, - { - fn on_rx(&mut self) { - let r = T::regs(); - unsafe { - let sr = sr(r).read(); - clear_interrupt_flags(r, sr); - - // This read also clears the error and idle interrupt flags on v1. - let b = rdr(r).read_volatile(); - - if sr.rxne() { - if sr.pe() { - warn!("Parity error"); - } - if sr.fe() { - warn!("Framing error"); - } - if sr.ne() { - warn!("Noise error"); - } - if sr.ore() { - warn!("Overrun error"); - } - - let buf = self.rx.push_buf(); - if !buf.is_empty() { - buf[0] = b; - self.rx.push(1); - } else { - warn!("RX buffer full, discard received byte"); - } - - if self.rx.is_full() { - self.rx_waker.wake(); - } - } - - if sr.idle() { - self.rx_waker.wake(); - }; - } - } - - fn on_tx(&mut self) { - let r = T::regs(); - unsafe { - if sr(r).read().txe() { - let buf = self.tx.pop_buf(); - if !buf.is_empty() { - r.cr1().modify(|w| { - w.set_txeie(true); - }); - tdr(r).write_volatile(buf[0].into()); - self.tx.pop(1); - self.tx_waker.wake(); - } else { - // Disable interrupt until we have something to transmit again - r.cr1().modify(|w| { - w.set_txeie(false); - }); - } - } - } - } - } - - impl<'d, T: Instance> PeripheralState for StateInner<'d, T> - where - Self: 'd, - { - type Interrupt = T::Interrupt; - fn on_interrupt(&mut self) { - self.on_rx(); - self.on_tx(); - } - } - - impl<'d, T: Instance> embassy::io::AsyncBufRead for BufferedUart<'d, T> { - fn poll_fill_buf( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { - self.inner.with(|state| { - compiler_fence(Ordering::SeqCst); - - // We have data ready in buffer? Return it. - let buf = state.rx.pop_buf(); - if !buf.is_empty() { - let buf: &[u8] = buf; - // Safety: buffer lives as long as uart - let buf: &[u8] = unsafe { core::mem::transmute(buf) }; - return Poll::Ready(Ok(buf)); - } - - state.rx_waker.register(cx.waker()); - Poll::>::Pending - }) - } - fn consume(mut self: Pin<&mut Self>, amt: usize) { - let signal = self.inner.with(|state| { - let full = state.rx.is_full(); - state.rx.pop(amt); - full - }); - if signal { - self.inner.pend(); - } - } - } - - impl<'d, T: Instance> embassy::io::AsyncWrite for BufferedUart<'d, T> { - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - let (poll, empty) = self.inner.with(|state| { - let empty = state.tx.is_empty(); - let tx_buf = state.tx.push_buf(); - if tx_buf.is_empty() { - state.tx_waker.register(cx.waker()); - return (Poll::Pending, empty); - } - - let n = core::cmp::min(tx_buf.len(), buf.len()); - tx_buf[..n].copy_from_slice(&buf[..n]); - state.tx.push(n); - - (Poll::Ready(Ok(n)), empty) - }); - if empty { - self.inner.pend(); - } - poll - } - - fn poll_flush( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { - self.inner.with(|state| { - if !state.tx.is_empty() { - state.tx_waker.register(cx.waker()); - return Poll::Pending; - } - - Poll::Ready(Ok(())) - }) - } - } -} +#[cfg(feature = "nightly")] +mod buffered; #[cfg(usart_v1)] fn tdr(r: crate::pac::usart::Usart) -> *mut u8 { @@ -662,6 +445,7 @@ fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg crate::pac::common::Reg { unborrow!($($pin),*); @@ -23,9 +19,24 @@ macro_rules! config_ulpi_pins { }; } +/// USB PHY type +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum PhyType { + /// Internal Full-Speed PHY + /// + /// Available on most High-Speed peripherals. + InternalFullSpeed, + /// Internal High-Speed PHY + /// + /// Available on a few STM32 chips. + InternalHighSpeed, + /// External ULPI High-Speed PHY + ExternalHighSpeed, +} + pub struct UsbOtg<'d, T: Instance> { phantom: PhantomData<&'d mut T>, - phy_type: PhyType, + _phy_type: PhyType, } impl<'d, T: Instance> UsbOtg<'d, T> { @@ -44,7 +55,7 @@ impl<'d, T: Instance> UsbOtg<'d, T> { Self { phantom: PhantomData, - phy_type: PhyType::InternalFullSpeed, + _phy_type: PhyType::InternalFullSpeed, } } @@ -71,7 +82,7 @@ impl<'d, T: Instance> UsbOtg<'d, T> { Self { phantom: PhantomData, - phy_type: PhyType::ExternalHighSpeed, + _phy_type: PhyType::ExternalHighSpeed, } } } @@ -83,29 +94,6 @@ impl<'d, T: Instance> Drop for UsbOtg<'d, T> { } } -unsafe impl<'d, T: Instance> Send for UsbOtg<'d, T> {} -unsafe impl<'d, T: Instance> Sync for UsbOtg<'d, T> {} - -unsafe impl<'d, T: Instance> UsbPeripheral for UsbOtg<'d, T> { - const REGISTERS: *const () = T::REGISTERS; - const HIGH_SPEED: bool = T::HIGH_SPEED; - const FIFO_DEPTH_WORDS: usize = T::FIFO_DEPTH_WORDS; - const ENDPOINT_COUNT: usize = T::ENDPOINT_COUNT; - - fn enable() { - ::enable(); - ::reset(); - } - - fn phy_type(&self) -> PhyType { - self.phy_type - } - - fn ahb_frequency_hz(&self) -> u32 { - ::frequency().0 - } -} - pub(crate) mod sealed { pub trait Instance { const REGISTERS: *const (); @@ -177,7 +165,7 @@ foreach_peripheral!( const FIFO_DEPTH_WORDS: usize = 512; const ENDPOINT_COUNT: usize = 8; } else { - compile_error!("USB_OTG_FS peripheral is not supported by this chip. Disable \"usb-otg-fs\" feature or select a different chip."); + compile_error!("USB_OTG_FS peripheral is not supported by this chip."); } } } @@ -214,7 +202,7 @@ foreach_peripheral!( const FIFO_DEPTH_WORDS: usize = 1024; const ENDPOINT_COUNT: usize = 9; } else { - compile_error!("USB_OTG_HS peripheral is not supported by this chip. Disable \"usb-otg-hs\" feature or select a different chip."); + compile_error!("USB_OTG_HS peripheral is not supported by this chip."); } } } @@ -222,12 +210,3 @@ foreach_peripheral!( impl Instance for peripherals::$inst {} }; ); - -foreach_interrupt!( - ($inst:ident, otgfs, $block:ident, GLOBAL, $irq:ident) => { - unsafe impl USBInterrupt for crate::interrupt::$irq {} - }; - ($inst:ident, otghs, $block:ident, GLOBAL, $irq:ident) => { - unsafe impl USBInterrupt for crate::interrupt::$irq {} - }; -); diff --git a/embassy/src/io/error.rs b/embassy/src/io/error.rs deleted file mode 100644 index 2092c0d18..000000000 --- a/embassy/src/io/error.rs +++ /dev/null @@ -1,142 +0,0 @@ -/// Categories of errors that can occur. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[non_exhaustive] -pub enum Error { - /// An entity was not found, often a file. - NotFound, - /// The operation lacked the necessary privileges to complete. - PermissionDenied, - /// The connection was refused by the remote server. - ConnectionRefused, - /// The connection was reset by the remote server. - ConnectionReset, - /// The connection was aborted (terminated) by the remote server. - ConnectionAborted, - /// The network operation failed because it was not connected yet. - NotConnected, - /// A socket address could not be bound because the address is already in - /// use elsewhere. - AddrInUse, - /// A nonexistent interface was requested or the requested address was not - /// local. - AddrNotAvailable, - /// The operation failed because a pipe was closed. - BrokenPipe, - /// An entity already exists, often a file. - AlreadyExists, - /// The operation needs to block to complete, but the blocking operation was - /// requested to not occur. - WouldBlock, - /// A parameter was incorrect. - InvalidInput, - /// Data not valid for the operation were encountered. - /// - /// Unlike [`InvalidInput`], this typically means that the operation - /// parameters were valid, however the error was caused by malformed - /// input data. - /// - /// For example, a function that reads a file into a string will error with - /// `InvalidData` if the file's contents are not valid UTF-8. - /// - /// [`InvalidInput`]: #variant.InvalidInput - InvalidData, - /// The I/O operation's timeout expired, causing it to be canceled. - TimedOut, - /// An error returned when an operation could not be completed because a - /// call to [`write`] returned [`Ok(0)`]. - /// - /// This typically means that an operation could only succeed if it wrote a - /// particular number of bytes but only a smaller number of bytes could be - /// written. - /// - /// [`write`]: ../../std/io/trait.Write.html#tymethod.write - /// [`Ok(0)`]: ../../std/io/type.Result.html - WriteZero, - /// This operation was interrupted. - /// - /// Interrupted operations can typically be retried. - Interrupted, - - /// An error returned when an operation could not be completed because an - /// "end of file" was reached prematurely. - /// - /// This typically means that an operation could only succeed if it read a - /// particular number of bytes but only a smaller number of bytes could be - /// read. - UnexpectedEof, - - /// An operation would have read more data if the given buffer was large. - /// - /// This typically means that the buffer has been filled with the first N bytes - /// of the read data. - Truncated, - - /// Any I/O error not part of this list. - Other, -} - -pub type Result = core::result::Result; - -#[cfg(feature = "std")] -impl From for Error { - fn from(err: std::io::Error) -> Error { - match err.kind() { - std::io::ErrorKind::NotFound => Error::NotFound, - std::io::ErrorKind::PermissionDenied => Error::PermissionDenied, - std::io::ErrorKind::ConnectionRefused => Error::ConnectionRefused, - std::io::ErrorKind::ConnectionReset => Error::ConnectionReset, - std::io::ErrorKind::ConnectionAborted => Error::ConnectionAborted, - std::io::ErrorKind::NotConnected => Error::NotConnected, - std::io::ErrorKind::AddrInUse => Error::AddrInUse, - std::io::ErrorKind::AddrNotAvailable => Error::AddrNotAvailable, - std::io::ErrorKind::BrokenPipe => Error::BrokenPipe, - std::io::ErrorKind::AlreadyExists => Error::AlreadyExists, - std::io::ErrorKind::WouldBlock => Error::WouldBlock, - std::io::ErrorKind::InvalidInput => Error::InvalidInput, - std::io::ErrorKind::InvalidData => Error::InvalidData, - std::io::ErrorKind::TimedOut => Error::TimedOut, - std::io::ErrorKind::WriteZero => Error::WriteZero, - std::io::ErrorKind::Interrupted => Error::Interrupted, - std::io::ErrorKind::UnexpectedEof => Error::UnexpectedEof, - _ => Error::Other, - } - } -} - -#[cfg(feature = "std")] -impl From for std::io::Error { - fn from(e: Error) -> Self { - let kind = match e { - Error::NotFound => std::io::ErrorKind::NotFound, - Error::PermissionDenied => std::io::ErrorKind::PermissionDenied, - Error::ConnectionRefused => std::io::ErrorKind::ConnectionRefused, - Error::ConnectionReset => std::io::ErrorKind::ConnectionReset, - Error::ConnectionAborted => std::io::ErrorKind::ConnectionAborted, - Error::NotConnected => std::io::ErrorKind::NotConnected, - Error::AddrInUse => std::io::ErrorKind::AddrInUse, - Error::AddrNotAvailable => std::io::ErrorKind::AddrNotAvailable, - Error::BrokenPipe => std::io::ErrorKind::BrokenPipe, - Error::AlreadyExists => std::io::ErrorKind::AlreadyExists, - Error::WouldBlock => std::io::ErrorKind::WouldBlock, - Error::InvalidInput => std::io::ErrorKind::InvalidInput, - Error::InvalidData => std::io::ErrorKind::InvalidData, - Error::TimedOut => std::io::ErrorKind::TimedOut, - Error::WriteZero => std::io::ErrorKind::WriteZero, - Error::Interrupted => std::io::ErrorKind::Interrupted, - Error::UnexpectedEof => std::io::ErrorKind::UnexpectedEof, - Error::Truncated => std::io::ErrorKind::Other, - Error::Other => std::io::ErrorKind::Other, - }; - std::io::Error::new(kind, "embassy::io::Error") - } -} - -impl core::fmt::Display for Error { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{:?}", self) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for Error {} diff --git a/embassy/src/io/mod.rs b/embassy/src/io/mod.rs deleted file mode 100644 index 52b050971..000000000 --- a/embassy/src/io/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -mod error; -#[cfg(feature = "std")] -mod std; -mod traits; -mod util; - -pub use self::error::*; -#[cfg(feature = "std")] -pub use self::std::*; -pub use self::traits::*; -pub use self::util::*; diff --git a/embassy/src/io/std.rs b/embassy/src/io/std.rs deleted file mode 100644 index 580d52891..000000000 --- a/embassy/src/io/std.rs +++ /dev/null @@ -1,41 +0,0 @@ -use core::pin::Pin; -use core::task::{Context, Poll}; -use futures::io as std_io; - -use super::{AsyncBufRead, AsyncWrite, Result}; - -pub struct FromStdIo(T); - -impl FromStdIo { - pub fn new(inner: T) -> Self { - Self(inner) - } -} - -impl AsyncBufRead for FromStdIo { - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let Self(inner) = unsafe { self.get_unchecked_mut() }; - unsafe { Pin::new_unchecked(inner) } - .poll_fill_buf(cx) - .map_err(|e| e.into()) - } - fn consume(self: Pin<&mut Self>, amt: usize) { - let Self(inner) = unsafe { self.get_unchecked_mut() }; - unsafe { Pin::new_unchecked(inner) }.consume(amt) - } -} - -impl AsyncWrite for FromStdIo { - fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll> { - let Self(inner) = unsafe { self.get_unchecked_mut() }; - unsafe { Pin::new_unchecked(inner) } - .poll_write(cx, buf) - .map_err(|e| e.into()) - } - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let Self(inner) = unsafe { self.get_unchecked_mut() }; - unsafe { Pin::new_unchecked(inner) } - .poll_flush(cx) - .map_err(|e| e.into()) - } -} diff --git a/embassy/src/io/traits.rs b/embassy/src/io/traits.rs deleted file mode 100644 index 06500a687..000000000 --- a/embassy/src/io/traits.rs +++ /dev/null @@ -1,175 +0,0 @@ -use core::ops::DerefMut; -use core::pin::Pin; -use core::task::{Context, Poll}; - -#[cfg(feature = "alloc")] -use alloc::boxed::Box; - -use super::error::Result; - -/// Read bytes asynchronously. -/// -/// This trait is analogous to the `std::io::BufRead` trait, but integrates -/// with the asynchronous task system. In particular, the `poll_fill_buf` -/// method, unlike `BufRead::fill_buf`, will automatically queue the current task -/// for wakeup and return if data is not yet available, rather than blocking -/// the calling thread. -pub trait AsyncBufRead { - /// Attempt to return the contents of the internal buffer, filling it with more data - /// from the inner reader if it is empty. - /// - /// On success, returns `Poll::Ready(Ok(buf))`. - /// - /// If no data is available for reading, the method returns - /// `Poll::Pending` and arranges for the current task (via - /// `cx.waker().wake_by_ref()`) to receive a notification when the object becomes - /// readable or is closed. - /// - /// This function is a lower-level call. It needs to be paired with the - /// [`consume`] method to function properly. When calling this - /// method, none of the contents will be "read" in the sense that later - /// calling [`poll_fill_buf`] may return the same contents. As such, [`consume`] must - /// be called with the number of bytes that are consumed from this buffer to - /// ensure that the bytes are never returned twice. - /// - /// [`poll_fill_buf`]: AsyncBufRead::poll_fill_buf - /// [`consume`]: AsyncBufRead::consume - /// - /// An empty buffer returned indicates that the stream has reached EOF. - /// - /// # Implementation - /// - /// This function may not return errors of kind `WouldBlock` or - /// `Interrupted`. Implementations must convert `WouldBlock` into - /// `Poll::Pending` and either internally retry or convert - /// `Interrupted` into another error kind. - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; - - /// Tells this buffer that `amt` bytes have been consumed from the buffer, - /// so they should no longer be returned in calls to [`poll_fill_buf`]. - /// - /// This function is a lower-level call. It needs to be paired with the - /// [`poll_fill_buf`] method to function properly. This function does - /// not perform any I/O, it simply informs this object that some amount of - /// its buffer, returned from [`poll_fill_buf`], has been consumed and should - /// no longer be returned. As such, this function may do odd things if - /// [`poll_fill_buf`] isn't called before calling it. - /// - /// The `amt` must be `<=` the number of bytes in the buffer returned by - /// [`poll_fill_buf`]. - /// - /// [`poll_fill_buf`]: AsyncBufRead::poll_fill_buf - fn consume(self: Pin<&mut Self>, amt: usize); -} - -/// Write bytes asynchronously. -/// -/// This trait is analogous to the `core::io::Write` trait, but integrates -/// with the asynchronous task system. In particular, the `poll_write` -/// method, unlike `Write::write`, will automatically queue the current task -/// for wakeup and return if the writer cannot take more data, rather than blocking -/// the calling thread. -pub trait AsyncWrite { - /// Attempt to write bytes from `buf` into the object. - /// - /// On success, returns `Poll::Ready(Ok(num_bytes_written))`. - /// - /// If the object is not ready for writing, the method returns - /// `Poll::Pending` and arranges for the current task (via - /// `cx.waker().wake_by_ref()`) to receive a notification when the object becomes - /// writable or is closed. - /// - /// # Implementation - /// - /// This function may not return errors of kind `WouldBlock` or - /// `Interrupted`. Implementations must convert `WouldBlock` into - /// `Poll::Pending` and either internally retry or convert - /// `Interrupted` into another error kind. - /// - /// `poll_write` must try to make progress by flushing the underlying object if - /// that is the only way the underlying object can become writable again. - fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll>; - - /// Attempt to flush the object, ensuring that any buffered data reach their destination. - /// - /// On success, returns Poll::Ready(Ok(())). - /// - /// If flushing cannot immediately complete, this method returns [Poll::Pending] and arranges for the - /// current task (via cx.waker()) to receive a notification when the object can make progress - /// towards flushing. - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; -} - -macro_rules! defer_async_read { - () => { - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut **self.get_mut()).poll_fill_buf(cx) - } - - fn consume(mut self: Pin<&mut Self>, amt: usize) { - Pin::new(&mut **self).consume(amt) - } - }; -} - -#[cfg(feature = "alloc")] -impl AsyncBufRead for Box { - defer_async_read!(); -} - -impl AsyncBufRead for &mut T { - defer_async_read!(); -} - -impl

AsyncBufRead for Pin

-where - P: DerefMut + Unpin, - P::Target: AsyncBufRead, -{ - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.get_mut().as_mut().poll_fill_buf(cx) - } - - fn consume(self: Pin<&mut Self>, amt: usize) { - self.get_mut().as_mut().consume(amt) - } -} - -macro_rules! deref_async_write { - () => { - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - Pin::new(&mut **self).poll_write(cx, buf) - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut **self).poll_flush(cx) - } - }; -} - -#[cfg(feature = "alloc")] -impl AsyncWrite for Box { - deref_async_write!(); -} - -impl AsyncWrite for &mut T { - deref_async_write!(); -} - -impl

AsyncWrite for Pin

-where - P: DerefMut + Unpin, - P::Target: AsyncWrite, -{ - fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll> { - self.get_mut().as_mut().poll_write(cx, buf) - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.get_mut().as_mut().poll_flush(cx) - } -} diff --git a/embassy/src/io/util/copy_buf.rs b/embassy/src/io/util/copy_buf.rs deleted file mode 100644 index 6d7932a0f..000000000 --- a/embassy/src/io/util/copy_buf.rs +++ /dev/null @@ -1,80 +0,0 @@ -use core::future::Future; -use core::pin::Pin; -use core::task::{Context, Poll}; -use futures::ready; -use pin_project::pin_project; - -use crate::io::{AsyncBufRead, AsyncWrite, Error, Result}; - -/// Creates a future which copies all the bytes from one object to another. -/// -/// The returned future will copy all the bytes read from this `AsyncBufRead` into the -/// `writer` specified. This future will only complete once the `reader` has hit -/// EOF and all bytes have been written to and flushed from the `writer` -/// provided. -/// -/// On success the number of bytes is returned. -/// -/// # Examples -/// -/// ``` ignore -/// # futures::executor::block_on(async { -/// use futures::io::{self, AsyncWriteExt, Cursor}; -/// -/// let reader = Cursor::new([1, 2, 3, 4]); -/// let mut writer = Cursor::new(vec![0u8; 5]); -/// -/// let bytes = io::copy_buf(reader, &mut writer).await?; -/// writer.close().await?; -/// -/// assert_eq!(bytes, 4); -/// assert_eq!(writer.into_inner(), [1, 2, 3, 4, 0]); -/// # Ok::<(), Box>(()) }).unwrap(); -/// ``` -pub fn copy_buf(reader: R, writer: &mut W) -> CopyBuf<'_, R, W> -where - R: AsyncBufRead, - W: AsyncWrite + Unpin + ?Sized, -{ - CopyBuf { - reader, - writer, - amt: 0, - } -} - -/// Future for the [`copy_buf()`] function. -#[pin_project] -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct CopyBuf<'a, R, W: ?Sized> { - #[pin] - reader: R, - writer: &'a mut W, - amt: usize, -} - -impl Future for CopyBuf<'_, R, W> -where - R: AsyncBufRead, - W: AsyncWrite + Unpin + ?Sized, -{ - type Output = Result; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut this = self.project(); - loop { - let buffer = ready!(this.reader.as_mut().poll_fill_buf(cx))?; - if buffer.is_empty() { - return Poll::Ready(Ok(*this.amt)); - } - - let i = ready!(Pin::new(&mut this.writer).poll_write(cx, buffer))?; - if i == 0 { - return Poll::Ready(Err(Error::WriteZero)); - } - *this.amt += i; - this.reader.as_mut().consume(i); - } - } -} diff --git a/embassy/src/io/util/drain.rs b/embassy/src/io/util/drain.rs deleted file mode 100644 index 2542876d8..000000000 --- a/embassy/src/io/util/drain.rs +++ /dev/null @@ -1,41 +0,0 @@ -use core::pin::Pin; -use futures::future::Future; -use futures::task::{Context, Poll}; - -use super::super::error::Result; -use super::super::traits::AsyncBufRead; - -pub struct Drain<'a, R: ?Sized> { - reader: &'a mut R, -} - -impl Unpin for Drain<'_, R> {} - -impl<'a, R: AsyncBufRead + ?Sized + Unpin> Drain<'a, R> { - pub(super) fn new(reader: &'a mut R) -> Self { - Self { reader } - } -} - -impl<'a, R: AsyncBufRead + ?Sized + Unpin> Future for Drain<'a, R> { - type Output = Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let Self { reader } = &mut *self; - let mut reader = Pin::new(reader); - - let mut n = 0; - - loop { - match reader.as_mut().poll_fill_buf(cx) { - Poll::Pending => return Poll::Ready(Ok(n)), - Poll::Ready(Err(e)) => return Poll::Ready(Err(e)), - Poll::Ready(Ok(buf)) => { - let len = buf.len(); - n += len; - reader.as_mut().consume(len); - } - } - } - } -} diff --git a/embassy/src/io/util/flush.rs b/embassy/src/io/util/flush.rs deleted file mode 100644 index 966ef10fb..000000000 --- a/embassy/src/io/util/flush.rs +++ /dev/null @@ -1,32 +0,0 @@ -use core::pin::Pin; -use futures::future::Future; -use futures::ready; -use futures::task::{Context, Poll}; - -use super::super::error::Result; -use super::super::traits::AsyncWrite; - -/// Future for the [`flush`](super::AsyncWriteExt::flush) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Flush<'a, W: ?Sized> { - writer: &'a mut W, -} - -impl Unpin for Flush<'_, W> {} - -impl<'a, W: AsyncWrite + ?Sized + Unpin> Flush<'a, W> { - pub(super) fn new(writer: &'a mut W) -> Self { - Flush { writer } - } -} - -impl Future for Flush<'_, W> { - type Output = Result<()>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = &mut *self; - let _ = ready!(Pin::new(&mut this.writer).poll_flush(cx))?; - Poll::Ready(Ok(())) - } -} diff --git a/embassy/src/io/util/mod.rs b/embassy/src/io/util/mod.rs deleted file mode 100644 index 49758ba99..000000000 --- a/embassy/src/io/util/mod.rs +++ /dev/null @@ -1,177 +0,0 @@ -use core::cmp::min; -use core::pin::Pin; -use core::task::{Context, Poll}; -use futures::ready; - -mod read; -pub use self::read::Read; - -mod read_buf; -pub use self::read_buf::ReadBuf; - -mod read_byte; -pub use self::read_byte::ReadByte; - -mod read_exact; -pub use self::read_exact::ReadExact; - -mod read_while; -pub use self::read_while::ReadWhile; - -mod read_to_end; -pub use self::read_to_end::ReadToEnd; - -mod skip_while; -pub use self::skip_while::SkipWhile; - -mod drain; -pub use self::drain::Drain; - -mod flush; -pub use self::flush::Flush; - -mod write; -pub use self::write::Write; - -mod write_all; -pub use self::write_all::WriteAll; - -mod write_byte; -pub use self::write_byte::WriteByte; - -#[cfg(feature = "alloc")] -mod split; -#[cfg(feature = "alloc")] -pub use self::split::{split, ReadHalf, WriteHalf}; - -mod copy_buf; -pub use self::copy_buf::{copy_buf, CopyBuf}; - -use super::error::Result; -use super::traits::{AsyncBufRead, AsyncWrite}; - -pub trait AsyncBufReadExt: AsyncBufRead { - fn poll_read( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> - where - Self: Unpin, - { - let mut this = &mut *self; - let rbuf = ready!(Pin::new(&mut this).poll_fill_buf(cx))?; - let n = min(buf.len(), rbuf.len()); - buf[..n].copy_from_slice(&rbuf[..n]); - Pin::new(&mut this).consume(n); - Poll::Ready(Ok(n)) - } - - fn read_while<'a, F: Fn(u8) -> bool>( - &'a mut self, - buf: &'a mut [u8], - f: F, - ) -> ReadWhile<'a, Self, F> - where - Self: Unpin, - { - ReadWhile::new(self, f, buf) - } - - fn skip_while bool>(&mut self, f: F) -> SkipWhile - where - Self: Unpin, - { - SkipWhile::new(self, f) - } - - fn drain(&mut self) -> Drain - where - Self: Unpin, - { - Drain::new(self) - } - - fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self> - where - Self: Unpin, - { - Read::new(self, buf) - } - - fn read_buf(&mut self) -> ReadBuf - where - Self: Unpin, - { - ReadBuf::new(self) - } - - fn read_byte(&mut self) -> ReadByte - where - Self: Unpin, - { - ReadByte::new(self) - } - - fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadExact<'a, Self> - where - Self: Unpin, - { - ReadExact::new(self, buf) - } - - fn read_to_end<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadToEnd<'a, Self> - where - Self: Unpin, - { - ReadToEnd::new(self, buf) - } -} - -impl AsyncBufReadExt for R {} - -pub async fn read_line( - r: &mut R, - buf: &mut [u8], -) -> Result { - r.skip_while(|b| b == b'\r' || b == b'\n').await?; - let n = r.read_while(buf, |b| b != b'\r' && b != b'\n').await?; - r.skip_while(|b| b == b'\r').await?; - //assert_eq!(b'\n', r.read_byte().await?); - r.read_byte().await?; - Ok(n) -} - -pub trait AsyncWriteExt: AsyncWrite { - fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> WriteAll<'a, Self> - where - Self: Unpin, - { - WriteAll::new(self, buf) - } - - fn write_byte(&mut self, byte: u8) -> WriteByte - where - Self: Unpin, - { - WriteByte::new(self, byte) - } - - fn write<'a>(&'a mut self, buf: &'a [u8]) -> Write<'a, Self> - where - Self: Unpin, - { - Write::new(self, buf) - } - - /// Awaits until all bytes have actually been written, and - /// not just enqueued as per the other "write" methods. - fn flush<'a>(&mut self) -> Flush - where - Self: Unpin, - { - Flush::new(self) - } -} - -impl AsyncWriteExt for R {} diff --git a/embassy/src/io/util/read.rs b/embassy/src/io/util/read.rs deleted file mode 100644 index 274b43a43..000000000 --- a/embassy/src/io/util/read.rs +++ /dev/null @@ -1,39 +0,0 @@ -use super::super::error::Result; -use super::super::traits::AsyncBufRead; - -use core::cmp::min; - -use core::pin::Pin; -use futures::future::Future; -use futures::ready; -use futures::task::{Context, Poll}; - -/// Future for the [`read_exact`](super::AsyncBufReadExt::read_exact) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Read<'a, R: ?Sized> { - reader: &'a mut R, - buf: &'a mut [u8], -} - -impl Unpin for Read<'_, R> {} - -impl<'a, R: AsyncBufRead + ?Sized + Unpin> Read<'a, R> { - pub(super) fn new(reader: &'a mut R, buf: &'a mut [u8]) -> Self { - Read { reader, buf } - } -} - -impl Future for Read<'_, R> { - type Output = Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = &mut *self; - let buf = ready!(Pin::new(&mut this.reader).poll_fill_buf(cx))?; - - let n = min(this.buf.len(), buf.len()); - this.buf[..n].copy_from_slice(&buf[..n]); - Pin::new(&mut this.reader).consume(n); - Poll::Ready(Ok(n)) - } -} diff --git a/embassy/src/io/util/read_buf.rs b/embassy/src/io/util/read_buf.rs deleted file mode 100644 index 71299b05e..000000000 --- a/embassy/src/io/util/read_buf.rs +++ /dev/null @@ -1,34 +0,0 @@ -use super::super::error::Result; -use super::super::traits::AsyncBufRead; - -use core::pin::Pin; -use futures::future::Future; -use futures::ready; -use futures::task::{Context, Poll}; - -pub struct ReadBuf<'a, R: ?Sized> { - reader: Option<&'a mut R>, -} - -impl Unpin for ReadBuf<'_, R> {} - -impl<'a, R: AsyncBufRead + ?Sized + Unpin> ReadBuf<'a, R> { - pub(super) fn new(reader: &'a mut R) -> Self { - ReadBuf { - reader: Some(reader), - } - } -} - -impl<'a, R: AsyncBufRead + ?Sized + Unpin> Future for ReadBuf<'a, R> { - type Output = Result<&'a [u8]>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = &mut *self; - - let buf = ready!(Pin::new(this.reader.as_mut().unwrap()).poll_fill_buf(cx))?; - let buf: &'a [u8] = unsafe { core::mem::transmute(buf) }; - this.reader = None; - Poll::Ready(Ok(buf)) - } -} diff --git a/embassy/src/io/util/read_byte.rs b/embassy/src/io/util/read_byte.rs deleted file mode 100644 index e5bbcb1ff..000000000 --- a/embassy/src/io/util/read_byte.rs +++ /dev/null @@ -1,36 +0,0 @@ -use core::pin::Pin; -use futures::future::Future; -use futures::ready; -use futures::task::{Context, Poll}; - -use super::super::error::{Error, Result}; -use super::super::traits::AsyncBufRead; - -pub struct ReadByte<'a, R: ?Sized> { - reader: &'a mut R, -} - -impl Unpin for ReadByte<'_, R> {} - -impl<'a, R: AsyncBufRead + ?Sized + Unpin> ReadByte<'a, R> { - pub(super) fn new(reader: &'a mut R) -> Self { - Self { reader } - } -} - -impl<'a, R: AsyncBufRead + ?Sized + Unpin> Future for ReadByte<'a, R> { - type Output = Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let Self { reader } = &mut *self; - let mut reader = Pin::new(reader); - let rbuf = ready!(reader.as_mut().poll_fill_buf(cx))?; - if rbuf.is_empty() { - return Poll::Ready(Err(Error::UnexpectedEof)); - } - - let r = rbuf[0]; - reader.as_mut().consume(1); - Poll::Ready(Ok(r)) - } -} diff --git a/embassy/src/io/util/read_exact.rs b/embassy/src/io/util/read_exact.rs deleted file mode 100644 index 4eecba4cc..000000000 --- a/embassy/src/io/util/read_exact.rs +++ /dev/null @@ -1,48 +0,0 @@ -use super::super::error::{Error, Result}; -use super::super::traits::AsyncBufRead; - -use core::cmp::min; -use core::mem; -use core::pin::Pin; -use futures::future::Future; -use futures::ready; -use futures::task::{Context, Poll}; - -/// Future for the [`read_exact`](super::AsyncBufReadExt::read_exact) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct ReadExact<'a, R: ?Sized> { - reader: &'a mut R, - buf: &'a mut [u8], -} - -impl Unpin for ReadExact<'_, R> {} - -impl<'a, R: AsyncBufRead + ?Sized + Unpin> ReadExact<'a, R> { - pub(super) fn new(reader: &'a mut R, buf: &'a mut [u8]) -> Self { - ReadExact { reader, buf } - } -} - -impl Future for ReadExact<'_, R> { - type Output = Result<()>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = &mut *self; - while !this.buf.is_empty() { - let buf = ready!(Pin::new(&mut this.reader).poll_fill_buf(cx))?; - if buf.is_empty() { - return Poll::Ready(Err(Error::UnexpectedEof)); - } - - let n = min(this.buf.len(), buf.len()); - this.buf[..n].copy_from_slice(&buf[..n]); - Pin::new(&mut this.reader).consume(n); - { - let (_, rest) = mem::take(&mut this.buf).split_at_mut(n); - this.buf = rest; - } - } - Poll::Ready(Ok(())) - } -} diff --git a/embassy/src/io/util/read_to_end.rs b/embassy/src/io/util/read_to_end.rs deleted file mode 100644 index d09999ad0..000000000 --- a/embassy/src/io/util/read_to_end.rs +++ /dev/null @@ -1,48 +0,0 @@ -use core::cmp::min; -use core::pin::Pin; -use futures::future::Future; -use futures::ready; -use futures::task::{Context, Poll}; - -use super::super::error::{Error, Result}; -use super::super::traits::AsyncBufRead; - -pub struct ReadToEnd<'a, R: ?Sized> { - reader: &'a mut R, - buf: &'a mut [u8], - n: usize, -} - -impl Unpin for ReadToEnd<'_, R> {} - -impl<'a, R: AsyncBufRead + ?Sized + Unpin> ReadToEnd<'a, R> { - pub(super) fn new(reader: &'a mut R, buf: &'a mut [u8]) -> Self { - Self { reader, buf, n: 0 } - } -} - -impl<'a, R: AsyncBufRead + ?Sized + Unpin> Future for ReadToEnd<'a, R> { - type Output = Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let Self { reader, buf, n } = &mut *self; - let mut reader = Pin::new(reader); - loop { - let rbuf = ready!(reader.as_mut().poll_fill_buf(cx))?; - if rbuf.is_empty() { - return Poll::Ready(Ok(*n)); - } - - if *n == buf.len() { - return Poll::Ready(Err(Error::Truncated)); - } - - // truncate data if it doesn't fit in buf - let p = min(rbuf.len(), buf.len() - *n); - buf[*n..*n + p].copy_from_slice(&rbuf[..p]); - *n += p; - - reader.as_mut().consume(p); - } - } -} diff --git a/embassy/src/io/util/read_while.rs b/embassy/src/io/util/read_while.rs deleted file mode 100644 index e24638039..000000000 --- a/embassy/src/io/util/read_while.rs +++ /dev/null @@ -1,61 +0,0 @@ -use core::cmp::min; -use core::pin::Pin; -use futures::future::Future; -use futures::ready; -use futures::task::{Context, Poll}; - -use super::super::error::{Error, Result}; -use super::super::traits::AsyncBufRead; - -pub struct ReadWhile<'a, R: ?Sized, F> { - reader: &'a mut R, - buf: &'a mut [u8], - n: usize, - f: F, -} - -impl Unpin for ReadWhile<'_, R, F> {} - -impl<'a, R: AsyncBufRead + ?Sized + Unpin, F: Fn(u8) -> bool> ReadWhile<'a, R, F> { - pub(super) fn new(reader: &'a mut R, f: F, buf: &'a mut [u8]) -> Self { - Self { - reader, - f, - buf, - n: 0, - } - } -} - -impl<'a, R: AsyncBufRead + ?Sized + Unpin, F: Fn(u8) -> bool> Future for ReadWhile<'a, R, F> { - type Output = Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let Self { reader, f, buf, n } = &mut *self; - let mut reader = Pin::new(reader); - loop { - let rbuf = ready!(reader.as_mut().poll_fill_buf(cx))?; - if rbuf.is_empty() { - return Poll::Ready(Err(Error::UnexpectedEof)); - } - - let (p, done) = match rbuf.iter().position(|&b| !f(b)) { - Some(p) => (p, true), - None => (rbuf.len(), false), - }; - - // truncate data if it doesn't fit in buf - let p2 = min(p, buf.len() - *n); - buf[*n..*n + p2].copy_from_slice(&rbuf[..p2]); - *n += p2; - - // consume it all, even if it doesn't fit. - // Otherwise we can deadlock because we never read to the ending char - reader.as_mut().consume(p); - - if done { - return Poll::Ready(Ok(*n)); - } - } - } -} diff --git a/embassy/src/io/util/skip_while.rs b/embassy/src/io/util/skip_while.rs deleted file mode 100644 index 6f0e167df..000000000 --- a/embassy/src/io/util/skip_while.rs +++ /dev/null @@ -1,45 +0,0 @@ -use core::iter::Iterator; -use core::pin::Pin; -use futures::future::Future; -use futures::ready; -use futures::task::{Context, Poll}; - -use super::super::error::{Error, Result}; -use super::super::traits::AsyncBufRead; - -pub struct SkipWhile<'a, R: ?Sized, F> { - reader: &'a mut R, - f: F, -} - -impl Unpin for SkipWhile<'_, R, F> {} - -impl<'a, R: AsyncBufRead + ?Sized + Unpin, F: Fn(u8) -> bool> SkipWhile<'a, R, F> { - pub(super) fn new(reader: &'a mut R, f: F) -> Self { - Self { reader, f } - } -} - -impl<'a, R: AsyncBufRead + ?Sized + Unpin, F: Fn(u8) -> bool> Future for SkipWhile<'a, R, F> { - type Output = Result<()>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let Self { reader, f } = &mut *self; - let mut reader = Pin::new(reader); - loop { - let buf = ready!(reader.as_mut().poll_fill_buf(cx))?; - if buf.is_empty() { - return Poll::Ready(Err(Error::UnexpectedEof)); - } - - let (p, done) = match buf.iter().position(|b| !f(*b)) { - Some(p) => (p, true), - None => (buf.len(), false), - }; - reader.as_mut().consume(p); - if done { - return Poll::Ready(Ok(())); - } - } - } -} diff --git a/embassy/src/io/util/split.rs b/embassy/src/io/util/split.rs deleted file mode 100644 index cc029aa53..000000000 --- a/embassy/src/io/util/split.rs +++ /dev/null @@ -1,43 +0,0 @@ -use alloc::rc::Rc; -use core::cell::UnsafeCell; -use core::pin::Pin; -use futures::task::{Context, Poll}; - -use super::super::error::Result; -use super::super::traits::{AsyncBufRead, AsyncWrite}; - -/// The readable half of an object returned from `AsyncBufRead::split`. -#[derive(Debug)] -pub struct ReadHalf { - handle: Rc>, -} - -/// The writable half of an object returned from `AsyncBufRead::split`. -#[derive(Debug)] -pub struct WriteHalf { - handle: Rc>, -} - -impl AsyncBufRead for ReadHalf { - fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(unsafe { &mut *self.handle.get() }).poll_fill_buf(cx) - } - - fn consume(self: Pin<&mut Self>, amt: usize) { - Pin::new(unsafe { &mut *self.handle.get() }).consume(amt) - } -} - -impl AsyncWrite for WriteHalf { - fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll> { - Pin::new(unsafe { &mut *self.handle.get() }).poll_write(cx, buf) - } - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(unsafe { &mut *self.handle.get() }).poll_flush(cx) - } -} - -pub fn split(t: T) -> (ReadHalf, WriteHalf) { - let c = Rc::new(UnsafeCell::new(t)); - (ReadHalf { handle: c.clone() }, WriteHalf { handle: c }) -} diff --git a/embassy/src/io/util/write.rs b/embassy/src/io/util/write.rs deleted file mode 100644 index 403cd59fe..000000000 --- a/embassy/src/io/util/write.rs +++ /dev/null @@ -1,33 +0,0 @@ -use core::pin::Pin; -use futures::future::Future; -use futures::ready; -use futures::task::{Context, Poll}; - -use super::super::error::Result; -use super::super::traits::AsyncWrite; - -/// Future for the [`write_all`](super::AsyncWriteExt::write_all) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct Write<'a, W: ?Sized> { - writer: &'a mut W, - buf: &'a [u8], -} - -impl Unpin for Write<'_, W> {} - -impl<'a, W: AsyncWrite + ?Sized + Unpin> Write<'a, W> { - pub(super) fn new(writer: &'a mut W, buf: &'a [u8]) -> Self { - Write { writer, buf } - } -} - -impl Future for Write<'_, W> { - type Output = Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = &mut *self; - let n = ready!(Pin::new(&mut this.writer).poll_write(cx, this.buf))?; - Poll::Ready(Ok(n)) - } -} diff --git a/embassy/src/io/util/write_all.rs b/embassy/src/io/util/write_all.rs deleted file mode 100644 index 8a7d9984c..000000000 --- a/embassy/src/io/util/write_all.rs +++ /dev/null @@ -1,44 +0,0 @@ -use core::mem; -use core::pin::Pin; -use futures::future::Future; -use futures::ready; -use futures::task::{Context, Poll}; - -use super::super::error::Result; -use super::super::traits::AsyncWrite; - -/// Future for the [`write_all`](super::AsyncWriteExt::write_all) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct WriteAll<'a, W: ?Sized> { - writer: &'a mut W, - buf: &'a [u8], -} - -impl Unpin for WriteAll<'_, W> {} - -impl<'a, W: AsyncWrite + ?Sized + Unpin> WriteAll<'a, W> { - pub(super) fn new(writer: &'a mut W, buf: &'a [u8]) -> Self { - WriteAll { writer, buf } - } -} - -impl Future for WriteAll<'_, W> { - type Output = Result<()>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = &mut *self; - while !this.buf.is_empty() { - let n = ready!(Pin::new(&mut this.writer).poll_write(cx, this.buf))?; - { - let (_, rest) = mem::take(&mut this.buf).split_at(n); - this.buf = rest; - } - if n == 0 { - panic!(); - } - } - - Poll::Ready(Ok(())) - } -} diff --git a/embassy/src/io/util/write_byte.rs b/embassy/src/io/util/write_byte.rs deleted file mode 100644 index 659e427b1..000000000 --- a/embassy/src/io/util/write_byte.rs +++ /dev/null @@ -1,39 +0,0 @@ -use core::pin::Pin; -use futures::future::Future; -use futures::ready; -use futures::task::{Context, Poll}; - -use super::super::error::Result; -use super::super::traits::AsyncWrite; - -/// Future for the [`write_all`](super::AsyncWriteExt::write_all) method. -#[derive(Debug)] -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct WriteByte<'a, W: ?Sized> { - writer: &'a mut W, - byte: u8, -} - -impl Unpin for WriteByte<'_, W> {} - -impl<'a, W: AsyncWrite + ?Sized + Unpin> WriteByte<'a, W> { - pub(super) fn new(writer: &'a mut W, byte: u8) -> Self { - WriteByte { writer, byte } - } -} - -impl Future for WriteByte<'_, W> { - type Output = Result<()>; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = &mut *self; - let buf = [this.byte; 1]; - let n = ready!(Pin::new(&mut this.writer).poll_write(cx, &buf))?; - if n == 0 { - panic!(); - } - assert!(n == 1); - - Poll::Ready(Ok(())) - } -} diff --git a/embassy/src/lib.rs b/embassy/src/lib.rs index ec697b40a..087bd357a 100644 --- a/embassy/src/lib.rs +++ b/embassy/src/lib.rs @@ -13,7 +13,6 @@ pub mod channel; pub mod executor; #[cfg(cortex_m)] pub mod interrupt; -pub mod io; pub mod mutex; #[cfg(feature = "time")] pub mod time; diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml index 4258544f0..ffac0a769 100644 --- a/examples/nrf/Cargo.toml +++ b/examples/nrf/Cargo.toml @@ -6,7 +6,7 @@ version = "0.1.0" [features] default = ["nightly"] -nightly = ["embassy-nrf/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embassy-usb-serial", "embassy-usb-hid", "embassy-usb-ncm"] +nightly = ["embassy-nrf/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embassy-usb-serial", "embassy-usb-hid", "embassy-usb-ncm", "embedded-io/async", "embassy-net/nightly"] [dependencies] embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-timestamp-uptime"] } @@ -16,6 +16,7 @@ embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defm embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"], optional = true } embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", features = ["defmt"], optional = true } embassy-usb-ncm = { version = "0.1.0", path = "../../embassy-usb-ncm", features = ["defmt"], optional = true } +embedded-io = "0.2.0" defmt = "0.3" defmt-rtt = "0.3" diff --git a/examples/nrf/src/bin/buffered_uart.rs b/examples/nrf/src/bin/buffered_uart.rs index 2cd163a9f..a64c5821b 100644 --- a/examples/nrf/src/bin/buffered_uart.rs +++ b/examples/nrf/src/bin/buffered_uart.rs @@ -4,9 +4,9 @@ use defmt::*; use embassy::executor::Spawner; -use embassy::io::{AsyncBufReadExt, AsyncWriteExt}; use embassy_nrf::buffered_uarte::State; use embassy_nrf::{buffered_uarte::BufferedUarte, interrupt, uarte, Peripherals}; +use embedded_io::asynch::{Read, Write}; use futures::pin_mut; use defmt_rtt as _; // global logger diff --git a/examples/nrf/src/bin/usb_ethernet.rs b/examples/nrf/src/bin/usb_ethernet.rs index f14a29c49..843487c03 100644 --- a/examples/nrf/src/bin/usb_ethernet.rs +++ b/examples/nrf/src/bin/usb_ethernet.rs @@ -10,9 +10,9 @@ use defmt::*; use embassy::blocking_mutex::raw::ThreadModeRawMutex; use embassy::channel::Channel; use embassy::executor::Spawner; -use embassy::io::{AsyncBufReadExt, AsyncWriteExt}; use embassy::util::Forever; -use embassy_net::{PacketBox, PacketBoxExt, PacketBuf, TcpSocket}; +use embassy_net::tcp::TcpSocket; +use embassy_net::{PacketBox, PacketBoxExt, PacketBuf}; use embassy_nrf::pac; use embassy_nrf::usb::Driver; use embassy_nrf::Peripherals; @@ -20,7 +20,9 @@ use embassy_nrf::{interrupt, peripherals}; use embassy_usb::{Builder, Config, UsbDevice}; use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State}; -use defmt_rtt as _; // global logger +use defmt_rtt as _; +use embedded_io::asynch::{Read, Write}; +// global logger use panic_probe as _; type MyDriver = Driver<'static, peripherals::USBD>; diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index 0853c323e..fa2a98a49 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -6,7 +6,8 @@ version = "0.1.0" [dependencies] embassy = { version = "0.1.0", path = "../../embassy", features = ["log", "std", "time", "nightly"] } -embassy-net = { version = "0.1.0", path = "../../embassy-net", features=["std", "log", "medium-ethernet", "tcp", "dhcpv4", "pool-16"] } +embassy-net = { version = "0.1.0", path = "../../embassy-net", features=["nightly", "std", "log", "medium-ethernet", "tcp", "dhcpv4", "pool-16"] } +embedded-io = { version = "0.2.0", features = ["async", "std"] } async-io = "1.6.0" env_logger = "0.9.0" diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs index 3b4bc6fea..daedffb0f 100644 --- a/examples/std/src/bin/net.rs +++ b/examples/std/src/bin/net.rs @@ -2,12 +2,13 @@ use clap::Parser; use embassy::executor::{Executor, Spawner}; -use embassy::io::AsyncWriteExt; use embassy::util::Forever; +use embassy_net::tcp::TcpSocket; use embassy_net::{ Config, Configurator, DhcpConfigurator, Ipv4Address, Ipv4Cidr, StackResources, - StaticConfigurator, TcpSocket, + StaticConfigurator, }; +use embedded_io::asynch::Write; use heapless::Vec; use log::*; diff --git a/examples/std/src/bin/serial.rs b/examples/std/src/bin/serial.rs index 129dc2090..b1e5b0142 100644 --- a/examples/std/src/bin/serial.rs +++ b/examples/std/src/bin/serial.rs @@ -5,8 +5,8 @@ mod serial_port; use async_io::Async; use embassy::executor::Executor; -use embassy::io::AsyncBufReadExt; use embassy::util::Forever; +use embedded_io::asynch::Read; use log::*; use nix::sys::termios; @@ -24,12 +24,12 @@ async fn run() { // Essentially, async_io::Async converts from AsRawFd+Read+Write to futures's AsyncRead+AsyncWrite let port = Async::new(port).unwrap(); - // This implements futures's AsyncBufRead based on futures's AsyncRead - let port = futures::io::BufReader::new(port); - - // We can then use FromStdIo to convert from futures's AsyncBufRead+AsyncWrite - // to embassy's AsyncBufRead+AsyncWrite - let mut port = embassy::io::FromStdIo::new(port); + // We can then use FromStdIo to convert from futures's AsyncRead+AsyncWrite + // to embedded_io's async Read+Write. + // + // This is not really needed, you could write the code below using futures::io directly. + // It's useful if you want to have portable code across embedded and std. + let mut port = embedded_io::adapters::FromFutures::new(port); info!("Serial opened!"); diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 1bc406495..e2065bed9 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -8,7 +8,7 @@ resolver = "2" [dependencies] embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits"] } -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "usb-otg"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti"] } defmt = "0.3" defmt-rtt = "0.3" diff --git a/examples/stm32f4/src/bin/usb_uart.rs b/examples/stm32f4/src/bin/usb_uart.rs deleted file mode 100644 index 251ed1eb0..000000000 --- a/examples/stm32f4/src/bin/usb_uart.rs +++ /dev/null @@ -1,99 +0,0 @@ -#![no_std] -#![no_main] -#![feature(type_alias_impl_trait)] - -use defmt_rtt as _; // global logger -use panic_probe as _; - -use defmt::{info, unwrap}; -use defmt_rtt as _; // global logger -use embassy::interrupt::InterruptExt; -use futures::pin_mut; -use panic_probe as _; // print out panic messages - -use embassy::executor::Spawner; -use embassy::io::{AsyncBufReadExt, AsyncWriteExt}; -use embassy_stm32::usb_otg::{State, Usb, UsbBus, UsbOtg, UsbSerial}; -use embassy_stm32::{interrupt, time::Hertz, Config, Peripherals}; -use usb_device::device::{UsbDeviceBuilder, UsbVidPid}; - -static mut EP_MEMORY: [u32; 2048] = [0; 2048]; - -// USB requires at least 48 MHz clock -fn config() -> Config { - let mut config = Config::default(); - config.rcc.sys_ck = Some(Hertz(48_000_000)); - config -} - -#[embassy::main(config = "config()")] -async fn main(_spawner: Spawner, p: Peripherals) { - let mut rx_buffer = [0u8; 64]; - // we send back input + cr + lf - let mut tx_buffer = [0u8; 66]; - - let peri = UsbOtg::new_fs(p.USB_OTG_FS, p.PA12, p.PA11); - let usb_bus = UsbBus::new(peri, unsafe { &mut EP_MEMORY }); - - let serial = UsbSerial::new(&usb_bus, &mut rx_buffer, &mut tx_buffer); - - let device = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd)) - .manufacturer("Fake company") - .product("Serial port") - .serial_number("TEST") - .device_class(0x02) - .build(); - - let irq = interrupt::take!(OTG_FS); - irq.set_priority(interrupt::Priority::P3); - - let mut state = State::new(); - let usb = unsafe { Usb::new(&mut state, device, serial, irq) }; - pin_mut!(usb); - - let (mut reader, mut writer) = usb.as_ref().take_serial_0(); - - info!("usb initialized!"); - - unwrap!( - writer - .write_all(b"\r\nInput returned upper cased on CR+LF\r\n") - .await - ); - - let mut buf = [0u8; 64]; - loop { - let mut n = 0; - - async { - loop { - let char = unwrap!(reader.read_byte().await); - - if char == b'\r' || char == b'\n' { - break; - } - - buf[n] = char; - n += 1; - - // stop if we're out of room - if n == buf.len() { - break; - } - } - } - .await; - - if n > 0 { - for char in buf[..n].iter_mut() { - // upper case - if 0x61 <= *char && *char <= 0x7a { - *char &= !0x20; - } - } - unwrap!(writer.write_all(&buf[..n]).await); - unwrap!(writer.write_all(b"\r\n").await); - unwrap!(writer.flush().await); - } - } -} diff --git a/examples/stm32f4/src/bin/usb_uart_ulpi.rs b/examples/stm32f4/src/bin/usb_uart_ulpi.rs deleted file mode 100644 index f6c373602..000000000 --- a/examples/stm32f4/src/bin/usb_uart_ulpi.rs +++ /dev/null @@ -1,114 +0,0 @@ -#![no_std] -#![no_main] -#![feature(type_alias_impl_trait)] - -use defmt_rtt as _; // global logger -use panic_probe as _; - -use defmt::{info, unwrap}; -use defmt_rtt as _; // global logger -use embassy::interrupt::InterruptExt; -use futures::pin_mut; -use panic_probe as _; // print out panic messages - -use embassy::executor::Spawner; -use embassy::io::{AsyncBufReadExt, AsyncWriteExt}; -use embassy_stm32::usb_otg::{State, Usb, UsbBus, UsbOtg, UsbSerial}; -use embassy_stm32::{interrupt, time::Hertz, Config, Peripherals}; -use usb_device::device::{UsbDeviceBuilder, UsbVidPid}; - -static mut EP_MEMORY: [u32; 2048] = [0; 2048]; - -// USB requires at least 48 MHz clock -fn config() -> Config { - let mut config = Config::default(); - config.rcc.sys_ck = Some(Hertz(48_000_000)); - config -} - -#[embassy::main(config = "config()")] -async fn main(_spawner: Spawner, p: Peripherals) { - let mut rx_buffer = [0u8; 64]; - // we send back input + cr + lf - let mut tx_buffer = [0u8; 66]; - - // USB with external high-speed PHY - let peri = UsbOtg::new_hs_ulpi( - p.USB_OTG_HS, - p.PA5, - p.PC2, - p.PC3, - p.PC0, - p.PA3, - p.PB0, - p.PB1, - p.PB10, - p.PB11, - p.PB12, - p.PB13, - p.PB5, - ); - let usb_bus = UsbBus::new(peri, unsafe { &mut EP_MEMORY }); - - let serial = UsbSerial::new(&usb_bus, &mut rx_buffer, &mut tx_buffer); - - let device = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd)) - .manufacturer("Fake company") - .product("Serial port") - .serial_number("TEST") - .device_class(0x02) - .build(); - - let irq = interrupt::take!(OTG_FS); - irq.set_priority(interrupt::Priority::P3); - - let mut state = State::new(); - let usb = unsafe { Usb::new(&mut state, device, serial, irq) }; - pin_mut!(usb); - - let (mut reader, mut writer) = usb.as_ref().take_serial_0(); - - info!("usb initialized!"); - - unwrap!( - writer - .write_all(b"\r\nInput returned upper cased on CR+LF\r\n") - .await - ); - - let mut buf = [0u8; 64]; - loop { - let mut n = 0; - - async { - loop { - let char = unwrap!(reader.read_byte().await); - - if char == b'\r' || char == b'\n' { - break; - } - - buf[n] = char; - n += 1; - - // stop if we're out of room - if n == buf.len() { - break; - } - } - } - .await; - - if n > 0 { - for char in buf[..n].iter_mut() { - // upper case - if 0x61 <= *char && *char <= 0x7a { - *char &= !0x20; - } - } - unwrap!(writer.write_all(&buf[..n]).await); - unwrap!(writer.write_all(b"\r\n").await); - unwrap!(writer.flush().await); - } - } -} diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index ce0a6d48f..f7af77da4 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -9,6 +9,7 @@ resolver = "2" embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-timestamp-uptime"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "net", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] } embassy-net = { path = "../../embassy-net", features = ["defmt", "tcp", "medium-ethernet", "pool-16"] } +embedded-io = { version = "0.2.0", features = ["async"] } defmt = "0.3" defmt-rtt = "0.3" diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index 33e41de9c..dca9338b2 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -5,12 +5,10 @@ use cortex_m_rt::entry; use defmt::*; use embassy::executor::{Executor, Spawner}; -use embassy::io::AsyncWriteExt; use embassy::time::{Duration, Timer}; use embassy::util::Forever; -use embassy_net::{ - Config as NetConfig, Ipv4Address, Ipv4Cidr, StackResources, StaticConfigurator, TcpSocket, -}; +use embassy_net::tcp::TcpSocket; +use embassy_net::{Config as NetConfig, Ipv4Address, Ipv4Cidr, StackResources, StaticConfigurator}; use embassy_stm32::eth::generic_smi::GenericSMI; use embassy_stm32::eth::{Ethernet, State}; use embassy_stm32::interrupt; @@ -19,6 +17,7 @@ use embassy_stm32::peripherals::RNG; use embassy_stm32::rng::Rng; use embassy_stm32::time::U32Ext; use embassy_stm32::Config; +use embedded_io::asynch::Write; use heapless::Vec; use defmt_rtt as _; // global logger diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 8906a1d0b..9c1569dd3 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -5,12 +5,11 @@ name = "embassy-stm32h7-examples" version = "0.1.0" resolver = "2" -[features] - [dependencies] embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "net", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } embassy-net = { path = "../../embassy-net", features = ["defmt", "tcp", "medium-ethernet", "pool-16"] } +embedded-io = { version = "0.2.0", features = ["async"] } defmt = "0.3" defmt-rtt = "0.3" diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index 9a2e7a33d..8ece29403 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -8,12 +8,10 @@ use panic_probe as _; use cortex_m_rt::entry; use defmt::*; use embassy::executor::{Executor, Spawner}; -use embassy::io::AsyncWriteExt; use embassy::time::{Duration, Timer}; use embassy::util::Forever; -use embassy_net::{ - Config as NetConfig, Ipv4Address, Ipv4Cidr, StackResources, StaticConfigurator, TcpSocket, -}; +use embassy_net::tcp::TcpSocket; +use embassy_net::{Config as NetConfig, Ipv4Address, Ipv4Cidr, StackResources, StaticConfigurator}; use embassy_stm32::eth::generic_smi::GenericSMI; use embassy_stm32::eth::{Ethernet, State}; use embassy_stm32::interrupt; @@ -22,6 +20,7 @@ use embassy_stm32::peripherals::RNG; use embassy_stm32::rng::Rng; use embassy_stm32::time::U32Ext; use embassy_stm32::Config; +use embedded_io::asynch::Write; use heapless::Vec; #[embassy::task] diff --git a/examples/stm32l0/.cargo/config.toml b/examples/stm32l0/.cargo/config.toml index 840faa62e..ec0b931f2 100644 --- a/examples/stm32l0/.cargo/config.toml +++ b/examples/stm32l0/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] # replace your chip as listed in `probe-run --list-chips` -runner = "probe-run --chip STM32L072CZTx" +runner = "probe-run --chip STM32L053R8Tx" [build] target = "thumbv6m-none-eabi" diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 1cdb2f374..d6848c27a 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -7,12 +7,11 @@ resolver = "2" [features] default = ["nightly"] -nightly = ["embassy-stm32/nightly", "embassy-lora", "lorawan-device", "lorawan"] +nightly = ["embassy-stm32/nightly", "embassy-lora", "lorawan-device", "lorawan", "embedded-io/async"] [dependencies] embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-timestamp-uptime"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "unstable-traits", "memory-x"] } - embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx127x", "time", "defmt"], optional = true} lorawan-device = { version = "0.7.1", default-features = false, features = ["async"], optional = true } @@ -22,6 +21,7 @@ defmt = "0.3" defmt-rtt = "0.3" embedded-storage = "0.3.0" +embedded-io = "0.2.0" cortex-m = "0.7.3" cortex-m-rt = "0.7.0" diff --git a/examples/stm32l0/src/bin/usart_irq.rs b/examples/stm32l0/src/bin/usart_irq.rs index abb27fa4f..4413a2945 100644 --- a/examples/stm32l0/src/bin/usart_irq.rs +++ b/examples/stm32l0/src/bin/usart_irq.rs @@ -2,13 +2,14 @@ #![no_main] #![feature(type_alias_impl_trait)] -use defmt_rtt as _; // global logger +use defmt_rtt as _; +use embedded_io::asynch::{Read, Write}; +// global logger use panic_probe as _; use defmt::*; use embassy::executor::Spawner; -use embassy::io::{AsyncBufReadExt, AsyncWriteExt}; use embassy_stm32::dma::NoDma; use embassy_stm32::interrupt; use embassy_stm32::usart::{BufferedUart, Config, State, Uart}; @@ -16,19 +17,21 @@ use embassy_stm32::Peripherals; #[embassy::main] async fn main(_spawner: Spawner, p: Peripherals) { + info!("Hi!"); + static mut TX_BUFFER: [u8; 8] = [0; 8]; static mut RX_BUFFER: [u8; 256] = [0; 256]; let mut config = Config::default(); config.baudrate = 9600; - let usart = Uart::new(p.USART1, p.PA10, p.PA9, NoDma, NoDma, config); + let usart = Uart::new(p.USART2, p.PA3, p.PA2, NoDma, NoDma, config); let mut state = State::new(); let mut usart = unsafe { BufferedUart::new( &mut state, usart, - interrupt::take!(USART1), + interrupt::take!(USART2), &mut TX_BUFFER, &mut RX_BUFFER, ) diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 2da549bb2..b3478f74e 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -10,7 +10,7 @@ resolver = "2" [dependencies] embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-timestamp-uptime"] } embassy-traits = { version = "0.1.0", path = "../../embassy-traits" } -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5vi", "time-driver-any", "exti", "unstable-traits", "usb-otg"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5vi", "time-driver-any", "exti", "unstable-traits"] } defmt = "0.3" defmt-rtt = "0.3" diff --git a/examples/stm32l4/src/bin/usb_uart.rs b/examples/stm32l4/src/bin/usb_uart.rs deleted file mode 100644 index 878309550..000000000 --- a/examples/stm32l4/src/bin/usb_uart.rs +++ /dev/null @@ -1,115 +0,0 @@ -#![no_std] -#![no_main] -#![feature(type_alias_impl_trait)] - -use defmt_rtt as _; // global logger -use panic_probe as _; - -use defmt::{info, unwrap}; -use defmt_rtt as _; // global logger -use embassy::interrupt::InterruptExt; -use futures::pin_mut; -use panic_probe as _; // print out panic messages - -use embassy::executor::Spawner; -use embassy::io::{AsyncBufReadExt, AsyncWriteExt}; -use embassy_stm32::pac::pwr::vals::Usv; -use embassy_stm32::pac::{PWR, RCC}; -use embassy_stm32::rcc::{ClockSrc, PLLClkDiv, PLLMul, PLLSource, PLLSrcDiv}; -use embassy_stm32::usb_otg::{State, Usb, UsbBus, UsbOtg, UsbSerial}; -use embassy_stm32::{interrupt, Config, Peripherals}; -use usb_device::device::{UsbDeviceBuilder, UsbVidPid}; - -static mut EP_MEMORY: [u32; 2048] = [0; 2048]; - -// USB requires at least 48 MHz clock -fn config() -> Config { - let mut config = Config::default(); - // set up a 80Mhz clock - config.rcc.mux = ClockSrc::PLL( - PLLSource::HSI16, - PLLClkDiv::Div2, - PLLSrcDiv::Div2, - PLLMul::Mul20, - None, - ); - // enable HSI48 clock for USB - config.rcc.hsi48 = true; - config -} - -#[embassy::main(config = "config()")] -async fn main(_spawner: Spawner, p: Peripherals) { - // Enable PWR peripheral - unsafe { RCC.apb1enr1().modify(|w| w.set_pwren(true)) }; - unsafe { PWR.cr2().modify(|w| w.set_usv(Usv::VALID)) } - - let mut rx_buffer = [0u8; 64]; - // we send back input + cr + lf - let mut tx_buffer = [0u8; 66]; - - let peri = UsbOtg::new_fs(p.USB_OTG_FS, p.PA12, p.PA11); - let usb_bus = UsbBus::new(peri, unsafe { &mut EP_MEMORY }); - - let serial = UsbSerial::new(&usb_bus, &mut rx_buffer, &mut tx_buffer); - - let device = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd)) - .manufacturer("Fake company") - .product("Serial port") - .serial_number("TEST") - .device_class(0x02) - .build(); - - let irq = interrupt::take!(OTG_FS); - irq.set_priority(interrupt::Priority::P3); - - let mut state = State::new(); - let usb = unsafe { Usb::new(&mut state, device, serial, irq) }; - pin_mut!(usb); - - let (mut reader, mut writer) = usb.as_ref().take_serial_0(); - - info!("usb initialized!"); - - unwrap!( - writer - .write_all(b"\r\nInput returned upper cased on CR+LF\r\n") - .await - ); - - let mut buf = [0u8; 64]; - loop { - let mut n = 0; - - async { - loop { - let char = unwrap!(reader.read_byte().await); - - if char == b'\r' || char == b'\n' { - break; - } - - buf[n] = char; - n += 1; - - // stop if we're out of room - if n == buf.len() { - break; - } - } - } - .await; - - if n > 0 { - for char in buf[..n].iter_mut() { - // upper case - if 0x61 <= *char && *char <= 0x7a { - *char &= !0x20; - } - } - unwrap!(writer.write_all(&buf[..n]).await); - unwrap!(writer.write_all(b"\r\n").await); - unwrap!(writer.flush().await); - } - } -}