diff options
| -rw-r--r-- | embassy-usb-driver/Cargo.toml | 1 | ||||
| -rw-r--r-- | embassy-usb-driver/src/lib.rs | 9 | ||||
| -rw-r--r-- | embassy-usb/Cargo.toml | 1 | ||||
| -rw-r--r-- | embassy-usb/src/class/cdc_acm.rs | 99 |
4 files changed, 110 insertions, 0 deletions
diff --git a/embassy-usb-driver/Cargo.toml b/embassy-usb-driver/Cargo.toml index 41493f00d..edb6551b0 100644 --- a/embassy-usb-driver/Cargo.toml +++ b/embassy-usb-driver/Cargo.toml | |||
| @@ -20,3 +20,4 @@ features = ["defmt"] | |||
| 20 | 20 | ||
| 21 | [dependencies] | 21 | [dependencies] |
| 22 | defmt = { version = "0.3", optional = true } | 22 | defmt = { version = "0.3", optional = true } |
| 23 | embedded-io-async = "0.6.1" | ||
diff --git a/embassy-usb-driver/src/lib.rs b/embassy-usb-driver/src/lib.rs index 3b705c8c4..d204e4d85 100644 --- a/embassy-usb-driver/src/lib.rs +++ b/embassy-usb-driver/src/lib.rs | |||
| @@ -395,3 +395,12 @@ pub enum EndpointError { | |||
| 395 | /// The endpoint is disabled. | 395 | /// The endpoint is disabled. |
| 396 | Disabled, | 396 | Disabled, |
| 397 | } | 397 | } |
| 398 | |||
| 399 | impl embedded_io_async::Error for EndpointError { | ||
| 400 | fn kind(&self) -> embedded_io_async::ErrorKind { | ||
| 401 | match self { | ||
| 402 | Self::BufferOverflow => embedded_io_async::ErrorKind::OutOfMemory, | ||
| 403 | Self::Disabled => embedded_io_async::ErrorKind::NotConnected, | ||
| 404 | } | ||
| 405 | } | ||
| 406 | } | ||
diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index 771190c89..4950fbe2a 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml | |||
| @@ -52,6 +52,7 @@ embassy-sync = { version = "0.6.2", path = "../embassy-sync" } | |||
| 52 | embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } | 52 | embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } |
| 53 | 53 | ||
| 54 | defmt = { version = "0.3", optional = true } | 54 | defmt = { version = "0.3", optional = true } |
| 55 | embedded-io-async = "0.6.1" | ||
| 55 | log = { version = "0.4.14", optional = true } | 56 | log = { version = "0.4.14", optional = true } |
| 56 | heapless = "0.8" | 57 | heapless = "0.8" |
| 57 | 58 | ||
diff --git a/embassy-usb/src/class/cdc_acm.rs b/embassy-usb/src/class/cdc_acm.rs index ea9d9fb7b..732a433f8 100644 --- a/embassy-usb/src/class/cdc_acm.rs +++ b/embassy-usb/src/class/cdc_acm.rs | |||
| @@ -410,6 +410,18 @@ impl<'d, D: Driver<'d>> Sender<'d, D> { | |||
| 410 | } | 410 | } |
| 411 | } | 411 | } |
| 412 | 412 | ||
| 413 | impl<'d, D: Driver<'d>> embedded_io_async::ErrorType for Sender<'d, D> { | ||
| 414 | type Error = EndpointError; | ||
| 415 | } | ||
| 416 | |||
| 417 | impl<'d, D: Driver<'d>> embedded_io_async::Write for Sender<'d, D> { | ||
| 418 | async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { | ||
| 419 | let len = core::cmp::min(buf.len(), self.max_packet_size() as usize); | ||
| 420 | self.write_packet(&buf[..len]).await?; | ||
| 421 | Ok(len) | ||
| 422 | } | ||
| 423 | } | ||
| 424 | |||
| 413 | /// CDC ACM class packet receiver. | 425 | /// CDC ACM class packet receiver. |
| 414 | /// | 426 | /// |
| 415 | /// You can obtain a `Receiver` with [`CdcAcmClass::split`] | 427 | /// You can obtain a `Receiver` with [`CdcAcmClass::split`] |
| @@ -451,6 +463,93 @@ impl<'d, D: Driver<'d>> Receiver<'d, D> { | |||
| 451 | pub async fn wait_connection(&mut self) { | 463 | pub async fn wait_connection(&mut self) { |
| 452 | self.read_ep.wait_enabled().await; | 464 | self.read_ep.wait_enabled().await; |
| 453 | } | 465 | } |
| 466 | |||
| 467 | /// Turn the `Receiver` into a [`BufferedReceiver`]. | ||
| 468 | /// | ||
| 469 | /// The supplied buffer must be large enough to hold max_packet_size bytes. | ||
| 470 | pub fn into_buffered(self, buf: &'d mut [u8]) -> BufferedReceiver<'d, D> { | ||
| 471 | BufferedReceiver { | ||
| 472 | receiver: self, | ||
| 473 | buffer: buf, | ||
| 474 | start: 0, | ||
| 475 | end: 0, | ||
| 476 | } | ||
| 477 | } | ||
| 478 | } | ||
| 479 | |||
| 480 | /// CDC ACM class buffered receiver. | ||
| 481 | /// | ||
| 482 | /// It is a requirement of the [`embedded_io_async::Read`] trait that arbitrarily small lengths of | ||
| 483 | /// data can be read from the stream. The [`Receiver`] can only read full packets at a time. The | ||
| 484 | /// `BufferedReceiver` instead buffers a single packet if the caller does not read all of the data, | ||
| 485 | /// so that the remaining data can be returned in subsequent calls. | ||
| 486 | /// | ||
| 487 | /// If you have no requirement to use the [`embedded_io_async::Read`] trait or to read a data length | ||
| 488 | /// less than the packet length, then it is more efficient to use the [`Receiver`] directly. | ||
| 489 | /// | ||
| 490 | /// You can obtain a `BufferedReceiver` with [`Receiver::into_buffered`]. | ||
| 491 | /// | ||
| 492 | /// [`embedded_io_async::Read`]: https://docs.rs/embedded-io-async/latest/embedded_io_async/trait.Read.html | ||
| 493 | pub struct BufferedReceiver<'d, D: Driver<'d>> { | ||
| 494 | receiver: Receiver<'d, D>, | ||
| 495 | buffer: &'d mut [u8], | ||
| 496 | start: usize, | ||
| 497 | end: usize, | ||
| 498 | } | ||
| 499 | |||
| 500 | impl<'d, D: Driver<'d>> BufferedReceiver<'d, D> { | ||
| 501 | fn read_from_buffer(&mut self, buf: &mut [u8]) -> usize { | ||
| 502 | let available = &self.buffer[self.start..self.end]; | ||
| 503 | let len = core::cmp::min(available.len(), buf.len()); | ||
| 504 | buf[..len].copy_from_slice(&self.buffer[..len]); | ||
| 505 | self.start += len; | ||
| 506 | len | ||
| 507 | } | ||
| 508 | |||
| 509 | /// Gets the current line coding. The line coding contains information that's mainly relevant | ||
| 510 | /// for USB to UART serial port emulators, and can be ignored if not relevant. | ||
| 511 | pub fn line_coding(&self) -> LineCoding { | ||
| 512 | self.receiver.line_coding() | ||
| 513 | } | ||
| 514 | |||
| 515 | /// Gets the DTR (data terminal ready) state | ||
| 516 | pub fn dtr(&self) -> bool { | ||
| 517 | self.receiver.dtr() | ||
| 518 | } | ||
| 519 | |||
| 520 | /// Gets the RTS (request to send) state | ||
| 521 | pub fn rts(&self) -> bool { | ||
| 522 | self.receiver.rts() | ||
| 523 | } | ||
| 524 | |||
| 525 | /// Waits for the USB host to enable this interface | ||
| 526 | pub async fn wait_connection(&mut self) { | ||
| 527 | self.receiver.wait_connection().await; | ||
| 528 | } | ||
| 529 | } | ||
| 530 | |||
| 531 | impl<'d, D: Driver<'d>> embedded_io_async::ErrorType for BufferedReceiver<'d, D> { | ||
| 532 | type Error = EndpointError; | ||
| 533 | } | ||
| 534 | |||
| 535 | impl<'d, D: Driver<'d>> embedded_io_async::Read for BufferedReceiver<'d, D> { | ||
| 536 | async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { | ||
| 537 | // If there is a buffered packet, return data from that first | ||
| 538 | if self.start != self.end { | ||
| 539 | return Ok(self.read_from_buffer(buf)); | ||
| 540 | } | ||
| 541 | |||
| 542 | // If the caller's buffer is large enough to contain an entire packet, read directly into | ||
| 543 | // that instead of buffering the packet internally. | ||
| 544 | if buf.len() > self.receiver.max_packet_size() as usize { | ||
| 545 | return self.receiver.read_packet(buf).await; | ||
| 546 | } | ||
| 547 | |||
| 548 | // Otherwise read a packet into the internal buffer, and return some of it to the caller | ||
| 549 | self.start = 0; | ||
| 550 | self.end = self.receiver.read_packet(&mut self.buffer).await?; | ||
| 551 | return Ok(self.read_from_buffer(buf)); | ||
| 552 | } | ||
| 454 | } | 553 | } |
| 455 | 554 | ||
| 456 | /// Number of stop bits for LineCoding | 555 | /// Number of stop bits for LineCoding |
