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
//! This is a platform agnostic Rust driver for the PCF8574, PCF8574A and PCF8575
//! I/O expanders, based on the [`embedded-hal`] traits.
//!
//! [`embedded-hal`]: https://github.com/rust-embedded/embedded-hal
//!
//! This driver allows you to:
//! - Set all the outputs to `0` or `1` at once. See `set()`.
//! - Read selected inputs. See `get()`.
//! - Set all the outputs repeatedly looping through an array. See `write_array()`.
//! - Read selected inputs repeatedly filling up an array. See `read_array()`.
//! - Split the device into individual input/output pins. See `split()`.
//!
//! ## The devices
//! The devices consist of 8 or 16 quasi-bidirectional ports, I²C-bus interface, three
//! hardware address inputs and interrupt output. The quasi-bidirectional port can be
//! independently assigned as an input to monitor interrupt status or keypads, or as an
//! output to activate indicator devices such as LEDs.
//!
//! The active LOW open-drain interrupt output (INT) can be connected to the interrupt logic
//! of the microcontroller and is activated when any input state differs from its corresponding
//! input port register state.
//!
//! Datasheets:
//! - [PCF8574 / PCF8574A](https://www.nxp.com/docs/en/data-sheet/PCF8574_PCF8574A.pdf)
//! - [PCF8575](https://www.nxp.com/documents/data_sheet/PCF8575.pdf)
//!
//! ## Splitting the device into individual input/output pins
//!
//! By calling `split()` on the device it is possible to get a structure holding the
//! individual pins as separate elements. These pins implement the `OutputPin` and
//! `InputPin` traits (the latter only if activating the `unproven` feature).
//! This way it is possible to use the pins transparently as normal I/O pins regardless
//! of the fact that an I/O expander is connected in between.
//! You can therefore also pass them to code expecting an `OutputPin` or `InputPin`.
//!
//! However, you need to keep the device you split alive (lifetime annotations have
//! put in place for Rust to enforce this).
//!
//! For each operation done on an input/output pin, a `read` or `write` will be done
//! through I2C for all the pins, using a cached value for the rest of pins not being
//! operated on. This should all be transparent to the user but if operating on more
//! than one pin at once, the `set` and `get` methods will be faster.
//! Similarly, if several pins must be changed/read at the same time, the `set` and
//! `get` methods would be the correct choice.
//!
//! At the moment, no mutex has been implemented for the individual pin access.
//!
//! ## Usage examples (see also examples folder)
//!
//! Please find additional examples using hardware in this repository: [driver-examples]
//!
//! [driver-examples]: https://github.com/eldruin/driver-examples
//!
//! ### Instantiating with the default address
//!
//! Import this crate and an `embedded_hal` implementation, then instantiate
//! the device:
//!
//! ```no_run
//! use linux_embedded_hal::I2cdev;
//! use pcf857x::{ Pcf8574, SlaveAddr };
//!
//! let dev = I2cdev::new("/dev/i2c-1").unwrap();
//! let address = SlaveAddr::default();
//! let mut expander = Pcf8574::new(dev, address);
//! ```
//!
//! ### Providing an alternative address
//!
//! ```no_run
//! use linux_embedded_hal::I2cdev;
//! use pcf857x::{ Pcf8574, SlaveAddr };
//!
//! let dev = I2cdev::new("/dev/i2c-1").unwrap();
//! let (a2, a1, a0) = (false, false, true);
//! let address = SlaveAddr::Alternative(a2, a1, a0);
//! let mut expander = Pcf8574::new(dev, address);
//! ```
//!
//! ### Setting the output pins and reading P0 and P7
//!
//! ```no_run
//! use linux_embedded_hal::I2cdev;
//! use pcf857x::{ Pcf8574, SlaveAddr, PinFlag };
//!
//! let dev = I2cdev::new("/dev/i2c-1").unwrap();
//! let address = SlaveAddr::default();
//! let mut expander = Pcf8574::new(dev, address);
//! let output_pin_status = 0b1010_1010;
//! expander.set(output_pin_status).unwrap();
//!
//! let mask_of_pins_to_be_read = PinFlag::P0 | PinFlag::P7;
//! let read_input_pin_status = expander.get(mask_of_pins_to_be_read).unwrap();
//!
//! println!("Input pin status: {}", read_input_pin_status);
//! ```
//!
//! ### Splitting device into individual input/output pins and setting them.
//!
//! ```no_run
//! use linux_embedded_hal::I2cdev;
//! use pcf857x::{ Pcf8574, SlaveAddr, PinFlag, OutputPin };
//!
//! let dev = I2cdev::new("/dev/i2c-1").unwrap();
//! let address = SlaveAddr::default();
//! let expander = Pcf8574::new(dev, address);
//! let mut parts = expander.split();
//! parts.p0.set_high().unwrap();
//! parts.p7.set_low().unwrap();
//! ```
//!
//! ### Splitting device into individual input/output pins and reading them.
//!
//! Only available if compiling with the "`unproven`" feature
//!
//! ```no_run
//! use linux_embedded_hal::I2cdev;
//! use pcf857x::{ Pcf8574, SlaveAddr, PinFlag };
//! #[cfg(feature="unproven")]
//! use pcf857x::InputPin;
//!
//! let dev = I2cdev::new("/dev/i2c-1").unwrap();
//! let address = SlaveAddr::default();
//! let expander = Pcf8574::new(dev, address);
//! let mut parts = expander.split();
//! #[cfg(feature="unproven")]
//! {
//! let is_input_p0_low = parts.p0.is_low().unwrap();
//! let is_input_p2_low = parts.p2.is_low().unwrap();
//! }
//! ```
pub use InputPin;
pub use OutputPin;
/// All possible errors in this crate
pub use crateSlaveAddr;
pub use cratePinFlag;
pub use crate;
pub use crate;
pub use cratePcf8575;