Add function to set the alarm1 to a date

pull/4/head
Diego Barrios Romero 2018-11-03 08:06:18 +01:00
parent e6a1c4826f
commit 46d6656009
5 changed files with 177 additions and 1 deletions

View File

@ -0,0 +1,71 @@
//! Alarm support
extern crate embedded_hal as hal;
use super::super::{ Ds323x, Hours, Register, BitFlags, Error };
use interface::{ ReadData, WriteData };
use super::{ decimal_to_packed_bcd, hours_to_register };
/// Parameters for setting Alarm1 on a date
#[derive(Debug, Clone, PartialEq)]
pub struct DateAlarm1 {
/// Date (day of month) [1-31]
pub date: u8,
/// Hour
pub hour: Hours,
/// Minute [0-59]
pub minute: u8,
/// Second [0-59]
pub second: u8
}
/// Alarm1 trigger rate
#[derive(Debug, Clone, PartialEq)]
pub enum Alarm1Matching {
/// Alarm once per second.
OncePerSecond,
/// Alarm when seconds match.
SecondsMatch,
/// Alarm when minutes and seconds match.
MinutesAndSecondsMatch,
/// Alarm when hours, minutes and seconds match.
HoursMinutesAndSecondsMatch,
/// Alarm when date/weekday, hours, minutes and seconds match.
AllMatch
}
fn get_matching_mask_alarm1(matching: Alarm1Matching) -> [u8; 4] {
const AM : u8 = BitFlags::ALARM_MATCH;
match matching {
Alarm1Matching::OncePerSecond => [AM, AM, AM, AM],
Alarm1Matching::SecondsMatch => [ 0, AM, AM, AM],
Alarm1Matching::MinutesAndSecondsMatch => [ 0, 0, AM, AM],
Alarm1Matching::HoursMinutesAndSecondsMatch => [ 0, 0, 0, AM],
Alarm1Matching::AllMatch => [ 0, 0, 0, 0],
}
}
impl<DI, IC, E> Ds323x<DI, IC>
where
DI: ReadData<Error = E> + WriteData<Error = E>
{
/// Set Alarm1 for date (day of month).
///
/// Will return an `Error::InvalidInputData` if any of the parameters is out of range.
pub fn set_alarm1_date(&mut self, when: DateAlarm1, matching: Alarm1Matching) -> Result<(), Error<E>> {
if when.date < 1 || when.date > 31 ||
when.minute > 59 ||
when.second > 59 {
return Err(Error::InvalidInputData);
}
let match_mask = get_matching_mask_alarm1(matching);
let mut data = [ Register::ALARM1_SECONDS,
decimal_to_packed_bcd(when.second) | match_mask[0],
decimal_to_packed_bcd(when.minute) | match_mask[1],
hours_to_register(&when.hour)? | match_mask[2],
decimal_to_packed_bcd(when.date) | match_mask[3]];
self.iface.write_data(&mut data)
}
}

View File

@ -1,5 +1,7 @@
mod configuration; mod configuration;
mod status; mod status;
mod alarms;
pub use self::alarms::{ DateAlarm1, Alarm1Matching };
mod datetime; mod datetime;
pub use self::datetime::{ Hours, DateTime }; pub use self::datetime::{ Hours, DateTime };
use super::{ BitFlags, Error }; use super::{ BitFlags, Error };

View File

@ -447,6 +447,7 @@ impl Register {
const AGING_OFFSET : u8 = 0x10; const AGING_OFFSET : u8 = 0x10;
const TEMP_MSB : u8 = 0x11; const TEMP_MSB : u8 = 0x11;
const TEMP_CONV : u8 = 0x13; const TEMP_CONV : u8 = 0x13;
const ALARM1_SECONDS : u8 = 0x07;
} }
struct BitFlags; struct BitFlags;
@ -472,6 +473,7 @@ impl BitFlags {
const ALARM2F : u8 = 0b0000_0010; const ALARM2F : u8 = 0b0000_0010;
const ALARM1F : u8 = 0b0000_0001; const ALARM1F : u8 = 0b0000_0001;
const TEMP_CONV_BAT : u8 = 0b0000_0001; const TEMP_CONV_BAT : u8 = 0b0000_0001;
const ALARM_MATCH : u8 = 0b1000_0000;
} }
const DEVICE_ADDRESS : u8 = 0b110_1000; const DEVICE_ADDRESS : u8 = 0b110_1000;
@ -498,7 +500,7 @@ pub struct Ds323x<DI, IC> {
pub mod interface; pub mod interface;
mod ds323x; mod ds323x;
pub use ds323x::{ Hours, DateTime }; pub use ds323x::{ Hours, DateTime, DateAlarm1, Alarm1Matching };
mod ds3231; mod ds3231;
mod ds3232; mod ds3232;
mod ds3234; mod ds3234;

99
tests/alarms.rs 100644
View File

@ -0,0 +1,99 @@
#[deny(warnings)]
extern crate embedded_hal_mock as hal;
use hal::i2c::Transaction as I2cTrans;
use hal::spi::Transaction as SpiTrans;
mod common;
use common::{ DEVICE_ADDRESS as DEV_ADDR, Register, new_ds3231,
new_ds3232, new_ds3234, destroy_ds3231, destroy_ds3232,
destroy_ds3234, BitFlags as BF };
extern crate ds323x;
use ds323x::{ DateAlarm1, Alarm1Matching as A1M, Hours, Error };
#[macro_export]
macro_rules! _set_invalid_alarm_test {
($name:ident, $method:ident, $create_method:ident, $destroy_method:ident, $alarm:expr, $matching:expr) => {
#[test]
fn $name() {
let mut dev = $create_method(&[]);
assert_invalid_input_data!(dev.$method($alarm, $matching));
$destroy_method(dev);
}
};
}
macro_rules! set_invalid_alarm_test {
($name:ident, $method:ident, $alarm:expr, $matching:expr) => {
mod $name {
use super::*;
_set_invalid_alarm_test!(cannot_set_invalid_ds3231, $method, new_ds3231, destroy_ds3231, $alarm, $matching);
_set_invalid_alarm_test!(cannot_set_invalid_ds3232, $method, new_ds3232, destroy_ds3232, $alarm, $matching);
_set_invalid_alarm_test!(cannot_set_invalid_ds3234, $method, new_ds3234, destroy_ds3234, $alarm, $matching);
}
};
}
mod alarm1 {
use super::*;
set_invalid_alarm_test!(date_invalid_s, set_alarm1_date, DateAlarm1{ date: 1, hour: Hours::H24(1), minute: 1, second: 60 }, A1M::AllMatch);
set_invalid_alarm_test!(date_invalid_min, set_alarm1_date, DateAlarm1{ date: 1, hour: Hours::H24(1), minute: 60, second: 1 }, A1M::AllMatch);
set_invalid_alarm_test!(date_invalid_h, set_alarm1_date, DateAlarm1{ date: 1, hour: Hours::H24(24), minute: 1, second: 1 }, A1M::AllMatch);
set_invalid_alarm_test!(date_invalid_am1, set_alarm1_date, DateAlarm1{ date: 1, hour: Hours::AM(0), minute: 1, second: 1 }, A1M::AllMatch);
set_invalid_alarm_test!(date_invalid_am2, set_alarm1_date, DateAlarm1{ date: 1, hour: Hours::AM(13), minute: 1, second: 1 }, A1M::AllMatch);
set_invalid_alarm_test!(date_invalid_pm1, set_alarm1_date, DateAlarm1{ date: 1, hour: Hours::PM(0), minute: 1, second: 1 }, A1M::AllMatch);
set_invalid_alarm_test!(date_invalid_pm2, set_alarm1_date, DateAlarm1{ date: 1, hour: Hours::PM(13), minute: 1, second: 1 }, A1M::AllMatch);
set_invalid_alarm_test!(date_invalid_d1, set_alarm1_date, DateAlarm1{ date: 0, hour: Hours::H24(1), minute: 1, second: 1 }, A1M::AllMatch);
set_invalid_alarm_test!(date_invalid_d2, set_alarm1_date, DateAlarm1{ date: 32, hour: Hours::H24(1), minute: 1, second: 1 }, A1M::AllMatch);
}
macro_rules! _set_values_test {
($name:ident, $method:ident, $create_method:ident, $destroy_method:ident, $value1:expr, $value2:expr, $transactions:expr) => {
#[test]
fn $name() {
let trans = $transactions;
let mut dev = $create_method(&trans);
dev.$method($value1, $value2).unwrap();
$destroy_method(dev);
}
};
}
macro_rules! set_values_test {
($name:ident, $method:ident, $value1:expr, $value2:expr, $i2c_transactions:expr, $spi_transactions:expr) => {
mod $name {
use super::*;
_set_values_test!(can_set_ds3231, $method, new_ds3231, destroy_ds3231, $value1, $value2, $i2c_transactions);
_set_values_test!(can_set_ds3232, $method, new_ds3232, destroy_ds3232, $value1, $value2, $i2c_transactions);
_set_values_test!(can_set_ds3234, $method, new_ds3234, destroy_ds3234, $value1, $value2, $spi_transactions);
}
};
}
macro_rules! set_alarm_test {
($name:ident, $method:ident, $alarm:expr, $matching:expr, $register:ident, [ $( $registers:expr ),+ ]) => {
set_values_test!($name, $method, $alarm, $matching,
[ I2cTrans::write(DEV_ADDR, vec![Register::$register, $( $registers ),*]) ],
[ SpiTrans::write(vec![Register::$register + 0x80, $( $registers ),*]) ]);
};
}
const AM : u8 = BF::ALARM_MATCH;
mod alarm1_date {
use super::*;
set_alarm_test!(h24, set_alarm1_date, DateAlarm1{ date: 1, hour: Hours::H24(2), minute: 3, second: 4 }, A1M::AllMatch,
ALARM1_SECONDS, [4, 3, 2, 1]);
set_alarm_test!(am, set_alarm1_date, DateAlarm1{ date: 1, hour: Hours::AM(2), minute: 3, second: 4 }, A1M::AllMatch,
ALARM1_SECONDS, [4, 3, 0b0100_0010, 1]);
set_alarm_test!(pm, set_alarm1_date, DateAlarm1{ date: 1, hour: Hours::PM(2), minute: 3, second: 4 }, A1M::AllMatch,
ALARM1_SECONDS, [4, 3, 0b0110_0010, 1]);
set_alarm_test!(match_hms, set_alarm1_date, DateAlarm1{ date: 1, hour: Hours::H24(2), minute: 3, second: 4 }, A1M::HoursMinutesAndSecondsMatch,
ALARM1_SECONDS, [ 4, 3, 2, AM | 1]);
set_alarm_test!(match_ms, set_alarm1_date, DateAlarm1{ date: 1, hour: Hours::H24(2), minute: 3, second: 4 }, A1M::MinutesAndSecondsMatch,
ALARM1_SECONDS, [ 4, 3, AM | 2, AM | 1]);
set_alarm_test!(match_s, set_alarm1_date, DateAlarm1{ date: 1, hour: Hours::H24(2), minute: 3, second: 4 }, A1M::SecondsMatch,
ALARM1_SECONDS, [ 4, AM | 3, AM | 2, AM | 1]);
set_alarm_test!(match_ops, set_alarm1_date, DateAlarm1{ date: 1, hour: Hours::H24(2), minute: 3, second: 4 }, A1M::OncePerSecond,
ALARM1_SECONDS, [AM | 4, AM | 3, AM | 2, AM | 1]);
}

View File

@ -27,6 +27,7 @@ impl Register {
pub const AGING_OFFSET : u8 = 0x10; pub const AGING_OFFSET : u8 = 0x10;
pub const TEMP_MSB : u8 = 0x11; pub const TEMP_MSB : u8 = 0x11;
pub const TEMP_CONV : u8 = 0x13; pub const TEMP_CONV : u8 = 0x13;
pub const ALARM1_SECONDS : u8 = 0x07;
} }
pub struct BitFlags; pub struct BitFlags;
@ -50,6 +51,7 @@ impl BitFlags {
pub const ALARM2F : u8 = 0b0000_0010; pub const ALARM2F : u8 = 0b0000_0010;
pub const ALARM1F : u8 = 0b0000_0001; pub const ALARM1F : u8 = 0b0000_0001;
pub const TEMP_CONV_BAT : u8 = 0b0000_0001; pub const TEMP_CONV_BAT : u8 = 0b0000_0001;
pub const ALARM_MATCH : u8 = 0b1000_0000;
} }
pub struct DummyOutputPin; pub struct DummyOutputPin;