ArduinoLibs
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
RTC.cpp
1 /*
2  * Copyright (C) 2012 Southern Storm Software, Pty Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include "RTC.h"
24 #if defined(ARDUINO) && ARDUINO >= 100
25 #include <Arduino.h>
26 #else
27 #include <WProgram.h>
28 #endif
29 #include <stdlib.h>
30 #include <string.h>
31 
58 #define DEFAULT_BYTE_COUNT 43 // Default simulates DS1307 NVRAM size.
59 
60 #define MILLIS_PER_DAY 86400000UL
61 #define MILLIS_PER_SECOND 1000UL
62 #define MILLIS_PER_MINUTE 60000UL
63 #define MILLIS_PER_HOUR 3600000UL
64 
65 static uint8_t monthLengths[] = {
66  31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
67 };
68 
69 static unsigned int monthOffsets[] = {
70  0,
71  31,
72  31 + 28,
73  31 + 28 + 31,
74  31 + 28 + 31 + 30,
75  31 + 28 + 31 + 30 + 31,
76  31 + 28 + 31 + 30 + 31 + 30,
77  31 + 28 + 31 + 30 + 31 + 30 + 31,
78  31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
79  31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
80  31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
81  31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
82 };
83 
84 inline bool isLeapYear(unsigned int year)
85 {
86  if ((year % 100) == 0)
87  return (year % 400) == 0;
88  else
89  return (year % 4) == 0;
90 }
91 
92 inline uint8_t monthLength(const RTCDate *date)
93 {
94  if (date->month != 2 || !isLeapYear(date->year))
95  return monthLengths[date->month - 1];
96  else
97  return 29;
98 }
99 
106  : midnight(millis() - 9 * MILLIS_PER_HOUR) // Simulated clock starts at 9am
107  , nvram(0)
108 {
109  // Start the simulated date at 1 Jan, 2000.
110  date.day = 1;
111  date.month = 1;
112  date.year = 2000;
113 
114  // Set all simulated alarms to 6am by default.
115  for (uint8_t index = 0; index < ALARM_COUNT; ++index) {
116  alarms[index].hour = 6;
117  alarms[index].minute = 0;
118  alarms[index].flags = 0;
119  }
120 }
121 
122 RTC::~RTC()
123 {
124  if (nvram)
125  free(nvram);
126 }
127 
135 {
136  return true;
137 }
138 
144 void RTC::readTime(RTCTime *value)
145 {
146  // Determine the number of seconds since the last midnight event.
147  unsigned long sinceMidnight = millis() - midnight;
148  if (sinceMidnight >= MILLIS_PER_DAY) {
149  // We have overflowed into the next day. Readjust midnight.
150  midnight += MILLIS_PER_DAY;
151  sinceMidnight -= MILLIS_PER_DAY;
152 
153  // Increment the simulated date.
154  adjustDays(&date, INCREMENT);
155  }
156  value->second = (uint8_t)(((sinceMidnight / MILLIS_PER_SECOND) % 60));
157  value->minute = (uint8_t)(((sinceMidnight / MILLIS_PER_MINUTE) % 60));
158  value->hour = (uint8_t)(sinceMidnight / MILLIS_PER_HOUR);
159 }
160 
169 void RTC::readDate(RTCDate *value)
170 {
171  *value = date;
172 }
173 
179 void RTC::writeTime(const RTCTime *value)
180 {
181  // Adjust the position of the last simulated midnight event.
182  unsigned long sinceMidnight =
183  value->second * MILLIS_PER_SECOND +
184  value->minute * MILLIS_PER_MINUTE +
185  value->hour * MILLIS_PER_HOUR;
186  midnight = millis() - sinceMidnight;
187 }
188 
194 void RTC::writeDate(const RTCDate *value)
195 {
196  date = *value;
197 }
198 
209 void RTC::readAlarm(uint8_t alarmNum, RTCAlarm *value)
210 {
211  *value = alarms[alarmNum];
212 }
213 
224 void RTC::writeAlarm(uint8_t alarmNum, const RTCAlarm *value)
225 {
226  alarms[alarmNum] = *value;
227 }
228 
235 int RTC::byteCount() const
236 {
237  return DEFAULT_BYTE_COUNT;
238 }
239 
247 uint8_t RTC::readByte(uint8_t offset)
248 {
249  if (nvram)
250  return nvram[offset];
251  else
252  return 0;
253 }
254 
262 void RTC::writeByte(uint8_t offset, uint8_t value)
263 {
264  if (nvram) {
265  nvram[offset] = value;
266  } else {
267  nvram = (uint8_t *)malloc(DEFAULT_BYTE_COUNT);
268  if (nvram) {
269  memset(nvram, 0, DEFAULT_BYTE_COUNT);
270  nvram[offset] = value;
271  }
272  }
273 }
274 
289 {
290  return NO_TEMPERATURE;
291 }
292 
313 void RTC::adjustDays(RTCDate *date, uint8_t flags)
314 {
315  if (flags & DECREMENT) {
316  --(date->day);
317  if (date->day == 0) {
318  if (!(flags & WRAP)) {
319  --(date->month);
320  if (date->month == 0)
321  date->month = 12;
322  }
323  date->day = monthLength(date);
324  }
325  } else {
326  ++(date->day);
327  if (date->day > monthLength(date)) {
328  if (!(flags & WRAP)) {
329  ++(date->month);
330  if (date->month == 13)
331  date->month = 1;
332  }
333  date->day = 1;
334  }
335  }
336 }
337 
343 void RTC::adjustMonths(RTCDate *date, uint8_t flags)
344 {
345  if (flags & DECREMENT) {
346  --(date->month);
347  if (date->month == 0) {
348  date->month = 12;
349  if (!(flags & WRAP) && date->year > 2000)
350  --(date->year);
351  }
352  } else {
353  ++(date->month);
354  if (date->month == 13) {
355  date->month = 1;
356  if (!(flags & WRAP) && date->year < 2099)
357  ++(date->year);
358  }
359  }
360  uint8_t len = monthLength(date);
361  if (date->day > len)
362  date->day = len;
363 }
364 
370 void RTC::adjustYears(RTCDate *date, uint8_t flags)
371 {
372  if (flags & DECREMENT) {
373  --(date->year);
374  if (date->year < 2000)
375  date->year = 2000;
376  } else {
377  ++(date->year);
378  if (date->year > 2099)
379  date->year = 2099;
380  }
381  uint8_t len = monthLength(date);
382  if (date->day > len)
383  date->day = len;
384 }
385 
400 {
401  // The +4 here adjusts for Jan 1, 2000 being a Saturday.
402  unsigned long daynum = date->day + 4;
403  daynum += monthOffsets[date->month - 1];
404  if (date->month > 2 && isLeapYear(date->year))
405  ++daynum;
406  daynum += 365UL * (date->year - 2000);
407  if (date->year > 2000)
408  daynum += ((date->year - 2001) / 4) + 1;
409  return (DayOfWeek)((daynum % 7) + 1);
410 }
411 
uint8_t month
Month of the year (1-12)
Definition: RTC.h:38
virtual void writeTime(const RTCTime *value)
Updates the time in the realtime clock to match value.
Definition: RTC.cpp:179
RTC()
Constructs a new realtime clock handler.
Definition: RTC.cpp:105
static DayOfWeek dayOfWeek(const RTCDate *date)
Returns the day of the week corresponding to date.
Definition: RTC.cpp:399
uint8_t minute
Minute within the hour (0-59)
Definition: RTC.h:31
virtual void readAlarm(uint8_t alarmNum, RTCAlarm *value)
Reads the details of the alarm with index alarmNum into value.
Definition: RTC.cpp:209
virtual void readDate(RTCDate *value)
Reads the current date from the realtime clock into value.
Definition: RTC.cpp:169
static const uint8_t DECREMENT
Decrement the day, month, or year in a call to adjustDays(), adjustMonths(), or adjustYears().
Definition: RTC.h:92
DayOfWeek
Day of the week corresponding to a date.
Definition: RTC.h:58
virtual void writeAlarm(uint8_t alarmNum, const RTCAlarm *value)
Updates the details of the alarm with index alarmNum from value.
Definition: RTC.cpp:224
static const uint8_t ALARM_COUNT
Number of alarms that are supported by RTC::readAlarm() and RTC::writeAlarm().
Definition: RTC.h:77
virtual void writeDate(const RTCDate *value)
Updates the date in the realtime clock to match value.
Definition: RTC.cpp:194
virtual int byteCount() const
Returns the number of bytes of non-volatile memory that can be used for storage of arbitrary settings...
Definition: RTC.cpp:235
uint8_t hour
Hour of the day for the alarm (0-23).
Definition: RTC.h:46
static const int NO_TEMPERATURE
Value that is returned from readTemperature() if the realtime clock chip cannot determine the tempera...
Definition: RTC.h:86
uint8_t flags
Additional flags for the alarm.
Definition: RTC.h:49
Stores date information from a realtime clock chip.
Definition: RTC.h:35
unsigned int year
Year (4-digit)
Definition: RTC.h:37
virtual int readTemperature()
Reads the value of the temperature sensor and returns the temperature in quarters of a degree celcius...
Definition: RTC.cpp:288
virtual void writeByte(uint8_t offset, uint8_t value)
Writes value to offset within the realtime clock's non-volatile memory.
Definition: RTC.cpp:262
static void adjustYears(RTCDate *date, uint8_t flags)
Adjusts date up or down one year according to flags.
Definition: RTC.cpp:370
uint8_t minute
Minute of the hour for the alarm (0-59).
Definition: RTC.h:47
static const uint8_t INCREMENT
Increment the day, month, or year in a call to adjustDays(), adjustMonths(), or adjustYears().
Definition: RTC.h:91
virtual uint8_t readByte(uint8_t offset)
Reads the byte at offset within the realtime clock's non-volatile memory.
Definition: RTC.cpp:247
static void adjustDays(RTCDate *date, uint8_t flags)
Adjusts date up or down one day according to flags.
Definition: RTC.cpp:313
Stores time information from a realtime clock chip.
Definition: RTC.h:28
Stores alarm information from a realtime clock chip.
Definition: RTC.h:42
static void adjustMonths(RTCDate *date, uint8_t flags)
Adjusts date up or down one month according to flags.
Definition: RTC.cpp:343
uint8_t hour
Hour of the day (0-23)
Definition: RTC.h:30
uint8_t day
Day of the month (1-31)
Definition: RTC.h:39
uint8_t second
Second within the minute (0-59)
Definition: RTC.h:32
virtual bool hasUpdates()
Returns true if the realtime clock has updated since the last call to this function.
Definition: RTC.cpp:134
virtual void readTime(RTCTime *value)
Reads the current time from the realtime clock into value.
Definition: RTC.cpp:144
static const uint8_t WRAP
Wrap around to the beginning of the current month/year rather than advance to the next one...
Definition: RTC.h:93