1#![no_std]
53#[macro_use]
54extern crate num_derive;
55use embedded_hal::i2c;
56use paste::paste;
57use types::LuxData;
58use types::RawData;
59
60mod fields;
61mod macros;
62mod registers;
63mod types;
64pub use crate::fields::*;
65pub use crate::registers::*;
66pub use crate::types::Error;
67
68const LTR303_BASE_ADDRESS: u8 = 0x29;
69
70create_struct_with! (LTR303Config, {mode: Mode, gain: Gain, integration_time: IntegrationTime, measurement_rate: MeasurementRate, int_thrsh_up: u16, int_thrsh_down: u16});
71
72impl Default for LTR303Config {
73 fn default() -> Self {
74 LTR303Config {
75 mode: crate::Mode::STANDBY,
76 gain: crate::Gain::Gain1x,
77 integration_time: crate::IntegrationTime::Ms100,
78 measurement_rate: crate::MeasurementRate::Ms500,
79 int_thrsh_up: 0x0000,
80 int_thrsh_down: 0xFFFF,
81 }
82 }
83}
84
85pub struct LTR303<I2C> {
86 i2c: I2C,
87 gain: Gain,
88 integration_time: IntegrationTime,
89}
90
91impl<I2C, E> LTR303<I2C>
92where
93 I2C: i2c::I2c<Error = E>,
94{
95 pub fn init(i2c: I2C) -> Self {
97 LTR303 {
98 i2c,
99 gain: Gain::Gain1x,
100 integration_time: IntegrationTime::Ms100,
101 }
102 }
103
104 pub fn get_mfc_id(&mut self) -> Result<u8, Error<E>> {
106 self.read_register(Register::MANUFAC_ID)
107 }
108
109 pub fn get_part_id(&mut self) -> Result<u8, Error<E>> {
111 self.read_register(Register::PART_ID)
112 }
113
114 pub fn destroy(self) -> I2C {
116 self.i2c
117 }
118
119 pub fn start_measurement(&mut self, config: <R303Config) -> Result<(), Error<E>> {
121 self.gain = config.gain;
123 self.integration_time = config.integration_time;
124
125 let control_reg = ControlRegister::default()
127 .with_gain(config.gain)
128 .with_mode(Mode::ACTIVE);
129
130 let meas_rate_reg = MeasRateRegister::default()
132 .with_integration_time(config.integration_time)
133 .with_measurement_rate(config.measurement_rate);
134
135 self.write_register(Register::ALS_MEAS_RATE, meas_rate_reg.value())?;
136
137 self.write_register(
139 Register::ALS_THRES_LOW_0,
140 config.int_thrsh_down.to_be_bytes()[1],
141 )?;
142 self.write_register(
143 Register::ALS_THRES_LOW_1,
144 config.int_thrsh_down.to_be_bytes()[0],
145 )?;
146 self.write_register(
147 Register::ALS_THRES_UP_0,
148 config.int_thrsh_up.to_be_bytes()[1],
149 )?;
150 self.write_register(
151 Register::ALS_THRES_UP_1,
152 config.int_thrsh_up.to_be_bytes()[0],
153 )?;
154
155 self.write_register(Register::INTERRUPT, 0b00000010)?;
158
159 self.write_register(Register::ALS_CONTR, control_reg.value())?;
161
162 Ok(())
163 }
164
165 pub fn get_status(&mut self) -> Result<StatusRegister, Error<E>> {
167 let data = self.read_register(Register::ALS_STATUS)?;
168
169 let status_reg: StatusRegister = data.into();
170 Ok(status_reg)
171 }
172
173 pub fn data_ready(&mut self) -> Result<bool, Error<E>> {
175 let status = self.get_status()?;
176 Ok(status.data_status.value == DataStatus::New)
177 }
178
179 pub fn get_lux_data(&mut self) -> Result<LuxData, Error<E>> {
182 let raw_data = self.get_raw_data()?;
183
184 Ok(LuxData {
185 lux_raw: raw_data,
186 lux_phys: raw_to_lux(
187 raw_data.ch1_raw,
188 raw_data.ch0_raw,
189 self.gain,
190 self.integration_time,
191 ),
192 })
193 }
194
195 pub fn standby(&mut self) -> Result<(), Error<E>> {
197 self.write_register(
198 Register::ALS_CONTR,
199 ControlRegister::default().with_mode(Mode::STANDBY).value(),
200 )?;
201 Ok(())
202 }
203}
204
205impl<I2C, E> LTR303<I2C>
206where
207 I2C: i2c::I2c<Error = E>,
208{
209 fn write_register(&mut self, register: u8, data: u8) -> Result<(), Error<E>> {
210 self.i2c
211 .write(LTR303_BASE_ADDRESS, &[register, data])
212 .map_err(Error::I2C)
213 .and(Ok(()))
214 }
215
216 fn read_register(&mut self, register: u8) -> Result<u8, Error<E>> {
217 let mut data: [u8; 1] = [0];
218 self.i2c
219 .write_read(LTR303_BASE_ADDRESS, &[register], &mut data)
220 .map_err(Error::I2C)
221 .and(Ok(data[0]))
222 }
223
224 fn get_raw_data(&mut self) -> Result<RawData, Error<E>> {
225 let mut data: [u8; 4] = [0; 4];
229 self.i2c
230 .write_read(LTR303_BASE_ADDRESS, &[Register::ALS_DATA_CH1_0], &mut data)
231 .map_err(Error::I2C)?;
232 let ch1_raw = u16::from_le_bytes([data[0], data[1]]);
233 let ch0_raw = u16::from_le_bytes([data[2], data[3]]);
234
235 Ok(RawData { ch0_raw, ch1_raw })
236 }
237}
238
239fn raw_to_lux(ch1_data: u16, ch0_data: u16, gain: Gain, itime: IntegrationTime) -> f32 {
240 let ratio = ch1_data as f32 / (ch0_data as f32 + ch1_data as f32);
241 let als_gain: f32 = gain.into();
242 let int_time: f32 = itime.into();
243
244 if ratio < 0.45 {
245 ((1.7743 * f32::from(ch0_data)) + (1.1059 * f32::from(ch1_data))) / als_gain / int_time
246 } else if (0.45..0.64).contains(&ratio) {
247 ((4.2785 * f32::from(ch0_data)) - (1.9548 * f32::from(ch1_data))) / als_gain / int_time
248 } else if (0.64..0.85).contains(&ratio) {
249 ((0.5926 * f32::from(ch0_data)) - (0.1185 * f32::from(ch1_data))) / als_gain / int_time
250 } else {
251 0.0
252 }
253}
254
255#[cfg(test)]
256mod tests {
257 extern crate std;
260 use crate::{DataStatus, DataValidity, Gain, IntStatus};
261
262 use super::*;
263
264 use embedded_hal_mock::eh1::i2c;
265 const LTR303_ADDR: u8 = 0x29;
266
267 #[test]
268 fn manufacturer_info() {
269 let expectations = [i2c::Transaction::write_read(
270 LTR303_ADDR,
271 std::vec![Register::MANUFAC_ID],
272 std::vec![0x05],
273 )];
274 let mock = i2c::Mock::new(&expectations);
275
276 let mut ltr303 = LTR303::init(mock);
277 let mfc = ltr303.get_mfc_id().unwrap();
278 assert_eq!(0x05, mfc);
279
280 let mut mock = ltr303.destroy();
281 mock.done(); }
283
284 #[test]
285 fn part_id() {
286 let expectations = [i2c::Transaction::write_read(
287 LTR303_ADDR,
288 std::vec![Register::PART_ID],
289 std::vec![0xA0],
290 )];
291 let mock = i2c::Mock::new(&expectations);
292
293 let mut ltr303 = LTR303::init(mock);
294 let part_id = ltr303.get_part_id().unwrap();
295 assert_eq!(0xA0, part_id);
296
297 let mut mock = ltr303.destroy();
298 mock.done(); }
300
301 #[test]
302 fn sensor_status() {
303 let expectations = [i2c::Transaction::write_read(
304 LTR303_ADDR,
305 std::vec![Register::ALS_STATUS],
306 std::vec![0b11111010],
307 )];
308 let mock = i2c::Mock::new(&expectations);
309
310 let mut ltr303 = LTR303::init(mock);
311 let sensor_status = ltr303.get_status().unwrap();
312
313 assert_eq!(sensor_status.data_status.value, DataStatus::Old);
314 assert_eq!(sensor_status.data_valid.value, DataValidity::DataInvalid);
315 assert_eq!(sensor_status.gain.value, Gain::Gain96x);
316 assert_eq!(sensor_status.int_status.value, IntStatus::Active);
317
318 assert_eq!(sensor_status.value(), 0b11111000);
319
320 let mut mock = ltr303.destroy();
321 mock.done(); }
323
324 #[test]
325 fn start_measurement() {
326 let expectations = [
327 i2c::Transaction::write(
328 LTR303_ADDR,
329 std::vec![Register::ALS_MEAS_RATE, 0b00010101], ),
331 i2c::Transaction::write(LTR303_ADDR, std::vec![Register::ALS_THRES_LOW_0, 0xFF]),
332 i2c::Transaction::write(LTR303_ADDR, std::vec![Register::ALS_THRES_LOW_1, 0xFF]),
333 i2c::Transaction::write(LTR303_ADDR, std::vec![Register::ALS_THRES_UP_0, 0x00]),
334 i2c::Transaction::write(LTR303_ADDR, std::vec![Register::ALS_THRES_UP_1, 0x00]),
335 i2c::Transaction::write(LTR303_ADDR, std::vec![Register::INTERRUPT, 0b00000010]),
336 i2c::Transaction::write(
337 LTR303_ADDR,
338 std::vec![Register::ALS_CONTR, 0b00000001], ),
340 ];
341
342 let mock = i2c::Mock::new(&expectations);
343
344 let config = LTR303Config {
345 integration_time: crate::IntegrationTime::Ms200,
346 measurement_rate: crate::MeasurementRate::Ms2000,
347 ..Default::default()
348 };
349
350 let mut ltr303 = LTR303::init(mock);
351
352 ltr303.start_measurement(&config).unwrap();
353
354 let mut mock = ltr303.destroy();
355 mock.done(); }
357
358 #[test]
360 fn single_shot_measurement() {
361 let expectations = [
364 i2c::Transaction::write(LTR303_ADDR, std::vec![Register::ALS_MEAS_RATE, 0b0001_1101]), i2c::Transaction::write(LTR303_ADDR, std::vec![Register::ALS_THRES_LOW_0, 0xFF]), i2c::Transaction::write(LTR303_ADDR, std::vec![Register::ALS_THRES_LOW_1, 0xFF]), i2c::Transaction::write(LTR303_ADDR, std::vec![Register::ALS_THRES_UP_0, 0x00]), i2c::Transaction::write(LTR303_ADDR, std::vec![Register::ALS_THRES_UP_1, 0x00]), i2c::Transaction::write(LTR303_ADDR, std::vec![Register::INTERRUPT, 0b00000010]), i2c::Transaction::write(LTR303_ADDR, std::vec![Register::ALS_CONTR, 0b0000_1001]), i2c::Transaction::write_read(
372 LTR303_ADDR,
373 std::vec![Register::ALS_STATUS],
374 std::vec![0b1010_0000],
375 ), i2c::Transaction::write_read(
377 LTR303_ADDR,
378 std::vec![Register::ALS_STATUS],
379 std::vec![0b0010_0100],
380 ), i2c::Transaction::write_read(
382 LTR303_ADDR,
383 std::vec![Register::ALS_DATA_CH1_0],
384 std::vec![0xAD, 0xDE, 0xEF, 0xBE],
385 ), i2c::Transaction::write(LTR303_ADDR, std::vec![Register::ALS_CONTR, 0b0000_0000]), ];
388 let mock = i2c::Mock::new(&expectations);
389
390 let config = crate::LTR303Config::default()
392 .with_integration_time(crate::IntegrationTime::Ms400)
393 .with_measurement_rate(crate::MeasurementRate::Ms2000)
394 .with_gain(crate::Gain::Gain4x);
395
396 let mut ltr303 = LTR303::init(mock);
397 ltr303.start_measurement(&config).unwrap();
398
399 while ltr303.get_status().unwrap().data_status.value != DataStatus::New {}
400
401 let lux_data = ltr303.get_lux_data().unwrap();
402 ltr303.standby().unwrap();
403
404 assert_eq!(lux_data.lux_raw.ch1_raw, 0xDEAD);
405 assert_eq!(lux_data.lux_raw.ch0_raw, 0xBEEF);
406
407 let mut mock = ltr303.destroy();
408 mock.done(); }
410
411 #[cfg(test)]
412 mod unit_tests {
413 use crate::{
414 raw_to_lux, ControlRegister, Field, Gain, IntegrationTime, MeasRateRegister,
415 MeasurementRate, Mode, ResetStatus,
416 };
417
418 #[test]
419 fn calculate_lux_from_raw() {
420 let ch0_data: u16 = 0x0000;
421 let ch1_data: u16 = 0xFFFF;
422
423 let ltr303_config = crate::LTR303Config::default();
425
426 let lux = raw_to_lux(
427 ch1_data,
428 ch0_data,
429 ltr303_config.gain,
430 ltr303_config.integration_time,
431 );
432
433 assert_eq!(lux, 0.0);
434
435 let ch0_data: u16 = 0x1000;
437 let ch1_data: u16 = 0x1000;
438 let lux = raw_to_lux(
439 ch1_data,
440 ch0_data,
441 ltr303_config.gain,
442 ltr303_config.integration_time,
443 );
444
445 assert_eq!(lux, 9517.875);
446 }
447
448 #[test]
449 fn test_registers() {
450 let control_reg = ControlRegister::default()
452 .with_mode(Mode::STANDBY)
453 .with_gain(Gain::Gain8x);
454
455 assert_eq!(control_reg.gain.value, Gain::Gain8x);
456 assert_eq!(control_reg.value(), 0b0000_1100);
457
458 let measrate_reg = MeasRateRegister::default()
459 .with_integration_time(IntegrationTime::Ms200)
460 .with_measurement_rate(MeasurementRate::Ms2000);
461
462 assert_eq!(measrate_reg.integration_time.value, IntegrationTime::Ms200);
463 assert_eq!(measrate_reg.value(), 0b0001_0101);
464 }
465
466 #[test]
467 fn test_register_from_u8() {
468 let contr_reg_val: u8 = 0b0000_1011;
470 let control_reg: ControlRegister = contr_reg_val.into();
471
472 assert_eq!(control_reg.gain.value, Gain::Gain4x);
473 assert_eq!(control_reg.sw_reset.value, ResetStatus::Resetting);
474 assert_eq!(control_reg.mode.value, Mode::ACTIVE);
475 }
476
477 #[test]
478 fn test_fields() {
479 let field1 = Field {
481 start_index: 1,
482 width: 4,
483 value: 0x0Bu8,
484 };
485 assert_eq!(field1.bits(), 0b0001_0110)
486 }
487 }
488}