diff --git a/README.md b/README.md index a037a97..ce1ff20 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ This driver allows you to: - Select the function of the INT/SQW output pin. See `use_int_sqw_output_as_interrupt`. - Enable and disable the square-wave generation. See `enable_square_wave`. - Select the square-wave frequency. See `set_square_wave_frequency`. +- Set alarms 1 and 2 with several matching policies. See `set_alarm1_date`. - Read whether alarms 1 or 2 have matched. See `has_alarm1_matched`. - Clear flag indicating that alarms 1 or 2 have matched. See `clear_alarm1_matched_flag`. - Enable and disable alarms 1 and 2 interrupt generation. See `enable_alarm1_interrupts`. diff --git a/src/ds323x/alarms.rs b/src/ds323x/alarms.rs index 7b7c702..7effa6d 100644 --- a/src/ds323x/alarms.rs +++ b/src/ds323x/alarms.rs @@ -47,6 +47,41 @@ pub enum Alarm1Matching { } +/// Parameters for setting Alarm2 on a date +#[derive(Debug, Clone, PartialEq)] +pub struct DateAlarm2 { + /// Date (day of month) [1-31] + pub date: u8, + /// Hour + pub hour: Hours, + /// Minute [0-59] + pub minute: u8 +} + +/// Parameters for setting Alarm2 on a weekday +#[derive(Debug, Clone, PartialEq)] +pub struct WeekdayAlarm2 { + /// Weekday [1-7] + pub weekday: u8, + /// Hour + pub hour: Hours, + /// Minute [0-59] + pub minute: u8 +} + +/// Alarm2 trigger rate +#[derive(Debug, Clone, PartialEq)] +pub enum Alarm2Matching { + /// Alarm once per minute. (00 seconds of every minute) + OncePerMinute, + /// Alarm when minutes match. + MinutesMatch, + /// Alarm when hours and minutes match. + HoursAndMinutesMatch, + /// Alarm when date/weekday, hours and minutes match. + AllMatch +} + fn get_matching_mask_alarm1(matching: Alarm1Matching) -> [u8; 4] { const AM : u8 = BitFlags::ALARM_MATCH; match matching { @@ -58,6 +93,16 @@ fn get_matching_mask_alarm1(matching: Alarm1Matching) -> [u8; 4] { } } +fn get_matching_mask_alarm2(matching: Alarm2Matching) -> [u8; 3] { + const AM : u8 = BitFlags::ALARM_MATCH; + match matching { + Alarm2Matching::OncePerMinute => [AM, AM, AM], + Alarm2Matching::MinutesMatch => [ 0, AM, AM], + Alarm2Matching::HoursAndMinutesMatch => [ 0, 0, AM], + Alarm2Matching::AllMatch => [ 0, 0, 0], + } +} + impl Ds323x where @@ -99,4 +144,35 @@ where self.iface.write_data(&mut data) } + /// Set Alarm2 for date (day of month). + /// + /// Will return an `Error::InvalidInputData` if any of the parameters is out of range. + pub fn set_alarm2_date(&mut self, when: DateAlarm2, matching: Alarm2Matching) -> Result<(), Error> { + if when.date < 1 || when.date > 31 || + when.minute > 59 { + return Err(Error::InvalidInputData); + } + let match_mask = get_matching_mask_alarm2(matching); + let mut data = [ Register::ALARM2_MINUTES, + decimal_to_packed_bcd(when.minute) | match_mask[0], + hours_to_register(&when.hour)? | match_mask[1], + decimal_to_packed_bcd(when.date) | match_mask[2]]; + self.iface.write_data(&mut data) + } + + /// Set Alarm2 for weekday. + /// + /// Will return an `Error::InvalidInputData` if any of the parameters is out of range. + pub fn set_alarm2_weekday(&mut self, when: WeekdayAlarm2, matching: Alarm2Matching) -> Result<(), Error> { + if when.weekday < 1 || when.weekday > 7 || + when.minute > 59 { + return Err(Error::InvalidInputData); + } + let match_mask = get_matching_mask_alarm2(matching); + let mut data = [ Register::ALARM2_MINUTES, + decimal_to_packed_bcd(when.minute) | match_mask[0], + hours_to_register(&when.hour)? | match_mask[1], + decimal_to_packed_bcd(when.weekday) | match_mask[2] | BitFlags::WEEKDAY]; + self.iface.write_data(&mut data) + } } diff --git a/src/ds323x/mod.rs b/src/ds323x/mod.rs index a2e7d98..a010af0 100644 --- a/src/ds323x/mod.rs +++ b/src/ds323x/mod.rs @@ -1,7 +1,8 @@ mod configuration; mod status; mod alarms; -pub use self::alarms::{ DateAlarm1, WeekdayAlarm1, Alarm1Matching }; +pub use self::alarms::{ DateAlarm1, WeekdayAlarm1, Alarm1Matching, + DateAlarm2, WeekdayAlarm2, Alarm2Matching }; mod datetime; pub use self::datetime::{ Hours, DateTime }; use super::{ BitFlags, Error }; diff --git a/src/lib.rs b/src/lib.rs index b15b257..6bae675 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ //! - Select the function of the INT/SQW output pin. See [`use_int_sqw_output_as_interrupt`]. //! - Enable and disable the square-wave generation. See [`enable_square_wave`]. //! - Select the square-wave frequency. See [`set_square_wave_frequency`]. +//! - Set alarms 1 and 2 with several matching policies. See [`set_alarm1_date`]. //! - Read whether alarms 1 or 2 have matched. See [`has_alarm1_matched`]. //! - Clear flag indicating that alarms 1 or 2 have matched. See [`clear_alarm1_matched_flag`]. //! - Enable and disable alarms 1 and 2 interrupt generation. See [`enable_alarm1_interrupts`]. @@ -37,6 +38,7 @@ //! [`use_int_sqw_output_as_interrupt`]: struct.Ds323x.html#method.use_int_sqw_output_as_interrupt //! [`enable_square_wave`]: struct.Ds323x.html#method.enable_square_wave //! [`set_square_wave_frequency`]: struct.Ds323x.html#method.set_square_wave_frequency +//! [`set_alarm1_date`]: struct.Ds323x.html#method.set_alarm1_date //! [`has_alarm1_matched`]: struct.Ds323x.html#method.has_alarm1_matched //! [`clear_alarm1_matched_flag`]: struct.Ds323x.html#method.clear_alarm1_matched_flag //! [`enable_alarm1_interrupts`]: struct.Ds323x.html#method.enable_alarm1_interrupts @@ -435,19 +437,20 @@ pub enum TempConvRate { struct Register; impl Register { - const SECONDS : u8 = 0x00; - const MINUTES : u8 = 0x01; - const HOURS : u8 = 0x02; - const DOW : u8 = 0x03; - const DOM : u8 = 0x04; - const MONTH : u8 = 0x05; - const YEAR : u8 = 0x06; - const CONTROL : u8 = 0x0E; - const STATUS : u8 = 0x0F; - const AGING_OFFSET : u8 = 0x10; - const TEMP_MSB : u8 = 0x11; - const TEMP_CONV : u8 = 0x13; + const SECONDS : u8 = 0x00; + const MINUTES : u8 = 0x01; + const HOURS : u8 = 0x02; + const DOW : u8 = 0x03; + const DOM : u8 = 0x04; + const MONTH : u8 = 0x05; + const YEAR : u8 = 0x06; const ALARM1_SECONDS : u8 = 0x07; + const ALARM2_MINUTES : u8 = 0x0B; + const CONTROL : u8 = 0x0E; + const STATUS : u8 = 0x0F; + const AGING_OFFSET : u8 = 0x10; + const TEMP_MSB : u8 = 0x11; + const TEMP_CONV : u8 = 0x13; } struct BitFlags; @@ -501,7 +504,8 @@ pub struct Ds323x { pub mod interface; mod ds323x; -pub use ds323x::{ Hours, DateTime, DateAlarm1, WeekdayAlarm1, Alarm1Matching }; +pub use ds323x::{ Hours, DateTime, DateAlarm1, WeekdayAlarm1, Alarm1Matching, + DateAlarm2, WeekdayAlarm2, Alarm2Matching }; mod ds3231; mod ds3232; mod ds3234; diff --git a/tests/alarms.rs b/tests/alarms.rs index 8636490..4816eb9 100644 --- a/tests/alarms.rs +++ b/tests/alarms.rs @@ -8,8 +8,8 @@ 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, WeekdayAlarm1, Alarm1Matching as A1M, Hours, Error }; -use ds323x::{ DateAlarm1, Alarm1Matching as A1M, Hours, Error }; +use ds323x::{ DateAlarm1, WeekdayAlarm1, Alarm1Matching as A1M, DateAlarm2, + WeekdayAlarm2, Alarm2Matching as A2M, Hours, Error }; #[macro_export] macro_rules! _set_invalid_alarm_test { @@ -56,8 +56,29 @@ mod alarm1 { set_invalid_alarm_test!(wd_invalid_d1, set_alarm1_weekday, WeekdayAlarm1{ weekday: 0, hour: Hours::H24(1), minute: 1, second: 1 }, A1M::AllMatch); set_invalid_alarm_test!(wd_invalid_d2, set_alarm1_weekday, WeekdayAlarm1{ weekday: 32, hour: Hours::H24(1), minute: 1, second: 1 }, A1M::AllMatch); } + +mod alarm2 { + use super::*; + set_invalid_alarm_test!(date_invalid_min, set_alarm2_date, DateAlarm2{ date: 1, hour: Hours::H24(1), minute: 60 }, A2M::AllMatch); + set_invalid_alarm_test!(date_invalid_h, set_alarm2_date, DateAlarm2{ date: 1, hour: Hours::H24(24), minute: 1 }, A2M::AllMatch); + set_invalid_alarm_test!(date_invalid_am1, set_alarm2_date, DateAlarm2{ date: 1, hour: Hours::AM(0), minute: 1 }, A2M::AllMatch); + set_invalid_alarm_test!(date_invalid_am2, set_alarm2_date, DateAlarm2{ date: 1, hour: Hours::AM(13), minute: 1 }, A2M::AllMatch); + set_invalid_alarm_test!(date_invalid_pm1, set_alarm2_date, DateAlarm2{ date: 1, hour: Hours::PM(0), minute: 1 }, A2M::AllMatch); + set_invalid_alarm_test!(date_invalid_pm2, set_alarm2_date, DateAlarm2{ date: 1, hour: Hours::PM(13), minute: 1 }, A2M::AllMatch); + set_invalid_alarm_test!(date_invalid_d1, set_alarm2_date, DateAlarm2{ date: 0, hour: Hours::H24(1), minute: 1 }, A2M::AllMatch); + set_invalid_alarm_test!(date_invalid_d2, set_alarm2_date, DateAlarm2{ date: 32, hour: Hours::H24(1), minute: 1 }, A2M::AllMatch); + + set_invalid_alarm_test!(wd_invalid_min, set_alarm2_weekday, WeekdayAlarm2{ weekday: 1, hour: Hours::H24(1), minute: 60 }, A2M::AllMatch); + set_invalid_alarm_test!(wd_invalid_h, set_alarm2_weekday, WeekdayAlarm2{ weekday: 1, hour: Hours::H24(24), minute: 1 }, A2M::AllMatch); + set_invalid_alarm_test!(wd_invalid_am1, set_alarm2_weekday, WeekdayAlarm2{ weekday: 1, hour: Hours::AM(0), minute: 1 }, A2M::AllMatch); + set_invalid_alarm_test!(wd_invalid_am2, set_alarm2_weekday, WeekdayAlarm2{ weekday: 1, hour: Hours::AM(13), minute: 1 }, A2M::AllMatch); + set_invalid_alarm_test!(wd_invalid_pm1, set_alarm2_weekday, WeekdayAlarm2{ weekday: 1, hour: Hours::PM(0), minute: 1 }, A2M::AllMatch); + set_invalid_alarm_test!(wd_invalid_pm2, set_alarm2_weekday, WeekdayAlarm2{ weekday: 1, hour: Hours::PM(13), minute: 1 }, A2M::AllMatch); + set_invalid_alarm_test!(wd_invalid_d1, set_alarm2_weekday, WeekdayAlarm2{ weekday: 0, hour: Hours::H24(1), minute: 1 }, A2M::AllMatch); + set_invalid_alarm_test!(wd_invalid_d2, set_alarm2_weekday, WeekdayAlarm2{ weekday: 32, hour: Hours::H24(1), minute: 1 }, A2M::AllMatch); } + macro_rules! _set_values_test { ($name:ident, $method:ident, $create_method:ident, $destroy_method:ident, $value1:expr, $value2:expr, $transactions:expr) => { #[test] @@ -128,3 +149,37 @@ mod alarm1_weekday { set_alarm_test!(match_ops, set_alarm1_weekday, WeekdayAlarm1{ weekday: 1, hour: Hours::H24(2), minute: 3, second: 4 }, A1M::OncePerSecond, ALARM1_SECONDS, [AM | 4, AM | 3, AM | 2, AM | BF::WEEKDAY | 1]); } + +mod alarm2_date { + use super::*; + set_alarm_test!(h24, set_alarm2_date, DateAlarm2{ date: 1, hour: Hours::H24(2), minute: 3 }, A2M::AllMatch, + ALARM2_MINUTES, [3, 2, 1]); + set_alarm_test!(am, set_alarm2_date, DateAlarm2{ date: 1, hour: Hours::AM(2), minute: 3 }, A2M::AllMatch, + ALARM2_MINUTES, [3, 0b0100_0010, 1]); + set_alarm_test!(pm, set_alarm2_date, DateAlarm2{ date: 1, hour: Hours::PM(2), minute: 3 }, A2M::AllMatch, + ALARM2_MINUTES, [3, 0b0110_0010, 1]); + + set_alarm_test!(match_hm, set_alarm2_date, DateAlarm2{ date: 1, hour: Hours::H24(2), minute: 3 }, A2M::HoursAndMinutesMatch, + ALARM2_MINUTES, [ 3, 2, AM | 1]); + set_alarm_test!(match_m, set_alarm2_date, DateAlarm2{ date: 1, hour: Hours::H24(2), minute: 3 }, A2M::MinutesMatch, + ALARM2_MINUTES, [ 3, AM | 2, AM | 1]); + set_alarm_test!(match_opm, set_alarm2_date, DateAlarm2{ date: 1, hour: Hours::H24(2), minute: 3 }, A2M::OncePerMinute, + ALARM2_MINUTES, [AM | 3, AM | 2, AM | 1]); +} + +mod alarm2_weekday { + use super::*; + set_alarm_test!(h24, set_alarm2_weekday, WeekdayAlarm2{ weekday: 1, hour: Hours::H24(2), minute: 3 }, A2M::AllMatch, + ALARM2_MINUTES, [3, 2, BF::WEEKDAY | 1]); + set_alarm_test!(am, set_alarm2_weekday, WeekdayAlarm2{ weekday: 1, hour: Hours::AM(2), minute: 3 }, A2M::AllMatch, + ALARM2_MINUTES, [3, 0b0100_0010, BF::WEEKDAY | 1]); + set_alarm_test!(pm, set_alarm2_weekday, WeekdayAlarm2{ weekday: 1, hour: Hours::PM(2), minute: 3 }, A2M::AllMatch, + ALARM2_MINUTES, [3, 0b0110_0010, BF::WEEKDAY | 1]); + + set_alarm_test!(match_hm, set_alarm2_weekday, WeekdayAlarm2{ weekday: 1, hour: Hours::H24(2), minute: 3 }, A2M::HoursAndMinutesMatch, + ALARM2_MINUTES, [ 3, 2, AM | BF::WEEKDAY | 1]); + set_alarm_test!(match_m, set_alarm2_weekday, WeekdayAlarm2{ weekday: 1, hour: Hours::H24(2), minute: 3 }, A2M::MinutesMatch, + ALARM2_MINUTES, [ 3, AM | 2, AM | BF::WEEKDAY | 1]); + set_alarm_test!(match_opm, set_alarm2_weekday, WeekdayAlarm2{ weekday: 1, hour: Hours::H24(2), minute: 3 }, A2M::OncePerMinute, + ALARM2_MINUTES, [AM | 3, AM | 2, AM | BF::WEEKDAY | 1]); +} diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 46a031a..52c0aef 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -16,18 +16,19 @@ pub struct Register; #[allow(unused)] impl Register { - pub const SECONDS : u8 = 0x00; - pub const MINUTES : u8 = 0x01; - pub const HOURS : u8 = 0x02; - pub const DOW : u8 = 0x03; - pub const DOM : u8 = 0x04; - pub const MONTH : u8 = 0x05; - pub const CONTROL : u8 = 0x0E; - pub const STATUS : u8 = 0x0F; - pub const AGING_OFFSET : u8 = 0x10; - pub const TEMP_MSB : u8 = 0x11; - pub const TEMP_CONV : u8 = 0x13; + pub const SECONDS : u8 = 0x00; + pub const MINUTES : u8 = 0x01; + pub const HOURS : u8 = 0x02; + pub const DOW : u8 = 0x03; + pub const DOM : u8 = 0x04; + pub const MONTH : u8 = 0x05; pub const ALARM1_SECONDS : u8 = 0x07; + pub const ALARM2_MINUTES : u8 = 0x0B; + pub const CONTROL : u8 = 0x0E; + pub const STATUS : u8 = 0x0F; + pub const AGING_OFFSET : u8 = 0x10; + pub const TEMP_MSB : u8 = 0x11; + pub const TEMP_CONV : u8 = 0x13; } pub struct BitFlags;