#[cfg(feature = "async")]
use crate::driver::PinSignal;
use crate::{
driver::ReadInputsResult,
input::Input,
output::Output,
pin::Pin,
types::{Direction, PinId},
};
use embedded_hal::{digital::PinState, i2c::I2c};
#[cfg(feature = "async")]
use embedded_hal_async::digital::Wait;
#[cfg(feature = "async")]
use {
crate::types::WaitMode,
embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal},
};
pub trait DriverHandler {
type Error: embedded_hal::digital::Error;
type I2c: I2c;
fn new(i2c: Self::I2c, a3: bool, a2: bool, a1: bool) -> Result<Self, Self::Error>
where
Self: Sized;
fn read_inputs(&self) -> Result<ReadInputsResult, Self::Error>;
fn set_direction(&self, pin: PinId, direction: Direction) -> Result<(), Self::Error>;
fn get_direction(&self, pin: PinId) -> Result<Direction, Self::Error>;
fn set_output(&self, pin: PinId) -> Result<(), Self::Error> {
self.set_direction(pin, Direction::Output)
}
fn set_input(&self, pin: PinId) -> Result<(), Self::Error> {
self.set_direction(pin, Direction::Input)
}
fn set_level(&self, pin: PinId, level: PinState) -> Result<(), Self::Error>;
fn get_level(&self, pin: PinId) -> Result<PinState, Self::Error>;
fn get_set_level(&self, pin: PinId) -> Result<PinState, Self::Error>;
fn set_high(&self, pin: PinId) -> Result<(), Self::Error> {
self.set_level(pin, PinState::High)
}
fn set_low(&self, pin: PinId) -> Result<(), Self::Error> {
self.set_level(pin, PinState::Low)
}
fn toggle(&self, pin: PinId) -> Result<(), Self::Error> {
let level = self.get_level(pin)?;
self.set_level(pin, !level)
}
fn input(&self, pin: PinId) -> Result<Input<'_, Self>, Self::Error>
where
Self: Sized,
{
Pin::new(self, pin).into_input()
}
fn output(&self, pin: PinId, level: PinState) -> Result<Output<'_, Self>, Self::Error>
where
Self: Sized,
{
Pin::new(self, pin).into_output(level)
}
#[cfg(feature = "async")]
fn get_signals(&self) -> &[PinSignal; 16];
#[cfg(feature = "async")]
fn get_signal(&self, pin: PinId) -> &PinSignal {
&self.get_signals()[pin as usize]
}
#[cfg(feature = "async")]
fn register_wait(&self, pin: PinId, mode: WaitMode) -> &Signal<CriticalSectionRawMutex, ()> {
use core::sync::atomic::Ordering;
self.get_signal(pin)
.wait_mode
.store(mode as u8, Ordering::Release);
&self.get_signal(pin).signal
}
#[cfg(feature = "async")]
fn get_wait_mode(&self, pin: PinId) -> WaitMode {
use core::sync::atomic::Ordering;
match self.get_signal(pin).wait_mode.load(Ordering::Acquire) {
1 => WaitMode::Falling,
2 => WaitMode::Rising,
3 => WaitMode::Low,
4 => WaitMode::High,
5 => WaitMode::AnyEdge,
_ => WaitMode::None,
}
}
#[cfg(feature = "async")]
fn clear_wait_mode(&self, pin: PinId) {
use core::sync::atomic::Ordering;
self.get_signal(pin)
.wait_mode
.store(WaitMode::None as u8, Ordering::Release)
}
#[cfg(feature = "async")]
#[allow(async_fn_in_trait)]
async fn monitor(&self, mut int_pin: impl Wait) {
loop {
use embassy_time::{Duration, Timer};
match int_pin.wait_for_falling_edge().await {
Ok(_) => {}
Err(_) => {
defmt::error!("wait for xl9555 int pin falling edge failed");
Timer::after(Duration::from_millis(200)).await;
continue;
}
}
Timer::after(Duration::from_millis(5)).await;
match self.read_inputs() {
Ok(ret) => {
let ReadInputsResult { now, old } = ret;
let changed = now ^ old;
for pin in 0..16u8 {
if changed & (1 << pin) == 0 {
continue;
}
let pin_id = PinId::from(pin);
let wait_mode = self.get_wait_mode(pin_id);
if wait_mode == WaitMode::None {
continue;
}
let pin_mask = 1 << pin;
let was_high = (old & pin_mask) != 0;
let is_high = (now & pin_mask) != 0;
let event = if was_high && !is_high {
Some(WaitMode::Falling)
} else if !was_high && is_high {
Some(WaitMode::Rising)
} else {
None
};
if let Some(event) = event {
let should_wake = match wait_mode {
WaitMode::Falling => event == WaitMode::Falling,
WaitMode::Rising => event == WaitMode::Rising,
WaitMode::Low => event == WaitMode::Falling,
WaitMode::High => event == WaitMode::Rising,
WaitMode::AnyEdge => true,
WaitMode::None => false,
};
if should_wake {
self.clear_wait_mode(pin_id);
self.get_signal(pin_id).signal.signal(());
}
}
}
}
Err(_) => Timer::after(Duration::from_millis(500)).await,
}
}
}
}