Merge pull request #221 from embassy-rs/heapless
Update Heapless to 0.7 (const generics)
This commit is contained in:
commit
cd44b221ed
@ -1,19 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "embassy-net-examples"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Dario Nieuwenhuis <dirbaio@dirbaio.net>"]
|
|
||||||
edition = "2018"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
heapless = { version = "0.5.6", default-features = false }
|
|
||||||
embassy = { version = "0.1.0", path = "../embassy", features=["std", "log"] }
|
|
||||||
embassy-std = { version = "0.1.0", path = "../embassy-std" }
|
|
||||||
embassy-net = { version = "0.1.0", path = "../embassy-net", features=["std", "log", "medium-ethernet", "tcp", "dhcpv4"] }
|
|
||||||
env_logger = "0.8.2"
|
|
||||||
log = "0.4.11"
|
|
||||||
futures = "0.3.8"
|
|
||||||
libc = "0.2.81"
|
|
||||||
async-io = "1.3.1"
|
|
||||||
smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev="ec59aba5e10cf91df0c9253d9c2aca4dd143d2ff", default-features = false }
|
|
||||||
clap = { version = "3.0.0-beta.2", features = ["derive"] }
|
|
||||||
rand_core = { version = "0.6.0", features = ["std"] }
|
|
@ -1,102 +0,0 @@
|
|||||||
#![feature(type_alias_impl_trait)]
|
|
||||||
#![feature(min_type_alias_impl_trait)]
|
|
||||||
#![feature(impl_trait_in_bindings)]
|
|
||||||
#![allow(incomplete_features)]
|
|
||||||
|
|
||||||
use clap::{AppSettings, Clap};
|
|
||||||
use embassy::executor::Spawner;
|
|
||||||
use embassy::io::AsyncWriteExt;
|
|
||||||
use embassy::util::Forever;
|
|
||||||
use embassy_net::*;
|
|
||||||
use embassy_std::Executor;
|
|
||||||
use heapless::Vec;
|
|
||||||
use log::*;
|
|
||||||
|
|
||||||
mod tuntap;
|
|
||||||
|
|
||||||
use crate::tuntap::TunTapDevice;
|
|
||||||
|
|
||||||
static DEVICE: Forever<TunTapDevice> = Forever::new();
|
|
||||||
static CONFIG: Forever<DhcpConfigurator> = Forever::new();
|
|
||||||
|
|
||||||
#[derive(Clap)]
|
|
||||||
#[clap(version = "1.0")]
|
|
||||||
#[clap(setting = AppSettings::ColoredHelp)]
|
|
||||||
struct Opts {
|
|
||||||
/// TAP device name
|
|
||||||
#[clap(long, default_value = "tap0")]
|
|
||||||
tap: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[embassy::task]
|
|
||||||
async fn net_task() {
|
|
||||||
embassy_net::run().await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[embassy::task]
|
|
||||||
async fn main_task(spawner: Spawner) {
|
|
||||||
let opts: Opts = Opts::parse();
|
|
||||||
|
|
||||||
// Init network device
|
|
||||||
let device = TunTapDevice::new(&opts.tap).unwrap();
|
|
||||||
|
|
||||||
// Static IP configuration
|
|
||||||
let config = StaticConfigurator::new(Config {
|
|
||||||
address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
|
|
||||||
dns_servers: Vec::new(),
|
|
||||||
gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
|
|
||||||
});
|
|
||||||
|
|
||||||
// DHCP configruation
|
|
||||||
let config = DhcpConfigurator::new();
|
|
||||||
|
|
||||||
// Init network stack
|
|
||||||
embassy_net::init(DEVICE.put(device), CONFIG.put(config));
|
|
||||||
|
|
||||||
// Launch network task
|
|
||||||
spawner.spawn(net_task()).unwrap();
|
|
||||||
|
|
||||||
// Then we can use it!
|
|
||||||
let mut rx_buffer = [0; 4096];
|
|
||||||
let mut tx_buffer = [0; 4096];
|
|
||||||
let mut socket = TcpSocket::new(&mut rx_buffer, &mut tx_buffer);
|
|
||||||
|
|
||||||
socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
|
|
||||||
|
|
||||||
let remote_endpoint = (Ipv4Address::new(192, 168, 69, 74), 8000);
|
|
||||||
info!("connecting to {:?}...", remote_endpoint);
|
|
||||||
let r = socket.connect(remote_endpoint).await;
|
|
||||||
if let Err(e) = r {
|
|
||||||
warn!("connect error: {:?}", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
info!("connected!");
|
|
||||||
loop {
|
|
||||||
let r = socket.write_all(b"Hello!\n").await;
|
|
||||||
if let Err(e) = r {
|
|
||||||
warn!("write error: {:?}", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
fn _embassy_rand(buf: &mut [u8]) {
|
|
||||||
use rand_core::{OsRng, RngCore};
|
|
||||||
OsRng.fill_bytes(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static EXECUTOR: Forever<Executor> = Forever::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.put(Executor::new());
|
|
||||||
executor.run(|spawner| {
|
|
||||||
spawner.spawn(main_task(spawner)).unwrap();
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,225 +0,0 @@
|
|||||||
use async_io::Async;
|
|
||||||
use libc;
|
|
||||||
use log::*;
|
|
||||||
use smoltcp::wire::EthernetFrame;
|
|
||||||
use std::io;
|
|
||||||
use std::io::{Read, Write};
|
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
|
||||||
|
|
||||||
pub const SIOCGIFMTU: libc::c_ulong = 0x8921;
|
|
||||||
pub const SIOCGIFINDEX: libc::c_ulong = 0x8933;
|
|
||||||
pub const ETH_P_ALL: libc::c_short = 0x0003;
|
|
||||||
pub const TUNSETIFF: libc::c_ulong = 0x400454CA;
|
|
||||||
pub const IFF_TUN: libc::c_int = 0x0001;
|
|
||||||
pub const IFF_TAP: libc::c_int = 0x0002;
|
|
||||||
pub const IFF_NO_PI: libc::c_int = 0x1000;
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct ifreq {
|
|
||||||
ifr_name: [libc::c_char; libc::IF_NAMESIZE],
|
|
||||||
ifr_data: libc::c_int, /* ifr_ifindex or ifr_mtu */
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ifreq_for(name: &str) -> ifreq {
|
|
||||||
let mut ifreq = ifreq {
|
|
||||||
ifr_name: [0; libc::IF_NAMESIZE],
|
|
||||||
ifr_data: 0,
|
|
||||||
};
|
|
||||||
for (i, byte) in name.as_bytes().iter().enumerate() {
|
|
||||||
ifreq.ifr_name[i] = *byte as libc::c_char
|
|
||||||
}
|
|
||||||
ifreq
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ifreq_ioctl(
|
|
||||||
lower: libc::c_int,
|
|
||||||
ifreq: &mut ifreq,
|
|
||||||
cmd: libc::c_ulong,
|
|
||||||
) -> io::Result<libc::c_int> {
|
|
||||||
unsafe {
|
|
||||||
let res = libc::ioctl(lower, cmd as _, ifreq as *mut ifreq);
|
|
||||||
if res == -1 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ifreq.ifr_data)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct TunTap {
|
|
||||||
fd: libc::c_int,
|
|
||||||
ifreq: ifreq,
|
|
||||||
mtu: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRawFd for TunTap {
|
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
|
||||||
self.fd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TunTap {
|
|
||||||
pub fn new(name: &str) -> io::Result<TunTap> {
|
|
||||||
unsafe {
|
|
||||||
let fd = libc::open(
|
|
||||||
"/dev/net/tun\0".as_ptr() as *const libc::c_char,
|
|
||||||
libc::O_RDWR | libc::O_NONBLOCK,
|
|
||||||
);
|
|
||||||
if fd == -1 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut ifreq = ifreq_for(name);
|
|
||||||
ifreq.ifr_data = IFF_TAP | IFF_NO_PI;
|
|
||||||
ifreq_ioctl(fd, &mut ifreq, TUNSETIFF)?;
|
|
||||||
|
|
||||||
let socket = libc::socket(libc::AF_INET, libc::SOCK_DGRAM, libc::IPPROTO_IP);
|
|
||||||
if socket == -1 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
let ip_mtu = ifreq_ioctl(socket, &mut ifreq, SIOCGIFMTU);
|
|
||||||
libc::close(socket);
|
|
||||||
let ip_mtu = ip_mtu? as usize;
|
|
||||||
|
|
||||||
// SIOCGIFMTU returns the IP MTU (typically 1500 bytes.)
|
|
||||||
// smoltcp counts the entire Ethernet packet in the MTU, so add the Ethernet header size to it.
|
|
||||||
let mtu = ip_mtu + EthernetFrame::<&[u8]>::header_len();
|
|
||||||
|
|
||||||
Ok(TunTap { fd, mtu, ifreq })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for TunTap {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
libc::close(self.fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl io::Read for TunTap {
|
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
||||||
let len = unsafe { libc::read(self.fd, buf.as_mut_ptr() as *mut libc::c_void, buf.len()) };
|
|
||||||
if len == -1 {
|
|
||||||
Err(io::Error::last_os_error())
|
|
||||||
} else {
|
|
||||||
Ok(len as usize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl io::Write for TunTap {
|
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
let len = unsafe { libc::write(self.fd, buf.as_ptr() as *mut libc::c_void, buf.len()) };
|
|
||||||
if len == -1 {
|
|
||||||
Err(io::Error::last_os_error())
|
|
||||||
} else {
|
|
||||||
Ok(len as usize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flush(&mut self) -> io::Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TunTapDevice {
|
|
||||||
device: Async<TunTap>,
|
|
||||||
waker: Option<Waker>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TunTapDevice {
|
|
||||||
pub fn new(name: &str) -> io::Result<TunTapDevice> {
|
|
||||||
Ok(Self {
|
|
||||||
device: Async::new(TunTap::new(name)?)?,
|
|
||||||
waker: None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use core::task::Waker;
|
|
||||||
use embassy_net::{DeviceCapabilities, LinkState, Packet, PacketBox, PacketBoxExt, PacketBuf};
|
|
||||||
use std::task::Context;
|
|
||||||
|
|
||||||
impl crate::Device for TunTapDevice {
|
|
||||||
fn is_transmit_ready(&mut self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transmit(&mut self, pkt: PacketBuf) {
|
|
||||||
// todo handle WouldBlock
|
|
||||||
match self.device.get_mut().write(&pkt) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
|
|
||||||
info!("transmit WouldBlock");
|
|
||||||
}
|
|
||||||
Err(e) => panic!("transmit error: {:?}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn receive(&mut self) -> Option<PacketBuf> {
|
|
||||||
let mut pkt = PacketBox::new(Packet::new()).unwrap();
|
|
||||||
loop {
|
|
||||||
match self.device.get_mut().read(&mut pkt[..]) {
|
|
||||||
Ok(n) => {
|
|
||||||
return Some(pkt.slice(0..n));
|
|
||||||
}
|
|
||||||
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
|
|
||||||
let ready = if let Some(w) = self.waker.as_ref() {
|
|
||||||
let mut cx = Context::from_waker(w);
|
|
||||||
let ready = self.device.poll_readable(&mut cx).is_ready();
|
|
||||||
ready
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
if !ready {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => panic!("read error: {:?}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn register_waker(&mut self, w: &Waker) {
|
|
||||||
match self.waker {
|
|
||||||
// Optimization: If both the old and new Wakers wake the same task, we can simply
|
|
||||||
// keep the old waker, skipping the clone. (In most executor implementations,
|
|
||||||
// cloning a waker is somewhat expensive, comparable to cloning an Arc).
|
|
||||||
Some(ref w2) if (w2.will_wake(w)) => {}
|
|
||||||
_ => {
|
|
||||||
// clone the new waker and store it
|
|
||||||
if let Some(old_waker) = core::mem::replace(&mut self.waker, Some(w.clone())) {
|
|
||||||
// We had a waker registered for another task. Wake it, so the other task can
|
|
||||||
// reregister itself if it's still interested.
|
|
||||||
//
|
|
||||||
// If two tasks are waiting on the same thing concurrently, this will cause them
|
|
||||||
// to wake each other in a loop fighting over this WakerRegistration. This wastes
|
|
||||||
// CPU but things will still work.
|
|
||||||
//
|
|
||||||
// If the user wants to have two tasks waiting on the same thing they should use
|
|
||||||
// a more appropriate primitive that can store multiple wakers.
|
|
||||||
old_waker.wake()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn capabilities(&mut self) -> DeviceCapabilities {
|
|
||||||
let mut caps = DeviceCapabilities::default();
|
|
||||||
caps.max_transmission_unit = self.device.get_ref().mtu;
|
|
||||||
caps
|
|
||||||
}
|
|
||||||
|
|
||||||
fn link_state(&mut self) -> LinkState {
|
|
||||||
LinkState::Up
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ethernet_address(&mut self) -> [u8; 6] {
|
|
||||||
[0x02, 0x03, 0x04, 0x05, 0x06, 0x07]
|
|
||||||
}
|
|
||||||
}
|
|
@ -25,7 +25,7 @@ log = { version = "0.4.11", optional = true }
|
|||||||
embassy = { version = "0.1.0", path = "../embassy" }
|
embassy = { version = "0.1.0", path = "../embassy" }
|
||||||
|
|
||||||
managed = { version = "0.8.0", default-features = false, features = [ "map" ]}
|
managed = { version = "0.8.0", default-features = false, features = [ "map" ]}
|
||||||
heapless = { version = "0.5.6", default-features = false }
|
heapless = { version = "0.7.1", default-features = false }
|
||||||
as-slice = { version = "0.1.4" }
|
as-slice = { version = "0.1.4" }
|
||||||
generic-array = { version = "0.14.4", default-features = false }
|
generic-array = { version = "0.14.4", default-features = false }
|
||||||
stable_deref_trait = { version = "1.2.0", default-features = false }
|
stable_deref_trait = { version = "1.2.0", default-features = false }
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use heapless::consts::*;
|
|
||||||
use heapless::Vec;
|
use heapless::Vec;
|
||||||
use smoltcp::time::Instant;
|
use smoltcp::time::Instant;
|
||||||
use smoltcp::wire::{Ipv4Address, Ipv4Cidr};
|
use smoltcp::wire::{Ipv4Address, Ipv4Cidr};
|
||||||
@ -29,7 +28,7 @@ pub enum Event {
|
|||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub address: Ipv4Cidr,
|
pub address: Ipv4Cidr,
|
||||||
pub gateway: Option<Ipv4Address>,
|
pub gateway: Option<Ipv4Address>,
|
||||||
pub dns_servers: Vec<Ipv4Address, U3>,
|
pub dns_servers: Vec<Ipv4Address, 3>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Configurator {
|
pub trait Configurator {
|
||||||
|
@ -18,4 +18,4 @@ nix = "0.21.0"
|
|||||||
libc = "0.2.81"
|
libc = "0.2.81"
|
||||||
clap = { version = "3.0.0-beta.2", features = ["derive"] }
|
clap = { version = "3.0.0-beta.2", features = ["derive"] }
|
||||||
rand_core = { version = "0.6.0", features = ["std"] }
|
rand_core = { version = "0.6.0", features = ["std"] }
|
||||||
heapless = { version = "0.5.6", default-features = false }
|
heapless = { version = "0.7.1", default-features = false }
|
||||||
|
@ -32,4 +32,4 @@ embedded-hal = { version = "0.2.4" }
|
|||||||
panic-probe = { version = "0.2.0", features= ["print-defmt"] }
|
panic-probe = { version = "0.2.0", features= ["print-defmt"] }
|
||||||
futures = { version = "0.3.8", default-features = false, features = ["async-await"] }
|
futures = { version = "0.3.8", default-features = false, features = ["async-await"] }
|
||||||
rtt-target = { version = "0.3", features = ["cortex-m"] }
|
rtt-target = { version = "0.3", features = ["cortex-m"] }
|
||||||
heapless = "0.7"
|
heapless = { version = "0.7.1", default-features = false }
|
Loading…
Reference in New Issue
Block a user