#![no_std]
use bit_field::BitField;
use embedded_hal::blocking::i2c::{Write, WriteRead};
use num_enum::TryFromPrimitive;
#[derive(Debug, Copy, Clone)]
pub enum Error<E> {
BusError(E),
}
impl<E> From<E> for Error<E> {
fn from(error: E) -> Self {
Error::BusError(error)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Direction {
Input = 1,
Output = 0,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Level {
High = 1,
Low = 0,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, Default)]
#[repr(u8)]
pub enum Pin {
#[default]
P00 = 0,
P01 = 1,
P02 = 2,
P03 = 3,
P04 = 4,
P05 = 5,
P06 = 6,
P07 = 7,
P10 = 8,
P11 = 9,
P12 = 10,
P13 = 11,
P14 = 12,
P15 = 13,
P16 = 14,
P17 = 15,
}
#[derive(Clone, Copy, Debug)]
pub struct Pca9539<I2C> {
i2c: I2C,
address: u8,
}
impl<I2C, E> Pca9539<I2C>
where
I2C: WriteRead<Error = E> + Write<Error = E>,
{
const DEFAULT_ADDRESS: u8 = 0x74;
pub fn new_default(i2c: I2C) -> Result<Self, Error<E>> {
Self::new(i2c, Self::DEFAULT_ADDRESS)
}
pub fn new(i2c: I2C, address: u8) -> Result<Self, Error<E>> {
Ok(Self { i2c, address })
}
pub fn address(&self) -> u8 {
self.address
}
pub fn read(&mut self, addr: u8) -> Result<u8, E> {
let mut data = [0u8];
self.i2c.write_read(self.address, &[addr], &mut data)?;
Ok(data[0])
}
pub fn write(&mut self, addr: u8, data: u8) -> Result<(), E> {
self.i2c.write(self.address, &[addr, data])
}
pub fn bit(&mut self, addr: u8, bit: usize) -> Result<bool, E> {
let data = self.read(addr)?;
Ok(data.get_bit(bit))
}
pub fn set_bit(&mut self, addr: u8, bit: usize, value: bool) -> Result<(), E> {
let mut data = self.read(addr)?;
data.set_bit(bit, value);
self.write(addr, data)
}
pub fn set_level(&mut self, pin: Pin, level: Level) -> Result<(), E> {
let pin = pin as u8;
self.set_bit(0x02 | (pin >> 3), pin as usize & 7, level == Level::High)
}
pub fn set_direction(&mut self, pin: Pin, direction: Direction) -> Result<(), E> {
let pin = pin as u8;
self.set_bit(
0x06 | (pin >> 3),
pin as usize & 7,
direction == Direction::Input,
)
}
}