use crate::config::Config;
use core::convert::TryFrom;
const DEVICE_BASE_ADDRESS: u8 = 0b100_0000;
#[derive(Debug, Default)]
pub struct Pca9685<I2C> {
pub(crate) i2c: I2C,
pub(crate) address: u8,
pub(crate) config: Config,
}
#[derive(Debug)]
pub enum Error<E> {
I2C(E),
InvalidInputData,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Channel {
C0,
C1,
C2,
C3,
C4,
C5,
C6,
C7,
C8,
C9,
C10,
C11,
C12,
C13,
C14,
C15,
All,
}
macro_rules! match_channel {
($value:expr, $($v:expr, $C:ident),*) => {
match $value {
$(
$v => Ok(Channel::$C),
)*
_ => Err(()),
}
};
}
macro_rules! impl_try_from_for_channel {
($T:ty) => {
impl TryFrom<$T> for Channel {
type Error = ();
fn try_from(value: $T) -> Result<Self, Self::Error> {
match_channel!(
value, 0, C0, 1, C1, 2, C2, 3, C3, 4, C4, 5, C5, 6, C6, 7, C7, 8, C8, 9, C9,
10, C10, 11, C11, 12, C12, 13, C13, 14, C14, 15, C15
)
}
}
};
}
impl_try_from_for_channel!(u8);
impl_try_from_for_channel!(u16);
impl_try_from_for_channel!(usize);
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum OutputLogicState {
Direct,
Inverted,
}
impl Default for OutputLogicState {
fn default() -> Self {
OutputLogicState::Direct
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum OutputStateChange {
OnStop,
OnAck,
}
impl Default for OutputStateChange {
fn default() -> Self {
OutputStateChange::OnStop
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum OutputDriver {
TotemPole,
OpenDrain,
}
impl Default for OutputDriver {
fn default() -> Self {
OutputDriver::TotemPole
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum DisabledOutputValue {
Zero,
OutputDriver,
HighImpedance,
}
impl Default for DisabledOutputValue {
fn default() -> Self {
DisabledOutputValue::Zero
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ProgrammableAddress {
Subaddress1,
Subaddress2,
Subaddress3,
AllCall,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum SlaveAddr {
Default,
Alternative(bool, bool, bool, bool, bool, bool),
}
impl Default for SlaveAddr {
fn default() -> Self {
SlaveAddr::Default
}
}
impl SlaveAddr {
pub fn address(self) -> u8 {
match self {
SlaveAddr::Default => DEVICE_BASE_ADDRESS,
SlaveAddr::Alternative(a5, a4, a3, a2, a1, a0) => {
DEVICE_BASE_ADDRESS
| ((a5 as u8) << 5)
| ((a4 as u8) << 4)
| ((a3 as u8) << 3)
| ((a2 as u8) << 2)
| ((a1 as u8) << 1)
| a0 as u8
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
macro_rules! default_test {
($name:ident, $type:ident, $default:ident) => {
#[test]
fn $name() {
assert_eq!($type::$default, $type::default());
}
};
}
default_test!(default_out_logic_state, OutputLogicState, Direct);
default_test!(default_out_change, OutputStateChange, OnStop);
default_test!(default_out_driver, OutputDriver, TotemPole);
default_test!(default_disabled_out_value, DisabledOutputValue, Zero);
#[test]
fn can_get_default_address() {
let addr = SlaveAddr::default();
assert_eq!(DEVICE_BASE_ADDRESS, addr.address());
}
}