Skip to main content

tsl2591_eh_driver/
lib.rs

1#![no_std]
2use bitfield::bitfield;
3use embedded_hal::i2c::{ErrorType, I2c};
4
5pub struct Driver<I2C> {
6    i2c: I2C,
7    integration_time: IntegrationTimes,
8    gain: Gain,
9}
10
11impl<E> From<E> for Error<E> {
12    fn from(error: E) -> Self {
13        Error::I2cError(error)
14    }
15}
16
17impl<I2C> Driver<I2C>
18where
19    I2C: I2c + ErrorType,
20{
21    pub fn new(i2c: I2C) -> Result<Driver<I2C>, Error<I2C::Error>> {
22        let mut driver = Driver {
23            i2c,
24            integration_time: IntegrationTimes::_200MS,
25            gain: Gain::MED,
26        };
27        let id = driver.get_id()?;
28        if id != chip::ID {
29            return Err(Error::IdMismatch(id));
30        }
31
32        driver.set_gain(driver.gain)?;
33        driver.set_timing(driver.integration_time)?;
34
35        Ok(driver)
36    }
37
38    pub fn new_define_integration(
39        i2c: I2C,
40        integration_time: IntegrationTimes,
41        gain: Gain,
42    ) -> Result<Driver<I2C>, Error<I2C::Error>> {
43        let mut driver = Driver {
44            i2c,
45            integration_time,
46            gain,
47        };
48        let id = driver.get_id()?;
49        if id != chip::ID {
50            return Err(Error::IdMismatch(id));
51        }
52
53        driver.set_gain(gain)?;
54        driver.set_timing(integration_time)?;
55
56        Ok(driver)
57    }
58
59    fn get_id(&mut self) -> Result<u8, Error<I2C::Error>> {
60        let mut buffer = [0u8; 1];
61        self.i2c.write_read(
62            chip::I2C_ADDR,
63            &[chip::COMMAND_BIT | chip::ID_ADDR],
64            &mut buffer,
65        )?;
66        Ok(buffer[0])
67    }
68
69    pub fn set_gain(&mut self, gain: Gain) -> Result<(), Error<I2C::Error>> {
70        self.i2c.write(
71            chip::I2C_ADDR,
72            &[
73                chip::COMMAND_BIT | chip::CONTROL,
74                self.integration_time as u8 | gain as u8,
75            ],
76        )?;
77        self.gain = gain;
78
79        Ok(())
80    }
81
82    pub fn set_timing(
83        &mut self,
84        integration_time: IntegrationTimes,
85    ) -> Result<(), Error<I2C::Error>> {
86        self.i2c.write(
87            chip::I2C_ADDR,
88            &[
89                chip::COMMAND_BIT | chip::CONTROL,
90                integration_time as u8 | self.gain as u8,
91            ],
92        )?;
93        self.integration_time = integration_time;
94
95        Ok(())
96    }
97
98    pub fn disable(&mut self) -> Result<(), Error<I2C::Error>> {
99        self.i2c.write(
100            chip::I2C_ADDR,
101            &[chip::COMMAND_BIT | chip::ENABLE, chip::ENABLE_POWEROFF],
102        )?;
103        Ok(())
104    }
105
106    pub fn enable(&mut self) -> Result<(), Error<I2C::Error>> {
107        self.i2c.write(
108            chip::I2C_ADDR,
109            &[
110                chip::COMMAND_BIT | chip::ENABLE,
111                chip::ENABLE_POWERON | chip::ENABLE_AEN | chip::ENABLE_AIEN | chip::ENABLE_NPIEN,
112            ],
113        )?;
114        Ok(())
115    }
116
117    pub fn get_enable(&mut self) -> Result<Enable, Error<I2C::Error>> {
118        let mut status = [0u8; 1];
119        self.i2c.write_read(
120            chip::I2C_ADDR,
121            &[chip::COMMAND_BIT | chip::ENABLE],
122            &mut status,
123        )?;
124        Ok(Enable(status[0]))
125    }
126
127    pub fn get_status(&mut self) -> Result<Status, Error<I2C::Error>> {
128        let mut status = [0u8; 1];
129        self.i2c.write_read(
130            chip::I2C_ADDR,
131            &[chip::COMMAND_BIT | chip::STATUS],
132            &mut status,
133        )?;
134        Ok(Status(status[0]))
135    }
136
137    pub fn get_channel_data(&mut self) -> Result<(u16, u16), Error<I2C::Error>> {
138        let mut buffer_1 = [0u8; 2];
139        let mut buffer_2 = [0u8; 2];
140        self.i2c.write_read(
141            chip::I2C_ADDR,
142            &[chip::COMMAND_BIT | chip::CHAN0_LOW],
143            &mut buffer_1,
144        )?;
145        self.i2c.write_read(
146            chip::I2C_ADDR,
147            &[chip::COMMAND_BIT | chip::CHAN1_LOW],
148            &mut buffer_2,
149        )?;
150        let channel_0 = ((buffer_1[1] as u16) << 8) | buffer_1[0] as u16;
151        let channel_1 = ((buffer_2[1] as u16) << 8) | buffer_2[0] as u16;
152        Ok((channel_0, channel_1))
153    }
154
155    pub fn get_luminosity(&mut self, mode: Mode) -> Result<u16, Error<I2C::Error>> {
156        let (channel_0, channel_1) = self.get_channel_data()?;
157        self.get_luminosity_from_channel_data(mode, channel_0, channel_1)
158    }
159
160    fn get_integration_in_ms(&self) -> f32 {
161        match self.integration_time {
162            IntegrationTimes::_100MS => 100.,
163            IntegrationTimes::_200MS => 200.,
164            IntegrationTimes::_300MS => 300.,
165            IntegrationTimes::_400MS => 400.,
166            IntegrationTimes::_500MS => 500.,
167            IntegrationTimes::_600MS => 600.,
168        }
169    }
170
171    fn get_gain_multiplier(&self) -> f32 {
172        match self.gain {
173            Gain::LOW => 1.,
174            Gain::MED => 25.,
175            Gain::HIGH => 428.,
176            Gain::MAX => 9876.,
177        }
178    }
179
180    pub fn calculate_lux(&mut self, ch_0: u16, ch_1: u16) -> Result<f32, Error<I2C::Error>> {
181        let max_count = match self.integration_time {
182            IntegrationTimes::_100MS => 0x8FFF,
183            _ => 0xFFFF,
184        };
185
186        if (ch_0 == max_count) | (ch_1 == max_count) {
187            // Signal an overflow
188            return Err(Error::SignalOverflow());
189        }
190
191        let a_time = self.get_integration_in_ms();
192        let a_gain = self.get_gain_multiplier();
193        let cpl = (a_time * a_gain) / 408.0;
194        let lux = (ch_0 as f32 - ch_1 as f32) * (1.0 - (ch_1 as f32 / ch_0 as f32)) / cpl;
195
196        Ok(lux)
197    }
198
199    pub fn get_luminosity_from_channel_data(&mut self, mode: Mode, ch_0: u16, ch_1: u16) -> Result<u16, Error<I2C::Error>> {
200        let full_luminosity: u32 = ((ch_1 as u32) << 16) | ch_0 as u32;
201
202        match mode {
203            Mode::FullSpectrum => Ok((full_luminosity & 0xFFFF) as u16),
204            Mode::Infrared => Ok((full_luminosity >> 16) as u16),
205            Mode::Visible => {
206                let infrared_and_visible = full_luminosity & 0xFFFF;
207                let infrared = full_luminosity >> 16;
208                if infrared > infrared_and_visible {
209                    Err(Error::InfraredOverflow())
210                } else {
211                    Ok((infrared_and_visible - infrared) as u16)
212                }
213            }
214        }
215    }
216}
217
218pub enum Mode {
219    Infrared,
220    Visible,
221    FullSpectrum,
222}
223
224#[derive(Clone, Copy)]
225pub enum IntegrationTimes {
226    _100MS = 0x00, // 100
227    _200MS = 0x01, // 200 millis
228    _300MS = 0x02, // 300 millis
229    _400MS = 0x03, // 400 millis
230    _500MS = 0x04, // 500 millis
231    _600MS = 0x05, // 600 millis
232}
233
234#[derive(Clone, Copy)]
235pub enum Gain {
236    LOW = 0x00,  // low gain (1x)
237    MED = 0x10,  // medium gain (25x)
238    HIGH = 0x20, // medium gain (428x)
239    MAX = 0x30,  // max gain (9876x)
240}
241
242#[allow(dead_code)]
243mod chip {
244    pub const I2C_ADDR: u8 = 0x29;
245    pub const ID: u8 = 0x50;
246    pub const ID_ADDR: u8 = 0x12;
247    pub const COMMAND_BIT: u8 = 0xA0;
248    pub const ENABLE_POWERON: u8 = 0x01;
249    pub const ENABLE_AEN: u8 = 0x02;
250    pub const ENABLE_AIEN: u8 = 0x10;
251    pub const ENABLE_POWEROFF: u8 = 0x00;
252    pub const ENABLE_NPIEN: u8 = 0x80;
253    pub const CHAN0_LOW: u8 = 0x14;
254    pub const CHAN1_LOW: u8 = 0x16;
255    pub const ENABLE: u8 = 0x00;
256    pub const CONTROL: u8 = 0x01;
257    pub const STATUS: u8 = 0x13;
258    pub const TSL2591_THRESHOLD_AILTH: u8 = 0x05; // ALS low threshold upper byte
259    pub const TSL2591_THRESHOLD_AIHTL: u8 = 0x06; // ALS high threshold lower byte
260    pub const TSL2591_THRESHOLD_AIHTH: u8 = 0x07; // ALS high threshold upper byte
261    pub const TSL2591_THRESHOLD_NPAILTL: u8 = 0x08; // No Persist ALS low threshold lower byte
262    pub const TSL2591_THRESHOLD_NPAILTH: u8 = 0x09; // No Persist ALS low threshold higher byte
263    pub const TSL2591_THRESHOLD_NPAIHTL: u8 = 0x0A; // No Persist ALS high threshold lower byte
264    pub const TSL2591_THRESHOLD_NPAIHTH: u8 = 0x0B; // No Persist ALS high threshold higher byte
265    pub const TSL2591_PERSIST_FILTER: u8 = 0x0C; // Interrupt persistence filter
266}
267
268#[derive(Clone, Copy, Debug)]
269pub enum Error<I2cError> {
270    I2cError(I2cError),
271    IdMismatch(u8),
272    SignalOverflow(),
273    InfraredOverflow(),
274}
275
276// enum PersitFilter {
277//     // Enumeration for the persistance filter (for interrupts)
278//     //  bit 7:4: 0
279//     TSL2591_PERSIST_EVERY = 0x00, // Every ALS cycle generates an interrupt
280//     TSL2591_PERSIST_ANY = 0x01,   // Any value outside of threshold range
281//     TSL2591_PERSIST_2 = 0x02,     // 2 consecutive values out of range
282//     TSL2591_PERSIST_3 = 0x03,     // 3 consecutive values out of range
283//     TSL2591_PERSIST_5 = 0x04,     // 5 consecutive values out of range
284//     TSL2591_PERSIST_10 = 0x05,    // 10 consecutive values out of range
285//     TSL2591_PERSIST_15 = 0x06,    // 15 consecutive values out of range
286//     TSL2591_PERSIST_20 = 0x07,    // 20 consecutive values out of range
287//     TSL2591_PERSIST_25 = 0x08,    // 25 consecutive values out of range
288//     TSL2591_PERSIST_30 = 0x09,    // 30 consecutive values out of range
289//     TSL2591_PERSIST_35 = 0x0A,    // 35 consecutive values out of range
290//     TSL2591_PERSIST_40 = 0x0B,    // 40 consecutive values out of range
291//     TSL2591_PERSIST_45 = 0x0C,    // 45 consecutive values out of range
292//     TSL2591_PERSIST_50 = 0x0D,    // 50 consecutive values out of range
293//     TSL2591_PERSIST_55 = 0x0E,    // 55 consecutive values out of range
294//     TSL2591_PERSIST_60 = 0x0F,    // 60 consecutive values out of range
295// }
296
297bitfield! {
298    pub struct Enable(u8);
299    impl Debug;
300    pub npien, _: 6;
301    pub sai, _: 5;
302    pub res, _: 4,3;
303    pub aen, _: 1;
304    pub pon, _: 0;
305}
306
307bitfield! {
308    pub struct Status(u8);
309    impl Debug;
310    pub npintr,_: 6,4;
311    pub aint, _: 4;
312    pub res, _: 3,3;
313    pub avalid, _: 0;
314}