Merge pull request #216 from embassy-rs/examples

Move examples to a subdirectory
This commit is contained in:
Dario Nieuwenhuis 2021-06-02 01:45:12 +02:00 committed by GitHub
commit 56ff8ebbd7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 374 additions and 36 deletions

View file

@ -26,12 +26,10 @@ jobs:
- package: embassy
target: thumbv6m-none-eabi
features: defmt
- package: embassy-std-examples
- package: examples/std
target: x86_64-unknown-linux-gnu
- package: embassy-net-examples
target: x86_64-unknown-linux-gnu
- package: embassy-nrf-examples
target: thumbv7em-none-eabi
- package: embassy-nrf
target: thumbv7em-none-eabi
features: nrf52805
@ -59,8 +57,12 @@ jobs:
- package: embassy-nrf
target: thumbv7em-none-eabi
features: nrf52840,defmt
- package: embassy-rp-examples
- package: examples/nrf
target: thumbv7em-none-eabi
- package: examples/rp
target: thumbv6m-none-eabi
- package: embassy-stm32
target: thumbv7em-none-eabi
features: stm32f411ce,defmt
@ -76,7 +78,7 @@ jobs:
- package: embassy-stm32
target: thumbv6m-none-eabi
features: stm32l053r8,defmt
- package: embassy-stm32-examples
- package: examples/stm32f4
target: thumbv7em-none-eabi
steps:

View file

@ -3,8 +3,8 @@
"editor.formatOnSave": true,
"rust-analyzer.checkOnSave.allFeatures": false,
"rust-analyzer.checkOnSave.allTargets": false,
"rust-analyzer.cargo.target": "thumbv7em-none-eabi",
"rust-analyzer.checkOnSave.target": "thumbv7em-none-eabi",
//"rust-analyzer.cargo.target": "thumbv7em-none-eabi",
//"rust-analyzer.checkOnSave.target": "thumbv7em-none-eabi",
"rust-analyzer.procMacro.enable": true,
"rust-analyzer.cargo.loadOutDirsFromCheck": true,
"files.watcherExclude": {

View file

@ -25,20 +25,21 @@ members = [
# nRF
#"embassy-nrf",
#"embassy-nrf-examples",
#"examples/nrf",
# stm32
#"embassy-stm32",
#"embassy-stm32-examples",
#"stm32-metapac",
# uncomment ONLY ONE example crate.
#"examples/stm32f4",
# rp2040
#"embassy-rp",
#"embassy-rp-examples",
#"examples/rp2040",
# std
#"embassy-std",
#"embassy-std-examples",
#"examples/std",
]
[profile.dev]

View file

@ -1,14 +0,0 @@
[package]
authors = ["Dario Nieuwenhuis <dirbaio@dirbaio.net>"]
edition = "2018"
name = "embassy-std-examples"
version = "0.1.0"
[dependencies]
async-io = "1.3.1"
embassy = { version = "0.1.0", path = "../embassy", features = ["log"] }
embassy-std = { version = "0.1.0", path = "../embassy-std" }
env_logger = "0.8.2"
futures = { version = "0.3.8", default-features = false, features = ["async-await"] }
log = "0.4.11"
nix = "0.19.1"

View file

@ -17,9 +17,9 @@ defmt-error = []
[dependencies]
embassy = { version = "0.1.0", path = "../embassy", features = ["defmt", "defmt-trace"] }
embassy-traits = { version = "0.1.0", path = "../embassy-traits", features = ["defmt"] }
embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", features = ["defmt", "defmt-trace", "nrf52840"] }
embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-trace"] }
embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] }
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "defmt-trace", "nrf52840"] }
defmt = "0.2.0"
defmt-rtt = "0.2.0"

View file

@ -17,8 +17,8 @@ defmt-error = []
[dependencies]
embassy = { version = "0.1.0", path = "../embassy", features = ["defmt", "defmt-trace"] }
embassy-rp = { version = "0.1.0", path = "../embassy-rp", features = ["defmt", "defmt-trace"] }
embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-trace"] }
embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "defmt-trace"] }
rp2040-pac2 = { git = "https://github.com/Dirbaio/rp2040-pac", rev="254f4677937801155ca3cb17c7bb9d38eb62683e" }
atomic-polyfill = { version = "0.1.1" }

21
examples/std/Cargo.toml Normal file
View file

@ -0,0 +1,21 @@
[package]
authors = ["Dario Nieuwenhuis <dirbaio@dirbaio.net>"]
edition = "2018"
name = "embassy-std-examples"
version = "0.1.0"
[dependencies]
embassy = { version = "0.1.0", path = "../../embassy", features = ["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"] }
smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev="ec59aba5e10cf91df0c9253d9c2aca4dd143d2ff", default-features = false }
async-io = "1.3.1"
env_logger = "0.8.2"
futures = { version = "0.3.8", default-features = false, features = ["async-await"] }
log = "0.4.11"
nix = "0.21.0"
libc = "0.2.81"
clap = { version = "3.0.0-beta.2", features = ["derive"] }
rand_core = { version = "0.6.0", features = ["std"] }
heapless = { version = "0.5.6", default-features = false }

103
examples/std/src/bin/net.rs Normal file
View file

@ -0,0 +1,103 @@
#![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::*;
#[path = "../tuntap.rs"]
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();
});
}

225
examples/std/src/tuntap.rs Normal file
View file

@ -0,0 +1,225 @@
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]
}
}

View file

@ -17,10 +17,10 @@ defmt-warn = []
defmt-error = []
[dependencies]
embassy = { version = "0.1.0", path = "../embassy", features = ["defmt", "defmt-trace"] }
embassy-traits = { version = "0.1.0", path = "../embassy-traits", features = ["defmt"] }
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", features = ["defmt", "defmt-trace", "stm32f429zi"] }
embassy-extras = {version = "0.1.0", path = "../embassy-extras" }
embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-trace"] }
embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "defmt-trace", "stm32f429zi"] }
embassy-extras = {version = "0.1.0", path = "../../embassy-extras" }
stm32f4 = { version = "0.13", features = ["stm32f429"] }
defmt = "0.2.0"