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 static unsigned int monthOffsets[] = { 00070 0, 00071 31, 00072 31 + 28, 00073 31 + 28 + 31, 00074 31 + 28 + 31 + 30, 00075 31 + 28 + 31 + 30 + 31, 00076 31 + 28 + 31 + 30 + 31 + 30, 00077 31 + 28 + 31 + 30 + 31 + 30 + 31, 00078 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, 00079 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, 00080 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, 00081 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 00082 }; 00083 00084 inline bool isLeapYear(unsigned int year) 00085 { 00086 if ((year % 100) == 0) 00087 return (year % 400) == 0; 00088 else 00089 return (year % 4) == 0; 00090 } 00091 00092 inline uint8_t monthLength(const RTCDate *date) 00093 { 00094 if (date->month != 2 || !isLeapYear(date->year)) 00095 return monthLengths[date->month - 1]; 00096 else 00097 return 29; 00098 } 00099 00105 RTC::RTC() 00106 : midnight(millis() - 9 * MILLIS_PER_HOUR) // Simulated clock starts at 9am 00107 , nvram(0) 00108 { 00109 // Start the simulated date at 1 Jan, 2000. 00110 date.day = 1; 00111 date.month = 1; 00112 date.year = 2000; 00113 00114 // Set all simulated alarms to 6am by default. 00115 for (uint8_t index = 0; index < ALARM_COUNT; ++index) { 00116 alarms[index].hour = 6; 00117 alarms[index].minute = 0; 00118 alarms[index].flags = 0; 00119 } 00120 } 00121 00122 RTC::~RTC() 00123 { 00124 if (nvram) 00125 free(nvram); 00126 } 00127 00134 bool RTC::hasUpdates() 00135 { 00136 return true; 00137 } 00138 00144 void RTC::readTime(RTCTime *value) 00145 { 00146 // Determine the number of seconds since the last midnight event. 00147 unsigned long sinceMidnight = millis() - midnight; 00148 if (sinceMidnight >= MILLIS_PER_DAY) { 00149 // We have overflowed into the next day. Readjust midnight. 00150 midnight += MILLIS_PER_DAY; 00151 sinceMidnight -= MILLIS_PER_DAY; 00152 00153 // Increment the simulated date. 00154 adjustDays(&date, INCREMENT); 00155 } 00156 value->second = (uint8_t)(((sinceMidnight / MILLIS_PER_SECOND) % 60)); 00157 value->minute = (uint8_t)(((sinceMidnight / MILLIS_PER_MINUTE) % 60)); 00158 value->hour = (uint8_t)(sinceMidnight / MILLIS_PER_HOUR); 00159 } 00160 00169 void RTC::readDate(RTCDate *value) 00170 { 00171 *value = date; 00172 } 00173 00179 void RTC::writeTime(const RTCTime *value) 00180 { 00181 // Adjust the position of the last simulated midnight event. 00182 unsigned long sinceMidnight = 00183 value->second * MILLIS_PER_SECOND + 00184 value->minute * MILLIS_PER_MINUTE + 00185 value->hour * MILLIS_PER_HOUR; 00186 midnight = millis() - sinceMidnight; 00187 } 00188 00194 void RTC::writeDate(const RTCDate *value) 00195 { 00196 date = *value; 00197 } 00198 00209 void RTC::readAlarm(uint8_t alarmNum, RTCAlarm *value) 00210 { 00211 *value = alarms[alarmNum]; 00212 } 00213 00224 void RTC::writeAlarm(uint8_t alarmNum, const RTCAlarm *value) 00225 { 00226 alarms[alarmNum] = *value; 00227 } 00228 00235 int RTC::byteCount() const 00236 { 00237 return DEFAULT_BYTE_COUNT; 00238 } 00239 00247 uint8_t RTC::readByte(uint8_t offset) 00248 { 00249 if (nvram) 00250 return nvram[offset]; 00251 else 00252 return 0; 00253 } 00254 00262 void RTC::writeByte(uint8_t offset, uint8_t value) 00263 { 00264 if (nvram) { 00265 nvram[offset] = value; 00266 } else { 00267 nvram = (uint8_t *)malloc(DEFAULT_BYTE_COUNT); 00268 if (nvram) { 00269 memset(nvram, 0, DEFAULT_BYTE_COUNT); 00270 nvram[offset] = value; 00271 } 00272 } 00273 } 00274 00288 int RTC::readTemperature() 00289 { 00290 return NO_TEMPERATURE; 00291 } 00292 00313 void RTC::adjustDays(RTCDate *date, uint8_t flags) 00314 { 00315 if (flags & DECREMENT) { 00316 --(date->day); 00317 if (date->day == 0) { 00318 if (!(flags & WRAP)) { 00319 --(date->month); 00320 if (date->month == 0) 00321 date->month = 12; 00322 } 00323 date->day = monthLength(date); 00324 } 00325 } else { 00326 ++(date->day); 00327 if (date->day > monthLength(date)) { 00328 if (!(flags & WRAP)) { 00329 ++(date->month); 00330 if (date->month == 13) 00331 date->month = 1; 00332 } 00333 date->day = 1; 00334 } 00335 } 00336 } 00337 00343 void RTC::adjustMonths(RTCDate *date, uint8_t flags) 00344 { 00345 if (flags & DECREMENT) { 00346 --(date->month); 00347 if (date->month == 0) { 00348 date->month = 12; 00349 if (!(flags & WRAP) && date->year > 2000) 00350 --(date->year); 00351 } 00352 } else { 00353 ++(date->month); 00354 if (date->month == 13) { 00355 date->month = 1; 00356 if (!(flags & WRAP) && date->year < 2099) 00357 ++(date->year); 00358 } 00359 } 00360 uint8_t len = monthLength(date); 00361 if (date->day > len) 00362 date->day = len; 00363 } 00364 00370 void RTC::adjustYears(RTCDate *date, uint8_t flags) 00371 { 00372 if (flags & DECREMENT) { 00373 --(date->year); 00374 if (date->year < 2000) 00375 date->year = 2000; 00376 } else { 00377 ++(date->year); 00378 if (date->year > 2099) 00379 date->year = 2099; 00380 } 00381 uint8_t len = monthLength(date); 00382 if (date->day > len) 00383 date->day = len; 00384 } 00385 00399 RTC::DayOfWeek RTC::dayOfWeek(const RTCDate *date) 00400 { 00401 // The +4 here adjusts for Jan 1, 2000 being a Saturday. 00402 unsigned long daynum = date->day + 4; 00403 daynum += monthOffsets[date->month - 1]; 00404 if (date->month > 2 && isLeapYear(date->year)) 00405 ++daynum; 00406 daynum += 365UL * (date->year - 2000); 00407 if (date->year > 2000) 00408 daynum += ((date->year - 2001) / 4) + 1; 00409 return (DayOfWeek)((daynum % 7) + 1); 00410 } 00411