#![no_std]
#![doc = include_str!("../README.md")]
use core::{future::Future, ops::DerefMut};
use embedded_hal::i2c::{ErrorType, I2c as _};
use embedded_hal_async::i2c::I2c as _;
pub const BASE_ADDRESS: u8 = 0x70;
pub trait MutexBase {
type Bus;
type Error;
fn new(v: Self::Bus) -> Self;
}
pub trait SyncMutex: MutexBase {
fn lock(&self) -> Result<impl DerefMut<Target = Self::Bus>, Self::Error>;
}
pub trait AsyncMutex: MutexBase {
fn lock(&self) -> impl Future<Output = Result<impl DerefMut<Target = Self::Bus>, Self::Error>>;
}
#[cfg(feature = "std")]
impl<T> MutexBase for std::sync::Mutex<T> {
type Bus = T;
type Error = ();
fn new(v: Self::Bus) -> Self {
Self::new(v)
}
}
#[cfg(feature = "std")]
impl<T> SyncMutex for std::sync::Mutex<T> {
fn lock(&self) -> Result<impl DerefMut<Target = Self::Bus>, Self::Error> {
self.lock().or(Err(()))
}
}
#[derive(Debug)]
pub enum Error<Mutex, Bus> {
Mutex(Mutex),
Bus(Bus),
}
impl<Mutex, Bus> embedded_hal::i2c::Error for Error<Mutex, Bus>
where
Mutex: core::fmt::Debug,
Bus: embedded_hal::i2c::Error,
{
fn kind(&self) -> embedded_hal::i2c::ErrorKind {
match self {
Error::Mutex(_) => embedded_hal::i2c::ErrorKind::Overrun,
Error::Bus(e) => e.kind(),
}
}
}
pub struct Pca9548a<Mutex> {
bus: Mutex,
address: u8,
}
impl<Mutex: MutexBase> Pca9548a<Mutex> {
pub fn new(bus: Mutex::Bus, address: u8) -> Self {
Self {
bus: Mutex::new(bus),
address,
}
}
pub fn subbus(&self, mask: u8) -> SubBus<'_, Mutex> {
SubBus { pca: self, mask }
}
pub fn single_subbus(&self, id: u8) -> SubBus<'_, Mutex> {
assert!(id < 8);
self.subbus(1 << id)
}
}
impl<Mutex: AsyncMutex> Pca9548a<Mutex> {
pub async fn bus_async(&self) -> Result<impl DerefMut<Target = Mutex::Bus> + '_, Mutex::Error> {
self.bus.lock().await
}
}
impl<Mutex: SyncMutex> Pca9548a<Mutex> {
pub fn bus(&self) -> Result<impl DerefMut<Target = Mutex::Bus> + '_, Mutex::Error> {
self.bus.lock()
}
}
impl<Mutex: AsyncMutex> Pca9548a<Mutex>
where
Mutex::Bus: embedded_hal_async::i2c::I2c,
{
pub async fn select_mask_async(
&self,
mask: u8,
) -> Result<
impl DerefMut<Target = Mutex::Bus> + '_,
Error<Mutex::Error, <Mutex::Bus as ErrorType>::Error>,
> {
let mut bus = self.bus_async().await.map_err(Error::Mutex)?;
bus.write(self.address, &[mask]).await.map_err(Error::Bus)?;
Ok(bus)
}
pub async fn select_single_async(
&self,
id: u8,
) -> Result<
impl DerefMut<Target = Mutex::Bus> + '_,
Error<Mutex::Error, <Mutex::Bus as ErrorType>::Error>,
> {
assert!(id < 8);
self.select_mask_async(1 << id).await
}
}
impl<Mutex: SyncMutex> Pca9548a<Mutex>
where
Mutex::Bus: embedded_hal::i2c::I2c,
{
pub fn select_mask(
&self,
mask: u8,
) -> Result<
impl DerefMut<Target = Mutex::Bus> + '_,
Error<Mutex::Error, <Mutex::Bus as ErrorType>::Error>,
> {
let mut bus = self.bus().map_err(Error::Mutex)?;
bus.write(self.address, &[mask]).map_err(Error::Bus)?;
Ok(bus)
}
pub fn select_single(
&self,
id: u8,
) -> Result<
impl DerefMut<Target = Mutex::Bus> + '_,
Error<Mutex::Error, <Mutex::Bus as ErrorType>::Error>,
> {
assert!(id < 8);
self.select_mask(1 << id)
}
}
pub struct SubBus<'a, Mutex> {
pca: &'a Pca9548a<Mutex>,
mask: u8,
}
impl<'a, Mutex> embedded_hal::i2c::ErrorType for SubBus<'a, Mutex>
where
Mutex: MutexBase,
Mutex::Error: core::fmt::Debug,
Mutex::Bus: embedded_hal::i2c::ErrorType,
{
type Error = Error<Mutex::Error, <Mutex::Bus as ErrorType>::Error>;
}
impl<'a, Mutex> SubBus<'a, Mutex>
where
Mutex: AsyncMutex,
Mutex::Bus: embedded_hal_async::i2c::I2c,
{
pub async fn select_async(
&self,
) -> Result<
impl DerefMut<Target = Mutex::Bus> + '_,
Error<Mutex::Error, <Mutex::Bus as ErrorType>::Error>,
> {
self.pca.select_mask_async(self.mask).await
}
}
impl<'a, Mutex> embedded_hal_async::i2c::I2c for SubBus<'a, Mutex>
where
Mutex: AsyncMutex,
Mutex::Error: core::fmt::Debug,
Mutex::Bus: embedded_hal_async::i2c::I2c,
{
async fn transaction(
&mut self,
address: u8,
operations: &mut [embedded_hal::i2c::Operation<'_>],
) -> Result<(), Self::Error> {
self.select_async()
.await?
.transaction(address, operations)
.await
.map_err(Error::Bus)
}
}
impl<'a, Mutex> SubBus<'a, Mutex>
where
Mutex: SyncMutex,
Mutex::Bus: embedded_hal::i2c::I2c,
{
pub fn select(
&self,
) -> Result<
impl DerefMut<Target = Mutex::Bus> + '_,
Error<Mutex::Error, <Mutex::Bus as ErrorType>::Error>,
> {
self.pca.select_mask(self.mask)
}
}
impl<'a, Mutex> embedded_hal::i2c::I2c for SubBus<'a, Mutex>
where
Mutex: SyncMutex,
Mutex::Error: core::fmt::Debug,
Mutex::Bus: embedded_hal::i2c::I2c,
{
fn transaction(
&mut self,
address: u8,
operations: &mut [embedded_hal::i2c::Operation<'_>],
) -> Result<(), Self::Error> {
self.select()?
.transaction(address, operations)
.map_err(Error::Bus)
}
}