#![deny(unsafe_code)]
#![deny(missing_docs)]
#![no_std]
extern crate embedded_hal as hal;
use hal::blocking::i2c;
#[derive(Debug)]
pub enum Error<E> {
I2C(E),
}
#[derive(Debug, Clone)]
pub enum SlaveAddr {
Default,
Alternative(bool, bool, bool)
}
impl Default for SlaveAddr {
fn default() -> Self {
SlaveAddr::Default
}
}
impl SlaveAddr {
fn addr(self, default: u8) -> u8 {
match self {
SlaveAddr::Default => default,
SlaveAddr::Alternative(a2, a1, a0) => default |
((a2 as u8) << 2) |
((a1 as u8) << 1) |
a0 as u8
}
}
}
const DEVICE_BASE_ADDRESS: u8 = 0b111_0000;
macro_rules! device {
( $($device_name:ident),+ ) => {
$(
#[derive(Debug, Default)]
pub struct $device_name<I2C> {
i2c: I2C,
address: u8,
}
impl<I2C, E> $device_name<I2C>
where
I2C: i2c::Write<Error = E>
{
pub fn new(i2c: I2C, address: SlaveAddr) -> Self {
$device_name {
i2c,
address: address.addr(DEVICE_BASE_ADDRESS),
}
}
pub fn destroy(self) -> I2C {
self.i2c
}
pub fn select_channels(&mut self, channels: u8) -> Result<(), Error<E>> {
self.i2c
.write(DEVICE_BASE_ADDRESS, &[channels])
.map_err(Error::I2C)
}
}
impl<I2C, E> $device_name<I2C>
where
I2C: i2c::Read<Error = E>
{
pub fn get_channel_status(&mut self) -> Result<u8, Error<E>> {
let mut data = [0];
self.i2c
.read(DEVICE_BASE_ADDRESS, &mut data)
.map_err(Error::I2C)
.and(Ok(data[0]))
}
}
impl<I2C, E> i2c::Write for $device_name<I2C>
where
I2C: i2c::Write<Error = E> {
type Error = E;
fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> {
self.i2c.write(address, bytes)
}
}
impl<I2C, E> i2c::Read for $device_name<I2C>
where
I2C: i2c::Read<Error = E> {
type Error = E;
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
self.i2c.read(address, buffer)
}
}
impl<I2C, E> i2c::WriteRead for $device_name<I2C>
where
I2C: i2c::WriteRead<Error = E> {
type Error = E;
fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> {
self.i2c.write_read(address, bytes, buffer)
}
}
)*
}
}
device!(TCA9548A, PCA9548A);
#[cfg(test)]
mod tests {
extern crate embedded_hal_mock as hal;
use super::*;
#[test]
fn can_get_default_address() {
let addr = SlaveAddr::default();
assert_eq!(DEVICE_BASE_ADDRESS, addr.addr(DEVICE_BASE_ADDRESS));
}
#[test]
fn can_generate_alternative_addresses() {
assert_eq!(0b111_0000, SlaveAddr::Alternative(false, false, false).addr(DEVICE_BASE_ADDRESS));
assert_eq!(0b111_0001, SlaveAddr::Alternative(false, false, true).addr(DEVICE_BASE_ADDRESS));
assert_eq!(0b111_0010, SlaveAddr::Alternative(false, true, false).addr(DEVICE_BASE_ADDRESS));
assert_eq!(0b111_0100, SlaveAddr::Alternative( true, false, false).addr(DEVICE_BASE_ADDRESS));
assert_eq!(0b111_0111, SlaveAddr::Alternative( true, true, true).addr(DEVICE_BASE_ADDRESS));
}
}