tildagon 0.0.2

Board support crate for the Electromagnetic Field Tildagon badge
use super::{
    aw9523b::{
        GpioDirection, PinMode, Port, Register, read_register, set_io_direction, set_pin_mode,
        write_register,
    },
    output::OutputPin,
    pin::{PinExt, TypeErasedPin},
};
use defmt::debug;
use embedded_hal::{digital::ErrorKind, i2c::I2c};

pub struct InputPin<I2C> {
    bus: I2C,
    pin: TypeErasedPin,
}

impl<I2C, E> InputPin<I2C>
where
    I2C: I2c<Error = E>,
{
    pub(crate) fn try_new(mut bus: I2C, pin: TypeErasedPin) -> Result<Self, E> {
        set_pin_mode(&mut bus, &pin, PinMode::Gpio)?;
        set_io_direction(&mut bus, &pin, GpioDirection::Input)?;
        Ok(Self { bus, pin })
    }

    pub fn into_output(self) -> Result<OutputPin<I2C>, E> {
        OutputPin::try_new(self.bus, self.pin)
    }

    pub fn set_interrupt(&mut self, enable: bool) -> Result<(), E> {
        let register = match self.pin.port() {
            Port::Port0 => Register::INT_P0,
            Port::Port1 => Register::INT_P1,
        };

        let value = read_register(&mut self.bus, self.pin.address(), register)?;

        let value = match enable {
            true => value & !self.pin.bit(),
            false => value | self.pin.bit(),
        };

        write_register(&mut self.bus, self.pin.address(), register, value)?;

        debug!("Set interrupt enable for pin {} to {}", self.pin, enable);
        Ok(())
    }
}

impl<I2C> embedded_hal::digital::ErrorType for InputPin<I2C> {
    type Error = ErrorKind;
}

impl<I2C, E> embedded_hal::digital::InputPin for InputPin<I2C>
where
    I2C: I2c<Error = E>,
{
    fn is_high(&mut self) -> Result<bool, Self::Error> {
        Ok(!self.is_low()?)
    }

    fn is_low(&mut self) -> Result<bool, Self::Error> {
        let register = match self.pin.port() {
            Port::Port0 => Register::INPUT_P0,
            Port::Port1 => Register::INPUT_P1,
        };

        let value = read_register(&mut self.bus, self.pin.address(), register)
            .map_err(|_| ErrorKind::Other)?;

        let is_low = value & self.pin.bit() == 0;

        debug!("Pin {} is low? {}", self.pin, is_low);
        Ok(is_low)
    }
}