mirror of https://github.com/eldruin/ds323x-rs
466 lines
15 KiB
Rust
466 lines
15 KiB
Rust
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]
|
|
)]
|
|
);
|
|
get_invalid_test!(
|
|
cannot_get_invalid_ds3232,
|
|
$method,
|
|
new_ds3232,
|
|
destroy_ds3232,
|
|
[I2cTrans::write_read(
|
|
DEV_ADDR,
|
|
vec![Register::MONTH],
|
|
vec![BitFlags::CENTURY]
|
|
)]
|
|
);
|
|
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 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 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, [0], [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 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);
|
|
}
|