]> git.piffa.net Git - arduino/blob - books/pdummies/Libraries/RTClib/RTClib.cpp
rotonda
[arduino] / books / pdummies / Libraries / RTClib / RTClib.cpp
1 // Code by JeeLabs http://news.jeelabs.org/code/
2 // Released to the public domain! Enjoy!
3
4 #include <Wire.h>
5 #include <avr/pgmspace.h>
6 #include "RTClib.h"
7
8 #define DS1307_ADDRESS 0x68
9 #define SECONDS_PER_DAY 86400L
10
11 #define SECONDS_FROM_1970_TO_2000 946684800
12
13 #if (ARDUINO >= 100)
14  #include <Arduino.h> // capital A so it is error prone on case-sensitive filesystems
15 #else
16  #include <WProgram.h>
17 #endif
18
19 int i = 0; //The new wire library needs to take an int when you are sending for the zero register
20 ////////////////////////////////////////////////////////////////////////////////
21 // utility code, some of this could be exposed in the DateTime API if needed
22
23 const uint8_t daysInMonth [] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 }; //has to be const or compiler compaints
24
25 // number of days since 2000/01/01, valid for 2001..2099
26 static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d) {
27     if (y >= 2000)
28         y -= 2000;
29     uint16_t days = d;
30     for (uint8_t i = 1; i < m; ++i)
31         days += pgm_read_byte(daysInMonth + i - 1);
32     if (m > 2 && y % 4 == 0)
33         ++days;
34     return days + 365 * y + (y + 3) / 4 - 1;
35 }
36
37 static long time2long(uint16_t days, uint8_t h, uint8_t m, uint8_t s) {
38     return ((days * 24L + h) * 60 + m) * 60 + s;
39 }
40
41 ////////////////////////////////////////////////////////////////////////////////
42 // DateTime implementation - ignores time zones and DST changes
43 // NOTE: also ignores leap seconds, see http://en.wikipedia.org/wiki/Leap_second
44
45 DateTime::DateTime (uint32_t t) {
46   t -= SECONDS_FROM_1970_TO_2000;    // bring to 2000 timestamp from 1970
47
48     ss = t % 60;
49     t /= 60;
50     mm = t % 60;
51     t /= 60;
52     hh = t % 24;
53     uint16_t days = t / 24;
54     uint8_t leap;
55     for (yOff = 0; ; ++yOff) {
56         leap = yOff % 4 == 0;
57         if (days < 365 + leap)
58             break;
59         days -= 365 + leap;
60     }
61     for (m = 1; ; ++m) {
62         uint8_t daysPerMonth = pgm_read_byte(daysInMonth + m - 1);
63         if (leap && m == 2)
64             ++daysPerMonth;
65         if (days < daysPerMonth)
66             break;
67         days -= daysPerMonth;
68     }
69     d = days + 1;
70 }
71
72 DateTime::DateTime (uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec) {
73     if (year >= 2000)
74         year -= 2000;
75     yOff = year;
76     m = month;
77     d = day;
78     hh = hour;
79     mm = min;
80     ss = sec;
81 }
82
83 static uint8_t conv2d(const char* p) {
84     uint8_t v = 0;
85     if ('0' <= *p && *p <= '9')
86         v = *p - '0';
87     return 10 * v + *++p - '0';
88 }
89
90 // A convenient constructor for using "the compiler's time":
91 //   DateTime now (__DATE__, __TIME__);
92 // NOTE: using PSTR would further reduce the RAM footprint
93 DateTime::DateTime (const char* date, const char* time) {
94     // sample input: date = "Dec 26 2009", time = "12:34:56"
95     yOff = conv2d(date + 9);
96     // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec 
97     switch (date[0]) {
98         case 'J': m = date[1] == 'a' ? 1 : m = date[2] == 'n' ? 6 : 7; break;
99         case 'F': m = 2; break;
100         case 'A': m = date[2] == 'r' ? 4 : 8; break;
101         case 'M': m = date[2] == 'r' ? 3 : 5; break;
102         case 'S': m = 9; break;
103         case 'O': m = 10; break;
104         case 'N': m = 11; break;
105         case 'D': m = 12; break;
106     }
107     d = conv2d(date + 4);
108     hh = conv2d(time);
109     mm = conv2d(time + 3);
110     ss = conv2d(time + 6);
111 }
112
113 uint8_t DateTime::dayOfWeek() const {    
114     uint16_t day = date2days(yOff, m, d);
115     return (day + 6) % 7; // Jan 1, 2000 is a Saturday, i.e. returns 6
116 }
117
118 uint32_t DateTime::unixtime(void) const {
119   uint32_t t;
120   uint16_t days = date2days(yOff, m, d);
121   t = time2long(days, hh, mm, ss);
122   t += SECONDS_FROM_1970_TO_2000;  // seconds from 1970 to 2000
123
124   return t;
125 }
126
127 ////////////////////////////////////////////////////////////////////////////////
128 // RTC_DS1307 implementation
129
130 static uint8_t bcd2bin (uint8_t val) { return val - 6 * (val >> 4); }
131 static uint8_t bin2bcd (uint8_t val) { return val + 6 * (val / 10); }
132
133 uint8_t RTC_DS1307::begin(void) {
134   return 1;
135 }
136
137
138 #if (ARDUINO >= 100)
139
140 uint8_t RTC_DS1307::isrunning(void) {
141   Wire.beginTransmission(DS1307_ADDRESS);
142   Wire.write(i);        
143   Wire.endTransmission();
144
145   Wire.requestFrom(DS1307_ADDRESS, 1);
146   uint8_t ss = Wire.read();
147   return !(ss>>7);
148 }
149
150 void RTC_DS1307::adjust(const DateTime& dt) {
151     Wire.beginTransmission(DS1307_ADDRESS);
152     Wire.write(i);
153     Wire.write(bin2bcd(dt.second()));
154     Wire.write(bin2bcd(dt.minute()));
155     Wire.write(bin2bcd(dt.hour()));
156     Wire.write(bin2bcd(0));
157     Wire.write(bin2bcd(dt.day()));
158     Wire.write(bin2bcd(dt.month()));
159     Wire.write(bin2bcd(dt.year() - 2000));
160     Wire.write(i);
161     Wire.endTransmission();
162 }
163
164 DateTime RTC_DS1307::now() {
165   Wire.beginTransmission(DS1307_ADDRESS);
166   Wire.write(i);        
167   Wire.endTransmission();
168   
169   Wire.requestFrom(DS1307_ADDRESS, 7);
170   uint8_t ss = bcd2bin(Wire.read() & 0x7F);
171   uint8_t mm = bcd2bin(Wire.read());
172   uint8_t hh = bcd2bin(Wire.read());
173   Wire.read();
174   uint8_t d = bcd2bin(Wire.read());
175   uint8_t m = bcd2bin(Wire.read());
176   uint16_t y = bcd2bin(Wire.read()) + 2000;
177   
178   return DateTime (y, m, d, hh, mm, ss);
179 }
180
181 #else
182
183 uint8_t RTC_DS1307::isrunning(void) {
184   Wire.beginTransmission(DS1307_ADDRESS);
185   Wire.send(i); 
186   Wire.endTransmission();
187
188   Wire.requestFrom(DS1307_ADDRESS, 1);
189   uint8_t ss = Wire.receive();
190   return !(ss>>7);
191 }
192
193 void RTC_DS1307::adjust(const DateTime& dt) {
194     Wire.beginTransmission(DS1307_ADDRESS);
195     Wire.send(i);
196     Wire.send(bin2bcd(dt.second()));
197     Wire.send(bin2bcd(dt.minute()));
198     Wire.send(bin2bcd(dt.hour()));
199     Wire.send(bin2bcd(0));
200     Wire.send(bin2bcd(dt.day()));
201     Wire.send(bin2bcd(dt.month()));
202     Wire.send(bin2bcd(dt.year() - 2000));
203     Wire.send(i);
204     Wire.endTransmission();
205 }
206
207 DateTime RTC_DS1307::now() {
208   Wire.beginTransmission(DS1307_ADDRESS);
209   Wire.send(i); 
210   Wire.endTransmission();
211   
212   Wire.requestFrom(DS1307_ADDRESS, 7);
213   uint8_t ss = bcd2bin(Wire.receive() & 0x7F);
214   uint8_t mm = bcd2bin(Wire.receive());
215   uint8_t hh = bcd2bin(Wire.receive());
216   Wire.receive();
217   uint8_t d = bcd2bin(Wire.receive());
218   uint8_t m = bcd2bin(Wire.receive());
219   uint16_t y = bcd2bin(Wire.receive()) + 2000;
220   
221   return DateTime (y, m, d, hh, mm, ss);
222 }
223
224 #endif
225
226
227 ////////////////////////////////////////////////////////////////////////////////
228 // RTC_Millis implementation
229
230 long RTC_Millis::offset = 0;
231
232 void RTC_Millis::adjust(const DateTime& dt) {
233     offset = dt.unixtime() - millis() / 1000;
234 }
235
236 DateTime RTC_Millis::now() {
237   return (uint32_t)(offset + millis() / 1000);
238 }
239
240 ////////////////////////////////////////////////////////////////////////////////