extern crate embedded_hal_mock as hal; use hal::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 );