aboutsummaryrefslogtreecommitdiff
path: root/examples/std/src
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-08-25 19:49:43 +0200
committerDario Nieuwenhuis <[email protected]>2023-08-25 20:45:23 +0200
commitd812cc574571e60a092f10727046c494face09c9 (patch)
tree2e7b6b84b5881b5e33944c3b448673b6017f04f4 /examples/std/src
parent623f37a27368c53d782cc9819c180bdf45f15612 (diff)
net-ppp: add std example.
Diffstat (limited to 'examples/std/src')
-rw-r--r--examples/std/src/bin/net_ppp.rs218
1 files changed, 218 insertions, 0 deletions
diff --git a/examples/std/src/bin/net_ppp.rs b/examples/std/src/bin/net_ppp.rs
new file mode 100644
index 000000000..9cf6e19df
--- /dev/null
+++ b/examples/std/src/bin/net_ppp.rs
@@ -0,0 +1,218 @@
1//! Testing against pppd:
2//!
3//! echo myuser $(hostname) mypass 192.168.7.10 >> /etc/ppp/pap-secrets
4//! socat -v -x PTY,link=pty1,rawer PTY,link=pty2,rawer
5//! sudo pppd $PWD/pty1 115200 192.168.7.1: ms-dns 8.8.4.4 ms-dns 8.8.8.8 nodetach debug local persist silent noproxyarp
6//! RUST_LOG=trace cargo run --bin net_ppp -- --device pty2
7//! ping 192.168.7.10
8//! nc 192.168.7.10 1234
9
10#![feature(type_alias_impl_trait)]
11#![feature(async_fn_in_trait, impl_trait_projections)]
12
13#[path = "../serial_port.rs"]
14mod serial_port;
15
16use async_io::Async;
17use clap::Parser;
18use embassy_executor::{Executor, Spawner};
19use embassy_net::tcp::TcpSocket;
20use embassy_net::{Config, ConfigV4, Ipv4Address, Ipv4Cidr, Stack, StackResources};
21use embassy_net_ppp::Runner;
22use embedded_io_async::Write;
23use futures::io::BufReader;
24use heapless::Vec;
25use log::*;
26use nix::sys::termios;
27use rand_core::{OsRng, RngCore};
28use static_cell::{make_static, StaticCell};
29
30use crate::serial_port::SerialPort;
31
32#[derive(Parser)]
33#[clap(version = "1.0")]
34struct Opts {
35 /// Serial port device name
36 #[clap(short, long)]
37 device: String,
38}
39
40#[embassy_executor::task]
41async fn net_task(stack: &'static Stack<embassy_net_ppp::Device<'static>>) -> ! {
42 stack.run().await
43}
44
45#[embassy_executor::task]
46async fn ppp_task(
47 stack: &'static Stack<embassy_net_ppp::Device<'static>>,
48 mut runner: Runner<'static>,
49 port: SerialPort,
50) -> ! {
51 let port = Async::new(port).unwrap();
52 let port = BufReader::new(port);
53 let port = adapter::FromFutures::new(port);
54
55 let config = embassy_net_ppp::Config {
56 username: b"myuser",
57 password: b"mypass",
58 };
59
60 runner
61 .run(port, config, |ipv4| {
62 let Some(addr) = ipv4.address else {
63 warn!("PPP did not provide an IP address.");
64 return;
65 };
66 let mut dns_servers = Vec::new();
67 for s in ipv4.dns_servers.iter().flatten() {
68 let _ = dns_servers.push(Ipv4Address::from_bytes(&s.0));
69 }
70 let config = ConfigV4::Static(embassy_net::StaticConfigV4 {
71 address: Ipv4Cidr::new(Ipv4Address::from_bytes(&addr.0), 0),
72 gateway: None,
73 dns_servers,
74 });
75 stack.set_config_v4(config);
76 })
77 .await
78 .unwrap();
79 unreachable!()
80}
81
82#[embassy_executor::task]
83async fn main_task(spawner: Spawner) {
84 let opts: Opts = Opts::parse();
85
86 // Open serial port
87 let baudrate = termios::BaudRate::B115200;
88 let port = SerialPort::new(opts.device.as_str(), baudrate).unwrap();
89
90 // Init network device
91 let state = make_static!(embassy_net_ppp::State::<4, 4>::new());
92 let (device, runner) = embassy_net_ppp::new(state);
93
94 // Generate random seed
95 let mut seed = [0; 8];
96 OsRng.fill_bytes(&mut seed);
97 let seed = u64::from_le_bytes(seed);
98
99 // Init network stack
100 let stack = &*make_static!(Stack::new(
101 device,
102 Config::default(), // don't configure IP yet
103 make_static!(StackResources::<3>::new()),
104 seed
105 ));
106
107 // Launch network task
108 spawner.spawn(net_task(stack)).unwrap();
109 spawner.spawn(ppp_task(stack, runner, port)).unwrap();
110
111 // Then we can use it!
112 let mut rx_buffer = [0; 4096];
113 let mut tx_buffer = [0; 4096];
114 let mut buf = [0; 4096];
115
116 loop {
117 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
118 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
119
120 info!("Listening on TCP:1234...");
121 if let Err(e) = socket.accept(1234).await {
122 warn!("accept error: {:?}", e);
123 continue;
124 }
125
126 info!("Received connection from {:?}", socket.remote_endpoint());
127
128 loop {
129 let n = match socket.read(&mut buf).await {
130 Ok(0) => {
131 warn!("read EOF");
132 break;
133 }
134 Ok(n) => n,
135 Err(e) => {
136 warn!("read error: {:?}", e);
137 break;
138 }
139 };
140
141 info!("rxd {:02x?}", &buf[..n]);
142
143 match socket.write_all(&buf[..n]).await {
144 Ok(()) => {}
145 Err(e) => {
146 warn!("write error: {:?}", e);
147 break;
148 }
149 };
150 }
151 }
152}
153
154static EXECUTOR: StaticCell<Executor> = StaticCell::new();
155
156fn main() {
157 env_logger::builder()
158 .filter_level(log::LevelFilter::Trace)
159 .filter_module("polling", log::LevelFilter::Info)
160 .filter_module("async_io", log::LevelFilter::Info)
161 .format_timestamp_nanos()
162 .init();
163
164 let executor = EXECUTOR.init(Executor::new());
165 executor.run(|spawner| {
166 spawner.spawn(main_task(spawner)).unwrap();
167 });
168}
169
170mod adapter {
171 use core::future::poll_fn;
172 use core::pin::Pin;
173
174 use futures::AsyncBufReadExt;
175
176 /// Adapter from `futures::io` traits.
177 #[derive(Clone)]
178 pub struct FromFutures<T: ?Sized> {
179 inner: T,
180 }
181
182 impl<T> FromFutures<T> {
183 /// Create a new adapter.
184 pub fn new(inner: T) -> Self {
185 Self { inner }
186 }
187 }
188
189 impl<T: ?Sized> embedded_io_async::ErrorType for FromFutures<T> {
190 type Error = std::io::Error;
191 }
192
193 impl<T: futures::io::AsyncRead + Unpin + ?Sized> embedded_io_async::Read for FromFutures<T> {
194 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
195 poll_fn(|cx| Pin::new(&mut self.inner).poll_read(cx, buf)).await
196 }
197 }
198
199 impl<T: futures::io::AsyncBufRead + Unpin + ?Sized> embedded_io_async::BufRead for FromFutures<T> {
200 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
201 self.inner.fill_buf().await
202 }
203
204 fn consume(&mut self, amt: usize) {
205 Pin::new(&mut self.inner).consume(amt)
206 }
207 }
208
209 impl<T: futures::io::AsyncWrite + Unpin + ?Sized> embedded_io_async::Write for FromFutures<T> {
210 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
211 poll_fn(|cx| Pin::new(&mut self.inner).poll_write(cx, buf)).await
212 }
213
214 async fn flush(&mut self) -> Result<(), Self::Error> {
215 poll_fn(|cx| Pin::new(&mut self.inner).poll_flush(cx)).await
216 }
217 }
218}