diff options
| -rw-r--r-- | embassy-net/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-net/src/lib.rs | 5 | ||||
| -rw-r--r-- | embassy-net/src/tcp.rs (renamed from embassy-net/src/tcp/mod.rs) | 129 | ||||
| -rw-r--r-- | embassy-net/src/tcp/io_impl.rs | 129 | ||||
| -rw-r--r-- | embassy-stm32/Cargo.toml | 2 | ||||
| -rw-r--r-- | examples/nrf/Cargo.toml | 4 | ||||
| -rw-r--r-- | examples/std/Cargo.toml | 2 |
7 files changed, 132 insertions, 143 deletions
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 8484aebc0..b58b52f18 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml | |||
| @@ -31,15 +31,13 @@ pool-32 = [] | |||
| 31 | pool-64 = [] | 31 | pool-64 = [] |
| 32 | pool-128 = [] | 32 | pool-128 = [] |
| 33 | 33 | ||
| 34 | nightly = ["embedded-io/async"] | ||
| 35 | |||
| 36 | [dependencies] | 34 | [dependencies] |
| 37 | 35 | ||
| 38 | defmt = { version = "0.3", optional = true } | 36 | defmt = { version = "0.3", optional = true } |
| 39 | log = { version = "0.4.14", optional = true } | 37 | log = { version = "0.4.14", optional = true } |
| 40 | 38 | ||
| 41 | embassy = { version = "0.1.0", path = "../embassy" } | 39 | embassy = { version = "0.1.0", path = "../embassy" } |
| 42 | embedded-io = "0.3.0" | 40 | embedded-io = { version = "0.3.0", features = [ "async" ] } |
| 43 | 41 | ||
| 44 | managed = { version = "0.8.0", default-features = false, features = [ "map" ] } | 42 | managed = { version = "0.8.0", default-features = false, features = [ "map" ] } |
| 45 | heapless = { version = "0.7.5", default-features = false } | 43 | heapless = { version = "0.7.5", default-features = false } |
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index ded841909..18dc1ef61 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs | |||
| @@ -1,9 +1,6 @@ | |||
| 1 | #![cfg_attr(not(feature = "std"), no_std)] | 1 | #![cfg_attr(not(feature = "std"), no_std)] |
| 2 | #![allow(clippy::new_without_default)] | 2 | #![allow(clippy::new_without_default)] |
| 3 | #![cfg_attr( | 3 | #![feature(generic_associated_types, type_alias_impl_trait)] |
| 4 | feature = "nightly", | ||
| 5 | feature(generic_associated_types, type_alias_impl_trait) | ||
| 6 | )] | ||
| 7 | 4 | ||
| 8 | // This mod MUST go first, so that the others see its macros. | 5 | // This mod MUST go first, so that the others see its macros. |
| 9 | pub(crate) mod fmt; | 6 | pub(crate) mod fmt; |
diff --git a/embassy-net/src/tcp/mod.rs b/embassy-net/src/tcp.rs index 425e6acbc..c18651b93 100644 --- a/embassy-net/src/tcp/mod.rs +++ b/embassy-net/src/tcp.rs | |||
| @@ -1,15 +1,14 @@ | |||
| 1 | use core::future::Future; | ||
| 1 | use core::marker::PhantomData; | 2 | use core::marker::PhantomData; |
| 2 | use core::mem; | 3 | use core::mem; |
| 3 | use core::task::Poll; | 4 | use core::task::Poll; |
| 5 | use futures::future::poll_fn; | ||
| 4 | use smoltcp::iface::{Context as SmolContext, SocketHandle}; | 6 | use smoltcp::iface::{Context as SmolContext, SocketHandle}; |
| 5 | use smoltcp::socket::TcpSocket as SyncTcpSocket; | 7 | use smoltcp::socket::TcpSocket as SyncTcpSocket; |
| 6 | use smoltcp::socket::{TcpSocketBuffer, TcpState}; | 8 | use smoltcp::socket::{TcpSocketBuffer, TcpState}; |
| 7 | use smoltcp::time::Duration; | 9 | use smoltcp::time::Duration; |
| 8 | use smoltcp::wire::IpEndpoint; | 10 | use smoltcp::wire::IpEndpoint; |
| 9 | 11 | ||
| 10 | #[cfg(feature = "nightly")] | ||
| 11 | mod io_impl; | ||
| 12 | |||
| 13 | use super::stack::Stack; | 12 | use super::stack::Stack; |
| 14 | 13 | ||
| 15 | #[derive(PartialEq, Eq, Clone, Copy, Debug)] | 14 | #[derive(PartialEq, Eq, Clone, Copy, Debug)] |
| @@ -221,10 +220,134 @@ impl<'d> embedded_io::Io for TcpSocket<'d> { | |||
| 221 | type Error = Error; | 220 | type Error = Error; |
| 222 | } | 221 | } |
| 223 | 222 | ||
| 223 | impl<'d> embedded_io::asynch::Read for TcpSocket<'d> { | ||
| 224 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | ||
| 225 | where | ||
| 226 | Self: 'a; | ||
| 227 | |||
| 228 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 229 | poll_fn(move |cx| { | ||
| 230 | // CAUTION: smoltcp semantics around EOF are different to what you'd expect | ||
| 231 | // from posix-like IO, so we have to tweak things here. | ||
| 232 | with_socket(self.handle, |s, _| match s.recv_slice(buf) { | ||
| 233 | // No data ready | ||
| 234 | Ok(0) => { | ||
| 235 | s.register_recv_waker(cx.waker()); | ||
| 236 | Poll::Pending | ||
| 237 | } | ||
| 238 | // Data ready! | ||
| 239 | Ok(n) => Poll::Ready(Ok(n)), | ||
| 240 | // EOF | ||
| 241 | Err(smoltcp::Error::Finished) => Poll::Ready(Ok(0)), | ||
| 242 | // Connection reset. TODO: this can also be timeouts etc, investigate. | ||
| 243 | Err(smoltcp::Error::Illegal) => Poll::Ready(Err(Error::ConnectionReset)), | ||
| 244 | // smoltcp returns no errors other than the above. | ||
| 245 | Err(_) => unreachable!(), | ||
| 246 | }) | ||
| 247 | }) | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | impl<'d> embedded_io::asynch::Write for TcpSocket<'d> { | ||
| 252 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | ||
| 253 | where | ||
| 254 | Self: 'a; | ||
| 255 | |||
| 256 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 257 | poll_fn(move |cx| { | ||
| 258 | with_socket(self.handle, |s, _| match s.send_slice(buf) { | ||
| 259 | // Not ready to send (no space in the tx buffer) | ||
| 260 | Ok(0) => { | ||
| 261 | s.register_send_waker(cx.waker()); | ||
| 262 | Poll::Pending | ||
| 263 | } | ||
| 264 | // Some data sent | ||
| 265 | Ok(n) => Poll::Ready(Ok(n)), | ||
| 266 | // Connection reset. TODO: this can also be timeouts etc, investigate. | ||
| 267 | Err(smoltcp::Error::Illegal) => Poll::Ready(Err(Error::ConnectionReset)), | ||
| 268 | // smoltcp returns no errors other than the above. | ||
| 269 | Err(_) => unreachable!(), | ||
| 270 | }) | ||
| 271 | }) | ||
| 272 | } | ||
| 273 | |||
| 274 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | ||
| 275 | where | ||
| 276 | Self: 'a; | ||
| 277 | |||
| 278 | fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { | ||
| 279 | poll_fn(move |_| { | ||
| 280 | Poll::Ready(Ok(())) // TODO: Is there a better implementation for this? | ||
| 281 | }) | ||
| 282 | } | ||
| 283 | } | ||
| 284 | |||
| 224 | impl<'d> embedded_io::Io for TcpReader<'d> { | 285 | impl<'d> embedded_io::Io for TcpReader<'d> { |
| 225 | type Error = Error; | 286 | type Error = Error; |
| 226 | } | 287 | } |
| 227 | 288 | ||
| 289 | impl<'d> embedded_io::asynch::Read for TcpReader<'d> { | ||
| 290 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | ||
| 291 | where | ||
| 292 | Self: 'a; | ||
| 293 | |||
| 294 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 295 | poll_fn(move |cx| { | ||
| 296 | // CAUTION: smoltcp semantics around EOF are different to what you'd expect | ||
| 297 | // from posix-like IO, so we have to tweak things here. | ||
| 298 | with_socket(self.handle, |s, _| match s.recv_slice(buf) { | ||
| 299 | // No data ready | ||
| 300 | Ok(0) => { | ||
| 301 | s.register_recv_waker(cx.waker()); | ||
| 302 | Poll::Pending | ||
| 303 | } | ||
| 304 | // Data ready! | ||
| 305 | Ok(n) => Poll::Ready(Ok(n)), | ||
| 306 | // EOF | ||
| 307 | Err(smoltcp::Error::Finished) => Poll::Ready(Ok(0)), | ||
| 308 | // Connection reset. TODO: this can also be timeouts etc, investigate. | ||
| 309 | Err(smoltcp::Error::Illegal) => Poll::Ready(Err(Error::ConnectionReset)), | ||
| 310 | // smoltcp returns no errors other than the above. | ||
| 311 | Err(_) => unreachable!(), | ||
| 312 | }) | ||
| 313 | }) | ||
| 314 | } | ||
| 315 | } | ||
| 316 | |||
| 228 | impl<'d> embedded_io::Io for TcpWriter<'d> { | 317 | impl<'d> embedded_io::Io for TcpWriter<'d> { |
| 229 | type Error = Error; | 318 | type Error = Error; |
| 230 | } | 319 | } |
| 320 | |||
| 321 | impl<'d> embedded_io::asynch::Write for TcpWriter<'d> { | ||
| 322 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | ||
| 323 | where | ||
| 324 | Self: 'a; | ||
| 325 | |||
| 326 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 327 | poll_fn(move |cx| { | ||
| 328 | with_socket(self.handle, |s, _| match s.send_slice(buf) { | ||
| 329 | // Not ready to send (no space in the tx buffer) | ||
| 330 | Ok(0) => { | ||
| 331 | s.register_send_waker(cx.waker()); | ||
| 332 | Poll::Pending | ||
| 333 | } | ||
| 334 | // Some data sent | ||
| 335 | Ok(n) => Poll::Ready(Ok(n)), | ||
| 336 | // Connection reset. TODO: this can also be timeouts etc, investigate. | ||
| 337 | Err(smoltcp::Error::Illegal) => Poll::Ready(Err(Error::ConnectionReset)), | ||
| 338 | // smoltcp returns no errors other than the above. | ||
| 339 | Err(_) => unreachable!(), | ||
| 340 | }) | ||
| 341 | }) | ||
| 342 | } | ||
| 343 | |||
| 344 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | ||
| 345 | where | ||
| 346 | Self: 'a; | ||
| 347 | |||
| 348 | fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { | ||
| 349 | poll_fn(move |_| { | ||
| 350 | Poll::Ready(Ok(())) // TODO: Is there a better implementation for this? | ||
| 351 | }) | ||
| 352 | } | ||
| 353 | } | ||
diff --git a/embassy-net/src/tcp/io_impl.rs b/embassy-net/src/tcp/io_impl.rs deleted file mode 100644 index b30c920b8..000000000 --- a/embassy-net/src/tcp/io_impl.rs +++ /dev/null | |||
| @@ -1,129 +0,0 @@ | |||
| 1 | use core::future::Future; | ||
| 2 | use core::task::Poll; | ||
| 3 | use futures::future::poll_fn; | ||
| 4 | |||
| 5 | use super::{with_socket, Error, TcpReader, TcpSocket, TcpWriter}; | ||
| 6 | |||
| 7 | impl<'d> embedded_io::asynch::Read for TcpSocket<'d> { | ||
| 8 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | ||
| 9 | where | ||
| 10 | Self: 'a; | ||
| 11 | |||
| 12 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 13 | poll_fn(move |cx| { | ||
| 14 | // CAUTION: smoltcp semantics around EOF are different to what you'd expect | ||
| 15 | // from posix-like IO, so we have to tweak things here. | ||
| 16 | with_socket(self.handle, |s, _| match s.recv_slice(buf) { | ||
| 17 | // No data ready | ||
| 18 | Ok(0) => { | ||
| 19 | s.register_recv_waker(cx.waker()); | ||
| 20 | Poll::Pending | ||
| 21 | } | ||
| 22 | // Data ready! | ||
| 23 | Ok(n) => Poll::Ready(Ok(n)), | ||
| 24 | // EOF | ||
| 25 | Err(smoltcp::Error::Finished) => Poll::Ready(Ok(0)), | ||
| 26 | // Connection reset. TODO: this can also be timeouts etc, investigate. | ||
| 27 | Err(smoltcp::Error::Illegal) => Poll::Ready(Err(Error::ConnectionReset)), | ||
| 28 | // smoltcp returns no errors other than the above. | ||
| 29 | Err(_) => unreachable!(), | ||
| 30 | }) | ||
| 31 | }) | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | impl<'d> embedded_io::asynch::Write for TcpSocket<'d> { | ||
| 36 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | ||
| 37 | where | ||
| 38 | Self: 'a; | ||
| 39 | |||
| 40 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 41 | poll_fn(move |cx| { | ||
| 42 | with_socket(self.handle, |s, _| match s.send_slice(buf) { | ||
| 43 | // Not ready to send (no space in the tx buffer) | ||
| 44 | Ok(0) => { | ||
| 45 | s.register_send_waker(cx.waker()); | ||
| 46 | Poll::Pending | ||
| 47 | } | ||
| 48 | // Some data sent | ||
| 49 | Ok(n) => Poll::Ready(Ok(n)), | ||
| 50 | // Connection reset. TODO: this can also be timeouts etc, investigate. | ||
| 51 | Err(smoltcp::Error::Illegal) => Poll::Ready(Err(Error::ConnectionReset)), | ||
| 52 | // smoltcp returns no errors other than the above. | ||
| 53 | Err(_) => unreachable!(), | ||
| 54 | }) | ||
| 55 | }) | ||
| 56 | } | ||
| 57 | |||
| 58 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | ||
| 59 | where | ||
| 60 | Self: 'a; | ||
| 61 | |||
| 62 | fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { | ||
| 63 | poll_fn(move |_| { | ||
| 64 | Poll::Ready(Ok(())) // TODO: Is there a better implementation for this? | ||
| 65 | }) | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | impl<'d> embedded_io::asynch::Read for TcpReader<'d> { | ||
| 70 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | ||
| 71 | where | ||
| 72 | Self: 'a; | ||
| 73 | |||
| 74 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 75 | poll_fn(move |cx| { | ||
| 76 | // CAUTION: smoltcp semantics around EOF are different to what you'd expect | ||
| 77 | // from posix-like IO, so we have to tweak things here. | ||
| 78 | with_socket(self.handle, |s, _| match s.recv_slice(buf) { | ||
| 79 | // No data ready | ||
| 80 | Ok(0) => { | ||
| 81 | s.register_recv_waker(cx.waker()); | ||
| 82 | Poll::Pending | ||
| 83 | } | ||
| 84 | // Data ready! | ||
| 85 | Ok(n) => Poll::Ready(Ok(n)), | ||
| 86 | // EOF | ||
| 87 | Err(smoltcp::Error::Finished) => Poll::Ready(Ok(0)), | ||
| 88 | // Connection reset. TODO: this can also be timeouts etc, investigate. | ||
| 89 | Err(smoltcp::Error::Illegal) => Poll::Ready(Err(Error::ConnectionReset)), | ||
| 90 | // smoltcp returns no errors other than the above. | ||
| 91 | Err(_) => unreachable!(), | ||
| 92 | }) | ||
| 93 | }) | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | impl<'d> embedded_io::asynch::Write for TcpWriter<'d> { | ||
| 98 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | ||
| 99 | where | ||
| 100 | Self: 'a; | ||
| 101 | |||
| 102 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 103 | poll_fn(move |cx| { | ||
| 104 | with_socket(self.handle, |s, _| match s.send_slice(buf) { | ||
| 105 | // Not ready to send (no space in the tx buffer) | ||
| 106 | Ok(0) => { | ||
| 107 | s.register_send_waker(cx.waker()); | ||
| 108 | Poll::Pending | ||
| 109 | } | ||
| 110 | // Some data sent | ||
| 111 | Ok(n) => Poll::Ready(Ok(n)), | ||
| 112 | // Connection reset. TODO: this can also be timeouts etc, investigate. | ||
| 113 | Err(smoltcp::Error::Illegal) => Poll::Ready(Err(Error::ConnectionReset)), | ||
| 114 | // smoltcp returns no errors other than the above. | ||
| 115 | Err(_) => unreachable!(), | ||
| 116 | }) | ||
| 117 | }) | ||
| 118 | } | ||
| 119 | |||
| 120 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | ||
| 121 | where | ||
| 122 | Self: 'a; | ||
| 123 | |||
| 124 | fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { | ||
| 125 | poll_fn(move |_| { | ||
| 126 | Poll::Ready(Ok(())) // TODO: Is there a better implementation for this? | ||
| 127 | }) | ||
| 128 | } | ||
| 129 | } | ||
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index ce36c7da2..e310d25f2 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -90,7 +90,7 @@ time-driver-tim12 = ["_time-driver"] | |||
| 90 | time-driver-tim15 = ["_time-driver"] | 90 | time-driver-tim15 = ["_time-driver"] |
| 91 | 91 | ||
| 92 | # Enable nightly-only features | 92 | # Enable nightly-only features |
| 93 | nightly = ["embassy/nightly", "embassy-net?/nightly", "embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io"] | 93 | nightly = ["embassy/nightly", "embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io"] |
| 94 | 94 | ||
| 95 | # Reexport stm32-metapac at `embassy_stm32::pac`. | 95 | # Reexport stm32-metapac at `embassy_stm32::pac`. |
| 96 | # This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version. | 96 | # This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version. |
diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml index d96eedf98..124725f95 100644 --- a/examples/nrf/Cargo.toml +++ b/examples/nrf/Cargo.toml | |||
| @@ -6,12 +6,12 @@ version = "0.1.0" | |||
| 6 | 6 | ||
| 7 | [features] | 7 | [features] |
| 8 | default = ["nightly"] | 8 | default = ["nightly"] |
| 9 | 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"] | 9 | nightly = ["embassy-nrf/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embassy-usb-serial", "embassy-usb-hid", "embassy-usb-ncm", "embedded-io/async", "embassy-net"] |
| 10 | 10 | ||
| 11 | [dependencies] | 11 | [dependencies] |
| 12 | embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-timestamp-uptime"] } | 12 | embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-timestamp-uptime"] } |
| 13 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } | 13 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } |
| 14 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } | 14 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true } |
| 15 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } | 15 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } |
| 16 | embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"], optional = true } | 16 | embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"], optional = true } |
| 17 | embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", features = ["defmt"], optional = true } | 17 | embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", features = ["defmt"], optional = true } |
diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index 863760a45..7e1c2e4bb 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml | |||
| @@ -6,7 +6,7 @@ version = "0.1.0" | |||
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy = { version = "0.1.0", path = "../../embassy", features = ["log", "std", "time", "nightly"] } | 8 | embassy = { version = "0.1.0", path = "../../embassy", features = ["log", "std", "time", "nightly"] } |
| 9 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features=["nightly", "std", "log", "medium-ethernet", "tcp", "dhcpv4", "pool-16"] } | 9 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "tcp", "dhcpv4", "pool-16"] } |
| 10 | embedded-io = { version = "0.3.0", features = ["async", "std", "futures"] } | 10 | embedded-io = { version = "0.3.0", features = ["async", "std", "futures"] } |
| 11 | 11 | ||
| 12 | async-io = "1.6.0" | 12 | async-io = "1.6.0" |
