Add methods to get/set the hours

pull/4/head
Diego Barrios Romero 2018-10-28 12:46:12 +01:00
parent c1b02cb3c0
commit b9610b6e73
6 changed files with 96 additions and 2 deletions

View File

@ -8,6 +8,7 @@ extremely accurate real-time clocks, based on the [`embedded-hal`] traits.
This driver allows you to: This driver allows you to:
- Read/write the seconds. - Read/write the seconds.
- Read/write the minutes. - Read/write the minutes.
- Read/write the hours in 24h or AM/PM format.
## The devices ## The devices

View File

@ -1,9 +1,20 @@
//! Common implementation //! Common implementation
extern crate embedded_hal as hal; extern crate embedded_hal as hal;
use super::super::{ Ds323x, Register, Error }; use super::super::{ Ds323x, Register, BitFlags, Error };
use interface::{ ReadRegister, WriteRegister }; use interface::{ ReadRegister, WriteRegister };
/// Hours in either 12-hour (AM/PM) or 24-hour format
#[derive(Debug, Clone, PartialEq)]
pub enum Hours {
/// AM [1-12]
AM(u8),
/// PM [1-12]
PM(u8),
/// 24H format [0-23]
H24(u8),
}
impl<DI, IC, E> Ds323x<DI, IC> impl<DI, IC, E> Ds323x<DI, IC>
where where
DI: ReadRegister<Error = E> DI: ReadRegister<Error = E>
@ -18,6 +29,24 @@ where
self.read_register_decimal(Register::MINUTES) self.read_register_decimal(Register::MINUTES)
} }
/// Read the hours.
pub fn get_hours(&mut self) -> Result<Hours, Error<E>> {
let data = self.iface.read_register(Register::HOURS)?;
self.get_hours_from_register(data)
}
fn get_hours_from_register(&self, data: u8) -> Result<Hours, Error<E>> {
if is_24h_format(data) {
Ok(Hours::H24(packed_bcd_to_decimal(data & !BitFlags::H24_H12)))
}
else if is_am(data) {
Ok(Hours::AM(packed_bcd_to_decimal(data & !(BitFlags::H24_H12 | BitFlags::AM_PM))))
}
else {
Ok(Hours::PM(packed_bcd_to_decimal(data & !(BitFlags::H24_H12 | BitFlags::AM_PM))))
}
}
fn read_register_decimal(&mut self, register: u8) -> Result<u8, Error<E>> { fn read_register_decimal(&mut self, register: u8) -> Result<u8, Error<E>> {
let data = self.iface.read_register(register)?; let data = self.iface.read_register(register)?;
Ok(packed_bcd_to_decimal(data)) Ok(packed_bcd_to_decimal(data))
@ -48,11 +77,40 @@ where
self.write_register_decimal(Register::MINUTES, minutes) self.write_register_decimal(Register::MINUTES, minutes)
} }
/// Set the hours.
///
/// Changes the operating mode to 12h/24h depending on the parameter.
///
/// Will return an `Error::InvalidInputData` if the hours are out of range.
pub fn set_hours(&mut self, hours: Hours) -> Result<(), Error<E>> {
let value = self.get_hours_register_value(&hours)?;
self.iface.write_register(Register::HOURS, value)
}
fn get_hours_register_value(&mut self, hours: &Hours) -> Result<u8, Error<E>> {
match *hours {
Hours::H24(h) if h > 23 => Err(Error::InvalidInputData),
Hours::H24(h) => Ok(decimal_to_packed_bcd(h)),
Hours::AM(h) if h < 1 || h > 12 => Err(Error::InvalidInputData),
Hours::AM(h) => Ok(BitFlags::H24_H12 | decimal_to_packed_bcd(h)),
Hours::PM(h) if h < 1 || h > 12 => Err(Error::InvalidInputData),
Hours::PM(h) => Ok(BitFlags::H24_H12 | BitFlags::AM_PM | decimal_to_packed_bcd(h)),
}
}
fn write_register_decimal(&mut self, register: u8, decimal_number: u8) -> Result<(), Error<E>> { fn write_register_decimal(&mut self, register: u8, decimal_number: u8) -> Result<(), Error<E>> {
self.iface.write_register(register, decimal_to_packed_bcd(decimal_number)) self.iface.write_register(register, decimal_to_packed_bcd(decimal_number))
} }
} }
fn is_24h_format(hours_data: u8) -> bool {
hours_data & BitFlags::H24_H12 == 0
}
fn is_am(hours_data: u8) -> bool {
hours_data & BitFlags::AM_PM == 0
}
// Transforms a decimal number to packed BCD format // Transforms a decimal number to packed BCD format
fn decimal_to_packed_bcd(dec: u8) -> u8 { fn decimal_to_packed_bcd(dec: u8) -> u8 {
((dec / 10) << 4) | (dec % 10) ((dec / 10) << 4) | (dec % 10)

View File

@ -1 +1,2 @@
mod datetime; mod datetime;
pub use self::datetime::Hours;

View File

@ -6,6 +6,7 @@
//! This driver allows you to: //! This driver allows you to:
//! - Read/write the seconds. //! - Read/write the seconds.
//! - Read/write the minutes. //! - Read/write the minutes.
//! - Read/write the hours in 24h or AM/PM format.
//! //!
//! ## The devices //! ## The devices
//! //!
@ -179,6 +180,14 @@ struct Register;
impl Register { impl Register {
const SECONDS : u8 = 0x00; const SECONDS : u8 = 0x00;
const MINUTES : u8 = 0x01; const MINUTES : u8 = 0x01;
const HOURS : u8 = 0x02;
}
struct BitFlags;
impl BitFlags {
const H24_H12 : u8 = 0b0100_0000;
const AM_PM : u8 = 0b0010_0000;
} }
const DEVICE_ADDRESS: u8 = 0b110_1000; const DEVICE_ADDRESS: u8 = 0b110_1000;
@ -265,3 +274,4 @@ where
} }
mod ds323x; mod ds323x;
pub use ds323x::Hours;

View File

@ -11,6 +11,7 @@ pub struct Register;
impl Register { impl Register {
pub const SECONDS : u8 = 0x00; pub const SECONDS : u8 = 0x00;
pub const MINUTES : u8 = 0x01; pub const MINUTES : u8 = 0x01;
pub const HOURS : u8 = 0x02;
} }
pub struct DummyOutputPin; pub struct DummyOutputPin;

View File

@ -6,6 +6,8 @@ use hal::spi::Transaction as SpiTrans;
mod common; mod common;
use common::{ DEVICE_ADDRESS, Register, new_ds3231, use common::{ DEVICE_ADDRESS, Register, new_ds3231,
new_ds3232, new_ds3234 }; new_ds3232, new_ds3234 };
extern crate ds323x;
use ds323x::{ Hours };
mod seconds { mod seconds {
use super::*; use super::*;
@ -49,4 +51,25 @@ mod minutes {
set_test!(can_set_ds3234, set_minutes, new_ds3234, 1, set_test!(can_set_ds3234, set_minutes, new_ds3234, 1,
SpiTrans::write(vec![Register::MINUTES + 0x80, 1])); SpiTrans::write(vec![Register::MINUTES + 0x80, 1]));
mod hours {
use super::*;
get_test!(can_get_ds3231, get_hours, new_ds3231, Hours::H24(21),
I2cTrans::write_read(DEVICE_ADDRESS, vec![Register::HOURS], vec![0b0010_0001]));
get_test!(can_get_ds3232, get_hours, new_ds3232, Hours::H24(21),
I2cTrans::write_read(DEVICE_ADDRESS, vec![Register::HOURS], vec![0b0010_0001]));
get_test!(can_get_ds3234, get_hours, new_ds3234, Hours::H24(21),
SpiTrans::transfer(vec![Register::HOURS, 0], vec![Register::HOURS, 0b0010_0001]));
set_test!(can_set_ds3231, set_hours, new_ds3231, Hours::H24(21),
I2cTrans::write(DEVICE_ADDRESS, vec![Register::HOURS, 0b0010_0001]));
set_test!(can_set_ds3232, set_hours, new_ds3232, Hours::H24(21),
I2cTrans::write(DEVICE_ADDRESS, vec![Register::HOURS, 0b0010_0001]));
set_test!(can_set_ds3234, set_hours, new_ds3234, Hours::H24(21),
SpiTrans::write(vec![Register::HOURS + 0x80, 0b0010_0001]));
} }