use embedded_hal_mock::eh1::{i2c::Transaction as I2cTrans, spi::Transaction as SpiTrans}; use rtcc::NaiveDateTime; mod common; use self::common::{ destroy_ds3231, destroy_ds3232, destroy_ds3234, new_ds3231, new_ds3232, new_ds3234, BitFlags, Register, DEVICE_ADDRESS as DEV_ADDR, }; #[allow(unused)] // Rust 1.31.0 is confused due to the macros use ds323x::Rtcc; use ds323x::{DateTimeAccess, Error, Hours, NaiveDate, NaiveTime}; fn new_datetime(y: i32, mo: u32, d: u32, h: u32, min: u32, s: u32) -> NaiveDateTime { NaiveDate::from_ymd_opt(y, mo, d) .unwrap() .and_hms_opt(h, min, s) .unwrap() } fn new_date(y: i32, mo: u32, d: u32) -> NaiveDate { NaiveDate::from_ymd_opt(y, mo, d).unwrap() } macro_rules! read_set_param_write_two_test { ($name:ident, $method:ident, $value:expr, $register:ident, $binary_value1_read:expr, $bin1:expr, $bin2:expr) => { _set_param_test!( $name, $method, $value, [ I2cTrans::write_read( DEV_ADDR, vec![Register::$register], vec![$binary_value1_read] ), I2cTrans::write(DEV_ADDR, vec![Register::$register, $bin1, $bin2]) ], [ SpiTrans::transaction_start(), SpiTrans::transfer_in_place( vec![Register::$register, 0], vec![Register::$register, $binary_value1_read] ), SpiTrans::transaction_end(), SpiTrans::transaction_start(), SpiTrans::write_vec(vec![Register::$register + 0x80, $bin1, $bin2]), SpiTrans::transaction_end(), ] ); }; } macro_rules! read_set_param_test { ($name:ident, $method:ident, $register:ident, $value:expr, $binary_value_read:expr, $binary_value_write:expr) => { _set_param_test!( $name, $method, $value, [ I2cTrans::write_read( DEV_ADDR, vec![Register::$register], vec![$binary_value_read] ), I2cTrans::write(DEV_ADDR, vec![Register::$register, $binary_value_write]) ], [ SpiTrans::transaction_start(), SpiTrans::transfer_in_place( vec![Register::$register, 0], vec![Register::$register, $binary_value_read] ), SpiTrans::transaction_end(), SpiTrans::transaction_start(), SpiTrans::write_vec(vec![Register::$register + 0x80, $binary_value_write]), SpiTrans::transaction_end(), ] ); }; } macro_rules! read_get_param_test { ($name:ident, $method:ident, $register:ident, $value:expr, $binary_value:expr) => { _get_param_test!( $name, $method, $value, [ I2cTrans::write_read(DEV_ADDR, vec![Register::MONTH], vec![1]), I2cTrans::write_read(DEV_ADDR, vec![Register::$register], vec![$binary_value]) ], [ SpiTrans::transaction_start(), SpiTrans::transfer_in_place(vec![Register::MONTH, 0], vec![Register::MONTH, 1]), SpiTrans::transaction_end(), SpiTrans::transaction_start(), SpiTrans::transfer_in_place( vec![Register::$register, 0], vec![Register::$register, $binary_value] ), SpiTrans::transaction_end(), ] ); }; } macro_rules! set_invalid_param_test { ($name:ident, $method:ident, $value:expr) => { mod $name { use super::*; set_invalid_test!( cannot_set_invalid_ds3231, $method, new_ds3231, destroy_ds3231, $value ); set_invalid_test!( cannot_set_invalid_ds3232, $method, new_ds3232, destroy_ds3232, $value ); set_invalid_test!( cannot_set_invalid_ds3234, $method, new_ds3234, destroy_ds3234, $value ); } }; } macro_rules! set_invalid_param_range_test { ($name:ident, $method:ident, $too_small_value:expr, $too_big_value:expr) => { mod $name { use super::*; set_invalid_param_test!(too_small, $method, $too_small_value); set_invalid_param_test!(too_big, $method, $too_big_value); } }; } macro_rules! get_invalid_device_century_test { ($name:ident, $method:ident) => { mod $name { use super::*; get_invalid_test!( cannot_get_invalid_ds3231, $method, new_ds3231, destroy_ds3231, [I2cTrans::write_read( DEV_ADDR, vec![Register::MONTH], vec![BitFlags::CENTURY | 0] )] ); get_invalid_test!( cannot_get_invalid_ds3232, $method, new_ds3232, destroy_ds3232, [I2cTrans::write_read( DEV_ADDR, vec![Register::MONTH], vec![BitFlags::CENTURY | 0] )] ); get_invalid_test!( cannot_get_invalid_ds3234, $method, new_ds3234, destroy_ds3234, [ SpiTrans::transaction_start(), SpiTrans::transfer_in_place( vec![Register::MONTH, 0], vec![Register::MONTH, BitFlags::CENTURY | 0] ), SpiTrans::transaction_end(), ] ); } }; } macro_rules! for_all { ($name:ident) => { mod $name { use super::*; $name!(for_ds3231, new_ds3231, destroy_ds3231); $name!(for_ds3232, new_ds3232, destroy_ds3232); $name!(for_ds3234, new_ds3234, destroy_ds3234); } }; } // TODO set/get date // TODO set/get time mod seconds { use super::*; read_get_param_test!(get, seconds, SECONDS, 1, 1); set_param_test!(set, set_seconds, SECONDS, 1, 1); set_invalid_param_test!(invalid, set_seconds, 60); get_invalid_device_century_test!(invalid_century, seconds); } mod minutes { use super::*; read_get_param_test!(get, minutes, MINUTES, 1, 1); set_param_test!(set, set_minutes, MINUTES, 1, 1); set_invalid_param_test!(invalid, set_minutes, 60); get_invalid_device_century_test!(invalid_century, minutes); } mod hours_24h { use super::*; read_get_param_test!(get, hours, HOURS, Hours::H24(21), 0b0010_0001); set_param_test!(set, set_hours, HOURS, Hours::H24(21), 0b0010_0001); set_invalid_param_test!(invalid, set_hours, Hours::H24(24)); get_invalid_device_century_test!(invalid_century, hours); } mod hours_12h_am { use super::*; read_get_param_test!(get, hours, HOURS, Hours::AM(12), 0b0101_0010); set_param_test!(set, set_hours, HOURS, Hours::AM(12), 0b0101_0010); set_invalid_param_range_test!(invalid, set_hours, Hours::AM(0), Hours::AM(13)); get_invalid_device_century_test!(invalid_century, hours); } mod hours_12h_pm { use super::*; read_get_param_test!(get, hours, HOURS, Hours::PM(12), 0b0111_0010); set_param_test!(set, set_hours, HOURS, Hours::PM(12), 0b0111_0010); set_invalid_param_range_test!(invalid, set_hours, Hours::PM(0), Hours::PM(13)); get_invalid_device_century_test!(invalid_century, hours); } mod weekday { use super::*; read_get_param_test!(get, weekday, DOW, 1, 1); set_param_test!(set, set_weekday, DOW, 1, 1); set_invalid_param_range_test!(invalid, set_weekday, 0, 8); get_invalid_device_century_test!(invalid_century, weekday); } mod day { use super::*; read_get_param_test!(get, day, DOM, 1, 1); set_param_test!(set, set_day, DOM, 1, 1); set_invalid_param_range_test!(invalid, set_day, 0, 32); get_invalid_device_century_test!(invalid_century, day); } mod month { use super::*; get_param_test!(get, month, MONTH, 1, 1); read_set_param_test!(set, set_month, MONTH, 12, 0b0000_0010, 0b0001_0010); set_invalid_param_range_test!(invalid, set_month, 0, 13); get_invalid_device_century_test!(invalid_century, month); } mod year { use super::*; read_get_param_test!(get, year, YEAR, 2099, 0b1001_1001); read_set_param_write_two_test!( set, set_year, 2099, MONTH, 0b1001_0010, 0b0001_0010, 0b1001_1001 ); set_invalid_param_range_test!(invalid, set_year, 1999, 2100); get_invalid_device_century_test!(invalid_century, year); } macro_rules! invalid_dt_test { ($name:ident, $create_method:ident, $destroy_method:ident) => { mod $name { use super::*; #[test] fn datetime_too_small() { let dt = new_datetime(1999, 1, 2, 3, 4, 5); let mut dev = $create_method(&[]); assert_invalid_input_data!(dev.set_datetime(&dt)); $destroy_method(dev); } #[test] fn datetime_too_big() { let dt = new_datetime(2100, 1, 2, 3, 4, 5); let mut dev = $create_method(&[]); assert_invalid_input_data!(dev.set_datetime(&dt)); $destroy_method(dev); } #[test] fn date_too_small() { let d = new_date(1999, 1, 2); let mut dev = $create_method(&[]); assert_invalid_input_data!(dev.set_date(&d)); $destroy_method(dev); } #[test] fn date_too_big() { let d = new_date(2100, 1, 2); let mut dev = $create_method(&[]); assert_invalid_input_data!(dev.set_date(&d)); $destroy_method(dev); } } }; } macro_rules! transactions_i2c_write { ($register:ident, [ $( $exp_bin:expr ),+ ]) => { [ I2cTrans::write(DEV_ADDR, vec![Register::$register, $( $exp_bin ),*]) ] }; } macro_rules! transactions_spi_write { ($register:ident, [ $( $exp_bin:expr ),+ ]) => { [ SpiTrans::transaction_start(), SpiTrans::write_vec(vec![Register::$register + 0x80, $( $exp_bin ),*]), SpiTrans::transaction_end() ] }; } macro_rules! dt_test { ($name:ident, $create_method:ident, $destroy_method:ident, $mac_trans_read:ident, $mac_trans_write:ident) => { mod $name { use super::*; #[test] fn get_datetime() { let dt = new_datetime(2018, 8, 13, 23, 59, 58); let mut dev = $create_method(&$mac_trans_read!( SECONDS, [ 0b0101_1000, 0b0101_1001, 0b0010_0011, 0b0000_0010, 0b0001_0011, 0b0000_1000, 0b0001_1000 ], [0, 0, 0, 0, 0, 0, 0] )); assert_eq!(dt, dev.datetime().unwrap()); $destroy_method(dev); } #[test] fn get_datetime_invalid_century() { let _dt = new_datetime(2018, 8, 13, 23, 59, 58); let mut dev = $create_method(&$mac_trans_read!( SECONDS, [ 0b0101_1000, 0b0101_1001, 0b0010_0011, 0b0000_0010, 0b0001_0011, 0b0000_1000 | BitFlags::CENTURY, 0b0001_1000 ], [0, 0, 0, 0, 0, 0, 0] )); assert_invalid_device_century!(dev.datetime()); $destroy_method(dev); } #[test] fn set_datetime() { let dt = new_datetime(2018, 8, 13, 23, 59, 58); let mut dev = $create_method(&$mac_trans_write!( SECONDS, [ 0b0101_1000, 0b0101_1001, 0b0010_0011, 0b0000_0010, 0b0001_0011, 0b0000_1000, 0b0001_1000 ] )); dev.set_datetime(&dt).unwrap(); $destroy_method(dev); } #[test] fn get_date() { let d = new_date(2018, 8, 13); let mut dev = $create_method(&$mac_trans_read!( DOM, [0b0001_0011, 0b0000_1000, 0b0001_1000], [0, 0, 0] )); assert_eq!(d, dev.date().unwrap()); $destroy_method(dev); } #[test] fn get_date_invalid_century() { let _d = new_date(2018, 8, 13); let mut dev = $create_method(&$mac_trans_read!( DOM, [0b0001_0011, 0b0000_1000 | BitFlags::CENTURY, 0b0001_1000], [0, 0, 0] )); assert_invalid_device_century!(dev.date()); $destroy_method(dev); } #[test] fn set_date() { let d = new_date(2018, 8, 13); let mut dev = $create_method(&$mac_trans_write!( DOW, [0b0000_0010, 0b0001_0011, 0b0000_1000, 0b0001_1000] )); dev.set_date(&d).unwrap(); $destroy_method(dev); } #[test] fn get_time() { let t = NaiveTime::from_hms_opt(23, 59, 58).unwrap(); let month_transaction = $mac_trans_read!(MONTH, [1], [0]); let time_transaction = $mac_trans_read!(SECONDS, [0b0101_1000, 0b0101_1001, 0b0010_0011], [0, 0, 0]); let mut transactions = vec![]; let mut i: usize = 0; while i < month_transaction.len() { transactions.push(month_transaction[i].clone()); i += 1; } let mut j: usize = 0; while j < time_transaction.len() { transactions.push(time_transaction[j].clone()); j += 1; } let mut dev = $create_method(&transactions); assert_eq!(t, dev.time().unwrap()); $destroy_method(dev); } #[test] fn get_time_invalid_century() { let transactions = $mac_trans_read!(MONTH, [0 | BitFlags::CENTURY], [0]); let mut dev = $create_method(&transactions); assert_invalid_device_century!(dev.time()); $destroy_method(dev); } #[test] fn set_time() { let t = NaiveTime::from_hms_opt(23, 59, 58).unwrap(); let mut dev = $create_method(&$mac_trans_write!( SECONDS, [0b0101_1000, 0b0101_1001, 0b0010_0011] )); dev.set_time(&t).unwrap(); $destroy_method(dev); } } }; } mod datetime { use super::*; dt_test!( for_ds3231, new_ds3231, destroy_ds3231, transactions_i2c_read, transactions_i2c_write ); dt_test!( for_ds3232, new_ds3232, destroy_ds3232, transactions_i2c_read, transactions_i2c_write ); dt_test!( for_ds3234, new_ds3234, destroy_ds3234, transactions_spi_read, transactions_spi_write ); for_all!(invalid_dt_test); }