#![feature(type_alias_impl_trait)] use clap::Parser; use embassy_executor::{Executor, Spawner}; use embassy_net::udp::UdpSocket; use embassy_net::{ConfigStrategy, Ipv4Address, Ipv4Cidr, PacketMetadata, Stack, StackResources}; use heapless::Vec; use log::*; use rand_core::{OsRng, RngCore}; use static_cell::StaticCell; #[path = "../tuntap.rs"] mod tuntap; use crate::tuntap::TunTapDevice; macro_rules! singleton { ($val:expr) => {{ type T = impl Sized; static STATIC_CELL: StaticCell = StaticCell::new(); STATIC_CELL.init_with(move || $val) }}; } #[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 } #[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 { ConfigStrategy::Static(embassy_net::Config { address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), dns_servers: Vec::new(), gateway: Some(Ipv4Address::new(192, 168, 69, 1)), }) } else { ConfigStrategy::Dhcp }; // 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 = &*singleton!(Stack::new( device, config, singleton!(StackResources::<1, 2, 8>::new()), seed )); // Launch network task spawner.spawn(net_task(stack)).unwrap(); // Then we can use it! let mut rx_meta = [PacketMetadata::EMPTY; 16]; let mut rx_buffer = [0; 4096]; let mut tx_meta = [PacketMetadata::EMPTY; 16]; let mut tx_buffer = [0; 4096]; let mut buf = [0; 4096]; let mut socket = UdpSocket::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer); socket.bind(9400).unwrap(); loop { let (n, ep) = socket.recv_from(&mut buf).await.unwrap(); if let Ok(s) = core::str::from_utf8(&buf[..n]) { info!("ECHO (to {}): {}", ep, s); } else { info!("ECHO (to {}): bytearray len {}", ep, n); } socket.send_to(&buf[..n], ep).await.unwrap(); } } 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(); }); }