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:
- Read/write the seconds.
- Read/write the minutes.
- Read/write the hours in 24h or AM/PM format.
## The devices

View File

@ -1,9 +1,20 @@
//! Common implementation
extern crate embedded_hal as hal;
use super::super::{ Ds323x, Register, Error };
use super::super::{ Ds323x, Register, BitFlags, Error };
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>
where
DI: ReadRegister<Error = E>
@ -18,6 +29,24 @@ where
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>> {
let data = self.iface.read_register(register)?;
Ok(packed_bcd_to_decimal(data))
@ -48,11 +77,40 @@ where
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>> {
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
fn decimal_to_packed_bcd(dec: u8) -> u8 {
((dec / 10) << 4) | (dec % 10)

View File

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

View File

@ -6,6 +6,7 @@
//! This driver allows you to:
//! - Read/write the seconds.
//! - Read/write the minutes.
//! - Read/write the hours in 24h or AM/PM format.
//!
//! ## The devices
//!
@ -179,6 +180,14 @@ struct Register;
impl Register {
const SECONDS : u8 = 0x00;
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;
@ -265,3 +274,4 @@ where
}
mod ds323x;
pub use ds323x::Hours;

View File

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

View File

@ -6,6 +6,8 @@ use hal::spi::Transaction as SpiTrans;
mod common;
use common::{ DEVICE_ADDRESS, Register, new_ds3231,
new_ds3232, new_ds3234 };
extern crate ds323x;
use ds323x::{ Hours };
mod seconds {
use super::*;
@ -49,4 +51,25 @@ mod minutes {
set_test!(can_set_ds3234, set_minutes, new_ds3234, 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]));
}