use alloc::boxed::Box;
use wasefire_applet_api::gpio as api;
pub use wasefire_applet_api::gpio::{Event, InputConfig, OutputConfig};
use wasefire_error::Error;
use crate::{convert, convert_bool, convert_unit};
pub fn count() -> usize {
convert(unsafe { api::count() }).unwrap_or(0)
}
#[derive(Debug)]
pub struct Config {
pub input: InputConfig,
pub output: OutputConfig,
pub initial: bool,
}
impl Config {
pub fn disconnected() -> Self {
Config::input(InputConfig::Disabled)
}
pub fn input(input: InputConfig) -> Self {
Config::new(input, OutputConfig::Disabled, false)
}
pub fn output(output: OutputConfig, initial: bool) -> Self {
Config::new(InputConfig::Disabled, output, initial)
}
pub fn new(input: InputConfig, output: OutputConfig, initial: bool) -> Self {
Config { input, output, initial }
}
fn mode(&self) -> usize {
let mut result = 0;
result |= self.input as u32;
result |= (self.output as u32) << 8;
result |= (self.initial as u32) << 16;
result as usize
}
}
pub fn configure(gpio: usize, config: &Config) -> Result<(), Error> {
let params = api::configure::Params { gpio, mode: config.mode() };
convert_unit(unsafe { api::configure(params) })
}
pub fn read(gpio: usize) -> Result<bool, Error> {
let params = api::read::Params { gpio };
convert_bool(unsafe { api::read(params) })
}
pub fn write(gpio: usize, value: bool) -> Result<(), Error> {
let params = api::write::Params { gpio, val: value as usize };
convert_unit(unsafe { api::write(params) })
}
pub fn last_write(gpio: usize) -> Result<bool, Error> {
let params = api::last_write::Params { gpio };
convert_bool(unsafe { api::last_write(params) })
}
pub struct Gpio(usize);
impl Drop for Gpio {
fn drop(&mut self) {
configure(self.0, &Config::disconnected()).unwrap();
}
}
impl Gpio {
pub fn new(gpio: usize, config: &Config) -> Result<Self, Error> {
configure(gpio, config)?;
Ok(Gpio(gpio))
}
pub fn read(&self) -> Result<bool, Error> {
read(self.0)
}
pub fn write(&self, value: bool) -> Result<(), Error> {
write(self.0, value)
}
pub fn last_write(&self) -> Result<bool, Error> {
last_write(self.0)
}
pub fn toggle(&self) -> Result<(), Error> {
self.write(!self.last_write()?)
}
}
pub trait Handler: 'static {
fn event(&self);
}
impl<F: Fn() + 'static> Handler for F {
fn event(&self) {
self()
}
}
#[must_use]
pub struct Listener<H: Handler> {
gpio: usize,
handler: *const H,
}
impl<H: Handler> Listener<H> {
pub fn new(gpio: usize, event: Event, handler: H) -> Result<Self, Error> {
let handler_func = Self::call;
let handler = Box::into_raw(Box::new(handler));
let handler_data = handler as *const u8;
let event = event as usize;
let params = api::register::Params { gpio, event, handler_func, handler_data };
convert_unit(unsafe { api::register(params) })?;
Ok(Listener { gpio, handler })
}
pub fn stop(self) {
core::mem::drop(self);
}
pub fn leak(self) {
core::mem::forget(self);
}
extern "C" fn call(data: *const u8) {
let handler = unsafe { &*(data as *const H) };
handler.event();
}
}
impl<H: Handler> Drop for Listener<H> {
fn drop(&mut self) {
let params = api::unregister::Params { gpio: self.gpio };
convert_unit(unsafe { api::unregister(params) }).unwrap();
drop(unsafe { Box::from_raw(self.handler as *mut H) });
}
}