diff --git a/Cargo.toml b/Cargo.toml index eab6402aa..4feeb2624 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,8 @@ members = [ # for all crates in the workspace together, including it would result in # incompatible features enabled in embassy. exclude = [ - "embassy-std" + "embassy-std", + "embassy-std-examples", ] [profile.dev] diff --git a/embassy-std-examples/Cargo.toml b/embassy-std-examples/Cargo.toml new file mode 100644 index 000000000..0998899c8 --- /dev/null +++ b/embassy-std-examples/Cargo.toml @@ -0,0 +1,14 @@ +[package] +authors = ["Dario Nieuwenhuis "] +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" diff --git a/embassy-std-examples/src/bin/serial.rs b/embassy-std-examples/src/bin/serial.rs new file mode 100644 index 000000000..b66b7de20 --- /dev/null +++ b/embassy-std-examples/src/bin/serial.rs @@ -0,0 +1,57 @@ +#![feature(type_alias_impl_trait)] + +#[path = "../serial_port.rs"] +mod serial_port; + +use async_io::Async; +use embassy::executor::task; +use embassy::io::{AsyncBufRead, AsyncBufReadExt, AsyncWrite, AsyncWriteExt}; +use embassy::util::Forever; +use embassy_std::Executor; +use log::*; +use nix::sys::termios; + +use self::serial_port::SerialPort; + +#[task] +async fn run() { + // Open the serial port. + let baudrate = termios::BaudRate::B115200; + let port = SerialPort::new("/dev/ttyACM0", baudrate).unwrap(); + //let port = Spy::new(port); + + // Use async_io's reactor for async IO. + // This demonstrates how embassy's executor can drive futures from another IO library. + // Essentially, async_io::Async converts from AsRawFd+Read+Write to futures's AsyncRead+AsyncWrite + let port = Async::new(port).unwrap(); + + // This implements futures's AsyncBufRead based on futures's AsyncRead + let port = futures::io::BufReader::new(port); + + // We can then use FromStdIo to convert from futures's AsyncBufRead+AsyncWrite + // to embassy's AsyncBufRead+AsyncWrite + let mut port = embassy::io::FromStdIo::new(port); + + info!("Serial opened!"); + + loop { + let mut buf = [0u8; 256]; + let n = port.read(&mut buf).await.unwrap(); + info!("read {:?}", &buf[..n]); + } +} + +static EXECUTOR: Forever = 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(run()).unwrap(); + }); +} diff --git a/embassy-std-examples/src/bin/tick.rs b/embassy-std-examples/src/bin/tick.rs new file mode 100644 index 000000000..af2305f33 --- /dev/null +++ b/embassy-std-examples/src/bin/tick.rs @@ -0,0 +1,29 @@ +#![feature(type_alias_impl_trait)] + +use embassy::executor::task; +use embassy::time::{Duration, Timer}; +use embassy::util::Forever; +use embassy_std::Executor; +use log::*; + +#[task] +async fn run() { + loop { + info!("tick"); + Timer::after(Duration::from_secs(1)).await; + } +} + +static EXECUTOR: Forever = Forever::new(); + +fn main() { + env_logger::builder() + .filter_level(log::LevelFilter::Debug) + .format_timestamp_nanos() + .init(); + + let executor = EXECUTOR.put(Executor::new()); + executor.run(|spawner| { + spawner.spawn(run()).unwrap(); + }); +} diff --git a/embassy-std-examples/src/serial_port.rs b/embassy-std-examples/src/serial_port.rs new file mode 100644 index 000000000..7ac1b1edb --- /dev/null +++ b/embassy-std-examples/src/serial_port.rs @@ -0,0 +1,71 @@ +use nix::fcntl::OFlag; +use nix::sys::termios; +use nix::Error; +use std::io; +use std::os::unix::io::{AsRawFd, RawFd}; + +pub struct SerialPort { + fd: RawFd, +} + +impl SerialPort { + pub fn new<'a, P: ?Sized + nix::NixPath>( + path: &P, + baudrate: termios::BaudRate, + ) -> io::Result { + let fd = nix::fcntl::open( + path, + OFlag::O_RDWR | OFlag::O_NOCTTY | OFlag::O_NONBLOCK, + nix::sys::stat::Mode::empty(), + ) + .map_err(to_io_error)?; + + let mut cfg = termios::tcgetattr(fd).map_err(to_io_error)?; + cfg.input_flags = termios::InputFlags::empty(); + cfg.output_flags = termios::OutputFlags::empty(); + cfg.control_flags = termios::ControlFlags::empty(); + cfg.local_flags = termios::LocalFlags::empty(); + termios::cfmakeraw(&mut cfg); + cfg.input_flags |= termios::InputFlags::IGNBRK; + cfg.control_flags |= termios::ControlFlags::CREAD; + //cfg.control_flags |= termios::ControlFlags::CRTSCTS; + termios::cfsetospeed(&mut cfg, baudrate).map_err(to_io_error)?; + termios::cfsetispeed(&mut cfg, baudrate).map_err(to_io_error)?; + termios::cfsetspeed(&mut cfg, baudrate).map_err(to_io_error)?; + // Set VMIN = 1 to block until at least one character is received. + cfg.control_chars[termios::SpecialCharacterIndices::VMIN as usize] = 1; + termios::tcsetattr(fd, termios::SetArg::TCSANOW, &cfg).map_err(to_io_error)?; + termios::tcflush(fd, termios::FlushArg::TCIOFLUSH).map_err(to_io_error)?; + + Ok(Self { fd }) + } +} + +impl AsRawFd for SerialPort { + fn as_raw_fd(&self) -> RawFd { + self.fd + } +} + +impl io::Read for SerialPort { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + nix::unistd::read(self.fd, buf).map_err(to_io_error) + } +} + +impl io::Write for SerialPort { + fn write(&mut self, buf: &[u8]) -> io::Result { + nix::unistd::write(self.fd, buf).map_err(to_io_error) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +fn to_io_error(e: Error) -> io::Error { + match e { + Error::Sys(errno) => errno.into(), + e => io::Error::new(io::ErrorKind::InvalidInput, e), + } +} diff --git a/test-build.sh b/test-build.sh index 8af5f843c..d556fb313 100755 --- a/test-build.sh +++ b/test-build.sh @@ -3,8 +3,7 @@ set -euxo pipefail # embassy std -(cd embassy; cargo build --features log,std) -(cd embassy-std; cargo build) +(cd embassy-std-examples; cargo build) # embassy embedded (cd embassy; cargo build --target thumbv7em-none-eabi)