aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-net/src/device.rs163
-rw-r--r--embassy-net/src/lib.rs6
-rw-r--r--embassy-net/src/packet_pool.rs107
-rw-r--r--embassy-net/src/stack.rs24
-rw-r--r--embassy-net/src/tcp.rs2
5 files changed, 105 insertions, 197 deletions
diff --git a/embassy-net/src/device.rs b/embassy-net/src/device.rs
index 4bdfd7720..5d86ca91e 100644
--- a/embassy-net/src/device.rs
+++ b/embassy-net/src/device.rs
@@ -1,10 +1,7 @@
1use core::task::Waker; 1use core::task::Context;
2 2
3use smoltcp::phy::{Device as SmolDevice, DeviceCapabilities}; 3use smoltcp::phy;
4use smoltcp::time::Instant as SmolInstant; 4pub use smoltcp::phy::{Checksum, ChecksumCapabilities, DeviceCapabilities, Medium};
5
6use crate::packet_pool::PacketBoxExt;
7use crate::{Packet, PacketBox, PacketBuf};
8 5
9#[derive(PartialEq, Eq, Clone, Copy)] 6#[derive(PartialEq, Eq, Clone, Copy)]
10pub enum LinkState { 7pub enum LinkState {
@@ -13,115 +10,133 @@ pub enum LinkState {
13} 10}
14 11
15pub trait Device { 12pub trait Device {
16 fn is_transmit_ready(&mut self) -> bool; 13 type RxToken<'a>: RxToken
17 fn transmit(&mut self, pkt: PacketBuf); 14 where
18 fn receive(&mut self) -> Option<PacketBuf>; 15 Self: 'a;
16 type TxToken<'a>: TxToken
17 where
18 Self: 'a;
19 19
20 fn register_waker(&mut self, waker: &Waker); 20 fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)>;
21 fn capabilities(&self) -> DeviceCapabilities; 21 fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>>;
22 fn link_state(&mut self) -> LinkState; 22 fn link_state(&mut self, cx: &mut Context) -> LinkState;
23
24 fn capabilities(&self) -> phy::DeviceCapabilities;
23 fn ethernet_address(&self) -> [u8; 6]; 25 fn ethernet_address(&self) -> [u8; 6];
24} 26}
25 27
26impl<T: ?Sized + Device> Device for &mut T { 28impl<T: ?Sized + Device> Device for &mut T {
27 fn is_transmit_ready(&mut self) -> bool { 29 type RxToken<'a> = T::RxToken<'a>
28 T::is_transmit_ready(self) 30 where
29 } 31 Self: 'a;
30 fn transmit(&mut self, pkt: PacketBuf) { 32 type TxToken<'a> = T::TxToken<'a>
31 T::transmit(self, pkt) 33 where
32 } 34 Self: 'a;
33 fn receive(&mut self) -> Option<PacketBuf> { 35
34 T::receive(self) 36 fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> {
37 T::transmit(self, cx)
35 } 38 }
36 fn register_waker(&mut self, waker: &Waker) { 39 fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
37 T::register_waker(self, waker) 40 T::receive(self, cx)
38 } 41 }
39 fn capabilities(&self) -> DeviceCapabilities { 42 fn capabilities(&self) -> phy::DeviceCapabilities {
40 T::capabilities(self) 43 T::capabilities(self)
41 } 44 }
42 fn link_state(&mut self) -> LinkState { 45 fn link_state(&mut self, cx: &mut Context) -> LinkState {
43 T::link_state(self) 46 T::link_state(self, cx)
44 } 47 }
45 fn ethernet_address(&self) -> [u8; 6] { 48 fn ethernet_address(&self) -> [u8; 6] {
46 T::ethernet_address(self) 49 T::ethernet_address(self)
47 } 50 }
48} 51}
49 52
50pub struct DeviceAdapter<D: Device> { 53/// A token to receive a single network packet.
51 pub device: D, 54pub trait RxToken {
52 caps: DeviceCapabilities, 55 /// Consumes the token to receive a single network packet.
56 ///
57 /// This method receives a packet and then calls the given closure `f` with the raw
58 /// packet bytes as argument.
59 fn consume<R, F>(self, f: F) -> R
60 where
61 F: FnOnce(&mut [u8]) -> R;
53} 62}
54 63
55impl<D: Device> DeviceAdapter<D> { 64/// A token to transmit a single network packet.
56 pub(crate) fn new(device: D) -> Self { 65pub trait TxToken {
57 Self { 66 /// Consumes the token to send a single network packet.
58 caps: device.capabilities(), 67 ///
59 device, 68 /// This method constructs a transmit buffer of size `len` and calls the passed
60 } 69 /// closure `f` with a mutable reference to that buffer. The closure should construct
61 } 70 /// a valid network packet (e.g. an ethernet packet) in the buffer. When the closure
71 /// returns, the transmit buffer is sent out.
72 fn consume<R, F>(self, len: usize, f: F) -> R
73 where
74 F: FnOnce(&mut [u8]) -> R;
75}
76
77///////////////////////////
78
79pub(crate) struct DeviceAdapter<'d, 'c, T>
80where
81 T: Device,
82{
83 // must be Some when actually using this to rx/tx
84 pub cx: Option<&'d mut Context<'c>>,
85 pub inner: &'d mut T,
62} 86}
63 87
64impl<D: Device> SmolDevice for DeviceAdapter<D> { 88impl<'d, 'c, T> phy::Device for DeviceAdapter<'d, 'c, T>
65 type RxToken<'a> = RxToken where Self: 'a; 89where
66 type TxToken<'a> = TxToken<'a, D> where Self: 'a; 90 T: Device,
91{
92 type RxToken<'a> = RxTokenAdapter<T::RxToken<'a>> where Self: 'a;
93 type TxToken<'a> = TxTokenAdapter<T::TxToken<'a>> where Self: 'a;
67 94
68 fn receive(&mut self) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { 95 fn receive(&mut self) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
69 let tx_pkt = PacketBox::new(Packet::new())?; 96 self.inner
70 let rx_pkt = self.device.receive()?; 97 .receive(self.cx.as_deref_mut().unwrap())
71 let rx_token = RxToken { pkt: rx_pkt }; 98 .map(|(rx, tx)| (RxTokenAdapter(rx), TxTokenAdapter(tx)))
72 let tx_token = TxToken {
73 device: &mut self.device,
74 pkt: tx_pkt,
75 };
76
77 Some((rx_token, tx_token))
78 } 99 }
79 100
80 /// Construct a transmit token. 101 /// Construct a transmit token.
81 fn transmit(&mut self) -> Option<Self::TxToken<'_>> { 102 fn transmit(&mut self) -> Option<Self::TxToken<'_>> {
82 if !self.device.is_transmit_ready() { 103 self.inner.transmit(self.cx.as_deref_mut().unwrap()).map(TxTokenAdapter)
83 return None;
84 }
85
86 let tx_pkt = PacketBox::new(Packet::new())?;
87 Some(TxToken {
88 device: &mut self.device,
89 pkt: tx_pkt,
90 })
91 } 104 }
92 105
93 /// Get a description of device capabilities. 106 /// Get a description of device capabilities.
94 fn capabilities(&self) -> DeviceCapabilities { 107 fn capabilities(&self) -> phy::DeviceCapabilities {
95 self.caps.clone() 108 self.inner.capabilities()
96 } 109 }
97} 110}
98 111
99pub struct RxToken { 112pub(crate) struct RxTokenAdapter<T>(T)
100 pkt: PacketBuf, 113where
101} 114 T: RxToken;
102 115
103impl smoltcp::phy::RxToken for RxToken { 116impl<T> phy::RxToken for RxTokenAdapter<T>
104 fn consume<R, F>(mut self, _timestamp: SmolInstant, f: F) -> smoltcp::Result<R> 117where
118 T: RxToken,
119{
120 fn consume<R, F>(self, _timestamp: smoltcp::time::Instant, f: F) -> smoltcp::Result<R>
105 where 121 where
106 F: FnOnce(&mut [u8]) -> smoltcp::Result<R>, 122 F: FnOnce(&mut [u8]) -> smoltcp::Result<R>,
107 { 123 {
108 f(&mut self.pkt) 124 self.0.consume(|buf| f(buf))
109 } 125 }
110} 126}
111 127
112pub struct TxToken<'a, D: Device> { 128pub(crate) struct TxTokenAdapter<T>(T)
113 device: &'a mut D, 129where
114 pkt: PacketBox, 130 T: TxToken;
115}
116 131
117impl<'a, D: Device> smoltcp::phy::TxToken for TxToken<'a, D> { 132impl<T> phy::TxToken for TxTokenAdapter<T>
118 fn consume<R, F>(self, _timestamp: SmolInstant, len: usize, f: F) -> smoltcp::Result<R> 133where
134 T: TxToken,
135{
136 fn consume<R, F>(self, _timestamp: smoltcp::time::Instant, len: usize, f: F) -> smoltcp::Result<R>
119 where 137 where
120 F: FnOnce(&mut [u8]) -> smoltcp::Result<R>, 138 F: FnOnce(&mut [u8]) -> smoltcp::Result<R>,
121 { 139 {
122 let mut buf = self.pkt.slice(0..len); 140 self.0.consume(len, |buf| f(buf))
123 let r = f(&mut buf)?;
124 self.device.transmit(buf);
125 Ok(r)
126 } 141 }
127} 142}
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs
index edb969842..e18e819cb 100644
--- a/embassy-net/src/lib.rs
+++ b/embassy-net/src/lib.rs
@@ -8,12 +8,9 @@
8// This mod MUST go first, so that the others see its macros. 8// This mod MUST go first, so that the others see its macros.
9pub(crate) mod fmt; 9pub(crate) mod fmt;
10 10
11mod device; 11pub mod device;
12mod packet_pool;
13mod stack; 12mod stack;
14 13
15pub use device::{Device, LinkState};
16pub use packet_pool::{Packet, PacketBox, PacketBoxExt, PacketBuf, MTU};
17pub use stack::{Config, ConfigStrategy, Stack, StackResources}; 14pub use stack::{Config, ConfigStrategy, Stack, StackResources};
18 15
19#[cfg(feature = "tcp")] 16#[cfg(feature = "tcp")]
@@ -23,7 +20,6 @@ pub mod tcp;
23pub mod udp; 20pub mod udp;
24 21
25// smoltcp reexports 22// smoltcp reexports
26pub use smoltcp::phy::{DeviceCapabilities, Medium};
27pub use smoltcp::time::{Duration as SmolDuration, Instant as SmolInstant}; 23pub use smoltcp::time::{Duration as SmolDuration, Instant as SmolInstant};
28#[cfg(feature = "medium-ethernet")] 24#[cfg(feature = "medium-ethernet")]
29pub use smoltcp::wire::{EthernetAddress, HardwareAddress}; 25pub use smoltcp::wire::{EthernetAddress, HardwareAddress};
diff --git a/embassy-net/src/packet_pool.rs b/embassy-net/src/packet_pool.rs
deleted file mode 100644
index cb8a1316c..000000000
--- a/embassy-net/src/packet_pool.rs
+++ /dev/null
@@ -1,107 +0,0 @@
1use core::ops::{Deref, DerefMut, Range};
2
3use as_slice::{AsMutSlice, AsSlice};
4use atomic_pool::{pool, Box};
5
6pub const MTU: usize = 1516;
7
8#[cfg(feature = "pool-4")]
9pub const PACKET_POOL_SIZE: usize = 4;
10
11#[cfg(feature = "pool-8")]
12pub const PACKET_POOL_SIZE: usize = 8;
13
14#[cfg(feature = "pool-16")]
15pub const PACKET_POOL_SIZE: usize = 16;
16
17#[cfg(feature = "pool-32")]
18pub const PACKET_POOL_SIZE: usize = 32;
19
20#[cfg(feature = "pool-64")]
21pub const PACKET_POOL_SIZE: usize = 64;
22
23#[cfg(feature = "pool-128")]
24pub const PACKET_POOL_SIZE: usize = 128;
25
26pool!(pub PacketPool: [Packet; PACKET_POOL_SIZE]);
27pub type PacketBox = Box<PacketPool>;
28
29#[repr(align(4))]
30pub struct Packet(pub [u8; MTU]);
31
32impl Packet {
33 pub const fn new() -> Self {
34 Self([0; MTU])
35 }
36}
37
38pub trait PacketBoxExt {
39 fn slice(self, range: Range<usize>) -> PacketBuf;
40}
41
42impl PacketBoxExt for PacketBox {
43 fn slice(self, range: Range<usize>) -> PacketBuf {
44 PacketBuf { packet: self, range }
45 }
46}
47
48impl AsSlice for Packet {
49 type Element = u8;
50
51 fn as_slice(&self) -> &[Self::Element] {
52 &self.deref()[..]
53 }
54}
55
56impl AsMutSlice for Packet {
57 fn as_mut_slice(&mut self) -> &mut [Self::Element] {
58 &mut self.deref_mut()[..]
59 }
60}
61
62impl Deref for Packet {
63 type Target = [u8; MTU];
64
65 fn deref(&self) -> &[u8; MTU] {
66 &self.0
67 }
68}
69
70impl DerefMut for Packet {
71 fn deref_mut(&mut self) -> &mut [u8; MTU] {
72 &mut self.0
73 }
74}
75
76pub struct PacketBuf {
77 packet: PacketBox,
78 range: Range<usize>,
79}
80
81impl AsSlice for PacketBuf {
82 type Element = u8;
83
84 fn as_slice(&self) -> &[Self::Element] {
85 &self.packet[self.range.clone()]
86 }
87}
88
89impl AsMutSlice for PacketBuf {
90 fn as_mut_slice(&mut self) -> &mut [Self::Element] {
91 &mut self.packet[self.range.clone()]
92 }
93}
94
95impl Deref for PacketBuf {
96 type Target = [u8];
97
98 fn deref(&self) -> &[u8] {
99 &self.packet[self.range.clone()]
100 }
101}
102
103impl DerefMut for PacketBuf {
104 fn deref_mut(&mut self) -> &mut [u8] {
105 &mut self.packet[self.range.clone()]
106 }
107}
diff --git a/embassy-net/src/stack.rs b/embassy-net/src/stack.rs
index 5c4fb0442..21316e485 100644
--- a/embassy-net/src/stack.rs
+++ b/embassy-net/src/stack.rs
@@ -12,7 +12,7 @@ use smoltcp::iface::{Interface, InterfaceBuilder, SocketSet, SocketStorage};
12#[cfg(feature = "medium-ethernet")] 12#[cfg(feature = "medium-ethernet")]
13use smoltcp::iface::{Neighbor, NeighborCache, Route, Routes}; 13use smoltcp::iface::{Neighbor, NeighborCache, Route, Routes};
14#[cfg(feature = "medium-ethernet")] 14#[cfg(feature = "medium-ethernet")]
15use smoltcp::phy::{Device as _, Medium}; 15use smoltcp::phy::Medium;
16#[cfg(feature = "dhcpv4")] 16#[cfg(feature = "dhcpv4")]
17use smoltcp::socket::dhcpv4; 17use smoltcp::socket::dhcpv4;
18use smoltcp::time::Instant as SmolInstant; 18use smoltcp::time::Instant as SmolInstant;
@@ -67,7 +67,7 @@ pub struct Stack<D: Device> {
67} 67}
68 68
69struct Inner<D: Device> { 69struct Inner<D: Device> {
70 device: DeviceAdapter<D>, 70 device: D,
71 link_up: bool, 71 link_up: bool,
72 config: Option<Config>, 72 config: Option<Config>,
73 #[cfg(feature = "dhcpv4")] 73 #[cfg(feature = "dhcpv4")]
@@ -83,7 +83,7 @@ pub(crate) struct SocketStack {
83 83
84impl<D: Device + 'static> Stack<D> { 84impl<D: Device + 'static> Stack<D> {
85 pub fn new<const ADDR: usize, const SOCK: usize, const NEIGH: usize>( 85 pub fn new<const ADDR: usize, const SOCK: usize, const NEIGH: usize>(
86 device: D, 86 mut device: D,
87 config: ConfigStrategy, 87 config: ConfigStrategy,
88 resources: &'static mut StackResources<ADDR, SOCK, NEIGH>, 88 resources: &'static mut StackResources<ADDR, SOCK, NEIGH>,
89 random_seed: u64, 89 random_seed: u64,
@@ -98,8 +98,6 @@ impl<D: Device + 'static> Stack<D> {
98 [0, 0, 0, 0, 0, 0] 98 [0, 0, 0, 0, 0, 0]
99 }; 99 };
100 100
101 let mut device = DeviceAdapter::new(device);
102
103 let mut b = InterfaceBuilder::new(); 101 let mut b = InterfaceBuilder::new();
104 b = b.ip_addrs(&mut resources.addresses[..]); 102 b = b.ip_addrs(&mut resources.addresses[..]);
105 b = b.random_seed(random_seed); 103 b = b.random_seed(random_seed);
@@ -111,7 +109,10 @@ impl<D: Device + 'static> Stack<D> {
111 b = b.routes(Routes::new(&mut resources.routes[..])); 109 b = b.routes(Routes::new(&mut resources.routes[..]));
112 } 110 }
113 111
114 let iface = b.finalize(&mut device); 112 let iface = b.finalize(&mut DeviceAdapter {
113 inner: &mut device,
114 cx: None,
115 });
115 116
116 let sockets = SocketSet::new(&mut resources.sockets[..]); 117 let sockets = SocketSet::new(&mut resources.sockets[..]);
117 118
@@ -155,7 +156,7 @@ impl<D: Device + 'static> Stack<D> {
155 } 156 }
156 157
157 pub fn ethernet_address(&self) -> [u8; 6] { 158 pub fn ethernet_address(&self) -> [u8; 6] {
158 self.with(|_s, i| i.device.device.ethernet_address()) 159 self.with(|_s, i| i.device.ethernet_address())
159 } 160 }
160 161
161 pub fn is_link_up(&self) -> bool { 162 pub fn is_link_up(&self) -> bool {
@@ -238,11 +239,14 @@ impl<D: Device + 'static> Inner<D> {
238 } 239 }
239 240
240 fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) { 241 fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) {
241 self.device.device.register_waker(cx.waker());
242 s.waker.register(cx.waker()); 242 s.waker.register(cx.waker());
243 243
244 let timestamp = instant_to_smoltcp(Instant::now()); 244 let timestamp = instant_to_smoltcp(Instant::now());
245 if s.iface.poll(timestamp, &mut self.device, &mut s.sockets).is_err() { 245 let mut smoldev = DeviceAdapter {
246 cx: Some(cx),
247 inner: &mut self.device,
248 };
249 if s.iface.poll(timestamp, &mut smoldev, &mut s.sockets).is_err() {
246 // If poll() returns error, it may not be done yet, so poll again later. 250 // If poll() returns error, it may not be done yet, so poll again later.
247 cx.waker().wake_by_ref(); 251 cx.waker().wake_by_ref();
248 return; 252 return;
@@ -250,7 +254,7 @@ impl<D: Device + 'static> Inner<D> {
250 254
251 // Update link up 255 // Update link up
252 let old_link_up = self.link_up; 256 let old_link_up = self.link_up;
253 self.link_up = self.device.device.link_state() == LinkState::Up; 257 self.link_up = self.device.link_state(cx) == LinkState::Up;
254 258
255 // Print when changed 259 // Print when changed
256 if old_link_up != self.link_up { 260 if old_link_up != self.link_up {
diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs
index 73cf2d4e4..0ed4b81e2 100644
--- a/embassy-net/src/tcp.rs
+++ b/embassy-net/src/tcp.rs
@@ -9,8 +9,8 @@ use smoltcp::time::Duration;
9use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; 9use smoltcp::wire::{IpEndpoint, IpListenEndpoint};
10 10
11use super::stack::Stack; 11use super::stack::Stack;
12use crate::device::Device;
12use crate::stack::SocketStack; 13use crate::stack::SocketStack;
13use crate::Device;
14 14
15#[derive(PartialEq, Eq, Clone, Copy, Debug)] 15#[derive(PartialEq, Eq, Clone, Copy, Debug)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))] 16#[cfg_attr(feature = "defmt", derive(defmt::Format))]