improve mcp23017 task

This commit is contained in:
2025-09-21 10:00:58 -07:00
parent 6d3fbb926e
commit e8f91d0d75
10 changed files with 324 additions and 120 deletions

View File

@@ -1,96 +1,23 @@
use crate::hardware::error::I2cError;
use anyhow::{bail, Result};
use embedded_hal::i2c::I2c;
use log::{info, trace};
use std::fmt::{Debug, Formatter};
use std::time::Instant;
mod pin;
mod driver;
mod task;
use anyhow::Result;
use embedded_hal::digital::PinState;
pub trait Mcp23017 {
fn init(&mut self) -> Result<()>;
fn set_pin(&mut self, pin: u8, value: bool) -> Result<()>;
fn flush(&mut self) -> Result<()>;
fn new_output_pin(&self, pin: u8) -> Result<impl Mcp23017OutputPin>;
fn flush(&self) -> Result<()>;
}
pub struct Mcp23017Driver<I2C> {
i2c: I2C,
address: u8,
bank: [u8; 2],
dirty: bool,
pub trait Mcp23017OutputPin {
fn set_state(&mut self, pin_state: PinState);
fn set_state_on_drop(&mut self, pin_state: PinState);
}
impl<I2C> Debug for Mcp23017Driver<I2C> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Mcp23017Driver {{ address: {} }}", self.address)
}
}
impl<I2C> Mcp23017Driver<I2C>
where
I2C: I2c,
I2C::Error: Send,
I2C::Error: Sync,
I2C::Error: 'static,
{
pub fn new(i2c: I2C, address: u8) -> Self {
trace!("Mcp23017Driver::new(i2c, address: {address:07b})");
Self {
i2c,
address,
bank: [0u8; _],
dirty: false,
}
}
}
impl<I2C> Mcp23017 for Mcp23017Driver<I2C>
where
I2C: I2c,
I2C::Error: Send,
I2C::Error: Sync,
I2C::Error: 'static,
{
fn init(&mut self) -> Result<()> {
trace!("Mcp23017Driver::init(self: {self:?})");
// Set each pin as an output (Addresses 0x00 & 0x01)
let data: [u8; _] = [0x00, 0x00, 0x00];
self.i2c.write(self.address, &data).map_err(I2cError)?;
Ok(())
}
fn set_pin(&mut self, pin: u8, value: bool) -> Result<()> {
trace!("Mcp23017Driver::set_pin(self: {self:?}, pin: {pin}, value: {value})");
let (pin_bank, dirty_flag, pin_index) = match pin {
0..8 => {
(&mut self.bank[0], &mut self.dirty, pin as u32)
}
8..16 => {
(&mut self.bank[1], &mut self.dirty, (pin as u32) - 8)
}
_ => bail!("Invalid Pin ID"),
};
let pin_mask = 1u8.unbounded_shl(pin_index);
let initial = *pin_bank;
if value {
*pin_bank |= pin_mask;
} else {
*pin_bank &= !pin_mask;
}
let result = *pin_bank;
if initial != result {
*dirty_flag = true;
}
Ok(())
}
fn flush(&mut self) -> Result<()> {
trace!("Mcp23017Driver::flush(self: {self:?})");
if self.dirty {
let data: [u8; _] = [0x12, self.bank[0], self.bank[1]];
// This blocks while writing
self.i2c.write(self.address, &data).map_err(I2cError)?;
}
Ok(())
}
}
pub use driver::Mcp23017Driver;
pub use task::Mcp23017Task;