aboutsummaryrefslogtreecommitdiff
path: root/examples/std/src
diff options
context:
space:
mode:
authorMathias <[email protected]>2023-02-13 14:55:15 +0100
committerMathias <[email protected]>2023-02-13 14:55:15 +0100
commit218b44652c149f895919b606a660b6eff30e8177 (patch)
tree5f985f6edd12926a6f374c17a3a0c3a4226088e7 /examples/std/src
parent86113e199f37fe0888979608a08bfdaf21bff19a (diff)
parent41a563aae3e474955892b27487e185f5f486f525 (diff)
Rebase on master
Diffstat (limited to 'examples/std/src')
-rw-r--r--examples/std/src/bin/net.rs15
-rw-r--r--examples/std/src/bin/net_dns.rs98
-rw-r--r--examples/std/src/bin/net_udp.rs13
-rw-r--r--examples/std/src/tuntap.rs119
4 files changed, 169 insertions, 76 deletions
diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs
index 9b1450b72..451850d99 100644
--- a/examples/std/src/bin/net.rs
+++ b/examples/std/src/bin/net.rs
@@ -1,9 +1,11 @@
1#![feature(type_alias_impl_trait)] 1#![feature(type_alias_impl_trait)]
2 2
3use std::default::Default;
4
3use clap::Parser; 5use clap::Parser;
4use embassy_executor::{Executor, Spawner}; 6use embassy_executor::{Executor, Spawner};
5use embassy_net::tcp::TcpSocket; 7use embassy_net::tcp::TcpSocket;
6use embassy_net::{ConfigStrategy, Ipv4Address, Ipv4Cidr, Stack, StackResources}; 8use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources};
7use embedded_io::asynch::Write; 9use embedded_io::asynch::Write;
8use heapless::Vec; 10use heapless::Vec;
9use log::*; 11use log::*;
@@ -48,13 +50,13 @@ async fn main_task(spawner: Spawner) {
48 50
49 // Choose between dhcp or static ip 51 // Choose between dhcp or static ip
50 let config = if opts.static_ip { 52 let config = if opts.static_ip {
51 ConfigStrategy::Static(embassy_net::Config { 53 Config::Static(embassy_net::StaticConfig {
52 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), 54 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
53 dns_servers: Vec::new(), 55 dns_servers: Vec::new(),
54 gateway: Some(Ipv4Address::new(192, 168, 69, 1)), 56 gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
55 }) 57 })
56 } else { 58 } else {
57 ConfigStrategy::Dhcp 59 Config::Dhcp(Default::default())
58 }; 60 };
59 61
60 // Generate random seed 62 // Generate random seed
@@ -63,12 +65,7 @@ async fn main_task(spawner: Spawner) {
63 let seed = u64::from_le_bytes(seed); 65 let seed = u64::from_le_bytes(seed);
64 66
65 // Init network stack 67 // Init network stack
66 let stack = &*singleton!(Stack::new( 68 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
67 device,
68 config,
69 singleton!(StackResources::<1, 2, 8>::new()),
70 seed
71 ));
72 69
73 // Launch network task 70 // Launch network task
74 spawner.spawn(net_task(stack)).unwrap(); 71 spawner.spawn(net_task(stack)).unwrap();
diff --git a/examples/std/src/bin/net_dns.rs b/examples/std/src/bin/net_dns.rs
new file mode 100644
index 000000000..e1cc45a38
--- /dev/null
+++ b/examples/std/src/bin/net_dns.rs
@@ -0,0 +1,98 @@
1#![feature(type_alias_impl_trait)]
2
3use std::default::Default;
4
5use clap::Parser;
6use embassy_executor::{Executor, Spawner};
7use embassy_net::dns::DnsQueryType;
8use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources};
9use heapless::Vec;
10use log::*;
11use rand_core::{OsRng, RngCore};
12use static_cell::StaticCell;
13
14#[path = "../tuntap.rs"]
15mod tuntap;
16
17use crate::tuntap::TunTapDevice;
18
19macro_rules! singleton {
20 ($val:expr) => {{
21 type T = impl Sized;
22 static STATIC_CELL: StaticCell<T> = StaticCell::new();
23 STATIC_CELL.init_with(move || $val)
24 }};
25}
26
27#[derive(Parser)]
28#[clap(version = "1.0")]
29struct Opts {
30 /// TAP device name
31 #[clap(long, default_value = "tap0")]
32 tap: String,
33 /// use a static IP instead of DHCP
34 #[clap(long)]
35 static_ip: bool,
36}
37
38#[embassy_executor::task]
39async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! {
40 stack.run().await
41}
42
43#[embassy_executor::task]
44async fn main_task(spawner: Spawner) {
45 let opts: Opts = Opts::parse();
46
47 // Init network device
48 let device = TunTapDevice::new(&opts.tap).unwrap();
49
50 // Choose between dhcp or static ip
51 let config = if opts.static_ip {
52 Config::Static(embassy_net::StaticConfig {
53 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 1), 24),
54 dns_servers: Vec::from_slice(&[Ipv4Address::new(8, 8, 4, 4).into(), Ipv4Address::new(8, 8, 8, 8).into()])
55 .unwrap(),
56 gateway: Some(Ipv4Address::new(192, 168, 69, 100)),
57 })
58 } else {
59 Config::Dhcp(Default::default())
60 };
61
62 // Generate random seed
63 let mut seed = [0; 8];
64 OsRng.fill_bytes(&mut seed);
65 let seed = u64::from_le_bytes(seed);
66
67 // Init network stack
68 let stack: &Stack<_> = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
69
70 // Launch network task
71 spawner.spawn(net_task(stack)).unwrap();
72
73 let host = "example.com";
74 info!("querying host {:?}...", host);
75 match stack.dns_query(host, DnsQueryType::A).await {
76 Ok(r) => {
77 info!("query response: {:?}", r);
78 }
79 Err(e) => {
80 warn!("query error: {:?}", e);
81 }
82 };
83}
84
85static EXECUTOR: StaticCell<Executor> = StaticCell::new();
86
87fn main() {
88 env_logger::builder()
89 .filter_level(log::LevelFilter::Debug)
90 .filter_module("async_io", log::LevelFilter::Info)
91 .format_timestamp_nanos()
92 .init();
93
94 let executor = EXECUTOR.init(Executor::new());
95 executor.run(|spawner| {
96 spawner.spawn(main_task(spawner)).unwrap();
97 });
98}
diff --git a/examples/std/src/bin/net_udp.rs b/examples/std/src/bin/net_udp.rs
index 392a97f0d..f1923f180 100644
--- a/examples/std/src/bin/net_udp.rs
+++ b/examples/std/src/bin/net_udp.rs
@@ -3,7 +3,7 @@
3use clap::Parser; 3use clap::Parser;
4use embassy_executor::{Executor, Spawner}; 4use embassy_executor::{Executor, Spawner};
5use embassy_net::udp::UdpSocket; 5use embassy_net::udp::UdpSocket;
6use embassy_net::{ConfigStrategy, Ipv4Address, Ipv4Cidr, PacketMetadata, Stack, StackResources}; 6use embassy_net::{Config, Ipv4Address, Ipv4Cidr, PacketMetadata, Stack, StackResources};
7use heapless::Vec; 7use heapless::Vec;
8use log::*; 8use log::*;
9use rand_core::{OsRng, RngCore}; 9use rand_core::{OsRng, RngCore};
@@ -47,13 +47,13 @@ async fn main_task(spawner: Spawner) {
47 47
48 // Choose between dhcp or static ip 48 // Choose between dhcp or static ip
49 let config = if opts.static_ip { 49 let config = if opts.static_ip {
50 ConfigStrategy::Static(embassy_net::Config { 50 Config::Static(embassy_net::StaticConfig {
51 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), 51 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
52 dns_servers: Vec::new(), 52 dns_servers: Vec::new(),
53 gateway: Some(Ipv4Address::new(192, 168, 69, 1)), 53 gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
54 }) 54 })
55 } else { 55 } else {
56 ConfigStrategy::Dhcp 56 Config::Dhcp(Default::default())
57 }; 57 };
58 58
59 // Generate random seed 59 // Generate random seed
@@ -62,12 +62,7 @@ async fn main_task(spawner: Spawner) {
62 let seed = u64::from_le_bytes(seed); 62 let seed = u64::from_le_bytes(seed);
63 63
64 // Init network stack 64 // Init network stack
65 let stack = &*singleton!(Stack::new( 65 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
66 device,
67 config,
68 singleton!(StackResources::<1, 2, 8>::new()),
69 seed
70 ));
71 66
72 // Launch network task 67 // Launch network task
73 spawner.spawn(net_task(stack)).unwrap(); 68 spawner.spawn(net_task(stack)).unwrap();
diff --git a/examples/std/src/tuntap.rs b/examples/std/src/tuntap.rs
index a0cace7f7..d918a2e62 100644
--- a/examples/std/src/tuntap.rs
+++ b/examples/std/src/tuntap.rs
@@ -1,8 +1,10 @@
1use std::io; 1use std::io;
2use std::io::{Read, Write}; 2use std::io::{Read, Write};
3use std::os::unix::io::{AsRawFd, RawFd}; 3use std::os::unix::io::{AsRawFd, RawFd};
4use std::task::Context;
4 5
5use async_io::Async; 6use async_io::Async;
7use embassy_net_driver::{self, Capabilities, Driver, LinkState};
6use log::*; 8use log::*;
7 9
8pub const SIOCGIFMTU: libc::c_ulong = 0x8921; 10pub const SIOCGIFMTU: libc::c_ulong = 0x8921;
@@ -125,54 +127,35 @@ impl io::Write for TunTap {
125 127
126pub struct TunTapDevice { 128pub struct TunTapDevice {
127 device: Async<TunTap>, 129 device: Async<TunTap>,
128 waker: Option<Waker>,
129} 130}
130 131
131impl TunTapDevice { 132impl TunTapDevice {
132 pub fn new(name: &str) -> io::Result<TunTapDevice> { 133 pub fn new(name: &str) -> io::Result<TunTapDevice> {
133 Ok(Self { 134 Ok(Self {
134 device: Async::new(TunTap::new(name)?)?, 135 device: Async::new(TunTap::new(name)?)?,
135 waker: None,
136 }) 136 })
137 } 137 }
138} 138}
139 139
140use core::task::Waker; 140impl Driver for TunTapDevice {
141use std::task::Context; 141 type RxToken<'a> = RxToken where Self: 'a;
142 142 type TxToken<'a> = TxToken<'a> where Self: 'a;
143use embassy_net::{Device, DeviceCapabilities, LinkState, Packet, PacketBox, PacketBoxExt, PacketBuf};
144
145impl Device for TunTapDevice {
146 fn is_transmit_ready(&mut self) -> bool {
147 true
148 }
149 143
150 fn transmit(&mut self, pkt: PacketBuf) { 144 fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
151 // todo handle WouldBlock 145 let mut buf = vec![0; self.device.get_ref().mtu];
152 match self.device.get_mut().write(&pkt) {
153 Ok(_) => {}
154 Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
155 info!("transmit WouldBlock");
156 }
157 Err(e) => panic!("transmit error: {:?}", e),
158 }
159 }
160
161 fn receive(&mut self) -> Option<PacketBuf> {
162 let mut pkt = PacketBox::new(Packet::new()).unwrap();
163 loop { 146 loop {
164 match self.device.get_mut().read(&mut pkt[..]) { 147 match self.device.get_mut().read(&mut buf) {
165 Ok(n) => { 148 Ok(n) => {
166 return Some(pkt.slice(0..n)); 149 buf.truncate(n);
150 return Some((
151 RxToken { buffer: buf },
152 TxToken {
153 device: &mut self.device,
154 },
155 ));
167 } 156 }
168 Err(e) if e.kind() == io::ErrorKind::WouldBlock => { 157 Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
169 let ready = if let Some(w) = self.waker.as_ref() { 158 if !self.device.poll_readable(cx).is_ready() {
170 let mut cx = Context::from_waker(w);
171 self.device.poll_readable(&mut cx).is_ready()
172 } else {
173 false
174 };
175 if !ready {
176 return None; 159 return None;
177 } 160 }
178 } 161 }
@@ -181,37 +164,19 @@ impl Device for TunTapDevice {
181 } 164 }
182 } 165 }
183 166
184 fn register_waker(&mut self, w: &Waker) { 167 fn transmit(&mut self, _cx: &mut Context) -> Option<Self::TxToken<'_>> {
185 match self.waker { 168 Some(TxToken {
186 // Optimization: If both the old and new Wakers wake the same task, we can simply 169 device: &mut self.device,
187 // keep the old waker, skipping the clone. (In most executor implementations, 170 })
188 // cloning a waker is somewhat expensive, comparable to cloning an Arc).
189 Some(ref w2) if (w2.will_wake(w)) => {}
190 _ => {
191 // clone the new waker and store it
192 if let Some(old_waker) = core::mem::replace(&mut self.waker, Some(w.clone())) {
193 // We had a waker registered for another task. Wake it, so the other task can
194 // reregister itself if it's still interested.
195 //
196 // If two tasks are waiting on the same thing concurrently, this will cause them
197 // to wake each other in a loop fighting over this WakerRegistration. This wastes
198 // CPU but things will still work.
199 //
200 // If the user wants to have two tasks waiting on the same thing they should use
201 // a more appropriate primitive that can store multiple wakers.
202 old_waker.wake()
203 }
204 }
205 }
206 } 171 }
207 172
208 fn capabilities(&self) -> DeviceCapabilities { 173 fn capabilities(&self) -> Capabilities {
209 let mut caps = DeviceCapabilities::default(); 174 let mut caps = Capabilities::default();
210 caps.max_transmission_unit = self.device.get_ref().mtu; 175 caps.max_transmission_unit = self.device.get_ref().mtu;
211 caps 176 caps
212 } 177 }
213 178
214 fn link_state(&mut self) -> LinkState { 179 fn link_state(&mut self, _cx: &mut Context) -> LinkState {
215 LinkState::Up 180 LinkState::Up
216 } 181 }
217 182
@@ -219,3 +184,41 @@ impl Device for TunTapDevice {
219 [0x02, 0x03, 0x04, 0x05, 0x06, 0x07] 184 [0x02, 0x03, 0x04, 0x05, 0x06, 0x07]
220 } 185 }
221} 186}
187
188#[doc(hidden)]
189pub struct RxToken {
190 buffer: Vec<u8>,
191}
192
193impl embassy_net_driver::RxToken for RxToken {
194 fn consume<R, F>(mut self, f: F) -> R
195 where
196 F: FnOnce(&mut [u8]) -> R,
197 {
198 f(&mut self.buffer)
199 }
200}
201
202#[doc(hidden)]
203pub struct TxToken<'a> {
204 device: &'a mut Async<TunTap>,
205}
206
207impl<'a> embassy_net_driver::TxToken for TxToken<'a> {
208 fn consume<R, F>(self, len: usize, f: F) -> R
209 where
210 F: FnOnce(&mut [u8]) -> R,
211 {
212 let mut buffer = vec![0; len];
213 let result = f(&mut buffer);
214
215 // todo handle WouldBlock with async
216 match self.device.get_mut().write(&buffer) {
217 Ok(_) => {}
218 Err(e) if e.kind() == io::ErrorKind::WouldBlock => info!("transmit WouldBlock"),
219 Err(e) => panic!("transmit error: {:?}", e),
220 }
221
222 result
223 }
224}