ArduinoLibs
|
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