Skip to content

Commit

Permalink
[WIP] Sketch out an API for managing interrupts
Browse files Browse the repository at this point in the history
  • Loading branch information
Rahix committed Mar 31, 2024
1 parent ce29a1e commit 6331614
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,29 @@ pub trait PortDriverPullUp: PortDriver {
fn set_pull_up(&mut self, mask: u32, enable: bool) -> Result<(), Self::Error>;
}

pub trait PortDriverIrqChange: PortDriver {
/// Read which pins changed state since the last interrupt request.
///
/// This method should reset the pin-change state such that a consecutive call does not report
/// the same pins again.
fn fetch_interrupt_changed(&mut self) -> Result<u32, Self::Error>;
}


pub trait PortDriverIrqState: PortDriver {
/// Read the state of pins at the last interrupt request.
///
/// This method should reset the pin-change state such that a consecutive call does not report
/// the same pins again.
///
/// The return value is a tuple of
///
/// 1. The mask of pins that changed state (must be the same value that would have been
/// reported by fetch_interrupt_changed())
/// 2. For the changed pins, the individual state that was latched at change time.
fn fetch_interrupt_state(&mut self) -> Result<(u32, u32), Self::Error>;
}

/// Pin Modes
pub mod mode {
/// Trait for pin-modes which can be used to set a logic level.
Expand Down
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ pub use bus::I2cBus;
pub use common::mode;
pub use multi::read_multiple;
pub use multi::write_multiple;
pub use multi::fetch_pin_change;
pub use multi::fetch_interrupt_state;
pub use mutex::PortMutex;
pub use pin::Pin;

Expand All @@ -80,6 +82,8 @@ pub(crate) use common::PortDriverPolarity;
pub(crate) use common::PortDriverPullDown;
pub(crate) use common::PortDriverPullUp;
pub(crate) use common::PortDriverTotemPole;
pub(crate) use common::PortDriverIrqChange;
pub(crate) use common::PortDriverIrqState;

pub use dev::max7321::Max7321;
pub use dev::mcp23x17::Mcp23x17;
Expand Down
42 changes: 42 additions & 0 deletions src/multi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,48 @@ where
Ok(ret)
}

pub fn fetch_pin_change<PD, MUTEX, MODE: crate::mode::HasInput, const N: usize>(
pins: [&crate::Pin<'_, MODE, MUTEX>; N],
) -> Result<[bool; N], PD::Error>
where
PD: crate::PortDriver + crate::PortDriverIrqChange,
MUTEX: crate::PortMutex<Port = PD>,
{
let port_driver = pins[0].port_driver();
let mask_in = port_driver.lock(|drv| drv.fetch_interrupt_changed())?;

let mut ret = [false; N];
for (pin, state) in pins.iter().zip(ret.iter_mut()) {
assert!(core::ptr::eq(pin.port_driver(), port_driver));
*state = mask_in & pin.pin_mask() != 0;
}

Ok(ret)
}

pub fn fetch_interrupt_state<PD, MUTEX, MODE: crate::mode::HasInput, const N: usize>(
pins: [&crate::Pin<'_, MODE, MUTEX>; N],
) -> Result<[Option<bool>; N], PD::Error>
where
PD: crate::PortDriver + crate::PortDriverIrqState,
MUTEX: crate::PortMutex<Port = PD>,
{
let port_driver = pins[0].port_driver();
let (mask_changed, mask_state) = port_driver.lock(|drv| drv.fetch_interrupt_state())?;

let mut ret = [None; N];
for (pin, state) in pins.iter().zip(ret.iter_mut()) {
assert!(core::ptr::eq(pin.port_driver(), port_driver));
*state = if mask_changed & pin.pin_mask() != 0 {
Some(mask_state & pin.pin_mask() != 0)
} else {
None
};
}

Ok(ret)
}

#[cfg(test)]
mod tests {
use embedded_hal_mock::eh1::i2c as mock_i2c;
Expand Down

0 comments on commit 6331614

Please sign in to comment.