Skip to content

Commit

Permalink
fixed bus (#7)
Browse files Browse the repository at this point in the history
* fixed bus

* fmt and clippy
  • Loading branch information
FloppyDisck authored Dec 1, 2024
1 parent 85c18f6 commit 4c4adb4
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 126 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ embedded-hal = "1.0.0"
thiserror = { version = "2.0.3", default-features = false }

[dev-dependencies]
shared-bus = { version= "0.3.1", features=['std'] }
embedded-hal-bus = { version = "0.2.0", features = ["std"] }
embedded-hal-mock = "0.11.1"
rstest = "0.16.0"
229 changes: 119 additions & 110 deletions src/bus.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{address_from_pins, error::MultiplexerError, error::Result as CrateResult};
use embedded_hal::blocking::i2c::{Read, SevenBitAddress, Write, WriteRead};
use crate::address_from_pins;
use crate::prelude::MultiplexerError;
use embedded_hal::i2c::{ErrorType, I2c, Operation, SevenBitAddress};

pub struct MultiplexerBus {
address: u8,
Expand All @@ -22,7 +23,7 @@ impl MultiplexerBus {
self
}

pub fn new_port<I2C: 'static + Send + Sync>(&self, i2c: I2C, port: u8) -> BusPort<I2C> {
pub fn new_port<I2C>(&self, i2c: I2C, port: u8) -> BusPort<I2C> {
let id = match port {
0 => 0b000_0001,
1 => 0b000_0010,
Expand All @@ -38,83 +39,82 @@ impl MultiplexerBus {
}
}

pub struct BusPort<I2C: 'static + Send + Sync> {
pub struct BusPort<I2C> {
bus: I2C,
address: u8,
port: u8,
}

impl<I2C> BusPort<I2C>
where
I2C: Write + Send + Sync,
I2C: I2c,
{
fn open_port(&mut self) -> CrateResult<()> {
fn open_port(&mut self) -> Result<(), MultiplexerError<I2C::Error>> {
match self.bus.write(self.address, &[self.port]) {
Ok(res) => Ok(res),
Err(_) => Err(MultiplexerError::WriteI2CError),
Err(_) => Err(MultiplexerError::PortError),
}
}
}

impl<I2C> Write for BusPort<I2C>
impl<I2C> ErrorType for BusPort<I2C>
where
I2C: Write + Send + Sync,
I2C: I2c,
{
type Error = MultiplexerError;

fn write(&mut self, address: SevenBitAddress, bytes: &[u8]) -> Result<(), Self::Error> {
self.open_port()?;
match self.bus.write(address, bytes) {
Ok(res) => Ok(res),
Err(_) => Err(MultiplexerError::WriteI2CError),
}
}
type Error = MultiplexerError<I2C::Error>;
}

impl<I2C> Read for BusPort<I2C>
impl<I2C> I2c for BusPort<I2C>
where
I2C: Read + Write + Send + Sync,
I2C: I2c,
{
type Error = MultiplexerError;

fn read(&mut self, address: SevenBitAddress, bytes: &mut [u8]) -> Result<(), Self::Error> {
fn read(&mut self, address: SevenBitAddress, read: &mut [u8]) -> Result<(), Self::Error> {
self.open_port()?;
match self.bus.read(address, bytes) {
Ok(res) => Ok(res),
Err(_) => Err(MultiplexerError::ReadI2CError),
}
self.bus
.read(address, read)
.map_err(|err| MultiplexerError::I2CError(err))
}
}

impl<I2C> WriteRead for BusPort<I2C>
where
I2C: WriteRead + Write + Send + Sync,
{
type Error = MultiplexerError;
fn write(&mut self, address: SevenBitAddress, write: &[u8]) -> Result<(), Self::Error> {
self.open_port()?;
self.bus
.write(address, write)
.map_err(|err| MultiplexerError::I2CError(err))
}

fn write_read(
&mut self,
address: SevenBitAddress,
buffer_in: &[u8],
buffer_out: &mut [u8],
write: &[u8],
read: &mut [u8],
) -> Result<(), Self::Error> {
self.open_port()?;
match self.bus.write_read(address, buffer_in, buffer_out) {
Ok(res) => Ok(res),
Err(_) => Err(MultiplexerError::WriteReadI2CError),
}
self.bus
.write_read(address, write, read)
.map_err(|err| MultiplexerError::I2CError(err))
}

fn transaction(
&mut self,
address: SevenBitAddress,
operations: &mut [Operation<'_>],
) -> Result<(), Self::Error> {
self.open_port()?;
self.bus
.transaction(address, operations)
.map_err(|err| MultiplexerError::I2CError(err))
}
}

#[cfg(test)]
mod test {
extern crate alloc;
use crate::prelude::*;
use embedded_hal::prelude::{
_embedded_hal_blocking_i2c_Read, _embedded_hal_blocking_i2c_Write,
_embedded_hal_blocking_i2c_WriteRead,
};
use embedded_hal_mock::common::Generic;
use embedded_hal_mock::i2c::{Mock, Transaction};
use alloc::vec;
use core::cell::RefCell;
use embedded_hal::i2c::I2c;
use embedded_hal_bus::i2c::RefCellDevice;
use embedded_hal_mock::eh1::i2c::{Mock, Transaction};

#[test]
fn multi_port_write() {
Expand All @@ -140,25 +140,28 @@ mod test {
Transaction::write(component_addr, vec![0x45, 0x48]),
];

let i2c = Mock::new(&expectations);
let bus = shared_bus::new_std!(Generic<Transaction> = i2c).unwrap();
let i2c = RefCell::new(Mock::new(&expectations));
let multiplexer = MultiplexerBus::new().with_address(multiplexer_addr);

let mut multiplexed_i2c_a = multiplexer.new_port(bus.acquire_i2c(), ports[0].0);
let mut multiplexed_i2c_b = multiplexer.new_port(bus.acquire_i2c(), ports[1].0);
let mut multiplexed_i2c_c = multiplexer.new_port(bus.acquire_i2c(), ports[2].0);
let mut multiplexed_i2c_d = multiplexer.new_port(bus.acquire_i2c(), ports[3].0);

assert!(multiplexed_i2c_a
.write(component_addr, &[0x05, 0x43])
.is_ok());
assert!(multiplexed_i2c_b.write(component_addr, &[0x55]).is_ok());
assert!(multiplexed_i2c_c
.write(component_addr, &[0x07, 0x39, 0x87])
.is_ok());
assert!(multiplexed_i2c_d
.write(component_addr, &[0x45, 0x48])
.is_ok());
{
let mut multiplexed_i2c_a = multiplexer.new_port(RefCellDevice::new(&i2c), ports[0].0);
let mut multiplexed_i2c_b = multiplexer.new_port(RefCellDevice::new(&i2c), ports[1].0);
let mut multiplexed_i2c_c = multiplexer.new_port(RefCellDevice::new(&i2c), ports[2].0);
let mut multiplexed_i2c_d = multiplexer.new_port(RefCellDevice::new(&i2c), ports[3].0);

assert!(multiplexed_i2c_a
.write(component_addr, &[0x05, 0x43])
.is_ok());
assert!(multiplexed_i2c_b.write(component_addr, &[0x55]).is_ok());
assert!(multiplexed_i2c_c
.write(component_addr, &[0x07, 0x39, 0x87])
.is_ok());
assert!(multiplexed_i2c_d
.write(component_addr, &[0x45, 0x48])
.is_ok());
}

i2c.into_inner().done();
}

#[test]
Expand All @@ -185,30 +188,33 @@ mod test {
Transaction::read(component_addr, vec![0x45, 0x48]),
];

let i2c = Mock::new(&expectations);
let bus = shared_bus::new_std!(Generic<Transaction> = i2c).unwrap();
let i2c = RefCell::new(Mock::new(&expectations));
let multiplexer = MultiplexerBus::new().with_address(multiplexer_addr);

let mut multiplexed_i2c_a = multiplexer.new_port(bus.acquire_i2c(), ports[0].0);
let mut multiplexed_i2c_b = multiplexer.new_port(bus.acquire_i2c(), ports[1].0);
let mut multiplexed_i2c_c = multiplexer.new_port(bus.acquire_i2c(), ports[2].0);
let mut multiplexed_i2c_d = multiplexer.new_port(bus.acquire_i2c(), ports[3].0);
{
let mut multiplexed_i2c_a = multiplexer.new_port(RefCellDevice::new(&i2c), ports[0].0);
let mut multiplexed_i2c_b = multiplexer.new_port(RefCellDevice::new(&i2c), ports[1].0);
let mut multiplexed_i2c_c = multiplexer.new_port(RefCellDevice::new(&i2c), ports[2].0);
let mut multiplexed_i2c_d = multiplexer.new_port(RefCellDevice::new(&i2c), ports[3].0);

let mut ma = [0; 2];
assert!(multiplexed_i2c_a.read(component_addr, &mut ma).is_ok());
assert_eq!(ma, [0x05, 0x43]);

let mut ma = [0; 2];
assert!(multiplexed_i2c_a.read(component_addr, &mut ma).is_ok());
assert_eq!(ma, [0x05, 0x43]);
let mut mb = [0; 1];
assert!(multiplexed_i2c_b.read(component_addr, &mut mb).is_ok());
assert_eq!(mb, [0x55]);

let mut mb = [0; 1];
assert!(multiplexed_i2c_b.read(component_addr, &mut mb).is_ok());
assert_eq!(mb, [0x55]);
let mut mc = [0; 3];
assert!(multiplexed_i2c_c.read(component_addr, &mut mc).is_ok());
assert_eq!(mc, [0x07, 0x39, 0x87]);

let mut mc = [0; 3];
assert!(multiplexed_i2c_c.read(component_addr, &mut mc).is_ok());
assert_eq!(mc, [0x07, 0x39, 0x87]);
let mut md = [0; 2];
assert!(multiplexed_i2c_d.read(component_addr, &mut md).is_ok());
assert_eq!(md, [0x45, 0x48]);
}

let mut md = [0; 2];
assert!(multiplexed_i2c_d.read(component_addr, &mut md).is_ok());
assert_eq!(md, [0x45, 0x48]);
i2c.into_inner().done();
}

#[test]
Expand All @@ -235,37 +241,40 @@ mod test {
Transaction::write_read(component_addr, vec![0x45, 0x48], vec![0x33, 0x43]),
];

let i2c = Mock::new(&expectations);
let bus = shared_bus::new_std!(Generic<Transaction> = i2c).unwrap();
let i2c = RefCell::new(Mock::new(&expectations));
let multiplexer = MultiplexerBus::new().with_address(multiplexer_addr);

let mut multiplexed_i2c_a = multiplexer.new_port(bus.acquire_i2c(), ports[0].0);
let mut multiplexed_i2c_b = multiplexer.new_port(bus.acquire_i2c(), ports[1].0);
let mut multiplexed_i2c_c = multiplexer.new_port(bus.acquire_i2c(), ports[2].0);
let mut multiplexed_i2c_d = multiplexer.new_port(bus.acquire_i2c(), ports[3].0);

let mut ma = [0x33, 0x43];
assert!(multiplexed_i2c_a
.write_read(component_addr, &[0x05, 0x43], &mut ma)
.is_ok());
assert_eq!(ma, [0x33, 0x43]);

let mut mb = [0x33, 0x43];
assert!(multiplexed_i2c_b
.write_read(component_addr, &[0x55], &mut mb)
.is_ok());
assert_eq!(mb, [0x33, 0x43]);

let mut mc = [0x33, 0x43];
assert!(multiplexed_i2c_c
.write_read(component_addr, &[0x07, 0x39, 0x87], &mut mc)
.is_ok());
assert_eq!(mc, [0x33, 0x43]);

let mut md = [0x33, 0x43];
assert!(multiplexed_i2c_d
.write_read(component_addr, &[0x45, 0x48], &mut md)
.is_ok());
assert_eq!(md, [0x33, 0x43]);
{
let mut multiplexed_i2c_a = multiplexer.new_port(RefCellDevice::new(&i2c), ports[0].0);
let mut multiplexed_i2c_b = multiplexer.new_port(RefCellDevice::new(&i2c), ports[1].0);
let mut multiplexed_i2c_c = multiplexer.new_port(RefCellDevice::new(&i2c), ports[2].0);
let mut multiplexed_i2c_d = multiplexer.new_port(RefCellDevice::new(&i2c), ports[3].0);

let mut ma = [0x33, 0x43];
assert!(multiplexed_i2c_a
.write_read(component_addr, &[0x05, 0x43], &mut ma)
.is_ok());
assert_eq!(ma, [0x33, 0x43]);

let mut mb = [0x33, 0x43];
assert!(multiplexed_i2c_b
.write_read(component_addr, &[0x55], &mut mb)
.is_ok());
assert_eq!(mb, [0x33, 0x43]);

let mut mc = [0x33, 0x43];
assert!(multiplexed_i2c_c
.write_read(component_addr, &[0x07, 0x39, 0x87], &mut mc)
.is_ok());
assert_eq!(mc, [0x33, 0x43]);

let mut md = [0x33, 0x43];
assert!(multiplexed_i2c_d
.write_read(component_addr, &[0x45, 0x48], &mut md)
.is_ok());
assert_eq!(md, [0x33, 0x43]);
}

i2c.into_inner().done();
}
}
22 changes: 20 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use embedded_hal::i2c::{Error, ErrorKind};
use thiserror::Error;

pub type Result<T> = core::result::Result<T, MultiplexerError>;
pub type Result<T, I2cError> = core::result::Result<T, MultiplexerError<I2cError>>;

#[derive(Error, Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
pub enum MultiplexerError {
pub enum MultiplexerError<I2cError>
where
I2cError: Error,
{
#[error("Write Read I2C Error")]
WriteReadI2CError,
#[error("Write I2C Error")]
Expand All @@ -12,4 +16,18 @@ pub enum MultiplexerError {
ReadI2CError,
#[error("Incorrect port supplied")]
PortError,
#[error("I2C Error")]
I2CError(I2cError),
}

impl<I2cError> Error for MultiplexerError<I2cError>
where
I2cError: Error,
{
fn kind(&self) -> ErrorKind {
match self {
Self::I2CError(e) => e.kind(),
_ => ErrorKind::Other,
}
}
}
Loading

0 comments on commit 4c4adb4

Please sign in to comment.