thermal_camera/grideye/
constants.rs

1//! Unless otherwise noted, the names used are the section headers from the datasheet without the
2//! word "register". Where appropriate, there will also be a corresponding `*Value` type with valid
3//! values to write to that register.
4use num_enum::{IntoPrimitive, TryFromPrimitive};
5
6/// The I2C address for the Grid-EYE sensor.
7///
8/// The names chosen are *not* because of the actual address values, but because of what the
9/// address selection pin is connected to (ground or VDD).
10#[derive(Clone, Copy, Debug, PartialEq, IntoPrimitive, TryFromPrimitive)]
11#[repr(u8)]
12pub enum Address {
13    Low = 0x68,
14    High = 0x69,
15}
16
17#[cfg(test)]
18mod address_test {
19    use super::Address;
20    use core::convert::TryFrom;
21
22    #[test]
23    fn try_low() {
24        let low = Address::try_from(0x68);
25        assert!(low.is_ok());
26        assert_eq!(low.unwrap(), Address::Low);
27    }
28
29    #[test]
30    fn try_high() {
31        let high = Address::try_from(0x69);
32        assert!(high.is_ok());
33        assert_eq!(high.unwrap(), Address::High);
34    }
35
36    #[test]
37    fn try_undefined() {
38        let zero = Address::try_from(0);
39        assert!(zero.is_err());
40    }
41}
42
43/// The registers used to access the Grid-EYE.
44#[derive(Clone, Copy, Debug, PartialEq, IntoPrimitive, TryFromPrimitive)]
45#[repr(u8)]
46pub enum Register {
47    /// See [PowerControlValue] for details on values
48    /// Read/write.
49    PowerControl = 0x00,
50
51    /// See [ResetValue] for details on values.
52    /// Write-only.
53    Reset = 0x01,
54
55    /// See [FrameRateValue] for details on values.
56    /// Read/write.
57    FrameRate = 0x02,
58
59    /// See [InterruptControlValue] for details on values.
60    /// Read/write.
61    InterruptControl = 0x03,
62
63    /// The status flags for the device. The flags will remain set until cleared by writing to
64    /// [StatusClear].
65    /// Read-only.
66    Status = 0x04,
67
68    /// Clear one or both of the status flags for the device.
69    /// Write-only.
70    StatusClear = 0x05,
71
72    /// Whether or not the pixel values should be overaged or not.
73    /// Read/write.
74    Average = 0x07,
75
76    /// A semi-documented register that is written to when changing the moving average mode.
77    /// Write-only.
78    AverageData = 0x1F,
79
80    /// The upper temperature limit for triggering an interrupt. This is in the
81    /// [pixel temperature](#pixel_temperatures) format.
82    /// Read/write.
83    InterruptLevelHighLower = 0x08,
84
85    /// The lower temperature limit for triggering an interrupt. This is in the
86    /// [pixel temperature](#pixel_temperatures) format.
87    /// Read/write.
88    InterruptLevelLowLower = 0x0A,
89
90    /// The hysteresis limit for triggering an interrupt. The datasheet isn't very clear as to how
91    /// this value is used. This is in the [pixel temperature](#pixel_temperatures) format.
92    /// Read/write.
93    InterruptHysteresisLower = 0x0C,
94
95    /// The sensor has an on-board thermistor useful for for calibrating the output of the camera.
96    /// This is in the [thermistor temperature](#thermistor_temperature) format.
97    /// Read-only.
98    ThermistorLower = 0x0E,
99
100    /// The first register of the interrupt table. It continues up through `0x17` with each
101    /// register representing a bitfield of whether or not that pixel in the image has triggered an
102    /// interrupt. The first bit of the first register is pixel 1, with the rest of the pixels
103    /// following in order from there (see [identifying pixels](grideye#identifying_pixels)\).
104    /// Read-only.
105    InterruptTableStart = 0x10,
106
107    /// The lower bits of the temperature of pixel 1. The upper bits are in the register following
108    /// this one, with the lower bits for pixel 2 after that and so on up through `0xFF`.
109    /// This is in the [pixel temperature](#pixel_temperature) format.
110    PixelTemperatureStart = 0x80,
111}
112
113/// On power on, the device is in [normal](PowerControlValue::Normal) mode. There are no
114/// restrictions for leaving normal mode. In [sleep](PowerControlValue::Sleep) mode, the only
115/// valid mode to change to is normal mode. When leaving sleep mode the value of other
116/// registers are undefined, and must be reset with this procedure:
117///
118/// 1. Set [Register::PowerControl] to [`Normal`](PowerControlValue::Normal).
119/// 2. Wait 50 milliseconds.
120/// 3. Set [Register::Reset] to [`Initial`](ResetValue::Initial).
121/// 4. Wait 2 milliseconds.
122/// 5. Set [Register::Reset] to [`Flag`](ResetValue::Flag).
123///
124/// The datasheet has a nice state diagram summarizing this.
125#[derive(Clone, Copy, Debug, PartialEq, IntoPrimitive, TryFromPrimitive)]
126#[repr(u8)]
127pub enum PowerControlValue {
128    /// Normal operation.
129    Normal = 0x00,
130
131    /// Sleep mode.
132    Sleep = 0x10,
133
134    /// Standby mode with the pixel temperature only being updated every 60 seconds.
135    Standby60 = 0x20,
136
137    /// Standby mode with the pixel temperature only being updated every 10 seconds.
138    Standby10 = 0x21,
139}
140
141#[cfg(test)]
142mod power_control_value_tests {
143    use super::PowerControlValue;
144    use core::convert::TryFrom;
145
146    #[test]
147    fn try_normal() {
148        let normal = PowerControlValue::try_from(0x0);
149        assert!(normal.is_ok());
150        assert_eq!(normal.unwrap(), PowerControlValue::Normal);
151    }
152
153    #[test]
154    fn try_sleep() {
155        let sleep = PowerControlValue::try_from(0x10);
156        assert!(sleep.is_ok());
157        assert_eq!(sleep.unwrap(), PowerControlValue::Sleep);
158    }
159
160    #[test]
161    fn try_standby_60() {
162        let standby_60 = PowerControlValue::try_from(0x20);
163        assert!(standby_60.is_ok());
164        assert_eq!(standby_60.unwrap(), PowerControlValue::Standby60);
165    }
166
167    #[test]
168    fn try_standby_10() {
169        let standby_10 = PowerControlValue::try_from(0x21);
170        assert!(standby_10.is_ok());
171        assert_eq!(standby_10.unwrap(), PowerControlValue::Standby10);
172    }
173
174    #[test]
175    fn unknown() {
176        let unknown = PowerControlValue::try_from(u8::MAX);
177        assert!(unknown.is_err());
178    }
179}
180
181/// There are two kinds of soft reset available by writing to [Register::Reset]. Only use
182/// [ResetValue::Initial] when changing from [sleep](PowerControlValue::sleep) to
183/// [normal](PowerControlValue::Normal) mode. The datasheet emphasizes that other values are not to
184/// be used.
185#[derive(Clone, Copy, Debug, PartialEq, IntoPrimitive, TryFromPrimitive)]
186#[repr(u8)]
187pub enum ResetValue {
188    /// Resets [Register::Status] and the interrupt table.
189    Flag = 0x30,
190
191    /// A [Flag] reset as well as re-reading sensor adjustment values.
192    Initial = 0x3F,
193}
194
195#[cfg(test)]
196mod reset_value_tests {
197    use super::ResetValue;
198    use core::convert::TryFrom;
199
200    #[test]
201    fn try_flag() {
202        let flag = ResetValue::try_from(0x30);
203        assert!(flag.is_ok());
204        assert_eq!(flag.unwrap(), ResetValue::Flag);
205    }
206
207    #[test]
208    fn try_initial() {
209        let initial = ResetValue::try_from(0x3F);
210        assert!(initial.is_ok());
211        assert_eq!(initial.unwrap(), ResetValue::Initial);
212    }
213
214    #[test]
215    fn try_unknown() {
216        let unknown = ResetValue::try_from(0);
217        assert!(unknown.is_err());
218    }
219}
220
221/// The frame rate of the camera. Internally, the sensor always runs at 10 FPS, but in 1 FPS mode
222/// it is averaging the frames internally to reduce noise.
223/// The names are slightly different from those used in the datasheet to conform to Rust's
224/// identifier rules.
225#[derive(Clone, Copy, Debug, PartialEq, IntoPrimitive, TryFromPrimitive)]
226#[repr(u8)]
227pub enum FrameRateValue {
228    /// 1 FPS.
229    Fps1 = 1,
230
231    /// 10 FPS.
232    #[num_enum(alternatives = [10])]
233    Fps10 = 0,
234}
235
236#[cfg(test)]
237mod frame_rate_tests {
238    use super::FrameRateValue;
239    use core::convert::TryFrom;
240
241    #[test]
242    fn try_1() {
243        let fps = FrameRateValue::try_from(1);
244        assert!(fps.is_ok());
245        assert_eq!(fps.unwrap(), FrameRateValue::Fps1);
246    }
247
248    #[test]
249    fn try_0() {
250        let fps = FrameRateValue::try_from(0);
251        assert!(fps.is_ok());
252        assert_eq!(fps.unwrap(), FrameRateValue::Fps10);
253    }
254
255    #[test]
256    fn try_10() {
257        let fps = FrameRateValue::try_from(10);
258        assert!(fps.is_ok());
259        assert_eq!(fps.unwrap(), FrameRateValue::Fps10);
260    }
261
262    #[test]
263    fn try_unknown() {
264        let unknown = FrameRateValue::try_from(20);
265        assert!(unknown.is_err());
266    }
267}
268
269/// How interrupts should be triggered.
270#[derive(Clone, Copy, Debug, PartialEq, IntoPrimitive)]
271#[repr(u8)]
272pub enum InterruptControlMode {
273    /// Interrupt triggered when an absolute temperature threshold is crossed.
274    Absolute = 0x2,
275
276    /// Interrupt triggered when the change in temperature has exceeded a threshold.
277    Difference = 0x0,
278}
279
280impl From<u8> for InterruptControlMode {
281    fn from(value: u8) -> Self {
282        match value & 0x2 {
283            0x2 => Self::Absolute,
284            _ => Self::Difference,
285        }
286    }
287}
288
289impl Default for InterruptControlMode {
290    // The initial value for the interrupt control register is 0x00
291    fn default() -> Self {
292        Self::Difference
293    }
294}
295
296#[cfg(test)]
297mod interrupt_control_mode_tests {
298    use super::InterruptControlMode;
299
300    #[test]
301    fn from_int() {
302        assert_eq!(
303            InterruptControlMode::from(0),
304            InterruptControlMode::Difference
305        );
306        assert_eq!(
307            InterruptControlMode::from(1),
308            InterruptControlMode::Difference
309        );
310        assert_eq!(
311            InterruptControlMode::from(2),
312            InterruptControlMode::Absolute
313        );
314    }
315
316    #[test]
317    fn default() {
318        assert_eq!(
319            InterruptControlMode::default(),
320            InterruptControlMode::Difference
321        );
322    }
323}
324
325/// A bitfield for controlling interrupts on the device.
326#[derive(Clone, Copy, Debug, Default, PartialEq)]
327pub struct InterruptControlValue {
328    /// Controls when interrupts are generated.
329    mode: InterruptControlMode,
330
331    /// If interrupts are enabled. This setting is only applicable when in
332    /// normal or one of the standby [modes][PowerControlValue].
333    enabled: bool,
334}
335
336impl InterruptControlValue {
337    /// Get the current interrupt mode.
338    pub fn mode(&self) -> InterruptControlMode {
339        self.mode
340    }
341
342    /// Set the interrupt mode.
343    pub fn set_mode(&mut self, mode: InterruptControlMode) {
344        self.mode = mode
345    }
346
347    /// Test if interrupts are enabled.
348    pub fn enabled(&self) -> bool {
349        self.enabled
350    }
351
352    /// Enable interrupts.
353    pub fn enable(&mut self) {
354        self.enabled = true
355    }
356
357    /// Disable interrupts.
358    pub fn disable(&mut self) {
359        self.enabled = false
360    }
361}
362
363impl From<u8> for InterruptControlValue {
364    fn from(value: u8) -> Self {
365        /* There are two bits relevant to the interrupt control, 0 and 1.
366         * Bit 0 controls whether or not interrupts are enabled
367         * Bit 1 controls the interrupt trigger mode.
368         */
369        Self {
370            mode: InterruptControlMode::from(value),
371            enabled: (value & 0x1) == 1,
372        }
373    }
374}
375
376impl From<InterruptControlValue> for bool {
377    fn from(value: InterruptControlValue) -> Self {
378        value.enabled
379    }
380}
381
382impl From<InterruptControlValue> for u8 {
383    fn from(value: InterruptControlValue) -> Self {
384        (value.mode as u8) | (value.enabled as u8)
385    }
386}
387
388#[cfg(test)]
389mod interrupt_control_value_tests {
390    use super::{InterruptControlMode, InterruptControlValue};
391
392    #[test]
393    fn from_byte() {
394        let disabled_difference = InterruptControlValue::from(0x0);
395        assert_eq!(disabled_difference.mode(), InterruptControlMode::Difference);
396        assert!(!disabled_difference.enabled());
397        let enabled_difference = InterruptControlValue::from(0x1);
398        assert_eq!(enabled_difference.mode(), InterruptControlMode::Difference);
399        assert!(enabled_difference.enabled());
400        let disabled_absolute = InterruptControlValue::from(0x2);
401        assert_eq!(disabled_absolute.mode(), InterruptControlMode::Absolute);
402        assert!(!disabled_absolute.enabled());
403        let enabled_absolute = InterruptControlValue::from(0x3);
404        assert_eq!(enabled_absolute.mode(), InterruptControlMode::Absolute);
405        assert!(enabled_absolute.enabled());
406    }
407
408    // Test that setting bits outside of the defined values are ignored
409    #[test]
410    fn from_byte_ignore_extra() {
411        let disabled_difference = InterruptControlValue::from(0x10);
412        assert_eq!(disabled_difference.mode(), InterruptControlMode::Difference);
413        assert!(!disabled_difference.enabled());
414        let enabled_difference = InterruptControlValue::from(0x11);
415        assert_eq!(enabled_difference.mode(), InterruptControlMode::Difference);
416        assert!(enabled_difference.enabled());
417        let disabled_absolute = InterruptControlValue::from(0x12);
418        assert_eq!(disabled_absolute.mode(), InterruptControlMode::Absolute);
419        assert!(!disabled_absolute.enabled());
420        let enabled_absolute = InterruptControlValue::from(0x13);
421        assert_eq!(enabled_absolute.mode(), InterruptControlMode::Absolute);
422        assert!(enabled_absolute.enabled());
423    }
424
425    #[test]
426    fn to_bool() {
427        // NOTE: there isn't a public constructor besides the [From] traits, so use that.
428        let disabled = InterruptControlValue::from(0x0);
429        assert!(!bool::from(disabled));
430        let enabled = InterruptControlValue::from(0x1);
431        assert!(bool::from(enabled));
432    }
433
434    #[test]
435    fn to_byte() {
436        // Just round-trip byte values.
437        for byte in 0..4 {
438            let value = InterruptControlValue::from(byte);
439            assert_eq!(byte, u8::from(value));
440        }
441    }
442
443    #[test]
444    fn set_enabled() {
445        let mut value = InterruptControlValue::default();
446        // Default is to be disabled
447        assert!(!value.enabled());
448        // Disabling something already disabled doesn't enable it.
449        value.disable();
450        assert!(!value.enabled());
451        // Disabled -> Enabled
452        value.enable();
453        assert!(value.enabled());
454        // Enabling something already enabled doesn't disable it.
455        value.enable();
456        assert!(value.enabled());
457        // Enabled -> Disabled
458        value.disable();
459        assert!(!value.enabled());
460    }
461
462    #[test]
463    fn set_mode() {
464        let mut value = InterruptControlValue::default();
465        // Default is difference mode
466        assert_eq!(value.mode(), InterruptControlMode::Difference);
467        // Difference -> Absolute
468        value.set_mode(InterruptControlMode::Absolute);
469        assert_eq!(value.mode(), InterruptControlMode::Absolute);
470        // Absolute -> Difference
471        value.set_mode(InterruptControlMode::Difference);
472        assert_eq!(value.mode(), InterruptControlMode::Difference);
473    }
474}
475
476#[derive(Clone, Copy, Debug, PartialEq)]
477#[repr(u8)]
478enum StatusBits {
479    TemperatureOverflow = 0x4,
480    Interrupt = 0x2,
481}
482
483/// A bitfield for the status flags of the device. This value is read from [Register::Status] and
484/// written to [Register::StatusClear].
485#[derive(Clone, Copy, Debug, Default, PartialEq)]
486pub struct StatusValue {
487    /// Set when the analog to digital conversion for the camera sensor overflows (in other words,
488    /// the camera sees something too hot).
489    temperature_overflow: bool,
490
491    /// Set when an interrupt has fired.
492    interrupt: bool,
493}
494
495impl StatusValue {
496    pub fn new(overflow: bool, interrupt: bool) -> Self {
497        Self {
498            temperature_overflow: overflow,
499            interrupt,
500        }
501    }
502
503    pub fn temperature_overflow(&self) -> bool {
504        self.temperature_overflow
505    }
506    pub fn interrupt(&self) -> bool {
507        self.interrupt
508    }
509}
510
511impl From<u8> for StatusValue {
512    fn from(value: u8) -> Self {
513        // The two bits we're concerned with are 1 and 2 (still 0-indexed).
514        // Bit 1 is the interrupt flag, and bit 2 is the overflow flag.
515        let temperature_overflow = (value & StatusBits::TemperatureOverflow as u8)
516            == StatusBits::TemperatureOverflow as u8;
517        let interrupt = (value & StatusBits::Interrupt as u8) == StatusBits::Interrupt as u8;
518        Self {
519            temperature_overflow,
520            interrupt,
521        }
522    }
523}
524
525impl From<StatusValue> for u8 {
526    fn from(value: StatusValue) -> Self {
527        let mut bitfield = 0u8;
528        if value.temperature_overflow {
529            bitfield |= StatusBits::TemperatureOverflow as u8;
530        }
531        if value.interrupt {
532            bitfield |= StatusBits::Interrupt as u8;
533        }
534        bitfield
535    }
536}
537
538#[cfg(test)]
539mod test_status_value {
540    use super::{StatusBits, StatusValue};
541
542    #[test]
543    fn create_and_access() {
544        for overflow in [true, false].iter() {
545            for interrupt in [true, false].iter() {
546                let value = StatusValue::new(*overflow, *interrupt);
547                assert_eq!(value.temperature_overflow(), *overflow);
548                assert_eq!(value.interrupt(), *interrupt);
549            }
550        }
551    }
552
553    #[test]
554    fn byte_no_flags() {
555        let value = StatusValue::from(0x0);
556        assert!(!value.temperature_overflow());
557        assert!(!value.interrupt());
558        assert_eq!(u8::from(value), 0x0);
559    }
560
561    #[test]
562    fn byte_only_overflow() {
563        let value = StatusValue::from(StatusBits::TemperatureOverflow as u8);
564        assert!(value.temperature_overflow());
565        assert!(!value.interrupt());
566        assert_eq!(u8::from(value), StatusBits::TemperatureOverflow as u8);
567    }
568
569    #[test]
570    fn byte_only_interrupt() {
571        let value = StatusValue::from(StatusBits::Interrupt as u8);
572        assert!(!value.temperature_overflow());
573        assert!(value.interrupt());
574        assert_eq!(u8::from(value), StatusBits::Interrupt as u8);
575    }
576
577    #[test]
578    fn byte_both_flags() {
579        let both_bits = StatusBits::Interrupt as u8 | StatusBits::TemperatureOverflow as u8;
580        let value = StatusValue::from(both_bits);
581        assert!(value.temperature_overflow());
582        assert!(value.interrupt());
583        assert_eq!(u8::from(value), both_bits);
584    }
585
586    #[test]
587    fn ignore_undefined() {
588        let all_set = StatusValue::from(0xF);
589        assert!(all_set.temperature_overflow());
590        assert!(all_set.interrupt());
591        assert_eq!(
592            u8::from(all_set),
593            StatusBits::Interrupt as u8 | StatusBits::TemperatureOverflow as u8
594        );
595        let none_set = StatusValue::from(0x9);
596        assert!(!none_set.temperature_overflow());
597        assert!(!none_set.interrupt());
598        assert_eq!(u8::from(none_set), 0x0);
599    }
600}
601
602/// Value for [Register::Average], controlling whether or not the values presented by the sensor
603/// are processed as a moving average of previous frames or not. Frankly the documentation of this
604/// feature is lacking, and it's unclear to me what it actually does while the different frame
605/// rates are set.
606#[derive(Clone, Copy, Debug, PartialEq, IntoPrimitive)]
607#[repr(u8)]
608pub enum AverageValue {
609    Disabled = 0x00,
610    Enabled = 0x20,
611}
612
613impl From<bool> for AverageValue {
614    fn from(value: bool) -> Self {
615        if value {
616            Self::Enabled
617        } else {
618            Self::Disabled
619        }
620    }
621}
622
623impl From<u8> for AverageValue {
624    fn from(value: u8) -> Self {
625        match value & 0x20 {
626            0x20 => Self::Enabled,
627            _ => Self::Disabled,
628        }
629    }
630}
631
632impl From<AverageValue> for bool {
633    fn from(value: AverageValue) -> Self {
634        value == AverageValue::Enabled
635    }
636}
637
638impl Default for AverageValue {
639    fn default() -> Self {
640        Self::Disabled
641    }
642}
643
644#[cfg(test)]
645mod average_tests {
646    use super::AverageValue;
647
648    #[test]
649    fn from_bool() {
650        assert_eq!(AverageValue::from(false), AverageValue::Disabled);
651        assert_eq!(AverageValue::from(true), AverageValue::Enabled);
652    }
653
654    #[test]
655    fn from_byte() {
656        // First the two expected values
657        assert_eq!(AverageValue::from(0x0), AverageValue::Disabled);
658        assert_eq!(AverageValue::from(0x20), AverageValue::Enabled);
659        // And that undefined bits are ignored
660        assert_eq!(AverageValue::from(0xF), AverageValue::Disabled);
661        assert_eq!(AverageValue::from(0xFF), AverageValue::Enabled);
662    }
663
664    #[test]
665    fn to_bool() {
666        assert!(!bool::from(AverageValue::Disabled));
667        assert!(bool::from(AverageValue::Enabled));
668    }
669}