1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
use crate::config::Config;
use core::convert::TryFrom;
const DEVICE_BASE_ADDRESS: u8 = 0b100_0000;

/// PCA9685 PWM/Servo/LED controller.
#[derive(Debug, Default)]
pub struct Pca9685<I2C> {
    /// The concrete I²C device implementation.
    pub(crate) i2c: I2C,
    /// The I²C device address.
    pub(crate) address: u8,
    /// Current device configuration.
    pub(crate) config: Config,
}

/// All possible errors in this crate
#[derive(Debug)]
pub enum Error<E> {
    /// I²C bus error
    I2C(E),
    /// Invalid input data provided
    InvalidInputData,
}

/// Output channel selection
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Channel {
    /// Channel 0
    C0,
    /// Channel 1
    C1,
    /// Channel 2
    C2,
    /// Channel 3
    C3,
    /// Channel 4
    C4,
    /// Channel 5
    C5,
    /// Channel 6
    C6,
    /// Channel 7
    C7,
    /// Channel 8
    C8,
    /// Channel 9
    C9,
    /// Channel 10
    C10,
    /// Channel 11
    C11,
    /// Channel 12
    C12,
    /// Channel 13
    C13,
    /// Channel 14
    C14,
    /// Channel 15
    C15,
    /// All channels
    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 = ();

            /// Will return an empty error for a value outside the range [0-15].
            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);

/// Output logic state inversion
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum OutputLogicState {
    /// Output logic state is not inverted (default).
    ///
    /// Value to set when external driver is used. Applicable when `OE = 0`.
    Direct,
    /// Output logic state is inverted.
    ///
    /// Value to set when no external driver is used. Applicable when `OE = 0`.
    Inverted,
}

impl Default for OutputLogicState {
    fn default() -> Self {
        OutputLogicState::Direct
    }
}

/// Output state change behavior
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum OutputStateChange {
    /// Outputs change on STOP. (default)
    ///
    /// This will update the outputs all at the same time.
    OnStop,
    /// Outputs change on ACK.
    ///
    /// This will update the outputs byte by byte.
    OnAck,
}

impl Default for OutputStateChange {
    fn default() -> Self {
        OutputStateChange::OnStop
    }
}

/// Output driver configuration
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum OutputDriver {
    /// Totem pole configuration (default).
    TotemPole,
    /// Open-drain configuration
    OpenDrain,
}

impl Default for OutputDriver {
    fn default() -> Self {
        OutputDriver::TotemPole
    }
}

/// Value set to all outputs when the output drivers are disabled (`OE` = 1).
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum DisabledOutputValue {
    /// Set all outputs to 0 (default).
    Zero,
    /// Set all outputs to a value dependent on the `OutputDriver` configuration.
    ///
    /// - Set all outputs to 1 for `OutputDriver::TotemPole`.
    /// - Set all outputs to high-impedance for `OutputDriver::OpenDrain`.
    OutputDriver,
    /// Set all outputs to high-impedance.
    HighImpedance,
}

impl Default for DisabledOutputValue {
    fn default() -> Self {
        DisabledOutputValue::Zero
    }
}

/// Additional programmable address types (volatile programming)
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ProgrammableAddress {
    /// Subaddress 1
    Subaddress1,
    /// Subaddress 2
    Subaddress2,
    /// Subaddress 3
    Subaddress3,
    /// LED all call address
    AllCall,
}

/// Possible slave addresses
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum SlaveAddr {
    /// Default slave address
    Default,
    /// Alternative slave address providing bit values for A5, A4, A3, A2, A1 and A0
    Alternative(bool, bool, bool, bool, bool, bool),
}

impl Default for SlaveAddr {
    /// Default slave address
    fn default() -> Self {
        SlaveAddr::Default
    }
}

impl SlaveAddr {
    /// Get the I2C slave address
    ///
    /// This is useful when switching between programmable addresses and the
    /// fixed hardware slave address.
    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());
    }
}