Skip to content

Commit

Permalink
#4: Migrated to embedded-hal v1
Browse files Browse the repository at this point in the history
  • Loading branch information
marius-meissner committed Dec 18, 2024
1 parent f96a49d commit 679ee25
Show file tree
Hide file tree
Showing 10 changed files with 282 additions and 220 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ readme = "README.md"
documentation = "https://docs.rs/pca9539"

[dependencies]
embedded-hal = { version = "0.2.7", features = ["unproven"] }
embedded-hal = { version = "1.0.0" }
bitmaps = { version = "3.1.0", default-features = false }
cortex-m = { version = "0.7.4", optional = true }
spin = { version = "0.9.8", optional = true }
Expand Down
38 changes: 22 additions & 16 deletions src/example.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,37 @@
//! Dummy I2C bus for examples
use core::convert::Infallible;
use embedded_hal::blocking::i2c::{Read, SevenBitAddress, Write};
use embedded_hal::i2c::{ErrorType, I2c, Operation, SevenBitAddress};

#[derive(Default)]
pub struct DummyI2CBus {
/// Command byte of last write operation
previous_register: u8,
}

impl Write for DummyI2CBus {
impl ErrorType for DummyI2CBus {
type Error = Infallible;

fn write(&mut self, _address: SevenBitAddress, _bytes: &[u8]) -> Result<(), Self::Error> {
self.previous_register = _bytes[0];
Ok(())
}
}

impl Read for DummyI2CBus {
type Error = Infallible;

fn read(&mut self, _address: SevenBitAddress, buffer: &mut [u8]) -> Result<(), Self::Error> {
match self.previous_register {
0x00 => buffer[0] = 0b0010_0110,
0x01 => buffer[0] = 0b1110_0101,
_ => {}
};
impl I2c<SevenBitAddress> for DummyI2CBus {
fn transaction(
&mut self,
_address: SevenBitAddress,
operations: &mut [Operation<'_>],
) -> Result<(), Self::Error> {
for operation in operations {
match operation {
Operation::Read(data) => {
match self.previous_register {
0x00 => data[0] = 0b0010_0110,
0x01 => data[0] = 0b1110_0101,
_ => {}
};
}
Operation::Write(data) => {
self.previous_register = data[0];
}
}
}

Ok(())
}
Expand Down
37 changes: 22 additions & 15 deletions src/expander.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ use core::cell::RefCell;
use core::fmt::{Debug, Formatter};
#[cfg(feature = "cortex-m")]
use cortex_m::interrupt::Mutex as CsMutex;
use embedded_hal::blocking::i2c::{Read, SevenBitAddress, Write};
use embedded_hal::digital::ErrorKind;
use embedded_hal::i2c::{I2c, SevenBitAddress};
use heapless::String;
#[cfg(feature = "spin")]
use spin::Mutex as SpinMutex;
Expand Down Expand Up @@ -129,7 +130,7 @@ pub enum Mode {
/// Abstraction of [PCA9539](<https://www.ti.com/lit/ds/symlink/pca9539.pdf?ts=1649342250975>) I/O expander
pub struct PCA9539<B>
where
B: Write<SevenBitAddress> + Read<SevenBitAddress>,
B: I2c<SevenBitAddress>,
{
bus: B,

Expand Down Expand Up @@ -164,9 +165,9 @@ where

/// Wrapped I2C error when refreshing input state
/// Reading input state consists of one write, followed by a read operation
pub enum RefreshInputError<B: Write + Read<u8>> {
WriteError(<B as Write>::Error),
ReadError(<B as Read>::Error),
pub enum RefreshInputError<B: I2c<SevenBitAddress>> {
WriteError(B::Error),
ReadError(B::Error),
}

const COMMAND_INPUT_0: u8 = 0x00;
Expand All @@ -183,7 +184,7 @@ const COMMAND_CONF_1: u8 = 0x07;

impl<B> PCA9539<B>
where
B: Write<SevenBitAddress> + Read<SevenBitAddress>,
B: I2c<SevenBitAddress>,
{
pub fn new(bus: B, address: u8) -> Self {
let mut expander = Self {
Expand Down Expand Up @@ -232,7 +233,7 @@ where
}

/// Switches the given pin to the input/output mode by adjusting the configuration register
pub fn set_mode(&mut self, bank: Bank, id: PinID, mode: Mode) -> Result<(), <B as Write>::Error> {
pub fn set_mode(&mut self, bank: Bank, id: PinID, mode: Mode) -> Result<(), B::Error> {
match bank {
Bank::Bank0 => self.configuration_0.set(id as usize, mode.into()),
Bank::Bank1 => self.configuration_1.set(id as usize, mode.into()),
Expand All @@ -241,7 +242,7 @@ where
}

/// Switches all pins of the given bank to output/input mode1
pub fn set_mode_all(&mut self, bank: Bank, mode: Mode) -> Result<(), <B as Write>::Error> {
pub fn set_mode_all(&mut self, bank: Bank, mode: Mode) -> Result<(), B::Error> {
let mut bitset = Bitmap::<8>::new();

if mode == Mode::Input {
Expand All @@ -267,7 +268,7 @@ where
}

/// Sets output state for all pins of a bank
pub fn set_state_all(&mut self, bank: Bank, is_high: bool) -> Result<(), <B as Write>::Error> {
pub fn set_state_all(&mut self, bank: Bank, is_high: bool) -> Result<(), B::Error> {
let mut bitset = Bitmap::<8>::new();

if is_high {
Expand All @@ -282,7 +283,7 @@ where
}

/// Reveres/Resets the input polarity of the given pin
pub fn reverse_polarity(&mut self, bank: Bank, id: PinID, reversed: bool) -> Result<(), <B as Write>::Error> {
pub fn reverse_polarity(&mut self, bank: Bank, id: PinID, reversed: bool) -> Result<(), B::Error> {
match bank {
Bank::Bank0 => self.polarity_0.set(id as usize, reversed),
Bank::Bank1 => self.polarity_1.set(id as usize, reversed),
Expand Down Expand Up @@ -332,7 +333,7 @@ where
}

/// Writes the configuration register of the given bank
fn write_conf(&mut self, bank: Bank) -> Result<(), <B as Write>::Error> {
fn write_conf(&mut self, bank: Bank) -> Result<(), B::Error> {
match bank {
Bank::Bank0 => self
.bus
Expand All @@ -344,15 +345,15 @@ where
}

/// Writes the output register of the given bank
pub fn write_output_state(&mut self, bank: Bank) -> Result<(), <B as Write>::Error> {
pub fn write_output_state(&mut self, bank: Bank) -> Result<(), B::Error> {
match bank {
Bank::Bank0 => self.bus.write(self.address, &[COMMAND_OUTPUT_0, *self.output_0.as_value()]),
Bank::Bank1 => self.bus.write(self.address, &[COMMAND_OUTPUT_1, *self.output_1.as_value()]),
}
}

/// Writes the polarity register of the given bank
fn write_polarity(&mut self, bank: Bank) -> Result<(), <B as Write>::Error> {
fn write_polarity(&mut self, bank: Bank) -> Result<(), B::Error> {
match bank {
Bank::Bank0 => self.bus.write(self.address, &[COMMAND_POLARITY_0, *self.polarity_0.as_value()]),
Bank::Bank1 => self.bus.write(self.address, &[COMMAND_POLARITY_1, *self.polarity_1.as_value()]),
Expand All @@ -369,7 +370,7 @@ impl From<Mode> for bool {
}
}

impl<B: Read<u8> + Write> Debug for RefreshInputError<B> {
impl<B: I2c> Debug for RefreshInputError<B> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
RefreshInputError::WriteError(_) => f.write_str("RefreshInputError::WriteError"),
Expand All @@ -378,11 +379,17 @@ impl<B: Read<u8> + Write> Debug for RefreshInputError<B> {
}
}

impl<B: Read<u8> + Write> RefreshInputError<B> {
impl<B: I2c> RefreshInputError<B> {
pub fn to_string(&self) -> String<10> {
match self {
RefreshInputError::WriteError(_) => String::try_from("WriteError").unwrap(),
RefreshInputError::ReadError(_) => String::try_from("ReadError").unwrap(),
}
}
}

impl<B: I2c> embedded_hal::digital::Error for RefreshInputError<B> {
fn kind(&self) -> ErrorKind {
ErrorKind::Other
}
}
22 changes: 11 additions & 11 deletions src/guard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@
use crate::expander::PCA9539;
use core::cell::RefCell;
use core::ops::DerefMut;
use embedded_hal::blocking::i2c::{Read, Write};

/// Manages the access of pins to expander reference
pub trait RefGuard<B>
where
B: Write + Read<u8>,
B: I2c<SevenBitAddress>,
{
fn access<F>(&self, f: F)
where
Expand All @@ -20,20 +19,20 @@ where
/// Guard which is neither Send or Sync, but is the most efficient
pub struct LockFreeGuard<'a, B>
where
B: Write + Read,
B: I2c<SevenBitAddress>,
{
expander: RefCell<&'a mut PCA9539<B>>,
}

impl<'a, B: Write + Read> LockFreeGuard<'a, B> {
impl<'a, B: I2c<SevenBitAddress>> LockFreeGuard<'a, B> {
pub fn new(expander: RefCell<&'a mut PCA9539<B>>) -> Self {
LockFreeGuard { expander }
}
}

impl<B> RefGuard<B> for LockFreeGuard<'_, B>
where
B: Write + Read<u8>,
B: I2c<SevenBitAddress>,
{
fn access<F>(&self, mut f: F)
where
Expand All @@ -45,18 +44,19 @@ where

#[cfg(feature = "cortex-m")]
use cortex_m::interrupt::Mutex as CsMutex;
use embedded_hal::i2c::{I2c, SevenBitAddress};

/// Guard bases on Cortex-M mutex, which is using critical sections internally
#[cfg(feature = "cortex-m")]
pub struct CsMutexGuard<'a, B>
where
B: Write + Read<u8>,
B: I2c<SevenBitAddress>,
{
expander: CsMutex<RefCell<&'a mut PCA9539<B>>>,
}

#[cfg(feature = "cortex-m")]
impl<'a, B: Write + Read> CsMutexGuard<'a, B> {
impl<'a, B: I2c<SevenBitAddress>> CsMutexGuard<'a, B> {
pub fn new(expander: CsMutex<RefCell<&'a mut PCA9539<B>>>) -> Self {
CsMutexGuard { expander }
}
Expand All @@ -65,7 +65,7 @@ impl<'a, B: Write + Read> CsMutexGuard<'a, B> {
#[cfg(feature = "cortex-m")]
impl<B> RefGuard<B> for CsMutexGuard<'_, B>
where
B: Write + Read<u8>,
B: I2c<SevenBitAddress>,
{
fn access<F>(&self, mut f: F)
where
Expand All @@ -83,13 +83,13 @@ use spin::Mutex as SpinMutex;
#[cfg(feature = "spin")]
pub struct SpinGuard<'a, B>
where
B: Write + Read<u8>,
B: I2c<SevenBitAddress>,
{
expander: SpinMutex<RefCell<&'a mut PCA9539<B>>>,
}

#[cfg(feature = "spin")]
impl<'a, B: Write + Read> SpinGuard<'a, B> {
impl<'a, B: I2c<SevenBitAddress>> SpinGuard<'a, B> {
pub fn new(expander: SpinMutex<RefCell<&'a mut PCA9539<B>>>) -> Self {
SpinGuard { expander }
}
Expand All @@ -98,7 +98,7 @@ impl<'a, B: Write + Read> SpinGuard<'a, B> {
#[cfg(feature = "spin")]
impl<B> RefGuard<B> for SpinGuard<'_, B>
where
B: Write + Read<u8>,
B: I2c<SevenBitAddress>,
{
fn access<F>(&self, mut f: F)
where
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
//! use pca9539::expander::Bank::Bank0;
//! use pca9539::expander::PCA9539;
//! use pca9539::expander::PinID::Pin1;
//! use embedded_hal::digital::v2::InputPin;
//! use embedded_hal::digital::InputPin;
//!
//! let i2c_bus = DummyI2CBus::default();
//! let mut expander = PCA9539::new(i2c_bus, 0x74);
//! let pins = expander.pins();
//!
//! let pin01 = pins.get_pin(Bank0, Pin1);
//! let mut pin01 = pins.get_pin(Bank0, Pin1);
//! assert!(pin01.is_high().unwrap());
#![cfg_attr(not(test), no_std)]
#![cfg_attr(feature = "strict", deny(warnings))]
Expand Down
Loading

0 comments on commit 679ee25

Please sign in to comment.