ArduinoLibs
RTC.cpp
00001 /*
00002  * Copyright (C) 2012 Southern Storm Software, Pty Ltd.
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a
00005  * copy of this software and associated documentation files (the "Software"),
00006  * to deal in the Software without restriction, including without limitation
00007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00008  * and/or sell copies of the Software, and to permit persons to whom the
00009  * Software is furnished to do so, subject to the following conditions:
00010  *
00011  * The above copyright notice and this permission notice shall be included
00012  * in all copies or substantial portions of the Software.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00015  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00017  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00019  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00020  * DEALINGS IN THE SOFTWARE.
00021  */
00022 
00023 #include "RTC.h"
00024 #if defined(ARDUINO) && ARDUINO >= 100
00025 #include <Arduino.h>
00026 #else
00027 #include <WProgram.h>
00028 #endif
00029 #include <stdlib.h>
00030 #include <string.h>
00031 
00058 #define DEFAULT_BYTE_COUNT  43  // Default simulates DS1307 NVRAM size.
00059 
00060 #define MILLIS_PER_DAY      86400000UL
00061 #define MILLIS_PER_SECOND   1000UL
00062 #define MILLIS_PER_MINUTE   60000UL
00063 #define MILLIS_PER_HOUR     3600000UL
00064 
00065 static uint8_t monthLengths[] = {
00066     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
00067 };
00068 
00069 inline bool isLeapYear(unsigned int year)
00070 {
00071     if ((year % 100) == 0)
00072         return (year % 400) == 0;
00073     else
00074         return (year % 4) == 0;
00075 }
00076 
00077 inline uint8_t monthLength(const RTCDate *date)
00078 {
00079     if (date->month != 2 || !isLeapYear(date->year))
00080         return monthLengths[date->month - 1];
00081     else
00082         return 29;
00083 }
00084 
00090 RTC::RTC()
00091     : midnight(millis() - 9 * MILLIS_PER_HOUR) // Simulated clock starts at 9am
00092     , nvram(0)
00093 {
00094     // Start the simulated date at 1 Jan, 2000.
00095     date.day = 1;
00096     date.month = 1;
00097     date.year = 2000;
00098 
00099     // Set all simulated alarms to 6am by default.
00100     for (uint8_t index = 0; index < ALARM_COUNT; ++index) {
00101         alarms[index].hour = 6;
00102         alarms[index].minute = 0;
00103         alarms[index].flags = 0;
00104     }
00105 }
00106 
00107 RTC::~RTC()
00108 {
00109     if (nvram)
00110         free(nvram);
00111 }
00112 
00119 bool RTC::hasUpdates()
00120 {
00121     return true;
00122 }
00123 
00129 void RTC::readTime(RTCTime *value)
00130 {
00131     // Determine the number of seconds since the last midnight event.
00132     unsigned long sinceMidnight = millis() - midnight;
00133     if (sinceMidnight >= MILLIS_PER_DAY) {
00134         // We have overflowed into the next day.  Readjust midnight.
00135         midnight += MILLIS_PER_DAY;
00136         sinceMidnight -= MILLIS_PER_DAY;
00137 
00138         // Increment the simulated date.
00139         adjustDays(&date, INCREMENT);
00140     }
00141     value->second = (uint8_t)(((sinceMidnight / MILLIS_PER_SECOND) % 60));
00142     value->minute = (uint8_t)(((sinceMidnight / MILLIS_PER_MINUTE) % 60));
00143     value->hour = (uint8_t)(sinceMidnight / MILLIS_PER_HOUR);
00144 }
00145 
00154 void RTC::readDate(RTCDate *value)
00155 {
00156     *value = date;
00157 }
00158 
00164 void RTC::writeTime(const RTCTime *value)
00165 {
00166     // Adjust the position of the last simulated midnight event.
00167     unsigned long sinceMidnight =
00168         value->second * MILLIS_PER_SECOND +
00169         value->minute * MILLIS_PER_MINUTE +
00170         value->hour   * MILLIS_PER_HOUR;
00171     midnight = millis() - sinceMidnight;
00172 }
00173 
00179 void RTC::writeDate(const RTCDate *value)
00180 {
00181     date = *value;
00182 }
00183 
00194 void RTC::readAlarm(uint8_t alarmNum, RTCAlarm *value)
00195 {
00196     *value = alarms[alarmNum];
00197 }
00198 
00209 void RTC::writeAlarm(uint8_t alarmNum, const RTCAlarm *value)
00210 {
00211     alarms[alarmNum] = *value;
00212 }
00213 
00220 int RTC::byteCount() const
00221 {
00222     return DEFAULT_BYTE_COUNT;
00223 }
00224 
00232 uint8_t RTC::readByte(uint8_t offset)
00233 {
00234     if (nvram)
00235         return nvram[offset];
00236     else
00237         return 0;
00238 }
00239 
00247 void RTC::writeByte(uint8_t offset, uint8_t value)
00248 {
00249     if (nvram) {
00250         nvram[offset] = value;
00251     } else {
00252         nvram = (uint8_t *)malloc(DEFAULT_BYTE_COUNT);
00253         if (nvram) {
00254             memset(nvram, 0, DEFAULT_BYTE_COUNT);
00255             nvram[offset] = value;
00256         }
00257     }
00258 }
00259 
00273 int RTC::readTemperature()
00274 {
00275     return NO_TEMPERATURE;
00276 }
00277 
00298 void RTC::adjustDays(RTCDate *date, uint8_t flags)
00299 {
00300     if (flags & DECREMENT) {
00301         --(date->day);
00302         if (date->day == 0) {
00303             if (!(flags & WRAP)) {
00304                 --(date->month);
00305                 if (date->month == 0)
00306                     date->month = 12;
00307             }
00308             date->day = monthLength(date);
00309         }
00310     } else {
00311         ++(date->day);
00312         if (date->day > monthLength(date)) {
00313             if (!(flags & WRAP)) {
00314                 ++(date->month);
00315                 if (date->month == 13)
00316                     date->month = 1;
00317             }
00318             date->day = 1;
00319         }
00320     }
00321 }
00322 
00328 void RTC::adjustMonths(RTCDate *date, uint8_t flags)
00329 {
00330     if (flags & DECREMENT) {
00331         --(date->month);
00332         if (date->month == 0) {
00333             date->month = 12;
00334             if (!(flags & WRAP) && date->year > 2000)
00335                 --(date->year);
00336         }
00337     } else {
00338         ++(date->month);
00339         if (date->month == 13) {
00340             date->month = 1;
00341             if (!(flags & WRAP) && date->year < 2099)
00342                 ++(date->year);
00343         }
00344     }
00345     uint8_t len = monthLength(date);
00346     if (date->day > len)
00347         date->day = len;
00348 }
00349 
00355 void RTC::adjustYears(RTCDate *date, uint8_t flags)
00356 {
00357     if (flags & DECREMENT) {
00358         --(date->year);
00359         if (date->year < 2000)
00360             date->year = 2000;
00361     } else {
00362         ++(date->year);
00363         if (date->year > 2099)
00364             date->year = 2099;
00365     }
00366     uint8_t len = monthLength(date);
00367     if (date->day > len)
00368         date->day = len;
00369 }
00370 
 All Classes Files Functions Variables Enumerations Enumerator