mod address;
mod eeprom;
pub mod hamming;
#[cfg_attr(feature = "std", allow(unused_imports))]
use num_traits::Float;
use core::iter;
use core::cmp::Ordering;
use crate::common::{Address, MelexisCamera, PixelAddressRange};
use crate::register::{AccessPattern, Subpage};
use crate::util::Sealed;
pub use address::RamAddress;
pub use eeprom::Mlx90641Calibration;
#[derive(Clone, Debug, PartialEq)]
pub struct Mlx90641();
impl Sealed for Mlx90641 {}
impl MelexisCamera for Mlx90641 {
type PixelRangeIterator = SubpageInterleave;
type PixelsInSubpageIterator = iter::Take<iter::Repeat<bool>>;
fn pixel_ranges(subpage: Subpage, _access_pattern: AccessPattern) -> Self::PixelRangeIterator {
SubpageInterleave::new(subpage)
}
fn pixels_in_subpage(
_subpage: Subpage,
_access_pattern: AccessPattern,
) -> Self::PixelsInSubpageIterator {
iter::repeat(true).take(Self::NUM_PIXELS)
}
const T_A_V_BE: Address = Address::new(RamAddress::AmbientTemperatureVoltageBe as u16);
const T_A_PTAT: Address = Address::new(RamAddress::AmbientTemperatureVoltage as u16);
fn compensation_pixel(subpage: Subpage) -> Address {
match subpage {
Subpage::Zero => RamAddress::CompensationPixelZero,
Subpage::One => RamAddress::CompensationPixelOne,
}
.into()
}
const GAIN: Address = Address::new(RamAddress::Gain as u16);
const V_DD_PIXEL: Address = Address::new(RamAddress::PixelSupplyVoltage as u16);
fn resolution_correction(calibrated_resolution: u8, current_resolution: u8) -> f32 {
let resolution_exp: i8 = calibrated_resolution as i8 - current_resolution as i8;
f32::from(resolution_exp).exp2()
}
const BASIC_TEMPERATURE_RANGE: usize = 2;
const SELF_HEATING: f32 = 5.0;
const HEIGHT: usize = 12;
const WIDTH: usize = 16;
const NUM_PIXELS: usize = Self::HEIGHT * Self::WIDTH;
}
#[derive(Clone, Copy, Debug)]
pub struct SubpageInterleave {
stride_count: u16,
base_address: u16,
}
impl SubpageInterleave {
const STRIDE_LENGTH: u16 = 32 * 2;
const PIXEL_START_ADDRESS: u16 = RamAddress::Base as u16;
const NUM_STRIDES: u16 = (Mlx90641::HEIGHT / 2) as u16;
fn new(subpage: Subpage) -> Self {
let starting_address: u16 = match subpage {
Subpage::Zero => Self::PIXEL_START_ADDRESS,
Subpage::One => Self::PIXEL_START_ADDRESS + (Self::STRIDE_LENGTH / 2),
};
Self {
stride_count: 0,
base_address: starting_address,
}
}
}
impl iter::Iterator for SubpageInterleave {
type Item = PixelAddressRange;
fn next(&mut self) -> Option<Self::Item> {
match self.stride_count.cmp(&Self::NUM_STRIDES) {
Ordering::Less => {
let next_value = PixelAddressRange {
start_address: (self.base_address + self.stride_count * Self::STRIDE_LENGTH)
.into(),
buffer_offset: (self.stride_count * Self::STRIDE_LENGTH) as usize,
length: Self::STRIDE_LENGTH as usize,
};
self.stride_count += 1;
Some(next_value)
}
_ => None,
}
}
}
#[cfg(test)]
mod test {
use crate::{AccessPattern, MelexisCamera, Resolution, Subpage};
use super::Mlx90641;
#[test]
fn pixels_in_subpage() {
let mut count = 0;
let sub0 = Mlx90641::pixels_in_subpage(Subpage::Zero, AccessPattern::Interleave);
let sub1 = Mlx90641::pixels_in_subpage(Subpage::One, AccessPattern::Interleave);
for (zero, one) in sub0.zip(sub1) {
assert_eq!(zero, one, "MLX90641 doesn't vary pixels on subpages");
assert!(zero, "Every pixel is valid for MLX90641");
count += 1;
}
assert_eq!(
count,
Mlx90641::NUM_PIXELS,
"Ever pixels needs a value for pixels_in_subpage()"
);
}
#[test]
fn resolution_correction() {
let resolutions = [
(Resolution::Sixteen, 4.0),
(Resolution::Seventeen, 2.0),
(Resolution::Eighteen, 1.0),
(Resolution::Nineteen, 0.5),
];
for (register_resolution, expected) in resolutions {
assert_eq!(
Mlx90641::resolution_correction(
Resolution::Eighteen as u8,
register_resolution as u8
),
expected,
)
}
}
}