xl9555-hal 0.3.0

embedded-hal driver for the XL9555 GPIO expander
Documentation
#[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,
            }
        }
    }
}