#![feature(type_alias_impl_trait)] use core::fmt::Write as _; use std::default::Default; use clap::Parser; use embassy_executor::{Executor, Spawner}; use embassy_net::tcp::TcpSocket; use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; use embassy_net_tuntap::TunTapDevice; use embassy_time::{Duration, Timer}; use embedded_io_async::Write as _; use heapless::Vec; use log::*; use rand_core::{OsRng, RngCore}; use static_cell::{make_static, StaticCell}; #[derive(Parser)] #[clap(version = "1.0")] struct Opts { /// TAP device name #[clap(long, default_value = "tap0")] tap: String, /// use a static IP instead of DHCP #[clap(long)] static_ip: bool, } #[embassy_executor::task] async fn net_task(stack: &'static Stack) -> ! { stack.run().await } #[derive(Default)] struct StrWrite(pub heapless::Vec); impl core::fmt::Write for StrWrite { fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> { self.0.extend_from_slice(s.as_bytes()).unwrap(); Ok(()) } } #[embassy_executor::task] async fn main_task(spawner: Spawner) { let opts: Opts = Opts::parse(); // Init network device let device = TunTapDevice::new(&opts.tap).unwrap(); // Choose between dhcp or static ip let config = if opts.static_ip { Config::ipv4_static(embassy_net::StaticConfigV4 { address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), dns_servers: Vec::new(), gateway: Some(Ipv4Address::new(192, 168, 69, 1)), }) } else { Config::dhcpv4(Default::default()) }; // Generate random seed let mut seed = [0; 8]; OsRng.fill_bytes(&mut seed); let seed = u64::from_le_bytes(seed); // Init network stack let stack = &*make_static!(Stack::new( device, config, make_static!(StackResources::<3>::new()), seed )); // Launch network task spawner.spawn(net_task(stack)).unwrap(); // Then we can use it! let mut rx_buffer = [0; 4096]; let mut tx_buffer = [0; 4096]; loop { let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); socket.set_timeout(Some(Duration::from_secs(10))); info!("Listening on TCP:9999..."); if let Err(_) = socket.accept(9999).await { warn!("accept error"); continue; } info!("Accepted a connection"); // Write some quick output for i in 1..=5 { let mut w = StrWrite::default(); write!(w, "{}! ", i).unwrap(); let r = socket.write_all(&w.0).await; if let Err(e) = r { warn!("write error: {:?}", e); return; } Timer::after(Duration::from_millis(500)).await; } info!("Closing the connection"); socket.abort(); info!("Flushing the RST out..."); _ = socket.flush().await; info!("Finished with the socket"); } } static EXECUTOR: StaticCell = StaticCell::new(); fn main() { env_logger::builder() .filter_level(log::LevelFilter::Debug) .filter_module("async_io", log::LevelFilter::Info) .format_timestamp_nanos() .init(); let executor = EXECUTOR.init(Executor::new()); executor.run(|spawner| { spawner.spawn(main_task(spawner)).unwrap(); }); }