extern crate embedded_hal_mock as hal;
use hal::eh1::i2c::Transaction as I2cTrans;
extern crate max3010x;
extern crate nb;
use max3010x::{FifoAlmostFullLevelInterrupt, Led, LedPulseWidth, SampleAveraging};
mod base;
use base::{destroy, new, BitFlags as BF, Register as Reg, DEV_ADDR};
read_test!(can_get_rev_id, get_revision_id, [], REV_ID, [0xAB], 0xAB);
read_test!(can_get_part_id, get_part_id, [], PART_ID, [0xAB], 0xAB);
read_test!(
can_get_fifo_overflow,
get_overflow_sample_count,
[],
OVF_COUNTER,
[0x15],
0x15
);
macro_rules! available_sample_count_test {
($name:ident, $wr_ptr:expr, $rd_ptr:expr, $expected:expr) => {
read_test!(
$name,
get_available_sample_count,
[],
FIFO_WR_PTR,
[$wr_ptr, 0, $rd_ptr],
$expected
);
};
}
mod available_sample_count {
use super::*;
available_sample_count_test!(zero, 0, 0, 0);
available_sample_count_test!(one, 1, 0, 1);
available_sample_count_test!(two, 2, 0, 2);
available_sample_count_test!(rollover, 0, 1, 31);
}
#[test]
fn can_start_temp_conversion() {
let transactions = [
I2cTrans::write_read(DEV_ADDR, vec![Reg::TEMP_CONFIG], vec![0]),
I2cTrans::write(DEV_ADDR, vec![Reg::TEMP_CONFIG, BF::TEMP_EN]),
];
let mut dev = new(&transactions);
let result = dev.read_temperature();
assert_would_block!(result);
destroy(dev);
}
#[test]
fn blocks_until_temp_ready() {
let transactions = [I2cTrans::write_read(
DEV_ADDR,
vec![Reg::TEMP_CONFIG],
vec![BF::TEMP_EN],
)];
let mut dev = new(&transactions);
let result = dev.read_temperature();
assert_would_block!(result);
destroy(dev);
}
#[test]
fn can_read_temperature() {
let transactions = [
I2cTrans::write_read(DEV_ADDR, vec![Reg::TEMP_CONFIG], vec![0]),
I2cTrans::write(DEV_ADDR, vec![Reg::TEMP_CONFIG, BF::TEMP_EN]),
I2cTrans::write_read(DEV_ADDR, vec![Reg::TEMP_CONFIG], vec![0]),
I2cTrans::write_read(DEV_ADDR, vec![Reg::TEMP_INT], vec![-128_i8 as u8, 8]),
];
let mut dev = new(&transactions);
assert_would_block!(dev.read_temperature());
let result = dev.read_temperature().unwrap();
assert_near!(-127.5, result, 0.2);
destroy(dev);
}
write_test!(can_shutdown, shutdown, [], MODE, [BF::SHUTDOWN]);
write_test!(can_wake_up, wake_up, [], MODE, [0]);
write_test!(can_reset, reset, [], MODE, [BF::RESET]);
write_test!(can_clear_fifo, clear_fifo, [], FIFO_WR_PTR, [0, 0, 0]);
#[test]
fn read_fifo_no_data_returns0() {
let transactions = [
I2cTrans::write(DEV_ADDR, vec![Reg::MODE, 0b010]),
I2cTrans::write(DEV_ADDR, vec![Reg::FIFO_WR_PTR, 0, 0, 0]),
I2cTrans::write_read(DEV_ADDR, vec![Reg::FIFO_WR_PTR], vec![0, 0, 0]),
];
let dev = new(&transactions);
let mut data = [0; 15];
let mut dev = dev.into_heart_rate().unwrap();
let result = dev.read_fifo(&mut data).unwrap();
assert_eq!(0, result);
destroy(dev);
}
#[test]
fn read_fifo_not_enough_input_data_returns0() {
let transactions = [
I2cTrans::write(DEV_ADDR, vec![Reg::MODE, 0b011]),
I2cTrans::write(DEV_ADDR, vec![Reg::FIFO_WR_PTR, 0, 0, 0]),
];
let dev = new(&transactions);
let mut dev = dev.into_oximeter().unwrap();
let mut data = [0; 1];
let result = dev.read_fifo(&mut data).unwrap();
assert_eq!(0, result);
destroy(dev);
}
fn read_fifo_samples_1channel(pulse_width: LedPulseWidth, spo2_config: u8, shift: usize) {
let transactions = [
I2cTrans::write(DEV_ADDR, vec![Reg::MODE, 0b010]),
I2cTrans::write(DEV_ADDR, vec![Reg::FIFO_WR_PTR, 0, 0, 0]),
I2cTrans::write(DEV_ADDR, vec![Reg::SPO2_CONFIG, spo2_config]),
I2cTrans::write_read(DEV_ADDR, vec![Reg::FIFO_WR_PTR], vec![2, 0, 0]),
I2cTrans::write_read(
DEV_ADDR,
vec![Reg::FIFO_DATA],
vec![
1 << shift,
2 << shift,
3 << shift,
4 << shift,
5 << shift,
6 << shift,
],
),
];
let dev = new(&transactions);
let mut data = [0; 2];
let mut dev = dev.into_heart_rate().unwrap();
dev.set_pulse_width(pulse_width).unwrap();
let result = dev.read_fifo(&mut data).unwrap();
assert_eq!(2, result);
assert_eq!([1 << 16 | 2 << 8 | 3, 4 << 16 | 5 << 8 | 6], data);
destroy(dev);
}
#[test]
fn read_fifo_samples_1channel_pw69() {
read_fifo_samples_1channel(LedPulseWidth::Pw69, 0, 3);
}
#[test]
fn read_fifo_samples_1channel_pw118() {
read_fifo_samples_1channel(LedPulseWidth::Pw118, 1, 2);
}
#[test]
fn read_fifo_samples_1channel_pw215() {
read_fifo_samples_1channel(LedPulseWidth::Pw215, 2, 1);
}
#[test]
fn read_fifo_samples_1channel_pw411() {
read_fifo_samples_1channel(LedPulseWidth::Pw411, 3, 0);
}
fn read_fifo_samples_2channels(pulse_width: LedPulseWidth, spo2_config: u8, shift: usize) {
let transactions = [
I2cTrans::write(DEV_ADDR, vec![Reg::MODE, 0b11]),
I2cTrans::write(DEV_ADDR, vec![Reg::FIFO_WR_PTR, 0, 0, 0]),
I2cTrans::write(DEV_ADDR, vec![Reg::SPO2_CONFIG, spo2_config]),
I2cTrans::write_read(DEV_ADDR, vec![Reg::FIFO_WR_PTR], vec![2, 0, 0]),
I2cTrans::write_read(
DEV_ADDR,
vec![Reg::FIFO_DATA],
vec![
1 << shift,
2 << shift,
3 << shift,
4 << shift,
5 << shift,
6 << shift,
],
),
];
let dev = new(&transactions);
let mut data = [0; 2];
let mut dev = dev.into_oximeter().unwrap();
dev.set_pulse_width(pulse_width).unwrap();
let result = dev.read_fifo(&mut data).unwrap();
assert_eq!(1, result);
assert_eq!([1 << 16 | 2 << 8 | 3, 4 << 16 | 5 << 8 | 6], data);
destroy(dev);
}
#[test]
fn read_fifo_samples_2channels_pw69() {
read_fifo_samples_2channels(LedPulseWidth::Pw69, 0, 3);
}
#[test]
fn read_fifo_samples_2channels_pw118() {
read_fifo_samples_2channels(LedPulseWidth::Pw118, 1, 2);
}
#[test]
fn read_fifo_samples_2channels_pw215() {
read_fifo_samples_2channels(LedPulseWidth::Pw215, 2, 1);
}
#[test]
fn read_fifo_samples_2channels_pw411() {
read_fifo_samples_2channels(LedPulseWidth::Pw411, 3, 0);
}
mod set_pulse_amplitude {
use super::*;
write_test!(led1, set_pulse_amplitude, [Led::Led1, 50], LED1_PA, [50]);
write_test!(led2, set_pulse_amplitude, [Led::Led2, 50], LED2_PA, [50]);
write_test!(all, set_pulse_amplitude, [Led::All, 50], LED1_PA, [50, 50]);
}
macro_rules! sample_avg_test {
($name:ident, $variant:ident, $expected:expr) => {
write_test!(
$name,
set_sample_averaging,
[SampleAveraging::$variant],
FIFO_CONFIG,
[$expected]
);
};
}
sample_avg_test!(sample_avg_1, Sa1, 0);
sample_avg_test!(sample_avg_2, Sa2, 0b0010_0000);
sample_avg_test!(sample_avg_4, Sa4, 0b0100_0000);
sample_avg_test!(sample_avg_8, Sa8, 0b0110_0000);
sample_avg_test!(sample_avg_16, Sa16, 0b1000_0000);
sample_avg_test!(sample_avg_32, Sa32, 0b1010_0000);
macro_rules! fifo_a_full_test {
($name:ident, $variant:ident, $expected:expr) => {
write_test!(
$name,
set_fifo_almost_full_level_interrupt,
[FifoAlmostFullLevelInterrupt::$variant],
FIFO_CONFIG,
[$expected]
);
};
}
fifo_a_full_test!(fifo_a_full_0, L0, 0);
fifo_a_full_test!(fifo_a_full_1, L1, 1);
fifo_a_full_test!(fifo_a_full_2, L2, 2);
fifo_a_full_test!(fifo_a_full_3, L3, 3);
fifo_a_full_test!(fifo_a_full_4, L4, 4);
fifo_a_full_test!(fifo_a_full_5, L5, 5);
fifo_a_full_test!(fifo_a_full_6, L6, 6);
fifo_a_full_test!(fifo_a_full_7, L7, 7);
fifo_a_full_test!(fifo_a_full_8, L8, 8);
fifo_a_full_test!(fifo_a_full_9, L9, 9);
fifo_a_full_test!(fifo_a_full_10, L10, 10);
fifo_a_full_test!(fifo_a_full_11, L11, 11);
fifo_a_full_test!(fifo_a_full_12, L12, 12);
fifo_a_full_test!(fifo_a_full_13, L13, 13);
fifo_a_full_test!(fifo_a_full_14, L14, 14);
fifo_a_full_test!(fifo_a_full_15, L15, 15);
high_low_flag_method_test!(
enable_fifo_rollover,
BF::FIFO_ROLLOVER_EN,
disable_fifo_rollover,
0,
FIFO_CONFIG
);