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
//! This is a platform agnostic Rust driver for the MLX90614/MLX90615
//! infrared thermometers using the [`embedded-hal`] traits.
//!
//! [`embedded-hal`]: https://github.com/rust-embedded/embedded-hal
//!
//! This driver allows you to:
//! - Read the last object temperature measurement. See: [`object1_temperature()`].
//! - Read the last ambient temperature measurement. See: [`ambient_temperature()`].
//! - Read the last raw IR measurement. See: [`raw_ir_channel1()`].
//! - Get/Set the emissivity. See: [`set_emissivity()`].
//! - Get the device ID. See: [`device_id()`].
//! - Set the device address. See: [`set_address()`].
//! - Put the device to sleep. See: [`sleep()`].
//! - Wake the device from sleep. See: [`wake_mlx90614()`].
//!
//! [`object1_temperature()`]: struct.Mlx9061x.html#method.object1_temperature
//! [`ambient_temperature()`]: struct.Mlx9061x.html#method.ambient_temperature
//! [`raw_ir_channel1()`]: struct.Mlx9061x.html#method.raw_ir_channel1
//! [`set_emissivity()`]: struct.Mlx9061x.html#method.set_emissivity
//! [`device_id()`]: struct.Mlx9061x.html#method.device_id
//! [`set_address()`]: struct.Mlx9061x.html#method.set_address
//! [`sleep()`]: struct.Mlx9061x.html#method.sleep
//!
//! <!-- TODO
//! [Introductory blog post](TODO)
//! -->
//!
//! ## The devices
//!
//! The MLX90614/MLX90615 are a infrared thermometers for non-contact temperature
//! measurements. Both the IR sensitive thermopile detector chip and the
//! signal conditioning ASSP are integrated in the same TO-39/TO-46 can.
//! Thanks to its low noise amplifier, 17-bit/16-bit ADC and powerful DSP unit,
//! a high accuracy and resolution of the thermometer is achieved.
//!
//! Depending on the MLX90614 model they feature a single-zone or dual-zone thermopile.
//!
//! The chips feature an 10-bit PWM and SMBus interface.
//!
//! The readout resolution is 0.01°C (MLX90614) / 0.02°C (MLX90615).
//!
//! This driver uses the SMBus interface.
//!
//! Documentation:
//! - Datasheets: [MLX90614](https://www.melexis.com/-/media/files/documents/datasheets/mlx90614-datasheet-melexis.pdf), [MLX90615](https://www.melexis.com/-/media/files/documents/datasheets/mlx90615-datasheet-melexis.pdf)
//! - [SMBus communication with MLX90614](https://www.melexis.com/-/media/files/documents/application-notes/mlx90614-smbus-communication-application-note-melexis.pdf)
//!
//! ## Usage examples (see also examples folder)
//!
//! To use this driver, import this crate and an `embedded_hal` implementation,
//! then instantiate the device.
//!
//! At least when interacting with the EEPROM it is necessary to insert delays.
//! This driver only adds the minimal amount of delays. i.e. only between two consecutive
//! operations inside a method.
//!
//! *IMPORTANT*: Users are advised to wait enough time between operations.
//! Otherwise the device will not behave properly.
//!
//! Please find additional examples using hardware in this repository: [driver-examples]
//!
//! [driver-examples]: https://github.com/eldruin/driver-examples
//!
//! ### Read the object 1 temperature with an MLX90614
//!
//! Some models feature single-zone or dual-zone thermopiles.
//!
//! ```no_run
//! use linux_embedded_hal::I2cdev;
//! use mlx9061x::{Mlx9061x, SlaveAddr};
//!
//! let dev = I2cdev::new("/dev/i2c-1").unwrap();
//! let addr = SlaveAddr::default();
//! let mut sensor = Mlx9061x::new_mlx90614(dev, addr, 5).unwrap();
//! let obj_temp = sensor.object1_temperature().unwrap_or(-1.0);
//! println!("Object temperature: {:.2}ºC", obj_temp);
//! ```
//!
//! ### Read the ambient temperature with an MLX90615
//!
//! ```no_run
//! # use linux_embedded_hal::I2cdev;
//! # use mlx9061x::{Mlx9061x, SlaveAddr};
//! #
//! # let dev = I2cdev::new("/dev/i2c-1").unwrap();
//! let addr = SlaveAddr::default();
//! let mut sensor = Mlx9061x::new_mlx90615(dev, addr, 5).unwrap();
//! let temp = sensor.ambient_temperature().unwrap_or(-1.0);
//! println!("Ambient temperature: {:.2}ºC", temp);
//! ```
//!
//! ### Get the device ID of an MLX90614
//!
//! ```no_run
//! # use linux_embedded_hal::I2cdev;
//! # use mlx9061x::{Mlx9061x, SlaveAddr};
//! #
//! # let dev = I2cdev::new("/dev/i2c-1").unwrap();
//! # let addr = SlaveAddr::default();
//! let mut sensor = Mlx9061x::new_mlx90614(dev, addr, 5).unwrap();
//! let id = sensor.device_id().unwrap_or(0);
//! println!("ID: 0x{:x?}", id);
//! ```
//!
//! ### Set the emissivity
//!
//! This change will be permanently stored in the device EEPROM.
//!
//! ```no_run
//! use linux_embedded_hal::{I2cdev, Delay};
//! use mlx9061x::{Mlx9061x, SlaveAddr};
//!
//! let dev = I2cdev::new("/dev/i2c-1").unwrap();
//! let addr = SlaveAddr::default();
//! let mut sensor = Mlx9061x::new_mlx90614(dev, addr, 5).unwrap();
//! let mut delay = Delay{};
//! sensor.set_emissivity(0.8, &mut delay).unwrap();
//! ```
//!
//! ### Change the device address
//!
//! This change will be permanently stored in the device EEPROM.
//!
//! ```no_run
//! use linux_embedded_hal::{I2cdev, Delay};
//! use mlx9061x::{Mlx9061x, SlaveAddr};
//!
//! let dev = I2cdev::new("/dev/i2c-1").unwrap();
//! let addr = SlaveAddr::default();
//! let mut sensor = Mlx9061x::new_mlx90614(dev, addr, 5).unwrap();
//! let mut delay = Delay{};
//! sensor.set_address(SlaveAddr::Alternative(0x5C), &mut delay).unwrap();
//! ```
//!
//! ### Put the device to sleep and wake it again
//!
//! Note that the I2C pin construction/deconstruction depends on the HAL implementation.
//!
//! ```no_run
//! # use embedded_hal::blocking::{delay::DelayMs, i2c};
//! # use embedded_hal::digital::v2::OutputPin;
//! # struct IoPin;
//! # impl OutputPin for IoPin {
//! # type Error = ();
//! # fn set_high(&mut self) -> Result<(), ()> { Ok(()) }
//! # fn set_low(&mut self) -> Result<(), ()> { Ok(()) }
//! # }
//! #
//! # struct I2c1 {
//! # scl: IoPin,
//! # sda: IoPin
//! # }
//! # impl i2c::Write for I2c1 {
//! # type Error = ();
//! # fn write(&mut self, addr: u8, data: &[u8]) -> Result<(), ()> { Ok(()) }
//! # }
//! # impl i2c::WriteRead for I2c1 {
//! # type Error = ();
//! # fn write_read(&mut self, addr: u8, data: &[u8], buf: &mut[u8]) -> Result<(), ()> { Ok(()) }
//! # }
//! #
//! # impl I2c1 {
//! # fn new(scl: IoPin, sda: IoPin) -> Self {
//! # I2c1 {
//! # scl, sda
//! # }
//! # }
//! # fn free(self) -> (IoPin, IoPin) {
//! # (self.scl, self.sda)
//! # }
//! # }
//! #
//! # struct Delay;
//! # impl DelayMs<u8> for Delay {
//! # fn delay_ms(&mut self, _: u8) {}
//! # }
//! # let sda = IoPin;
//! # let scl = IoPin;
//! use mlx9061x::{Mlx9061x, SlaveAddr, wake_mlx90614};
//!
//! let i2cdev = I2c1::new(scl, sda); // This depends on your HAL
//! let addr = SlaveAddr::default();
//! let mut sensor = Mlx9061x::new_mlx90614(i2cdev, addr, 5).unwrap();
//! // ...
//! sensor.sleep().unwrap();
//! // ...
//! // To wake the device, destroy it and get the SCL/SDA pins back
//! let i2cdev = sensor.destroy();
//! let (mut scl, mut sda) = i2cdev.free(); // This depends on your HAL
//! let mut delay = Delay{};
//! wake_mlx90614(&mut scl, &mut sda, &mut delay).unwrap();
//!
//! // Now recreate the I2C device and sensor
//! let i2cdev = I2c1::new(scl, sda);
//! let mut sensor = Mlx9061x::new_mlx90614(i2cdev, addr, 5).unwrap();
//! // Then you can use the sensor as usual
//! ```
// avoid suggestion about inclusive ranges containing floats
use PhantomData;
pub use crate wake_mlx90614;
pub use crate wake_mlx90615;
pub use crate;
/// MLX90614/MLX90615 device driver