1use crate::config::Config;
2use core::convert::TryFrom;
3use core::fmt::{Display, Formatter};
4
5#[cfg(feature = "std")]
6extern crate std;
7
8const DEVICE_BASE_ADDRESS: u8 = 0b100_0000;
9
10#[derive(Debug)]
12pub struct Pca9685<I2C> {
13 pub(crate) i2c: I2C,
15 pub(crate) address: u8,
17 pub(crate) config: Config,
19}
20
21#[derive(Debug, PartialEq, Eq)]
23pub enum Error<E> {
24 I2C(E),
26 InvalidInputData,
28}
29
30impl<E: Display> Display for Error<E> {
32 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
33 match self {
34 Error::I2C(e) => write!(f, "I²C bus error: {}", e),
35 Error::InvalidInputData => write!(f, "Invalid input data provided"),
36 }
37 }
38}
39
40#[cfg(feature = "std")]
41impl<E: std::error::Error> std::error::Error for Error<E> {}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
45pub enum Channel {
46 C0,
48 C1,
50 C2,
52 C3,
54 C4,
56 C5,
58 C6,
60 C7,
62 C8,
64 C9,
66 C10,
68 C11,
70 C12,
72 C13,
74 C14,
76 C15,
78 All,
80}
81macro_rules! match_channel {
82 ($value:expr, $($v:expr, $C:ident),*) => {
83 match $value {
84 $(
85 $v => Ok(Channel::$C),
86 )*
87 _ => Err(()),
88 }
89 };
90}
91
92macro_rules! impl_try_from_for_channel {
93 ($T:ty) => {
94 impl TryFrom<$T> for Channel {
95 type Error = ();
96
97 fn try_from(value: $T) -> Result<Self, Self::Error> {
99 match_channel!(
100 value, 0, C0, 1, C1, 2, C2, 3, C3, 4, C4, 5, C5, 6, C6, 7, C7, 8, C8, 9, C9,
101 10, C10, 11, C11, 12, C12, 13, C13, 14, C14, 15, C15
102 )
103 }
104 }
105 };
106}
107impl_try_from_for_channel!(u8);
108impl_try_from_for_channel!(u16);
109impl_try_from_for_channel!(usize);
110
111#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
113pub enum OutputLogicState {
114 #[default]
118 Direct,
119 Inverted,
123}
124
125#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
127pub enum OutputStateChange {
128 #[default]
132 OnStop,
133 OnAck,
137}
138
139#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
141pub enum OutputDriver {
142 #[default]
144 TotemPole,
145 OpenDrain,
147}
148
149#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
151pub enum DisabledOutputValue {
152 #[default]
154 Zero,
155 OutputDriver,
160 HighImpedance,
162}
163
164#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
166pub enum ProgrammableAddress {
167 Subaddress1,
169 Subaddress2,
171 Subaddress3,
173 AllCall,
175}
176
177#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
179pub struct Address(pub(crate) u8);
180
181impl Default for Address {
183 fn default() -> Self {
184 Address(DEVICE_BASE_ADDRESS)
185 }
186}
187
188impl From<u8> for Address {
190 fn from(a: u8) -> Self {
191 Address(a)
192 }
193}
194
195impl From<(bool, bool, bool, bool, bool, bool)> for Address {
197 fn from(a: (bool, bool, bool, bool, bool, bool)) -> Self {
198 Address(
199 DEVICE_BASE_ADDRESS
200 | ((a.0 as u8) << 5)
201 | ((a.1 as u8) << 4)
202 | ((a.2 as u8) << 3)
203 | ((a.3 as u8) << 2)
204 | ((a.4 as u8) << 1)
205 | a.5 as u8,
206 )
207 }
208}
209
210#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
212pub struct ChannelOnOffControl {
213 pub on: u16,
215 pub off: u16,
217 pub full_on: bool,
219 pub full_off: bool,
221}
222
223#[cfg(test)]
224mod tests {
225 use super::*;
226
227 macro_rules! default_test {
228 ($name:ident, $type:ident, $default:ident) => {
229 #[test]
230 fn $name() {
231 assert_eq!($type::$default, $type::default());
232 }
233 };
234 }
235
236 default_test!(default_out_logic_state, OutputLogicState, Direct);
237 default_test!(default_out_change, OutputStateChange, OnStop);
238 default_test!(default_out_driver, OutputDriver, TotemPole);
239 default_test!(default_disabled_out_value, DisabledOutputValue, Zero);
240
241 #[test]
242 fn can_get_default_address() {
243 let addr = Address::default();
244 assert_eq!(DEVICE_BASE_ADDRESS, addr.0);
245 }
246}
247
248#[cfg(all(test, feature = "std"))]
249mod std_tests {
250 use super::*;
251 use std::format;
252
253 struct TestError;
254 impl Display for TestError {
255 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
256 write!(f, "test")
257 }
258 }
259
260 #[test]
261 fn test_display_implementation_invalid_input_data() {
262 let expected = "Invalid input data provided";
263 let error = Error::<TestError>::InvalidInputData;
264 let actual = format!("{}", error);
265
266 assert_eq!(expected, actual)
267 }
268
269 #[test]
270 fn test_display_implementation_i2c_error() {
271 let expected = "I²C bus error: test";
272 let error = Error::<TestError>::I2C(TestError);
273 let actual = format!("{}", error);
274
275 assert_eq!(expected, actual)
276 }
277}