mirror of
https://github.com/taigrr/arduinolibs
synced 2025-01-18 04:33:12 -08:00
Split simulated clock code out of DS1307RTC
This change should make it easier to support other realtime clock chips in the future.
This commit is contained in:
parent
23de656b9f
commit
81624f6d5e
@ -22,8 +22,6 @@
|
|||||||
|
|
||||||
#include "DS1307RTC.h"
|
#include "DS1307RTC.h"
|
||||||
#include <WProgram.h>
|
#include <WProgram.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \class DS1307RTC DS1307RTC.h <DS1307RTC.h>
|
* \class DS1307RTC DS1307RTC.h <DS1307RTC.h>
|
||||||
@ -34,14 +32,18 @@
|
|||||||
* provides support for reading and writing information about alarms
|
* provides support for reading and writing information about alarms
|
||||||
* and other clock settings.
|
* and other clock settings.
|
||||||
*
|
*
|
||||||
* If there is no DS1307 chip on the I2C bus, this class will simulate the
|
* If there is no DS1307 chip on the I2C bus, this class will fall back to
|
||||||
* current time and date based on the value of millis(). At startup the
|
* the RTC class to simulate the current time and date based on the value
|
||||||
* simulated time and date is set to 9am on the 1st of January, 2012.
|
* of millis().
|
||||||
*
|
*
|
||||||
* The DS1307 uses a 2-digit year so this class is limited to dates between
|
* The DS1307 uses a 2-digit year so this class is limited to dates between
|
||||||
* 2000 and 2099 inclusive.
|
* 2000 and 2099 inclusive.
|
||||||
*
|
*
|
||||||
* \sa RTCTime, RTCDate, RTCAlarm
|
* Note: if this class has not been used with the DS1307 chip before,
|
||||||
|
* then the contents of NVRAM will be cleared. Any previous contents
|
||||||
|
* will be lost.
|
||||||
|
*
|
||||||
|
* \sa RTC
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// I2C address of the RTC chip (7-bit).
|
// I2C address of the RTC chip (7-bit).
|
||||||
@ -59,36 +61,10 @@
|
|||||||
#define DS1307_NVRAM 0x08
|
#define DS1307_NVRAM 0x08
|
||||||
|
|
||||||
// Alarm storage at the end of the RTC's NVRAM.
|
// Alarm storage at the end of the RTC's NVRAM.
|
||||||
#define DS1307_NUM_ALARMS 4
|
|
||||||
#define DS1307_ALARM_SIZE 3
|
#define DS1307_ALARM_SIZE 3
|
||||||
#define DS1307_ALARMS (64 - DS1307_NUM_ALARMS * DS1307_ALARM_SIZE - 1)
|
#define DS1307_ALARMS (64 - RTC::ALARM_COUNT * DS1307_ALARM_SIZE - 1)
|
||||||
#define DS1307_ALARM_MAGIC 63
|
#define DS1307_ALARM_MAGIC 63
|
||||||
|
|
||||||
#define MILLIS_PER_DAY 86400000UL
|
|
||||||
#define MILLIS_PER_SECOND 1000UL
|
|
||||||
#define MILLIS_PER_MINUTE 60000UL
|
|
||||||
#define MILLIS_PER_HOUR 3600000UL
|
|
||||||
|
|
||||||
static uint8_t monthLengths[] = {
|
|
||||||
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bool isLeapYear(unsigned int year)
|
|
||||||
{
|
|
||||||
if ((year % 100) == 0)
|
|
||||||
return (year % 400) == 0;
|
|
||||||
else
|
|
||||||
return (year % 4) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint8_t monthLength(const RTCDate *date)
|
|
||||||
{
|
|
||||||
if (date->month != 2 || !isLeapYear(date->year))
|
|
||||||
return monthLengths[date->month - 1];
|
|
||||||
else
|
|
||||||
return 29;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Attaches to a realtime clock slave device on \a bus.
|
* \brief Attaches to a realtime clock slave device on \a bus.
|
||||||
*
|
*
|
||||||
@ -102,19 +78,9 @@ inline uint8_t monthLength(const RTCDate *date)
|
|||||||
DS1307RTC::DS1307RTC(BitBangI2C &bus, uint8_t oneHzPin)
|
DS1307RTC::DS1307RTC(BitBangI2C &bus, uint8_t oneHzPin)
|
||||||
: _bus(&bus)
|
: _bus(&bus)
|
||||||
, _oneHzPin(oneHzPin)
|
, _oneHzPin(oneHzPin)
|
||||||
, _alarmCount(0)
|
|
||||||
, _alarmOffset(0)
|
|
||||||
, prevOneHz(false)
|
, prevOneHz(false)
|
||||||
, _isRealTime(true)
|
, _isRealTime(true)
|
||||||
, midnight(millis() - 9 * MILLIS_PER_HOUR) // Simulated clock starts at 9am
|
|
||||||
, alarms(0)
|
|
||||||
, nvram(0)
|
|
||||||
{
|
{
|
||||||
// Start the simulated date at 1 Jan, 2012.
|
|
||||||
date.day = 1;
|
|
||||||
date.month = 1;
|
|
||||||
date.year = 2012;
|
|
||||||
|
|
||||||
// Make sure the CH bit in register 0 is off or the clock won't update.
|
// Make sure the CH bit in register 0 is off or the clock won't update.
|
||||||
if (_bus->startWrite(DS1307_I2C_ADDRESS) == BitBangI2C::ACK) {
|
if (_bus->startWrite(DS1307_I2C_ADDRESS) == BitBangI2C::ACK) {
|
||||||
_bus->write(DS1307_SECOND);
|
_bus->write(DS1307_SECOND);
|
||||||
@ -142,14 +108,14 @@ DS1307RTC::DS1307RTC(BitBangI2C &bus, uint8_t oneHzPin)
|
|||||||
_bus->write(0x10);
|
_bus->write(0x10);
|
||||||
_bus->stop();
|
_bus->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize the alarms in the RTC chip's NVRAM.
|
||||||
|
if (_isRealTime)
|
||||||
|
initAlarms();
|
||||||
}
|
}
|
||||||
|
|
||||||
DS1307RTC::~DS1307RTC()
|
DS1307RTC::~DS1307RTC()
|
||||||
{
|
{
|
||||||
if (alarms)
|
|
||||||
free(alarms);
|
|
||||||
if (nvram)
|
|
||||||
free(nvram);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -157,13 +123,6 @@ DS1307RTC::~DS1307RTC()
|
|||||||
* \brief Returns true if the realtime clock is on the I2C bus; false if the time and date are simulated.
|
* \brief Returns true if the realtime clock is on the I2C bus; false if the time and date are simulated.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Returns true if the realtime clock has updated since the last call to this function.
|
|
||||||
*
|
|
||||||
* If the object is not using the 1 Hz pin, then this function will always
|
|
||||||
* return true. Otherwise it only returns true when the 1 Hz square wave
|
|
||||||
* output pin on the DS1307 changes from low to high.
|
|
||||||
*/
|
|
||||||
bool DS1307RTC::hasUpdates()
|
bool DS1307RTC::hasUpdates()
|
||||||
{
|
{
|
||||||
// If not using a 1 Hz pin or there is no RTC chip available,
|
// If not using a 1 Hz pin or there is no RTC chip available,
|
||||||
@ -203,11 +162,6 @@ inline uint8_t fromHourBCD(uint8_t value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Reads the current time from the realtime clock into \a value.
|
|
||||||
*
|
|
||||||
* \sa writeTime(), readDate()
|
|
||||||
*/
|
|
||||||
void DS1307RTC::readTime(RTCTime *value)
|
void DS1307RTC::readTime(RTCTime *value)
|
||||||
{
|
{
|
||||||
if (_isRealTime) {
|
if (_isRealTime) {
|
||||||
@ -219,31 +173,14 @@ void DS1307RTC::readTime(RTCTime *value)
|
|||||||
value->hour = fromHourBCD(_bus->read(BitBangI2C::NACK));
|
value->hour = fromHourBCD(_bus->read(BitBangI2C::NACK));
|
||||||
_bus->stop();
|
_bus->stop();
|
||||||
} else {
|
} else {
|
||||||
// Determine the number of seconds since the last midnight event.
|
RTC::readTime(value);
|
||||||
unsigned long sinceMidnight = millis() - midnight;
|
|
||||||
if (sinceMidnight >= MILLIS_PER_DAY) {
|
|
||||||
// We have overflowed into the next day. Readjust midnight.
|
|
||||||
midnight += MILLIS_PER_DAY;
|
|
||||||
sinceMidnight -= MILLIS_PER_DAY;
|
|
||||||
|
|
||||||
// Increment the simulated date.
|
|
||||||
adjustDays(&date, INCREMENT);
|
|
||||||
}
|
|
||||||
value->second = (uint8_t)(((sinceMidnight / MILLIS_PER_SECOND) % 60));
|
|
||||||
value->minute = (uint8_t)(((sinceMidnight / MILLIS_PER_MINUTE) % 60));
|
|
||||||
value->hour = (uint8_t)(sinceMidnight / MILLIS_PER_HOUR);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Reads the current date from the realtime clock into \a value.
|
|
||||||
*
|
|
||||||
* \sa writeDate(), readTime()
|
|
||||||
*/
|
|
||||||
void DS1307RTC::readDate(RTCDate *value)
|
void DS1307RTC::readDate(RTCDate *value)
|
||||||
{
|
{
|
||||||
if (!_isRealTime) {
|
if (!_isRealTime) {
|
||||||
*value = date;
|
RTC::readDate(value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_bus->startWrite(DS1307_I2C_ADDRESS);
|
_bus->startWrite(DS1307_I2C_ADDRESS);
|
||||||
@ -260,11 +197,6 @@ inline uint8_t toBCD(uint8_t value)
|
|||||||
return ((value / 10) << 4) + (value % 10);
|
return ((value / 10) << 4) + (value % 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Updates the time in the realtime clock to match \a value.
|
|
||||||
*
|
|
||||||
* \sa readTime(), writeDate()
|
|
||||||
*/
|
|
||||||
void DS1307RTC::writeTime(const RTCTime *value)
|
void DS1307RTC::writeTime(const RTCTime *value)
|
||||||
{
|
{
|
||||||
if (_isRealTime) {
|
if (_isRealTime) {
|
||||||
@ -275,20 +207,10 @@ void DS1307RTC::writeTime(const RTCTime *value)
|
|||||||
_bus->write(toBCD(value->hour)); // Changes mode to 24-hour clock.
|
_bus->write(toBCD(value->hour)); // Changes mode to 24-hour clock.
|
||||||
_bus->stop();
|
_bus->stop();
|
||||||
} else {
|
} else {
|
||||||
// Adjust the position of the last simulated midnight event.
|
RTC::writeTime(value);
|
||||||
unsigned long sinceMidnight =
|
|
||||||
value->second * MILLIS_PER_SECOND +
|
|
||||||
value->minute * MILLIS_PER_MINUTE +
|
|
||||||
value->hour * MILLIS_PER_HOUR;
|
|
||||||
midnight = millis() - sinceMidnight;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Updates the date in the realtime clock to match \a value.
|
|
||||||
*
|
|
||||||
* \sa readDate(), writeTime()
|
|
||||||
*/
|
|
||||||
void DS1307RTC::writeDate(const RTCDate *value)
|
void DS1307RTC::writeDate(const RTCDate *value)
|
||||||
{
|
{
|
||||||
if (_isRealTime) {
|
if (_isRealTime) {
|
||||||
@ -299,34 +221,12 @@ void DS1307RTC::writeDate(const RTCDate *value)
|
|||||||
_bus->write(toBCD(value->year % 100));
|
_bus->write(toBCD(value->year % 100));
|
||||||
_bus->stop();
|
_bus->stop();
|
||||||
} else {
|
} else {
|
||||||
date = *value;
|
RTC::writeDate(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Returns the number of alarms that can be stored in the realtime clock's non-volatile memory.
|
|
||||||
*
|
|
||||||
* At least 4 alarms will be provided by this class.
|
|
||||||
*
|
|
||||||
* \sa readAlarm(), writeAlarm()
|
|
||||||
*/
|
|
||||||
uint8_t DS1307RTC::alarmCount()
|
|
||||||
{
|
|
||||||
initAlarms();
|
|
||||||
return _alarmCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Reads the details of the alarm with index \a alarmNum into \a value.
|
|
||||||
*
|
|
||||||
* Alarm details are stored at the end of the realtime clock's non-volatile
|
|
||||||
* memory.
|
|
||||||
*
|
|
||||||
* \sa writeAlarm(), alarmCount()
|
|
||||||
*/
|
|
||||||
void DS1307RTC::readAlarm(uint8_t alarmNum, RTCAlarm *value)
|
void DS1307RTC::readAlarm(uint8_t alarmNum, RTCAlarm *value)
|
||||||
{
|
{
|
||||||
initAlarms();
|
|
||||||
if (_isRealTime) {
|
if (_isRealTime) {
|
||||||
_bus->startWrite(DS1307_I2C_ADDRESS);
|
_bus->startWrite(DS1307_I2C_ADDRESS);
|
||||||
_bus->write(DS1307_ALARMS + alarmNum * DS1307_ALARM_SIZE);
|
_bus->write(DS1307_ALARMS + alarmNum * DS1307_ALARM_SIZE);
|
||||||
@ -335,27 +235,13 @@ void DS1307RTC::readAlarm(uint8_t alarmNum, RTCAlarm *value)
|
|||||||
value->minute = fromBCD(_bus->read());
|
value->minute = fromBCD(_bus->read());
|
||||||
value->flags = _bus->read(BitBangI2C::NACK);
|
value->flags = _bus->read(BitBangI2C::NACK);
|
||||||
_bus->stop();
|
_bus->stop();
|
||||||
} else if (alarms) {
|
|
||||||
*value = alarms[alarmNum];
|
|
||||||
} else {
|
} else {
|
||||||
// Alarms default to 6am when simulated.
|
RTC::readAlarm(alarmNum, value);
|
||||||
value->hour = 6;
|
|
||||||
value->minute = 0;
|
|
||||||
value->flags = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Updates the details of the alarm with index \a alarmNum from \a value.
|
|
||||||
*
|
|
||||||
* Alarm details are stored at the end of the realtime clock's non-volatile
|
|
||||||
* memory.
|
|
||||||
*
|
|
||||||
* \sa readAlarm(), alarmCount()
|
|
||||||
*/
|
|
||||||
void DS1307RTC::writeAlarm(uint8_t alarmNum, const RTCAlarm *value)
|
void DS1307RTC::writeAlarm(uint8_t alarmNum, const RTCAlarm *value)
|
||||||
{
|
{
|
||||||
initAlarms();
|
|
||||||
if (_isRealTime) {
|
if (_isRealTime) {
|
||||||
_bus->startWrite(DS1307_I2C_ADDRESS);
|
_bus->startWrite(DS1307_I2C_ADDRESS);
|
||||||
_bus->write(DS1307_ALARMS + alarmNum * DS1307_ALARM_SIZE);
|
_bus->write(DS1307_ALARMS + alarmNum * DS1307_ALARM_SIZE);
|
||||||
@ -363,16 +249,11 @@ void DS1307RTC::writeAlarm(uint8_t alarmNum, const RTCAlarm *value)
|
|||||||
_bus->write(toBCD(value->minute));
|
_bus->write(toBCD(value->minute));
|
||||||
_bus->write(value->flags);
|
_bus->write(value->flags);
|
||||||
_bus->stop();
|
_bus->stop();
|
||||||
} else if (alarms) {
|
} else {
|
||||||
alarms[alarmNum] = *value;
|
RTC::writeAlarm(alarmNum, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Reads the byte at \a offset within the realtime clock's non-volatile memory.
|
|
||||||
*
|
|
||||||
* \sa writeByte()
|
|
||||||
*/
|
|
||||||
uint8_t DS1307RTC::readByte(uint8_t offset)
|
uint8_t DS1307RTC::readByte(uint8_t offset)
|
||||||
{
|
{
|
||||||
if (_isRealTime) {
|
if (_isRealTime) {
|
||||||
@ -382,18 +263,11 @@ uint8_t DS1307RTC::readByte(uint8_t offset)
|
|||||||
uint8_t value = _bus->read(BitBangI2C::NACK);
|
uint8_t value = _bus->read(BitBangI2C::NACK);
|
||||||
_bus->stop();
|
_bus->stop();
|
||||||
return value;
|
return value;
|
||||||
} else if (nvram) {
|
|
||||||
return nvram[offset];
|
|
||||||
} else {
|
} else {
|
||||||
return 0xFF;
|
return RTC::readByte(offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Writes \a value to \a offset within the realtime clock's non-volatile memory.
|
|
||||||
*
|
|
||||||
* \sa readByte()
|
|
||||||
*/
|
|
||||||
void DS1307RTC::writeByte(uint8_t offset, uint8_t value)
|
void DS1307RTC::writeByte(uint8_t offset, uint8_t value)
|
||||||
{
|
{
|
||||||
if (_isRealTime) {
|
if (_isRealTime) {
|
||||||
@ -401,221 +275,38 @@ void DS1307RTC::writeByte(uint8_t offset, uint8_t value)
|
|||||||
_bus->write(DS1307_NVRAM + offset);
|
_bus->write(DS1307_NVRAM + offset);
|
||||||
_bus->write(value);
|
_bus->write(value);
|
||||||
_bus->stop();
|
_bus->stop();
|
||||||
} else if (nvram) {
|
|
||||||
nvram[offset] = value;
|
|
||||||
} else {
|
} else {
|
||||||
nvram = (uint8_t *)malloc(DS1307_ALARMS - DS1307_NVRAM);
|
RTC::writeByte(offset, value);
|
||||||
if (nvram) {
|
|
||||||
memset(nvram, 0xFF, DS1307_ALARMS - DS1307_NVRAM);
|
|
||||||
nvram[offset] = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* \var DS1307RTC::INCREMENT
|
|
||||||
* \brief Increment the day, month, or year.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \var DS1307RTC::DECREMENT
|
|
||||||
* \brief Decrement the day, month, or year.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \var DS1307RTC::WRAP
|
|
||||||
* \brief Wrap around to the beginning of the current month/year rather than advance to the next one.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Adjusts \a date up or down one day according to \a flags.
|
|
||||||
*
|
|
||||||
* \sa adjustMonths(), adjustYears()
|
|
||||||
*/
|
|
||||||
void DS1307RTC::adjustDays(RTCDate *date, uint8_t flags)
|
|
||||||
{
|
|
||||||
if (flags & DECREMENT) {
|
|
||||||
--(date->day);
|
|
||||||
if (date->day == 0) {
|
|
||||||
if (!(flags & WRAP)) {
|
|
||||||
--(date->month);
|
|
||||||
if (date->month == 0)
|
|
||||||
date->month = 12;
|
|
||||||
}
|
|
||||||
date->day = monthLength(date);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
++(date->day);
|
|
||||||
if (date->day > monthLength(date)) {
|
|
||||||
if (!(flags & WRAP)) {
|
|
||||||
++(date->month);
|
|
||||||
if (date->month == 13)
|
|
||||||
date->month = 1;
|
|
||||||
}
|
|
||||||
date->day = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Adjusts \a date up or down one month according to \a flags.
|
|
||||||
*
|
|
||||||
* \sa adjustDays(), adjustYears()
|
|
||||||
*/
|
|
||||||
void DS1307RTC::adjustMonths(RTCDate *date, uint8_t flags)
|
|
||||||
{
|
|
||||||
if (flags & DECREMENT) {
|
|
||||||
--(date->month);
|
|
||||||
if (date->month == 0) {
|
|
||||||
date->month = 12;
|
|
||||||
if (!(flags & WRAP) && date->year > 2000)
|
|
||||||
--(date->year);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
++(date->month);
|
|
||||||
if (date->month == 13) {
|
|
||||||
date->month = 1;
|
|
||||||
if (!(flags & WRAP) && date->year < 2099)
|
|
||||||
++(date->year);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uint8_t len = monthLength(date);
|
|
||||||
if (date->day > len)
|
|
||||||
date->day = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Adjusts \a date up or down one year according to \a flags.
|
|
||||||
*
|
|
||||||
* \sa adjustDays(), adjustMonths()
|
|
||||||
*/
|
|
||||||
void DS1307RTC::adjustYears(RTCDate *date, uint8_t flags)
|
|
||||||
{
|
|
||||||
if (flags & DECREMENT) {
|
|
||||||
--(date->year);
|
|
||||||
if (date->year < 2000)
|
|
||||||
date->year = 2000;
|
|
||||||
} else {
|
|
||||||
++(date->year);
|
|
||||||
if (date->year > 2099)
|
|
||||||
date->year = 2099;
|
|
||||||
}
|
|
||||||
uint8_t len = monthLength(date);
|
|
||||||
if (date->day > len)
|
|
||||||
date->day = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DS1307RTC::initAlarms()
|
void DS1307RTC::initAlarms()
|
||||||
{
|
{
|
||||||
if (_alarmCount != 0)
|
|
||||||
return;
|
|
||||||
if (!_isRealTime) {
|
|
||||||
// No RTC clock available, so fake the alarms.
|
|
||||||
alarms = (RTCAlarm *)malloc(sizeof(RTCAlarm) * DS1307_NUM_ALARMS);
|
|
||||||
RTCAlarm alarm;
|
|
||||||
alarm.hour = 6; // Default to 6am for alarms.
|
|
||||||
alarm.minute = 0;
|
|
||||||
alarm.flags = 0;
|
|
||||||
for (uint8_t index = 0; index < _alarmCount; ++index)
|
|
||||||
writeAlarm(index, &alarm);
|
|
||||||
_alarmCount = DS1307_NUM_ALARMS;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_bus->startWrite(DS1307_I2C_ADDRESS);
|
_bus->startWrite(DS1307_I2C_ADDRESS);
|
||||||
_bus->write(DS1307_ALARM_MAGIC);
|
_bus->write(DS1307_ALARM_MAGIC);
|
||||||
_bus->startRead(DS1307_I2C_ADDRESS);
|
_bus->startRead(DS1307_I2C_ADDRESS);
|
||||||
uint8_t value = _bus->read(BitBangI2C::NACK);
|
uint8_t value = _bus->read(BitBangI2C::NACK);
|
||||||
_bus->stop();
|
_bus->stop();
|
||||||
if ((value & 0xF0) == 0xB0) {
|
if (value != (0xB0 + ALARM_COUNT)) {
|
||||||
// RTC chip was previously initialized with alarm information.
|
|
||||||
_alarmCount = value & 0x0F;
|
|
||||||
} else {
|
|
||||||
// This is the first time we have used this clock chip,
|
// This is the first time we have used this clock chip,
|
||||||
// so initialize all alarms to their default state.
|
// so initialize all alarms to their default state.
|
||||||
// Note: if the number of alarms is changed in the future,
|
|
||||||
// then the high nibble will still be 0xB, with the low
|
|
||||||
// nibble the actual number of alarms that are stored.
|
|
||||||
_alarmCount = DS1307_NUM_ALARMS;
|
|
||||||
RTCAlarm alarm;
|
RTCAlarm alarm;
|
||||||
alarm.hour = 6; // Default to 6am for alarms.
|
alarm.hour = 6; // Default to 6am for alarms.
|
||||||
alarm.minute = 0;
|
alarm.minute = 0;
|
||||||
alarm.flags = 0;
|
alarm.flags = 0;
|
||||||
for (uint8_t index = 0; index < _alarmCount; ++index)
|
for (uint8_t index = 0; index < ALARM_COUNT; ++index)
|
||||||
writeAlarm(index, &alarm);
|
writeAlarm(index, &alarm);
|
||||||
_bus->startWrite(DS1307_I2C_ADDRESS);
|
_bus->startWrite(DS1307_I2C_ADDRESS);
|
||||||
_bus->write(DS1307_ALARM_MAGIC);
|
_bus->write(DS1307_ALARM_MAGIC);
|
||||||
_bus->write(0xB0 + _alarmCount);
|
_bus->write(0xB0 + ALARM_COUNT);
|
||||||
|
_bus->stop();
|
||||||
|
|
||||||
|
// Also clear the rest of NVRAM so that it is in a known state.
|
||||||
|
// Otherwise we'll have whatever garbage was present at power-on.
|
||||||
|
_bus->startWrite(DS1307_I2C_ADDRESS);
|
||||||
|
_bus->write(DS1307_NVRAM);
|
||||||
|
for (uint8_t index = DS1307_NVRAM; index < DS1307_ALARMS; ++index)
|
||||||
|
_bus->write(0);
|
||||||
_bus->stop();
|
_bus->stop();
|
||||||
}
|
}
|
||||||
_alarmOffset = DS1307_ALARM_MAGIC - _alarmCount * DS1307_ALARM_SIZE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* \class RTCTime DS1307RTC.h <DS1307RTC.h>
|
|
||||||
* \brief Stores time information from a realtime clock chip.
|
|
||||||
*
|
|
||||||
* \sa RTCDate, RTCAlarm, DS1307RTC
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \var RTCTime::hour
|
|
||||||
* \brief Hour of the day (0-23)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \var RTCTime::minute
|
|
||||||
* \brief Minute within the hour (0-59)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \var RTCTime::second
|
|
||||||
* \brief Second within the minute (0-59)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \class RTCDate DS1307RTC.h <DS1307RTC.h>
|
|
||||||
* \brief Stores date information from a realtime clock chip.
|
|
||||||
*
|
|
||||||
* \sa RTCTime, RTCAlarm, DS1307RTC
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \var RTCDate::year
|
|
||||||
* \brief Year (4-digit)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \var RTCDate::month
|
|
||||||
* \brief Month of the year (1-12)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \var RTCDate::day
|
|
||||||
* \brief Day of the month (1-31)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \class RTCAlarm DS1307RTC.h <DS1307RTC.h>
|
|
||||||
* \brief Stores alarm information from a realtime clock chip.
|
|
||||||
*
|
|
||||||
* \sa RTCTime, RTCDate, DS1307RTC
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \var RTCAlarm::hour
|
|
||||||
* \brief Hour of the day for the alarm (0-23).
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \var RTCAlarm::minute
|
|
||||||
* \brief Minute of the hour for the alarm (0-59).
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \var RTCAlarm::flags
|
|
||||||
* \brief Additional flags for the alarm.
|
|
||||||
*
|
|
||||||
* The least significant bit will be 0 if the alarm is disabled or
|
|
||||||
* 1 if the alarm is enabled. Other bits can be used by the application
|
|
||||||
* for any purpose.
|
|
||||||
*/
|
|
||||||
|
@ -23,30 +23,10 @@
|
|||||||
#ifndef DS1307RTC_h
|
#ifndef DS1307RTC_h
|
||||||
#define DS1307RTC_h
|
#define DS1307RTC_h
|
||||||
|
|
||||||
|
#include "RTC.h"
|
||||||
#include "BitBangI2C.h"
|
#include "BitBangI2C.h"
|
||||||
|
|
||||||
struct RTCTime
|
class DS1307RTC : public RTC {
|
||||||
{
|
|
||||||
uint8_t hour;
|
|
||||||
uint8_t minute;
|
|
||||||
uint8_t second;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RTCDate
|
|
||||||
{
|
|
||||||
unsigned int year;
|
|
||||||
uint8_t month;
|
|
||||||
uint8_t day;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RTCAlarm
|
|
||||||
{
|
|
||||||
uint8_t hour;
|
|
||||||
uint8_t minute;
|
|
||||||
uint8_t flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DS1307RTC {
|
|
||||||
public:
|
public:
|
||||||
DS1307RTC(BitBangI2C &bus, uint8_t oneHzPin = 255);
|
DS1307RTC(BitBangI2C &bus, uint8_t oneHzPin = 255);
|
||||||
~DS1307RTC();
|
~DS1307RTC();
|
||||||
@ -61,33 +41,17 @@ public:
|
|||||||
void writeTime(const RTCTime *value);
|
void writeTime(const RTCTime *value);
|
||||||
void writeDate(const RTCDate *value);
|
void writeDate(const RTCDate *value);
|
||||||
|
|
||||||
uint8_t alarmCount();
|
|
||||||
void readAlarm(uint8_t alarmNum, RTCAlarm *value);
|
void readAlarm(uint8_t alarmNum, RTCAlarm *value);
|
||||||
void writeAlarm(uint8_t alarmNum, const RTCAlarm *value);
|
void writeAlarm(uint8_t alarmNum, const RTCAlarm *value);
|
||||||
|
|
||||||
uint8_t readByte(uint8_t offset);
|
uint8_t readByte(uint8_t offset);
|
||||||
void writeByte(uint8_t offset, uint8_t value);
|
void writeByte(uint8_t offset, uint8_t value);
|
||||||
|
|
||||||
// Flags for adjustDays(), adjustMonths(), and adjustYears().
|
|
||||||
static const uint8_t INCREMENT = 0x0000;
|
|
||||||
static const uint8_t DECREMENT = 0x0001;
|
|
||||||
static const uint8_t WRAP = 0x0002;
|
|
||||||
|
|
||||||
static void adjustDays(RTCDate *date, uint8_t flags);
|
|
||||||
static void adjustMonths(RTCDate *date, uint8_t flags);
|
|
||||||
static void adjustYears(RTCDate *date, uint8_t flags);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BitBangI2C *_bus;
|
BitBangI2C *_bus;
|
||||||
uint8_t _oneHzPin;
|
uint8_t _oneHzPin;
|
||||||
uint8_t _alarmCount;
|
|
||||||
uint8_t _alarmOffset;
|
|
||||||
bool prevOneHz;
|
bool prevOneHz;
|
||||||
bool _isRealTime;
|
bool _isRealTime;
|
||||||
unsigned long midnight;
|
|
||||||
RTCDate date;
|
|
||||||
RTCAlarm *alarms;
|
|
||||||
uint8_t *nvram;
|
|
||||||
|
|
||||||
void initAlarms();
|
void initAlarms();
|
||||||
};
|
};
|
||||||
|
408
libraries/BitBangI2C/RTC.cpp
Normal file
408
libraries/BitBangI2C/RTC.cpp
Normal file
@ -0,0 +1,408 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "RTC.h"
|
||||||
|
#include <WProgram.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class RTC RTC.h <RTC.h>
|
||||||
|
* \brief Base class for realtime clock handlers.
|
||||||
|
*
|
||||||
|
* This class simplifies the process of reading and writing the time and
|
||||||
|
* date information in a realtime clock chip. The class also provides
|
||||||
|
* support for reading and writing information about alarms and other
|
||||||
|
* clock settings.
|
||||||
|
*
|
||||||
|
* It is intended that the application will instantiate a subclass of this
|
||||||
|
* class to handle the specific realtime clock chip in the system. The default
|
||||||
|
* implementation in RTC simulates a clock based on the value of millis(),
|
||||||
|
* with alarms and clock settings stored in main memory.
|
||||||
|
*
|
||||||
|
* Because the common DS1307 realtime clock chip uses a 2-digit year,
|
||||||
|
* this class is also limited to dates between 2000 and 2099 inclusive.
|
||||||
|
*
|
||||||
|
* \sa RTCTime, RTCDate, RTCAlarm, DS1307RTC
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \var RTC::ALARM_COUNT
|
||||||
|
* \brief Number of alarms that are supported by RTC::readAlarm() and RTC::writeAlarm().
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \var RTC::BYTE_COUNT
|
||||||
|
* \brief Number of bytes that are supported by RTC::readByte() and RTC::writeByte().
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MILLIS_PER_DAY 86400000UL
|
||||||
|
#define MILLIS_PER_SECOND 1000UL
|
||||||
|
#define MILLIS_PER_MINUTE 60000UL
|
||||||
|
#define MILLIS_PER_HOUR 3600000UL
|
||||||
|
|
||||||
|
static uint8_t monthLengths[] = {
|
||||||
|
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool isLeapYear(unsigned int year)
|
||||||
|
{
|
||||||
|
if ((year % 100) == 0)
|
||||||
|
return (year % 400) == 0;
|
||||||
|
else
|
||||||
|
return (year % 4) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint8_t monthLength(const RTCDate *date)
|
||||||
|
{
|
||||||
|
if (date->month != 2 || !isLeapYear(date->year))
|
||||||
|
return monthLengths[date->month - 1];
|
||||||
|
else
|
||||||
|
return 29;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Constructs a new realtime clock handler.
|
||||||
|
*
|
||||||
|
* \sa hasUpdates()
|
||||||
|
*/
|
||||||
|
RTC::RTC()
|
||||||
|
: midnight(millis() - 9 * MILLIS_PER_HOUR) // Simulated clock starts at 9am
|
||||||
|
, nvram(0)
|
||||||
|
{
|
||||||
|
// Start the simulated date at 1 Jan, 2012.
|
||||||
|
date.day = 1;
|
||||||
|
date.month = 1;
|
||||||
|
date.year = 2012;
|
||||||
|
|
||||||
|
// Set all simulated alarms to 6am by default.
|
||||||
|
for (uint8_t index = 0; index < ALARM_COUNT; ++index) {
|
||||||
|
alarms[index].hour = 6;
|
||||||
|
alarms[index].minute = 0;
|
||||||
|
alarms[index].flags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RTC::~RTC()
|
||||||
|
{
|
||||||
|
if (nvram)
|
||||||
|
free(nvram);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Returns true if the realtime clock has updated since the last call to this function.
|
||||||
|
*
|
||||||
|
* The default implementation returns true, indicating that an update is
|
||||||
|
* always available to be read.
|
||||||
|
*/
|
||||||
|
bool RTC::hasUpdates()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Reads the current time from the realtime clock into \a value.
|
||||||
|
*
|
||||||
|
* \sa writeTime(), readDate()
|
||||||
|
*/
|
||||||
|
void RTC::readTime(RTCTime *value)
|
||||||
|
{
|
||||||
|
// Determine the number of seconds since the last midnight event.
|
||||||
|
unsigned long sinceMidnight = millis() - midnight;
|
||||||
|
if (sinceMidnight >= MILLIS_PER_DAY) {
|
||||||
|
// We have overflowed into the next day. Readjust midnight.
|
||||||
|
midnight += MILLIS_PER_DAY;
|
||||||
|
sinceMidnight -= MILLIS_PER_DAY;
|
||||||
|
|
||||||
|
// Increment the simulated date.
|
||||||
|
adjustDays(&date, INCREMENT);
|
||||||
|
}
|
||||||
|
value->second = (uint8_t)(((sinceMidnight / MILLIS_PER_SECOND) % 60));
|
||||||
|
value->minute = (uint8_t)(((sinceMidnight / MILLIS_PER_MINUTE) % 60));
|
||||||
|
value->hour = (uint8_t)(sinceMidnight / MILLIS_PER_HOUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Reads the current date from the realtime clock into \a value.
|
||||||
|
*
|
||||||
|
* The time should be read first with readTime() as the default implementation
|
||||||
|
* only advances the date when the time is read and it crosses midnight.
|
||||||
|
*
|
||||||
|
* \sa writeDate(), readTime()
|
||||||
|
*/
|
||||||
|
void RTC::readDate(RTCDate *value)
|
||||||
|
{
|
||||||
|
*value = date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Updates the time in the realtime clock to match \a value.
|
||||||
|
*
|
||||||
|
* \sa readTime(), writeDate()
|
||||||
|
*/
|
||||||
|
void RTC::writeTime(const RTCTime *value)
|
||||||
|
{
|
||||||
|
// Adjust the position of the last simulated midnight event.
|
||||||
|
unsigned long sinceMidnight =
|
||||||
|
value->second * MILLIS_PER_SECOND +
|
||||||
|
value->minute * MILLIS_PER_MINUTE +
|
||||||
|
value->hour * MILLIS_PER_HOUR;
|
||||||
|
midnight = millis() - sinceMidnight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Updates the date in the realtime clock to match \a value.
|
||||||
|
*
|
||||||
|
* \sa readDate(), writeTime()
|
||||||
|
*/
|
||||||
|
void RTC::writeDate(const RTCDate *value)
|
||||||
|
{
|
||||||
|
date = *value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Reads the details of the alarm with index \a alarmNum into \a value.
|
||||||
|
*
|
||||||
|
* The \a alarmNum parameter must be between 0 and \ref ALARM_COUNT - 1.
|
||||||
|
*
|
||||||
|
* Alarm details are stored at the end of the realtime clock's non-volatile
|
||||||
|
* memory.
|
||||||
|
*
|
||||||
|
* \sa writeAlarm(), alarmCount()
|
||||||
|
*/
|
||||||
|
void RTC::readAlarm(uint8_t alarmNum, RTCAlarm *value)
|
||||||
|
{
|
||||||
|
*value = alarms[alarmNum];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Updates the details of the alarm with index \a alarmNum from \a value.
|
||||||
|
*
|
||||||
|
* The \a alarmNum parameter must be between 0 and \ref ALARM_COUNT - 1.
|
||||||
|
*
|
||||||
|
* Alarm details are stored at the end of the realtime clock's non-volatile
|
||||||
|
* memory.
|
||||||
|
*
|
||||||
|
* \sa readAlarm(), alarmCount()
|
||||||
|
*/
|
||||||
|
void RTC::writeAlarm(uint8_t alarmNum, const RTCAlarm *value)
|
||||||
|
{
|
||||||
|
alarms[alarmNum] = *value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Reads the byte at \a offset within the realtime clock's non-volatile memory.
|
||||||
|
*
|
||||||
|
* The \a offset parameter must be between 0 and \ref BYTE_COUNT - 1.
|
||||||
|
*
|
||||||
|
* \sa writeByte()
|
||||||
|
*/
|
||||||
|
uint8_t RTC::readByte(uint8_t offset)
|
||||||
|
{
|
||||||
|
if (nvram)
|
||||||
|
return nvram[offset];
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Writes \a value to \a offset within the realtime clock's non-volatile memory.
|
||||||
|
*
|
||||||
|
* The \a offset parameter must be between 0 and \ref BYTE_COUNT - 1.
|
||||||
|
*
|
||||||
|
* \sa readByte()
|
||||||
|
*/
|
||||||
|
void RTC::writeByte(uint8_t offset, uint8_t value)
|
||||||
|
{
|
||||||
|
if (nvram) {
|
||||||
|
nvram[offset] = value;
|
||||||
|
} else {
|
||||||
|
nvram = (uint8_t *)malloc(BYTE_COUNT);
|
||||||
|
if (nvram) {
|
||||||
|
memset(nvram, 0, BYTE_COUNT);
|
||||||
|
nvram[offset] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \var RTC::INCREMENT
|
||||||
|
* \brief Increment the day, month, or year in a call to adjustDays(), adjustMonths(), or adjustYears().
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \var RTC::DECREMENT
|
||||||
|
* \brief Decrement the day, month, or year in a call to adjustDays(), adjustMonths(), or adjustYears().
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \var RTC::WRAP
|
||||||
|
* \brief Wrap around to the beginning of the current month/year rather than advance to the next one.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Adjusts \a date up or down one day according to \a flags.
|
||||||
|
*
|
||||||
|
* \sa adjustMonths(), adjustYears()
|
||||||
|
*/
|
||||||
|
void RTC::adjustDays(RTCDate *date, uint8_t flags)
|
||||||
|
{
|
||||||
|
if (flags & DECREMENT) {
|
||||||
|
--(date->day);
|
||||||
|
if (date->day == 0) {
|
||||||
|
if (!(flags & WRAP)) {
|
||||||
|
--(date->month);
|
||||||
|
if (date->month == 0)
|
||||||
|
date->month = 12;
|
||||||
|
}
|
||||||
|
date->day = monthLength(date);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
++(date->day);
|
||||||
|
if (date->day > monthLength(date)) {
|
||||||
|
if (!(flags & WRAP)) {
|
||||||
|
++(date->month);
|
||||||
|
if (date->month == 13)
|
||||||
|
date->month = 1;
|
||||||
|
}
|
||||||
|
date->day = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Adjusts \a date up or down one month according to \a flags.
|
||||||
|
*
|
||||||
|
* \sa adjustDays(), adjustYears()
|
||||||
|
*/
|
||||||
|
void RTC::adjustMonths(RTCDate *date, uint8_t flags)
|
||||||
|
{
|
||||||
|
if (flags & DECREMENT) {
|
||||||
|
--(date->month);
|
||||||
|
if (date->month == 0) {
|
||||||
|
date->month = 12;
|
||||||
|
if (!(flags & WRAP) && date->year > 2000)
|
||||||
|
--(date->year);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
++(date->month);
|
||||||
|
if (date->month == 13) {
|
||||||
|
date->month = 1;
|
||||||
|
if (!(flags & WRAP) && date->year < 2099)
|
||||||
|
++(date->year);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint8_t len = monthLength(date);
|
||||||
|
if (date->day > len)
|
||||||
|
date->day = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Adjusts \a date up or down one year according to \a flags.
|
||||||
|
*
|
||||||
|
* \sa adjustDays(), adjustMonths()
|
||||||
|
*/
|
||||||
|
void RTC::adjustYears(RTCDate *date, uint8_t flags)
|
||||||
|
{
|
||||||
|
if (flags & DECREMENT) {
|
||||||
|
--(date->year);
|
||||||
|
if (date->year < 2000)
|
||||||
|
date->year = 2000;
|
||||||
|
} else {
|
||||||
|
++(date->year);
|
||||||
|
if (date->year > 2099)
|
||||||
|
date->year = 2099;
|
||||||
|
}
|
||||||
|
uint8_t len = monthLength(date);
|
||||||
|
if (date->day > len)
|
||||||
|
date->day = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class RTCTime RTC.h <RTC.h>
|
||||||
|
* \brief Stores time information from a realtime clock chip.
|
||||||
|
*
|
||||||
|
* \sa RTCDate, RTCAlarm, RTC
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \var RTCTime::hour
|
||||||
|
* \brief Hour of the day (0-23)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \var RTCTime::minute
|
||||||
|
* \brief Minute within the hour (0-59)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \var RTCTime::second
|
||||||
|
* \brief Second within the minute (0-59)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class RTCDate RTC.h <RTC.h>
|
||||||
|
* \brief Stores date information from a realtime clock chip.
|
||||||
|
*
|
||||||
|
* \sa RTCTime, RTCAlarm, RTC
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \var RTCDate::year
|
||||||
|
* \brief Year (4-digit)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \var RTCDate::month
|
||||||
|
* \brief Month of the year (1-12)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \var RTCDate::day
|
||||||
|
* \brief Day of the month (1-31)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class RTCAlarm RTC.h <RTC.h>
|
||||||
|
* \brief Stores alarm information from a realtime clock chip.
|
||||||
|
*
|
||||||
|
* \sa RTCTime, RTCDate, RTC
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \var RTCAlarm::hour
|
||||||
|
* \brief Hour of the day for the alarm (0-23).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \var RTCAlarm::minute
|
||||||
|
* \brief Minute of the hour for the alarm (0-59).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \var RTCAlarm::flags
|
||||||
|
* \brief Additional flags for the alarm.
|
||||||
|
*
|
||||||
|
* The least significant bit will be 0 if the alarm is disabled or
|
||||||
|
* 1 if the alarm is enabled. Other bits can be used by the application
|
||||||
|
* for any purpose.
|
||||||
|
*/
|
89
libraries/BitBangI2C/RTC.h
Normal file
89
libraries/BitBangI2C/RTC.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RTC_h
|
||||||
|
#define RTC_h
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
struct RTCTime
|
||||||
|
{
|
||||||
|
uint8_t hour;
|
||||||
|
uint8_t minute;
|
||||||
|
uint8_t second;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RTCDate
|
||||||
|
{
|
||||||
|
unsigned int year;
|
||||||
|
uint8_t month;
|
||||||
|
uint8_t day;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RTCAlarm
|
||||||
|
{
|
||||||
|
uint8_t hour;
|
||||||
|
uint8_t minute;
|
||||||
|
uint8_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RTC
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RTC();
|
||||||
|
~RTC();
|
||||||
|
|
||||||
|
virtual bool hasUpdates();
|
||||||
|
|
||||||
|
virtual void readTime(RTCTime *value);
|
||||||
|
virtual void readDate(RTCDate *value);
|
||||||
|
|
||||||
|
virtual void writeTime(const RTCTime *value);
|
||||||
|
virtual void writeDate(const RTCDate *value);
|
||||||
|
|
||||||
|
static const uint8_t ALARM_COUNT = 4;
|
||||||
|
|
||||||
|
virtual void readAlarm(uint8_t alarmNum, RTCAlarm *value);
|
||||||
|
virtual void writeAlarm(uint8_t alarmNum, const RTCAlarm *value);
|
||||||
|
|
||||||
|
static const uint8_t BYTE_COUNT = 43;
|
||||||
|
|
||||||
|
virtual uint8_t readByte(uint8_t offset);
|
||||||
|
virtual void writeByte(uint8_t offset, uint8_t value);
|
||||||
|
|
||||||
|
// Flags for adjustDays(), adjustMonths(), and adjustYears().
|
||||||
|
static const uint8_t INCREMENT = 0x0000;
|
||||||
|
static const uint8_t DECREMENT = 0x0001;
|
||||||
|
static const uint8_t WRAP = 0x0002;
|
||||||
|
|
||||||
|
static void adjustDays(RTCDate *date, uint8_t flags);
|
||||||
|
static void adjustMonths(RTCDate *date, uint8_t flags);
|
||||||
|
static void adjustYears(RTCDate *date, uint8_t flags);
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned long midnight;
|
||||||
|
RTCDate date;
|
||||||
|
RTCAlarm alarms[ALARM_COUNT];
|
||||||
|
uint8_t *nvram;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -1,5 +1,6 @@
|
|||||||
BitBangI2C KEYWORD1
|
BitBangI2C KEYWORD1
|
||||||
DS1307RTC KEYWORD1
|
DS1307RTC KEYWORD1
|
||||||
|
RTC KEYWORD1
|
||||||
|
|
||||||
start KEYWORD2
|
start KEYWORD2
|
||||||
stop KEYWORD2
|
stop KEYWORD2
|
||||||
|
Loading…
x
Reference in New Issue
Block a user