1mod address;
5mod eeprom;
6pub mod hamming;
7
8#[cfg_attr(feature = "std", allow(unused_imports))]
11use num_traits::Float;
12
13use core::iter;
14use core::cmp::Ordering;
15
16use crate::common::{Address, MelexisCamera, PixelAddressRange};
17use crate::register::{AccessPattern, Subpage};
18use crate::util::Sealed;
19
20pub use address::RamAddress;
21pub use eeprom::Mlx90641Calibration;
22
23#[derive(Clone, Debug, PartialEq)]
28pub struct Mlx90641();
29
30impl Sealed for Mlx90641 {}
31
32impl MelexisCamera for Mlx90641 {
33 type PixelRangeIterator = SubpageInterleave;
34 type PixelsInSubpageIterator = iter::Take<iter::Repeat<bool>>;
35
36 fn pixel_ranges(subpage: Subpage, _access_pattern: AccessPattern) -> Self::PixelRangeIterator {
37 SubpageInterleave::new(subpage)
39 }
40
41 fn pixels_in_subpage(
42 _subpage: Subpage,
43 _access_pattern: AccessPattern,
44 ) -> Self::PixelsInSubpageIterator {
45 iter::repeat(true).take(Self::NUM_PIXELS)
47 }
48
49 const T_A_V_BE: Address = Address::new(RamAddress::AmbientTemperatureVoltageBe as u16);
50
51 const T_A_PTAT: Address = Address::new(RamAddress::AmbientTemperatureVoltage as u16);
52
53 fn compensation_pixel(subpage: Subpage) -> Address {
54 match subpage {
55 Subpage::Zero => RamAddress::CompensationPixelZero,
56 Subpage::One => RamAddress::CompensationPixelOne,
57 }
58 .into()
59 }
60
61 const GAIN: Address = Address::new(RamAddress::Gain as u16);
62
63 const V_DD_PIXEL: Address = Address::new(RamAddress::PixelSupplyVoltage as u16);
64
65 fn resolution_correction(calibrated_resolution: u8, current_resolution: u8) -> f32 {
66 let resolution_exp: i8 = calibrated_resolution as i8 - current_resolution as i8;
68 f32::from(resolution_exp).exp2()
70 }
71
72 const BASIC_TEMPERATURE_RANGE: usize = 2;
74
75 const SELF_HEATING: f32 = 5.0;
77
78 const HEIGHT: usize = 12;
79
80 const WIDTH: usize = 16;
81
82 const NUM_PIXELS: usize = Self::HEIGHT * Self::WIDTH;
83}
84
85#[derive(Clone, Copy, Debug)]
86pub struct SubpageInterleave {
87 stride_count: u16,
88 base_address: u16,
89}
90
91impl SubpageInterleave {
92 const STRIDE_LENGTH: u16 = 32 * 2;
103
104 const PIXEL_START_ADDRESS: u16 = RamAddress::Base as u16;
106
107 const NUM_STRIDES: u16 = (Mlx90641::HEIGHT / 2) as u16;
109
110 fn new(subpage: Subpage) -> Self {
111 let starting_address: u16 = match subpage {
112 Subpage::Zero => Self::PIXEL_START_ADDRESS,
113 Subpage::One => Self::PIXEL_START_ADDRESS + (Self::STRIDE_LENGTH / 2),
115 };
116 Self {
117 stride_count: 0,
118 base_address: starting_address,
119 }
120 }
121}
122
123impl iter::Iterator for SubpageInterleave {
124 type Item = PixelAddressRange;
125
126 fn next(&mut self) -> Option<Self::Item> {
127 match self.stride_count.cmp(&Self::NUM_STRIDES) {
129 Ordering::Less => {
130 let next_value = PixelAddressRange {
131 start_address: (self.base_address + self.stride_count * Self::STRIDE_LENGTH)
132 .into(),
133 buffer_offset: (self.stride_count * Self::STRIDE_LENGTH) as usize,
134 length: Self::STRIDE_LENGTH as usize,
135 };
136 self.stride_count += 1;
137 Some(next_value)
138 }
139 _ => None,
140 }
141 }
142}
143
144#[cfg(test)]
145mod test {
146 use crate::{AccessPattern, MelexisCamera, Resolution, Subpage};
147
148 use super::Mlx90641;
149
150 #[test]
151 fn pixels_in_subpage() {
152 let mut count = 0;
153 let sub0 = Mlx90641::pixels_in_subpage(Subpage::Zero, AccessPattern::Interleave);
155 let sub1 = Mlx90641::pixels_in_subpage(Subpage::One, AccessPattern::Interleave);
156 for (zero, one) in sub0.zip(sub1) {
157 assert_eq!(zero, one, "MLX90641 doesn't vary pixels on subpages");
158 assert!(zero, "Every pixel is valid for MLX90641");
159 count += 1;
160 }
161 assert_eq!(
162 count,
163 Mlx90641::NUM_PIXELS,
164 "Ever pixels needs a value for pixels_in_subpage()"
165 );
166 }
167
168 #[test]
169 fn resolution_correction() {
170 let resolutions = [
171 (Resolution::Sixteen, 4.0),
172 (Resolution::Seventeen, 2.0),
173 (Resolution::Eighteen, 1.0),
174 (Resolution::Nineteen, 0.5),
175 ];
176 for (register_resolution, expected) in resolutions {
177 assert_eq!(
178 Mlx90641::resolution_correction(
179 Resolution::Eighteen as u8,
181 register_resolution as u8
182 ),
183 expected,
184 )
185 }
186 }
187}