Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,28 @@ 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 @@ -67,6 +67,8 @@ mod pin;

pub use bus::I2cBus;
pub use common::mode;
pub use multi::fetch_interrupt_state;
pub use multi::fetch_pin_change;
pub use multi::read_multiple;
pub use multi::write_multiple;
pub use mutex::PortMutex;
Expand All @@ -76,6 +78,8 @@ pub(crate) use bus::I2cExt;
pub(crate) use bus::SpiBus;
pub(crate) use common::Direction;
pub(crate) use common::PortDriver;
pub(crate) use common::PortDriverIrqChange;
pub(crate) use common::PortDriverIrqState;
pub(crate) use common::PortDriverPolarity;
pub(crate) use common::PortDriverPullDown;
pub(crate) use common::PortDriverPullUp;
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