Add support for setting alarm 2

pull/4/head
Diego Barrios Romero 2018-11-03 08:11:38 +01:00
parent c3927e46c3
commit b717f4e62b
6 changed files with 165 additions and 27 deletions

View File

@ -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`.

View File

@ -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<DI, IC, E> Ds323x<DI, IC>
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<E>> {
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<E>> {
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)
}
}

View File

@ -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 };

View File

@ -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<DI, IC> {
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;

View File

@ -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]);
}

View File

@ -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;