diff options
Diffstat (limited to 'embassy-net/src')
| -rw-r--r-- | embassy-net/src/tcp.rs | 62 | ||||
| -rw-r--r-- | embassy-net/src/udp.rs | 53 |
2 files changed, 112 insertions, 3 deletions
diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index 043062e06..a00ced8f4 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs | |||
| @@ -10,7 +10,7 @@ | |||
| 10 | 10 | ||
| 11 | use core::future::poll_fn; | 11 | use core::future::poll_fn; |
| 12 | use core::mem; | 12 | use core::mem; |
| 13 | use core::task::Poll; | 13 | use core::task::{Context, Poll}; |
| 14 | 14 | ||
| 15 | use embassy_time::Duration; | 15 | use embassy_time::Duration; |
| 16 | use smoltcp::iface::{Interface, SocketHandle}; | 16 | use smoltcp::iface::{Interface, SocketHandle}; |
| @@ -274,6 +274,16 @@ impl<'a> TcpSocket<'a> { | |||
| 274 | .await | 274 | .await |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | /// Wait until the socket becomes readable. | ||
| 278 | /// | ||
| 279 | /// A socket becomes readable when the receive half of the full-duplex connection is open | ||
| 280 | /// (see [may_recv](#method.may_recv)), and there is some pending data in the receive buffer. | ||
| 281 | /// | ||
| 282 | /// This is the equivalent of [read](#method.read), without buffering any data. | ||
| 283 | pub async fn wait_read_ready(&self) { | ||
| 284 | poll_fn(move |cx| self.io.poll_read_ready(cx)).await | ||
| 285 | } | ||
| 286 | |||
| 277 | /// Read data from the socket. | 287 | /// Read data from the socket. |
| 278 | /// | 288 | /// |
| 279 | /// Returns how many bytes were read, or an error. If no data is available, it waits | 289 | /// Returns how many bytes were read, or an error. If no data is available, it waits |
| @@ -285,6 +295,16 @@ impl<'a> TcpSocket<'a> { | |||
| 285 | self.io.read(buf).await | 295 | self.io.read(buf).await |
| 286 | } | 296 | } |
| 287 | 297 | ||
| 298 | /// Wait until the socket becomes writable. | ||
| 299 | /// | ||
| 300 | /// A socket becomes writable when the transmit half of the full-duplex connection is open | ||
| 301 | /// (see [may_send](#method.may_send)), and the transmit buffer is not full. | ||
| 302 | /// | ||
| 303 | /// This is the equivalent of [write](#method.write), without sending any data. | ||
| 304 | pub async fn wait_write_ready(&self) { | ||
| 305 | poll_fn(move |cx| self.io.poll_write_ready(cx)).await | ||
| 306 | } | ||
| 307 | |||
| 288 | /// Write data to the socket. | 308 | /// Write data to the socket. |
| 289 | /// | 309 | /// |
| 290 | /// Returns how many bytes were written, or an error. If the socket is not ready to | 310 | /// Returns how many bytes were written, or an error. If the socket is not ready to |
| @@ -376,11 +396,25 @@ impl<'a> TcpSocket<'a> { | |||
| 376 | self.io.with_mut(|s, _| s.abort()) | 396 | self.io.with_mut(|s, _| s.abort()) |
| 377 | } | 397 | } |
| 378 | 398 | ||
| 379 | /// Get whether the socket is ready to send data, i.e. whether there is space in the send buffer. | 399 | /// Return whether the transmit half of the full-duplex connection is open. |
| 400 | /// | ||
| 401 | /// This function returns true if it's possible to send data and have it arrive | ||
| 402 | /// to the remote endpoint. However, it does not make any guarantees about the state | ||
| 403 | /// of the transmit buffer, and even if it returns true, [write](#method.write) may | ||
| 404 | /// not be able to enqueue any octets. | ||
| 405 | /// | ||
| 406 | /// In terms of the TCP state machine, the socket must be in the `ESTABLISHED` or | ||
| 407 | /// `CLOSE-WAIT` state. | ||
| 380 | pub fn may_send(&self) -> bool { | 408 | pub fn may_send(&self) -> bool { |
| 381 | self.io.with(|s, _| s.may_send()) | 409 | self.io.with(|s, _| s.may_send()) |
| 382 | } | 410 | } |
| 383 | 411 | ||
| 412 | /// Check whether the transmit half of the full-duplex connection is open | ||
| 413 | /// (see [may_send](#method.may_send)), and the transmit buffer is not full. | ||
| 414 | pub fn can_send(&self) -> bool { | ||
| 415 | self.io.with(|s, _| s.can_send()) | ||
| 416 | } | ||
| 417 | |||
| 384 | /// return whether the receive half of the full-duplex connection is open. | 418 | /// return whether the receive half of the full-duplex connection is open. |
| 385 | /// This function returns true if it’s possible to receive data from the remote endpoint. | 419 | /// This function returns true if it’s possible to receive data from the remote endpoint. |
| 386 | /// It will return true while there is data in the receive buffer, and if there isn’t, | 420 | /// It will return true while there is data in the receive buffer, and if there isn’t, |
| @@ -427,7 +461,7 @@ impl<'d> TcpIo<'d> { | |||
| 427 | }) | 461 | }) |
| 428 | } | 462 | } |
| 429 | 463 | ||
| 430 | fn with_mut<R>(&mut self, f: impl FnOnce(&mut tcp::Socket, &mut Interface) -> R) -> R { | 464 | fn with_mut<R>(&self, f: impl FnOnce(&mut tcp::Socket, &mut Interface) -> R) -> R { |
| 431 | self.stack.with_mut(|i| { | 465 | self.stack.with_mut(|i| { |
| 432 | let socket = i.sockets.get_mut::<tcp::Socket>(self.handle); | 466 | let socket = i.sockets.get_mut::<tcp::Socket>(self.handle); |
| 433 | let res = f(socket, &mut i.iface); | 467 | let res = f(socket, &mut i.iface); |
| @@ -436,6 +470,17 @@ impl<'d> TcpIo<'d> { | |||
| 436 | }) | 470 | }) |
| 437 | } | 471 | } |
| 438 | 472 | ||
| 473 | fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<()> { | ||
| 474 | self.with_mut(|s, _| { | ||
| 475 | if s.can_recv() { | ||
| 476 | Poll::Ready(()) | ||
| 477 | } else { | ||
| 478 | s.register_recv_waker(cx.waker()); | ||
| 479 | Poll::Pending | ||
| 480 | } | ||
| 481 | }) | ||
| 482 | } | ||
| 483 | |||
| 439 | async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { | 484 | async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { |
| 440 | poll_fn(move |cx| { | 485 | poll_fn(move |cx| { |
| 441 | // CAUTION: smoltcp semantics around EOF are different to what you'd expect | 486 | // CAUTION: smoltcp semantics around EOF are different to what you'd expect |
| @@ -464,6 +509,17 @@ impl<'d> TcpIo<'d> { | |||
| 464 | .await | 509 | .await |
| 465 | } | 510 | } |
| 466 | 511 | ||
| 512 | fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll<()> { | ||
| 513 | self.with_mut(|s, _| { | ||
| 514 | if s.can_send() { | ||
| 515 | Poll::Ready(()) | ||
| 516 | } else { | ||
| 517 | s.register_send_waker(cx.waker()); | ||
| 518 | Poll::Pending | ||
| 519 | } | ||
| 520 | }) | ||
| 521 | } | ||
| 522 | |||
| 467 | async fn write(&mut self, buf: &[u8]) -> Result<usize, Error> { | 523 | async fn write(&mut self, buf: &[u8]) -> Result<usize, Error> { |
| 468 | poll_fn(move |cx| { | 524 | poll_fn(move |cx| { |
| 469 | self.with_mut(|s, _| match s.send_slice(buf) { | 525 | self.with_mut(|s, _| match s.send_slice(buf) { |
diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index ac650364e..76602edc2 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs | |||
| @@ -103,6 +103,32 @@ impl<'a> UdpSocket<'a> { | |||
| 103 | }) | 103 | }) |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | /// Wait until the socket becomes readable. | ||
| 107 | /// | ||
| 108 | /// A socket is readable when a packet has been received, or when there are queued packets in | ||
| 109 | /// the buffer. | ||
| 110 | pub async fn wait_recv_ready(&self) { | ||
| 111 | poll_fn(move |cx| self.poll_recv_ready(cx)).await | ||
| 112 | } | ||
| 113 | |||
| 114 | /// Wait until a datagram can be read. | ||
| 115 | /// | ||
| 116 | /// When no datagram is readable, this method will return `Poll::Pending` and | ||
| 117 | /// register the current task to be notified when a datagram is received. | ||
| 118 | /// | ||
| 119 | /// When a datagram is received, this method will return `Poll::Ready`. | ||
| 120 | pub fn poll_recv_ready(&self, cx: &mut Context<'_>) -> Poll<()> { | ||
| 121 | self.with_mut(|s, _| { | ||
| 122 | if s.can_recv() { | ||
| 123 | Poll::Ready(()) | ||
| 124 | } else { | ||
| 125 | // socket buffer is empty wait until at least one byte has arrived | ||
| 126 | s.register_recv_waker(cx.waker()); | ||
| 127 | Poll::Pending | ||
| 128 | } | ||
| 129 | }) | ||
| 130 | } | ||
| 131 | |||
| 106 | /// Receive a datagram. | 132 | /// Receive a datagram. |
| 107 | /// | 133 | /// |
| 108 | /// This method will wait until a datagram is received. | 134 | /// This method will wait until a datagram is received. |
| @@ -164,6 +190,33 @@ impl<'a> UdpSocket<'a> { | |||
| 164 | .await | 190 | .await |
| 165 | } | 191 | } |
| 166 | 192 | ||
| 193 | /// Wait until the socket becomes writable. | ||
| 194 | /// | ||
| 195 | /// A socket becomes writable when there is space in the buffer, from initial memory or after | ||
| 196 | /// dispatching datagrams on a full buffer. | ||
| 197 | pub async fn wait_send_ready(&self) { | ||
| 198 | poll_fn(move |cx| self.poll_send_ready(cx)).await | ||
| 199 | } | ||
| 200 | |||
| 201 | /// Wait until a datagram can be sent. | ||
| 202 | /// | ||
| 203 | /// When no datagram can be sent (i.e. the buffer is full), this method will return | ||
| 204 | /// `Poll::Pending` and register the current task to be notified when | ||
| 205 | /// space is freed in the buffer after a datagram has been dispatched. | ||
| 206 | /// | ||
| 207 | /// When a datagram can be sent, this method will return `Poll::Ready`. | ||
| 208 | pub fn poll_send_ready(&self, cx: &mut Context<'_>) -> Poll<()> { | ||
| 209 | self.with_mut(|s, _| { | ||
| 210 | if s.can_send() { | ||
| 211 | Poll::Ready(()) | ||
| 212 | } else { | ||
| 213 | // socket buffer is full wait until a datagram has been dispatched | ||
| 214 | s.register_send_waker(cx.waker()); | ||
| 215 | Poll::Pending | ||
| 216 | } | ||
| 217 | }) | ||
| 218 | } | ||
| 219 | |||
| 167 | /// Send a datagram to the specified remote endpoint. | 220 | /// Send a datagram to the specified remote endpoint. |
| 168 | /// | 221 | /// |
| 169 | /// This method will wait until the datagram has been sent. | 222 | /// This method will wait until the datagram has been sent. |
