diff --git a/Cargo.toml b/Cargo.toml index af44fae..bc62c88 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ license = "MIT OR Apache-2.0" [dependencies] embedded-hal-0-2 = { package = "embedded-hal", version = "0.2.4", features = ["unproven"] } embedded-hal = "1" +embedded-io = "0.6.1" switch-hal = "0.4.0" nb = "0.1.1" riot-sys = "0.7.13" diff --git a/build.rs b/build.rs index ac5ffc3..78c7c4c 100644 --- a/build.rs +++ b/build.rs @@ -95,6 +95,7 @@ fn main() { "periph_gpio", "periph_i2c", "periph_spi", + "periph_uart", "prng_shaxprng", "pthread", "random", diff --git a/src/lib.rs b/src/lib.rs index 20c2a92..874f2b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -143,6 +143,9 @@ pub mod adc; #[cfg(riot_module_periph_dac)] pub mod dac; +#[cfg(riot_module_periph_uart)] +pub mod uart; + #[cfg(riot_module_ztimer)] pub mod ztimer; diff --git a/src/uart/mod.rs b/src/uart/mod.rs new file mode 100644 index 0000000..f9f4ea3 --- /dev/null +++ b/src/uart/mod.rs @@ -0,0 +1,99 @@ +//! Wrapper for using the UART +use crate::error::{NegativeErrorExt, NumericError}; +use embedded_io; +use embedded_io::ErrorKind; +use riot_sys::libc::c_void; +use riot_sys::macro_UART_DEV; +use riot_sys::uart_init; +use riot_sys::uart_t; +use riot_sys::uart_write; + +pub struct UARTDevice { + dev: uart_t, +} + +impl embedded_io::Error for NumericError { + fn kind(&self) -> ErrorKind { + match -self.number() as _ { + riot_sys::ENODEV => ErrorKind::NotFound, + riot_sys::ENOTSUP => ErrorKind::Unsupported, + _ => ErrorKind::Other, + } + } +} + +impl embedded_io::ErrorType for UARTDevice { + type Error = NumericError; +} + +impl UARTDevice { + /// Create a new UARTDevice from a RIOT descriptor + pub fn from_c(dev: uart_t) -> Self { + UARTDevice { dev } + } + + /// Create a new UARTDevice from device number + pub fn from_port(dev: u32) -> Self { + UARTDevice { + dev: unsafe { macro_UART_DEV(dev) }, + } + } + + unsafe extern "C" fn cb(ctx: *mut c_void, byte: u8) { + let real_cb: &'static mut F = unsafe { &mut *(ctx as *mut _) }; + (real_cb)(byte); + } + + pub fn init_with_fn( + &mut self, + baudrate: u32, + callback: &'static mut F, + ) -> Result<(), NumericError> { + let result = { + unsafe { + uart_init( + self.dev, + baudrate, + Some(UARTDevice::cb::), + callback as *const _ as *mut _, + ) + } + }; + + result + .negative_to_error() + .map_or_else(|err| Err(NumericError::from(err)), |_| Ok(())) + } + + pub fn init_with_closure( + &mut self, + baudrate: u32, + callback: F, + ) -> Result<(), NumericError> { + let result = { + unsafe { + uart_init( + self.dev, + baudrate, + Some(UARTDevice::cb::), + &callback as *const _ as *mut _, + ) + } + }; + + result + .negative_to_error() + .map_or_else(|err| Err(NumericError::from(err)), |_| Ok(())) + } +} + +impl embedded_io::Write for UARTDevice { + fn write(&mut self, buf: &[u8]) -> Result { + unsafe { uart_write(self.dev, buf.as_ptr(), buf.len() as u32) }; + Ok(buf.len()) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + Ok(()) + } +} diff --git a/tests/uart/Cargo.toml b/tests/uart/Cargo.toml new file mode 100644 index 0000000..f5e84bb --- /dev/null +++ b/tests/uart/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "riot-wrappers-test-uart" +version = "0.1.0" +authors = ["Bennet Hattesen "] +edition = "2021" +publish = false + +[lib] +crate-type = ["staticlib"] + +[profile.release] +panic = "abort" + +[dependencies] +riot-wrappers = { path = "../..", features = [ + "set_panic_handler", + "panic_handler_format", +] } +embedded-io = "0.6.1" +static_cell = "2.1.0" diff --git a/tests/uart/Makefile b/tests/uart/Makefile new file mode 100644 index 0000000..b711aa3 --- /dev/null +++ b/tests/uart/Makefile @@ -0,0 +1,8 @@ +# name of your application +APPLICATION = riot-wrappers-test-uart +APPLICATION_RUST_MODULE = riot_wrappers_test_uart +BASELIBS += $(APPLICATION_RUST_MODULE).module +FEATURES_REQUIRED += rust_target +FEATURES_REQUIRED += periph_uart + +include $(RIOTBASE)/Makefile.include diff --git a/tests/uart/src/lib.rs b/tests/uart/src/lib.rs new file mode 100644 index 0000000..f6055d0 --- /dev/null +++ b/tests/uart/src/lib.rs @@ -0,0 +1,43 @@ +#![no_std] +#![feature(type_alias_impl_trait)] +use core::ffi::c_void; +use embedded_io::{Error, Write}; +use riot_wrappers::println; +use riot_wrappers::riot_main; +use riot_wrappers::uart::UARTDevice; +use static_cell::StaticCell; + +riot_main!(main); + +fn main() { + let mut uart = UARTDevice::from_port(0); + fn echo_writer(byte: u8) { + static mut count: u8 = 0; + let mut _count = unsafe { count }; + let character = byte as char; + if character.is_ascii_lowercase() { + println!("{:}:{:}", _count, character.to_ascii_uppercase()); + } else if character.is_ascii_uppercase() { + println!("{:}:{:}", _count, character.to_ascii_lowercase()); + } else { + println!("{:}:{:}", _count, character); + } + _count += 1; + unsafe { count = _count }; + }; + static CB: StaticCell = StaticCell::new(); + let cb = CB.init(echo_writer); + let res = uart.init_with_fn(115200, cb); + + // Alternatively, you can use a closure: + // let res = uart.init_with_closure(115200, |mem: u8| { + // println!("Hello frome closure!"); + // echo_writer(mem); + // }); + match res { + Ok(_) => { + let _ = uart.write(b"Uart initialised, type something in!\n"); + } + Err(err) => println!("Error: {:?}", err.kind()), + } +}